From 755430ba686194511c13379049fe7362529b2b2a Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Sat, 17 May 2025 00:01:34 -0700 Subject: [PATCH 001/398] Add scheme to redirect total Qgwl to top 100 river outlets --- components/mosart/bld/build-namelist | 1 + .../namelist_defaults_mosart.xml | 1 + .../namelist_definition_mosart.xml | 8 + components/mosart/src/cpl/rof_comp_mct.F90 | 2 +- components/mosart/src/riverroute/RtmMod.F90 | 305 +++++++++++++++++- components/mosart/src/riverroute/RtmVar.F90 | 1 + 6 files changed, 311 insertions(+), 7 deletions(-) diff --git a/components/mosart/bld/build-namelist b/components/mosart/bld/build-namelist index 2ce54f39a2c6..9175d3d12136 100755 --- a/components/mosart/bld/build-namelist +++ b/components/mosart/bld/build-namelist @@ -330,6 +330,7 @@ else { add_default($nl, 'RoutingMethod'); add_default($nl, 'DLevelH2R'); add_default($nl, 'DLevelR'); + add_default($nl, 'redirect_total_qgwl'); # add_default($nl, 'finidat_rtm' , 'rof_grid'=>$ROF_GRID, 'simyr'=>$opts{'simyr'}, 'nofail'=>1 ); my $val = 0; if ($NCPL_BASE_PERIOD eq "year") { diff --git a/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml b/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml index b3e2ad8c9269..e8e0b9f0a1e2 100644 --- a/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml +++ b/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml @@ -24,6 +24,7 @@ for the CLM data in the CESM distribution .false. 0 .false. +.false. .false. 283.15 50 diff --git a/components/mosart/bld/namelist_files/namelist_definition_mosart.xml b/components/mosart/bld/namelist_files/namelist_definition_mosart.xml index c21879908ed6..1d3b54fe068a 100644 --- a/components/mosart/bld/namelist_files/namelist_definition_mosart.xml +++ b/components/mosart/bld/namelist_files/namelist_definition_mosart.xml @@ -126,6 +126,14 @@ Default: .false. If .true., mosart will read in bgc nutrients and send to ocean. + +Default: .false. +If .true., mosart will redirect total qgwl to the ocean. + + 0) then + allocate(all_outlet_gindices(num_all_outlets_global)) + allocate(all_outlet_discharges(num_all_outlets_global)) + else + ! Handle cases where no outlets are found if necessary, or let current_top_n_count be 0 + num_all_outlets_global = 0 ! Ensure it's zero if no outlets + endif + else + num_all_outlets_global = 0 ! Non-master tasks initialize to 0 + endif + call MPI_Bcast(num_all_outlets_global, 1, MPI_INTEGER, mastertask, mpicom_rof, ier) + + if(num_all_outlets_global > 0) then + call MPI_Gatherv(outlet_gindices_local, local_outlet_count, MPI_INTEGER, & + all_outlet_gindices, recvcounts, displs, MPI_INTEGER, & + mastertask, mpicom_rof, ier) + call MPI_Gatherv(outlet_discharges_local, local_outlet_count, MPI_REAL8, & + all_outlet_discharges, recvcounts, displs, MPI_REAL8, & + mastertask, mpicom_rof, ier) + endif + + if (allocated(outlet_gindices_local)) deallocate(outlet_gindices_local) + if (allocated(outlet_discharges_local)) deallocate(outlet_discharges_local) + + ! Rank on master, calculate proportions, and prepare corrections + current_top_n_count = 0 ! Initialize for all tasks + if (masterproc) then + if (num_all_outlets_global > 0) then + allocate(sorted_outlets(num_all_outlets_global)) + do i = 1, num_all_outlets_global + sorted_outlets(i)%gidx = all_outlet_gindices(i) + sorted_outlets(i)%discharge = all_outlet_discharges(i) + enddo + if (allocated(all_outlet_gindices)) deallocate(all_outlet_gindices) + if (allocated(all_outlet_discharges)) deallocate(all_outlet_discharges) + + call sort_outlets_by_discharge_desc(sorted_outlets, num_all_outlets_global) + + current_top_n_count = min(num_top_outlets_for_qgwl, num_all_outlets_global) + sum_discharge_top_n = 0.0_r8 + do i = 1, current_top_n_count + sum_discharge_top_n = sum_discharge_top_n + sorted_outlets(i)%discharge + enddo + if(current_top_n_count > 0) then + if (abs(sum_discharge_top_n) > 1.0e-9_r8) then ! Avoid division by zero + block + real(r8) :: qgwl_to_discharge_ratio_percent + + qgwl_to_discharge_ratio_percent = (global_net_qgwl / sum_discharge_top_n) * 100.0_r8 + + ! Print the ratio + write(iulog, *) trim(subname), & + 'Debug QGWL Ratio: (GlobalNetQGWL / SumTopNDischarge) = ', & + qgwl_to_discharge_ratio_percent, '%', & + ' (N_used = ', current_top_n_count, & + ', N_param = ', num_top_outlets_for_qgwl, ')' ! Using your var name + + ! Check and print warning if magnitude is > 5% + if (abs(qgwl_to_discharge_ratio_percent) > 5.0_r8) then + call shr_sys_flush(iulog) ! Flush previous message + write(iulog, *) trim(subname), & + 'WARNING: QGWL_Redist_Ratio magnitude > 5% (', & + qgwl_to_discharge_ratio_percent, '%). ', & + 'N_used = ', current_top_n_count, & + ', N_param = ', num_top_outlets_for_qgwl, & + '. Consider increasing N_param.' + call shr_sys_flush(iulog) ! Flush warning + endif + end block + else + write(iulog, *) trim(subname), & + 'Debug QGWL Ratio: Sum of Top ', current_top_n_count, & + ' Outlet Discharges is near zero. Ratio not calculated.' + endif + else + write(iulog, *) trim(subname), & + 'Debug QGWL Ratio: No top outlets selected (N_used = 0). Redistribution skipped.' + endif + if (current_top_n_count > 0) then + allocate(qgwl_correction_gindices(current_top_n_count)) + allocate(qgwl_correction_values(current_top_n_count)) + qgwl_correction_values = 0.0_r8 + do i = 1, current_top_n_count + qgwl_correction_gindices(i) = sorted_outlets(i)%gidx + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * global_net_qgwl + enddo + else + write(iulog, '(A)') trim(subname), & + 'Debug: No top outlets selected for QGWL redistribution (current_top_n_count is 0).' + allocate(qgwl_correction_gindices(current_top_n_count)) + allocate(qgwl_correction_values(current_top_n_count)) + qgwl_correction_values = 0.0_r8 + if (sum_discharge_top_n > 1.0e-9_r8) then ! Avoid division by zero + do i = 1, current_top_n_count + qgwl_correction_gindices(i) = sorted_outlets(i)%gidx + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * global_net_qgwl + enddo + else ! If sum of top N discharge is zero (or tiny), distribute equally (or handle as error/no distribution) + do i = 1, current_top_n_count + qgwl_correction_gindices(i) = sorted_outlets(i)%gidx + qgwl_correction_values(i) = global_net_qgwl / real(current_top_n_count, kind=r8) + enddo + endif + endif + if(allocated(sorted_outlets)) deallocate(sorted_outlets) + else + current_top_n_count = 0 ! No outlets globally + endif ! num_all_outlets_global > 0 + endif ! masterproc + + ! Broadcast correction info + call MPI_Bcast(current_top_n_count, 1, MPI_INTEGER, mastertask, mpicom_rof, ier) + if (.not. masterproc .and. current_top_n_count > 0) then + if (allocated(qgwl_correction_gindices)) deallocate(qgwl_correction_gindices) + if (allocated(qgwl_correction_values)) deallocate(qgwl_correction_values) + allocate(qgwl_correction_gindices(current_top_n_count)) + allocate(qgwl_correction_values(current_top_n_count)) + endif + if (current_top_n_count > 0) then + call MPI_Bcast(qgwl_correction_gindices, current_top_n_count, MPI_INTEGER, mastertask, mpicom_rof, ier) + call MPI_Bcast(qgwl_correction_values, current_top_n_count, MPI_REAL8, mastertask, mpicom_rof, ier) + + ! Populate local correction array + do k = 1, current_top_n_count + target_gidx = qgwl_correction_gindices(k) + do nr_local = rtmCTL%begr, rtmCTL%endr + if (rtmCTL%gindex(nr_local) == target_gidx) then + qgwl_correction_local(nr_local) = qgwl_correction_local(nr_local) + qgwl_correction_values(k) + exit + endif + enddo + enddo + endif ! current_top_n_count > 0 for broadcast and local application + + if (allocated(qgwl_correction_gindices)) deallocate(qgwl_correction_gindices) + if (allocated(qgwl_correction_values)) deallocate(qgwl_correction_values) + if (allocated(recvcounts)) deallocate(recvcounts) + if (allocated(displs)) deallocate(displs) + + call t_stopf('mosartr_qgwl_redir_dist') + endif ! global_net_qgwl /= 0.0_r8 (or just global_net_qgwl condition removed as per your last request) + endif ! redirect_total_qgwl_flag + + + ! This loop should now use the qgwl_correction_local array + do nt = 1,nt_rtm + do nr = rtmCTL%begr,rtmCTL%endr + volr_init = rtmCTL%volr(nr,nt) + + rtmCTL%runoff(nr,nt) = flow(nr,nt) ! This is main channel outflow from routing + rtmCTL%runofftot(nr,nt) = rtmCTL%direct(nr,nt) ! This is ice, qdto (if flag off), etc. + + if (rtmCTL%mask(nr) == 1) then ! Land + rtmCTL%runofflnd(nr,nt) = rtmCTL%runoff(nr,nt) + rtmCTL%dvolrdtlnd(nr,nt)= rtmCTL%dvolrdt(nr,nt) + elseif (rtmCTL%mask(nr) >= 2) then ! Ocean or Outlet + rtmCTL%runoffocn(nr,nt) = rtmCTL%runoff(nr,nt) ! Routed component + + ! Apply the distributed global qgwl correction ONLY to liquid tracer at target outlets + if (redirect_total_qgwl_flag .and. nt == nt_nliq) then + rtmCTL%runoffocn(nr,nt) = rtmCTL%runoffocn(nr,nt) + qgwl_correction_local(nr) + endif + rtmCTL%runofftot(nr,nt) = rtmCTL%runofftot(nr,nt) + rtmCTL%runoffocn(nr,nt) ! Add potentially corrected routed flow + rtmCTL%dvolrdtocn(nr,nt)= rtmCTL%dvolrdt(nr,nt) + endif + enddo ! nr + enddo ! nt + if (allocated(qgwl_correction_local)) deallocate(qgwl_correction_local) + + call t_stopf('mosartr_subcycling') !----------------------------------- @@ -5073,5 +5348,23 @@ end subroutine SubTimestep !----------------------------------------------------------------------- -end module RtmMod +subroutine sort_outlets_by_discharge_desc(outlets_array, count) !TZ negative runoff + implicit none + integer, intent(in) :: count + type(outlet_discharge_info_type), intent(inout) :: outlets_array(:) ! Assumed-shape + integer :: i, j + type(outlet_discharge_info_type) :: temp_outlet_info + ! Bubble sort + if (count < 2) return + do i = 1, count - 1 + do j = 1, count - i + if (outlets_array(j)%discharge < outlets_array(j+1)%discharge) then + temp_outlet_info = outlets_array(j) + outlets_array(j) = outlets_array(j+1) + outlets_array(j+1) = temp_outlet_info + endif + enddo + enddo +end subroutine sort_outlets_by_discharge_desc +end module RtmMod \ No newline at end of file diff --git a/components/mosart/src/riverroute/RtmVar.F90 b/components/mosart/src/riverroute/RtmVar.F90 index 7818d3b4bdf6..7cb72100732b 100644 --- a/components/mosart/src/riverroute/RtmVar.F90 +++ b/components/mosart/src/riverroute/RtmVar.F90 @@ -40,6 +40,7 @@ module RtmVar integer, public :: nlayers = 30 ! Maximum number of reservoir layers for stratification logical, public :: noland = .false. ! true => no valid land points -- do NOT run logical, public :: data_bgc_fluxes_to_ocean_flag = .false.! read in and send BGC fluxes to ocean flag + logical, public :: redirect_total_qgwl = .false. ! redirect total qgwl flag character(len=32) , public :: decomp_option ! decomp option character(len=32) , public :: smat_option ! smatrix multiply option (opt, Xonly, Yonly) ! opt = XandY in MCT From 900af6794671e680e4c683aa9eb97547f8ca1326 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Mon, 2 Jun 2025 17:53:08 -0700 Subject: [PATCH 002/398] Implementation to only redistribute negative Qgwl --- components/mosart/bld/build-namelist | 2 +- .../namelist_defaults_mosart.xml | 2 +- .../namelist_definition_mosart.xml | 4 +- components/mosart/src/cpl/rof_comp_mct.F90 | 2 +- components/mosart/src/riverroute/RtmMod.F90 | 72 +++++++++++-------- components/mosart/src/riverroute/RtmVar.F90 | 2 +- 6 files changed, 47 insertions(+), 37 deletions(-) diff --git a/components/mosart/bld/build-namelist b/components/mosart/bld/build-namelist index 9175d3d12136..74ffc6bc0abe 100755 --- a/components/mosart/bld/build-namelist +++ b/components/mosart/bld/build-namelist @@ -330,7 +330,7 @@ else { add_default($nl, 'RoutingMethod'); add_default($nl, 'DLevelH2R'); add_default($nl, 'DLevelR'); - add_default($nl, 'redirect_total_qgwl'); + add_default($nl, 'redirect_negative_qgwl'); # add_default($nl, 'finidat_rtm' , 'rof_grid'=>$ROF_GRID, 'simyr'=>$opts{'simyr'}, 'nofail'=>1 ); my $val = 0; if ($NCPL_BASE_PERIOD eq "year") { diff --git a/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml b/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml index e8e0b9f0a1e2..c68944769b2a 100644 --- a/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml +++ b/components/mosart/bld/namelist_files/namelist_defaults_mosart.xml @@ -24,7 +24,7 @@ for the CLM data in the CESM distribution .false. 0 .false. -.false. +.false. .false. 283.15 50 diff --git a/components/mosart/bld/namelist_files/namelist_definition_mosart.xml b/components/mosart/bld/namelist_files/namelist_definition_mosart.xml index 1d3b54fe068a..41ce96eac36e 100644 --- a/components/mosart/bld/namelist_files/namelist_definition_mosart.xml +++ b/components/mosart/bld/namelist_files/namelist_definition_mosart.xml @@ -126,12 +126,12 @@ Default: .false. If .true., mosart will read in bgc nutrients and send to ocean. - Default: .false. -If .true., mosart will redirect total qgwl to the ocean. +If .true., mosart will redirect negative qgwl to the ocean. 1.0e-9_r8) then ! Avoid division by zero do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * global_net_qgwl + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * global_net_negative_qgwl enddo else ! If sum of top N discharge is zero (or tiny), distribute equally (or handle as error/no distribution) do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = global_net_qgwl / real(current_top_n_count, kind=r8) + qgwl_correction_values(i) = global_net_negative_qgwl / real(current_top_n_count, kind=r8) enddo endif endif @@ -3086,8 +3096,8 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (allocated(displs)) deallocate(displs) call t_stopf('mosartr_qgwl_redir_dist') - endif ! global_net_qgwl /= 0.0_r8 (or just global_net_qgwl condition removed as per your last request) - endif ! redirect_total_qgwl_flag + endif ! global_net_negative_qgwl /= 0.0_r8 (or just global_net_negative_qgwl condition removed as per your last request) + endif ! redirect_negative_qgwl_flag ! This loop should now use the qgwl_correction_local array @@ -3105,7 +3115,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) rtmCTL%runoffocn(nr,nt) = rtmCTL%runoff(nr,nt) ! Routed component ! Apply the distributed global qgwl correction ONLY to liquid tracer at target outlets - if (redirect_total_qgwl_flag .and. nt == nt_nliq) then + if (redirect_negative_qgwl_flag .and. nt == nt_nliq) then rtmCTL%runoffocn(nr,nt) = rtmCTL%runoffocn(nr,nt) + qgwl_correction_local(nr) endif rtmCTL%runofftot(nr,nt) = rtmCTL%runofftot(nr,nt) + rtmCTL%runoffocn(nr,nt) ! Add potentially corrected routed flow diff --git a/components/mosart/src/riverroute/RtmVar.F90 b/components/mosart/src/riverroute/RtmVar.F90 index 7cb72100732b..64c8e6307159 100644 --- a/components/mosart/src/riverroute/RtmVar.F90 +++ b/components/mosart/src/riverroute/RtmVar.F90 @@ -40,7 +40,7 @@ module RtmVar integer, public :: nlayers = 30 ! Maximum number of reservoir layers for stratification logical, public :: noland = .false. ! true => no valid land points -- do NOT run logical, public :: data_bgc_fluxes_to_ocean_flag = .false.! read in and send BGC fluxes to ocean flag - logical, public :: redirect_total_qgwl = .false. ! redirect total qgwl flag + logical, public :: redirect_negative_qgwl = .false. ! redirect negative qgwl flag character(len=32) , public :: decomp_option ! decomp option character(len=32) , public :: smat_option ! smatrix multiply option (opt, Xonly, Yonly) ! opt = XandY in MCT From b96bd31374afe4ae679274d240307cf88e585602 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Wed, 6 Aug 2025 16:40:04 -0700 Subject: [PATCH 003/398] implement offsetting scheme --- components/mosart/src/riverroute/RtmMod.F90 | 109 +++++++++++++------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 32985aed296a..677fb45bfd49 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -142,7 +142,8 @@ module RtmMod ! Variables for TNR redirection integer, parameter :: num_top_outlets_for_qgwl = 500 ! Number of top outlets to use - real(r8), save :: global_net_negative_qgwl = 0.0_r8 ! Global Total negative qgwl + real(r8), save :: global_positive_qgwl_sum = 0.0_r8 ! Sum of all positive qgwl + real(r8), save :: global_negative_qgwl_sum = 0.0_r8 ! Sum of all negative qgwl real(r8), save :: delt_save ! previous delt @@ -2238,7 +2239,10 @@ subroutine Rtmrun(rstwr,nlend,rdate) !scs ! Variables for negative runoff redirection - real(r8) :: local_qgwl_sum + + real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum + real(r8) :: net_global_qgwl, original_cell_qgwl, reduction + integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets integer :: local_outlet_count @@ -2387,42 +2391,68 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! data for euler solver, in m3/s here ! Aggregate global Qgwl (TNR) if flag is true --- - global_net_negative_qgwl = 0.0_r8 ! Reset global sum each step - if (redirect_negative_qgwl_flag) then - local_qgwl_sum = 0.0_r8 ! This will sum local NEGATIVE qgwl - do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%qgwl(nr, nt_nliq) < 0.0_r8) then - local_qgwl_sum = local_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) - TRunoff%qgwl(nr, nt_nliq) = 0.0_r8 ! Negative part is removed for global redistribution - else - TRunoff%qgwl(nr, nt_nliq) = rtmCTL%qgwl(nr, nt_nliq) ! Positive part goes to local routing + global_negative_qgwl_sum = 0.0_r8 ! Reset global sum each step + + if (redirect_negative_qgwl_flag) then + local_negative_qgwl_sum = 0.0_r8 ! This will sum local NEGATIVE qgwl + local_positive_qgwl_sum = 0.0_r8 ! This will sum local POSITIVE qgwl + + do nr = rtmCTL%begr, rtmCTL%endr + if (rtmCTL%qgwl(nr, nt_nliq) > 0.0_r8) then + local_positive_qgwl_sum = local_positive_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) + elseif (rtmCTL%qgwl(nr, nt_nliq) < 0.0_r8) then + local_negative_qgwl_sum = local_negative_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) endif - ! Handle other tracers for qgwl if necessary - assuming qgwl for other tracers - ! should follow the original rtmCTL input if not the liquid one being modified. - do nt = 1, nt_rtm - if (nt /= nt_nliq) then - TRunoff%qgwl(nr, nt) = rtmCTL%qgwl(nr, nt) ! Other tracers pass through - endif - enddo - ! If qgwl for nt_nliq was positive, it's already set above. - ! If qgwl for nt_nliq was negative, it was zeroed out for nt_nliq. - enddo - - call MPI_Allreduce(local_qgwl_sum, global_net_negative_qgwl, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) - if (ier /= MPI_SUCCESS) then - if (masterproc) write(iulog,*) trim(subname),' ERROR in MPI_Allreduce for global_net_negative_qgwl, ier=',ier - call shr_sys_abort(trim(subname)//' MPI_Allreduce error for global_net_negative_qgwl') - endif - + enddo + + ! Use direct MPI_Allreduce to get the global sums A and B on all processes + call MPI_Allreduce(local_positive_qgwl_sum, global_positive_qgwl_sum, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) + call MPI_Allreduce(local_negative_qgwl_sum, global_negative_qgwl_sum, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) + + net_global_qgwl = global_positive_qgwl_sum + global_negative_qgwl_sum + if (masterproc) then - write(iulog,'(A,ES15.6)') trim(subname)//' Global negative sum of Qgwl this step: ', global_net_negative_qgwl + write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Positive Sum =', global_positive_qgwl_sum + write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Negative Sum =', global_negative_qgwl_sum + write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Net Sum =', net_global_qgwl endif - else + + ! Decide how to set TRunoff%qgwl for local routing + if (net_global_qgwl >= 0.0_r8) then + ! --- SCENARIO A: Net global QGWL is non-negative. Balance the negative by proportionally reducing positive. --- + do nr = rtmCTL%begr, rtmCTL%endr + original_cell_qgwl = rtmCTL%qgwl(nr, nt_nliq) + if (original_cell_qgwl > 0.0_r8) then ! This cell has positive qgwl + if (global_positive_qgwl_sum > 1.0e-9_r8) then ! Avoid division by zero + ! Calculate how much this cell should contribute to offsetting the negative sum + reduction = (original_cell_qgwl / global_positive_qgwl_sum) * abs(global_negative_qgwl_sum) + TRunoff%qgwl(nr, nt_nliq) = max(0.0_r8, original_cell_qgwl - reduction) + else ! No positive qgwl anywhere, so this branch shouldn't be hit if original_cell_qgwl > 0 + TRunoff%qgwl(nr, nt_nliq) = original_cell_qgwl + endif + else ! This cell has negative or zero qgwl + TRunoff%qgwl(nr, nt_nliq) = 0.0_r8 ! Its negativity is balanced by the global positives + endif + ! Pass through other tracers unmodified + do nt = 1, nt_rtm + if (nt /= nt_nliq) then + TRunoff%qgwl(nr, nt) = rtmCTL%qgwl(nr, nt) + endif + enddo + enddo + else + ! --- SCENARIO B: Net global QGWL is negative. No local qgwl input. --- + ! The deficit (net_global_qgwl) will be redistributed to top N outlets later. + do nr = rtmCTL%begr, rtmCTL%endr + TRunoff%qgwl(nr, :) = 0.0_r8 + enddo + endif + else ! If flag is false, ensure TRunoff gets the qgwl from rtmCTL for routing do nr = rtmCTL%begr, rtmCTL%endr TRunoff%qgwl(nr, :) = rtmCTL%qgwl(nr, :) enddo - endif + endif do nr = rtmCTL%begr,rtmCTL%endr do nt = 1,nt_rtm @@ -2912,12 +2942,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) enddo enddo - ! Collect outlet discharge, Rank, Redistribute global_net_negative_qgwl, Update discharge map --- + ! Collect outlet discharge, Rank, Redistribute net_global_qgwl, Update discharge map --- allocate(qgwl_correction_local(rtmCTL%begr:rtmCTL%endr)) ! Moved allocation here qgwl_correction_local = 0.0_r8 ! Initialize if (redirect_negative_qgwl_flag) then ! Check the main flag first - if (global_net_negative_qgwl < 0.0_r8) then ! Only proceed if there's some net qgwl to redistribute (can be pos or neg) + if (net_global_qgwl < 0.0_r8) then ! Only proceed if there's negative net qgwl to redistribute call t_startf('mosartr_qgwl_redir_dist') ! Identify local outlets and their current discharges @@ -3004,7 +3034,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) block real(r8) :: qgwl_to_discharge_ratio_percent - qgwl_to_discharge_ratio_percent = (global_net_negative_qgwl / sum_discharge_top_n) * 100.0_r8 + qgwl_to_discharge_ratio_percent = (net_global_qgwl / sum_discharge_top_n) * 100.0_r8 ! Print the ratio write(iulog, *) trim(subname), & @@ -3040,7 +3070,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) qgwl_correction_values = 0.0_r8 do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * global_net_negative_qgwl + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * net_global_qgwl enddo else write(iulog, '(A)') trim(subname), & @@ -3051,12 +3081,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (sum_discharge_top_n > 1.0e-9_r8) then ! Avoid division by zero do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * global_net_negative_qgwl + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * net_global_qgwl enddo else ! If sum of top N discharge is zero (or tiny), distribute equally (or handle as error/no distribution) do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = global_net_negative_qgwl / real(current_top_n_count, kind=r8) + qgwl_correction_values(i) = net_global_qgwl / real(current_top_n_count, kind=r8) enddo endif endif @@ -3096,7 +3126,10 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (allocated(displs)) deallocate(displs) call t_stopf('mosartr_qgwl_redir_dist') - endif ! global_net_negative_qgwl /= 0.0_r8 (or just global_net_negative_qgwl condition removed as per your last request) + else + write(iulog, *) trim(subname), & + 'Global net QGWL is positive, offsetting the negative values.' + endif ! net_global_qgwl < 0.0_r8 endif ! redirect_negative_qgwl_flag From 8cb9508ead1a241180c5aeaf38a6b5734caac3e6 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Sat, 18 Oct 2025 00:38:45 -0700 Subject: [PATCH 004/398] Reprosum instead of MPI_Allreduce --- components/mosart/src/riverroute/RtmMod.F90 | 174 ++++++++++++++++---- 1 file changed, 140 insertions(+), 34 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 677fb45bfd49..2758e406d097 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -15,6 +15,7 @@ module RtmMod use rof_cpl_indices , only : nt_rtm, rtm_tracers, KW, DW use seq_flds_mod , only : rof_sed use RtmSpmd , only : masterproc, npes, iam, mpicom_rof, ROFID, mastertask + use shr_reprosum_mod, only : shr_reprosum_calc use mpi use RtmVar , only : re, spval, rtmlon, rtmlat, iulog, ice_runoff, & frivinp_rtm, frivinp_mesh, finidat_rtm, nrevsn_rtm,rstraflag,ngeom,nlayers,rinittemp, & @@ -2255,7 +2256,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8), allocatable :: qgwl_correction_values(:) ! Values to apply integer, allocatable :: qgwl_correction_gindices(:) ! Global indices for these corrections real(r8), allocatable :: qgwl_correction_local(:) ! Local portion of correction array - + real(r8) :: qgwl_to_redistribute ! Amount to redistribute (Scenario A or B) character(len=*),parameter :: subname = '(Rtmrun) ' !----------------------------------------------------------------------- @@ -2405,9 +2406,30 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif enddo - ! Use direct MPI_Allreduce to get the global sums A and B on all processes - call MPI_Allreduce(local_positive_qgwl_sum, global_positive_qgwl_sum, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) - call MPI_Allreduce(local_negative_qgwl_sum, global_negative_qgwl_sum, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) + ! Use reproducible sum for bit-for-bit reproducibility across PE layouts + block + real(r8) :: pos_local(1,1), pos_global(1) + real(r8) :: neg_local(1,1), neg_global(1) + + ! Reproducible sum for positive qgwl + pos_local(1,1) = local_positive_qgwl_sum + call shr_reprosum_calc(pos_local, pos_global, 1, 1, 1, & + commid=mpicom_rof) + global_positive_qgwl_sum = pos_global(1) + + ! Reproducible sum for negative qgwl + neg_local(1,1) = local_negative_qgwl_sum + call shr_reprosum_calc(neg_local, neg_global, 1, 1, 1, & + commid=mpicom_rof) + global_negative_qgwl_sum = neg_global(1) + + ! Diagnostic output for debugging + if (masterproc) then + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum = ', global_positive_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum = ', global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Net Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum + endif + end block net_global_qgwl = global_positive_qgwl_sum + global_negative_qgwl_sum @@ -2418,31 +2440,18 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif ! Decide how to set TRunoff%qgwl for local routing + ! For BOTH scenarios, we let original qgwl flow to direct discharge, + ! and then add corrections at outlets to balance negative values if (net_global_qgwl >= 0.0_r8) then - ! --- SCENARIO A: Net global QGWL is non-negative. Balance the negative by proportionally reducing positive. --- + ! --- SCENARIO A: Net global QGWL is non-negative. --- + ! Let original qgwl flow to rtmCTL%direct (no modification here) + ! The negative qgwl will be balanced by adding to outlets later do nr = rtmCTL%begr, rtmCTL%endr - original_cell_qgwl = rtmCTL%qgwl(nr, nt_nliq) - if (original_cell_qgwl > 0.0_r8) then ! This cell has positive qgwl - if (global_positive_qgwl_sum > 1.0e-9_r8) then ! Avoid division by zero - ! Calculate how much this cell should contribute to offsetting the negative sum - reduction = (original_cell_qgwl / global_positive_qgwl_sum) * abs(global_negative_qgwl_sum) - TRunoff%qgwl(nr, nt_nliq) = max(0.0_r8, original_cell_qgwl - reduction) - else ! No positive qgwl anywhere, so this branch shouldn't be hit if original_cell_qgwl > 0 - TRunoff%qgwl(nr, nt_nliq) = original_cell_qgwl - endif - else ! This cell has negative or zero qgwl - TRunoff%qgwl(nr, nt_nliq) = 0.0_r8 ! Its negativity is balanced by the global positives - endif - ! Pass through other tracers unmodified - do nt = 1, nt_rtm - if (nt /= nt_nliq) then - TRunoff%qgwl(nr, nt) = rtmCTL%qgwl(nr, nt) - endif - enddo + TRunoff%qgwl(nr, :) = rtmCTL%qgwl(nr, :) enddo else - ! --- SCENARIO B: Net global QGWL is negative. No local qgwl input. --- - ! The deficit (net_global_qgwl) will be redistributed to top N outlets later. + ! --- SCENARIO B: Net global QGWL is negative. Redistribute ALL qgwl mass to outlets.--- + ! Set all local qgwl to zero - entire net amount will be added at outlets do nr = rtmCTL%begr, rtmCTL%endr TRunoff%qgwl(nr, :) = 0.0_r8 enddo @@ -2454,6 +2463,8 @@ subroutine Rtmrun(rstwr,nlend,rdate) enddo endif + ! Remove the incorrect "before" diagnostic from here - will be added at the right location + do nr = rtmCTL%begr,rtmCTL%endr do nt = 1,nt_rtm TRunoff%qsur(nr,nt) = rtmCTL%qsur(nr,nt) @@ -2942,12 +2953,29 @@ subroutine Rtmrun(rstwr,nlend,rdate) enddo enddo - ! Collect outlet discharge, Rank, Redistribute net_global_qgwl, Update discharge map --- + ! Collect outlet discharge, Rank, Redistribute qgwl, Update discharge map --- allocate(qgwl_correction_local(rtmCTL%begr:rtmCTL%endr)) ! Moved allocation here qgwl_correction_local = 0.0_r8 ! Initialize if (redirect_negative_qgwl_flag) then ! Check the main flag first - if (net_global_qgwl < 0.0_r8) then ! Only proceed if there's negative net qgwl to redistribute + ! Determine amount to redistribute: + ! Scenario A (net >= 0): redistribute abs(negative_sum) to balance negatives + ! Scenario B (net < 0): redistribute net_global_qgwl (entire net amount) + if (net_global_qgwl >= 0.0_r8) then + qgwl_to_redistribute = abs(global_negative_qgwl_sum) ! Scenario A + if (masterproc) then + write(iulog, *) trim(subname), 'Using Scenario A: redistributing negative qgwl (', & + qgwl_to_redistribute, ' m3/s) to outlets' + endif + else + qgwl_to_redistribute = net_global_qgwl ! Scenario B (negative value) + if (masterproc) then + write(iulog, *) trim(subname), 'Using Scenario B: redistributing entire net qgwl (', & + qgwl_to_redistribute, ' m3/s) to outlets' + endif + endif + + if (abs(qgwl_to_redistribute) > 1.0e-15_r8) then ! Only proceed if there's something to redistribute call t_startf('mosartr_qgwl_redir_dist') ! Identify local outlets and their current discharges @@ -3033,12 +3061,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (abs(sum_discharge_top_n) > 1.0e-9_r8) then ! Avoid division by zero block real(r8) :: qgwl_to_discharge_ratio_percent - - qgwl_to_discharge_ratio_percent = (net_global_qgwl / sum_discharge_top_n) * 100.0_r8 - + + qgwl_to_discharge_ratio_percent = (qgwl_to_redistribute / sum_discharge_top_n) * 100.0_r8 + ! Print the ratio write(iulog, *) trim(subname), & - 'Debug QGWL Ratio: (GlobalNetQGWL / SumTopNDischarge) = ', & + 'Debug QGWL Ratio: (QGWL_to_redistribute / SumTopNDischarge) = ', & qgwl_to_discharge_ratio_percent, '%', & ' (N_used = ', current_top_n_count, & ', N_param = ', num_top_outlets_for_qgwl, ')' ! Using your var name @@ -3070,7 +3098,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) qgwl_correction_values = 0.0_r8 do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * net_global_qgwl + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * qgwl_to_redistribute enddo else write(iulog, '(A)') trim(subname), & @@ -3081,12 +3109,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (sum_discharge_top_n > 1.0e-9_r8) then ! Avoid division by zero do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * net_global_qgwl + qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * qgwl_to_redistribute enddo else ! If sum of top N discharge is zero (or tiny), distribute equally (or handle as error/no distribution) do i = 1, current_top_n_count qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = net_global_qgwl / real(current_top_n_count, kind=r8) + qgwl_correction_values(i) = qgwl_to_redistribute / real(current_top_n_count, kind=r8) enddo endif endif @@ -3147,6 +3175,46 @@ subroutine Rtmrun(rstwr,nlend,rdate) elseif (rtmCTL%mask(nr) >= 2) then ! Ocean or Outlet rtmCTL%runoffocn(nr,nt) = rtmCTL%runoff(nr,nt) ! Routed component + ! ===================================================== + ! DIAGNOSTIC: Global sum BEFORE outlet corrections (once per timestep) + ! ===================================================== + if (nt == nt_nliq .and. nr == rtmCTL%begr) then ! Only do this once per timestep + block + real(r8) :: local_total_liquid_before, global_total_liquid_before + integer :: nr_temp + local_total_liquid_before = 0.0_r8 + do nr_temp = rtmCTL%begr, rtmCTL%endr + ! Sum what will be sent to coupler: rtmCTL%direct + rtmCTL%runoff + local_total_liquid_before = local_total_liquid_before + & + rtmCTL%direct(nr_temp, nt_nliq) + rtmCTL%runoff(nr_temp, nt_nliq) + enddo + + ! Use reproducible sum for bit-for-bit reproducibility across PE layouts + block + real(r8) :: before_local(1,1), before_global(1) + + ! Reproducible sum for total liquid before + before_local(1,1) = local_total_liquid_before + call shr_reprosum_calc(before_local, before_global, 1, 1, 1, & + commid=mpicom_rof) + global_total_liquid_before = before_global(1) + + ! Diagnostic output for debugging + if (masterproc) then + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Total Liquid Before = ', global_total_liquid_before + endif + end block + + if (masterproc) then + if (redirect_negative_qgwl_flag) then + write(iulog, '(A,ES24.16)') trim(subname)//' CONSERVATION CHECK: Global liquid runoff BEFORE outlet corrections (redirect=ON) = ', global_total_liquid_before + else + write(iulog, '(A,ES24.16)') trim(subname)//' CONSERVATION CHECK: Global liquid runoff BEFORE outlet corrections (baseline) = ', global_total_liquid_before + endif + endif + end block + endif + ! Apply the distributed global qgwl correction ONLY to liquid tracer at target outlets if (redirect_negative_qgwl_flag .and. nt == nt_nliq) then rtmCTL%runoffocn(nr,nt) = rtmCTL%runoffocn(nr,nt) + qgwl_correction_local(nr) @@ -3156,6 +3224,44 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif enddo ! nr enddo ! nt + + ! ===================================================== + ! DIAGNOSTIC: Global sum of total liquid runoff AFTER redirection + ! This should equal the "before" sum for conservation (only when redirect is ON) + ! ===================================================== + if (redirect_negative_qgwl_flag) then + block + real(r8) :: local_total_liquid_after, global_total_liquid_after + local_total_liquid_after = 0.0_r8 + do nr = rtmCTL%begr, rtmCTL%endr + ! Sum what actually gets sent to coupler: rtmCTL%direct + rtmCTL%runoff + ! This matches exactly what rof_comp_mct.F90 sends to ocean + local_total_liquid_after = local_total_liquid_after + & + rtmCTL%direct(nr, nt_nliq) + rtmCTL%runoff(nr, nt_nliq) + enddo + + ! Use reproducible sum for bit-for-bit reproducibility across PE layouts + block + real(r8) :: after_local(1,1), after_global(1) + + ! Reproducible sum for total liquid after + after_local(1,1) = local_total_liquid_after + call shr_reprosum_calc(after_local, after_global, 1, 1, 1, & + commid=mpicom_rof) + global_total_liquid_after = after_global(1) + + ! Diagnostic output for debugging + if (masterproc) then + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Total Liquid After = ', global_total_liquid_after + endif + end block + + if (masterproc) then + write(iulog, '(A,ES24.16)') trim(subname)//' CONSERVATION CHECK: Global liquid runoff AFTER redirection = ', global_total_liquid_after + endif + end block + endif + if (allocated(qgwl_correction_local)) deallocate(qgwl_correction_local) From 330622278d51b82e6d04d0de1467073c49ad28f5 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Sat, 18 Oct 2025 02:33:44 -0700 Subject: [PATCH 005/398] Fixing error for Scenario B --- components/mosart/src/riverroute/RtmMod.F90 | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 2758e406d097..28c7967323d6 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2959,13 +2959,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (redirect_negative_qgwl_flag) then ! Check the main flag first ! Determine amount to redistribute: - ! Scenario A (net >= 0): redistribute abs(negative_sum) to balance negatives - ! Scenario B (net < 0): redistribute net_global_qgwl (entire net amount) + ! Scenario A (net >= 0): Original qgwl flows to direct (no outlet correction needed) + ! Scenario B (net < 0): All qgwl zeroed, redistribute net amount to outlets if (net_global_qgwl >= 0.0_r8) then - qgwl_to_redistribute = abs(global_negative_qgwl_sum) ! Scenario A + qgwl_to_redistribute = 0.0_r8 ! Scenario A: negatives already in direct discharge if (masterproc) then - write(iulog, *) trim(subname), 'Using Scenario A: redistributing negative qgwl (', & - qgwl_to_redistribute, ' m3/s) to outlets' + write(iulog, *) trim(subname), 'Using Scenario A: original qgwl flows to direct (no outlet correction)' endif else qgwl_to_redistribute = net_global_qgwl ! Scenario B (negative value) @@ -3216,10 +3215,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif ! Apply the distributed global qgwl correction ONLY to liquid tracer at target outlets + ! Apply to rtmCTL%runoff (not runoffocn) since runoff is what gets sent to coupler if (redirect_negative_qgwl_flag .and. nt == nt_nliq) then - rtmCTL%runoffocn(nr,nt) = rtmCTL%runoffocn(nr,nt) + qgwl_correction_local(nr) + rtmCTL%runoff(nr,nt) = rtmCTL%runoff(nr,nt) + qgwl_correction_local(nr) + rtmCTL%runoffocn(nr,nt) = rtmCTL%runoff(nr,nt) ! Keep runoffocn in sync endif - rtmCTL%runofftot(nr,nt) = rtmCTL%runofftot(nr,nt) + rtmCTL%runoffocn(nr,nt) ! Add potentially corrected routed flow + rtmCTL%runofftot(nr,nt) = rtmCTL%runofftot(nr,nt) + rtmCTL%runoffocn(nr,nt) ! Add corrected routed flow rtmCTL%dvolrdtocn(nr,nt)= rtmCTL%dvolrdt(nr,nt) endif enddo ! nr @@ -3235,7 +3236,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) local_total_liquid_after = 0.0_r8 do nr = rtmCTL%begr, rtmCTL%endr ! Sum what actually gets sent to coupler: rtmCTL%direct + rtmCTL%runoff - ! This matches exactly what rof_comp_mct.F90 sends to ocean + ! rtmCTL%runoff includes the qgwl correction applied at line 3221 local_total_liquid_after = local_total_liquid_after + & rtmCTL%direct(nr, nt_nliq) + rtmCTL%runoff(nr, nt_nliq) enddo @@ -3301,7 +3302,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (rtmCTL%mask(nr) >= 2) then ! (2 -- Ocean; 3 -- Outlet. --Inund.) - budget_terms(br_ocnout,nt) = budget_terms(br_ocnout,nt) + rtmCTL%runoff(nr,nt)*delt_coupling ! (Volume of outflows to oceans. Note that rtmCTL%runoff is averge value of sub-steps used by MOSART. --Inund.) + budget_terms(br_ocnout,nt) = budget_terms(br_ocnout,nt) + rtmCTL%runoff(nr,nt)*delt_coupling ! (Volume of outflows to oceans. runoff includes qgwl corrections from line 3221. --Inund.) budget_terms(br_erolpo,nt) = budget_terms(br_erolpo,nt) + eroup_lagi(nr,nt)*delt_coupling ! (Volume of outflows to oceans in the previous MOSART sub-step. ! Also eroup_lagi is averge value of several previous MOSART sub-steps. --Inund.) budget_terms(br_erolco,nt) = budget_terms(br_erolco,nt) + eroup_lagf(nr,nt)*delt_coupling ! (Volume of outflows to oceans. Actually eroup_lagf is same as the above rtmCTL%runoff. --Inund.) From 9078cbad38b3590357f06c8abb5d61a5fdfd0517 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Sat, 18 Oct 2025 03:22:13 -0700 Subject: [PATCH 006/398] Fixing error for Scenario A --- components/mosart/src/riverroute/RtmMod.F90 | 26 ++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 28c7967323d6..57a3c6cdc874 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2242,7 +2242,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Variables for negative runoff redirection real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum - real(r8) :: net_global_qgwl, original_cell_qgwl, reduction + real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets @@ -2440,14 +2440,28 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif ! Decide how to set TRunoff%qgwl for local routing - ! For BOTH scenarios, we let original qgwl flow to direct discharge, - ! and then add corrections at outlets to balance negative values if (net_global_qgwl >= 0.0_r8) then ! --- SCENARIO A: Net global QGWL is non-negative. --- - ! Let original qgwl flow to rtmCTL%direct (no modification here) - ! The negative qgwl will be balanced by adding to outlets later + ! Proportionally reduce positive qgwl to offset negatives, zero out negative cells + ! This ensures NO negative qgwl enters the ocean at any grid cell + + if (global_positive_qgwl_sum > 0.0_r8) then + ! Calculate scaling factor: (positive - |negative|) / positive = net / positive + scaling_factor = net_global_qgwl / global_positive_qgwl_sum + else + scaling_factor = 1.0_r8 ! No positive qgwl, keep as is + endif + do nr = rtmCTL%begr, rtmCTL%endr - TRunoff%qgwl(nr, :) = rtmCTL%qgwl(nr, :) + do nt = 1, nt_rtm + if (rtmCTL%qgwl(nr, nt) > 0.0_r8) then + ! Positive cell: scale down proportionally + TRunoff%qgwl(nr, nt) = rtmCTL%qgwl(nr, nt) * scaling_factor + else + ! Negative or zero cell: set to zero + TRunoff%qgwl(nr, nt) = 0.0_r8 + endif + enddo enddo else ! --- SCENARIO B: Net global QGWL is negative. Redistribute ALL qgwl mass to outlets.--- From 2fc7068e79704e256d7f43ba6e2bb58bab11eb45 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Sun, 19 Oct 2025 01:49:42 -0700 Subject: [PATCH 007/398] optimize diagnostic outputs --- components/mosart/src/riverroute/RtmMod.F90 | 332 +++++--------------- 1 file changed, 84 insertions(+), 248 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 57a3c6cdc874..0dc179c42c24 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2257,6 +2257,13 @@ subroutine Rtmrun(rstwr,nlend,rdate) integer, allocatable :: qgwl_correction_gindices(:) ! Global indices for these corrections real(r8), allocatable :: qgwl_correction_local(:) ! Local portion of correction array real(r8) :: qgwl_to_redistribute ! Amount to redistribute (Scenario A or B) + real(r8) :: local_total_outlet_discharge, global_total_outlet_discharge + real(r8) :: outlet_discharge_local(1,1), outlet_discharge_global(1) + real(r8) :: qgwl_to_discharge_ratio_percent + real(r8) :: conservation_error + real(r8) :: global_total_liquid_before, global_total_liquid_after + real(r8) :: local_correction_sum, global_correction_sum + real(r8) :: correction_local(1,1), correction_global(1) character(len=*),parameter :: subname = '(Rtmrun) ' !----------------------------------------------------------------------- @@ -2423,8 +2430,8 @@ subroutine Rtmrun(rstwr,nlend,rdate) commid=mpicom_rof) global_negative_qgwl_sum = neg_global(1) - ! Diagnostic output for debugging - if (masterproc) then + ! Diagnostic output only when do_budget == 3 + if (masterproc .and. do_budget == 3) then write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum = ', global_positive_qgwl_sum write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum = ', global_negative_qgwl_sum write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Net Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum @@ -2433,7 +2440,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) net_global_qgwl = global_positive_qgwl_sum + global_negative_qgwl_sum - if (masterproc) then + if (masterproc .and. do_budget == 3) then write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Positive Sum =', global_positive_qgwl_sum write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Negative Sum =', global_negative_qgwl_sum write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Net Sum =', net_global_qgwl @@ -2977,12 +2984,12 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Scenario B (net < 0): All qgwl zeroed, redistribute net amount to outlets if (net_global_qgwl >= 0.0_r8) then qgwl_to_redistribute = 0.0_r8 ! Scenario A: negatives already in direct discharge - if (masterproc) then + if (masterproc .and. do_budget == 3) then write(iulog, *) trim(subname), 'Using Scenario A: original qgwl flows to direct (no outlet correction)' endif else qgwl_to_redistribute = net_global_qgwl ! Scenario B (negative value) - if (masterproc) then + if (masterproc .and. do_budget == 3) then write(iulog, *) trim(subname), 'Using Scenario B: redistributing entire net qgwl (', & qgwl_to_redistribute, ' m3/s) to outlets' endif @@ -2991,190 +2998,68 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (abs(qgwl_to_redistribute) > 1.0e-15_r8) then ! Only proceed if there's something to redistribute call t_startf('mosartr_qgwl_redir_dist') - ! Identify local outlets and their current discharges - local_outlet_count = 0 - do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%mask(nr) == 3) then ! Is it an outlet? - local_outlet_count = local_outlet_count + 1 - endif - enddo - - if (allocated(outlet_gindices_local)) deallocate(outlet_gindices_local) - if (allocated(outlet_discharges_local)) deallocate(outlet_discharges_local) - allocate(outlet_gindices_local(local_outlet_count)) - allocate(outlet_discharges_local(local_outlet_count)) - local_outlet_count = 0 ! Reset for population + ! Calculate total discharge from all outlets globally using reprosum + local_total_outlet_discharge = 0.0_r8 do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%mask(nr) == 3) then - local_outlet_count = local_outlet_count + 1 - outlet_gindices_local(local_outlet_count) = rtmCTL%gindex(nr) - outlet_discharges_local(local_outlet_count) = rtmCTL%runoffocn(nr, nt_nliq) ! Current discharge - endif + if (rtmCTL%mask(nr) == 3) then ! Outlet cell + local_total_outlet_discharge = local_total_outlet_discharge + rtmCTL%runoffocn(nr, nt_nliq) + endif enddo - ! Gather all outlet discharges to master for ranking - if (allocated(recvcounts)) deallocate(recvcounts) - if (allocated(displs)) deallocate(displs) - allocate(recvcounts(npes), displs(npes)) - call MPI_Gather(local_outlet_count, 1, MPI_INTEGER, recvcounts, 1, MPI_INTEGER, mastertask, mpicom_rof, ier) + ! Use reproducible sum for bit-for-bit reproducibility across PE layouts + outlet_discharge_local(1,1) = local_total_outlet_discharge + call shr_reprosum_calc(outlet_discharge_local, outlet_discharge_global, 1, 1, 1, commid=mpicom_rof) + global_total_outlet_discharge = outlet_discharge_global(1) + ! Print diagnostic on master if (masterproc) then - displs(1) = 0 - num_all_outlets_global = recvcounts(1) - do i = 2, npes - displs(i) = displs(i-1) + recvcounts(i-1) - num_all_outlets_global = num_all_outlets_global + recvcounts(i) - enddo - if (allocated(all_outlet_gindices)) deallocate(all_outlet_gindices) - if (allocated(all_outlet_discharges)) deallocate(all_outlet_discharges) - if (num_all_outlets_global > 0) then - allocate(all_outlet_gindices(num_all_outlets_global)) - allocate(all_outlet_discharges(num_all_outlets_global)) - else - ! Handle cases where no outlets are found if necessary, or let current_top_n_count be 0 - num_all_outlets_global = 0 ! Ensure it's zero if no outlets - endif - else - num_all_outlets_global = 0 ! Non-master tasks initialize to 0 - endif - call MPI_Bcast(num_all_outlets_global, 1, MPI_INTEGER, mastertask, mpicom_rof, ier) - - if(num_all_outlets_global > 0) then - call MPI_Gatherv(outlet_gindices_local, local_outlet_count, MPI_INTEGER, & - all_outlet_gindices, recvcounts, displs, MPI_INTEGER, & - mastertask, mpicom_rof, ier) - call MPI_Gatherv(outlet_discharges_local, local_outlet_count, MPI_REAL8, & - all_outlet_discharges, recvcounts, displs, MPI_REAL8, & - mastertask, mpicom_rof, ier) - endif + if (abs(global_total_outlet_discharge) > 1.0e-9_r8) then + qgwl_to_discharge_ratio_percent = (qgwl_to_redistribute / global_total_outlet_discharge) * 100.0_r8 - if (allocated(outlet_gindices_local)) deallocate(outlet_gindices_local) - if (allocated(outlet_discharges_local)) deallocate(outlet_discharges_local) + if (do_budget == 3) then + write(iulog, *) trim(subname), & + 'Debug QGWL Ratio: (QGWL_to_redistribute / TotalOutletDischarge) = ', & + qgwl_to_discharge_ratio_percent, '% (', qgwl_to_redistribute, ' m3/s)' + endif - ! Rank on master, calculate proportions, and prepare corrections - current_top_n_count = 0 ! Initialize for all tasks - if (masterproc) then - if (num_all_outlets_global > 0) then - allocate(sorted_outlets(num_all_outlets_global)) - do i = 1, num_all_outlets_global - sorted_outlets(i)%gidx = all_outlet_gindices(i) - sorted_outlets(i)%discharge = all_outlet_discharges(i) - enddo - if (allocated(all_outlet_gindices)) deallocate(all_outlet_gindices) - if (allocated(all_outlet_discharges)) deallocate(all_outlet_discharges) - - call sort_outlets_by_discharge_desc(sorted_outlets, num_all_outlets_global) - - current_top_n_count = min(num_top_outlets_for_qgwl, num_all_outlets_global) - sum_discharge_top_n = 0.0_r8 - do i = 1, current_top_n_count - sum_discharge_top_n = sum_discharge_top_n + sorted_outlets(i)%discharge - enddo - if(current_top_n_count > 0) then - if (abs(sum_discharge_top_n) > 1.0e-9_r8) then ! Avoid division by zero - block - real(r8) :: qgwl_to_discharge_ratio_percent - - qgwl_to_discharge_ratio_percent = (qgwl_to_redistribute / sum_discharge_top_n) * 100.0_r8 - - ! Print the ratio - write(iulog, *) trim(subname), & - 'Debug QGWL Ratio: (QGWL_to_redistribute / SumTopNDischarge) = ', & - qgwl_to_discharge_ratio_percent, '%', & - ' (N_used = ', current_top_n_count, & - ', N_param = ', num_top_outlets_for_qgwl, ')' ! Using your var name - - ! Check and print warning if magnitude is > 5% - if (abs(qgwl_to_discharge_ratio_percent) > 5.0_r8) then - call shr_sys_flush(iulog) ! Flush previous message - write(iulog, *) trim(subname), & - 'WARNING: QGWL_Redist_Ratio magnitude > 5% (', & - qgwl_to_discharge_ratio_percent, '%). ', & - 'N_used = ', current_top_n_count, & - ', N_param = ', num_top_outlets_for_qgwl, & - '. Consider increasing N_param.' - call shr_sys_flush(iulog) ! Flush warning - endif - end block - else - write(iulog, *) trim(subname), & - 'Debug QGWL Ratio: Sum of Top ', current_top_n_count, & - ' Outlet Discharges is near zero. Ratio not calculated.' - endif - else + ! Always check and warn if magnitude is > 5% (regardless of do_budget) + if (abs(qgwl_to_discharge_ratio_percent) > 5.0_r8) then + call shr_sys_flush(iulog) write(iulog, *) trim(subname), & - 'Debug QGWL Ratio: No top outlets selected (N_used = 0). Redistribution skipped.' - endif - if (current_top_n_count > 0) then - allocate(qgwl_correction_gindices(current_top_n_count)) - allocate(qgwl_correction_values(current_top_n_count)) - qgwl_correction_values = 0.0_r8 - do i = 1, current_top_n_count - qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * qgwl_to_redistribute - enddo - else - write(iulog, '(A)') trim(subname), & - 'Debug: No top outlets selected for QGWL redistribution (current_top_n_count is 0).' - allocate(qgwl_correction_gindices(current_top_n_count)) - allocate(qgwl_correction_values(current_top_n_count)) - qgwl_correction_values = 0.0_r8 - if (sum_discharge_top_n > 1.0e-9_r8) then ! Avoid division by zero - do i = 1, current_top_n_count - qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = (sorted_outlets(i)%discharge / sum_discharge_top_n) * qgwl_to_redistribute - enddo - else ! If sum of top N discharge is zero (or tiny), distribute equally (or handle as error/no distribution) - do i = 1, current_top_n_count - qgwl_correction_gindices(i) = sorted_outlets(i)%gidx - qgwl_correction_values(i) = qgwl_to_redistribute / real(current_top_n_count, kind=r8) - enddo - endif - endif - if(allocated(sorted_outlets)) deallocate(sorted_outlets) - else - current_top_n_count = 0 ! No outlets globally - endif ! num_all_outlets_global > 0 - endif ! masterproc - - ! Broadcast correction info - call MPI_Bcast(current_top_n_count, 1, MPI_INTEGER, mastertask, mpicom_rof, ier) - if (.not. masterproc .and. current_top_n_count > 0) then - if (allocated(qgwl_correction_gindices)) deallocate(qgwl_correction_gindices) - if (allocated(qgwl_correction_values)) deallocate(qgwl_correction_values) - allocate(qgwl_correction_gindices(current_top_n_count)) - allocate(qgwl_correction_values(current_top_n_count)) + 'WARNING: QGWL_Redist_Ratio magnitude > 5% (', & + qgwl_to_discharge_ratio_percent, '%). This may impact global hydrology.' + call shr_sys_flush(iulog) + endif + else + if (do_budget == 3) then + write(iulog, *) trim(subname), & + 'Debug QGWL Ratio: Total outlet discharge is near zero. Ratio not calculated.' + endif + endif endif - if (current_top_n_count > 0) then - call MPI_Bcast(qgwl_correction_gindices, current_top_n_count, MPI_INTEGER, mastertask, mpicom_rof, ier) - call MPI_Bcast(qgwl_correction_values, current_top_n_count, MPI_REAL8, mastertask, mpicom_rof, ier) - - ! Populate local correction array - do k = 1, current_top_n_count - target_gidx = qgwl_correction_gindices(k) - do nr_local = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%gindex(nr_local) == target_gidx) then - qgwl_correction_local(nr_local) = qgwl_correction_local(nr_local) + qgwl_correction_values(k) - exit - endif - enddo - enddo - endif ! current_top_n_count > 0 for broadcast and local application - if (allocated(qgwl_correction_gindices)) deallocate(qgwl_correction_gindices) - if (allocated(qgwl_correction_values)) deallocate(qgwl_correction_values) - if (allocated(recvcounts)) deallocate(recvcounts) - if (allocated(displs)) deallocate(displs) + ! Each PE calculates corrections for its local outlets proportionally + if (abs(global_total_outlet_discharge) > 1.0e-9_r8) then + do nr = rtmCTL%begr, rtmCTL%endr + if (rtmCTL%mask(nr) == 3) then ! Outlet cell + ! Proportional correction based on this outlet's discharge + qgwl_correction_local(nr) = (rtmCTL%runoffocn(nr, nt_nliq) / global_total_outlet_discharge) * qgwl_to_redistribute + endif + enddo + else + ! If total discharge is zero, no redistribution (corrections remain 0) + if (masterproc) then + write(iulog, *) trim(subname), & + 'Warning: Cannot redistribute qgwl - total outlet discharge is zero' + endif + endif call t_stopf('mosartr_qgwl_redir_dist') - else - write(iulog, *) trim(subname), & - 'Global net QGWL is positive, offsetting the negative values.' - endif ! net_global_qgwl < 0.0_r8 - endif ! redirect_negative_qgwl_flag + endif ! abs(qgwl_to_redistribute) > 1.0e-15 + endif ! redirect_negative_qgwl_flag - ! This loop should now use the qgwl_correction_local array + ! Apply outlet corrections to runoff do nt = 1,nt_rtm do nr = rtmCTL%begr,rtmCTL%endr volr_init = rtmCTL%volr(nr,nt) @@ -3188,46 +3073,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) elseif (rtmCTL%mask(nr) >= 2) then ! Ocean or Outlet rtmCTL%runoffocn(nr,nt) = rtmCTL%runoff(nr,nt) ! Routed component - ! ===================================================== - ! DIAGNOSTIC: Global sum BEFORE outlet corrections (once per timestep) - ! ===================================================== - if (nt == nt_nliq .and. nr == rtmCTL%begr) then ! Only do this once per timestep - block - real(r8) :: local_total_liquid_before, global_total_liquid_before - integer :: nr_temp - local_total_liquid_before = 0.0_r8 - do nr_temp = rtmCTL%begr, rtmCTL%endr - ! Sum what will be sent to coupler: rtmCTL%direct + rtmCTL%runoff - local_total_liquid_before = local_total_liquid_before + & - rtmCTL%direct(nr_temp, nt_nliq) + rtmCTL%runoff(nr_temp, nt_nliq) - enddo - - ! Use reproducible sum for bit-for-bit reproducibility across PE layouts - block - real(r8) :: before_local(1,1), before_global(1) - - ! Reproducible sum for total liquid before - before_local(1,1) = local_total_liquid_before - call shr_reprosum_calc(before_local, before_global, 1, 1, 1, & - commid=mpicom_rof) - global_total_liquid_before = before_global(1) - - ! Diagnostic output for debugging - if (masterproc) then - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Total Liquid Before = ', global_total_liquid_before - endif - end block - - if (masterproc) then - if (redirect_negative_qgwl_flag) then - write(iulog, '(A,ES24.16)') trim(subname)//' CONSERVATION CHECK: Global liquid runoff BEFORE outlet corrections (redirect=ON) = ', global_total_liquid_before - else - write(iulog, '(A,ES24.16)') trim(subname)//' CONSERVATION CHECK: Global liquid runoff BEFORE outlet corrections (baseline) = ', global_total_liquid_before - endif - endif - end block - endif - ! Apply the distributed global qgwl correction ONLY to liquid tracer at target outlets ! Apply to rtmCTL%runoff (not runoffocn) since runoff is what gets sent to coupler if (redirect_negative_qgwl_flag .and. nt == nt_nliq) then @@ -3240,43 +3085,34 @@ subroutine Rtmrun(rstwr,nlend,rdate) enddo ! nr enddo ! nt - ! ===================================================== - ! DIAGNOSTIC: Global sum of total liquid runoff AFTER redirection - ! This should equal the "before" sum for conservation (only when redirect is ON) - ! ===================================================== - if (redirect_negative_qgwl_flag) then - block - real(r8) :: local_total_liquid_after, global_total_liquid_after - local_total_liquid_after = 0.0_r8 - do nr = rtmCTL%begr, rtmCTL%endr - ! Sum what actually gets sent to coupler: rtmCTL%direct + rtmCTL%runoff - ! rtmCTL%runoff includes the qgwl correction applied at line 3221 - local_total_liquid_after = local_total_liquid_after + & - rtmCTL%direct(nr, nt_nliq) + rtmCTL%runoff(nr, nt_nliq) - enddo - - ! Use reproducible sum for bit-for-bit reproducibility across PE layouts - block - real(r8) :: after_local(1,1), after_global(1) - - ! Reproducible sum for total liquid after - after_local(1,1) = local_total_liquid_after - call shr_reprosum_calc(after_local, after_global, 1, 1, 1, & - commid=mpicom_rof) - global_total_liquid_after = after_global(1) - - ! Diagnostic output for debugging - if (masterproc) then - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Total Liquid After = ', global_total_liquid_after - endif - end block + ! Conservation check: verify that corrections were applied correctly + if (redirect_negative_qgwl_flag .and. abs(qgwl_to_redistribute) > 1.0e-15_r8) then + ! Sum up all the corrections that were applied + local_correction_sum = 0.0_r8 + do nr = rtmCTL%begr, rtmCTL%endr + local_correction_sum = local_correction_sum + qgwl_correction_local(nr) + enddo + + ! Use reprosum for bit-for-bit reproducibility + correction_local(1,1) = local_correction_sum + call shr_reprosum_calc(correction_local, correction_global, 1, 1, 1, commid=mpicom_rof) + global_correction_sum = correction_global(1) - if (masterproc) then - write(iulog, '(A,ES24.16)') trim(subname)//' CONSERVATION CHECK: Global liquid runoff AFTER redirection = ', global_total_liquid_after + ! Check if total corrections match what we intended to redistribute + if (masterproc) then + conservation_error = abs(global_correction_sum - qgwl_to_redistribute) + if (conservation_error > 1.0e-10_r8) then + call shr_sys_flush(iulog) + write(iulog, '(A)') trim(subname)//' WARNING: QGWL redistribution error detected!' + write(iulog, '(A,ES24.16)') trim(subname)//' Intended to redistribute = ', qgwl_to_redistribute + write(iulog, '(A,ES24.16)') trim(subname)//' Actually redistributed = ', global_correction_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Difference = ', conservation_error + call shr_sys_flush(iulog) endif - end block + endif endif + ! Deallocate qgwl_correction_local after use if (allocated(qgwl_correction_local)) deallocate(qgwl_correction_local) From 1b0d77cd86cbd3a5574bcf17445416b9d8a60ac7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:17:21 +0000 Subject: [PATCH 008/398] Bump actions/upload-artifact from 4 to 5 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/e3sm-gh-ci-cime-tests.yml | 2 +- .github/workflows/e3sm-gh-ci-w-cime-tests.yml | 2 +- .github/workflows/eamxx-gh-clang-format.yml | 2 +- .github/workflows/eamxx-v1-testing.yml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e3sm-gh-ci-cime-tests.yml b/.github/workflows/e3sm-gh-ci-cime-tests.yml index 993238566d7b..5819a2e7cf94 100644 --- a/.github/workflows/e3sm-gh-ci-cime-tests.yml +++ b/.github/workflows/e3sm-gh-ci-cime-tests.yml @@ -60,7 +60,7 @@ jobs: ./create_test ${{ matrix.test }} --wait --debug - name: Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: ${{ always() }} with: name: ${{ matrix.test }} diff --git a/.github/workflows/e3sm-gh-ci-w-cime-tests.yml b/.github/workflows/e3sm-gh-ci-w-cime-tests.yml index 2f635a3cd098..cea68d3e056c 100644 --- a/.github/workflows/e3sm-gh-ci-w-cime-tests.yml +++ b/.github/workflows/e3sm-gh-ci-w-cime-tests.yml @@ -45,7 +45,7 @@ jobs: ./create_test ${{ matrix.test }} --wait --debug - name: Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: ${{ always() }} with: name: ${{ matrix.test }} diff --git a/.github/workflows/eamxx-gh-clang-format.yml b/.github/workflows/eamxx-gh-clang-format.yml index 6278cc743625..3263f124fd21 100644 --- a/.github/workflows/eamxx-gh-clang-format.yml +++ b/.github/workflows/eamxx-gh-clang-format.yml @@ -138,7 +138,7 @@ jobs: fi - name: upload diff patch if: ${{ env.status_fail == 'true' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: ${{ env.fname }} path: "components/eamxx/${{ env.fname }}" diff --git a/.github/workflows/eamxx-v1-testing.yml b/.github/workflows/eamxx-v1-testing.yml index 0fd2d3db068e..29c5e28e5ed1 100644 --- a/.github/workflows/eamxx-v1-testing.yml +++ b/.github/workflows/eamxx-v1-testing.yml @@ -112,7 +112,7 @@ jobs: ./cime/scripts/create_test ${{ matrix.test.full_name }} ${{ env.flags }} --wait - name: Upload log files if: ${{ always() }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: logs.${{ matrix.test.short_name }} path: | @@ -126,7 +126,7 @@ jobs: NODE_EXTRA_CA_CERTS: ${{ env.NODE_EXTRA_CA_CERTS }} - name: Upload nc files if: ${{ failure() && steps.run-tests.outcome == 'failure' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: outputs.${{ matrix.test.short_name }} path: | From df6114fb6932b03acc1781e971e7786877477371 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Mon, 27 Oct 2025 15:46:12 -0700 Subject: [PATCH 009/398] try to fix PEM test fail --- components/mosart/src/riverroute/RtmMod.F90 | 98 +++++++++------------ 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 0dc179c42c24..3e3fd68a9291 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -132,11 +132,6 @@ module RtmMod logical :: do_rtmflood logical :: do_rtm - type :: outlet_discharge_info_type - integer :: gidx - real(r8) :: discharge - end type outlet_discharge_info_type - ! Namelist variable and flag for TNR redirection logical, public :: redirect_negative_qgwl = .false. ! Namelist control logical, save :: redirect_negative_qgwl_flag = .false. ! Module flag @@ -2244,17 +2239,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor - integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task - real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets - integer :: local_outlet_count - integer, allocatable :: all_outlet_gindices(:) ! Gathered on master - real(r8), allocatable :: all_outlet_discharges(:) ! Gathered on master - integer, allocatable :: recvcounts(:), displs(:) ! For MPI_Gatherv - type(outlet_discharge_info_type), allocatable :: sorted_outlets(:) - integer :: num_all_outlets_global, current_top_n_count, target_gidx - real(r8) :: sum_discharge_top_n - real(r8), allocatable :: qgwl_correction_values(:) ! Values to apply - integer, allocatable :: qgwl_correction_gindices(:) ! Global indices for these corrections real(r8), allocatable :: qgwl_correction_local(:) ! Local portion of correction array real(r8) :: qgwl_to_redistribute ! Amount to redistribute (Scenario A or B) real(r8) :: local_total_outlet_discharge, global_total_outlet_discharge @@ -2264,6 +2248,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8) :: global_total_liquid_before, global_total_liquid_after real(r8) :: local_correction_sum, global_correction_sum real(r8) :: correction_local(1,1), correction_global(1) + real(r8) :: correction_ratio ! Ratio to apply: qgwl_to_redistribute / global_total_outlet_discharge character(len=*),parameter :: subname = '(Rtmrun) ' !----------------------------------------------------------------------- @@ -2414,21 +2399,21 @@ subroutine Rtmrun(rstwr,nlend,rdate) enddo ! Use reproducible sum for bit-for-bit reproducibility across PE layouts + ! Combine both positive and negative sums in one call for efficiency block - real(r8) :: pos_local(1,1), pos_global(1) - real(r8) :: neg_local(1,1), neg_global(1) + real(r8) :: local_sums(2,1), global_sums(2) - ! Reproducible sum for positive qgwl - pos_local(1,1) = local_positive_qgwl_sum - call shr_reprosum_calc(pos_local, pos_global, 1, 1, 1, & - commid=mpicom_rof) - global_positive_qgwl_sum = pos_global(1) + ! Pack both positive and negative sums + local_sums(1,1) = local_positive_qgwl_sum + local_sums(2,1) = local_negative_qgwl_sum - ! Reproducible sum for negative qgwl - neg_local(1,1) = local_negative_qgwl_sum - call shr_reprosum_calc(neg_local, neg_global, 1, 1, 1, & + ! Single reproducible sum call for both fields + call shr_reprosum_calc(local_sums, global_sums, 2, 1, 1, & commid=mpicom_rof) - global_negative_qgwl_sum = neg_global(1) + + ! Unpack results + global_positive_qgwl_sum = global_sums(1) + global_negative_qgwl_sum = global_sums(2) ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then @@ -2452,13 +2437,19 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Proportionally reduce positive qgwl to offset negatives, zero out negative cells ! This ensures NO negative qgwl enters the ocean at any grid cell - if (global_positive_qgwl_sum > 0.0_r8) then - ! Calculate scaling factor: (positive - |negative|) / positive = net / positive - scaling_factor = net_global_qgwl / global_positive_qgwl_sum - else - scaling_factor = 1.0_r8 ! No positive qgwl, keep as is + ! Master PE calculates scaling factor, then broadcasts for bit-for-bit reproducibility + if (masterproc) then + if (global_positive_qgwl_sum > 0.0_r8) then + ! Calculate scaling factor: (positive - |negative|) / positive = net / positive + scaling_factor = net_global_qgwl / global_positive_qgwl_sum + else + scaling_factor = 1.0_r8 ! No positive qgwl, keep as is + endif endif + ! Broadcast scaling factor from master to all PEs + call MPI_Bcast(scaling_factor, 1, MPI_REAL8, 0, mpicom_rof, ier) + do nr = rtmCTL%begr, rtmCTL%endr do nt = 1, nt_rtm if (rtmCTL%qgwl(nr, nt) > 0.0_r8) then @@ -2998,10 +2989,11 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (abs(qgwl_to_redistribute) > 1.0e-15_r8) then ! Only proceed if there's something to redistribute call t_startf('mosartr_qgwl_redir_dist') - ! Calculate total discharge from all outlets globally using reprosum + ! Calculate total discharge from outlets with discharge > 1.0 m3/s + ! This threshold filters out small outlets and ensures numerical stability local_total_outlet_discharge = 0.0_r8 do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%mask(nr) == 3) then ! Outlet cell + if (rtmCTL%mask(nr) == 3 .and. rtmCTL%runoffocn(nr, nt_nliq) > 1.0_r8) then local_total_outlet_discharge = local_total_outlet_discharge + rtmCTL%runoffocn(nr, nt_nliq) endif enddo @@ -3038,19 +3030,28 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif endif - ! Each PE calculates corrections for its local outlets proportionally + ! Master PE calculates the correction ratio, then broadcast to all PEs + ! This ensures bit-for-bit reproducibility across different PE layouts (PEM test) if (abs(global_total_outlet_discharge) > 1.0e-9_r8) then + if (masterproc) then + correction_ratio = qgwl_to_redistribute / global_total_outlet_discharge + endif + + ! Broadcast the correction ratio from master to all PEs + call MPI_Bcast(correction_ratio, 1, MPI_REAL8, 0, mpicom_rof, ier) + + ! All PEs apply the same ratio to their local outlets > 1.0 m3/s do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%mask(nr) == 3) then ! Outlet cell - ! Proportional correction based on this outlet's discharge - qgwl_correction_local(nr) = (rtmCTL%runoffocn(nr, nt_nliq) / global_total_outlet_discharge) * qgwl_to_redistribute + if (rtmCTL%mask(nr) == 3 .and. rtmCTL%runoffocn(nr, nt_nliq) > 1.0_r8) then + ! Apply the correction ratio + qgwl_correction_local(nr) = rtmCTL%runoffocn(nr, nt_nliq) * correction_ratio endif enddo else ! If total discharge is zero, no redistribution (corrections remain 0) if (masterproc) then write(iulog, *) trim(subname), & - 'Warning: Cannot redistribute qgwl - total outlet discharge is zero' + 'Warning: Cannot redistribute qgwl - total outlet discharge (>1 m3/s) is zero' endif endif @@ -5348,23 +5349,4 @@ end subroutine SubTimestep !----------------------------------------------------------------------- -subroutine sort_outlets_by_discharge_desc(outlets_array, count) !TZ negative runoff - implicit none - integer, intent(in) :: count - type(outlet_discharge_info_type), intent(inout) :: outlets_array(:) ! Assumed-shape - integer :: i, j - type(outlet_discharge_info_type) :: temp_outlet_info - ! Bubble sort - if (count < 2) return - do i = 1, count - 1 - do j = 1, count - i - if (outlets_array(j)%discharge < outlets_array(j+1)%discharge) then - temp_outlet_info = outlets_array(j) - outlets_array(j) = outlets_array(j+1) - outlets_array(j+1) = temp_outlet_info - endif - enddo - enddo -end subroutine sort_outlets_by_discharge_desc - end module RtmMod \ No newline at end of file From 8948e32f838bffff5337f5978c5ad7ab3c86bfda Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Thu, 30 Oct 2025 11:58:14 -0700 Subject: [PATCH 010/398] Revert "try to fix PEM test fail" This reverts commit df6114fb6932b03acc1781e971e7786877477371. --- components/mosart/src/riverroute/RtmMod.F90 | 98 ++++++++++++--------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 3e3fd68a9291..0dc179c42c24 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -132,6 +132,11 @@ module RtmMod logical :: do_rtmflood logical :: do_rtm + type :: outlet_discharge_info_type + integer :: gidx + real(r8) :: discharge + end type outlet_discharge_info_type + ! Namelist variable and flag for TNR redirection logical, public :: redirect_negative_qgwl = .false. ! Namelist control logical, save :: redirect_negative_qgwl_flag = .false. ! Module flag @@ -2239,6 +2244,17 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor + integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task + real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets + integer :: local_outlet_count + integer, allocatable :: all_outlet_gindices(:) ! Gathered on master + real(r8), allocatable :: all_outlet_discharges(:) ! Gathered on master + integer, allocatable :: recvcounts(:), displs(:) ! For MPI_Gatherv + type(outlet_discharge_info_type), allocatable :: sorted_outlets(:) + integer :: num_all_outlets_global, current_top_n_count, target_gidx + real(r8) :: sum_discharge_top_n + real(r8), allocatable :: qgwl_correction_values(:) ! Values to apply + integer, allocatable :: qgwl_correction_gindices(:) ! Global indices for these corrections real(r8), allocatable :: qgwl_correction_local(:) ! Local portion of correction array real(r8) :: qgwl_to_redistribute ! Amount to redistribute (Scenario A or B) real(r8) :: local_total_outlet_discharge, global_total_outlet_discharge @@ -2248,7 +2264,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8) :: global_total_liquid_before, global_total_liquid_after real(r8) :: local_correction_sum, global_correction_sum real(r8) :: correction_local(1,1), correction_global(1) - real(r8) :: correction_ratio ! Ratio to apply: qgwl_to_redistribute / global_total_outlet_discharge character(len=*),parameter :: subname = '(Rtmrun) ' !----------------------------------------------------------------------- @@ -2399,21 +2414,21 @@ subroutine Rtmrun(rstwr,nlend,rdate) enddo ! Use reproducible sum for bit-for-bit reproducibility across PE layouts - ! Combine both positive and negative sums in one call for efficiency block - real(r8) :: local_sums(2,1), global_sums(2) - - ! Pack both positive and negative sums - local_sums(1,1) = local_positive_qgwl_sum - local_sums(2,1) = local_negative_qgwl_sum + real(r8) :: pos_local(1,1), pos_global(1) + real(r8) :: neg_local(1,1), neg_global(1) - ! Single reproducible sum call for both fields - call shr_reprosum_calc(local_sums, global_sums, 2, 1, 1, & + ! Reproducible sum for positive qgwl + pos_local(1,1) = local_positive_qgwl_sum + call shr_reprosum_calc(pos_local, pos_global, 1, 1, 1, & commid=mpicom_rof) + global_positive_qgwl_sum = pos_global(1) - ! Unpack results - global_positive_qgwl_sum = global_sums(1) - global_negative_qgwl_sum = global_sums(2) + ! Reproducible sum for negative qgwl + neg_local(1,1) = local_negative_qgwl_sum + call shr_reprosum_calc(neg_local, neg_global, 1, 1, 1, & + commid=mpicom_rof) + global_negative_qgwl_sum = neg_global(1) ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then @@ -2437,19 +2452,13 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Proportionally reduce positive qgwl to offset negatives, zero out negative cells ! This ensures NO negative qgwl enters the ocean at any grid cell - ! Master PE calculates scaling factor, then broadcasts for bit-for-bit reproducibility - if (masterproc) then - if (global_positive_qgwl_sum > 0.0_r8) then - ! Calculate scaling factor: (positive - |negative|) / positive = net / positive - scaling_factor = net_global_qgwl / global_positive_qgwl_sum - else - scaling_factor = 1.0_r8 ! No positive qgwl, keep as is - endif + if (global_positive_qgwl_sum > 0.0_r8) then + ! Calculate scaling factor: (positive - |negative|) / positive = net / positive + scaling_factor = net_global_qgwl / global_positive_qgwl_sum + else + scaling_factor = 1.0_r8 ! No positive qgwl, keep as is endif - ! Broadcast scaling factor from master to all PEs - call MPI_Bcast(scaling_factor, 1, MPI_REAL8, 0, mpicom_rof, ier) - do nr = rtmCTL%begr, rtmCTL%endr do nt = 1, nt_rtm if (rtmCTL%qgwl(nr, nt) > 0.0_r8) then @@ -2989,11 +2998,10 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (abs(qgwl_to_redistribute) > 1.0e-15_r8) then ! Only proceed if there's something to redistribute call t_startf('mosartr_qgwl_redir_dist') - ! Calculate total discharge from outlets with discharge > 1.0 m3/s - ! This threshold filters out small outlets and ensures numerical stability + ! Calculate total discharge from all outlets globally using reprosum local_total_outlet_discharge = 0.0_r8 do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%mask(nr) == 3 .and. rtmCTL%runoffocn(nr, nt_nliq) > 1.0_r8) then + if (rtmCTL%mask(nr) == 3) then ! Outlet cell local_total_outlet_discharge = local_total_outlet_discharge + rtmCTL%runoffocn(nr, nt_nliq) endif enddo @@ -3030,28 +3038,19 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif endif - ! Master PE calculates the correction ratio, then broadcast to all PEs - ! This ensures bit-for-bit reproducibility across different PE layouts (PEM test) + ! Each PE calculates corrections for its local outlets proportionally if (abs(global_total_outlet_discharge) > 1.0e-9_r8) then - if (masterproc) then - correction_ratio = qgwl_to_redistribute / global_total_outlet_discharge - endif - - ! Broadcast the correction ratio from master to all PEs - call MPI_Bcast(correction_ratio, 1, MPI_REAL8, 0, mpicom_rof, ier) - - ! All PEs apply the same ratio to their local outlets > 1.0 m3/s do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%mask(nr) == 3 .and. rtmCTL%runoffocn(nr, nt_nliq) > 1.0_r8) then - ! Apply the correction ratio - qgwl_correction_local(nr) = rtmCTL%runoffocn(nr, nt_nliq) * correction_ratio + if (rtmCTL%mask(nr) == 3) then ! Outlet cell + ! Proportional correction based on this outlet's discharge + qgwl_correction_local(nr) = (rtmCTL%runoffocn(nr, nt_nliq) / global_total_outlet_discharge) * qgwl_to_redistribute endif enddo else ! If total discharge is zero, no redistribution (corrections remain 0) if (masterproc) then write(iulog, *) trim(subname), & - 'Warning: Cannot redistribute qgwl - total outlet discharge (>1 m3/s) is zero' + 'Warning: Cannot redistribute qgwl - total outlet discharge is zero' endif endif @@ -5349,4 +5348,23 @@ end subroutine SubTimestep !----------------------------------------------------------------------- +subroutine sort_outlets_by_discharge_desc(outlets_array, count) !TZ negative runoff + implicit none + integer, intent(in) :: count + type(outlet_discharge_info_type), intent(inout) :: outlets_array(:) ! Assumed-shape + integer :: i, j + type(outlet_discharge_info_type) :: temp_outlet_info + ! Bubble sort + if (count < 2) return + do i = 1, count - 1 + do j = 1, count - i + if (outlets_array(j)%discharge < outlets_array(j+1)%discharge) then + temp_outlet_info = outlets_array(j) + outlets_array(j) = outlets_array(j+1) + outlets_array(j+1) = temp_outlet_info + endif + enddo + enddo +end subroutine sort_outlets_by_discharge_desc + end module RtmMod \ No newline at end of file From c2ca073bc0bc004ec606f57fdb0c03889cf33260 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Thu, 30 Oct 2025 14:55:10 -0700 Subject: [PATCH 011/398] fix reprosum error --- components/mosart/src/riverroute/RtmMod.F90 | 87 +++++++++++++-------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 0dc179c42c24..9121593e3aec 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2240,9 +2240,10 @@ subroutine Rtmrun(rstwr,nlend,rdate) !scs ! Variables for negative runoff redirection - + real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor + integer :: local_neg_count, global_neg_count integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets @@ -2264,6 +2265,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8) :: global_total_liquid_before, global_total_liquid_after real(r8) :: local_correction_sum, global_correction_sum real(r8) :: correction_local(1,1), correction_global(1) + real(r8) :: correction_ratio ! Ratio to apply: qgwl_to_redistribute / global_total_outlet_discharge character(len=*),parameter :: subname = '(Rtmrun) ' !----------------------------------------------------------------------- @@ -2404,61 +2406,63 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (redirect_negative_qgwl_flag) then local_negative_qgwl_sum = 0.0_r8 ! This will sum local NEGATIVE qgwl local_positive_qgwl_sum = 0.0_r8 ! This will sum local POSITIVE qgwl + local_neg_count = 0 do nr = rtmCTL%begr, rtmCTL%endr if (rtmCTL%qgwl(nr, nt_nliq) > 0.0_r8) then local_positive_qgwl_sum = local_positive_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) elseif (rtmCTL%qgwl(nr, nt_nliq) < 0.0_r8) then local_negative_qgwl_sum = local_negative_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) + local_neg_count = local_neg_count + 1 endif enddo - ! Use reproducible sum for bit-for-bit reproducibility across PE layouts - block - real(r8) :: pos_local(1,1), pos_global(1) - real(r8) :: neg_local(1,1), neg_global(1) + ! Count total negative cells globally + call MPI_Reduce(local_neg_count, global_neg_count, 1, MPI_INTEGER, MPI_SUM, 0, mpicom_rof, ier) - ! Reproducible sum for positive qgwl - pos_local(1,1) = local_positive_qgwl_sum - call shr_reprosum_calc(pos_local, pos_global, 1, 1, 1, & - commid=mpicom_rof) - global_positive_qgwl_sum = pos_global(1) + ! Use combined reproducible sum for bit-for-bit reproducibility across PE layouts + ! This sums both positive and negative qgwl in a single call for efficiency + block + real(r8) :: local_sums(1,2), global_sums(2) - ! Reproducible sum for negative qgwl - neg_local(1,1) = local_negative_qgwl_sum - call shr_reprosum_calc(neg_local, neg_global, 1, 1, 1, & + ! Combined reprosum: arr(dsummands, nflds) where nflds=2 + local_sums(1,1) = local_positive_qgwl_sum + local_sums(1,2) = local_negative_qgwl_sum + call shr_reprosum_calc(local_sums, global_sums, 1, 1, 2, & commid=mpicom_rof) - global_negative_qgwl_sum = neg_global(1) + global_positive_qgwl_sum = global_sums(1) + global_negative_qgwl_sum = global_sums(2) ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum = ', global_positive_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum = ', global_negative_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Net Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum + write(iulog, '(A,I10)') trim(subname)//' Global count of negative qgwl cells = ', global_neg_count + write(iulog, '(A,ES24.16)') trim(subname)//' Global Positive qgwl Sum = ', global_positive_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Global Negative qgwl Sum = ', global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Global Net qgwl Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum endif end block net_global_qgwl = global_positive_qgwl_sum + global_negative_qgwl_sum - if (masterproc .and. do_budget == 3) then - write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Positive Sum =', global_positive_qgwl_sum - write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Negative Sum =', global_negative_qgwl_sum - write(iulog, *) trim(subname), 'Debug QGWL Balancing: Global Net Sum =', net_global_qgwl - endif - ! Decide how to set TRunoff%qgwl for local routing if (net_global_qgwl >= 0.0_r8) then ! --- SCENARIO A: Net global QGWL is non-negative. --- ! Proportionally reduce positive qgwl to offset negatives, zero out negative cells ! This ensures NO negative qgwl enters the ocean at any grid cell - if (global_positive_qgwl_sum > 0.0_r8) then - ! Calculate scaling factor: (positive - |negative|) / positive = net / positive - scaling_factor = net_global_qgwl / global_positive_qgwl_sum - else - scaling_factor = 1.0_r8 ! No positive qgwl, keep as is + ! Master PE calculates scaling factor, then broadcasts for bit-for-bit reproducibility + if (masterproc) then + if (global_positive_qgwl_sum > 0.0_r8) then + ! Calculate scaling factor: (positive - |negative|) / positive = net / positive + scaling_factor = net_global_qgwl / global_positive_qgwl_sum + else + scaling_factor = 1.0_r8 ! No positive qgwl, keep as is + endif endif + ! Broadcast scaling factor from master to all PEs + call MPI_Bcast(scaling_factor, 1, MPI_REAL8, 0, mpicom_rof, ier) + do nr = rtmCTL%begr, rtmCTL%endr do nt = 1, nt_rtm if (rtmCTL%qgwl(nr, nt) > 0.0_r8) then @@ -3038,12 +3042,33 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif endif - ! Each PE calculates corrections for its local outlets proportionally + ! Master PE calculates the correction ratio, then broadcast to all PEs + ! This ensures bit-for-bit reproducibility across different PE layouts (PEM test) if (abs(global_total_outlet_discharge) > 1.0e-9_r8) then + if (masterproc) then + correction_ratio = qgwl_to_redistribute / global_total_outlet_discharge + + ! Check if correction ratio magnitude exceeds 100% + if (correction_ratio < -1.0_r8) then + call shr_sys_flush(iulog) + write(iulog, *) trim(subname), & + 'WARNING: Correction ratio < -100% (', correction_ratio, ').' + write(iulog, *) trim(subname), & + 'Negative runoff to ocean is unavoidable as negative qgwl magnitude (', & + abs(qgwl_to_redistribute), ' m3/s) exceeds total outlet discharge (', & + global_total_outlet_discharge, ' m3/s).' + call shr_sys_flush(iulog) + endif + endif + + ! Broadcast the correction ratio from master to all PEs + call MPI_Bcast(correction_ratio, 1, MPI_REAL8, 0, mpicom_rof, ier) + + ! All PEs apply the same ratio to their local outlets do nr = rtmCTL%begr, rtmCTL%endr if (rtmCTL%mask(nr) == 3) then ! Outlet cell - ! Proportional correction based on this outlet's discharge - qgwl_correction_local(nr) = (rtmCTL%runoffocn(nr, nt_nliq) / global_total_outlet_discharge) * qgwl_to_redistribute + ! Apply the correction ratio + qgwl_correction_local(nr) = rtmCTL%runoffocn(nr, nt_nliq) * correction_ratio endif enddo else From 1bf9a82089a5056732011afc9b2d83290e553687 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Thu, 30 Oct 2025 15:37:15 -0700 Subject: [PATCH 012/398] remove some diag calculations --- components/mosart/src/riverroute/RtmMod.F90 | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 9121593e3aec..739ffac84019 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2243,7 +2243,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor - integer :: local_neg_count, global_neg_count integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets @@ -2406,20 +2405,15 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (redirect_negative_qgwl_flag) then local_negative_qgwl_sum = 0.0_r8 ! This will sum local NEGATIVE qgwl local_positive_qgwl_sum = 0.0_r8 ! This will sum local POSITIVE qgwl - local_neg_count = 0 do nr = rtmCTL%begr, rtmCTL%endr if (rtmCTL%qgwl(nr, nt_nliq) > 0.0_r8) then local_positive_qgwl_sum = local_positive_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) elseif (rtmCTL%qgwl(nr, nt_nliq) < 0.0_r8) then local_negative_qgwl_sum = local_negative_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) - local_neg_count = local_neg_count + 1 endif enddo - ! Count total negative cells globally - call MPI_Reduce(local_neg_count, global_neg_count, 1, MPI_INTEGER, MPI_SUM, 0, mpicom_rof, ier) - ! Use combined reproducible sum for bit-for-bit reproducibility across PE layouts ! This sums both positive and negative qgwl in a single call for efficiency block @@ -2435,7 +2429,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then - write(iulog, '(A,I10)') trim(subname)//' Global count of negative qgwl cells = ', global_neg_count write(iulog, '(A,ES24.16)') trim(subname)//' Global Positive qgwl Sum = ', global_positive_qgwl_sum write(iulog, '(A,ES24.16)') trim(subname)//' Global Negative qgwl Sum = ', global_negative_qgwl_sum write(iulog, '(A,ES24.16)') trim(subname)//' Global Net qgwl Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum From 39fa31cade4c3ec5f9c8c2d51edb3b48e2c9e94f Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Thu, 30 Oct 2025 23:26:40 -0700 Subject: [PATCH 013/398] detect reprosum problem --- components/mosart/src/riverroute/RtmMod.F90 | 43 ++++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 739ffac84019..693aef3b325f 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2418,19 +2418,35 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! This sums both positive and negative qgwl in a single call for efficiency block real(r8) :: local_sums(1,2), global_sums(2) + real(r8) :: check_pos_mpi, check_neg_mpi ! For debugging PEM ! Combined reprosum: arr(dsummands, nflds) where nflds=2 local_sums(1,1) = local_positive_qgwl_sum local_sums(1,2) = local_negative_qgwl_sum + + ! DEBUG: Check what reprosum receives on master PE + if (masterproc .and. do_budget == 3) then + write(iulog, '(A,ES24.16)') trim(subname)//' [PE0] LOCAL Positive input = ', local_sums(1,1) + write(iulog, '(A,ES24.16)') trim(subname)//' [PE0] LOCAL Negative input = ', local_sums(1,2) + endif + call shr_reprosum_calc(local_sums, global_sums, 1, 1, 2, & commid=mpicom_rof) global_positive_qgwl_sum = global_sums(1) global_negative_qgwl_sum = global_sums(2) + ! DEBUG: Compare reprosum with MPI_Allreduce for PEM debugging + call MPI_Allreduce(local_positive_qgwl_sum, check_pos_mpi, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) + call MPI_Allreduce(local_negative_qgwl_sum, check_neg_mpi, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) + ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then - write(iulog, '(A,ES24.16)') trim(subname)//' Global Positive qgwl Sum = ', global_positive_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' Global Negative qgwl Sum = ', global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum = ', global_positive_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum = ', global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' MPI_ALLREDUCE Positive Sum = ', check_pos_mpi + write(iulog, '(A,ES24.16)') trim(subname)//' MPI_ALLREDUCE Negative Sum = ', check_neg_mpi + write(iulog, '(A,ES24.16)') trim(subname)//' Diff (REPROSUM - MPI) Positive = ', global_positive_qgwl_sum - check_pos_mpi + write(iulog, '(A,ES24.16)') trim(subname)//' Diff (REPROSUM - MPI) Negative = ', global_negative_qgwl_sum - check_neg_mpi write(iulog, '(A,ES24.16)') trim(subname)//' Global Net qgwl Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum endif end block @@ -2451,11 +2467,22 @@ subroutine Rtmrun(rstwr,nlend,rdate) else scaling_factor = 1.0_r8 ! No positive qgwl, keep as is endif + ! DEBUG: Show scaling factor calculation + if (do_budget == 3) then + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] net_global_qgwl = ', net_global_qgwl + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] global_positive_qgwl_sum = ', global_positive_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] scaling_factor (before bcast) = ', scaling_factor + endif endif ! Broadcast scaling factor from master to all PEs call MPI_Bcast(scaling_factor, 1, MPI_REAL8, 0, mpicom_rof, ier) + ! DEBUG: Verify broadcast on all PEs + if (do_budget == 3) then + write(iulog, '(A,I5,A,ES24.16)') trim(subname)//' [PE ', iam, '] scaling_factor (after bcast) = ', scaling_factor + endif + do nr = rtmCTL%begr, rtmCTL%endr do nt = 1, nt_rtm if (rtmCTL%qgwl(nr, nt) > 0.0_r8) then @@ -3041,6 +3068,13 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (masterproc) then correction_ratio = qgwl_to_redistribute / global_total_outlet_discharge + ! DEBUG: Show correction ratio calculation + if (do_budget == 3) then + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario B] qgwl_to_redistribute = ', qgwl_to_redistribute + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario B] global_total_outlet_discharge = ', global_total_outlet_discharge + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario B] correction_ratio (before bcast) = ', correction_ratio + endif + ! Check if correction ratio magnitude exceeds 100% if (correction_ratio < -1.0_r8) then call shr_sys_flush(iulog) @@ -3057,6 +3091,11 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Broadcast the correction ratio from master to all PEs call MPI_Bcast(correction_ratio, 1, MPI_REAL8, 0, mpicom_rof, ier) + ! DEBUG: Verify broadcast on all PEs + if (do_budget == 3) then + write(iulog, '(A,I5,A,ES24.16)') trim(subname)//' [PE ', iam, '] correction_ratio (after bcast) = ', correction_ratio + endif + ! All PEs apply the same ratio to their local outlets do nr = rtmCTL%begr, rtmCTL%endr if (rtmCTL%mask(nr) == 3) then ! Outlet cell From f50555635123a7449bff6e53f64016c78bf4180f Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Fri, 31 Oct 2025 00:39:32 -0700 Subject: [PATCH 014/398] revert to seperate reprosum calls --- components/mosart/src/riverroute/RtmMod.F90 | 38 ++++++++------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 693aef3b325f..cc344518ca42 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2414,39 +2414,29 @@ subroutine Rtmrun(rstwr,nlend,rdate) endif enddo - ! Use combined reproducible sum for bit-for-bit reproducibility across PE layouts - ! This sums both positive and negative qgwl in a single call for efficiency + ! Use separate reproducible sum calls for bit-for-bit reproducibility across PE layouts + ! NOTE: Combined reprosum (nflds=2) was found to be non-reproducible for positive field + ! while negative field was reproducible, suggesting a bug in multi-field reprosum block - real(r8) :: local_sums(1,2), global_sums(2) - real(r8) :: check_pos_mpi, check_neg_mpi ! For debugging PEM + real(r8) :: pos_local(1,1), pos_global(1) + real(r8) :: neg_local(1,1), neg_global(1) - ! Combined reprosum: arr(dsummands, nflds) where nflds=2 - local_sums(1,1) = local_positive_qgwl_sum - local_sums(1,2) = local_negative_qgwl_sum - - ! DEBUG: Check what reprosum receives on master PE - if (masterproc .and. do_budget == 3) then - write(iulog, '(A,ES24.16)') trim(subname)//' [PE0] LOCAL Positive input = ', local_sums(1,1) - write(iulog, '(A,ES24.16)') trim(subname)//' [PE0] LOCAL Negative input = ', local_sums(1,2) - endif - - call shr_reprosum_calc(local_sums, global_sums, 1, 1, 2, & + ! Separate reprosum for positive qgwl + pos_local(1,1) = local_positive_qgwl_sum + call shr_reprosum_calc(pos_local, pos_global, 1, 1, 1, & commid=mpicom_rof) - global_positive_qgwl_sum = global_sums(1) - global_negative_qgwl_sum = global_sums(2) + global_positive_qgwl_sum = pos_global(1) - ! DEBUG: Compare reprosum with MPI_Allreduce for PEM debugging - call MPI_Allreduce(local_positive_qgwl_sum, check_pos_mpi, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) - call MPI_Allreduce(local_negative_qgwl_sum, check_neg_mpi, 1, MPI_REAL8, MPI_SUM, mpicom_rof, ier) + ! Separate reprosum for negative qgwl + neg_local(1,1) = local_negative_qgwl_sum + call shr_reprosum_calc(neg_local, neg_global, 1, 1, 1, & + commid=mpicom_rof) + global_negative_qgwl_sum = neg_global(1) ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum = ', global_positive_qgwl_sum write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum = ', global_negative_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' MPI_ALLREDUCE Positive Sum = ', check_pos_mpi - write(iulog, '(A,ES24.16)') trim(subname)//' MPI_ALLREDUCE Negative Sum = ', check_neg_mpi - write(iulog, '(A,ES24.16)') trim(subname)//' Diff (REPROSUM - MPI) Positive = ', global_positive_qgwl_sum - check_pos_mpi - write(iulog, '(A,ES24.16)') trim(subname)//' Diff (REPROSUM - MPI) Negative = ', global_negative_qgwl_sum - check_neg_mpi write(iulog, '(A,ES24.16)') trim(subname)//' Global Net qgwl Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum endif end block From a91ff9e1bb871fda05c000a942c2748cb3dc182f Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Fri, 31 Oct 2025 02:01:20 -0700 Subject: [PATCH 015/398] another attempt --- components/mosart/src/riverroute/RtmMod.F90 | 47 ++++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index cc344518ca42..9cc08f3c209a 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -44,7 +44,7 @@ module RtmMod use MOSART_physics_mod, only : Euler use MOSART_physics_mod, only : updatestate_hillslope, updatestate_subnetwork, & updatestate_mainchannel - use MOSART_BGC_type, only : TSedi, TSedi_para, MOSART_sediment_init + use MOSART_BGC_type, only : TSedi, TSedi_para, MOSART_sediment_init, TINYVALUE_s use MOSART_RES_type, only : Tres, MOSART_reservoir_sed_init, Tres_para !#ifdef INCLUDE_WRM use WRM_type_mod , only : ctlSubwWRM, WRMUnit, StorWater @@ -2241,7 +2241,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Variables for negative runoff redirection - real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum + real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum, local_total_qgwl_sum real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task @@ -2405,39 +2405,44 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (redirect_negative_qgwl_flag) then local_negative_qgwl_sum = 0.0_r8 ! This will sum local NEGATIVE qgwl local_positive_qgwl_sum = 0.0_r8 ! This will sum local POSITIVE qgwl + local_total_qgwl_sum = 0.0_r8 ! This will sum ALL qgwl (for verification) + ! Use TINYVALUE_s threshold to avoid non-reproducibility from near-zero values + ! that can flip sign across different PE layouts due to floating-point noise do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%qgwl(nr, nt_nliq) > 0.0_r8) then + if (rtmCTL%qgwl(nr, nt_nliq) > TINYVALUE_s) then local_positive_qgwl_sum = local_positive_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) - elseif (rtmCTL%qgwl(nr, nt_nliq) < 0.0_r8) then + elseif (rtmCTL%qgwl(nr, nt_nliq) < -TINYVALUE_s) then local_negative_qgwl_sum = local_negative_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) endif + ! Sum ALL qgwl values without threshold for verification + local_total_qgwl_sum = local_total_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) enddo - ! Use separate reproducible sum calls for bit-for-bit reproducibility across PE layouts - ! NOTE: Combined reprosum (nflds=2) was found to be non-reproducible for positive field - ! while negative field was reproducible, suggesting a bug in multi-field reprosum + ! Use combined reproducible sum for efficiency (3 fields: positive, negative, total) block - real(r8) :: pos_local(1,1), pos_global(1) - real(r8) :: neg_local(1,1), neg_global(1) + real(r8) :: local_sums(1,3), global_sums(3) + real(r8) :: global_total_qgwl_sum - ! Separate reprosum for positive qgwl - pos_local(1,1) = local_positive_qgwl_sum - call shr_reprosum_calc(pos_local, pos_global, 1, 1, 1, & - commid=mpicom_rof) - global_positive_qgwl_sum = pos_global(1) + ! Pack all three sums into combined array + local_sums(1,1) = local_positive_qgwl_sum + local_sums(1,2) = local_negative_qgwl_sum + local_sums(1,3) = local_total_qgwl_sum - ! Separate reprosum for negative qgwl - neg_local(1,1) = local_negative_qgwl_sum - call shr_reprosum_calc(neg_local, neg_global, 1, 1, 1, & + ! Single combined reprosum call for all three fields + call shr_reprosum_calc(local_sums, global_sums, 1, 1, 3, & commid=mpicom_rof) - global_negative_qgwl_sum = neg_global(1) + global_positive_qgwl_sum = global_sums(1) + global_negative_qgwl_sum = global_sums(2) + global_total_qgwl_sum = global_sums(3) ! Diagnostic output only when do_budget == 3 if (masterproc .and. do_budget == 3) then - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum = ', global_positive_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum = ', global_negative_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' Global Net qgwl Sum = ', global_positive_qgwl_sum + global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum (with threshold) = ', global_positive_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum (with threshold) = ', global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Total Sum (all values) = ', global_total_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Net from pos+neg = ', global_positive_qgwl_sum + global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Difference (Total - Net) = ', global_total_qgwl_sum - (global_positive_qgwl_sum + global_negative_qgwl_sum) endif end block From a28ca9cf9e29912899c6fdfeb774479ae6f5a806 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Fri, 31 Oct 2025 23:54:46 -0700 Subject: [PATCH 016/398] PEM test passed --- components/mosart/src/riverroute/RtmMod.F90 | 97 +++++++++++---------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 9cc08f3c209a..664492b5d64e 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -44,7 +44,7 @@ module RtmMod use MOSART_physics_mod, only : Euler use MOSART_physics_mod, only : updatestate_hillslope, updatestate_subnetwork, & updatestate_mainchannel - use MOSART_BGC_type, only : TSedi, TSedi_para, MOSART_sediment_init, TINYVALUE_s + use MOSART_BGC_type, only : TSedi, TSedi_para, MOSART_sediment_init use MOSART_RES_type, only : Tres, MOSART_reservoir_sed_init, Tres_para !#ifdef INCLUDE_WRM use WRM_type_mod , only : ctlSubwWRM, WRMUnit, StorWater @@ -143,7 +143,8 @@ module RtmMod ! Variables for TNR redirection integer, parameter :: num_top_outlets_for_qgwl = 500 ! Number of top outlets to use - real(r8), save :: global_positive_qgwl_sum = 0.0_r8 ! Sum of all positive qgwl + real(r8), parameter :: TINYVALUE_s = 1.0e-14_r8 ! Threshold for near-zero qgwl values + real(r8), save :: global_positive_qgwl_sum = 0.0_r8 ! Sum of all positive qgwl real(r8), save :: global_negative_qgwl_sum = 0.0_r8 ! Sum of all negative qgwl real(r8), save :: delt_save ! previous delt @@ -2403,47 +2404,62 @@ subroutine Rtmrun(rstwr,nlend,rdate) global_negative_qgwl_sum = 0.0_r8 ! Reset global sum each step if (redirect_negative_qgwl_flag) then - local_negative_qgwl_sum = 0.0_r8 ! This will sum local NEGATIVE qgwl - local_positive_qgwl_sum = 0.0_r8 ! This will sum local POSITIVE qgwl - local_total_qgwl_sum = 0.0_r8 ! This will sum ALL qgwl (for verification) - - ! Use TINYVALUE_s threshold to avoid non-reproducibility from near-zero values - ! that can flip sign across different PE layouts due to floating-point noise - do nr = rtmCTL%begr, rtmCTL%endr - if (rtmCTL%qgwl(nr, nt_nliq) > TINYVALUE_s) then - local_positive_qgwl_sum = local_positive_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) - elseif (rtmCTL%qgwl(nr, nt_nliq) < -TINYVALUE_s) then - local_negative_qgwl_sum = local_negative_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) - endif - ! Sum ALL qgwl values without threshold for verification - local_total_qgwl_sum = local_total_qgwl_sum + rtmCTL%qgwl(nr, nt_nliq) - enddo - - ! Use combined reproducible sum for efficiency (3 fields: positive, negative, total) + ! Use sparse packing approach: only include values exceeding threshold in reprosum + ! This avoids near-zero values that can flip sign across PE layouts block - real(r8) :: local_sums(1,3), global_sums(3) + real(r8), allocatable :: local_qgwl_array(:,:) + real(r8) :: global_sums(2) real(r8) :: global_total_qgwl_sum + integer :: num_positive, num_negative, num_total + integer :: idx_pos, idx_neg, idx_tot + integer :: local_count + integer :: nstep, yr, mon, day, tod + + ! First pass: count how many values exceed threshold + num_positive = 0 + num_negative = 0 + do nr = rtmCTL%begr, rtmCTL%endr + if (rtmCTL%qgwl(nr, nt_nliq) > TINYVALUE_s) then + num_positive = num_positive + 1 + elseif (rtmCTL%qgwl(nr, nt_nliq) < -TINYVALUE_s) then + num_negative = num_negative + 1 + endif + enddo + + ! Total entries to pack + local_count = num_positive + num_negative - ! Pack all three sums into combined array - local_sums(1,1) = local_positive_qgwl_sum - local_sums(1,2) = local_negative_qgwl_sum - local_sums(1,3) = local_total_qgwl_sum + ! Allocate sparse array for reprosum (2 fields: positive and negative) + allocate(local_qgwl_array(local_count, 2)) + local_qgwl_array(:,:) = 0.0_r8 - ! Single combined reprosum call for all three fields - call shr_reprosum_calc(local_sums, global_sums, 1, 1, 3, & + ! Second pass: pack only values exceeding threshold + idx_pos = 0 + idx_neg = 0 + do nr = rtmCTL%begr, rtmCTL%endr + if (rtmCTL%qgwl(nr, nt_nliq) > TINYVALUE_s) then + idx_pos = idx_pos + 1 + local_qgwl_array(idx_pos, 1) = rtmCTL%qgwl(nr, nt_nliq) + elseif (rtmCTL%qgwl(nr, nt_nliq) < -TINYVALUE_s) then + idx_neg = idx_neg + 1 + local_qgwl_array(num_positive + idx_neg, 2) = rtmCTL%qgwl(nr, nt_nliq) + endif + enddo + + ! Reproducible sum with sparse packing + call shr_reprosum_calc(local_qgwl_array, global_sums, local_count, local_count, 2, & commid=mpicom_rof) global_positive_qgwl_sum = global_sums(1) global_negative_qgwl_sum = global_sums(2) - global_total_qgwl_sum = global_sums(3) - ! Diagnostic output only when do_budget == 3 + ! Diagnostic output - total positive, negative, and net sums if (masterproc .and. do_budget == 3) then - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Positive Sum (with threshold) = ', global_positive_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Negative Sum (with threshold) = ', global_negative_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' REPROSUM Total Sum (all values) = ', global_total_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' Net from pos+neg = ', global_positive_qgwl_sum + global_negative_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' Difference (Total - Net) = ', global_total_qgwl_sum - (global_positive_qgwl_sum + global_negative_qgwl_sum) + write(iulog, '(A,ES24.16)') trim(subname)//' Global positive qgwl (threshold)=', global_positive_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Global negative qgwl (threshold)=', global_negative_qgwl_sum + write(iulog, '(A,ES24.16)') trim(subname)//' Net global qgwl (pos+neg) =', global_positive_qgwl_sum + global_negative_qgwl_sum endif + + deallocate(local_qgwl_array) end block net_global_qgwl = global_positive_qgwl_sum + global_negative_qgwl_sum @@ -2473,18 +2489,14 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Broadcast scaling factor from master to all PEs call MPI_Bcast(scaling_factor, 1, MPI_REAL8, 0, mpicom_rof, ier) - ! DEBUG: Verify broadcast on all PEs - if (do_budget == 3) then - write(iulog, '(A,I5,A,ES24.16)') trim(subname)//' [PE ', iam, '] scaling_factor (after bcast) = ', scaling_factor - endif - + ! Apply scaling with TINYVALUE_s threshold to ensure reproducibility do nr = rtmCTL%begr, rtmCTL%endr do nt = 1, nt_rtm - if (rtmCTL%qgwl(nr, nt) > 0.0_r8) then + if (rtmCTL%qgwl(nr, nt) > TINYVALUE_s) then ! Positive cell: scale down proportionally TRunoff%qgwl(nr, nt) = rtmCTL%qgwl(nr, nt) * scaling_factor else - ! Negative or zero cell: set to zero + ! Negative, zero, or near-zero cell: set to zero TRunoff%qgwl(nr, nt) = 0.0_r8 endif enddo @@ -3086,11 +3098,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) ! Broadcast the correction ratio from master to all PEs call MPI_Bcast(correction_ratio, 1, MPI_REAL8, 0, mpicom_rof, ier) - ! DEBUG: Verify broadcast on all PEs - if (do_budget == 3) then - write(iulog, '(A,I5,A,ES24.16)') trim(subname)//' [PE ', iam, '] correction_ratio (after bcast) = ', correction_ratio - endif - ! All PEs apply the same ratio to their local outlets do nr = rtmCTL%begr, rtmCTL%endr if (rtmCTL%mask(nr) == 3) then ! Outlet cell From ec68102cf4ab4144e2a0aaed6d2168b7a0cb3bb1 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Sat, 1 Nov 2025 01:07:14 -0700 Subject: [PATCH 017/398] remove unused stuff --- components/mosart/src/riverroute/RtmMod.F90 | 55 ++------------------- 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 664492b5d64e..047b4c5e2a3a 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -132,17 +132,9 @@ module RtmMod logical :: do_rtmflood logical :: do_rtm - type :: outlet_discharge_info_type - integer :: gidx - real(r8) :: discharge - end type outlet_discharge_info_type - - ! Namelist variable and flag for TNR redirection + ! Namelist variable and flag for negative qgwl redirection logical, public :: redirect_negative_qgwl = .false. ! Namelist control logical, save :: redirect_negative_qgwl_flag = .false. ! Module flag - - ! Variables for TNR redirection - integer, parameter :: num_top_outlets_for_qgwl = 500 ! Number of top outlets to use real(r8), parameter :: TINYVALUE_s = 1.0e-14_r8 ! Threshold for near-zero qgwl values real(r8), save :: global_positive_qgwl_sum = 0.0_r8 ! Sum of all positive qgwl real(r8), save :: global_negative_qgwl_sum = 0.0_r8 ! Sum of all negative qgwl @@ -2241,31 +2233,16 @@ subroutine Rtmrun(rstwr,nlend,rdate) !scs ! Variables for negative runoff redirection - - real(r8) :: local_positive_qgwl_sum, local_negative_qgwl_sum, local_total_qgwl_sum - real(r8) :: net_global_qgwl, original_cell_qgwl, reduction, scaling_factor - - integer, allocatable :: outlet_gindices_local(:) ! Local array of global indices of outlets on this task - real(r8), allocatable :: outlet_discharges_local(:) ! Local array of discharges for these outlets - integer :: local_outlet_count - integer, allocatable :: all_outlet_gindices(:) ! Gathered on master - real(r8), allocatable :: all_outlet_discharges(:) ! Gathered on master - integer, allocatable :: recvcounts(:), displs(:) ! For MPI_Gatherv - type(outlet_discharge_info_type), allocatable :: sorted_outlets(:) - integer :: num_all_outlets_global, current_top_n_count, target_gidx - real(r8) :: sum_discharge_top_n - real(r8), allocatable :: qgwl_correction_values(:) ! Values to apply - integer, allocatable :: qgwl_correction_gindices(:) ! Global indices for these corrections - real(r8), allocatable :: qgwl_correction_local(:) ! Local portion of correction array - real(r8) :: qgwl_to_redistribute ! Amount to redistribute (Scenario A or B) + real(r8) :: net_global_qgwl, scaling_factor + real(r8), allocatable :: qgwl_correction_local(:) + real(r8) :: qgwl_to_redistribute real(r8) :: local_total_outlet_discharge, global_total_outlet_discharge real(r8) :: outlet_discharge_local(1,1), outlet_discharge_global(1) real(r8) :: qgwl_to_discharge_ratio_percent real(r8) :: conservation_error - real(r8) :: global_total_liquid_before, global_total_liquid_after real(r8) :: local_correction_sum, global_correction_sum real(r8) :: correction_local(1,1), correction_global(1) - real(r8) :: correction_ratio ! Ratio to apply: qgwl_to_redistribute / global_total_outlet_discharge + real(r8) :: correction_ratio character(len=*),parameter :: subname = '(Rtmrun) ' !----------------------------------------------------------------------- @@ -2405,7 +2382,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (redirect_negative_qgwl_flag) then ! Use sparse packing approach: only include values exceeding threshold in reprosum - ! This avoids near-zero values that can flip sign across PE layouts block real(r8), allocatable :: local_qgwl_array(:,:) real(r8) :: global_sums(2) @@ -5405,25 +5381,4 @@ subroutine SubTimestep end do end subroutine SubTimestep -!----------------------------------------------------------------------- - -subroutine sort_outlets_by_discharge_desc(outlets_array, count) !TZ negative runoff - implicit none - integer, intent(in) :: count - type(outlet_discharge_info_type), intent(inout) :: outlets_array(:) ! Assumed-shape - integer :: i, j - type(outlet_discharge_info_type) :: temp_outlet_info - ! Bubble sort - if (count < 2) return - do i = 1, count - 1 - do j = 1, count - i - if (outlets_array(j)%discharge < outlets_array(j+1)%discharge) then - temp_outlet_info = outlets_array(j) - outlets_array(j) = outlets_array(j+1) - outlets_array(j+1) = temp_outlet_info - endif - enddo - enddo -end subroutine sort_outlets_by_discharge_desc - end module RtmMod \ No newline at end of file From e0553650e9b8067589aa941bfb2b7352f04fe2fd Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sun, 2 Nov 2025 14:46:55 +0000 Subject: [PATCH 018/398] Fix RAW (read after write) race hazard in theta-l_kokkos limiter Also remove (slow) profiling calls --- .../homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp | 3 --- .../homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp | 8 ++------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp b/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp index 38f9dc8573d8..8618899c692c 100644 --- a/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp +++ b/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp @@ -343,8 +343,6 @@ struct CaarFunctorImpl { set_rk_stage_data(data); - profiling_resume(); - GPTLstart("caar compute"); int nerr; Kokkos::parallel_reduce("caar loop pre-boundary exchange", m_policy_pre, *this, nerr); @@ -367,7 +365,6 @@ struct CaarFunctorImpl { limiter.run(data.np1); - profiling_pause(); } KOKKOS_INLINE_FUNCTION diff --git a/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp b/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp index 7914c0a60e3a..ea0dfd8085a3 100644 --- a/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp +++ b/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp @@ -99,15 +99,11 @@ struct LimiterFunctor { void run (const int& tl) { - profiling_resume(); - GPTLstart("caar limiter"); m_np1 = tl; Kokkos::parallel_for("caar loop dp3d limiter", m_policy_dp3d_lim, *this); Kokkos::fence(); GPTLstop("caar limiter"); - - profiling_pause(); } KOKKOS_INLINE_FUNCTION @@ -147,6 +143,7 @@ struct LimiterFunctor { #endif result = result<=diff_as_real(k) ? result : diff_as_real(k); }, reducer); + kv.team_barrier(); auto vtheta_dp = Homme::subview(m_state.m_vtheta_dp,kv.ie,m_np1,igp,jgp); @@ -168,8 +165,6 @@ struct LimiterFunctor { }); } - kv.team_barrier(); - // This loop must be done over physical levels, unless we implement // masks, like it has been done in the E3SM/scream project Real mass_new = 0.0; @@ -194,6 +189,7 @@ struct LimiterFunctor { vtheta_dp(ilev) *= dp(ilev); }); } //end of min_diff < 0 + kv.team_barrier(); Kokkos::parallel_for(Kokkos::ThreadVectorRange(kv.team,NUM_LEV), [&](const int ilev) { From 89d781c9a37e8fde0ca4d792e8cf4d6c9636fc36 Mon Sep 17 00:00:00 2001 From: Tian Zhou Date: Wed, 5 Nov 2025 11:07:32 -0800 Subject: [PATCH 019/398] consolidate diagnostic outputs --- components/mosart/src/riverroute/RtmMod.F90 | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/components/mosart/src/riverroute/RtmMod.F90 b/components/mosart/src/riverroute/RtmMod.F90 index 047b4c5e2a3a..20adb886705c 100644 --- a/components/mosart/src/riverroute/RtmMod.F90 +++ b/components/mosart/src/riverroute/RtmMod.F90 @@ -2458,7 +2458,7 @@ subroutine Rtmrun(rstwr,nlend,rdate) if (do_budget == 3) then write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] net_global_qgwl = ', net_global_qgwl write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] global_positive_qgwl_sum = ', global_positive_qgwl_sum - write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] scaling_factor (before bcast) = ', scaling_factor + write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario A] scaling_factor = ', scaling_factor endif endif @@ -3029,7 +3029,19 @@ subroutine Rtmrun(rstwr,nlend,rdate) qgwl_to_discharge_ratio_percent, '% (', qgwl_to_redistribute, ' m3/s)' endif - ! Always check and warn if magnitude is > 5% (regardless of do_budget) + ! Check for concerning redistribution ratios + if (abs(qgwl_to_discharge_ratio_percent) > 100.0_r8) then + call shr_sys_flush(iulog) + write(iulog, *) trim(subname), & + 'WARNING: QGWL_Redist_Ratio magnitude > 100% (', & + qgwl_to_discharge_ratio_percent, '%).' + write(iulog, *) trim(subname), & + 'Negative runoff to ocean is unavoidable as negative qgwl magnitude (', & + abs(qgwl_to_redistribute), ' m3/s) exceeds total outlet discharge (', & + global_total_outlet_discharge, ' m3/s).' + call shr_sys_flush(iulog) + endif + if (abs(qgwl_to_discharge_ratio_percent) > 5.0_r8) then call shr_sys_flush(iulog) write(iulog, *) trim(subname), & @@ -3057,18 +3069,6 @@ subroutine Rtmrun(rstwr,nlend,rdate) write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario B] global_total_outlet_discharge = ', global_total_outlet_discharge write(iulog, '(A,ES24.16)') trim(subname)//' [Scenario B] correction_ratio (before bcast) = ', correction_ratio endif - - ! Check if correction ratio magnitude exceeds 100% - if (correction_ratio < -1.0_r8) then - call shr_sys_flush(iulog) - write(iulog, *) trim(subname), & - 'WARNING: Correction ratio < -100% (', correction_ratio, ').' - write(iulog, *) trim(subname), & - 'Negative runoff to ocean is unavoidable as negative qgwl magnitude (', & - abs(qgwl_to_redistribute), ' m3/s) exceeds total outlet discharge (', & - global_total_outlet_discharge, ' m3/s).' - call shr_sys_flush(iulog) - endif endif ! Broadcast the correction ratio from master to all PEs From f5a16d13ccef07dab8f5f2b0d31d3dbe6adf4d57 Mon Sep 17 00:00:00 2001 From: Peter Schwartz Date: Fri, 7 Nov 2025 12:56:42 -0500 Subject: [PATCH 020/398] Use ieee intrinsics to avoid trapping ieee_inexact signals --- components/elm/src/biogeophys/SoilStateType.F90 | 10 ++++++---- components/elm/src/main/initVerticalMod.F90 | 6 +++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index 79ab33fcb8ea..2f2579b2282f 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -331,6 +331,7 @@ subroutine InitCold(this, bounds) use SharedParamsMod , only : ParamsShareInst use FuncPedotransferMod , only : pedotransf, get_ipedof use RootBiophysMod , only : init_vegrootfr + use, intrinsic :: ieee_exceptions ! ! !ARGUMENTS: class(soilstate_type) :: this @@ -468,10 +469,11 @@ subroutine InitCold(this, bounds) ! Try to read soil information from the file. call ncd_io(ncid=ncid, varname='ZSOI', flag='read', data=zsoifl, dim1name=grlnd, readvar=readvar) if (.not. readvar ) then - ! Variable ZSOI not found, use the ELM parameters. - do j = 1, nlevsoifl - zsoifl(j) = scalez*(exp(zecoeff*(j-0.5_r8))-1._r8) !node depths - end do + call ieee_set_flag(ieee_all,.false.) + call ieee_set_halting_mode(ieee_inexact, .false.) + do j = 1, nlevgrnd + zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths + enddo end if dzsoifl(1) = 0.5_r8*(zsoifl(1)+zsoifl(2)) !thickness b/n two interfaces diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index 27a089cc26d6..b40949e89e2c 100755 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -44,6 +44,7 @@ module initVerticalMod !------------------------------------------------------------------------ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) + use, intrinsic :: ieee_exceptions ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -170,8 +171,11 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) ! Soil layers not available from the input, and no additional layers needed. Use the ! default soil thickness settings. ! ----------------------------------------------------------------- + call ieee_set_flag(ieee_all,.false.) + call ieee_set_halting_mode(ieee_inexact, .false.) + do j = 1, nlevgrnd - zsoi(j) = scalez*(exp(zecoeff*(j-0.5_r8))-1._r8) !node depths + zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo end if deallocate(zsoi_in) From 57a57afb53c8fa4151cd3237d3c7348444e90dea Mon Sep 17 00:00:00 2001 From: Peter Schwartz Date: Fri, 7 Nov 2025 14:52:42 -0600 Subject: [PATCH 021/398] fix c/p mistake --- components/elm/src/biogeophys/SoilStateType.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index 2f2579b2282f..ed20b4ba24dc 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -471,8 +471,8 @@ subroutine InitCold(this, bounds) if (.not. readvar ) then call ieee_set_flag(ieee_all,.false.) call ieee_set_halting_mode(ieee_inexact, .false.) - do j = 1, nlevgrnd - zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths + do j = 1, nlevsoifl + zsoifl(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo end if From 1e05fe5f7b35366157ea11da6bba83a52bff3ee9 Mon Sep 17 00:00:00 2001 From: Peter Schwartz Date: Fri, 7 Nov 2025 15:16:01 -0600 Subject: [PATCH 022/398] add check in case compiler doesn't support inexact halting --- components/elm/src/biogeophys/SoilStateType.F90 | 6 ++++-- components/elm/src/main/initVerticalMod.F90 | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index ed20b4ba24dc..aed21ffc739c 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -469,8 +469,10 @@ subroutine InitCold(this, bounds) ! Try to read soil information from the file. call ncd_io(ncid=ncid, varname='ZSOI', flag='read', data=zsoifl, dim1name=grlnd, readvar=readvar) if (.not. readvar ) then - call ieee_set_flag(ieee_all,.false.) - call ieee_set_halting_mode(ieee_inexact, .false.) + if (ieee_support_halting(ieee_inexact)) then + call ieee_set_flag(ieee_all,.false.) + call ieee_set_halting_mode(ieee_inexact, .false.) + end if do j = 1, nlevsoifl zsoifl(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index b40949e89e2c..642579331a98 100755 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -171,8 +171,10 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) ! Soil layers not available from the input, and no additional layers needed. Use the ! default soil thickness settings. ! ----------------------------------------------------------------- - call ieee_set_flag(ieee_all,.false.) - call ieee_set_halting_mode(ieee_inexact, .false.) + if (ieee_support_halting(ieee_inexact)) then + call ieee_set_flag(ieee_all,.false.) + call ieee_set_halting_mode(ieee_inexact, .false.) + end if do j = 1, nlevgrnd zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths From 3d4f2fe03978027071fe956113284de4a380a696 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Tue, 11 Nov 2025 12:48:43 -0800 Subject: [PATCH 023/398] remove unneeded code and initialize variables before they are read in to prevent lingering NaNs --- components/eam/src/control/iop_data_mod.F90 | 40 ++++++++++----------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index f7b05dee5e09..5b66323794a7 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -110,7 +110,6 @@ module iop_data_mod real(r8), public :: asdifobs(1) ! observed asdif real(r8), public :: wfld(plev) ! Vertical motion (slt) - real(r8), public :: wfldh(plevp) ! Vertical motion (slt) real(r8), public :: divq(plev,pcnst) ! Divergence of moisture real(r8), public :: divt(plev) ! Divergence of temperature real(r8), public :: divu(plev) ! Horiz Divergence of E/W @@ -677,10 +676,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) real(r8) dummy real(r8) lat,xlat real(r8) srf(1) ! value at surface - real(r8) pmid(plev) ! pressure at model levels (time n) - real(r8) pint(plevp) ! pressure at model interfaces (n ) - real(r8) pdel(plev) ! pdel(k) = pint (k+1)-pint (k) - real(r8) weight real(r8) tmpdata(1) real(r8) coldata(plev) real(r8) ps_surf, thelat, thelon, the_clat @@ -1041,6 +1036,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q=.true. endif + cldobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'cld', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, cldobs, status ) if ( status .ne. nf90_noerr ) then @@ -1049,6 +1045,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_cld = .true. endif + clwpobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'clwp', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, clwpobs, status ) if ( status .ne. nf90_noerr ) then @@ -1067,6 +1064,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + divq(:,:) = 0.0_r8 ! Initialize to zero to prevent missing end values being set to NaN call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1085,6 +1083,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + vertdivq(:,:) = 0.0_r8 ! Initialize to zero to prevent missing end values being set to NaN call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1105,11 +1104,11 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) do m = 1, pcnst + divq3d(1:,m)=0._r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, trim(cnst_name(m))//'_dten', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq3d(:,m), status ) if ( status .ne. nf90_noerr ) then have_cnst(m) = .false. - divq3d(1:,m)=0._r8 else have_cnst(m) = .true. endif @@ -1135,6 +1134,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('NUMLIQ', inumliq, abrtf=.false.) if ( inumliq > 0 ) then have_srf = .false. + numliqobs = 0.0_r8 call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMLIQ', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numliqobs, status ) if ( status .ne. nf90_noerr ) then @@ -1151,12 +1151,14 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldliqobs, status ) if ( status .ne. nf90_noerr ) then have_cldliq = .false. + cldliqobs = 0.0_r8 else have_cldliq = .true. endif call cnst_get_ind('CLDICE', icldice) + cldiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1169,6 +1171,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) if ( inumice > 0 ) then have_srf = .false. + numiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1188,6 +1191,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + divu = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divu', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divu, status ) if ( status .ne. nf90_noerr ) then @@ -1206,6 +1210,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + divv = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divv', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divv, status ) if ( status .ne. nf90_noerr ) then @@ -1224,6 +1229,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + divt = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'divT', have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt, status ) if ( status .ne. nf90_noerr ) then @@ -1242,6 +1248,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + vertdivt = 0.0_r8 call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivT', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivt, status ) if ( status .ne. nf90_noerr ) then @@ -1261,6 +1268,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + divt3d = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divT3d', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt3d, status ) if ( status .ne. nf90_noerr ) then @@ -1280,22 +1288,8 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) ptend= srf(1) endif - call plevs0(1 ,plon ,plev ,psobs ,pint,pmid ,pdel) call shr_sys_flush( iulog ) - ! Build interface vector for the specified omega profile - ! (weighted average in pressure of specified level values) - - wfldh(1) = 0.0_r8 - - do k=2,plev - weight = (pint(k) - pmid(k-1))/(pmid(k) - pmid(k-1)) - wfldh(k) = (1.0_r8 - weight)*wfld(k-1) + weight*wfld(k) - end do - - wfldh(plevp) = 0.0_r8 - - status = nf90_inq_varid( ncid, 'usrf', varid ) if ( status .ne. nf90_noerr ) then have_srf = .false. @@ -1314,6 +1308,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) endif ! large scale / geostropic horizontal wind (for nudging) + uls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'u_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, uls, status ) if ( status .ne. nf90_noerr ) then @@ -1347,6 +1342,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call shr_sys_flush( iulog ) ! large scale / geostropic meridional wind (for nudging) + vls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'v_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, vls, status ) if ( status .ne. nf90_noerr ) then @@ -1369,6 +1365,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_prec = .true. endif + q1obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q1', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q1obs, status ) if ( status .ne. nf90_noerr ) then @@ -1377,8 +1374,9 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q1 = .true. endif + q2obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q2', & - .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q1obs, status ) + .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q2obs, status ) if ( status .ne. nf90_noerr ) then have_q2 = .false. else From 2385d4a50673d022336dccaff9a57cc9e9c71884 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Tue, 11 Nov 2025 13:33:47 -0800 Subject: [PATCH 024/398] initialize large scale omega to zero --- components/eam/src/control/iop_data_mod.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index 5b66323794a7..534b002ce8e6 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -1447,7 +1447,8 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call wrap_get_vara_realx (ncid,varid,strt4,cnt4,tground) have_tg = .true. endif - + + wfld = 0.0_r8 ! Initialize call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'omega', .true., ptend, fill_ends, dplevs, nlev,psobs, hyam, hybm, wfld, status ) if ( status .ne. nf90_noerr ) then From 201ecf235c75e29f7e5cc1bcc943bed2b636bdc9 Mon Sep 17 00:00:00 2001 From: Peter Schwartz Date: Thu, 13 Nov 2025 16:30:47 -0500 Subject: [PATCH 025/398] Added using_nvhpc parameter which is set if using nvidia compiler --- components/elm/src/biogeophys/SoilStateType.F90 | 9 ++++++++- components/elm/src/main/initVerticalMod.F90 | 16 +++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index aed21ffc739c..0b6037b42c71 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -105,6 +105,12 @@ module SoilStateType end type soilstate_type !------------------------------------------------------------------------ +#ifdef CPRNVIDIA + logical, parameter :: using_nvhpc = .true. +#else + logical, parameter :: using_nvhpc = .false. +#endif + contains !------------------------------------------------------------------------ @@ -469,7 +475,8 @@ subroutine InitCold(this, bounds) ! Try to read soil information from the file. call ncd_io(ncid=ncid, varname='ZSOI', flag='read', data=zsoifl, dim1name=grlnd, readvar=readvar) if (.not. readvar ) then - if (ieee_support_halting(ieee_inexact)) then + !NOTE: Workaround due to compiler issue with nvhpc 25.x when using -Ktrap=fp + if (using_nvhpc .and. ieee_support_halting(ieee_inexact)) then call ieee_set_flag(ieee_all,.false.) call ieee_set_halting_mode(ieee_inexact, .false.) end if diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index 642579331a98..d6a2ff099f1d 100755 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -39,6 +39,11 @@ module initVerticalMod ! !PUBLIC MEMBER FUNCTIONS: public :: initVertical !------------------------------------------------------------------------ +#ifdef CPRNVIDIA + logical, parameter :: using_nvhpc = .true. +#else + logical, parameter :: using_nvhpc = .false. +#endif contains @@ -167,15 +172,16 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) zsoi(j) = scalez*(exp(zecoeff*((j - nlev_equalspace)-0.5_r8))-1._r8) + nlev_equalspace * thick_equal enddo else - ! ----------------------------------------------------------------- - ! Soil layers not available from the input, and no additional layers needed. Use the - ! default soil thickness settings. - ! ----------------------------------------------------------------- - if (ieee_support_halting(ieee_inexact)) then + !NOTE: Workaround due to compiler issue with nvhpc 25.x when using -Ktrap=fp + if (using_nvhpc .and. ieee_support_halting(ieee_inexact)) then call ieee_set_flag(ieee_all,.false.) call ieee_set_halting_mode(ieee_inexact, .false.) end if + ! ----------------------------------------------------------------- + ! Soil layers not available from the input, and no additional layers needed. Use the + ! default soil thickness settings. + ! ----------------------------------------------------------------- do j = 1, nlevgrnd zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo From 93dd69185d5d9069fb9f89c011d4116d54fbe1d5 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Thu, 13 Nov 2025 17:17:16 -0600 Subject: [PATCH 026/398] Update testing support for Greenland configurations Swap out low-res 20km mesh with var. res. 4-to-40km mesh; generalize shell commands and namelist file changes (not specific to a single mesh resolution); exclude regional stats generation for MALI (which prohibits comparison between multiple MALI hist. files); add ERS test for BG config. --- .../allactive/{gis20km => gis}/shell_commands | 0 cime_config/testmods_dirs/allactive/gis/user_nl_mali | 2 ++ cime_config/testmods_dirs/allactive/gis20km/user_nl_mali | 1 - cime_config/testmods_dirs/config_pes_tests.xml | 2 +- cime_config/tests.py | 8 ++++---- .../testmods_dirs/mali/{gis20km => gis}/shell_commands | 0 .../testmods_dirs/mali/{gis20km => gis}/user_nl_mali | 1 + 7 files changed, 8 insertions(+), 6 deletions(-) rename cime_config/testmods_dirs/allactive/{gis20km => gis}/shell_commands (100%) create mode 100644 cime_config/testmods_dirs/allactive/gis/user_nl_mali delete mode 100644 cime_config/testmods_dirs/allactive/gis20km/user_nl_mali rename components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/{gis20km => gis}/shell_commands (100%) rename components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/{gis20km => gis}/user_nl_mali (76%) diff --git a/cime_config/testmods_dirs/allactive/gis20km/shell_commands b/cime_config/testmods_dirs/allactive/gis/shell_commands similarity index 100% rename from cime_config/testmods_dirs/allactive/gis20km/shell_commands rename to cime_config/testmods_dirs/allactive/gis/shell_commands diff --git a/cime_config/testmods_dirs/allactive/gis/user_nl_mali b/cime_config/testmods_dirs/allactive/gis/user_nl_mali new file mode 100644 index 000000000000..5b40fb4c8069 --- /dev/null +++ b/cime_config/testmods_dirs/allactive/gis/user_nl_mali @@ -0,0 +1,2 @@ +config_am_globalstats_enable = .false. +config_am_regionalstats_enable = .false. diff --git a/cime_config/testmods_dirs/allactive/gis20km/user_nl_mali b/cime_config/testmods_dirs/allactive/gis20km/user_nl_mali deleted file mode 100644 index 8b88e2add6c6..000000000000 --- a/cime_config/testmods_dirs/allactive/gis20km/user_nl_mali +++ /dev/null @@ -1 +0,0 @@ -config_am_globalstats_enable = .false. diff --git a/cime_config/testmods_dirs/config_pes_tests.xml b/cime_config/testmods_dirs/config_pes_tests.xml index 8fd0d25d361b..dc33e24b14f5 100644 --- a/cime_config/testmods_dirs/config_pes_tests.xml +++ b/cime_config/testmods_dirs/config_pes_tests.xml @@ -354,7 +354,7 @@ - + GIS 20km (low-res) testing config diff --git a/cime_config/tests.py b/cime_config/tests.py index 77cc83f883ac..26e2ed57f963 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -144,10 +144,10 @@ "e3sm_landice_developer" : { "tests" : ( - "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", - "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-gis20km", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-gis", + "ERS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-gis", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-gis", + "ERS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-gis", "SMS.ne30_oECv3_gis.IGELM_MLI.elm-extrasnowlayers", "ERS_Ld5.TL319_oQU240wLI_gis4to40.MPAS_FOLISIO_JRA1p5.mpaso-jra_1958", "ERS_Ld5.TL319_oQU240wLI_ais8to30.MPAS_FOLISIO_JRA1p5.mpaso-jra_1958", 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/gis/shell_commands similarity index 100% rename from components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/shell_commands rename to components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands 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/gis/user_nl_mali similarity index 76% rename from components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis20km/user_nl_mali rename to components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali index 4ef8179b7cf3..2c8123fcef85 100644 --- 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/gis/user_nl_mali @@ -1,3 +1,4 @@ +config_am_regionalstats_enable = .false. config_am_globalstats_enable = .false. config_adaptive_timestep = .true. config_adaptive_timestep_force_interval = '0000-00-01_00:00:00' From 77970bdccb16a7a0ec4c216db323abe17eab8cd8 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Fri, 14 Nov 2025 14:13:48 -0600 Subject: [PATCH 027/398] More updates to testing support for Greenland configurations Add reg exp matching to cime archiving script to pull in wider range of MPAS hist files in testing; Correct pe layouts for Chrys and PM testing. --- cime_config/config_archive.xml | 2 + .../testmods_dirs/config_pes_tests.xml | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/cime_config/config_archive.xml b/cime_config/config_archive.xml index 4f844a971de8..18145d0bfc75 100644 --- a/cime_config/config_archive.xml +++ b/cime_config/config_archive.xml @@ -124,6 +124,8 @@ rst hist + \w+ + \w+\.\w+ unset rpointer.glc$NINST_STRING diff --git a/cime_config/testmods_dirs/config_pes_tests.xml b/cime_config/testmods_dirs/config_pes_tests.xml index dc33e24b14f5..f5b9b81898c8 100644 --- a/cime_config/testmods_dirs/config_pes_tests.xml +++ b/cime_config/testmods_dirs/config_pes_tests.xml @@ -355,9 +355,45 @@ - + + + GIS 4to40km (low-res) testing config + 64 + 64 + + 512 + 512 + 512 + 512 + 512 + 256 + 512 + 512 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + - GIS 20km (low-res) testing config + GIS 4to40km (low-res) testing config 128 128 From 2b385e45b2c0dea434bb7d852e308e0c5209daa2 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Fri, 14 Nov 2025 15:29:38 -0800 Subject: [PATCH 028/398] move initialization to zero inside the getinterpdata routine. Still need to initialize all divq arrays to zero outside since this routine is only called on the first constituent --- .../eam/src/control/getinterpnetcdfdata.F90 | 4 ++++ components/eam/src/control/iop_data_mod.F90 | 20 ++----------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/components/eam/src/control/getinterpnetcdfdata.F90 b/components/eam/src/control/getinterpnetcdfdata.F90 index 4f7182ec3dab..3d41b0ca9857 100644 --- a/components/eam/src/control/getinterpnetcdfdata.F90 +++ b/components/eam/src/control/getinterpnetcdfdata.F90 @@ -76,6 +76,10 @@ subroutine getinterpncdata( NCID, camlat, camlon, TimeIdx, & ! ------- code --------- +! If fill ends is not applied, then initialize all values to zero to +! prevent uninitialized memory for the leves where there is no data. + if (.not. fill_ends) outData(:) = 0.0_r8 + call shr_scam_GetCloseLatLon(ncid,camlat,camlon,closelat,closelon,latidx,lonidx) ! diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index 534b002ce8e6..3fc29163f0a2 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -1036,7 +1036,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q=.true. endif - cldobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'cld', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, cldobs, status ) if ( status .ne. nf90_noerr ) then @@ -1045,7 +1044,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_cld = .true. endif - clwpobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'clwp', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, clwpobs, status ) if ( status .ne. nf90_noerr ) then @@ -1064,7 +1062,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - divq(:,:) = 0.0_r8 ! Initialize to zero to prevent missing end values being set to NaN + divq(:,:) = 0.0_r8 ! Initialize all to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1083,7 +1081,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - vertdivq(:,:) = 0.0_r8 ! Initialize to zero to prevent missing end values being set to NaN + vertdivq(:,:) = 0.0_r8 ! Initialize all to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1104,7 +1102,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) do m = 1, pcnst - divq3d(1:,m)=0._r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, trim(cnst_name(m))//'_dten', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq3d(:,m), status ) if ( status .ne. nf90_noerr ) then @@ -1134,7 +1131,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('NUMLIQ', inumliq, abrtf=.false.) if ( inumliq > 0 ) then have_srf = .false. - numliqobs = 0.0_r8 call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMLIQ', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numliqobs, status ) if ( status .ne. nf90_noerr ) then @@ -1158,7 +1154,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('CLDICE', icldice) - cldiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1171,7 +1166,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) if ( inumice > 0 ) then have_srf = .false. - numiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1191,7 +1185,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - divu = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divu', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divu, status ) if ( status .ne. nf90_noerr ) then @@ -1210,7 +1203,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - divv = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divv', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divv, status ) if ( status .ne. nf90_noerr ) then @@ -1229,7 +1221,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - divt = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'divT', have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt, status ) if ( status .ne. nf90_noerr ) then @@ -1248,7 +1239,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - vertdivt = 0.0_r8 call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivT', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivt, status ) if ( status .ne. nf90_noerr ) then @@ -1268,7 +1258,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - divt3d = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divT3d', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt3d, status ) if ( status .ne. nf90_noerr ) then @@ -1308,7 +1297,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) endif ! large scale / geostropic horizontal wind (for nudging) - uls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'u_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, uls, status ) if ( status .ne. nf90_noerr ) then @@ -1342,7 +1330,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call shr_sys_flush( iulog ) ! large scale / geostropic meridional wind (for nudging) - vls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'v_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, vls, status ) if ( status .ne. nf90_noerr ) then @@ -1365,7 +1352,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_prec = .true. endif - q1obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q1', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q1obs, status ) if ( status .ne. nf90_noerr ) then @@ -1374,7 +1360,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q1 = .true. endif - q2obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q2', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q2obs, status ) if ( status .ne. nf90_noerr ) then @@ -1448,7 +1433,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_tg = .true. endif - wfld = 0.0_r8 ! Initialize call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'omega', .true., ptend, fill_ends, dplevs, nlev,psobs, hyam, hybm, wfld, status ) if ( status .ne. nf90_noerr ) then From 334eae08801938ca8fae2e909ff2981c8b6ea753 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Fri, 14 Nov 2025 15:31:27 -0800 Subject: [PATCH 029/398] remove lingering hard initialization set in the interface level --- components/eam/src/control/iop_data_mod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index 3fc29163f0a2..2f2bb9dace09 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -1147,7 +1147,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldliqobs, status ) if ( status .ne. nf90_noerr ) then have_cldliq = .false. - cldliqobs = 0.0_r8 else have_cldliq = .true. endif From f9cd810ef486933e8c9f64474967a78f59c56cd6 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Tue, 18 Nov 2025 17:18:20 -0600 Subject: [PATCH 030/398] Finish updated testing support for Greenland configurations Updated pes support for testing on Chrys and PM-cpu; reduce no. of days for ERS tests; remove no longer needed test mod support (due to default timestepping setting changes); rename test mod dir names; update default pe layouts for IG cases --- cime_config/allactive/config_pesall.xml | 6 +- .../{gis => landiceBG}/shell_commands | 4 - .../allactive/{gis => landiceBG}/user_nl_mali | 0 cime_config/tests.py | 8 +- components/elm/cime_config/config_pes.xml | 110 +++++++++++++++--- .../namelist_files/namelist_defaults_mali.xml | 4 +- .../testmods_dirs/mali/gis/shell_commands | 4 - .../testmods_dirs/mali/gis/user_nl_mali | 4 +- .../mali/landiceIG/shell_commands | 6 + .../testmods_dirs/mali/landiceIG/user_nl_mali | 2 + 10 files changed, 112 insertions(+), 36 deletions(-) rename cime_config/testmods_dirs/allactive/{gis => landiceBG}/shell_commands (61%) rename cime_config/testmods_dirs/allactive/{gis => landiceBG}/user_nl_mali (100%) create mode 100644 components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/shell_commands create mode 100644 components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/user_nl_mali diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index 39b155427184..5fad6a6a73d2 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -2518,8 +2518,8 @@ GIS 20km (low-res) testing config - 128 - 128 + 64 + 64 512 512 @@ -2536,6 +2536,8 @@ pm-cpu: GIS 20 or 40km (low-res) testing config, 2 nodes, 128x1 + 128 + 128 256 256 256 diff --git a/cime_config/testmods_dirs/allactive/gis/shell_commands b/cime_config/testmods_dirs/allactive/landiceBG/shell_commands similarity index 61% rename from cime_config/testmods_dirs/allactive/gis/shell_commands rename to cime_config/testmods_dirs/allactive/landiceBG/shell_commands index 4547393d8728..48e4476439b8 100644 --- a/cime_config/testmods_dirs/allactive/gis/shell_commands +++ b/cime_config/testmods_dirs/allactive/landiceBG/shell_commands @@ -1,7 +1,3 @@ -./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 diff --git a/cime_config/testmods_dirs/allactive/gis/user_nl_mali b/cime_config/testmods_dirs/allactive/landiceBG/user_nl_mali similarity index 100% rename from cime_config/testmods_dirs/allactive/gis/user_nl_mali rename to cime_config/testmods_dirs/allactive/landiceBG/user_nl_mali diff --git a/cime_config/tests.py b/cime_config/tests.py index 26e2ed57f963..a06dbc4dbf56 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -144,10 +144,10 @@ "e3sm_landice_developer" : { "tests" : ( - "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-gis", - "ERS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-gis", - "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-gis", - "ERS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-gis", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-landiceIG", + "ERS_Ld3.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-landiceIG", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-landiceBG", + "ERS_Ld3.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-landiceBG", "SMS.ne30_oECv3_gis.IGELM_MLI.elm-extrasnowlayers", "ERS_Ld5.TL319_oQU240wLI_gis4to40.MPAS_FOLISIO_JRA1p5.mpaso-jra_1958", "ERS_Ld5.TL319_oQU240wLI_ais8to30.MPAS_FOLISIO_JRA1p5.mpaso-jra_1958", diff --git a/components/elm/cime_config/config_pes.xml b/components/elm/cime_config/config_pes.xml index c662cc64ed5e..8c18028f814e 100644 --- a/components/elm/cime_config/config_pes.xml +++ b/components/elm/cime_config/config_pes.xml @@ -457,10 +457,10 @@ - - - - GIS 20km (low-res) testing config + + + + pm-cpu: GIS 1-to-10km (high-res) baseline config 128 128 @@ -469,7 +469,7 @@ 128 128 128 - 128 + 960 128 128 @@ -490,26 +490,101 @@ 0 0 0 + 0 + 0 + + + + + + GIS 1-to-10km (high-res) baseline config + 64 + 64 + + 64 + 64 + 64 + 64 + 64 + 960 + 64 + 64 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 - - - - GIS 1-to-10km (high-res) config + + + + pm-cpu: GIS 4-to-40km (med-res) baseline config 128 128 - 512 - 512 - 512 - 512 - 512 - 512 - 512 - 512 + 128 + 128 + 128 + 128 + 128 + 128 + 128 + 128 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + chrys: GIS 4-to-40km (med-res) baseline config + 64 + 64 + + 64 + 64 + 64 + 64 + 64 + 64 + 64 + 64 1 @@ -528,6 +603,7 @@ 0 0 0 + 0 0 diff --git a/components/mpas-albany-landice/bld/namelist_files/namelist_defaults_mali.xml b/components/mpas-albany-landice/bld/namelist_files/namelist_defaults_mali.xml index 166d5d48a18f..47ffa808f864 100644 --- a/components/mpas-albany-landice/bld/namelist_files/namelist_defaults_mali.xml +++ b/components/mpas-albany-landice/bld/namelist_files/namelist_defaults_mali.xml @@ -134,7 +134,7 @@ 'forward_euler' 2 3 -.false. +.true. 3600.0 3.15e9 0.25 @@ -143,7 +143,7 @@ .false. .true. .true. -'1000-00-00_00:00:00' +'0000-00-01_00:00:00' .false. diff --git a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands index 4547393d8728..48e4476439b8 100644 --- a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands +++ b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands @@ -1,7 +1,3 @@ -./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 diff --git a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali index 2c8123fcef85..5b40fb4c8069 100644 --- a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali +++ b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali @@ -1,4 +1,2 @@ -config_am_regionalstats_enable = .false. config_am_globalstats_enable = .false. -config_adaptive_timestep = .true. -config_adaptive_timestep_force_interval = '0000-00-01_00:00:00' +config_am_regionalstats_enable = .false. diff --git a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/shell_commands b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/shell_commands new file mode 100644 index 000000000000..48e4476439b8 --- /dev/null +++ b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/shell_commands @@ -0,0 +1,6 @@ +./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/landiceIG/user_nl_mali b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/user_nl_mali new file mode 100644 index 000000000000..5b40fb4c8069 --- /dev/null +++ b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/landiceIG/user_nl_mali @@ -0,0 +1,2 @@ +config_am_globalstats_enable = .false. +config_am_regionalstats_enable = .false. From d3dc9d0f4ed69cd4924c47632aa5527c79afde21 Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Wed, 12 Nov 2025 11:16:55 -0600 Subject: [PATCH 031/398] Adding CRYO CMIP7 compsets --- cime_config/allactive/config_compsets.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cime_config/allactive/config_compsets.xml b/cime_config/allactive/config_compsets.xml index e0f2d2792eca..0cee7c18f5ec 100755 --- a/cime_config/allactive/config_compsets.xml +++ b/cime_config/allactive/config_compsets.xml @@ -411,6 +411,11 @@ 1850SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1850-CMIP7 + 1850SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1850-4xCO2 1850SOI_EAM%CMIP6-4xCO2_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV @@ -426,6 +431,11 @@ 1950SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1950-CMIP7 + 1950SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1850-DISMF 1850SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV @@ -441,6 +451,11 @@ 20TRSOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO20TR-CMIP7 + 20TRSOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYOSSP245 SSP245SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV From 15f7f974482fdc985ad3a20125ff934fae513495 Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Wed, 12 Nov 2025 14:57:25 -0600 Subject: [PATCH 032/398] Adding 4xCO2 and 1pctCO2 compsets --- cime_config/allactive/config_compsets.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cime_config/allactive/config_compsets.xml b/cime_config/allactive/config_compsets.xml index 0cee7c18f5ec..7f5596e7fbf3 100755 --- a/cime_config/allactive/config_compsets.xml +++ b/cime_config/allactive/config_compsets.xml @@ -421,11 +421,21 @@ 1850SOI_EAM%CMIP6-4xCO2_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1850-CMIP7-4xCO2 + 1850SOI%CMIP7-4xCO2_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1850-1pctCO2 1850SOI_EAM%CMIP6-1pctCO2_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1850-CMIP7-1pctCO2 + 1850SOI%CMIP7-1pctCO2_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV + + CRYO1950 1950SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV From b031184ba989302b01f8c2132a58b7eb781efcfd Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Thu, 20 Nov 2025 17:58:28 -0600 Subject: [PATCH 033/398] Adding CRYO*-CMIP7-DISMF compsets --- cime_config/allactive/config_compsets.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cime_config/allactive/config_compsets.xml b/cime_config/allactive/config_compsets.xml index 7f5596e7fbf3..5cdf2fc67025 100755 --- a/cime_config/allactive/config_compsets.xml +++ b/cime_config/allactive/config_compsets.xml @@ -451,11 +451,21 @@ 1850SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV + + CRYO1850-CMIP7-DISMF + 1850SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV + + CRYO1950-DISMF 1950SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV + + CRYO1950-CMIP7-DISMF + 1950SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV + + CRYO20TR 20TRSOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV From 16ffced7c5fde77e0b1aa8d64016b892efdc2896 Mon Sep 17 00:00:00 2001 From: Peter Schwartz Date: Sun, 23 Nov 2025 18:43:33 -0500 Subject: [PATCH 034/398] remove if guard and replace with ifdef directly --- components/elm/src/biogeophys/SoilStateType.F90 | 15 +++++---------- components/elm/src/main/initVerticalMod.F90 | 16 ++++++---------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index 0b6037b42c71..c2c125af854f 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -105,12 +105,6 @@ module SoilStateType end type soilstate_type !------------------------------------------------------------------------ -#ifdef CPRNVIDIA - logical, parameter :: using_nvhpc = .true. -#else - logical, parameter :: using_nvhpc = .false. -#endif - contains !------------------------------------------------------------------------ @@ -475,11 +469,12 @@ subroutine InitCold(this, bounds) ! Try to read soil information from the file. call ncd_io(ncid=ncid, varname='ZSOI', flag='read', data=zsoifl, dim1name=grlnd, readvar=readvar) if (.not. readvar ) then + +#ifdef CPRNVIDIA !NOTE: Workaround due to compiler issue with nvhpc 25.x when using -Ktrap=fp - if (using_nvhpc .and. ieee_support_halting(ieee_inexact)) then - call ieee_set_flag(ieee_all,.false.) - call ieee_set_halting_mode(ieee_inexact, .false.) - end if + call ieee_set_flag(ieee_all,.false.) + call ieee_set_halting_mode(ieee_inexact, .false.) +#endif do j = 1, nlevsoifl zsoifl(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index d6a2ff099f1d..1fc64726ab82 100755 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -39,11 +39,6 @@ module initVerticalMod ! !PUBLIC MEMBER FUNCTIONS: public :: initVertical !------------------------------------------------------------------------ -#ifdef CPRNVIDIA - logical, parameter :: using_nvhpc = .true. -#else - logical, parameter :: using_nvhpc = .false. -#endif contains @@ -172,19 +167,20 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) zsoi(j) = scalez*(exp(zecoeff*((j - nlev_equalspace)-0.5_r8))-1._r8) + nlev_equalspace * thick_equal enddo else - !NOTE: Workaround due to compiler issue with nvhpc 25.x when using -Ktrap=fp - if (using_nvhpc .and. ieee_support_halting(ieee_inexact)) then - call ieee_set_flag(ieee_all,.false.) - call ieee_set_halting_mode(ieee_inexact, .false.) - end if ! ----------------------------------------------------------------- ! Soil layers not available from the input, and no additional layers needed. Use the ! default soil thickness settings. ! ----------------------------------------------------------------- + !NOTE: Workaround due to compiler issue with nvhpc 25.x when using -Ktrap=fp +#ifdef CPRNVIDIA + call ieee_set_flag(ieee_all,.false.) + call ieee_set_halting_mode(ieee_inexact, .false.) +#endif do j = 1, nlevgrnd zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo + print *, "done with init vertical" end if deallocate(zsoi_in) From 7bd8a3d3da4ee5fb31a698ce02bb883932414ac8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 11:11:55 +0000 Subject: [PATCH 035/398] Bump actions/checkout from 5 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/e3sm-gh-ci-cime-tests.yml | 2 +- .github/workflows/e3sm-gh-ci-w-cime-tests.yml | 2 +- .github/workflows/e3sm-gh-md-linter.yml | 2 +- .github/workflows/e3sm-gh-pages.yml | 2 +- .github/workflows/eamxx-gh-clang-format.yml | 2 +- .github/workflows/eamxx-sa-coverage.yml | 4 ++-- .github/workflows/eamxx-sa-sanitizer.yml | 4 ++-- .github/workflows/eamxx-sa-testing.yml | 4 ++-- .github/workflows/eamxx-scripts-tests.yml | 2 +- .github/workflows/eamxx-v1-testing.yml | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/e3sm-gh-ci-cime-tests.yml b/.github/workflows/e3sm-gh-ci-cime-tests.yml index 798b638e0c48..eb6aafac93c3 100644 --- a/.github/workflows/e3sm-gh-ci-cime-tests.yml +++ b/.github/workflows/e3sm-gh-ci-cime-tests.yml @@ -47,7 +47,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: show-progress: false submodules: recursive diff --git a/.github/workflows/e3sm-gh-ci-w-cime-tests.yml b/.github/workflows/e3sm-gh-ci-w-cime-tests.yml index 93b15299789f..7f775b838902 100644 --- a/.github/workflows/e3sm-gh-ci-w-cime-tests.yml +++ b/.github/workflows/e3sm-gh-ci-w-cime-tests.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: show-progress: false submodules: recursive diff --git a/.github/workflows/e3sm-gh-md-linter.yml b/.github/workflows/e3sm-gh-md-linter.yml index 2bf00657598c..d657d6a04805 100644 --- a/.github/workflows/e3sm-gh-md-linter.yml +++ b/.github/workflows/e3sm-gh-md-linter.yml @@ -17,7 +17,7 @@ jobs: if: ${{ github.repository == 'E3SM-Project/E3SM' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: tj-actions/changed-files@v47 diff --git a/.github/workflows/e3sm-gh-pages.yml b/.github/workflows/e3sm-gh-pages.yml index 67134564fde8..8a2d0f5aa43b 100644 --- a/.github/workflows/e3sm-gh-pages.yml +++ b/.github/workflows/e3sm-gh-pages.yml @@ -39,7 +39,7 @@ jobs: shell: bash -leo pipefail {0} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: persist-credentials: false show-progress: false diff --git a/.github/workflows/eamxx-gh-clang-format.yml b/.github/workflows/eamxx-gh-clang-format.yml index 6278cc743625..68365182aab5 100644 --- a/.github/workflows/eamxx-gh-clang-format.yml +++ b/.github/workflows/eamxx-gh-clang-format.yml @@ -34,7 +34,7 @@ jobs: clang-format-linter: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: tj-actions/changed-files@v47 diff --git a/.github/workflows/eamxx-sa-coverage.yml b/.github/workflows/eamxx-sa-coverage.yml index 7b7f86665459..6d65ab748bf6 100644 --- a/.github/workflows/eamxx-sa-coverage.yml +++ b/.github/workflows/eamxx-sa-coverage.yml @@ -27,7 +27,7 @@ jobs: name: gcc-openmp / cov steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false @@ -47,7 +47,7 @@ jobs: name: gcc-cuda / cov steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false diff --git a/.github/workflows/eamxx-sa-sanitizer.yml b/.github/workflows/eamxx-sa-sanitizer.yml index eb64f43d8a46..bcd6dec0e438 100644 --- a/.github/workflows/eamxx-sa-sanitizer.yml +++ b/.github/workflows/eamxx-sa-sanitizer.yml @@ -27,7 +27,7 @@ jobs: name: gcc-openmp / valg steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false @@ -51,7 +51,7 @@ jobs: name: gcc-cuda / ${{ matrix.build_type }} steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false diff --git a/.github/workflows/eamxx-sa-testing.yml b/.github/workflows/eamxx-sa-testing.yml index 9c030ba1d2cf..babf8f8b463f 100644 --- a/.github/workflows/eamxx-sa-testing.yml +++ b/.github/workflows/eamxx-sa-testing.yml @@ -86,7 +86,7 @@ jobs: name: gcc-openmp / ${{ matrix.build_type }} steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false @@ -126,7 +126,7 @@ jobs: name: gcc-cuda / ${{ matrix.test.build_type }} steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false diff --git a/.github/workflows/eamxx-scripts-tests.yml b/.github/workflows/eamxx-scripts-tests.yml index fdec1d06ab9f..08cc61b118de 100644 --- a/.github/workflows/eamxx-scripts-tests.yml +++ b/.github/workflows/eamxx-scripts-tests.yml @@ -40,7 +40,7 @@ jobs: runs-on: [self-hosted, gcc, ghci-snl-cpu] steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false diff --git a/.github/workflows/eamxx-v1-testing.yml b/.github/workflows/eamxx-v1-testing.yml index 0fd2d3db068e..432d46b7037c 100644 --- a/.github/workflows/eamxx-v1-testing.yml +++ b/.github/workflows/eamxx-v1-testing.yml @@ -83,7 +83,7 @@ jobs: name: cpu-gcc / ${{ matrix.test.short_name }} steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false show-progress: false From a366dd81229f68ad7322a6a249c66267a8eb9d08 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 20 Feb 2024 12:58:16 -0600 Subject: [PATCH 036/398] Add Momentum coupling variables passed from driver to MPAS-O --- components/mpas-ocean/driver/mpaso_cpl_indices.F | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/mpas-ocean/driver/mpaso_cpl_indices.F b/components/mpas-ocean/driver/mpaso_cpl_indices.F index 9c2d735b648b..77ab3ff269cb 100644 --- a/components/mpas-ocean/driver/mpaso_cpl_indices.F +++ b/components/mpas-ocean/driver/mpaso_cpl_indices.F @@ -137,6 +137,13 @@ module mpaso_cpl_indices integer :: index_x2o_Sw_Hs ! Significant wave height integer :: index_x2o_Sw_Fp ! Peak wave frequency integer :: index_x2o_Sw_Dp ! Peak wave direction + integer :: index_x2o_Sw_Charn !Charnock coefficient accounting for the wave stress + integer :: index_x2o_Faww_Tawx !Wave supported stress + integer :: index_x2o_Faww_Tawy !Wave supported stress + integer :: index_x2o_Fwow_Twox !Wave to Ocean momentum flux + integer :: index_x2o_Fwow_Twoy !Wave to Ocean momentum flux + integer :: index_x2o_Faow_Tocx !Wave Net Ocean momentum flux + integer :: index_x2o_Faow_Tocy !Wave Net Ocean momentum flux ! drv -> glc and internal drv fields @@ -357,6 +364,13 @@ subroutine mpaso_cpl_indices_set( ) index_x2o_Sw_Hs = mct_avect_indexra(x2o,'Sw_Hs') index_x2o_Sw_Fp = mct_avect_indexra(x2o,'Sw_Fp') index_x2o_Sw_Dp = mct_avect_indexra(x2o,'Sw_Dp') + index_x2o_Sw_Charn = mct_avect_indexra(x2o,'Sw_Charn') + index_x2o_Faww_Tawx = mct_avect_indexra(x2o,'Faww_Tawx') + index_x2o_Faww_Tawy = mct_avect_indexra(x2o,'Faww_Tawy') + index_x2o_Fwow_Twox = mct_avect_indexra(x2o,'Fwow_Twox') + index_x2o_Fwow_Twoy = mct_avect_indexra(x2o,'Fwow_Twoy') + index_x2o_Faow_Tocx = mct_avect_indexra(x2o,'Faow_Tocx') + index_x2o_Faow_Tocy = mct_avect_indexra(x2o,'Faow_Tocy') endif call mct_aVect_clean(x2o) call mct_aVect_clean(o2x) From 9e5309dc3f186094b9135f3f36736b83f7d96979 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 20 Feb 2024 13:33:36 -0600 Subject: [PATCH 037/398] Add wave momentum coupling variablesfrom drivert to ocn_comp_mct --- components/mpas-ocean/driver/ocn_comp_mct.F | 83 ++++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/components/mpas-ocean/driver/ocn_comp_mct.F b/components/mpas-ocean/driver/ocn_comp_mct.F index 1a45b3d5d0f8..8840c770317c 100644 --- a/components/mpas-ocean/driver/ocn_comp_mct.F +++ b/components/mpas-ocean/driver/ocn_comp_mct.F @@ -2133,9 +2133,16 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ landIceHeatFluxField, & landIceFractionField, & windSpeed10mField, & - significantWaveHeightField, & + significantWaveHeightField, & peakWaveFrequencyField, & - peakWaveDirectionField + peakWaveDirectionField, & + charnockSeaStateField, & + waveSupportedZonalWindStressField, & + waveSupportedMeridionalWindStressField, & + waveToOceanZonalWindStressField, & + waveToOceanMeridionalWindStressField, & + waveNetOceanZonalWindStressField, & + waveNetOceanMeridionalWindStressField !landIcePressureField type (field2DReal), pointer :: iceFluxPhytoCField, & @@ -2187,7 +2194,14 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ windSpeed10m, & significantWaveHeight, & peakWaveFrequency, & - peakWaveDirection + peakWaveDirection, & + charnockSeaState, & + waveSupportedZonalWindStress, & + waveSupportedMeridionalWindStress, & + waveToOceanZonalWindStress, & + waveToOceanMeridionalWindStress, & + waveNetOceanZonalWindStress, & + waveNetOceanMeridionalWindStress !landIcePressure real (kind=RKIND), dimension(:), pointer :: latCell @@ -2286,6 +2300,13 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ call mpas_pool_get_field(forcingPool, 'significantWaveHeight', significantWaveHeightField) call mpas_pool_get_field(forcingPool, 'peakWaveFrequency', peakWaveFrequencyField) call mpas_pool_get_field(forcingPool, 'peakWaveDirection', peakWaveDirectionField) + call mpas_pool_get_field(forcingPool, 'charnockSeaState', charnockSeaStateField) + call mpas_pool_get_field(forcingPool, 'waveSupportedZonalWindStress', waveSupportedZonalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveSupportedMeridionalWindStress', waveSupportedMeridionalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveToOceanZonalWindStress', waveToOceanZonalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveToOceanMeridionalWindStress', waveToOceanMeridionalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveNetOceanZonalWindStress', waveNetOceanZonalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveNetOceanMeridionalWindStress', waveNetOceanMeridionalWindStressField) call mpas_pool_get_field(forcingPool, 'landIceFreshwaterFlux', landIceFreshwaterFluxField) call mpas_pool_get_field(forcingPool, 'landIceHeatFlux', landIceHeatFluxField) @@ -2332,6 +2353,13 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ significantWaveHeight => significantWaveHeightField % array peakWaveFrequency => peakWaveFrequencyField % array peakWaveDirection => peakWaveDirectionField % array + charnockSeaState => charnockSeaStateField % array + waveSupportedZonalWindStress => waveSupportedZonalWindStressField % array + waveSupportedMeridionalWindStress => waveSupportedMeridionalWindStressField % array + waveToOceanZonalWindStress => waveToOceanZonalWindStressField % array + waveToOceanMeridionalWindStress => waveToOceanMeridionalWindStressField % array + waveNetOceanZonalWindStress => waveNetOceanZonalWindStressField % array + waveNetOceanMeridionalWindStress => waveNetOceanMeridionalWindStressField % array !landIcePressure => landIcePressureField % array call mpas_pool_get_array(meshPool, 'latCell', latCell) @@ -2542,6 +2570,27 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ if ( peakWaveDirectionField % isActive ) then peakWaveDirection(i) = x2o_o % rAttr(index_x2o_Sw_Dp, n) end if + if ( charnockSeaStateField % isActive ) then + charnockSeaState(i) = x2o_o % rAttr(index_x2o_Sw_Charn, n) + end if + if ( waveSupportedZonalWindStressField % isActive ) then + waveSupportedZonalWindStress(i) = x2o_o % rAttr(index_x2o_Faww_Tawx, n) + end if + if ( waveSupportedMeridionalWindStressField % isActive ) then + waveSupportedMeridionalWindStress(i) = x2o_o % rAttr(index_x2o_Faww_Tawy, n) + end if + if ( waveToOceanZonalWindStressField % isActive ) then + waveToOceanZonalWindStress(i) = x2o_o % rAttr(index_x2o_Fwow_Twox, n) + end if + if ( waveToOceanMeridionalWindStressField % isActive ) then + waveToOceanMeridionalWindStress(i) = x2o_o % rAttr(index_x2o_Fwow_Twoy, n) + end if + if ( waveNetOceanZonalWindStressField % isActive ) then + waveNetOceanZonalWindStress(i) = x2o_o % rAttr(index_x2o_Faow_Tocx, n) + end if + if ( waveNetOceanMeridionalWindStressField % isActive ) then + waveNetOceanMeridionalWindStress(i) = x2o_o % rAttr(index_x2o_Faow_Tocy, n) + end if endif if (config_cvmix_kpp_use_theory_wave .or. config_eke_correction_enable) then @@ -2720,6 +2769,13 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ call mpas_pool_get_field(forcingPool, 'significantWaveHeight', significantWaveHeightField) call mpas_pool_get_field(forcingPool, 'peakWaveFrequency', peakWaveFrequencyField) call mpas_pool_get_field(forcingPool, 'peakWaveDirection', peakWaveDirectionField) + call mpas_pool_get_field(forcingPool, 'charnockSeaState', charnockSeaStateField) + call mpas_pool_get_field(forcingPool, 'waveSupportedZonalWindStress', waveSupportedZonalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveSupportedMeridionalWindStress', waveSupportedMeridionalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveToOceanZonalWindStress', waveToOceanZonalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveToOceanMeridionalWindStress', waveToOceanMeridionalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveNetOceanZonalWindStress', waveNetOceanZonalWindStressField) + call mpas_pool_get_field(forcingPool, 'waveNetOceanMeridionalWindStress', waveNetOceanMeridionalWindStressField) call mpas_pool_get_field(forcingPool, 'landIceFreshwaterFlux', landIceFreshwaterFluxField) call mpas_pool_get_field(forcingPool, 'landIceHeatFlux', landIceHeatFluxField) @@ -2856,6 +2912,27 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ if ( peakWaveDirectionField % isActive ) then call mpas_dmpar_exch_halo_field(peakWaveDirectionField) end if + if ( charnockSeaStateField % isActive ) then + call mpas_dmpar_exch_halo_field(charnockSeaStateField) + end if + if ( waveSupportedZonalWindStressField % isActive ) then + call mpas_dmpar_exch_halo_field(waveSupportedZonalWindStressField) + end if + if ( waveSupportedMeridionalWindStressField % isActive ) then + call mpas_dmpar_exch_halo_field(waveSupportedMeridionalWindStressField) + end if + if ( waveToOceanZonalWindStressField % isActive ) then + call mpas_dmpar_exch_halo_field(waveToOceanZonalWindStressField) + end if + if ( waveToOceanMeridionalWindStressField % isActive ) then + call mpas_dmpar_exch_halo_field(waveToOceanMeridionalWindStressField) + end if + if ( waveNetOceanZonalWindStressField % isActive ) then + call mpas_dmpar_exch_halo_field(waveNetOceanZonalWindStressField) + end if + if ( waveNetOceanMeridionalWindStressField % isActive ) then + call mpas_dmpar_exch_halo_field(waveNetOceanMeridionalWindStressField) + end if if ( landIceFreshwaterFluxField % isActive ) then call mpas_dmpar_exch_halo_field(landIceFreshwaterFluxField) From 631b90a5b9eead16ffa9bc7c555e2439c95e9a09 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 20 Feb 2024 13:36:39 -0600 Subject: [PATCH 038/398] add Wave momentum coupling variable to MPAS-O Registry --- components/mpas-ocean/src/Registry.xml | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/components/mpas-ocean/src/Registry.xml b/components/mpas-ocean/src/Registry.xml index bcf270172826..f49ad5a3fc8a 100644 --- a/components/mpas-ocean/src/Registry.xml +++ b/components/mpas-ocean/src/Registry.xml @@ -4062,6 +4062,34 @@ + + + + + + + Date: Tue, 20 Feb 2024 13:52:19 -0600 Subject: [PATCH 039/398] Add wave to driver momentum coupling variables --- components/ww3/src/cpl/wav_comp_mct.F90 | 28 ++++++++++++++++++++-- components/ww3/src/cpl/ww3_cpl_indices.f90 | 15 +++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index f83fec41809b..d221573e0141 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -136,7 +136,8 @@ MODULE WAV_COMP_MCT sig, nk, zb, dmin, & usspf use w3wdatmd, only: time, w3ndat, w3setw, wlv, va, ust, ice - use w3adatmd, only: ussp, w3naux, w3seta, sxx, sxy, syy, fliwnd, flcold, dw, cg, wn, hs, fp0, thp0 + use w3adatmd, only: ussp, w3naux, w3seta, sxx, sxy, syy, fliwnd, flcold, dw, cg, wn, hs, fp0, thp0, & + charn, tauwix, tauwiy, tauox, tauoy, tauocx, tauocy use w3idatmd, only: inflags1, inflags2,w3seti, w3ninp USE W3IDATMD, ONLY: TC0, CX0, CY0, TCN, CXN, CYN, ICEP1, ICEP5, TI1, TI5 USE W3IDATMD, ONLY: TW0, WX0, WY0, DT0, TWN, WXN, WYN, DTN @@ -174,7 +175,9 @@ MODULE WAV_COMP_MCT index_w2x_Sw_ustokes_wavenumber_4, index_w2x_Sw_vstokes_wavenumber_4, & index_w2x_Sw_ustokes_wavenumber_5, index_w2x_Sw_vstokes_wavenumber_5, & index_w2x_Sw_ustokes_wavenumber_6, index_w2x_Sw_vstokes_wavenumber_6, & - index_w2x_Sw_Hs, index_w2x_Sw_Fp, index_w2x_Sw_Dp + index_w2x_Sw_Hs, index_w2x_Sw_Fp, index_w2x_Sw_Dp, index_w2x_Sw_Charn, & + index_w2x_Faww_Tawx, index_w2x_Faww_Tawy, index_w2x_Fwow_Twox, & + index_w2x_Fwow_Twoy, index_w2x_Faow_Tocx, index_w2x_Faow_Tocy use shr_sys_mod , only : shr_sys_flush, shr_sys_abort @@ -722,6 +725,7 @@ SUBROUTINE WAV_INIT_MCT( EClock, cdata, x2w_w, w2x_w, NLFilename ) ! F F 6 10 TAUICE TWI Wave to sea ice stress ! F F 6 11 PHICE FIC Wave to sea ice energy flux ! F F 6 12 USSP USP Partitioned surface Stokes drift + ! F F 6 13 TAUOC[X,Y] TOC Total momentum to the ocean ! ------------------------------------------------- ! 7 Wave-bottom layer ! ------------------------------------------------- @@ -1166,6 +1170,10 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) do i = 1,usspf(2) call w3xyrtn(nseal,USSP(1:nseal,i),USSP(1:nseal,nk+i),AnglDL) enddo + ! rotate surface stress variables for momentum coupling + call w3xyrtn(nseal, TAUWIX(1:nseal), TAUWIY(1:nseal), AnglDL) + call w3xyrtn(nseal, TAUOX(1:nseal), TAUOY(1:nseal), AnglDL) + call w3xyrtn(nseal, TAUOCX(1:nseal), TAUOCY(1:nseal), AnglDL) ! copy ww3 data to coupling datatype do jsea=1, nseal @@ -1196,6 +1204,14 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = USSP(jsea,6) w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = USSP(jsea,nk+6) + + w2x_w%rattr(index_w2x_Sw_Charn,jsea) = CHARN(jsea) + w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) + w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) + w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) + w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 1000*TAUOY(jsea) + w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = TAUOCX(jsea) + w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) endif else if (wav_ocn_coup .eq. 'twoway') then @@ -1220,6 +1236,14 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = 0.0 w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = 0.0 + + w2x_w%rattr(index_w2x_Sw_Charn,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 0.0 + w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 0.0 + w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = 0.0 endif endif enddo diff --git a/components/ww3/src/cpl/ww3_cpl_indices.f90 b/components/ww3/src/cpl/ww3_cpl_indices.f90 index 9dafd32a455f..a6bb91a00a86 100644 --- a/components/ww3/src/cpl/ww3_cpl_indices.f90 +++ b/components/ww3/src/cpl/ww3_cpl_indices.f90 @@ -36,6 +36,13 @@ module ww3_cpl_indices integer :: index_w2x_Sw_Hs integer :: index_w2x_Sw_Fp integer :: index_w2x_Sw_Dp + integer :: index_w2x_Sw_Charn + integer :: index_w2x_Faww_Tawx + integer :: index_w2x_Faww_Tawy + integer :: index_w2x_Fwow_Twox + integer :: index_w2x_Fwow_Twoy + integer :: index_w2x_Faow_Tocx + integer :: index_w2x_Faow_Tocy contains @@ -67,7 +74,6 @@ subroutine ww3_cpl_indices_set( ) index_w2x_Sw_Hs = mct_avect_indexra(w2x,'Sw_Hs') ! Significant wave height index_w2x_Sw_Fp = mct_avect_indexra(w2x,'Sw_Fp') ! Peak wave freqency index_w2x_Sw_Dp = mct_avect_indexra(w2x,'Sw_Dp') ! Peak wave direction - index_w2x_Sw_ustokes_wavenumber_1 = mct_avect_indexra(w2x,'Sw_ustokes_wavenumber_1') ! partitioned Stokes drift u 1 index_w2x_Sw_vstokes_wavenumber_1 = mct_avect_indexra(w2x,'Sw_vstokes_wavenumber_1') ! partitioned Stokes drift v 1 index_w2x_Sw_ustokes_wavenumber_2 = mct_avect_indexra(w2x,'Sw_ustokes_wavenumber_2') ! partitioned Stokes drift u 2 @@ -80,6 +86,13 @@ subroutine ww3_cpl_indices_set( ) index_w2x_Sw_vstokes_wavenumber_5 = mct_avect_indexra(w2x,'Sw_vstokes_wavenumber_5') ! partitioned Stokes drift v 5 index_w2x_Sw_ustokes_wavenumber_6 = mct_avect_indexra(w2x,'Sw_ustokes_wavenumber_6') ! partitioned Stokes drift u 6 index_w2x_Sw_vstokes_wavenumber_6 = mct_avect_indexra(w2x,'Sw_vstokes_wavenumber_6') ! partitioned Stokes drift v 6 + index_w2x_Sw_Charn = mct_avect_indexra(w2x,'Sw_Charn') ! Charnock coeff accounting for the wave stress (Janssen 1989, 1991) + index_w2x_Faww_Tawx = mct_avect_indexra(w2x,'Faww_Tawx') ! Zonal Wave supported stress (Stress from atmosphere to waves) + index_w2x_Faww_Tawy = mct_avect_indexra(w2x,'Faww_Tawy') ! Meridional Wave supported stress (Stress from atmosphere to waves) + index_w2x_Fwow_Twox = mct_avect_indexra(w2x,'Fwow_Twox') ! Zonal Wave to ocean stress (Not total ocean momentum stress ) + index_w2x_Fwow_Twoy = mct_avect_indexra(w2x,'Fwow_Twoy') ! MeridionalWave to ocean stress (Not total ocean momentum stress) + index_w2x_Faow_Tocx = mct_avect_indexra(w2x,'Faow_Tocx') ! Zonal Net ocean stress (total ocean momentum stress ) + index_w2x_Faow_Tocy = mct_avect_indexra(w2x,'Faow_Tocy') !Meridional Net ocean stress (total ocean momentum stress) endif call mct_aVect_clean(x2w) call mct_aVect_clean(w2x) From da0e96b1cdde3d02e47877d8c8903ae5d9e9ee5c Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 20 Feb 2024 14:00:33 -0600 Subject: [PATCH 040/398] Add wave momentum coupling stress variables to seq_flds_mod --- driver-mct/shr/seq_flds_mod.F90 | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 467246698330..1f4fd998fb71 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -2666,6 +2666,64 @@ subroutine seq_flds_set(nmlfile, ID, infodata) units = 'deg' attname = 'Sw_Dp' call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faww_Tawx') + call seq_flds_add(x2o_fluxes,'Faww_Tawx') + longname = 'Zonal wave supported stress' + stdname = 'Zonal_wave_supported_stress' + units = 'N m-2' + attname = 'Faww_Tawx' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faww_Tawy') + call seq_flds_add(x2o_fluxes,'Faww_Tawy') + longname = 'Meridional wave supported wind stress' + stdname = 'Meridional_wave_supported_wind_stress' + units = 'N m-2' + attname = 'Faww_Tawy' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Fwow_Twox') + call seq_flds_add(x2o_fluxes,'Fwow_Twox') + longname = 'Zonal wave to ocean wind stress' + stdname = 'Zonal_wave_to_ocean_wind_stress' + units = 'N m-2' + attname = 'Fwow_Twox' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Fwow_Twoy') + call seq_flds_add(x2o_fluxes,'Fwow_Twoy') + longname = 'Meridional wave to ocean wind stress' + stdname = 'Meridional_wave_to_ocean_wind_stress' + units = 'N m-2' + attname = 'Fwow_Twoy' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faow_Tocx') + call seq_flds_add(x2o_fluxes,'Faow_Tocx') + longname = 'Zonal Net ocean wind stress by wave model' + stdname = 'Zonal_net_ocean_wind_stress_wavemodel' + units = 'N m-2' + attname = 'Faow_Tocx' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faow_Tocy') + call seq_flds_add(x2o_fluxes,'Faow_Tocy') + longname = 'Meridional Net ocean wind stress by wave model' + stdname = 'Meridional_net_ocean_wind_stress_wavemodel' + units = 'N m-2' + attname = 'Faow_Tocy' + call metadata_set(attname, longname, stdname, units) + endif + + if (wav_ocn_coup == 'twoway') then + call seq_flds_add(w2x_states,'Sw_Charn') + call seq_flds_add(x2o_states,'Sw_Charn') + longname = 'Charnock coefficent based on sea state' + stdname = 'Charnock_coefficent_based_on_sea_state' + units = '' + attname = 'Sw_Charn' + call metadata_set(attname, longname, stdname, units) endif !---------------------------- From d4f2cfcd5b3d5e482248d46fe1262c90f9d26a67 Mon Sep 17 00:00:00 2001 From: Olawale Ikuyajolu Date: Sat, 23 Apr 2022 10:44:40 -0500 Subject: [PATCH 041/398] Add charnock SeaState to shr_flux_mod --- share/util/shr_flux_mod.F90 | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index cb62a489fde3..7046909ec54b 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -150,7 +150,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & & taux ,tauy ,tref ,qref , & & ocn_surface_flux_scheme, & & duu10n, u10res, ustar_sv ,re_sv ,ssq_sv, & - & missval, wsresp, tau_est, ugust) + & missval, wsresp, tau_est, ugust, charnockSeaState) ! !USES: @@ -205,6 +205,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & real(R8),intent(in) ,optional :: wsresp(nMax) ! boundary layer wind response to stress (m/s/Pa) real(R8),intent(in) ,optional :: tau_est(nMax) ! stress in equilibrium with boundary layer (Pa) real(R8),intent(in) ,optional :: ugust(nMax) ! extra wind speed from gustiness (m/s) + real(R8),intent(in) ,optional :: charnockSeaState(nMax) !Charnock coeff accounting for the wave stress (Janssen 1989, 1991) ! !EOP @@ -547,9 +548,9 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & & ,zo,zot,zoq,hol,ustar,tstar,qstar & ! out: ss scales & ,rd,rh,re & ! out: exch. coeffs & ,trf,qrf,urf,vrf & ! out: reference-height params - & ,wsresp(n),tau_est(n)) ! in: optional stress params + & ,wsresp(n),tau_est(n) & ! in: optional stress params for the sake of maintaining same defs + & ,charnockSeaState(n)) ! in: optional charnock sea state -! for the sake of maintaining same defs hol=zbot(n)/hol rd=sqrt(rd) rh=sqrt(rh) @@ -2513,9 +2514,10 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params & ,zo,zot,zoq,L,usr,tsr,qsr & ! out: ss scales & ,Cd,Ch,Ce & ! out: exch. coeffs & ,trf,qrf,urf,vrf & ! out: reference-height params - & ,wsresp,tau_est) ! in: optional stress params + & ,wsresp,tau_est & ! in: optional stress params + & ,charnsea) ! in: optional charnock sea state -! !USES: +!USES: IMPLICIT NONE @@ -2526,6 +2528,8 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params real(R8),intent(out):: tau,hsb,hlb,zo,zot,zoq,L,usr,tsr,qsr,Cd,Ch,Ce & & ,trf,qrf,urf,vrf real(R8),intent(in),optional:: wsresp,tau_est +real(R8),intent(in) ,optional :: charnsea !Charnock coeff accounting for the wave stress (Janssen 1989, 1991) + ! !EOP real(R8) ua,va,ta,q,rb,us,vs,ts,qs,zi,zu,zt,zq,zru,zrq,zrt ! internal vars @@ -2633,13 +2637,14 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params qsr = (dq-dqer*jcool)*von/(log(zq/zot10)-psit_30(zq/L10)) ! parametrisation for Charney parameter (section 3c of Fairall et al. 2003) - charn=0.011_R8 + !charn=0.011_R8 if (ut .GT. 10.0_R8) then - charn=0.011_R8+(ut-10.0_R8)/(18.0_R8-10.0_R8)*(0.018_R8-0.011_R8) + !charn=0.011_R8+(ut-10.0_R8)/(18.0_R8-10.0_R8)*(0.018_R8-0.011_R8) endif if (ut .GT. 18.0_R8) then - charn=0.018_R8 + !charn=0.018_R8 endif + charn = charnsea !use Charnock coefficient accounting for the wave stress (Janssen 1989, 1991) if (present(wsresp) .and. present(tau_est)) prev_tau = tau_est tau_diff = 1.e100_R8 From 1abb424bb502c6465ff6d5d8848e901bc59853a7 Mon Sep 17 00:00:00 2001 From: Olawale Ikuyajolu Date: Sun, 24 Apr 2022 15:42:12 -0500 Subject: [PATCH 042/398] Couple atm and wave through charnock sea state --- driver-mct/main/cime_comp_mod.F90 | 15 +++-- driver-mct/main/prep_atm_mod.F90 | 97 +++++++++++++++++++++++++++++-- driver-mct/main/seq_flux_mct.F90 | 18 +++++- 3 files changed, 117 insertions(+), 13 deletions(-) diff --git a/driver-mct/main/cime_comp_mod.F90 b/driver-mct/main/cime_comp_mod.F90 index 07de7462d4ec..4d177e4c4d5f 100644 --- a/driver-mct/main/cime_comp_mod.F90 +++ b/driver-mct/main/cime_comp_mod.F90 @@ -70,7 +70,7 @@ module cime_comp_mod use seq_comm_mct, only: CPLATMID,CPLLNDID,CPLOCNID,CPLICEID,CPLGLCID,CPLROFID,CPLWAVID,CPLESPID use seq_comm_mct, only: IACID, ALLIACID, CPLALLIACID, CPLIACID use seq_comm_mct, only: num_inst_atm, num_inst_lnd, num_inst_rof - use seq_comm_mct, only: num_inst_ocn, num_inst_ice, num_inst_glc + use seq_comm_mct, only: num_inst_ocn, num_inst_ice, num_inst_glc, num_inst_wav use seq_comm_mct, only: num_inst_wav, num_inst_esp use seq_comm_mct, only: num_inst_iac use seq_comm_mct, only: num_inst_xao, num_inst_frc, num_inst_phys @@ -256,11 +256,13 @@ module cime_comp_mod !- from prep routines (arrays of instances) type(mct_aVect) , pointer :: a2x_ox(:) => null() type(mct_aVect) , pointer :: o2x_ax(:) => null() + type(mct_aVect) , pointer :: w2x_ax(:) => null() type(mct_aVect) , pointer :: xao_ox(:) => null() type(mct_aVect) , pointer :: xao_ax(:) => null() !- from component type (single instance inside array of components) type(mct_aVect) , pointer :: o2x_ox => null() + type(mct_aVect) , pointer :: w2x_ox(:) => null() type(mct_aVect) , pointer :: a2x_ax => null() character(len=CL) :: inst_suffix @@ -436,6 +438,7 @@ module cime_comp_mod logical :: lnd_c2_rof ! .true. => lnd to rof coupling on logical :: lnd_c2_glc ! .true. => lnd to glc coupling on logical :: ocn_c2_atm ! .true. => ocn to atm coupling on + logical :: wav_c2_atm ! .true. => wav to atm coupling on logical :: ocn_c2_ice ! .true. => ocn to ice coupling on logical :: ocn_c2_glctf ! .true. => ocn to glc thermal forcing coupling on integer :: glc_nzoc ! number of z-levels for ocn/glc TF coupling @@ -2046,7 +2049,7 @@ subroutine cime_init() call t_adj_detailf(+2) if (drv_threading) call seq_comm_setnthreads(nthreads_CPLID) - call prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_atm) + call prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_lnd, wav_c2_atm) call prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_lnd) @@ -3882,11 +3885,13 @@ subroutine cime_run_atmocn_fluxes(hashint) do exi = 1,num_inst_xao eai = mod((exi-1),num_inst_atm) + 1 eoi = mod((exi-1),num_inst_ocn) + 1 + ewi = mod((exi-1),num_inst_wav) + 1 efi = mod((exi-1),num_inst_frc) + 1 a2x_ax => component_get_c2x_cx(atm(eai)) o2x_ax => prep_atm_get_o2x_ax() ! array over all instances + w2x_ax => prep_atm_get_w2x_ax() ! array over all instances xao_ax => prep_aoflux_get_xao_ax() ! array over all instances - call seq_flux_atmocn_mct(infodata, tod, dtime, a2x_ax, o2x_ax(eoi), xao_ax(exi)) + call seq_flux_atmocn_mct(infodata, tod, dtime, a2x_ax, o2x_ax(eoi), xao_ax(exi), w2x_ax(ewi)) enddo call t_drvstopf ('CPL:atmocna_fluxa',hashint=hashint(6)) @@ -3902,10 +3907,12 @@ subroutine cime_run_atmocn_fluxes(hashint) eai = mod((exi-1),num_inst_atm) + 1 eoi = mod((exi-1),num_inst_ocn) + 1 efi = mod((exi-1),num_inst_frc) + 1 + ewi = mod((exi-1),num_inst_wav) + 1 a2x_ox => prep_ocn_get_a2x_ox() + w2x_ox => prep_ocn_get_w2x_ox() o2x_ox => component_get_c2x_cx(ocn(eoi)) xao_ox => prep_aoflux_get_xao_ox() - call seq_flux_atmocn_mct(infodata, tod, dtime, a2x_ox(eai), o2x_ox, xao_ox(exi)) + call seq_flux_atmocn_mct(infodata, tod, dtime, a2x_ox(eai), o2x_ox, xao_ox(exi), w2x_ox(ewi)) enddo call t_drvstopf ('CPL:atmocnp_fluxo',hashint=hashint(6)) endif ! aoflux_grid diff --git a/driver-mct/main/prep_atm_mod.F90 b/driver-mct/main/prep_atm_mod.F90 index eafdc45c1758..674a1f725433 100644 --- a/driver-mct/main/prep_atm_mod.F90 +++ b/driver-mct/main/prep_atm_mod.F90 @@ -4,8 +4,8 @@ module prep_atm_mod use shr_kind_mod, only: cs => SHR_KIND_CS use shr_kind_mod, only: cl => SHR_KIND_CL use shr_sys_mod, only: shr_sys_abort, shr_sys_flush - use seq_comm_mct, only: num_inst_atm, num_inst_ocn, num_inst_ice, num_inst_lnd, num_inst_xao, & - num_inst_frc, num_inst_max, num_inst_iac, CPLID, ATMID, logunit + use seq_comm_mct, only: num_inst_atm, num_inst_ocn, num_inst_ice, num_inst_lnd, num_inst_wav, & + num_inst_xao, num_inst_frc, num_inst_max, num_inst_iac, CPLID, ATMID, logunit use seq_comm_mct, only: seq_comm_getData=>seq_comm_setptrs use seq_infodata_mod, only: seq_infodata_type, seq_infodata_getdata use seq_map_type_mod @@ -15,7 +15,7 @@ module prep_atm_mod use mct_mod use perf_mod use component_type_mod, only: component_get_x2c_cx, component_get_c2x_cx - use component_type_mod, only: atm, lnd, ocn, ice, iac + use component_type_mod, only: atm, lnd, ocn, ice, wav, iac implicit none save @@ -31,15 +31,18 @@ module prep_atm_mod public :: prep_atm_get_l2x_ax public :: prep_atm_get_i2x_ax public :: prep_atm_get_o2x_ax + public :: prep_atm_get_w2x_ax public :: prep_atm_get_z2x_ax public :: prep_atm_calc_l2x_ax public :: prep_atm_calc_i2x_ax public :: prep_atm_calc_o2x_ax + public :: prep_atm_calc_w2x_ax public :: prep_atm_calc_z2x_ax public :: prep_atm_get_mapper_So2a public :: prep_atm_get_mapper_Fo2a + public :: prep_atm_get_mapper_Sw2a public :: prep_atm_get_mapper_Sl2a public :: prep_atm_get_mapper_Fl2a public :: prep_atm_get_mapper_Si2a @@ -58,6 +61,7 @@ module prep_atm_mod ! mappers type(seq_map), pointer :: mapper_So2a + type(seq_map), pointer :: mapper_Sw2a type(seq_map), pointer :: mapper_Sl2a type(seq_map), pointer :: mapper_Si2a type(seq_map), pointer :: mapper_Sz2a @@ -70,6 +74,7 @@ module prep_atm_mod type(mct_aVect), pointer :: l2x_ax(:) ! Lnd export, atm grid, cpl pes - allocated in driver type(mct_aVect), pointer :: i2x_ax(:) ! Ice export, atm grid, cpl pes - allocated in driver type(mct_aVect), pointer :: o2x_ax(:) ! Ocn export, atm grid, cpl pes - allocated in driver + type(mct_aVect), pointer :: w2x_ax(:) ! Wav export, atm grid, cpl pes -allocated in driver type(mct_aVect), pointer :: z2x_ax(:) ! Iac export, atm grid, cpl pes - allocated in driver ! other module variables @@ -82,7 +87,7 @@ module prep_atm_mod !================================================================================================ - subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_atm) + subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_atm, wav_c2_atm) !--------------------------------------------------------------- ! Description @@ -94,22 +99,27 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at logical , intent(in) :: ice_c2_atm ! .true. => ice to atm coupling on logical , intent(in) :: lnd_c2_atm ! .true. => lnd to atm coupling on logical , intent(in) :: iac_c2_atm ! .true. => iac to atm coupling on + logical , intent(in) :: wav_c2_atm ! .true. => wav to atm coupling on + ! ! Local Variables integer :: lsize_a - integer :: eli, eii, emi, ezi + integer :: eli, eii, emi, ezi, ewi logical :: samegrid_ao ! samegrid atm and ocean logical :: samegrid_az ! samegrid atm and iac + logical :: samegrid_aw ! samegrid atm and wave logical :: esmf_map_flag ! .true. => use esmf for mapping logical :: atm_present ! .true. => atm is present logical :: ocn_present ! .true. => ocn is present logical :: ice_present ! .true. => ice is present logical :: lnd_present ! .true. => lnd is prsent logical :: iac_present ! .true. => iac is prsent + logical :: wav_present ! .true. => wav is prsent character(CL) :: ocn_gnam ! ocn grid character(CL) :: atm_gnam ! atm grid character(CL) :: lnd_gnam ! lnd grid character(CL) :: iac_gnam ! iac grid + character(CL) :: wav_gnam ! wav grid type(mct_avect), pointer :: a2x_ax character(*), parameter :: subname = '(prep_atm_init)' character(*), parameter :: F00 = "('"//subname//" : ', 4A )" @@ -121,13 +131,16 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at ice_present=ice_present, & lnd_present=lnd_present, & iac_present=iac_present, & + wav_present=wav_present, & atm_gnam=atm_gnam, & ocn_gnam=ocn_gnam, & lnd_gnam=lnd_gnam, & iac_gnam=iac_gnam, & + wav_gnam=wav_gnam, & esmf_map_flag=esmf_map_flag) allocate(mapper_So2a) + allocate(mapper_Sw2a) allocate(mapper_Sl2a) allocate(mapper_Si2a) allocate(mapper_Fo2a) @@ -153,6 +166,13 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at call mct_aVect_init(o2x_ax(emi), rList=seq_flds_o2x_fields, lsize=lsize_a) call mct_aVect_zero(o2x_ax(emi)) enddo + + allocate(w2x_ax(num_inst_wav)) + do ewi = 1,num_inst_wav + call mct_aVect_init(w2x_ax(ewi), rList=seq_flds_w2x_fields,lsize=lsize_a) + call mct_aVect_zero(w2x_ax(ewi)) + end do + allocate(i2x_ax(num_inst_ice)) do eii = 1,num_inst_ice call mct_aVect_init(i2x_ax(eii), rList=seq_flds_i2x_fields, lsize=lsize_a) @@ -167,9 +187,22 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at samegrid_al = .true. samegrid_ao = .true. samegrid_az = .true. + samegrid_aw = .true. if (trim(atm_gnam) /= trim(lnd_gnam)) samegrid_al = .false. if (trim(atm_gnam) /= trim(ocn_gnam)) samegrid_ao = .false. if (trim(atm_gnam) /= trim(iac_gnam)) samegrid_az = .false. + if (trim(atm_gnam) /= trim(wav_gnam)) samegrid_aw = .false. + + if (wav_c2_atm) then + if (iamroot_CPLID) then + write(logunit,*) ' ' + write(logunit,F00) 'Initializing mapper_Sw2a' + end if + call seq_map_init_rcfile(mapper_Sw2a, wav(1), atm(1), & + 'seq_maps.rc','wav2atm_smapname:','wav2atm_smaptype:',samegrid_aw, & + 'mapper_Sw2a initialization',esmf_map_flag) + end if + call shr_sys_flush(logunit) if (ocn_c2_atm) then if (iamroot_CPLID) then @@ -269,7 +302,7 @@ subroutine prep_atm_mrg(infodata, fractions_ax, xao_ax, timer_mrg) character(len=*) , intent(in) :: timer_mrg ! ! Local Variables - integer :: eli, eoi, eii, exi, efi, eai, emi, ezi + integer :: eli, eoi, eii, exi, efi, eai, emi, ezi, ewi type(mct_avect), pointer :: x2a_ax character(*), parameter :: subname = '(prep_atm_mrg)' character(*), parameter :: F00 = "('"//subname//" : ', 4A )" @@ -285,6 +318,7 @@ subroutine prep_atm_mrg(infodata, fractions_ax, xao_ax, timer_mrg) efi = mod((eai-1),num_inst_frc) + 1 emi = mod((eai-1),num_inst_max) + 1 ezi = mod((eai-1),num_inst_iac) + 1 + ewi = mod((eai-1),num_inst_wav) + 1 x2a_ax => component_get_x2c_cx(atm(eai)) ! This is actually modifying x2a_ax call prep_atm_merge(l2x_ax(eli), o2x_ax(emi), xao_ax(exi), & @@ -502,6 +536,7 @@ subroutine prep_atm_merge( l2x_a, o2x_a, xao_a, i2x_a, z2x_a, fractions_a, x2a_a end if end do + ! --- add some checks --- ! --- make sure all terms agree on merge or non-merge aspect --- @@ -523,6 +558,7 @@ subroutine prep_atm_merge( l2x_a, o2x_a, xao_a, i2x_a, z2x_a, fractions_a, x2a_a write(logunit,*) subname,' ERROR: lindx and oindx merge logic error ',trim(itemc_atm(ka)) call shr_sys_abort(subname//' ERROR lindx and oindx merge logic error') endif + if (xindx(ka) > 0 .and. iindx(ka) > 0 .and. (xmerge(ka) .neqv. imerge(ka))) then write(logunit,*) subname,' ERROR: xindx and iindx merge logic error ',trim(itemc_atm(ka)) call shr_sys_abort(subname//' ERROR xindx and iindx merge logic error') @@ -536,6 +572,7 @@ subroutine prep_atm_merge( l2x_a, o2x_a, xao_a, i2x_a, z2x_a, fractions_a, x2a_a call shr_sys_abort(subname//' ERROR iindx and oindx merge logic error') endif + end do end if @@ -800,6 +837,44 @@ subroutine prep_atm_calc_o2x_ax(fractions_ox, timer) end subroutine prep_atm_calc_o2x_ax + + !================================================================================================ + + subroutine prep_atm_calc_w2x_ax(fractions_wx, timer) + !--------------------------------------------------------------- + ! Description + ! Create w2x_ax (note that w2x_ax is a local module variable) + ! + ! Arguments + type(mct_aVect) , optional, intent(in) :: fractions_wx(:) + character(len=*), optional, intent(in) :: timer + ! + ! Local Variables + integer :: eoi, efi, emi, ewi + type(mct_aVect) , pointer :: w2x_ox + character(*), parameter :: subname = '(prep_atm_calc_w2x_ax)' + character(*), parameter :: F00 = "('"//subname//" : ', 4A )" + !--------------------------------------------------------------- + + call t_drvstartf (trim(timer),barrier=mpicom_CPLID) + do emi = 1,num_inst_wav + ewi = mod((emi-1),num_inst_wav) + 1 + efi = mod((emi-1),num_inst_frc) + 1 + + w2x_ox => component_get_c2x_cx(wav(ewi)) + if (present(fractions_wx)) then + call seq_map_map(mapper_Sw2a, w2x_ox, w2x_ax(ewi),& + fldlist=seq_flds_w2x_states,norm=.true., & + avwts_s=fractions_wx(efi),avwtsfld_s='wfrac') + else + call seq_map_map(mapper_Sw2a, w2x_ox, w2x_ax(ewi),& + fldlist=seq_flds_w2x_states,norm=.true.) + endif + enddo + call t_drvstopf (trim(timer)) + + end subroutine prep_atm_calc_w2x_ax + !================================================================================================ subroutine prep_atm_calc_i2x_ax(fractions_ix, timer) @@ -916,6 +991,11 @@ function prep_atm_get_o2x_ax() prep_atm_get_o2x_ax => o2x_ax(:) end function prep_atm_get_o2x_ax + function prep_atm_get_w2x_ax() + type(mct_aVect), pointer :: prep_atm_get_w2x_ax(:) + prep_atm_get_w2x_ax => w2x_ax(:) + end function prep_atm_get_w2x_ax + function prep_atm_get_z2x_ax() type(mct_aVect), pointer :: prep_atm_get_z2x_ax(:) prep_atm_get_z2x_ax => z2x_ax(:) @@ -926,6 +1006,11 @@ function prep_atm_get_mapper_So2a() prep_atm_get_mapper_So2a => mapper_So2a end function prep_atm_get_mapper_So2a + function prep_atm_get_mapper_Sw2a() + type(seq_map), pointer :: prep_atm_get_mapper_Sw2a + prep_atm_get_mapper_Sw2a => mapper_Sw2a + end function prep_atm_get_mapper_Sw2a + function prep_atm_get_mapper_Fo2a() type(seq_map), pointer :: prep_atm_get_mapper_Fo2a prep_atm_get_mapper_Fo2a => mapper_Fo2a diff --git a/driver-mct/main/seq_flux_mct.F90 b/driver-mct/main/seq_flux_mct.F90 index 92782264faae..5835e7688dde 100644 --- a/driver-mct/main/seq_flux_mct.F90 +++ b/driver-mct/main/seq_flux_mct.F90 @@ -46,6 +46,7 @@ module seq_flux_mct real(r8), allocatable :: ubot (:) ! atm velocity, zonal real(r8), allocatable :: vbot (:) ! atm velocity, meridional real(r8), allocatable :: wsresp(:) ! atm response to surface stress + real(r8), allocatable :: charnsea(:) ! Charnock coeff accounting for the wave stress real(r8), allocatable :: tau_est(:)! estimation of tau in equilibrium with wind real(r8), allocatable :: ugust_atm(:) ! atm gustiness real(r8), allocatable :: thbot(:) ! atm potential T @@ -145,6 +146,7 @@ module seq_flux_mct integer :: index_o2x_So_t integer :: index_o2x_So_u integer :: index_o2x_So_v + integer :: index_w2x_Sw_Charn integer :: index_o2x_So_fswpen integer :: index_o2x_So_s integer :: index_o2x_So_roce_16O @@ -295,6 +297,11 @@ subroutine seq_flux_init_mct(comp, fractions) allocate( vocn(nloc),stat=ier) if(ier/=0) call mct_die(subName,'allocate vocn',ier) vocn = 0.0_r8 + + allocate( charnsea(nloc),stat=ier) + if(ier/=0) call mct_die(subName,'allocate charnsea',ier) + charnsea = 0.0_r8 + allocate( tocn(nloc),stat=ier) if(ier/=0) call mct_die(subName,'allocate tocn',ier) tocn = 0.0_r8 @@ -1313,7 +1320,7 @@ end subroutine seq_flux_atmocnexch_mct !=============================================================================== - subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) + subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) !----------------------------------------------------------------------- ! @@ -1323,6 +1330,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) integer(in) , intent(in) :: tod,dt ! NEW type(mct_aVect) , intent(in) :: a2x ! a2x_ax or a2x_ox type(mct_aVect) , intent(in) :: o2x ! o2x_ax or o2x_ox + type(mct_aVect), optional, intent(in) :: w2x ! w2x_wx type(mct_aVect) , intent(inout) :: xao ! ! Local variables @@ -1330,7 +1338,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) logical :: flux_albav ! flux avg option logical :: dead_comps ! .true. => dead components are used integer(in) :: n ! indices - integer(in) :: nloc, nloca, nloco ! number of gridcells + integer(in) :: nloc, nloca, nloco, nlocw ! number of gridcells logical,save:: first_call = .true. logical :: cold_start ! .true. to initialize internal fields in shr_flux diurnal logical :: read_restart ! .true. => continue run @@ -1445,6 +1453,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) index_o2x_So_roce_16O = mct_aVect_indexRA(o2x,'So_roce_16O', perrWith='quiet') index_o2x_So_roce_HDO = mct_aVect_indexRA(o2x,'So_roce_HDO', perrWith='quiet') index_o2x_So_roce_18O = mct_aVect_indexRA(o2x,'So_roce_18O', perrWith='quiet') + index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') call shr_flux_adjust_constants(flux_convergence_tolerance=flux_convergence, & flux_convergence_max_iteration=flux_max_iteration, & coldair_outbreak_mod=coldair_outbreak_mod) @@ -1458,6 +1467,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) nloc = mct_aVect_lsize(xao) nloca = mct_aVect_lsize(a2x) nloco = mct_aVect_lsize(o2x) + nlocw = mct_aVect_lsize(w2x) if (nloc /= nloca .or. nloc /= nloco) then call shr_sys_abort(trim(subname)//' ERROR nloc sizes do not match') @@ -1548,6 +1558,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) tocn(n) = o2x%rAttr(index_o2x_So_t ,n) uocn(n) = o2x%rAttr(index_o2x_So_u ,n) vocn(n) = o2x%rAttr(index_o2x_So_v ,n) + charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) if ( index_o2x_So_roce_16O /= 0 ) roce_16O(n) = o2x%rAttr(index_o2x_So_roce_16O, n) if ( index_o2x_So_roce_HDO /= 0 ) roce_HDO(n) = o2x%rAttr(index_o2x_So_roce_HDO, n) if ( index_o2x_So_roce_18O /= 0 ) roce_18O(n) = o2x%rAttr(index_o2x_So_roce_18O, n) @@ -1634,7 +1645,8 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao) evap , evap_16O, evap_HDO, evap_18O, taux , tauy, tref, qref , & ocn_surface_flux_scheme, & duu10n, u10res, ustar, re , ssq, & - wsresp=wsresp, tau_est=tau_est, ugust=ugust_atm) + wsresp=wsresp, tau_est=tau_est, ugust=ugust_atm, & + charnockSeaState=charnsea) !missval should not be needed if flux calc !consistent with mrgx2a fraction !duu10n,ustar, re , ssq, missval = 0.0_r8 ) From ce49680d67260eaca7f28821391bfa756aaebb3e Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 20 Feb 2024 12:49:01 -0600 Subject: [PATCH 043/398] Add wind stress variables for wave momentum coupling to output streams. add xtime to wave output --- components/mpas-ocean/cime_config/buildnml | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 6382cae78c27..ef0c23eea3fe 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -976,6 +976,8 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') + lines.append(' ') + lines.append(' ') if ocn_bgc in ['eco_only', 'eco_and_dms', 'eco_and_macromolecules', 'eco_and_dms_and_macromolecules']: lines.append(' ') lines.append(' ') @@ -1008,12 +1010,47 @@ def buildnml(case, caseroot, compname): lines.append(' packages="highFrequencyOutputAMPKG">') 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(' ') + 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(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') lines.append('') lines.append('') lines.append(' Date: Tue, 20 Feb 2024 15:31:45 -0600 Subject: [PATCH 044/398] modify ocean stress by wave effect (components/mpas-ocean/driver/ocn_comp_mct.F) --- components/mpas-ocean/driver/ocn_comp_mct.F | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/mpas-ocean/driver/ocn_comp_mct.F b/components/mpas-ocean/driver/ocn_comp_mct.F index 8840c770317c..1aad9a4c2e10 100644 --- a/components/mpas-ocean/driver/ocn_comp_mct.F +++ b/components/mpas-ocean/driver/ocn_comp_mct.F @@ -2467,10 +2467,10 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ do i = 1, nCellsSolve n = n + 1 if ( windStressZonalField % isActive ) then - windStressZonal(i) = x2o_o % rAttr(index_x2o_Foxx_taux, n) + windStressZonal(i) = x2o_o % rAttr(index_x2o_Foxx_taux, n) - (x2o_o % rAttr(index_x2o_Faww_Tawx, n) - x2o_o % rAttr(index_x2o_Fwow_Twox, n)) end if if ( windStressMeridionalField % isActive ) then - windStressMeridional(i) = x2o_o % rAttr(index_x2o_Foxx_tauy, n) + windStressMeridional(i) = x2o_o % rAttr(index_x2o_Foxx_tauy, n) - (x2o_o % rAttr(index_x2o_Faww_Tawy, n) - x2o_o % rAttr(index_x2o_Fwow_Twoy, n)) end if if ( latentHeatFluxField % isActive ) then From e5cf037638a3a09830b846b9114551dd189617df Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 2 May 2024 11:50:21 -0500 Subject: [PATCH 045/398] add config namelist for momentum coupling --- components/mpas-ocean/bld/build-namelist | 2 ++ components/mpas-ocean/bld/build-namelist-section | 1 + .../bld/namelist_files/namelist_defaults_mpaso.xml | 1 + .../bld/namelist_files/namelist_definition_mpaso.xml | 8 ++++++++ components/mpas-ocean/driver/ocn_comp_mct.F | 12 ++++++++++-- components/mpas-ocean/src/Registry.xml | 4 ++++ 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/components/mpas-ocean/bld/build-namelist b/components/mpas-ocean/bld/build-namelist index 4d280349138f..47cb182fae2c 100755 --- a/components/mpas-ocean/bld/build-namelist +++ b/components/mpas-ocean/bld/build-namelist @@ -698,8 +698,10 @@ if ($ocn_wave eq 'true' ) { if ($ocn_wave eq 'true' ) { add_default($nl, 'config_use_active_wave', 'val'=>'.true.'); + add_default($nl, 'config_momentum_use_active_wave', 'val'=>'.true.'); } else { add_default($nl, 'config_use_active_wave', 'val'=>'.false.'); + add_default($nl, 'config_momentum_use_active_wave', 'val'=>'.false.'); } add_default($nl, 'config_n_stokes_drift_wavenumber_partitions'); diff --git a/components/mpas-ocean/bld/build-namelist-section b/components/mpas-ocean/bld/build-namelist-section index 9c9270f067db..13ba26d55348 100755 --- a/components/mpas-ocean/bld/build-namelist-section +++ b/components/mpas-ocean/bld/build-namelist-section @@ -211,6 +211,7 @@ add_default($nl, 'config_cvmix_kpp_use_active_wave'); ################################# add_default($nl, 'config_use_active_wave'); +add_default($nl, 'config_momentum_use_active_wave'); add_default($nl, 'config_n_stokes_drift_wavenumber_partitions'); ######################## 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 b73346e547a9..332b3bf6cdf9 100644 --- a/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml +++ b/components/mpas-ocean/bld/namelist_files/namelist_defaults_mpaso.xml @@ -356,6 +356,7 @@ .false. +.false. 6 diff --git a/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml b/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml index 80638a16953f..e3710e48e12a 100644 --- a/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml +++ b/components/mpas-ocean/bld/namelist_files/namelist_definition_mpaso.xml @@ -1121,6 +1121,14 @@ Valid values: .true. or .false. Default: Defined in namelist_defaults.xml + +Flag for correcting momentum in ocean due waves. Requires config_use_active_wave = .true. + +Valid values: .true. or .false. +Default: Defined in namelist_defaults.xml + + Number of wavenumber partitions to be used in reconstructing wave-induced Stokes drift profile diff --git a/components/mpas-ocean/driver/ocn_comp_mct.F b/components/mpas-ocean/driver/ocn_comp_mct.F index 1aad9a4c2e10..200f2c0be954 100644 --- a/components/mpas-ocean/driver/ocn_comp_mct.F +++ b/components/mpas-ocean/driver/ocn_comp_mct.F @@ -2467,10 +2467,18 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ do i = 1, nCellsSolve n = n + 1 if ( windStressZonalField % isActive ) then - windStressZonal(i) = x2o_o % rAttr(index_x2o_Foxx_taux, n) - (x2o_o % rAttr(index_x2o_Faww_Tawx, n) - x2o_o % rAttr(index_x2o_Fwow_Twox, n)) + if (config_momentum_use_active_wave) then + windStressZonal(i) = x2o_o % rAttr(index_x2o_Foxx_taux, n) - (x2o_o % rAttr(index_x2o_Faww_Tawx, n) - x2o_o % rAttr(index_x2o_Fwow_Twox, n)) + else + windStressZonal(i) = x2o_o % rAttr(index_x2o_Foxx_taux, n) + endif end if if ( windStressMeridionalField % isActive ) then - windStressMeridional(i) = x2o_o % rAttr(index_x2o_Foxx_tauy, n) - (x2o_o % rAttr(index_x2o_Faww_Tawy, n) - x2o_o % rAttr(index_x2o_Fwow_Twoy, n)) + if (config_momentum_use_active_wave) then + windStressMeridional(i) = x2o_o % rAttr(index_x2o_Foxx_tauy, n) - (x2o_o % rAttr(index_x2o_Faww_Tawy, n) - x2o_o % rAttr(index_x2o_Fwow_Twoy, n)) + else + windStressMeridional(i) = x2o_o % rAttr(index_x2o_Foxx_tauy, n) + endif end if if ( latentHeatFluxField % isActive ) then diff --git a/components/mpas-ocean/src/Registry.xml b/components/mpas-ocean/src/Registry.xml index f49ad5a3fc8a..eb991f052840 100644 --- a/components/mpas-ocean/src/Registry.xml +++ b/components/mpas-ocean/src/Registry.xml @@ -677,6 +677,10 @@ description="Flag for using prognostic waves. Controls the allocation of wave arrays and computation of Stokes drift profiles." possible_values=".true. or .false." /> + Date: Thu, 30 May 2024 12:30:41 -0500 Subject: [PATCH 046/398] adding wav_atm_coup and wav_ocn_coup flags replace ocn_wave flag with new wav_ocn_coup flag bug fix to wav_ocn_coup testing wav_ocn_coup settings syntax fix the buildnml for drv_in for wav_coupling variables --- components/mpas-ocean/bld/build-namelist | 10 ++--- components/mpas-ocean/cime_config/buildnml | 34 ++--------------- .../ww3/cime_config/config_component.xml | 2 - components/ww3/src/cpl/wav_comp_mct.F90 | 14 ++++--- components/ww3/src/cpl/ww3_cpl_indices.f90 | 20 +++++----- driver-mct/cime_config/buildnml | 1 + .../cime_config/namelist_definition_drv.xml | 14 ++++++- driver-mct/main/seq_flux_mct.F90 | 20 ++++++++-- driver-mct/shr/seq_flds_mod.F90 | 23 +++++++----- share/util/shr_flux_mod.F90 | 37 +++++++++++++------ 10 files changed, 96 insertions(+), 79 deletions(-) diff --git a/components/mpas-ocean/bld/build-namelist b/components/mpas-ocean/bld/build-namelist index 47cb182fae2c..9fed488de9ef 100755 --- a/components/mpas-ocean/bld/build-namelist +++ b/components/mpas-ocean/bld/build-namelist @@ -61,7 +61,6 @@ OPTIONS (Needed to run build-namelist from SourceMods dir) -inst_string inst_string variable -ocn_bgc ocean BGC configuration - -ocn_wave ocean wave coupling flag -ocn_co2_type how atm co2 is set within MPASO -atm_co2_const_val value of atm co2 if ocn_co2_type = constant -ice_bgc check for coupling with sea ice BGC @@ -118,7 +117,6 @@ my %opts = ( help => 0, decomp_prefix => undef, date_stamp => undef, ocn_bgc => undef, - ocn_wave => undef, ocn_co2_type => undef, atm_co2_const_val => undef, ice_bgc => undef, @@ -146,7 +144,6 @@ GetOptions( "decomp_prefix=s" => \$opts{'decomp_prefix'}, "date_stamp=s" => \$opts{'date_stamp'}, "ocn_bgc=s" => \$opts{'ocn_bgc'}, - "ocn_wave=s" => \$opts{'ocn_wave'}, "ocn_co2_type=s" => \$opts{'ocn_co2_type'}, "atm_co2_const_val=s" => \$opts{'atm_co2_const_val'}, "ice_bgc=s" => \$opts{'ice_bgc'}, @@ -191,7 +188,6 @@ my $OCN_SGR = $opts{'ocn_sgr'}; my $decomp_prefix = $opts{'decomp_prefix'}; my $date_stamp = $opts{'date_stamp'}; my $ocn_bgc = $opts{'ocn_bgc'}; -my $ocn_wave = $opts{'ocn_wave'}; my $ocn_co2_type = $opts{'ocn_co2_type'}; my $atm_co2_const_val = $opts{'atm_co2_const_val'}; my $ice_bgc = $opts{'ice_bgc'}; @@ -449,6 +445,8 @@ my $START_TOD = "$xmlvars{'START_TOD'}"; my $RUN_REFDATE = "$xmlvars{'RUN_REFDATE'}"; my $CONTINUE_RUN = "$xmlvars{'CONTINUE_RUN'}"; +my $wav_ocn_coup = "$xmlvars{'WAV_OCN_COUP'}"; + my $output_r = "./${CASE}.mpaso.r"; my $output_h = "./${CASE}.mpaso.h"; my $output_d = "./${CASE}.mpaso.d"; @@ -681,7 +679,7 @@ add_default($nl, 'configure_cvmix_kpp_minimum_OBL_under_sea_ice'); add_default($nl, 'config_cvmix_kpp_stop_OBL_search'); add_default($nl, 'config_cvmix_kpp_use_enhanced_diff'); add_default($nl, 'config_cvmix_kpp_nonlocal_with_implicit_mix'); -if ($ocn_wave eq 'true' ) { +if ($wav_ocn_coup eq 'true' ) { add_default($nl, 'config_cvmix_kpp_use_theory_wave', 'val'=>'.false.'); add_default($nl, 'config_cvmix_kpp_use_active_wave', 'val'=>'.true.'); add_default($nl, 'config_cvmix_kpp_langmuir_mixing_opt', 'val'=>'LWF16'); @@ -696,7 +694,7 @@ if ($ocn_wave eq 'true' ) { # Namelist group: wave_coupling # ################################# -if ($ocn_wave eq 'true' ) { +if ($wav_ocn_coup eq 'true' ) { add_default($nl, 'config_use_active_wave', 'val'=>'.true.'); add_default($nl, 'config_momentum_use_active_wave', 'val'=>'.true.'); } else { diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index ef0c23eea3fe..409af25957a1 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -36,10 +36,10 @@ def buildnml(case, caseroot, compname): ocn_iceberg = case.get_value("MPASO_ICEBERG") ocn_sgr = case.get_value("MPASO_SGR") ocn_bgc = case.get_value("MPASO_BGC") - ocn_wave = case.get_value("MPASO_WAVE") ocn_tidal_mixing = case.get_value("MPASO_TIDAL_MIXING") glc_nzoc = case.get_value("GLC_NZOC") ocn_glc_ismf_coupling = case.get_value("OCN_GLC_ISMF_COUPLING") + wav_ocn_coup = case.get_value("WAV_OCN_COUP") ocn_co2_type = case.get_value("OCN_CO2_TYPE") atm_co2_const_val = case.get_value("CCSM_CO2_PPMV") ice_bgc = case.get_value("MPASI_BGC") @@ -542,7 +542,6 @@ def buildnml(case, caseroot, compname): sysmod += " -ocn_iceberg '{}'".format(ocn_iceberg) sysmod += " -ocn_sgr '{}'".format(ocn_sgr) sysmod += " -ocn_bgc '{}'".format(ocn_bgc) - sysmod += " -ocn_wave '{}'".format(ocn_wave) sysmod += " -ocn_tidal_mixing '{}'".format(ocn_tidal_mixing) sysmod += " -glc_nzoc '{}'".format(glc_nzoc) sysmod += " -ocn_glc_ismf_coupling '{}'".format(ocn_glc_ismf_coupling) @@ -997,7 +996,7 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append('') lines.append('') - if ocn_wave == 'true': + if wav_ocn_coup == 'true': 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(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append('') - lines.append('') lines.append('') lines.append(' ') lines.append(' ') - if ocn_wave == 'true': + if wav_ocn_coup == 'true': lines.append(' ') lines.append(' ') lines.append(' ') diff --git a/components/ww3/cime_config/config_component.xml b/components/ww3/cime_config/config_component.xml index 27523b8f42d9..63032eda31f1 100644 --- a/components/ww3/cime_config/config_component.xml +++ b/components/ww3/cime_config/config_component.xml @@ -42,8 +42,6 @@ env_case.xml Option to set WW3 Spectral Resolution. - - ========================================= diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index d221573e0141..77647156a3f4 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -1182,7 +1182,10 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) IY = MAPSF(ISEA,2) if (MAPSTA(IY,IX) .eq. 1) then - if (wav_ocn_coup .eq. 'twoway') then + if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then + w2x_w%rattr(index_w2x_Sw_Charn,jsea) = CHARN(jsea) + endif + if (wav_ocn_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Hs,jsea) = HS(jsea) w2x_w%rattr(index_w2x_Sw_Fp,jsea) = FP0(jsea) w2x_w%rattr(index_w2x_Sw_Dp,jsea) = THP0(jsea) @@ -1205,7 +1208,6 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = USSP(jsea,6) w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = USSP(jsea,nk+6) - w2x_w%rattr(index_w2x_Sw_Charn,jsea) = CHARN(jsea) w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) @@ -1214,6 +1216,9 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) endif else + if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then + w2x_w%rattr(index_w2x_Sw_Charn,jsea) = 0.0 + endif if (wav_ocn_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Hs,jsea) = 0.0 w2x_w%rattr(index_w2x_Sw_Fp,jsea) = 0.0 @@ -1237,15 +1242,14 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = 0.0 w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_Charn,jsea) = 0.0 w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 0.0 w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 0.0 w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 0.0 w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 0.0 w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = 0.0 w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = 0.0 - endif - endif + endif + endif enddo !---------------------------------------------------------------------------- diff --git a/components/ww3/src/cpl/ww3_cpl_indices.f90 b/components/ww3/src/cpl/ww3_cpl_indices.f90 index a6bb91a00a86..f105a7ecabb5 100644 --- a/components/ww3/src/cpl/ww3_cpl_indices.f90 +++ b/components/ww3/src/cpl/ww3_cpl_indices.f90 @@ -47,8 +47,8 @@ module ww3_cpl_indices contains subroutine ww3_cpl_indices_set( ) - - use seq_flds_mod, only : wav_ocn_coup + + use seq_flds_mod, only : wav_atm_coup, wav_ocn_coup type(mct_aVect) :: w2x ! temporary type(mct_aVect) :: x2w ! temporary @@ -70,10 +70,19 @@ subroutine ww3_cpl_indices_set( ) index_x2w_So_bldepth = mct_avect_indexra(x2w,'So_bldepth') ! Boundary layer depth index_x2w_So_ssh = mct_avect_indexra(x2w,'So_ssh') ! Sea surface height + if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then + index_w2x_Sw_Charn = mct_avect_indexra(w2x,'Sw_Charn') ! Charnock coeff accounting for the wave stress (Janssen 1989, 1991) + endif if (wav_ocn_coup .eq. 'twoway') then index_w2x_Sw_Hs = mct_avect_indexra(w2x,'Sw_Hs') ! Significant wave height index_w2x_Sw_Fp = mct_avect_indexra(w2x,'Sw_Fp') ! Peak wave freqency index_w2x_Sw_Dp = mct_avect_indexra(w2x,'Sw_Dp') ! Peak wave direction + index_w2x_Faww_Tawx = mct_avect_indexra(w2x,'Faww_Tawx') ! Zonal Wave supported stress (Stress from atmosphere to waves) + index_w2x_Faww_Tawy = mct_avect_indexra(w2x,'Faww_Tawy') ! Meridional Wave supported stress (Stress from atmosphere to waves) + index_w2x_Fwow_Twox = mct_avect_indexra(w2x,'Fwow_Twox') ! Zonal Wave to ocean stress (Not total ocean momentum stress ) + index_w2x_Fwow_Twoy = mct_avect_indexra(w2x,'Fwow_Twoy') ! MeridionalWave to ocean stress (Not total ocean momentum stress) + index_w2x_Faow_Tocx = mct_avect_indexra(w2x,'Faow_Tocx') ! Zonal Net ocean stress (total ocean momentum stress ) + index_w2x_Faow_Tocy = mct_avect_indexra(w2x,'Faow_Tocy') !Meridional Net ocean stress (total ocean momentum stress) index_w2x_Sw_ustokes_wavenumber_1 = mct_avect_indexra(w2x,'Sw_ustokes_wavenumber_1') ! partitioned Stokes drift u 1 index_w2x_Sw_vstokes_wavenumber_1 = mct_avect_indexra(w2x,'Sw_vstokes_wavenumber_1') ! partitioned Stokes drift v 1 index_w2x_Sw_ustokes_wavenumber_2 = mct_avect_indexra(w2x,'Sw_ustokes_wavenumber_2') ! partitioned Stokes drift u 2 @@ -86,13 +95,6 @@ subroutine ww3_cpl_indices_set( ) index_w2x_Sw_vstokes_wavenumber_5 = mct_avect_indexra(w2x,'Sw_vstokes_wavenumber_5') ! partitioned Stokes drift v 5 index_w2x_Sw_ustokes_wavenumber_6 = mct_avect_indexra(w2x,'Sw_ustokes_wavenumber_6') ! partitioned Stokes drift u 6 index_w2x_Sw_vstokes_wavenumber_6 = mct_avect_indexra(w2x,'Sw_vstokes_wavenumber_6') ! partitioned Stokes drift v 6 - index_w2x_Sw_Charn = mct_avect_indexra(w2x,'Sw_Charn') ! Charnock coeff accounting for the wave stress (Janssen 1989, 1991) - index_w2x_Faww_Tawx = mct_avect_indexra(w2x,'Faww_Tawx') ! Zonal Wave supported stress (Stress from atmosphere to waves) - index_w2x_Faww_Tawy = mct_avect_indexra(w2x,'Faww_Tawy') ! Meridional Wave supported stress (Stress from atmosphere to waves) - index_w2x_Fwow_Twox = mct_avect_indexra(w2x,'Fwow_Twox') ! Zonal Wave to ocean stress (Not total ocean momentum stress ) - index_w2x_Fwow_Twoy = mct_avect_indexra(w2x,'Fwow_Twoy') ! MeridionalWave to ocean stress (Not total ocean momentum stress) - index_w2x_Faow_Tocx = mct_avect_indexra(w2x,'Faow_Tocx') ! Zonal Net ocean stress (total ocean momentum stress ) - index_w2x_Faow_Tocy = mct_avect_indexra(w2x,'Faow_Tocy') !Meridional Net ocean stress (total ocean momentum stress) endif call mct_aVect_clean(x2w) call mct_aVect_clean(w2x) diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 924219045600..cdf0f30a54d9 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -75,6 +75,7 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): # --------------------------------------------------- if case.get_value('COMP_WAV') == 'ww3': config['WAVSPEC'] = case.get_value('WAV_SPEC') + config['WAV_ATM_COUP'] = '.true.' if case.get_value('COMP_ATM') == 'eam' else '.false.' if case.get_value('COMP_OCN') == 'mpaso': config['WAV_OCN_COUP'] = 'twoway' elif case.get_value('COMP_OCN') == 'docn': diff --git a/driver-mct/cime_config/namelist_definition_drv.xml b/driver-mct/cime_config/namelist_definition_drv.xml index 06dd07b75ef0..c1dcbd135903 100644 --- a/driver-mct/cime_config/namelist_definition_drv.xml +++ b/driver-mct/cime_config/namelist_definition_drv.xml @@ -318,7 +318,7 @@ char seq_flds seq_cplflds_inparm - One- or Two-way coupling between Wave and Ocn. + One- or Two-way coupling between Wave and Ocean none oneway @@ -326,6 +326,18 @@ + + logical + seq_flds + seq_cplflds_inparm + One- or Two-way coupling between Wave and Atm + + none + oneway + twoway + + + logical seq_flds diff --git a/driver-mct/main/seq_flux_mct.F90 b/driver-mct/main/seq_flux_mct.F90 index 5835e7688dde..cfc9f12ad3f9 100644 --- a/driver-mct/main/seq_flux_mct.F90 +++ b/driver-mct/main/seq_flux_mct.F90 @@ -1453,7 +1453,9 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) index_o2x_So_roce_16O = mct_aVect_indexRA(o2x,'So_roce_16O', perrWith='quiet') index_o2x_So_roce_HDO = mct_aVect_indexRA(o2x,'So_roce_HDO', perrWith='quiet') index_o2x_So_roce_18O = mct_aVect_indexRA(o2x,'So_roce_18O', perrWith='quiet') - index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') + if (wav_ocn_coup .or. wav_atm_coup) then + index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') + endif call shr_flux_adjust_constants(flux_convergence_tolerance=flux_convergence, & flux_convergence_max_iteration=flux_max_iteration, & coldair_outbreak_mod=coldair_outbreak_mod) @@ -1558,7 +1560,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) tocn(n) = o2x%rAttr(index_o2x_So_t ,n) uocn(n) = o2x%rAttr(index_o2x_So_u ,n) vocn(n) = o2x%rAttr(index_o2x_So_v ,n) - charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) + if (wav_atm_coup) charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) if ( index_o2x_So_roce_16O /= 0 ) roce_16O(n) = o2x%rAttr(index_o2x_So_roce_16O, n) if ( index_o2x_So_roce_HDO /= 0 ) roce_HDO(n) = o2x%rAttr(index_o2x_So_roce_HDO, n) if ( index_o2x_So_roce_18O /= 0 ) roce_18O(n) = o2x%rAttr(index_o2x_So_roce_18O, n) @@ -1637,7 +1639,8 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) duu10n,ustar, re , ssq, wsresp=wsresp, tau_est=tau_est) u10res = sqrt(duu10n) ! atm-supplied gustiness not implemented for UA else - call shr_flux_atmocn (nloc , zbot , ubot, vbot, thbot, & + if (wav_atm_coup) then + call shr_flux_atmocn (nloc , zbot , ubot, vbot, thbot, & shum , shum_16O , shum_HDO, shum_18O, dens , tbot, uocn, vocn , & tocn , emask, seq_flux_atmocn_minwind, & sen , lat , lwup , & @@ -1647,6 +1650,17 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) duu10n, u10res, ustar, re , ssq, & wsresp=wsresp, tau_est=tau_est, ugust=ugust_atm, & charnockSeaState=charnsea) + else + call shr_flux_atmocn (nloc , zbot , ubot, vbot, thbot, & + shum , shum_16O , shum_HDO, shum_18O, dens , tbot, uocn, vocn , & + tocn , emask, seq_flux_atmocn_minwind, & + sen , lat , lwup , & + roce_16O, roce_HDO, roce_18O, & + evap , evap_16O, evap_HDO, evap_18O, taux , tauy, tref, qref , & + ocn_surface_flux_scheme, & + duu10n, u10res, ustar, re , ssq, & + wsresp=wsresp, tau_est=tau_est, ugust=ugust_atm) + endif !missval should not be needed if flux calc !consistent with mrgx2a fraction !duu10n,ustar, re , ssq, missval = 0.0_r8 ) diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 1f4fd998fb71..7b11b01eb6cd 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -164,6 +164,7 @@ module seq_flds_mod logical :: rof_sed ! .true. if river model includes sediment logical :: add_iac_to_cplstate ! .true. if iac fields are added to coupler history files character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on + character(len=CS) :: wav_atm_coup ! 'twoway' if wave-ocean two-way coupling turned on !---------------------------------------------------------------------------- ! metadata @@ -410,7 +411,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) glc_nec, glc_nzoc, ice_ncat, seq_flds_i2o_per_cat, flds_bgc_oi, & nan_check_component_fields, rof_heat, atm_flux_method, atm_gustiness, & rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, rof_sed, & - wav_ocn_coup, add_iac_to_cplstate + wav_ocn_coup, wav_atm_coup, add_iac_to_cplstate ! user specified new fields integer, parameter :: nfldmax = 200 @@ -456,6 +457,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ocn_rof_two_way = .false. rof_sed = .false. wav_ocn_coup = 'none' + wav_atm_coup = 'none' add_iac_to_cplstate = .false. unitn = shr_file_getUnit() @@ -494,6 +496,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call shr_mpi_bcast(ocn_rof_two_way, mpicom) call shr_mpi_bcast(rof_sed, mpicom) call shr_mpi_bcast(wav_ocn_coup, mpicom) + call shr_mpi_bcast(wav_atm_coup, mpicom) call shr_mpi_bcast(add_iac_to_cplstate, mpicom) call glc_elevclass_init(glc_nec) @@ -2547,6 +2550,14 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ! wav->ocn and ocn->wav !----------------------------- if (wav_ocn_coup == 'twoway') then + call seq_flds_add(w2x_states,'Sw_Hs') + call seq_flds_add(x2o_states,'Sw_Hs') + longname = 'Significant wave height' + stdname = 'significant_wave_height' + units = 'm' + attname = 'Sw_Hs' + call metadata_set(attname, longname, stdname, units) + call seq_flds_add(w2x_states,'Sw_ustokes_wavenumber_1') call seq_flds_add(x2o_states,'Sw_ustokes_wavenumber_1') longname = 'Partitioned Stokes drift u component, wavenumber 1' @@ -2643,14 +2654,6 @@ subroutine seq_flds_set(nmlfile, ID, infodata) attname = 'Sw_vstokes_wavenumber_6' call metadata_set(attname, longname, stdname, units) - call seq_flds_add(w2x_states,'Sw_Hs') - call seq_flds_add(x2o_states,'Sw_Hs') - longname = 'Significant wave height' - stdname = 'significant_wave_height' - units = 'm' - attname = 'Sw_Hs' - call metadata_set(attname, longname, stdname, units) - call seq_flds_add(w2x_states,'Sw_Fp') call seq_flds_add(x2o_states,'Sw_Fp') longname = 'Peak wave frequency' @@ -2716,7 +2719,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call metadata_set(attname, longname, stdname, units) endif - if (wav_ocn_coup == 'twoway') then + if (wav_atm_coup == 'twoway' .or. wav_ocn_coup == 'twoway') then call seq_flds_add(w2x_states,'Sw_Charn') call seq_flds_add(x2o_states,'Sw_Charn') longname = 'Charnock coefficent based on sea state' diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index 7046909ec54b..8fe9bbe8c86f 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -155,6 +155,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & ! !USES: use water_isotopes, only: wiso_flxoce !subroutine used to calculate water isotope fluxes. + use seq_flds_mod, only : wav_atm_coup implicit none ! !INPUT/OUTPUT PARAMETERS: @@ -540,8 +541,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & endif endif ssq = 0.98_R8 * qsat(ts(n)) / rbot(n) ! sea surf hum (kg/kg) - - call cor30a(ubot(n),vbot(n),tbot(n),qbot(n),rbot(n) & ! in atm params + if (wav_atm_coup) then + call cor30a(ubot(n),vbot(n),tbot(n),qbot(n),rbot(n) & ! in atm params & ,us(n),vs(n),ts(n),ssq & ! in surf params & ,zpbl,zbot(n),zbot(n),zref,ztref,ztref & ! in heights & ,tau,hsb,hlb & ! out: fluxes @@ -550,7 +551,16 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & & ,trf,qrf,urf,vrf & ! out: reference-height params & ,wsresp(n),tau_est(n) & ! in: optional stress params for the sake of maintaining same defs & ,charnockSeaState(n)) ! in: optional charnock sea state - + else + call cor30a(ubot(n),vbot(n),tbot(n),qbot(n),rbot(n) & ! in atm params + & ,us(n),vs(n),ts(n),ssq & ! in surf params + & ,zpbl,zbot(n),zbot(n),zref,ztref,ztref & ! in heights + & ,tau,hsb,hlb & ! out: fluxes + & ,zo,zot,zoq,hol,ustar,tstar,qstar & ! out: ss scales + & ,rd,rh,re & ! out: exch. coeffs + & ,trf,qrf,urf,vrf & ! out: reference-height params + & ,wsresp(n),tau_est(n) ) ! in: optional stress params for the sake of maintaining same defs + endif hol=zbot(n)/hol rd=sqrt(rd) rh=sqrt(rh) @@ -2518,7 +2528,7 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params & ,charnsea) ! in: optional charnock sea state !USES: - +use seq_flds_mod, only : wav_atm_coup IMPLICIT NONE ! !INPUT/OUTPUT PARAMETERS: @@ -2636,15 +2646,18 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params tsr = (dt-dter*jcool)*von/(log(zt/zot10)-psit_30(zt/L10)) qsr = (dq-dqer*jcool)*von/(log(zq/zot10)-psit_30(zq/L10)) -! parametrisation for Charney parameter (section 3c of Fairall et al. 2003) - !charn=0.011_R8 - if (ut .GT. 10.0_R8) then - !charn=0.011_R8+(ut-10.0_R8)/(18.0_R8-10.0_R8)*(0.018_R8-0.011_R8) - endif - if (ut .GT. 18.0_R8) then - !charn=0.018_R8 + if (wav_atm_coup) then + charn = charnsea !use Charnock coefficient from active wave model (Janssen 1989, 1991) + else + ! parametrisation for Charney parameter (section 3c of Fairall et al. 2003) + charn=0.011_R8 + if (ut .GT. 10.0_R8) then + charn=0.011_R8+(ut-10.0_R8)/(18.0_R8-10.0_R8)*(0.018_R8-0.011_R8) + endif + if (ut .GT. 18.0_R8) then + charn=0.018_R8 + endif endif - charn = charnsea !use Charnock coefficient accounting for the wave stress (Janssen 1989, 1991) if (present(wsresp) .and. present(tau_est)) prev_tau = tau_est tau_diff = 1.e100_R8 From 77cb0905d6fb39fe71387d9341fb1d17d266823c Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Fri, 7 Jun 2024 12:55:38 -0500 Subject: [PATCH 047/398] change all wave coupling namelists from boolean to char. i.e. wav_ocn_coup = 'none', 'one', or 'two' for no coupling, one way coupling (ocn to wav), or full two way coupling --- components/mpas-ocean/bld/build-namelist | 8 +- components/mpas-ocean/cime_config/buildnml | 5 +- components/ww3/src/cpl/wav_comp_mct.F90 | 110 +++++++++--------- driver-mct/cime_config/buildnml | 3 +- .../cime_config/namelist_definition_drv.xml | 11 ++ driver-mct/main/seq_flux_mct.F90 | 8 +- driver-mct/shr/seq_flds_mod.F90 | 18 +-- share/util/shr_flux_mod.F90 | 4 +- 8 files changed, 89 insertions(+), 78 deletions(-) diff --git a/components/mpas-ocean/bld/build-namelist b/components/mpas-ocean/bld/build-namelist index 9fed488de9ef..66472df56e6f 100755 --- a/components/mpas-ocean/bld/build-namelist +++ b/components/mpas-ocean/bld/build-namelist @@ -444,8 +444,8 @@ my $RUN_STARTDATE = "$xmlvars{'RUN_STARTDATE'}"; my $START_TOD = "$xmlvars{'START_TOD'}"; my $RUN_REFDATE = "$xmlvars{'RUN_REFDATE'}"; my $CONTINUE_RUN = "$xmlvars{'CONTINUE_RUN'}"; - -my $wav_ocn_coup = "$xmlvars{'WAV_OCN_COUP'}"; +my $COMP_OCN = "$xmlvars{'COMP_OCN'}"; +my $COMP_WAV = "$xmlvars{'COMP_WAV'}"; my $output_r = "./${CASE}.mpaso.r"; my $output_h = "./${CASE}.mpaso.h"; @@ -679,7 +679,7 @@ add_default($nl, 'configure_cvmix_kpp_minimum_OBL_under_sea_ice'); add_default($nl, 'config_cvmix_kpp_stop_OBL_search'); add_default($nl, 'config_cvmix_kpp_use_enhanced_diff'); add_default($nl, 'config_cvmix_kpp_nonlocal_with_implicit_mix'); -if ($wav_ocn_coup eq 'true' ) { +if ($COMP_WAV eq 'ww3' and $COMP_OCN eq 'mpaso' ) { add_default($nl, 'config_cvmix_kpp_use_theory_wave', 'val'=>'.false.'); add_default($nl, 'config_cvmix_kpp_use_active_wave', 'val'=>'.true.'); add_default($nl, 'config_cvmix_kpp_langmuir_mixing_opt', 'val'=>'LWF16'); @@ -694,7 +694,7 @@ if ($wav_ocn_coup eq 'true' ) { # Namelist group: wave_coupling # ################################# -if ($wav_ocn_coup eq 'true' ) { +if ($COMP_WAV eq 'ww3' and $COMP_OCN eq 'mpaso' ) { add_default($nl, 'config_use_active_wave', 'val'=>'.true.'); add_default($nl, 'config_momentum_use_active_wave', 'val'=>'.true.'); } else { diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 409af25957a1..e7c4c949fd0b 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -39,7 +39,6 @@ def buildnml(case, caseroot, compname): ocn_tidal_mixing = case.get_value("MPASO_TIDAL_MIXING") glc_nzoc = case.get_value("GLC_NZOC") ocn_glc_ismf_coupling = case.get_value("OCN_GLC_ISMF_COUPLING") - wav_ocn_coup = case.get_value("WAV_OCN_COUP") ocn_co2_type = case.get_value("OCN_CO2_TYPE") atm_co2_const_val = case.get_value("CCSM_CO2_PPMV") ice_bgc = case.get_value("MPASI_BGC") @@ -996,7 +995,7 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append('') lines.append('') - if wav_ocn_coup == 'true': + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': lines.append('') lines.append(' ') lines.append(' ') - if wav_ocn_coup == 'true': + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': lines.append(' ') lines.append(' ') lines.append(' ') diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index 77647156a3f4..1b81e7768c12 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -1186,68 +1186,66 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_Charn,jsea) = CHARN(jsea) endif if (wav_ocn_coup .eq. 'twoway') then - w2x_w%rattr(index_w2x_Sw_Hs,jsea) = HS(jsea) - w2x_w%rattr(index_w2x_Sw_Fp,jsea) = FP0(jsea) - w2x_w%rattr(index_w2x_Sw_Dp,jsea) = THP0(jsea) - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_1,jsea) = USSP(jsea,1) - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_1,jsea) = USSP(jsea,nk+1) + w2x_w%rattr(index_w2x_Sw_Hs,jsea) = HS(jsea) + w2x_w%rattr(index_w2x_Sw_Fp,jsea) = FP0(jsea) + w2x_w%rattr(index_w2x_Sw_Dp,jsea) = THP0(jsea) + w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) + w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) + w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) + w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 1000*TAUOY(jsea) + w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = TAUOCX(jsea) + w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) + + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_1,jsea) = USSP(jsea,1) + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_1,jsea) = USSP(jsea,nk+1) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_2,jsea) = USSP(jsea,2) + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_2,jsea) = USSP(jsea,nk+2) + + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_3,jsea) = USSP(jsea,3) + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_3,jsea) = USSP(jsea,nk+3) + + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_4,jsea) = USSP(jsea,4) + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_4,jsea) = USSP(jsea,nk+4) + + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_5,jsea) = USSP(jsea,5) + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_5,jsea) = USSP(jsea,nk+5) + + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = USSP(jsea,6) + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = USSP(jsea,nk+6) + endif + else + if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then + w2x_w%rattr(index_w2x_Sw_Charn,jsea) = 0.0 + endif + if (wav_ocn_coup .eq. 'twoway') then + w2x_w%rattr(index_w2x_Sw_Hs,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_Fp,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_Dp,jsea) = 0.0 + + w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 0.0 + w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 0.0 + w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = 0.0 + w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_2,jsea) = USSP(jsea,2) - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_2,jsea) = USSP(jsea,nk+2) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_1,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_1,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_3,jsea) = USSP(jsea,3) - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_3,jsea) = USSP(jsea,nk+3) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_2,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_2,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_4,jsea) = USSP(jsea,4) - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_4,jsea) = USSP(jsea,nk+4) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_3,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_3,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_5,jsea) = USSP(jsea,5) - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_5,jsea) = USSP(jsea,nk+5) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_4,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_4,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = USSP(jsea,6) - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = USSP(jsea,nk+6) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_5,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_5,jsea) = 0.0 - w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) - w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) - w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) - w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 1000*TAUOY(jsea) - w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = TAUOCX(jsea) - w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) - endif - else - if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then - w2x_w%rattr(index_w2x_Sw_Charn,jsea) = 0.0 - endif - if (wav_ocn_coup .eq. 'twoway') then - w2x_w%rattr(index_w2x_Sw_Hs,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_Fp,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_Dp,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_1,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_1,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_2,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_2,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_3,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_3,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_4,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_4,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_5,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_5,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = 0.0 - w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = 0.0 - - w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 0.0 - w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 0.0 - w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 0.0 - w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 0.0 - w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = 0.0 - w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_6,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_6,jsea) = 0.0 endif endif enddo diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index cdf0f30a54d9..7af91afac075 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -75,7 +75,8 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): # --------------------------------------------------- if case.get_value('COMP_WAV') == 'ww3': config['WAVSPEC'] = case.get_value('WAV_SPEC') - config['WAV_ATM_COUP'] = '.true.' if case.get_value('COMP_ATM') == 'eam' else '.false.' + config['WAV_ATM_COUP'] = 'two' if case.get_value('COMP_ATM') == 'eam' else 'one' + config['WAV_ICE_COUP'] = 'two' if case.get_value('COMP_ICE') == 'mpassi' else 'one' if case.get_value('COMP_OCN') == 'mpaso': config['WAV_OCN_COUP'] = 'twoway' elif case.get_value('COMP_OCN') == 'docn': diff --git a/driver-mct/cime_config/namelist_definition_drv.xml b/driver-mct/cime_config/namelist_definition_drv.xml index c1dcbd135903..6831b41d7dab 100644 --- a/driver-mct/cime_config/namelist_definition_drv.xml +++ b/driver-mct/cime_config/namelist_definition_drv.xml @@ -338,6 +338,17 @@ + + char + seq_flds + seq_cplflds_inparm + One- or Two-way coupling between Wave and Sea Ice. + + none + oneway + + + logical seq_flds diff --git a/driver-mct/main/seq_flux_mct.F90 b/driver-mct/main/seq_flux_mct.F90 index cfc9f12ad3f9..e4ceabbdd17e 100644 --- a/driver-mct/main/seq_flux_mct.F90 +++ b/driver-mct/main/seq_flux_mct.F90 @@ -1453,8 +1453,8 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) index_o2x_So_roce_16O = mct_aVect_indexRA(o2x,'So_roce_16O', perrWith='quiet') index_o2x_So_roce_HDO = mct_aVect_indexRA(o2x,'So_roce_HDO', perrWith='quiet') index_o2x_So_roce_18O = mct_aVect_indexRA(o2x,'So_roce_18O', perrWith='quiet') - if (wav_ocn_coup .or. wav_atm_coup) then - index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') + if (wav_ocn_coup == 'two' .or. wav_atm_coup == 'two') then + index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') endif call shr_flux_adjust_constants(flux_convergence_tolerance=flux_convergence, & flux_convergence_max_iteration=flux_max_iteration, & @@ -1560,7 +1560,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) tocn(n) = o2x%rAttr(index_o2x_So_t ,n) uocn(n) = o2x%rAttr(index_o2x_So_u ,n) vocn(n) = o2x%rAttr(index_o2x_So_v ,n) - if (wav_atm_coup) charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) + if (wav_atm_coup == 'two') charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) if ( index_o2x_So_roce_16O /= 0 ) roce_16O(n) = o2x%rAttr(index_o2x_So_roce_16O, n) if ( index_o2x_So_roce_HDO /= 0 ) roce_HDO(n) = o2x%rAttr(index_o2x_So_roce_HDO, n) if ( index_o2x_So_roce_18O /= 0 ) roce_18O(n) = o2x%rAttr(index_o2x_So_roce_18O, n) @@ -1639,7 +1639,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) duu10n,ustar, re , ssq, wsresp=wsresp, tau_est=tau_est) u10res = sqrt(duu10n) ! atm-supplied gustiness not implemented for UA else - if (wav_atm_coup) then + if (wav_atm_coup == 'two') then call shr_flux_atmocn (nloc , zbot , ubot, vbot, thbot, & shum , shum_16O , shum_HDO, shum_18O, dens , tbot, uocn, vocn , & tocn , emask, seq_flux_atmocn_minwind, & diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 7b11b01eb6cd..6b16a9712b07 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -165,7 +165,7 @@ module seq_flds_mod logical :: add_iac_to_cplstate ! .true. if iac fields are added to coupler history files character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on character(len=CS) :: wav_atm_coup ! 'twoway' if wave-ocean two-way coupling turned on - + character(len=CS) :: wav_ice_coup ! 'two' if wave-ice two-way coupling turned on !---------------------------------------------------------------------------- ! metadata !---------------------------------------------------------------------------- @@ -411,7 +411,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) glc_nec, glc_nzoc, ice_ncat, seq_flds_i2o_per_cat, flds_bgc_oi, & nan_check_component_fields, rof_heat, atm_flux_method, atm_gustiness, & rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, rof_sed, & - wav_ocn_coup, wav_atm_coup, add_iac_to_cplstate + wav_ocn_coup, wav_atm_coup, wav_ice_coup, add_iac_to_cplstate ! user specified new fields integer, parameter :: nfldmax = 200 @@ -458,6 +458,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) rof_sed = .false. wav_ocn_coup = 'none' wav_atm_coup = 'none' + wav_ice_coup = 'none' add_iac_to_cplstate = .false. unitn = shr_file_getUnit() @@ -497,6 +498,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call shr_mpi_bcast(rof_sed, mpicom) call shr_mpi_bcast(wav_ocn_coup, mpicom) call shr_mpi_bcast(wav_atm_coup, mpicom) + call shr_mpi_bcast(wav_ice_coup, mpicom) call shr_mpi_bcast(add_iac_to_cplstate, mpicom) call glc_elevclass_init(glc_nec) @@ -690,7 +692,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2r_states,"Sa_u") call seq_flds_add(a2x_states_to_rof,"Sa_u") endif - call seq_flds_add(x2w_states,"Sa_u") + if (wav_atm_coup .ne. 'none') call seq_flds_add(x2w_states,"Sa_u") longname = 'Zonal wind at the lowest model level' stdname = 'eastward_wind' units = 'm s-1' @@ -705,7 +707,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2r_states,"Sa_v") call seq_flds_add(a2x_states_to_rof,"Sa_v") endif - call seq_flds_add(x2w_states,"Sa_v") + if (wav_atm_coup .ne. 'none') call seq_flds_add(x2w_states,"Sa_v") longname = 'Meridional wind at the lowest model level' stdname = 'northward_wind' units = 'm s-1' @@ -754,7 +756,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2r_states,"Sa_tbot") call seq_flds_add(a2x_states_to_rof,"Sa_tbot") endif - call seq_flds_add(x2w_states,"Sa_tbot") + if (wav_atm_coup .ne. 'none') call seq_flds_add(x2w_states,"Sa_tbot") longname = 'Temperature at the lowest model level' stdname = 'air_temperature' units = 'K' @@ -1555,7 +1557,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ! Fractional ice coverage wrt ocean call seq_flds_add(i2x_states,"Si_ifrac") call seq_flds_add(x2o_states,"Si_ifrac") - call seq_flds_add(x2w_states,"Si_ifrac") + if (wav_ice_coup .ne. 'none') call seq_flds_add(x2w_states,"Si_ifrac") longname = 'Fractional ice coverage wrt ocean' stdname = 'sea_ice_area_fraction' units = '1' @@ -2213,7 +2215,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ! Sea ice thickness call seq_flds_add(i2x_states,"Si_ithick") - call seq_flds_add(x2w_states,"Si_ithick") + if (wav_ice_coup .ne. 'none') call seq_flds_add(x2w_states,"Si_ithick") longname = 'Sea ice thickness' stdname = 'sea_ice_thickness' units = 'm' @@ -2721,7 +2723,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) if (wav_atm_coup == 'twoway' .or. wav_ocn_coup == 'twoway') then call seq_flds_add(w2x_states,'Sw_Charn') - call seq_flds_add(x2o_states,'Sw_Charn') + if (wav_ocn_coup == 'two') call seq_flds_add(x2o_states,'Sw_Charn') longname = 'Charnock coefficent based on sea state' stdname = 'Charnock_coefficent_based_on_sea_state' units = '' diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index 8fe9bbe8c86f..ef4d151aeb70 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -541,7 +541,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & endif endif ssq = 0.98_R8 * qsat(ts(n)) / rbot(n) ! sea surf hum (kg/kg) - if (wav_atm_coup) then + if (wav_atm_coup .eq. 'two') then call cor30a(ubot(n),vbot(n),tbot(n),qbot(n),rbot(n) & ! in atm params & ,us(n),vs(n),ts(n),ssq & ! in surf params & ,zpbl,zbot(n),zbot(n),zref,ztref,ztref & ! in heights @@ -2646,7 +2646,7 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params tsr = (dt-dter*jcool)*von/(log(zt/zot10)-psit_30(zt/L10)) qsr = (dq-dqer*jcool)*von/(log(zq/zot10)-psit_30(zq/L10)) - if (wav_atm_coup) then + if (wav_atm_coup .eq. 'two') then charn = charnsea !use Charnock coefficient from active wave model (Janssen 1989, 1991) else ! parametrisation for Charney parameter (section 3c of Fairall et al. 2003) From a69a558180531810e93595887c6da187a6ec80c1 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 11 Jun 2024 16:38:13 -0500 Subject: [PATCH 048/398] add F+WW3 compset modify F+WW3 compset --- components/ww3/cime_config/config_compsets.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/ww3/cime_config/config_compsets.xml b/components/ww3/cime_config/config_compsets.xml index 1fb44c188a63..e54003b8d1d8 100644 --- a/components/ww3/cime_config/config_compsets.xml +++ b/components/ww3/cime_config/config_compsets.xml @@ -24,6 +24,11 @@ 2000_DATM%CFSR_SLND_SICE_SOCN_SROF_SGLC_WW3%sp36x36 + + F2010-WW3 + 2010_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%PRES_DOCN%DOM_MOSART_SGLC_WW3%sp36x36 + + DTESTM-JRA1p5-WW3 2000_DATM%JRA-1p5_SLND_MPASSI_DOCN%SOM_DROF%JRA-1p5_SGLC_WW3%sp36x36_TEST From d9c9f28c109f84cafd5e68184c9428923d57331f Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Wed, 10 Jul 2024 15:40:38 -0500 Subject: [PATCH 049/398] add comment to shr_flux_mod about coare3.0 w/ wave coupling. update anvil Pe layout for B case with waves --- share/util/shr_flux_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index ef4d151aeb70..7f8a776a2c87 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -137,7 +137,7 @@ end subroutine shr_flux_adjust_constants ! ! 2011-Mar-13 - J. Nusbaumer - Water Isotope ocean flux added. ! 2019-May-16 - Jack Reeves Eyre (UA) and Kai Zhang (PNNL) - Added COARE/Fairall surface flux scheme option (ocn_surface_flux_scheme .eq. 1) based on code from Thomas Toniazzo (Bjerknes Centre, Bergen) ” -! +! 2024-Jul-10 - E. Thomas ethomas@lanl.gov - implementing Coare3.0 w/ Wave coupling (uses charnock paramter from WW3) ! !INTERFACE: ------------------------------------------------------------------ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & From 6e1e33369266a2755c4bca2463425b3a337aeeb9 Mon Sep 17 00:00:00 2001 From: Youngsung Kim Date: Fri, 14 Nov 2025 10:39:50 -0500 Subject: [PATCH 050/398] loads gcc-native/12.3 module on Frontier, related to the issue #7886 --- cime_config/machines/config_machines.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 9bc4c7a971eb..1f7bda578397 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -1326,7 +1326,8 @@ Core/25.03 PrgEnv-gnu cpe/24.11 - libunwind/1.8.1 + gcc-native/12.3 + libunwind cray-python/3.11.7 subversion git From b362f414913c05970f38d0b9e25098156fb733f7 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Fri, 26 Jul 2024 16:12:00 -0500 Subject: [PATCH 051/398] add monthly and daily wave output streams bug fix (remove duplicate line) and update pio format. --- components/mpas-ocean/cime_config/buildnml | 44 +++++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index e7c4c949fd0b..066f23055f3e 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -996,16 +996,45 @@ def buildnml(case, caseroot, compname): lines.append('') lines.append('') if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': - 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(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append('') + lines.append('') + lines.append('') + lines.append(' packages="timeSeriesStatsDailyAMPKG">') lines.append('') lines.append(' ') lines.append(' ') @@ -1535,11 +1564,6 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') - if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') lines.append('') lines.append('') From e411c4ca50c8bb6706426686fe4e6b660e624c7a Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Mon, 12 Aug 2024 11:23:14 -0500 Subject: [PATCH 052/398] update PE layout for fully coupled wave compsets, clean up namelist scripts --- components/ww3/bld/build-namelist | 7 +------ components/ww3/cime_config/config_compsets.xml | 9 ++------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/components/ww3/bld/build-namelist b/components/ww3/bld/build-namelist index 092dab3ffba5..df2ac2c63186 100755 --- a/components/ww3/bld/build-namelist +++ b/components/ww3/bld/build-namelist @@ -354,7 +354,7 @@ if ($NML_TYPE eq "ww3_grid") { add_default($nl, 'timesteps%dtkth'); add_default($nl, 'timesteps%dtmin'); - add_default($nl, 'grid%name'); + add_default($nl, 'grid%name', 'val'=>"'${WAV_GRID}'"); add_default($nl, 'grid%nml'); add_default($nl, 'grid%type'); add_default($nl, 'grid%coord'); @@ -387,11 +387,6 @@ if ($NML_TYPE eq "ww3_grid_nml") { add_default($nl, 'unrot'); add_default($nl, 'ussp', 'val'=>"1"); - #add_default($nl, 'iussp', 'val'=>"3"); - #add_default($nl, 'stk_wn', 'val'=>"0.04,0.11,0.3305"); - #add_default($nl, 'stk_wn', 'val'=>"0.025,0.08,0.16,0.35"); - #add_default($nl, 'iussp', 'val'=>"4"); - #add_default($nl, 'stk_wn', 'val'=>"0.025,0.08,0.16,0.35"); add_default($nl, 'iussp', 'val'=>"6"); add_default($nl, 'stk_wn', 'val'=>"0.01,0.03,0.06,0.1,0.2,0.35"); diff --git a/components/ww3/cime_config/config_compsets.xml b/components/ww3/cime_config/config_compsets.xml index e54003b8d1d8..01de245a23b2 100644 --- a/components/ww3/cime_config/config_compsets.xml +++ b/components/ww3/cime_config/config_compsets.xml @@ -15,13 +15,8 @@ - VWW3-CFSv2 - 2000_DATM%CFSv2_SLND_SICE_SOCN_SROF_SGLC_WW3%sp36x36 - - - - VWW3-CFSR - 2000_DATM%CFSR_SLND_SICE_SOCN_SROF_SGLC_WW3%sp36x36 + VWW3-JRA1p5 + 2000_DATM%JRA-1p5_SLND_SICE_SOCN_SROF_SGLC_WW3%sp36x36 From 98f5b67b47eca9aa7639f61c7244a5817db392df Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 26 Sep 2024 10:15:11 -0500 Subject: [PATCH 053/398] fix wav coupling flags put wave output in default MPAS-O files (to ensure correct time series analysis member calculations) add wave to ocn flux cime_config/config_grids.xml wave to ocn flux driver-mct/cime_config/config_component.xml wave to ocn flux driver-mct/cime_config/namelist_definition_drv.xml flux wave to ocn prep_ocn_mod.F90 --- cime_config/config_grids.xml | 11 +++ components/mpas-ocean/cime_config/buildnml | 90 +++++++------------ driver-mct/cime_config/buildnml | 5 +- driver-mct/cime_config/config_component.xml | 17 ++++ .../cime_config/namelist_definition_drv.xml | 30 +++++++ driver-mct/main/prep_ocn_mod.F90 | 18 +++- 6 files changed, 110 insertions(+), 61 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index fa5c99769f0d..b84c997254da 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -3930,8 +3930,10 @@ ATM2ROF_FMAPNAME ATM2ROF_SMAPNAME ATM2WAV_SMAPNAME + WAV2ATM_SMAPNAME OCN2WAV_SMAPNAME WAV2OCN_SMAPNAME + WAV2OCN_FMAPNAME ICE2WAV_SMAPNAME ROF2OCN_LIQ_RMAPNAME @@ -5486,6 +5488,10 @@ cpl/gridmaps/wQU225Icos30E3r5/map_ne30pg2_to_wQU225Icos30E3r5_esmfbilin.20240910.nc +<<<<<<< HEAD +======= + cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_ne30pg2_esmfbilin.20240910.nc +>>>>>>> cd6a57fcd5 (add wave to ocn flux cime_config/config_grids.xml) @@ -5500,12 +5506,17 @@ cpl/gridmaps/wQU225EC30to60E2r2/map_wQU225EC30to60E2r2_TO_EC30to60E2r2_blin.20220222.nc + cpl/gridmaps/wQU225EC30to60E2r2/map_wQU225EC30to60E2r2_TO_EC30to60E2r2_aave.20220222.nc cpl/gridmaps/wQU225EC30to60E2r2/map_EC30to60E2r2_TO_wQU225EC30to60E2r2_blin.20220222.nc cpl/gridmaps/wQU225EC30to60E2r2/map_EC30to60E2r2_TO_wQU225EC30to60E2r2_blin.20220222.nc cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_IcoswISC30E3r5_esmfbilin.20240910.nc +<<<<<<< HEAD +======= + cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_IcoswISC30E3r5_esmfaave.20240910.nc +>>>>>>> cd6a57fcd5 (add wave to ocn flux cime_config/config_grids.xml) cpl/gridmaps/wQU225Icos30E3r5/map_IcoswISC30E3r5_to_wQU225Icos30E3r5_esmfbilin.20240910.nc cpl/gridmaps/wQU225Icos30E3r5/map_IcoswISC30E3r5_to_wQU225Icos30E3r5_esmfbilin.20240910.nc diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 066f23055f3e..2c9b2be56a57 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -995,64 +995,6 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append('') lines.append('') - if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': - 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(' ') - 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(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append(' ') - lines.append('') - lines.append('') lines.append('') lines.append(' ') lines.append(' ') + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') if ocn_bgc in ['eco_only', 'eco_and_dms', 'eco_and_macromolecules', 'eco_and_dms_and_macromolecules']: lines.append(' ') lines.append(' ') @@ -1386,6 +1333,15 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') if not (ocn_grid.startswith("oRRS1") or ocn_grid.startswith("RRSwISC6")): lines.append(' ') lines.append(' ') @@ -1594,6 +1550,15 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') if ocn_iceberg == 'true': lines.append(' ') @@ -1656,6 +1621,15 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') + lines.append(' ') if ocn_iceberg == 'true': lines.append(' ') diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 7af91afac075..7bb002f414b3 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -75,12 +75,13 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): # --------------------------------------------------- if case.get_value('COMP_WAV') == 'ww3': config['WAVSPEC'] = case.get_value('WAV_SPEC') - config['WAV_ATM_COUP'] = 'two' if case.get_value('COMP_ATM') == 'eam' else 'one' - config['WAV_ICE_COUP'] = 'two' if case.get_value('COMP_ICE') == 'mpassi' else 'one' + config['WAV_ATM_COUP'] = 'twoway' if case.get_value('COMP_ATM') == 'eam' else 'oneway' if case.get_value('COMP_OCN') == 'mpaso': config['WAV_OCN_COUP'] = 'twoway' elif case.get_value('COMP_OCN') == 'docn': config['WAV_OCN_COUP'] = 'oneway' + if case.get_value('COMP_ICE') == 'mpassi': + config['WAV_ICE_COUP'] = 'two' elif case.get_value('COMP_WAV') == 'dwav': config['WAVSPEC'] = 'sp36x36' else: diff --git a/driver-mct/cime_config/config_component.xml b/driver-mct/cime_config/config_component.xml index 752398a885ec..ad46211109e0 100644 --- a/driver-mct/cime_config/config_component.xml +++ b/driver-mct/cime_config/config_component.xml @@ -2054,6 +2054,23 @@ wav2ocn state mapping file decomp type + + char + idmap + run_domain + env_run.xml + wav2ocn flux mapping file + + + + char + X,Y + X + run_domain + env_run.xml + wav2ocn flux mapping file decomp type + + char idmap diff --git a/driver-mct/cime_config/namelist_definition_drv.xml b/driver-mct/cime_config/namelist_definition_drv.xml index 6831b41d7dab..59b824eea280 100644 --- a/driver-mct/cime_config/namelist_definition_drv.xml +++ b/driver-mct/cime_config/namelist_definition_drv.xml @@ -5125,6 +5125,36 @@ + + char + mapping + abs + seq_maps + + wav to ocn flux mapping file for fluxes + + + $WAV2OCN_FMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $WAV2OCN_FMAPTYPE + X + + + char(10) drv_physics diff --git a/driver-mct/main/prep_ocn_mod.F90 b/driver-mct/main/prep_ocn_mod.F90 index 1af5f0786d0d..32fc58992372 100644 --- a/driver-mct/main/prep_ocn_mod.F90 +++ b/driver-mct/main/prep_ocn_mod.F90 @@ -66,6 +66,7 @@ module prep_ocn_mod public :: prep_ocn_get_mapper_Sg2o public :: prep_ocn_get_mapper_Fg2o public :: prep_ocn_get_mapper_Sw2o + public :: prep_ocn_get_mapper_Fw2o !-------------------------------------------------------------------------- ! Private interfaces @@ -90,6 +91,7 @@ module prep_ocn_mod type(seq_map), pointer :: mapper_Fg2o type(seq_map), pointer :: mapper_Sg2o type(seq_map), pointer :: mapper_Sw2o + type(seq_map), pointer :: mapper_Fw2o ! attribute vectors type(mct_aVect), pointer :: a2x_ox(:) ! Atm export, ocn grid, cpl pes @@ -190,6 +192,7 @@ subroutine prep_ocn_init(infodata, atm_c2_ocn, atm_c2_ice, ice_c2_ocn, rof_c2_oc allocate(mapper_Sg2o) allocate(mapper_Fg2o) allocate(mapper_Sw2o) + allocate(mapper_Fw2o) if (ocn_present) then @@ -382,6 +385,13 @@ subroutine prep_ocn_init(infodata, atm_c2_ocn, atm_c2_ice, ice_c2_ocn, rof_c2_oc call seq_map_init_rcfile(mapper_Sw2o, wav(1), ocn(1), & 'seq_maps.rc', 'wav2ocn_smapname:', 'wav2ocn_smaptype:',samegrid_ow, & 'mapper_Sw2o initialization') + if (iamroot_CPLID) then + write(logunit,*) ' ' + write(logunit,F00) 'Initializing mapper_Fw2o' + end if + call seq_map_init_rcfile(mapper_Fw2o, wav(1), ocn(1), & + 'seq_maps.rc', 'wav2ocn_fmapname:', 'wav2ocn_fmaptype:',samegrid_ow, & + 'mapper_Fw2o initialization') endif call shr_sys_flush(logunit) @@ -1447,7 +1457,8 @@ subroutine prep_ocn_calc_w2x_ox(timer) call t_drvstartf (trim(timer),barrier=mpicom_CPLID) do ewi = 1,num_inst_wav w2x_wx => component_get_c2x_cx(wav(ewi)) - call seq_map_map(mapper_Sw2o, w2x_wx, w2x_ox(ewi), norm=.true.) + call seq_map_map(mapper_Sw2o, w2x_wx, w2x_ox(ewi),fldlist=seq_flds_w2x_states, norm=.true.) + call seq_map_map(mapper_Fw2o, w2x_wx, w2x_ox(ewi),fldlist=seq_flds_w2x_fluxes, norm=.true.) enddo call t_drvstopf (trim(timer)) end subroutine prep_ocn_calc_w2x_ox @@ -1549,4 +1560,9 @@ function prep_ocn_get_mapper_Sw2o() prep_ocn_get_mapper_Sw2o => mapper_Sw2o end function prep_ocn_get_mapper_Sw2o + function prep_ocn_get_mapper_Fw2o() + type(seq_map), pointer :: prep_ocn_get_mapper_Fw2o + prep_ocn_get_mapper_Fw2o => mapper_Fw2o + end function prep_ocn_get_mapper_Fw2o + end module prep_ocn_mod From 3bb07921476a131d554a655bfd2b6bdd83312d81 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Wed, 6 Nov 2024 14:53:48 -0600 Subject: [PATCH 054/398] fix rebase on ICOS mesh add wav2atm smap remove 'two' way coupling option from wav_ic_coup add WAV2ATM remap file for EC30to60 grid add wave to atm remapping for T319 grid add wave output remove duplicate lines --- cime_config/config_grids.xml | 8 ++--- components/mpas-ocean/cime_config/buildnml | 4 +++ components/ww3/src/cpl/wav_comp_mct.F90 | 6 ---- driver-mct/cime_config/buildnml | 2 +- driver-mct/cime_config/config_component.xml | 17 ++++++++++ .../cime_config/namelist_definition_drv.xml | 31 +++++++++++++++++++ 6 files changed, 55 insertions(+), 13 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index b84c997254da..e37e41af8f0d 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -5484,18 +5484,17 @@ cpl/gridmaps/wQU225EC30to60E2r2/map_ne30pg2_TO_wQU225EC30to60E2r2_blin.20220222.nc + cpl/gridmaps/wQU225EC30to60E2r2/map_wQU225EC30to60E2r2_TO_ne30pg2_blin.20220222.nc cpl/gridmaps/wQU225Icos30E3r5/map_ne30pg2_to_wQU225Icos30E3r5_esmfbilin.20240910.nc -<<<<<<< HEAD -======= cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_ne30pg2_esmfbilin.20240910.nc ->>>>>>> cd6a57fcd5 (add wave to ocn flux cime_config/config_grids.xml) cpl/gridmaps/wQU225EC30to60E2r2/map_TL319_TO_wQU225EC30to60E2r2_blin.20220602.nc + cpl/gridmaps/wQU225EC30to60E2r2/map_wQU225EC30to60E2r2_TO_TL319_blin.20220602.nc @@ -5513,10 +5512,7 @@ cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_IcoswISC30E3r5_esmfbilin.20240910.nc -<<<<<<< HEAD -======= cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_IcoswISC30E3r5_esmfaave.20240910.nc ->>>>>>> cd6a57fcd5 (add wave to ocn flux cime_config/config_grids.xml) cpl/gridmaps/wQU225Icos30E3r5/map_IcoswISC30E3r5_to_wQU225Icos30E3r5_esmfbilin.20240910.nc cpl/gridmaps/wQU225Icos30E3r5/map_IcoswISC30E3r5_to_wQU225Icos30E3r5_esmfbilin.20240910.nc diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index 2c9b2be56a57..d684025fdcb2 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -976,6 +976,10 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') + if case.get_value('COMP_WAV') == 'ww3' and case.get_value('COMP_OCN') == 'mpaso': + lines.append(' ') + lines.append(' ') + lines.append(' ') if ocn_bgc in ['eco_only', 'eco_and_dms', 'eco_and_macromolecules', 'eco_and_dms_and_macromolecules']: lines.append(' ') lines.append(' ') diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index 1b81e7768c12..201f47440e6e 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -1189,12 +1189,6 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_Hs,jsea) = HS(jsea) w2x_w%rattr(index_w2x_Sw_Fp,jsea) = FP0(jsea) w2x_w%rattr(index_w2x_Sw_Dp,jsea) = THP0(jsea) - w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) - w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) - w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) - w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 1000*TAUOY(jsea) - w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = TAUOCX(jsea) - w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_1,jsea) = USSP(jsea,1) w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_1,jsea) = USSP(jsea,nk+1) diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 7bb002f414b3..8cd2e2b723f5 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -81,7 +81,7 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): elif case.get_value('COMP_OCN') == 'docn': config['WAV_OCN_COUP'] = 'oneway' if case.get_value('COMP_ICE') == 'mpassi': - config['WAV_ICE_COUP'] = 'two' + config['WAV_ICE_COUP'] = 'one' elif case.get_value('COMP_WAV') == 'dwav': config['WAVSPEC'] = 'sp36x36' else: diff --git a/driver-mct/cime_config/config_component.xml b/driver-mct/cime_config/config_component.xml index ad46211109e0..75469c5babd6 100644 --- a/driver-mct/cime_config/config_component.xml +++ b/driver-mct/cime_config/config_component.xml @@ -1535,6 +1535,23 @@ atm2wav state mapping file decomp type + + char + idmap + run_domain + env_run.xml + wav2atm state mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + wav2atm state mapping file decomp type + + char idmap diff --git a/driver-mct/cime_config/namelist_definition_drv.xml b/driver-mct/cime_config/namelist_definition_drv.xml index 59b824eea280..662b7217d95a 100644 --- a/driver-mct/cime_config/namelist_definition_drv.xml +++ b/driver-mct/cime_config/namelist_definition_drv.xml @@ -5035,6 +5035,37 @@ + + char + mapping + abs + seq_maps + + atm to wav state mapping file for states + + + $WAV2ATM_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $WAV2ATM_SMAPTYPE + X + + + + char mapping From e4a8f77d686999147ae6c70f9d0f1215d91570e2 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 16 Jan 2025 17:30:46 -0600 Subject: [PATCH 055/398] preliminary PR layouts for WW3 compsets Chrysalis,anvil,pm-cpu --- components/ww3/cime_config/config_pes.xml | 218 ++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/components/ww3/cime_config/config_pes.xml b/components/ww3/cime_config/config_pes.xml index b0ece74ac235..80acf5edc2ea 100644 --- a/components/ww3/cime_config/config_pes.xml +++ b/components/ww3/cime_config/config_pes.xml @@ -34,4 +34,222 @@ + + + + D + WW3 + + 180 + 180 + 180 + 180 + 180 + 180 + 180 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 180 + + + + G + WW3 + + 648 + 648 + 648 + 648 + 648 + 648 + 648 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 648 + + + + WCYCL* + WW3 ~4.9 SYPD + + 1350 + 72 + 72 + 1296 + 180 + 1368 + 216 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 1296 + 1296 + 0 + 1368 + 0 + 1548 + + + + + + D + WW3 + + 320 + 320 + 320 + 320 + 320 + 320 + 320 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 320 + + + + G + WW3 + + 640 + 640 + 640 + 640 + 640 + 640 + 512 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 640 + + + + WCYCL* + WW3 ~4.8 SYPD + + 675 + 192 + 192 + 512 + 192 + 704 + 640 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 512 + 512 + 0 + 704 + 0 + 896 + + + + + + --compset WCYCL* + WW3 ~4.1 SYPD + + 1080 + 384 + 384 + 768 + 512 + 1152 + 1280 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 768 + 768 + 0 + 1152 + 0 + 1664 + + + + From 79c42ab49838dfedee75ac319a4444ceed7d4100 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 11 Feb 2025 09:44:08 -0600 Subject: [PATCH 056/398] ensure use of default sfc flux scheme with wave coupling modify default sfc flux scheme for waves TL319 to Icos wave mesh fixes --- cime_config/config_grids.xml | 15 ++++++ driver-mct/cime_config/buildnml | 11 +++-- share/util/shr_flux_mod.F90 | 87 +++++++++++++++++++++++++++------ 3 files changed, 92 insertions(+), 21 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index e37e41af8f0d..27b26e2a9702 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -2477,6 +2477,16 @@ EC30to60E2r2 + + TL319 + TL319 + IcoswISC30E3r5 + JRA025 + null + wQU225Icos30E3r5 + IcoswISC30E3r5 + + ne16np4 ne16np4 @@ -5497,6 +5507,11 @@ cpl/gridmaps/wQU225EC30to60E2r2/map_wQU225EC30to60E2r2_TO_TL319_blin.20220602.nc + + cpl/gridmaps/wQU225Icos30E3r5/map_TL319_to_wQU225Icos30E3r5_esmfbilin.20250128.nc + cpl/gridmaps/wQU225Icos30E3r5/map_wQU225Icos30E3r5_to_TL319_esmfbilin.20250128.nc + + cpl/gridmaps/wQU225EC60to30/map_wQU225EC60to30_TO_oEC60to30v3_blin.20210428.nc cpl/gridmaps/wQU225EC60to30/map_oEC60to30v3_TO_wQU225EC60to30_blin.20210428.nc diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 8cd2e2b723f5..0356292c7e69 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -78,16 +78,17 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): config['WAV_ATM_COUP'] = 'twoway' if case.get_value('COMP_ATM') == 'eam' else 'oneway' if case.get_value('COMP_OCN') == 'mpaso': config['WAV_OCN_COUP'] = 'twoway' + config['ocn_surface_flux_scheme'] = 0 elif case.get_value('COMP_OCN') == 'docn': config['WAV_OCN_COUP'] = 'oneway' - if case.get_value('COMP_ICE') == 'mpassi': - config['WAV_ICE_COUP'] = 'one' + if case.get_value('COMP_ICE') == 'mpassi': + config['WAV_ICE_COUP'] = 'oneway' elif case.get_value('COMP_WAV') == 'dwav': - config['WAVSPEC'] = 'sp36x36' + config['WAVSPEC'] = 'sp36x36' else: - config['WAVSPEC'] = 'none' + config['WAVSPEC'] = 'none' - #---------------------------------------------------- + #---------------------------------------------------- # Initialize namelist defaults #---------------------------------------------------- nmlgen.init_defaults(infile, config) diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index 7f8a776a2c87..efe6c7eb6cff 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -150,7 +150,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & & taux ,tauy ,tref ,qref , & & ocn_surface_flux_scheme, & & duu10n, u10res, ustar_sv ,re_sv ,ssq_sv, & - & missval, wsresp, tau_est, ugust, charnockSeaState) + & missval, wsresp, tau_est, ugust, z0_wav, ustar_wav, charnockSeaState) ! !USES: @@ -206,6 +206,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & real(R8),intent(in) ,optional :: wsresp(nMax) ! boundary layer wind response to stress (m/s/Pa) real(R8),intent(in) ,optional :: tau_est(nMax) ! stress in equilibrium with boundary layer (Pa) real(R8),intent(in) ,optional :: ugust(nMax) ! extra wind speed from gustiness (m/s) + real(R8),intent(in) ,optional :: z0_wav(nMax) !surface roughness length from WW3 + real(R8),intent(in) ,optional :: ustar_wav(nMax) !friction velocity from WW3 real(R8),intent(in) ,optional :: charnockSeaState(nMax) !Charnock coeff accounting for the wave stress (Janssen 1989, 1991) ! !EOP @@ -257,6 +259,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & real(R8) :: tau_diff ! difference in tau across iterations (Pa) real(R8) :: prev_tau_diff ! previous value of tau_diff (Pa) real(R8) :: wind_adj ! iteration-adjusted wind speed (m/s) +!!++ Large with waves + real(R8) :: cdn_wav !!++ COARE only real(R8) :: zo,zot,zoq ! roughness lengths real(R8) :: hsb,hlb ! sens & lat heat flxs at zbot @@ -277,12 +281,11 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & real(R8) :: tdiff(nMax) ! tbot - ts real(R8) :: vscl - qsat(Tk) = 640380.0_R8 / exp(5107.4_R8/Tk) cdn(Umps) = 0.0027_R8 / Umps + 0.000142_R8 + 0.0000764_R8 * Umps psimhu(xd) = log((1.0_R8+xd*(2.0_R8+xd))*(1.0_R8+xd*xd)/8.0_R8) - 2.0_R8*atan(xd) + 1.571_R8 psixhu(xd) = 2.0_R8 * log((1.0_R8 + xd*xd)/2.0_R8) - + !--- formats ---------------------------------------- character(*),parameter :: subName = '(shr_flux_atmOcn) ' character(*),parameter :: F00 = "('(shr_flux_atmOcn) ',4a)" @@ -364,16 +367,31 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !------------------------------------------------------------ !--- neutral coefficients, z/L = 0.0 --- stable = 0.5_R8 + sign(0.5_R8 , delt) - rdn = sqrt(cdn(vmag)) + if (wav_atm_coup .eq. 'two') then + cdn_wav = cdn_wave(loc_karman,zref,z0_wav) + rdn = sqrt(cdn_wav) + ! rdn calculated from Z0 will be constant + else + rdn = sqrt(cdn(vmag)) + endif rhn = (1.0_R8-stable) * 0.0327_R8 + stable * 0.018_R8 !(1.0_R8-stable) * chxcdu + stable * chxcds ren = 0.0346_R8 !cexcd !--- ustar, tstar, qstar --- - ustar = rdn * vmag + write(s_logunit,*) 'ET EDIT: ustar first', ustar + if (wav_atm_coup .eq. 'two') then + ustar = ustar_wav + else + ustar = rdn * vmag + endif tstar = rhn * delt qstar = ren * delq ustar_prev = ustar*2.0_R8 + write(s_logunit,*) 'ET EDIT: z0', z0_wav + write(s_logunit,*) 'ET EDIT: cdn_wav:', cdn_wav + write(s_logunit,*) 'ET EDIT: rdn:', rdn + write(s_logunit,*) 'ET EDIT: ustar first', ustar if (present(wsresp) .and. present(tau_est)) prev_tau = tau_est(n) tau_diff = 1.e100_R8 wind_adj = wind0 @@ -406,16 +424,18 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & xqq = sqrt(xsq) psimh = -5.0_R8*hol*stable + (1.0_R8-stable)*psimhu(xqq) psixh = -5.0_R8*hol*stable + (1.0_R8-stable)*psixhu(xqq) - - !--- shift wind speed using old coefficient --- - rd = rdn / max(1.0_R8 + rdn/loc_karman*(alz-psimh), 1.e-3_r8) - u10n = vmag * rd / rdn - - !--- update transfer coeffs at 10m and neutral stability --- - rdn = sqrt(cdn(u10n)) - ren = 0.0346_R8 !cexcd - rhn = (1.0_R8-stable)*0.0327_R8 + stable * 0.018_R8 - !(1.0_R8-stable) * chxcdu + stable * chxcds + + if (wav_atm_coup .ne. 'two') then + !--- shift wind speed using old coefficient --- + rd = rdn / max(1.0_R8 + rdn/loc_karman*(alz-psimh), 1.e-3_r8) + u10n = vmag * rd / rdn + + !--- update transfer coeffs at 10m and neutral stability --- + rdn = sqrt(cdn(u10n)) + ren = 0.0346_R8 !cexcd + rhn = (1.0_R8-stable)*0.0327_R8 + stable * 0.018_R8 + !(1.0_R8-stable) * chxcdu + stable * chxcds + endif !--- shift all coeffs to measurement height and stability --- rd = rdn / max(1.0_R8 + rdn/loc_karman*(alz-psimh), 1.e-3_r8) @@ -1133,6 +1153,41 @@ SUBROUTINE shr_flux_atmOcn_UA( & END subroutine shr_flux_atmOcn_UA +!=============================================================================== +! Functions used by default surface flux scheme for Wave Coupling +!=============================================================================== +function z0_wave(charn, us, g) result(z0_wav) + implicit none + + ! input variables + real(R8), intent(in) :: charn ! charcnock parameter + real(R8), intent(in) :: us ! u star + real(R8), intent(in) :: g ! gravity + + ! local variables + real(R8) :: z0_wav + + z0_wav = charn * (us**2) / g + +end function zo_wave + +function cdn_wave(kappa,zr,z0) result(cdn_wav) + implicit none + + ! input variables + real(R8), intent(in) :: kappa !von Karmen constant + real(R8), intent(in) :: zr ! reference height (10m) + real(R8), intent(in) :: z0 ! roughness length based on wave state + + ! local variables + real(R8) :: a, b + real(R8) :: cdn_wav + + a = zr / z0 + b = log(a) + cdn_wav = (kappa**2) / (b**2) + +end function cdn_wave !=============================================================================== ! Functions/subroutines used by UA surface flux scheme. !=============================================================================== @@ -1140,7 +1195,7 @@ END subroutine shr_flux_atmOcn_UA ! Stability function for rb < 0 real(R8) function psi_ua(k,zeta) - + implicit none !-----Input variables.---------- From a6b72fd0da667dd8e8353ee33fc117db252048bc Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Fri, 4 Apr 2025 11:50:43 -0500 Subject: [PATCH 057/398] adding ustar and z0 from ww3 typo correction --- .../mpas-ocean/driver/mpaso_cpl_indices.F | 4 ++++ components/mpas-ocean/driver/ocn_comp_mct.F | 22 +++++++++++++++++++ .../namelist_files/namelist_defaults_ww3.xml | 2 +- components/ww3/src/cpl/wav_comp_mct.F90 | 9 ++++++-- components/ww3/src/cpl/ww3_cpl_indices.f90 | 5 +++++ driver-mct/main/seq_flux_mct.F90 | 20 +++++++++++++++-- driver-mct/shr/seq_flds_mod.F90 | 15 +++++++++++++ share/util/shr_flux_mod.F90 | 18 +++++++-------- 8 files changed, 81 insertions(+), 14 deletions(-) diff --git a/components/mpas-ocean/driver/mpaso_cpl_indices.F b/components/mpas-ocean/driver/mpaso_cpl_indices.F index 77ab3ff269cb..d0732ce9a9b3 100644 --- a/components/mpas-ocean/driver/mpaso_cpl_indices.F +++ b/components/mpas-ocean/driver/mpaso_cpl_indices.F @@ -137,6 +137,8 @@ module mpaso_cpl_indices integer :: index_x2o_Sw_Hs ! Significant wave height integer :: index_x2o_Sw_Fp ! Peak wave frequency integer :: index_x2o_Sw_Dp ! Peak wave direction + integer :: index_x2o_Sw_Z0 ! surface roughness length from WW3 + integer :: index_x2o_Sw_Ustar ! Friction velocity from WW3 integer :: index_x2o_Sw_Charn !Charnock coefficient accounting for the wave stress integer :: index_x2o_Faww_Tawx !Wave supported stress integer :: index_x2o_Faww_Tawy !Wave supported stress @@ -364,6 +366,8 @@ subroutine mpaso_cpl_indices_set( ) index_x2o_Sw_Hs = mct_avect_indexra(x2o,'Sw_Hs') index_x2o_Sw_Fp = mct_avect_indexra(x2o,'Sw_Fp') index_x2o_Sw_Dp = mct_avect_indexra(x2o,'Sw_Dp') + index_x2o_Sw_Z0 = mct_avect_indexra(x2o,'Sw_Z0') + index_x2o_Sw_Ustar = mct_avect_indexra(x2o,'Sw_Ustar') index_x2o_Sw_Charn = mct_avect_indexra(x2o,'Sw_Charn') index_x2o_Faww_Tawx = mct_avect_indexra(x2o,'Faww_Tawx') index_x2o_Faww_Tawy = mct_avect_indexra(x2o,'Faww_Tawy') diff --git a/components/mpas-ocean/driver/ocn_comp_mct.F b/components/mpas-ocean/driver/ocn_comp_mct.F index 200f2c0be954..0e83fbf634c8 100644 --- a/components/mpas-ocean/driver/ocn_comp_mct.F +++ b/components/mpas-ocean/driver/ocn_comp_mct.F @@ -2136,6 +2136,8 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ significantWaveHeightField, & peakWaveFrequencyField, & peakWaveDirectionField, & + z0wavField, & + ustarwavField, & charnockSeaStateField, & waveSupportedZonalWindStressField, & waveSupportedMeridionalWindStressField, & @@ -2195,6 +2197,8 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ significantWaveHeight, & peakWaveFrequency, & peakWaveDirection, & + z0wav, & + ustarwav, & charnockSeaState, & waveSupportedZonalWindStress, & waveSupportedMeridionalWindStress, & @@ -2300,6 +2304,8 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ call mpas_pool_get_field(forcingPool, 'significantWaveHeight', significantWaveHeightField) call mpas_pool_get_field(forcingPool, 'peakWaveFrequency', peakWaveFrequencyField) call mpas_pool_get_field(forcingPool, 'peakWaveDirection', peakWaveDirectionField) + call mpas_pool_get_field(forcingPool, 'z0wav', z0wavField) + call mpas_pool_get_field(forcingPool, 'ustarwav', ustarwavField) call mpas_pool_get_field(forcingPool, 'charnockSeaState', charnockSeaStateField) call mpas_pool_get_field(forcingPool, 'waveSupportedZonalWindStress', waveSupportedZonalWindStressField) call mpas_pool_get_field(forcingPool, 'waveSupportedMeridionalWindStress', waveSupportedMeridionalWindStressField) @@ -2353,6 +2359,8 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ significantWaveHeight => significantWaveHeightField % array peakWaveFrequency => peakWaveFrequencyField % array peakWaveDirection => peakWaveDirectionField % array + z0wav => z0wavField % array + ustarwav => ustarwavField % array charnockSeaState => charnockSeaStateField % array waveSupportedZonalWindStress => waveSupportedZonalWindStressField % array waveSupportedMeridionalWindStress => waveSupportedMeridionalWindStressField % array @@ -2578,6 +2586,12 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ if ( peakWaveDirectionField % isActive ) then peakWaveDirection(i) = x2o_o % rAttr(index_x2o_Sw_Dp, n) end if + if ( z0wavField % isActive ) then + z0wav(i) = x2o_o % rAttr(index_x2o_Sw_Z0, n) + end if + if ( ustarwavField % isActive ) then + ustarwav(i) = x2o_o % rAttr(index_x2o_Sw_Ustar, n) + end if if ( charnockSeaStateField % isActive ) then charnockSeaState(i) = x2o_o % rAttr(index_x2o_Sw_Charn, n) end if @@ -2777,6 +2791,8 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ call mpas_pool_get_field(forcingPool, 'significantWaveHeight', significantWaveHeightField) call mpas_pool_get_field(forcingPool, 'peakWaveFrequency', peakWaveFrequencyField) call mpas_pool_get_field(forcingPool, 'peakWaveDirection', peakWaveDirectionField) + call mpas_pool_get_field(forcingPool, 'z0wav', z0wavField) + call mpas_pool_get_field(forcingPool, 'ustarwav', ustarwavField) call mpas_pool_get_field(forcingPool, 'charnockSeaState', charnockSeaStateField) call mpas_pool_get_field(forcingPool, 'waveSupportedZonalWindStress', waveSupportedZonalWindStressField) call mpas_pool_get_field(forcingPool, 'waveSupportedMeridionalWindStress', waveSupportedMeridionalWindStressField) @@ -2920,6 +2936,12 @@ subroutine ocn_import_mct(x2o_o, errorCode)!{{{ if ( peakWaveDirectionField % isActive ) then call mpas_dmpar_exch_halo_field(peakWaveDirectionField) end if + if ( z0wavField % isActive ) then + call mpas_dmpar_exch_halo_field(z0wavField) + end if + if ( ustarwavField % isActive ) then + call mpas_dmpar_exch_halo_field(ustarwavField) + end if if ( charnockSeaStateField % isActive ) then call mpas_dmpar_exch_halo_field(charnockSeaStateField) end if diff --git a/components/ww3/bld/namelist_files/namelist_defaults_ww3.xml b/components/ww3/bld/namelist_files/namelist_defaults_ww3.xml index 63b12122c85d..19e363a32bcf 100644 --- a/components/ww3/bld/namelist_files/namelist_defaults_ww3.xml +++ b/components/ww3/bld/namelist_files/namelist_defaults_ww3.xml @@ -19,7 +19,7 @@ attributes to express the dependency. 0 0 "WND HS FP DP USS" -"USS USP HS FP DP" +"USS USP HS FP DP CHA UST U1" diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index 201f47440e6e..cad41040caea 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -137,7 +137,7 @@ MODULE WAV_COMP_MCT usspf use w3wdatmd, only: time, w3ndat, w3setw, wlv, va, ust, ice use w3adatmd, only: ussp, w3naux, w3seta, sxx, sxy, syy, fliwnd, flcold, dw, cg, wn, hs, fp0, thp0, & - charn, tauwix, tauwiy, tauox, tauoy, tauocx, tauocy + charn, tauwix, tauwiy, tauox, tauoy, tauocx, tauocy, usero use w3idatmd, only: inflags1, inflags2,w3seti, w3ninp USE W3IDATMD, ONLY: TC0, CX0, CY0, TCN, CXN, CYN, ICEP1, ICEP5, TI1, TI5 USE W3IDATMD, ONLY: TW0, WX0, WY0, DT0, TWN, WXN, WYN, DTN @@ -175,7 +175,8 @@ MODULE WAV_COMP_MCT index_w2x_Sw_ustokes_wavenumber_4, index_w2x_Sw_vstokes_wavenumber_4, & index_w2x_Sw_ustokes_wavenumber_5, index_w2x_Sw_vstokes_wavenumber_5, & index_w2x_Sw_ustokes_wavenumber_6, index_w2x_Sw_vstokes_wavenumber_6, & - index_w2x_Sw_Hs, index_w2x_Sw_Fp, index_w2x_Sw_Dp, index_w2x_Sw_Charn, & + index_w2x_Sw_Hs, index_w2x_Sw_Fp, index_w2x_Sw_Dp, & + index_w2x_Sw_Charn, index_w2x_Sw_Ustar, index_w2x_Sw_Z0, & index_w2x_Faww_Tawx, index_w2x_Faww_Tawy, index_w2x_Fwow_Twox, & index_w2x_Fwow_Twoy, index_w2x_Faow_Tocx, index_w2x_Faow_Tocy @@ -1184,6 +1185,8 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Charn,jsea) = CHARN(jsea) + w2x_w%rattr(index_w2x_Sw_Ustar,jsea) = UST(jsea) ! Friction velocity + w2x_w%rattr(index_w2x_Sw_Z0,jsea) = USERO(jsea,1) ! Z0 surface roughness length endif if (wav_ocn_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Hs,jsea) = HS(jsea) @@ -1210,6 +1213,8 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) else if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Charn,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_Ustar,jsea) = 0.0 + w2x_w%rattr(index_w2x_Sw_Z0,jsea) = 0.0 endif if (wav_ocn_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Hs,jsea) = 0.0 diff --git a/components/ww3/src/cpl/ww3_cpl_indices.f90 b/components/ww3/src/cpl/ww3_cpl_indices.f90 index f105a7ecabb5..7a4ac961624a 100644 --- a/components/ww3/src/cpl/ww3_cpl_indices.f90 +++ b/components/ww3/src/cpl/ww3_cpl_indices.f90 @@ -37,6 +37,9 @@ module ww3_cpl_indices integer :: index_w2x_Sw_Fp integer :: index_w2x_Sw_Dp integer :: index_w2x_Sw_Charn + integer :: index_w2x_Sw_Ustar + integer :: index_w2x_Sw_Z0 + integer :: index_w2x_Faww_Tawx integer :: index_w2x_Faww_Tawy integer :: index_w2x_Fwow_Twox @@ -72,6 +75,8 @@ subroutine ww3_cpl_indices_set( ) if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then index_w2x_Sw_Charn = mct_avect_indexra(w2x,'Sw_Charn') ! Charnock coeff accounting for the wave stress (Janssen 1989, 1991) + index_w2x_Sw_Ustar = mct_avect_indexra(w2x,'Sw_Ustar') ! Friction velocity + index_w2x_Sw_Z0 = mct_avect_indexra(w2x,'Sw_Z0') ! Roughness length endif if (wav_ocn_coup .eq. 'twoway') then index_w2x_Sw_Hs = mct_avect_indexra(w2x,'Sw_Hs') ! Significant wave height diff --git a/driver-mct/main/seq_flux_mct.F90 b/driver-mct/main/seq_flux_mct.F90 index e4ceabbdd17e..dfd0efa855d1 100644 --- a/driver-mct/main/seq_flux_mct.F90 +++ b/driver-mct/main/seq_flux_mct.F90 @@ -47,6 +47,8 @@ module seq_flux_mct real(r8), allocatable :: vbot (:) ! atm velocity, meridional real(r8), allocatable :: wsresp(:) ! atm response to surface stress real(r8), allocatable :: charnsea(:) ! Charnock coeff accounting for the wave stress + real(r8), allocatable :: ustarwav(:) ! Friction velocity from WW3 + real(r8), allocatable :: z0wav(:) ! Surface roughness length from WW3 real(r8), allocatable :: tau_est(:)! estimation of tau in equilibrium with wind real(r8), allocatable :: ugust_atm(:) ! atm gustiness real(r8), allocatable :: thbot(:) ! atm potential T @@ -147,6 +149,8 @@ module seq_flux_mct integer :: index_o2x_So_u integer :: index_o2x_So_v integer :: index_w2x_Sw_Charn + integer :: index_w2x_Sw_Z0 + integer :: index_w2x_Sw_Ustar integer :: index_o2x_So_fswpen integer :: index_o2x_So_s integer :: index_o2x_So_roce_16O @@ -301,6 +305,12 @@ subroutine seq_flux_init_mct(comp, fractions) allocate( charnsea(nloc),stat=ier) if(ier/=0) call mct_die(subName,'allocate charnsea',ier) charnsea = 0.0_r8 + allocate( ustarwav(nloc),stat=ier) + if(ier/=0) call mct_die(subName,'allocate ustarwav',ier) + ustarwav = 0.0_r8 + allocate( z0wav(nloc),stat=ier) + if(ier/=0) call mct_die(subName,'allocate z0wav',ier) + z0wav = 0.0_r8 allocate( tocn(nloc),stat=ier) if(ier/=0) call mct_die(subName,'allocate tocn',ier) @@ -1455,6 +1465,8 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) index_o2x_So_roce_18O = mct_aVect_indexRA(o2x,'So_roce_18O', perrWith='quiet') if (wav_ocn_coup == 'two' .or. wav_atm_coup == 'two') then index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') + index_w2x_Sw_Z0 = mct_aVect_indexRA(w2x,'Sw_Z0') + index_w2x_Sw_Ustar = mct_aVect_indexRA(w2x,'Sw_Ustar') endif call shr_flux_adjust_constants(flux_convergence_tolerance=flux_convergence, & flux_convergence_max_iteration=flux_max_iteration, & @@ -1560,7 +1572,11 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) tocn(n) = o2x%rAttr(index_o2x_So_t ,n) uocn(n) = o2x%rAttr(index_o2x_So_u ,n) vocn(n) = o2x%rAttr(index_o2x_So_v ,n) - if (wav_atm_coup == 'two') charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) + if (wav_atm_coup == 'two') then + charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) + ustarwav(n) = w2x%rAttr(index_w2x_Sw_Ustar ,n) + z0wav(n) = w2x%rAttr(index_w2x_Sw_Z0 ,n) + endif if ( index_o2x_So_roce_16O /= 0 ) roce_16O(n) = o2x%rAttr(index_o2x_So_roce_16O, n) if ( index_o2x_So_roce_HDO /= 0 ) roce_HDO(n) = o2x%rAttr(index_o2x_So_roce_HDO, n) if ( index_o2x_So_roce_18O /= 0 ) roce_18O(n) = o2x%rAttr(index_o2x_So_roce_18O, n) @@ -1649,7 +1665,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) ocn_surface_flux_scheme, & duu10n, u10res, ustar, re , ssq, & wsresp=wsresp, tau_est=tau_est, ugust=ugust_atm, & - charnockSeaState=charnsea) + z0wav=z0wav, ustarwav=ustarwav, charnockSeaState=charnsea) else call shr_flux_atmocn (nloc , zbot , ubot, vbot, thbot, & shum , shum_16O , shum_HDO, shum_18O, dens , tbot, uocn, vocn , & diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 6b16a9712b07..6d9f428dad34 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -2729,6 +2729,21 @@ subroutine seq_flds_set(nmlfile, ID, infodata) units = '' attname = 'Sw_Charn' call metadata_set(attname, longname, stdname, units) + call seq_flds_add(w2x_states,'Sw_Ustar') + if (wav_ocn_coup == 'two') call seq_flds_add(x2o_states,'Sw_Ustar') + longname = 'Friction Velocity based on sea state' + stdname = 'Frcition_velocity_based_on_sea_state' + units = '' + attname = 'Sw_Ustar' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_states,'Sw_Z0') + if (wav_ocn_coup == 'two') call seq_flds_add(x2o_states,'Sw_Z0') + longname = 'Surface Roughness Length based on wave state' + stdname = 'Surface_roughness_length_based_on_wave_state' + units = '' + attname = 'Sw_Z0' + call metadata_set(attname, longname, stdname, units) endif !---------------------------- diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index efe6c7eb6cff..9f2724309627 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -150,7 +150,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & & taux ,tauy ,tref ,qref , & & ocn_surface_flux_scheme, & & duu10n, u10res, ustar_sv ,re_sv ,ssq_sv, & - & missval, wsresp, tau_est, ugust, z0_wav, ustar_wav, charnockSeaState) + & missval, wsresp, tau_est, ugust, z0wav, ustarwav, charnockSeaState) ! !USES: @@ -206,8 +206,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & real(R8),intent(in) ,optional :: wsresp(nMax) ! boundary layer wind response to stress (m/s/Pa) real(R8),intent(in) ,optional :: tau_est(nMax) ! stress in equilibrium with boundary layer (Pa) real(R8),intent(in) ,optional :: ugust(nMax) ! extra wind speed from gustiness (m/s) - real(R8),intent(in) ,optional :: z0_wav(nMax) !surface roughness length from WW3 - real(R8),intent(in) ,optional :: ustar_wav(nMax) !friction velocity from WW3 + real(R8),intent(in) ,optional :: z0wav(nMax) !surface roughness length from WW3 + real(R8),intent(in) ,optional :: ustarwav(nMax) !friction velocity from WW3 real(R8),intent(in) ,optional :: charnockSeaState(nMax) !Charnock coeff accounting for the wave stress (Janssen 1989, 1991) ! !EOP @@ -368,7 +368,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- neutral coefficients, z/L = 0.0 --- stable = 0.5_R8 + sign(0.5_R8 , delt) if (wav_atm_coup .eq. 'two') then - cdn_wav = cdn_wave(loc_karman,zref,z0_wav) + cdn_wav = cdn_wave(loc_karman,zref,z0wav) rdn = sqrt(cdn_wav) ! rdn calculated from Z0 will be constant else @@ -388,7 +388,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & tstar = rhn * delt qstar = ren * delq ustar_prev = ustar*2.0_R8 - write(s_logunit,*) 'ET EDIT: z0', z0_wav + write(s_logunit,*) 'ET EDIT: z0', z0wav write(s_logunit,*) 'ET EDIT: cdn_wav:', cdn_wav write(s_logunit,*) 'ET EDIT: rdn:', rdn write(s_logunit,*) 'ET EDIT: ustar first', ustar @@ -1156,7 +1156,7 @@ END subroutine shr_flux_atmOcn_UA !=============================================================================== ! Functions used by default surface flux scheme for Wave Coupling !=============================================================================== -function z0_wave(charn, us, g) result(z0_wav) +function z0_wave(charn, us, g) result(z0wav) implicit none ! input variables @@ -1165,11 +1165,11 @@ function z0_wave(charn, us, g) result(z0_wav) real(R8), intent(in) :: g ! gravity ! local variables - real(R8) :: z0_wav + real(R8) :: z0wav - z0_wav = charn * (us**2) / g + z0wav = charn * (us**2) / g -end function zo_wave +end function z0_wave function cdn_wave(kappa,zr,z0) result(cdn_wav) implicit none From 2c2be72b8724de4076bab2889a9cb091afefd5d6 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 1 May 2025 16:24:29 -0500 Subject: [PATCH 058/398] update Largeyeager coupling to waves remove print statements remove z0,ustar = 0 issue from ocn_comp_mct: fix applied elsewhere. clean up rebase bug fix after last rebase add comment --- components/mpas-ocean/src/Registry.xml | 8 +++ .../namelist_files/namelist_defaults_ww3.xml | 2 +- components/ww3/src/cpl/wav_comp_mct.F90 | 13 +++-- .../cime_config/namelist_definition_drv.xml | 4 +- driver-mct/main/seq_flux_mct.F90 | 8 +-- driver-mct/shr/seq_flds_mod.F90 | 9 ++-- share/util/shr_flux_mod.F90 | 53 +++++++++---------- 7 files changed, 54 insertions(+), 43 deletions(-) diff --git a/components/mpas-ocean/src/Registry.xml b/components/mpas-ocean/src/Registry.xml index eb991f052840..11e80f4a02c9 100644 --- a/components/mpas-ocean/src/Registry.xml +++ b/components/mpas-ocean/src/Registry.xml @@ -4070,6 +4070,14 @@ + + 0 0 "WND HS FP DP USS" -"USS USP HS FP DP CHA UST U1" +"USS USP HS FP DP CHA Z0 USTAR2" diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index cad41040caea..cc9c816a6328 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -137,7 +137,7 @@ MODULE WAV_COMP_MCT usspf use w3wdatmd, only: time, w3ndat, w3setw, wlv, va, ust, ice use w3adatmd, only: ussp, w3naux, w3seta, sxx, sxy, syy, fliwnd, flcold, dw, cg, wn, hs, fp0, thp0, & - charn, tauwix, tauwiy, tauox, tauoy, tauocx, tauocy, usero + charn, z0,ustar2, tauwix, tauwiy, tauox, tauoy, tauocx, tauocy use w3idatmd, only: inflags1, inflags2,w3seti, w3ninp USE W3IDATMD, ONLY: TC0, CX0, CY0, TCN, CXN, CYN, ICEP1, ICEP5, TI1, TI5 USE W3IDATMD, ONLY: TW0, WX0, WY0, DT0, TWN, WXN, WYN, DTN @@ -1185,14 +1185,21 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) if (wav_ocn_coup .eq. 'twoway' .or. wav_atm_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Charn,jsea) = CHARN(jsea) - w2x_w%rattr(index_w2x_Sw_Ustar,jsea) = UST(jsea) ! Friction velocity - w2x_w%rattr(index_w2x_Sw_Z0,jsea) = USERO(jsea,1) ! Z0 surface roughness length + w2x_w%rattr(index_w2x_Sw_Ustar,jsea) = USTAR2(jsea) ! Friction velocity + w2x_w%rattr(index_w2x_Sw_Z0,jsea) = Z0(jsea) ! Z0 surface roughness length endif if (wav_ocn_coup .eq. 'twoway') then w2x_w%rattr(index_w2x_Sw_Hs,jsea) = HS(jsea) w2x_w%rattr(index_w2x_Sw_Fp,jsea) = FP0(jsea) w2x_w%rattr(index_w2x_Sw_Dp,jsea) = THP0(jsea) + w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) + w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) + w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) + w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 1000*TAUOY(jsea) + w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = TAUOCX(jsea) + w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) + w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_1,jsea) = USSP(jsea,1) w2x_w%rattr(index_w2x_Sw_vstokes_wavenumber_1,jsea) = USSP(jsea,nk+1) w2x_w%rattr(index_w2x_Sw_ustokes_wavenumber_2,jsea) = USSP(jsea,2) diff --git a/driver-mct/cime_config/namelist_definition_drv.xml b/driver-mct/cime_config/namelist_definition_drv.xml index 662b7217d95a..43e6f0c2d9e5 100644 --- a/driver-mct/cime_config/namelist_definition_drv.xml +++ b/driver-mct/cime_config/namelist_definition_drv.xml @@ -327,10 +327,10 @@ - logical + char seq_flds seq_cplflds_inparm - One- or Two-way coupling between Wave and Atm + One- or Two-way coupling between Wave and Atm. none oneway diff --git a/driver-mct/main/seq_flux_mct.F90 b/driver-mct/main/seq_flux_mct.F90 index dfd0efa855d1..5e24cc21f3c2 100644 --- a/driver-mct/main/seq_flux_mct.F90 +++ b/driver-mct/main/seq_flux_mct.F90 @@ -307,7 +307,7 @@ subroutine seq_flux_init_mct(comp, fractions) charnsea = 0.0_r8 allocate( ustarwav(nloc),stat=ier) if(ier/=0) call mct_die(subName,'allocate ustarwav',ier) - ustarwav = 0.0_r8 + ustarwav = 0.0_r8 allocate( z0wav(nloc),stat=ier) if(ier/=0) call mct_die(subName,'allocate z0wav',ier) z0wav = 0.0_r8 @@ -1463,7 +1463,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) index_o2x_So_roce_16O = mct_aVect_indexRA(o2x,'So_roce_16O', perrWith='quiet') index_o2x_So_roce_HDO = mct_aVect_indexRA(o2x,'So_roce_HDO', perrWith='quiet') index_o2x_So_roce_18O = mct_aVect_indexRA(o2x,'So_roce_18O', perrWith='quiet') - if (wav_ocn_coup == 'two' .or. wav_atm_coup == 'two') then + if (wav_ocn_coup == 'twoway' .or. wav_atm_coup == 'twoway') then index_w2x_Sw_Charn = mct_aVect_indexRA(w2x,'Sw_Charn') index_w2x_Sw_Z0 = mct_aVect_indexRA(w2x,'Sw_Z0') index_w2x_Sw_Ustar = mct_aVect_indexRA(w2x,'Sw_Ustar') @@ -1572,7 +1572,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) tocn(n) = o2x%rAttr(index_o2x_So_t ,n) uocn(n) = o2x%rAttr(index_o2x_So_u ,n) vocn(n) = o2x%rAttr(index_o2x_So_v ,n) - if (wav_atm_coup == 'two') then + if (wav_atm_coup == 'twoway') then charnsea(n) = w2x%rAttr(index_w2x_Sw_Charn ,n) ustarwav(n) = w2x%rAttr(index_w2x_Sw_Ustar ,n) z0wav(n) = w2x%rAttr(index_w2x_Sw_Z0 ,n) @@ -1655,7 +1655,7 @@ subroutine seq_flux_atmocn_mct(infodata, tod, dt, a2x, o2x, xao, w2x) duu10n,ustar, re , ssq, wsresp=wsresp, tau_est=tau_est) u10res = sqrt(duu10n) ! atm-supplied gustiness not implemented for UA else - if (wav_atm_coup == 'two') then + if (wav_atm_coup == 'twoway') then call shr_flux_atmocn (nloc , zbot , ubot, vbot, thbot, & shum , shum_16O , shum_HDO, shum_18O, dens , tbot, uocn, vocn , & tocn , emask, seq_flux_atmocn_minwind, & diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 6d9f428dad34..87228b6d184e 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -165,7 +165,7 @@ module seq_flds_mod logical :: add_iac_to_cplstate ! .true. if iac fields are added to coupler history files character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on character(len=CS) :: wav_atm_coup ! 'twoway' if wave-ocean two-way coupling turned on - character(len=CS) :: wav_ice_coup ! 'two' if wave-ice two-way coupling turned on + character(len=CS) :: wav_ice_coup ! 'twoway' if wave-ice two-way coupling turned on !---------------------------------------------------------------------------- ! metadata !---------------------------------------------------------------------------- @@ -2723,14 +2723,15 @@ subroutine seq_flds_set(nmlfile, ID, infodata) if (wav_atm_coup == 'twoway' .or. wav_ocn_coup == 'twoway') then call seq_flds_add(w2x_states,'Sw_Charn') - if (wav_ocn_coup == 'two') call seq_flds_add(x2o_states,'Sw_Charn') + if (wav_ocn_coup == 'twoway') call seq_flds_add(x2o_states,'Sw_Charn') longname = 'Charnock coefficent based on sea state' stdname = 'Charnock_coefficent_based_on_sea_state' units = '' attname = 'Sw_Charn' call metadata_set(attname, longname, stdname, units) + call seq_flds_add(w2x_states,'Sw_Ustar') - if (wav_ocn_coup == 'two') call seq_flds_add(x2o_states,'Sw_Ustar') + if (wav_ocn_coup == 'twoway') call seq_flds_add(x2o_states,'Sw_Ustar') longname = 'Friction Velocity based on sea state' stdname = 'Frcition_velocity_based_on_sea_state' units = '' @@ -2738,7 +2739,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call metadata_set(attname, longname, stdname, units) call seq_flds_add(w2x_states,'Sw_Z0') - if (wav_ocn_coup == 'two') call seq_flds_add(x2o_states,'Sw_Z0') + if (wav_ocn_coup == 'twoway') call seq_flds_add(x2o_states,'Sw_Z0') longname = 'Surface Roughness Length based on wave state' stdname = 'Surface_roughness_length_based_on_wave_state' units = '' diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index 9f2724309627..303c308387f5 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -137,7 +137,8 @@ end subroutine shr_flux_adjust_constants ! ! 2011-Mar-13 - J. Nusbaumer - Water Isotope ocean flux added. ! 2019-May-16 - Jack Reeves Eyre (UA) and Kai Zhang (PNNL) - Added COARE/Fairall surface flux scheme option (ocn_surface_flux_scheme .eq. 1) based on code from Thomas Toniazzo (Bjerknes Centre, Bergen) ” -! 2024-Jul-10 - E. Thomas ethomas@lanl.gov - implementing Coare3.0 w/ Wave coupling (uses charnock paramter from WW3) +! 2024-Jul - E. Thomas ethomas@lanl.gov - implementing Coare3.0 w/ Wave coupling +! 2025-Mar - E. Thomas ethomas@lanl.gov - implementing Large+Yeager(default) Flux shceme w/ Wave coupling ! !INTERFACE: ------------------------------------------------------------------ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & @@ -367,8 +368,12 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !------------------------------------------------------------ !--- neutral coefficients, z/L = 0.0 --- stable = 0.5_R8 + sign(0.5_R8 , delt) - if (wav_atm_coup .eq. 'two') then - cdn_wav = cdn_wave(loc_karman,zref,z0wav) + if (wav_atm_coup .eq. 'twoway') then + if (z0wav(n) == 0.0_R8 ) then + cdn_wav = cdn_wave(loc_karman,zref,0.0001_R8) + else + cdn_wav = cdn_wave(loc_karman,zref,z0wav(n)) + endif rdn = sqrt(cdn_wav) ! rdn calculated from Z0 will be constant else @@ -379,19 +384,20 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & ren = 0.0346_R8 !cexcd !--- ustar, tstar, qstar --- - write(s_logunit,*) 'ET EDIT: ustar first', ustar - if (wav_atm_coup .eq. 'two') then - ustar = ustar_wav + if (wav_atm_coup .eq. 'twoway') then + if (ustarwav(n) == 0.0_R8 ) then + ustar = ustarwav(n)+0.1_R8 + else + ustar = ustarwav(n) + endif else ustar = rdn * vmag endif tstar = rhn * delt qstar = ren * delq ustar_prev = ustar*2.0_R8 - write(s_logunit,*) 'ET EDIT: z0', z0wav - write(s_logunit,*) 'ET EDIT: cdn_wav:', cdn_wav - write(s_logunit,*) 'ET EDIT: rdn:', rdn - write(s_logunit,*) 'ET EDIT: ustar first', ustar + write(s_logunit,*) 'ET EDIT: cdn_wav first:', cdn_wav + write(s_logunit,*) 'ET EDIT: rdn first:', rdn if (present(wsresp) .and. present(tau_est)) prev_tau = tau_est(n) tau_diff = 1.e100_R8 wind_adj = wind0 @@ -425,7 +431,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & psimh = -5.0_R8*hol*stable + (1.0_R8-stable)*psimhu(xqq) psixh = -5.0_R8*hol*stable + (1.0_R8-stable)*psixhu(xqq) - if (wav_atm_coup .ne. 'two') then + if (wav_atm_coup .ne. 'twoway') then !--- shift wind speed using old coefficient --- rd = rdn / max(1.0_R8 + rdn/loc_karman*(alz-psimh), 1.e-3_r8) u10n = vmag * rd / rdn @@ -444,6 +450,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- update ustar, tstar, qstar using updated, shifted coeffs -- ustar = rd * vmag + write(s_logunit,*) 'ET EDIT: number iterations', iter + write(s_logunit,*) 'ET EDIT: ustar iteration', ustar tstar = rh * delt qstar = re * delq @@ -459,6 +467,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & vmag = max(seq_flux_atmocn_minwind, vmag) end if enddo + write(s_logunit,*) 'ET EDIT final num iter:', iter + write(s_logunit,*) 'ET EDIT: final ustar:', ustar if (iter < 1) then write(s_logunit,*) ustar,ustar_prev,flux_con_tol,flux_con_max_iter call shr_sys_abort('No iterations performed ' // errMsg(sourcefile, __LINE__)) @@ -561,7 +571,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & endif endif ssq = 0.98_R8 * qsat(ts(n)) / rbot(n) ! sea surf hum (kg/kg) - if (wav_atm_coup .eq. 'two') then + if (wav_atm_coup .eq. 'twoway') then call cor30a(ubot(n),vbot(n),tbot(n),qbot(n),rbot(n) & ! in atm params & ,us(n),vs(n),ts(n),ssq & ! in surf params & ,zpbl,zbot(n),zbot(n),zref,ztref,ztref & ! in heights @@ -1156,21 +1166,6 @@ END subroutine shr_flux_atmOcn_UA !=============================================================================== ! Functions used by default surface flux scheme for Wave Coupling !=============================================================================== -function z0_wave(charn, us, g) result(z0wav) - implicit none - - ! input variables - real(R8), intent(in) :: charn ! charcnock parameter - real(R8), intent(in) :: us ! u star - real(R8), intent(in) :: g ! gravity - - ! local variables - real(R8) :: z0wav - - z0wav = charn * (us**2) / g - -end function z0_wave - function cdn_wave(kappa,zr,z0) result(cdn_wav) implicit none @@ -1186,8 +1181,8 @@ function cdn_wave(kappa,zr,z0) result(cdn_wav) a = zr / z0 b = log(a) cdn_wav = (kappa**2) / (b**2) - end function cdn_wave + !=============================================================================== ! Functions/subroutines used by UA surface flux scheme. !=============================================================================== @@ -2701,7 +2696,7 @@ subroutine cor30a(ubt,vbt,tbt,qbt,rbt & ! in atm params tsr = (dt-dter*jcool)*von/(log(zt/zot10)-psit_30(zt/L10)) qsr = (dq-dqer*jcool)*von/(log(zq/zot10)-psit_30(zq/L10)) - if (wav_atm_coup .eq. 'two') then + if (wav_atm_coup .eq. 'twoway') then charn = charnsea !use Charnock coefficient from active wave model (Janssen 1989, 1991) else ! parametrisation for Charney parameter (section 3c of Fairall et al. 2003) From 1ee85e4b80979506dbf163ea82c46905066daa38 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 8 May 2025 11:58:51 -0700 Subject: [PATCH 059/398] add F20TR+WW3 compset --- components/ww3/cime_config/config_compsets.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/ww3/cime_config/config_compsets.xml b/components/ww3/cime_config/config_compsets.xml index 01de245a23b2..ee655497f16a 100644 --- a/components/ww3/cime_config/config_compsets.xml +++ b/components/ww3/cime_config/config_compsets.xml @@ -23,6 +23,11 @@ F2010-WW3 2010_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%PRES_DOCN%DOM_MOSART_SGLC_WW3%sp36x36 + + + F20TR-WW3 + 20TR_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%PRES_DOCN%DOM_MOSART_SGLC_WW3%sp36x36 + DTESTM-JRA1p5-WW3 From 9ec01dc6e17827a9120a2cb3d36c31730675604d Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 27 May 2025 11:18:07 -0700 Subject: [PATCH 060/398] remove charn and ice fract output for WW3-enabled runs remove print statements in shr_flux_mod for new wave-flux calculations typo fixes --- components/mpas-ocean/cime_config/buildnml | 7 ------- share/util/shr_flux_mod.F90 | 10 ++-------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/components/mpas-ocean/cime_config/buildnml b/components/mpas-ocean/cime_config/buildnml index d684025fdcb2..cfcc1bbaa939 100755 --- a/components/mpas-ocean/cime_config/buildnml +++ b/components/mpas-ocean/cime_config/buildnml @@ -1269,7 +1269,6 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') if ocn_bgc in ['eco_only', 'eco_and_dms', 'eco_and_macromolecules', 'eco_and_dms_and_macromolecules']: lines.append(' ') lines.append(' ') @@ -1341,10 +1340,8 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') lines.append(' ') if not (ocn_grid.startswith("oRRS1") or ocn_grid.startswith("RRSwISC6")): lines.append(' ') @@ -1558,10 +1555,8 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') lines.append(' ') if ocn_iceberg == 'true': lines.append(' ') @@ -1629,10 +1624,8 @@ def buildnml(case, caseroot, compname): lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') lines.append(' ') lines.append(' ') - lines.append(' ') lines.append(' ') if ocn_iceberg == 'true': lines.append(' ') diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index 303c308387f5..ed780c2bf1cd 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -138,7 +138,7 @@ end subroutine shr_flux_adjust_constants ! 2011-Mar-13 - J. Nusbaumer - Water Isotope ocean flux added. ! 2019-May-16 - Jack Reeves Eyre (UA) and Kai Zhang (PNNL) - Added COARE/Fairall surface flux scheme option (ocn_surface_flux_scheme .eq. 1) based on code from Thomas Toniazzo (Bjerknes Centre, Bergen) ” ! 2024-Jul - E. Thomas ethomas@lanl.gov - implementing Coare3.0 w/ Wave coupling -! 2025-Mar - E. Thomas ethomas@lanl.gov - implementing Large+Yeager(default) Flux shceme w/ Wave coupling +! 2025-Mar - E. Thomas ethomas@lanl.gov - implementing Large+Yeager(default) Flux scheme w/ Wave coupling ! !INTERFACE: ------------------------------------------------------------------ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & @@ -260,7 +260,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & real(R8) :: tau_diff ! difference in tau across iterations (Pa) real(R8) :: prev_tau_diff ! previous value of tau_diff (Pa) real(R8) :: wind_adj ! iteration-adjusted wind speed (m/s) -!!++ Large with waves +!!++ Large and Yeager with waves real(R8) :: cdn_wav !!++ COARE only real(R8) :: zo,zot,zoq ! roughness lengths @@ -396,8 +396,6 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & tstar = rhn * delt qstar = ren * delq ustar_prev = ustar*2.0_R8 - write(s_logunit,*) 'ET EDIT: cdn_wav first:', cdn_wav - write(s_logunit,*) 'ET EDIT: rdn first:', rdn if (present(wsresp) .and. present(tau_est)) prev_tau = tau_est(n) tau_diff = 1.e100_R8 wind_adj = wind0 @@ -450,8 +448,6 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- update ustar, tstar, qstar using updated, shifted coeffs -- ustar = rd * vmag - write(s_logunit,*) 'ET EDIT: number iterations', iter - write(s_logunit,*) 'ET EDIT: ustar iteration', ustar tstar = rh * delt qstar = re * delq @@ -467,8 +463,6 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & vmag = max(seq_flux_atmocn_minwind, vmag) end if enddo - write(s_logunit,*) 'ET EDIT final num iter:', iter - write(s_logunit,*) 'ET EDIT: final ustar:', ustar if (iter < 1) then write(s_logunit,*) ustar,ustar_prev,flux_con_tol,flux_con_max_iter call shr_sys_abort('No iterations performed ' // errMsg(sourcefile, __LINE__)) From 77b45ce42e340e1718df7795a854c9326bb0513c Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 18 Sep 2025 10:44:35 -0500 Subject: [PATCH 061/398] reduce U* threshold to avoid divide by zero issues typo fix in comment --- share/util/shr_flux_mod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index ed780c2bf1cd..f0ac361fe1f8 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -386,7 +386,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- ustar, tstar, qstar --- if (wav_atm_coup .eq. 'twoway') then if (ustarwav(n) == 0.0_R8 ) then - ustar = ustarwav(n)+0.1_R8 + ustar = ustarwav(n)+0.01_R8 else ustar = ustarwav(n) endif @@ -1164,7 +1164,7 @@ function cdn_wave(kappa,zr,z0) result(cdn_wav) implicit none ! input variables - real(R8), intent(in) :: kappa !von Karmen constant + real(R8), intent(in) :: kappa ! von Karman constant real(R8), intent(in) :: zr ! reference height (10m) real(R8), intent(in) :: z0 ! roughness length based on wave state From f84d32ba358b45d8b7082d820d902d632e7357fb Mon Sep 17 00:00:00 2001 From: Andrew Roberts Date: Mon, 3 Nov 2025 15:07:43 -0700 Subject: [PATCH 062/398] Update to reference shared constants in E3SM Update comment to reflect correct coupled exchange with atmosphere. --- components/ww3/src/cpl/wav_comp_mct.F90 | 12 ++++++++---- driver-mct/shr/seq_flds_mod.F90 | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/ww3/src/cpl/wav_comp_mct.F90 b/components/ww3/src/cpl/wav_comp_mct.F90 index cc9c816a6328..7ba2a9e5b673 100644 --- a/components/ww3/src/cpl/wav_comp_mct.F90 +++ b/components/ww3/src/cpl/wav_comp_mct.F90 @@ -198,6 +198,8 @@ MODULE WAV_COMP_MCT use shr_nl_mod , only : shr_nl_find_group_name use shr_mpi_mod , only : shr_mpi_bcast + use shr_const_mod , only : shr_const_rhofw + ! implicit none ! @@ -1193,10 +1195,12 @@ SUBROUTINE WAV_RUN_MCT(EClock, cdata_w, x2w_w, w2x_w) w2x_w%rattr(index_w2x_Sw_Fp,jsea) = FP0(jsea) w2x_w%rattr(index_w2x_Sw_Dp,jsea) = THP0(jsea) - w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = 1000*TAUWIX(jsea) !Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) - w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = 1000*TAUWIY(jsea) - w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = 1000*TAUOX(jsea) - w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = 1000*TAUOY(jsea) + ! Conversion to N m^{-2} by multiplying by density of water (See eqn 2.99 WW3 Manual) + ! N.B. WW3 makes a freshwater assumption rather than using the density of sea water. + w2x_w%rattr(index_w2x_Faww_Tawx,jsea) = shr_const_rhofw*TAUWIX(jsea) + w2x_w%rattr(index_w2x_Faww_Tawy,jsea) = shr_const_rhofw*TAUWIY(jsea) + w2x_w%rattr(index_w2x_Fwow_Twox,jsea) = shr_const_rhofw*TAUOX(jsea) + w2x_w%rattr(index_w2x_Fwow_Twoy,jsea) = shr_const_rhofw*TAUOY(jsea) w2x_w%rattr(index_w2x_Faow_Tocx,jsea) = TAUOCX(jsea) w2x_w%rattr(index_w2x_Faow_Tocy,jsea) = TAUOCY(jsea) diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 87228b6d184e..5004fd554b6c 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -164,7 +164,7 @@ module seq_flds_mod logical :: rof_sed ! .true. if river model includes sediment logical :: add_iac_to_cplstate ! .true. if iac fields are added to coupler history files character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on - character(len=CS) :: wav_atm_coup ! 'twoway' if wave-ocean two-way coupling turned on + character(len=CS) :: wav_atm_coup ! 'twoway' if wave-atm two-way coupling turned on character(len=CS) :: wav_ice_coup ! 'twoway' if wave-ice two-way coupling turned on !---------------------------------------------------------------------------- ! metadata From 001249b7c3dda228aa68111a45675d228db7f1de Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Thu, 13 Nov 2025 11:39:02 -0600 Subject: [PATCH 063/398] use 'tiny' value in shr_flux_mod. add check to log(a) --- share/util/shr_flux_mod.F90 | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index f0ac361fe1f8..e311c187d4e0 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -223,6 +223,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !!++ COARE only real(R8),parameter :: zpbl =700.0_R8 ! PBL depth [m] for gustiness parametriz. + real(R8),parameter :: tiny = 1.0e-12_R8 !--- local variables -------------------------------- integer(IN) :: n ! vector loop index integer(IN) :: iter @@ -369,8 +370,9 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- neutral coefficients, z/L = 0.0 --- stable = 0.5_R8 + sign(0.5_R8 , delt) if (wav_atm_coup .eq. 'twoway') then - if (z0wav(n) == 0.0_R8 ) then - cdn_wav = cdn_wave(loc_karman,zref,0.0001_R8) + if (z0wav(n) .lt. tiny) then + ! z0wav == 0 for cold-start-WW3 situations + cdn_wav = cdn_wave(loc_karman,zref,tiny) else cdn_wav = cdn_wave(loc_karman,zref,z0wav(n)) endif @@ -385,8 +387,8 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- ustar, tstar, qstar --- if (wav_atm_coup .eq. 'twoway') then - if (ustarwav(n) == 0.0_R8 ) then - ustar = ustarwav(n)+0.01_R8 + if (ustarwav(n) .lt. tiny) then + ustar = ustarwav(n)+tiny else ustar = ustarwav(n) endif @@ -1172,9 +1174,13 @@ function cdn_wave(kappa,zr,z0) result(cdn_wav) real(R8) :: a, b real(R8) :: cdn_wav - a = zr / z0 - b = log(a) - cdn_wav = (kappa**2) / (b**2) + if (zr .gt. z0) then + a = zr / z0 + b = log(a) + cdn_wav = (kappa**2) / (b**2) + else + call shr_sys_abort(" CDN_Wave Error: Roughness length is greater than reference height (10m). Solution Not Realistic.") + endif end function cdn_wave !=============================================================================== From 29fecec025dc35254dd6b8012828100551cd0a20 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Thu, 11 Sep 2025 12:13:31 -0700 Subject: [PATCH 064/398] Removes LC ruby machine --- cime_config/allactive/config_pesall.xml | 22 ------ .../machines/cmake_macros/intel_ruby.cmake | 10 --- cime_config/machines/config_batch.xml | 7 -- cime_config/machines/config_machines.xml | 67 ------------------- 4 files changed, 106 deletions(-) delete mode 100644 cime_config/machines/cmake_macros/intel_ruby.cmake diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index 39b155427184..d313390ca4f3 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -2296,28 +2296,6 @@ - - - - -4 - -4 - -4 - -4 - -4 - -4 - -4 - -4 - - - 1 - 1 - 1 - 1 - 1 - 1 - - - diff --git a/cime_config/machines/cmake_macros/intel_ruby.cmake b/cime_config/machines/cmake_macros/intel_ruby.cmake deleted file mode 100644 index e874bfb7eaf6..000000000000 --- a/cime_config/machines/cmake_macros/intel_ruby.cmake +++ /dev/null @@ -1,10 +0,0 @@ -string(APPEND CPPDEFS " -DNO_SHR_VMATH -DCNL") -string(APPEND CMAKE_Fortran_FLAGS_DEBUG " -check all -ftrapuv") -string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/usr/tce/packages/gcc/gcc-10.3.1-magic/lib/gcc/x86_64-redhat-linux/10/") - -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/hdf5-1.10.7-ewjpbjdhjgjzrzjcvwyjyuulaesbsjhg/lib") -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/netcdf-c-4.4.1.1-vaxofekwvnvngh7wptmzkwdb7tkzvesn/lib") -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/netcdf-fortran-4.4.4-3pzbx2unddhladhubaahhhysjmprzqi2/lib") -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/parallel-netcdf-1.11.0-tzgdalakmem7tod6cruhqyeackeix5q5/lib") - -set(KOKKOS_OPTIONS "--with-serial --ldflags='-L/usr/tce/packages/gcc/gcc-10.3.1-magic/lib/gcc/x86_64-redhat-linux/10/'") diff --git a/cime_config/machines/config_batch.xml b/cime_config/machines/config_batch.xml index f0cfe6800f8e..d5809e2fd9c3 100644 --- a/cime_config/machines/config_batch.xml +++ b/cime_config/machines/config_batch.xml @@ -222,13 +222,6 @@ - - - pbatch - pdebug - - - pbatch diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 9bc4c7a971eb..d134746c99cd 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3041,73 +3041,6 @@ - - LLNL Linux Cluster, Linux (pgi), 56 pes/node, batch system is Slurm - LINUX - intel - mpich - cbronze - /p/lustre2/$USER/e3sm_scratch/ruby - /usr/workspace/e3sm/ccsm3data/inputdata - /usr/workspace/e3sm/ccsm3data/inputdata/atm/datm7 - /p/lustre2/$USER/archive/$CASE - /p/lustre2/$USER/ccsm_baselines/$COMPILER - /usr/workspace/e3sm/apps/cprnc - 8 - slurm - boutte3 -at- llnl.gov - 56 - 56 - - - - - srun - - --mpi=pmi2 - --export=ALL - -n {{ total_tasks }} -N {{ num_nodes }} - -c 1 - --cpu_bind=cores - -m plane={{ tasks_per_node }} - - - - /usr/share/lmod/lmod/init/env_modules_python.py - /usr/share/lmod/lmod/init/perl - /usr/share/lmod/lmod/init/sh - /usr/share/lmod/lmod/init/csh - module - module - /usr/share/lmod/lmod/libexec/lmod python - /usr/share/lmod/lmod/libexec/lmod perl - - python/3.9.12 - git - subversion - cmake/3.19.2 - mkl/2022.1.0 - intel-classic/2021.6.0-magic - /usr/workspace/e3sm/spack/modules/ruby/linux-rhel8-x86_64/Core - mvapich2/2.3.7-ll7cmqm - hdf5/1.10.7-ewjpbjd - netcdf-c/4.4.1.1-vaxofek - netcdf-fortran/4.4.4-3pzbx2u - parallel-netcdf/1.11.0-tzgdala - - - $CIME_OUTPUT_ROOT/$CASE/run - $CIME_OUTPUT_ROOT/$CASE/bld - - 128M - FALSE - /usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/hdf5-1.10.7-ewjpbjdhjgjzrzjcvwyjyuulaesbsjhg - /usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/netcdf-c-4.4.1.1-vaxofekwvnvngh7wptmzkwdb7tkzvesn - /usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/netcdf-fortran-4.4.4-3pzbx2unddhladhubaahhhysjmprzqi2 - /usr/workspace/e3sm/spack/libs/linux-rhel8-cascadelake/intel-2021.6.0/parallel-netcdf-1.11.0-tzgdalakmem7tod6cruhqyeackeix5q5 - - - LLNL Linux Cluster, 112 pes/node, batch system is Slurm LINUX From 79b34a9796d9c5978911c09c19bfa68e713529f1 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Tue, 23 Sep 2025 15:05:11 -0700 Subject: [PATCH 065/398] Updates dane configuration --- .../machines/Depends.dane.oneapi-ifx.cmake | 5 ++ .../machines/cmake_macros/intel_dane.cmake | 10 ---- .../cmake_macros/oneapi-ifx_dane.cmake | 9 ++++ cime_config/machines/config_machines.xml | 51 ++++++++++--------- 4 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 cime_config/machines/Depends.dane.oneapi-ifx.cmake delete mode 100644 cime_config/machines/cmake_macros/intel_dane.cmake create mode 100644 cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake diff --git a/cime_config/machines/Depends.dane.oneapi-ifx.cmake b/cime_config/machines/Depends.dane.oneapi-ifx.cmake new file mode 100644 index 000000000000..ce517471ef82 --- /dev/null +++ b/cime_config/machines/Depends.dane.oneapi-ifx.cmake @@ -0,0 +1,5 @@ +# compile mpas_seaice_core_interface.f90 with ifort, not ifx +if (NOT MPILIB STREQUAL "openmpi") + e3sm_add_flags("${CMAKE_BINARY_DIR}/core_seaice/model_forward/mpas_seaice_core_interface.f90" "-fc=ifort") + e3sm_add_flags("${CMAKE_BINARY_DIR}/core_landice/mode_forward/mpas_li_core_interface.f90" "-fc=ifort") +endif() diff --git a/cime_config/machines/cmake_macros/intel_dane.cmake b/cime_config/machines/cmake_macros/intel_dane.cmake deleted file mode 100644 index ef25a97b300e..000000000000 --- a/cime_config/machines/cmake_macros/intel_dane.cmake +++ /dev/null @@ -1,10 +0,0 @@ -string(APPEND CPPDEFS " -DNO_SHR_VMATH -DCNL") -string(APPEND CMAKE_Fortran_FLAGS_DEBUG " -check all -ftrapuv") -string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/usr/tce/packages/gcc/gcc-10.3.1-magic/lib/gcc/x86_64-redhat-linux/10/") - -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/hdf5-1.10.7-766kapalbrdntu2pcgdgbhg2ch26gsuv/lib") -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/netcdf-c-4.4.1.1-2uznnlwgiezxute6iyqzqjrpolokeaib/lib") -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/netcdf-fortran-4.4.4-itpstyordbern7vlulmlnt47eeeokzfp/lib") -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/parallel-netcdf-1.11.0-26sxm4mormsglmhi24poix7sugbigkck/lib") - -set(KOKKOS_OPTIONS "--with-serial --ldflags='-L/usr/tce/packages/gcc/gcc-10.3.1-magic/lib/gcc/x86_64-redhat-linux/10/'") diff --git a/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake b/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake new file mode 100644 index 000000000000..faad4f8c89a0 --- /dev/null +++ b/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake @@ -0,0 +1,9 @@ +list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/hdf5-1.14.5-oq4xvuvma5emdmqlrhhugf5f2fbl2miq/lib" ) +list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-c-4.9.2-3a4qa33n36d4ryrne2des3653ka4rsfa/lib" ) +list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-fortran-4.6.1-7mybbfylyzezbv2sc2rjhnkewhnyx3ge/lib" ) +list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/parallel-netcdf-1.14.0-d6xfqf4wccp4eiohquw3idjppqff7mtj/lib" ) + +# get_cmake_property(_variableNames VARIABLES) +# foreach (_variableName ${_variableNames}) +# message("${_variableName}=${${_variableName}}") +# endforeach() diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index d134746c99cd..e1450f69b442 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3044,19 +3044,19 @@ LLNL Linux Cluster, 112 pes/node, batch system is Slurm LINUX - intel + oneapi-ifx mpich - cbronze + e3smtest /p/lustre2/$USER/e3sm_scratch/dane - /usr/workspace/e3sm/ccsm3data/inputdata - /usr/workspace/e3sm/ccsm3data/inputdata/atm/datm7 + /p/vast1/e3sm/ccsm3data/inputdata + /p/vast1/e3sm/ccsm3data/inputdata/atm/datm7 /p/lustre2/$USER/archive/$CASE /p/lustre2/$USER/ccsm_baselines/$COMPILER /usr/workspace/e3sm/apps/cprnc 8 slurm boutte3 -at- llnl.gov - 224 + 112 112 @@ -3064,11 +3064,9 @@ srun - --mpi=pmi2 - --export=ALL - -n {{ total_tasks }} -N {{ num_nodes }} - -c 1 + -l -n {{ total_tasks }} -N {{ num_nodes }} --kill-on-bad-exit --cpu_bind=cores + -c $ENV{OMP_NUM_THREADS} -m plane={{ tasks_per_node }} @@ -3081,30 +3079,35 @@ module /usr/share/lmod/lmod/libexec/lmod python /usr/share/lmod/lmod/libexec/lmod perl - + python/3.9.12 git subversion + cmake/3.26.3 mkl/2022.1.0 - intel-classic/2021.6.0-magic - cmake/3.19.2 - /usr/workspace/e3sm/spack/modules/dane/linux-rhel8-x86_64/Core - mvapich2/2.3.7-27jao34 - hdf5/1.10.7-766kapa - netcdf-c/4.4.1.1-2uznnlw - netcdf-fortran/4.4.4-itpstyo - parallel-netcdf/1.11.0-26sxm4m + + + intel/2023.2.1-magic + /usr/workspace/e3sm/spack/dane/intel/modules/Core + mvapich2/2.3.7 + hdf5/1.14.5 + netcdf-c/4.9.2 + netcdf-fortran/4.6.1 + parallel-netcdf/1.14.0 $CIME_OUTPUT_ROOT/$CASE/run $CIME_OUTPUT_ROOT/$CASE/bld - + 128M - FALSE - /usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/hdf5-1.10.7-766kapalbrdntu2pcgdgbhg2ch26gsuv - /usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/netcdf-c-4.4.1.1-2uznnlwgiezxute6iyqzqjrpolokeaib - /usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/netcdf-fortran-4.4.4-itpstyordbern7vlulmlnt47eeeokzfp - /usr/workspace/e3sm/spack/libs/linux-rhel8-sapphirerapids/intel-2021.6.0/parallel-netcdf-1.11.0-26sxm4mormsglmhi24poix7sugbigkck + + + /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/hdf5-1.14.5-oq4xvuvma5emdmqlrhhugf5f2fbl2miq + /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-c-4.9.2-3a4qa33n36d4ryrne2des3653ka4rsfa + /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-fortran-4.6.1-7mybbfylyzezbv2sc2rjhnkewhnyx3ge + /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/parallel-netcdf-1.14.0-d6xfqf4wccp4eiohquw3idjppqff7mtj + /usr/tce/packages/intel/intel-2023.2.1-magic/lib:$ENV{LD_LIBRARY_PATH} + /usr/tce/packages/intel/intel-2023.2.1/compiler/2023.2.1/linux/bin/intel64:$ENV{PATH}" From a1dbc45f59436017dfe67a968ec4c10eb77ef927 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Tue, 7 Oct 2025 15:47:38 -0700 Subject: [PATCH 066/398] Adds missing modules and removes hard coded paths --- .../machines/cmake_macros/oneapi-ifx_dane.cmake | 8 ++++---- cime_config/machines/config_machines.xml | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake b/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake index faad4f8c89a0..6fc9370fd4bd 100644 --- a/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake +++ b/cime_config/machines/cmake_macros/oneapi-ifx_dane.cmake @@ -1,7 +1,7 @@ -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/hdf5-1.14.5-oq4xvuvma5emdmqlrhhugf5f2fbl2miq/lib" ) -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-c-4.9.2-3a4qa33n36d4ryrne2des3653ka4rsfa/lib" ) -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-fortran-4.6.1-7mybbfylyzezbv2sc2rjhnkewhnyx3ge/lib" ) -list(APPEND CMAKE_BUILD_RPATH "/usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/parallel-netcdf-1.14.0-d6xfqf4wccp4eiohquw3idjppqff7mtj/lib" ) +list(APPEND CMAKE_BUILD_RPATH "$ENV{HDF5_ROOT}/lib" ) +list(APPEND CMAKE_BUILD_RPATH "$ENV{NETCDF_C_PATH}/lib" ) +list(APPEND CMAKE_BUILD_RPATH "$ENV{NETCDF_FORTRAN_PATH}/lib" ) +list(APPEND CMAKE_BUILD_RPATH "$ENV{PNETCDF_PATH}/lib" ) # get_cmake_property(_variableNames VARIABLES) # foreach (_variableName ${_variableNames}) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index e1450f69b442..0710bc1380f3 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3089,6 +3089,9 @@ intel/2023.2.1-magic /usr/workspace/e3sm/spack/dane/intel/modules/Core + intel-oneapi-runtime/2023.2.0 + gcc-runtime/12.1.1 + glibc/2.28 mvapich2/2.3.7 hdf5/1.14.5 netcdf-c/4.9.2 @@ -3102,11 +3105,10 @@ 128M - /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/hdf5-1.14.5-oq4xvuvma5emdmqlrhhugf5f2fbl2miq - /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-c-4.9.2-3a4qa33n36d4ryrne2des3653ka4rsfa - /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/netcdf-fortran-4.6.1-7mybbfylyzezbv2sc2rjhnkewhnyx3ge - /usr/workspace/e3sm/spack/dane/intel/libs/linux-sapphirerapids/parallel-netcdf-1.14.0-d6xfqf4wccp4eiohquw3idjppqff7mtj - /usr/tce/packages/intel/intel-2023.2.1-magic/lib:$ENV{LD_LIBRARY_PATH} + $ENV{HDF5_ROOT} + $ENV{NETCDF_C_PATH} + $ENV{NETCDF_FORTRAN_PATH} + $ENV{PNETCDF_PATH} /usr/tce/packages/intel/intel-2023.2.1/compiler/2023.2.1/linux/bin/intel64:$ENV{PATH}" From 951189fa6db5832507abe0b1db83d09a49908ded Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 18 Nov 2025 10:10:35 -0600 Subject: [PATCH 067/398] update logic for ww3-atm coupling --- driver-mct/cime_config/buildnml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 0356292c7e69..2e2dfbcd823f 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -75,12 +75,17 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): # --------------------------------------------------- if case.get_value('COMP_WAV') == 'ww3': config['WAVSPEC'] = case.get_value('WAV_SPEC') - config['WAV_ATM_COUP'] = 'twoway' if case.get_value('COMP_ATM') == 'eam' else 'oneway' + if case.get_value('COMP_ATM') == 'eam': + config['WAV_ATM_COUP'] = 'twoway' + else: + config['WAV_ATM_COUP'] = 'oneway' + if case.get_value('COMP_OCN') == 'mpaso': config['WAV_OCN_COUP'] = 'twoway' config['ocn_surface_flux_scheme'] = 0 elif case.get_value('COMP_OCN') == 'docn': config['WAV_OCN_COUP'] = 'oneway' + if case.get_value('COMP_ICE') == 'mpassi': config['WAV_ICE_COUP'] = 'oneway' elif case.get_value('COMP_WAV') == 'dwav': From ced7316a9a85ff5a91b33c04833e3bb85ff46503 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Mon, 24 Nov 2025 16:14:03 -0600 Subject: [PATCH 068/398] update ww3 submodule --- components/ww3/src/WW3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ww3/src/WW3 b/components/ww3/src/WW3 index ad107eb52b5e..62e77e77d764 160000 --- a/components/ww3/src/WW3 +++ b/components/ww3/src/WW3 @@ -1 +1 @@ -Subproject commit ad107eb52b5e18117d4ca77fb03bb187d5db9245 +Subproject commit 62e77e77d764292f9d8ad8a7d90b3e81782a2aab From 7c4219c84e663f14784c3568e437c15e488e9f06 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 24 Nov 2025 15:39:03 -0800 Subject: [PATCH 069/398] white space and comment cleanup for zm_conv_evap --- components/eam/src/physics/cam/zm_conv.F90 | 309 ++++++++++----------- 1 file changed, 148 insertions(+), 161 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 867510c867bf..faf8d03e3af2 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -682,9 +682,9 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! - evaporate some precip directly into the environment using a Sundqvist type algorithm !---------------------------------------------------------------------------- #ifdef SCREAM_CONFIG_IS_CMAKE - use zm_eamxx_bridge_wv_saturation, only: qsat + use zm_eamxx_bridge_wv_saturation, only: qsat #else - use wv_saturation, only: qsat + use wv_saturation, only: qsat #endif !---------------------------------------------------------------------------- ! Arguments @@ -736,182 +736,169 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & prdsnow(1:ncol,1:pver) = 0._r8 end if -! convert input precip to kg/m2/s - prec(:ncol) = prec(:ncol)*1000._r8 - -! determine saturation vapor pressure - call qsat(t(1:ncol, 1:pver), pmid(1:ncol, 1:pver), & - es(1:ncol, 1:pver), qs(1:ncol, 1:pver)) - -! determine ice fraction in rain production (use cloud water parameterization fraction at present) - call cldfrc_fice(ncol, t, fice, fsnow_conv) - -! zero the flux integrals on the top boundary - flxprec(:ncol,1) = 0._r8 - flxsnow(:ncol,1) = 0._r8 - evpvint(:ncol) = 0._r8 - omsm=0.99999_r8 ! to prevent problems due to round off error - - do k = 1, pver - do i = 1, ncol - -! Melt snow falling into layer, if necessary. - if( zm_param%old_snow ) then - if (t(i,k) > zm_const%tfreez) then - flxsntm(i) = 0._r8 - snowmlt(i) = flxsnow(i,k) * zm_const%grav/ pdel(i,k) - else - flxsntm(i) = flxsnow(i,k) - snowmlt(i) = 0._r8 - end if - else - ! make sure melting snow doesn't reduce temperature below threshold - if (t(i,k) > zm_const%tfreez) then - dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/pdel(i,k)*deltat - if (t(i,k) + dum .le. zm_const%tfreez) then - dum = (t(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/deltat - dum = dum/(flxsnow(i,k)*zm_const%grav/pdel(i,k)) - dum = max(0._r8,dum) - dum = min(1._r8,dum) - else - dum = 1._r8 - end if - dum = dum*omsm - flxsntm(i) = flxsnow(i,k)*(1.0_r8-dum) - snowmlt(i) = dum*flxsnow(i,k)*zm_const%grav/ pdel(i,k) - else - flxsntm(i) = flxsnow(i,k) - snowmlt(i) = 0._r8 - end if - end if + ! convert input precip to kg/m2/s + prec(:ncol) = prec(:ncol)*1000._r8 + + ! determine saturation vapor pressure + call qsat(t(1:ncol, 1:pver), pmid(1:ncol, 1:pver), es(1:ncol, 1:pver), qs(1:ncol, 1:pver)) + + ! determine ice fraction in rain production (use cloud water parameterization fraction at present) + call cldfrc_fice(ncol, t, fice, fsnow_conv) + ! zero the flux integrals on the top boundary + flxprec(:ncol,1) = 0._r8 + flxsnow(:ncol,1) = 0._r8 + evpvint(:ncol) = 0._r8 + + omsm=0.99999_r8 ! to prevent problems due to round off error + + do k = 1, pver + do i = 1, ncol + + ! Melt snow falling into layer, if necessary. + if( zm_param%old_snow ) then + if (t(i,k) > zm_const%tfreez) then + flxsntm(i) = 0._r8 + snowmlt(i) = flxsnow(i,k) * zm_const%grav/ pdel(i,k) + else + flxsntm(i) = flxsnow(i,k) + snowmlt(i) = 0._r8 + end if + else + ! make sure melting snow doesn't reduce temperature below threshold + if (t(i,k) > zm_const%tfreez) then + dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/pdel(i,k)*deltat + if (t(i,k) + dum .le. zm_const%tfreez) then + dum = (t(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/deltat + dum = dum/(flxsnow(i,k)*zm_const%grav/pdel(i,k)) + dum = max(0._r8,dum) + dum = min(1._r8,dum) + else + dum = 1._r8 + end if + dum = dum*omsm + flxsntm(i) = flxsnow(i,k)*(1.0_r8-dum) + snowmlt(i) = dum*flxsnow(i,k)*zm_const%grav/ pdel(i,k) + else + flxsntm(i) = flxsnow(i,k) + snowmlt(i) = 0._r8 + end if + end if -! relative humidity depression must be > 0 for evaporation - evplimit = max(1._r8 - q(i,k)/qs(i,k), 0._r8) + ! relative humidity depression must be > 0 for evaporation + evplimit = max(1._r8 - q(i,k)/qs(i,k), 0._r8) -! total evaporation depends on flux in the top of the layer -! flux prec is the net production above layer minus evaporation into environmet - evpprec(i) = zm_param%ke * (1._r8 - cldfrc(i,k)) * evplimit * sqrt(flxprec(i,k)) -!********************************************************** -!! evpprec(i) = 0. ! turn off evaporation for now -!********************************************************** + ! total evaporation depends on flux in the top of the layer + ! flux prec is the net production above layer minus evaporation into environmet + evpprec(i) = zm_param%ke * (1._r8 - cldfrc(i,k)) * evplimit * sqrt(flxprec(i,k)) -! Don't let evaporation supersaturate layer (approx). Layer may already be saturated. -! Currently does not include heating/cooling change to qs - evplimit = max(0._r8, (qs(i,k)-q(i,k)) / deltat) + ! Don't let evaporation supersaturate layer (approx). Layer may already be saturated. + ! Currently does not include heating/cooling change to qs + evplimit = max(0._r8, (qs(i,k)-q(i,k)) / deltat) -! Don't evaporate more than is falling into the layer - do not evaporate rain formed -! in this layer but if precip production is negative, remove from the available precip -! Negative precip production occurs because of evaporation in downdrafts. -!!$ evplimit = flxprec(i,k) * gravit / pdel(i,k) + min(prdprec(i,k), 0.) - evplimit = min(evplimit, flxprec(i,k) * zm_const%grav / pdel(i,k)) + ! Don't evaporate more than is falling into the layer from above. + ! Don't evaporate rain formed in this layer, but if precip production + ! is negative, remove from the available precip. Negative precip + ! production occurs because of evaporation in downdrafts. + evplimit = min(evplimit, flxprec(i,k) * zm_const%grav / pdel(i,k)) -! Total evaporation cannot exceed input precipitation - evplimit = min(evplimit, (prec(i) - evpvint(i)) * zm_const%grav / pdel(i,k)) + ! Total evaporation cannot exceed input precipitation + evplimit = min(evplimit, (prec(i) - evpvint(i)) * zm_const%grav / pdel(i,k)) - evpprec(i) = min(evplimit, evpprec(i)) + evpprec(i) = min(evplimit, evpprec(i)) - if( .not.zm_param%old_snow ) then + if( .not.zm_param%old_snow ) then evpprec(i) = max(0._r8, evpprec(i)) evpprec(i) = evpprec(i)*omsm - end if - -! evaporation of snow depends on snow fraction of total precipitation in the top after melting - if (flxprec(i,k) > 0._r8) then -! evpsnow(i) = evpprec(i) * flxsntm(i) / flxprec(i,k) -! prevent roundoff problems - work1 = min(max(0._r8,flxsntm(i)/flxprec(i,k)),1._r8) - if (.not.zm_param%old_snow .and. prdsnow(i,k)>prdprec(i,k)) work1 = 1._r8 - evpsnow(i) = evpprec(i) * work1 - else - evpsnow(i) = 0._r8 - end if - -! vertically integrated evaporation - evpvint(i) = evpvint(i) + evpprec(i) * pdel(i,k)/zm_const%grav - -! net precip production is production - evaporation - ntprprd(i,k) = prdprec(i,k) - evpprec(i) -! net snow production is precip production * ice fraction - evaporation - melting -!pjrworks ntsnprd(i,k) = prdprec(i,k)*fice(i,k) - evpsnow(i) - snowmlt(i) -!pjrwrks2 ntsnprd(i,k) = prdprec(i,k)*fsnow_conv(i,k) - evpsnow(i) - snowmlt(i) -! the small amount added to flxprec in the work1 expression has been increased from -! 1e-36 to 8.64e-11 (1e-5 mm/day). This causes the temperature based partitioning -! scheme to be used for small flxprec amounts. This is to address error growth problems. - - if( zm_param%old_snow ) then + end if + + ! evaporation of snow depends on snow fraction of total precipitation in the top after melting + if (flxprec(i,k) > 0._r8) then + ! use limiters to prevent roundoff problems + work1 = min( max(0._r8, flxsntm(i)/flxprec(i,k) ), 1._r8) + if (.not.zm_param%old_snow .and. prdsnow(i,k)>prdprec(i,k)) work1 = 1._r8 + evpsnow(i) = evpprec(i) * work1 + else + evpsnow(i) = 0._r8 + end if + + ! vertically integrated evaporation + evpvint(i) = evpvint(i) + evpprec(i) * pdel(i,k)/zm_const%grav + + ! net precip production => production - evaporation + ntprprd(i,k) = prdprec(i,k) - evpprec(i) + + ! net snow production => precip production * ice fraction - evaporation - melting + + ! the small amount added to flxprec in the work1 expression was increased + ! from 1e-36 to 8.64e-11 (1e-5 mm/day) to address error growth problems. + ! This causes temperature partitioning to be used for small flxprec amounts. + + if( zm_param%old_snow ) then #ifdef PERGRO - work1 = min(max(0._r8,flxsnow(i,k)/(flxprec(i,k)+8.64e-11_r8)),1._r8) + work1 = min(max(0._r8,flxsnow(i,k)/(flxprec(i,k)+8.64e-11_r8)),1._r8) #else - if (flxprec(i,k).gt.0._r8) then - work1 = min(max(0._r8,flxsnow(i,k)/flxprec(i,k)),1._r8) - else - work1 = 0._r8 - endif + if (flxprec(i,k).gt.0._r8) then + work1 = min(max(0._r8,flxsnow(i,k)/flxprec(i,k)),1._r8) + else + work1 = 0._r8 + endif #endif - work2 = max(fsnow_conv(i,k), work1) - if (snowmlt(i).gt.0._r8) work2 = 0._r8 -! work2 = fsnow_conv(i,k) - ntsnprd(i,k) = prdprec(i,k)*work2 - evpsnow(i) - snowmlt(i) - tend_s_snwprd (i,k) = prdprec(i,k)*work2*zm_const%latice - tend_s_snwevmlt(i,k) = - ( evpsnow(i) + snowmlt(i) )*zm_const%latice - else - ntsnprd(i,k) = prdsnow(i,k) - min(flxsnow(i,k)*zm_const%grav/pdel(i,k), evpsnow(i)+snowmlt(i)) - tend_s_snwprd (i,k) = prdsnow(i,k)*zm_const%latice - tend_s_snwevmlt(i,k) = -min(flxsnow(i,k)*zm_const%grav/pdel(i,k), evpsnow(i)+snowmlt(i) )*zm_const%latice - end if - -! precipitation fluxes - flxprec(i,k+1) = flxprec(i,k) + ntprprd(i,k) * pdel(i,k)/zm_const%grav - flxsnow(i,k+1) = flxsnow(i,k) + ntsnprd(i,k) * pdel(i,k)/zm_const%grav - -! protect against rounding error - flxprec(i,k+1) = max(flxprec(i,k+1), 0._r8) - flxsnow(i,k+1) = max(flxsnow(i,k+1), 0._r8) -! more protection (pjr) -! flxsnow(i,k+1) = min(flxsnow(i,k+1), flxprec(i,k+1)) - -! heating (cooling) and moistening due to evaporation -! - latent heat of vaporization for precip production has already been accounted for -! - snow is contained in prec - if( zm_param%old_snow ) then - tend_s(i,k) =-evpprec(i)*zm_const%latvap + ntsnprd(i,k)*zm_const%latice - else - tend_s(i,k) =-evpprec(i)*zm_const%latvap + tend_s_snwevmlt(i,k) - end if - - tend_q(i,k) = evpprec(i) - end do - end do - -! protect against rounding error - if( .not.zm_param%old_snow ) then - do i = 1, ncol - if(flxsnow(i,pverp).gt.flxprec(i,pverp)) then - dum = (flxsnow(i,pverp)-flxprec(i,pverp))*zm_const%grav - do k = pver, 1, -1 - if (ntsnprd(i,k)>ntprprd(i,k).and. dum > 0._r8) then - ntsnprd(i,k) = ntsnprd(i,k) - dum/pdel(i,k) - tend_s_snwevmlt(i,k) = tend_s_snwevmlt(i,k) - dum/pdel(i,k)*zm_const%latice - tend_s(i,k) = tend_s(i,k) - dum/pdel(i,k)*zm_const%latice - dum = 0._r8 - end if - end do - flxsnow(i,pverp) = flxprec(i,pverp) - end if - end do - end if + work2 = max(fsnow_conv(i,k), work1) + if (snowmlt(i).gt.0._r8) work2 = 0._r8 + ntsnprd(i,k) = prdprec(i,k)*work2 - evpsnow(i) - snowmlt(i) + tend_s_snwprd (i,k) = prdprec(i,k)*work2*zm_const%latice + tend_s_snwevmlt(i,k) = - ( evpsnow(i) + snowmlt(i) )*zm_const%latice + else + ntsnprd(i,k) = prdsnow(i,k) - min(flxsnow(i,k)*zm_const%grav/pdel(i,k), evpsnow(i)+snowmlt(i)) + tend_s_snwprd (i,k) = prdsnow(i,k)*zm_const%latice + tend_s_snwevmlt(i,k) = -min(flxsnow(i,k)*zm_const%grav/pdel(i,k), evpsnow(i)+snowmlt(i) )*zm_const%latice + end if + + ! precipitation fluxes + flxprec(i,k+1) = flxprec(i,k) + ntprprd(i,k) * pdel(i,k)/zm_const%grav + flxsnow(i,k+1) = flxsnow(i,k) + ntsnprd(i,k) * pdel(i,k)/zm_const%grav + + ! protect against rounding error + flxprec(i,k+1) = max(flxprec(i,k+1), 0._r8) + flxsnow(i,k+1) = max(flxsnow(i,k+1), 0._r8) + ! heating (cooling) and moistening due to evaporation + ! - latent heat of vaporization for precip production has already been accounted for + ! - snow is contained in prec + if( zm_param%old_snow ) then + tend_s(i,k) =-evpprec(i)*zm_const%latvap + ntsnprd(i,k)*zm_const%latice + else + tend_s(i,k) =-evpprec(i)*zm_const%latvap + tend_s_snwevmlt(i,k) + end if + + tend_q(i,k) = evpprec(i) + end do ! i + end do ! k -! set output precipitation rates (m/s) - prec(:ncol) = flxprec(:ncol,pver+1) / 1000._r8 - snow(:ncol) = flxsnow(:ncol,pver+1) / 1000._r8 + ! protect against rounding error + if( .not.zm_param%old_snow ) then + do i = 1, ncol + if(flxsnow(i,pverp).gt.flxprec(i,pverp)) then + dum = (flxsnow(i,pverp)-flxprec(i,pverp))*zm_const%grav + do k = pver, 1, -1 + if (ntsnprd(i,k)>ntprprd(i,k).and. dum > 0._r8) then + ntsnprd(i,k) = ntsnprd(i,k) - dum/pdel(i,k) + tend_s_snwevmlt(i,k) = tend_s_snwevmlt(i,k) - dum/pdel(i,k)*zm_const%latice + tend_s(i,k) = tend_s(i,k) - dum/pdel(i,k)*zm_const%latice + dum = 0._r8 + end if + end do + flxsnow(i,pverp) = flxprec(i,pverp) + end if + end do + end if -!********************************************************** -!!$ tend_s(:ncol,:) = 0. ! turn heating off -!********************************************************** + ! set output precipitation rates (m/s) + prec(:ncol) = flxprec(:ncol,pver+1) / 1000._r8 + snow(:ncol) = flxsnow(:ncol,pver+1) / 1000._r8 - end subroutine zm_conv_evap +end subroutine zm_conv_evap !=================================================================================================== From 1be8e06ad775d5b0bffc3a7b8bdb7d8adfd49277 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 24 Nov 2025 15:43:16 -0800 Subject: [PATCH 070/398] convert omsm to module parameter --- components/eam/src/physics/cam/zm_conv.F90 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index faf8d03e3af2..5c38866afee5 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -34,8 +34,9 @@ module zm_conv type(zm_param_t), public :: zm_param ! derived type to hold ZM tunable parameters !---------------------------------------------------------------------------- ! private variables - real(r8), parameter :: capelmt = 70._r8 ! threshold value for cape for deep convection - real(r8), parameter :: trigdcapelmt = 0._r8 ! threshold value of dcape for deep convection + real(r8), parameter :: capelmt = 70._r8 ! threshold value for cape for deep convection + real(r8), parameter :: trigdcapelmt = 0._r8 ! threshold value of dcape for deep convection + real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error !=================================================================================================== contains !=================================================================================================== @@ -727,8 +728,6 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & real(r8) :: work2 ! temporary work variable real(r8) :: evplimit ! temporary work variable for evaporation limits real(r8) :: dum ! temporary work variable - real(r8) :: omsm ! to prevent problems due to round off error - !---------------------------------------------------------------------------- if (zm_param%zm_microp) then prdsnow(1:ncol,1:pver) = microp_st%sprd(1:ncol,1:pver) @@ -749,8 +748,6 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & flxprec(:ncol,1) = 0._r8 flxsnow(:ncol,1) = 0._r8 evpvint(:ncol) = 0._r8 - - omsm=0.99999_r8 ! to prevent problems due to round off error do k = 1, pver do i = 1, ncol @@ -1048,7 +1045,6 @@ subroutine cldprp(pcols, ncol, pver, pverp, & real(r8), dimension(pcols,pverp):: pflxs ! frozen precipitation flux thru layer real(r8) dum, sdum - real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error real(r8), parameter :: mu_min = 0.02_r8 ! minimum value of mu real(r8), parameter :: t_homofrz = 233.15_r8 ! homogeneous freezing temperature real(r8), parameter :: t_mphase = 40._r8 ! mixed phase temperature = tfreez-t_homofrz = 273.15K - 233.15K From 3cbea07d3856b0c01cd8e05116749ba2a4c26fa0 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 24 Nov 2025 15:47:49 -0800 Subject: [PATCH 071/398] comment clean-up --- components/eam/src/physics/cam/zm_conv.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 5c38866afee5..b137be563bc6 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -22,12 +22,12 @@ module zm_conv !---------------------------------------------------------------------------- implicit none save - private ! Make default type private + private !---------------------------------------------------------------------------- ! public methods public zm_convi ! ZM scheme initialization public zm_convr ! ZM scheme calculations - public zm_conv_evap ! evaporation of precip from ZM schemea + public zm_conv_evap ! ZM scheme evaporation of precip !---------------------------------------------------------------------------- ! public variables type(zm_const_t), public :: zm_const ! derived type to hold ZM constants From fe34db915b118113deff6155f57960eaf34db54a Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Tue, 25 Nov 2025 09:39:17 -0600 Subject: [PATCH 072/398] Add CRYO1850-CMIP7 to e3sm_prod test suite --- cime_config/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/tests.py b/cime_config/tests.py index 8594d96bdf13..6dd1cb8e3e6d 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -433,6 +433,7 @@ "SMS_Ld1.ne30pg2_r05_IcoswISC30E3r5.WCYCLSSP585.allactive-wcprodssp", "SMS_Ld1_P512.northamericax4v1pg2_r025_IcoswISC30E3r5.WCYCL1850.allactive-wcprodrrm_1850", "SMS_D_Ld1.ne30pg2_r05_IcoswISC30E3r5.CRYO1850", + "SMS_D_Ld1.ne30pg2_r05_IcoswISC30E3r5.CRYO1850-CMIP7", ) }, From f51df9afda815aac3cc5b6ac1705345bb2411931 Mon Sep 17 00:00:00 2001 From: Erin Thomas Date: Tue, 25 Nov 2025 13:44:23 -0600 Subject: [PATCH 073/398] fix u10n for e3sm diagnotics U10 variable in coupled setup. fix to tiny --- share/util/shr_flux_mod.F90 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/share/util/shr_flux_mod.F90 b/share/util/shr_flux_mod.F90 index e311c187d4e0..3bef3fed0643 100644 --- a/share/util/shr_flux_mod.F90 +++ b/share/util/shr_flux_mod.F90 @@ -388,7 +388,7 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & !--- ustar, tstar, qstar --- if (wav_atm_coup .eq. 'twoway') then if (ustarwav(n) .lt. tiny) then - ustar = ustarwav(n)+tiny + ustar = tiny ! set to tiny to avoid a divide by zero error else ustar = ustarwav(n) endif @@ -464,7 +464,13 @@ SUBROUTINE shr_flux_atmOcn(nMax ,zbot ,ubot ,vbot ,thbot , & end if vmag = max(seq_flux_atmocn_minwind, vmag) end if + enddo + + if (wav_atm_coup .eq. 'twoway') then + u10n = vmag * rd / rdn + endif + if (iter < 1) then write(s_logunit,*) ustar,ustar_prev,flux_con_tol,flux_con_max_iter call shr_sys_abort('No iterations performed ' // errMsg(sourcefile, __LINE__)) From 177745a5c785de594a930b4c19df7c9a638d726c Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 25 Nov 2025 12:00:53 -0800 Subject: [PATCH 074/398] cleanup cldprp() interface --- components/eam/src/physics/cam/zm_conv.F90 | 244 +++++++++------------ 1 file changed, 101 insertions(+), 143 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index b137be563bc6..43128ee6f3d8 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -480,17 +480,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! obtain cloud properties. - call cldprp(pcols, ncol, pver, pverp, & - qg ,tg ,ug ,vg ,pg , & - zg ,sg ,mu ,eu ,du , & - md ,ed ,sd ,qd ,mc , & - qu ,su ,zfg ,qs ,hmn , & - hsat ,shat ,qlg , & - maxg ,lelg ,jt ,jlcl , & - maxg ,j0 ,jd ,lengath ,msg , & - pflxg ,evpg ,cug ,rprdg ,zm_param%limcnv , & - landfracg, tpertg, & - aero ,loc_microp_st ) ! < added for ZM micro + call cldprp(pcols, ncol, pver, pverp, lengath, msg, zm_param%limcnv, & + pg, zg, zfg, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & + maxg, maxg, lelg, jt, jlcl, j0, jd, & + mu, eu, du, md, ed, mc, & + su, qu, qlg, sd, qd, & + hmn, hsat, qs, cug, evpg, pflxg, rprdg, & + aero, loc_microp_st ) !---------------------------------------------------------------------------- ! convert detrainment from units of "1/m" to "1/mb". @@ -899,136 +895,98 @@ end subroutine zm_conv_evap !=================================================================================================== -subroutine cldprp(pcols, ncol, pver, pverp, & - q ,t ,u ,v ,p , & - z ,s ,mu ,eu ,du , & - md ,ed ,sd ,qd ,mc , & - qu ,su ,zf ,qst ,hmn , & - hsat ,shat ,ql , & - jb ,lel ,jt ,jlcl , & - mx ,j0 ,jd ,il2g ,msg , & - pflx ,evp ,cu ,rprd ,limcnv , & - landfrac,tpertg , & - aero ,loc_microp_st ) - -!----------------------------------------------------------------------- -! -! Purpose: -! -! -! Method: -! may 09/91 - guang jun zhang, m.lazare, n.mcfarlane. -! original version cldprop. -! -! Author: See above, modified by P. Rasch -! This is contributed code not fully standardized by the CCM core group. -! -! this code is very much rougher than virtually anything else in the CCM -! there are debug statements left strewn about and code segments disabled -! these are to facilitate future development. We expect to release a -! cleaner code in a future release -! -! the documentation has been enhanced to the degree that we are able -! -!----------------------------------------------------------------------- - +subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & + p, z, zf, t, s, shat, q, u, v, landfrac, tpertg, & + jb, mx, lel, jt, jlcl, j0, jd, & + mu, eu, du, md, ed, mc, & + su, qu, ql, sd, qd, & + hmn, hsat, qst, cu, evp, pflx, rprd, & + aero, loc_microp_st ) + !---------------------------------------------------------------------------- + ! Purpose: + !---------------------------------------------------------------------------- implicit none + !---------------------------------------------------------------------------- + ! Arguments + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: il2g ! number of gathered columns (lengath) + integer, intent(in ) :: msg ! missing moisture vals + integer, intent(in ) :: limcnv ! convection limiting level + real(r8), dimension(pcols,pver), intent(in ) :: p ! env pressure at mid-point + real(r8), dimension(pcols,pver), intent(in ) :: z ! env altitude at mid-point + real(r8), dimension(pcols,pverp),intent(in ) :: zf ! env altitude at interface + real(r8), dimension(pcols,pver), intent(in ) :: t ! env temperature + real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: shat ! interface values of dry stat energy + real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: u ! env zonal wind + real(r8), dimension(pcols,pver), intent(in ) :: v ! env meridional wind + real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction + real(r8), dimension(pcols), intent(in ) :: tpertg ! PBL temperature perturbation + integer, dimension(pcols), intent(in ) :: jb ! updraft base level + integer, dimension(pcols), intent(in ) :: mx ! updraft base level (same is jb) + integer, dimension(pcols), intent(in ) :: lel ! updraft launch level + integer, dimension(pcols), intent(out) :: jt ! updraft plume top + integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level + integer, dimension(pcols), intent(out) :: j0 ! level where updraft begins detraining + integer, dimension(pcols), intent(out) :: jd ! level of downdraft + real(r8), dimension(pcols,pver), intent(out) :: mu ! updraft mass flux + real(r8), dimension(pcols,pver), intent(out) :: eu ! entrainment rate of updraft + real(r8), dimension(pcols,pver), intent(out) :: du ! detrainement rate of updraft + real(r8), dimension(pcols,pver), intent(out) :: md ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(out) :: ed ! entrainment rate of downdraft + real(r8), dimension(pcols,pver), intent(out) :: mc ! net mass flux + real(r8), dimension(pcols,pver), intent(out) :: su ! updraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(out) :: qu ! updraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water + real(r8), dimension(pcols,pver), intent(out) :: sd ! dndraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(out) :: qd ! dndraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(out) :: hmn ! env moist stat energy + real(r8), dimension(pcols,pver), intent(out) :: hsat ! env saturated moist stat energy + real(r8), dimension(pcols,pver), intent(out) :: qst ! env saturation mixing ratio + real(r8), dimension(pcols,pver), intent(out) :: cu ! condensation rate + real(r8), dimension(pcols,pver), intent(out) :: evp ! evaporation rate + real(r8), dimension(pcols,pverp),intent(out) :: pflx ! precipitation flux thru layer + real(r8), dimension(pcols,pver), intent(out) :: rprd ! rate of production of precip at that layer + type(zm_aero_t), intent(in ) :: aero ! aerosol object + type(zm_microp_st) :: loc_microp_st ! state and tendency of convective microphysics + !---------------------------------------------------------------------------- + ! Local variables + real(r8), dimension(pcols,pver) :: gamma + real(r8), dimension(pcols,pver) :: dz + real(r8), dimension(pcols,pver) :: iprm + real(r8), dimension(pcols,pver) :: hu + real(r8), dimension(pcols,pver) :: hd + real(r8), dimension(pcols,pver) :: eps + real(r8), dimension(pcols,pver) :: f + real(r8), dimension(pcols,pver) :: k1 + real(r8), dimension(pcols,pver) :: i2 + real(r8), dimension(pcols,pver) :: ihat + real(r8), dimension(pcols,pver) :: i3 + real(r8), dimension(pcols,pver) :: idag + real(r8), dimension(pcols,pver) :: i4 + real(r8), dimension(pcols,pver) :: qsthat + real(r8), dimension(pcols,pver) :: hsthat + real(r8), dimension(pcols,pver) :: gamhat + real(r8), dimension(pcols,pver) :: qds + real(r8), dimension(pcols) :: c0mask + real(r8), dimension(pcols) :: hmin + real(r8), dimension(pcols) :: expdif + real(r8), dimension(pcols) :: expnum + real(r8), dimension(pcols) :: ftemp + real(r8), dimension(pcols) :: eps0 + real(r8), dimension(pcols) :: rmue + real(r8), dimension(pcols) :: zuef + real(r8), dimension(pcols) :: zdef + real(r8), dimension(pcols) :: epsm + real(r8), dimension(pcols) :: ratmjb + real(r8), dimension(pcols) :: est + real(r8), dimension(pcols) :: totpcp + real(r8), dimension(pcols) :: totevp -!------------------------------------------------------------------------------ -! -! Input arguments -! - integer, intent(in) :: pcols ! maximum number of columns - integer, intent(in) :: ncol ! actual number of columns - integer, intent(in) :: pver ! number of mid-point vertical levels - integer, intent(in) :: pverp ! number of interface vertical levels - real(r8), intent(in) :: q(pcols,pver) ! spec. humidity of env - real(r8), intent(in) :: t(pcols,pver) ! temp of env - real(r8), intent(in) :: p(pcols,pver) ! pressure of env - real(r8), intent(in) :: z(pcols,pver) ! height of env - real(r8), intent(in) :: s(pcols,pver) ! normalized dry static energy of env - real(r8), intent(in) :: zf(pcols,pverp) ! height of interfaces - real(r8), intent(in) :: u(pcols,pver) ! zonal velocity of env - real(r8), intent(in) :: v(pcols,pver) ! merid. velocity of env - - real(r8), intent(in) :: landfrac(pcols) ! RBN Landfrac - - integer, intent(in) :: jb(pcols) ! updraft base level - integer, intent(in) :: lel(pcols) ! updraft launch level - integer, intent(out) :: jt(pcols) ! updraft plume top - integer, intent(out) :: jlcl(pcols) ! updraft lifting cond level - integer, intent(in) :: mx(pcols) ! updraft base level (same is jb) - integer, intent(out) :: j0(pcols) ! level where updraft begins detraining - integer, intent(out) :: jd(pcols) ! level of downdraft - integer, intent(in) :: limcnv ! convection limiting level - integer, intent(in) :: il2g !CORE GROUP REMOVE - integer, intent(in) :: msg ! missing moisture vals (always 0) - real(r8), intent(in) :: shat(pcols,pver) ! interface values of dry stat energy - real(r8), intent(in) :: tpertg(pcols) - - type(zm_aero_t), intent(in) :: aero ! aerosol object - -! -! output -! - real(r8), intent(out) :: rprd(pcols,pver) ! rate of production of precip at that layer - real(r8), intent(out) :: du(pcols,pver) ! detrainement rate of updraft - real(r8), intent(out) :: ed(pcols,pver) ! entrainment rate of downdraft - real(r8), intent(out) :: eu(pcols,pver) ! entrainment rate of updraft - real(r8), intent(out) :: hmn(pcols,pver) ! moist stat energy of env - real(r8), intent(out) :: hsat(pcols,pver) ! sat moist stat energy of env - real(r8), intent(out) :: mc(pcols,pver) ! net mass flux - real(r8), intent(out) :: md(pcols,pver) ! downdraft mass flux - real(r8), intent(out) :: mu(pcols,pver) ! updraft mass flux - real(r8), intent(out) :: pflx(pcols,pverp) ! precipitation flux thru layer - real(r8), intent(out) :: qd(pcols,pver) ! spec humidity of downdraft - real(r8), intent(out) :: ql(pcols,pver) ! liq water of updraft - real(r8), intent(out) :: qst(pcols,pver) ! saturation mixing ratio of env. - real(r8), intent(out) :: qu(pcols,pver) ! spec hum of updraft - real(r8), intent(out) :: sd(pcols,pver) ! normalized dry stat energy of downdraft - real(r8), intent(out) :: su(pcols,pver) ! normalized dry stat energy of updraft - - ! Convective microphysics - type(zm_microp_st) :: loc_microp_st ! state and tendency of convective microphysics - -! -! Local workspace -! - real(r8) gamma(pcols,pver) - real(r8) dz(pcols,pver) - real(r8) iprm(pcols,pver) - real(r8) hu(pcols,pver) - real(r8) hd(pcols,pver) - real(r8) eps(pcols,pver) - real(r8) f(pcols,pver) - real(r8) k1(pcols,pver) - real(r8) i2(pcols,pver) - real(r8) ihat(pcols,pver) - real(r8) i3(pcols,pver) - real(r8) idag(pcols,pver) - real(r8) i4(pcols,pver) - real(r8) qsthat(pcols,pver) - real(r8) hsthat(pcols,pver) - real(r8) gamhat(pcols,pver) - real(r8) cu(pcols,pver) - real(r8) evp(pcols,pver) - real(r8) qds(pcols,pver) -! RBN For c0mask - real(r8) c0mask(pcols) - - real(r8) hmin(pcols) - real(r8) expdif(pcols) - real(r8) expnum(pcols) - real(r8) ftemp(pcols) - real(r8) eps0(pcols) - real(r8) rmue(pcols) - real(r8) zuef(pcols) - real(r8) zdef(pcols) - real(r8) epsm(pcols) - real(r8) ratmjb(pcols) - real(r8) est(pcols) - real(r8) totpcp(pcols) - real(r8) totevp(pcols) real(r8) ql1 real(r8) tu real(r8) estu @@ -1049,8 +1007,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, & real(r8), parameter :: t_homofrz = 233.15_r8 ! homogeneous freezing temperature real(r8), parameter :: t_mphase = 40._r8 ! mixed phase temperature = tfreez-t_homofrz = 273.15K - 233.15K - integer jto(pcols) ! updraft plume old top - integer tmplel(pcols) + integer, dimension(pcols) :: jto ! updraft plume old top + integer, dimension(pcols) :: tmplel integer iter, itnum integer m @@ -1060,8 +1018,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, & integer kount integer i,k - logical doit(pcols) - logical done(pcols) + logical, dimension(pcols) :: doit + logical, dimension(pcols) :: done ! !------------------------------------------------------------------------------ From a9036a6d36f6145dec9fb0f4d1da33b33fd9f3f2 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Fri, 26 Sep 2025 17:37:32 -0500 Subject: [PATCH 075/398] Remove setting of xao Av Remove setting of xao Av. Loop bound is no longer set by MCT and debugger was complaining. --- driver-moab/main/seq_flux_mct.F90 | 44 ------------------------------- 1 file changed, 44 deletions(-) diff --git a/driver-moab/main/seq_flux_mct.F90 b/driver-moab/main/seq_flux_mct.F90 index b5bcd6642ce9..1965b04db809 100644 --- a/driver-moab/main/seq_flux_mct.F90 +++ b/driver-moab/main/seq_flux_mct.F90 @@ -1937,50 +1937,6 @@ subroutine seq_flux_atmocn_moab(infodata, tod, dt, a2x, o2x, xao, mbid, mbfid) call mbSetCellTagVals(mbfid, 'So_u10withgusts', u10gust, nloc) call mbSetCellTagVals(mbfid, 'So_fswpen', fswpen, nloc) - do n = 1,nloc - if (mask(n) == 0) then - xao%rAttr(index_xao_Faox_sen ,n) = 0.0_r8 - xao%rAttr(index_xao_Faox_lat ,n) = 0.0_r8 - xao%rAttr(index_xao_Faox_taux,n) = 0.0_r8 - xao%rAttr(index_xao_Faox_tauy,n) = 0.0_r8 - xao%rAttr(index_xao_Faox_evap,n) = 0.0_r8 - if ( index_xao_Faox_evap_16O /= 0 ) xao%rAttr(index_xao_Faox_evap_16O,n) = evap_16O(n) - if ( index_xao_Faox_evap_HDO /= 0 ) xao%rAttr(index_xao_Faox_evap_HDO,n) = evap_HDO(n) - if ( index_xao_Faox_evap_18O /= 0 ) xao%rAttr(index_xao_Faox_evap_18O,n) = evap_18O(n) - xao%rAttr(index_xao_So_tref ,n) = 0.0_r8 - xao%rAttr(index_xao_So_qref ,n) = 0.0_r8 - xao%rAttr(index_xao_So_ustar ,n) = 0.0_r8 ! friction velocity - xao%rAttr(index_xao_So_re ,n) = 0.0_r8 ! reynolds number - xao%rAttr(index_xao_So_ssq ,n) = 0.0_r8 ! s.hum. saturation at Ts - xao%rAttr(index_xao_Faox_lwup,n) = 0.0_r8 - xao%rAttr(index_xao_So_duu10n,n) = 0.0_r8 - xao%rAttr(index_xao_So_u10 ,n) = 0.0_r8 - xao%rAttr(index_xao_So_u10withgusts ,n) = 0.0_r8 - if (flux_diurnal) then - xao%rAttr(index_xao_So_warm_diurn ,n) = warm(n) - xao%rAttr(index_xao_So_salt_diurn ,n) = salt(n) - xao%rAttr(index_xao_So_speed_diurn ,n) = speed(n) - xao%rAttr(index_xao_So_regime_diurn ,n) = regime(n) - xao%rAttr(index_xao_So_warmMax_diurn ,n) = warmMax(n) - xao%rAttr(index_xao_So_windMax_diurn ,n) = windMax(n) - xao%rAttr(index_xao_So_qSolAvg_diurn ,n) = qSolAvg(n) - xao%rAttr(index_xao_So_windAvg_diurn ,n) = windAvg(n) - xao%rAttr(index_xao_So_warmMaxInc_diurn ,n) = warmMaxInc(n) - xao%rAttr(index_xao_So_windMaxInc_diurn ,n) = windMaxInc(n) - xao%rAttr(index_xao_So_qSolInc_diurn ,n) = qSolInc(n) - xao%rAttr(index_xao_So_windInc_diurn ,n) = windInc(n) - xao%rAttr(index_xao_So_nInc_diurn ,n) = nInc(n) - xao%rAttr(index_xao_So_tbulk_diurn ,n) = tbulk(n) - xao%rAttr(index_xao_So_tskin_diurn ,n) = tskin(n) - xao%rAttr(index_xao_So_tskin_day_diurn ,n) = tskin_day(n) - xao%rAttr(index_xao_So_tskin_night_diurn,n) = tskin_night(n) - xao%rAttr(index_xao_So_cskin_diurn ,n) = cskin(n) - xao%rAttr(index_xao_So_cskin_night_diurn,n) = cskin_night(n) - xao%rAttr(index_xao_So_fswpen ,n) = fswpen(n) - endif - end if - enddo - #ifdef MOABDEBUG ! debug out file write(lnum,"(I0.2)")num_moab_exports From f0c221d15bd8701c01f1cf5000dd53639f04f3b2 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Fri, 26 Sep 2025 17:38:50 -0500 Subject: [PATCH 076/398] Use correct temporary array sizes Use correct temporary array sizes for ice and ocean instead of the maximum. Requires one more temp array. Also use a logical to allocate them just once. --- driver-moab/main/seq_frac_mct.F90 | 39 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/driver-moab/main/seq_frac_mct.F90 b/driver-moab/main/seq_frac_mct.F90 index 151f09773216..8c8587fc04b8 100644 --- a/driver-moab/main/seq_frac_mct.F90 +++ b/driver-moab/main/seq_frac_mct.F90 @@ -901,9 +901,10 @@ subroutine seq_frac_set(infodata, ice, ocn, fractions_a, fractions_i, fractions_ integer :: n integer :: ki, kl, ko, kf real(r8),allocatable :: fcorr(:) - real(r8),allocatable :: tagValues(:) ! used for setting some default tags - real(r8),allocatable :: tagValues2(:) ! used for setting some default tags - real(r8),allocatable :: tagValues3(:) ! used for setting some default tags + real(r8),allocatable,save :: tagValues(:) ! used for setting some default tags + real(r8),allocatable,save :: tagValues2(:) ! used for setting some default tags + real(r8),allocatable,save :: tagValues3(:) ! used for setting some default tags + real(r8),allocatable,save :: tagValues4(:) ! used for setting some default tags logical, save :: first_time = .true. ! moab @@ -939,11 +940,9 @@ subroutine seq_frac_set(infodata, ice, ocn, fractions_a, fractions_i, fractions_ dom_i => component_get_dom_cx(ice) i2x_i => component_get_c2x_cx(ice) - ! make local array big enough to old ocean or ice data. + ! make local array big enough to hold ocean or ice data. if (mbixid .ge. 0) arrSize_i = mbGetnCells(mbixid) if (mboxid .ge. 0) arrSize_o = mbGetnCells(mboxid) - arrSize = arrSize_i - if (arrSize_o .gt. arrSize) arrSize = arrSize_o ! entire update depends on if ice present. if (ice_present) then @@ -960,26 +959,26 @@ subroutine seq_frac_set(infodata, ice, ocn, fractions_a, fractions_i, fractions_ call seq_frac_check(fractions_i,'ice set') ! MOAB - allocate(tagValues(arrSize) ) - allocate(tagValues2(arrSize) ) - allocate(tagValues3(arrSize) ) + if (first_time) then + allocate(tagValues(arrSize_i) ) + allocate(tagValues2(arrSize_i) ) + allocate(tagValues3(arrSize_i) ) + endif ! copy Si_ifrac to ifrac - call mbGetCellTagVals(mbixid, 'Si_ifrac',tagValues,arrSize) - call mbSetCellTagVals(mbixid, 'ifrac',tagValues,arrSize) + call mbGetCellTagVals(mbixid, 'Si_ifrac',tagValues,arrSize_i) + call mbSetCellTagVals(mbixid, 'ifrac',tagValues,arrSize_i) ! update ifrac and ofrac - call mbGetCellTagVals(mbixid, 'ifrac',tagValues,arrSize) - call mbGetCellTagVals(mbixid, 'frac',tagValues2,arrSize) - call mbGetCellTagVals(mbixid, 'ofrac',tagValues3,arrSize) + call mbGetCellTagVals(mbixid, 'frac',tagValues2,arrSize_i) !fractions_i%rAttr(ki,:) = fractions_i%rAttr(ki,:) * dom_i%data%rAttr(kf,:) tagValues(:) = tagValues(:)*tagValues2(:) - call mbSetCellTagVals(mbixid, 'ifrac',tagValues,arrSize) + call mbSetCellTagVals(mbixid, 'ifrac',tagValues,arrSize_i) !fractions_i%rAttr(ko,:) = dom_i%data%rAttr(kf,:) - fractions_i%rAttr(ki,:) tagValues3(:) = tagValues2(:) - tagValues(:) - call mbSetCellTagVals(mbixid, 'ofrac',tagValues3,arrSize) + call mbSetCellTagVals(mbixid, 'ofrac',tagValues3,arrSize_i) #ifdef MOABDEBUG write(lnum,"(I0.2)")num_moab_exports @@ -989,16 +988,20 @@ subroutine seq_frac_set(infodata, ice, ocn, fractions_a, fractions_i, fractions_ #endif if (ocn_present) then + if (first_time) then + allocate(tagValues4(arrSize_o) ) + endif mapper_i2o => prep_ocn_get_mapper_SFi2o() call seq_map_map(mapper_i2o, fractions_i, fractions_o, & fldlist='ofrac:ifrac',norm=.false.) call seq_frac_check(fractions_o, 'ocn set') ! set the ofrac on mbofxid instance, because it is needed for prep_aoxflux - call mbGetCellTagVals(mboxid, 'ofrac',tagValues,arrSize) - call mbSetCellTagVals(mbofxid, 'ofrac',tagValues,arrSize) + call mbGetCellTagVals(mboxid, 'ofrac',tagValues4,arrSize_o) + call mbSetCellTagVals(mbofxid, 'ofrac',tagValues4,arrSize_o) endif + first_time=.false. if (atm_present) then mapper_i2a => prep_atm_get_mapper_Fi2a() From 80545694eb0f334809b3ea93ae31531348af517c Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Mon, 1 Sep 2025 19:09:12 -0500 Subject: [PATCH 077/398] first pass at atm spectral separation need to add ext tags fix data atm too --- components/eam/src/cpl/atm_comp_mct.F90 | 9 +- components/eam/src/dynamics/se/dyn_comp.F90 | 4 +- .../homme/interface/phys_grid_mod.F90 | 49 +- components/homme/src/share/semoab_mod.F90 | 1189 +++++++++++++++++ 4 files changed, 1223 insertions(+), 28 deletions(-) diff --git a/components/eam/src/cpl/atm_comp_mct.F90 b/components/eam/src/cpl/atm_comp_mct.F90 index 67f574357d84..5b467b6d83b3 100644 --- a/components/eam/src/cpl/atm_comp_mct.F90 +++ b/components/eam/src/cpl/atm_comp_mct.F90 @@ -515,12 +515,15 @@ subroutine atm_init_mct( EClock, cdata_a, x2a_a, a2x_a, NLFilename ) call atm_export_moab(Eclock, cam_out) #endif else ! if (StepNo != 0) then + +#ifdef HAVE_MOAB + call t_startf('atm_read_srfrest_moab') + call atm_read_srfrest_moab ( EClock ) + call t_stopf('atm_read_srfrest_moab') +#else call t_startf('atm_read_srfrest_mct') call atm_read_srfrest_mct( EClock, x2a_a, a2x_a ) call t_stopf('atm_read_srfrest_mct') -#ifdef HAVE_MOAB - call atm_read_srfrest_moab ( EClock ) - #endif ! Sent .true. as an optional argument so that restart_init is set to .true. in atm_import diff --git a/components/eam/src/dynamics/se/dyn_comp.F90 b/components/eam/src/dynamics/se/dyn_comp.F90 index faff6ffd314b..b2e04cc21adf 100644 --- a/components/eam/src/dynamics/se/dyn_comp.F90 +++ b/components/eam/src/dynamics/se/dyn_comp.F90 @@ -106,7 +106,7 @@ subroutine dyn_init1(fh, NLFileName, dyn_in, dyn_out) use seq_comm_mct, only: MHID, MHFID ! id of homme moab coarse and fine applications use seq_comm_mct, only: ATMID use seq_comm_mct, only: mhpgid ! id of pgx moab application - use semoab_mod, only: create_moab_meshes + use semoab_mod, only: create_moab_pg_mesh use iMOAB, only : iMOAB_RegisterApplication use iso_c_binding #endif @@ -269,7 +269,7 @@ subroutine dyn_init1(fh, NLFileName, dyn_in, dyn_out) end if #ifdef HAVE_MOAB - call create_moab_meshes(par, elem, fv_nphys) + call create_moab_pg_mesh(par, elem, fv_nphys) #endif ! Define the CAM grids (this has to be after dycore spinup). ! Physics-grid will be defined later by phys_grid_init diff --git a/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 b/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 index 2f13cbc274d0..7c0abdc73f2c 100644 --- a/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 +++ b/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 @@ -552,7 +552,7 @@ subroutine phys_grid_init (pgN) use seq_comm_mct, only: MHID, MHFID ! id of homme moab coarse and fine applications use seq_comm_mct, only: ATMID use seq_comm_mct, only: mhpgid ! id of pgx moab application - use semoab_mod, only: create_moab_meshes + use semoab_mod, only: create_moab_pg_mesh, create_spectral_moab_meshes use iMOAB, only : iMOAB_RegisterApplication use iso_c_binding #endif @@ -624,27 +624,28 @@ subroutine phys_grid_init (pgN) call compute_global_coords (pg) call compute_global_area (pg) #ifdef HAVE_MOAB + appname="HM_COARSE"//C_NULL_CHAR + ATM_ID1 = 120 ! + ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHID) + if (ierr > 0 ) & + call abortmp('Error: cannot register moab app') + if(par%masterproc) then + write(iulog,*) " " + write(iulog,*) "register MOAB app:", trim(appname), " MHID=", MHID + write(iulog,*) " " + endif + appname="HM_FINE"//C_NULL_CHAR + ATM_ID1 = 119 ! this number should not conflict with other components IDs; how do we know? + ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHFID) + if (ierr > 0 ) & + call abortmp('Error: cannot register moab app for fine mesh') + if(par%masterproc) then + write(iulog,*) " " + write(iulog,*) "register MOAB app:", trim(appname), " MHFID=", MHFID + write(iulog,*) " " + endif if (pgN > 0) then - appname="HM_COARSE"//C_NULL_CHAR - ATM_ID1 = 120 ! - ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHID) - if (ierr > 0 ) & - call abortmp('Error: cannot register moab app') - if(par%masterproc) then - write(iulog,*) " " - write(iulog,*) "register MOAB app:", trim(appname), " MHID=", MHID - write(iulog,*) " " - endif - appname="HM_FINE"//C_NULL_CHAR - ATM_ID1 = 119 ! this number should not conflict with other components IDs; how do we know? - ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHFID) - if (ierr > 0 ) & - call abortmp('Error: cannot register moab app for fine mesh') - if(par%masterproc) then - write(iulog,*) " " - write(iulog,*) "register MOAB app:", trim(appname), " MHFID=", MHFID - write(iulog,*) " " - endif + appname="HM_PGX"//C_NULL_CHAR ATM_ID1 = ATMID(1) ! this number should not conflict with other components IDs; how do we know? ! @@ -662,8 +663,10 @@ subroutine phys_grid_init (pgN) ! 1 ) spectral coarse mesh ! 2 ) GLL fine quad mesh (used mostly for visualization) ! 3 ) pgN FV type mesh, (most of the time pg2 mesh), used for coupling with other components; - call create_moab_meshes(par, elem, pgN) - endif + call create_moab_pg_mesh(par, elem, pgN) + else + call create_spectral_moab_meshes(par, elem) + endif #endif end subroutine phys_grid_init diff --git a/components/homme/src/share/semoab_mod.F90 b/components/homme/src/share/semoab_mod.F90 index 4841cb84b543..8d46a441173f 100644 --- a/components/homme/src/share/semoab_mod.F90 +++ b/components/homme/src/share/semoab_mod.F90 @@ -76,6 +76,1195 @@ integer function search_in(intarr, leng, value) end function search_in + subroutine create_spectral_moab_meshes(par, elem) +use ISO_C_BINDING + use iMOAB, only: iMOAB_CreateVertices, iMOAB_WriteMesh, iMOAB_CreateElements, & + iMOAB_ResolveSharedEntities, iMOAB_UpdateMeshInfo, iMOAB_DefineTagStorage, & + iMOAB_SetIntTagStorage, iMOAB_ReduceTagsMax, iMOAB_GetIntTagStorage + use coordinate_systems_mod, only : cartesian3D_t, spherical_to_cart, spherical_polar_t + + type (element_t), intent(inout) :: elem(:) + type (parallel_t) , intent(in) :: par + + integer ierr, i, j, ie, iv, block_ID, k, numvals + integer icol, irow, je, linx ! local indices in fine el connect + + real(kind=real_kind), allocatable :: moab_vert_coords(:) + + integer moab_dim_cquads, ix, idx, nverts, nverts_c ! used for indexing in loops; nverts will have the number of local vertices + + integer nelemd2 ! do not confuse this with dimensions_mod::nelemd + + integer(kind=long_kind), dimension(:), allocatable :: gdofv + ! this will be moab vertex handle locally + integer, dimension(:), allocatable :: moabvh + integer, dimension(:), allocatable :: indx ! this will be ordered + + integer, dimension(:), allocatable :: vdone, elemids, vgids, gdofel + integer, dimension(:), allocatable :: vdone_c, moabconn_c, moabvh_c + integer currentval, dimcoord, dimen, num_el, mbtype, nve + + character*100 outfile, wopts, localmeshfile, lnum, tagname, newtagg + integer tagtype, numco, tag_sto_len, ent_type, tagindex + type (cartesian3D_t) :: cart + integer igcol, ii, neigh + + ! for np=4, + ! 28, 32, 36, 35 + ! 25, 29, 33, 34 + ! j | 13, 17, 21, 22 + ! 1, 5, 9, 10 + !(1,1) i-> + + ! character*100 outfile, wopts, localmeshfile, lnum, tagname + ! integer tagtype, numco, tag_sto_len, ent_type, tagindex + do j=1,np-1 + do i =1, np-1 + ix = (j-1)*(np-1)+i-1 + local_map(i,j) = ix*4 + 1 + enddo + enddo + do j=1, np-1 + i = j + local_map(np, j) = ((np-1)*j-1)*4 + 2 + local_map(i, np) = ( (np-1)*(np-2)+i-1)*4 + 4 + enddo + local_map(np, np) = ((np-1)*(np-1)-1)*4 + 3 + + nelemd2 = (nelemd)*(np-1)*(np-1) + moab_dim_cquads = (nelemd)*4*(np-1)*(np-1) + + if(par%masterproc) then + write (iulog, *) " MOAB: semoab_mod module: create_spectral_moab_meshes on processor " , par%rank ," nelemd: " , nelemd + endif + + if ( nelemd > 0 ) then + allocate(gdofv(moab_dim_cquads)) + allocate(elemids(nelemd2)) + endif + + k=0 ! will be the index for element global dofs + do ie=1,nelemd + do j=1,np-1 + do i=1,np-1 + ix = (ie-1)*(np-1)*(np-1)+(j-1)*(np-1)+i-1 + gdofv(ix*4+1) = elem(ie)%gdofP(i,j) + gdofv(ix*4+2) = elem(ie)%gdofP(i+1,j) + gdofv(ix*4+3) = elem(ie)%gdofP(i+1,j+1) + gdofv(ix*4+4) = elem(ie)%gdofP(i,j+1) + elemids(ix+1) = (elem(ie)%GlobalId-1)*(np-1)*(np-1)+(j-1)*(np-1)+i + enddo + enddo + enddo + +! order according to global dofs + + if ( nelemd > 0 ) then + allocate(moabvh(moab_dim_cquads)) + allocate(indx(moab_dim_cquads)) + + allocate(moabconn(moab_dim_cquads)) + call IndexSet(moab_dim_cquads, indx) + call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) +! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) + endif + idx=0 + currentval = 0 + if ( nelemd > 0 ) then + currentval = gdofv( indx(1)) + idx = 1 + endif + + do ix=1,moab_dim_cquads + if (gdofv(indx(ix)) .ne. currentval ) then + idx=idx+1 + currentval = gdofv(indx(ix)) + endif + moabvh(ix) = idx ! the vertex in connectivity array will be at this local index + ! this will be the moab connectivity + moabconn(indx(ix)) = idx + enddo + + nverts = idx + if(par%masterproc) then + write (iulog, *) " MOAB: there are ", nverts, " local vertices on master task ", currentval, " is the max local gdof" + endif + if ( nelemd > 0 ) then + allocate(moab_vert_coords(3*nverts) ) + allocate(vdone(nverts)) + else + allocate(vdone(1)) ! will be passed to iMOAB_ResolveSharedEnts, and compilers are complaining about non-allocated arrays + endif + vdone = 0; + if ( nelemd > 0 ) currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices + + do ix=1,moab_dim_cquads + idx = indx(ix) ! index in initial array, vertices in all fine quads + k = (idx-1)/(4*(np-1)*(np-1)) ! index of coarse quad, locally, starts at 0 + ie = 1 + k ! this is the element number; starts at nets=1 + je = ( idx -1 -k*(np-1)*(np-1)*4 ) / 4 + 1 ! local fine quad in coarse, 1 to (np-1) ^ 2 + irow = (je-1)/(np-1)+1 + icol = je - (np-1)*(irow-1) + linx = idx - k*(np-1)*(np-1)*4 -(je-1)*4 ! this should be 1, 2, 3, 4 + if( linx == 1) then + j = irow + i = icol + else if (linx == 2) then + j = irow + i = icol + 1 + else if (linx == 3) then + j = irow + 1 + i = icol + 1 + else ! linx == 4 + j = irow + 1 + i = icol + endif + + iv = moabvh(ix) + if (vdone(iv) .eq. 0) then + cart = spherical_to_cart (elem(ie)%spherep(i,j) ) + moab_vert_coords ( 3*(iv-1)+1 ) = cart%x + moab_vert_coords ( 3*(iv-1)+2 ) = cart%y + moab_vert_coords ( 3*(iv-1)+3 ) = cart%z + vdone(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities ! convert to int, from long int + endif + + enddo + + dimcoord = nverts*3 + dimen = 3 + if ( nelemd > 0 ) then + ierr = iMOAB_CreateVertices(MHFID, dimcoord, dimen, moab_vert_coords) + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB vertices ') + endif + !!num_el = nelemd2 + mbtype = 3 ! quadrilateral + nve = 4; + block_ID = 200 ! this will be for coarse mesh + + if ( nelemd > 0 ) then + ierr = iMOAB_CreateElements( MHFID, nelemd2, mbtype, nve, moabconn, block_ID ); + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB elements') + endif + ! nverts: num vertices; vdone will store now the markers used in global resolve + ! for this particular problem, markers are the global dofs at corner nodes +! set the global id for vertices +! first, retrieve the tag + tagname='GDOF'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = 1 + ierr = iMOAB_DefineTagStorage(MHFID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve global id tag') + ! now set the values + ent_type = 0 ! vertex type + if ( nverts > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHFID, tagname, nverts , ent_type, vdone) + if (ierr > 0 ) & + call abortmp('Error: fail to set marker id tag for vertices') + endif + + ! we need to call this even when no mesh locally, it involves a collective + ierr = iMOAB_ResolveSharedEntities( MHFID, nverts, vdone ); + if (ierr > 0 ) & + call abortmp('Error: fail to resolve shared entities') + + if ( nelemd > 0) then + vdone = -1 ! reuse vdone for the new tag, GLOBAL_ID (actual tag that we want to store global dof ) + endif +! use element offset for actual global dofs + ! tagtype = 0 ! dense, integer + ! numco = 1 + newtagg='GLOBAL_ID'//C_NULL_CHAR + ierr = iMOAB_DefineTagStorage(MHFID, newtagg, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to create new GDOF tag') + do ie=1,nelemd + do ii=1,elem(ie)%idxp%NumUniquePts + i=elem(ie)%idxp%ia(ii) + j=elem(ie)%idxp%ja(ii) + igcol = elem(ie)%idxp%UniquePtoffset+ii-1 + ix = local_map(i,j) + idx = moabconn((ie-1)*(np-1)*(np-1)*4 + ix) ! should + vdone ( idx ) = igcol + end do + end do + ! now set the values + ent_type = 0 ! vertex type + if ( nverts > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vdone) + if (ierr > 0 ) & + call abortmp('Error: fail to set global dof tag for vertices') + endif + + ierr = iMOAB_ReduceTagsMax ( MHFID, tagindex, ent_type) + if (ierr > 0 ) & + call abortmp('Error: fail to reduce max tag') + + ! set global id tag for elements + ent_type = 1 ! now set the global id tag on elements + if ( nelemd2 > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nelemd2 , ent_type, elemids) + if (ierr > 0 ) & + call abortmp('Error: fail to set global id tag for elements') + endif + +! now, after reduction, we can get the actual global ids for each vertex in the fine mesh +! before, some vertices that were owned in MOAB but not owned in CAM did not have the right global ID tag +! so vdone will be now correct on every task (no -1 anymore ) + ent_type = 0 ! vertex type + if ( nverts > 0 ) then + allocate(vgids(nverts)) + ierr = iMOAB_GetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vgids) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GLOBAL ID on each task') + endif + ierr = iMOAB_UpdateMeshInfo(MHFID) + if (ierr > 0 ) & + call abortmp('Error: fail to update mesh info') +#ifdef MOABDEBUG +! write out the mesh file to disk, in parallel + outfile = 'wholeFineATM.h5m'//C_NULL_CHAR + wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR + ierr = iMOAB_WriteMesh(MHFID, outfile, wopts) + if (ierr > 0 ) & + call abortmp('Error: fail to write the mesh file') +#endif + + +! now create the coarse mesh, but the global dofs will come from fine mesh, after solving + ! nelemd2 = nelemd + moab_dim_cquads = (nelemd)*4 + + if ( nelemd > 0 ) then + allocate(gdofel(nelemd*np*np)) + endif + k=0 ! will be the index for element global dofs + do ie=1,nelemd + ix = ie-1 + ! + gdofv(ix*4+1) = elem(ie)%gdofP(1,1) + gdofv(ix*4+2) = elem(ie)%gdofP(np,1) + gdofv(ix*4+3) = elem(ie)%gdofP(np,np) + gdofv(ix*4+4) = elem(ie)%gdofP(1,np) + elemids(ix+1) = elem(ie)%GlobalId + enddo +! now original order + +! order according to global dofs +! allocate(indx(moab_dim_cquads)) + if ( nelemd > 0 ) then + call IndexSet(moab_dim_cquads, indx) + call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) +! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) + + allocate(moabvh_c(moab_dim_cquads)) + + allocate(moabconn_c(moab_dim_cquads)) + endif + idx = 0 + if ( nelemd > 0 ) then + idx=1 + currentval = gdofv( indx(1)) + endif + do ix=1,moab_dim_cquads + if (gdofv(indx(ix)) .ne. currentval ) then + idx=idx+1 + currentval = gdofv(indx(ix)) + endif + moabvh_c(ix) = idx ! the vertex in connectivity array will be at this local index + ! this will be the moab connectivity + moabconn_c(indx(ix)) = idx + enddo + nverts_c = idx + if(par%masterproc) then + write (iulog, *) " MOAB: there are ", nverts_c, " local vertices on master task, coarse mesh" + endif +! allocate(moab_vert_coords(3*idx) ) + if ( nelemd > 0 ) then + allocate(vdone_c(nverts_c)) + vdone_c = 0; + currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices + endif + + do ix=1,moab_dim_cquads + i = indx(ix) ! index in initial array + ie = 1+ (i-1)/4 ! this is the element number + j = i - ( i-1)/4*4 ! local index of vertex in element i + iv = moabvh_c(ix) + if (vdone_c(iv) .eq. 0) then + moab_vert_coords ( 3*(iv-1)+1 ) = elem(ie)%corners3d(j)%x + moab_vert_coords ( 3*(iv-1)+2 ) = elem(ie)%corners3d(j)%y + moab_vert_coords ( 3*(iv-1)+3 ) = elem(ie)%corners3d(j)%z + vdone_c(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities + endif + + enddo + + dimcoord = nverts_c*3 + dimen = 3 + if ( nverts_c > 0 ) then + ierr = iMOAB_CreateVertices(MHID, dimcoord, dimen, moab_vert_coords) + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB vertices ') + endif + ! num_el = nelemd + mbtype = 3 ! quadrilateral + nve = 4; + block_ID = 100 ! this will be for coarse mesh + + if ( nelemd > 0 ) then + ierr = iMOAB_CreateElements( MHID, nelemd, mbtype, nve, moabconn_c, block_ID ); + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB elements') + endif + ! idx: num vertices; vdone will store now the markers used in global resolve + ! for this particular problem, markers are the global dofs at corner nodes +! set the global id for vertices +! first, retrieve the tag + tagname='GDOFV'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = 1 + ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GDOFV id tag') + ierr = iMOAB_DefineTagStorage(MHID, newtagg, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GLOBAL_ID tag on coarse mesh') + ! now set the values + ent_type = 0 ! vertex type + if ( nverts_c > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, tagname, nverts_c , ent_type, vdone_c) + if (ierr > 0 ) & + call abortmp('Error: fail to set GDOFV tag for vertices') + endif + ! set global id tag for coarse elements, too; they will start at nets=1, end at nete=nelemd + ent_type = 1 ! now set the global id tag on elements + if ( nelemd > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nelemd , ent_type, elemids) + if (ierr > 0 ) & + call abortmp('Error: fail to set global id tag for vertices') + endif + + ierr = iMOAB_ResolveSharedEntities( MHID, idx, vdone_c ); + if (ierr > 0 ) & + call abortmp('Error: fail to resolve shared entities') + +! global dofs are the GLL points are set for each element + tagname='GLOBAL_DOFS'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = np*np ! usually, it is 16; each element will have the dofs in order + ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to create global DOFS tag') + ! now set the values + ! set global dofs tag for coarse elements, too; they will start at nets=1, end at nete=nelemd + ent_type = 1 ! now set the global id tag on elements + numvals = nelemd*np*np ! input is the total number of values + ! form gdofel from vgids + do ie=1, nelemd + ix = (ie-1)*np*np ! ie: index in coarse element + je = (ie-1) * 4 * (np-1) * (np -1) ! index in moabconn array + ! vgids are global ids for fine vertices (1,nverts) + iv = 1 + do j=1,np + do i=1,np + k = local_map(i,j) + gdofel(ix+iv) = vgids( moabconn( je + k ) ) + iv = iv + 1 + enddo + enddo + ! extract global ids + vdone_c( moabconn_c( (ie-1)*4+1) ) = vgids ( moabconn(je+1 )) + vdone_c( moabconn_c( (ie-1)*4+2) ) = vgids ( moabconn(je+ 4*(np-2)+2 )) ! valid for np = 4, 10 + vdone_c( moabconn_c( (ie-1)*4+3) ) = vgids ( moabconn(je+ 4*((np-1)*(np-1)-1) + 3 )) ! for np = 4, 35 + vdone_c( moabconn_c( (ie-1)*4+4) ) = vgids ( moabconn(je+ 4*(np-2)*(np-1) + 4 )) ! 28 for np = 4 + enddo + if ( nelemd > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, tagname, numvals, ent_type, gdofel) + if (ierr > 0 ) & + call abortmp('Error: fail to set globalDOFs tag for coarse elements') + endif + + ! set the global ids for coarse vertices the same as corresponding fine vertices + ent_type = 0 ! vertex type + if ( nverts_c > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nverts_c , ent_type, vdone_c) + if (ierr > 0 ) & + call abortmp('Error: fail to set GLOBAL_DOFS tag values') + endif + + ierr = iMOAB_UpdateMeshInfo(MHID) + if (ierr > 0 ) & + call abortmp('Error: fail to update mesh info') +#ifdef MOABDEBUG +! write out the mesh file to disk, in parallel + outfile = 'wholeATM.h5m'//C_NULL_CHAR + wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR + ierr = iMOAB_WriteMesh(MHID, outfile, wopts) + if (ierr > 0 ) & + call abortmp('Error: fail to write the mesh file') +#endif + ! deallocate + if ( nelemd > 0 ) then + deallocate(moabvh) + deallocate(moabconn) ! do not keep it anymore, we are not setting another tag on fine mesh + deallocate(gdofel) + deallocate(indx) + deallocate(elemids) + deallocate(gdofv) + deallocate(moabvh_c) + deallocate(moabconn_c) + deallocate(vdone_c) + endif + deallocate(vdone) ! we are always allocating this now +! end copy + end subroutine create_spectral_moab_meshes + + subroutine create_moab_pg_mesh(par, elem, fv_nphys) + + use ISO_C_BINDING + use iMOAB, only: iMOAB_CreateVertices, iMOAB_WriteMesh, iMOAB_CreateElements, & + iMOAB_ResolveSharedEntities, iMOAB_UpdateMeshInfo, iMOAB_DefineTagStorage, & + iMOAB_SetIntTagStorage, iMOAB_ReduceTagsMax, iMOAB_GetIntTagStorage + use coordinate_systems_mod, only : cartesian3D_t, spherical_to_cart, spherical_polar_t + + type (element_t), intent(inout) :: elem(:) + type (parallel_t) , intent(in) :: par + integer , intent(in) :: fv_nphys + + integer ierr, i, j, ie, iv, block_ID, k, numvals + integer icol, irow, je, linx ! local indices in fine el connect + + real(kind=real_kind), allocatable :: moab_vert_coords(:) + + integer moab_dim_cquads, ix, idx, nverts, nverts_c ! used for indexing in loops; nverts will have the number of local vertices + + integer nelemd2 ! do not confuse this with dimensions_mod::nelemd + + integer(kind=long_kind), dimension(:), allocatable :: gdofv + ! this will be moab vertex handle locally + integer, dimension(:), allocatable :: moabvh + integer, dimension(:), allocatable :: indx ! this will be ordered + + integer, dimension(:), allocatable :: vdone, elemids, vgids, gdofel + integer, dimension(:), allocatable :: vdone_c, moabconn_c, moabvh_c + integer currentval, dimcoord, dimen, num_el, mbtype, nve + + character*100 outfile, wopts, localmeshfile, lnum, tagname, newtagg + integer tagtype, numco, tag_sto_len, ent_type, tagindex + type (cartesian3D_t) :: cart + integer igcol, ii, neigh + + integer nedges_c, nverts_pg, nelem_pg, edge_index, j1 + integer, dimension(:), allocatable :: local_cell_gids, indx_cell + integer, dimension(:,:), allocatable :: elem_edge, edge + integer, dimension(:), allocatable :: vdone_pg, moabconn_pg + + integer nat_edge_order(4) + integer internal_edges, boundary_edges, reverse_edges + integer edge_verts(4) ! local per coarse element ! nverts_c < edge_verts <= nverts_c + edge_index + integer middle_vertex ! nverts_c + edge_index < middle_vertex <= verts_pg + type (spherical_polar_t) :: current_2d_vertex + logical pos_edge ! when looping over edges , use gdof for marking !! + + nat_edge_order = (/south, east, north, west/) + + ! for np=4, + ! 28, 32, 36, 35 + ! 25, 29, 33, 34 + ! j | 13, 17, 21, 22 + ! 1, 5, 9, 10 + !(1,1) i-> + + ! character*100 outfile, wopts, localmeshfile, lnum, tagname + ! integer tagtype, numco, tag_sto_len, ent_type, tagindex + do j=1,np-1 + do i =1, np-1 + ix = (j-1)*(np-1)+i-1 + local_map(i,j) = ix*4 + 1 + enddo + enddo + do j=1, np-1 + i = j + local_map(np, j) = ((np-1)*j-1)*4 + 2 + local_map(i, np) = ( (np-1)*(np-2)+i-1)*4 + 4 + enddo + local_map(np, np) = ((np-1)*(np-1)-1)*4 + 3 + + nelemd2 = (nelemd)*(np-1)*(np-1) + moab_dim_cquads = (nelemd)*4*(np-1)*(np-1) + + if(par%masterproc) then + write (iulog, *) " MOAB: semoab_mod module: create_moab_mesh_fine; on processor " , par%rank ," nelemd: " , nelemd + endif + + if ( nelemd > 0 ) then + allocate(gdofv(moab_dim_cquads)) + allocate(elemids(nelemd2)) + endif + + k=0 ! will be the index for element global dofs + do ie=1,nelemd + do j=1,np-1 + do i=1,np-1 + ix = (ie-1)*(np-1)*(np-1)+(j-1)*(np-1)+i-1 + gdofv(ix*4+1) = elem(ie)%gdofP(i,j) + gdofv(ix*4+2) = elem(ie)%gdofP(i+1,j) + gdofv(ix*4+3) = elem(ie)%gdofP(i+1,j+1) + gdofv(ix*4+4) = elem(ie)%gdofP(i,j+1) + elemids(ix+1) = (elem(ie)%GlobalId-1)*(np-1)*(np-1)+(j-1)*(np-1)+i + enddo + enddo + enddo + +! order according to global dofs + + if ( nelemd > 0 ) then + allocate(moabvh(moab_dim_cquads)) + allocate(indx(moab_dim_cquads)) + + allocate(moabconn(moab_dim_cquads)) + call IndexSet(moab_dim_cquads, indx) + call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) +! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) + endif + idx=0 + currentval = 0 + if ( nelemd > 0 ) then + currentval = gdofv( indx(1)) + idx = 1 + endif + + do ix=1,moab_dim_cquads + if (gdofv(indx(ix)) .ne. currentval ) then + idx=idx+1 + currentval = gdofv(indx(ix)) + endif + moabvh(ix) = idx ! the vertex in connectivity array will be at this local index + ! this will be the moab connectivity + moabconn(indx(ix)) = idx + enddo + + nverts = idx + if(par%masterproc) then + write (iulog, *) " MOAB: there are ", nverts, " local vertices on master task ", currentval, " is the max local gdof" + endif + if ( nelemd > 0 ) then + allocate(moab_vert_coords(3*nverts) ) + allocate(vdone(nverts)) + else + allocate(vdone(1)) ! will be passed to iMOAB_ResolveSharedEnts, and compilers are complaining about non-allocated arrays + endif + vdone = 0; + if ( nelemd > 0 ) currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices + + do ix=1,moab_dim_cquads + idx = indx(ix) ! index in initial array, vertices in all fine quads + k = (idx-1)/(4*(np-1)*(np-1)) ! index of coarse quad, locally, starts at 0 + ie = 1 + k ! this is the element number; starts at nets=1 + je = ( idx -1 -k*(np-1)*(np-1)*4 ) / 4 + 1 ! local fine quad in coarse, 1 to (np-1) ^ 2 + irow = (je-1)/(np-1)+1 + icol = je - (np-1)*(irow-1) + linx = idx - k*(np-1)*(np-1)*4 -(je-1)*4 ! this should be 1, 2, 3, 4 + if( linx == 1) then + j = irow + i = icol + else if (linx == 2) then + j = irow + i = icol + 1 + else if (linx == 3) then + j = irow + 1 + i = icol + 1 + else ! linx == 4 + j = irow + 1 + i = icol + endif + + iv = moabvh(ix) + if (vdone(iv) .eq. 0) then + cart = spherical_to_cart (elem(ie)%spherep(i,j) ) + moab_vert_coords ( 3*(iv-1)+1 ) = cart%x + moab_vert_coords ( 3*(iv-1)+2 ) = cart%y + moab_vert_coords ( 3*(iv-1)+3 ) = cart%z + vdone(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities ! convert to int, from long int + endif + + enddo + + dimcoord = nverts*3 + dimen = 3 + if ( nelemd > 0 ) then + ierr = iMOAB_CreateVertices(MHFID, dimcoord, dimen, moab_vert_coords) + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB vertices ') + endif + !!num_el = nelemd2 + mbtype = 3 ! quadrilateral + nve = 4; + block_ID = 200 ! this will be for coarse mesh + + if ( nelemd > 0 ) then + ierr = iMOAB_CreateElements( MHFID, nelemd2, mbtype, nve, moabconn, block_ID ); + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB elements') + endif + ! nverts: num vertices; vdone will store now the markers used in global resolve + ! for this particular problem, markers are the global dofs at corner nodes +! set the global id for vertices +! first, retrieve the tag + tagname='GDOF'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = 1 + ierr = iMOAB_DefineTagStorage(MHFID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve global id tag') + ! now set the values + ent_type = 0 ! vertex type + if ( nverts > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHFID, tagname, nverts , ent_type, vdone) + if (ierr > 0 ) & + call abortmp('Error: fail to set marker id tag for vertices') + endif + + ! we need to call this even when no mesh locally, it involves a collective + ierr = iMOAB_ResolveSharedEntities( MHFID, nverts, vdone ); + if (ierr > 0 ) & + call abortmp('Error: fail to resolve shared entities') + + if ( nelemd > 0) then + vdone = -1 ! reuse vdone for the new tag, GLOBAL_ID (actual tag that we want to store global dof ) + endif +! use element offset for actual global dofs + ! tagtype = 0 ! dense, integer + ! numco = 1 + newtagg='GLOBAL_ID'//C_NULL_CHAR + ierr = iMOAB_DefineTagStorage(MHFID, newtagg, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to create new GDOF tag') + do ie=1,nelemd + do ii=1,elem(ie)%idxp%NumUniquePts + i=elem(ie)%idxp%ia(ii) + j=elem(ie)%idxp%ja(ii) + igcol = elem(ie)%idxp%UniquePtoffset+ii-1 + ix = local_map(i,j) + idx = moabconn((ie-1)*(np-1)*(np-1)*4 + ix) ! should + vdone ( idx ) = igcol + end do + end do + ! now set the values + ent_type = 0 ! vertex type + if ( nverts > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vdone) + if (ierr > 0 ) & + call abortmp('Error: fail to set global dof tag for vertices') + endif + + ierr = iMOAB_ReduceTagsMax ( MHFID, tagindex, ent_type) + if (ierr > 0 ) & + call abortmp('Error: fail to reduce max tag') + + ! set global id tag for elements + ent_type = 1 ! now set the global id tag on elements + if ( nelemd2 > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nelemd2 , ent_type, elemids) + if (ierr > 0 ) & + call abortmp('Error: fail to set global id tag for elements') + endif + +! now, after reduction, we can get the actual global ids for each vertex in the fine mesh +! before, some vertices that were owned in MOAB but not owned in CAM did not have the right global ID tag +! so vdone will be now correct on every task (no -1 anymore ) + ent_type = 0 ! vertex type + if ( nverts > 0 ) then + allocate(vgids(nverts)) + ierr = iMOAB_GetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vgids) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GLOBAL ID on each task') + endif + ierr = iMOAB_UpdateMeshInfo(MHFID) + if (ierr > 0 ) & + call abortmp('Error: fail to update mesh info') +#ifdef MOABDEBUG +! write out the mesh file to disk, in parallel + outfile = 'wholeFineATM.h5m'//C_NULL_CHAR + wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR + ierr = iMOAB_WriteMesh(MHFID, outfile, wopts) + if (ierr > 0 ) & + call abortmp('Error: fail to write the mesh file') +#endif + + +! now create the coarse mesh, but the global dofs will come from fine mesh, after solving + ! nelemd2 = nelemd + moab_dim_cquads = (nelemd)*4 + + if ( nelemd > 0 ) then + allocate(gdofel(nelemd*np*np)) + endif + k=0 ! will be the index for element global dofs + do ie=1,nelemd + ix = ie-1 + ! + gdofv(ix*4+1) = elem(ie)%gdofP(1,1) + gdofv(ix*4+2) = elem(ie)%gdofP(np,1) + gdofv(ix*4+3) = elem(ie)%gdofP(np,np) + gdofv(ix*4+4) = elem(ie)%gdofP(1,np) + elemids(ix+1) = elem(ie)%GlobalId + enddo +! now original order + +! order according to global dofs +! allocate(indx(moab_dim_cquads)) + if ( nelemd > 0 ) then + call IndexSet(moab_dim_cquads, indx) + call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) +! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) + + allocate(moabvh_c(moab_dim_cquads)) + + allocate(moabconn_c(moab_dim_cquads)) + endif + idx = 0 + if ( nelemd > 0 ) then + idx=1 + currentval = gdofv( indx(1)) + endif + do ix=1,moab_dim_cquads + if (gdofv(indx(ix)) .ne. currentval ) then + idx=idx+1 + currentval = gdofv(indx(ix)) + endif + moabvh_c(ix) = idx ! the vertex in connectivity array will be at this local index + ! this will be the moab connectivity + moabconn_c(indx(ix)) = idx + enddo + nverts_c = idx + if(par%masterproc) then + write (iulog, *) " MOAB: there are ", nverts_c, " local vertices on master task, coarse mesh" + endif +! allocate(moab_vert_coords(3*idx) ) + if ( nelemd > 0 ) then + allocate(vdone_c(nverts_c)) + vdone_c = 0; + currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices + endif + + do ix=1,moab_dim_cquads + i = indx(ix) ! index in initial array + ie = 1+ (i-1)/4 ! this is the element number + j = i - ( i-1)/4*4 ! local index of vertex in element i + iv = moabvh_c(ix) + if (vdone_c(iv) .eq. 0) then + moab_vert_coords ( 3*(iv-1)+1 ) = elem(ie)%corners3d(j)%x + moab_vert_coords ( 3*(iv-1)+2 ) = elem(ie)%corners3d(j)%y + moab_vert_coords ( 3*(iv-1)+3 ) = elem(ie)%corners3d(j)%z + vdone_c(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities + endif + + enddo + + dimcoord = nverts_c*3 + dimen = 3 + if ( nverts_c > 0 ) then + ierr = iMOAB_CreateVertices(MHID, dimcoord, dimen, moab_vert_coords) + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB vertices ') + endif + ! num_el = nelemd + mbtype = 3 ! quadrilateral + nve = 4; + block_ID = 100 ! this will be for coarse mesh + + if ( nelemd > 0 ) then + ierr = iMOAB_CreateElements( MHID, nelemd, mbtype, nve, moabconn_c, block_ID ); + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB elements') + endif + ! idx: num vertices; vdone will store now the markers used in global resolve + ! for this particular problem, markers are the global dofs at corner nodes +! set the global id for vertices +! first, retrieve the tag + tagname='GDOFV'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = 1 + ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GDOFV id tag') + ierr = iMOAB_DefineTagStorage(MHID, newtagg, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GLOBAL_ID tag on coarse mesh') + ! now set the values + ent_type = 0 ! vertex type + if ( nverts_c > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, tagname, nverts_c , ent_type, vdone_c) + if (ierr > 0 ) & + call abortmp('Error: fail to set GDOFV tag for vertices') + endif + ! set global id tag for coarse elements, too; they will start at nets=1, end at nete=nelemd + ent_type = 1 ! now set the global id tag on elements + if ( nelemd > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nelemd , ent_type, elemids) + if (ierr > 0 ) & + call abortmp('Error: fail to set global id tag for vertices') + endif + + ierr = iMOAB_ResolveSharedEntities( MHID, idx, vdone_c ); + if (ierr > 0 ) & + call abortmp('Error: fail to resolve shared entities') + +! global dofs are the GLL points are set for each element + tagname='GLOBAL_DOFS'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = np*np ! usually, it is 16; each element will have the dofs in order + ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to create global DOFS tag') + ! now set the values + ! set global dofs tag for coarse elements, too; they will start at nets=1, end at nete=nelemd + ent_type = 1 ! now set the global id tag on elements + numvals = nelemd*np*np ! input is the total number of values + ! form gdofel from vgids + do ie=1, nelemd + ix = (ie-1)*np*np ! ie: index in coarse element + je = (ie-1) * 4 * (np-1) * (np -1) ! index in moabconn array + ! vgids are global ids for fine vertices (1,nverts) + iv = 1 + do j=1,np + do i=1,np + k = local_map(i,j) + gdofel(ix+iv) = vgids( moabconn( je + k ) ) + iv = iv + 1 + enddo + enddo + ! extract global ids + vdone_c( moabconn_c( (ie-1)*4+1) ) = vgids ( moabconn(je+1 )) + vdone_c( moabconn_c( (ie-1)*4+2) ) = vgids ( moabconn(je+ 4*(np-2)+2 )) ! valid for np = 4, 10 + vdone_c( moabconn_c( (ie-1)*4+3) ) = vgids ( moabconn(je+ 4*((np-1)*(np-1)-1) + 3 )) ! for np = 4, 35 + vdone_c( moabconn_c( (ie-1)*4+4) ) = vgids ( moabconn(je+ 4*(np-2)*(np-1) + 4 )) ! 28 for np = 4 + enddo + if ( nelemd > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, tagname, numvals, ent_type, gdofel) + if (ierr > 0 ) & + call abortmp('Error: fail to set globalDOFs tag for coarse elements') + endif + + ! set the global ids for coarse vertices the same as corresponding fine vertices + ent_type = 0 ! vertex type + if ( nverts_c > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nverts_c , ent_type, vdone_c) + if (ierr > 0 ) & + call abortmp('Error: fail to set GLOBAL_DOFS tag values') + endif + + ierr = iMOAB_UpdateMeshInfo(MHID) + if (ierr > 0 ) & + call abortmp('Error: fail to update mesh info') +#ifdef MOABDEBUG +! write out the mesh file to disk, in parallel + outfile = 'wholeATM.h5m'//C_NULL_CHAR + wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR + ierr = iMOAB_WriteMesh(MHID, outfile, wopts) + if (ierr > 0 ) & + call abortmp('Error: fail to write the mesh file') +#endif + + if (fv_nphys > 0 ) then + ! create FV mesh, base on PGx + atm_pg_active = .true. ! from now on, we will migrate / send tags for FV / ATM_PG2 mesh + ! first count the number of edges in the coarse mesh; + ! use euler: v-m+f = 2 => m = v + f - 2 + nedges_c = nverts_c + nelemd - 1 ! could be more, if unconnected regions ? + if ( nedges_c < 0 ) nedges_c = 0 ! it cannot be negative + internal_edges = 0 + boundary_edges = 0 + reverse_edges = 0 + nelem_pg = fv_nphys * fv_nphys * nelemd ! each coarse cell is divided in fv_nphys x fv_nphys subcells + ! + ! there are new vertices on each coarse edge (fv_phys - 1) , and (fv_nphys - 1) * (fv_nphys - 1) + ! new vertices on each coarse cell + if ( nelemd > 0 ) then + allocate (local_cell_gids(nelemd)) + allocate (indx_cell(nelemd)) + allocate (edge(2,nedges_c)) ! + endif + do ie=1, nelemd ! + local_cell_gids(ie) = elem(ie)%GlobalID + enddo + if ( nelemd > 0 ) then + call IndexSet(nelemd, indx_cell) + call IndexSort(nelemd, indx_cell, local_cell_gids, descend=.false.) + ! print *, ' local_cell_gids ', local_cell_gids + ! print *, ' indx_cell ', indx_cell + allocate( elem_edge (4, nelemd) ) + ! print *, '------------------------------- ' + ! print *, "RANK:", par%rank + endif + edge_index = 0 + do ie=1, nelemd ! + ! we need to check if neighbor is with id smaller; that means it was already created ? + ! print *, '-------------- ' + ! print *, ' elem ', ie, elem(ie)%desc%actual_neigh_edges, elem(ie)%vertex%number, elem(ie)%GlobalID + ! print *, ' nodes ', ( moabconn_c( (ie-1)*4+j), j=1,4 ) + ! print *, ' ids ', (vdone_c( moabconn_c( (ie-1)*4+j) ), j=1,4) + ! print *, ' neigh: ', (elem(ie)%desc%globalID(j), j=1,4) + ! print *, ' neigh order ', ( elem(ie)%desc%globalID(nat_edge_order(j)),j = 1,4 ) + k = elem(ie)%GlobalID ! current id + do j = 1,4 + ix = j+1 + if (ix .eq. 5) ix = 1 ! next vertex in connectivity array + neigh = elem(ie)%desc%globalID(nat_edge_order(j)) ! id neighbor + idx = search_in(local_cell_gids, nelemd, neigh) ! index in local cells + ! print *, ' ', j, 'neigh:', neigh, ' index' , idx + + if ( idx .gt. 0 ) then + ! a local edge is interior + + if (k < neigh) then ! form the edge, increment edge index + edge_index = edge_index + 1 + edge(1, edge_index) = moabconn_c(4*(ie-1) + j) ! first vertex + edge(2, edge_index) = moabconn_c(4*(ie-1) + ix) ! second vertex index + elem_edge(j, ie) = edge_index + internal_edges = internal_edges + 1 + ! print *, ' edge:', edge_index, edge(1, edge_index), edge(2, edge_index), 'verts:' , & + ! vdone_c(edge(1, edge_index)), vdone_c(edge(2, edge_index)), ' element ', ie, ' intedge:', internal_edges + + else + ! find the edge in the other list elem(idx)%globalID( nat_edge_order(j) ) + do j1 = 1,4 + if ( elem(idx)%desc%globalID( nat_edge_order(j1) ) .eq. k ) then + elem_edge(j, ie) = - elem_edge(j1, idx) ! inverse oriented + reverse_edges = reverse_edges + 1 + ! print *, ' negative edge: ', elem_edge(j, ie), edge(1, -elem_edge(j, ie)), edge(2, -elem_edge(j, ie)), & + ! 'verts:', vdone_c(edge(1, -elem_edge(j, ie))), vdone_c(edge(2, -elem_edge(j, ie))), 'indx neg', reverse_edges + endif + enddo + + endif + else ! idx is 0, so it means the edge is on the boundary, form it + edge_index = edge_index + 1 + edge(1, edge_index) = moabconn_c(4*(ie-1) + j) ! first vertex + edge(2, edge_index) = moabconn_c(4*(ie-1) + ix) ! second vertex index + elem_edge(j, ie) = edge_index + boundary_edges = boundary_edges + 1 + ! print *, ' edge:', edge_index, edge(1, edge_index), edge(2, edge_index), 'verts:' , & + ! vdone_c(edge(1, edge_index)), vdone_c(edge(2, edge_index)), ' element ', ie, & + ! ' bedge:', boundary_edges + endif + enddo + enddo + ! show off + nverts_pg = nverts_c + (fv_nphys - 1) * edge_index + (fv_nphys - 1) * (fv_nphys - 1) * nelemd + ! print *, " MOAB: there are ", nverts_pg, " local vertices on master task on pg mesh ", edge_index , " local coarse edges ", & + ! boundary_edges , ' boundary edges ' + if(par%masterproc) then + write (iulog, *) " MOAB: there are ", nverts_pg, " local vertices on master task on pg mesh ", edge_index , " local coarse edges " + endif + !print *, '\n ELEMENTS: ' + !do ie=1,nelemd + ! print *, ie, elem(ie)%GlobalID, ' local nodes:', ( moabconn_c( (ie-1)*4+j), j=1,4 ), ' edges:', (elem_edge(j, ie), j=1,4) + !enddo + !print *, '\n EDGES:' + !do ie=1,edge_index + ! print *, ie, (edge(j, ie), j=1,2) + !enddo + ! now generate phys grid, uniform FV type mesh; + ! 2 cases: fv_nphys is 1 or 2; when 2, we need new nodes; will use the same id as + ! the gdof on edge is used, with the smaller id chosen, among + if ( nelemd > 0 ) then + allocate(moabconn_pg(4*nelem_pg)) ! connectivity + ! reuse moab_vert_coords for coordinates of pg mesh + ! the first nverts_c coords are the same as coarse mesh; but we do create new + allocate(vdone_pg(nverts_pg)) + else + allocate(vdone_pg(1)) + endif + do iv = 1, nverts_c + vdone_pg(iv) = vdone_c(iv) ! also the coordinates will be the same !! + enddo + + ! copy the coordinates from the middle + j1 = 0 ! index in edge vertices; increase only for positive edges + ! still need some + if (fv_nphys .eq. 2) then + current_2d_vertex%r = 1. + do ie = 1,nelemd + ix = (ie-1)*np*np ! ie: index in coarse element + do j=1,4 + idx = elem_edge(j, ie) ! + if (idx .gt. 0) then ! increment edges, add vertex ! + j1 = j1 + 1 ! index in moab_vert_coords for edges ! nverts_c + j1 for vertex edges ! + ! current_2d_vertex%lat, current_2d_vertex%lon + pos_edge = .true. + iv = nverts_c + j1 + edge_verts(j) = iv ! to form the local connectivity array + if ( vdone_c(edge(1, idx)) .gt. vdone_c(edge(2, idx)) ) pos_edge = .false. + if (j .eq. 1) then + call gfr_f_get_corner_latlon(ie, 1, 1, 2, current_2d_vertex%lat, current_2d_vertex%lon) + if (pos_edge) then + vdone_pg (iv) = gdofel(ix + 2) ! elem(ie)%gdofP(2,1) ! gdofel(ix+ (j-1)*np + i) + else + vdone_pg (iv) = gdofel(ix + np - 1) !elem(ie)%gdofP(np-1,1) ! + endif + else if (j .eq. 2) then + call gfr_f_get_corner_latlon(ie, 2, 1, 3, current_2d_vertex%lat, current_2d_vertex%lon) + if (pos_edge) then + vdone_pg (iv) = gdofel(ix + (2 - 1) * np + np)!elem(ie)%gdofP(np,2) ! ! gdofel(ix+ (j-1)*np + i) + else + vdone_pg (iv) = gdofel(ix + (np - 2) * np + np)!elem(ie)%gdofP(np,np - 1) ! + endif + else if (j .eq. 3) then + call gfr_f_get_corner_latlon(ie, 2, 2, 4, current_2d_vertex%lat, current_2d_vertex%lon) + if (pos_edge) then + vdone_pg (iv) = gdofel(ix+ (np - 1) * np + np - 1)!elem(ie)%gdofP(np-1,np) ! + else + vdone_pg (iv) = gdofel(ix+ (np-1)*np + 2) !elem(ie)%gdofP(2,np) ! + endif + else ! if (j .eq. 4) + call gfr_f_get_corner_latlon(ie, 1, 2, 1, current_2d_vertex%lat, current_2d_vertex%lon) + if (pos_edge) then + vdone_pg (iv) = gdofel(ix+ (np - 2)*np + 1) !elem(ie)%gdofP(1,np-1) ! + else + vdone_pg (iv) = gdofel(ix+ ( 2 - 1 )*np + 1) ! elem(ie)%gdofP(1,2) ! + endif + endif + ! create the 3d vertex ! + cart = spherical_to_cart (current_2d_vertex ) + moab_vert_coords ( 3*(iv-1)+1 ) = cart%x + moab_vert_coords ( 3*(iv-1)+2 ) = cart%y + moab_vert_coords ( 3*(iv-1)+3 ) = cart%z + ! print *, 'ie, j, iv, vdone_pg(iv): ', ie, j, iv, vdone_pg(iv) + else ! the vertex was already created, but we need the index for connectivity of local fv cells + edge_verts(j) = nverts_c + ( -idx ) ! idx is index of edge (negative for already created) + endif + + enddo ! do j=1,4 + ! create the middle vertex too, in the center + call gfr_f_get_corner_latlon(ie, 1, 1, 3, current_2d_vertex%lat, current_2d_vertex%lon) + iv = nverts_c + edge_index + ie ! middle vertices are after corners, and edge vertices + middle_vertex = iv + vdone_pg (middle_vertex) = gdofel(ix+ np + 2)!elem(ie)%gdofP(2,2) ! first in the interior, not on edges! + ! print *, 'ie, middle = iv, vdone_pg(iv): ', ie, iv, vdone_pg(iv) + cart = spherical_to_cart (current_2d_vertex ) + moab_vert_coords ( 3*(iv-1)+1 ) = cart%x + moab_vert_coords ( 3*(iv-1)+2 ) = cart%y + moab_vert_coords ( 3*(iv-1)+3 ) = cart%z + + ! now form the local 2x2 cells, one by one; set the global id tag too! + idx = (ie-1)*4 + ix = idx * 4 ! + ! first + moabconn_pg(ix + 1) = moabconn_c(4*(ie-1)+1) + moabconn_pg(ix + 2) = edge_verts(1) + moabconn_pg(ix + 3) = middle_vertex + moabconn_pg(ix + 4) = edge_verts(4) + elemids(idx+1) = (elem(ie)%GlobalId-1)*4+1 + ! second + moabconn_pg(ix + 4 + 1) = edge_verts(1) + moabconn_pg(ix + 4 + 2) = moabconn_c(4*(ie-1)+2) + moabconn_pg(ix + 4 + 3) = edge_verts(2) + moabconn_pg(ix + 4 + 4) = middle_vertex + elemids(idx+2) = (elem(ie)%GlobalId-1)*4+2 + ! third + moabconn_pg(ix + 8 + 1) = edge_verts(4) + moabconn_pg(ix + 8 + 2) = middle_vertex + moabconn_pg(ix + 8 + 3) = edge_verts(3) + moabconn_pg(ix + 8 + 4) = moabconn_c(4*(ie-1)+4) + elemids(idx+3) = (elem(ie)%GlobalId-1)*4+3 + ! fourth + moabconn_pg(ix + 12 + 1) = middle_vertex + moabconn_pg(ix + 12 + 2) = edge_verts(2) + moabconn_pg(ix + 12 + 3) = moabconn_c(4*(ie-1)+3) + moabconn_pg(ix + 12 + 4) = edge_verts(3) + elemids(idx+4) = (elem(ie)%GlobalId-1)*4+4 + + enddo + ! now copy from coarse for pg mesh + + dimcoord = nverts_pg*3 + dimen = 3 + if ( nverts_pg > 0 ) then + ierr = iMOAB_CreateVertices(MHPGID, dimcoord, dimen, moab_vert_coords) + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB vertices ') + endif + ! num_el = nelem_pg * + mbtype = 3 ! quadrilateral + nve = 4; + block_ID = 300 ! this will be for pg mesh + + if ( nelem_pg > 0 ) then + ierr = iMOAB_CreateElements( MHPGID, nelem_pg, mbtype, nve, moabconn_pg, block_ID ); + if (ierr > 0 ) & + call abortmp('Error: fail to create MOAB elements') + endif + tagname='GLOBAL_ID'//C_NULL_CHAR + tagtype = 0 ! dense, integer + numco = 1 + ierr = iMOAB_DefineTagStorage(MHPGID, tagname, tagtype, numco, tagindex ) + if (ierr > 0 ) & + call abortmp('Error: fail to retrieve GLOBAL id tag') + + ! now set the values + ent_type = 0 ! vertex type + if ( nverts_pg > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHPGID, tagname, nverts_pg , ent_type, vdone_pg) + if (ierr > 0 ) & + call abortmp('Error: fail to set global id tag for vertices') + endif + ! set global id tag for pg2 elements, too; they will start at nets=1, end at nete=nelemd*4 + ent_type = 1 ! now set the global id tag on elements + if ( nelem_pg > 0 ) then + ierr = iMOAB_SetIntTagStorage ( MHPGID, tagname, nelem_pg , ent_type, elemids) + if (ierr > 0 ) & + call abortmp('Error: fail to set global id tag for edges') + endif + + ! this involves a collective, vdone_pg can be empty + ierr = iMOAB_ResolveSharedEntities( MHPGID, nverts_pg, vdone_pg ); + if (ierr > 0 ) & + call abortmp('Error: fail to resolve shared ents for pg2 mesh') + + ierr = iMOAB_UpdateMeshInfo(MHPGID) + if (ierr > 0 ) & + call abortmp('Error: fail to update mesh info for pg2 mesh') +#ifdef MOABDEBUG + ! write out the mesh file to disk, in parallel + outfile = 'wholeATM_PG2.h5m'//C_NULL_CHAR + wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR + ierr = iMOAB_WriteMesh(MHPGID, outfile, wopts) + if (ierr > 0 ) & + call abortmp('Error: fail to write the mesh file') +#endif + endif ! only valid for pg == 2 + if ( nelemd > 0 ) then + deallocate (local_cell_gids) + deallocate (indx_cell) + deallocate (edge) ! + deallocate(moabconn_pg) ! connectivity + endif + deallocate(vdone_pg) ! this is now always allocated/deallocated, even for no mesh here + endif + + ! deallocate + if ( nelemd > 0 ) then + deallocate(moabvh) + deallocate(moabconn) ! do not keep it anymore, we are not setting another tag on fine mesh + deallocate(gdofel) + deallocate(indx) + deallocate(elemids) + deallocate(gdofv) + deallocate(moabvh_c) + deallocate(moabconn_c) + deallocate(vdone_c) + endif + deallocate(vdone) ! we are always allocating this now +! end copy + + end subroutine create_moab_pg_mesh + subroutine create_moab_meshes(par, elem, fv_nphys) use ISO_C_BINDING From da7a6cb55bd00c35945b6a1d022f2cfe4a05860a Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Thu, 18 Sep 2025 12:40:54 -0500 Subject: [PATCH 078/398] add more extension fields for _ext tags, we need more methods to retrieve data Or maybe we will go back to dual mesh, and then dual mesh will be like any other FV mesh on coupler side the _ext tags use about twice as much memory while the dual mesh would be more optimal --- driver-moab/main/cplcomp_exchange_mod.F90 | 37 +++++++---- driver-moab/shr/seq_flds_mod.F90 | 76 +++++++++++------------ 2 files changed, 61 insertions(+), 52 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 6d5c4bdc638c..1fa5273a3ce3 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -9,8 +9,8 @@ module cplcomp_exchange_mod use seq_map_type_mod use component_type_mod use seq_flds_mod, only: seq_flds_dom_coord, seq_flds_dom_other - use seq_flds_mod, only: seq_flds_dom_fields - use seq_flds_mod, only: seq_flds_a2x_ext_fields, seq_flds_a2x_fields, seq_flds_x2a_fields ! + use seq_flds_mod, only: seq_flds_dom_fields, seq_flds_dom_ext_fields + use seq_flds_mod, only: seq_flds_a2x_ext_fields, seq_flds_a2x_fields, seq_flds_x2a_ext_fields, seq_flds_x2a_fields ! use seq_flds_mod, only: seq_flds_o2x_fields ! needed for MOAB init of ocean fields o2x to be able to transfer to coupler use seq_flds_mod, only: seq_flds_x2o_fields ! needed for MOAB init of ocean fields x2o to be able to transfer from coupler use seq_flds_mod, only: seq_flds_i2x_fields, seq_flds_x2i_fields ! needed for MOAB init of ice fields x2o on coupler side, to save them @@ -1231,8 +1231,14 @@ subroutine cplcomp_moab_Init(infodata,comp) write(logunit,*) subname,' error in defining tags on atm on coupler ' call shr_sys_abort(subname//' ERROR in defining tags ') endif + if (atm_pg_active) then + tagname = trim(seq_flds_x2a_fields)//C_NULL_CHAR + numco = 1 ! usually 1 value per cell + else ! this is not supported now, but leave it here + tagname = trim(seq_flds_x2a_ext_fields)//C_NULL_CHAR ! MOAB versions of a2x for spectral + numco = 16 ! np*np ! usually 16 values per cell, GLL points; should be 4 x 4 = 16 + endif - tagname = trim(seq_flds_x2a_fields)//C_NULL_CHAR ! TODO should be also x2a_ext for spectral case ierr = iMOAB_DefineTagStorage(mbaxid, tagname, tagtype, numco, tagindex ) if (ierr .ne. 0) then write(logunit,*) subname,' error in defining tags seq_flds_x2a_fields on atm on coupler ' @@ -1240,19 +1246,28 @@ subroutine cplcomp_moab_Init(infodata,comp) endif !add the normalization tag - tagname = trim(seq_flds_dom_fields)//":norm8wt"//C_NULL_CHAR + if (atm_pg_active) then + tagname = trim(seq_flds_dom_fields)//C_NULL_CHAR + numco = 1 ! usually 1 value per cell + else ! this is not supported now, but leave it here + tagname = trim(seq_flds_dom_ext_fields)//C_NULL_CHAR ! MOAB versions of a2x for spectral + numco = 16 ! np*np ! usually 16 values per cell, GLL points; should be 4 x 4 = 16 + endif + ierr = iMOAB_DefineTagStorage(mbaxid, tagname, tagtype, numco, tagindex ) if (ierr .ne. 0) then write(logunit,*) subname,' error in defining tags seq_flds_dom_fields on atm on coupler ' call shr_sys_abort(subname//' ERROR in defining tags ') endif - ! also, frac, area, masks has to come from atm mphaid, not from domain file reader - ! this is hard to digest :( - tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR - ! TODO: this should be called on the joint procs, not coupler only. - call component_exch_moab(comp, mphaid, mbaxid, 0, tagname, context_exch='doma') - ! copy aream from area in case atm_mesh - call copy_aream_from_area(mbaxid) + if (atm_pg_active) then + ! also, frac, area, masks has to come from atm mphaid, not from domain file reader + ! this is hard to digest :( + tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR + ! TODO: this should be called on the joint procs, not coupler only. + call component_exch_moab(comp, mphaid, mbaxid, 0, tagname, context_exch='doma') + ! copy aream from area in case atm_mesh + call copy_aream_from_area(mbaxid) + endif endif ! coupler pes #ifdef MOABDEBUG diff --git a/driver-moab/shr/seq_flds_mod.F90 b/driver-moab/shr/seq_flds_mod.F90 index f8abf9e4c396..efb75f41d3d7 100644 --- a/driver-moab/shr/seq_flds_mod.F90 +++ b/driver-moab/shr/seq_flds_mod.F90 @@ -190,8 +190,6 @@ module seq_flds_mod character(CXX) :: seq_flds_a2x_states character(CXX) :: seq_flds_a2x_fluxes - character(CXX) :: seq_flds_a2x_ext_states - character(CXX) :: seq_flds_a2x_ext_fluxes character(CXX) :: seq_flds_a2x_states_to_rof character(CXX) :: seq_flds_a2x_fluxes_to_rof character(CXX) :: seq_flds_x2a_states @@ -259,10 +257,13 @@ module seq_flds_mod !---------------------------------------------------------------------------- character(CXX) :: seq_flds_dom_fields + character(CXX) :: seq_flds_dom_ext_fields character(CXX) :: seq_flds_a2x_fields character(CXX) :: seq_flds_a2x_ext_fields character(CXX) :: seq_flds_a2x_fields_to_rof + character(CXX) :: seq_flds_a2x_ext_fields_to_rof character(CXX) :: seq_flds_x2a_fields + character(CXX) :: seq_flds_x2a_ext_fields character(CXX) :: seq_flds_i2x_fields character(CXX) :: seq_flds_x2i_fields character(CXX) :: seq_flds_l2x_fields @@ -390,7 +391,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) !------ namelist ----- character(len=CSS) :: fldname, fldflow - character(len=CSS) :: fldname_ext ! use for moab extensions + type(mct_string) :: mctOStr ! mct string for output outfield logical :: is_state, is_flux integer :: i,n @@ -423,9 +424,6 @@ subroutine seq_flds_set(nmlfile, ID, infodata) character(len=*),parameter :: subname = '(seq_flds_set) ' - type(mct_list) :: temp_list - integer :: size_list, index_list - !------------------------------------------------------------------------------- call seq_comm_setptrs(ID,mpicom=mpicom) @@ -4099,45 +4097,14 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call catFields(seq_flds_x2w_fields, seq_flds_x2w_states, seq_flds_x2w_fluxes) call catFields(seq_flds_o2x_fields_to_rof, seq_flds_o2x_states_to_rof, seq_flds_o2x_fluxes_to_rof) ! form character(CXX) :: seq_flds_a2x_ext_states from seq_flds_a2x_states by adding _ext in each field - ! first form a list - call mct_list_init(temp_list ,seq_flds_a2x_fields) - size_list=mct_list_nitem (temp_list) - seq_flds_a2x_ext_fields='' - do index_list = 1, size_list - call mct_list_get(mctOStr,index_list,temp_list) - fldname = mct_string_toChar(mctOStr) - fldname_ext = trim(fldname)//'_ext' - call seq_flds_add(seq_flds_a2x_ext_fields,trim(fldname_ext)) - enddo - seq_flds_a2x_ext_fluxes='' - call mct_list_clean(temp_list) - ! seq_flds_a2x_fluxes - call mct_list_init(temp_list ,seq_flds_a2x_fluxes) - size_list=mct_list_nitem (temp_list) - do index_list = 1, size_list - call mct_list_get(mctOStr,index_list,temp_list) - fldname = mct_string_toChar(mctOStr) - fldname_ext = trim(fldname)//'_ext' - call seq_flds_add(seq_flds_a2x_ext_fluxes,trim(fldname_ext)) - enddo - call mct_list_clean(temp_list) - call mct_list_init(temp_list ,seq_flds_a2x_states) - size_list=mct_list_nitem (temp_list) - seq_flds_a2x_ext_states='' - do index_list = 1, size_list - call mct_list_get(mctOStr,index_list,temp_list) - fldname = mct_string_toChar(mctOStr) - fldname_ext = trim(fldname)//'_ext' - call seq_flds_add(seq_flds_a2x_ext_states,trim(fldname_ext)) - enddo - call mct_list_clean(temp_list) + call create_moab_ext_fields(seq_flds_a2x_fields,seq_flds_a2x_ext_fields) + call create_moab_ext_fields(seq_flds_x2a_fields,seq_flds_x2a_ext_fields) + call create_moab_ext_fields(seq_flds_dom_fields,seq_flds_dom_ext_fields) + call create_moab_ext_fields(seq_flds_a2x_ext_fields_to_rof, seq_flds_a2x_fields_to_rof) - if (seq_comm_iamroot(ID)) then write(logunit,*) subname//': seq_flds_dom_fields= ',trim(seq_flds_dom_fields) - write(logunit,*) subname//': seq_flds_a2x_ext_states= ',trim(seq_flds_a2x_ext_states) - write(logunit,*) subname//': seq_flds_a2x_ext_fluxes= ',trim(seq_flds_a2x_ext_fluxes) write(logunit,*) subname//': seq_flds_a2x_ext_fields= ',trim(seq_flds_a2x_ext_fields) write(logunit,*) subname//': seq_flds_xao_fields= ',trim(seq_flds_xao_fields) endif @@ -4557,4 +4524,31 @@ subroutine moab_set_tag_from_av(tagname, avx, index, mbapid, dataarr, lsize) end subroutine moab_set_tag_from_av + subroutine create_moab_ext_fields(initial_fields, extented_fields) +! !USES: + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + character(CXX), intent(in) :: initial_fields + character(CXX), intent(out) :: extented_fields + + type(mct_list) :: temp_list + character(len=CSS) :: fldname + character(len=CSS) :: fldname_ext ! use for moab extensions + type(mct_string) :: mctOStr ! mct string for output outfield + integer :: size_list, index_list + + ! first form a list + call mct_list_init(temp_list ,initial_fields) + size_list=mct_list_nitem (temp_list) + extented_fields='' + do index_list = 1, size_list + call mct_list_get(mctOStr,index_list,temp_list) + fldname = mct_string_toChar(mctOStr) + fldname_ext = trim(fldname)//'_ext' + call seq_flds_add(extented_fields,trim(fldname_ext)) + enddo + call mct_list_clean(temp_list) + + end subroutine create_moab_ext_fields end module seq_flds_mod From 2517435b4a1c720e13f8b6e9ef810c3c70696bbf Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Thu, 18 Sep 2025 18:48:22 -0500 Subject: [PATCH 079/398] get rid of _ext tags they are a relic from the past we were supporting atm spectral to ocean projection, using tempestremap moved to pg2 mesh, so spectral will be used only in monogrid scenarions there should be no mapping in spectral cases (ne4np4, for exanple) All grids are related to atm np4 gll points; either dual mesh, or culled dual mesh on coupler side (land) atm will be on coupler side just point cloud (migrated from comp side, directly) --- driver-moab/main/cplcomp_exchange_mod.F90 | 65 ++++++++++------------- driver-moab/shr/seq_flds_mod.F90 | 40 +------------- 2 files changed, 30 insertions(+), 75 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 1fa5273a3ce3..6796cd6d899b 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -9,8 +9,8 @@ module cplcomp_exchange_mod use seq_map_type_mod use component_type_mod use seq_flds_mod, only: seq_flds_dom_coord, seq_flds_dom_other - use seq_flds_mod, only: seq_flds_dom_fields, seq_flds_dom_ext_fields - use seq_flds_mod, only: seq_flds_a2x_ext_fields, seq_flds_a2x_fields, seq_flds_x2a_ext_fields, seq_flds_x2a_fields ! + use seq_flds_mod, only: seq_flds_dom_fields + use seq_flds_mod, only: seq_flds_a2x_fields, seq_flds_x2a_fields ! use seq_flds_mod, only: seq_flds_o2x_fields ! needed for MOAB init of ocean fields o2x to be able to transfer to coupler use seq_flds_mod, only: seq_flds_x2o_fields ! needed for MOAB init of ocean fields x2o to be able to transfer from coupler use seq_flds_mod, only: seq_flds_i2x_fields, seq_flds_x2i_fields ! needed for MOAB init of ice fields x2o on coupler side, to save them @@ -1126,7 +1126,7 @@ subroutine cplcomp_moab_Init(infodata,comp) ierr = iMOAB_SendMesh(mhpgid, mpicom_join, mpigrp_cplid, id_join, partMethod) else ! still use the mhid, original coarse mesh - ierr = iMOAB_SendMesh(mhid, mpicom_join, mpigrp_cplid, id_join, partMethod) + ierr = iMOAB_SendMesh(mphaid, mpicom_join, mpigrp_cplid, id_join, partMethod) endif if (ierr .ne. 0) then write(logunit,*) subname,' error in sending mesh from atm comp ' @@ -1145,6 +1145,9 @@ subroutine cplcomp_moab_Init(infodata,comp) endif !!!! FULL ATM if ( trim(atm_mesh) == 'none' ) then ! full atm + ! will receive either pg2 mesh, or point cloud mesh corresponding to GLL points + ! (mphaid app) for spectral case + ! this cannot be used for maps (either computed online or read) ierr = iMOAB_ReceiveMesh(mbaxid, mpicom_join, mpigrp_old, id_old) if (ierr .ne. 0) then write(logunit,*) subname,' error in receiving mesh on atm coupler ' @@ -1181,14 +1184,15 @@ subroutine cplcomp_moab_Init(infodata,comp) ! iMOAB_FreeSenderBuffers needs to be called after receiving the mesh !!!!!!!! ATM COMPONENT - if (mhid .ge. 0) then ! we are on component atm pes + if (mphaid .ge. 0) then ! we are on component atm pes !!!!! FULL ATM if ( trim(atm_mesh) == 'none' ) then ! full atmosphere context_id = id_join if (atm_pg_active) then! we send mesh from mhpgid app ierr = iMOAB_FreeSenderBuffers(mhpgid, context_id) else - ierr = iMOAB_FreeSenderBuffers(mhid, context_id) + ! we send mesh from point cloud data + ierr = iMOAB_FreeSenderBuffers(mphaid, context_id) endif if (ierr .ne. 0) then write(logunit,*) subname,' error in freeing send buffers ' @@ -1201,7 +1205,7 @@ subroutine cplcomp_moab_Init(infodata,comp) ! graph between atm phys, mphaid, and atm dyn on coupler, mbaxid ! phys atm group is mpigrp_old, coupler group is mpigrp_cplid typeA = 2 ! point cloud for mphaid - typeB = 1 ! spectral elements + typeB = 2 ! in spectral case, we will have just point cloud on coupler PEs if (atm_pg_active) then typeB = 3 ! in this case, we will have cells associated with DOFs as GLOBAL_ID tag endif @@ -1209,6 +1213,8 @@ subroutine cplcomp_moab_Init(infodata,comp) ! components/cam/src/cpl/atm_comp_mct.F90 ! components/data_comps/datm/src/atm_comp_mct.F90 ! line 177 !! + ! this is not needed for migrating point cloud to point cloud ! + ! it is needed only after migrating pg2 mesh to cpupler ierr = iMOAB_ComputeCommGraph( mphaid, mbaxid, mpicom_join, mpigrp_old, mpigrp_cplid, & typeA, typeB, ATM_PHYS_CID, id_join) ! ID_JOIN is now 6 @@ -1218,26 +1224,17 @@ subroutine cplcomp_moab_Init(infodata,comp) if (mbaxid .ge. 0 ) then ! coupler pes tagtype = 1 ! dense, double - if (atm_pg_active) then - tagname = trim(seq_flds_a2x_fields)//C_NULL_CHAR - numco = 1 ! usually 1 value per cell - else ! this is not supported now, but leave it here - tagname = trim(seq_flds_a2x_ext_fields)//C_NULL_CHAR ! MOAB versions of a2x for spectral - numco = 16 ! np*np ! usually 16 values per cell, GLL points; should be 4 x 4 = 16 - endif + tagname = trim(seq_flds_a2x_fields)//C_NULL_CHAR + numco = 1 ! usually 1 value per cell ierr = iMOAB_DefineTagStorage(mbaxid, tagname, tagtype, numco, tagindex ) if (ierr .ne. 0) then write(logunit,*) subname,' error in defining tags on atm on coupler ' call shr_sys_abort(subname//' ERROR in defining tags ') endif - if (atm_pg_active) then - tagname = trim(seq_flds_x2a_fields)//C_NULL_CHAR - numco = 1 ! usually 1 value per cell - else ! this is not supported now, but leave it here - tagname = trim(seq_flds_x2a_ext_fields)//C_NULL_CHAR ! MOAB versions of a2x for spectral - numco = 16 ! np*np ! usually 16 values per cell, GLL points; should be 4 x 4 = 16 - endif + + tagname = trim(seq_flds_x2a_fields)//C_NULL_CHAR + numco = 1 ! usually 1 value per cell ierr = iMOAB_DefineTagStorage(mbaxid, tagname, tagtype, numco, tagindex ) if (ierr .ne. 0) then @@ -1246,28 +1243,24 @@ subroutine cplcomp_moab_Init(infodata,comp) endif !add the normalization tag - if (atm_pg_active) then - tagname = trim(seq_flds_dom_fields)//C_NULL_CHAR - numco = 1 ! usually 1 value per cell - else ! this is not supported now, but leave it here - tagname = trim(seq_flds_dom_ext_fields)//C_NULL_CHAR ! MOAB versions of a2x for spectral - numco = 16 ! np*np ! usually 16 values per cell, GLL points; should be 4 x 4 = 16 - endif + + tagname = trim(seq_flds_dom_fields)//C_NULL_CHAR + numco = 1 ! usually 1 value per cell ierr = iMOAB_DefineTagStorage(mbaxid, tagname, tagtype, numco, tagindex ) if (ierr .ne. 0) then write(logunit,*) subname,' error in defining tags seq_flds_dom_fields on atm on coupler ' call shr_sys_abort(subname//' ERROR in defining tags ') endif - if (atm_pg_active) then - ! also, frac, area, masks has to come from atm mphaid, not from domain file reader - ! this is hard to digest :( - tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR - ! TODO: this should be called on the joint procs, not coupler only. - call component_exch_moab(comp, mphaid, mbaxid, 0, tagname, context_exch='doma') - ! copy aream from area in case atm_mesh - call copy_aream_from_area(mbaxid) - endif + + ! also, frac, area, masks has to come from atm mphaid, not from domain file reader + ! this is hard to digest :( + tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR + ! TODO: this should be called on the joint procs, not coupler only. + call component_exch_moab(comp, mphaid, mbaxid, 0, tagname, context_exch='doma') + ! copy aream from area in case atm_mesh + call copy_aream_from_area(mbaxid) + endif ! coupler pes #ifdef MOABDEBUG diff --git a/driver-moab/shr/seq_flds_mod.F90 b/driver-moab/shr/seq_flds_mod.F90 index efb75f41d3d7..9aa3be8d5b1a 100644 --- a/driver-moab/shr/seq_flds_mod.F90 +++ b/driver-moab/shr/seq_flds_mod.F90 @@ -257,13 +257,9 @@ module seq_flds_mod !---------------------------------------------------------------------------- character(CXX) :: seq_flds_dom_fields - character(CXX) :: seq_flds_dom_ext_fields character(CXX) :: seq_flds_a2x_fields - character(CXX) :: seq_flds_a2x_ext_fields character(CXX) :: seq_flds_a2x_fields_to_rof - character(CXX) :: seq_flds_a2x_ext_fields_to_rof character(CXX) :: seq_flds_x2a_fields - character(CXX) :: seq_flds_x2a_ext_fields character(CXX) :: seq_flds_i2x_fields character(CXX) :: seq_flds_x2i_fields character(CXX) :: seq_flds_l2x_fields @@ -4096,16 +4092,9 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call catFields(seq_flds_w2x_fields, seq_flds_w2x_states, seq_flds_w2x_fluxes) call catFields(seq_flds_x2w_fields, seq_flds_x2w_states, seq_flds_x2w_fluxes) call catFields(seq_flds_o2x_fields_to_rof, seq_flds_o2x_states_to_rof, seq_flds_o2x_fluxes_to_rof) - ! form character(CXX) :: seq_flds_a2x_ext_states from seq_flds_a2x_states by adding _ext in each field - - call create_moab_ext_fields(seq_flds_a2x_fields,seq_flds_a2x_ext_fields) - call create_moab_ext_fields(seq_flds_x2a_fields,seq_flds_x2a_ext_fields) - call create_moab_ext_fields(seq_flds_dom_fields,seq_flds_dom_ext_fields) - call create_moab_ext_fields(seq_flds_a2x_ext_fields_to_rof, seq_flds_a2x_fields_to_rof) - + if (seq_comm_iamroot(ID)) then write(logunit,*) subname//': seq_flds_dom_fields= ',trim(seq_flds_dom_fields) - write(logunit,*) subname//': seq_flds_a2x_ext_fields= ',trim(seq_flds_a2x_ext_fields) write(logunit,*) subname//': seq_flds_xao_fields= ',trim(seq_flds_xao_fields) endif @@ -4524,31 +4513,4 @@ subroutine moab_set_tag_from_av(tagname, avx, index, mbapid, dataarr, lsize) end subroutine moab_set_tag_from_av - subroutine create_moab_ext_fields(initial_fields, extented_fields) -! !USES: - implicit none - - ! !INPUT/OUTPUT PARAMETERS: - character(CXX), intent(in) :: initial_fields - character(CXX), intent(out) :: extented_fields - - type(mct_list) :: temp_list - character(len=CSS) :: fldname - character(len=CSS) :: fldname_ext ! use for moab extensions - type(mct_string) :: mctOStr ! mct string for output outfield - integer :: size_list, index_list - - ! first form a list - call mct_list_init(temp_list ,initial_fields) - size_list=mct_list_nitem (temp_list) - extented_fields='' - do index_list = 1, size_list - call mct_list_get(mctOStr,index_list,temp_list) - fldname = mct_string_toChar(mctOStr) - fldname_ext = trim(fldname)//'_ext' - call seq_flds_add(extented_fields,trim(fldname_ext)) - enddo - call mct_list_clean(temp_list) - - end subroutine create_moab_ext_fields end module seq_flds_mod From 5c94799d880feef794fc4c5a01bcc9de0f272ec9 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Fri, 19 Sep 2025 14:59:41 -0500 Subject: [PATCH 080/398] initialize aream for land too it may be left 0 for spectral case; no maps, so no aream to read from anywhere --- driver-moab/main/cplcomp_exchange_mod.F90 | 35 ++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 6796cd6d899b..83d411483fa7 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -995,12 +995,18 @@ subroutine copy_aream_from_area(mbappid) integer :: ierr, ent_type ! copy aream from area - if (mbappid >= 0) then ! coupler atm procs + if (mbappid >= 0) then ! coupler procs ierr = iMOAB_GetMeshInfo ( mbappid, nvert, nvise, nbl, nsurf, nvisBC ) - arrSize = nvise(1) ! cells + if ( (mbappid .eq. mbaxid) .and. (.not. atm_pg_active)) then + ! this is the spectral case, for atm only + arrSize = nvert(1) ! cells + ent_type = 0 ! vertices + else + arrSize = nvise(1) ! cells + ent_type = 1 ! cells + endif allocate(tagValues(arrSize)) tagname = 'area'//C_NULL_CHAR - ent_type = 1 ! cells ierr = iMOAB_GetDoubleTagStorage( mbappid, tagname, arrsize , ent_type, tagValues ) tagname = 'aream'//C_NULL_CHAR ierr = iMOAB_SetDoubleTagStorage( mbappid, tagname, arrsize , ent_type, tagValues ) @@ -1252,12 +1258,13 @@ subroutine cplcomp_moab_Init(infodata,comp) write(logunit,*) subname,' error in defining tags seq_flds_dom_fields on atm on coupler ' call shr_sys_abort(subname//' ERROR in defining tags ') endif - - ! also, frac, area, masks has to come from atm mphaid, not from domain file reader - ! this is hard to digest :( - tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR - ! TODO: this should be called on the joint procs, not coupler only. - call component_exch_moab(comp, mphaid, mbaxid, 0, tagname, context_exch='doma') + endif ! coupler pes + ! also, frac, area, masks has to come from atm mphaid, not from domain file reader + ! this is hard to digest :( + tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR + ! TODO: this should be called on the joint procs, not coupler only. + call component_exch_moab(comp, mphaid, mbaxid, 0, tagname, context_exch='doma') + if (mbaxid .ge. 0 ) then ! coupler pes only ! copy aream from area in case atm_mesh call copy_aream_from_area(mbaxid) @@ -1657,6 +1664,12 @@ subroutine cplcomp_moab_Init(infodata,comp) tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR call component_exch_moab(comp, mlnid, mblxid, 0, tagname, context_exch='doml') + ! initialize aream with area; in some cases lnd will not have any maps, so aream still need to + ! have some values (not only 0) + ! spectral case seems to need this, as everything is monogrid + if (MPI_COMM_NULL /= mpicom_new ) then ! we are on the coupler pes + call copy_aream_from_area(mblxid) + endif #ifdef MOABDEBUG outfile = 'recMeshLand.h5m'//C_NULL_CHAR wopts = ';PARALLEL=WRITE_PART'//C_NULL_CHAR ! @@ -1906,7 +1919,9 @@ subroutine cplcomp_moab_Init(infodata,comp) call component_exch_moab(comp, mrofid, mbrxid, 0, tagname, context_exch='domr') ! copy aream from area in all cases ! initialize aream from area; it may have different values in the end, or reset again - call copy_aream_from_area(mbrxid) + if (mbrxid > 0) then ! on coupler pes only + call copy_aream_from_area(mbrxid) + endif #ifdef MOABDEBUG if (mbrxid >= 0) then outfile = 'recMeshRof.h5m'//C_NULL_CHAR From 455444eafc613c1155955fd8e7dd1295ed35feaf Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Fri, 19 Sep 2025 15:55:26 -0500 Subject: [PATCH 081/398] do not project aream for lnd for spectral case in general, aream for lnd is projected from atm in same grid cases, spectral (monogrid), do not need to project anymore --- driver-moab/main/component_mod.F90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/driver-moab/main/component_mod.F90 b/driver-moab/main/component_mod.F90 index 60f94f6992b3..fe02ddb032b6 100644 --- a/driver-moab/main/component_mod.F90 +++ b/driver-moab/main/component_mod.F90 @@ -467,6 +467,7 @@ subroutine component_init_aream(infodata, rof_c2_ocn, samegrid_ao, samegrid_al, use seq_comm_mct, only: mblxid ! iMOAB id for lnd migrated mesh to coupler pes use seq_comm_mct, only: mbaxid ! iMOAB id for atm migrated mesh to coupler pes use seq_comm_mct, only: mbrxid ! iMOAB id for rof migrated mesh to coupler pes + use seq_comm_mct, only: atm_pg_active ! ! ! Arguments type (seq_infodata_type) , intent(inout) :: infodata @@ -594,7 +595,9 @@ subroutine component_init_aream(infodata, rof_c2_ocn, samegrid_ao, samegrid_al, dom_s => component_get_dom_cx(atm(1)) !dom_ax dom_d => component_get_dom_cx(lnd(1)) !dom_lx - call seq_map_map(mapper_Sa2l, av_s=dom_s%data, av_d=dom_d%data, fldlist='aream') + if (atm_pg_active) then + call seq_map_map(mapper_Sa2l, av_s=dom_s%data, av_d=dom_d%data, fldlist='aream') + endif else gsmap_d => component_get_gsmap_cx(lnd(1)) ! gsmap_lx dom_d => component_get_dom_cx(lnd(1)) ! dom_lx From 5939ef6bd8077bdf0ca0def46f42fe6230b439e1 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Tue, 23 Sep 2025 10:52:13 -0500 Subject: [PATCH 082/398] spectral case fixes atm will be type 2 on coupler side, when atm_pg_active is false it cannot be used for any map read or compute, it can be only monogrid case there are still differences shown with MOABCOMP, so something is still not right --- driver-moab/main/component_mod.F90 | 13 ++++++++----- driver-moab/main/cplcomp_exchange_mod.F90 | 6 ------ driver-moab/main/prep_atm_mod.F90 | 18 +++++++++++++++--- driver-moab/main/prep_lnd_mod.F90 | 2 +- driver-moab/main/prep_ocn_mod.F90 | 2 +- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/driver-moab/main/component_mod.F90 b/driver-moab/main/component_mod.F90 index fe02ddb032b6..68c378e92bbb 100644 --- a/driver-moab/main/component_mod.F90 +++ b/driver-moab/main/component_mod.F90 @@ -529,7 +529,12 @@ subroutine component_init_aream(infodata, rof_c2_ocn, samegrid_ao, samegrid_al, nloc = mct_avect_lsize(dom_s%data) allocate(data1(nloc)) data1 = dom_s%data%rAttr(ka,:) - ent_type = 1 ! element dense double tags + if (atm_pg_active) then + ent_type = 1 ! element dense double tags + else ! this is true only for spectral atm now + ent_type = 0 ! for pure spectral case, the atm is PC on coupler side + endif + allocate(gids(nloc)) gids = dom_s%data%iAttr(mct_aVect_indexIA(dom_s%data,"GlobGridNum"),:) ! ! now set data on the coupler side too @@ -594,10 +599,8 @@ subroutine component_init_aream(infodata, rof_c2_ocn, samegrid_ao, samegrid_al, if (samegrid_al) then dom_s => component_get_dom_cx(atm(1)) !dom_ax dom_d => component_get_dom_cx(lnd(1)) !dom_lx - - if (atm_pg_active) then - call seq_map_map(mapper_Sa2l, av_s=dom_s%data, av_d=dom_d%data, fldlist='aream') - endif + ! it should work for FV and spectral too + call seq_map_map(mapper_Sa2l, av_s=dom_s%data, av_d=dom_d%data, fldlist='aream') else gsmap_d => component_get_gsmap_cx(lnd(1)) ! gsmap_lx dom_d => component_get_dom_cx(lnd(1)) ! dom_lx diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 83d411483fa7..262237bb7912 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -1664,12 +1664,6 @@ subroutine cplcomp_moab_Init(infodata,comp) tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR call component_exch_moab(comp, mlnid, mblxid, 0, tagname, context_exch='doml') - ! initialize aream with area; in some cases lnd will not have any maps, so aream still need to - ! have some values (not only 0) - ! spectral case seems to need this, as everything is monogrid - if (MPI_COMM_NULL /= mpicom_new ) then ! we are on the coupler pes - call copy_aream_from_area(mblxid) - endif #ifdef MOABDEBUG outfile = 'recMeshLand.h5m'//C_NULL_CHAR wopts = ';PARALLEL=WRITE_PART'//C_NULL_CHAR ! diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index d5a923722497..687b679bacf6 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -1088,7 +1088,11 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) write(logunit,*) subname,' error in getting info ' call shr_sys_abort(subname//' error in getting info ') endif - lsize = nvise(1) ! number of active cells + if (atm_pg_active) then + lsize = nvise(1) ! number of active cells + else + lsize = nvert(1) ! for the spectral case, everything is pc from now on + endif ! mct avs are used just for their fields metadata, not the actual reals ! (name of the fields) ! need these always, not only the first time @@ -1296,7 +1300,11 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) endif ! end first-time ! Get data from MOAB - ent_type = 1 ! cells + if (atm_pg_active) then + ent_type = 1 ! cells + else + ent_type = 0 ! vertices, it is PC + endif tagname = trim(seq_flds_x2a_fields)//C_NULL_CHAR arrsize = naflds * lsize ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, x2a_am) @@ -1536,7 +1544,11 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) ! loop over all fields in seq_flds_x2a_fields call mct_list_init(temp_list ,seq_flds_x2a_fields) size_list=mct_list_nitem (temp_list) - ent_type = 1 ! cell for atm, atm_pg_active + if (atm_pg_active) then + ent_type = 1 ! cell for atm, atm_pg_active + else + ent_type = 0 ! vertices is spectral case + endif if (iamroot) print *, subname, num_moab_exports, trim(seq_flds_x2a_fields) do index_list = 1, size_list call mct_list_get(mctOStr,index_list,temp_list) diff --git a/driver-moab/main/prep_lnd_mod.F90 b/driver-moab/main/prep_lnd_mod.F90 index 08d208d1c60e..bd737a1fccf5 100644 --- a/driver-moab/main/prep_lnd_mod.F90 +++ b/driver-moab/main/prep_lnd_mod.F90 @@ -592,7 +592,7 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln if (atm_pg_active) then type1 = 3; ! fv for atm; cgll does not work anyway else - type1 = 1 ! this projection works (cgll to fv), but reverse does not ( fv - cgll) + type1 = 2 ! in this case, atm is just PC endif type2 = 3; ! FV mesh on coupler land ierr = iMOAB_ComputeCommGraph( mbaxid, mblxid, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & diff --git a/driver-moab/main/prep_ocn_mod.F90 b/driver-moab/main/prep_ocn_mod.F90 index efa90630d3fd..806abdd3e696 100644 --- a/driver-moab/main/prep_ocn_mod.F90 +++ b/driver-moab/main/prep_ocn_mod.F90 @@ -586,7 +586,7 @@ subroutine prep_ocn_init(infodata, atm_c2_ocn, atm_c2_ice, ice_c2_ocn, rof_c2_oc if (atm_pg_active) then type1 = 3; ! FV for ATM; CGLL does not work correctly in parallel at the moment else - type1 = 1 ! This projection works (CGLL to FV), but reverse does not (FV - CGLL) + type1 = 2 ! in the spectral case, the type on coupler will be point cloud endif type2 = 3; ! FV mesh on coupler OCN From de80a20a98a55f107d72ad0353a482c2ec0396be Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Tue, 23 Sep 2025 15:06:03 -0500 Subject: [PATCH 083/398] more spectral fixes the utilities in shr_moab_mod.F90 need to know if spectral atm is involved; then, instead of cells, use vertices nb and tags --- driver-moab/main/prep_aoflux_mod.F90 | 11 ++++++++-- driver-moab/main/prep_atm_mod.F90 | 32 +++++++++++++++++++--------- driver-moab/shr/shr_moab_mod.F90 | 21 +++++++++++++++--- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/driver-moab/main/prep_aoflux_mod.F90 b/driver-moab/main/prep_aoflux_mod.F90 index 958403da0e55..3e0b150632b9 100644 --- a/driver-moab/main/prep_aoflux_mod.F90 +++ b/driver-moab/main/prep_aoflux_mod.F90 @@ -12,6 +12,7 @@ module prep_aoflux_mod use seq_comm_mct, only : mbox2id ! used only for debugging ocn and mct #endif use seq_comm_mct, only : mbaxid ! iMOAB app id for atm on cpl pes + use seq_comm_mct, only: atm_pg_active ! whether the atm uses FV mesh or not ; made true if fv_nphys > 0 use seq_comm_mct, only: seq_comm_getData=>seq_comm_setptrs use seq_comm_mct, only : num_moab_exports use seq_infodata_mod, only: seq_infodata_getdata, seq_infodata_type @@ -227,9 +228,15 @@ subroutine prep_aoflux_init (infodata) ! find out the number of local elements in moab mesh ierr = iMOAB_GetMeshInfo ( mbaxid, nvert, nvise, nbl, nsurf, nvisBC ); ! could be different of lsize_o ! local size of vertices is different from lsize_o - arrSize = nvise(1) * size_list ! there are size_list tags that need to be zeroed out + if(atm_pg_active) then + arrSize = nvise(1) * size_list ! there are size_list tags that need to be zeroed out + ent_type = 1 ! cell type now, not a point cloud anymore + else + arrSize = nvert(1) * size_list + ent_type = 0 ! vertex type now, point cloud + endif allocate(tagValues(arrSize) ) - ent_type = 1 ! cell type now, not a point cloud anymore + tagValues = 0._r8 ierr = iMOAB_SetDoubleTagStorage ( mbaxid, tagname, arrSize , ent_type, tagValues) deallocate(tagValues) diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index 687b679bacf6..295efb8aeb87 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -393,7 +393,7 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at if (atm_pg_active) then type2 = 3; ! FV for ATM; CGLL does not work correctly in parallel at the moment else - type2 = 1 ! This projection works (CGLL to FV), but reverse does not (FV - CGLL) + type2 = 2 ! from now on, spectral is on PC on coupler side, too; no mapping allowed, just reorder? endif ierr = iMOAB_ComputeCommGraph( mboxid, mbaxid, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & ocn(1)%cplcompid, atm(1)%cplcompid ) @@ -515,14 +515,19 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at mapper_Fof2a%weight_identifier = wgtIdFo2a mapper_Fof2a%mbname = 'mapper_Fof2a' - type1 = 3; ! fv for ocean and atm; fv-cgll does not work anyway - type2 = 3; + type1 = 3; ! fv for ocean and atm; + if (atm_pg_active) then ! + type2 = 3 + else + type2 = 2 ! PC cloud + endif if (.not. samegrid_ao) then ! data-OCN case ! we use the same intx, because the mesh will be the same, between mbofxid and mboxid ierr = iMOAB_ComputeCommGraph( mbofxid, mbintxoa, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & context_id, idintx) else ! this is a case appearing in the data ocean case --res ne4pg2_ne4pg2 --compset FAQP + ! also in spectral case, monogrid --res ne4_ne4 --compset F2010-SCREAMv1 ( type2 is 2, point cloud ) ierr = iMOAB_ComputeCommGraph( mbofxid, mbaxid, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & context_id, atm(1)%cplcompid ) if (ierr .ne. 0) then @@ -748,8 +753,12 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at mapper_Fi2a%weight_identifier = wgtIdFi2a mapper_Fi2a%mbname = 'mapper_Fi2a' if ( samegrid_ao ) then ! this case can appear in cice case - type1 = 3; ! fv for ice and atm; - type2 = 3; + type1 = 3 ! fv for ice + if (atm_pg_active) then + type2 = 3 + else + type2 = 2 ! this is spectral case , PC cloud for atm + endif ierr = iMOAB_ComputeCommGraph( mbixid, mbaxid, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & ice(1)%cplcompid, atm(1)%cplcompid ) if (ierr .ne. 0) then @@ -905,8 +914,8 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at endif - type1 = 3; ! fv for lnd and atm; fv-cgll does not work anyway - type2 = 3; + type1 = 3 ! fv for lnd and atm; fv-cgll does not work anyway + type2 = 3 ierr = iMOAB_ComputeCommGraph( mblxid, mbintxla, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & lnd(1)%cplcompid, idintx) if (ierr .ne. 0) then @@ -919,8 +928,12 @@ subroutine prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_at ! so we compute just a comm graph, between lnd and atm dofs, on the coupler; target is atm ! land is point cloud in this case, type1 = 2 call seq_comm_getinfo(CPLID, mpigrp=mpigrp_CPLID) ! make sure we have the right MPI group - type1 = 3; ! full mesh for land now - type2 = 3; ! fv for target atm + type1 = 3 ! full mesh for land now + if (atm_pg_active) then + type2 = 3 ! fv for target atm + else + type2 = 2 ! point cloud for spectral + endif ierr = iMOAB_ComputeCommGraph( mblxid, mbaxid, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & lnd(1)%cplcompid, atm(1)%cplcompid) if (ierr .ne. 0) then @@ -1561,7 +1574,6 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) ! loop over all fields in seq_flds_o2x_fields call mct_list_init(temp_list ,seq_flds_o2x_fields) size_list=mct_list_nitem (temp_list) - ent_type = 1 ! cell for atm, atm_pg_active if (iamroot) print *, subname, num_moab_exports, trim(seq_flds_o2x_fields) do index_list = 1, size_list call mct_list_get(mctOStr,index_list,temp_list) diff --git a/driver-moab/shr/shr_moab_mod.F90 b/driver-moab/shr/shr_moab_mod.F90 index f07d4da4ad6a..b51a0def95bd 100644 --- a/driver-moab/shr/shr_moab_mod.F90 +++ b/driver-moab/shr/shr_moab_mod.F90 @@ -7,6 +7,7 @@ module shr_moab_mod use shr_sys_mod, only: shr_sys_abort use seq_comm_mct, only: logunit + use seq_comm_mct, only: atm_pg_active, mbaxid use shr_kind_mod, only: CXX => shr_kind_CXX use shr_kind_mod , only: R8 => SHR_KIND_R8 use iso_c_binding @@ -53,7 +54,12 @@ integer function mbGetnCells(moabid) call shr_sys_abort(subname//' error in getting info ') endif - mbGetnCells = nvise(1) + ! only case on coupler side that we actually want number of vertices is when we use spectral atm + if ( .not. atm_pg_active .and. mbaxid .eq. moabid) then + mbGetnCells = nvert(1) + else + mbGetnCells = nvise(1) + endif end function mbGetnCells @@ -85,7 +91,12 @@ subroutine mbGetCellTagVals(mbid, intag,inarray,nMax) !----------------------------------------------------------------------- ! - ent_type=1 + if ( .not. atm_pg_active .and. mbaxid .eq. mbid) then + ent_type = 0 + else + ent_type = 1 + endif + tagname = trim(intag)//C_NULL_CHAR ierr = iMOAB_GetDoubleTagStorage (mbid, tagname, nMax , ent_type, inarray) if (ierr .ne. 0) then @@ -123,7 +134,11 @@ subroutine mbSetCellTagVals(mbid, intag,inarray,nMax) !----------------------------------------------------------------------- ! - ent_type=1 + if ( .not. atm_pg_active .and. mbaxid .eq. mbid) then + ent_type = 0 + else + ent_type = 1 + endif tagname = trim(intag)//C_NULL_CHAR ierr = iMOAB_SetDoubleTagStorage (mbid, tagname, nMax , ent_type, inarray) if (ierr .ne. 0) then From 6392f2ea8aae9c9d30b9834e32a4a2dfd7392b32 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Wed, 24 Sep 2025 11:59:40 -0500 Subject: [PATCH 084/398] io needs also spectral case changes the only coupler instance that uses vertices for primary data is the atm in spectral case anoter fix needed is for regular pg2 case; not working anymore --- driver-moab/main/seq_io_mod.F90 | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/driver-moab/main/seq_io_mod.F90 b/driver-moab/main/seq_io_mod.F90 index 6831e21dbce7..7af70c1e840f 100644 --- a/driver-moab/main/seq_io_mod.F90 +++ b/driver-moab/main/seq_io_mod.F90 @@ -33,6 +33,7 @@ module seq_io_mod use shr_sys_mod, only: shr_sys_abort use seq_comm_mct, only: logunit, CPLID, seq_comm_setptrs use seq_comm_mct, only: seq_comm_namelen, seq_comm_name + use seq_comm_mct, only: mbaxid, atm_pg_active use seq_flds_mod, only : seq_flds_lookup use mct_mod ! mct wrappers use pio @@ -1615,7 +1616,8 @@ end subroutine seq_io_write_time ! file_ind [in, optional] - File index for multi-file support ! ! !NOTES: - ! - Only cell-type entities are supported (ent_type=1). + ! - Only cell-type entities are supported (ent_type=1). + ! - not anymore: spectral case, atm needs vertices ent_type=0 ! - Handles reordering of local/global cell IDs for correct output. ! - If matrix is not present, data is read from MOAB tags; if present, matrix is written directly. ! - Skips writing the field "hgt" as a temporary exclusion. @@ -1623,6 +1625,7 @@ end subroutine seq_io_write_time ! ! !REVISION HISTORY: ! 2025-07-20 - Cursor - initial documentation + ! 2025-09-24 allow vertex type for entity, for spectral case for atmosphere ! ! !INTERFACE: ------------------------------------------------------------------ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, matrix, nx, ny, nt, file_ind, dims2din, dims2do, mask ) @@ -1691,7 +1694,6 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, ! should we write a warning? return endif - ent_type = 1 ! cells type lfile_ind = 0 if (present(file_ind)) lfile_ind=file_ind @@ -1700,7 +1702,6 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, call mct_list_init(temp_list ,trim(tag_list)) size_list=mct_list_nitem (temp_list) ! role of nf, number fields - ent_type = 1 ! cell for atm, atm_pg_active if (size_list < 1) then write(logunit,*) subname,' ERROR: size_list = ',size_list,trim(dname) @@ -1727,8 +1728,13 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, ! get the local size ns ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) - ns = nvise(1) ! local cells - + if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then + ent_type = 0 + ns = nvert(1) ! local vertices + else + ent_type = 1 + ns = nvise(1) ! local cells + endif if (lwhead) then if (present(dims2din)) then dimid2(1)=dims2din(1) @@ -2623,6 +2629,7 @@ end subroutine seq_io_read_char ! ! !NOTES: ! - Only cell-type entities are supported (ent_type=1). + ! - not anymore: spectral case, atm, uses vertices, ent_type = 0 ! - Handles reordering of local/global cell IDs for correct mapping. ! - If matrix is present, data is stored in the matrix; otherwise, data is set as MOAB tags. ! - Skips reading the field "hgt" as a temporary exclusion. @@ -2630,6 +2637,7 @@ end subroutine seq_io_read_char ! ! !REVISION HISTORY: ! 2025-07-20 - Cursor - initial documentation + ! 2025-09-24 spectral case atm ! ! !INTERFACE: ------------------------------------------------------------------ @@ -2687,7 +2695,6 @@ subroutine seq_io_read_moab_tags(filename, mbxid, dname, tag_list, matrix, nx) call mct_list_init(temp_list ,trim(tag_list)) size_list=mct_list_nitem (temp_list) ! role of nf, number fields - ent_type = 1 ! cell for atm, atm_pg_active if (size_list < 1) then write(logunit,*) subname,' ERROR: size_list = ',size_list,trim(dname) @@ -2723,7 +2730,13 @@ subroutine seq_io_read_moab_tags(filename, mbxid, dname, tag_list, matrix, nx) endif lny = 1 ! do we need 2 var, or just 1 ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) - ns = nvise(1) ! local cells + if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then + ent_type = 0 + ns = nvert(1) ! local vertices + else + ent_type = 1 + ns = nvise(1) ! local cells + endif allocate(data1(ns)) allocate(data_reorder(ns)) allocate(dof(ns)) From e3598b952d37285f6c897741de0ac371bb602bf9 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Wed, 24 Sep 2025 12:57:43 -0500 Subject: [PATCH 085/398] field norm8wt removed by mistake not sure yet when --- driver-moab/main/cplcomp_exchange_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 262237bb7912..95c34f3e39a5 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -1250,7 +1250,7 @@ subroutine cplcomp_moab_Init(infodata,comp) !add the normalization tag - tagname = trim(seq_flds_dom_fields)//C_NULL_CHAR + tagname = trim(seq_flds_dom_fields)//":norm8wt"//C_NULL_CHAR numco = 1 ! usually 1 value per cell ierr = iMOAB_DefineTagStorage(mbaxid, tagname, tagtype, numco, tagindex ) From 12dae1a1c0d63e2c4caa9b2476d6d649b47e8e34 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Thu, 25 Sep 2025 14:33:25 -0500 Subject: [PATCH 086/398] remove spectral mesh only method spectral mesh will not be instanced at all for pure spectral; it is not used at all right now only in the pgx case the spectral mesh is instanced and that is just because it is easier to instance all meshes, not just pgx FV mesh maybe it should be cleaned out completely --- .../homme/interface/phys_grid_mod.F90 | 73 ++- components/homme/src/share/semoab_mod.F90 | 447 ------------------ 2 files changed, 35 insertions(+), 485 deletions(-) diff --git a/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 b/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 index 7c0abdc73f2c..b4989b0e40fc 100644 --- a/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 +++ b/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 @@ -552,7 +552,7 @@ subroutine phys_grid_init (pgN) use seq_comm_mct, only: MHID, MHFID ! id of homme moab coarse and fine applications use seq_comm_mct, only: ATMID use seq_comm_mct, only: mhpgid ! id of pgx moab application - use semoab_mod, only: create_moab_pg_mesh, create_spectral_moab_meshes + use semoab_mod, only: create_moab_pg_mesh use iMOAB, only : iMOAB_RegisterApplication use iso_c_binding #endif @@ -624,48 +624,45 @@ subroutine phys_grid_init (pgN) call compute_global_coords (pg) call compute_global_area (pg) #ifdef HAVE_MOAB - appname="HM_COARSE"//C_NULL_CHAR - ATM_ID1 = 120 ! - ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHID) - if (ierr > 0 ) & - call abortmp('Error: cannot register moab app') - if(par%masterproc) then - write(iulog,*) " " - write(iulog,*) "register MOAB app:", trim(appname), " MHID=", MHID - write(iulog,*) " " - endif - appname="HM_FINE"//C_NULL_CHAR - ATM_ID1 = 119 ! this number should not conflict with other components IDs; how do we know? - ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHFID) - if (ierr > 0 ) & - call abortmp('Error: cannot register moab app for fine mesh') - if(par%masterproc) then - write(iulog,*) " " - write(iulog,*) "register MOAB app:", trim(appname), " MHFID=", MHFID - write(iulog,*) " " - endif if (pgN > 0) then - - appname="HM_PGX"//C_NULL_CHAR - ATM_ID1 = ATMID(1) ! this number should not conflict with other components IDs; how do we know? - ! - ! in this case, we reuse the main atm id, mhid will not be used for intersection anymore - ! still, need to be careful - ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, mhpgid) - if (ierr > 0 ) & - call abortmp('Error: cannot register moab app for fine mesh') - if(par%masterproc) then - write(iulog,*) " " - write(iulog,*) "register MOAB app:", trim(appname), " MHPGID=", mhpgid - write(iulog,*) " " - endif + appname="HM_COARSE"//C_NULL_CHAR + ATM_ID1 = 120 ! + ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHID) + if (ierr > 0 ) & + call abortmp('Error: cannot register moab app') + if(par%masterproc) then + write(iulog,*) " " + write(iulog,*) "register MOAB app:", trim(appname), " MHID=", MHID + write(iulog,*) " " + endif + appname="HM_FINE"//C_NULL_CHAR + ATM_ID1 = 119 ! this number should not conflict with other components IDs; how do we know? + ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, MHFID) + if (ierr > 0 ) & + call abortmp('Error: cannot register moab app for fine mesh') + if(par%masterproc) then + write(iulog,*) " " + write(iulog,*) "register MOAB app:", trim(appname), " MHFID=", MHFID + write(iulog,*) " " + endif + appname="HM_PGX"//C_NULL_CHAR + ATM_ID1 = ATMID(1) ! this number should not conflict with other components IDs; how do we know? + ! + ! in this case, we reuse the main atm id, mhid will not be used for intersection anymore + ! still, need to be careful + ierr = iMOAB_RegisterApplication(appname, par%comm, ATM_ID1, mhpgid) + if (ierr > 0 ) & + call abortmp('Error: cannot register moab app for fine mesh') + if(par%masterproc) then + write(iulog,*) " " + write(iulog,*) "register MOAB app:", trim(appname), " MHPGID=", mhpgid + write(iulog,*) " " + endif ! instance distributed moab meshes from elem structures ! 1 ) spectral coarse mesh ! 2 ) GLL fine quad mesh (used mostly for visualization) ! 3 ) pgN FV type mesh, (most of the time pg2 mesh), used for coupling with other components; - call create_moab_pg_mesh(par, elem, pgN) - else - call create_spectral_moab_meshes(par, elem) + call create_moab_pg_mesh(par, elem, pgN) endif #endif end subroutine phys_grid_init diff --git a/components/homme/src/share/semoab_mod.F90 b/components/homme/src/share/semoab_mod.F90 index 8d46a441173f..4461c2fb39a7 100644 --- a/components/homme/src/share/semoab_mod.F90 +++ b/components/homme/src/share/semoab_mod.F90 @@ -76,453 +76,6 @@ integer function search_in(intarr, leng, value) end function search_in - subroutine create_spectral_moab_meshes(par, elem) -use ISO_C_BINDING - use iMOAB, only: iMOAB_CreateVertices, iMOAB_WriteMesh, iMOAB_CreateElements, & - iMOAB_ResolveSharedEntities, iMOAB_UpdateMeshInfo, iMOAB_DefineTagStorage, & - iMOAB_SetIntTagStorage, iMOAB_ReduceTagsMax, iMOAB_GetIntTagStorage - use coordinate_systems_mod, only : cartesian3D_t, spherical_to_cart, spherical_polar_t - - type (element_t), intent(inout) :: elem(:) - type (parallel_t) , intent(in) :: par - - integer ierr, i, j, ie, iv, block_ID, k, numvals - integer icol, irow, je, linx ! local indices in fine el connect - - real(kind=real_kind), allocatable :: moab_vert_coords(:) - - integer moab_dim_cquads, ix, idx, nverts, nverts_c ! used for indexing in loops; nverts will have the number of local vertices - - integer nelemd2 ! do not confuse this with dimensions_mod::nelemd - - integer(kind=long_kind), dimension(:), allocatable :: gdofv - ! this will be moab vertex handle locally - integer, dimension(:), allocatable :: moabvh - integer, dimension(:), allocatable :: indx ! this will be ordered - - integer, dimension(:), allocatable :: vdone, elemids, vgids, gdofel - integer, dimension(:), allocatable :: vdone_c, moabconn_c, moabvh_c - integer currentval, dimcoord, dimen, num_el, mbtype, nve - - character*100 outfile, wopts, localmeshfile, lnum, tagname, newtagg - integer tagtype, numco, tag_sto_len, ent_type, tagindex - type (cartesian3D_t) :: cart - integer igcol, ii, neigh - - ! for np=4, - ! 28, 32, 36, 35 - ! 25, 29, 33, 34 - ! j | 13, 17, 21, 22 - ! 1, 5, 9, 10 - !(1,1) i-> - - ! character*100 outfile, wopts, localmeshfile, lnum, tagname - ! integer tagtype, numco, tag_sto_len, ent_type, tagindex - do j=1,np-1 - do i =1, np-1 - ix = (j-1)*(np-1)+i-1 - local_map(i,j) = ix*4 + 1 - enddo - enddo - do j=1, np-1 - i = j - local_map(np, j) = ((np-1)*j-1)*4 + 2 - local_map(i, np) = ( (np-1)*(np-2)+i-1)*4 + 4 - enddo - local_map(np, np) = ((np-1)*(np-1)-1)*4 + 3 - - nelemd2 = (nelemd)*(np-1)*(np-1) - moab_dim_cquads = (nelemd)*4*(np-1)*(np-1) - - if(par%masterproc) then - write (iulog, *) " MOAB: semoab_mod module: create_spectral_moab_meshes on processor " , par%rank ," nelemd: " , nelemd - endif - - if ( nelemd > 0 ) then - allocate(gdofv(moab_dim_cquads)) - allocate(elemids(nelemd2)) - endif - - k=0 ! will be the index for element global dofs - do ie=1,nelemd - do j=1,np-1 - do i=1,np-1 - ix = (ie-1)*(np-1)*(np-1)+(j-1)*(np-1)+i-1 - gdofv(ix*4+1) = elem(ie)%gdofP(i,j) - gdofv(ix*4+2) = elem(ie)%gdofP(i+1,j) - gdofv(ix*4+3) = elem(ie)%gdofP(i+1,j+1) - gdofv(ix*4+4) = elem(ie)%gdofP(i,j+1) - elemids(ix+1) = (elem(ie)%GlobalId-1)*(np-1)*(np-1)+(j-1)*(np-1)+i - enddo - enddo - enddo - -! order according to global dofs - - if ( nelemd > 0 ) then - allocate(moabvh(moab_dim_cquads)) - allocate(indx(moab_dim_cquads)) - - allocate(moabconn(moab_dim_cquads)) - call IndexSet(moab_dim_cquads, indx) - call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) -! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) - endif - idx=0 - currentval = 0 - if ( nelemd > 0 ) then - currentval = gdofv( indx(1)) - idx = 1 - endif - - do ix=1,moab_dim_cquads - if (gdofv(indx(ix)) .ne. currentval ) then - idx=idx+1 - currentval = gdofv(indx(ix)) - endif - moabvh(ix) = idx ! the vertex in connectivity array will be at this local index - ! this will be the moab connectivity - moabconn(indx(ix)) = idx - enddo - - nverts = idx - if(par%masterproc) then - write (iulog, *) " MOAB: there are ", nverts, " local vertices on master task ", currentval, " is the max local gdof" - endif - if ( nelemd > 0 ) then - allocate(moab_vert_coords(3*nverts) ) - allocate(vdone(nverts)) - else - allocate(vdone(1)) ! will be passed to iMOAB_ResolveSharedEnts, and compilers are complaining about non-allocated arrays - endif - vdone = 0; - if ( nelemd > 0 ) currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices - - do ix=1,moab_dim_cquads - idx = indx(ix) ! index in initial array, vertices in all fine quads - k = (idx-1)/(4*(np-1)*(np-1)) ! index of coarse quad, locally, starts at 0 - ie = 1 + k ! this is the element number; starts at nets=1 - je = ( idx -1 -k*(np-1)*(np-1)*4 ) / 4 + 1 ! local fine quad in coarse, 1 to (np-1) ^ 2 - irow = (je-1)/(np-1)+1 - icol = je - (np-1)*(irow-1) - linx = idx - k*(np-1)*(np-1)*4 -(je-1)*4 ! this should be 1, 2, 3, 4 - if( linx == 1) then - j = irow - i = icol - else if (linx == 2) then - j = irow - i = icol + 1 - else if (linx == 3) then - j = irow + 1 - i = icol + 1 - else ! linx == 4 - j = irow + 1 - i = icol - endif - - iv = moabvh(ix) - if (vdone(iv) .eq. 0) then - cart = spherical_to_cart (elem(ie)%spherep(i,j) ) - moab_vert_coords ( 3*(iv-1)+1 ) = cart%x - moab_vert_coords ( 3*(iv-1)+2 ) = cart%y - moab_vert_coords ( 3*(iv-1)+3 ) = cart%z - vdone(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities ! convert to int, from long int - endif - - enddo - - dimcoord = nverts*3 - dimen = 3 - if ( nelemd > 0 ) then - ierr = iMOAB_CreateVertices(MHFID, dimcoord, dimen, moab_vert_coords) - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB vertices ') - endif - !!num_el = nelemd2 - mbtype = 3 ! quadrilateral - nve = 4; - block_ID = 200 ! this will be for coarse mesh - - if ( nelemd > 0 ) then - ierr = iMOAB_CreateElements( MHFID, nelemd2, mbtype, nve, moabconn, block_ID ); - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB elements') - endif - ! nverts: num vertices; vdone will store now the markers used in global resolve - ! for this particular problem, markers are the global dofs at corner nodes -! set the global id for vertices -! first, retrieve the tag - tagname='GDOF'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = 1 - ierr = iMOAB_DefineTagStorage(MHFID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve global id tag') - ! now set the values - ent_type = 0 ! vertex type - if ( nverts > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHFID, tagname, nverts , ent_type, vdone) - if (ierr > 0 ) & - call abortmp('Error: fail to set marker id tag for vertices') - endif - - ! we need to call this even when no mesh locally, it involves a collective - ierr = iMOAB_ResolveSharedEntities( MHFID, nverts, vdone ); - if (ierr > 0 ) & - call abortmp('Error: fail to resolve shared entities') - - if ( nelemd > 0) then - vdone = -1 ! reuse vdone for the new tag, GLOBAL_ID (actual tag that we want to store global dof ) - endif -! use element offset for actual global dofs - ! tagtype = 0 ! dense, integer - ! numco = 1 - newtagg='GLOBAL_ID'//C_NULL_CHAR - ierr = iMOAB_DefineTagStorage(MHFID, newtagg, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to create new GDOF tag') - do ie=1,nelemd - do ii=1,elem(ie)%idxp%NumUniquePts - i=elem(ie)%idxp%ia(ii) - j=elem(ie)%idxp%ja(ii) - igcol = elem(ie)%idxp%UniquePtoffset+ii-1 - ix = local_map(i,j) - idx = moabconn((ie-1)*(np-1)*(np-1)*4 + ix) ! should - vdone ( idx ) = igcol - end do - end do - ! now set the values - ent_type = 0 ! vertex type - if ( nverts > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vdone) - if (ierr > 0 ) & - call abortmp('Error: fail to set global dof tag for vertices') - endif - - ierr = iMOAB_ReduceTagsMax ( MHFID, tagindex, ent_type) - if (ierr > 0 ) & - call abortmp('Error: fail to reduce max tag') - - ! set global id tag for elements - ent_type = 1 ! now set the global id tag on elements - if ( nelemd2 > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nelemd2 , ent_type, elemids) - if (ierr > 0 ) & - call abortmp('Error: fail to set global id tag for elements') - endif - -! now, after reduction, we can get the actual global ids for each vertex in the fine mesh -! before, some vertices that were owned in MOAB but not owned in CAM did not have the right global ID tag -! so vdone will be now correct on every task (no -1 anymore ) - ent_type = 0 ! vertex type - if ( nverts > 0 ) then - allocate(vgids(nverts)) - ierr = iMOAB_GetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vgids) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GLOBAL ID on each task') - endif - ierr = iMOAB_UpdateMeshInfo(MHFID) - if (ierr > 0 ) & - call abortmp('Error: fail to update mesh info') -#ifdef MOABDEBUG -! write out the mesh file to disk, in parallel - outfile = 'wholeFineATM.h5m'//C_NULL_CHAR - wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR - ierr = iMOAB_WriteMesh(MHFID, outfile, wopts) - if (ierr > 0 ) & - call abortmp('Error: fail to write the mesh file') -#endif - - -! now create the coarse mesh, but the global dofs will come from fine mesh, after solving - ! nelemd2 = nelemd - moab_dim_cquads = (nelemd)*4 - - if ( nelemd > 0 ) then - allocate(gdofel(nelemd*np*np)) - endif - k=0 ! will be the index for element global dofs - do ie=1,nelemd - ix = ie-1 - ! - gdofv(ix*4+1) = elem(ie)%gdofP(1,1) - gdofv(ix*4+2) = elem(ie)%gdofP(np,1) - gdofv(ix*4+3) = elem(ie)%gdofP(np,np) - gdofv(ix*4+4) = elem(ie)%gdofP(1,np) - elemids(ix+1) = elem(ie)%GlobalId - enddo -! now original order - -! order according to global dofs -! allocate(indx(moab_dim_cquads)) - if ( nelemd > 0 ) then - call IndexSet(moab_dim_cquads, indx) - call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) -! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) - - allocate(moabvh_c(moab_dim_cquads)) - - allocate(moabconn_c(moab_dim_cquads)) - endif - idx = 0 - if ( nelemd > 0 ) then - idx=1 - currentval = gdofv( indx(1)) - endif - do ix=1,moab_dim_cquads - if (gdofv(indx(ix)) .ne. currentval ) then - idx=idx+1 - currentval = gdofv(indx(ix)) - endif - moabvh_c(ix) = idx ! the vertex in connectivity array will be at this local index - ! this will be the moab connectivity - moabconn_c(indx(ix)) = idx - enddo - nverts_c = idx - if(par%masterproc) then - write (iulog, *) " MOAB: there are ", nverts_c, " local vertices on master task, coarse mesh" - endif -! allocate(moab_vert_coords(3*idx) ) - if ( nelemd > 0 ) then - allocate(vdone_c(nverts_c)) - vdone_c = 0; - currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices - endif - - do ix=1,moab_dim_cquads - i = indx(ix) ! index in initial array - ie = 1+ (i-1)/4 ! this is the element number - j = i - ( i-1)/4*4 ! local index of vertex in element i - iv = moabvh_c(ix) - if (vdone_c(iv) .eq. 0) then - moab_vert_coords ( 3*(iv-1)+1 ) = elem(ie)%corners3d(j)%x - moab_vert_coords ( 3*(iv-1)+2 ) = elem(ie)%corners3d(j)%y - moab_vert_coords ( 3*(iv-1)+3 ) = elem(ie)%corners3d(j)%z - vdone_c(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities - endif - - enddo - - dimcoord = nverts_c*3 - dimen = 3 - if ( nverts_c > 0 ) then - ierr = iMOAB_CreateVertices(MHID, dimcoord, dimen, moab_vert_coords) - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB vertices ') - endif - ! num_el = nelemd - mbtype = 3 ! quadrilateral - nve = 4; - block_ID = 100 ! this will be for coarse mesh - - if ( nelemd > 0 ) then - ierr = iMOAB_CreateElements( MHID, nelemd, mbtype, nve, moabconn_c, block_ID ); - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB elements') - endif - ! idx: num vertices; vdone will store now the markers used in global resolve - ! for this particular problem, markers are the global dofs at corner nodes -! set the global id for vertices -! first, retrieve the tag - tagname='GDOFV'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = 1 - ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GDOFV id tag') - ierr = iMOAB_DefineTagStorage(MHID, newtagg, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GLOBAL_ID tag on coarse mesh') - ! now set the values - ent_type = 0 ! vertex type - if ( nverts_c > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, tagname, nverts_c , ent_type, vdone_c) - if (ierr > 0 ) & - call abortmp('Error: fail to set GDOFV tag for vertices') - endif - ! set global id tag for coarse elements, too; they will start at nets=1, end at nete=nelemd - ent_type = 1 ! now set the global id tag on elements - if ( nelemd > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nelemd , ent_type, elemids) - if (ierr > 0 ) & - call abortmp('Error: fail to set global id tag for vertices') - endif - - ierr = iMOAB_ResolveSharedEntities( MHID, idx, vdone_c ); - if (ierr > 0 ) & - call abortmp('Error: fail to resolve shared entities') - -! global dofs are the GLL points are set for each element - tagname='GLOBAL_DOFS'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = np*np ! usually, it is 16; each element will have the dofs in order - ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to create global DOFS tag') - ! now set the values - ! set global dofs tag for coarse elements, too; they will start at nets=1, end at nete=nelemd - ent_type = 1 ! now set the global id tag on elements - numvals = nelemd*np*np ! input is the total number of values - ! form gdofel from vgids - do ie=1, nelemd - ix = (ie-1)*np*np ! ie: index in coarse element - je = (ie-1) * 4 * (np-1) * (np -1) ! index in moabconn array - ! vgids are global ids for fine vertices (1,nverts) - iv = 1 - do j=1,np - do i=1,np - k = local_map(i,j) - gdofel(ix+iv) = vgids( moabconn( je + k ) ) - iv = iv + 1 - enddo - enddo - ! extract global ids - vdone_c( moabconn_c( (ie-1)*4+1) ) = vgids ( moabconn(je+1 )) - vdone_c( moabconn_c( (ie-1)*4+2) ) = vgids ( moabconn(je+ 4*(np-2)+2 )) ! valid for np = 4, 10 - vdone_c( moabconn_c( (ie-1)*4+3) ) = vgids ( moabconn(je+ 4*((np-1)*(np-1)-1) + 3 )) ! for np = 4, 35 - vdone_c( moabconn_c( (ie-1)*4+4) ) = vgids ( moabconn(je+ 4*(np-2)*(np-1) + 4 )) ! 28 for np = 4 - enddo - if ( nelemd > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, tagname, numvals, ent_type, gdofel) - if (ierr > 0 ) & - call abortmp('Error: fail to set globalDOFs tag for coarse elements') - endif - - ! set the global ids for coarse vertices the same as corresponding fine vertices - ent_type = 0 ! vertex type - if ( nverts_c > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nverts_c , ent_type, vdone_c) - if (ierr > 0 ) & - call abortmp('Error: fail to set GLOBAL_DOFS tag values') - endif - - ierr = iMOAB_UpdateMeshInfo(MHID) - if (ierr > 0 ) & - call abortmp('Error: fail to update mesh info') -#ifdef MOABDEBUG -! write out the mesh file to disk, in parallel - outfile = 'wholeATM.h5m'//C_NULL_CHAR - wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR - ierr = iMOAB_WriteMesh(MHID, outfile, wopts) - if (ierr > 0 ) & - call abortmp('Error: fail to write the mesh file') -#endif - ! deallocate - if ( nelemd > 0 ) then - deallocate(moabvh) - deallocate(moabconn) ! do not keep it anymore, we are not setting another tag on fine mesh - deallocate(gdofel) - deallocate(indx) - deallocate(elemids) - deallocate(gdofv) - deallocate(moabvh_c) - deallocate(moabconn_c) - deallocate(vdone_c) - endif - deallocate(vdone) ! we are always allocating this now -! end copy - end subroutine create_spectral_moab_meshes - subroutine create_moab_pg_mesh(par, elem, fv_nphys) use ISO_C_BINDING From b9f6c09ac17f83c539c6be7e3ca0dfc934508eb5 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Fri, 26 Sep 2025 15:11:01 -0500 Subject: [PATCH 087/398] for spectral case, global size changes when writing history files, the global size needs to be the number of global vertices, for spectral case ( atm_pg_active false) --- driver-moab/main/seq_io_mod.F90 | 49 +++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/driver-moab/main/seq_io_mod.F90 b/driver-moab/main/seq_io_mod.F90 index 7af70c1e840f..28fd14053c09 100644 --- a/driver-moab/main/seq_io_mod.F90 +++ b/driver-moab/main/seq_io_mod.F90 @@ -1711,9 +1711,23 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, lpre = trim(dname) ! find out the number of global cells, needed for defining the variables length ierr = iMOAB_GetGlobalInfo( mbxid, dummy, ng) - lnx = ng lny = 1 +#ifdef MOABCOMP + write(logunit,*) subname, 'lnx, lny, mbxid ', lnx, lny, mbxid +#endif + + ! get the local size ns + ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) + if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then + ent_type = 0 + ns = nvert(1) ! local vertices + lnx = dummy ! number of global vertices + else + ent_type = 1 + ns = nvise(1) ! local cells + lnx = ng + endif ! it is needed to overwrite that for land, ng is too small ! ( for ne4pg2 it is 201 instead of 384) if (present(nx)) then @@ -1725,16 +1739,10 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, if (present(nt)) then frame = nt endif - - ! get the local size ns - ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) - if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then - ent_type = 0 - ns = nvert(1) ! local vertices - else - ent_type = 1 - ns = nvise(1) ! local cells - endif +#ifdef MOABCOMP + write(logunit,*) subname, ' ent_type, ns ', ent_type, ns + write(logunit,*) subname, ' tag_list ', trim(tag_list) +#endif if (lwhead) then if (present(dims2din)) then dimid2(1)=dims2din(1) @@ -2719,23 +2727,24 @@ subroutine seq_io_read_moab_tags(filename, mbxid, dname, tag_list, matrix, nx) ! find out the number of global cells, needed for defining the variables length ierr = iMOAB_GetGlobalInfo( mbxid, dummy, ng) - lnx = ng - ! it is needed to overwrite that for land, ng is too small - ! ( for ne4pg2 it is 201 instead of 384) - if (present(nx)) then -#ifdef MOABCOMP - if (iam==0) write(logunit,*) subname, ' nx present: ', nx -#endif - lnx = nx - endif lny = 1 ! do we need 2 var, or just 1 ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then ent_type = 0 ns = nvert(1) ! local vertices + lnx = dummy ! number of global vertices else ent_type = 1 ns = nvise(1) ! local cells + lnx = ng + endif + ! it is needed to overwrite that for land, ng is too small + ! ( for ne4pg2 it is 201 instead of 384) + if (present(nx)) then +#ifdef MOABCOMP + if (iam==0) write(logunit,*) subname, ' nx present: ', nx +#endif + lnx = nx endif allocate(data1(ns)) allocate(data_reorder(ns)) From 72c511d9cc38ac0c4abfe540eae235de9c7fefc6 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Fri, 3 Oct 2025 13:12:30 -0500 Subject: [PATCH 088/398] replace dummy with ngv ngv is the number of global vertices for the imoab app it is used only for spectral case the other calls iMOAB_GetGlobalInfo need the number of cells, not the number of vertices --- driver-moab/main/seq_hist_mod.F90 | 1 - driver-moab/main/seq_io_mod.F90 | 12 ++++++------ driver-moab/main/seq_rest_mod.F90 | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/driver-moab/main/seq_hist_mod.F90 b/driver-moab/main/seq_hist_mod.F90 index a523f4ee1b1b..81e1aa56318b 100644 --- a/driver-moab/main/seq_hist_mod.F90 +++ b/driver-moab/main/seq_hist_mod.F90 @@ -46,7 +46,6 @@ module seq_hist_mod use seq_flds_mod, only: seq_flds_i2x_fields, seq_flds_r2x_fields,seq_flds_dom_fields use seq_flds_mod, only: seq_flds_l2x_fields, seq_flds_x2a_fields, seq_flds_x2i_fields use seq_flds_mod, only: seq_flds_x2l_fields, seq_flds_x2r_fields - use iMOAB, only: iMOAB_GetGlobalInfo use shr_moab_mod, only: mbGetnCells,mbGetCellTagVals use component_type_mod diff --git a/driver-moab/main/seq_io_mod.F90 b/driver-moab/main/seq_io_mod.F90 index 28fd14053c09..a50726a02eb3 100644 --- a/driver-moab/main/seq_io_mod.F90 +++ b/driver-moab/main/seq_io_mod.F90 @@ -1673,7 +1673,7 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, integer(in),target :: dimid2(2) integer(in),target :: dimid3(3) integer(in),pointer :: dimid(:) - integer(in) :: dummy, ent_type, ierr + integer(in) :: ngv, ent_type, ierr real(r8) :: lfillvalue integer, allocatable :: indx(:) ! this will be ordered integer, allocatable :: Dof(:) ! will be filled with global ids from cells @@ -1710,7 +1710,7 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, lpre = trim(dname) ! find out the number of global cells, needed for defining the variables length - ierr = iMOAB_GetGlobalInfo( mbxid, dummy, ng) + ierr = iMOAB_GetGlobalInfo( mbxid, ngv, ng) lny = 1 #ifdef MOABCOMP write(logunit,*) subname, 'lnx, lny, mbxid ', lnx, lny, mbxid @@ -1722,7 +1722,7 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then ent_type = 0 ns = nvert(1) ! local vertices - lnx = dummy ! number of global vertices + lnx = ngv ! number of global vertices else ent_type = 1 ns = nvise(1) ! local cells @@ -2693,7 +2693,7 @@ subroutine seq_io_read_moab_tags(filename, mbxid, dname, tag_list, matrix, nx) type(mct_string) :: mctOStr ! character(CXX) ::tagname, field - integer(in) :: dummy, ent_type, ierr + integer(in) :: ngv, ent_type, ierr character(*),parameter :: subName = '(seq_io_read_moab_tags) ' @@ -2726,13 +2726,13 @@ subroutine seq_io_read_moab_tags(filename, mbxid, dname, tag_list, matrix, nx) endif ! find out the number of global cells, needed for defining the variables length - ierr = iMOAB_GetGlobalInfo( mbxid, dummy, ng) + ierr = iMOAB_GetGlobalInfo( mbxid, ngv, ng) lny = 1 ! do we need 2 var, or just 1 ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then ent_type = 0 ns = nvert(1) ! local vertices - lnx = dummy ! number of global vertices + lnx = ngv ! number of global vertices else ent_type = 1 ns = nvise(1) ! local cells diff --git a/driver-moab/main/seq_rest_mod.F90 b/driver-moab/main/seq_rest_mod.F90 index 25fbad42bbf6..f20c4c0a185c 100644 --- a/driver-moab/main/seq_rest_mod.F90 +++ b/driver-moab/main/seq_rest_mod.F90 @@ -386,7 +386,7 @@ subroutine seq_rest_mb_read(rest_file, infodata, samegrid_al, samegrid_lr) integer (in), pointer :: l2racc_lm_cnt integer (in) :: nx_lnd ! will be used if land and atm are on same grid - integer (in) :: ierr, dummy + integer (in) :: ierr, ngv real(r8), dimension(:,:), pointer :: p_x2oacc_om real(r8), dimension(:,:), pointer :: p_o2racc_om @@ -453,12 +453,12 @@ subroutine seq_rest_mb_read(rest_file, infodata, samegrid_al, samegrid_lr) if (lnd_present) then if(samegrid_al) then ! nx for land will be from global nb atmosphere - ierr = iMOAB_GetGlobalInfo(mbaxid, dummy, nx_lnd) ! max id for land will come from atm + ierr = iMOAB_GetGlobalInfo(mbaxid, ngv, nx_lnd) ! max id for land will come from atm call seq_io_read(moab_rest_file, mblxid, 'fractions_lx', & 'afrac:lfrac:lfrin', nx=nx_lnd) else if(samegrid_lr) then ! nx for land will be from global nb rof - ierr = iMOAB_GetGlobalInfo(mbrxid, dummy, nx_lnd) ! max id for land will come from rof + ierr = iMOAB_GetGlobalInfo(mbrxid, ngv, nx_lnd) ! max id for land will come from rof call seq_io_read(moab_rest_file, mblxid, 'fractions_lx', & 'afrac:lfrac:lfrin', nx=nx_lnd) else ! is this ever true ? @@ -474,13 +474,13 @@ subroutine seq_rest_mb_read(rest_file, infodata, samegrid_al, samegrid_lr) p_l2racc_lm => prep_rof_get_l2racc_lm() if(samegrid_al) then ! nx for land will be from global nb atmosphere - ierr = iMOAB_GetGlobalInfo(mbaxid, dummy, nx_lnd) ! max id for land will come from atm + ierr = iMOAB_GetGlobalInfo(mbaxid, ngv, nx_lnd) ! max id for land will come from atm call seq_io_read(moab_rest_file, mblxid, 'l2racc_lx', & trim(tagname), & matrix = p_l2racc_lm, nx=nx_lnd) else if(samegrid_lr) then ! nx for land will be from global nb rof - ierr = iMOAB_GetGlobalInfo(mbrxid, dummy, nx_lnd) ! max id for land will come from rof + ierr = iMOAB_GetGlobalInfo(mbrxid, ngv, nx_lnd) ! max id for land will come from rof call seq_io_read(moab_rest_file, mblxid, 'l2racc_lx', & trim(tagname), & matrix = p_l2racc_lm, nx=nx_lnd) @@ -1013,7 +1013,7 @@ subroutine seq_rest_mb_write(EClock_d, seq_SyncClock, infodata, & integer (in), pointer :: l2racc_lm_cnt integer (in) :: nx_lnd ! will be used if land and atm are on same grid - integer (in) :: ierr, dummy + integer (in) :: ierr, ngv real(r8), dimension(:,:), pointer :: p_x2oacc_om real(r8), dimension(:,:), pointer :: p_o2racc_om @@ -1192,13 +1192,13 @@ subroutine seq_rest_mb_write(EClock_d, seq_SyncClock, infodata, & if (lnd_present) then if(samegrid_al) then ! nx for land will be from global nb atmosphere - ierr = iMOAB_GetGlobalInfo(mbaxid, dummy, nx_lnd) ! max id for land will come from atm + ierr = iMOAB_GetGlobalInfo(mbaxid, ngv, nx_lnd) ! max id for land will come from atm call seq_io_write(rest_file, mblxid, 'fractions_lx', & 'afrac:lfrac:lfrin', & ! seq_frac_mod: character(*),parameter :: fraclist_l = 'afrac:lfrac:lfrin' whead=whead, wdata=wdata, nx=nx_lnd) else if(samegrid_lr) then ! nx for land will be from global nb atmosphere - ierr = iMOAB_GetGlobalInfo(mbrxid, dummy, nx_lnd) ! max id for land will come from rof + ierr = iMOAB_GetGlobalInfo(mbrxid, ngv, nx_lnd) ! max id for land will come from rof call seq_io_write(rest_file, mblxid, 'fractions_lx', & 'afrac:lfrac:lfrin', & ! seq_frac_mod: character(*),parameter :: fraclist_l = 'afrac:lfrac:lfrin' whead=whead, wdata=wdata, nx=nx_lnd) @@ -1220,13 +1220,13 @@ subroutine seq_rest_mb_write(EClock_d, seq_SyncClock, infodata, & p_l2racc_lm => prep_rof_get_l2racc_lm() if(samegrid_al) then ! nx for land will be from global nb atmosphere - ierr = iMOAB_GetGlobalInfo(mbaxid, dummy, nx_lnd) ! max id for land will come from atm + ierr = iMOAB_GetGlobalInfo(mbaxid, ngv, nx_lnd) ! max id for land will come from atm call seq_io_write(rest_file, mblxid, 'l2racc_lx', & trim(tagname), & whead=whead, wdata=wdata, matrix = p_l2racc_lm, nx=nx_lnd) else if(samegrid_lr) then ! nx for land will be from global nb atmosphere - ierr = iMOAB_GetGlobalInfo(mbrxid, dummy, nx_lnd) ! max id for land will come from rof + ierr = iMOAB_GetGlobalInfo(mbrxid, ngv, nx_lnd) ! max id for land will come from rof call seq_io_write(rest_file, mblxid, 'l2racc_lx', & trim(tagname), & whead=whead, wdata=wdata, matrix = p_l2racc_lm, nx=nx_lnd) From 565de46d311332d7d1b1b74d05648d51eef8376d Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Wed, 8 Oct 2025 09:53:53 -0500 Subject: [PATCH 089/398] scm land case fixes introduce mb_scm_land logical it is false, except when land is identified as scm (lnd_nx and lnd_ny are both 1) it is turn on if needed in lnd moab cx init it will trigger land migrate of PC cloud, not a read from domain file also, Sa2l map will involve type vertex for land history and restart for land still have to be fixed --- driver-moab/main/cplcomp_exchange_mod.F90 | 104 +++++++++++++++------- driver-moab/main/prep_lnd_mod.F90 | 7 +- driver-moab/shr/seq_comm_mct.F90 | 1 + 3 files changed, 81 insertions(+), 31 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 95c34f3e39a5..d13630b9ce13 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -24,6 +24,7 @@ module cplcomp_exchange_mod use seq_comm_mct, only : mhpgid ! iMOAB app id for atm pgx grid, on atm pes use seq_comm_mct, only : atm_pg_active ! flag if PG mesh instanced use seq_comm_mct, only : mlnid , mblxid ! iMOAB app id for land , on land pes and coupler pes + use seq_comm_mct, only : mb_scm_land ! logical used to identify land scm case; moab will migrate land then use seq_comm_mct, only : mphaid ! iMOAB app id for phys atm; comp atm is 5, phys 5+200 use seq_comm_mct, only : MPSIID, mbixid ! sea-ice on comp pes and on coupler pes use seq_comm_mct, only : mrofid, mbrxid ! iMOAB id of moab rof app on comp pes and on coupler too @@ -1066,6 +1067,7 @@ subroutine cplcomp_moab_Init(infodata,comp) character(CXX) :: newlist integer nvert(3), nvise(3), nbl(3), nsurf(3), nvisBC(3) logical :: rof_present, lnd_prognostic + integer :: land_nx, land_ny ! try to identify if scm case; then land mesh will be migrated, not read real(r8), allocatable :: tagValues(:) ! used for setting aream tags for atm domain read case integer :: arrsize ! for the size of tagValues type(mct_list) :: temp_list @@ -1128,7 +1130,8 @@ subroutine cplcomp_moab_Init(infodata,comp) ! send mesh to coupler !!!! FULL ATM if ( trim(atm_mesh) == 'none' ) then ! full model - if (atm_pg_active) then ! change : send the pg2 mesh, not coarse mesh, when atm pg active + if (atm_pg_active) then ! change : send the point cloud phys grid mesh, not coarse mesh, + ! when atm pg active ierr = iMOAB_SendMesh(mhpgid, mpicom_join, mpigrp_cplid, id_join, partMethod) else ! still use the mhid, original coarse mesh @@ -1556,7 +1559,13 @@ subroutine cplcomp_moab_Init(infodata,comp) call seq_comm_getinfo(cplid ,mpigrp=mpigrp_cplid) ! receiver group call seq_comm_getinfo(id_old,mpigrp=mpigrp_old) ! component group pes call seq_infodata_GetData(infodata,rof_present=rof_present, lnd_prognostic=lnd_prognostic) + call seq_infodata_GetData(infodata,lnd_nx=land_nx, lnd_ny=land_ny) + if (land_nx .eq. 1 .and. land_ny .eq.1 ) then + ! turn on mb_scm_land + mb_scm_land = .true. ! we identified a scm case for land, we will migrate mesh, not read + ! the domain file anymore + endif ! use land full mesh if (MPI_COMM_NULL /= mpicom_new ) then ! we are on the coupler pes appname = "COUPLE_LAND"//C_NULL_CHAR @@ -1566,27 +1575,60 @@ subroutine cplcomp_moab_Init(infodata,comp) write(logunit,*) subname,' error in registering coupler land ' call shr_sys_abort(subname//' ERROR in registering coupler land') endif - ! do not receive the mesh anymore, read it from file, then pair it with mlnid, component land PC mesh - ! similar to rof mosart mesh - ! do not cull in case of data land, like all other data models - ! for regular land model, cull, because the lnd component culls too - if (lnd_prognostic) then - ropts = 'PARALLEL=READ_PART;PARTITION_METHOD=SQIJ;VARIABLE=;REPARTITION'//C_NULL_CHAR - else - ropts = 'PARALLEL=READ_PART;PARTITION_METHOD=SQIJ;VARIABLE=;REPARTITION;NO_CULLING'//C_NULL_CHAR - endif - call seq_infodata_GetData(infodata,lnd_domain=lnd_domain) - outfile = trim(lnd_domain)//C_NULL_CHAR - nghlay = 0 ! no ghost layers - if (seq_comm_iamroot(CPLID) ) then - write(logunit, *) "loading land domain file from file: ", trim(lnd_domain), & - " with options: ", trim(ropts) + endif + + if (mb_scm_land) then + ! change : send the point cloud land mesh (1 point usually) + ! when mb_scm_land + if (MPI_COMM_NULL /= mpicom_old ) then ! it means we are on the component pes (land) + ! send mesh to coupler then + ierr = iMOAB_SendMesh(mlnid, mpicom_join, mpigrp_cplid, id_join, partMethod) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in sending mesh from lnd comp ' + call shr_sys_abort(subname//' ERROR in sending mesh from lnd comp') + endif endif - ierr = iMOAB_LoadMesh(mblxid, outfile, ropts, nghlay) - if (ierr .ne. 0) then - write(logunit,*) subname,' error in reading land coupler mesh from ', trim(lnd_domain) - call shr_sys_abort(subname//' ERROR in reading land coupler mesh') + if (MPI_COMM_NULL /= mpicom_new ) then ! we are on the coupler pes + ierr = iMOAB_ReceiveMesh(mblxid, mpicom_join, mpigrp_old, id_old) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in receiving mesh from lnd comp ' + call shr_sys_abort(subname//' ERROR in receiving mesh from lnd comp') + endif endif + if (MPI_COMM_NULL /= mpicom_old) then ! we are on component lnd pes again, release buffers + context_id = id_join + ierr = iMOAB_FreeSenderBuffers(mlnid, context_id) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in freeing buffers ' + call shr_sys_abort(subname//' ERROR in freeing buffers ') + endif + endif + else + if (MPI_COMM_NULL /= mpicom_new ) then ! we are on the coupler pes + ! do not receive the mesh anymore, read it from file, then pair it with mlnid, component land PC mesh + ! similar to rof mosart mesh + ! do not cull in case of data land, like all other data models + ! for regular land model, cull, because the lnd component culls too + if (lnd_prognostic) then + ropts = 'PARALLEL=READ_PART;PARTITION_METHOD=SQIJ;VARIABLE=;REPARTITION'//C_NULL_CHAR + else + ropts = 'PARALLEL=READ_PART;PARTITION_METHOD=SQIJ;VARIABLE=;REPARTITION;NO_CULLING'//C_NULL_CHAR + endif + call seq_infodata_GetData(infodata,lnd_domain=lnd_domain) + outfile = trim(lnd_domain)//C_NULL_CHAR + nghlay = 0 ! no ghost layers + if (seq_comm_iamroot(CPLID) ) then + write(logunit, *) "loading land domain file from file: ", trim(lnd_domain), & + " with options: ", trim(ropts) + endif + ierr = iMOAB_LoadMesh(mblxid, outfile, ropts, nghlay) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in reading land coupler mesh from ', trim(lnd_domain) + call shr_sys_abort(subname//' ERROR in reading land coupler mesh') + endif + endif + endif + if (MPI_COMM_NULL /= mpicom_new ) then ! we are on the coupler pes ! need to add global id tag to the app, it will be used in restart tagtype = 0 ! dense, integer numco = 1 @@ -1645,22 +1687,24 @@ subroutine cplcomp_moab_Init(infodata,comp) endif ! end of coupler pes - ! we are now on joint pes, compute comm graph between lnd and coupler model - typeA = 2 ! point cloud on component PEs, land - typeB = 3 ! full mesh on coupler pes, we just read it + if (mlnid >= 0) then ierr = iMOAB_GetMeshInfo ( mlnid, nvert, nvise, nbl, nsurf, nvisBC ) - comp%mbApCCid = mlnid ! phys atm + comp%mbApCCid = mlnid ! land comp%mbGridType = typeA - 2 ! 0 or 1, pc or cells comp%mblsize = nvert(1) ! vertices endif - ierr = iMOAB_ComputeCommGraph( mlnid, mblxid, mpicom_join, mpigrp_old, mpigrp_cplid, & - typeA, typeB, id_old, id_join) - if (ierr .ne. 0) then - write(logunit,*) subname,' error in computing comm graph for lnd model ' - call shr_sys_abort(subname//' ERROR in computing comm graph for lnd model ') + if ( .not. mb_scm_land ) then + ! we are now on joint pes, compute comm graph between lnd and coupler model + typeA = 2 ! point cloud on component PEs, land + typeB = 3 ! full mesh on coupler pes, we just read it + ierr = iMOAB_ComputeCommGraph( mlnid, mblxid, mpicom_join, mpigrp_old, mpigrp_cplid, & + typeA, typeB, id_old, id_join) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in computing comm graph for lnd model ' + call shr_sys_abort(subname//' ERROR in computing comm graph for lnd model ') + endif endif - tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR call component_exch_moab(comp, mlnid, mblxid, 0, tagname, context_exch='doml') diff --git a/driver-moab/main/prep_lnd_mod.F90 b/driver-moab/main/prep_lnd_mod.F90 index bd737a1fccf5..4120b87b5bf5 100644 --- a/driver-moab/main/prep_lnd_mod.F90 +++ b/driver-moab/main/prep_lnd_mod.F90 @@ -15,6 +15,7 @@ module prep_lnd_mod use seq_comm_mct, only: mphaid ! iMOAB id for phys atm on atm pes use seq_comm_mct, only: mhpgid ! iMOAB id for atm pgx grid, on atm pes; created with se and gll grids use seq_comm_mct, only: mblxid ! iMOAB id for land migrated mesh to coupler pes + use seq_comm_mct, only: mb_scm_land ! flag that identifies PC for land; use seq_comm_mct, only: mbrxid ! iMOAB id of moab rof on coupler pes (FV now) use seq_comm_mct, only: mbintxal ! iMOAB id for intx mesh between atm and lnd use seq_comm_mct, only: mbintxrl ! iMOAB id for intx mesh between river and land @@ -594,7 +595,11 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln else type1 = 2 ! in this case, atm is just PC endif - type2 = 3; ! FV mesh on coupler land + if (mb_scm_land) then + type2 = 2 ! point cloud for land too, on coupler side; just one point, actually + else + type2 = 3; ! FV mesh on coupler land + endif ierr = iMOAB_ComputeCommGraph( mbaxid, mblxid, mpicom_CPLID, mpigrp_CPLID, mpigrp_CPLID, type1, type2, & atm(1)%cplcompid, lnd(1)%cplcompid) if (ierr .ne. 0) then diff --git a/driver-moab/shr/seq_comm_mct.F90 b/driver-moab/shr/seq_comm_mct.F90 index d48aa3e20f76..86e9e4db48c3 100644 --- a/driver-moab/shr/seq_comm_mct.F90 +++ b/driver-moab/shr/seq_comm_mct.F90 @@ -227,6 +227,7 @@ module seq_comm_mct integer, public :: mbintxao ! iMOAB id for intersection mesh between ocean and atmosphere integer, public :: mbintxoa ! iMOAB id for intersection mesh between atmosphere and ocean integer, public :: mblxid ! iMOAB id for land mesh migrated to coupler pes + logical, public :: mb_scm_land = .false. ! land will be migrated if this is true, for scm case; usually one point only !!#ifdef MOABDEBUG integer, public :: mblx2id ! iMOAB id for land mesh instanced from MCT on coupler pes integer, public :: mbox2id ! iMOAB id for ocn mesh instanced from MCT on coupler pes From cffe276793fad3b646c943fcdc516f77a2ad3ca5 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Wed, 8 Oct 2025 10:00:25 -0500 Subject: [PATCH 090/398] fix for conus case problem appeared for conus, debug mode case: SMS_D_Ln5.conusx4v1pg2_r05_IcoswISC30E3r5.F2010.chrysalis_gnu euler formula assumes there is only one connected region, when number of edges is computed HSFC does not guarantee that, especially for RRM meshes select arbitrarily 3 as more connected regions could be possible we could actually allocate much more, nedges_c to be number of quads * 4 Also, when skip match needs to be checked first, before mapid triggered in debug mode only --- components/homme/src/share/semoab_mod.F90 | 1 + driver-moab/main/seq_map_mod.F90 | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/homme/src/share/semoab_mod.F90 b/components/homme/src/share/semoab_mod.F90 index 4461c2fb39a7..0c5725edd2b2 100644 --- a/components/homme/src/share/semoab_mod.F90 +++ b/components/homme/src/share/semoab_mod.F90 @@ -530,6 +530,7 @@ subroutine create_moab_pg_mesh(par, elem, fv_nphys) ! first count the number of edges in the coarse mesh; ! use euler: v-m+f = 2 => m = v + f - 2 nedges_c = nverts_c + nelemd - 1 ! could be more, if unconnected regions ? + nedges_c = nedges_c + 3 ! assume more than one connected region if ( nedges_c < 0 ) nedges_c = 0 ! it cannot be negative internal_edges = 0 boundary_edges = 0 diff --git a/driver-moab/main/seq_map_mod.F90 b/driver-moab/main/seq_map_mod.F90 index df2489b446cd..845e5269af0b 100644 --- a/driver-moab/main/seq_map_mod.F90 +++ b/driver-moab/main/seq_map_mod.F90 @@ -112,7 +112,7 @@ subroutine seq_map_init_rcfile( mapper, comp_s, comp_d, & if (mct_gsmap_Identical(gsmap_s,gsmap_d)) then if(.not.skip_match) call seq_map_mapmatch(mapid,gsmap_s=gsmap_s,gsmap_d=gsmap_d,strategy="copy") - if (mapid > 0 .and. .not. skip_match) then + if (.not. skip_match .and. mapid > 0 ) then call seq_map_mappoint(mapid,mapper) else if(skip_match .and. seq_comm_iamroot(CPLID)) then @@ -128,7 +128,7 @@ subroutine seq_map_init_rcfile( mapper, comp_s, comp_d, & elseif (samegrid) then if(.not.skip_match) call seq_map_mapmatch(mapid,gsmap_s=gsmap_s,gsmap_d=gsmap_d,strategy="rearrange") - if (mapid > 0 .and. .not. skip_match) then + if (.not. skip_match .and. mapid > 0 ) then call seq_map_mappoint(mapid,mapper) else if(skip_match .and. seq_comm_iamroot(CPLID)) then @@ -151,7 +151,7 @@ subroutine seq_map_init_rcfile( mapper, comp_s, comp_d, & if(.not.skip_match) call seq_map_mapmatch(mapid,gsMap_s=gsMap_s,gsMap_d=gsMap_d,mapfile=mapfile,strategy=maptype) - if (mapid > 0 .and. .not. skip_match) then + if (.not. skip_match .and. mapid > 0) then call seq_map_mappoint(mapid,mapper) else if(skip_match .and. seq_comm_iamroot(CPLID)) then @@ -302,7 +302,7 @@ subroutine seq_map_init_rearrolap(mapper, comp_s, comp_d, string, no_match) if (mct_gsmap_Identical(gsmap_s,gsmap_d)) then if(.not.skip_match) call seq_map_mapmatch(mapid,gsmap_s=gsmap_s,gsmap_d=gsmap_d,strategy="copy") - if (mapid > 0 .and. .not.skip_match) then + if (.not.skip_match .and. mapid > 0) then call seq_map_mappoint(mapid,mapper) else if(skip_match .and. seq_comm_iamroot(CPLID)) then @@ -318,7 +318,7 @@ subroutine seq_map_init_rearrolap(mapper, comp_s, comp_d, string, no_match) else if(.not.skip_match) call seq_map_mapmatch(mapid,gsmap_s=gsmap_s,gsmap_d=gsmap_d,strategy="rearrange") - if (mapid > 0 .and. .not.skip_match) then + if (.not.skip_match .and. mapid > 0) then call seq_map_mappoint(mapid,mapper) else if(skip_match .and. seq_comm_iamroot(CPLID)) then From c3706f891e6b6c8478be55a71d12519ed1efdd07 Mon Sep 17 00:00:00 2001 From: Iulian Grindeanu Date: Wed, 8 Oct 2025 15:47:36 -0500 Subject: [PATCH 091/398] retrieve moab matrices only when it makes sense matrices o2x_am, used for atm merge, should not be retrieved if ocean is not active similar for ice, and xao fluxes --- driver-moab/main/prep_atm_mod.F90 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index 295efb8aeb87..a5492c58f1dd 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -1355,33 +1355,41 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) call shr_sys_abort(subname//' error in getting fractions_am from atm instance ') endif + if (mboxid > 0) then ! retrieve projection only when ox is active ? tagname = trim(seq_flds_o2x_fields)//C_NULL_CHAR arrsize = noflds * lsize ! allocate (o2x_am (lsize, noflds)) ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, o2x_am) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting o2x_am array ') endif - + endif + + if (mbixid > 0) then tagname = trim(seq_flds_i2x_fields)//C_NULL_CHAR arrsize = niflds * lsize ! allocate (i2x_am (lsize, niflds)) ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, i2x_am) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting i2x_am array ') endif + endif + if (mblxid > 0) then ! tagname = trim(seq_flds_l2x_fields)//C_NULL_CHAR arrsize = nlflds * lsize ! allocate (l2x_am (lsize, nlflds)) ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, l2x_am) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting l2x_am array ') endif + endif + if (mboxid > 0) then tagname = trim(seq_flds_xao_fields)//C_NULL_CHAR arrsize = nxflds * lsize ! allocate (xao_am (lsize, nxflds)) ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, xao_am) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting xao_om array ') endif + endif do n = 1,lsize From 551292f8fe3030dadccab004eb48b270dd7337e2 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Tue, 14 Oct 2025 14:59:19 -0500 Subject: [PATCH 092/398] Isolate atm ops in prep_rof_mrg_moab with rof_heat Ops involving a2x_rm in prep_rof_mrg_moab should only happen when rof_heat is true. --- driver-moab/main/prep_rof_mod.F90 | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/driver-moab/main/prep_rof_mod.F90 b/driver-moab/main/prep_rof_mod.F90 index 29d2be67bd82..ee68e44f99f1 100644 --- a/driver-moab/main/prep_rof_mod.F90 +++ b/driver-moab/main/prep_rof_mod.F90 @@ -1703,15 +1703,19 @@ subroutine prep_rof_mrg_moab (infodata, cime_model) ! (name of the fields) ! need these always, not only the first time l2x_r => l2r_rx(1) - a2x_r => a2r_rx(1) x2r_r => component_get_x2c_cx(rof(1)) nflds = mct_aVect_nRattr(x2r_r) ! these are saved after first time - naflds = mct_aVect_nRattr(a2x_r) + + if (rof_heat) then + a2x_r => a2r_rx(1) + naflds = mct_aVect_nRattr(a2x_r) + allocate(a2x_rm (lsize, naflds)) + endif + nlflds = mct_aVect_nRattr(l2x_r) allocate(x2r_rm (lsize, nflds)) - allocate(a2x_rm (lsize, naflds)) allocate(l2x_rm (lsize, nlflds)) ! allocate fractions too ! use the fraclist fraclist_r = 'lfrac:lfrin:rfrac' @@ -1867,11 +1871,13 @@ subroutine prep_rof_mrg_moab (infodata, cime_model) endif ! a2x_rm (lsize, naflds)) - tagname = trim(seq_flds_a2x_fields_to_rof)//C_NULL_CHAR - arrsize = naflds * lsize ! allocate (a2x_rm (lsize, naflds)) - ierr = iMOAB_GetDoubleTagStorage ( mbrxid, tagname, arrsize , ent_type, a2x_rm) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' error in getting a2x_rm array ') + if (rof_heat) then + tagname = trim(seq_flds_a2x_fields_to_rof)//C_NULL_CHAR + arrsize = naflds * lsize ! allocate (a2x_rm (lsize, naflds)) + ierr = iMOAB_GetDoubleTagStorage ( mbrxid, tagname, arrsize , ent_type, a2x_rm) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' error in getting a2x_rm array ') + endif endif ! l2x_rm tagname = trim(seq_flds_l2x_fluxes_to_rof)//C_NULL_CHAR From 2958603fa9d4f12a2210db4e8287dc2921b16f19 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Wed, 29 Oct 2025 21:46:05 -0500 Subject: [PATCH 093/398] add areafact_samegrid to component_init_areacor_moab Add areafact_samegrid to component_init_areacor_moab and when its true, set the area correction factors to 1. As done in driver-mct. --- driver-moab/main/cime_comp_mod.F90 | 10 +++--- driver-moab/main/component_mod.F90 | 56 ++++++++++++++++-------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/driver-moab/main/cime_comp_mod.F90 b/driver-moab/main/cime_comp_mod.F90 index 6a782d848e4a..ce56276fa689 100644 --- a/driver-moab/main/cime_comp_mod.F90 +++ b/driver-moab/main/cime_comp_mod.F90 @@ -2182,28 +2182,28 @@ subroutine cime_init() call mpi_barrier(mpicom_GLOID,ierr) if (atm_present) call component_init_areacor(atm, areafact_samegrid, seq_flds_a2x_fluxes) ! send initial data to coupler - if (atm_present) call component_init_areacor_moab(atm, mphaid, mbaxid, seq_flds_a2x_fluxes, seq_flds_a2x_fields) + if (atm_present) call component_init_areacor_moab(atm, areafact_samegrid, mphaid, mbaxid, seq_flds_a2x_fluxes, seq_flds_a2x_fields) ! component_exch_moab(atm(1), mphaid, mbaxid, 0, seq_flds_a2x_fields) call mpi_barrier(mpicom_GLOID,ierr) if (lnd_present) call component_init_areacor(lnd, areafact_samegrid, seq_flds_l2x_fluxes) ! MOABTODO : lnd is vertex or cell ? - if (lnd_present) call component_init_areacor_moab(lnd, mlnid, mblxid, seq_flds_l2x_fluxes, seq_flds_l2x_fields) + if (lnd_present) call component_init_areacor_moab(lnd, areafact_samegrid, mlnid, mblxid, seq_flds_l2x_fluxes, seq_flds_l2x_fields) !component_exch_moab(lnd(1), mlnid, mblxid, 0, seq_flds_l2x_fields) call mpi_barrier(mpicom_GLOID,ierr) if (rof_present) call component_init_areacor(rof, areafact_samegrid, seq_flds_r2x_fluxes) - if (rof_present) call component_init_areacor_moab(rof, mrofid, mbrxid, seq_flds_r2x_fluxes, seq_flds_r2x_fields) + if (rof_present) call component_init_areacor_moab(rof, areafact_samegrid, mrofid, mbrxid, seq_flds_r2x_fluxes, seq_flds_r2x_fields) !component_exch_moab(rof(1), mrofid, mbrxid, 0, seq_flds_r2x_fields) call mpi_barrier(mpicom_GLOID,ierr) if (ocn_present) call component_init_areacor(ocn, areafact_samegrid, seq_flds_o2x_fluxes) - if (ocn_present) call component_init_areacor_moab(ocn, mpoid, mboxid, seq_flds_o2x_fluxes, seq_flds_o2x_fields) + if (ocn_present) call component_init_areacor_moab(ocn, areafact_samegrid, mpoid, mboxid, seq_flds_o2x_fluxes, seq_flds_o2x_fields) ! component_exch_moab(ocn(1), mpoid, mboxid, 0, seq_flds_o2x_fields) call mpi_barrier(mpicom_GLOID,ierr) if (ice_present) call component_init_areacor(ice, areafact_samegrid, seq_flds_i2x_fluxes) - if (ice_present) call component_init_areacor_moab(ice, mpsiid, mbixid, seq_flds_i2x_fluxes, seq_flds_i2x_fields) + if (ice_present) call component_init_areacor_moab(ice, areafact_samegrid, mpsiid, mbixid, seq_flds_i2x_fluxes, seq_flds_i2x_fields) !component_exch_moab(ice(1), mpsiid, mbixid, 0, seq_flds_i2x_fields) call mpi_barrier(mpicom_GLOID,ierr) diff --git a/driver-moab/main/component_mod.F90 b/driver-moab/main/component_mod.F90 index 68c378e92bbb..0e81834d9691 100644 --- a/driver-moab/main/component_mod.F90 +++ b/driver-moab/main/component_mod.F90 @@ -740,7 +740,7 @@ subroutine component_init_areacor(comp, samegrid, seq_flds_c2x_fluxes) end subroutine component_init_areacor -subroutine component_init_areacor_moab (comp, mbccid, mbcxid, seq_flds_c2x_fluxes, seq_flds_c2x_fields) +subroutine component_init_areacor_moab (comp, samegrid, mbccid, mbcxid, seq_flds_c2x_fluxes, seq_flds_c2x_fields) !--------------------------------------------------------------- ! COMPONENT PES and CPL/COMPONENT (for exchange only) ! @@ -754,6 +754,7 @@ subroutine component_init_areacor_moab (comp, mbccid, mbcxid, seq_flds_c2x_fluxe ! ! Arguments type(component_type) , intent(inout) :: comp(:) + logical , intent(in) :: samegrid integer , intent(in) :: mbccid ! comp side integer , intent(in) :: mbcxid ! coupler side ! point cloud or FV type, to use vertices or cells for setting/getting the area tags and corrections @@ -790,32 +791,35 @@ subroutine component_init_areacor_moab (comp, mbccid, mbcxid, seq_flds_c2x_fluxe lsize = comp(1)%mblsize allocate(areas (lsize, 3)) ! lsize is along grid; read mask too allocate(factors (lsize, 2)) - factors = 1.0 ! initialize with 1.0 all factors; then maybe correct them - ! get areas - tagname='area:aream:mask'//C_NULL_CHAR - arrsize = 3 * lsize - ierr = iMOAB_GetDoubleTagStorage ( mbccid, tagname, arrsize , comp(1)%mbGridType, areas(1,1) ) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' cannot get areas ') - endif - ! now compute the factors - do i=1,lsize - rmask = areas(i,3) - rarea = areas(i, 1) - raream = areas(i, 2) - if ( abs(rmask) >= 1.0e-06) then - if (rarea * raream /= 0.0_R8) then - factors(i,1) = rarea/raream - factors(i,2)= 1.0_R8/factors(i,1) - else - write(logunit,*) trim(subname),' ERROR area,aream= ', & - rarea,raream,' in ',i,lsize - call shr_sys_flush(logunit) - call shr_sys_abort() - endif - endif - enddo + factors = 1.0_r8 ! initialize with 1.0 all factors; + if (.not.samegrid) then ! only correct if not monogrid (SCM case) + ! get areas + tagname='area:aream:mask'//C_NULL_CHAR + arrsize = 3 * lsize + ierr = iMOAB_GetDoubleTagStorage ( mbccid, tagname, arrsize , comp(1)%mbGridType, areas(1,1) ) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' cannot get areas ') + endif + ! now compute the factors + do i=1,lsize + rmask = areas(i,3) + + rarea = areas(i, 1) + raream = areas(i, 2) + if ( abs(rmask) >= 1.0e-06) then + if (rarea * raream /= 0.0_R8) then + factors(i,1) = rarea/raream + factors(i,2)= 1.0_R8/factors(i,1) + else + write(logunit,*) trim(subname),' ERROR area,aream= ', & + rarea,raream,' in ',i,lsize + call shr_sys_flush(logunit) + call shr_sys_abort() + endif + endif + enddo + endif ! set factors as tags ! define the tags mdl2drv and drv2mdl on component sides, and compute them based on area and aream tagname = 'mdl2drv:drv2mdl'//C_NULL_CHAR From 2ed0a1df3a01671fc5ea6f95ace8b6177ea5487a Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Sun, 2 Nov 2025 21:55:20 -0600 Subject: [PATCH 094/398] Add more handling of single column mode for land Add more handling of single column mode for land. --- driver-moab/main/cplcomp_exchange_mod.F90 | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index d13630b9ce13..ba8ee2be71e7 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -998,8 +998,8 @@ subroutine copy_aream_from_area(mbappid) ! copy aream from area if (mbappid >= 0) then ! coupler procs ierr = iMOAB_GetMeshInfo ( mbappid, nvert, nvise, nbl, nsurf, nvisBC ) - if ( (mbappid .eq. mbaxid) .and. (.not. atm_pg_active)) then - ! this is the spectral case, for atm only + if (.not.atm_pg_active) then + ! this is the spectral monogrid case arrSize = nvert(1) ! cells ent_type = 0 ! vertices else @@ -1662,11 +1662,16 @@ subroutine cplcomp_moab_Init(infodata,comp) nfields=mct_list_nitem (temp_list) if (nfields > 0) then ierr = iMOAB_GetMeshInfo ( mblxid, nvert, nvise, nbl, nsurf, nvisBC ) - arrsize = nvise(1)*nfields + if (mb_scm_land) then + arrsize = nvert(1)*nfields + ent_type = 0 ! cell + else + arrsize = nvise(1)*nfields + ent_type = 1 ! cell + endif allocate(tagValues(arrsize)) tagname = trim(newlist)//C_NULL_CHAR tagValues = 0.0_r8 - ent_type = 1 ! cells ierr = iMOAB_SetDoubleTagStorage ( mblxid, tagname, arrsize , ent_type, tagValues) if (ierr .ne. 0) then write(logunit,*) subname,' error in zeroing Flrr tags on land', ierr @@ -1691,6 +1696,8 @@ subroutine cplcomp_moab_Init(infodata,comp) if (mlnid >= 0) then ierr = iMOAB_GetMeshInfo ( mlnid, nvert, nvise, nbl, nsurf, nvisBC ) comp%mbApCCid = mlnid ! land + ! MOAB TODO: check this logic. Seems to assume typeA might be + ! 3 or 2 but only typeB has that possibility. comp%mbGridType = typeA - 2 ! 0 or 1, pc or cells comp%mblsize = nvert(1) ! vertices endif @@ -1707,6 +1714,9 @@ subroutine cplcomp_moab_Init(infodata,comp) endif tagname = 'lat:lon:area:frac:mask'//C_NULL_CHAR call component_exch_moab(comp, mlnid, mblxid, 0, tagname, context_exch='doml') + if (mblxid > 0) then ! on coupler pes only + call copy_aream_from_area(mblxid) + endif #ifdef MOABDEBUG outfile = 'recMeshLand.h5m'//C_NULL_CHAR From 2b4fd5c6a7ac6fd5fffbc4540a4276ea217201e4 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Sun, 2 Nov 2025 21:58:48 -0600 Subject: [PATCH 095/398] Cover scm for land in mb routines Also check for single column model when land mb id is passed in and set ent_type appropriately. --- driver-moab/shr/shr_moab_mod.F90 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/driver-moab/shr/shr_moab_mod.F90 b/driver-moab/shr/shr_moab_mod.F90 index b51a0def95bd..9fde5f4d5c71 100644 --- a/driver-moab/shr/shr_moab_mod.F90 +++ b/driver-moab/shr/shr_moab_mod.F90 @@ -7,7 +7,7 @@ module shr_moab_mod use shr_sys_mod, only: shr_sys_abort use seq_comm_mct, only: logunit - use seq_comm_mct, only: atm_pg_active, mbaxid + use seq_comm_mct, only: atm_pg_active, mbaxid,mb_scm_land,mblxid use shr_kind_mod, only: CXX => shr_kind_CXX use shr_kind_mod , only: R8 => SHR_KIND_R8 use iso_c_binding @@ -55,7 +55,8 @@ integer function mbGetnCells(moabid) endif ! only case on coupler side that we actually want number of vertices is when we use spectral atm - if ( .not. atm_pg_active .and. mbaxid .eq. moabid) then + if ((.not. atm_pg_active .and. (mbaxid .eq. moabid)) .or. & + (mb_scm_land .and. (mblxid .eq. moabid))) then mbGetnCells = nvert(1) else mbGetnCells = nvise(1) @@ -90,8 +91,8 @@ subroutine mbGetCellTagVals(mbid, intag,inarray,nMax) character(*), parameter :: subname = '(mbGetCellTagVals) ' !----------------------------------------------------------------------- ! - - if ( .not. atm_pg_active .and. mbaxid .eq. mbid) then + if ((.not. atm_pg_active .and. (mbaxid .eq. mbid)) .or. & + (mb_scm_land .and. (mblxid .eq. mbid))) then ent_type = 0 else ent_type = 1 @@ -134,7 +135,8 @@ subroutine mbSetCellTagVals(mbid, intag,inarray,nMax) !----------------------------------------------------------------------- ! - if ( .not. atm_pg_active .and. mbaxid .eq. mbid) then + if ((.not. atm_pg_active .and. (mbaxid .eq. mbid)) .or. & + (mb_scm_land .and. (mblxid .eq. mbid))) then ent_type = 0 else ent_type = 1 From 1625e42db0ef73f5250d68ad21c6ecc610e6de61 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Sun, 2 Nov 2025 22:00:54 -0600 Subject: [PATCH 096/398] Zero Si_snowh for single_column In single_column case, zero out Si_snowh to match eam history with driver-mct --- driver-moab/main/prep_atm_mod.F90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index a5492c58f1dd..52bd01820347 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -1046,6 +1046,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) integer :: n,ka,ki,kl,ko,kx,kof,kif,klf,klf_st,i,i1,o1 integer, save :: lsize integer, save :: index_x2a_Sf_lfrac, index_x2a_Sf_ifrac, index_x2a_Sf_ofrac + integer, save :: index_x2a_Si_snowh character(CL) :: atm_gnam, lnd_gnam character(CL) :: fracstr, fracstr_st @@ -1076,6 +1077,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) integer nvert(3), nvise(3), nbl(3), nsurf(3), nvisBC(3) ! for moab info character(CXX) ::tagname, mct_field integer :: ent_type, ierr, arrsize + logical :: single_column #ifdef MOABDEBUG character*32 :: outfile, wopts, lnum #endif @@ -1090,6 +1092,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) !----------------------------------------------------------------------- ! call seq_comm_getdata(CPLID, iamroot=iamroot) + call seq_infodata_getdata(infodata,single_column=single_column) if (first_time) then @@ -1122,6 +1125,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) index_x2a_Sf_lfrac = mct_aVect_indexRA(x2a_a,'Sf_lfrac') index_x2a_Sf_ifrac = mct_aVect_indexRA(x2a_a,'Sf_ifrac') index_x2a_Sf_ofrac = mct_aVect_indexRA(x2a_a,'Sf_ofrac') + index_x2a_Si_snowh = mct_aVect_indexRA(x2a_a,'Si_snowh') !ngflds = mct_aVect_nRattr(g2x_o) allocate(fractions_am(lsize,5)) ! there are 5 fractions 'afrac:ifrac:ofrac:lfrac:lfrin' @@ -1396,6 +1400,8 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) x2a_am(n, index_x2a_Sf_lfrac) = fractions_am(n, klf) ! x2a_a%rAttr(index_x2a_Sf_lfrac,n) = fractions_a%Rattr(klf,n) x2a_am(n, index_x2a_Sf_ifrac) = fractions_am(n, kif) ! x2a_a%rAttr(index_x2a_Sf_ifrac,n) = fractions_a%Rattr(kif,n) x2a_am(n, index_x2a_Sf_ofrac) = fractions_am(n, kof) ! x2a_a%rAttr(index_x2a_Sf_ofrac,n) = fractions_a%Rattr(kof,n) + ! zero out Si_snowh for single column to match MCT + if(single_column) x2a_am(n, index_x2a_Si_snowh) = 0.0_r8 end do !--- document fraction operations --- From 7cbd583c250d2eac1bf66d4e3bea928abc2625be Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 3 Nov 2025 10:56:19 -0600 Subject: [PATCH 097/398] Set ent_type correctly for scm land Set ent_type correctly for scm land --- driver-moab/main/seq_io_mod.F90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/driver-moab/main/seq_io_mod.F90 b/driver-moab/main/seq_io_mod.F90 index a50726a02eb3..c03d525ba18e 100644 --- a/driver-moab/main/seq_io_mod.F90 +++ b/driver-moab/main/seq_io_mod.F90 @@ -33,7 +33,7 @@ module seq_io_mod use shr_sys_mod, only: shr_sys_abort use seq_comm_mct, only: logunit, CPLID, seq_comm_setptrs use seq_comm_mct, only: seq_comm_namelen, seq_comm_name - use seq_comm_mct, only: mbaxid, atm_pg_active + use seq_comm_mct, only: mbaxid, atm_pg_active,mblxid,mb_scm_land use seq_flds_mod, only : seq_flds_lookup use mct_mod ! mct wrappers use pio @@ -1719,7 +1719,8 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, ! get the local size ns ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) - if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then + if ((.not. atm_pg_active .and. (mbaxid .eq. mbxid)) .or. & + (mb_scm_land .and. (mblxid .eq. mbxid))) then ent_type = 0 ns = nvert(1) ! local vertices lnx = ngv ! number of global vertices @@ -2729,7 +2730,8 @@ subroutine seq_io_read_moab_tags(filename, mbxid, dname, tag_list, matrix, nx) ierr = iMOAB_GetGlobalInfo( mbxid, ngv, ng) lny = 1 ! do we need 2 var, or just 1 ierr = iMOAB_GetMeshInfo ( mbxid, nvert, nvise, nbl, nsurf, nvisBC ) - if (mbxid .eq. mbaxid .and. .not. atm_pg_active) then + if ((.not. atm_pg_active .and. (mbaxid .eq. mbxid)) .or. & + (mb_scm_land .and. (mblxid .eq. mbxid))) then ent_type = 0 ns = nvert(1) ! local vertices lnx = ngv ! number of global vertices From 5602ce070529cef3ddf9142db268e552c96d757a Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 3 Nov 2025 10:57:31 -0600 Subject: [PATCH 098/398] Set ent_type correctly with land is single column Set ent_type correctly with land is in single column mode for section that zeros river variables. --- driver-moab/main/prep_lnd_mod.F90 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/driver-moab/main/prep_lnd_mod.F90 b/driver-moab/main/prep_lnd_mod.F90 index 4120b87b5bf5..b73080a10f3a 100644 --- a/driver-moab/main/prep_lnd_mod.F90 +++ b/driver-moab/main/prep_lnd_mod.F90 @@ -22,6 +22,7 @@ module prep_lnd_mod use seq_comm_mct, only: mbaxid ! iMOAB id for atm migrated mesh to coupler pes use seq_comm_mct, only: atm_pg_active ! whether the atm uses FV mesh or not ; made true if fv_nphys > 0 + use seq_comm_mct, only: mb_scm_land ! use dimensions_mod, only: np ! for atmosphere use seq_comm_mct, only: seq_comm_getinfo => seq_comm_setptrs use seq_map_type_mod @@ -400,9 +401,15 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln write(logunit,*) subname,' cant get size of land mesh' call shr_sys_abort(subname//' ERROR in getting size of land mesh') endif - ! land is now cell mesh on coupler side - mlsize = nvise(1) - ent_type = 1 ! cell + ! land is usually cell on coupler but could be point + if(mb_scm_land) then + mlsize = nvert(1) + ent_type = 0 ! point cloud + else + mlsize = nvise(1) + ent_type = 1 ! cell + endif + ! set to 0 all fields that are projected from river nrflds = mct_aVect_nRattr(r2x_lx(1)) ! these are the numbers of fields in seq_flds_r2x_fields arrsize = nrflds*mlsize From f5909dacdfc31bbff143caa50e5435c1d7126fa0 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Wed, 5 Nov 2025 20:10:16 -0600 Subject: [PATCH 099/398] Change how mb_scm_land is set Use single_column and scm_multcol to determine if mb_scm_land should be set. DP case will not have land_nx=land_ny=1 --- driver-moab/main/cplcomp_exchange_mod.F90 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index ba8ee2be71e7..ee6e6dda2f7a 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -1066,8 +1066,7 @@ subroutine cplcomp_moab_Init(infodata,comp) character(CXX) :: tagname character(CXX) :: newlist integer nvert(3), nvise(3), nbl(3), nsurf(3), nvisBC(3) - logical :: rof_present, lnd_prognostic - integer :: land_nx, land_ny ! try to identify if scm case; then land mesh will be migrated, not read + logical :: rof_present, lnd_prognostic, single_column, scm_multcols real(r8), allocatable :: tagValues(:) ! used for setting aream tags for atm domain read case integer :: arrsize ! for the size of tagValues type(mct_list) :: temp_list @@ -1559,9 +1558,9 @@ subroutine cplcomp_moab_Init(infodata,comp) call seq_comm_getinfo(cplid ,mpigrp=mpigrp_cplid) ! receiver group call seq_comm_getinfo(id_old,mpigrp=mpigrp_old) ! component group pes call seq_infodata_GetData(infodata,rof_present=rof_present, lnd_prognostic=lnd_prognostic) - call seq_infodata_GetData(infodata,lnd_nx=land_nx, lnd_ny=land_ny) - - if (land_nx .eq. 1 .and. land_ny .eq.1 ) then + call seq_infodata_GetData(infodata,single_column=single_column, & + scm_multcols=scm_multcols) + if (single_column .or. scm_multcols) then ! turn on mb_scm_land mb_scm_land = .true. ! we identified a scm case for land, we will migrate mesh, not read ! the domain file anymore From b14022a866566e3a082917235d630f73651cd279 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Fri, 7 Nov 2025 14:36:52 -0600 Subject: [PATCH 100/398] Set mbGridType to 0 for mlnid Set mbGridType to 0 for mlnid. Some code was moved for the scm case which broke the calculation that was here. --- driver-moab/main/cplcomp_exchange_mod.F90 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index ee6e6dda2f7a..e14aadcb2dbd 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -1695,9 +1695,7 @@ subroutine cplcomp_moab_Init(infodata,comp) if (mlnid >= 0) then ierr = iMOAB_GetMeshInfo ( mlnid, nvert, nvise, nbl, nsurf, nvisBC ) comp%mbApCCid = mlnid ! land - ! MOAB TODO: check this logic. Seems to assume typeA might be - ! 3 or 2 but only typeB has that possibility. - comp%mbGridType = typeA - 2 ! 0 or 1, pc or cells + comp%mbGridType = 0 ! 0 or 1, pc or cells comp%mblsize = nvert(1) ! vertices endif if ( .not. mb_scm_land ) then From 131c17bdab9d3dc9a2520b2a6d7145a33cc4259c Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Sun, 9 Nov 2025 23:19:54 -0600 Subject: [PATCH 101/398] Make sure areas are initialized in areacor Make sure areas are initialized in areacor by moving the iMOAB_GetDouble call that does it outside of the if(.not.samegrid) block. aream is needed later. --- driver-moab/main/component_mod.F90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/driver-moab/main/component_mod.F90 b/driver-moab/main/component_mod.F90 index 0e81834d9691..18a80bfcc1bb 100644 --- a/driver-moab/main/component_mod.F90 +++ b/driver-moab/main/component_mod.F90 @@ -793,14 +793,14 @@ subroutine component_init_areacor_moab (comp, samegrid, mbccid, mbcxid, seq_flds allocate(factors (lsize, 2)) factors = 1.0_r8 ! initialize with 1.0 all factors; + ! get areas + tagname='area:aream:mask'//C_NULL_CHAR + arrsize = 3 * lsize + ierr = iMOAB_GetDoubleTagStorage ( mbccid, tagname, arrsize , comp(1)%mbGridType, areas(1,1) ) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' cannot get areas ') + endif if (.not.samegrid) then ! only correct if not monogrid (SCM case) - ! get areas - tagname='area:aream:mask'//C_NULL_CHAR - arrsize = 3 * lsize - ierr = iMOAB_GetDoubleTagStorage ( mbccid, tagname, arrsize , comp(1)%mbGridType, areas(1,1) ) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' cannot get areas ') - endif ! now compute the factors do i=1,lsize rmask = areas(i,3) @@ -819,7 +819,7 @@ subroutine component_init_areacor_moab (comp, samegrid, mbccid, mbcxid, seq_flds endif endif enddo - endif + endif ! if .not.samegrid ! set factors as tags ! define the tags mdl2drv and drv2mdl on component sides, and compute them based on area and aream tagname = 'mdl2drv:drv2mdl'//C_NULL_CHAR From fdf5cdbaf291c2a2143090132d282dd0ae4c1eca Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Sun, 9 Nov 2025 23:40:33 -0600 Subject: [PATCH 102/398] In atm merge, make sure arrays for other components are initialized xao_am, l2x_am, i2x_am, and o2x_am are only set using GetDouble if the corresponding model is present. For at least o2x_am, it was still used in a merge even if not present. So 0 those arrays if the corresponding moab app id is not set. This zero's the Faoo_h2otemp field for the moab coupler. --- driver-moab/main/prep_atm_mod.F90 | 62 ++++++++++++++++--------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index 52bd01820347..17b6a1105d4e 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -1360,40 +1360,48 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) endif if (mboxid > 0) then ! retrieve projection only when ox is active ? - tagname = trim(seq_flds_o2x_fields)//C_NULL_CHAR - arrsize = noflds * lsize ! allocate (o2x_am (lsize, noflds)) - ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, o2x_am) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' error in getting o2x_am array ') - endif + tagname = trim(seq_flds_o2x_fields)//C_NULL_CHAR + arrsize = noflds * lsize ! allocate (o2x_am (lsize, noflds)) + ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, o2x_am) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' error in getting o2x_am array ') + endif + else + o2x_am(:,:)=0.0_r8 endif if (mbixid > 0) then - tagname = trim(seq_flds_i2x_fields)//C_NULL_CHAR - arrsize = niflds * lsize ! allocate (i2x_am (lsize, niflds)) - ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, i2x_am) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' error in getting i2x_am array ') + tagname = trim(seq_flds_i2x_fields)//C_NULL_CHAR + arrsize = niflds * lsize ! allocate (i2x_am (lsize, niflds)) + ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, i2x_am) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' error in getting i2x_am array ') + endif + else + i2x_am(:,:)=0.0_r8 endif - endif if (mblxid > 0) then ! - tagname = trim(seq_flds_l2x_fields)//C_NULL_CHAR - arrsize = nlflds * lsize ! allocate (l2x_am (lsize, nlflds)) - ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, l2x_am) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' error in getting l2x_am array ') + tagname = trim(seq_flds_l2x_fields)//C_NULL_CHAR + arrsize = nlflds * lsize ! allocate (l2x_am (lsize, nlflds)) + ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, l2x_am) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' error in getting l2x_am array ') + endif + else + l2x_am(:,:)=0.0_r8 endif - endif if (mboxid > 0) then - tagname = trim(seq_flds_xao_fields)//C_NULL_CHAR - arrsize = nxflds * lsize ! allocate (xao_am (lsize, nxflds)) - ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, xao_am) - if (ierr .ne. 0) then - call shr_sys_abort(subname//' error in getting xao_om array ') + tagname = trim(seq_flds_xao_fields)//C_NULL_CHAR + arrsize = nxflds * lsize ! allocate (xao_am (lsize, nxflds)) + ierr = iMOAB_GetDoubleTagStorage ( mbaxid, tagname, arrsize , ent_type, xao_am) + if (ierr .ne. 0) then + call shr_sys_abort(subname//' error in getting xao_om array ') + endif + else + xao_am(:,:)=0.0_r8 endif - endif do n = 1,lsize @@ -1456,12 +1464,6 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) enddo endif ! first time - ! we need to do something equivalent, to copy in a2x_am the tags from those shared indices - ! call mct_aVect_copy(aVin=l2x_a, aVout=x2a_a, vector=mct_usevector, sharedIndices=l2x_SharedIndices) - !call mct_aVect_copy(aVin=o2x_a, aVout=x2a_a, vector=mct_usevector, sharedIndices=o2x_SharedIndices) - !call mct_aVect_copy(aVin=i2x_a, aVout=x2a_a, vector=mct_usevector, sharedIndices=i2x_SharedIndices) - !call mct_aVect_copy(aVin=xao_a, aVout=x2a_a, vector=mct_usevector, sharedIndices=xao_SharedIndices) - ! If flux to atm is coming only from the ocean (based on field being in o2x_a) - ! -- then scale by both ocean and ice fraction ! If flux to atm is coming only from the land or ice or coupler From dd582214e8e1f52d33cf4823c27e568c25997258 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Tue, 11 Nov 2025 22:58:35 -0600 Subject: [PATCH 103/398] Make sure land fluxes are zero when no land model 'Fall_' fluxes that are not merged have to be set to 0 in MOAB when there's no land model. Otherwise they will keep the default value. Found while testing the aquaplanet case and dust fluxes were -1e+10 --- driver-moab/main/prep_atm_mod.F90 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index 17b6a1105d4e..7937568f2b12 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -1077,7 +1077,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) integer nvert(3), nvise(3), nbl(3), nsurf(3), nvisBC(3) ! for moab info character(CXX) ::tagname, mct_field integer :: ent_type, ierr, arrsize - logical :: single_column + logical :: single_column,lnd_present #ifdef MOABDEBUG character*32 :: outfile, wopts, lnum #endif @@ -1092,7 +1092,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) !----------------------------------------------------------------------- ! call seq_comm_getdata(CPLID, iamroot=iamroot) - call seq_infodata_getdata(infodata,single_column=single_column) + call seq_infodata_getdata(infodata,single_column=single_column,lnd_present=lnd_present) if (first_time) then @@ -1531,6 +1531,13 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) end if end if endif + ! if no land, make sure any 'Fall' fluxes that are not merged are 0. + ! e.g. dust fluxes + if(.not.lnd_present) then + if((lindx(ka)>0) .and. .not.lstate(ka) .and. .not.lmerge(ka)) then + x2a_am(n,ka) = 0.0_r8 + endif + endif if (iindx(ka) > 0 .and. fraci > 0._r8) then if (imerge(ka)) then x2a_am(n, ka) = x2a_am(n, ka) + i2x_am(n, iindx(ka)) * fraci From 65275427e5298414fdcb1cab04042f97b978151b Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Thu, 20 Nov 2025 14:55:03 -0600 Subject: [PATCH 104/398] Add DTESTM case to moab ERS and PEM suites. Add DTESTM case to moab ERS and PEM suites. Will fail until sequencing fix added. --- cime_config/tests.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cime_config/tests.py b/cime_config/tests.py index 8594d96bdf13..304227e0b871 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -893,6 +893,7 @@ "ERS_Vmoab_Ld3.ne4pg2_ne4pg2.I1850CNPRDCTCBCTOP", "ERS_Vmoab_Ld3.T62_oQU240wLI.GMPAS-IAF", "ERS_Vmoab_Ld3.T62_oQU120.CMPASO-NYF", + "ERS_Vmoab_Ld3.T62_oQU240.DTESTM", "ERS_Vmoab_Ld3.r05_r05.RMOSGPCC", "ERS_Vmoab_Ld3.ne4pg2_ne4pg2.F2010-SCREAMv1", ) @@ -908,6 +909,7 @@ "PEM_Vmoab_Ld3.ne4pg2_ne4pg2.I1850CNPRDCTCBCTOP", "PEM_Vmoab_Ld3.T62_oQU240wLI.GMPAS-IAF", "PEM_Vmoab_Ld3.T62_oQU120.CMPASO-NYF", + "PEM_Vmoab_Ld3.T62_oQU240.DTESTM", "PEM_Vmoab_Ld3.r05_r05.RMOSGPCC", "PEM_Vmoab_Ld3.ne4pg2_ne4pg2.F2010-SCREAMv1", ) From b7fad162e8268bb230ae70a7dbe0f0fd559e89ca Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Tue, 25 Nov 2025 01:15:05 -0600 Subject: [PATCH 105/398] Switch back to using create_moab_meshes Remove create_moab_pg_mesh (which was supposed to pair with create_moab_spectral_mesh) and just use the original creae_moab_meshes which has the same code. Add in the fix for rrm meshes and the fix for the vnode_c call to ResolveSharedEntities --- components/eam/src/dynamics/se/dyn_comp.F90 | 4 +- components/homme/src/share/semoab_mod.F90 | 750 +------------------- 2 files changed, 7 insertions(+), 747 deletions(-) diff --git a/components/eam/src/dynamics/se/dyn_comp.F90 b/components/eam/src/dynamics/se/dyn_comp.F90 index b2e04cc21adf..faff6ffd314b 100644 --- a/components/eam/src/dynamics/se/dyn_comp.F90 +++ b/components/eam/src/dynamics/se/dyn_comp.F90 @@ -106,7 +106,7 @@ subroutine dyn_init1(fh, NLFileName, dyn_in, dyn_out) use seq_comm_mct, only: MHID, MHFID ! id of homme moab coarse and fine applications use seq_comm_mct, only: ATMID use seq_comm_mct, only: mhpgid ! id of pgx moab application - use semoab_mod, only: create_moab_pg_mesh + use semoab_mod, only: create_moab_meshes use iMOAB, only : iMOAB_RegisterApplication use iso_c_binding #endif @@ -269,7 +269,7 @@ subroutine dyn_init1(fh, NLFileName, dyn_in, dyn_out) end if #ifdef HAVE_MOAB - call create_moab_pg_mesh(par, elem, fv_nphys) + call create_moab_meshes(par, elem, fv_nphys) #endif ! Define the CAM grids (this has to be after dycore spinup). ! Physics-grid will be defined later by phys_grid_init diff --git a/components/homme/src/share/semoab_mod.F90 b/components/homme/src/share/semoab_mod.F90 index 0c5725edd2b2..29b496076eee 100644 --- a/components/homme/src/share/semoab_mod.F90 +++ b/components/homme/src/share/semoab_mod.F90 @@ -76,749 +76,6 @@ integer function search_in(intarr, leng, value) end function search_in - subroutine create_moab_pg_mesh(par, elem, fv_nphys) - - use ISO_C_BINDING - use iMOAB, only: iMOAB_CreateVertices, iMOAB_WriteMesh, iMOAB_CreateElements, & - iMOAB_ResolveSharedEntities, iMOAB_UpdateMeshInfo, iMOAB_DefineTagStorage, & - iMOAB_SetIntTagStorage, iMOAB_ReduceTagsMax, iMOAB_GetIntTagStorage - use coordinate_systems_mod, only : cartesian3D_t, spherical_to_cart, spherical_polar_t - - type (element_t), intent(inout) :: elem(:) - type (parallel_t) , intent(in) :: par - integer , intent(in) :: fv_nphys - - integer ierr, i, j, ie, iv, block_ID, k, numvals - integer icol, irow, je, linx ! local indices in fine el connect - - real(kind=real_kind), allocatable :: moab_vert_coords(:) - - integer moab_dim_cquads, ix, idx, nverts, nverts_c ! used for indexing in loops; nverts will have the number of local vertices - - integer nelemd2 ! do not confuse this with dimensions_mod::nelemd - - integer(kind=long_kind), dimension(:), allocatable :: gdofv - ! this will be moab vertex handle locally - integer, dimension(:), allocatable :: moabvh - integer, dimension(:), allocatable :: indx ! this will be ordered - - integer, dimension(:), allocatable :: vdone, elemids, vgids, gdofel - integer, dimension(:), allocatable :: vdone_c, moabconn_c, moabvh_c - integer currentval, dimcoord, dimen, num_el, mbtype, nve - - character*100 outfile, wopts, localmeshfile, lnum, tagname, newtagg - integer tagtype, numco, tag_sto_len, ent_type, tagindex - type (cartesian3D_t) :: cart - integer igcol, ii, neigh - - integer nedges_c, nverts_pg, nelem_pg, edge_index, j1 - integer, dimension(:), allocatable :: local_cell_gids, indx_cell - integer, dimension(:,:), allocatable :: elem_edge, edge - integer, dimension(:), allocatable :: vdone_pg, moabconn_pg - - integer nat_edge_order(4) - integer internal_edges, boundary_edges, reverse_edges - integer edge_verts(4) ! local per coarse element ! nverts_c < edge_verts <= nverts_c + edge_index - integer middle_vertex ! nverts_c + edge_index < middle_vertex <= verts_pg - type (spherical_polar_t) :: current_2d_vertex - logical pos_edge ! when looping over edges , use gdof for marking !! - - nat_edge_order = (/south, east, north, west/) - - ! for np=4, - ! 28, 32, 36, 35 - ! 25, 29, 33, 34 - ! j | 13, 17, 21, 22 - ! 1, 5, 9, 10 - !(1,1) i-> - - ! character*100 outfile, wopts, localmeshfile, lnum, tagname - ! integer tagtype, numco, tag_sto_len, ent_type, tagindex - do j=1,np-1 - do i =1, np-1 - ix = (j-1)*(np-1)+i-1 - local_map(i,j) = ix*4 + 1 - enddo - enddo - do j=1, np-1 - i = j - local_map(np, j) = ((np-1)*j-1)*4 + 2 - local_map(i, np) = ( (np-1)*(np-2)+i-1)*4 + 4 - enddo - local_map(np, np) = ((np-1)*(np-1)-1)*4 + 3 - - nelemd2 = (nelemd)*(np-1)*(np-1) - moab_dim_cquads = (nelemd)*4*(np-1)*(np-1) - - if(par%masterproc) then - write (iulog, *) " MOAB: semoab_mod module: create_moab_mesh_fine; on processor " , par%rank ," nelemd: " , nelemd - endif - - if ( nelemd > 0 ) then - allocate(gdofv(moab_dim_cquads)) - allocate(elemids(nelemd2)) - endif - - k=0 ! will be the index for element global dofs - do ie=1,nelemd - do j=1,np-1 - do i=1,np-1 - ix = (ie-1)*(np-1)*(np-1)+(j-1)*(np-1)+i-1 - gdofv(ix*4+1) = elem(ie)%gdofP(i,j) - gdofv(ix*4+2) = elem(ie)%gdofP(i+1,j) - gdofv(ix*4+3) = elem(ie)%gdofP(i+1,j+1) - gdofv(ix*4+4) = elem(ie)%gdofP(i,j+1) - elemids(ix+1) = (elem(ie)%GlobalId-1)*(np-1)*(np-1)+(j-1)*(np-1)+i - enddo - enddo - enddo - -! order according to global dofs - - if ( nelemd > 0 ) then - allocate(moabvh(moab_dim_cquads)) - allocate(indx(moab_dim_cquads)) - - allocate(moabconn(moab_dim_cquads)) - call IndexSet(moab_dim_cquads, indx) - call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) -! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) - endif - idx=0 - currentval = 0 - if ( nelemd > 0 ) then - currentval = gdofv( indx(1)) - idx = 1 - endif - - do ix=1,moab_dim_cquads - if (gdofv(indx(ix)) .ne. currentval ) then - idx=idx+1 - currentval = gdofv(indx(ix)) - endif - moabvh(ix) = idx ! the vertex in connectivity array will be at this local index - ! this will be the moab connectivity - moabconn(indx(ix)) = idx - enddo - - nverts = idx - if(par%masterproc) then - write (iulog, *) " MOAB: there are ", nverts, " local vertices on master task ", currentval, " is the max local gdof" - endif - if ( nelemd > 0 ) then - allocate(moab_vert_coords(3*nverts) ) - allocate(vdone(nverts)) - else - allocate(vdone(1)) ! will be passed to iMOAB_ResolveSharedEnts, and compilers are complaining about non-allocated arrays - endif - vdone = 0; - if ( nelemd > 0 ) currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices - - do ix=1,moab_dim_cquads - idx = indx(ix) ! index in initial array, vertices in all fine quads - k = (idx-1)/(4*(np-1)*(np-1)) ! index of coarse quad, locally, starts at 0 - ie = 1 + k ! this is the element number; starts at nets=1 - je = ( idx -1 -k*(np-1)*(np-1)*4 ) / 4 + 1 ! local fine quad in coarse, 1 to (np-1) ^ 2 - irow = (je-1)/(np-1)+1 - icol = je - (np-1)*(irow-1) - linx = idx - k*(np-1)*(np-1)*4 -(je-1)*4 ! this should be 1, 2, 3, 4 - if( linx == 1) then - j = irow - i = icol - else if (linx == 2) then - j = irow - i = icol + 1 - else if (linx == 3) then - j = irow + 1 - i = icol + 1 - else ! linx == 4 - j = irow + 1 - i = icol - endif - - iv = moabvh(ix) - if (vdone(iv) .eq. 0) then - cart = spherical_to_cart (elem(ie)%spherep(i,j) ) - moab_vert_coords ( 3*(iv-1)+1 ) = cart%x - moab_vert_coords ( 3*(iv-1)+2 ) = cart%y - moab_vert_coords ( 3*(iv-1)+3 ) = cart%z - vdone(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities ! convert to int, from long int - endif - - enddo - - dimcoord = nverts*3 - dimen = 3 - if ( nelemd > 0 ) then - ierr = iMOAB_CreateVertices(MHFID, dimcoord, dimen, moab_vert_coords) - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB vertices ') - endif - !!num_el = nelemd2 - mbtype = 3 ! quadrilateral - nve = 4; - block_ID = 200 ! this will be for coarse mesh - - if ( nelemd > 0 ) then - ierr = iMOAB_CreateElements( MHFID, nelemd2, mbtype, nve, moabconn, block_ID ); - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB elements') - endif - ! nverts: num vertices; vdone will store now the markers used in global resolve - ! for this particular problem, markers are the global dofs at corner nodes -! set the global id for vertices -! first, retrieve the tag - tagname='GDOF'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = 1 - ierr = iMOAB_DefineTagStorage(MHFID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve global id tag') - ! now set the values - ent_type = 0 ! vertex type - if ( nverts > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHFID, tagname, nverts , ent_type, vdone) - if (ierr > 0 ) & - call abortmp('Error: fail to set marker id tag for vertices') - endif - - ! we need to call this even when no mesh locally, it involves a collective - ierr = iMOAB_ResolveSharedEntities( MHFID, nverts, vdone ); - if (ierr > 0 ) & - call abortmp('Error: fail to resolve shared entities') - - if ( nelemd > 0) then - vdone = -1 ! reuse vdone for the new tag, GLOBAL_ID (actual tag that we want to store global dof ) - endif -! use element offset for actual global dofs - ! tagtype = 0 ! dense, integer - ! numco = 1 - newtagg='GLOBAL_ID'//C_NULL_CHAR - ierr = iMOAB_DefineTagStorage(MHFID, newtagg, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to create new GDOF tag') - do ie=1,nelemd - do ii=1,elem(ie)%idxp%NumUniquePts - i=elem(ie)%idxp%ia(ii) - j=elem(ie)%idxp%ja(ii) - igcol = elem(ie)%idxp%UniquePtoffset+ii-1 - ix = local_map(i,j) - idx = moabconn((ie-1)*(np-1)*(np-1)*4 + ix) ! should - vdone ( idx ) = igcol - end do - end do - ! now set the values - ent_type = 0 ! vertex type - if ( nverts > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vdone) - if (ierr > 0 ) & - call abortmp('Error: fail to set global dof tag for vertices') - endif - - ierr = iMOAB_ReduceTagsMax ( MHFID, tagindex, ent_type) - if (ierr > 0 ) & - call abortmp('Error: fail to reduce max tag') - - ! set global id tag for elements - ent_type = 1 ! now set the global id tag on elements - if ( nelemd2 > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHFID, newtagg, nelemd2 , ent_type, elemids) - if (ierr > 0 ) & - call abortmp('Error: fail to set global id tag for elements') - endif - -! now, after reduction, we can get the actual global ids for each vertex in the fine mesh -! before, some vertices that were owned in MOAB but not owned in CAM did not have the right global ID tag -! so vdone will be now correct on every task (no -1 anymore ) - ent_type = 0 ! vertex type - if ( nverts > 0 ) then - allocate(vgids(nverts)) - ierr = iMOAB_GetIntTagStorage ( MHFID, newtagg, nverts , ent_type, vgids) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GLOBAL ID on each task') - endif - ierr = iMOAB_UpdateMeshInfo(MHFID) - if (ierr > 0 ) & - call abortmp('Error: fail to update mesh info') -#ifdef MOABDEBUG -! write out the mesh file to disk, in parallel - outfile = 'wholeFineATM.h5m'//C_NULL_CHAR - wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR - ierr = iMOAB_WriteMesh(MHFID, outfile, wopts) - if (ierr > 0 ) & - call abortmp('Error: fail to write the mesh file') -#endif - - -! now create the coarse mesh, but the global dofs will come from fine mesh, after solving - ! nelemd2 = nelemd - moab_dim_cquads = (nelemd)*4 - - if ( nelemd > 0 ) then - allocate(gdofel(nelemd*np*np)) - endif - k=0 ! will be the index for element global dofs - do ie=1,nelemd - ix = ie-1 - ! - gdofv(ix*4+1) = elem(ie)%gdofP(1,1) - gdofv(ix*4+2) = elem(ie)%gdofP(np,1) - gdofv(ix*4+3) = elem(ie)%gdofP(np,np) - gdofv(ix*4+4) = elem(ie)%gdofP(1,np) - elemids(ix+1) = elem(ie)%GlobalId - enddo -! now original order - -! order according to global dofs -! allocate(indx(moab_dim_cquads)) - if ( nelemd > 0 ) then - call IndexSet(moab_dim_cquads, indx) - call IndexSort(moab_dim_cquads, indx, gdofv, descend=.false.) -! after sort, gdofv( indx(i)) < gdofv( indx(i+1) ) - - allocate(moabvh_c(moab_dim_cquads)) - - allocate(moabconn_c(moab_dim_cquads)) - endif - idx = 0 - if ( nelemd > 0 ) then - idx=1 - currentval = gdofv( indx(1)) - endif - do ix=1,moab_dim_cquads - if (gdofv(indx(ix)) .ne. currentval ) then - idx=idx+1 - currentval = gdofv(indx(ix)) - endif - moabvh_c(ix) = idx ! the vertex in connectivity array will be at this local index - ! this will be the moab connectivity - moabconn_c(indx(ix)) = idx - enddo - nverts_c = idx - if(par%masterproc) then - write (iulog, *) " MOAB: there are ", nverts_c, " local vertices on master task, coarse mesh" - endif -! allocate(moab_vert_coords(3*idx) ) - if ( nelemd > 0 ) then - allocate(vdone_c(nverts_c)) - vdone_c = 0; - currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices - endif - - do ix=1,moab_dim_cquads - i = indx(ix) ! index in initial array - ie = 1+ (i-1)/4 ! this is the element number - j = i - ( i-1)/4*4 ! local index of vertex in element i - iv = moabvh_c(ix) - if (vdone_c(iv) .eq. 0) then - moab_vert_coords ( 3*(iv-1)+1 ) = elem(ie)%corners3d(j)%x - moab_vert_coords ( 3*(iv-1)+2 ) = elem(ie)%corners3d(j)%y - moab_vert_coords ( 3*(iv-1)+3 ) = elem(ie)%corners3d(j)%z - vdone_c(iv) = gdofv(indx(ix)) ! this will be now our tag used for resolving shared entities - endif - - enddo - - dimcoord = nverts_c*3 - dimen = 3 - if ( nverts_c > 0 ) then - ierr = iMOAB_CreateVertices(MHID, dimcoord, dimen, moab_vert_coords) - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB vertices ') - endif - ! num_el = nelemd - mbtype = 3 ! quadrilateral - nve = 4; - block_ID = 100 ! this will be for coarse mesh - - if ( nelemd > 0 ) then - ierr = iMOAB_CreateElements( MHID, nelemd, mbtype, nve, moabconn_c, block_ID ); - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB elements') - endif - ! idx: num vertices; vdone will store now the markers used in global resolve - ! for this particular problem, markers are the global dofs at corner nodes -! set the global id for vertices -! first, retrieve the tag - tagname='GDOFV'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = 1 - ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GDOFV id tag') - ierr = iMOAB_DefineTagStorage(MHID, newtagg, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GLOBAL_ID tag on coarse mesh') - ! now set the values - ent_type = 0 ! vertex type - if ( nverts_c > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, tagname, nverts_c , ent_type, vdone_c) - if (ierr > 0 ) & - call abortmp('Error: fail to set GDOFV tag for vertices') - endif - ! set global id tag for coarse elements, too; they will start at nets=1, end at nete=nelemd - ent_type = 1 ! now set the global id tag on elements - if ( nelemd > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nelemd , ent_type, elemids) - if (ierr > 0 ) & - call abortmp('Error: fail to set global id tag for vertices') - endif - - ierr = iMOAB_ResolveSharedEntities( MHID, idx, vdone_c ); - if (ierr > 0 ) & - call abortmp('Error: fail to resolve shared entities') - -! global dofs are the GLL points are set for each element - tagname='GLOBAL_DOFS'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = np*np ! usually, it is 16; each element will have the dofs in order - ierr = iMOAB_DefineTagStorage(MHID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to create global DOFS tag') - ! now set the values - ! set global dofs tag for coarse elements, too; they will start at nets=1, end at nete=nelemd - ent_type = 1 ! now set the global id tag on elements - numvals = nelemd*np*np ! input is the total number of values - ! form gdofel from vgids - do ie=1, nelemd - ix = (ie-1)*np*np ! ie: index in coarse element - je = (ie-1) * 4 * (np-1) * (np -1) ! index in moabconn array - ! vgids are global ids for fine vertices (1,nverts) - iv = 1 - do j=1,np - do i=1,np - k = local_map(i,j) - gdofel(ix+iv) = vgids( moabconn( je + k ) ) - iv = iv + 1 - enddo - enddo - ! extract global ids - vdone_c( moabconn_c( (ie-1)*4+1) ) = vgids ( moabconn(je+1 )) - vdone_c( moabconn_c( (ie-1)*4+2) ) = vgids ( moabconn(je+ 4*(np-2)+2 )) ! valid for np = 4, 10 - vdone_c( moabconn_c( (ie-1)*4+3) ) = vgids ( moabconn(je+ 4*((np-1)*(np-1)-1) + 3 )) ! for np = 4, 35 - vdone_c( moabconn_c( (ie-1)*4+4) ) = vgids ( moabconn(je+ 4*(np-2)*(np-1) + 4 )) ! 28 for np = 4 - enddo - if ( nelemd > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, tagname, numvals, ent_type, gdofel) - if (ierr > 0 ) & - call abortmp('Error: fail to set globalDOFs tag for coarse elements') - endif - - ! set the global ids for coarse vertices the same as corresponding fine vertices - ent_type = 0 ! vertex type - if ( nverts_c > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHID, newtagg, nverts_c , ent_type, vdone_c) - if (ierr > 0 ) & - call abortmp('Error: fail to set GLOBAL_DOFS tag values') - endif - - ierr = iMOAB_UpdateMeshInfo(MHID) - if (ierr > 0 ) & - call abortmp('Error: fail to update mesh info') -#ifdef MOABDEBUG -! write out the mesh file to disk, in parallel - outfile = 'wholeATM.h5m'//C_NULL_CHAR - wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR - ierr = iMOAB_WriteMesh(MHID, outfile, wopts) - if (ierr > 0 ) & - call abortmp('Error: fail to write the mesh file') -#endif - - if (fv_nphys > 0 ) then - ! create FV mesh, base on PGx - atm_pg_active = .true. ! from now on, we will migrate / send tags for FV / ATM_PG2 mesh - ! first count the number of edges in the coarse mesh; - ! use euler: v-m+f = 2 => m = v + f - 2 - nedges_c = nverts_c + nelemd - 1 ! could be more, if unconnected regions ? - nedges_c = nedges_c + 3 ! assume more than one connected region - if ( nedges_c < 0 ) nedges_c = 0 ! it cannot be negative - internal_edges = 0 - boundary_edges = 0 - reverse_edges = 0 - nelem_pg = fv_nphys * fv_nphys * nelemd ! each coarse cell is divided in fv_nphys x fv_nphys subcells - ! - ! there are new vertices on each coarse edge (fv_phys - 1) , and (fv_nphys - 1) * (fv_nphys - 1) - ! new vertices on each coarse cell - if ( nelemd > 0 ) then - allocate (local_cell_gids(nelemd)) - allocate (indx_cell(nelemd)) - allocate (edge(2,nedges_c)) ! - endif - do ie=1, nelemd ! - local_cell_gids(ie) = elem(ie)%GlobalID - enddo - if ( nelemd > 0 ) then - call IndexSet(nelemd, indx_cell) - call IndexSort(nelemd, indx_cell, local_cell_gids, descend=.false.) - ! print *, ' local_cell_gids ', local_cell_gids - ! print *, ' indx_cell ', indx_cell - allocate( elem_edge (4, nelemd) ) - ! print *, '------------------------------- ' - ! print *, "RANK:", par%rank - endif - edge_index = 0 - do ie=1, nelemd ! - ! we need to check if neighbor is with id smaller; that means it was already created ? - ! print *, '-------------- ' - ! print *, ' elem ', ie, elem(ie)%desc%actual_neigh_edges, elem(ie)%vertex%number, elem(ie)%GlobalID - ! print *, ' nodes ', ( moabconn_c( (ie-1)*4+j), j=1,4 ) - ! print *, ' ids ', (vdone_c( moabconn_c( (ie-1)*4+j) ), j=1,4) - ! print *, ' neigh: ', (elem(ie)%desc%globalID(j), j=1,4) - ! print *, ' neigh order ', ( elem(ie)%desc%globalID(nat_edge_order(j)),j = 1,4 ) - k = elem(ie)%GlobalID ! current id - do j = 1,4 - ix = j+1 - if (ix .eq. 5) ix = 1 ! next vertex in connectivity array - neigh = elem(ie)%desc%globalID(nat_edge_order(j)) ! id neighbor - idx = search_in(local_cell_gids, nelemd, neigh) ! index in local cells - ! print *, ' ', j, 'neigh:', neigh, ' index' , idx - - if ( idx .gt. 0 ) then - ! a local edge is interior - - if (k < neigh) then ! form the edge, increment edge index - edge_index = edge_index + 1 - edge(1, edge_index) = moabconn_c(4*(ie-1) + j) ! first vertex - edge(2, edge_index) = moabconn_c(4*(ie-1) + ix) ! second vertex index - elem_edge(j, ie) = edge_index - internal_edges = internal_edges + 1 - ! print *, ' edge:', edge_index, edge(1, edge_index), edge(2, edge_index), 'verts:' , & - ! vdone_c(edge(1, edge_index)), vdone_c(edge(2, edge_index)), ' element ', ie, ' intedge:', internal_edges - - else - ! find the edge in the other list elem(idx)%globalID( nat_edge_order(j) ) - do j1 = 1,4 - if ( elem(idx)%desc%globalID( nat_edge_order(j1) ) .eq. k ) then - elem_edge(j, ie) = - elem_edge(j1, idx) ! inverse oriented - reverse_edges = reverse_edges + 1 - ! print *, ' negative edge: ', elem_edge(j, ie), edge(1, -elem_edge(j, ie)), edge(2, -elem_edge(j, ie)), & - ! 'verts:', vdone_c(edge(1, -elem_edge(j, ie))), vdone_c(edge(2, -elem_edge(j, ie))), 'indx neg', reverse_edges - endif - enddo - - endif - else ! idx is 0, so it means the edge is on the boundary, form it - edge_index = edge_index + 1 - edge(1, edge_index) = moabconn_c(4*(ie-1) + j) ! first vertex - edge(2, edge_index) = moabconn_c(4*(ie-1) + ix) ! second vertex index - elem_edge(j, ie) = edge_index - boundary_edges = boundary_edges + 1 - ! print *, ' edge:', edge_index, edge(1, edge_index), edge(2, edge_index), 'verts:' , & - ! vdone_c(edge(1, edge_index)), vdone_c(edge(2, edge_index)), ' element ', ie, & - ! ' bedge:', boundary_edges - endif - enddo - enddo - ! show off - nverts_pg = nverts_c + (fv_nphys - 1) * edge_index + (fv_nphys - 1) * (fv_nphys - 1) * nelemd - ! print *, " MOAB: there are ", nverts_pg, " local vertices on master task on pg mesh ", edge_index , " local coarse edges ", & - ! boundary_edges , ' boundary edges ' - if(par%masterproc) then - write (iulog, *) " MOAB: there are ", nverts_pg, " local vertices on master task on pg mesh ", edge_index , " local coarse edges " - endif - !print *, '\n ELEMENTS: ' - !do ie=1,nelemd - ! print *, ie, elem(ie)%GlobalID, ' local nodes:', ( moabconn_c( (ie-1)*4+j), j=1,4 ), ' edges:', (elem_edge(j, ie), j=1,4) - !enddo - !print *, '\n EDGES:' - !do ie=1,edge_index - ! print *, ie, (edge(j, ie), j=1,2) - !enddo - ! now generate phys grid, uniform FV type mesh; - ! 2 cases: fv_nphys is 1 or 2; when 2, we need new nodes; will use the same id as - ! the gdof on edge is used, with the smaller id chosen, among - if ( nelemd > 0 ) then - allocate(moabconn_pg(4*nelem_pg)) ! connectivity - ! reuse moab_vert_coords for coordinates of pg mesh - ! the first nverts_c coords are the same as coarse mesh; but we do create new - allocate(vdone_pg(nverts_pg)) - else - allocate(vdone_pg(1)) - endif - do iv = 1, nverts_c - vdone_pg(iv) = vdone_c(iv) ! also the coordinates will be the same !! - enddo - - ! copy the coordinates from the middle - j1 = 0 ! index in edge vertices; increase only for positive edges - ! still need some - if (fv_nphys .eq. 2) then - current_2d_vertex%r = 1. - do ie = 1,nelemd - ix = (ie-1)*np*np ! ie: index in coarse element - do j=1,4 - idx = elem_edge(j, ie) ! - if (idx .gt. 0) then ! increment edges, add vertex ! - j1 = j1 + 1 ! index in moab_vert_coords for edges ! nverts_c + j1 for vertex edges ! - ! current_2d_vertex%lat, current_2d_vertex%lon - pos_edge = .true. - iv = nverts_c + j1 - edge_verts(j) = iv ! to form the local connectivity array - if ( vdone_c(edge(1, idx)) .gt. vdone_c(edge(2, idx)) ) pos_edge = .false. - if (j .eq. 1) then - call gfr_f_get_corner_latlon(ie, 1, 1, 2, current_2d_vertex%lat, current_2d_vertex%lon) - if (pos_edge) then - vdone_pg (iv) = gdofel(ix + 2) ! elem(ie)%gdofP(2,1) ! gdofel(ix+ (j-1)*np + i) - else - vdone_pg (iv) = gdofel(ix + np - 1) !elem(ie)%gdofP(np-1,1) ! - endif - else if (j .eq. 2) then - call gfr_f_get_corner_latlon(ie, 2, 1, 3, current_2d_vertex%lat, current_2d_vertex%lon) - if (pos_edge) then - vdone_pg (iv) = gdofel(ix + (2 - 1) * np + np)!elem(ie)%gdofP(np,2) ! ! gdofel(ix+ (j-1)*np + i) - else - vdone_pg (iv) = gdofel(ix + (np - 2) * np + np)!elem(ie)%gdofP(np,np - 1) ! - endif - else if (j .eq. 3) then - call gfr_f_get_corner_latlon(ie, 2, 2, 4, current_2d_vertex%lat, current_2d_vertex%lon) - if (pos_edge) then - vdone_pg (iv) = gdofel(ix+ (np - 1) * np + np - 1)!elem(ie)%gdofP(np-1,np) ! - else - vdone_pg (iv) = gdofel(ix+ (np-1)*np + 2) !elem(ie)%gdofP(2,np) ! - endif - else ! if (j .eq. 4) - call gfr_f_get_corner_latlon(ie, 1, 2, 1, current_2d_vertex%lat, current_2d_vertex%lon) - if (pos_edge) then - vdone_pg (iv) = gdofel(ix+ (np - 2)*np + 1) !elem(ie)%gdofP(1,np-1) ! - else - vdone_pg (iv) = gdofel(ix+ ( 2 - 1 )*np + 1) ! elem(ie)%gdofP(1,2) ! - endif - endif - ! create the 3d vertex ! - cart = spherical_to_cart (current_2d_vertex ) - moab_vert_coords ( 3*(iv-1)+1 ) = cart%x - moab_vert_coords ( 3*(iv-1)+2 ) = cart%y - moab_vert_coords ( 3*(iv-1)+3 ) = cart%z - ! print *, 'ie, j, iv, vdone_pg(iv): ', ie, j, iv, vdone_pg(iv) - else ! the vertex was already created, but we need the index for connectivity of local fv cells - edge_verts(j) = nverts_c + ( -idx ) ! idx is index of edge (negative for already created) - endif - - enddo ! do j=1,4 - ! create the middle vertex too, in the center - call gfr_f_get_corner_latlon(ie, 1, 1, 3, current_2d_vertex%lat, current_2d_vertex%lon) - iv = nverts_c + edge_index + ie ! middle vertices are after corners, and edge vertices - middle_vertex = iv - vdone_pg (middle_vertex) = gdofel(ix+ np + 2)!elem(ie)%gdofP(2,2) ! first in the interior, not on edges! - ! print *, 'ie, middle = iv, vdone_pg(iv): ', ie, iv, vdone_pg(iv) - cart = spherical_to_cart (current_2d_vertex ) - moab_vert_coords ( 3*(iv-1)+1 ) = cart%x - moab_vert_coords ( 3*(iv-1)+2 ) = cart%y - moab_vert_coords ( 3*(iv-1)+3 ) = cart%z - - ! now form the local 2x2 cells, one by one; set the global id tag too! - idx = (ie-1)*4 - ix = idx * 4 ! - ! first - moabconn_pg(ix + 1) = moabconn_c(4*(ie-1)+1) - moabconn_pg(ix + 2) = edge_verts(1) - moabconn_pg(ix + 3) = middle_vertex - moabconn_pg(ix + 4) = edge_verts(4) - elemids(idx+1) = (elem(ie)%GlobalId-1)*4+1 - ! second - moabconn_pg(ix + 4 + 1) = edge_verts(1) - moabconn_pg(ix + 4 + 2) = moabconn_c(4*(ie-1)+2) - moabconn_pg(ix + 4 + 3) = edge_verts(2) - moabconn_pg(ix + 4 + 4) = middle_vertex - elemids(idx+2) = (elem(ie)%GlobalId-1)*4+2 - ! third - moabconn_pg(ix + 8 + 1) = edge_verts(4) - moabconn_pg(ix + 8 + 2) = middle_vertex - moabconn_pg(ix + 8 + 3) = edge_verts(3) - moabconn_pg(ix + 8 + 4) = moabconn_c(4*(ie-1)+4) - elemids(idx+3) = (elem(ie)%GlobalId-1)*4+3 - ! fourth - moabconn_pg(ix + 12 + 1) = middle_vertex - moabconn_pg(ix + 12 + 2) = edge_verts(2) - moabconn_pg(ix + 12 + 3) = moabconn_c(4*(ie-1)+3) - moabconn_pg(ix + 12 + 4) = edge_verts(3) - elemids(idx+4) = (elem(ie)%GlobalId-1)*4+4 - - enddo - ! now copy from coarse for pg mesh - - dimcoord = nverts_pg*3 - dimen = 3 - if ( nverts_pg > 0 ) then - ierr = iMOAB_CreateVertices(MHPGID, dimcoord, dimen, moab_vert_coords) - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB vertices ') - endif - ! num_el = nelem_pg * - mbtype = 3 ! quadrilateral - nve = 4; - block_ID = 300 ! this will be for pg mesh - - if ( nelem_pg > 0 ) then - ierr = iMOAB_CreateElements( MHPGID, nelem_pg, mbtype, nve, moabconn_pg, block_ID ); - if (ierr > 0 ) & - call abortmp('Error: fail to create MOAB elements') - endif - tagname='GLOBAL_ID'//C_NULL_CHAR - tagtype = 0 ! dense, integer - numco = 1 - ierr = iMOAB_DefineTagStorage(MHPGID, tagname, tagtype, numco, tagindex ) - if (ierr > 0 ) & - call abortmp('Error: fail to retrieve GLOBAL id tag') - - ! now set the values - ent_type = 0 ! vertex type - if ( nverts_pg > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHPGID, tagname, nverts_pg , ent_type, vdone_pg) - if (ierr > 0 ) & - call abortmp('Error: fail to set global id tag for vertices') - endif - ! set global id tag for pg2 elements, too; they will start at nets=1, end at nete=nelemd*4 - ent_type = 1 ! now set the global id tag on elements - if ( nelem_pg > 0 ) then - ierr = iMOAB_SetIntTagStorage ( MHPGID, tagname, nelem_pg , ent_type, elemids) - if (ierr > 0 ) & - call abortmp('Error: fail to set global id tag for edges') - endif - - ! this involves a collective, vdone_pg can be empty - ierr = iMOAB_ResolveSharedEntities( MHPGID, nverts_pg, vdone_pg ); - if (ierr > 0 ) & - call abortmp('Error: fail to resolve shared ents for pg2 mesh') - - ierr = iMOAB_UpdateMeshInfo(MHPGID) - if (ierr > 0 ) & - call abortmp('Error: fail to update mesh info for pg2 mesh') -#ifdef MOABDEBUG - ! write out the mesh file to disk, in parallel - outfile = 'wholeATM_PG2.h5m'//C_NULL_CHAR - wopts = 'PARALLEL=WRITE_PART'//C_NULL_CHAR - ierr = iMOAB_WriteMesh(MHPGID, outfile, wopts) - if (ierr > 0 ) & - call abortmp('Error: fail to write the mesh file') -#endif - endif ! only valid for pg == 2 - if ( nelemd > 0 ) then - deallocate (local_cell_gids) - deallocate (indx_cell) - deallocate (edge) ! - deallocate(moabconn_pg) ! connectivity - endif - deallocate(vdone_pg) ! this is now always allocated/deallocated, even for no mesh here - endif - - ! deallocate - if ( nelemd > 0 ) then - deallocate(moabvh) - deallocate(moabconn) ! do not keep it anymore, we are not setting another tag on fine mesh - deallocate(gdofel) - deallocate(indx) - deallocate(elemids) - deallocate(gdofv) - deallocate(moabvh_c) - deallocate(moabconn_c) - deallocate(vdone_c) - endif - deallocate(vdone) ! we are always allocating this now -! end copy - - end subroutine create_moab_pg_mesh - subroutine create_moab_meshes(par, elem, fv_nphys) use ISO_C_BINDING @@ -1144,9 +401,11 @@ subroutine create_moab_meshes(par, elem, fv_nphys) ! allocate(moab_vert_coords(3*idx) ) if ( nelemd > 0 ) then allocate(vdone_c(nverts_c)) - vdone_c = 0; - currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices + else + allocate(vdone_c(1)) ! will be passed to iMOAB_ResolveSharedEnts, and compilers are complaining about non-allocated arrays endif + vdone_c = 0 + if ( nelemd > 0 ) currentval = gdofv( indx(1)) ! start over to identify coordinates of the vertices do ix=1,moab_dim_cquads i = indx(ix) ! index in initial array @@ -1273,6 +532,7 @@ subroutine create_moab_meshes(par, elem, fv_nphys) ! first count the number of edges in the coarse mesh; ! use euler: v-m+f = 2 => m = v + f - 2 nedges_c = nverts_c + nelemd - 1 ! could be more, if unconnected regions ? + nedges_c = nedges_c + 3 ! assume more than one connected region if ( nedges_c < 0 ) nedges_c = 0 ! it cannot be negative internal_edges = 0 boundary_edges = 0 From 3a4842c336f4bde8e41b465768f0aec613445b3b Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Mon, 24 Nov 2025 19:36:37 -0800 Subject: [PATCH 106/398] Marks if grid cell vertices are duplciate The vertices of each grid cells are marked as duplicate or not. The duplicate vertices are skipped when the code tries to identify vertices of edges that are common between two grid cells. --- .../elm/src/data_types/MOABGridType.F90 | 64 +++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/components/elm/src/data_types/MOABGridType.F90 b/components/elm/src/data_types/MOABGridType.F90 index 1e01c85016c2..63026a015695 100644 --- a/components/elm/src/data_types/MOABGridType.F90 +++ b/components/elm/src/data_types/MOABGridType.F90 @@ -47,31 +47,32 @@ module MOABGridType integer, parameter :: max_num_neighbor = 10 type, public :: grid_cell - integer :: num_owned ! number of owned "active" grid cells - integer :: num_ghost ! number of ghost "active" grid cells - integer :: num_ghosted ! number of owned + ghost "active" grid cells - integer :: num_global ! number of global "active" grid cells + integer :: num_owned ! number of owned "active" grid cells + integer :: num_ghost ! number of ghost "active" grid cells + integer :: num_ghosted ! number of owned + ghost "active" grid cells + integer :: num_global ! number of global "active" grid cells - integer, pointer :: natural_id(:) ! [num_ghosted] ID of cell in the full mesh, while accounting for active and inactive cells - logical, pointer :: is_owned(:) ! [num_ghosted] true if the grid cell locally owned - integer, pointer :: owner_rank(:) ! [num_ghosted] MPI rank that owns the cell + integer, pointer :: natural_id(:) ! [num_ghosted] ID of cell in the full mesh, while accounting for active and inactive cells + logical, pointer :: is_owned(:) ! [num_ghosted] true if the grid cell locally owned + integer, pointer :: owner_rank(:) ! [num_ghosted] MPI rank that owns the cell - integer, pointer :: num_neighbor (:) ! [num_ghosted] number of neighboring grid cells - integer, pointer :: neighbor_id(:,:) ! [num_ghosted, max_num_neighbor] ghosted ID of neighboring grid cells + integer, pointer :: num_neighbor (:) ! [num_ghosted] number of neighboring grid cells + integer, pointer :: neighbor_id(:,:) ! [num_ghosted, max_num_neighbor] ghosted ID of neighboring grid cells - integer, pointer :: num_vertex(:) ! [num_ghosted] number of vertices - integer, pointer :: vertex_id(:,:) ! [num_ghosted, max_num_neigbor] IDs of vertices + integer, pointer :: num_vertex(:) ! [num_ghosted] number of vertices + integer, pointer :: vertex_id(:,:) ! [num_ghosted, max_num_neigbor] IDs of vertices - real(r8), pointer :: lat(:) ! [num_ghosted] latitude of the cell - real(r8), pointer :: lon(:) ! [num_ghosted] longitude of the cell + real(r8), pointer :: lat(:) ! [num_ghosted] latitude of the cell + real(r8), pointer :: lon(:) ! [num_ghosted] longitude of the cell - integer :: nv ! length of 'nv' dimension in the mesh - real(r8), pointer :: latv(:,:) ! [num_ghosted, nv] latitude of cell vertices - real(r8), pointer :: lonv(:,:) ! [num_ghosted, nv] longitude of cell vertices + integer :: nv ! length of 'nv' dimension in the mesh + real(r8), pointer :: latv(:,:) ! [num_ghosted, nv] latitude of cell vertices + real(r8), pointer :: lonv(:,:) ! [num_ghosted, nv] longitude of cell vertices + logical, pointer :: is_vert_duplicate(:,:) ! [num_ghosted, nv] is a duplicate vertex - integer, pointer :: elm2moab(:) ! [num_ghosted] for ELM's grid cell given by g (where begg <= g <= endg), - ! return the correponding MOAB grid cell 'i' (where 1 <= i <= num_ghosted) - integer, pointer :: moab2elm(:) ! [num_ghosted] vice-versa of elm2moab + integer, pointer :: elm2moab(:) ! [num_ghosted] for ELM's grid cell given by g (where begg <= g <= endg), + ! return the correponding MOAB grid cell 'i' (where 1 <= i <= num_ghosted) + integer, pointer :: moab2elm(:) ! [num_ghosted] vice-versa of elm2moab end type grid_cell type, public :: grid_vertex @@ -429,6 +430,9 @@ subroutine read_grid_cell_lat_lon() integer :: ierr integer :: ni, nj, dimid, count real(r8), pointer :: data2d(:,:) + integer :: v1, v2 + real(r8) :: dist + real(r8), parameter :: dist_threshold = 1.e-10 ierr = pio_openfile(pio_subsystem, ncid, io_type, trim(fatmlndfrc), PIO_NOWRITE) if (ierr /= pio_noerr) then @@ -528,6 +532,9 @@ subroutine read_grid_cell_lat_lon() allocate(moab_gcell%lonv(moab_gcell%num_ghosted, moab_gcell%nv)) allocate(data2d(moab_gcell%nv, moab_gcell%num_ghosted)) + allocate(moab_gcell%is_vert_duplicate(moab_gcell%num_ghosted, moab_gcell%nv)) + moab_gcell%is_vert_duplicate(:,:) = .false. + varname = 'xv' ierr = pio_inq_varid(ncid, trim(varname), varid) if (ierr /= pio_noerr) then @@ -593,6 +600,19 @@ subroutine read_grid_cell_lat_lon() call pio_closefile(ncid) deallocate(compdof) + ! mark vertices that are duplicate + do g = 1, moab_gcell%num_ghosted + do v1 = 1, moab_gcell%nv - 1 + do v2 = 2, moab_gcell%nv + dist = (moab_gcell%lonv(g, v1) - moab_gcell%lonv(g, v2))**2._r8 + & + (moab_gcell%latv(g, v1) - moab_gcell%latv(g, v2))**2._r8 + if (dist < dist_threshold) then + moab_gcell%is_vert_duplicate(g, v2) = .true. + endif + end do + end do + end do + end subroutine read_grid_cell_lat_lon !------------------------------------------------------------------------------ @@ -618,10 +638,16 @@ subroutine set_internal_edge_lat_lon() vertex_count = 0 do v1 = 1, moab_gcell%nv + ! if the vertex is duplicate, skip it + if (moab_gcell%is_vert_duplicate(gup, v1)) cycle + latv_up = moab_gcell%latv(gup, v1) lonv_up = moab_gcell%lonv(gup, v1) do v2 = 1, moab_gcell%nv + ! if the vertex is duplicate, skip it + if (moab_gcell%is_vert_duplicate(gdn, v2)) cycle + latv_dn = moab_gcell%latv(gdn, v2) lonv_dn = moab_gcell%lonv(gdn, v2) From 5f0fe3e5aec0d8e0d8f726d6ebd392baa85f4016 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Tue, 25 Nov 2025 18:14:42 -0600 Subject: [PATCH 107/398] Make sure eamxx calls create_moab_meshes Change the eamxx call from create_moab_pg_meshes to create_moab_meshes. --- .../eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 b/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 index b4989b0e40fc..67ac681f5b12 100644 --- a/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 +++ b/components/eamxx/src/dynamics/homme/interface/phys_grid_mod.F90 @@ -552,7 +552,7 @@ subroutine phys_grid_init (pgN) use seq_comm_mct, only: MHID, MHFID ! id of homme moab coarse and fine applications use seq_comm_mct, only: ATMID use seq_comm_mct, only: mhpgid ! id of pgx moab application - use semoab_mod, only: create_moab_pg_mesh + use semoab_mod, only: create_moab_meshes use iMOAB, only : iMOAB_RegisterApplication use iso_c_binding #endif @@ -662,7 +662,7 @@ subroutine phys_grid_init (pgN) ! 1 ) spectral coarse mesh ! 2 ) GLL fine quad mesh (used mostly for visualization) ! 3 ) pgN FV type mesh, (most of the time pg2 mesh), used for coupling with other components; - call create_moab_pg_mesh(par, elem, pgN) + call create_moab_meshes(par, elem, pgN) endif #endif end subroutine phys_grid_init From 83038020395582caca2b87ac9ce08084c1a02a4a Mon Sep 17 00:00:00 2001 From: Vijay Mahadevan Date: Thu, 27 Nov 2025 15:20:59 -0600 Subject: [PATCH 108/398] Remove unnecessary MOABConfig.h includes from Fortran --- components/data_comps/docn/src/docn_comp_mod.F90 | 1 - driver-moab/main/cplcomp_exchange_mod.F90 | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/components/data_comps/docn/src/docn_comp_mod.F90 b/components/data_comps/docn/src/docn_comp_mod.F90 index 025f13d2c8b7..f8ef2b2ba86d 100644 --- a/components/data_comps/docn/src/docn_comp_mod.F90 +++ b/components/data_comps/docn/src/docn_comp_mod.F90 @@ -127,7 +127,6 @@ subroutine docn_comp_init(Eclock, x2o, o2x, & use pio , only : iosystem_desc_t use shr_pio_mod, only : shr_pio_getiosys, shr_pio_getiotype #ifdef HAVE_MOAB -#include "moab/MOABConfig.h" use iMOAB, only: iMOAB_DefineTagStorage, iMOAB_GetDoubleTagStorage, & iMOAB_SetIntTagStorage, iMOAB_SetDoubleTagStorage, & iMOAB_ResolveSharedEntities, iMOAB_CreateVertices, & diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index e14aadcb2dbd..866543ee2a4c 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -35,7 +35,6 @@ module cplcomp_exchange_mod implicit none private ! except #include -#include "moab/MOABConfig.h" save !-------------------------------------------------------------------------- @@ -1086,12 +1085,10 @@ subroutine cplcomp_moab_Init(infodata,comp) mpicom_old = comp%mpicom_compid mpicom_join = comp%mpicom_cplcompid - partMethod = 0 ! trivial partitioning + ! partMethod = 0 ! trivial partitioning + partMethod = 2 ! it is better to use RCB for atmosphere and ocean (needs MOAB_HAVE_ZOLTAN) context_id = -1 ! original sends/receives, so the context is -1 ! needed only to free send buffers -#ifdef MOAB_HAVE_ZOLTAN - partMethod = 2 ! it is better to use RCB for atmosphere and ocean too -#endif call seq_comm_getinfo(ID_old ,mpicom=mpicom_old) call seq_comm_getinfo(ID_new ,mpicom=mpicom_new) @@ -1115,7 +1112,6 @@ subroutine cplcomp_moab_Init(infodata,comp) ! find atm mesh/domain file if it exists; it would be for data atm model (atm_prognostic false) call seq_infodata_GetData(infodata,atm_mesh = atm_mesh) - !!!!!!!! ON ATM COMPONENT if (mphaid >= 0) then ! component atm procs ierr = iMOAB_GetMeshInfo ( mphaid, nvert, nvise, nbl, nsurf, nvisBC ) From 2942f23fd9a54fc0ea65243b964092d44c2c25db Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 30 Nov 2025 19:54:31 -0600 Subject: [PATCH 109/398] Disables creating ELM grid cells using MOAB --- components/elm/src/main/elm_finalizeMod.F90 | 2 +- components/elm/src/main/elm_initializeMod.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/src/main/elm_finalizeMod.F90 b/components/elm/src/main/elm_finalizeMod.F90 index c2cb1b099ce7..70ea70e23a22 100644 --- a/components/elm/src/main/elm_finalizeMod.F90 +++ b/components/elm/src/main/elm_finalizeMod.F90 @@ -42,7 +42,7 @@ subroutine final( ) ! #ifdef HAVE_MOAB - call elm_moab_finalize() + !call elm_moab_finalize() #endif #ifdef USE_PETSC_LIB diff --git a/components/elm/src/main/elm_initializeMod.F90 b/components/elm/src/main/elm_initializeMod.F90 index 43e124372c83..73158d198b81 100755 --- a/components/elm/src/main/elm_initializeMod.F90 +++ b/components/elm/src/main/elm_initializeMod.F90 @@ -1271,7 +1271,7 @@ subroutine elm_moab_interface_init()!(bounds) call elm_moab_initialize() ! load the mesh file for ELM - call elm_moab_load_grid_file(fatmlndfrc) + !call elm_moab_load_grid_file(fatmlndfrc) end subroutine elm_moab_interface_init #endif From 33cf8c1d6bc31fc3d821d02d7358002813a0daa9 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Sun, 30 Nov 2025 21:51:35 -0600 Subject: [PATCH 110/398] Add comments and clean white space Add comments, some from review, and remove some tabs. --- driver-moab/main/cime_comp_mod.F90 | 18 +++++++++++++----- driver-moab/main/cplcomp_exchange_mod.F90 | 12 ++++++------ driver-moab/main/prep_atm_mod.F90 | 8 ++++---- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/driver-moab/main/cime_comp_mod.F90 b/driver-moab/main/cime_comp_mod.F90 index ce56276fa689..4975d767622c 100644 --- a/driver-moab/main/cime_comp_mod.F90 +++ b/driver-moab/main/cime_comp_mod.F90 @@ -3091,9 +3091,9 @@ subroutine cime_run() !---------------------------------------------------------- !| ATM/OCN SETUP (rasm_option1) + ! map i,w to ocean, calc atmocn fluxes, do merge, accum, + ! calc ocn albedos !---------------------------------------------------------- - ! The following maps to the ocean, computes atm/ocn fluxes, merges to the ocean, - ! accumulates ocn input and computes ocean albedos if (ocn_present) then if (trim(cpl_seq_option) == 'RASM_OPTION1') then call cime_run_atmocn_setup(hashint) @@ -3102,6 +3102,7 @@ subroutine cime_run() !---------------------------------------------------------- !| OCN SETUP-SEND (cesm1_mod, cesm1_mod_tight, or rasm_option1) + ! make ocean time average, send. !---------------------------------------------------------- if (ocn_present .and. ocnrun_alarm) then if (trim(cpl_seq_option) == 'CESM1_MOD' .or. & @@ -3113,9 +3114,11 @@ subroutine cime_run() !---------------------------------------------------------- !| MAP ATM to OCN - ! update mboxid with latest atm data - ! This will be used later in the ice prep and in the - ! atm/ocn flux calculation + ! map a 2 o again only for CESM1_MOD and CESM1_MOD_TIGHT where + ! the a2o map above was undone. + ! This will be used later in the atm/ocn flux calculation + ! form a2i by mapping the output of a2o to i. + ! This will be used later in the ice prep !---------------------------------------------------------- if (trim(cpl_seq_option) == 'CESM1_MOD' .or. & trim(cpl_seq_option) == 'CESM1_MOD_TIGHT') then @@ -3140,6 +3143,7 @@ subroutine cime_run() !---------------------------------------------------------- !| LND SETUP-SEND + ! map a2l, merge land, diag, send !---------------------------------------------------------- if (lnd_present .and. lndrun_alarm) then call cime_run_lnd_setup_send() @@ -3147,6 +3151,9 @@ subroutine cime_run() !---------------------------------------------------------- !| ICE SETUP-SEND + ! map o2i (o2x_ox to o2x_ix) + ! MCT ONLY: map a2x_ox to a2x_i + ! mrg ice, diag, send !---------------------------------------------------------- if (ice_present .and. icerun_alarm) then call cime_run_ice_setup_send() @@ -3161,6 +3168,7 @@ subroutine cime_run() !---------------------------------------------------------- !| ROF SETUP-SEND + ! avg rof, map l2r, a2r, o2r, mrg, diag send !---------------------------------------------------------- if (rof_present .and. rofrun_alarm) then call cime_run_rof_setup_send() diff --git a/driver-moab/main/cplcomp_exchange_mod.F90 b/driver-moab/main/cplcomp_exchange_mod.F90 index 866543ee2a4c..f00415bf0dd2 100644 --- a/driver-moab/main/cplcomp_exchange_mod.F90 +++ b/driver-moab/main/cplcomp_exchange_mod.F90 @@ -1657,13 +1657,13 @@ subroutine cplcomp_moab_Init(infodata,comp) nfields=mct_list_nitem (temp_list) if (nfields > 0) then ierr = iMOAB_GetMeshInfo ( mblxid, nvert, nvise, nbl, nsurf, nvisBC ) - if (mb_scm_land) then - arrsize = nvert(1)*nfields - ent_type = 0 ! cell + if (mb_scm_land) then + arrsize = nvert(1)*nfields + ent_type = 0 ! cell else - arrsize = nvise(1)*nfields - ent_type = 1 ! cell - endif + arrsize = nvise(1)*nfields + ent_type = 1 ! cell + endif allocate(tagValues(arrsize)) tagname = trim(newlist)//C_NULL_CHAR tagValues = 0.0_r8 diff --git a/driver-moab/main/prep_atm_mod.F90 b/driver-moab/main/prep_atm_mod.F90 index 7937568f2b12..a3c010281e1d 100644 --- a/driver-moab/main/prep_atm_mod.F90 +++ b/driver-moab/main/prep_atm_mod.F90 @@ -1366,7 +1366,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting o2x_am array ') endif - else + else ! o2x_am will still be used in merge so make sure its 0 when no ocean o2x_am(:,:)=0.0_r8 endif @@ -1377,7 +1377,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting i2x_am array ') endif - else + else ! i2x_am will still be used in merge so make sure its 0 when no sea ice i2x_am(:,:)=0.0_r8 endif @@ -1388,7 +1388,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting l2x_am array ') endif - else + else ! l2x_am will still be used in merge so make sure its 0 when no land l2x_am(:,:)=0.0_r8 endif @@ -1399,7 +1399,7 @@ subroutine prep_atm_mrg_moab(infodata, xao_ax) if (ierr .ne. 0) then call shr_sys_abort(subname//' error in getting xao_om array ') endif - else + else ! xao_am will still be used in merge so make sure its 0 when no ocean xao_am(:,:)=0.0_r8 endif From 369723b082f67241c2be457350f6c5a2f746206e Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 08:02:46 -0800 Subject: [PATCH 111/398] remove redundant initialization --- components/eam/src/physics/cam/zm_conv.F90 | 124 ++++++++------------- 1 file changed, 44 insertions(+), 80 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 43128ee6f3d8..360c4112fdf3 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -903,7 +903,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & hmn, hsat, qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) !---------------------------------------------------------------------------- - ! Purpose: + ! Purpose: Determine properties of ZM updrafts and downdrafts !---------------------------------------------------------------------------- implicit none !---------------------------------------------------------------------------- @@ -992,7 +992,6 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8) estu real(r8) qstu - real(r8) small real(r8) mdt ! Convective microphysics @@ -1003,10 +1002,6 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols,pverp):: pflxs ! frozen precipitation flux thru layer real(r8) dum, sdum - real(r8), parameter :: mu_min = 0.02_r8 ! minimum value of mu - real(r8), parameter :: t_homofrz = 233.15_r8 ! homogeneous freezing temperature - real(r8), parameter :: t_mphase = 40._r8 ! mixed phase temperature = tfreez-t_homofrz = 273.15K - 233.15K - integer, dimension(pcols) :: jto ! updraft plume old top integer, dimension(pcols) :: tmplel @@ -1018,11 +1013,16 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer kount integer i,k - logical, dimension(pcols) :: doit + logical, dimension(pcols) :: doit ! flag to reset cloud logical, dimension(pcols) :: done -! -!------------------------------------------------------------------------------ + real(r8), parameter :: small = 1.e-20_r8 ! small number to limit blowup when normalizing by mass flux + real(r8), parameter :: mu_min = 0.02_r8 ! minimum value of mu + real(r8), parameter :: t_homofrz = 233.15_r8 ! homogeneous freezing temperature + real(r8), parameter :: t_mphase = 40._r8 ! mixed phase temperature = tfreez-t_homofrz = 273.15K - 233.15K + real(r8), parameter :: hu_diff_min = -2000._r8 ! limit on hu(i,k)-hsthat(i,k) + + !---------------------------------------------------------------------------- do i = 1,il2g ftemp(i) = 0._r8 @@ -1030,18 +1030,15 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & expdif(i) = 0._r8 c0mask(i) = zm_param%c0_ocn*(1._r8-landfrac(i)) + zm_param%c0_lnd*landfrac(i) end do -! -!jr Change from msg+1 to 1 to prevent blowup -! + + ! calculate layer thickness do k = 1,pver do i = 1,il2g dz(i,k) = zf(i,k) - zf(i,k+1) end do end do -! -! initialize many output and work variables to zero -! + ! initialize many output and work variables to zero pflx(:il2g,1) = 0 do k = 1,pver @@ -1066,12 +1063,11 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & mc(i,k) = 0._r8 qu(i,k) = q(i,k) su(i,k) = s(i,k) + + ! calculate saturation specific humidity call qsat_hPa(t(i,k), p(i,k), est(i), qst(i,k)) -!++bee - if ( p(i,k)-est(i) <= 0._r8 ) then - qst(i,k) = 1.0_r8 - end if -!--bee + if ( p(i,k)-est(i) <= 0._r8 ) qst(i,k) = 1.0_r8 + gamma(i,k) = qst(i,k)*(1._r8 + qst(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t(i,k)**2)*zm_const%latvap/zm_const%cpair hmn(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*q(i,k) hsat(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*qst(i,k) @@ -1081,44 +1077,19 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! Convective microphysics fice(i,k) = 0._r8 tug(i,k) = 0._r8 - if (zm_param%zm_microp) then - loc_microp_st%qcde(i,k) = 0._r8 - loc_microp_st%qide(i,k) = 0._r8 - loc_microp_st%qsde(i,k) = 0._r8 - loc_microp_st%ncde(i,k) = 0._r8 - loc_microp_st%nide(i,k) = 0._r8 - loc_microp_st%nsde(i,k) = 0._r8 - loc_microp_st%cmel(i,k) = 0._r8 - loc_microp_st%cmei(i,k) = 0._r8 - loc_microp_st%wu(i,k) = 0._r8 - loc_microp_st%qliq(i,k) = 0._r8 - loc_microp_st%qice(i,k) = 0._r8 - loc_microp_st%qrain(i,k) = 0._r8 - loc_microp_st%qsnow(i,k) = 0._r8 - loc_microp_st%qgraupel(i,k) = 0._r8 - loc_microp_st%qnl(i,k) = 0._r8 - loc_microp_st%qni(i,k) = 0._r8 - loc_microp_st%qnr(i,k) = 0._r8 - loc_microp_st%qns(i,k) = 0._r8 - loc_microp_st%qng(i,k) = 0._r8 - loc_microp_st%sprd(i,k) = 0._r8 - loc_microp_st%frz(i,k) = 0._r8 - tmp_frz(i,k) = 0._r8 - end if + tmp_frz(i,k) = 0._r8 + end do end do -! -!jr Set to zero things which make this routine blow up -! + + ! Set to zero things which make this routine blow up do k=1,msg do i=1,il2g rprd(i,k) = 0._r8 end do end do -! -! interpolate the layer values of qst, hsat and gamma to -! layer interfaces -! + + ! interpolate the layer values of qst, hsat and gamma to layer interfaces do k = 1, msg+1 do i = 1,il2g hsthat(i,k) = hsat(i,k) @@ -1146,10 +1117,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do -! -! initialize cloud top to highest plume top. -!jr changed hard-wired 4 to limcnv+1 (not to exceed pver) -! + + ! initialize cloud top to highest plume top. + ! changed hard-wired 4 to limcnv+1 (not to exceed pver) jt(:) = pver jto(:)= pver do i = 1,il2g @@ -1159,10 +1129,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & jlcl(i) = lel(i) hmin(i) = 1.E6_r8 end do -! -! find the level of minimum hsat, where detrainment starts -! + ! find the level of minimum hsat, where detrainment starts do k = msg + 1,pver do i = 1,il2g if (hsat(i,k) <= hmin(i) .and. k >= jt(i) .and. k <= jb(i)) then @@ -1174,14 +1142,12 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do i = 1,il2g j0(i) = min(j0(i),jb(i)-2) j0(i) = max(j0(i),jt(i)+2) -! -! Fix from Guang Zhang to address out of bounds array reference -! + + ! this prevents out of bounds array reference j0(i) = min(j0(i),pver) end do -! -! Initialize certain arrays inside cloud -! + + ! Initialize certain arrays inside cloud do k = msg + 1,pver do i = 1,il2g if (k >= jt(i) .and. k <= jb(i)) then @@ -1202,11 +1168,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do -! -! ********************************************************* -! compute taylor series for approximate eps(z) below -! ********************************************************* -! + + ! ********************************************************* + ! compute taylor series for approximate eps(z) below + ! ********************************************************* do k = pver - 1,msg + 1,-1 do i = 1,il2g if (k < jb(i) .and. k >= jt(i)) then @@ -1220,9 +1185,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do -! -! re-initialize hmin array for ensuing calculation. -! + + ! re-initialize hmin array for ensuing calculation. do i = 1,il2g hmin(i) = 1.E6_r8 end do @@ -1234,11 +1198,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do -! -! ********************************************************* -! compute approximate eps(z) using above taylor series -! ********************************************************* -! + + ! ********************************************************* + ! compute approximate eps(z) using above taylor series + ! ********************************************************* do k = msg + 2,pver do i = 1,il2g expnum(i) = 0._r8 @@ -1387,8 +1350,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k=klowest-2,khighest-1,-1 do i=1,il2g if (doit(i) .and. k <= jb(i)-2 .and. k >= lel(i)-1) then - if (hu(i,k) <= hsthat(i,k) .and. hu(i,k+1) > hsthat(i,k+1) .and. mu(i,k) >= mu_min) then - if (hu(i,k)-hsthat(i,k) < -2000._r8) then + if (hu(i,k) <= hsthat(i,k) .and. & + hu(i,k+1) > hsthat(i,k+1) .and. & + mu(i,k) >= mu_min) then + if ( hu(i,k)-hsthat(i,k) < hu_diff_min) then jt(i) = k + 1 doit(i) = .false. else @@ -1646,7 +1611,6 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - small = 1.e-20_r8 do k = msg + 1,pver do i = 1,il2g if ((k >= jt(i) .and. k <= pver) .and. eps0(i) > 0._r8) then From 2dc5534ceefd04fe3034e549271c7d76bd9e8e9e Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 09:56:53 -0800 Subject: [PATCH 112/398] more cldprp cleanup --- components/eam/src/physics/cam/zm_conv.F90 | 250 +++++++++------------ 1 file changed, 107 insertions(+), 143 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 360c4112fdf3..afa133348f8a 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -5,6 +5,13 @@ module zm_conv ! Contributors: Guang Zhang, Norman McFarlane, Michael Lazare, Phil Rasch, ! Rich Neale, Byron Boville, Xiaoliang Song, Walter Hannah !---------------------------------------------------------------------------- + ! for equations and technical details the best reference is: + ! Neale, R., Gettelman, A., Park, S., Chen, C.-C., Lauritzen, P. H., et al. + ! (2012). Description of the NCAR Community Atmosphere Model (CAM 5.0). + ! https://doi.org/10.5065/wgtk-4g06 + ! which can also be found here: + ! https://opensky.ucar.edu/islandora/object/technotes%3A594?search_api_fulltext=CAM5 + !---------------------------------------------------------------------------- #ifdef SCREAM_CONFIG_IS_CMAKE use zm_eamxx_bridge_params, only: r8 use zm_eamxx_bridge_methods,only: cldfrc_fice @@ -955,7 +962,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & type(zm_microp_st) :: loc_microp_st ! state and tendency of convective microphysics !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: gamma + real(r8), dimension(pcols,pver) :: gamma ! used for pseudo-adiabatic lapse rate real(r8), dimension(pcols,pver) :: dz real(r8), dimension(pcols,pver) :: iprm real(r8), dimension(pcols,pver) :: hu @@ -1031,54 +1038,53 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & c0mask(i) = zm_param%c0_ocn*(1._r8-landfrac(i)) + zm_param%c0_lnd*landfrac(i) end do - ! calculate layer thickness - do k = 1,pver - do i = 1,il2g - dz(i,k) = zf(i,k) - zf(i,k+1) - end do - end do - - ! initialize many output and work variables to zero - pflx(:il2g,1) = 0 - + ! initialize variables do k = 1,pver do i = 1,il2g - k1(i,k) = 0._r8 - i2(i,k) = 0._r8 - i3(i,k) = 0._r8 - i4(i,k) = 0._r8 - mu(i,k) = 0._r8 - f(i,k) = 0._r8 - eps(i,k) = 0._r8 - eu(i,k) = 0._r8 - du(i,k) = 0._r8 - ql(i,k) = 0._r8 - cu(i,k) = 0._r8 - evp(i,k) = 0._r8 - qds(i,k) = q(i,k) - md(i,k) = 0._r8 - ed(i,k) = 0._r8 - sd(i,k) = s(i,k) - qd(i,k) = q(i,k) - mc(i,k) = 0._r8 - qu(i,k) = q(i,k) - su(i,k) = s(i,k) - + ! misc work variables + k1(i,k) = 0._r8 + i2(i,k) = 0._r8 + i3(i,k) = 0._r8 + i4(i,k) = 0._r8 + f(i,k) = 0._r8 + eps(i,k) = 0._r8 + ! mass fluxes & mixing variables + mu(i,k) = 0._r8 + eu(i,k) = 0._r8 + du(i,k) = 0._r8 + mc(i,k) = 0._r8 + md(i,k) = 0._r8 + ed(i,k) = 0._r8 + ! cloud process variables + ql(i,k) = 0._r8 + evp(i,k) = 0._r8 + cu(i,k) = 0._r8 + rprd(i,k) = 0._r8 + pflx(i,k) = 0._r8 + ! calculate layer thickness + dz(i,k) = zf(i,k) - zf(i,k+1) ! calculate saturation specific humidity call qsat_hPa(t(i,k), p(i,k), est(i), qst(i,k)) if ( p(i,k)-est(i) <= 0._r8 ) qst(i,k) = 1.0_r8 - - gamma(i,k) = qst(i,k)*(1._r8 + qst(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t(i,k)**2)*zm_const%latvap/zm_const%cpair - hmn(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*q(i,k) - hsat(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*qst(i,k) - hu(i,k) = hmn(i,k) - hd(i,k) = hmn(i,k) - rprd(i,k) = 0._r8 - ! Convective microphysics - fice(i,k) = 0._r8 - tug(i,k) = 0._r8 - tmp_frz(i,k) = 0._r8 - + ! compute gamma - see eq. (4.117) + gamma(i,k) = qst(i,k)*(1._r8 + qst(i,k)/zm_const%epsilo) & + * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t(i,k)**2) & + * zm_const%latvap/zm_const%cpair + ! cloud thermodynamic variables + su(i,k) = s(i,k) + sd(i,k) = s(i,k) + qd(i,k) = q(i,k) + qds(i,k) = q(i,k) + qu(i,k) = q(i,k) + hmn(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*q(i,k) + hsat(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*qst(i,k) + hu(i,k) = hmn(i,k) + hd(i,k) = hmn(i,k) + ! convective microphysics + pflxs(i,k) = 0._r8 + fice(i,k) = 0._r8 + tug(i,k) = 0._r8 + tmp_frz(i,k)= 0._r8 end do end do @@ -1110,16 +1116,15 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if hsthat(i,k) = zm_const%cpair*shat(i,k) + zm_const%latvap*qsthat(i,k) if (abs(gamma(i,k-1)-gamma(i,k)) > 1.E-6_r8) then - gamhat(i,k) = log(gamma(i,k-1)/gamma(i,k))*gamma(i,k-1)*gamma(i,k)/ & - (gamma(i,k-1)-gamma(i,k)) + gamhat(i,k) = log(gamma(i,k-1)/gamma(i,k))*gamma(i,k-1)*gamma(i,k)/ (gamma(i,k-1)-gamma(i,k)) else gamhat(i,k) = gamma(i,k) end if end do end do - ! initialize cloud top to highest plume top. - ! changed hard-wired 4 to limcnv+1 (not to exceed pver) + !---------------------------------------------------------------------------- + ! initialize cloud top to highest plume top (upper/lower limit => pver / limcnv+1) jt(:) = pver jto(:)= pver do i = 1,il2g @@ -1130,7 +1135,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & hmin(i) = 1.E6_r8 end do - ! find the level of minimum hsat, where detrainment starts + !---------------------------------------------------------------------------- + ! find the level of minimum saturated MSE (hsat), where detrainment starts do k = msg + 1,pver do i = 1,il2g if (hsat(i,k) <= hmin(i) .and. k >= jt(i) .and. k <= jb(i)) then @@ -1142,36 +1148,34 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do i = 1,il2g j0(i) = min(j0(i),jb(i)-2) j0(i) = max(j0(i),jt(i)+2) - - ! this prevents out of bounds array reference + ! use limiter to prevent out of bounds array reference j0(i) = min(j0(i),pver) end do - ! Initialize certain arrays inside cloud + !---------------------------------------------------------------------------- + ! Initialize cloud moist and dry static energies (hu=MSE & su=DSE) do k = msg + 1,pver do i = 1,il2g if (k >= jt(i) .and. k <= jb(i)) then - ! Tunable temperature perturbation (tiedke_add) was already added to parcel hu/su to - ! represent subgrid temperature perturbation. If PBL temperature perturbation (tpert) - ! is used to represent subgrid temperature perturbation, tiedke_add may need to be - ! removed. In addition, current calculation of PBL temperature perturbation is not - ! accurate enough so that a new tunable parameter tpert_fac was introduced. This introduced - ! new uncertainties into the ZM scheme. The original code of ZM scheme will be used - ! when tpert_fix=.true. - if(zm_param%tpert_fix) then - hu(i,k) = hmn(i,mx(i)) + zm_const%cpair*zm_param%tiedke_add - su(i,k) = s(i,mx(i)) + zm_param%tiedke_add - else - hu(i,k) = hmn(i,mx(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) - su(i,k) = s(i,mx(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) - end if + ! Tunable temperature perturbation (tiedke_add) was already added to parcel hu/su to + ! represent subgrid temperature perturbation. If PBL temperature pert (tpert) also + ! represents subgrid temperature pert, tiedke_add may need to be removed. Additionally, + ! current calculation of PBL temperature perturbation is not accurate enough so that a + ! new tunable parameter tpert_fac was introduced. This introduced new uncertainties into + ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. + if(zm_param%tpert_fix) then + hu(i,k) = hmn(i,mx(i)) + zm_const%cpair*zm_param%tiedke_add + su(i,k) = s(i,mx(i)) + zm_param%tiedke_add + else + hu(i,k) = hmn(i,mx(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) + su(i,k) = s(i,mx(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) + end if end if end do end do - ! ********************************************************* + !---------------------------------------------------------------------------- ! compute taylor series for approximate eps(z) below - ! ********************************************************* do k = pver - 1,msg + 1,-1 do i = 1,il2g if (k < jb(i) .and. k >= jt(i)) then @@ -1186,10 +1190,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - ! re-initialize hmin array for ensuing calculation. - do i = 1,il2g - hmin(i) = 1.E6_r8 - end do + !---------------------------------------------------------------------------- + ! re-initialize hmin array for ensuing calculation + hmin(1:il2g) = 1.E6_r8 do k = msg + 1,pver do i = 1,il2g if (k >= j0(i) .and. k <= jb(i) .and. hmn(i,k) <= hmin(i)) then @@ -1199,27 +1202,25 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - ! ********************************************************* + !---------------------------------------------------------------------------- ! compute approximate eps(z) using above taylor series - ! ********************************************************* do k = msg + 2,pver do i = 1,il2g - expnum(i) = 0._r8 - ftemp(i) = 0._r8 + expnum(i) = 0._r8 + ftemp(i) = 0._r8 if (k < jt(i) .or. k >= jb(i)) then - k1(i,k) = 0._r8 - expnum(i) = 0._r8 + k1(i,k) = 0._r8 + expnum(i)= 0._r8 else expnum(i) = hmn(i,mx(i)) - (hsat(i,k-1)*(zf(i,k)-z(i,k)) + & hsat(i,k)* (z(i,k-1)-zf(i,k)))/(z(i,k-1)-z(i,k)) end if if ((expdif(i) > 100._r8 .and. expnum(i) > 0._r8) .and. k1(i,k) > expnum(i)*dz(i,k)) then ftemp(i) = expnum(i)/k1(i,k) - f(i,k) = ftemp(i) + i2(i,k)/k1(i,k)*ftemp(i)**2 + & - (2._r8*i2(i,k)**2-k1(i,k)*i3(i,k))/k1(i,k)**2* & - ftemp(i)**3 + (-5._r8*k1(i,k)*i2(i,k)*i3(i,k)+ & - 5._r8*i2(i,k)**3+k1(i,k)**2*i4(i,k))/ & - k1(i,k)**3*ftemp(i)**4 + f(i,k) = ftemp(i) + & + i2(i,k)/k1(i,k) * ftemp(i)**2 + & + (2._r8*i2(i,k)**2-k1(i,k)*i3(i,k))/k1(i,k)**2 * ftemp(i)**3 + & + (-5._r8*k1(i,k)*i2(i,k)*i3(i,k)+ 5._r8*i2(i,k)**3+k1(i,k)**2*i4(i,k))/ k1(i,k)**3*ftemp(i)**4 f(i,k) = max(f(i,k),0._r8) f(i,k) = min(f(i,k),0.0002_r8) end if @@ -1227,7 +1228,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do do i = 1,il2g if (j0(i) < jb(i)) then - if (f(i,j0(i)) < 1.E-6_r8 .and. f(i,j0(i)+1) > f(i,j0(i))) j0(i) = j0(i) + 1 + if ( f(i,j0(i))<1.E-6_r8 .and. f(i,j0(i)+1)>f(i,j0(i)) ) then + j0(i) = j0(i) + 1 + end if end if end do do k = msg + 2,pver @@ -1248,17 +1251,13 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k = pver,msg + 1,-1 do i = 1,il2g - if (k >= j0(i) .and. k <= jb(i)) then - eps(i,k) = f(i,j0(i)) - end if - end do - end do - do k = pver,msg + 1,-1 - do i = 1,il2g - if (k < j0(i) .and. k >= jt(i)) eps(i,k) = f(i,k) + if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) + if ( k =jt(i) ) eps(i,k) = f(i,k) end do end do + !---------------------------------------------------------------------------- + ! iteration to set cloud properties itnum = 1 if (zm_param%zm_microp) itnum = 2 @@ -1282,8 +1281,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do - ! specify the updraft mass flux mu, entrainment eu, detrainment du and moist static energy hu. - ! here and below mu, eu,du, md and ed are all normalized by mb + ! specify the updraft mass flux (mu), entrainment (eu), detrainment (du), and MSE (hu) + ! here and below mu,eu,du,md,ed are all normalized by cloud base mass flux (mb) do i = 1,il2g if (eps0(i) > 0._r8) then mu(i,jb(i)) = 1._r8 @@ -1577,14 +1576,11 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do ! iter = 1,itnum -! specify downdraft properties (no downdrafts if jd.ge.jb). -! scale down downward mass flux profile so that net flux -! (up-down) at cloud base in not negative. -! + !---------------------------------------------------------------------------- + ! specify downdraft properties (note - no downdrafts if jd>=jb) + ! downward mass flux profile is scaled so that net flux (up-down) at cloud base in not negative do i = 1,il2g -! -! in normal downdraft strength run alfa=0.2. In test4 alfa=0.1 -! + ! in normal downdraft strength run alfa=0.2. In test4 alfa=0.1 jt(i) = min(jt(i),jb(i)-1) jd(i) = max(j0(i),jt(i)+1) jd(i) = min(jd(i),jb(i)) @@ -1620,9 +1616,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do -! -! calculate updraft and downdraft properties. -! + + ! calculate updraft and downdraft properties do k = msg + 2,pver do i = 1,il2g if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then @@ -1631,12 +1626,12 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do -! + do i = 1,il2g qd(i,jd(i)) = qds(i,jd(i)) sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*qd(i,jd(i)))/zm_const%cpair end do -! + do k = msg + 2,pver do i = 1,il2g if (k >= jd(i) .and. k < jb(i) .and. eps0(i) > 0._r8) then @@ -1651,26 +1646,14 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do do i = 1,il2g -!*guang totevp(i) = totevp(i) + md(i,jd(i))*q(i,jd(i)-1) - totevp(i) = totevp(i) + md(i,jd(i))*qd(i,jd(i)) - md(i,jb(i))*qd(i,jb(i)) end do -!!$ if (.true.) then - if (.false.) then - do i = 1,il2g - k = jb(i) - if (eps0(i) > 0._r8) then - evp(i,k) = -ed(i,k)*q(i,k) + (md(i,k)*qd(i,k))/dz(i,k) - evp(i,k) = max(evp(i,k),0._r8) - totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q(i,k) - end if - end do - endif do i = 1,il2g totpcp(i) = max(totpcp(i),0._r8) totevp(i) = max(totevp(i),0._r8) end do -! + do k = msg + 2,pver do i = 1,il2g if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then @@ -1693,15 +1676,14 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do -! compute the net precipitation flux across interfaces - pflx(:il2g,1) = 0._r8 - if (zm_param%zm_microp) pflxs(:,:) = 0._r8 + ! compute the net precipitation flux across interfaces do k = 2,pverp do i = 1,il2g pflx(i,k) = pflx(i,k-1) + rprd(i,k-1)*dz(i,k-1) if (zm_param%zm_microp) pflxs(i,k) = pflxs(i,k-1) + loc_microp_st%sprd(i,k-1)*dz(i,k-1) end do end do + ! protect against rounding error if (zm_param%zm_microp) then do i = 1,il2g @@ -1719,12 +1701,14 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do ! i end if ! zm_param%zm_microp + ! calculate net mass flux do k = msg + 1,pver do i = 1,il2g mc(i,k) = mu(i,k) + md(i,k) end do end do + ! disable columns if top is at or below LCL if using ZM microphysics if (zm_param%zm_microp) then do i = 1,il2g if ( jt(i)>=jlcl(i) ) then @@ -1739,29 +1723,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ed(i,k) = 0._r8 mc(i,k) = 0._r8 rprd(i,k) = 0._r8 - loc_microp_st%sprd(i,k) = 0._r8 fice(i,k) = 0._r8 - loc_microp_st%qcde(i,k) = 0._r8 - loc_microp_st%qide(i,k) = 0._r8 - loc_microp_st%qsde(i,k) = 0._r8 - loc_microp_st%ncde(i,k) = 0._r8 - loc_microp_st%nide(i,k) = 0._r8 - loc_microp_st%nsde(i,k) = 0._r8 - loc_microp_st%frz(i,k) = 0._r8 - loc_microp_st%wu(i,k) = 0._r8 - loc_microp_st%cmel(i,k) = 0._r8 - loc_microp_st%cmei(i,k) = 0._r8 - loc_microp_st%qliq(i,k) = 0._r8 - loc_microp_st%qice(i,k) = 0._r8 - loc_microp_st%qrain(i,k)= 0._r8 - loc_microp_st%qsnow(i,k)= 0._r8 - loc_microp_st%qgraupel(i,k) = 0._r8 - loc_microp_st%qnl(i,k) = 0._r8 - loc_microp_st%qni(i,k) = 0._r8 - loc_microp_st%qnr(i,k) = 0._r8 - loc_microp_st%qns(i,k) = 0._r8 - loc_microp_st%qng(i,k) = 0._r8 end do + call zm_microp_st_zero(loc_microp_st,i,pver) end if end do end if From c8afbffd991b8738b050b78557fb41894ac2bff4 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 10:56:25 -0800 Subject: [PATCH 113/398] more cldprp cleanup --- components/eam/src/physics/cam/zm_conv.F90 | 115 ++++++++++----------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index afa133348f8a..3c2ab1487659 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -962,44 +962,46 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & type(zm_microp_st) :: loc_microp_st ! state and tendency of convective microphysics !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: gamma ! used for pseudo-adiabatic lapse rate - real(r8), dimension(pcols,pver) :: dz - real(r8), dimension(pcols,pver) :: iprm - real(r8), dimension(pcols,pver) :: hu - real(r8), dimension(pcols,pver) :: hd - real(r8), dimension(pcols,pver) :: eps - real(r8), dimension(pcols,pver) :: f - real(r8), dimension(pcols,pver) :: k1 - real(r8), dimension(pcols,pver) :: i2 - real(r8), dimension(pcols,pver) :: ihat - real(r8), dimension(pcols,pver) :: i3 - real(r8), dimension(pcols,pver) :: idag - real(r8), dimension(pcols,pver) :: i4 - real(r8), dimension(pcols,pver) :: qsthat - real(r8), dimension(pcols,pver) :: hsthat - real(r8), dimension(pcols,pver) :: gamhat - real(r8), dimension(pcols,pver) :: qds - real(r8), dimension(pcols) :: c0mask - real(r8), dimension(pcols) :: hmin - real(r8), dimension(pcols) :: expdif - real(r8), dimension(pcols) :: expnum - real(r8), dimension(pcols) :: ftemp - real(r8), dimension(pcols) :: eps0 - real(r8), dimension(pcols) :: rmue - real(r8), dimension(pcols) :: zuef - real(r8), dimension(pcols) :: zdef - real(r8), dimension(pcols) :: epsm - real(r8), dimension(pcols) :: ratmjb - real(r8), dimension(pcols) :: est - real(r8), dimension(pcols) :: totpcp - real(r8), dimension(pcols) :: totevp - - real(r8) ql1 - real(r8) tu - real(r8) estu - real(r8) qstu - - real(r8) mdt + real(r8), dimension(pcols,pver) :: gamma ! latent-heating correction for pseudo-adiabatic parcel lifting + real(r8), dimension(pcols,pver) :: dz ! layer thickness + real(r8), dimension(pcols,pver) :: hu ! updraft moist static energy + real(r8), dimension(pcols,pver) :: hd ! dndraft moist static energy + real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst + real(r8), dimension(pcols,pver) :: hsthat ! interface interpolated hst + real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma + real(r8), dimension(pcols,pver) :: qds ! dndraft saturation specific humdity + real(r8), dimension(pcols) :: c0mask ! land/ocean modification + real(r8), dimension(pcols) :: hmin ! mid-tropospheric MSE minimum + + real(r8), dimension(pcols) :: rmue ! + real(r8), dimension(pcols) :: zuef ! + real(r8), dimension(pcols) :: zdef ! + real(r8), dimension(pcols) :: epsm ! + real(r8), dimension(pcols) :: ratmjb ! + real(r8), dimension(pcols) :: est ! + real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) + real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) + + ! variables used for Taylor series expansion when solving eq (4.78) for lamda_D + real(r8), dimension(pcols,pver) :: eps ! ? + real(r8), dimension(pcols,pver) :: f ! ? + real(r8), dimension(pcols) :: ftemp ! temporary value of f + real(r8), dimension(pcols) :: eps0 ! ? + real(r8), dimension(pcols) :: expdif ! diff between env MSE low-level max and mid-level min + real(r8), dimension(pcols) :: expnum ! ? + real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series + real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series + real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series + real(r8), dimension(pcols,pver) :: idag ! term for Taylor series + + real(r8) ql1 ! ? + real(r8) tu ! ? + real(r8) estu ! ? + real(r8) qstu ! ? + real(r8) mdt ! ? ! Convective microphysics real(r8), dimension(pcols,pver) :: fice ! ice fraction in precip production @@ -1294,6 +1296,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & tmplel(i) = jt(i) end if end do + + ! compute updraft mass fluxes - see eq (4.79) - (4.81) do k = pver,msg + 1,-1 do i = 1,il2g if (eps0(i) > 0._r8 .and. (k >= tmplel(i) .and. k < jb(i))) then @@ -1621,8 +1625,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k = msg + 2,pver do i = 1,il2g if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then - qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k))/ & - (zm_const%latvap*(1._r8 + gamhat(i,k))) + qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) end if end do end do @@ -1656,13 +1659,14 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k = msg + 2,pver do i = 1,il2g + ! ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then md(i,k) = md (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) ed(i,k) = ed (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) evp(i,k) = evp(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) else - md(i,k) = 0._r8 - ed(i,k) = 0._r8 + md(i,k) = 0._r8 + ed(i,k) = 0._r8 evp(i,k) = 0._r8 end if ! rprd is the cloud water converted to rain - (rain evaporated) @@ -1684,9 +1688,16 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - ! protect against rounding error + ! calculate net mass flux + do k = msg + 1,pver + do i = 1,il2g + mc(i,k) = mu(i,k) + md(i,k) + end do + end do + if (zm_param%zm_microp) then do i = 1,il2g + ! protect against rounding error if(pflxs(i,pverp).gt.pflx(i,pverp)) then dum = (pflxs(i,pverp)-pflx(i,pverp))/omsm do k = pver, msg+2, -1 @@ -1698,19 +1709,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do ! k end if - end do ! i - end if ! zm_param%zm_microp - - ! calculate net mass flux - do k = msg + 1,pver - do i = 1,il2g - mc(i,k) = mu(i,k) + md(i,k) - end do - end do - - ! disable columns if top is at or below LCL if using ZM microphysics - if (zm_param%zm_microp) then - do i = 1,il2g + ! disable columns if top is at or below LCL if using ZM microphysics if ( jt(i)>=jlcl(i) ) then do k = msg + 1,pver mu(i,k) = 0._r8 @@ -1724,10 +1723,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & mc(i,k) = 0._r8 rprd(i,k) = 0._r8 fice(i,k) = 0._r8 - end do + end do ! k call zm_microp_st_zero(loc_microp_st,i,pver) end if - end do + end do ! i end if return From 6d16a39fa602ac0fc902c7a88d7ab351d205c84d Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 11:35:32 -0800 Subject: [PATCH 114/398] more cldprp cleanup --- components/eam/src/physics/cam/zm_conv.F90 | 94 +++++++++------------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 3c2ab1487659..13a569fdeecd 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -41,9 +41,10 @@ module zm_conv type(zm_param_t), public :: zm_param ! derived type to hold ZM tunable parameters !---------------------------------------------------------------------------- ! private variables - real(r8), parameter :: capelmt = 70._r8 ! threshold value for cape for deep convection - real(r8), parameter :: trigdcapelmt = 0._r8 ! threshold value of dcape for deep convection - real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error + real(r8), parameter :: capelmt = 70._r8 ! threshold value for cape for deep convection + real(r8), parameter :: trigdcapelmt = 0._r8 ! threshold value of dcape for deep convection + real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error + real(r8), parameter :: interp_diff_min = 1.E-6_r8 ! minimum threshold for interpolation method - see eq (4.109), (4.118), (4.119) !=================================================================================================== contains !=================================================================================================== @@ -471,12 +472,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & sdifr = abs((sg(i,k)-sg(i,k-1))/max(sg(i,k-1),sg(i,k))) if (qg(i,k) > 0._r8 .or. qg(i,k-1) > 0._r8) & qdifr = abs((qg(i,k)-qg(i,k-1))/max(qg(i,k-1),qg(i,k))) - if (sdifr > 1.E-6_r8) then + if (sdifr > interp_diff_min) then shat(i,k) = log(sg(i,k-1)/sg(i,k))*sg(i,k-1)*sg(i,k)/(sg(i,k-1)-sg(i,k)) else shat(i,k) = 0.5_r8* (sg(i,k)+sg(i,k-1)) end if - if (qdifr > 1.E-6_r8) then + if (qdifr > interp_diff_min) then qhat(i,k) = log(qg(i,k-1)/qg(i,k))*qg(i,k-1)*qg(i,k)/(qg(i,k-1)-qg(i,k)) else qhat(i,k) = 0.5_r8* (qg(i,k)+qg(i,k-1)) @@ -485,7 +486,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & end do !---------------------------------------------------------------------------- - ! obtain cloud properties. + ! calculate updraft and downdraft properties call cldprp(pcols, ncol, pver, pverp, lengath, msg, zm_param%limcnv, & pg, zg, zfg, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & @@ -920,7 +921,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels integer, intent(in ) :: il2g ! number of gathered columns (lengath) - integer, intent(in ) :: msg ! missing moisture vals + integer, intent(in ) :: msg ! missing moisture levels integer, intent(in ) :: limcnv ! convection limiting level real(r8), dimension(pcols,pver), intent(in ) :: p ! env pressure at mid-point real(r8), dimension(pcols,pver), intent(in ) :: z ! env altitude at mid-point @@ -1034,9 +1035,11 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- do i = 1,il2g - ftemp(i) = 0._r8 + ftemp(i) = 0._r8 expnum(i) = 0._r8 expdif(i) = 0._r8 + totpcp(i) = 0._r8 + totevp(i) = 0._r8 c0mask(i) = zm_param%c0_ocn*(1._r8-landfrac(i)) + zm_param%c0_lnd*landfrac(i) end do @@ -1090,37 +1093,25 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - ! Set to zero things which make this routine blow up - do k=1,msg - do i=1,il2g - rprd(i,k) = 0._r8 - end do - end do - - ! interpolate the layer values of qst, hsat and gamma to layer interfaces - do k = 1, msg+1 + !---------------------------------------------------------------------------- + ! interpolate the mid-point values to interfaces + do k = msg+1,pver do i = 1,il2g hsthat(i,k) = hsat(i,k) qsthat(i,k) = qst(i,k) gamhat(i,k) = gamma(i,k) - end do - end do - do i = 1,il2g - totpcp(i) = 0._r8 - totevp(i) = 0._r8 - end do - do k = msg + 2,pver - do i = 1,il2g - if (abs(qst(i,k-1)-qst(i,k)) > 1.E-6_r8) then - qsthat(i,k) = log(qst(i,k-1)/qst(i,k))*qst(i,k-1)*qst(i,k)/ (qst(i,k-1)-qst(i,k)) - else - qsthat(i,k) = qst(i,k) - end if - hsthat(i,k) = zm_const%cpair*shat(i,k) + zm_const%latvap*qsthat(i,k) - if (abs(gamma(i,k-1)-gamma(i,k)) > 1.E-6_r8) then - gamhat(i,k) = log(gamma(i,k-1)/gamma(i,k))*gamma(i,k-1)*gamma(i,k)/ (gamma(i,k-1)-gamma(i,k)) - else - gamhat(i,k) = gamma(i,k) + if (k>msg+1) then + if (abs(qst(i,k-1)-qst(i,k)) > interp_diff_min) then + qsthat(i,k) = log(qst(i,k-1)/qst(i,k))*qst(i,k-1)*qst(i,k)/ (qst(i,k-1)-qst(i,k)) + else + qsthat(i,k) = qst(i,k) + end if + hsthat(i,k) = zm_const%cpair*shat(i,k) + zm_const%latvap*qsthat(i,k) + if (abs(gamma(i,k-1)-gamma(i,k)) > interp_diff_min) then + gamhat(i,k) = log(gamma(i,k-1)/gamma(i,k))*gamma(i,k-1)*gamma(i,k)/ (gamma(i,k-1)-gamma(i,k)) + else + gamhat(i,k) = gamma(i,k) + end if end if end do end do @@ -1278,29 +1269,24 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do do i = 1,il2g - totpcp(i) = 0._r8 - if (zm_param%zm_microp) hu(i,jb(i)) = hmn(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add + totpcp(i) = 0._r8 + if (zm_param%zm_microp) hu(i,jb(i)) = hmn(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add end do - - ! specify the updraft mass flux (mu), entrainment (eu), detrainment (du), and MSE (hu) - ! here and below mu,eu,du,md,ed are all normalized by cloud base mass flux (mb) - do i = 1,il2g - if (eps0(i) > 0._r8) then - mu(i,jb(i)) = 1._r8 - eu(i,jb(i)) = mu(i,jb(i))/dz(i,jb(i)) - end if - if (zm_param%zm_microp) then - tmplel(i) = lel(i) - else - tmplel(i) = jt(i) - end if - end do - - ! compute updraft mass fluxes - see eq (4.79) - (4.81) do k = pver,msg + 1,-1 do i = 1,il2g - if (eps0(i) > 0._r8 .and. (k >= tmplel(i) .and. k < jb(i))) then + ! intialize updraft mass flux variables - here and below all normalized by cloud base mass flux (mb) + if (eps0(i) > 0._r8) then + mu(i,jb(i)) = 1._r8 + eu(i,jb(i)) = mu(i,jb(i))/dz(i,jb(i)) + end if + if (zm_param%zm_microp) then + tmplel(i) = lel(i) + else + tmplel(i) = jt(i) + end if + ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) + if (eps0(i) > 0._r8 .and. (k >= tmplel(i) .and. k < jb(i))) then zuef(i) = zf(i,k) - zf(i,jb(i)) rmue(i) = (1._r8/eps0(i))* (exp(eps(i,k+1)*zuef(i))-1._r8)/zuef(i) mu(i,k) = (1._r8/eps0(i))* (exp(eps(i,k )*zuef(i))-1._r8)/zuef(i) From f70293626ba9323c5fe2c6e5017e045169fb26d7 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 13:32:53 -0800 Subject: [PATCH 115/398] create calculate_fractional_entrainment() --- components/eam/src/physics/cam/zm_conv.F90 | 396 ++++++++++++--------- 1 file changed, 231 insertions(+), 165 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 13a569fdeecd..90f5afdd1448 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -903,6 +903,169 @@ end subroutine zm_conv_evap !=================================================================================================== +subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, & + jb, jt, j0, z, zf, dz, hmn, hsat, hmin, & + eps, eps0) + !---------------------------------------------------------------------------- + ! Purpose: Determine properties of ZM updrafts and downdrafts + !---------------------------------------------------------------------------- + implicit none + !---------------------------------------------------------------------------- + ! Arguments + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: il2g ! number of gathered columns (lengath) + integer, intent(in ) :: msg ! missing moisture levels + integer, dimension(pcols), intent(in ) :: jb ! updraft base level + integer, dimension(pcols), intent(in ) :: jt ! updraft top level + integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining + real(r8), dimension(pcols,pver), intent(in ) :: z ! env altitude at mid-point + real(r8), dimension(pcols,pverp),intent(in ) :: zf ! env altitude at interface + real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness + real(r8), dimension(pcols,pver), intent(in ) :: hmn ! env moist stat energy + real(r8), dimension(pcols,pver), intent(in ) :: hsat ! env saturated moist stat energy + real(r8), dimension(pcols) , intent(inout) :: hmin ! mid-tropospheric MSE minimum + real(r8), dimension(pcols,pver), intent( out) :: eps ! fractional entrainment + real(r8), dimension(pcols) , intent( out) :: eps0 ! fractional entrainment maximum + !---------------------------------------------------------------------------- + ! Local variables + + integer :: i,k ! loop iterators + + ! variables used for Taylor series expansion when solving eq (4.78) for lamda_D (i.e. fractional entrainment) + real(r8), dimension(pcols,pver) :: f ! fractional entrainment work variable + real(r8), dimension(pcols) :: ftemp ! temporary value of f + real(r8), dimension(pcols) :: expdif ! diff between env MSE low-level max and mid-level min + real(r8), dimension(pcols) :: expnum ! ? + real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series + real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series + real(r8), dimension(pcols,pver) :: idag ! term for Taylor series + real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series + + real(r8), parameter :: lambda_min = 0._r8 ! limiter + real(r8), parameter :: lambda_max = 0.0002_r8 ! limiter + real(r8), parameter :: lambda_thrs = 1.E-6_r8 ! threshold + !---------------------------------------------------------------------------- + + ! initialize 1D variables + do i = 1,il2g + ftemp(i) = 0._r8 + expnum(i) = 0._r8 + expdif(i) = 0._r8 + end do + + ! initialize 2D variables + do k = 1,pver + do i = 1,il2g + ! misc work variables + k1(i,k) = 0._r8 + i2(i,k) = 0._r8 + i3(i,k) = 0._r8 + i4(i,k) = 0._r8 + f(i,k) = 0._r8 + eps(i,k) = 0._r8 + end do + end do + + !---------------------------------------------------------------------------- + ! compute taylor series for approximate eps(z) below + do k = pver - 1,msg + 1,-1 + do i = 1,il2g + if (k < jb(i) .and. k >= jt(i)) then + k1(i,k) = k1(i,k+1) + (hmn(i,jb(i))-hmn(i,k))*dz(i,k) + ihat(i,k) = 0.5_r8* (k1(i,k+1)+k1(i,k)) + i2(i,k) = i2(i,k+1) + ihat(i,k)*dz(i,k) + idag(i,k) = 0.5_r8* (i2(i,k+1)+i2(i,k)) + i3(i,k) = i3(i,k+1) + idag(i,k)*dz(i,k) + iprm(i,k) = 0.5_r8* (i3(i,k+1)+i3(i,k)) + i4(i,k) = i4(i,k+1) + iprm(i,k)*dz(i,k) + end if + end do + end do + + !---------------------------------------------------------------------------- + ! re-initialize hmin array for ensuing calculation + hmin(1:il2g) = 1.E6_r8 + do k = msg + 1,pver + do i = 1,il2g + if (k >= j0(i) .and. k <= jb(i) .and. hmn(i,k) <= hmin(i)) then + hmin(i) = hmn(i,k) + expdif(i) = hmn(i,jb(i)) - hmin(i) + end if + end do + end do + + !---------------------------------------------------------------------------- + ! compute approximate eps(z) using above taylor series + do k = msg + 2,pver + do i = 1,il2g + expnum(i) = 0._r8 + ftemp(i) = 0._r8 + if (k < jt(i) .or. k >= jb(i)) then + k1(i,k) = 0._r8 + expnum(i)= 0._r8 + else + expnum(i) = hmn(i,jb(i)) - (hsat(i,k-1)*(zf(i,k)-z(i,k)) + & + hsat(i,k)* (z(i,k-1)-zf(i,k)))/(z(i,k-1)-z(i,k)) + end if + if ((expdif(i) > 100._r8 .and. expnum(i) > 0._r8) .and. k1(i,k) > expnum(i)*dz(i,k)) then + ftemp(i) = expnum(i) / k1(i,k) + f(i,k) = ftemp(i) + & + i2(i,k)/k1(i,k) * ftemp(i)**2 + & + (2._r8*i2(i,k)**2-k1(i,k)*i3(i,k))/k1(i,k)**2 * ftemp(i)**3 + & + (-5._r8*k1(i,k)*i2(i,k)*i3(i,k)+ 5._r8*i2(i,k)**3+k1(i,k)**2*i4(i,k))/k1(i,k)**3 * ftemp(i)**4 + f(i,k) = max(f(i,k),lambda_min) + f(i,k) = min(f(i,k),lambda_max) + end if + end do + end do + + ! move detrainment level downward if fractional entrainment is too low + do i = 1,il2g + if (j0(i) < jb(i)) then + if ( f(i,j0(i))<1.E-6_r8 .and. f(i,j0(i)+1)>f(i,j0(i)) ) then + j0(i) = j0(i) + 1 + end if + end if + end do + + ! ensure that entrainment does not increase above the level that detrainment starts + do k = msg + 2,pver + do i = 1,il2g + if (k >= jt(i) .and. k <= j0(i)) then + f(i,k) = max(f(i,k),f(i,k-1)) + end if + end do + end do + + ! ? + do i = 1,il2g + eps0(i) = f(i,j0(i)) + eps(i,jb(i)) = eps0(i) + end do + + ! The modification below comes from: + ! Rasch, P. J., J. E. Kristjánsson, A comparison of the CCM3 model climate + ! using diagnosed and predicted condensate parameterizations, J. Clim., 1997. + do k = pver,msg + 1,-1 + do i = 1,il2g + if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) + if ( k =jt(i) ) eps(i,k) = f(i,k) + end do + end do + + !---------------------------------------------------------------------------- + return + +end subroutine calculate_fractional_entrainment + +!=================================================================================================== + subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & p, z, zf, t, s, shat, q, u, v, landfrac, tpertg, & jb, mx, lel, jt, jlcl, j0, jd, & @@ -935,7 +1098,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction real(r8), dimension(pcols), intent(in ) :: tpertg ! PBL temperature perturbation integer, dimension(pcols), intent(in ) :: jb ! updraft base level - integer, dimension(pcols), intent(in ) :: mx ! updraft base level (same is jb) + integer, dimension(pcols), intent(in ) :: mx ! updraft base level (same is jb) <<<<<< REMOVE REDUNDANCY integer, dimension(pcols), intent(in ) :: lel ! updraft launch level integer, dimension(pcols), intent(out) :: jt ! updraft plume top integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level @@ -983,20 +1146,20 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) - ! variables used for Taylor series expansion when solving eq (4.78) for lamda_D - real(r8), dimension(pcols,pver) :: eps ! ? - real(r8), dimension(pcols,pver) :: f ! ? - real(r8), dimension(pcols) :: ftemp ! temporary value of f - real(r8), dimension(pcols) :: eps0 ! ? - real(r8), dimension(pcols) :: expdif ! diff between env MSE low-level max and mid-level min - real(r8), dimension(pcols) :: expnum ! ? - real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series - real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series - real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series - real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series - real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series - real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series - real(r8), dimension(pcols,pver) :: idag ! term for Taylor series + ! ! variables used for Taylor series expansion when solving eq (4.78) for lamda_D + real(r8), dimension(pcols,pver) :: eps ! fractional entrainment + ! real(r8), dimension(pcols,pver) :: f ! ? + ! real(r8), dimension(pcols) :: ftemp ! temporary value of f + real(r8), dimension(pcols) :: eps0 ! fractional entrainment max + ! real(r8), dimension(pcols) :: expdif ! diff between env MSE low-level max and mid-level min + ! real(r8), dimension(pcols) :: expnum ! ? + ! real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series + ! real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series + ! real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series + ! real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series + ! real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series + ! real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series + ! real(r8), dimension(pcols,pver) :: idag ! term for Taylor series real(r8) ql1 ! ? real(r8) tu ! ? @@ -1013,10 +1176,11 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8) dum, sdum integer, dimension(pcols) :: jto ! updraft plume old top - integer, dimension(pcols) :: tmplel - integer iter, itnum - integer m + integer :: tmp_k_limit ! temporary limit on k index in various contexts + integer :: iter ! ? + integer :: itnum ! ? + integer :: m integer khighest integer klowest @@ -1024,7 +1188,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer i,k logical, dimension(pcols) :: doit ! flag to reset cloud - logical, dimension(pcols) :: done + logical, dimension(pcols) :: done ! ? real(r8), parameter :: small = 1.e-20_r8 ! small number to limit blowup when normalizing by mass flux real(r8), parameter :: mu_min = 0.02_r8 ! minimum value of mu @@ -1034,25 +1198,16 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- + ! initialize 1D variables do i = 1,il2g - ftemp(i) = 0._r8 - expnum(i) = 0._r8 - expdif(i) = 0._r8 totpcp(i) = 0._r8 totevp(i) = 0._r8 c0mask(i) = zm_param%c0_ocn*(1._r8-landfrac(i)) + zm_param%c0_lnd*landfrac(i) end do - ! initialize variables + ! initialize 2D variables do k = 1,pver do i = 1,il2g - ! misc work variables - k1(i,k) = 0._r8 - i2(i,k) = 0._r8 - i3(i,k) = 0._r8 - i4(i,k) = 0._r8 - f(i,k) = 0._r8 - eps(i,k) = 0._r8 ! mass fluxes & mixing variables mu(i,k) = 0._r8 eu(i,k) = 0._r8 @@ -1130,20 +1285,19 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! find the level of minimum saturated MSE (hsat), where detrainment starts - do k = msg + 1,pver - do i = 1,il2g + do i = 1,il2g + do k = msg + 1,pver if (hsat(i,k) <= hmin(i) .and. k >= jt(i) .and. k <= jb(i)) then hmin(i) = hsat(i,k) j0(i) = k end if - end do - end do - do i = 1,il2g + end do ! k + ! apply limiters to j0 j0(i) = min(j0(i),jb(i)-2) j0(i) = max(j0(i),jt(i)+2) - ! use limiter to prevent out of bounds array reference + ! don't let j0 be greater than pver j0(i) = min(j0(i),pver) - end do + end do ! i !---------------------------------------------------------------------------- ! Initialize cloud moist and dry static energies (hu=MSE & su=DSE) @@ -1168,86 +1322,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do !---------------------------------------------------------------------------- - ! compute taylor series for approximate eps(z) below - do k = pver - 1,msg + 1,-1 - do i = 1,il2g - if (k < jb(i) .and. k >= jt(i)) then - k1(i,k) = k1(i,k+1) + (hmn(i,mx(i))-hmn(i,k))*dz(i,k) - ihat(i,k) = 0.5_r8* (k1(i,k+1)+k1(i,k)) - i2(i,k) = i2(i,k+1) + ihat(i,k)*dz(i,k) - idag(i,k) = 0.5_r8* (i2(i,k+1)+i2(i,k)) - i3(i,k) = i3(i,k+1) + idag(i,k)*dz(i,k) - iprm(i,k) = 0.5_r8* (i3(i,k+1)+i3(i,k)) - i4(i,k) = i4(i,k+1) + iprm(i,k)*dz(i,k) - end if - end do - end do - - !---------------------------------------------------------------------------- - ! re-initialize hmin array for ensuing calculation - hmin(1:il2g) = 1.E6_r8 - do k = msg + 1,pver - do i = 1,il2g - if (k >= j0(i) .and. k <= jb(i) .and. hmn(i,k) <= hmin(i)) then - hmin(i) = hmn(i,k) - expdif(i) = hmn(i,mx(i)) - hmin(i) - end if - end do - end do - - !---------------------------------------------------------------------------- - ! compute approximate eps(z) using above taylor series - do k = msg + 2,pver - do i = 1,il2g - expnum(i) = 0._r8 - ftemp(i) = 0._r8 - if (k < jt(i) .or. k >= jb(i)) then - k1(i,k) = 0._r8 - expnum(i)= 0._r8 - else - expnum(i) = hmn(i,mx(i)) - (hsat(i,k-1)*(zf(i,k)-z(i,k)) + & - hsat(i,k)* (z(i,k-1)-zf(i,k)))/(z(i,k-1)-z(i,k)) - end if - if ((expdif(i) > 100._r8 .and. expnum(i) > 0._r8) .and. k1(i,k) > expnum(i)*dz(i,k)) then - ftemp(i) = expnum(i)/k1(i,k) - f(i,k) = ftemp(i) + & - i2(i,k)/k1(i,k) * ftemp(i)**2 + & - (2._r8*i2(i,k)**2-k1(i,k)*i3(i,k))/k1(i,k)**2 * ftemp(i)**3 + & - (-5._r8*k1(i,k)*i2(i,k)*i3(i,k)+ 5._r8*i2(i,k)**3+k1(i,k)**2*i4(i,k))/ k1(i,k)**3*ftemp(i)**4 - f(i,k) = max(f(i,k),0._r8) - f(i,k) = min(f(i,k),0.0002_r8) - end if - end do - end do - do i = 1,il2g - if (j0(i) < jb(i)) then - if ( f(i,j0(i))<1.E-6_r8 .and. f(i,j0(i)+1)>f(i,j0(i)) ) then - j0(i) = j0(i) + 1 - end if - end if - end do - do k = msg + 2,pver - do i = 1,il2g - if (k >= jt(i) .and. k <= j0(i)) then - f(i,k) = max(f(i,k),f(i,k-1)) - end if - end do - end do - do i = 1,il2g - eps0(i) = f(i,j0(i)) - eps(i,jb(i)) = eps0(i) - end do - - ! This is set to match: - ! Rasch, P. J., J. E. Kristjánsson, A comparison of the CCM3 model climate - ! using diagnosed and predicted condensate parameterizations, J. Clim., 1997. - - do k = pver,msg + 1,-1 - do i = 1,il2g - if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) - if ( k =jt(i) ) eps(i,k) = f(i,k) - end do - end do + ! calculate fractional entrainment (i.e. "lambda D") - see eq (4.78) from Neale et al. (2012) + call calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, & + jb, jt, j0, z, zf, dz, hmn, hsat, hmin, & + eps, eps0) !---------------------------------------------------------------------------- ! iteration to set cloud properties @@ -1279,20 +1357,17 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & if (eps0(i) > 0._r8) then mu(i,jb(i)) = 1._r8 eu(i,jb(i)) = mu(i,jb(i))/dz(i,jb(i)) - end if - if (zm_param%zm_microp) then - tmplel(i) = lel(i) - else - tmplel(i) = jt(i) - end if - ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) - if (eps0(i) > 0._r8 .and. (k >= tmplel(i) .and. k < jb(i))) then - zuef(i) = zf(i,k) - zf(i,jb(i)) - rmue(i) = (1._r8/eps0(i))* (exp(eps(i,k+1)*zuef(i))-1._r8)/zuef(i) - mu(i,k) = (1._r8/eps0(i))* (exp(eps(i,k )*zuef(i))-1._r8)/zuef(i) - eu(i,k) = (rmue(i)-mu(i,k+1))/dz(i,k) - du(i,k) = (rmue(i)-mu(i,k))/dz(i,k) - end if + if ( zm_param%zm_microp) tmp_k_limit = lel(i) + if (.not.zm_param%zm_microp) tmp_k_limit = jt(i) + ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) + if ( k>=tmp_k_limit .and. k0._r8 end do end do @@ -1358,7 +1433,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do do i = 1,il2g - if (iter == 1) jto(i) = jt(i) + if (iter == 1) jto(i) = jt(i) end do do k = pver,msg + 1,-1 @@ -1377,9 +1452,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - do i = 1,il2g - done(i) = .false. - end do + ! determine LCL - see eq (4.127)- (4.130) of Neale et al. (2012) + done(1:il2g) = .false. kount = 0 do k = pver,msg + 2,-1 do i = 1,il2g @@ -1388,10 +1462,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & su(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. eps0(i) > 0._r8) then - su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + & - dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s(i,k) - qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q(i,k)- & - du(i,k)*qst(i,k)) + su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s(i,k) + qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q(i,k) - du(i,k)*qst(i,k)) tu = su(i,k) - zm_const%grav/zm_const%cpair*zf(i,k) call qsat_hPa(tu, (p(i,k)+p(i,k-1))/2._r8, estu, qstu) if (qu(i,k) >= qstu) then @@ -1409,39 +1481,33 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k = msg + 2,pver do i = 1,il2g if ((k > jt(i) .and. k <= jlcl(i)) .and. eps0(i) > 0._r8) then - su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k))/(zm_const%cpair* (1._r8+gamhat(i,k))) - qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k))/ & - (zm_const%latvap* (1._r8+gamhat(i,k))) + su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) + qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if end do end do - do i = 1,il2g - if (zm_param%zm_microp) then - tmplel(i) = jlcl(i)+1 - else - tmplel(i) = jb(i) - end if - end do - ! compute condensation in updraft do k = pver,msg + 2,-1 do i = 1,il2g - if (k >= jt(i) .and. k < tmplel(i) .and. eps0(i) > 0._r8) then - if (zm_param%zm_microp) then - cu(i,k) = ((mu(i,k)*su(i,k)-mu(i,k+1)*su(i,k+1))/ & - dz(i,k)- eu(i,k)*s(i,k)+du(i,k)*su(i,k))/(zm_const%latvap/zm_const%cpair) & - - zm_const%latice*tmp_frz(i,k)/zm_const%latvap - else - - cu(i,k) = ((mu(i,k)*su(i,k)-mu(i,k+1)*su(i,k+1))/ & - dz(i,k)- (eu(i,k)-du(i,k))*s(i,k))/(zm_const%latvap/zm_const%cpair) - end if - if (k == jt(i)) cu(i,k) = 0._r8 - cu(i,k) = max(0._r8,cu(i,k)) - end if - end do - end do + if (eps0(i)>0._r8) then + if ( zm_param%zm_microp) tmp_k_limit = jlcl(i)+1 + if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) + if ( k>=jt(i) .and. k0._r8 + end do ! i + end do ! k if (zm_param%zm_microp) then From 875657d88ca94f59274150fb06beb3166a30dba8 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 13:42:11 -0800 Subject: [PATCH 116/398] remove redundant mx variable --- components/eam/src/physics/cam/zm_conv.F90 | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 90f5afdd1448..936f4e263851 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -490,7 +490,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & call cldprp(pcols, ncol, pver, pverp, lengath, msg, zm_param%limcnv, & pg, zg, zfg, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & - maxg, maxg, lelg, jt, jlcl, j0, jd, & + maxg, lelg, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, qlg, sd, qd, & hmn, hsat, qs, cug, evpg, pflxg, rprdg, & @@ -1068,7 +1068,7 @@ end subroutine calculate_fractional_entrainment subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & p, z, zf, t, s, shat, q, u, v, landfrac, tpertg, & - jb, mx, lel, jt, jlcl, j0, jd, & + jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, ql, sd, qd, & hmn, hsat, qst, cu, evp, pflx, rprd, & @@ -1098,8 +1098,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction real(r8), dimension(pcols), intent(in ) :: tpertg ! PBL temperature perturbation integer, dimension(pcols), intent(in ) :: jb ! updraft base level - integer, dimension(pcols), intent(in ) :: mx ! updraft base level (same is jb) <<<<<< REMOVE REDUNDANCY - integer, dimension(pcols), intent(in ) :: lel ! updraft launch level + integer, dimension(pcols), intent(in ) :: lel ! updraft parcel launch level integer, dimension(pcols), intent(out) :: jt ! updraft plume top integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level integer, dimension(pcols), intent(out) :: j0 ! level where updraft begins detraining @@ -1311,11 +1310,11 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! new tunable parameter tpert_fac was introduced. This introduced new uncertainties into ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. if(zm_param%tpert_fix) then - hu(i,k) = hmn(i,mx(i)) + zm_const%cpair*zm_param%tiedke_add - su(i,k) = s(i,mx(i)) + zm_param%tiedke_add + hu(i,k) = hmn(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add + su(i,k) = s(i,jb(i)) + zm_param%tiedke_add else - hu(i,k) = hmn(i,mx(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) - su(i,k) = s(i,mx(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) + hu(i,k) = hmn(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) + su(i,k) = s(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) end if end if end do @@ -1458,7 +1457,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k = pver,msg + 2,-1 do i = 1,il2g if (k == jb(i) .and. eps0(i) > 0._r8) then - qu(i,k) = q(i,mx(i)) + qu(i,k) = q(i,jb(i)) su(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. eps0(i) > 0._r8) then From 9801736d71d85f0cb9d8faf09a94ffdb673a6cce Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 14:24:29 -0800 Subject: [PATCH 117/398] variable renaming --- components/eam/src/physics/cam/zm_conv.F90 | 240 ++++++++++----------- 1 file changed, 116 insertions(+), 124 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 936f4e263851..8a6284022b2d 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -81,7 +81,7 @@ end subroutine zm_convi !=================================================================================================== subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & - t, qh, omega, pap, paph, dpp, geos, zm, zi, pblh, & + t_mid, qh, omega, pap, paph, dpp, geos, z_mid_in, z_int_in, pblh, & tpert, landfrac, t_star, q_star, & lengath, ideep, maxg, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & @@ -97,15 +97,15 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, intent(in ) :: pverp ! number of interface levels logical, intent(in ) :: is_first_step ! flag for first step of run real(r8), intent(in ) :: delt ! model time-step [s] - real(r8), dimension(pcols,pver), intent(in ) :: t ! temperature [K] + real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] real(r8), dimension(pcols,pver), intent(in ) :: qh ! specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: omega ! vertical pressure velocity [Pa/s] real(r8), dimension(pcols,pver), intent(in ) :: pap ! mid-point pressure [Pa] real(r8), dimension(pcols,pverp),intent(in ) :: paph ! interface pressure [Pa] real(r8), dimension(pcols,pver), intent(in ) :: dpp ! pressure thickness [Pa] real(r8), dimension(pcols), intent(in ) :: geos ! surface geopotential [m2/s2] - real(r8), dimension(pcols,pver), intent(in ) :: zm ! mid-point geopotential [m2/s2] - real(r8), dimension(pcols,pverp),intent(in ) :: zi ! interface geopotential [m2/s2] + real(r8), dimension(pcols,pver), intent(in ) :: z_mid_in ! mid-point geopotential [m2/s2] + real(r8), dimension(pcols,pverp),intent(in ) :: z_int_in ! interface geopotential [m2/s2] real(r8), dimension(pcols), intent(in ) :: pblh ! boundary layer height [m] real(r8), dimension(pcols), intent(in ) :: tpert ! parcel temperature perturbation [K] real(r8), dimension(pcols), intent(in ) :: landfrac ! land fraction @@ -142,8 +142,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! Local variables real(r8), dimension(pcols,pver) :: q ! local copy of specific humidity [kg/kg] real(r8), dimension(pcols,pver) :: p ! local copy of mid-point pressure [mb] - real(r8), dimension(pcols,pver) :: z ! local copy of mid-point altitude [m] - real(r8), dimension(pcols,pverp):: zf ! local copy of interface altitude [m] + real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] + real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] real(r8), dimension(pcols,pverp):: pf ! local copy of interface pressure [mb] real(r8), dimension(pcols,pver) :: s ! scaled dry static energy (t+gz/cp) [K] @@ -182,10 +182,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver) :: qg ! gathered specific humidity real(r8), dimension(pcols,pver) :: tg ! gathered temperature at interface real(r8), dimension(pcols,pver) :: pg ! gathered values of p - real(r8), dimension(pcols,pver) :: zg ! gathered values of z + real(r8), dimension(pcols,pver) :: z_mid_g ! gathered values of z_mid real(r8), dimension(pcols,pver) :: sg ! gathered values of s real(r8), dimension(pcols,pver) :: tpg ! gathered values of tp - real(r8), dimension(pcols,pverp):: zfg ! gathered values of zf + real(r8), dimension(pcols,pverp):: z_int_g ! gathered values of z_int real(r8), dimension(pcols,pver) :: qstpg ! gathered values of qstp real(r8), dimension(pcols,pver) :: ug ! gathered values of u real(r8), dimension(pcols,pver) :: vg ! gathered values of v @@ -209,8 +209,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver) :: su ! gathered updraft dry static energy real(r8), dimension(pcols,pver) :: qs ! gathered saturation specific humidity real(r8), dimension(pcols,pver) :: shat ! gathered upper interface dry static energy - real(r8), dimension(pcols,pver) :: hmn ! gathered moist static energy - real(r8), dimension(pcols,pver) :: hsat ! gathered saturated moist static energy real(r8), dimension(pcols,pver) :: qlg ! gathered cloud liquid water real(r8), dimension(pcols,pver) :: dudt ! gathered u-wind tendency at gathered points real(r8), dimension(pcols,pver) :: dvdt ! gathered v-wind tendency at gathered points @@ -285,20 +283,20 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,ncol zs(i) = geos(i)*zm_const%rgrav pf(i,pver+1) = paph(i,pver+1)*0.01_r8 - zf(i,pver+1) = zi(i,pver+1) + zs(i) + z_int(i,pver+1) = z_int_in(i,pver+1) + zs(i) end do do k = 1,pver do i = 1,ncol p(i,k) = pap(i,k)*0.01_r8 pf(i,k) = paph(i,k)*0.01_r8 - z(i,k) = zm(i,k) + zs(i) - zf(i,k) = zi(i,k) + zs(i) + z_mid(i,k) = z_mid_in(i,k) + zs(i) + z_int(i,k) = z_int_in(i,k) + zs(i) end do end do do k = pver - 1,msg + 1,-1 do i = 1,ncol - if (abs(z(i,k)-zs(i)-pblh(i)) < (zf(i,k)-zf(i,k+1))*0.5_r8) pblt(i) = k + if (abs(z_mid(i,k)-zs(i)-pblh(i)) < (z_int(i,k)-z_int(i,k+1))*0.5_r8) pblt(i) = k end do end do @@ -309,7 +307,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = 1,pver do i = 1,ncol q(i,k) = qh(i,k) - s(i,k) = t(i,k) + (zm_const%grav/zm_const%cpair)*z(i,k) + s(i,k) = t_mid(i,k) + (zm_const%grav/zm_const%cpair)*z_mid(i,k) tp(i,k) = 0.0_r8 shat(i,k) = s(i,k) qhat(i,k) = q(i,k) @@ -334,7 +332,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & iclosure = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & - q, t, z, p, pf, & + q, t_mid, z_mid, p, pf, & pblt, tpert, & tp, qstp, maxi, tl, & lcl, lel, cape, & @@ -347,7 +345,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & dcapemx(:ncol) = maxi(:ncol) call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & - q_star, t_star, z, p, pf, & + q_star, t_star, z_mid, p, pf, & pblt, tpert, & tpm1, qstpm1, maxim1, tlm1, & lclm1, lelm1, capem1, & @@ -404,18 +402,18 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = 1,pver dp(i,k) = 0.01_r8*dpp(ideep(i),k) qg(i,k) = q(ideep(i),k) - tg(i,k) = t(ideep(i),k) + tg(i,k) = t_mid(ideep(i),k) pg(i,k) = p(ideep(i),k) - zg(i,k) = z(ideep(i),k) + z_mid_g(i,k) = z_mid(ideep(i),k) sg(i,k) = s(ideep(i),k) tpg(i,k) = tp(ideep(i),k) - zfg(i,k) = zf(ideep(i),k) + z_int_g(i,k) = z_int(ideep(i),k) qstpg(i,k) = qstp(ideep(i),k) omegag(i,k) = omega(ideep(i),k) ug(i,k) = 0._r8 vg(i,k) = 0._r8 end do - zfg(i,pverp) = zf(ideep(i),pver+1) + z_int_g(i,pverp) = z_int(ideep(i),pver+1) capeg(i) = cape(ideep(i)) lclg(i) = lcl(ideep(i)) lelg(i) = lel(ideep(i)) @@ -426,6 +424,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & tpertg(i) = tpert(ideep(i)) end do + !---------------------------------------------------------------------------- + ! copy aerosol data to gathered arrays + if (zm_param%zm_microp) then if (aero%scheme == 'modal') then do m = 1, aero%nmodes @@ -489,11 +490,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! calculate updraft and downdraft properties call cldprp(pcols, ncol, pver, pverp, lengath, msg, zm_param%limcnv, & - pg, zg, zfg, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & + pg, z_mid_g, z_int_g, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & maxg, lelg, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, qlg, sd, qd, & - hmn, hsat, qs, cug, evpg, pflxg, rprdg, & + qs, cug, evpg, pflxg, rprdg, & aero, loc_microp_st ) !---------------------------------------------------------------------------- @@ -501,15 +502,15 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = msg + 1,pver do i = 1,lengath - du (i,k) = du (i,k)* (zfg(i,k)-zfg(i,k+1))/dp(i,k) - eu (i,k) = eu (i,k)* (zfg(i,k)-zfg(i,k+1))/dp(i,k) - ed (i,k) = ed (i,k)* (zfg(i,k)-zfg(i,k+1))/dp(i,k) - cug (i,k) = cug (i,k)* (zfg(i,k)-zfg(i,k+1))/dp(i,k) - rprdg(i,k) = rprdg(i,k)* (zfg(i,k)-zfg(i,k+1))/dp(i,k) - evpg (i,k) = evpg (i,k)* (zfg(i,k)-zfg(i,k+1))/dp(i,k) + du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + ed (i,k) = ed (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + cug (i,k) = cug (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + rprdg(i,k) = rprdg(i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + evpg (i,k) = evpg (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) if (zm_param%zm_microp) then - loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k) * (zfg(i,k)-zfg(i,k+1))/dp(i,k) - loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k) * (zfg(i,k)-zfg(i,k+1))/dp(i,k) + loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) end if end do end do @@ -517,10 +518,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- call closure(pcols, ncol, pver, pverp, & - qg ,tg ,pg ,zg ,sg , & + qg ,tg ,pg ,z_mid_g ,sg , & tpg ,qs ,qu ,su ,mc , & du ,mu ,md ,qd ,sd , & - qhat ,shat ,dp ,qstpg ,zfg , & + qhat ,shat ,dp ,qstpg ,z_int_g , & qlg ,dsubcld ,mb ,capeg ,tlg , & lclg ,lelg ,jt ,maxg ,1 , & lengath ,msg ,capelmt_wk ) @@ -546,7 +547,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & if (zm_param%no_deep_pbl) then do i=1,lengath - if (zm(ideep(i),jt(i)) < pblh(ideep(i))) mb(i) = 0 + if (z_mid_in(ideep(i),jt(i)) < pblh(ideep(i))) mb(i) = 0 end do end if @@ -677,7 +678,7 @@ end subroutine zm_convr !=================================================================================================== subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & - pmid, pdel, t, q, prdprec, cldfrc, & + pmid, pdel, t_mid, q, prdprec, cldfrc, & tend_s, tend_q, tend_s_snwprd, tend_s_snwevmlt, & prec, snow, ntprprd, ntsnprd, flxprec, flxsnow, microp_st ) !---------------------------------------------------------------------------- @@ -700,7 +701,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & real(r8), intent(in ) :: deltat ! time step [s] real(r8), dimension(pcols,pver), intent(in ) :: pmid ! midpoint pressure [Pa] real(r8), dimension(pcols,pver), intent(in ) :: pdel ! layer thickness [Pa] - real(r8), dimension(pcols,pver), intent(in ) :: t ! temperature [K] + real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] real(r8), dimension(pcols,pver), intent(in ) :: q ! water vapor [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: prdprec ! precipitation production [kg/kg/s] real(r8), dimension(pcols,pver), intent(in ) :: cldfrc ! cloud fraction @@ -743,10 +744,10 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & prec(:ncol) = prec(:ncol)*1000._r8 ! determine saturation vapor pressure - call qsat(t(1:ncol, 1:pver), pmid(1:ncol, 1:pver), es(1:ncol, 1:pver), qs(1:ncol, 1:pver)) + call qsat(t_mid(1:ncol, 1:pver), pmid(1:ncol, 1:pver), es(1:ncol, 1:pver), qs(1:ncol, 1:pver)) ! determine ice fraction in rain production (use cloud water parameterization fraction at present) - call cldfrc_fice(ncol, t, fice, fsnow_conv) + call cldfrc_fice(ncol, t_mid, fice, fsnow_conv) ! zero the flux integrals on the top boundary flxprec(:ncol,1) = 0._r8 @@ -758,7 +759,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! Melt snow falling into layer, if necessary. if( zm_param%old_snow ) then - if (t(i,k) > zm_const%tfreez) then + if (t_mid(i,k) > zm_const%tfreez) then flxsntm(i) = 0._r8 snowmlt(i) = flxsnow(i,k) * zm_const%grav/ pdel(i,k) else @@ -767,10 +768,10 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & end if else ! make sure melting snow doesn't reduce temperature below threshold - if (t(i,k) > zm_const%tfreez) then + if (t_mid(i,k) > zm_const%tfreez) then dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/pdel(i,k)*deltat - if (t(i,k) + dum .le. zm_const%tfreez) then - dum = (t(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/deltat + if (t_mid(i,k) + dum .le. zm_const%tfreez) then + dum = (t_mid(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/deltat dum = dum/(flxsnow(i,k)*zm_const%grav/pdel(i,k)) dum = max(0._r8,dum) dum = min(1._r8,dum) @@ -904,7 +905,7 @@ end subroutine zm_conv_evap !=================================================================================================== subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, & - jb, jt, j0, z, zf, dz, hmn, hsat, hmin, & + jb, jt, j0, z_mid, z_int, dz, hmn, hsat, hmin, & eps, eps0) !---------------------------------------------------------------------------- ! Purpose: Determine properties of ZM updrafts and downdrafts @@ -921,8 +922,8 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, integer, dimension(pcols), intent(in ) :: jb ! updraft base level integer, dimension(pcols), intent(in ) :: jt ! updraft top level integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining - real(r8), dimension(pcols,pver), intent(in ) :: z ! env altitude at mid-point - real(r8), dimension(pcols,pverp),intent(in ) :: zf ! env altitude at interface + real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness real(r8), dimension(pcols,pver), intent(in ) :: hmn ! env moist stat energy real(r8), dimension(pcols,pver), intent(in ) :: hsat ! env saturated moist stat energy @@ -1010,8 +1011,8 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, k1(i,k) = 0._r8 expnum(i)= 0._r8 else - expnum(i) = hmn(i,jb(i)) - (hsat(i,k-1)*(zf(i,k)-z(i,k)) + & - hsat(i,k)* (z(i,k-1)-zf(i,k)))/(z(i,k-1)-z(i,k)) + expnum(i) = hmn(i,jb(i)) - (hsat(i,k-1)*(z_int(i,k)-z_mid(i,k)) + & + hsat(i,k)* (z_mid(i,k-1)-z_int(i,k)))/(z_mid(i,k-1)-z_mid(i,k)) end if if ((expdif(i) > 100._r8 .and. expnum(i) > 0._r8) .and. k1(i,k) > expnum(i)*dz(i,k)) then ftemp(i) = expnum(i) / k1(i,k) @@ -1067,11 +1068,11 @@ end subroutine calculate_fractional_entrainment !=================================================================================================== subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & - p, z, zf, t, s, shat, q, u, v, landfrac, tpertg, & + p, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, ql, sd, qd, & - hmn, hsat, qst, cu, evp, pflx, rprd, & + qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) !---------------------------------------------------------------------------- ! Purpose: Determine properties of ZM updrafts and downdrafts @@ -1087,9 +1088,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer, intent(in ) :: msg ! missing moisture levels integer, intent(in ) :: limcnv ! convection limiting level real(r8), dimension(pcols,pver), intent(in ) :: p ! env pressure at mid-point - real(r8), dimension(pcols,pver), intent(in ) :: z ! env altitude at mid-point - real(r8), dimension(pcols,pverp),intent(in ) :: zf ! env altitude at interface - real(r8), dimension(pcols,pver), intent(in ) :: t ! env temperature + real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface + real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! env temperature real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) real(r8), dimension(pcols,pver), intent(in ) :: shat ! interface values of dry stat energy real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity @@ -1101,7 +1102,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer, dimension(pcols), intent(in ) :: lel ! updraft parcel launch level integer, dimension(pcols), intent(out) :: jt ! updraft plume top integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level - integer, dimension(pcols), intent(out) :: j0 ! level where updraft begins detraining + integer, dimension(pcols), intent(out) :: j0 ! level where detrainment begins (starting at hmin) integer, dimension(pcols), intent(out) :: jd ! level of downdraft real(r8), dimension(pcols,pver), intent(out) :: mu ! updraft mass flux real(r8), dimension(pcols,pver), intent(out) :: eu ! entrainment rate of updraft @@ -1114,8 +1115,6 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water real(r8), dimension(pcols,pver), intent(out) :: sd ! dndraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: qd ! dndraft specific humidity [kg/kg] - real(r8), dimension(pcols,pver), intent(out) :: hmn ! env moist stat energy - real(r8), dimension(pcols,pver), intent(out) :: hsat ! env saturated moist stat energy real(r8), dimension(pcols,pver), intent(out) :: qst ! env saturation mixing ratio real(r8), dimension(pcols,pver), intent(out) :: cu ! condensation rate real(r8), dimension(pcols,pver), intent(out) :: evp ! evaporation rate @@ -1127,6 +1126,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! Local variables real(r8), dimension(pcols,pver) :: gamma ! latent-heating correction for pseudo-adiabatic parcel lifting real(r8), dimension(pcols,pver) :: dz ! layer thickness + real(r8), dimension(pcols,pver) :: hmn ! env moist stat energy + real(r8), dimension(pcols,pver) :: hsat ! env saturated moist stat energy real(r8), dimension(pcols,pver) :: hu ! updraft moist static energy real(r8), dimension(pcols,pver) :: hd ! dndraft moist static energy real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst @@ -1145,20 +1146,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) - ! ! variables used for Taylor series expansion when solving eq (4.78) for lamda_D real(r8), dimension(pcols,pver) :: eps ! fractional entrainment - ! real(r8), dimension(pcols,pver) :: f ! ? - ! real(r8), dimension(pcols) :: ftemp ! temporary value of f real(r8), dimension(pcols) :: eps0 ! fractional entrainment max - ! real(r8), dimension(pcols) :: expdif ! diff between env MSE low-level max and mid-level min - ! real(r8), dimension(pcols) :: expnum ! ? - ! real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series - ! real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series - ! real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series - ! real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series - ! real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series - ! real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series - ! real(r8), dimension(pcols,pver) :: idag ! term for Taylor series real(r8) ql1 ! ? real(r8) tu ! ? @@ -1221,13 +1210,13 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & rprd(i,k) = 0._r8 pflx(i,k) = 0._r8 ! calculate layer thickness - dz(i,k) = zf(i,k) - zf(i,k+1) + dz(i,k) = z_int(i,k) - z_int(i,k+1) ! calculate saturation specific humidity - call qsat_hPa(t(i,k), p(i,k), est(i), qst(i,k)) + call qsat_hPa(t_mid(i,k), p(i,k), est(i), qst(i,k)) if ( p(i,k)-est(i) <= 0._r8 ) qst(i,k) = 1.0_r8 ! compute gamma - see eq. (4.117) gamma(i,k) = qst(i,k)*(1._r8 + qst(i,k)/zm_const%epsilo) & - * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t(i,k)**2) & + * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_mid(i,k)**2) & * zm_const%latvap/zm_const%cpair ! cloud thermodynamic variables su(i,k) = s(i,k) @@ -1235,8 +1224,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & qd(i,k) = q(i,k) qds(i,k) = q(i,k) qu(i,k) = q(i,k) - hmn(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*q(i,k) - hsat(i,k) = zm_const%cpair*t(i,k) + zm_const%grav*z(i,k) + zm_const%latvap*qst(i,k) + hmn(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q(i,k) + hsat(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*qst(i,k) hu(i,k) = hmn(i,k) hd(i,k) = hmn(i,k) ! convective microphysics @@ -1323,7 +1312,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! calculate fractional entrainment (i.e. "lambda D") - see eq (4.78) from Neale et al. (2012) call calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, & - jb, jt, j0, z, zf, dz, hmn, hsat, hmin, & + jb, jt, j0, z_mid, z_int, dz, hmn, hsat, hmin, & eps, eps0) !---------------------------------------------------------------------------- @@ -1360,7 +1349,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & if (.not.zm_param%zm_microp) tmp_k_limit = jt(i) ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) if ( k>=tmp_k_limit .and. k jt(i) .and. k < jb(i)) .and. eps0(i) > 0._r8) then su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s(i,k) qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q(i,k) - du(i,k)*qst(i,k)) - tu = su(i,k) - zm_const%grav/zm_const%cpair*zf(i,k) + tu = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) call qsat_hPa(tu, (p(i,k)+p(i,k-1))/2._r8, estu, qstu) if (qu(i,k) >= qstu) then jlcl(i) = k @@ -1510,12 +1499,12 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & if (zm_param%zm_microp) then - tug(:il2g,:) = t(:il2g,:) + tug(:il2g,:) = t_mid(:il2g,:) fice(:,:) = 0._r8 do k = pver, msg+2, -1 do i = 1, il2g - tug(i,k) = su(i,k) - zm_const%grav/zm_const%cpair*zf(i,k) + tug(i,k) = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) end do end do @@ -1545,7 +1534,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & call zm_mphy( pcols, il2g, msg, & zm_const%grav, zm_const%cpair, zm_const%rdair, & zm_param%auto_fac, zm_param%accr_fac, zm_param%micro_dcs, & - jb, jt, jlcl, su, qu, mu, du, eu, zf, p, t, q, gamhat, eps0, & + jb, jt, jlcl, su, qu, mu, du, eu, z_int, p, t_mid, q, gamhat, eps0, & loc_microp_st%cmel, loc_microp_st%cmei, aero, & loc_microp_st%qliq, loc_microp_st%qice, loc_microp_st%qnl, loc_microp_st%qni, & loc_microp_st%qcde, loc_microp_st%qide, loc_microp_st%ncde, loc_microp_st%nide, & @@ -1648,7 +1637,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do k = msg + 1,pver do i = 1,il2g if ((k > jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8) then - zdef(i) = zf(i,jd(i)) - zf(i,k) + zdef(i) = z_int(i,jd(i)) - z_int(i,k) md(i,k) = -zm_param%alfa / (2._r8*eps0(i))*(exp(2._r8*epsm(i)*zdef(i))-1._r8)/zdef(i) end if end do @@ -1786,10 +1775,10 @@ end subroutine cldprp !=================================================================================================== subroutine closure(pcols, ncol, pver, pverp, & - q ,t ,p ,z ,s , & + q ,t_mid ,p ,z_mid ,s , & tp ,qs ,qu ,su ,mc , & du ,mu ,md ,qd ,sd , & - qhat ,shat ,dp ,qstp ,zf , & + qhat ,shat ,dp ,qstp ,z_int , & ql ,dsubcld ,mb ,cape ,tl , & lcl ,lel ,jt ,mx ,il1g , & il2g ,msg ,capelmt ) @@ -1822,10 +1811,10 @@ subroutine closure(pcols, ncol, pver, pverp, & integer, intent(in) :: pver ! number of mid-point vertical levels integer, intent(in) :: pverp ! number of interface vertical levels real(r8), intent(inout) :: q(pcols,pver) ! spec humidity - real(r8), intent(inout) :: t(pcols,pver) ! temperature + real(r8), intent(inout) :: t_mid(pcols,pver) ! temperature real(r8), intent(inout) :: p(pcols,pver) ! pressure (mb) real(r8), intent(inout) :: mb(pcols) ! cloud base mass flux - real(r8), intent(in) :: z(pcols,pver) ! height (m) + real(r8), intent(in) :: z_mid(pcols,pver) ! height (m) real(r8), intent(in) :: s(pcols,pver) ! normalized dry static energy real(r8), intent(in) :: tp(pcols,pver) ! parcel temp real(r8), intent(in) :: qs(pcols,pver) ! sat spec humidity @@ -1841,7 +1830,7 @@ subroutine closure(pcols, ncol, pver, pverp, & real(r8), intent(in) :: shat(pcols,pver) ! env. normalized dry static energy at intrfcs real(r8), intent(in) :: dp(pcols,pver) ! pressure thickness of layers real(r8), intent(in) :: qstp(pcols,pver) ! spec humidity of parcel - real(r8), intent(in) :: zf(pcols,pver+1) ! height of interface levels + real(r8), intent(in) :: z_int(pcols,pver+1) ! height of interface levels real(r8), intent(in) :: ql(pcols,pver) ! liquid water mixing ratio real(r8), intent(in) :: cape(pcols) ! available pot. energy of column @@ -1893,8 +1882,8 @@ subroutine closure(pcols, ncol, pver, pverp, & dqbdt(i) = (1._r8/dsubcld(i))* (mu(i,mx(i))*(qhat(i,mx(i))-qu(i,mx(i)))+ & md(i,mx(i))* (qhat(i,mx(i))-qd(i,mx(i)))) debdt = zm_const%epsilo*p(i,mx(i))/ (zm_const%epsilo+q(i,mx(i)))**2*dqbdt(i) - dtldt(i) = -2840._r8* (3.5_r8/t(i,mx(i))*dtbdt(i)-debdt/eb)/ & - (3.5_r8*log(t(i,mx(i)))-log(eb)-4.805_r8)**2 + dtldt(i) = -2840._r8* (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & + (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 end do ! ! dtmdt and dqmdt are cumulus heating and drying. @@ -1941,20 +1930,20 @@ subroutine closure(pcols, ncol, pver, pverp, & do i = il1g,il2g if (k >= lel(i) .and. k <= lcl(i)) then thetavp(i,k) = tp(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) - thetavm(i,k) = t(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + thetavm(i,k) = t_mid(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) dqsdtp(i,k) = qstp(i,k)* (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) ! ! dtpdt is the parcel temperature change due to change of ! subcloud layer properties during convection. ! dtpdt(i,k) = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp(i,k)-qstp(i,k)/tp(i,k)))* & - (dtbdt(i)/t(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/ & + (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/ & tl(i)**2*dtldt(i))) ! ! dboydt is the integrand of cape change. ! dboydt(i,k) = ((dtpdt(i,k)/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i)))* & - (1.608_r8 * dqsdtp(i,k) * dtpdt(i,k) -dqbdt(i))) - (dtmdt(i,k)/t(i,k)+0.608_r8/ & + (1.608_r8 * dqsdtp(i,k) * dtpdt(i,k) -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & (1._r8+0.608_r8*q(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp(i,k)/thetavm(i,k) end if end do @@ -1964,12 +1953,12 @@ subroutine closure(pcols, ncol, pver, pverp, & do i = il1g,il2g if (k > lcl(i) .and. k < mx(i)) then thetavp(i,k) = tp(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,mx(i))) - thetavm(i,k) = t(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + thetavm(i,k) = t_mid(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) ! ! dboydt is the integrand of cape change. ! - dboydt(i,k) = (dtbdt(i)/t(i,mx(i))+0.608_r8/ (1._r8+0.608_r8*q(i,mx(i)))*dqbdt(i)- & - dtmdt(i,k)/t(i,k)-0.608_r8/ (1._r8+0.608_r8*q(i,k))*dqmdt(i,k))* & + dboydt(i,k) = (dtbdt(i)/t_mid(i,mx(i))+0.608_r8/ (1._r8+0.608_r8*q(i,mx(i)))*dqbdt(i)- & + dtmdt(i,k)/t_mid(i,k)-0.608_r8/ (1._r8+0.608_r8*q(i,k))*dqmdt(i,k))* & zm_const%grav*thetavp(i,k)/thetavm(i,k) end if end do @@ -1984,7 +1973,7 @@ subroutine closure(pcols, ncol, pver, pverp, & do k = kmin, kmax do i = il1g,il2g if ( k >= lel(i) .and. k <= mx(i) - 1) then - dadt(i) = dadt(i) + dboydt(i,k)* (zf(i,k)-zf(i,k+1)) + dadt(i) = dadt(i) + dboydt(i,k)* (z_int(i,k)-z_int(i,k+1)) endif end do end do @@ -2012,35 +2001,33 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & implicit none !---------------------------------------------------------------------------- ! Arguments - integer, intent(in) :: pcols ! maximum number of columns - integer, intent(in) :: ncol ! actual number of columns - integer, intent(in) :: pver ! number of mid-point vertical levels - integer, intent(in) :: pverp ! number of interface vertical levels - integer, intent(in) :: il1g - integer, intent(in) :: il2g - integer, intent(in) :: msg - - real(r8), intent(in) :: q(pcols,pver) - real(r8), intent(in) :: qs(pcols,pver) - real(r8), intent(in) :: qu(pcols,pver) - real(r8), intent(in) :: su(pcols,pver) - real(r8), intent(in) :: du(pcols,pver) - real(r8), intent(in) :: qhat(pcols,pver) - real(r8), intent(in) :: shat(pcols,pver) - real(r8), intent(in) :: dp(pcols,pver) - real(r8), intent(in) :: mu(pcols,pver) - real(r8), intent(in) :: md(pcols,pver) - real(r8), intent(in) :: sd(pcols,pver) - real(r8), intent(in) :: qd(pcols,pver) - real(r8), intent(in) :: ql(pcols,pver) - real(r8), intent(in) :: evp(pcols,pver) - real(r8), intent(in) :: cu(pcols,pver) - real(r8), intent(in) :: dsubcld(pcols) - - real(r8),intent(out) :: dqdt(pcols,pver),dsdt(pcols,pver) - real(r8),intent(out) :: dl(pcols,pver) - - type(zm_microp_st), intent(inout) :: loc_microp_st ! convective microphysics state and tendencies + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: il1g ! + integer, intent(in ) :: il2g ! + integer, intent(in ) :: msg ! + real(r8), dimension(pcols,pver), intent(in ) :: q ! + real(r8), dimension(pcols,pver), intent(in ) :: qs ! + real(r8), dimension(pcols,pver), intent(in ) :: qu ! + real(r8), dimension(pcols,pver), intent(in ) :: su ! + real(r8), dimension(pcols,pver), intent(in ) :: du ! + real(r8), dimension(pcols,pver), intent(in ) :: qhat ! + real(r8), dimension(pcols,pver), intent(in ) :: shat ! + real(r8), dimension(pcols,pver), intent(in ) :: dp ! + real(r8), dimension(pcols,pver), intent(in ) :: mu ! + real(r8), dimension(pcols,pver), intent(in ) :: md ! + real(r8), dimension(pcols,pver), intent(in ) :: sd ! + real(r8), dimension(pcols,pver), intent(in ) :: qd ! + real(r8), dimension(pcols,pver), intent(in ) :: ql ! + real(r8), dimension(pcols,pver), intent(in ) :: evp ! + real(r8), dimension(pcols,pver), intent(in ) :: cu ! + real(r8), dimension(pcols), intent(in ) :: dsubcld ! + real(r8), dimension(pcols,pver), intent( out) :: dqdt ! + real(r8), dimension(pcols,pver), intent( out) :: dsdt ! + real(r8), dimension(pcols,pver), intent( out) :: dl ! + type(zm_microp_st), intent(inout) :: loc_microp_st! convective microphysics state and tendencies !---------------------------------------------------------------------------- ! Local variables integer i,k @@ -2050,6 +2037,7 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & integer mx(pcols) real(r8) emc !---------------------------------------------------------------------------- + ! initialize variables do k = msg + 1,pver do i = il1g,il2g dsdt(i,k) = 0._r8 @@ -2066,6 +2054,7 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & end do end do + !---------------------------------------------------------------------------- ! find the highest level top and bottom levels of convection ktm = pver kbm = pver @@ -2074,6 +2063,8 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & kbm = min(kbm,mx(i)) end do + !---------------------------------------------------------------------------- + ! calculate large-scale tendencies do k = ktm,pver-1 do i = il1g,il2g emc = -cu(i,k) + evp(i,k) ! condensation in updraft and evaporating rain in downdraft @@ -2108,7 +2099,8 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & end do end do -! + !---------------------------------------------------------------------------- + ! calculate large-scale tendencies at and below cloud base #ifdef CPRCRAY !DIR$ NOINTERCHANGE! #endif @@ -2129,7 +2121,7 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & end if end do end do -! + !---------------------------------------------------------------------------- return end subroutine q1q2_pjr From 9f8eb31e6194af2c4e768e62f18e43fa0abfe114 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 15:19:07 -0800 Subject: [PATCH 118/398] more renaming --- components/eam/src/physics/cam/zm_conv.F90 | 183 +++++++++++---------- 1 file changed, 93 insertions(+), 90 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 8a6284022b2d..404ef48e7907 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -22,7 +22,7 @@ module zm_conv #endif use zm_conv_cape, only: compute_dilute_cape use zm_conv_types, only: zm_const_t, zm_param_t - use zm_conv_util, only: qsat_hpa ! remove after moving cldprp to new module + use zm_conv_util, only: qsat_hpa use zm_aero_type, only: zm_aero_t use zm_microphysics_state, only: zm_microp_st, zm_microp_st_alloc, zm_microp_st_dealloc use zm_microphysics_state, only: zm_microp_st_ini, zm_microp_st_zero, zm_microp_st_scatter @@ -81,7 +81,8 @@ end subroutine zm_convi !=================================================================================================== subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & - t_mid, qh, omega, pap, paph, dpp, geos, z_mid_in, z_int_in, pblh, & + t_mid, qh, omega, p_mid_in, p_int_in, p_del_in, & + geos, z_mid_in, z_int_in, pbl_hgt, & tpert, landfrac, t_star, q_star, & lengath, ideep, maxg, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & @@ -100,13 +101,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] real(r8), dimension(pcols,pver), intent(in ) :: qh ! specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: omega ! vertical pressure velocity [Pa/s] - real(r8), dimension(pcols,pver), intent(in ) :: pap ! mid-point pressure [Pa] - real(r8), dimension(pcols,pverp),intent(in ) :: paph ! interface pressure [Pa] - real(r8), dimension(pcols,pver), intent(in ) :: dpp ! pressure thickness [Pa] + real(r8), dimension(pcols,pver), intent(in ) :: p_mid_in ! mid-point pressure [Pa] + real(r8), dimension(pcols,pverp),intent(in ) :: p_int_in ! interface pressure [Pa] + real(r8), dimension(pcols,pver), intent(in ) :: p_del_in ! pressure thickness [Pa] real(r8), dimension(pcols), intent(in ) :: geos ! surface geopotential [m2/s2] real(r8), dimension(pcols,pver), intent(in ) :: z_mid_in ! mid-point geopotential [m2/s2] real(r8), dimension(pcols,pverp),intent(in ) :: z_int_in ! interface geopotential [m2/s2] - real(r8), dimension(pcols), intent(in ) :: pblh ! boundary layer height [m] + real(r8), dimension(pcols), intent(in ) :: pbl_hgt ! boundary layer height [m] real(r8), dimension(pcols), intent(in ) :: tpert ! parcel temperature perturbation [K] real(r8), dimension(pcols), intent(in ) :: landfrac ! land fraction real(r8),pointer,dimension(:,:), intent(in ) :: t_star ! for DCAPE - prev temperature [K] @@ -140,22 +141,21 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- ! Local variables + real(r8), dimension(pcols,pver) :: s ! scaled dry static energy (t+gz/cp) [K] real(r8), dimension(pcols,pver) :: q ! local copy of specific humidity [kg/kg] - real(r8), dimension(pcols,pver) :: p ! local copy of mid-point pressure [mb] + real(r8), dimension(pcols,pver) :: p_mid ! local copy of mid-point pressure [mb] + real(r8), dimension(pcols,pverp):: p_int ! local copy of interface pressure [mb] real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] - real(r8), dimension(pcols,pverp):: pf ! local copy of interface pressure [mb] - real(r8), dimension(pcols,pver) :: s ! scaled dry static energy (t+gz/cp) [K] - - real(r8), dimension(pcols) :: zs ! surface altitude [m] + real(r8), dimension(pcols) :: z_srf ! surface altitude [m] real(r8), dimension(pcols,pver) :: dlg ! gathered detraining cld h2o tend real(r8), dimension(pcols,pverp):: pflxg ! gathered precip flux at each level real(r8), dimension(pcols,pver) :: cug ! gathered condensation rate real(r8), dimension(pcols,pver) :: evpg ! gathered evap rate of rain in downdraft real(r8), dimension(pcols) :: mumax ! max value of mu/dp - integer, dimension(pcols) :: pblt ! pbl top indices - integer, dimension(pcols) :: pbltg ! gathered pbl top indices + integer, dimension(pcols) :: pbl_top ! pbl top indices + integer, dimension(pcols) :: pbl_top_g ! gathered pbl top indices real(r8), dimension(pcols,pver) :: tp ! parcel temperature [K] real(r8), dimension(pcols,pver) :: qstp ! parcel saturation specific humidity [kg/kg] @@ -261,7 +261,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & rliq(i) = 0._r8 pflx(i,pverp) = 0 pflxg(i,pverp) = 0 - pblt(i) = pver + pbl_top(i) = pver dsubcld(i) = 0._r8 jctop(i) = pver jcbot(i) = 1 @@ -281,22 +281,26 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! calculate local pressure (mbs) and height (m) for both interface and mid-point do i = 1,ncol - zs(i) = geos(i)*zm_const%rgrav - pf(i,pver+1) = paph(i,pver+1)*0.01_r8 - z_int(i,pver+1) = z_int_in(i,pver+1) + zs(i) + z_srf(i) = geos(i)*zm_const%rgrav + p_int(i,pver+1) = p_int_in(i,pver+1)*0.01_r8 + z_int(i,pver+1) = z_int_in(i,pver+1) + z_srf(i) end do do k = 1,pver do i = 1,ncol - p(i,k) = pap(i,k)*0.01_r8 - pf(i,k) = paph(i,k)*0.01_r8 - z_mid(i,k) = z_mid_in(i,k) + zs(i) - z_int(i,k) = z_int_in(i,k) + zs(i) + p_mid(i,k) = p_mid_in(i,k)*0.01_r8 + p_int(i,k) = p_int_in(i,k)*0.01_r8 + z_mid(i,k) = z_mid_in(i,k) + z_srf(i) + z_int(i,k) = z_int_in(i,k) + z_srf(i) end do end do + !---------------------------------------------------------------------------- + ! locate PBL top index do k = pver - 1,msg + 1,-1 do i = 1,ncol - if (abs(z_mid(i,k)-zs(i)-pblh(i)) < (z_int(i,k)-z_int(i,k+1))*0.5_r8) pblt(i) = k + if (abs(z_mid(i,k)-z_srf(i)-pbl_hgt(i)) < (z_int(i,k)-z_int(i,k+1))*0.5_r8) then + pbl_top(i) = k + end if end do end do @@ -332,8 +336,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & iclosure = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & - q, t_mid, z_mid, p, pf, & - pblt, tpert, & + q, t_mid, z_mid, p_mid, p_int, & + pbl_top, tpert, & tp, qstp, maxi, tl, & lcl, lel, cape, & zm_const, zm_param, & @@ -345,8 +349,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & dcapemx(:ncol) = maxi(:ncol) call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & - q_star, t_star, z_mid, p, pf, & - pblt, tpert, & + q_star, t_star, z_mid, p_mid, p_int, & + pbl_top, tpert, & tpm1, qstpm1, maxim1, tlm1, & lclm1, lelm1, capem1, & zm_const, zm_param, & @@ -400,28 +404,28 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,lengath do k = 1,pver - dp(i,k) = 0.01_r8*dpp(ideep(i),k) - qg(i,k) = q(ideep(i),k) - tg(i,k) = t_mid(ideep(i),k) - pg(i,k) = p(ideep(i),k) - z_mid_g(i,k) = z_mid(ideep(i),k) - sg(i,k) = s(ideep(i),k) - tpg(i,k) = tp(ideep(i),k) + dp(i,k) = 0.01_r8*p_del_in(ideep(i),k) + qg(i,k) = q(ideep(i),k) + tg(i,k) = t_mid(ideep(i),k) + pg(i,k) = p_mid(ideep(i),k) + z_mid_g(i,k) = z_mid(ideep(i),k) + sg(i,k) = s(ideep(i),k) + tpg(i,k) = tp(ideep(i),k) z_int_g(i,k) = z_int(ideep(i),k) - qstpg(i,k) = qstp(ideep(i),k) - omegag(i,k) = omega(ideep(i),k) - ug(i,k) = 0._r8 - vg(i,k) = 0._r8 + qstpg(i,k) = qstp(ideep(i),k) + omegag(i,k) = omega(ideep(i),k) + ug(i,k) = 0._r8 + vg(i,k) = 0._r8 end do - z_int_g(i,pverp) = z_int(ideep(i),pver+1) - capeg(i) = cape(ideep(i)) - lclg(i) = lcl(ideep(i)) - lelg(i) = lel(ideep(i)) - maxg(i) = maxi(ideep(i)) - tlg(i) = tl(ideep(i)) - landfracg(i) = landfrac(ideep(i)) - pbltg(i) = pblt(ideep(i)) - tpertg(i) = tpert(ideep(i)) + z_int_g(i,pverp) = z_int(ideep(i),pver+1) + capeg(i) = cape(ideep(i)) + lclg(i) = lcl(ideep(i)) + lelg(i) = lel(ideep(i)) + maxg(i) = maxi(ideep(i)) + tlg(i) = tl(ideep(i)) + landfracg(i) = landfrac(ideep(i)) + pbl_top_g(i) = pbl_top(ideep(i)) + tpertg(i) = tpert(ideep(i)) end do !---------------------------------------------------------------------------- @@ -539,7 +543,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & else mb(i) = 0._r8 endif - if (zm_param%clos_dyn_adj) mb(i) = max(mb(i) - omegag(i,pbltg(i))*0.01_r8, 0._r8) + if (zm_param%clos_dyn_adj) mb(i) = max(mb(i) - omegag(i,pbl_top_g(i))*0.01_r8, 0._r8) end do !---------------------------------------------------------------------------- @@ -547,7 +551,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & if (zm_param%no_deep_pbl) then do i=1,lengath - if (z_mid_in(ideep(i),jt(i)) < pblh(ideep(i))) mb(i) = 0 + if (z_mid_in(ideep(i),jt(i)) < pbl_hgt(ideep(i))) mb(i) = 0 end do end if @@ -585,13 +589,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! compute temperature and moisture changes due to convection. - call q1q2_pjr(pcols, ncol, pver, pverp, & - dqdt ,dsdt ,qg ,qs ,qu , & - su ,du ,qhat ,shat ,dp , & - mu ,md ,sd ,qd ,qlg , & - dsubcld ,jt ,maxg ,1 ,lengath , msg, & - dlg ,evpg ,cug ,& - loc_microp_st) + call zm_calculate_output_tend(pcols, ncol, pver, pverp, & + dqdt, dsdt, qg, qs, qu, & + su, du, qhat, shat, dp, & + mu, md, sd, qd, qlg, & + dsubcld, jt, maxg, 1, lengath, msg, & + dlg, evpg, cug, & + loc_microp_st) !---------------------------------------------------------------------------- ! conservation check and adjusment @@ -641,9 +645,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,ncol do k = pver,msg + 1,-1 if (zm_param%zm_microp) then - prec(i) = prec(i) - dpp(i,k)* (q(i,k)-qh(i,k)) - dpp(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt else - prec(i) = prec(i) - dpp(i,k)* (q(i,k)-qh(i,k)) - dpp(i,k)*(dlf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k))*2._r8*delt end if end do ! obtain final precipitation rate in m/s @@ -656,11 +660,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = 1, pver do i = 1, ncol if (zm_param%zm_microp) then - rliq(i) = rliq(i) + (dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*dpp(i,k)/zm_const%grav + rliq(i) = rliq(i) + (dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*p_del_in(i,k)/zm_const%grav microp_st%rice(i) = microp_st%rice(i) & - + (microp_st%dif(i,k)+microp_st%dsf(i,k))*dpp(i,k)/zm_const%grav + + (microp_st%dif(i,k)+microp_st%dsf(i,k))*p_del_in(i,k)/zm_const%grav else - rliq(i) = rliq(i) + dlf(i,k)*dpp(i,k)/zm_const%grav + rliq(i) = rliq(i) + dlf(i,k)*p_del_in(i,k)/zm_const%grav end if end do end do @@ -1068,7 +1072,7 @@ end subroutine calculate_fractional_entrainment !=================================================================================================== subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & - p, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & + p_mid, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, ql, sd, qd, & @@ -1087,7 +1091,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer, intent(in ) :: il2g ! number of gathered columns (lengath) integer, intent(in ) :: msg ! missing moisture levels integer, intent(in ) :: limcnv ! convection limiting level - real(r8), dimension(pcols,pver), intent(in ) :: p ! env pressure at mid-point + real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! env pressure at mid-point real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! env temperature @@ -1212,8 +1216,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! calculate layer thickness dz(i,k) = z_int(i,k) - z_int(i,k+1) ! calculate saturation specific humidity - call qsat_hPa(t_mid(i,k), p(i,k), est(i), qst(i,k)) - if ( p(i,k)-est(i) <= 0._r8 ) qst(i,k) = 1.0_r8 + call qsat_hPa(t_mid(i,k), p_mid(i,k), est(i), qst(i,k)) + if ( p_mid(i,k)-est(i) <= 0._r8 ) qst(i,k) = 1.0_r8 ! compute gamma - see eq. (4.117) gamma(i,k) = qst(i,k)*(1._r8 + qst(i,k)/zm_const%epsilo) & * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_mid(i,k)**2) & @@ -1453,7 +1457,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s(i,k) qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q(i,k) - du(i,k)*qst(i,k)) tu = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) - call qsat_hPa(tu, (p(i,k)+p(i,k-1))/2._r8, estu, qstu) + call qsat_hPa(tu, (p_mid(i,k)+p_mid(i,k-1))/2._r8, estu, qstu) if (qu(i,k) >= qstu) then jlcl(i) = k kount = kount + 1 @@ -1534,7 +1538,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & call zm_mphy( pcols, il2g, msg, & zm_const%grav, zm_const%cpair, zm_const%rdair, & zm_param%auto_fac, zm_param%accr_fac, zm_param%micro_dcs, & - jb, jt, jlcl, su, qu, mu, du, eu, z_int, p, t_mid, q, gamhat, eps0, & + jb, jt, jlcl, su, qu, mu, du, eu, z_int, p_mid, t_mid, q, gamhat, eps0, & loc_microp_st%cmel, loc_microp_st%cmei, aero, & loc_microp_st%qliq, loc_microp_st%qice, loc_microp_st%qnl, loc_microp_st%qni, & loc_microp_st%qcde, loc_microp_st%qide, loc_microp_st%ncde, loc_microp_st%nide, & @@ -1775,7 +1779,7 @@ end subroutine cldprp !=================================================================================================== subroutine closure(pcols, ncol, pver, pverp, & - q ,t_mid ,p ,z_mid ,s , & + q ,t_mid ,p_mid ,z_mid ,s , & tp ,qs ,qu ,su ,mc , & du ,mu ,md ,qd ,sd , & qhat ,shat ,dp ,qstp ,z_int , & @@ -1812,7 +1816,7 @@ subroutine closure(pcols, ncol, pver, pverp, & integer, intent(in) :: pverp ! number of interface vertical levels real(r8), intent(inout) :: q(pcols,pver) ! spec humidity real(r8), intent(inout) :: t_mid(pcols,pver) ! temperature - real(r8), intent(inout) :: p(pcols,pver) ! pressure (mb) + real(r8), intent(inout) :: p_mid(pcols,pver) ! pressure (mb) real(r8), intent(inout) :: mb(pcols) ! cloud base mass flux real(r8), intent(in) :: z_mid(pcols,pver) ! height (m) real(r8), intent(in) :: s(pcols,pver) ! normalized dry static energy @@ -1876,12 +1880,12 @@ subroutine closure(pcols, ncol, pver, pverp, & ! do i = il1g,il2g mb(i) = 0._r8 - eb = p(i,mx(i))*q(i,mx(i))/ (zm_const%epsilo+q(i,mx(i))) + eb = p_mid(i,mx(i))*q(i,mx(i))/ (zm_const%epsilo+q(i,mx(i))) dtbdt(i) = (1._r8/dsubcld(i))* (mu(i,mx(i))*(shat(i,mx(i))-su(i,mx(i)))+ & md(i,mx(i))* (shat(i,mx(i))-sd(i,mx(i)))) dqbdt(i) = (1._r8/dsubcld(i))* (mu(i,mx(i))*(qhat(i,mx(i))-qu(i,mx(i)))+ & md(i,mx(i))* (qhat(i,mx(i))-qd(i,mx(i)))) - debdt = zm_const%epsilo*p(i,mx(i))/ (zm_const%epsilo+q(i,mx(i)))**2*dqbdt(i) + debdt = zm_const%epsilo*p_mid(i,mx(i))/ (zm_const%epsilo+q(i,mx(i)))**2*dqbdt(i) dtldt(i) = -2840._r8* (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 end do @@ -1929,8 +1933,8 @@ subroutine closure(pcols, ncol, pver, pverp, & do k = msg + 1,pver do i = il1g,il2g if (k >= lel(i) .and. k <= lcl(i)) then - thetavp(i,k) = tp(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) - thetavm(i,k) = t_mid(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + thetavp(i,k) = tp(i,k)* (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) + thetavm(i,k) = t_mid(i,k)* (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) dqsdtp(i,k) = qstp(i,k)* (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) ! ! dtpdt is the parcel temperature change due to change of @@ -1952,8 +1956,8 @@ subroutine closure(pcols, ncol, pver, pverp, & do k = msg + 1,pver do i = il1g,il2g if (k > lcl(i) .and. k < mx(i)) then - thetavp(i,k) = tp(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,mx(i))) - thetavm(i,k) = t_mid(i,k)* (1000._r8/p(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + thetavp(i,k) = tp(i,k) * (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,mx(i))) + thetavm(i,k) = t_mid(i,k)* (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) ! ! dboydt is the integrand of cape change. ! @@ -1988,13 +1992,13 @@ end subroutine closure !=================================================================================================== -subroutine q1q2_pjr(pcols, ncol, pver, pverp, & - dqdt ,dsdt ,q ,qs ,qu , & - su ,du ,qhat ,shat ,dp , & - mu ,md ,sd ,qd ,ql , & - dsubcld ,jt ,mx ,il1g ,il2g , msg, & - dl ,evp ,cu ,& - loc_microp_st) +subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & + dqdt, dsdt, q, qs, qu, & + su, du, qhat, shat, dp, & + mu, md, sd, qd, ql, & + dsubcld, jt, mx, il1g, il2g, msg, & + dl, evp, cu, & + loc_microp_st) !---------------------------------------------------------------------------- ! Purpose: initialize quantities for ZM convection scheme !---------------------------------------------------------------------------- @@ -2076,8 +2080,6 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & -md(i,k)* (sd(i,k)-shat(i,k)) & )/dp(i,k) - if (zm_param%zm_microp) dsdt(i,k) = dsdt(i,k) + zm_const%latice/zm_const%cpair*loc_microp_st%frz(i,k) - dqdt(i,k) = emc + & (+mu(i,k+1)* (qu(i,k+1)-qhat(i,k+1)) & -mu(i,k)* (qu(i,k)-qhat(i,k)) & @@ -2086,12 +2088,13 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & )/dp(i,k) if (zm_param%zm_microp) then - dl (i,k) = du(i,k)*loc_microp_st%qcde(i,k+1) - loc_microp_st%dif (i,k) = du(i,k)*loc_microp_st%qide(i,k+1) - loc_microp_st%dnlf(i,k) = du(i,k)*loc_microp_st%ncde(i,k+1) - loc_microp_st%dnif(i,k) = du(i,k)*loc_microp_st%nide(i,k+1) - loc_microp_st%dsf (i,k) = du(i,k)*loc_microp_st%qsde(i,k+1) - loc_microp_st%dnsf(i,k) = du(i,k)*loc_microp_st%nsde(i,k+1) + dsdt(i,k) = dsdt(i,k) + zm_const%latice/zm_const%cpair*loc_microp_st%frz(i,k) + dl (i,k) = du(i,k)*loc_microp_st%qcde(i,k+1) + loc_microp_st%dif (i,k) = du(i,k)*loc_microp_st%qide(i,k+1) + loc_microp_st%dnlf(i,k) = du(i,k)*loc_microp_st%ncde(i,k+1) + loc_microp_st%dnif(i,k) = du(i,k)*loc_microp_st%nide(i,k+1) + loc_microp_st%dsf (i,k) = du(i,k)*loc_microp_st%qsde(i,k+1) + loc_microp_st%dnsf(i,k) = du(i,k)*loc_microp_st%nsde(i,k+1) else dl(i,k) = du(i,k)*ql(i,k+1) end if @@ -2123,7 +2126,7 @@ subroutine q1q2_pjr(pcols, ncol, pver, pverp, & end do !---------------------------------------------------------------------------- return -end subroutine q1q2_pjr +end subroutine zm_calculate_output_tend !=================================================================================================== From 4167a2685fa92a88f378f17d7d1ea76cc97bea5e Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 15:44:55 -0800 Subject: [PATCH 119/398] more renaming --- components/eam/src/physics/cam/zm_conv.F90 | 237 ++++++++++----------- 1 file changed, 117 insertions(+), 120 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 404ef48e7907..9b82276ba9f5 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -493,7 +493,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! calculate updraft and downdraft properties - call cldprp(pcols, ncol, pver, pverp, lengath, msg, zm_param%limcnv, & + call cldprp(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & pg, z_mid_g, z_int_g, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & maxg, lelg, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & @@ -908,32 +908,31 @@ end subroutine zm_conv_evap !=================================================================================================== -subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, & - jb, jt, j0, z_mid, z_int, dz, hmn, hsat, hmin, & - eps, eps0) +subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & + jb, jt, j0, z_mid, z_int, dz, & + h_env, h_env_sat, h_env_min, eps, eps0) !---------------------------------------------------------------------------- ! Purpose: Determine properties of ZM updrafts and downdrafts !---------------------------------------------------------------------------- implicit none !---------------------------------------------------------------------------- ! Arguments - integer, intent(in ) :: pcols ! maximum number of columns - integer, intent(in ) :: ncol ! actual number of columns - integer, intent(in ) :: pver ! number of mid-point vertical levels - integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: il2g ! number of gathered columns (lengath) - integer, intent(in ) :: msg ! missing moisture levels - integer, dimension(pcols), intent(in ) :: jb ! updraft base level - integer, dimension(pcols), intent(in ) :: jt ! updraft top level - integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining - real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point - real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface - real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness - real(r8), dimension(pcols,pver), intent(in ) :: hmn ! env moist stat energy - real(r8), dimension(pcols,pver), intent(in ) :: hsat ! env saturated moist stat energy - real(r8), dimension(pcols) , intent(inout) :: hmin ! mid-tropospheric MSE minimum - real(r8), dimension(pcols,pver), intent( out) :: eps ! fractional entrainment - real(r8), dimension(pcols) , intent( out) :: eps0 ! fractional entrainment maximum + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: msg ! missing moisture levels + integer, dimension(pcols), intent(in ) :: jb ! updraft base level + integer, dimension(pcols), intent(in ) :: jt ! updraft top level + integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining + real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface + real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness + real(r8), dimension(pcols,pver), intent(in ) :: h_env ! env moist stat energy + real(r8), dimension(pcols,pver), intent(in ) :: h_env_sat ! env saturated moist stat energy + real(r8), dimension(pcols) , intent(inout) :: h_env_min ! mid-tropospheric MSE minimum + real(r8), dimension(pcols,pver), intent( out) :: eps ! fractional entrainment + real(r8), dimension(pcols) , intent( out) :: eps0 ! fractional entrainment maximum !---------------------------------------------------------------------------- ! Local variables @@ -958,7 +957,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, !---------------------------------------------------------------------------- ! initialize 1D variables - do i = 1,il2g + do i = 1,ncol ftemp(i) = 0._r8 expnum(i) = 0._r8 expdif(i) = 0._r8 @@ -966,7 +965,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, ! initialize 2D variables do k = 1,pver - do i = 1,il2g + do i = 1,ncol ! misc work variables k1(i,k) = 0._r8 i2(i,k) = 0._r8 @@ -980,9 +979,9 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, !---------------------------------------------------------------------------- ! compute taylor series for approximate eps(z) below do k = pver - 1,msg + 1,-1 - do i = 1,il2g + do i = 1,ncol if (k < jb(i) .and. k >= jt(i)) then - k1(i,k) = k1(i,k+1) + (hmn(i,jb(i))-hmn(i,k))*dz(i,k) + k1(i,k) = k1(i,k+1) + (h_env(i,jb(i))-h_env(i,k))*dz(i,k) ihat(i,k) = 0.5_r8* (k1(i,k+1)+k1(i,k)) i2(i,k) = i2(i,k+1) + ihat(i,k)*dz(i,k) idag(i,k) = 0.5_r8* (i2(i,k+1)+i2(i,k)) @@ -994,13 +993,13 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, end do !---------------------------------------------------------------------------- - ! re-initialize hmin array for ensuing calculation - hmin(1:il2g) = 1.E6_r8 + ! re-initialize minimum MSE for ensuing calculation + h_env_min(1:ncol) = 1.E6_r8 do k = msg + 1,pver - do i = 1,il2g - if (k >= j0(i) .and. k <= jb(i) .and. hmn(i,k) <= hmin(i)) then - hmin(i) = hmn(i,k) - expdif(i) = hmn(i,jb(i)) - hmin(i) + do i = 1,ncol + if (k >= j0(i) .and. k <= jb(i) .and. h_env(i,k) <= h_env_min(i)) then + h_env_min(i) = h_env(i,k) + expdif(i) = h_env(i,jb(i)) - h_env_min(i) end if end do end do @@ -1008,15 +1007,15 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, !---------------------------------------------------------------------------- ! compute approximate eps(z) using above taylor series do k = msg + 2,pver - do i = 1,il2g + do i = 1,ncol expnum(i) = 0._r8 ftemp(i) = 0._r8 if (k < jt(i) .or. k >= jb(i)) then k1(i,k) = 0._r8 expnum(i)= 0._r8 else - expnum(i) = hmn(i,jb(i)) - (hsat(i,k-1)*(z_int(i,k)-z_mid(i,k)) + & - hsat(i,k)* (z_mid(i,k-1)-z_int(i,k)))/(z_mid(i,k-1)-z_mid(i,k)) + expnum(i) = h_env(i,jb(i)) - (h_env_sat(i,k-1)*(z_int(i,k)-z_mid(i,k)) + & + h_env_sat(i,k)*(z_mid(i,k-1)-z_int(i,k)))/(z_mid(i,k-1)-z_mid(i,k)) end if if ((expdif(i) > 100._r8 .and. expnum(i) > 0._r8) .and. k1(i,k) > expnum(i)*dz(i,k)) then ftemp(i) = expnum(i) / k1(i,k) @@ -1031,7 +1030,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, end do ! move detrainment level downward if fractional entrainment is too low - do i = 1,il2g + do i = 1,ncol if (j0(i) < jb(i)) then if ( f(i,j0(i))<1.E-6_r8 .and. f(i,j0(i)+1)>f(i,j0(i)) ) then j0(i) = j0(i) + 1 @@ -1041,15 +1040,15 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, ! ensure that entrainment does not increase above the level that detrainment starts do k = msg + 2,pver - do i = 1,il2g + do i = 1,ncol if (k >= jt(i) .and. k <= j0(i)) then f(i,k) = max(f(i,k),f(i,k-1)) end if end do end do - ! ? - do i = 1,il2g + ! specify maximum fractional entrainment + do i = 1,ncol eps0(i) = f(i,j0(i)) eps(i,jb(i)) = eps0(i) end do @@ -1058,7 +1057,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, ! Rasch, P. J., J. E. Kristjánsson, A comparison of the CCM3 model climate ! using diagnosed and predicted condensate parameterizations, J. Clim., 1997. do k = pver,msg + 1,-1 - do i = 1,il2g + do i = 1,ncol if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) if ( k =jt(i) ) eps(i,k) = f(i,k) end do @@ -1071,7 +1070,7 @@ end subroutine calculate_fractional_entrainment !=================================================================================================== -subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & +subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & p_mid, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & @@ -1084,11 +1083,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & implicit none !---------------------------------------------------------------------------- ! Arguments - integer, intent(in ) :: pcols ! maximum number of columns - integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pcols ! declared number of columns + integer, intent(in ) :: ncol ! actual number of columns for iteration integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: il2g ! number of gathered columns (lengath) integer, intent(in ) :: msg ! missing moisture levels integer, intent(in ) :: limcnv ! convection limiting level real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! env pressure at mid-point @@ -1106,7 +1104,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & integer, dimension(pcols), intent(in ) :: lel ! updraft parcel launch level integer, dimension(pcols), intent(out) :: jt ! updraft plume top integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level - integer, dimension(pcols), intent(out) :: j0 ! level where detrainment begins (starting at hmin) + integer, dimension(pcols), intent(out) :: j0 ! level where detrainment begins (starting at h_env_min) integer, dimension(pcols), intent(out) :: jd ! level of downdraft real(r8), dimension(pcols,pver), intent(out) :: mu ! updraft mass flux real(r8), dimension(pcols,pver), intent(out) :: eu ! entrainment rate of updraft @@ -1130,8 +1128,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! Local variables real(r8), dimension(pcols,pver) :: gamma ! latent-heating correction for pseudo-adiabatic parcel lifting real(r8), dimension(pcols,pver) :: dz ! layer thickness - real(r8), dimension(pcols,pver) :: hmn ! env moist stat energy - real(r8), dimension(pcols,pver) :: hsat ! env saturated moist stat energy + real(r8), dimension(pcols,pver) :: h_env ! ambient env moist stat energy + real(r8), dimension(pcols,pver) :: h_env_sat ! ambient env saturated moist stat energy + real(r8), dimension(pcols) :: h_env_min ! mid-tropospheric MSE minimum real(r8), dimension(pcols,pver) :: hu ! updraft moist static energy real(r8), dimension(pcols,pver) :: hd ! dndraft moist static energy real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst @@ -1139,7 +1138,6 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma real(r8), dimension(pcols,pver) :: qds ! dndraft saturation specific humdity real(r8), dimension(pcols) :: c0mask ! land/ocean modification - real(r8), dimension(pcols) :: hmin ! mid-tropospheric MSE minimum real(r8), dimension(pcols) :: rmue ! real(r8), dimension(pcols) :: zuef ! @@ -1191,7 +1189,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! initialize 1D variables - do i = 1,il2g + do i = 1,ncol totpcp(i) = 0._r8 totevp(i) = 0._r8 c0mask(i) = zm_param%c0_ocn*(1._r8-landfrac(i)) + zm_param%c0_lnd*landfrac(i) @@ -1199,7 +1197,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! initialize 2D variables do k = 1,pver - do i = 1,il2g + do i = 1,ncol ! mass fluxes & mixing variables mu(i,k) = 0._r8 eu(i,k) = 0._r8 @@ -1223,15 +1221,15 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_mid(i,k)**2) & * zm_const%latvap/zm_const%cpair ! cloud thermodynamic variables - su(i,k) = s(i,k) - sd(i,k) = s(i,k) - qd(i,k) = q(i,k) - qds(i,k) = q(i,k) - qu(i,k) = q(i,k) - hmn(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q(i,k) - hsat(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*qst(i,k) - hu(i,k) = hmn(i,k) - hd(i,k) = hmn(i,k) + su(i,k) = s(i,k) + sd(i,k) = s(i,k) + qd(i,k) = q(i,k) + qds(i,k) = q(i,k) + qu(i,k) = q(i,k) + h_env(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q(i,k) + h_env_sat(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*qst(i,k) + hu(i,k) = h_env(i,k) + hd(i,k) = h_env(i,k) ! convective microphysics pflxs(i,k) = 0._r8 fice(i,k) = 0._r8 @@ -1243,8 +1241,8 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! interpolate the mid-point values to interfaces do k = msg+1,pver - do i = 1,il2g - hsthat(i,k) = hsat(i,k) + do i = 1,ncol + hsthat(i,k) = h_env_sat(i,k) qsthat(i,k) = qst(i,k) gamhat(i,k) = gamma(i,k) if (k>msg+1) then @@ -1267,20 +1265,20 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! initialize cloud top to highest plume top (upper/lower limit => pver / limcnv+1) jt(:) = pver jto(:)= pver - do i = 1,il2g + do i = 1,ncol jt(i) = max(lel(i),limcnv+1) jt(i) = min(jt(i),pver) jd(i) = pver jlcl(i) = lel(i) - hmin(i) = 1.E6_r8 + h_env_min(i) = 1.E6_r8 end do !---------------------------------------------------------------------------- - ! find the level of minimum saturated MSE (hsat), where detrainment starts - do i = 1,il2g + ! find the level of minimum saturated MSE (h_env_sat), where detrainment starts + do i = 1,ncol do k = msg + 1,pver - if (hsat(i,k) <= hmin(i) .and. k >= jt(i) .and. k <= jb(i)) then - hmin(i) = hsat(i,k) + if (h_env_sat(i,k) <= h_env_min(i) .and. k >= jt(i) .and. k <= jb(i)) then + h_env_min(i) = h_env_sat(i,k) j0(i) = k end if end do ! k @@ -1294,7 +1292,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! Initialize cloud moist and dry static energies (hu=MSE & su=DSE) do k = msg + 1,pver - do i = 1,il2g + do i = 1,ncol if (k >= jt(i) .and. k <= jb(i)) then ! Tunable temperature perturbation (tiedke_add) was already added to parcel hu/su to ! represent subgrid temperature perturbation. If PBL temperature pert (tpert) also @@ -1303,11 +1301,11 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! new tunable parameter tpert_fac was introduced. This introduced new uncertainties into ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. if(zm_param%tpert_fix) then - hu(i,k) = hmn(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add - su(i,k) = s(i,jb(i)) + zm_param%tiedke_add + hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add + su(i,k) = s(i,jb(i)) + zm_param%tiedke_add else - hu(i,k) = hmn(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) - su(i,k) = s(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) + hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) + su(i,k) = s(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) end if end if end do @@ -1315,9 +1313,9 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! calculate fractional entrainment (i.e. "lambda D") - see eq (4.78) from Neale et al. (2012) - call calculate_fractional_entrainment(pcols, ncol, pver, pverp, il2g, msg, & - jb, jt, j0, z_mid, z_int, dz, hmn, hsat, hmin, & - eps, eps0) + call calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & + jb, jt, j0, z_mid, z_int, dz, & + h_env, h_env_sat, h_env_min, eps, eps0) !---------------------------------------------------------------------------- ! iteration to set cloud properties @@ -1328,7 +1326,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & do iter = 1,itnum do k = pver,msg + 1,-1 - do i = 1,il2g + do i = 1,ncol cu(i,k) = 0._r8 ql(i,k) = 0._r8 if (zm_param%zm_microp) then @@ -1338,13 +1336,13 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do - do i = 1,il2g + do i = 1,ncol totpcp(i) = 0._r8 - if (zm_param%zm_microp) hu(i,jb(i)) = hmn(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add + if (zm_param%zm_microp) hu(i,jb(i)) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add end do do k = pver,msg + 1,-1 - do i = 1,il2g + do i = 1,ncol ! intialize updraft mass flux variables - here and below all normalized by cloud base mass flux (mb) if (eps0(i) > 0._r8) then mu(i,jb(i)) = 1._r8 @@ -1365,28 +1363,28 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & khighest = pverp klowest = 1 - do i=1,il2g + do i=1,ncol khighest = min(khighest,lel(i)) klowest = max(klowest,jb(i)) end do do k = klowest-1,khighest,-1 - do i = 1,il2g + do i = 1,ncol if (k <= jb(i)-1 .and. k >= lel(i) .and. eps0(i) > 0._r8) then if (mu(i,k) < 0.02_r8) then - hu(i,k) = hmn(i,k) + hu(i,k) = h_env(i,k) mu(i,k) = 0._r8 eu(i,k) = 0._r8 du(i,k) = mu(i,k+1)/dz(i,k) else if (zm_param%zm_microp) then hu(i,k) = ( mu(i,k+1)*hu(i,k+1) & - +dz(i,k)*( eu(i,k)*hmn(i,k) & + +dz(i,k)*( eu(i,k)*h_env(i,k) & +zm_const%latice*tmp_frz(i,k) ) & ) / ( mu(i,k) + dz(i,k)*du(i,k) ) else hu(i,k) = mu(i,k+1)/mu(i,k)*hu(i,k+1) + & - dz(i,k)/mu(i,k)* (eu(i,k)*hmn(i,k)- du(i,k)*hsat(i,k)) + dz(i,k)/mu(i,k)* (eu(i,k)*h_env(i,k)- du(i,k)*h_env_sat(i,k)) end if end if end if @@ -1395,7 +1393,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! reset cloud top index beginning from two layers above the ! cloud base (i.e. if cloud is only one layer thick, top is not reset - do i=1,il2g + do i=1,ncol doit(i) = .true. tot_frz(i)= 0._r8 do k = pver,msg + 1,-1 @@ -1404,7 +1402,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do do k=klowest-2,khighest-1,-1 - do i=1,il2g + do i=1,ncol if (doit(i) .and. k <= jb(i)-2 .and. k >= lel(i)-1) then if (hu(i,k) <= hsthat(i,k) .and. & hu(i,k+1) > hsthat(i,k+1) .and. & @@ -1424,17 +1422,17 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - do i = 1,il2g + do i = 1,ncol if (iter == 1) jto(i) = jt(i) end do do k = pver,msg + 1,-1 - do i = 1,il2g + do i = 1,ncol if (k >= lel(i) .and. k <= jt(i) .and. eps0(i) > 0._r8) then mu(i,k) = 0._r8 eu(i,k) = 0._r8 du(i,k) = 0._r8 - hu(i,k) = hmn(i,k) + hu(i,k) = h_env(i,k) end if if (k == jt(i) .and. eps0(i) > 0._r8) then du(i,k) = mu(i,k+1)/dz(i,k) @@ -1445,10 +1443,10 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do ! determine LCL - see eq (4.127)- (4.130) of Neale et al. (2012) - done(1:il2g) = .false. + done(1:ncol) = .false. kount = 0 do k = pver,msg + 2,-1 - do i = 1,il2g + do i = 1,ncol if (k == jb(i) .and. eps0(i) > 0._r8) then qu(i,k) = q(i,jb(i)) su(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair @@ -1465,13 +1463,13 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end if end do - if (kount >= il2g) goto 690 + if (kount >= ncol) goto 690 end do 690 continue do k = msg + 2,pver - do i = 1,il2g + do i = 1,ncol if ((k > jt(i) .and. k <= jlcl(i)) .and. eps0(i) > 0._r8) then su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) @@ -1481,7 +1479,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! compute condensation in updraft do k = pver,msg + 2,-1 - do i = 1,il2g + do i = 1,ncol if (eps0(i)>0._r8) then if ( zm_param%zm_microp) tmp_k_limit = jlcl(i)+1 if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) @@ -1503,17 +1501,17 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & if (zm_param%zm_microp) then - tug(:il2g,:) = t_mid(:il2g,:) - fice(:,:) = 0._r8 + tug(1:ncol,:) = t_mid(1:ncol,:) + fice(1:ncol,:) = 0._r8 do k = pver, msg+2, -1 - do i = 1, il2g + do i = 1, ncol tug(i,k) = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) end do end do do k = 1, pver-1 - do i = 1, il2g + do i = 1, ncol if (tug(i,k+1) > zm_const%tfreez) then ! If warmer than zm_const%tfreez then water phase fice(i,k) = 0._r8 @@ -1528,14 +1526,14 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do do k = 1, pver - do i = 1,il2g + do i = 1,ncol loc_microp_st%cmei(i,k) = cu(i,k)* fice(i,k) loc_microp_st%cmel(i,k) = cu(i,k) * (1._r8-fice(i,k)) end do end do #ifndef SCREAM_CONFIG_IS_CMAKE - call zm_mphy( pcols, il2g, msg, & + call zm_mphy( pcols, ncol, msg, & zm_const%grav, zm_const%cpair, zm_const%rdair, & zm_param%auto_fac, zm_param%accr_fac, zm_param%micro_dcs, & jb, jt, jlcl, su, qu, mu, du, eu, z_int, p_mid, t_mid, q, gamhat, eps0, & @@ -1565,7 +1563,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & #endif do k = pver,msg + 2,-1 - do i = 1,il2g + do i = 1,ncol ! In the original ZM scheme, which does not consider ice phase, ql actually represents total cloud ! water. With convective microphysics, loc_microp_st%qliq and loc_microp_st%qice represent cloud ! liquid water and cloud ice, respectively. Since ql is still used in other subroutines as total @@ -1575,7 +1573,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do - do i = 1,il2g + do i = 1,ncol if (iter == 2 .and. jt(i)> jto(i)) then do k = jt(i), jto(i), -1 loc_microp_st%frz(i,k) = 0.0_r8 @@ -1585,7 +1583,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do do k = pver,msg + 2,-1 - do i = 1,il2g + do i = 1,ncol if (k >= jt(i) .and. k < jb(i) .and. eps0(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-du(i,k)*( loc_microp_st%qcde(i,k+1) & +loc_microp_st%qide(i,k+1) & @@ -1604,7 +1602,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! mu, ql are interface quantities ! cu, du, eu, rprd are midpoint quantites do k = pver,msg + 2,-1 - do i = 1,il2g + do i = 1,ncol rprd(i,k) = 0._r8 if (k >= jt(i) .and. k < jb(i) .and. eps0(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then if (mu(i,k) > 0._r8) then @@ -1627,19 +1625,19 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & !---------------------------------------------------------------------------- ! specify downdraft properties (note - no downdrafts if jd>=jb) ! downward mass flux profile is scaled so that net flux (up-down) at cloud base in not negative - do i = 1,il2g + do i = 1,ncol ! in normal downdraft strength run alfa=0.2. In test4 alfa=0.1 jt(i) = min(jt(i),jb(i)-1) jd(i) = max(j0(i),jt(i)+1) jd(i) = min(jd(i),jb(i)) - hd(i,jd(i)) = hmn(i,jd(i)-1) + hd(i,jd(i)) = h_env(i,jd(i)-1) if (jd(i) < jb(i) .and. eps0(i) > 0._r8) then epsm(i) = eps0(i) md(i,jd(i)) = -zm_param%alfa * epsm(i) / eps0(i) end if end do do k = msg + 1,pver - do i = 1,il2g + do i = 1,ncol if ((k > jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8) then zdef(i) = z_int(i,jd(i)) - z_int(i,k) md(i,k) = -zm_param%alfa / (2._r8*eps0(i))*(exp(2._r8*epsm(i)*zdef(i))-1._r8)/zdef(i) @@ -1647,7 +1645,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do end do do k = msg + 1,pver - do i = 1,il2g + do i = 1,ncol if ((k >= jt(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then ratmjb(i) = min(abs(mu(i,jb(i))/md(i,jb(i))),1._r8) md(i,k) = md(i,k)*ratmjb(i) @@ -1656,31 +1654,31 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end do do k = msg + 1,pver - do i = 1,il2g + do i = 1,ncol if ((k >= jt(i) .and. k <= pver) .and. eps0(i) > 0._r8) then ed(i,k-1) = (md(i,k-1)-md(i,k))/dz(i,k-1) mdt = min(md(i,k),-small) - hd(i,k) = (md(i,k-1)*hd(i,k-1) - dz(i,k-1)*ed(i,k-1)*hmn(i,k-1))/mdt + hd(i,k) = (md(i,k-1)*hd(i,k-1) - dz(i,k-1)*ed(i,k-1)*h_env(i,k-1))/mdt end if end do end do ! calculate updraft and downdraft properties do k = msg + 2,pver - do i = 1,il2g + do i = 1,ncol if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) end if end do end do - do i = 1,il2g + do i = 1,ncol qd(i,jd(i)) = qds(i,jd(i)) sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*qd(i,jd(i)))/zm_const%cpair end do do k = msg + 2,pver - do i = 1,il2g + do i = 1,ncol if (k >= jd(i) .and. k < jb(i) .and. eps0(i) > 0._r8) then qd(i,k+1) = qds(i,k+1) evp(i,k) = -ed(i,k)*q(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) @@ -1692,17 +1690,16 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & end if end do end do - do i = 1,il2g - totevp(i) = totevp(i) + md(i,jd(i))*qd(i,jd(i)) - md(i,jb(i))*qd(i,jb(i)) - end do - do i = 1,il2g + ! calculate total precip for downdraft scaling + do i = 1,ncol + totevp(i) = totevp(i) + md(i,jd(i))*qd(i,jd(i)) - md(i,jb(i))*qd(i,jb(i)) totpcp(i) = max(totpcp(i),0._r8) totevp(i) = max(totevp(i),0._r8) end do do k = msg + 2,pver - do i = 1,il2g + do i = 1,ncol ! ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then md(i,k) = md (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) @@ -1726,7 +1723,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! compute the net precipitation flux across interfaces do k = 2,pverp - do i = 1,il2g + do i = 1,ncol pflx(i,k) = pflx(i,k-1) + rprd(i,k-1)*dz(i,k-1) if (zm_param%zm_microp) pflxs(i,k) = pflxs(i,k-1) + loc_microp_st%sprd(i,k-1)*dz(i,k-1) end do @@ -1734,13 +1731,13 @@ subroutine cldprp(pcols, ncol, pver, pverp, il2g, msg, limcnv, & ! calculate net mass flux do k = msg + 1,pver - do i = 1,il2g + do i = 1,ncol mc(i,k) = mu(i,k) + md(i,k) end do end do if (zm_param%zm_microp) then - do i = 1,il2g + do i = 1,ncol ! protect against rounding error if(pflxs(i,pverp).gt.pflx(i,pverp)) then dum = (pflxs(i,pverp)-pflx(i,pverp))/omsm From feb93709cd8208726d63de3f219e26144841cb66 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 15:51:39 -0800 Subject: [PATCH 120/398] clean up zm_calculate_output_tend --- components/eam/src/physics/cam/zm_conv.F90 | 34 +++++++++------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 9b82276ba9f5..41aa042e5c9c 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -1997,7 +1997,7 @@ subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & dl, evp, cu, & loc_microp_st) !---------------------------------------------------------------------------- - ! Purpose: initialize quantities for ZM convection scheme + ! Purpose: calculate final output tendencies for the ZM convection scheme !---------------------------------------------------------------------------- implicit none !---------------------------------------------------------------------------- @@ -2070,28 +2070,24 @@ subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & do i = il1g,il2g emc = -cu(i,k) + evp(i,k) ! condensation in updraft and evaporating rain in downdraft - dsdt(i,k) = -zm_const%latvap/zm_const%cpair*emc & - + (+mu(i,k+1)* (su(i,k+1)-shat(i,k+1)) & - -mu(i,k)* (su(i,k)-shat(i,k)) & - +md(i,k+1)* (sd(i,k+1)-shat(i,k+1)) & - -md(i,k)* (sd(i,k)-shat(i,k)) & - )/dp(i,k) + dsdt(i,k) = -zm_const%latvap/zm_const%cpair*emc + & + (+mu(i,k+1)*(su(i,k+1)-shat(i,k+1)) - mu(i,k)*(su(i,k)-shat(i,k)) & + +md(i,k+1)*(sd(i,k+1)-shat(i,k+1)) - md(i,k)*(sd(i,k)-shat(i,k)) & + )/dp(i,k) dqdt(i,k) = emc + & - (+mu(i,k+1)* (qu(i,k+1)-qhat(i,k+1)) & - -mu(i,k)* (qu(i,k)-qhat(i,k)) & - +md(i,k+1)* (qd(i,k+1)-qhat(i,k+1)) & - -md(i,k)* (qd(i,k)-qhat(i,k)) & - )/dp(i,k) + (+mu(i,k+1)*(qu(i,k+1)-qhat(i,k+1)) - mu(i,k)*(qu(i,k)-qhat(i,k)) & + +md(i,k+1)*(qd(i,k+1)-qhat(i,k+1)) - md(i,k)*(qd(i,k)-qhat(i,k)) & + )/dp(i,k) if (zm_param%zm_microp) then dsdt(i,k) = dsdt(i,k) + zm_const%latice/zm_const%cpair*loc_microp_st%frz(i,k) - dl (i,k) = du(i,k)*loc_microp_st%qcde(i,k+1) loc_microp_st%dif (i,k) = du(i,k)*loc_microp_st%qide(i,k+1) loc_microp_st%dnlf(i,k) = du(i,k)*loc_microp_st%ncde(i,k+1) loc_microp_st%dnif(i,k) = du(i,k)*loc_microp_st%nide(i,k+1) loc_microp_st%dsf (i,k) = du(i,k)*loc_microp_st%qsde(i,k+1) loc_microp_st%dnsf(i,k) = du(i,k)*loc_microp_st%nsde(i,k+1) + dl(i,k) = du(i,k)*loc_microp_st%qcde(i,k+1) else dl(i,k) = du(i,k)*ql(i,k+1) end if @@ -2107,14 +2103,10 @@ subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & do k = kbm,pver do i = il1g,il2g if (k == mx(i)) then - dsdt(i,k) = (1._r8/dsubcld(i))* & - (-mu(i,k)* (su(i,k)-shat(i,k)) & - -md(i,k)* (sd(i,k)-shat(i,k)) & - ) - dqdt(i,k) = (1._r8/dsubcld(i))* & - (-mu(i,k)*(qu(i,k)-qhat(i,k)) & - -md(i,k)*(qd(i,k)-qhat(i,k)) & - ) + dsdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(su(i,k)-shat(i,k)) & + -md(i,k)*(sd(i,k)-shat(i,k)) ) + dqdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(qu(i,k)-qhat(i,k)) & + -md(i,k)*(qd(i,k)-qhat(i,k)) ) else if (k > mx(i)) then dsdt(i,k) = dsdt(i,k-1) dqdt(i,k) = dqdt(i,k-1) From cfd96a078875e5cee3a06d8e8b37ea281869c302 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 1 Dec 2025 16:26:17 -0800 Subject: [PATCH 121/398] cleanup closure() --- components/eam/src/physics/cam/zm_conv.F90 | 331 ++++++++++----------- 1 file changed, 163 insertions(+), 168 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 41aa042e5c9c..38d97f20f9e0 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -1775,189 +1775,177 @@ end subroutine cldprp !=================================================================================================== -subroutine closure(pcols, ncol, pver, pverp, & - q ,t_mid ,p_mid ,z_mid ,s , & - tp ,qs ,qu ,su ,mc , & - du ,mu ,md ,qd ,sd , & - qhat ,shat ,dp ,qstp ,z_int , & - ql ,dsubcld ,mb ,cape ,tl , & - lcl ,lel ,jt ,mx ,il1g , & - il2g ,msg ,capelmt ) -!----------------------------------------------------------------------- -! -! Purpose: -! -! -! Method: -! -! -! -! Author: G. Zhang and collaborators. CCM contact:P. Rasch -! This is contributed code not fully standardized by the CCM core group. -! -! this code is very much rougher than virtually anything else in the CCM -! We expect to release cleaner code in a future release -! -! the documentation has been enhanced to the degree that we are able -! -!----------------------------------------------------------------------- - +! subroutine closure(pcols, ncol, pver, pverp, & +! q, t_mid, p_mid, z_mid, s, & +! tp, qs, qu, su, mc, & +! du, mu, md, qd, sd, & +! qhat, shat, dp, qstp, z_int, & +! ql, dsubcld, mb, cape, tl, & +! lcl, lel, jt, mx, il1g, & +! il2g, msg, capelmt ) +subroutine closure(pcols, ncol, pver, pverp, msg, capelmt, & + lcl, lel, jt, mx, + q, t_mid, p_mid, z_mid, s, & + tp, qs, qu, su, mc, & + du, mu, md, qd, sd, & + qhat, shat, dp, qstp, z_int, & + ql, dsubcld, mb, cape, tl ) + !---------------------------------------------------------------------------- + ! Purpose: calculate closure condition for ZM convection scheme + !---------------------------------------------------------------------------- implicit none - -! -!-----------------------------Arguments--------------------------------- -! - integer, intent(in) :: pcols ! maximum number of columns - integer, intent(in) :: ncol ! actual number of columns - integer, intent(in) :: pver ! number of mid-point vertical levels - integer, intent(in) :: pverp ! number of interface vertical levels - real(r8), intent(inout) :: q(pcols,pver) ! spec humidity - real(r8), intent(inout) :: t_mid(pcols,pver) ! temperature - real(r8), intent(inout) :: p_mid(pcols,pver) ! pressure (mb) - real(r8), intent(inout) :: mb(pcols) ! cloud base mass flux - real(r8), intent(in) :: z_mid(pcols,pver) ! height (m) - real(r8), intent(in) :: s(pcols,pver) ! normalized dry static energy - real(r8), intent(in) :: tp(pcols,pver) ! parcel temp - real(r8), intent(in) :: qs(pcols,pver) ! sat spec humidity - real(r8), intent(in) :: qu(pcols,pver) ! updraft spec. humidity - real(r8), intent(in) :: su(pcols,pver) ! normalized dry stat energy of updraft - real(r8), intent(in) :: mc(pcols,pver) ! net convective mass flux - real(r8), intent(in) :: du(pcols,pver) ! detrainment from updraft - real(r8), intent(in) :: mu(pcols,pver) ! mass flux of updraft - real(r8), intent(in) :: md(pcols,pver) ! mass flux of downdraft - real(r8), intent(in) :: qd(pcols,pver) ! spec. humidity of downdraft - real(r8), intent(in) :: sd(pcols,pver) ! dry static energy of downdraft - real(r8), intent(in) :: qhat(pcols,pver) ! environment spec humidity at interfaces - real(r8), intent(in) :: shat(pcols,pver) ! env. normalized dry static energy at intrfcs - real(r8), intent(in) :: dp(pcols,pver) ! pressure thickness of layers - real(r8), intent(in) :: qstp(pcols,pver) ! spec humidity of parcel - real(r8), intent(in) :: z_int(pcols,pver+1) ! height of interface levels - real(r8), intent(in) :: ql(pcols,pver) ! liquid water mixing ratio - - real(r8), intent(in) :: cape(pcols) ! available pot. energy of column - real(r8), intent(in) :: tl(pcols) - real(r8), intent(in) :: dsubcld(pcols) ! thickness of subcloud layer - - integer, intent(in) :: lcl(pcols) ! index of lcl - integer, intent(in) :: lel(pcols) ! index of launch leve - integer, intent(in) :: jt(pcols) ! top of updraft - integer, intent(in) :: mx(pcols) ! base of updraft -! -!--------------------------Local variables------------------------------ -! - real(r8) dtpdt(pcols,pver) - real(r8) dqsdtp(pcols,pver) - real(r8) dtmdt(pcols,pver) - real(r8) dqmdt(pcols,pver) - real(r8) dboydt(pcols,pver) - real(r8) thetavp(pcols,pver) - real(r8) thetavm(pcols,pver) - - real(r8) dtbdt(pcols),dqbdt(pcols),dtldt(pcols) + !---------------------------------------------------------------------------- + ! Arguments + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: msg ! ? + real(r8), intent(in ) :: capelmt ! ? + real(r8), dimension(pcols,pver), intent(inout) :: q ! spec humidity + real(r8), dimension(pcols,pver), intent(inout) :: t_mid ! temperature + real(r8), dimension(pcols,pver), intent(inout) :: p_mid ! pressure (mb) + real(r8), dimension(pcols), intent(inout) :: mb ! cloud base mass flux + real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! height (m) + real(r8), dimension(pcols,pver), intent(in ) :: s ! normalized dry static energy + real(r8), dimension(pcols,pver), intent(in ) :: tp ! parcel temp + real(r8), dimension(pcols,pver), intent(in ) :: qs ! sat spec humidity + real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft spec. humidity + real(r8), dimension(pcols,pver), intent(in ) :: su ! normalized dry stat energy of updraft + real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux + real(r8), dimension(pcols,pver), intent(in ) :: du ! detrainment from updraft + real(r8), dimension(pcols,pver), intent(in ) :: mu ! mass flux of updraft + real(r8), dimension(pcols,pver), intent(in ) :: md ! mass flux of downdraft + real(r8), dimension(pcols,pver), intent(in ) :: qd ! spec. humidity of downdraft + real(r8), dimension(pcols,pver), intent(in ) :: sd ! dry static energy of downdraft + real(r8), dimension(pcols,pver), intent(in ) :: qhat ! environment spec humidity at interfaces + real(r8), dimension(pcols,pver), intent(in ) :: shat ! env. normalized dry static energy at intrfcs + real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness of layers + real(r8), dimension(pcols,pver), intent(in ) :: qstp ! spec humidity of parcel + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! height of interface levels + real(r8), dimension(pcols,pver), intent(in ) :: ql ! liquid water mixing ratio + real(r8), dimension(pcols), intent(in ) :: cape ! available pot. energy of column + real(r8), dimension(pcols), intent(in ) :: tl ! ? + real(r8), dimension(pcols), intent(in ) :: dsubcld ! thickness of subcloud layer + integer, dimension(pcols), intent(in ) :: lcl ! index of lcl + integer, dimension(pcols), intent(in ) :: lel ! index of launch leve + integer, dimension(pcols), intent(in ) :: jt ! top of updraft + integer, dimension(pcols), intent(in ) :: mx ! base of updraft + !---------------------------------------------------------------------------- + ! Local variables + real(r8), dimension(pcols,pver) :: dtpdt ! ? + real(r8), dimension(pcols,pver) :: dqsdtp ! ? + real(r8), dimension(pcols,pver) :: dtmdt ! convective temperature tendency + real(r8), dimension(pcols,pver) :: dqmdt ! convective sp. humidity tendency + real(r8), dimension(pcols,pver) :: dboydt ! integrand of cape change + real(r8), dimension(pcols,pver) :: thetavp ! ? + real(r8), dimension(pcols,pver) :: thetavm ! ? + real(r8), dimension(pcols) :: dtbdt ! parcel temperature change due to change of subcloud layer properties during convection + real(r8), dimension(pcols) :: dqbdt ! ? + real(r8), dimension(pcols) :: dtldt ! ? + real(r8), dimension(pcols) :: dadt ! ? real(r8) beta - real(r8) capelmt - real(r8) dadt(pcols) real(r8) debdt real(r8) dltaa real(r8) eb + integer i, k, kmin, kmax - integer i - integer il1g - integer il2g - integer k, kmin, kmax - integer msg - -! change of subcloud layer properties due to convection is -! related to cumulus updrafts and downdrafts. -! mc(z)=f(z)*mb, mub=betau*mb, mdb=betad*mb are used -! to define betau, betad and f(z). -! note that this implies all time derivatives are in effect -! time derivatives per unit cloud-base mass flux, i.e. they -! have units of 1/mb instead of 1/sec. -! - do i = il1g,il2g - mb(i) = 0._r8 - eb = p_mid(i,mx(i))*q(i,mx(i))/ (zm_const%epsilo+q(i,mx(i))) - dtbdt(i) = (1._r8/dsubcld(i))* (mu(i,mx(i))*(shat(i,mx(i))-su(i,mx(i)))+ & - md(i,mx(i))* (shat(i,mx(i))-sd(i,mx(i)))) - dqbdt(i) = (1._r8/dsubcld(i))* (mu(i,mx(i))*(qhat(i,mx(i))-qu(i,mx(i)))+ & - md(i,mx(i))* (qhat(i,mx(i))-qd(i,mx(i)))) - debdt = zm_const%epsilo*p_mid(i,mx(i))/ (zm_const%epsilo+q(i,mx(i)))**2*dqbdt(i) - dtldt(i) = -2840._r8* (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & - (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 - end do -! -! dtmdt and dqmdt are cumulus heating and drying. -! + real(r8), parameter :: + real(r8), parameter :: + real(r8), parameter :: + real(r8), parameter :: + + !---------------------------------------------------------------------------- + ! change of subcloud layer properties due to convection is + ! related to cumulus updrafts and downdrafts. + ! mc(z)=f(z)*mb, mub=betau*mb, mdb=betad*mb are used + ! to define betau, betad and f(z). + ! note that this implies all time derivatives are in effect + ! time derivatives per unit cloud-base mass flux, i.e. they + ! have units of 1/mb instead of 1/sec. + !---------------------------------------------------------------------------- + ! initialize output tendencies do k = msg + 1,pver - do i = il1g,il2g + do i = 1,ncol dtmdt(i,k) = 0._r8 dqmdt(i,k) = 0._r8 end do end do -! + + !---------------------------------------------------------------------------- + ! ? + do i = 1,ncol + mb(i) = 0._r8 + eb = p_mid(i,mx(i))*q(i,mx(i))/ (zm_const%epsilo+q(i,mx(i))) + dtbdt(i) = (1._r8/dsubcld(i)) & + *( mu(i,mx(i))*(shat(i,mx(i))-su(i,mx(i))) & + +md(i,mx(i))*(shat(i,mx(i))-sd(i,mx(i))) ) + dqbdt(i) = (1._r8/dsubcld(i)) & + *( mu(i,mx(i))*(qhat(i,mx(i))-qu(i,mx(i))) & + +md(i,mx(i))*(qhat(i,mx(i))-qd(i,mx(i))) ) + debdt = zm_const%epsilo*p_mid(i,mx(i)) / (zm_const%epsilo+q(i,mx(i)))**2 * dqbdt(i) + dtldt(i) = -2840._r8 * (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & + (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 + end do + + !---------------------------------------------------------------------------- + ! ? do k = msg + 1,pver - 1 - do i = il1g,il2g - if (k == jt(i)) then - dtmdt(i,k) = (1._r8/dp(i,k))*(mu(i,k+1)* (su(i,k+1)-shat(i,k+1)- & - zm_const%latvap/zm_const%cpair*ql(i,k+1))+md(i,k+1)* (sd(i,k+1)-shat(i,k+1))) - dqmdt(i,k) = (1._r8/dp(i,k))*(mu(i,k+1)* (qu(i,k+1)- & - qhat(i,k+1)+ql(i,k+1))+md(i,k+1)*(qd(i,k+1)-qhat(i,k+1))) + do i = 1,ncol + if (k==jt(i)) then + dtmdt(i,k) = (1._r8/dp(i,k)) & + *(mu(i,k+1)*(su(i,k+1)-shat(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & + + md(i,k+1)*(sd(i,k+1)-shat(i,k+1))) + dqmdt(i,k) = (1._r8/dp(i,k)) & + *(mu(i,k+1)*(qu(i,k+1)-qhat(i,k+1)+ql(i,k+1) ) & + + md(i,k+1)*(qd(i,k+1)-qhat(i,k+1))) end if end do end do -! + + !---------------------------------------------------------------------------- + ! ? beta = 0._r8 do k = msg + 1,pver - 1 - do i = il1g,il2g - if (k > jt(i) .and. k < mx(i)) then - dtmdt(i,k) = (mc(i,k)* (shat(i,k)-s(i,k))+mc(i,k+1)* (s(i,k)-shat(i,k+1)))/ & - dp(i,k) - zm_const%latvap/zm_const%cpair*du(i,k)*(beta*ql(i,k)+ (1-beta)*ql(i,k+1)) -! dqmdt(i,k)=(mc(i,k)*(qhat(i,k)-q(i,k)) -! 1 +mc(i,k+1)*(q(i,k)-qhat(i,k+1)))/dp(i,k) -! 2 +du(i,k)*(qs(i,k)-q(i,k)) -! 3 +du(i,k)*(beta*ql(i,k)+(1-beta)*ql(i,k+1)) - - dqmdt(i,k) = (mu(i,k+1)* (qu(i,k+1)-qhat(i,k+1)+zm_const%cpair/zm_const%latvap* (su(i,k+1)-s(i,k)))- & - mu(i,k)* (qu(i,k)-qhat(i,k)+zm_const%cpair/zm_const%latvap*(su(i,k)-s(i,k)))+md(i,k+1)* & - (qd(i,k+1)-qhat(i,k+1)+zm_const%cpair/zm_const%latvap*(sd(i,k+1)-s(i,k)))-md(i,k)* & - (qd(i,k)-qhat(i,k)+zm_const%cpair/zm_const%latvap*(sd(i,k)-s(i,k))))/dp(i,k) + & - du(i,k)* (beta*ql(i,k)+(1-beta)*ql(i,k+1)) + do i = 1,ncol + if ( k>jt(i) .and. k= lel(i) .and. k <= lcl(i)) then - thetavp(i,k) = tp(i,k)* (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) - thetavm(i,k) = t_mid(i,k)* (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) - dqsdtp(i,k) = qstp(i,k)* (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) -! -! dtpdt is the parcel temperature change due to change of -! subcloud layer properties during convection. -! - dtpdt(i,k) = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp(i,k)-qstp(i,k)/tp(i,k)))* & - (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/ & - tl(i)**2*dtldt(i))) -! -! dboydt is the integrand of cape change. -! + do i = 1,ncol + if ( k>=lel(i) .and. k<=lcl(i) ) then + thetavp(i,k) = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) + thetavm(i,k) = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + dqsdtp(i,k) = qstp(i,k) * (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) + dtpdt(i,k) = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp(i,k)-qstp(i,k)/tp(i,k)))* & + (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/ & + tl(i)**2*dtldt(i))) dboydt(i,k) = ((dtpdt(i,k)/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i)))* & (1.608_r8 * dqsdtp(i,k) * dtpdt(i,k) -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & (1._r8+0.608_r8*q(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp(i,k)/thetavm(i,k) end if end do end do -! + + !---------------------------------------------------------------------------- + ! ? do k = msg + 1,pver - do i = il1g,il2g - if (k > lcl(i) .and. k < mx(i)) then - thetavp(i,k) = tp(i,k) * (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,mx(i))) - thetavm(i,k) = t_mid(i,k)* (1000._r8/p_mid(i,k))** (zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) -! -! dboydt is the integrand of cape change. -! + do i = 1,ncol + if ( k>lcl(i) .and. k= lel(i) .and. k <= mx(i) - 1) then - dadt(i) = dadt(i) + dboydt(i,k)* (z_int(i,k)-z_int(i,k+1)) + dadt(i) = dadt(i) + dboydt(i,k)*(z_int(i,k)-z_int(i,k+1)) endif end do end do - do i = il1g,il2g - dltaa = -1._r8* (cape(i)-capelmt) - if (dadt(i) /= 0._r8) mb(i) = max(dltaa/zm_param%tau/dadt(i),0._r8) - if (zm_param%zm_microp .and. mx(i)-jt(i) < 2._r8) mb(i) =0.0_r8 + + !---------------------------------------------------------------------------- + ! ? + do i = 1,ncol + dltaa = -1._r8*( cape(i) - capelmt ) + if (dadt(i) /= 0._r8) then + mb(i) = max(dltaa/zm_param%tau/dadt(i),0._r8) + end if + if (zm_param%zm_microp .and. mx(i)-jt(i) < 2._r8) then + mb(i) = 0.0_r8 + end if end do -! + + !---------------------------------------------------------------------------- return end subroutine closure From f83bbc26701d086658aa71e98c5c7d4b5a4f1917 Mon Sep 17 00:00:00 2001 From: "Andrew M. Bradley" Date: Mon, 15 Jul 2024 15:21:26 -0500 Subject: [PATCH 122/398] Hommexx: Fix the general-case anti-pattern of team_barrier in a TTR. team_barrier can appear inside a TeamThreadRange only with special threading configurations. Since we want to test threading using the mimic-GPU setup with general thread configurations, convert all the cases to be correct in all threading configurations. --- components/homme/src/share/cxx/HybridVCoord.hpp | 1 - .../homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp | 8 -------- .../homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp | 6 +----- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/components/homme/src/share/cxx/HybridVCoord.hpp b/components/homme/src/share/cxx/HybridVCoord.hpp index b96237acc04c..1348246c00aa 100644 --- a/components/homme/src/share/cxx/HybridVCoord.hpp +++ b/components/homme/src/share/cxx/HybridVCoord.hpp @@ -108,7 +108,6 @@ class HybridVCoord auto dp_ij = Homme::subview(dp,igp,jgp); ColumnOps::column_reduction(kv,dp_ij,ps(igp,jgp)); - kv.team_barrier(); Kokkos::single(Kokkos::PerThread(kv.team),[&](){ ps(igp,jgp) += hybrid_ai0*ps0; diff --git a/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp b/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp index 8618899c692c..fbb97a25b94e 100644 --- a/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp +++ b/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp @@ -547,20 +547,14 @@ struct CaarFunctorImpl { Kokkos::single(Kokkos::PerThread(kv.team),[&]() { pi_i(0)[0] = m_hvcoord.ps0*m_hvcoord.hybrid_ai0; }); - kv.team_barrier(); ColumnOps::column_scan_mid_to_int(kv,dp,pi_i); ColumnOps::compute_midpoint_values(kv,pi_i,pi); - // Barrier so that the buffer shared by pi_i and omega_i is free for - // omega_i to use. - kv.team_barrier(); - Kokkos::single(Kokkos::PerThread(kv.team),[&]() { omega_i(0)[0] = 0.0; }); - kv.team_barrier(); ColumnOps::column_scan_mid_to_int(kv,div_vdp,omega_i); // Average omega_i to midpoints, and change sign, since later @@ -1222,7 +1216,6 @@ struct CaarFunctorImpl { ColumnOps::compute_midpoint_values(kv,prod_x,mgrad_x); ColumnOps::compute_midpoint_values(kv,prod_y,mgrad_y); } - kv.team_barrier(); // Apply pgrad_correction: mgrad += cp*T0*(grad(log(exner))-grad(exner)/exner) (if applicable) if (m_pgrad_correction) { @@ -1241,7 +1234,6 @@ struct CaarFunctorImpl { mgrad_y(ilev) += cp*T0*(grad_tmp_i_y(ilev) - grad_exner_i_y(ilev)/exner_i(ilev)); }); } - kv.team_barrier(); // Compute KE. Also, add fcor to vort auto u = Homme::subview(m_state.m_v,kv.ie,m_data.n0,0,igp,jgp); diff --git a/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp b/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp index ea0dfd8085a3..f36966a4bca5 100644 --- a/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp +++ b/components/homme/src/theta-l_kokkos/cxx/LimiterFunctor.hpp @@ -126,8 +126,6 @@ struct LimiterFunctor { diff(ilev) = (dp(ilev) - m_dp3d_thresh*dp0(ilev))*spheremp; }); - kv.team_barrier(); - Real min_diff = Kokkos::reduction_identity::min(); auto diff_as_real = Homme::viewAsReal(diff); auto dp_as_real = Homme::viewAsReal(dp); @@ -143,7 +141,6 @@ struct LimiterFunctor { #endif result = result<=diff_as_real(k) ? result : diff_as_real(k); }, reducer); - kv.team_barrier(); auto vtheta_dp = Homme::subview(m_state.m_vtheta_dp,kv.ie,m_np1,igp,jgp); @@ -188,8 +185,7 @@ struct LimiterFunctor { dp(ilev) = diff(ilev)/spheremp + m_dp3d_thresh*dp0(ilev); vtheta_dp(ilev) *= dp(ilev); }); - } //end of min_diff < 0 - kv.team_barrier(); + } // end of min_diff < 0 Kokkos::parallel_for(Kokkos::ThreadVectorRange(kv.team,NUM_LEV), [&](const int ilev) { From b8957f73c9d39a798c282d1b37b3cf4af2bf4b90 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 12:18:18 -0700 Subject: [PATCH 123/398] Hommexx: fix handling of reduction in hybrid coord ps_ref calculation --- components/homme/src/share/cxx/HybridVCoord.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/homme/src/share/cxx/HybridVCoord.hpp b/components/homme/src/share/cxx/HybridVCoord.hpp index 1348246c00aa..7b3712640c4d 100644 --- a/components/homme/src/share/cxx/HybridVCoord.hpp +++ b/components/homme/src/share/cxx/HybridVCoord.hpp @@ -107,10 +107,11 @@ class HybridVCoord auto dp_ij = Homme::subview(dp,igp,jgp); - ColumnOps::column_reduction(kv,dp_ij,ps(igp,jgp)); + Real ps_val = 0; + ColumnOps::column_reduction(kv,dp_ij,ps_val); Kokkos::single(Kokkos::PerThread(kv.team),[&](){ - ps(igp,jgp) += hybrid_ai0*ps0; + ps(igp,jgp) = ps_val + hybrid_ai0*ps0; }); }); kv.team_barrier(); From 09f1e8bce62f87f3e479fdde41a5c1922081742c Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 12:22:08 -0700 Subject: [PATCH 124/398] EAMxx: add support for rank-0 fields in compute_mask --- .../src/share/field/tests/compute_mask.cpp | 59 +++++++++++++++++++ .../src/share/field/utils/compute_mask.cpp | 23 ++++++-- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/components/eamxx/src/share/field/tests/compute_mask.cpp b/components/eamxx/src/share/field/tests/compute_mask.cpp index 03a7478c3b44..a95c9b04603e 100644 --- a/components/eamxx/src/share/field/tests/compute_mask.cpp +++ b/components/eamxx/src/share/field/tests/compute_mask.cpp @@ -18,6 +18,8 @@ TEST_CASE ("compute_mask") { std::vector dims3d = {ncols,2,nlevs}; std::vector dims2d = {ncols,nlevs}; + FieldIdentifier fid0d ("foo", {}, units, "some_grid"); + FieldIdentifier fid0di ("foo", {}, units, "some_grid",DataType::IntType); FieldIdentifier fid3d ("foo", {tags3d,dims3d}, units, "some_grid"); FieldIdentifier fid3di ("foo", {tags3d,dims3d}, units, "some_grid", DataType::IntType); FieldIdentifier fid2d ("foo", {tags2d,dims2d}, units, "some_grid"); @@ -89,6 +91,63 @@ TEST_CASE ("compute_mask") { compute_mask(x,2,Comparison::LT,m); REQUIRE(views_are_equal(m,zero)); + // x<=2 is true + m.deep_copy(-1); + compute_mask(x,2,Comparison::LE,m); + REQUIRE(views_are_equal(m,one)); + } + SECTION ("check 0d") { + Field x(fid0d), one(fid0di), zero(fid0di), m(fid0di); + + x.allocate_view(); + one.allocate_view(); + m.allocate_view(); + zero.allocate_view(); + + one.deep_copy(1); + zero.deep_copy(0); + x.deep_copy(2); + + // x==1 is false + m.deep_copy(-1); + compute_mask(x,1,Comparison::EQ,m); + REQUIRE(views_are_equal(m,zero)); + + // x!=1 is true + m.deep_copy(-1); + compute_mask(x,1,Comparison::NE,m); + REQUIRE(views_are_equal(m,one)); + + // x==2 is true + m.deep_copy(-1); + compute_mask(x,2,Comparison::EQ,m); + REQUIRE(views_are_equal(m,one)); + + // x>1 is true + m.deep_copy(-1); + compute_mask(x,1,Comparison::GT,m); + REQUIRE(views_are_equal(m,one)); + + // x>2 is false + m.deep_copy(-1); + compute_mask(x,2,Comparison::GT,m); + REQUIRE(views_are_equal(m,zero)); + + // x>=2 is true + m.deep_copy(-1); + compute_mask(x,2,Comparison::GE,m); + REQUIRE(views_are_equal(m,one)); + + // x<3 is true + m.deep_copy(-1); + compute_mask(x,3,Comparison::LT,m); + REQUIRE(views_are_equal(m,one)); + + // x<2 is flase + m.deep_copy(-1); + compute_mask(x,2,Comparison::LT,m); + REQUIRE(views_are_equal(m,zero)); + // x<=2 is true m.deep_copy(-1); compute_mask(x,2,Comparison::LE,m); diff --git a/components/eamxx/src/share/field/utils/compute_mask.cpp b/components/eamxx/src/share/field/utils/compute_mask.cpp index 5674ac5d16f2..d9596a22e8dd 100644 --- a/components/eamxx/src/share/field/utils/compute_mask.cpp +++ b/components/eamxx/src/share/field/utils/compute_mask.cpp @@ -53,7 +53,13 @@ void compute_mask (const Field& f, const ST value, Comparison CMP, Field& mask) auto mv = mask.get_view(); if (contiguous) { auto v = f.get_view(); - if constexpr (N==1) { + if constexpr (N==0) { + range_t policy(0,1); + auto lambda = KOKKOS_LAMBDA (int) { + mv() = compare(v(),value,CMP); + }; + Kokkos::parallel_for(policy,lambda); + } else if constexpr (N==1) { range_t policy(0,end[0]); auto lambda = KOKKOS_LAMBDA (int i) { mv(i) = compare(v(i),value,CMP); @@ -138,11 +144,15 @@ void compute_mask (const Field& f, const ScalarWrapper value, Comparison CMP, Fi { // Sanity checks EKAT_REQUIRE_MSG (f.is_allocated(), - "Error! Input field was not yet allocated.\n"); - EKAT_REQUIRE_MSG (f.rank()>0 and f.rank()<=6, - "Error! Input field rank not supported.\n"); + "Error! Input field was not yet allocated.\n" + " - field name; " + f.name() + "\n"); + EKAT_REQUIRE_MSG (f.rank()<=6, + "Error! Input field rank not supported.\n" + " - field name; " + f.name() + "\n" + " - field rank: " + std::to_string(f.rank()) + "\n"); EKAT_REQUIRE_MSG (mask.is_allocated(), - "Error! Mask field was not yet allocated.\n"); + "Error! Mask field was not yet allocated.\n" + " - mask field name; " + mask.name() + "\n"); EKAT_REQUIRE_MSG (not mask.is_read_only(), "Error! Cannot update mask field, as it is read-only.\n" " - mask name: " + mask.name() + "\n"); @@ -170,6 +180,7 @@ void compute_mask (const Field& f, const ScalarWrapper value, Comparison CMP, Fi switch (f_dt) { case DataType::IntType: switch(f.rank()) { + case 0: impl::compute_mask<0>(f,value.as(),CMP,mask); break; case 1: impl::compute_mask<1>(f,value.as(),CMP,mask); break; case 2: impl::compute_mask<2>(f,value.as(),CMP,mask); break; case 3: impl::compute_mask<3>(f,value.as(),CMP,mask); break; @@ -179,6 +190,7 @@ void compute_mask (const Field& f, const ScalarWrapper value, Comparison CMP, Fi } break; case DataType::FloatType: switch(f.rank()) { + case 0: impl::compute_mask<0>(f,value.as(),CMP,mask); break; case 1: impl::compute_mask<1>(f,value.as(),CMP,mask); break; case 2: impl::compute_mask<2>(f,value.as(),CMP,mask); break; case 3: impl::compute_mask<3>(f,value.as(),CMP,mask); break; @@ -188,6 +200,7 @@ void compute_mask (const Field& f, const ScalarWrapper value, Comparison CMP, Fi } break; case DataType::DoubleType: switch(f.rank()) { + case 0: impl::compute_mask<0>(f,value.as(),CMP,mask); break; case 1: impl::compute_mask<1>(f,value.as(),CMP,mask); break; case 2: impl::compute_mask<2>(f,value.as(),CMP,mask); break; case 3: impl::compute_mask<3>(f,value.as(),CMP,mask); break; From 4cef1b1d6c21a9cf55785f0b3b723db9b903082c Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Tue, 2 Dec 2025 12:05:24 -0800 Subject: [PATCH 125/398] Removes a print statement Deletes a print statement that was mistakenly added. --- components/elm/src/main/initVerticalMod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index 1fc64726ab82..b504e60d3809 100755 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -180,7 +180,6 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) do j = 1, nlevgrnd zsoi(j) = scalez*(exp(zecoeff*(dble(j)-0.5_r8))-1._r8) !node depths enddo - print *, "done with init vertical" end if deallocate(zsoi_in) From 26fe31830b3b9d855d59b3363ac71464675e3fe3 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 2 Dec 2025 12:54:07 -0800 Subject: [PATCH 126/398] cleanup closure() --- components/eam/src/physics/cam/zm_conv.F90 | 284 +++++++++++---------- 1 file changed, 143 insertions(+), 141 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 38d97f20f9e0..8040fb97a197 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -5,10 +5,25 @@ module zm_conv ! Contributors: Guang Zhang, Norman McFarlane, Michael Lazare, Phil Rasch, ! Rich Neale, Byron Boville, Xiaoliang Song, Walter Hannah !---------------------------------------------------------------------------- - ! for equations and technical details the best reference is: + ! Relevant literature: + ! + ! ZM95 => Zhang, G. J., & N. A. McFarlane (1995): Sensitivity of climate + ! simulations to the parameterization of cumulus convection in the Canadian + ! climate centre general circulation model. Atmosphere-Ocean, 33(3), + ! 407–446. https://doi.org/10.1080/07055900.1995.9649539 + ! + ! Z02 => Zhang, G. J. (2002): Convective quasi-equilibrium in midlatitude + ! continental environment and its effect on convective parameterization, + ! J. Geophys. Res., 107(D14), doi:10.1029/2001JD001005 + ! + ! AS74 => Arakawa, A., and W. H. Schubert (1974): Interaction of a Cumulus + ! Cloud Ensemble with the Large-Scale Environment, Part I. J. Atmos. Sci., + ! 31, 674–701, https://doi.org/10.1175/1520-0469(1974)031<0674:IOACCE>2.0.CO;2 + !---------------------------------------------------------------------------- + ! for equations and details the best reference is the CAM5 tehcnical description: ! Neale, R., Gettelman, A., Park, S., Chen, C.-C., Lauritzen, P. H., et al. - ! (2012). Description of the NCAR Community Atmosphere Model (CAM 5.0). - ! https://doi.org/10.5065/wgtk-4g06 + ! (2012). Description of the NCAR Community Atmosphere Model (CAM 5.0). + ! https://doi.org/10.5065/wgtk-4g06 ! which can also be found here: ! https://opensky.ucar.edu/islandora/object/technotes%3A594?search_api_fulltext=CAM5 !---------------------------------------------------------------------------- @@ -41,8 +56,8 @@ module zm_conv type(zm_param_t), public :: zm_param ! derived type to hold ZM tunable parameters !---------------------------------------------------------------------------- ! private variables - real(r8), parameter :: capelmt = 70._r8 ! threshold value for cape for deep convection - real(r8), parameter :: trigdcapelmt = 0._r8 ! threshold value of dcape for deep convection + real(r8), parameter :: cape_threshold = 70._r8 ! threshold value of cape for deep convection + real(r8), parameter :: dcape_threshold = 0._r8 ! threshold value of dcape for deep convection real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error real(r8), parameter :: interp_diff_min = 1.E-6_r8 ! minimum threshold for interpolation method - see eq (4.109), (4.118), (4.119) !=================================================================================================== @@ -175,7 +190,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols) :: capem1 ! time n-1 CAPE logical iclosure ! flag for compute_dilute_cape() - real(r8) capelmt_wk ! local capelmt to allow exceptions when calling closure() with trigdcape + real(r8) cape_threshold_alt ! local cape_threshold to allow exceptions when calling closure() with dcape trigger integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep @@ -362,31 +377,31 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! determine whether ZM is active in each column (ideep=1) or not (ideep=0), ! based on requirement that cape>0 and lel capelmt) then - lengath = lengath + 1 - gather_index(lengath) = i - end if - else if (cape(i) > 0.0_r8 .and. dcape(i) > trigdcapelmt) then - ! use constant 0 or a separate threshold for capt because capelmt is for default trigger - lengath = lengath + 1 - gather_index(lengath) = i - endif - else - if (cape(i) > capelmt) then - lengath = lengath + 1 - gather_index(lengath) = i + if (zm_param%trig_dcape) then + if (is_first_step) then + if (cape(i) > cape_threshold) then + lengath = lengath + 1 + gather_index(lengath) = i + end if + else + if (cape(i) > cape_threshold_alt .and. dcape(i) > dcape_threshold) then + ! use constant 0 or a separate threshold for capt because cape_threshold is for default trigger + lengath = lengath + 1 + gather_index(lengath) = i + end if + endif + else + if (cape(i) > cape_threshold) then + lengath = lengath + 1 + gather_index(lengath) = i + end if end if - end if end do if (lengath.eq.0) then @@ -501,8 +516,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & qs, cug, evpg, pflxg, rprdg, & aero, loc_microp_st ) - !---------------------------------------------------------------------------- - ! convert detrainment from units of "1/m" to "1/mb". + !--------------------------------------------------------------------------- + ! convert detrainment from units of "per length" [1/m] to "per pressure" [1/mb]. do k = msg + 1,pver do i = 1,lengath @@ -521,14 +536,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- - call closure(pcols, ncol, pver, pverp, & - qg ,tg ,pg ,z_mid_g ,sg , & - tpg ,qs ,qu ,su ,mc , & - du ,mu ,md ,qd ,sd , & - qhat ,shat ,dp ,qstpg ,z_int_g , & - qlg ,dsubcld ,mb ,capeg ,tlg , & - lclg ,lelg ,jt ,maxg ,1 , & - lengath ,msg ,capelmt_wk ) + call closure(pcols, ncol, pver, pverp, msg, cape_threshold_alt, & + lclg, lelg, jt, maxg, dsubcld, & + z_mid_g, z_int_g, pg, dp, tg, & + sg, qg, qs, qlg, shat, qhat, & + tlg, tpg, qstpg, su, qu, & + mc, du, mu, md, qd, sd, capeg, mb ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. @@ -1775,96 +1788,92 @@ end subroutine cldprp !=================================================================================================== -! subroutine closure(pcols, ncol, pver, pverp, & -! q, t_mid, p_mid, z_mid, s, & -! tp, qs, qu, su, mc, & -! du, mu, md, qd, sd, & -! qhat, shat, dp, qstp, z_int, & -! ql, dsubcld, mb, cape, tl, & -! lcl, lel, jt, mx, il1g, & -! il2g, msg, capelmt ) -subroutine closure(pcols, ncol, pver, pverp, msg, capelmt, & - lcl, lel, jt, mx, - q, t_mid, p_mid, z_mid, s, & - tp, qs, qu, su, mc, & - du, mu, md, qd, sd, & - qhat, shat, dp, qstp, z_int, & - ql, dsubcld, mb, cape, tl ) - !---------------------------------------------------------------------------- - ! Purpose: calculate closure condition for ZM convection scheme +subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & + lcl, lel, jt, mx, dsubcld, & + z_mid, z_int, p_mid, dp, t_mid, & + s, q, qs, ql, shat, qhat, & + tl, tp, qstp, su, qu, & + mc, du, mu, md, qd, sd, cape, mb ) + !---------------------------------------------------------------------------- + ! Purpose: calculate closure condition for ZM convection scheme using the + ! revised quasi-equilibrium hypothesis of Z02, in which a + ! quasi-equilibrium exists between the convective and large-scale + ! modifications of the free-tropospheric CAPE, such that the net + ! contribution is negilgible. This differs notably from AS74, where + ! they assumed that CAPE changes from free-tropospheric and boundary + ! layer changes are in balance. The Z02 revised closure is based on + ! the observation that the total CAPE change is comparable to the + ! CAPE change due to boundary layer thermodynamic changes. !---------------------------------------------------------------------------- implicit none !---------------------------------------------------------------------------- ! Arguments - integer, intent(in ) :: pcols ! maximum number of columns - integer, intent(in ) :: ncol ! actual number of columns - integer, intent(in ) :: pver ! number of mid-point vertical levels - integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! ? - real(r8), intent(in ) :: capelmt ! ? - real(r8), dimension(pcols,pver), intent(inout) :: q ! spec humidity - real(r8), dimension(pcols,pver), intent(inout) :: t_mid ! temperature - real(r8), dimension(pcols,pver), intent(inout) :: p_mid ! pressure (mb) - real(r8), dimension(pcols), intent(inout) :: mb ! cloud base mass flux - real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! height (m) - real(r8), dimension(pcols,pver), intent(in ) :: s ! normalized dry static energy - real(r8), dimension(pcols,pver), intent(in ) :: tp ! parcel temp - real(r8), dimension(pcols,pver), intent(in ) :: qs ! sat spec humidity - real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft spec. humidity - real(r8), dimension(pcols,pver), intent(in ) :: su ! normalized dry stat energy of updraft - real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux - real(r8), dimension(pcols,pver), intent(in ) :: du ! detrainment from updraft - real(r8), dimension(pcols,pver), intent(in ) :: mu ! mass flux of updraft - real(r8), dimension(pcols,pver), intent(in ) :: md ! mass flux of downdraft - real(r8), dimension(pcols,pver), intent(in ) :: qd ! spec. humidity of downdraft - real(r8), dimension(pcols,pver), intent(in ) :: sd ! dry static energy of downdraft - real(r8), dimension(pcols,pver), intent(in ) :: qhat ! environment spec humidity at interfaces - real(r8), dimension(pcols,pver), intent(in ) :: shat ! env. normalized dry static energy at intrfcs - real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness of layers - real(r8), dimension(pcols,pver), intent(in ) :: qstp ! spec humidity of parcel - real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! height of interface levels - real(r8), dimension(pcols,pver), intent(in ) :: ql ! liquid water mixing ratio - real(r8), dimension(pcols), intent(in ) :: cape ! available pot. energy of column - real(r8), dimension(pcols), intent(in ) :: tl ! ? - real(r8), dimension(pcols), intent(in ) :: dsubcld ! thickness of subcloud layer - integer, dimension(pcols), intent(in ) :: lcl ! index of lcl - integer, dimension(pcols), intent(in ) :: lel ! index of launch leve - integer, dimension(pcols), intent(in ) :: jt ! top of updraft - integer, dimension(pcols), intent(in ) :: mx ! base of updraft + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: msg ! ? + real(r8), intent(in ) :: cape_threshold_in ! CAPE threshold for "cloud work function" (i.e. A) + integer, dimension(pcols), intent(in ) :: lcl ! index of lcl + integer, dimension(pcols), intent(in ) :: lel ! index of launch leve + integer, dimension(pcols), intent(in ) :: jt ! top of updraft + integer, dimension(pcols), intent(in ) :: mx ! base of updraft + real(r8), dimension(pcols), intent(in ) :: dsubcld ! thickness of subcloud layer + real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! altitude (m) + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! height of interface levels + real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! ambient pressure (mb) + real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness of layers + real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! ambient temperature + real(r8), dimension(pcols,pver), intent(in ) :: s ! ambient dry static energy (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: q ! ambient spec humidity + real(r8), dimension(pcols,pver), intent(in ) :: qs ! ambient saturation specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: ql ! ambient liquid water mixing ratio + real(r8), dimension(pcols,pver), intent(in ) :: shat ! env. normalized dry static energy at intrfcs + real(r8), dimension(pcols,pver), intent(in ) :: qhat ! environment specific humidity at interfaces + real(r8), dimension(pcols), intent(in ) :: tl ! parcel temperature at lcl + real(r8), dimension(pcols,pver), intent(in ) :: tp ! parcel temperature + real(r8), dimension(pcols,pver), intent(in ) :: qstp ! parcel spec humidity + real(r8), dimension(pcols,pver), intent(in ) :: su ! updraft dry static energy (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux + real(r8), dimension(pcols,pver), intent(in ) :: du ! detrainment from updraft + real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: md ! dndraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: qd ! dndraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: sd ! dndraft dry static energy + real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy + real(r8), dimension(pcols), intent(out) :: mb ! cloud base mass flux !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: dtpdt ! ? - real(r8), dimension(pcols,pver) :: dqsdtp ! ? real(r8), dimension(pcols,pver) :: dtmdt ! convective temperature tendency real(r8), dimension(pcols,pver) :: dqmdt ! convective sp. humidity tendency real(r8), dimension(pcols,pver) :: dboydt ! integrand of cape change - real(r8), dimension(pcols,pver) :: thetavp ! ? - real(r8), dimension(pcols,pver) :: thetavm ! ? real(r8), dimension(pcols) :: dtbdt ! parcel temperature change due to change of subcloud layer properties during convection real(r8), dimension(pcols) :: dqbdt ! ? real(r8), dimension(pcols) :: dtldt ! ? - real(r8), dimension(pcols) :: dadt ! ? - real(r8) beta - real(r8) debdt - real(r8) dltaa - real(r8) eb - integer i, k, kmin, kmax - - real(r8), parameter :: - real(r8), parameter :: - real(r8), parameter :: - real(r8), parameter :: - - !---------------------------------------------------------------------------- - ! change of subcloud layer properties due to convection is - ! related to cumulus updrafts and downdrafts. - ! mc(z)=f(z)*mb, mub=betau*mb, mdb=betad*mb are used - ! to define betau, betad and f(z). - ! note that this implies all time derivatives are in effect - ! time derivatives per unit cloud-base mass flux, i.e. they - ! have units of 1/mb instead of 1/sec. - !---------------------------------------------------------------------------- - ! initialize output tendencies + real(r8), dimension(pcols) :: dadt ! CAPE consumption rate per unit cloud base mass flux (i.e. F in ZM95) + real(r8) :: dtpdt ! ? + real(r8) :: dqsdtp ! ? + real(r8) :: thetavp ! cloud virtual potential temperature + real(r8) :: thetavm ! ambient virtual potential temperature + real(r8) :: dltaa ! Analogous to the "cloud work function" described by AS74 + real(r8) :: beta = 0._r8 ! apparently this does nothing? + real(r8) :: eb ! + real(r8) :: debdt ! + integer :: i, k ! loop iterators + integer :: kmin, kmax ! k iteration limits + !---------------------------------------------------------------------------- + ! NOTES: + ! The change of subcloud layer properties due to convection is related to + ! updrafts and downdrafts. The following formulas are used to define + ! betau, betad and f(z): + ! mc(z) = f(z)*mb + ! mub = betau*mb + ! mdb = betad*mb + ! This implies all time derivatives are effectively time derivatives + ! per unit cloud-base mass flux, and have units of 1/mb instead of 1/sec. + !---------------------------------------------------------------------------- + ! initialization do k = msg + 1,pver do i = 1,ncol dtmdt(i,k) = 0._r8 @@ -1905,12 +1914,11 @@ subroutine closure(pcols, ncol, pver, pverp, msg, capelmt, & !---------------------------------------------------------------------------- ! ? - beta = 0._r8 do k = msg + 1,pver - 1 do i = 1,ncol if ( k>jt(i) .and. k=lel(i) .and. k<=lcl(i) ) then - thetavp(i,k) = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) - thetavm(i,k) = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) - dqsdtp(i,k) = qstp(i,k) * (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) - dtpdt(i,k) = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp(i,k)-qstp(i,k)/tp(i,k)))* & - (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/ & - tl(i)**2*dtldt(i))) - dboydt(i,k) = ((dtpdt(i,k)/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i)))* & - (1.608_r8 * dqsdtp(i,k) * dtpdt(i,k) -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & - (1._r8+0.608_r8*q(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp(i,k)/thetavm(i,k) + thetavp = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) + thetavm = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + dqsdtp = qstp(i,k) * (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) + dtpdt = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp-qstp(i,k)/tp(i,k)))* & + (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/tl(i)**2*dtldt(i))) + dboydt(i,k) = ((dtpdt/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i)))* & + (1.608_r8 * dqsdtp * dtpdt -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & + (1._r8+0.608_r8*q(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp/thetavm end if - end do - end do - - !---------------------------------------------------------------------------- - ! ? - do k = msg + 1,pver - do i = 1,ncol + ! calculate dboydt between parcel launch and LCL if ( k>lcl(i) .and. k Date: Tue, 2 Dec 2025 17:12:39 -0600 Subject: [PATCH 127/398] Additional changes to updated testing support for Greenland configurations Remove redundant 'gis' testmods dir under MALI component subdir; change pe layouts for testing to use 512 vs 256 pes; update description of default pe layout for IG case tests; update 'extra snowlayers' test to use 4-to-40km Greenland grid rather than no-longer-supported 20km grid --- cime_config/testmods_dirs/config_pes_tests.xml | 8 ++++---- cime_config/tests.py | 2 +- components/elm/cime_config/config_pes.xml | 4 ++-- .../testdefs/testmods_dirs/mali/gis/shell_commands | 6 ------ .../testdefs/testmods_dirs/mali/gis/user_nl_mali | 2 -- 5 files changed, 7 insertions(+), 15 deletions(-) delete mode 100644 components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands delete mode 100644 components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali diff --git a/cime_config/testmods_dirs/config_pes_tests.xml b/cime_config/testmods_dirs/config_pes_tests.xml index f5b9b81898c8..7535cb2d4307 100644 --- a/cime_config/testmods_dirs/config_pes_tests.xml +++ b/cime_config/testmods_dirs/config_pes_tests.xml @@ -357,7 +357,7 @@ - GIS 4to40km (low-res) testing config + chrysalis: BG-case testing config. using 4-to-40km (low-res) GIS init. cond. 64 64 @@ -366,7 +366,7 @@ 512 512 512 - 256 + 512 512 512 @@ -393,7 +393,7 @@ - GIS 4to40km (low-res) testing config + pm-cpu: BG-case testing config. using 4-to-40km (low-res) GIS init. cond. 128 128 @@ -402,7 +402,7 @@ 512 512 512 - 256 + 512 512 512 diff --git a/cime_config/tests.py b/cime_config/tests.py index a06dbc4dbf56..8629a84731f9 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -148,7 +148,7 @@ "ERS_Ld3.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.mali-landiceIG", "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-landiceBG", "ERS_Ld3.ne30pg2_r05_IcoswISC30E3r5_gis4to40.BGWCYCL1850.allactive-landiceBG", - "SMS.ne30_oECv3_gis.IGELM_MLI.elm-extrasnowlayers", + "SMS.ne30pg2_r05_IcoswISC30E3r5_gis4to40.IGELM_MLI.elm-extrasnowlayers", "ERS_Ld5.TL319_oQU240wLI_gis4to40.MPAS_FOLISIO_JRA1p5.mpaso-jra_1958", "ERS_Ld5.TL319_oQU240wLI_ais8to30.MPAS_FOLISIO_JRA1p5.mpaso-jra_1958", ) diff --git a/components/elm/cime_config/config_pes.xml b/components/elm/cime_config/config_pes.xml index 8c18028f814e..85741a632819 100644 --- a/components/elm/cime_config/config_pes.xml +++ b/components/elm/cime_config/config_pes.xml @@ -460,7 +460,7 @@ - pm-cpu: GIS 1-to-10km (high-res) baseline config + pm-cpu: IG-case testing config. using 1-to-10km (high-res) GIS init. cond. 128 128 @@ -497,7 +497,7 @@ - GIS 1-to-10km (high-res) baseline config + chrysalis: IG-case testing config. using 1-to-10km (high-res) GIS init. cond. 64 64 diff --git a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands deleted file mode 100644 index 48e4476439b8..000000000000 --- a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/shell_commands +++ /dev/null @@ -1,6 +0,0 @@ -./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/gis/user_nl_mali b/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali deleted file mode 100644 index 5b40fb4c8069..000000000000 --- a/components/mpas-albany-landice/cime_config/testdefs/testmods_dirs/mali/gis/user_nl_mali +++ /dev/null @@ -1,2 +0,0 @@ -config_am_globalstats_enable = .false. -config_am_regionalstats_enable = .false. From 01f176b44b737c7cdbe7cc63ffd6d3ae51c6668a Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 2 Dec 2025 15:17:17 -0800 Subject: [PATCH 128/398] more consistent for loop formatting --- components/eam/src/physics/cam/zm_conv.F90 | 96 +++++++++++----------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 8040fb97a197..7c21e7473117 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -311,7 +311,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! locate PBL top index - do k = pver - 1,msg + 1,-1 + do k = pver-1, msg+1, -1 do i = 1,ncol if (abs(z_mid(i,k)-z_srf(i)-pbl_hgt(i)) < (z_int(i,k)-z_int(i,k+1))*0.5_r8) then pbl_top(i) = k @@ -382,7 +382,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & if ( zm_param%trig_dcape .and. (.not.is_first_step) ) cape_threshold_alt = 0.0_r8 lengath = 0 - do i=1,ncol + do i = 1,ncol if (zm_param%trig_dcape) then if (is_first_step) then if (cape(i) > cape_threshold) then @@ -410,7 +410,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & return end if - do ii=1,lengath + do ii = 1,lengath ideep(ii)=gather_index(ii) end do @@ -474,7 +474,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! calculate sub-cloud layer pressure "thickness" for use in ! closure and tendency routines. - do k = msg + 1,pver + do k = msg+1, pver do i = 1,lengath if (k >= maxg(i)) then dsubcld(i) = dsubcld(i) + dp(i,k) @@ -484,7 +484,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! define interfacial values for (q,s) used in subsequent routines. - do k = msg + 2,pver + do k = msg+2, pver do i = 1,lengath sdifr = 0._r8 qdifr = 0._r8 @@ -519,7 +519,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !--------------------------------------------------------------------------- ! convert detrainment from units of "per length" [1/m] to "per pressure" [1/mb]. - do k = msg + 1,pver + do k = msg+1, pver do i = 1,lengath du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) @@ -546,9 +546,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. - do i=1,lengath + do i = 1,lengath mumax(i) = 0 - do k=msg + 2,pver + do k = msg+2, pver mumax(i) = max(mumax(i), mu(i,k)/dp(i,k)) end do if (mumax(i) > 0._r8) then @@ -563,7 +563,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! don't allow convection within PBL (suggestion of Bjorn Stevens, 8-2000) if (zm_param%no_deep_pbl) then - do i=1,lengath + do i = 1,lengath if (z_mid_in(ideep(i),jt(i)) < pbl_hgt(ideep(i))) mb(i) = 0 end do end if @@ -571,12 +571,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! apply cloud base mass flux scaling - do i=1,lengath + do i = 1,lengath ! zero out micro data for inactive columns if ( zm_param%zm_microp .and. mb(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) - do k=msg+1,pver + do k = msg+1,pver mu (i,k) = mu (i,k)*mb(i) md (i,k) = md (i,k)*mb(i) mc (i,k) = mc (i,k)*mb(i) @@ -620,7 +620,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! scatter data (i.e. undo the gathering) - do k = msg + 1,pver + do k = msg+1, pver #ifdef CPRCRAY !DIR$ CONCURRENT #endif @@ -656,7 +656,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! Compute precip by integrating change in water vapor minus detrained cloud water do i = 1,ncol - do k = pver,msg + 1,-1 + do k = pver, msg+1, -1 if (zm_param%zm_microp) then prec(i) = prec(i) - p_del_in(i,k)*(q(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt else @@ -991,7 +991,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & !---------------------------------------------------------------------------- ! compute taylor series for approximate eps(z) below - do k = pver - 1,msg + 1,-1 + do k = pver-1, msg+1, -1 do i = 1,ncol if (k < jb(i) .and. k >= jt(i)) then k1(i,k) = k1(i,k+1) + (h_env(i,jb(i))-h_env(i,k))*dz(i,k) @@ -1008,7 +1008,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & !---------------------------------------------------------------------------- ! re-initialize minimum MSE for ensuing calculation h_env_min(1:ncol) = 1.E6_r8 - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol if (k >= j0(i) .and. k <= jb(i) .and. h_env(i,k) <= h_env_min(i)) then h_env_min(i) = h_env(i,k) @@ -1019,7 +1019,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & !---------------------------------------------------------------------------- ! compute approximate eps(z) using above taylor series - do k = msg + 2,pver + do k = msg+2, pver do i = 1,ncol expnum(i) = 0._r8 ftemp(i) = 0._r8 @@ -1052,7 +1052,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & end do ! ensure that entrainment does not increase above the level that detrainment starts - do k = msg + 2,pver + do k = msg+2, pver do i = 1,ncol if (k >= jt(i) .and. k <= j0(i)) then f(i,k) = max(f(i,k),f(i,k-1)) @@ -1069,7 +1069,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & ! The modification below comes from: ! Rasch, P. J., J. E. Kristjánsson, A comparison of the CCM3 model climate ! using diagnosed and predicted condensate parameterizations, J. Clim., 1997. - do k = pver,msg + 1,-1 + do k = pver, msg+1, -1 do i = 1,ncol if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) if ( k =jt(i) ) eps(i,k) = f(i,k) @@ -1253,7 +1253,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & !---------------------------------------------------------------------------- ! interpolate the mid-point values to interfaces - do k = msg+1,pver + do k = msg+1, pver do i = 1,ncol hsthat(i,k) = h_env_sat(i,k) qsthat(i,k) = qst(i,k) @@ -1289,7 +1289,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & !---------------------------------------------------------------------------- ! find the level of minimum saturated MSE (h_env_sat), where detrainment starts do i = 1,ncol - do k = msg + 1,pver + do k = msg+1, pver if (h_env_sat(i,k) <= h_env_min(i) .and. k >= jt(i) .and. k <= jb(i)) then h_env_min(i) = h_env_sat(i,k) j0(i) = k @@ -1304,7 +1304,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & !---------------------------------------------------------------------------- ! Initialize cloud moist and dry static energies (hu=MSE & su=DSE) - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol if (k >= jt(i) .and. k <= jb(i)) then ! Tunable temperature perturbation (tiedke_add) was already added to parcel hu/su to @@ -1338,7 +1338,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & do iter = 1,itnum - do k = pver,msg + 1,-1 + do k = pver, msg+1, -1 do i = 1,ncol cu(i,k) = 0._r8 ql(i,k) = 0._r8 @@ -1354,7 +1354,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & if (zm_param%zm_microp) hu(i,jb(i)) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add end do - do k = pver,msg + 1,-1 + do k = pver, msg+1, -1 do i = 1,ncol ! intialize updraft mass flux variables - here and below all normalized by cloud base mass flux (mb) if (eps0(i) > 0._r8) then @@ -1376,7 +1376,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & khighest = pverp klowest = 1 - do i=1,ncol + do i = 1,ncol khighest = min(khighest,lel(i)) klowest = max(klowest,jb(i)) end do @@ -1406,16 +1406,16 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & ! reset cloud top index beginning from two layers above the ! cloud base (i.e. if cloud is only one layer thick, top is not reset - do i=1,ncol + do i = 1,ncol doit(i) = .true. tot_frz(i)= 0._r8 - do k = pver,msg + 1,-1 + do k = pver, msg+1, -1 tot_frz(i)= tot_frz(i) + tmp_frz(i,k)*dz(i,k) end do end do - do k=klowest-2,khighest-1,-1 - do i=1,ncol + do k = klowest-2, khighest-1, -1 + do i = 1,ncol if (doit(i) .and. k <= jb(i)-2 .and. k >= lel(i)-1) then if (hu(i,k) <= hsthat(i,k) .and. & hu(i,k+1) > hsthat(i,k+1) .and. & @@ -1439,7 +1439,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & if (iter == 1) jto(i) = jt(i) end do - do k = pver,msg + 1,-1 + do k = pver, msg+1, -1 do i = 1,ncol if (k >= lel(i) .and. k <= jt(i) .and. eps0(i) > 0._r8) then mu(i,k) = 0._r8 @@ -1458,7 +1458,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & ! determine LCL - see eq (4.127)- (4.130) of Neale et al. (2012) done(1:ncol) = .false. kount = 0 - do k = pver,msg + 2,-1 + do k = pver, msg+2, -1 do i = 1,ncol if (k == jb(i) .and. eps0(i) > 0._r8) then qu(i,k) = q(i,jb(i)) @@ -1481,7 +1481,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & 690 continue - do k = msg + 2,pver + do k = msg+2, pver do i = 1,ncol if ((k > jt(i) .and. k <= jlcl(i)) .and. eps0(i) > 0._r8) then su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) @@ -1491,7 +1491,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end do ! compute condensation in updraft - do k = pver,msg + 2,-1 + do k = pver, msg+2, -1 do i = 1,ncol if (eps0(i)>0._r8) then if ( zm_param%zm_microp) tmp_k_limit = jlcl(i)+1 @@ -1575,7 +1575,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & loc_microp_st%dsfm, loc_microp_st%dsfn ) #endif - do k = pver,msg + 2,-1 + do k = pver, msg+2, -1 do i = 1,ncol ! In the original ZM scheme, which does not consider ice phase, ql actually represents total cloud ! water. With convective microphysics, loc_microp_st%qliq and loc_microp_st%qice represent cloud @@ -1595,7 +1595,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end if end do - do k = pver,msg + 2,-1 + do k = pver, msg+2, -1 do i = 1,ncol if (k >= jt(i) .and. k < jb(i) .and. eps0(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-du(i,k)*( loc_microp_st%qcde(i,k+1) & @@ -1614,7 +1614,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & ! consistently applied. ! mu, ql are interface quantities ! cu, du, eu, rprd are midpoint quantites - do k = pver,msg + 2,-1 + do k = pver, msg+2, -1 do i = 1,ncol rprd(i,k) = 0._r8 if (k >= jt(i) .and. k < jb(i) .and. eps0(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then @@ -1649,7 +1649,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & md(i,jd(i)) = -zm_param%alfa * epsm(i) / eps0(i) end if end do - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol if ((k > jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8) then zdef(i) = z_int(i,jd(i)) - z_int(i,k) @@ -1657,7 +1657,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end if end do end do - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol if ((k >= jt(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then ratmjb(i) = min(abs(mu(i,jb(i))/md(i,jb(i))),1._r8) @@ -1666,7 +1666,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end do end do - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol if ((k >= jt(i) .and. k <= pver) .and. eps0(i) > 0._r8) then ed(i,k-1) = (md(i,k-1)-md(i,k))/dz(i,k-1) @@ -1677,7 +1677,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end do ! calculate updraft and downdraft properties - do k = msg + 2,pver + do k = msg+2, pver do i = 1,ncol if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) @@ -1690,7 +1690,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*qd(i,jd(i)))/zm_const%cpair end do - do k = msg + 2,pver + do k = msg+2, pver do i = 1,ncol if (k >= jd(i) .and. k < jb(i) .and. eps0(i) > 0._r8) then qd(i,k+1) = qds(i,k+1) @@ -1711,7 +1711,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & totevp(i) = max(totevp(i),0._r8) end do - do k = msg + 2,pver + do k = msg+2, pver do i = 1,ncol ! ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then @@ -1743,7 +1743,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end do ! calculate net mass flux - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol mc(i,k) = mu(i,k) + md(i,k) end do @@ -1765,7 +1765,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end if ! disable columns if top is at or below LCL if using ZM microphysics if ( jt(i)>=jlcl(i) ) then - do k = msg + 1,pver + do k = msg+1, pver mu(i,k) = 0._r8 eu(i,k) = 0._r8 du(i,k) = 0._r8 @@ -1874,7 +1874,7 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & ! per unit cloud-base mass flux, and have units of 1/mb instead of 1/sec. !---------------------------------------------------------------------------- ! initialization - do k = msg + 1,pver + do k = msg+1, pver do i = 1,ncol dtmdt(i,k) = 0._r8 dqmdt(i,k) = 0._r8 @@ -1899,7 +1899,7 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & !---------------------------------------------------------------------------- ! ? - do k = msg + 1,pver - 1 + do k = msg+1, pver-1 do i = 1,ncol if (k==jt(i)) then dtmdt(i,k) = (1._r8/dp(i,k)) & @@ -1914,7 +1914,7 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & !---------------------------------------------------------------------------- ! ? - do k = msg + 1,pver - 1 + do k = msg+1, pver-1 do i = 1,ncol if ( k>jt(i) .and. k=lel(i) .and. k<=lcl(i) ) then @@ -2036,7 +2036,7 @@ subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & real(r8) emc !---------------------------------------------------------------------------- ! initialize variables - do k = msg + 1,pver + do k = msg+1, pver do i = il1g,il2g dsdt(i,k) = 0._r8 dqdt(i,k) = 0._r8 From 8ee14afa96c88cbb53c7daac60dacb572585570d Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 3 Dec 2025 09:37:23 -0800 Subject: [PATCH 129/398] more closure() cleanup --- components/eam/src/physics/cam/zm_conv.F90 | 81 +++++++++------------- 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 7c21e7473117..778616ffab51 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -1832,7 +1832,7 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: qhat ! environment specific humidity at interfaces real(r8), dimension(pcols), intent(in ) :: tl ! parcel temperature at lcl real(r8), dimension(pcols,pver), intent(in ) :: tp ! parcel temperature - real(r8), dimension(pcols,pver), intent(in ) :: qstp ! parcel spec humidity + real(r8), dimension(pcols,pver), intent(in ) :: qstp ! parcel specific humidity real(r8), dimension(pcols,pver), intent(in ) :: su ! updraft dry static energy (normalized) real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux @@ -1845,44 +1845,35 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols), intent(out) :: mb ! cloud base mass flux !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: dtmdt ! convective temperature tendency - real(r8), dimension(pcols,pver) :: dqmdt ! convective sp. humidity tendency real(r8), dimension(pcols,pver) :: dboydt ! integrand of cape change - real(r8), dimension(pcols) :: dtbdt ! parcel temperature change due to change of subcloud layer properties during convection - real(r8), dimension(pcols) :: dqbdt ! ? - real(r8), dimension(pcols) :: dtldt ! ? - real(r8), dimension(pcols) :: dadt ! CAPE consumption rate per unit cloud base mass flux (i.e. F in ZM95) + real(r8), dimension(pcols,pver) :: dtmdt ! free tropospheric tendencies + real(r8), dimension(pcols,pver) :: dqmdt ! free tropospheric tendencies + real(r8), dimension(pcols) :: dtbdt ! sub-cloud layer tendencies + real(r8), dimension(pcols) :: dqbdt ! sub-cloud layer tendencies + real(r8), dimension(pcols) :: dtldt ! sub-cloud layer tendencies + real(r8), dimension(pcols) :: dadt ! CAPE consumption rate per unit cloud base mass flux (i.e. "F") real(r8) :: dtpdt ! ? real(r8) :: dqsdtp ! ? real(r8) :: thetavp ! cloud virtual potential temperature real(r8) :: thetavm ! ambient virtual potential temperature - real(r8) :: dltaa ! Analogous to the "cloud work function" described by AS74 - real(r8) :: beta = 0._r8 ! apparently this does nothing? - real(r8) :: eb ! - real(r8) :: debdt ! + real(r8) :: dltaa ! Analogous to the "cloud work function" described by AS74 (i.e. "A") + real(r8) :: eb ! ? + real(r8) :: debdt ! ? integer :: i, k ! loop iterators - integer :: kmin, kmax ! k iteration limits - !---------------------------------------------------------------------------- - ! NOTES: - ! The change of subcloud layer properties due to convection is related to - ! updrafts and downdrafts. The following formulas are used to define - ! betau, betad and f(z): - ! mc(z) = f(z)*mb - ! mub = betau*mb - ! mdb = betad*mb - ! This implies all time derivatives are effectively time derivatives - ! per unit cloud-base mass flux, and have units of 1/mb instead of 1/sec. + integer :: kmin, kmax ! vertical iteration limits for vertical integration + + real(r8), parameter :: beta = 0._r8 ! proportion to use liquid water from layer below !---------------------------------------------------------------------------- ! initialization - do k = msg+1, pver - do i = 1,ncol - dtmdt(i,k) = 0._r8 - dqmdt(i,k) = 0._r8 - end do - end do + dadt(1:ncol) = 0._r8 + dtmdt(1:ncol,(msg+1):pver) = 0._r8 + dqmdt(1:ncol,(msg+1):pver) = 0._r8 + + kmin = minval(lel(1:ncol)) + kmax = maxval( mx(1:ncol)) - 1 !---------------------------------------------------------------------------- - ! ? + ! Calculate sub-cloud tendencies of virtual temperature and humidity do i = 1,ncol mb(i) = 0._r8 eb = p_mid(i,mx(i))*q(i,mx(i))/ (zm_const%epsilo+q(i,mx(i))) @@ -1898,9 +1889,10 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & end do !---------------------------------------------------------------------------- - ! ? + ! Calculate dtmdt & dqmdt do k = msg+1, pver-1 do i = 1,ncol + ! cloud top if (k==jt(i)) then dtmdt(i,k) = (1._r8/dp(i,k)) & *(mu(i,k+1)*(su(i,k+1)-shat(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & @@ -1909,13 +1901,7 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & *(mu(i,k+1)*(qu(i,k+1)-qhat(i,k+1)+ql(i,k+1) ) & + md(i,k+1)*(qd(i,k+1)-qhat(i,k+1))) end if - end do - end do - - !---------------------------------------------------------------------------- - ! ? - do k = msg+1, pver-1 - do i = 1,ncol + ! below cloud top if ( k>jt(i) .and. klcl(i) .and. k=lel(i) .and. k<=lcl(i) ) then thetavp = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) thetavm = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) @@ -1944,22 +1938,11 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & (1.608_r8 * dqsdtp * dtpdt -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & (1._r8+0.608_r8*q(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp/thetavm end if - ! calculate dboydt between parcel launch and LCL - if ( k>lcl(i) .and. k= lel(i) .and. k <= mx(i) - 1) then From 84830c10ab7859f0b2e82fc3943aada0a9a1baae Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 3 Dec 2025 10:34:05 -0800 Subject: [PATCH 130/398] more renaming --- components/eam/src/physics/cam/zm_conv.F90 | 52 +++++++++---------- .../eam/src/physics/cam/zm_conv_cape.F90 | 20 +++---- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 778616ffab51..448f6e656bb0 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -189,8 +189,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, dimension(pcols) :: maxim1 ! time n-1 index of level with largest moist static energy real(r8), dimension(pcols) :: capem1 ! time n-1 CAPE - logical iclosure ! flag for compute_dilute_cape() - real(r8) cape_threshold_alt ! local cape_threshold to allow exceptions when calling closure() with dcape trigger + logical cape_calc_msemax_klev ! flag for compute_dilute_cape() + real(r8) cape_threshold_alt ! local cape_threshold to allow exceptions when calling zm_closure() with dcape trigger integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep @@ -245,7 +245,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), parameter :: dcon = 25.e-6_r8 real(r8), parameter :: mucon = 5.3_r8 - integer dcapemx(pcols) ! launching level index saved from 1st call for CAPE calculation; used in 2nd call when DCAPE-ULL active + integer prev_msemax_klev(pcols) ! launching level index saved from 1st call for CAPE calculation; used in 2nd call when DCAPE-ULL active !---------------------------------------------------------------------------- ! Set upper limit of convection to "limcnv-1" @@ -344,11 +344,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! Evaluate Tparcel, qs(Tparcel), buoyancy, CAPE, lcl, lel, parcel launch level at index maxi()=hmax - ! - call #1, iclosure=.true. standard calculation using state of current step - ! - call #2, iclosure=.false. use state from previous step and launch level from call #1 + ! - call #1, cape_calc_msemax_klev=.true. standard calculation using state of current step + ! - call #2, cape_calc_msemax_klev=.false. use launch level (msemax_klev) from previous call ! DCAPE is the difference in CAPE between the two calls using the same launch level - iclosure = .true. + cape_calc_msemax_klev = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & q, t_mid, z_mid, p_mid, p_int, & @@ -356,12 +356,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & tp, qstp, maxi, tl, & lcl, lel, cape, & zm_const, zm_param, & - iclosure ) + cape_calc_msemax_klev ) ! Calculate dcape trigger condition if ( .not.is_first_step .and. zm_param%trig_dcape ) then - iclosure = .false. - dcapemx(:ncol) = maxi(:ncol) + cape_calc_msemax_klev = .false. + prev_msemax_klev(:ncol) = maxi(:ncol) call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & q_star, t_star, z_mid, p_mid, p_int, & @@ -369,7 +369,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & tpm1, qstpm1, maxim1, tlm1, & lclm1, lelm1, capem1, & zm_const, zm_param, & - iclosure, dcapemx ) + cape_calc_msemax_klev, prev_msemax_klev ) dcape(:ncol) = (cape(:ncol)-capem1(:ncol))/(delt*2._r8) endif @@ -471,9 +471,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & end if !---------------------------------------------------------------------------- - ! calculate sub-cloud layer pressure "thickness" for use in - ! closure and tendency routines. - + ! calculate sub-cloud layer pressure "thickness" for closure and tendency calculations do k = msg+1, pver do i = 1,lengath if (k >= maxg(i)) then @@ -483,7 +481,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & end do !---------------------------------------------------------------------------- - ! define interfacial values for (q,s) used in subsequent routines. + ! define interfacial values for (q,s) used in subsequent routines do k = msg+2, pver do i = 1,lengath sdifr = 0._r8 @@ -536,12 +534,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- - call closure(pcols, ncol, pver, pverp, msg, cape_threshold_alt, & - lclg, lelg, jt, maxg, dsubcld, & - z_mid_g, z_int_g, pg, dp, tg, & - sg, qg, qs, qlg, shat, qhat, & - tlg, tpg, qstpg, su, qu, & - mc, du, mu, md, qd, sd, capeg, mb ) + call zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_alt, & + lclg, lelg, jt, maxg, dsubcld, & + z_mid_g, z_int_g, pg, dp, tg, & + sg, qg, qs, qlg, shat, qhat, & + tlg, tpg, qstpg, su, qu, & + mc, du, mu, md, qd, sd, capeg, mb ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. @@ -1788,12 +1786,12 @@ end subroutine cldprp !=================================================================================================== -subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & - lcl, lel, jt, mx, dsubcld, & - z_mid, z_int, p_mid, dp, t_mid, & - s, q, qs, ql, shat, qhat, & - tl, tp, qstp, su, qu, & - mc, du, mu, md, qd, sd, cape, mb ) +subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & + lcl, lel, jt, mx, dsubcld, & + z_mid, z_int, p_mid, dp, t_mid, & + s, q, qs, ql, shat, qhat, & + tl, tp, qstp, su, qu, & + mc, du, mu, md, qd, sd, cape, mb ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the ! revised quasi-equilibrium hypothesis of Z02, in which a @@ -1965,7 +1963,7 @@ subroutine closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & !---------------------------------------------------------------------------- return -end subroutine closure +end subroutine zm_closure !=================================================================================================== diff --git a/components/eam/src/physics/cam/zm_conv_cape.F90 b/components/eam/src/physics/cam/zm_conv_cape.F90 index a469cc7755e2..455af77d76ca 100644 --- a/components/eam/src/physics/cam/zm_conv_cape.F90 +++ b/components/eam/src/physics/cam/zm_conv_cape.F90 @@ -34,7 +34,7 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & lcl_temperature, lcl_klev, & eql_klev, cape, & zm_const, zm_param, & - iclosure, dcapemx, & + iclosure, prev_msemax_klev, & use_input_tq_mx, q_mx, t_mx ) !---------------------------------------------------------------------------- ! Purpose: calculate convective available potential energy (CAPE), lifting @@ -72,9 +72,9 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & real(r8), dimension(pcols), intent(inout) :: cape ! convective available potential energy type(zm_const_t), intent(in ) :: zm_const ! derived type to hold ZM constants type(zm_param_t), intent(in ) :: zm_param ! derived type to hold ZM tunable parameters - logical, intent(in ) :: iclosure ! true for normal procedure, otherwise use dcapemx from 1st call - integer, dimension(pcols), optional, intent(in ) :: dcapemx ! values of msemax_klev from previous call for dcape closure - logical, optional, intent(in ) :: use_input_tq_mx ! if .true., use input values of dcapemx, q_mx, t_mx in the CAPE calculation + logical, intent(in ) :: calc_msemax_klev ! true for normal procedure, otherwise use prev_msemax_klev from 1st call + integer, dimension(pcols), optional, intent(in ) :: prev_msemax_klev ! values of msemax_klev from previous call for dcape closure + logical, optional, intent(in ) :: use_input_tq_mx ! if .true., use input values of prev_msemax_klev, q_mx, t_mx in the CAPE calculation real(r8), dimension(pcols), optional, intent(inout) :: q_mx ! specified sp humidity to apply at level of max MSE if use_input_tq_mx=.true. real(r8), dimension(pcols), optional, intent(inout) :: t_mx ! specified temperature to apply at level of max MSE if use_input_tq_mx=.true. !---------------------------------------------------------------------------- @@ -105,8 +105,8 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & if ( use_input_tq_mx_loc .and. & ((.not.present(t_mx)) .or. & (.not.present(q_mx)) .or. & - (.not.present(dcapemx)) ) ) then - call endrun('compute_dilute_cape: use_input_tq_mx = .true. but dcapemx, t_mx or q_mx is not provided') + (.not.present(prev_msemax_klev)) ) ) then + call endrun('compute_dilute_cape: use_input_tq_mx = .true. but prev_msemax_klev, t_mx or q_mx is not provided') end if !---------------------------------------------------------------------------- @@ -118,11 +118,11 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & ! initialize msemax_klev and potentially modify T/q if (use_input_tq_mx_loc) then ! note - in this case we expect: - ! (1) the incoming array dcapemx contains prev identified launching level index, and + ! (1) the incoming array prev_msemax_klev contains prev identified launching level index, and ! (2) the arrays q_mx and t_mx contain q and T values at the old launching level ! at the time when the old launching level was identified. ! Copy the old values to work arrays for calculations in the rest of this subroutine - msemax_klev(1:ncol) = dcapemx(1:ncol) + msemax_klev(1:ncol) = prev_msemax_klev(1:ncol) do i=1,ncol sp_humidity(i,msemax_klev(i)) = q_mx(i) temperature(i,msemax_klev(i)) = t_mx(i) @@ -161,8 +161,8 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & ! Set level of max moist static energy for parcel initialization if ( zm_param%trig_dcape .and. (.not.iclosure) ) then ! Use max moist static energy level that is passed in - if (.not.present(dcapemx)) call endrun('** ZM CONV compute_dilute_cape: dcapemx not present **') - msemax_klev(1:ncol) = dcapemx(1:ncol) + if (.not.present(prev_msemax_klev)) call endrun('** ZM CONV compute_dilute_cape: prev_msemax_klev not present **') + msemax_klev(1:ncol) = prev_msemax_klev(1:ncol) elseif (.not.use_input_tq_mx_loc) then if ( zm_param%trig_ull) msemax_top_k(1:ncol) = pblt_ull(1:ncol) if (.not.zm_param%trig_ull) msemax_top_k(1:ncol) = pblt (1:ncol) From d4bc94da94a5c3e79df88c4a49de85dd06018769 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 3 Dec 2025 10:44:25 -0800 Subject: [PATCH 131/398] rename cldprp zm_cloud_properties --- components/eam/src/physics/cam/zm_conv.F90 | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 448f6e656bb0..3a1949398a65 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -506,13 +506,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! calculate updraft and downdraft properties - call cldprp(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & - pg, z_mid_g, z_int_g, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & - maxg, lelg, jt, jlcl, j0, jd, & - mu, eu, du, md, ed, mc, & - su, qu, qlg, sd, qd, & - qs, cug, evpg, pflxg, rprdg, & - aero, loc_microp_st ) + call zm_cloud_properties(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & + pg, z_mid_g, z_int_g, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & + maxg, lelg, jt, jlcl, j0, jd, & + mu, eu, du, md, ed, mc, & + su, qu, qlg, sd, qd, & + qs, cug, evpg, pflxg, rprdg, & + aero, loc_microp_st ) !--------------------------------------------------------------------------- ! convert detrainment from units of "per length" [1/m] to "per pressure" [1/mb]. @@ -1081,13 +1081,13 @@ end subroutine calculate_fractional_entrainment !=================================================================================================== -subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & - p_mid, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & - jb, lel, jt, jlcl, j0, jd, & - mu, eu, du, md, ed, mc, & - su, qu, ql, sd, qd, & - qst, cu, evp, pflx, rprd, & - aero, loc_microp_st ) +subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & + p_mid, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & + jb, lel, jt, jlcl, j0, jd, & + mu, eu, du, md, ed, mc, & + su, qu, ql, sd, qd, & + qst, cu, evp, pflx, rprd, & + aero, loc_microp_st ) !---------------------------------------------------------------------------- ! Purpose: Determine properties of ZM updrafts and downdrafts !---------------------------------------------------------------------------- @@ -1782,7 +1782,7 @@ subroutine cldprp(pcols, ncol, pver, pverp, msg, limcnv, & end if return -end subroutine cldprp +end subroutine zm_cloud_properties !=================================================================================================== From 6ac28d57b6825429991fa952543180b3f9fcb29f Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 3 Dec 2025 10:46:18 -0800 Subject: [PATCH 132/398] rename fractional entrainment routine --- components/eam/src/physics/cam/zm_conv.F90 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 3a1949398a65..23373c1bca08 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -919,9 +919,9 @@ end subroutine zm_conv_evap !=================================================================================================== -subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & - jb, jt, j0, z_mid, z_int, dz, & - h_env, h_env_sat, h_env_min, eps, eps0) +subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & + jb, jt, j0, z_mid, z_int, dz, & + h_env, h_env_sat, h_env_min, eps, eps0) !---------------------------------------------------------------------------- ! Purpose: Determine properties of ZM updrafts and downdrafts !---------------------------------------------------------------------------- @@ -1077,7 +1077,7 @@ subroutine calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & !---------------------------------------------------------------------------- return -end subroutine calculate_fractional_entrainment +end subroutine zm_calc_fractional_entrainment !=================================================================================================== @@ -1324,9 +1324,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & !---------------------------------------------------------------------------- ! calculate fractional entrainment (i.e. "lambda D") - see eq (4.78) from Neale et al. (2012) - call calculate_fractional_entrainment(pcols, ncol, pver, pverp, msg, & - jb, jt, j0, z_mid, z_int, dz, & - h_env, h_env_sat, h_env_min, eps, eps0) + call zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & + jb, jt, j0, z_mid, z_int, dz, & + h_env, h_env_sat, h_env_min, eps, eps0) !---------------------------------------------------------------------------- ! iteration to set cloud properties From 4315e8d2e93c806604ea028415e67a3003e5aff1 Mon Sep 17 00:00:00 2001 From: Steven Brus Date: Wed, 3 Dec 2025 15:03:33 -0600 Subject: [PATCH 133/398] Update driver-moab cime_config for wave momentum coupling --- driver-moab/cime_config/buildnml | 9 ++ driver-moab/cime_config/config_component.xml | 34 ++++++++ .../cime_config/namelist_definition_drv.xml | 85 ++++++++++++++++++- 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/driver-moab/cime_config/buildnml b/driver-moab/cime_config/buildnml index ce3ed839635d..3805b61e8cec 100755 --- a/driver-moab/cime_config/buildnml +++ b/driver-moab/cime_config/buildnml @@ -75,10 +75,19 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): # --------------------------------------------------- if case.get_value('COMP_WAV') == 'ww3': config['WAVSPEC'] = case.get_value('WAV_SPEC') + if case.get_value('COMP_ATM') == 'eam': + config['WAV_ATM_COUP'] = 'twoway' + else: + config['WAV_ATM_COUP'] = 'oneway' + if case.get_value('COMP_OCN') == 'mpaso': config['WAV_OCN_COUP'] = 'twoway' + config['ocn_surface_flux_scheme'] = 0 elif case.get_value('COMP_OCN') == 'docn': config['WAV_OCN_COUP'] = 'oneway' + + if case.get_value('COMP_ICE') == 'mpassi': + config['WAV_ICE_COUP'] = 'oneway' elif case.get_value('COMP_WAV') == 'dwav': config['WAVSPEC'] = 'sp36x36' else: diff --git a/driver-moab/cime_config/config_component.xml b/driver-moab/cime_config/config_component.xml index b6dbd33f033b..66ce520f7c3c 100644 --- a/driver-moab/cime_config/config_component.xml +++ b/driver-moab/cime_config/config_component.xml @@ -1535,6 +1535,23 @@ atm2wav state mapping file decomp type + + char + idmap + run_domain + env_run.xml + wav2atm state mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + wav2atm state mapping file decomp type + + char idmap @@ -2036,6 +2053,23 @@ wav2ocn state mapping file decomp type + + char + idmap + run_domain + env_run.xml + wav2ocn flux mapping file + + + + char + X,Y + X + run_domain + env_run.xml + wav2ocn flux mapping file decomp type + + char idmap diff --git a/driver-moab/cime_config/namelist_definition_drv.xml b/driver-moab/cime_config/namelist_definition_drv.xml index c1bdc82ca8ba..1310e5cd558f 100644 --- a/driver-moab/cime_config/namelist_definition_drv.xml +++ b/driver-moab/cime_config/namelist_definition_drv.xml @@ -318,7 +318,7 @@ char seq_flds seq_cplflds_inparm - One- or Two-way coupling between Wave and Ocn. + One- or Two-way coupling between Wave and Ocean none oneway @@ -326,6 +326,29 @@ + + char + seq_flds + seq_cplflds_inparm + One- or Two-way coupling between Wave and Atm. + + none + oneway + twoway + + + + + char + seq_flds + seq_cplflds_inparm + One- or Two-way coupling between Wave and Sea Ice. + + none + oneway + + + @@ -4908,6 +4931,36 @@ + + char + mapping + abs + seq_maps + + atm to wav state mapping file for states + + + $WAV2ATM_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $WAV2ATM_SMAPTYPE + X + + + char mapping @@ -4998,6 +5051,36 @@ + + char + mapping + abs + seq_maps + + wav to ocn flux mapping file for fluxes + + + $WAV2OCN_FMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $WAV2OCN_FMAPTYPE + X + + + char(10) drv_physics From cc110e8dff5fb0f063ab0f4d408fce8a7b22d762 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 3 Dec 2025 14:06:09 -0800 Subject: [PATCH 134/398] fix ZM cape args --- components/eam/src/physics/cam/misc_diagnostics.F90 | 12 ++++++------ components/eam/src/physics/cam/zm_conv_cape.F90 | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/eam/src/physics/cam/misc_diagnostics.F90 b/components/eam/src/physics/cam/misc_diagnostics.F90 index 581834e5d9f0..08055d651bde 100644 --- a/components/eam/src/physics/cam/misc_diagnostics.F90 +++ b/components/eam/src/physics/cam/misc_diagnostics.F90 @@ -196,7 +196,7 @@ subroutine compute_cape_diags( state, pbuf, pcols, pver, pverp, cape_out, dcape_ integer :: idx, kk, lchnk, ncol, msg - logical :: iclosure = .true. ! set to .true. to avoid interference with trig_dcape + logical :: calc_msemax_klev = .true. ! set to .true. to avoid interference with trig_dcape ! variables that distinguish different calls of compute_dilute_cape @@ -290,7 +290,7 @@ subroutine compute_cape_diags( state, pbuf, pcols, pver, pverp, cape_out, dcape_ ! Calculate CAPE using the new state; also return launching level index ! and T, qv values at (new) launching level !------------------------------------------------------------------------ - iclosure = .true. + calc_msemax_klev = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & qv_new, temp_new, & @@ -301,7 +301,7 @@ subroutine compute_cape_diags( state, pbuf, pcols, pver, pverp, cape_out, dcape_ ztl, zlcl, zlel, & cape_new_pcl_new_env, & zm_const, zm_param, & - iclosure, & + calc_msemax_klev, & use_input_tq_mx = .false., & q_mx = q_mx_new, & t_mx = t_mx_new ) @@ -323,7 +323,7 @@ subroutine compute_cape_diags( state, pbuf, pcols, pver, pverp, cape_out, dcape_ ! Calculate cape_old_pcl_new_env using ! - new state (T, qv profiles) ! - old launching level and parcel T, qv - iclosure = .true. + calc_msemax_klev = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & qv_new, temp_new, & @@ -334,8 +334,8 @@ subroutine compute_cape_diags( state, pbuf, pcols, pver, pverp, cape_out, dcape_ ztl, zlcl, zlel, & cape_old_pcl_new_env, & zm_const, zm_param, & - iclosure, & - dcapemx = mx_old, & + calc_msemax_klev, & + prev_msemax_klev = mx_old, & use_input_tq_mx = .true., & q_mx = q_mx_old, & t_mx = t_mx_old ) diff --git a/components/eam/src/physics/cam/zm_conv_cape.F90 b/components/eam/src/physics/cam/zm_conv_cape.F90 index 455af77d76ca..4537b79e9198 100644 --- a/components/eam/src/physics/cam/zm_conv_cape.F90 +++ b/components/eam/src/physics/cam/zm_conv_cape.F90 @@ -34,7 +34,7 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & lcl_temperature, lcl_klev, & eql_klev, cape, & zm_const, zm_param, & - iclosure, prev_msemax_klev, & + calc_msemax_klev, prev_msemax_klev, & use_input_tq_mx, q_mx, t_mx ) !---------------------------------------------------------------------------- ! Purpose: calculate convective available potential energy (CAPE), lifting @@ -159,7 +159,7 @@ subroutine compute_dilute_cape( pcols, ncol, pver, pverp, & !---------------------------------------------------------------------------- ! Set level of max moist static energy for parcel initialization - if ( zm_param%trig_dcape .and. (.not.iclosure) ) then + if ( zm_param%trig_dcape .and. (.not.calc_msemax_klev) ) then ! Use max moist static energy level that is passed in if (.not.present(prev_msemax_klev)) call endrun('** ZM CONV compute_dilute_cape: prev_msemax_klev not present **') msemax_klev(1:ncol) = prev_msemax_klev(1:ncol) From 47308e979033d647aea04dcaed6d02e812c40b88 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 3 Dec 2025 15:47:14 -0700 Subject: [PATCH 135/398] EAMxx: fix comments and error msg formatting --- components/eamxx/src/share/field/tests/compute_mask.cpp | 2 +- components/eamxx/src/share/field/utils/compute_mask.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/eamxx/src/share/field/tests/compute_mask.cpp b/components/eamxx/src/share/field/tests/compute_mask.cpp index a95c9b04603e..4f55f82afccf 100644 --- a/components/eamxx/src/share/field/tests/compute_mask.cpp +++ b/components/eamxx/src/share/field/tests/compute_mask.cpp @@ -86,7 +86,7 @@ TEST_CASE ("compute_mask") { compute_mask(x,3,Comparison::LT,m); REQUIRE(views_are_equal(m,one)); - // x<2 is flase + // x<2 is false m.deep_copy(-1); compute_mask(x,2,Comparison::LT,m); REQUIRE(views_are_equal(m,zero)); diff --git a/components/eamxx/src/share/field/utils/compute_mask.cpp b/components/eamxx/src/share/field/utils/compute_mask.cpp index d9596a22e8dd..ecc38156cc67 100644 --- a/components/eamxx/src/share/field/utils/compute_mask.cpp +++ b/components/eamxx/src/share/field/utils/compute_mask.cpp @@ -145,14 +145,14 @@ void compute_mask (const Field& f, const ScalarWrapper value, Comparison CMP, Fi // Sanity checks EKAT_REQUIRE_MSG (f.is_allocated(), "Error! Input field was not yet allocated.\n" - " - field name; " + f.name() + "\n"); + " - field name: " + f.name() + "\n"); EKAT_REQUIRE_MSG (f.rank()<=6, "Error! Input field rank not supported.\n" - " - field name; " + f.name() + "\n" + " - field name: " + f.name() + "\n" " - field rank: " + std::to_string(f.rank()) + "\n"); EKAT_REQUIRE_MSG (mask.is_allocated(), "Error! Mask field was not yet allocated.\n" - " - mask field name; " + mask.name() + "\n"); + " - mask field name: " + mask.name() + "\n"); EKAT_REQUIRE_MSG (not mask.is_read_only(), "Error! Cannot update mask field, as it is read-only.\n" " - mask name: " + mask.name() + "\n"); From 3b2d4d2ac63255a62fe931ca727e8916402f77c6 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 3 Dec 2025 15:55:43 -0800 Subject: [PATCH 136/398] create zm_downdraft_properties() --- components/eam/src/physics/cam/zm_conv.F90 | 405 ++++++++++++--------- 1 file changed, 235 insertions(+), 170 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 23373c1bca08..2aafe0d4009e 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -58,8 +58,9 @@ module zm_conv ! private variables real(r8), parameter :: cape_threshold = 70._r8 ! threshold value of cape for deep convection real(r8), parameter :: dcape_threshold = 0._r8 ! threshold value of dcape for deep convection - real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error real(r8), parameter :: interp_diff_min = 1.E-6_r8 ! minimum threshold for interpolation method - see eq (4.109), (4.118), (4.119) + real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error + real(r8), parameter :: small = 1.e-20_r8 ! small number to limit blowup when normalizing by mass flux !=================================================================================================== contains !=================================================================================================== @@ -984,8 +985,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & i4(i,k) = 0._r8 f(i,k) = 0._r8 eps(i,k) = 0._r8 - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- ! compute taylor series for approximate eps(z) below @@ -1000,8 +1001,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & iprm(i,k) = 0.5_r8* (i3(i,k+1)+i3(i,k)) i4(i,k) = i4(i,k+1) + iprm(i,k)*dz(i,k) end if - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- ! re-initialize minimum MSE for ensuing calculation @@ -1012,8 +1013,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & h_env_min(i) = h_env(i,k) expdif(i) = h_env(i,jb(i)) - h_env_min(i) end if - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- ! compute approximate eps(z) using above taylor series @@ -1037,8 +1038,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & f(i,k) = max(f(i,k),lambda_min) f(i,k) = min(f(i,k),lambda_max) end if - end do - end do + end do ! i + end do ! k ! move detrainment level downward if fractional entrainment is too low do i = 1,ncol @@ -1047,7 +1048,7 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & j0(i) = j0(i) + 1 end if end if - end do + end do ! i ! ensure that entrainment does not increase above the level that detrainment starts do k = msg+2, pver @@ -1055,8 +1056,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & if (k >= jt(i) .and. k <= j0(i)) then f(i,k) = max(f(i,k),f(i,k-1)) end if - end do - end do + end do ! i + end do ! k ! specify maximum fractional entrainment do i = 1,ncol @@ -1071,8 +1072,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & do i = 1,ncol if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) if ( k =jt(i) ) eps(i,k) = f(i,k) - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- return @@ -1081,6 +1082,139 @@ end subroutine zm_calc_fractional_entrainment !=================================================================================================== +subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & + jb, jt, j0, jd, z_int, dz, s, q, h_env, & + eps, eps0, qsthat, hsthat, gamhat, rprd, & + mu, md, ed, sd, qd, hd, qds, evp, totevp ) + !---------------------------------------------------------------------------- + ! Purpose: Calculate properties of ZM downdrafts + ! Notes: + ! - Downward mass flux is scaled so that net flux (up-down) at cloud base in not negative + ! - No downdrafts if jd>=jb + !---------------------------------------------------------------------------- + implicit none + !---------------------------------------------------------------------------- + ! Arguments + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: msg ! missing moisture levels + integer, dimension(pcols), intent(in ) :: jb ! updraft base level + integer, dimension(pcols), intent(inout) :: jt ! updraft top level + integer, dimension(pcols), intent(in ) :: j0 ! level where updraft begins detraining + integer, dimension(pcols), intent(inout) :: jd ! level of downdraft + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface + real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness + real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: h_env ! ambient env moist stat energy + real(r8), dimension(pcols,pver), intent(in ) :: eps ! fractional entrainment + real(r8), dimension(pcols), intent(in ) :: eps0 ! fractional entrainment max + real(r8), dimension(pcols,pver), intent(in ) :: qsthat ! interface interpolated qst + real(r8), dimension(pcols,pver), intent(in ) :: hsthat ! interface interpolated hst + real(r8), dimension(pcols,pver), intent(in ) :: gamhat ! interface interpolated gamma + real(r8), dimension(pcols,pver), intent(in ) :: rprd ! rate of production of precip at that layer + real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: md ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: ed ! downdraft entrainment rate + real(r8), dimension(pcols,pver), intent(inout) :: sd ! dndraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(inout) :: qd ! dndraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(inout) :: hd ! dndraft moist static energy + real(r8), dimension(pcols,pver), intent(inout) :: qds ! dndraft saturation specific humdity + real(r8), dimension(pcols,pver), intent(inout) :: evp ! evaporation rate + real(r8), dimension(pcols), intent(inout) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) + !---------------------------------------------------------------------------- + ! Local variables + integer :: i,k ! loop iterators + real(r8), dimension(pcols) :: ratmjb ! + real(r8) dz_tmp ! temporary vertical thickness for downdraft mass flux calculation + real(r8) mdt ! temporary downdraft mass flux for normalization + !---------------------------------------------------------------------------- + ! calculate downdraft mass flux + do i = 1,ncol + jt(i) = min(jt(i),jb(i)-1) + jd(i) = max(j0(i),jt(i)+1) + jd(i) = min(jd(i),jb(i)) + hd(i,jd(i)) = h_env(i,jd(i)-1) + if (jd(i) < jb(i) .and. eps0(i) > 0._r8) then + ! NOTE - this nonsensical eps0/eps0 factor was retained to preserve BFB results during ZM refactoring + md(i,jd(i)) = -zm_param%alfa * eps0(i) / eps0(i) + end if + end do ! i + do k = msg+1, pver + do i = 1,ncol + if ((k > jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8) then + dz_tmp = z_int(i,jd(i)) - z_int(i,k) + md(i,k) = -zm_param%alfa / (2._r8*eps0(i))*(exp(2._r8*eps0(i)*dz_tmp)-1._r8)/dz_tmp + end if + end do ! i + end do ! k + do k = msg+1, pver + do i = 1,ncol + if ((k >= jt(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then + ratmjb(i) = min(abs(mu(i,jb(i))/md(i,jb(i))),1._r8) + md(i,k) = md(i,k)*ratmjb(i) + end if + end do ! i + end do ! k + + !---------------------------------------------------------------------------- + ! calculate downdraft entrainment and MSE + do k = msg+1, pver + do i = 1,ncol + if ((k >= jt(i) .and. k <= pver) .and. eps0(i) > 0._r8) then + ed(i,k-1) = (md(i,k-1)-md(i,k))/dz(i,k-1) + mdt = min(md(i,k),-small) + hd(i,k) = (md(i,k-1)*hd(i,k-1) - dz(i,k-1)*ed(i,k-1)*h_env(i,k-1))/mdt + end if + end do ! i + end do ! k + + !---------------------------------------------------------------------------- + ! calculate downdraft specific humidity + do k = msg+2, pver + do i = 1,ncol + if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then + qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) + end if + end do ! i + end do ! k + + !---------------------------------------------------------------------------- + ! downdraft quantities at source level + do i = 1,ncol + qd(i,jd(i)) = qds(i,jd(i)) + sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*qd(i,jd(i)))/zm_const%cpair + end do + + !---------------------------------------------------------------------------- + ! calculate downdraft evaporation + do k = msg+2, pver + do i = 1,ncol + if (k >= jd(i) .and. k < jb(i) .and. eps0(i) > 0._r8) then + qd(i,k+1) = qds(i,k+1) + evp(i,k) = -ed(i,k)*q(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) + evp(i,k) = max(evp(i,k),0._r8) + mdt = min(md(i,k+1),-small) + if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) + sd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s(i,k))*dz(i,k) + md(i,k)*sd(i,k))/mdt + totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q(i,k) + end if + end do ! i + end do ! k + + do i = 1,ncol + totevp(i) = totevp(i) + md(i,jd(i))*qd(i,jd(i)) - md(i,jb(i))*qd(i,jb(i)) + end do + + !---------------------------------------------------------------------------- + return + +end subroutine zm_downdraft_properties + +!=================================================================================================== + subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & p_mid, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & jb, lel, jt, jlcl, j0, jd, & @@ -1121,7 +1255,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(out) :: eu ! entrainment rate of updraft real(r8), dimension(pcols,pver), intent(out) :: du ! detrainement rate of updraft real(r8), dimension(pcols,pver), intent(out) :: md ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(out) :: ed ! entrainment rate of downdraft + real(r8), dimension(pcols,pver), intent(out) :: ed ! downdraft entrainment rate real(r8), dimension(pcols,pver), intent(out) :: mc ! net mass flux real(r8), dimension(pcols,pver), intent(out) :: su ! updraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: qu ! updraft specific humidity [kg/kg] @@ -1149,49 +1283,39 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma real(r8), dimension(pcols,pver) :: qds ! dndraft saturation specific humdity real(r8), dimension(pcols) :: c0mask ! land/ocean modification - - real(r8), dimension(pcols) :: rmue ! - real(r8), dimension(pcols) :: zuef ! - real(r8), dimension(pcols) :: zdef ! - real(r8), dimension(pcols) :: epsm ! - real(r8), dimension(pcols) :: ratmjb ! - real(r8), dimension(pcols) :: est ! real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) - real(r8), dimension(pcols,pver) :: eps ! fractional entrainment real(r8), dimension(pcols) :: eps0 ! fractional entrainment max - real(r8) ql1 ! ? - real(r8) tu ! ? - real(r8) estu ! ? - real(r8) qstu ! ? - real(r8) mdt ! ? - ! Convective microphysics - real(r8), dimension(pcols,pver) :: fice ! ice fraction in precip production - real(r8), dimension(pcols,pver) :: tug ! temporary updraft temperature - real(r8), dimension(pcols,pver) :: tmp_frz ! temporary rate of freezing - real(r8), dimension(pcols) :: tot_frz ! total column freezing rate - real(r8), dimension(pcols,pverp):: pflxs ! frozen precipitation flux thru layer - real(r8) dum, sdum - - integer, dimension(pcols) :: jto ! updraft plume old top - - integer :: tmp_k_limit ! temporary limit on k index in various contexts - integer :: iter ! ? - integer :: itnum ! ? - integer :: m - - integer khighest - integer klowest - integer kount - integer i,k + real(r8), dimension(pcols,pver) :: fice ! ice fraction in precip production + real(r8), dimension(pcols,pver) :: tug ! temporary updraft temperature + real(r8), dimension(pcols,pver) :: tmp_frz ! temporary rate of freezing + real(r8), dimension(pcols) :: tot_frz ! total column freezing rate + real(r8), dimension(pcols,pverp):: pflxs ! frozen precipitation flux thru layer + integer, dimension(pcols) :: jto ! updraft plume old top + + real(r8) :: zuef ! temporary vertical thickness for updraft calculations + real(r8) :: rmue ! temporary for updraft entrainment calculations + real(r8) :: ql1 ! temporary cloud water + real(r8) :: tu ! updraft temperature + real(r8) :: est ! saturation vapor pressure + real(r8) :: estu ! updraft saturation vapor pressure + real(r8) :: qstu ! updraft saturation specific humidity + real(r8) :: dum, sdum ! dummy variables for round-off error protection + + integer :: tmp_k_limit ! temporary limit on k index in various contexts + integer :: iter ! iteration counter + integer :: itnum ! iteration number + integer :: khighest ! k iteration limit + integer :: klowest ! k iteration limit + integer :: kount ! counter for LCL determination + integer :: i,k ! loop iterator logical, dimension(pcols) :: doit ! flag to reset cloud - logical, dimension(pcols) :: done ! ? + logical, dimension(pcols) :: done ! flag for LCL determination - real(r8), parameter :: small = 1.e-20_r8 ! small number to limit blowup when normalizing by mass flux real(r8), parameter :: mu_min = 0.02_r8 ! minimum value of mu real(r8), parameter :: t_homofrz = 233.15_r8 ! homogeneous freezing temperature real(r8), parameter :: t_mphase = 40._r8 ! mixed phase temperature = tfreez-t_homofrz = 273.15K - 233.15K @@ -1225,8 +1349,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! calculate layer thickness dz(i,k) = z_int(i,k) - z_int(i,k+1) ! calculate saturation specific humidity - call qsat_hPa(t_mid(i,k), p_mid(i,k), est(i), qst(i,k)) - if ( p_mid(i,k)-est(i) <= 0._r8 ) qst(i,k) = 1.0_r8 + call qsat_hPa(t_mid(i,k), p_mid(i,k), est, qst(i,k)) + if ( p_mid(i,k)-est <= 0._r8 ) qst(i,k) = 1.0_r8 ! compute gamma - see eq. (4.117) gamma(i,k) = qst(i,k)*(1._r8 + qst(i,k)/zm_const%epsilo) & * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_mid(i,k)**2) & @@ -1246,8 +1370,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & fice(i,k) = 0._r8 tug(i,k) = 0._r8 tmp_frz(i,k)= 0._r8 - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- ! interpolate the mid-point values to interfaces @@ -1269,8 +1393,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & gamhat(i,k) = gamma(i,k) end if end if - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- ! initialize cloud top to highest plume top (upper/lower limit => pver / limcnv+1) @@ -1282,7 +1406,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & jd(i) = pver jlcl(i) = lel(i) h_env_min(i) = 1.E6_r8 - end do + end do ! i !---------------------------------------------------------------------------- ! find the level of minimum saturated MSE (h_env_sat), where detrainment starts @@ -1319,8 +1443,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & su(i,k) = s(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) end if end if - end do - end do + end do ! i + end do ! k !---------------------------------------------------------------------------- ! calculate fractional entrainment (i.e. "lambda D") - see eq (4.78) from Neale et al. (2012) @@ -1345,8 +1469,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & loc_microp_st%qice(i,k) = 0._r8 loc_microp_st%frz(i,k) = 0._r8 end if - end do - end do + end do ! i + end do ! k do i = 1,ncol totpcp(i) = 0._r8 if (zm_param%zm_microp) hu(i,jb(i)) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add @@ -1362,15 +1486,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (.not.zm_param%zm_microp) tmp_k_limit = jt(i) ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) if ( k>=tmp_k_limit .and. k0._r8 - end do - end do + end do ! i + end do ! k khighest = pverp klowest = 1 @@ -1399,8 +1523,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end if end if end if - end do - end do + end do ! i + end do ! k ! reset cloud top index beginning from two layers above the ! cloud base (i.e. if cloud is only one layer thick, top is not reset @@ -1409,8 +1533,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & tot_frz(i)= 0._r8 do k = pver, msg+1, -1 tot_frz(i)= tot_frz(i) + tmp_frz(i,k)*dz(i,k) - end do - end do + end do ! k + end do ! i do k = klowest-2, khighest-1, -1 do i = 1,ncol @@ -1430,8 +1554,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & doit(i) = .false. end if end if - end do - end do + end do ! i + end do ! k do i = 1,ncol if (iter == 1) jto(i) = jt(i) @@ -1450,8 +1574,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & eu(i,k) = 0._r8 mu(i,k) = 0._r8 end if - end do - end do + end do ! i + end do ! k ! determine LCL - see eq (4.127)- (4.130) of Neale et al. (2012) done(1:ncol) = .false. @@ -1473,9 +1597,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & done(i) = .true. end if end if - end do + end do ! i if (kount >= ncol) goto 690 - end do + end do ! k 690 continue @@ -1485,8 +1609,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if - end do - end do + end do ! i + end do ! k ! compute condensation in updraft do k = pver, msg+2, -1 @@ -1510,6 +1634,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end do ! i end do ! k + !------------------------------------------------------------------------- + ! microphysical calculation + if (zm_param%zm_microp) then tug(1:ncol,:) = t_mid(1:ncol,:) @@ -1518,8 +1645,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+2, -1 do i = 1, ncol tug(i,k) = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) - end do - end do + end do ! i + end do ! k do k = 1, pver-1 do i = 1, ncol @@ -1533,15 +1660,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! mixed phase - ice frac decreasing linearly from t_homofrz to zm_const%tfreez fice(i,k) =(zm_const%tfreez - tug(i,k+1)) / t_mphase end if - end do - end do + end do ! i + end do ! k do k = 1, pver do i = 1,ncol loc_microp_st%cmei(i,k) = cu(i,k)* fice(i,k) loc_microp_st%cmel(i,k) = cu(i,k) * (1._r8-fice(i,k)) - end do - end do + end do ! i + end do ! k #ifndef SCREAM_CONFIG_IS_CMAKE call zm_mphy( pcols, ncol, msg, & @@ -1581,17 +1708,17 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! cloud water, here ql is calculated as total cloud water for consistency. ql(i,k) = loc_microp_st%qliq(i,k)+ loc_microp_st%qice(i,k) loc_microp_st%frz(i,k) = tmp_frz(i,k) - end do - end do + end do ! i + end do ! k do i = 1,ncol if (iter == 2 .and. jt(i)> jto(i)) then do k = jt(i), jto(i), -1 loc_microp_st%frz(i,k) = 0.0_r8 cu(i,k)=0.0_r8 - end do + end do ! k end if - end do + end do ! i do k = pver, msg+2, -1 do i = 1,ncol @@ -1600,8 +1727,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & +loc_microp_st%qide(i,k+1) & +loc_microp_st%qsde(i,k+1) )) end if - end do - end do + end do ! i + end do ! k else ! no microphysics @@ -1626,92 +1753,30 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-du(i,k)*ql(i,k+1)) rprd(i,k) = c0mask(i)*mu(i,k)*ql(i,k) end if - end do - end do + end do ! i + end do ! k end if ! zm_param%zm_microp end do ! iter = 1,itnum !---------------------------------------------------------------------------- - ! specify downdraft properties (note - no downdrafts if jd>=jb) - ! downward mass flux profile is scaled so that net flux (up-down) at cloud base in not negative - do i = 1,ncol - ! in normal downdraft strength run alfa=0.2. In test4 alfa=0.1 - jt(i) = min(jt(i),jb(i)-1) - jd(i) = max(j0(i),jt(i)+1) - jd(i) = min(jd(i),jb(i)) - hd(i,jd(i)) = h_env(i,jd(i)-1) - if (jd(i) < jb(i) .and. eps0(i) > 0._r8) then - epsm(i) = eps0(i) - md(i,jd(i)) = -zm_param%alfa * epsm(i) / eps0(i) - end if - end do - do k = msg+1, pver - do i = 1,ncol - if ((k > jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8) then - zdef(i) = z_int(i,jd(i)) - z_int(i,k) - md(i,k) = -zm_param%alfa / (2._r8*eps0(i))*(exp(2._r8*epsm(i)*zdef(i))-1._r8)/zdef(i) - end if - end do - end do - do k = msg+1, pver - do i = 1,ncol - if ((k >= jt(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then - ratmjb(i) = min(abs(mu(i,jb(i))/md(i,jb(i))),1._r8) - md(i,k) = md(i,k)*ratmjb(i) - end if - end do - end do + ! calculate downdraft properties + call zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & + jb, jt, j0, jd, z_int, dz, s, q, h_env, & + eps, eps0, qsthat, hsthat, gamhat, rprd, & + mu, md, ed, sd, qd, hd, qds, evp, totevp) - do k = msg+1, pver - do i = 1,ncol - if ((k >= jt(i) .and. k <= pver) .and. eps0(i) > 0._r8) then - ed(i,k-1) = (md(i,k-1)-md(i,k))/dz(i,k-1) - mdt = min(md(i,k),-small) - hd(i,k) = (md(i,k-1)*hd(i,k-1) - dz(i,k-1)*ed(i,k-1)*h_env(i,k-1))/mdt - end if - end do - end do - - ! calculate updraft and downdraft properties - do k = msg+2, pver - do i = 1,ncol - if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then - qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) - end if - end do - end do - - do i = 1,ncol - qd(i,jd(i)) = qds(i,jd(i)) - sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*qd(i,jd(i)))/zm_const%cpair - end do - - do k = msg+2, pver - do i = 1,ncol - if (k >= jd(i) .and. k < jb(i) .and. eps0(i) > 0._r8) then - qd(i,k+1) = qds(i,k+1) - evp(i,k) = -ed(i,k)*q(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) - evp(i,k) = max(evp(i,k),0._r8) - mdt = min(md(i,k+1),-small) - if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) - sd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s(i,k))*dz(i,k) + md(i,k)*sd(i,k))/mdt - totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q(i,k) - end if - end do - end do - - ! calculate total precip for downdraft scaling + !---------------------------------------------------------------------------- + ! ensure totpcp and totevp are non-negative do i = 1,ncol - totevp(i) = totevp(i) + md(i,jd(i))*qd(i,jd(i)) - md(i,jb(i))*qd(i,jb(i)) totpcp(i) = max(totpcp(i),0._r8) totevp(i) = max(totevp(i),0._r8) end do do k = msg+2, pver do i = 1,ncol - ! ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) + ! also ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then md(i,k) = md (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) ed(i,k) = ed (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) @@ -1729,23 +1794,23 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end if end if rprd(i,k) = rprd(i,k)-evp(i,k) - end do - end do + end do ! i + end do ! k ! compute the net precipitation flux across interfaces do k = 2,pverp do i = 1,ncol pflx(i,k) = pflx(i,k-1) + rprd(i,k-1)*dz(i,k-1) if (zm_param%zm_microp) pflxs(i,k) = pflxs(i,k-1) + loc_microp_st%sprd(i,k-1)*dz(i,k-1) - end do - end do + end do ! i + end do ! k ! calculate net mass flux do k = msg+1, pver do i = 1,ncol mc(i,k) = mu(i,k) + md(i,k) - end do - end do + end do ! i + end do ! k if (zm_param%zm_microp) then do i = 1,ncol @@ -1779,7 +1844,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_microp_st_zero(loc_microp_st,i,pver) end if end do ! i - end if + end if ! zm_microp return end subroutine zm_cloud_properties From 40f115787f25f23e6eab7a05e94935f3a76db076 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 4 Dec 2025 10:36:11 -0800 Subject: [PATCH 137/398] change PERGRO handling --- components/eam/src/physics/cam/zm_conv.F90 | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 2aafe0d4009e..c6eb4d332987 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -749,6 +749,16 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & real(r8) :: work2 ! temporary work variable real(r8) :: evplimit ! temporary work variable for evaporation limits real(r8) :: dum ! temporary work variable + + logical :: pergro_active ! flag for perturbation growth test (pergro) + real(r8), parameter :: pergro_perturbation = 8.64e-11_r8 ! value used when pergro_active is true + !---------------------------------------------------------------------------- + ! set flag for perturbation growth test +#ifdef PERGRO + pergro_active = .true. +#else + pergro_active = .false. +#endif !---------------------------------------------------------------------------- if (zm_param%zm_microp) then prdsnow(1:ncol,1:pver) = microp_st%sprd(1:ncol,1:pver) @@ -853,15 +863,15 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! This causes temperature partitioning to be used for small flxprec amounts. if( zm_param%old_snow ) then -#ifdef PERGRO - work1 = min(max(0._r8,flxsnow(i,k)/(flxprec(i,k)+8.64e-11_r8)),1._r8) -#else - if (flxprec(i,k).gt.0._r8) then - work1 = min(max(0._r8,flxsnow(i,k)/flxprec(i,k)),1._r8) + if (pergro_active) then + work1 = min(max(0._r8,flxsnow(i,k)/(flxprec(i,k)+pergro_perturbation)),1._r8) else - work1 = 0._r8 - endif -#endif + if (flxprec(i,k).gt.0._r8) then + work1 = min(max(0._r8,flxsnow(i,k)/flxprec(i,k)),1._r8) + else + work1 = 0._r8 + endif + end if work2 = max(fsnow_conv(i,k), work1) if (snowmlt(i).gt.0._r8) work2 = 0._r8 ntsnprd(i,k) = prdprec(i,k)*work2 - evpsnow(i) - snowmlt(i) From d8a035e36c5f11f5da16d2b933e52c343cdadb53 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 4 Dec 2025 12:53:59 -0800 Subject: [PATCH 138/398] cleanup and rename entrainment --- components/eam/src/physics/cam/zm_conv.F90 | 309 ++++++++++----------- 1 file changed, 150 insertions(+), 159 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index c6eb4d332987..a10ffcba812c 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -601,7 +601,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! compute temperature and moisture changes due to convection. - call zm_calculate_output_tend(pcols, ncol, pver, pverp, & + call zm_calc_output_tend(pcols, ncol, pver, pverp, & dqdt, dsdt, qg, qs, qu, & su, du, qhat, shat, dp, & mu, md, sd, qd, qlg, & @@ -784,7 +784,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & do i = 1, ncol ! Melt snow falling into layer, if necessary. - if( zm_param%old_snow ) then + if (zm_param%old_snow) then if (t_mid(i,k) > zm_const%tfreez) then flxsntm(i) = 0._r8 snowmlt(i) = flxsnow(i,k) * zm_const%grav/ pdel(i,k) @@ -835,7 +835,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & evpprec(i) = min(evplimit, evpprec(i)) - if( .not.zm_param%old_snow ) then + if (.not.zm_param%old_snow) then evpprec(i) = max(0._r8, evpprec(i)) evpprec(i) = evpprec(i)*omsm end if @@ -862,7 +862,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! from 1e-36 to 8.64e-11 (1e-5 mm/day) to address error growth problems. ! This causes temperature partitioning to be used for small flxprec amounts. - if( zm_param%old_snow ) then + if (zm_param%old_snow) then if (pergro_active) then work1 = min(max(0._r8,flxsnow(i,k)/(flxprec(i,k)+pergro_perturbation)),1._r8) else @@ -894,7 +894,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! heating (cooling) and moistening due to evaporation ! - latent heat of vaporization for precip production has already been accounted for ! - snow is contained in prec - if( zm_param%old_snow ) then + if (zm_param%old_snow) then tend_s(i,k) =-evpprec(i)*zm_const%latvap + ntsnprd(i,k)*zm_const%latice else tend_s(i,k) =-evpprec(i)*zm_const%latvap + tend_s_snwevmlt(i,k) @@ -905,9 +905,9 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & end do ! k ! protect against rounding error - if( .not.zm_param%old_snow ) then + if (.not.zm_param%old_snow) then do i = 1, ncol - if(flxsnow(i,pverp).gt.flxprec(i,pverp)) then + if (flxsnow(i,pverp).gt.flxprec(i,pverp)) then dum = (flxsnow(i,pverp)-flxprec(i,pverp))*zm_const%grav do k = pver, 1, -1 if (ntsnprd(i,k)>ntprprd(i,k).and. dum > 0._r8) then @@ -932,74 +932,65 @@ end subroutine zm_conv_evap subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & jb, jt, j0, z_mid, z_int, dz, & - h_env, h_env_sat, h_env_min, eps, eps0) + h_env, h_env_sat, h_env_min, & + lambda, lambda_max) !---------------------------------------------------------------------------- ! Purpose: Determine properties of ZM updrafts and downdrafts !---------------------------------------------------------------------------- implicit none !---------------------------------------------------------------------------- ! Arguments - integer, intent(in ) :: pcols ! maximum number of columns - integer, intent(in ) :: ncol ! actual number of columns - integer, intent(in ) :: pver ! number of mid-point vertical levels - integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! missing moisture levels - integer, dimension(pcols), intent(in ) :: jb ! updraft base level - integer, dimension(pcols), intent(in ) :: jt ! updraft top level - integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining - real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point - real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface - real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness - real(r8), dimension(pcols,pver), intent(in ) :: h_env ! env moist stat energy - real(r8), dimension(pcols,pver), intent(in ) :: h_env_sat ! env saturated moist stat energy - real(r8), dimension(pcols) , intent(inout) :: h_env_min ! mid-tropospheric MSE minimum - real(r8), dimension(pcols,pver), intent( out) :: eps ! fractional entrainment - real(r8), dimension(pcols) , intent( out) :: eps0 ! fractional entrainment maximum + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: msg ! missing moisture levels + integer, dimension(pcols), intent(in ) :: jb ! updraft base level + integer, dimension(pcols), intent(in ) :: jt ! updraft top level + integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining + real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface + real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness + real(r8), dimension(pcols,pver), intent(in ) :: h_env ! env moist stat energy + real(r8), dimension(pcols,pver), intent(in ) :: h_env_sat ! env saturated moist stat energy + real(r8), dimension(pcols) , intent(inout) :: h_env_min ! mid-tropospheric MSE minimum + real(r8), dimension(pcols,pver), intent( out) :: lambda ! fractional entrainment + real(r8), dimension(pcols) , intent( out) :: lambda_max ! fractional entrainment maximum !---------------------------------------------------------------------------- ! Local variables integer :: i,k ! loop iterators ! variables used for Taylor series expansion when solving eq (4.78) for lamda_D (i.e. fractional entrainment) - real(r8), dimension(pcols,pver) :: f ! fractional entrainment work variable - real(r8), dimension(pcols) :: ftemp ! temporary value of f - real(r8), dimension(pcols) :: expdif ! diff between env MSE low-level max and mid-level min - real(r8), dimension(pcols) :: expnum ! ? - real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series - real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series - real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series - real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series - real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series - real(r8), dimension(pcols,pver) :: idag ! term for Taylor series - real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series - - real(r8), parameter :: lambda_min = 0._r8 ! limiter - real(r8), parameter :: lambda_max = 0.0002_r8 ! limiter - real(r8), parameter :: lambda_thrs = 1.E-6_r8 ! threshold + real(r8), dimension(pcols,pver) :: lambda_tmp ! fractional entrainment work variable + real(r8), dimension(pcols,pver) :: k1 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i2 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i3 ! term for Taylor series + real(r8), dimension(pcols,pver) :: i4 ! term for Taylor series + real(r8), dimension(pcols,pver) :: ihat ! term for Taylor series + real(r8), dimension(pcols,pver) :: idag ! term for Taylor series + real(r8), dimension(pcols,pver) :: iprm ! term for Taylor series + real(r8) :: tmp ! term for Taylor series + real(r8) :: expnum ! term for Taylor series + + real(r8), parameter :: lambda_limit_min = 0._r8 ! limiter + real(r8), parameter :: lambda_limit_max = 0.0002_r8 ! limiter + real(r8), parameter :: lambda_threshold = 1.E-6_r8 ! threshold for moving detrainment level !---------------------------------------------------------------------------- - - ! initialize 1D variables - do i = 1,ncol - ftemp(i) = 0._r8 - expnum(i) = 0._r8 - expdif(i) = 0._r8 - end do - - ! initialize 2D variables + ! initialize variables do k = 1,pver do i = 1,ncol - ! misc work variables - k1(i,k) = 0._r8 - i2(i,k) = 0._r8 - i3(i,k) = 0._r8 - i4(i,k) = 0._r8 - f(i,k) = 0._r8 - eps(i,k) = 0._r8 + k1(i,k) = 0._r8 + i2(i,k) = 0._r8 + i3(i,k) = 0._r8 + i4(i,k) = 0._r8 + lambda_tmp(i,k) = 0._r8 + lambda(i,k) = 0._r8 end do ! i end do ! k !---------------------------------------------------------------------------- - ! compute taylor series for approximate eps(z) below + ! compute taylor series for approximate lambda(z) below do k = pver-1, msg+1, -1 do i = 1,ncol if (k < jb(i) .and. k >= jt(i)) then @@ -1021,32 +1012,30 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & do i = 1,ncol if (k >= j0(i) .and. k <= jb(i) .and. h_env(i,k) <= h_env_min(i)) then h_env_min(i) = h_env(i,k) - expdif(i) = h_env(i,jb(i)) - h_env_min(i) end if end do ! i end do ! k !---------------------------------------------------------------------------- - ! compute approximate eps(z) using above taylor series + ! compute approximate lambda(z) using above taylor series - see eq (A6) in ZM95 do k = msg+2, pver do i = 1,ncol - expnum(i) = 0._r8 - ftemp(i) = 0._r8 + expnum = 0._r8 if (k < jt(i) .or. k >= jb(i)) then k1(i,k) = 0._r8 - expnum(i)= 0._r8 + expnum = 0._r8 else - expnum(i) = h_env(i,jb(i)) - (h_env_sat(i,k-1)*(z_int(i,k)-z_mid(i,k)) + & - h_env_sat(i,k)*(z_mid(i,k-1)-z_int(i,k)))/(z_mid(i,k-1)-z_mid(i,k)) + expnum = h_env(i,jb(i)) - (h_env_sat(i,k-1)*(z_int(i,k)-z_mid(i,k)) + & + h_env_sat(i,k)*(z_mid(i,k-1)-z_int(i,k)))/(z_mid(i,k-1)-z_mid(i,k)) end if - if ((expdif(i) > 100._r8 .and. expnum(i) > 0._r8) .and. k1(i,k) > expnum(i)*dz(i,k)) then - ftemp(i) = expnum(i) / k1(i,k) - f(i,k) = ftemp(i) + & - i2(i,k)/k1(i,k) * ftemp(i)**2 + & - (2._r8*i2(i,k)**2-k1(i,k)*i3(i,k))/k1(i,k)**2 * ftemp(i)**3 + & - (-5._r8*k1(i,k)*i2(i,k)*i3(i,k)+ 5._r8*i2(i,k)**3+k1(i,k)**2*i4(i,k))/k1(i,k)**3 * ftemp(i)**4 - f(i,k) = max(f(i,k),lambda_min) - f(i,k) = min(f(i,k),lambda_max) + if ( ( (h_env(i,jb(i))-h_env_min(i)) > 100._r8 .and. expnum > 0._r8 ) .and. k1(i,k) > expnum*dz(i,k)) then + tmp = expnum / k1(i,k) + lambda_tmp(i,k) = tmp + & + i2(i,k)/k1(i,k) * tmp**2 + & + (2._r8*i2(i,k)**2-k1(i,k)*i3(i,k))/k1(i,k)**2 * tmp**3 + & + (-5._r8*k1(i,k)*i2(i,k)*i3(i,k)+5._r8*i2(i,k)**3+k1(i,k)**2*i4(i,k))/k1(i,k)**3 * tmp**4 + lambda_tmp(i,k) = max(lambda_tmp(i,k),lambda_limit_min) + lambda_tmp(i,k) = min(lambda_tmp(i,k),lambda_limit_max) end if end do ! i end do ! k @@ -1054,7 +1043,7 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & ! move detrainment level downward if fractional entrainment is too low do i = 1,ncol if (j0(i) < jb(i)) then - if ( f(i,j0(i))<1.E-6_r8 .and. f(i,j0(i)+1)>f(i,j0(i)) ) then + if ( lambda_tmp(i,j0(i))lambda_tmp(i,j0(i)) ) then j0(i) = j0(i) + 1 end if end if @@ -1064,15 +1053,15 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & do k = msg+2, pver do i = 1,ncol if (k >= jt(i) .and. k <= j0(i)) then - f(i,k) = max(f(i,k),f(i,k-1)) + lambda_tmp(i,k) = max(lambda_tmp(i,k),lambda_tmp(i,k-1)) end if end do ! i end do ! k ! specify maximum fractional entrainment do i = 1,ncol - eps0(i) = f(i,j0(i)) - eps(i,jb(i)) = eps0(i) + lambda_max(i) = lambda_tmp(i,j0(i)) + lambda(i,jb(i)) = lambda_max(i) end do ! The modification below comes from: @@ -1080,8 +1069,8 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & ! using diagnosed and predicted condensate parameterizations, J. Clim., 1997. do k = pver, msg+1, -1 do i = 1,ncol - if ( k >=j0(i) .and. k<=jb(i) ) eps(i,k) = f(i,j0(i)) - if ( k =jt(i) ) eps(i,k) = f(i,k) + if ( k >=j0(i) .and. k<=jb(i) ) lambda(i,k) = lambda_tmp(i,j0(i)) + if ( k =jt(i) ) lambda(i,k) = lambda_tmp(i,k) end do ! i end do ! k @@ -1094,7 +1083,7 @@ end subroutine zm_calc_fractional_entrainment subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s, q, h_env, & - eps, eps0, qsthat, hsthat, gamhat, rprd, & + lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & mu, md, ed, sd, qd, hd, qds, evp, totevp ) !---------------------------------------------------------------------------- ! Purpose: Calculate properties of ZM downdrafts @@ -1105,35 +1094,35 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & implicit none !---------------------------------------------------------------------------- ! Arguments - integer, intent(in ) :: pcols ! maximum number of columns - integer, intent(in ) :: ncol ! actual number of columns - integer, intent(in ) :: pver ! number of mid-point vertical levels - integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! missing moisture levels - integer, dimension(pcols), intent(in ) :: jb ! updraft base level - integer, dimension(pcols), intent(inout) :: jt ! updraft top level - integer, dimension(pcols), intent(in ) :: j0 ! level where updraft begins detraining - integer, dimension(pcols), intent(inout) :: jd ! level of downdraft - real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface - real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness - real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) - real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity - real(r8), dimension(pcols,pver), intent(in ) :: h_env ! ambient env moist stat energy - real(r8), dimension(pcols,pver), intent(in ) :: eps ! fractional entrainment - real(r8), dimension(pcols), intent(in ) :: eps0 ! fractional entrainment max - real(r8), dimension(pcols,pver), intent(in ) :: qsthat ! interface interpolated qst - real(r8), dimension(pcols,pver), intent(in ) :: hsthat ! interface interpolated hst - real(r8), dimension(pcols,pver), intent(in ) :: gamhat ! interface interpolated gamma - real(r8), dimension(pcols,pver), intent(in ) :: rprd ! rate of production of precip at that layer - real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux - real(r8), dimension(pcols,pver), intent(inout) :: md ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(inout) :: ed ! downdraft entrainment rate - real(r8), dimension(pcols,pver), intent(inout) :: sd ! dndraft dry static energy [K] (normalized) - real(r8), dimension(pcols,pver), intent(inout) :: qd ! dndraft specific humidity [kg/kg] - real(r8), dimension(pcols,pver), intent(inout) :: hd ! dndraft moist static energy - real(r8), dimension(pcols,pver), intent(inout) :: qds ! dndraft saturation specific humdity - real(r8), dimension(pcols,pver), intent(inout) :: evp ! evaporation rate - real(r8), dimension(pcols), intent(inout) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + integer, intent(in ) :: msg ! missing moisture levels + integer, dimension(pcols), intent(in ) :: jb ! updraft base level + integer, dimension(pcols), intent(inout) :: jt ! updraft top level + integer, dimension(pcols), intent(in ) :: j0 ! level where updraft begins detraining + integer, dimension(pcols), intent(inout) :: jd ! level of downdraft + real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface + real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness + real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: h_env ! ambient env moist stat energy + real(r8), dimension(pcols,pver), intent(in ) :: lambda ! fractional entrainment + real(r8), dimension(pcols), intent(in ) :: lambda_max ! fractional entrainment max + real(r8), dimension(pcols,pver), intent(in ) :: qsthat ! interface interpolated qst + real(r8), dimension(pcols,pver), intent(in ) :: hsthat ! interface interpolated hst + real(r8), dimension(pcols,pver), intent(in ) :: gamhat ! interface interpolated gamma + real(r8), dimension(pcols,pver), intent(in ) :: rprd ! rate of production of precip at that layer + real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: md ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: ed ! downdraft entrainment rate + real(r8), dimension(pcols,pver), intent(inout) :: sd ! dndraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(inout) :: qd ! dndraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(inout) :: hd ! dndraft moist static energy + real(r8), dimension(pcols,pver), intent(inout) :: qds ! dndraft saturation specific humdity + real(r8), dimension(pcols,pver), intent(inout) :: evp ! evaporation rate + real(r8), dimension(pcols), intent(inout) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) !---------------------------------------------------------------------------- ! Local variables integer :: i,k ! loop iterators @@ -1147,22 +1136,23 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jd(i) = max(j0(i),jt(i)+1) jd(i) = min(jd(i),jb(i)) hd(i,jd(i)) = h_env(i,jd(i)-1) - if (jd(i) < jb(i) .and. eps0(i) > 0._r8) then - ! NOTE - this nonsensical eps0/eps0 factor was retained to preserve BFB results during ZM refactoring - md(i,jd(i)) = -zm_param%alfa * eps0(i) / eps0(i) + if (jd(i) < jb(i) .and. lambda_max(i) > 0._r8) then + ! NOTE - this nonsensical lambda_max/lambda_max factor + ! was retained to preserve BFB results during ZM refactoring + md(i,jd(i)) = -zm_param%alfa * lambda_max(i) / lambda_max(i) end if end do ! i do k = msg+1, pver do i = 1,ncol - if ((k > jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8) then + if ((k > jd(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8) then dz_tmp = z_int(i,jd(i)) - z_int(i,k) - md(i,k) = -zm_param%alfa / (2._r8*eps0(i))*(exp(2._r8*eps0(i)*dz_tmp)-1._r8)/dz_tmp + md(i,k) = -zm_param%alfa / (2._r8*lambda_max(i))*(exp(2._r8*lambda_max(i)*dz_tmp)-1._r8)/dz_tmp end if end do ! i end do ! k do k = msg+1, pver do i = 1,ncol - if ((k >= jt(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then + if ((k >= jt(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8 .and. jd(i) < jb(i)) then ratmjb(i) = min(abs(mu(i,jb(i))/md(i,jb(i))),1._r8) md(i,k) = md(i,k)*ratmjb(i) end if @@ -1173,7 +1163,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & ! calculate downdraft entrainment and MSE do k = msg+1, pver do i = 1,ncol - if ((k >= jt(i) .and. k <= pver) .and. eps0(i) > 0._r8) then + if ((k >= jt(i) .and. k <= pver) .and. lambda_max(i) > 0._r8) then ed(i,k-1) = (md(i,k-1)-md(i,k))/dz(i,k-1) mdt = min(md(i,k),-small) hd(i,k) = (md(i,k-1)*hd(i,k-1) - dz(i,k-1)*ed(i,k-1)*h_env(i,k-1))/mdt @@ -1185,7 +1175,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & ! calculate downdraft specific humidity do k = msg+2, pver do i = 1,ncol - if ((k >= jd(i) .and. k <= jb(i)) .and. eps0(i) > 0._r8 .and. jd(i) < jb(i)) then + if ((k >= jd(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8 .and. jd(i) < jb(i)) then qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) end if end do ! i @@ -1202,7 +1192,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & ! calculate downdraft evaporation do k = msg+2, pver do i = 1,ncol - if (k >= jd(i) .and. k < jb(i) .and. eps0(i) > 0._r8) then + if (k >= jd(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8) then qd(i,k+1) = qds(i,k+1) evp(i,k) = -ed(i,k)*q(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) evp(i,k) = max(evp(i,k),0._r8) @@ -1281,30 +1271,30 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & type(zm_microp_st) :: loc_microp_st ! state and tendency of convective microphysics !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: gamma ! latent-heating correction for pseudo-adiabatic parcel lifting - real(r8), dimension(pcols,pver) :: dz ! layer thickness - real(r8), dimension(pcols,pver) :: h_env ! ambient env moist stat energy - real(r8), dimension(pcols,pver) :: h_env_sat ! ambient env saturated moist stat energy - real(r8), dimension(pcols) :: h_env_min ! mid-tropospheric MSE minimum - real(r8), dimension(pcols,pver) :: hu ! updraft moist static energy - real(r8), dimension(pcols,pver) :: hd ! dndraft moist static energy - real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst - real(r8), dimension(pcols,pver) :: hsthat ! interface interpolated hst - real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma - real(r8), dimension(pcols,pver) :: qds ! dndraft saturation specific humdity - real(r8), dimension(pcols) :: c0mask ! land/ocean modification - real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) - real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) - real(r8), dimension(pcols,pver) :: eps ! fractional entrainment - real(r8), dimension(pcols) :: eps0 ! fractional entrainment max + real(r8), dimension(pcols,pver) :: gamma ! latent-heating correction for pseudo-adiabatic parcel lifting + real(r8), dimension(pcols,pver) :: dz ! layer thickness + real(r8), dimension(pcols,pver) :: h_env ! ambient env moist stat energy + real(r8), dimension(pcols,pver) :: h_env_sat ! ambient env saturated moist stat energy + real(r8), dimension(pcols) :: h_env_min ! mid-tropospheric MSE minimum + real(r8), dimension(pcols,pver) :: hu ! updraft moist static energy + real(r8), dimension(pcols,pver) :: hd ! dndraft moist static energy + real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst + real(r8), dimension(pcols,pver) :: hsthat ! interface interpolated hst + real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma + real(r8), dimension(pcols,pver) :: qds ! dndraft saturation specific humdity + real(r8), dimension(pcols) :: c0mask ! land/ocean modification + real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) + real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) + real(r8), dimension(pcols,pver) :: lambda ! fractional entrainment + real(r8), dimension(pcols) :: lambda_max ! fractional entrainment max ! Convective microphysics - real(r8), dimension(pcols,pver) :: fice ! ice fraction in precip production - real(r8), dimension(pcols,pver) :: tug ! temporary updraft temperature - real(r8), dimension(pcols,pver) :: tmp_frz ! temporary rate of freezing - real(r8), dimension(pcols) :: tot_frz ! total column freezing rate - real(r8), dimension(pcols,pverp):: pflxs ! frozen precipitation flux thru layer - integer, dimension(pcols) :: jto ! updraft plume old top + real(r8), dimension(pcols,pver) :: fice ! ice fraction in precip production + real(r8), dimension(pcols,pver) :: tug ! temporary updraft temperature + real(r8), dimension(pcols,pver) :: tmp_frz ! temporary rate of freezing + real(r8), dimension(pcols) :: tot_frz ! total column freezing rate + real(r8), dimension(pcols,pverp):: pflxs ! frozen precipitation flux thru layer + integer, dimension(pcols) :: jto ! updraft plume old top real(r8) :: zuef ! temporary vertical thickness for updraft calculations real(r8) :: rmue ! temporary for updraft entrainment calculations @@ -1445,7 +1435,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! current calculation of PBL temperature perturbation is not accurate enough so that a ! new tunable parameter tpert_fac was introduced. This introduced new uncertainties into ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. - if(zm_param%tpert_fix) then + if (zm_param%tpert_fix) then hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add su(i,k) = s(i,jb(i)) + zm_param%tiedke_add else @@ -1460,7 +1450,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! calculate fractional entrainment (i.e. "lambda D") - see eq (4.78) from Neale et al. (2012) call zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & jb, jt, j0, z_mid, z_int, dz, & - h_env, h_env_sat, h_env_min, eps, eps0) + h_env, h_env_sat, h_env_min, & + lambda, lambda_max) !---------------------------------------------------------------------------- ! iteration to set cloud properties @@ -1489,7 +1480,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+1, -1 do i = 1,ncol ! intialize updraft mass flux variables - here and below all normalized by cloud base mass flux (mb) - if (eps0(i) > 0._r8) then + if (lambda_max(i) > 0._r8) then mu(i,jb(i)) = 1._r8 eu(i,jb(i)) = mu(i,jb(i))/dz(i,jb(i)) if ( zm_param%zm_microp) tmp_k_limit = lel(i) @@ -1497,12 +1488,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) if ( k>=tmp_k_limit .and. k0._r8 + end if ! lambda_max(i)>0._r8 end do ! i end do ! k @@ -1515,7 +1506,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = klowest-1,khighest,-1 do i = 1,ncol - if (k <= jb(i)-1 .and. k >= lel(i) .and. eps0(i) > 0._r8) then + if (k <= jb(i)-1 .and. k >= lel(i) .and. lambda_max(i) > 0._r8) then if (mu(i,k) < 0.02_r8) then hu(i,k) = h_env(i,k) mu(i,k) = 0._r8 @@ -1573,13 +1564,13 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+1, -1 do i = 1,ncol - if (k >= lel(i) .and. k <= jt(i) .and. eps0(i) > 0._r8) then + if (k >= lel(i) .and. k <= jt(i) .and. lambda_max(i) > 0._r8) then mu(i,k) = 0._r8 eu(i,k) = 0._r8 du(i,k) = 0._r8 hu(i,k) = h_env(i,k) end if - if (k == jt(i) .and. eps0(i) > 0._r8) then + if (k == jt(i) .and. lambda_max(i) > 0._r8) then du(i,k) = mu(i,k+1)/dz(i,k) eu(i,k) = 0._r8 mu(i,k) = 0._r8 @@ -1592,11 +1583,11 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & kount = 0 do k = pver, msg+2, -1 do i = 1,ncol - if (k == jb(i) .and. eps0(i) > 0._r8) then + if (k == jb(i) .and. lambda_max(i) > 0._r8) then qu(i,k) = q(i,jb(i)) su(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair end if - if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. eps0(i) > 0._r8) then + if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. lambda_max(i) > 0._r8) then su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s(i,k) qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q(i,k) - du(i,k)*qst(i,k)) tu = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) @@ -1615,7 +1606,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = msg+2, pver do i = 1,ncol - if ((k > jt(i) .and. k <= jlcl(i)) .and. eps0(i) > 0._r8) then + if ((k > jt(i) .and. k <= jlcl(i)) .and. lambda_max(i) > 0._r8) then su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if @@ -1625,7 +1616,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! compute condensation in updraft do k = pver, msg+2, -1 do i = 1,ncol - if (eps0(i)>0._r8) then + if (lambda_max(i)>0._r8) then if ( zm_param%zm_microp) tmp_k_limit = jlcl(i)+1 if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) if ( k>=jt(i) .and. k0._r8 + end if ! lambda_max(i)>0._r8 end do ! i end do ! k @@ -1684,7 +1675,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_mphy( pcols, ncol, msg, & zm_const%grav, zm_const%cpair, zm_const%rdair, & zm_param%auto_fac, zm_param%accr_fac, zm_param%micro_dcs, & - jb, jt, jlcl, su, qu, mu, du, eu, z_int, p_mid, t_mid, q, gamhat, eps0, & + jb, jt, jlcl, su, qu, mu, du, eu, z_int, p_mid, t_mid, q, gamhat, lambda_max, & loc_microp_st%cmel, loc_microp_st%cmei, aero, & loc_microp_st%qliq, loc_microp_st%qice, loc_microp_st%qnl, loc_microp_st%qni, & loc_microp_st%qcde, loc_microp_st%qide, loc_microp_st%ncde, loc_microp_st%nide, & @@ -1732,7 +1723,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+2, -1 do i = 1,ncol - if (k >= jt(i) .and. k < jb(i) .and. eps0(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then + if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-du(i,k)*( loc_microp_st%qcde(i,k+1) & +loc_microp_st%qide(i,k+1) & +loc_microp_st%qsde(i,k+1) )) @@ -1752,7 +1743,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+2, -1 do i = 1,ncol rprd(i,k) = 0._r8 - if (k >= jt(i) .and. k < jb(i) .and. eps0(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then + if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then if (mu(i,k) > 0._r8) then ql1 = 1._r8/mu(i,k)* (mu(i,k+1)*ql(i,k+1)- & dz(i,k)*du(i,k)*ql(i,k+1)+dz(i,k)*cu(i,k)) @@ -1774,7 +1765,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! calculate downdraft properties call zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s, q, h_env, & - eps, eps0, qsthat, hsthat, gamhat, rprd, & + lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & mu, md, ed, sd, qd, hd, qds, evp, totevp) !---------------------------------------------------------------------------- @@ -1825,7 +1816,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (zm_param%zm_microp) then do i = 1,ncol ! protect against rounding error - if(pflxs(i,pverp).gt.pflx(i,pverp)) then + if (pflxs(i,pverp).gt.pflx(i,pverp)) then dum = (pflxs(i,pverp)-pflx(i,pverp))/omsm do k = pver, msg+2, -1 if (loc_microp_st%sprd(i,k) > 0._r8 .and. dum > 0._r8) then @@ -2042,7 +2033,7 @@ end subroutine zm_closure !=================================================================================================== -subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & +subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & dqdt, dsdt, q, qs, qu, & su, du, qhat, shat, dp, & mu, md, sd, qd, ql, & @@ -2168,7 +2159,7 @@ subroutine zm_calculate_output_tend(pcols, ncol, pver, pverp, & end do !---------------------------------------------------------------------------- return -end subroutine zm_calculate_output_tend +end subroutine zm_calc_output_tend !=================================================================================================== From 46913a1ae35dfad9af5cb14aa9ea652aee4842b9 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 4 Dec 2025 15:06:53 -0800 Subject: [PATCH 139/398] bug fix --- components/eam/src/physics/cam/zm_conv.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index a10ffcba812c..ddb8fac57341 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -508,7 +508,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! calculate updraft and downdraft properties call zm_cloud_properties(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & - pg, z_mid_g, z_int_g, tg, sg, shat, qg, ug, vg, landfracg, tpertg, & + pg, z_mid_g, z_int_g, tg, sg, shat, qg, & + landfracg, tpertg, & maxg, lelg, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, qlg, sd, qd, & @@ -535,7 +536,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- - call zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_alt, & + call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_alt, & lclg, lelg, jt, maxg, dsubcld, & z_mid_g, z_int_g, pg, dp, tg, & sg, qg, qs, qlg, shat, qhat, & @@ -1216,7 +1217,8 @@ end subroutine zm_downdraft_properties !=================================================================================================== subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & - p_mid, z_mid, z_int, t_mid, s, shat, q, u, v, landfrac, tpertg, & + p_mid, z_mid, z_int, t_mid, s, shat, q, & + landfrac, tpertg, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, ql, sd, qd, & @@ -1241,8 +1243,6 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) real(r8), dimension(pcols,pver), intent(in ) :: shat ! interface values of dry stat energy real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity - real(r8), dimension(pcols,pver), intent(in ) :: u ! env zonal wind - real(r8), dimension(pcols,pver), intent(in ) :: v ! env meridional wind real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction real(r8), dimension(pcols), intent(in ) :: tpertg ! PBL temperature perturbation integer, dimension(pcols), intent(in ) :: jb ! updraft base level @@ -1889,7 +1889,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness of layers real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! ambient temperature real(r8), dimension(pcols,pver), intent(in ) :: s ! ambient dry static energy (normalized) - real(r8), dimension(pcols,pver), intent(in ) :: q ! ambient spec humidity + real(r8), dimension(pcols,pver), intent(in ) :: q ! ambient specific humidity real(r8), dimension(pcols,pver), intent(in ) :: qs ! ambient saturation specific humidity real(r8), dimension(pcols,pver), intent(in ) :: ql ! ambient liquid water mixing ratio real(r8), dimension(pcols,pver), intent(in ) :: shat ! env. normalized dry static energy at intrfcs From 8215d744916015dfce5a57448b8dd43da065600b Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 4 Dec 2025 16:23:32 -0800 Subject: [PATCH 140/398] more renaming --- components/eam/src/physics/cam/zm_conv.F90 | 216 ++++++++++----------- 1 file changed, 106 insertions(+), 110 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index ddb8fac57341..da492c923d53 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -157,8 +157,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: s ! scaled dry static energy (t+gz/cp) [K] - real(r8), dimension(pcols,pver) :: q ! local copy of specific humidity [kg/kg] + real(r8), dimension(pcols,pver) :: s_mid ! scaled dry static energy (t+gz/cp) [K] + real(r8), dimension(pcols,pver) :: q_mid ! local copy of specific humidity [kg/kg] real(r8), dimension(pcols,pver) :: p_mid ! local copy of mid-point pressure [mb] real(r8), dimension(pcols,pverp):: p_int ! local copy of interface pressure [mb] real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] @@ -195,11 +195,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep - real(r8), dimension(pcols,pver) :: qg ! gathered specific humidity - real(r8), dimension(pcols,pver) :: tg ! gathered temperature at interface + real(r8), dimension(pcols,pver) :: qg ! gathered mid-point env specific humidity + real(r8), dimension(pcols,pver) :: q_int ! gathered interface env specific humidity + real(r8), dimension(pcols,pver) :: t_mid_g ! gathered temperature at interface real(r8), dimension(pcols,pver) :: pg ! gathered values of p real(r8), dimension(pcols,pver) :: z_mid_g ! gathered values of z_mid real(r8), dimension(pcols,pver) :: sg ! gathered values of s + real(r8), dimension(pcols,pver) :: s_int ! gathered upper interface dry static energy real(r8), dimension(pcols,pver) :: tpg ! gathered values of tp real(r8), dimension(pcols,pverp):: z_int_g ! gathered values of z_int real(r8), dimension(pcols,pver) :: qstpg ! gathered values of qstp @@ -220,14 +222,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy real(r8), dimension(pcols,pver) :: qd ! gathered downdraft specific humidity real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux - real(r8), dimension(pcols,pver) :: qhat ! gathered upper interface specific humidity real(r8), dimension(pcols,pver) :: qu ! gathered updraft specific humidity real(r8), dimension(pcols,pver) :: su ! gathered updraft dry static energy real(r8), dimension(pcols,pver) :: qs ! gathered saturation specific humidity - real(r8), dimension(pcols,pver) :: shat ! gathered upper interface dry static energy real(r8), dimension(pcols,pver) :: qlg ! gathered cloud liquid water - real(r8), dimension(pcols,pver) :: dudt ! gathered u-wind tendency at gathered points - real(r8), dimension(pcols,pver) :: dvdt ! gathered v-wind tendency at gathered points real(r8), dimension(pcols) :: mb ! cloud base mass flux integer, dimension(pcols) :: jlcl ! updraft lifting cond level @@ -262,8 +260,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & mcon(i,k) = 0._r8 dqdt(i,k) = 0._r8 dsdt(i,k) = 0._r8 - dudt(i,k) = 0._r8 - dvdt(i,k) = 0._r8 pflx(i,k) = 0._r8 pflxg(i,k) = 0._r8 rprd(i,k) = 0._r8 @@ -326,11 +322,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = 1,pver do i = 1,ncol - q(i,k) = qh(i,k) - s(i,k) = t_mid(i,k) + (zm_const%grav/zm_const%cpair)*z_mid(i,k) - tp(i,k) = 0.0_r8 - shat(i,k) = s(i,k) - qhat(i,k) = q(i,k) + q_mid(i,k) = qh(i,k) + s_mid(i,k) = t_mid(i,k) + (zm_const%grav/zm_const%cpair)*z_mid(i,k) + tp(i,k) = 0.0_r8 + s_int(i,k) = s_mid(i,k) + q_int(i,k) = q_mid(i,k) end do end do @@ -352,7 +348,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & cape_calc_msemax_klev = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & - q, t_mid, z_mid, p_mid, p_int, & + q_mid, t_mid, z_mid, p_mid, p_int, & pbl_top, tpert, & tp, qstp, maxi, tl, & lcl, lel, cape, & @@ -421,11 +417,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,lengath do k = 1,pver dp(i,k) = 0.01_r8*p_del_in(ideep(i),k) - qg(i,k) = q(ideep(i),k) - tg(i,k) = t_mid(ideep(i),k) + qg(i,k) = q_mid(ideep(i),k) + t_mid_g(i,k) = t_mid(ideep(i),k) pg(i,k) = p_mid(ideep(i),k) z_mid_g(i,k) = z_mid(ideep(i),k) - sg(i,k) = s(ideep(i),k) + sg(i,k) = s_mid(ideep(i),k) tpg(i,k) = tp(ideep(i),k) z_int_g(i,k) = z_int(ideep(i),k) qstpg(i,k) = qstp(ideep(i),k) @@ -492,14 +488,14 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & if (qg(i,k) > 0._r8 .or. qg(i,k-1) > 0._r8) & qdifr = abs((qg(i,k)-qg(i,k-1))/max(qg(i,k-1),qg(i,k))) if (sdifr > interp_diff_min) then - shat(i,k) = log(sg(i,k-1)/sg(i,k))*sg(i,k-1)*sg(i,k)/(sg(i,k-1)-sg(i,k)) + s_int(i,k) = log(sg(i,k-1)/sg(i,k))*sg(i,k-1)*sg(i,k)/(sg(i,k-1)-sg(i,k)) else - shat(i,k) = 0.5_r8* (sg(i,k)+sg(i,k-1)) + s_int(i,k) = 0.5_r8* (sg(i,k)+sg(i,k-1)) end if if (qdifr > interp_diff_min) then - qhat(i,k) = log(qg(i,k-1)/qg(i,k))*qg(i,k-1)*qg(i,k)/(qg(i,k-1)-qg(i,k)) + q_int(i,k) = log(qg(i,k-1)/qg(i,k))*qg(i,k-1)*qg(i,k)/(qg(i,k-1)-qg(i,k)) else - qhat(i,k) = 0.5_r8* (qg(i,k)+qg(i,k-1)) + q_int(i,k) = 0.5_r8* (qg(i,k)+qg(i,k-1)) end if end do end do @@ -508,7 +504,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! calculate updraft and downdraft properties call zm_cloud_properties(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & - pg, z_mid_g, z_int_g, tg, sg, shat, qg, & + pg, z_mid_g, z_int_g, t_mid_g, sg, s_int, qg, & landfracg, tpertg, & maxg, lelg, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & @@ -538,8 +534,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_alt, & lclg, lelg, jt, maxg, dsubcld, & - z_mid_g, z_int_g, pg, dp, tg, & - sg, qg, qs, qlg, shat, qhat, & + z_mid_g, z_int_g, pg, dp, t_mid_g, & + sg, qg, qs, qlg, s_int, q_int, & tlg, tpg, qstpg, su, qu, & mc, du, mu, md, qd, sd, capeg, mb ) @@ -604,7 +600,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & call zm_calc_output_tend(pcols, ncol, pver, pverp, & dqdt, dsdt, qg, qs, qu, & - su, du, qhat, shat, dp, & + su, du, q_int, s_int, dp, & mu, md, sd, qd, qlg, & dsubcld, jt, maxg, 1, lengath, msg, & dlg, evpg, cug, & @@ -626,15 +622,15 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & #endif do i = 1,lengath ! q is updated to compute net precip. - q(ideep(i),k) = qh(ideep(i),k) + 2._r8*delt*dqdt(i,k) - qtnd(ideep(i),k) = dqdt (i,k) - rprd(ideep(i),k) = rprdg(i,k) - zdu (ideep(i),k) = du (i,k) - mcon(ideep(i),k) = mc (i,k) - heat(ideep(i),k) = dsdt (i,k)*zm_const%cpair - dlf (ideep(i),k) = dlg (i,k) - pflx(ideep(i),k) = pflxg(i,k) - ql (ideep(i),k) = qlg (i,k) + q_mid(ideep(i),k) = qh(ideep(i),k) + 2._r8*delt*dqdt(i,k) + qtnd(ideep(i),k) = dqdt (i,k) + rprd(ideep(i),k) = rprdg(i,k) + zdu (ideep(i),k) = du (i,k) + mcon(ideep(i),k) = mc (i,k) + heat(ideep(i),k) = dsdt (i,k)*zm_const%cpair + dlf (ideep(i),k) = dlg (i,k) + pflx(ideep(i),k) = pflxg(i,k) + ql (ideep(i),k) = qlg (i,k) end do end do @@ -658,9 +654,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,ncol do k = pver, msg+1, -1 if (zm_param%zm_microp) then - prec(i) = prec(i) - p_del_in(i,k)*(q(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt else - prec(i) = prec(i) - p_del_in(i,k)*(q(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k))*2._r8*delt end if end do ! obtain final precipitation rate in m/s @@ -695,7 +691,7 @@ end subroutine zm_convr !=================================================================================================== subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & - pmid, pdel, t_mid, q, prdprec, cldfrc, & + pmid, pdel, t_mid, q_mid, prdprec, cldfrc, & tend_s, tend_q, tend_s_snwprd, tend_s_snwevmlt, & prec, snow, ntprprd, ntsnprd, flxprec, flxsnow, microp_st ) !---------------------------------------------------------------------------- @@ -719,7 +715,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & real(r8), dimension(pcols,pver), intent(in ) :: pmid ! midpoint pressure [Pa] real(r8), dimension(pcols,pver), intent(in ) :: pdel ! layer thickness [Pa] real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] - real(r8), dimension(pcols,pver), intent(in ) :: q ! water vapor [kg/kg] + real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! water vapor [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: prdprec ! precipitation production [kg/kg/s] real(r8), dimension(pcols,pver), intent(in ) :: cldfrc ! cloud fraction real(r8), dimension(pcols,pver), intent(inout) :: tend_s ! heating rate [J/kg/s] @@ -815,7 +811,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & end if ! relative humidity depression must be > 0 for evaporation - evplimit = max(1._r8 - q(i,k)/qs(i,k), 0._r8) + evplimit = max(1._r8 - q_mid(i,k)/qs(i,k), 0._r8) ! total evaporation depends on flux in the top of the layer ! flux prec is the net production above layer minus evaporation into environmet @@ -823,7 +819,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! Don't let evaporation supersaturate layer (approx). Layer may already be saturated. ! Currently does not include heating/cooling change to qs - evplimit = max(0._r8, (qs(i,k)-q(i,k)) / deltat) + evplimit = max(0._r8, (qs(i,k)-q_mid(i,k)) / deltat) ! Don't evaporate more than is falling into the layer from above. ! Don't evaporate rain formed in this layer, but if precip production @@ -1083,7 +1079,7 @@ end subroutine zm_calc_fractional_entrainment !=================================================================================================== subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & - jb, jt, j0, jd, z_int, dz, s, q, h_env, & + jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & mu, md, ed, sd, qd, hd, qds, evp, totevp ) !---------------------------------------------------------------------------- @@ -1106,8 +1102,8 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & integer, dimension(pcols), intent(inout) :: jd ! level of downdraft real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface real(r8), dimension(pcols,pver) ,intent(in ) :: dz ! layer thickness - real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) - real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: s_mid ! env dry static energy of env [K] (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! env specific humidity real(r8), dimension(pcols,pver), intent(in ) :: h_env ! ambient env moist stat energy real(r8), dimension(pcols,pver), intent(in ) :: lambda ! fractional entrainment real(r8), dimension(pcols), intent(in ) :: lambda_max ! fractional entrainment max @@ -1195,12 +1191,12 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do i = 1,ncol if (k >= jd(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8) then qd(i,k+1) = qds(i,k+1) - evp(i,k) = -ed(i,k)*q(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) + evp(i,k) = -ed(i,k)*q_mid(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) evp(i,k) = max(evp(i,k),0._r8) mdt = min(md(i,k+1),-small) if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) - sd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s(i,k))*dz(i,k) + md(i,k)*sd(i,k))/mdt - totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q(i,k) + sd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s_mid(i,k))*dz(i,k) + md(i,k)*sd(i,k))/mdt + totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q_mid(i,k) end if end do ! i end do ! k @@ -1217,7 +1213,7 @@ end subroutine zm_downdraft_properties !=================================================================================================== subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & - p_mid, z_mid, z_int, t_mid, s, shat, q, & + p_mid, z_mid, z_int, t_mid, s_mid, s_int, q_mid, & landfrac, tpertg, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & @@ -1240,9 +1236,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! env altitude at interface real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! env temperature - real(r8), dimension(pcols,pver), intent(in ) :: s ! env dry static energy of env [K] (normalized) - real(r8), dimension(pcols,pver), intent(in ) :: shat ! interface values of dry stat energy - real(r8), dimension(pcols,pver), intent(in ) :: q ! env specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: s_mid ! env dry static energy of env [K] (normalized) + real(r8), dimension(pcols,pver), intent(in ) :: s_int ! interface values of dry stat energy + real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! env specific humidity real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction real(r8), dimension(pcols), intent(in ) :: tpertg ! PBL temperature perturbation integer, dimension(pcols), intent(in ) :: jb ! updraft base level @@ -1356,12 +1352,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_mid(i,k)**2) & * zm_const%latvap/zm_const%cpair ! cloud thermodynamic variables - su(i,k) = s(i,k) - sd(i,k) = s(i,k) - qd(i,k) = q(i,k) - qds(i,k) = q(i,k) - qu(i,k) = q(i,k) - h_env(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q(i,k) + su(i,k) = s_mid(i,k) + sd(i,k) = s_mid(i,k) + qd(i,k) = q_mid(i,k) + qds(i,k) = q_mid(i,k) + qu(i,k) = q_mid(i,k) + h_env(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q_mid(i,k) h_env_sat(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*qst(i,k) hu(i,k) = h_env(i,k) hd(i,k) = h_env(i,k) @@ -1386,7 +1382,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & else qsthat(i,k) = qst(i,k) end if - hsthat(i,k) = zm_const%cpair*shat(i,k) + zm_const%latvap*qsthat(i,k) + hsthat(i,k) = zm_const%cpair*s_int(i,k) + zm_const%latvap*qsthat(i,k) if (abs(gamma(i,k-1)-gamma(i,k)) > interp_diff_min) then gamhat(i,k) = log(gamma(i,k-1)/gamma(i,k))*gamma(i,k-1)*gamma(i,k)/ (gamma(i,k-1)-gamma(i,k)) else @@ -1437,10 +1433,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. if (zm_param%tpert_fix) then hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add - su(i,k) = s(i,jb(i)) + zm_param%tiedke_add + su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add else hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) - su(i,k) = s(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) + su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) end if end if end do ! i @@ -1584,12 +1580,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+2, -1 do i = 1,ncol if (k == jb(i) .and. lambda_max(i) > 0._r8) then - qu(i,k) = q(i,jb(i)) + qu(i,k) = q_mid(i,jb(i)) su(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. lambda_max(i) > 0._r8) then - su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s(i,k) - qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q(i,k) - du(i,k)*qst(i,k)) + su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s_mid(i,k) + qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q_mid(i,k) - du(i,k)*qst(i,k)) tu = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) call qsat_hPa(tu, (p_mid(i,k)+p_mid(i,k-1))/2._r8, estu, qstu) if (qu(i,k) >= qstu) then @@ -1607,7 +1603,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = msg+2, pver do i = 1,ncol if ((k > jt(i) .and. k <= jlcl(i)) .and. lambda_max(i) > 0._r8) then - su(i,k) = shat(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) + su(i,k) = s_int(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if end do ! i @@ -1621,10 +1617,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) if ( k>=jt(i) .and. kjt(i) .and. klcl(i) .and. k=lel(i) .and. k<=lcl(i) ) then - thetavp = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i))) - thetavm = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q(i,k)) + thetavp = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q_mid(i,mx(i))) + thetavm = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q_mid(i,k)) dqsdtp = qstp(i,k) * (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) dtpdt = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp-qstp(i,k)/tp(i,k)))* & - (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q(i,mx(i))/tl(i)**2*dtldt(i))) - dboydt(i,k) = ((dtpdt/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q(i,mx(i)))* & + (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q_mid(i,mx(i))/tl(i)**2*dtldt(i))) + dboydt(i,k) = ((dtpdt/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q_mid(i,mx(i)))* & (1.608_r8 * dqsdtp * dtpdt -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & - (1._r8+0.608_r8*q(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp/thetavm + (1._r8+0.608_r8*q_mid(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp/thetavm end if end do end do @@ -2035,7 +2031,7 @@ end subroutine zm_closure subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & dqdt, dsdt, q, qs, qu, & - su, du, qhat, shat, dp, & + su, du, q_int, s_int, dp, & mu, md, sd, qd, ql, & dsubcld, jt, mx, il1g, il2g, msg, & dl, evp, cu, & @@ -2058,8 +2054,8 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & real(r8), dimension(pcols,pver), intent(in ) :: qu ! real(r8), dimension(pcols,pver), intent(in ) :: su ! real(r8), dimension(pcols,pver), intent(in ) :: du ! - real(r8), dimension(pcols,pver), intent(in ) :: qhat ! - real(r8), dimension(pcols,pver), intent(in ) :: shat ! + real(r8), dimension(pcols,pver), intent(in ) :: q_int ! + real(r8), dimension(pcols,pver), intent(in ) :: s_int ! real(r8), dimension(pcols,pver), intent(in ) :: dp ! real(r8), dimension(pcols,pver), intent(in ) :: mu ! real(r8), dimension(pcols,pver), intent(in ) :: md ! @@ -2115,13 +2111,13 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & emc = -cu(i,k) + evp(i,k) ! condensation in updraft and evaporating rain in downdraft dsdt(i,k) = -zm_const%latvap/zm_const%cpair*emc + & - (+mu(i,k+1)*(su(i,k+1)-shat(i,k+1)) - mu(i,k)*(su(i,k)-shat(i,k)) & - +md(i,k+1)*(sd(i,k+1)-shat(i,k+1)) - md(i,k)*(sd(i,k)-shat(i,k)) & + (+mu(i,k+1)*(su(i,k+1)-s_int(i,k+1)) - mu(i,k)*(su(i,k)-s_int(i,k)) & + +md(i,k+1)*(sd(i,k+1)-s_int(i,k+1)) - md(i,k)*(sd(i,k)-s_int(i,k)) & )/dp(i,k) dqdt(i,k) = emc + & - (+mu(i,k+1)*(qu(i,k+1)-qhat(i,k+1)) - mu(i,k)*(qu(i,k)-qhat(i,k)) & - +md(i,k+1)*(qd(i,k+1)-qhat(i,k+1)) - md(i,k)*(qd(i,k)-qhat(i,k)) & + (+mu(i,k+1)*(qu(i,k+1)-q_int(i,k+1)) - mu(i,k)*(qu(i,k)-q_int(i,k)) & + +md(i,k+1)*(qd(i,k+1)-q_int(i,k+1)) - md(i,k)*(qd(i,k)-q_int(i,k)) & )/dp(i,k) if (zm_param%zm_microp) then @@ -2147,10 +2143,10 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & do k = kbm,pver do i = il1g,il2g if (k == mx(i)) then - dsdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(su(i,k)-shat(i,k)) & - -md(i,k)*(sd(i,k)-shat(i,k)) ) - dqdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(qu(i,k)-qhat(i,k)) & - -md(i,k)*(qd(i,k)-qhat(i,k)) ) + dsdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(su(i,k)-s_int(i,k)) & + -md(i,k)*(sd(i,k)-s_int(i,k)) ) + dqdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(qu(i,k)-q_int(i,k)) & + -md(i,k)*(qd(i,k)-q_int(i,k)) ) else if (k > mx(i)) then dsdt(i,k) = dsdt(i,k-1) dqdt(i,k) = dqdt(i,k-1) From b73559ee5a737659a1d654cc5685de79aa910d8f Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Mon, 19 Sep 2022 09:26:32 -0700 Subject: [PATCH 141/398] ocn to lnd one way coupling first commit Conflicts: components/data_comps/docn/cime_config/config_component.xml components/data_comps/docn/cime_config/namelist_definition_docn.xml components/data_comps/docn/src/docn_comp_mod.F90 components/data_comps/docn/src/docn_shr_mod.F90 components/elm/src/biogeophys/BalanceCheckMod.F90 components/elm/src/biogeophys/SoilHydrologyMod.F90 components/elm/src/cpl/elm_cpl_indices.F90 components/elm/src/cpl/lnd_comp_mct.F90 components/elm/src/data_types/ColumnDataType.F90 components/elm/src/main/controlMod.F90 components/mpas-ocean/driver/mpaso_cpl_indices.F driver-mct/cime_config/namelist_definition_drv.xml driver-mct/shr/seq_flds_mod.F90 driver-mct/shr/seq_infodata_mod.F90 --- .../docn/cime_config/config_component.xml | 22 ++- .../cime_config/namelist_definition_docn.xml | 23 ++- .../data_comps/docn/src/docn_comp_mod.F90 | 49 ++++- .../data_comps/docn/src/docn_shr_mod.F90 | 3 +- .../elm/cime_config/config_compsets.xml | 7 + .../elm/src/biogeophys/BalanceCheckMod.F90 | 9 +- .../src/biogeophys/HydrologyNoDrainageMod.F90 | 15 +- .../elm/src/biogeophys/SoilHydrologyMod.F90 | 50 ++++- components/elm/src/cpl/elm_cpl_indices.F90 | 6 +- components/elm/src/cpl/lnd_comp_mct.F90 | 15 +- components/elm/src/cpl/lnd_import_export.F90 | 9 +- .../elm/src/data_types/ColumnDataType.F90 | 8 + components/elm/src/main/controlMod.F90 | 6 +- components/elm/src/main/elm_driver.F90 | 5 +- components/elm/src/main/elm_instMod.F90 | 4 + components/elm/src/main/elm_varctl.F90 | 5 + components/elm/src/main/ocn2lndType.F90 | 131 +++++++++++++ .../mpas-ocean/driver/mpaso_cpl_indices.F | 4 + driver-mct/cime_config/buildnml | 4 + driver-mct/cime_config/config_component.xml | 68 +++++++ .../cime_config/namelist_definition_drv.xml | 133 +++++++++++++ driver-mct/main/cime_comp_mod.F90 | 23 ++- driver-mct/main/prep_lnd_mod.F90 | 177 +++++++++++++++++- driver-mct/shr/seq_flds_mod.F90 | 23 ++- driver-mct/shr/seq_infodata_mod.F90 | 14 +- 25 files changed, 762 insertions(+), 51 deletions(-) create mode 100644 components/elm/src/main/ocn2lndType.F90 diff --git a/components/data_comps/docn/cime_config/config_component.xml b/components/data_comps/docn/cime_config/config_component.xml index 68ec6a18c9f9..e7a4843e8ebc 100644 --- a/components/data_comps/docn/cime_config/config_component.xml +++ b/components/data_comps/docn/cime_config/config_component.xml @@ -13,7 +13,7 @@ This file may have ocn desc entries. --> - DOCN + DOCN null mode prescribed ocean mode slab ocean mode @@ -33,6 +33,7 @@ analytic aquaplanet sst - option 10 file input aquaplanet sst globally constant SST for idealized experiments, such as RCE + coastal inundation estimated with bathtub method with GTSM sea water level @@ -46,7 +47,7 @@ char - prescribed,sst_aquap1,sst_aquap2,sst_aquap3,sst_aquap4,sst_aquap5,sst_aquap6,sst_aquap7,sst_aquap8,sst_aquap9,sst_aquap10,sst_aquap11,sst_aquap12,sst_aquap13,sst_aquap14,sst_aquap15,sst_aquapfile,som,rso,som_aquap,sst_aquap_constant,interannual,null + prescribed,sst_aquap1,sst_aquap2,sst_aquap3,sst_aquap4,sst_aquap5,sst_aquap6,sst_aquap7,sst_aquap8,sst_aquap9,sst_aquap10,sst_aquap11,sst_aquap12,sst_aquap13,sst_aquap14,sst_aquap15,sst_aquapfile,som,rso,som_aquap,sst_aquap_constant,interannual,GTSM,null prescribed null @@ -73,6 +74,7 @@ sst_aquap15 sst_aquapfile sst_aquap_constant + GTSM run_component_docn env_run.xml @@ -144,6 +146,19 @@ This is only used when DOCN_MODE=sst_aquapfile. + + char + + UNSET + + coastal_inundation.$SSTICE_YEAR_START-01.nc + + run_component_docn + env_run.xml + Sets aquaplanet forcing filename instead of using an analytic form. + This is only used when DOCN_MODE=sst_aquapfile. + + real @@ -264,6 +279,7 @@ 2016 2020 1869 + 1950 run_component_cam_sstice env_run.xml @@ -293,6 +309,7 @@ 2016 2020 1869 + 1950 run_component_cam_sstice env_run.xml @@ -316,6 +333,7 @@ 2016 2020 2016 + 2014 run_component_cam_sstice env_run.xml diff --git a/components/data_comps/docn/cime_config/namelist_definition_docn.xml b/components/data_comps/docn/cime_config/namelist_definition_docn.xml index fb28b7471c50..38b935f05359 100644 --- a/components/data_comps/docn/cime_config/namelist_definition_docn.xml +++ b/components/data_comps/docn/cime_config/namelist_definition_docn.xml @@ -63,6 +63,7 @@ rso som interannual + GTSM @@ -97,6 +98,7 @@ $DIN_LOC_ROOT/ocn/docn7/SOM / $DIN_LOC_ROOT/atm/cam/sst + $DIN_LOC_ROOT/ocn/docn7/GTSM @@ -111,6 +113,7 @@ $DOCN_SOM_FILENAME $SSTICE_GRID_FILENAME sst_HadOIBl_bc_1x1_1850_2014_c150416.nc + $DOCN_GTSM_FILENAME @@ -137,6 +140,14 @@ lon lon lat lat + + time time + xc lon + yc lat + area area + mask mask + frac frac + @@ -151,6 +162,7 @@ $DIN_LOC_ROOT/ocn/docn7/SOM / $DIN_LOC_ROOT/atm/cam/sst + $DIN_LOC_ROOT/ocn/docn7/GTSM @@ -165,6 +177,7 @@ $DOCN_SOM_FILENAME $SSTICE_DATA_FILENAME sst_HadOIBl_bc_1x1_1850_2014_c150416.nc + coastal_inundation.%ym.nc @@ -200,6 +213,10 @@ SST_cpl t + + T t + Inund frac_h2oocn + @@ -225,6 +242,7 @@ 1 $SSTICE_YEAR_ALIGN 1 + $SSTICE_YEAR_ALIGN @@ -240,6 +258,7 @@ 1 $SSTICE_YEAR_START 1850 + $SSTICE_YEAR_START @@ -255,6 +274,7 @@ 1 $SSTICE_YEAR_END 2014 + $SSTICE_YEAR_END @@ -270,7 +290,7 @@ char streams shr_strdata_nml - SSTDATA,SST_AQUAP1,SST_AQUAP2,SST_AQUAP3,SST_AQUAP4,SST_AQUAP5,SST_AQUAP6,SST_AQUAP7,SST_AQUAP8,SST_AQUAP9,SST_AQUAP10,SST_AQUAP11,SST_AQUAP12,SST_AQUAP13,SST_AQUAP14,SST_AQUAP15,SST_AQUAPFILE,SST_AQUAP_CONSTANT,SOM,RSO,SOM_AQUAP,IAF,NULL,COPYALL + SSTDATA,SST_AQUAP1,SST_AQUAP2,SST_AQUAP3,SST_AQUAP4,SST_AQUAP5,SST_AQUAP6,SST_AQUAP7,SST_AQUAP8,SST_AQUAP9,SST_AQUAP10,SST_AQUAP11,SST_AQUAP12,SST_AQUAP13,SST_AQUAP14,SST_AQUAP15,SST_AQUAPFILE,SST_AQUAP_CONSTANT,SOM,RSO,SOM_AQUAP,IAF,GTSM,NULL,COPYALL General method that operates on the data. This is generally implemented in the data models but is set in the strdata method for @@ -347,6 +367,7 @@ RSO SOM_AQUAP IAF + GTSM diff --git a/components/data_comps/docn/src/docn_comp_mod.F90 b/components/data_comps/docn/src/docn_comp_mod.F90 index f8ef2b2ba86d..a774c4b2729e 100644 --- a/components/data_comps/docn/src/docn_comp_mod.F90 +++ b/components/data_comps/docn/src/docn_comp_mod.F90 @@ -69,7 +69,7 @@ module docn_comp_mod real(R8),parameter :: latice = shr_const_latice ! latent heat of fusion real(R8),parameter :: ocnsalt = shr_const_ocn_ref_sal ! ocean reference salinity - integer(IN) :: kt,ks,ku,kv,kdhdx,kdhdy,kq,kswp ! field indices + integer(IN) :: kt,ks,ku,kv,kdhdx,kdhdy,kq,kswp,kh2o ! field indices integer(IN) :: kswnet,klwup,klwdn,ksen,klat,kmelth,ksnow,krofi integer(IN) :: kh,kqbot,kfraz,kssh,kh2ot integer(IN) :: k10uu ! index for u10 @@ -90,13 +90,15 @@ module docn_comp_mod #endif !-------------------------------------------------------------------------- - integer(IN) , parameter :: ktrans = 8 - character(12) , parameter :: avifld(1:ktrans) = & - (/ "t ","u ","v ","dhdx ",& - "dhdy ","s ","h ","qbot "/) - character(12) , parameter :: avofld(1:ktrans) = & - (/ "So_t ","So_u ","So_v ","So_dhdx ",& - "So_dhdy ","So_s ","strm_h ","strm_qbot "/) + integer(IN) , parameter :: ktrans = 9 + character(14) , parameter :: avifld(1:ktrans) = & + (/ "t ","u ","v ","dhdx ",& + "dhdy ","s ","h ","qbot ",& + "frac_h2oocn "/) + character(14) , parameter :: avofld(1:ktrans) = & + (/ "So_t ","So_u ","So_v ","So_dhdx ",& + "So_dhdy ","So_s ","strm_h ","strm_qbot ",& + "So_frac_h2oocn"/) character(len=*),parameter :: flds_strm = 'strm_h:strm_qbot:So_t' !-------------------------------------------------------------------------- @@ -226,6 +228,8 @@ subroutine docn_comp_init(Eclock, x2o, o2x, & datamode == 'SOM_AQUAP' .or. datamode == 'SST_AQUAP_CONSTANT' ) then ! Special logic for either prescribed or som aquaplanet - overwrite and call shr_strdata_init(SDOCN,mpicom,compid,name='ocn', calendar=calendar, reset_domain_mask=.true.) + elseif (trim(datamode) == 'GTSM') then + call shr_strdata_init(SDOCN,mpicom,compid,name='ocn', calendar=calendar, dmodel_domain_fracname_from_stream='frac') else call shr_strdata_init(SDOCN,mpicom,compid,name='ocn', calendar=calendar) end if @@ -288,6 +292,7 @@ subroutine docn_comp_init(Eclock, x2o, o2x, & kq = mct_aVect_indexRA(o2x,'Fioo_q') ! ocn freezing melting potential kfraz = mct_aVect_indexRA(o2x,'Fioo_frazil') ! ocn frazil kh2ot = mct_aVect_indexRA(o2x,'Faoo_h2otemp') ! ocn frazil + kh2o = mct_aVect_indexRA(o2x,'So_frac_h2oocn', perrwith='quiet') call mct_aVect_init(x2o, rList=seq_flds_x2o_fields, lsize=lsize) call mct_aVect_zero(x2o) @@ -660,6 +665,9 @@ subroutine docn_comp_run(EClock, x2o, o2x, & o2x%rAttr(kq ,n) = 0.0_R8 ! make sure frazil is 0. MPAS-seaice will still use it. o2x%rAttr(kfraz,n) = 0.0_R8 + if (kh2o /= 0) then + o2x%rAttr(kh2o, n) = 0.0_R8 + endif if (kswp /= 0) then o2x%rAttr(kswp ,n) = swp end if @@ -901,7 +909,30 @@ subroutine docn_comp_run(EClock, x2o, o2x, & somtp(n) = o2x%rAttr(kt,n) ! save temp enddo endif ! firstcall - + case('GTSM') + lsize = mct_avect_lsize(o2x) + do n = 1,lsize + if (ksomask /= 0) then + o2x%rAttr(ksomask, n) = ggrid%data%rAttr(kfrac,n) + end if + o2x%rAttr(kt ,n) = o2x%rAttr(kt,n) + TkFrz + o2x%rAttr(ks ,n) = ocnsalt + o2x%rAttr(ku ,n) = 0.0_R8 + o2x%rAttr(kv ,n) = 0.0_R8 + o2x%rAttr(kdhdx,n) = 0.0_R8 + o2x%rAttr(kdhdy,n) = 0.0_R8 + o2x%rAttr(kq ,n) = 0.0_R8 + if (kh2o /= 0) then + if (o2x%rAttr(kh2o, n) < 0.0_R8) then + o2x%rAttr(kh2o, n) = 0.0_R8 ! Inundation cannot be negative + else + o2x%rAttr(kh2o, n) = o2x%rAttr(kh2o, n) + endif + endif + if (kswp /= 0) then + o2x%rAttr(kswp ,n) = swp + end if + enddo end select call t_stopf('docn_datamode') diff --git a/components/data_comps/docn/src/docn_shr_mod.F90 b/components/data_comps/docn/src/docn_shr_mod.F90 index fef714c83b4d..a5c6a098df7f 100644 --- a/components/data_comps/docn/src/docn_shr_mod.F90 +++ b/components/data_comps/docn/src/docn_shr_mod.F90 @@ -161,7 +161,8 @@ subroutine docn_shr_read_namelists(mpicom, my_task, master_task, & trim(datamode) == 'IAF' .or. & trim(datamode) == 'SOM' .or. & ! Traditional slab ocean trim(datamode) == 'RSO' .or. & ! Relaxed slab ocean - trim(datamode) == 'SOM_AQUAP') then ! Aquaplanet slab ocean + trim(datamode) == 'SOM_AQUAP' .or. & ! Aquaplanet slab ocean + trim(datamode) == 'GTSM') then if (my_task == master_task) then write(logunit,F00) ' docn datamode = ',trim(datamode) end if diff --git a/components/elm/cime_config/config_compsets.xml b/components/elm/cime_config/config_compsets.xml index e52c8a4a890c..d6ae2ec97d92 100644 --- a/components/elm/cime_config/config_compsets.xml +++ b/components/elm/cime_config/config_compsets.xml @@ -982,6 +982,13 @@ 2000_DATM%1PT_ELM%SP_SICE_SOCN_MOSART_SGLC_SWAV + + + + GTSM2ELM + 2000_DATM%GSWP3v1_ELM_SICE_DOCN%GTSM_SROF_SGLC_SWAV + + diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 index c39487e5e91d..951e65deb1fa 100755 --- a/components/elm/src/biogeophys/BalanceCheckMod.F90 +++ b/components/elm/src/biogeophys/BalanceCheckMod.F90 @@ -252,6 +252,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & snow_sinks => col_wf%snow_sinks , & ! Output: [real(r8) (:) ] snow sinks (mm H2O /s) qflx_lateral => col_wf%qflx_lateral , & ! Input: [real(r8) (:) ] lateral flux of water to neighboring column (mm H2O /s) qflx_h2orof_drain => col_wf%qflx_h2orof_drain , & ! Input: [real(r8) (:) ] drainange from floodplain inundation volume (mm H2O/s) + qflx_h2oocn_drain => col_wf%qflx_h2oocn_drain , & ! Input: [real(r8) (:) ] drainange from floodplain inundation volume (mm H2O/s) eflx_lwrad_out => veg_ef%eflx_lwrad_out , & ! Input: [real(r8) (:) ] emitted infrared (longwave) radiation (W/m**2) eflx_lwrad_net => veg_ef%eflx_lwrad_net , & ! Input: [real(r8) (:) ] net infrared (longwave) rad (W/m**2) [+ = to atm] @@ -336,7 +337,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & + qflx_surf_irrig_col(c) + qflx_over_supply_col(c) & - qflx_evap_tot(c) - qflx_surf(c) - qflx_h2osfc_surf(c) - qflx_to_downhill(c) & - qflx_qrgwl(c) - qflx_drain(c) - qflx_drain_perched(c) - qflx_snwcp_ice(c) - qflx_ice_runoff_xs(c) & - - qflx_lateral(c) + qflx_h2orof_drain(c)) * dtime + - qflx_lateral(c) + qflx_h2orof_drain(c) + qflx_h2oocn_drain(c)) * dtime dwb(c) = (endwb(c)-begwb(c))/dtime else @@ -407,7 +408,8 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & write(iulog,*)'qflx_lateral = ',qflx_lateral(indexc) write(iulog,*)'total_plant_stored_h2o_col = ',total_plant_stored_h2o_col(indexc) write(iulog,*)'qflx_h2orof_drain = ',qflx_h2orof_drain(indexc) - write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc) + write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc) + write(iulog,*)'qflx_h2oocn_drain = ',qflx_h2oocn_drain(indexc) write(iulog,*)'elm model is stopping' call endrun(decomp_index=indexc, elmlevel=namec, msg=errmsg(__FILE__, __LINE__)) @@ -438,7 +440,8 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & write(iulog,*)'qflx_lateral = ',qflx_lateral(indexc) write(iulog,*)'total_plant_stored_h2o_col = ',total_plant_stored_h2o_col(indexc) write(iulog,*)'qflx_h2orof_drain = ',qflx_h2orof_drain(indexc) - write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc) + write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc) + write(iulog,*)'qflx_h2oocn_drain = ',qflx_h2oocn_drain(indexc) write(iulog,*)'elm model is stopping' call endrun(decomp_index=indexc, elmlevel=namec, msg=errmsg(__FILE__, __LINE__)) end if diff --git a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 index fa6fe25c4ae7..763bf8772b44 100644 --- a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -10,10 +10,11 @@ Module HydrologyNoDrainageMod 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 ocn2lndType , only : ocn2lnd_type use lnd2atmType , only : lnd2atm_type use AerosolType , only : aerosol_type use EnergyFluxType , only : energyflux_type - use CanopyStateType , only : canopystate_type + use CanopyStateType , only : canopystate_type use SoilHydrologyType , only : soilhydrology_type use SoilStateType , only : soilstate_type use LandunitType , only : lun_pp @@ -44,7 +45,7 @@ subroutine HydrologyNoDrainage(bounds, & num_urbanc, filter_urbanc, & num_snowc, filter_snowc, & num_nosnowc, filter_nosnowc, canopystate_vars, & - atm2lnd_vars, lnd2atm_vars, soilstate_vars, & + atm2lnd_vars, ocn2lnd_vars, lnd2atm_vars, soilstate_vars, & energyflux_vars, soilhydrology_vars, aerosol_vars) ! !DESCRIPTION: ! This is the main subroutine to execute the calculation of soil/snow @@ -93,6 +94,7 @@ subroutine HydrologyNoDrainage(bounds, & integer , intent(inout) :: num_nosnowc ! number of column non-snow points integer , intent(inout) :: filter_nosnowc(:) ! column filter for non-snow points type(atm2lnd_type) , intent(in) :: atm2lnd_vars + type(ocn2lnd_type) , intent(in) :: ocn2lnd_vars type(lnd2atm_type) , intent(in) :: lnd2atm_vars type(soilstate_type) , intent(inout) :: soilstate_vars type(energyflux_type) , intent(in) :: energyflux_vars @@ -194,15 +196,16 @@ subroutine HydrologyNoDrainage(bounds, & !------------------------------------------------------------------------------------ if (use_pflotran .and. pf_hmode) then - call Infiltration(bounds, num_hydrononsoic, filter_hydrononsoic, & - num_urbanc, filter_urbanc, atm2lnd_vars, lnd2atm_vars, & + call Infiltration(bounds, num_hydrononsoic, filter_hydrononsoic, & + num_urbanc, filter_urbanc, atm2lnd_vars, ocn2lnd_vars, lnd2atm_vars, & energyflux_vars, soilhydrology_vars, soilstate_vars, dtime) else !------------------------------------------------------------------------------------ - call Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & - atm2lnd_vars, lnd2atm_vars, energyflux_vars, soilhydrology_vars, soilstate_vars, dtime) + call Infiltration(bounds, num_hydrologyc, filter_hydrologyc, & + num_urbanc, filter_urbanc, atm2lnd_vars, ocn2lnd_vars, lnd2atm_vars, & + energyflux_vars, soilhydrology_vars, soilstate_vars, dtime) !------------------------------------------------------------------------------------ end if diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index e226adf96ebe..27af8585f78d 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -9,7 +9,7 @@ module SoilHydrologyMod use decompMod , only : bounds_type use elm_varctl , only : iulog, use_vichydro use elm_varctl , only : use_lnd_rof_two_way, lnd_rof_coupling_nstep - use elm_varctl , only : use_modified_infil + use elm_varctl , only : use_modified_infil, use_ocn_lnd_one_way use elm_varcon , only : e_ice, denh2o, denice, rpi use EnergyFluxType , only : energyflux_type use SoilHydrologyType , only : soilhydrology_type @@ -22,7 +22,7 @@ module SoilHydrologyMod use ColumnDataType , only : col_es, col_ws, col_wf use VegetationType , only : veg_pp use VegetationDataType, only : veg_wf - use abortutils , only : endrun + use abortutils , only : endrun ! ! !PUBLIC TYPES: @@ -291,7 +291,7 @@ end subroutine SurfaceRunoff !----------------------------------------------------------------------- subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & - atm2lnd_vars, lnd2atm_vars, energyflux_vars, soilhydrology_vars, soilstate_vars, dtime) + atm2lnd_vars, ocn2lnd_vars, lnd2atm_vars, energyflux_vars, soilhydrology_vars, soilstate_vars, dtime) ! ! !DESCRIPTION: ! Calculate infiltration into surface soil layer (minus the evaporation) @@ -307,6 +307,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f use landunit_varcon , only : istsoil, istcrop, ilowcenpoly, iflatcenpoly, ihighcenpoly use elm_time_manager , only : get_step_size, get_nstep use atm2lndType , only : atm2lnd_type ! land river two way coupling + use ocn2lndType , only : ocn2lnd_type use lnd2atmType , only : lnd2atm_type use subgridAveMod , only : c2g ! @@ -317,6 +318,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f integer , intent(in) :: num_urbanc ! number of column urban points in column filter integer , intent(in) :: filter_urbanc(:) ! column filter for urban points type(atm2lnd_type) , intent(in) :: atm2lnd_vars ! land river two way coupling + type(ocn2lnd_type) , intent(in) :: ocn2lnd_vars ! ocean land one way coupling type(lnd2atm_type) , intent(in) :: lnd2atm_vars type(energyflux_type) , intent(in) :: energyflux_vars type(soilhydrology_type) , intent(inout) :: soilhydrology_vars @@ -383,6 +385,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f h2osfc => col_ws%h2osfc , & ! Output: [real(r8) (:) ] surface water (mm) h2orof => col_ws%h2orof , & ! Output: [real(r8) (:) ] floodplain inudntion volume (mm) frac_h2orof => col_ws%frac_h2orof , & ! Output: [real(r8) (:) ] floodplain inudntion fraction (-) + frac_h2oocn => col_ws%frac_h2oocn , & ! Output: [real(r8) (:) ] coastal inudntion fraction (-) iwp_microrel => col_ws%iwp_microrel , & ! Input: [real(r8) (:) ] ice wedge polygon microtopographic relief (m) iwp_exclvol => col_ws%iwp_exclvol , & ! Input: [real(r8) (:) ] ice wedge polygon excluded volume (m) iwp_ddep => col_ws%iwp_ddep , & ! Input: [real(r8) (:) ] ice wedge polygon depression depth (m) @@ -399,6 +402,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f qflx_gross_infl_soil => col_wf%qflx_gross_infl_soil , & ! Output: [real(r8) (:)] gross infiltration (mm H2O/s) qflx_gross_evap_soil => col_wf%qflx_gross_evap_soil , & ! Output: [real(r8) (:)] gross evaporation (mm H2O/s) qflx_h2orof_drain => col_wf%qflx_h2orof_drain , & ! Output: [real(r8) (:)] drainange from floodplain inundation volume (mm H2O/s) + qflx_h2oocn_drain => col_wf%qflx_h2oocn_drain , & ! Output: [real(r8) (:)] drainange from coastal inundation volume (mm H2O/s) smpmin => soilstate_vars%smpmin_col , & ! Input: [real(r8) (:) ] restriction for min of soil potential (mm) sucsat => soilstate_vars%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) @@ -455,7 +459,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f qflx_evap(c)=qflx_ev_soil(c) endif - !0. partition grid-level floodplain inundation volume and fraction to each column + !0. partition grid-level floodplain/coastal inundation volume and fraction to each column if (use_lnd_rof_two_way) then if (mod(get_nstep(),lnd_rof_coupling_nstep) == 1 .or. get_nstep() <= 1 .or. lnd_rof_coupling_nstep == 1) then h2orof(c) = atm2lnd_vars%h2orof_grc(g) * wtgcell(c) @@ -467,6 +471,13 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f endif endif + if (use_ocn_lnd_one_way) then + frac_h2oocn(c) = ocn2lnd_vars%frac_h2oocn_grc(g) * wtgcell(c) + if ( frac_h2oocn(c) > 1.0_r8 - fsno - frac_h2osfc(c) ) then + frac_h2oocn(c) = 1.0_r8 - fsno - frac_h2osfc(c) + endif + endif + !1. partition surface inputs between soil and h2osfc qflx_in_soil(c) = (1._r8 - frac_h2osfc(c)) * (qflx_top_soil(c) - qflx_surf(c)) qflx_in_h2osfc(c) = frac_h2osfc(c) * (qflx_top_soil(c) - qflx_surf(c)) @@ -528,6 +539,8 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f if (use_lnd_rof_two_way) then qflx_infl_excess(c) = max(0._r8,qflx_in_soil(c) - (1.0_r8 - frac_h2osfc(c) - frac_h2orof(c))*qinmax) + elseif (use_ocn_lnd_one_way) then + qflx_infl_excess(c) = max(0._r8,qflx_in_soil(c) - (1.0_r8 - frac_h2osfc(c) - frac_h2oocn(c))*qinmax) else qflx_infl_excess(c) = max(0._r8,qflx_in_soil(c) - (1.0_r8 - frac_h2osfc(c))*qinmax) endif @@ -665,6 +678,32 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f qflx_gross_infl_soil(c) = qflx_gross_infl_soil(c) + qflx_h2osfc_drain(c) endif + !9. add drainage from coastal inundation to qflx_infl (ocean land one way coupling) + if (use_ocn_lnd_one_way) then + + ! estimate the available volume [mm H2O] in the first soil layer for floodplain infiltration + h2osoi_left_vol1 = max(0._r8,(pondmx+watsat(c,1)*dz(c,1)*1.e3_r8-h2osoi_ice(c,1)-watmin)) - & + max(0._r8,h2osoi_liq(c,1)-watmin) + if (h2osoi_left_vol1 < 0._r8) then + h2osoi_left_vol1 = 0._r8 + endif + + if (frac_h2oocn(c) > 0._r8 .and. frac_h2oocn(c) > fsat(c)) then + h2osoi_left_vol1 = (frac_h2oocn(c) - fsat(c)) * h2osoi_left_vol1 + ! no drainage from ocn inundation if the 1st layer soil is saturated + qflx_h2oocn_drain(c)=min((frac_h2oocn(c) - fsat(c))*qinmax, h2osoi_left_vol1/dtime) + else + qflx_h2oocn_drain(c)=0._r8 + endif + + qflx_infl(c) = qflx_infl(c) + qflx_h2oocn_drain(c) + qflx_gross_infl_soil(c) = qflx_gross_infl_soil(c) + qflx_h2osfc_drain(c) + qflx_h2oocn_drain(c) + + else + qflx_gross_infl_soil(c) = qflx_gross_infl_soil(c) + qflx_h2osfc_drain(c) + endif + + else ! non-vegetated landunits (i.e. urban) use original CLM4 code if (snl(c) >= 0) then @@ -692,6 +731,9 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f if (use_lnd_rof_two_way) then qflx_h2orof_drain(c) = 0._r8 endif + if (use_ocn_lnd_one_way) then + qflx_h2oocn_drain(c) = 0._r8 + endif end if end do diff --git a/components/elm/src/cpl/elm_cpl_indices.F90 b/components/elm/src/cpl/elm_cpl_indices.F90 index 0d300fbc94fb..d3abcda0b8ca 100644 --- a/components/elm/src/cpl/elm_cpl_indices.F90 +++ b/components/elm/src/cpl/elm_cpl_indices.F90 @@ -128,6 +128,7 @@ module elm_cpl_indices integer, public ::index_x2l_Flrr_deficit ! rtm->lnd supply deficit integer, public ::index_x2l_Sr_h2orof ! rtm->lnd floodplain inundation volume integer, public ::index_x2l_Sr_frac_h2orof ! rtm->lnd floodplain inundation fraction + integer, public ::index_x2l_So_frac_h2oocn ! ocn->lnd coastal inundation fraction ! In the following, index 0 is bare land, other indices are glc elevation classes integer, public ::index_x2l_Sg_frac(0:glc_nec_max) = 0 ! Fraction of glacier from glc model @@ -157,7 +158,7 @@ subroutine elm_cpl_indices_set( ) ! ! !USES: use seq_flds_mod , only: seq_flds_x2l_fields, seq_flds_l2x_fields, & - lnd_rof_two_way, rof_sed + lnd_rof_two_way, ocn_lnd_one_way, rof_sed use mct_mod , only: mct_aVect, mct_aVect_init, mct_avect_indexra use mct_mod , only: mct_aVect_clean, mct_avect_nRattr use seq_drydep_mod , only: drydep_fields_token, lnd_drydep @@ -315,6 +316,9 @@ subroutine elm_cpl_indices_set( ) index_x2l_Sr_h2orof = mct_avect_indexra(x2l,'Sr_h2orof') index_x2l_Sr_frac_h2orof= mct_avect_indexra(x2l,'Sr_frac_h2orof') endif + if (ocn_lnd_one_way) then + index_x2l_So_frac_h2oocn= mct_avect_indexra(x2l,'So_frac_h2oocn') + endif !------------------------------------------------------------- ! glc coupling diff --git a/components/elm/src/cpl/lnd_comp_mct.F90 b/components/elm/src/cpl/lnd_comp_mct.F90 index 6b5a6dbe6b08..6bfabe91f1ed 100644 --- a/components/elm/src/cpl/lnd_comp_mct.F90 +++ b/components/elm/src/cpl/lnd_comp_mct.F90 @@ -90,10 +90,12 @@ subroutine lnd_init_mct( EClock, cdata_l, x2l_l, l2x_l, NLFilename ) seq_infodata_start_type_start, seq_infodata_start_type_cont, & seq_infodata_start_type_brnch use seq_comm_mct , only : seq_comm_suffix, seq_comm_inst, seq_comm_name - use seq_flds_mod , only : seq_flds_x2l_fields, seq_flds_l2x_fields, lnd_rof_two_way + use seq_flds_mod , only : seq_flds_x2l_fields, seq_flds_l2x_fields + use seq_flds_mod , only : lnd_rof_two_way, ocn_lnd_one_way use spmdMod , only : masterproc, npes, spmd_init - use elm_varctl , only : nsrStartup, nsrContinue, nsrBranch, use_lnd_rof_two_way + use elm_varctl , only : nsrStartup, nsrContinue, nsrBranch use elm_varctl , only: elm_varctl_set_iac_flag + use elm_varctl , only : use_lnd_rof_two_way, use_ocn_lnd_one_way use elm_cpl_indices , only : elm_cpl_indices_set use perf_mod , only : t_startf, t_stopf use mct_mod @@ -291,6 +293,8 @@ subroutine lnd_init_mct( EClock, cdata_l, x2l_l, l2x_l, NLFilename ) use_lnd_rof_two_way = lnd_rof_two_way + use_ocn_lnd_one_way = ocn_lnd_one_way + ! Read namelist, grid and surface data call initialize1( ) @@ -317,6 +321,7 @@ subroutine lnd_init_mct( EClock, cdata_l, x2l_l, l2x_l, NLFilename ) call get_proc_bounds( bounds ) call lnd_SetgsMap_mct( bounds, mpicom_lnd, LNDID, gsMap_lnd ) + lsz = mct_gsMap_lsize(gsMap_lnd, mpicom_lnd) call lnd_domain_mct( bounds, lsz, gsMap_lnd, dom_l ) @@ -378,7 +383,7 @@ subroutine lnd_init_mct( EClock, cdata_l, x2l_l, l2x_l, NLFilename ) ! Fill in infodata settings - call seq_infodata_PutData(infodata, lnd_prognostic=.true.) + call seq_infodata_PutData(infodata, lnd_prognostic=.true., lndocn_prognostic=use_ocn_lnd_one_way) call seq_infodata_PutData(infodata, lnd_nx=ldomain%ni, lnd_ny=ldomain%nj, precip_downscaling_method = precip_downscaling_method) #ifdef HAVE_MOAB @@ -435,7 +440,7 @@ subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l) ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use elm_instMod , only : lnd2atm_vars, atm2lnd_vars, lnd2glc_vars, glc2lnd_vars - use elm_instMod , only : lnd2iac_vars, iac2lnd_vars + use elm_instMod , only : lnd2iac_vars, iac2lnd_vars, ocn2lnd_vars use elm_driver , only : elm_drv use elm_time_manager, only : get_curr_date, get_nstep, get_curr_calday, get_step_size use elm_time_manager, only : advance_timestep, set_nextsw_cday,update_rad_dtime @@ -555,7 +560,7 @@ subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l) ! Map to elm (only when state and/or fluxes need to be updated) call t_startf ('lc_lnd_import') - call lnd_import( bounds, x2l_l%rattr, atm2lnd_vars, glc2lnd_vars, lnd2atm_vars, iac2lnd_vars) + call lnd_import( bounds, x2l_l%rattr, atm2lnd_vars, glc2lnd_vars, ocn2lnd_vars, lnd2atm_vars, iac2lnd_vars) #ifdef HAVE_MOAB ! calling MOAB's import last means this is what the model will use. call lnd_import_moab( EClock, bounds, atm2lnd_vars, glc2lnd_vars) diff --git a/components/elm/src/cpl/lnd_import_export.F90 b/components/elm/src/cpl/lnd_import_export.F90 index 75c6111da77f..1353b35ae1c5 100644 --- a/components/elm/src/cpl/lnd_import_export.F90 +++ b/components/elm/src/cpl/lnd_import_export.F90 @@ -11,6 +11,7 @@ module lnd_import_export use iac2lndMod , only: iac2lnd_type use elm_varctl , only: iac_present, iulog use elm_varpar , only: numpft, numharvest + use ocn2lndType , only: ocn2lnd_type use GridcellType , only: grc_pp ! for access to gridcell topology use TopounitDataType , only: top_as, top_af ! atmospheric state and flux variables use elm_cpl_indices @@ -23,8 +24,7 @@ module lnd_import_export contains !=============================================================================== - subroutine lnd_import( bounds, x2l, atm2lnd_vars, glc2lnd_vars, lnd2atm_vars, iac2lnd_vars) - + subroutine lnd_import( bounds, x2l, atm2lnd_vars, glc2lnd_vars, ocn2lnd_vars, lnd2atm_vars, iac2lnd_vars) !--------------------------------------------------------------------------- ! !DESCRIPTION: ! Convert the input data from the coupler to the land model @@ -53,6 +53,7 @@ subroutine lnd_import( bounds, x2l, atm2lnd_vars, glc2lnd_vars, lnd2atm_vars, ia real(r8) , intent(in) :: x2l(:,:) ! driver import state to land model type(atm2lnd_type) , intent(inout) :: atm2lnd_vars ! elm internal input data type type(glc2lnd_type) , intent(inout) :: glc2lnd_vars ! elm internal input data type + type(ocn2lnd_type) , intent(inout) :: ocn2lnd_vars type(lnd2atm_type) , intent(in) :: lnd2atm_vars type(iac2lnd_type) , intent(inout) :: iac2lnd_vars ! elm iac to land ! @@ -205,6 +206,10 @@ subroutine lnd_import( bounds, x2l, atm2lnd_vars, glc2lnd_vars, lnd2atm_vars, ia atm2lnd_vars%frac_h2orof_grc(g) = x2l(index_x2l_Sr_frac_h2orof,i) endif + if (index_x2l_So_frac_h2oocn /= 0) then + ocn2lnd_vars%frac_h2oocn_grc(g) = x2l(index_x2l_So_frac_h2oocn,i) + endif + ! Determine required receive fields #ifdef CPL_BYPASS diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index 3833186b2429..273458025a97 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -169,6 +169,7 @@ module ColumnDataType real(r8), pointer :: vsfm_soilp_col_1d (:) => null() ! 1D soil liquid pressure from VSFM [Pa] real(r8), pointer :: h2orof (:) => null() ! floodplain inundation volume received from rof (mm) real(r8), pointer :: frac_h2orof (:) => null() ! floodplain inundation fraction received from rof (-) + real(r8), pointer :: frac_h2oocn (:) => null() ! coastal inundation fraction received from ocn (-) ! polygonal tundra (NGEE Arctic IM1) real(r8), pointer :: iwp_microrel (:) => null() ! ice wedge polygon microtopographic relief (m) real(r8), pointer :: iwp_exclvol (:) => null() ! ice wedge polygon excluded volume (m) @@ -528,6 +529,7 @@ module ColumnDataType real(r8), pointer :: qflx_irr_demand (:) => null() ! col surface irrigation demand (mm H2O /s) real(r8), pointer :: qflx_over_supply (:) => null() ! col over supplied irrigation real(r8), pointer :: qflx_h2orof_drain (:) => null() ! drainage from floodplain inundation volume (mm H2O/s)) + real(r8), pointer :: qflx_h2oocn_drain (:) => null() ! drainage from coastal inundation volume (mm H2O/s) real(r8), pointer :: qflx_from_uphill (:) => null() ! input to top soil layer from uphill topounit(s) (mm H2O/s)) real(r8), pointer :: qflx_to_downhill (:) => null() ! output from column to the downhill topounit (mm H2O/s)) @@ -1461,6 +1463,7 @@ subroutine col_ws_init(this, begc, endc, h2osno_input, snow_depth_input, watsat_ allocate(this%vsfm_soilp_col_1d (ncells)) ; this%vsfm_soilp_col_1d (:) = spval allocate(this%h2orof (begc:endc)) ; this%h2orof (:) = spval allocate(this%frac_h2orof (begc:endc)) ; this%frac_h2orof (:) = spval + allocate(this%frac_h2oocn (begc:endc)) ; this%frac_h2oocn (:) = nan if (use_polygonal_tundra) then ! polygonal tundra/ice wedge polygons: allocate(this%iwp_microrel (begc:endc)) ; this%iwp_microrel (:) = spval @@ -1690,6 +1693,7 @@ subroutine col_ws_init(this, begc, endc, h2osno_input, snow_depth_input, watsat_ this%frac_h2osfc_act(c) = 0._r8 this%h2orof(c) = 0._r8 this%frac_h2orof(c) = 0._r8 + this%frac_h2oocn(c) = 0._r8 if (lun_pp%urbpoi(l)) then ! From Bonan 1996 (LSM technical note) @@ -5848,6 +5852,7 @@ subroutine col_wf_init(this, begc, endc) allocate(this%qflx_over_supply (begc:endc)) ; this%qflx_over_supply (:) = spval allocate(this%qflx_irr_demand (begc:endc)) ; this%qflx_irr_demand (:) = spval allocate(this%qflx_h2orof_drain (begc:endc)) ; this%qflx_h2orof_drain (:) = spval + allocate(this%qflx_h2oocn_drain (begc:endc)) ; this%qflx_h2oocn_drain (:) = spval allocate(this%qflx_from_uphill (begc:endc)) ; this%qflx_from_uphill (:) = spval allocate(this%qflx_to_downhill (begc:endc)) ; this%qflx_to_downhill (:) = spval @@ -6039,8 +6044,11 @@ subroutine col_wf_init(this, begc, endc) this%qflx_grnd_irrig(begc:endc) = 0._r8 this%qflx_over_supply(begc:endc) = 0._r8 this%qflx_h2orof_drain(begc:endc)= 0._r8 + this%qflx_h2oocn_drain(begc:endc)= 0._r8 + this%qflx_from_uphill(begc:endc) = 0._r8 this%qflx_to_downhill(begc:endc) = 0._r8 + ! needed for CNNLeaching do c = begc, endc l = col_pp%landunit(c) diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index edb50f316959..f21eb1ffd8e7 100755 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -1023,12 +1023,13 @@ subroutine control_spmd() ! land river two way coupling call mpi_bcast (use_lnd_rof_two_way , 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (lnd_rof_coupling_nstep, 1, MPI_INTEGER, 0, mpicom, ier) + ! ocean land one way coupling + call mpi_bcast (use_ocn_lnd_one_way , 1, MPI_LOGICAL, 0, mpicom, ier) !SNICAR-AD call mpi_bcast (snow_shape, len(snow_shape), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (snicar_atm_type, len(snicar_atm_type), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (use_dust_snow_internal_mixing, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (mpi_sync_nstep_freq, 1, MPI_INTEGER, 0, mpicom, ier) ! use modified infiltration scheme in surface water storage @@ -1320,6 +1321,9 @@ subroutine control_print () ! land river two way coupling write(iulog,*) ' use_lnd_rof_two_way = ', use_lnd_rof_two_way write(iulog,*) ' lnd_rof_coupling_nstep = ', lnd_rof_coupling_nstep + + write(iulog,*) ' use_ocn_lnd_one_way = ', use_ocn_lnd_one_way + write(iulog,*) ' mpi_sync_nstep_freq = ', mpi_sync_nstep_freq write(iulog,*) ' use_modified_infil = ', use_modified_infil diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 896095a12c92..78fd71fb9cdf 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -125,6 +125,7 @@ module elm_driver use elm_instMod , only : waterflux_vars use elm_instMod , only : waterstate_vars use elm_instMod , only : atm2lnd_vars + use elm_instMod , only : ocn2lnd_vars use elm_instMod , only : lnd2atm_vars use elm_instMod , only : glc2lnd_vars use elm_instMod , only : lnd2glc_vars @@ -906,8 +907,8 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) filter(nc)%num_urbanc, filter(nc)%urbanc, & filter(nc)%num_snowc, filter(nc)%snowc, & filter(nc)%num_nosnowc, filter(nc)%nosnowc,canopystate_vars, & - atm2lnd_vars, lnd2atm_vars, soilstate_vars, energyflux_vars, & - soilhydrology_vars, aerosol_vars ) + atm2lnd_vars, ocn2lnd_vars, lnd2atm_vars, soilstate_vars, & + energyflux_vars, soilhydrology_vars, aerosol_vars ) ! Calculate column-integrated aerosol masses, and ! mass concentrations for radiative calculations and output diff --git a/components/elm/src/main/elm_instMod.F90 b/components/elm/src/main/elm_instMod.F90 index 2ce43f15f4a9..dd133e23e7b7 100644 --- a/components/elm/src/main/elm_instMod.F90 +++ b/components/elm/src/main/elm_instMod.F90 @@ -43,6 +43,7 @@ module elm_instMod use VOCEmissionMod , only : vocemis_type use atm2lndType , only : atm2lnd_type use lnd2atmType , only : lnd2atm_type + use ocn2lndType , only : ocn2lnd_type use lnd2glcMod , only : lnd2glc_type use glc2lndMod , only : glc2lnd_type use glcDiagnosticsMod , only : glc_diagnostics_type @@ -121,6 +122,7 @@ module elm_instMod type(surfalb_type) :: surfalb_vars type(surfrad_type) :: surfrad_vars type(atm2lnd_type) :: atm2lnd_vars + type(ocn2lnd_type) :: ocn2lnd_vars type(glc2lnd_type) :: glc2lnd_vars type(lnd2atm_type) :: lnd2atm_vars type(lnd2glc_type) :: lnd2glc_vars @@ -393,6 +395,8 @@ subroutine elm_inst_biogeophys(bounds_proc) call atm2lnd_vars%Init( bounds_proc ) call lnd2atm_vars%Init( bounds_proc ) + call ocn2lnd_vars%Init( bounds_proc ) + ! Initialize glc2lnd and lnd2glc even if running without create_glacier_mec_landunit, ! because at least some variables (such as the icemask) are referred to in code that ! is executed even when running without glc_mec. diff --git a/components/elm/src/main/elm_varctl.F90 b/components/elm/src/main/elm_varctl.F90 index 66fb18bc23b2..317b15796edd 100644 --- a/components/elm/src/main/elm_varctl.F90 +++ b/components/elm/src/main/elm_varctl.F90 @@ -570,6 +570,11 @@ module elm_varctl !---------------------------------------------------------- logical, public :: use_lnd_rof_two_way = .false. integer, public :: lnd_rof_coupling_nstep = 0 + + !---------------------------------------------------------- + ! ocean land one way coupling + !---------------------------------------------------------- + logical, public :: use_ocn_lnd_one_way = .false. !---------------------------------------------------------- diff --git a/components/elm/src/main/ocn2lndType.F90 b/components/elm/src/main/ocn2lndType.F90 new file mode 100644 index 000000000000..c893de45ce19 --- /dev/null +++ b/components/elm/src/main/ocn2lndType.F90 @@ -0,0 +1,131 @@ +module ocn2lndType + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Handle ocn2lnd, lnd2ocn mapping + ! + ! !USES: + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_megan_mod , only : shr_megan_mechcomps_n + use elm_varpar , only : numrad, ndst, nlevgrnd !ndst = number of dust bins. + use elm_varcon , only : rair, grav, cpair, hfus, tfrz, spval + use elm_varctl , only : iulog + use seq_drydep_mod, only : n_drydep, drydep_method, DD_XLND + use decompMod , only : bounds_type + use abortutils , only : endrun + use seq_flds_mod , only : ocn_lnd_one_way + ! + ! !PUBLIC TYPES: + implicit none + private + save + ! + ! !PUBLIC DATA TYPES + !---------------------------------------------------- + ! ocean -> land variables structure + ! + type, public :: ocn2lnd_type + + real(r8), pointer :: frac_h2oocn_grc(:) => null() ! sea surface height [m] + + contains + + procedure, public :: Init + procedure, private :: InitAllocate + procedure, private :: InitHistory + procedure, public :: Restart + + end type ocn2lnd_type + + contains + + !------------------------------------------------------------------------ + subroutine Init(this, bounds) + + class(ocn2lnd_type) :: this + type(bounds_type), intent(in) :: bounds + + call this%InitAllocate(bounds) + call this%InitHistory(bounds) + + end subroutine Init + + !------------------------------------------------------------------------ + subroutine InitAllocate(this, bounds) + ! + ! !DESCRIPTION: + ! Initialize ocn2lnd derived type + ! + ! !ARGUMENTS: + class(ocn2lnd_type) :: this + type(bounds_type), intent(in) :: bounds + ! + ! !LOCAL VARIABLES: + real(r8) :: ival = 0.0_r8 ! initial value + real :: ival_float = 0.0 + integer :: ival_int = 0 + integer*2 :: ival_short = 0 + integer :: begg, endg + integer :: begc, endc + integer :: begp, endp + !------------------------------------------------------------------------ + + begg = bounds%begg; endg= bounds%endg + begc = bounds%begc; endc= bounds%endc + begp = bounds%begp; endp= bounds%endp + + allocate(this%frac_h2oocn_grc(begg:endg)); this%frac_h2oocn_grc(:) = ival + + end subroutine InitAllocate + + !------------------------------------------------------------------------ + subroutine InitHistory(this, bounds) + ! + ! !USES: + use histFileMod, only : hist_addfld1d + ! + ! !ARGUMENTS: + class(ocn2lnd_type) :: this + type(bounds_type), intent(in) :: bounds + ! + ! !LOCAL VARIABLES: + integer :: begg, endg + integer :: begp, endp + !--------------------------------------------------------------------- + + begg = bounds%begg; endg= bounds%endg + begp = bounds%begp; endp= bounds%endp + + if (ocn_lnd_one_way) then + this%frac_h2oocn_grc(begg:endg) = spval + call hist_addfld1d (fname='FRAC_H2OOCN', units='-' , & + avgflag='A', long_name='coastal inundation fraction', & + ptr_lnd=this%frac_h2oocn_grc) + endif + + end subroutine InitHistory + + !------------------------------------------------------------------------ + subroutine Restart(this, bounds, ncid, flag) + ! + ! !USES: + use restUtilMod + use ncdio_pio + ! + ! !ARGUMENTS: + class(ocn2lnd_type) :: this + type(bounds_type), intent(in) :: bounds + type(file_desc_t), intent(inout) :: ncid + character(len=*) , intent(in) :: flag + ! + ! !LOCAL VARIABLES: + logical :: readvar + !------------------------------------------------------------------------ + + ! TODO: do we need restart for ocean-land one way coupling? + + end subroutine Restart + +end module ocn2lndType \ No newline at end of file diff --git a/components/mpas-ocean/driver/mpaso_cpl_indices.F b/components/mpas-ocean/driver/mpaso_cpl_indices.F index d0732ce9a9b3..de86b439c2ea 100644 --- a/components/mpas-ocean/driver/mpaso_cpl_indices.F +++ b/components/mpas-ocean/driver/mpaso_cpl_indices.F @@ -26,6 +26,7 @@ module mpaso_cpl_indices integer :: index_o2x_Faoo_fco2_ocn integer :: index_o2x_Faoo_fdms_ocn integer :: index_o2x_So_ssh + integer :: index_o2x_So_frac_h2oocn integer :: index_o2x_Foxo_ismw integer :: index_o2x_Foxo_rrofl integer :: index_o2x_Foxo_rrofi @@ -219,6 +220,9 @@ subroutine mpaso_cpl_indices_set( ) index_o2x_Faoo_fco2_ocn = mct_avect_indexra(o2x,'Faoo_fco2_ocn',perrWith='quiet') index_o2x_Faoo_fdms_ocn = mct_avect_indexra(o2x,'Faoo_fdms_ocn',perrWith='quiet') index_o2x_So_ssh = mct_avect_indexra(o2x,'So_ssh') + if (ocn_lnd_one_way) then + index_o2x_So_frac_h2oocn= mct_avect_indexra(o2x,'So_ssh') + endif index_o2x_Foxo_ismw = mct_avect_indexra(o2x,'Foxo_ismw',perrWith='quiet') index_o2x_Foxo_rrofl = mct_avect_indexra(o2x,'Foxo_rrofl',perrWith='quiet') diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 2e2dfbcd823f..d5831ee20717 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -274,6 +274,10 @@ def write_seq_maps_file(case, nmlgen, confdir): if "rof2ocn_" in name: if case.get_value("COMP_OCN") == 'docn': logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) + elif "ocn2lnd_" in name: + logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) + elif "lnd2ocn_" in name: + logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) else: expect(gridvalue[component1] == gridvalue[component2], "Need to provide valid mapping file between {} and {} in xml variable {} ".\ diff --git a/driver-mct/cime_config/config_component.xml b/driver-mct/cime_config/config_component.xml index 75469c5babd6..bd37ac940fac 100644 --- a/driver-mct/cime_config/config_component.xml +++ b/driver-mct/cime_config/config_component.xml @@ -2156,6 +2156,74 @@ iac2lnd state mapping file decomp type + + char + idmap + run_domain + env_run.xml + ocn2lnd state mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2lnd state mapping file decomp type + + + + char + idmap + run_domain + env_run.xml + ocn2lnd flux mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2lnd flux mapping file decomp type + + + + char + idmap + run_domain + env_run.xml + lnd2ocn state mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + lnd2ocn state mapping file decomp type + + + + char + idmap + run_domain + env_run.xml + lnd2ocn flux mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + lnd2ocn flux mapping file decomp type + + char none,npfix,cart3d,cart3d_diag,cart3d_uvw,cart3d_uvw_diag diff --git a/driver-mct/cime_config/namelist_definition_drv.xml b/driver-mct/cime_config/namelist_definition_drv.xml index 43e6f0c2d9e5..aedfe9bb1b21 100644 --- a/driver-mct/cime_config/namelist_definition_drv.xml +++ b/driver-mct/cime_config/namelist_definition_drv.xml @@ -302,6 +302,18 @@ + + logical + seq_flds + seq_cplflds_inparm + + If set to .true., adds fields needed to calculate ocean-land one-way coupling + + + .false. + + + logical seq_flds @@ -358,6 +370,7 @@ .false. + @@ -5381,6 +5394,126 @@ + + char + mapping + abs + seq_maps + + ocn to lnd mapping file for states + + + $OCN2LND_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $OCN2LND_SMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to rof mapping file for fluxes + + + $OCN2LND_FMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $OCN2LND_FMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to rof mapping file for states + + + $LND2OCN_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $LND2OCN_SMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to rof mapping file for fluxes + + + $LND2OCN_FMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $LND2OCN_FMAPTYPE + X + + + logical data_assimilation diff --git a/driver-mct/main/cime_comp_mod.F90 b/driver-mct/main/cime_comp_mod.F90 index 4d177e4c4d5f..becb4026feeb 100644 --- a/driver-mct/main/cime_comp_mod.F90 +++ b/driver-mct/main/cime_comp_mod.F90 @@ -418,6 +418,7 @@ module cime_comp_mod logical :: atm_prognostic ! .true. => atm comp expects input logical :: lnd_prognostic ! .true. => lnd comp expects input + logical :: lndocn_prognostic ! .ture. => lnd comp expects ocean inputs logical :: ice_prognostic ! .true. => ice comp expects input logical :: iceberg_prognostic ! .true. => ice comp can handle iceberg input logical :: ocn_prognostic ! .true. => ocn comp expects input @@ -445,6 +446,7 @@ module cime_comp_mod logical :: ocn_c2_glcshelf ! .true. => ocn to glc ice shelf coupling on logical :: ocn_c2_wav ! .true. => ocn to wav coupling on logical :: ocn_c2_rof ! .true. => ocn to rof coupling on + logical :: ocn_c2_lnd ! .true. => ocn to lnd coupling on logical :: ice_c2_atm ! .true. => ice to atm coupling on logical :: ice_c2_ocn ! .true. => ice to ocn coupling on logical :: ice_c2_wav ! .true. => ice to wav coupling on @@ -1690,6 +1692,7 @@ subroutine cime_init() flood_present=flood_present, & atm_prognostic=atm_prognostic, & lnd_prognostic=lnd_prognostic, & + lndocn_prognostic=lndocn_prognostic, & ice_prognostic=ice_prognostic, & iceberg_prognostic=iceberg_prognostic, & ocn_prognostic=ocn_prognostic, & @@ -1767,6 +1770,7 @@ subroutine cime_init() ocn_c2_ice = .false. ocn_c2_wav = .false. ocn_c2_rof = .false. + ocn_c2_lnd = .false. ice_c2_atm = .false. ice_c2_ocn = .false. ice_c2_wav = .false. @@ -1805,7 +1809,7 @@ subroutine cime_init() if (glc_prognostic .and. (glc_nzoc > 0)) ocn_c2_glctf = .true. if (wav_prognostic) ocn_c2_wav = .true. if (rofocn_prognostic) ocn_c2_rof = .true. - + if (lndocn_prognostic) ocn_c2_lnd = .true. endif if (ice_present) then if (atm_prognostic) ice_c2_atm = .true. @@ -1882,6 +1886,7 @@ subroutine cime_init() write(logunit,F0L)'atm model prognostic = ',atm_prognostic write(logunit,F0L)'lnd model prognostic = ',lnd_prognostic write(logunit,F0L)'ocn model prognostic = ',ocn_prognostic + write(logunit,F0L)'lnd ocn prognostic = ',lndocn_prognostic write(logunit,F0L)'ice model prognostic = ',ice_prognostic write(logunit,F0L)'iceberg prognostic = ',iceberg_prognostic write(logunit,F0L)'glc model prognostic = ',glc_prognostic @@ -1907,6 +1912,7 @@ subroutine cime_init() write(logunit,F0L)'ocn_c2_ice = ',ocn_c2_ice write(logunit,F0L)'ocn_c2_wav = ',ocn_c2_wav write(logunit,F0L)'ocn_c2_rof = ',ocn_c2_rof + write(logunit,F0L)'ocn_c2_lnd = ',ocn_c2_lnd write(logunit,F0L)'ice_c2_atm = ',ice_c2_atm write(logunit,F0L)'ice_c2_ocn = ',ice_c2_ocn write(logunit,F0L)'ice_c2_wav = ',ice_c2_wav @@ -2008,6 +2014,12 @@ subroutine cime_init() call shr_sys_flush(logunit) endif endif + if (lndocn_prognostic .and. .not.ocn_present) then + if (iamroot_CPLID) then + write(logunit,F00) 'WARNING: lndocn_prognostic is TRUE but ocn_present is FALSE' + call shr_sys_flush(logunit) + endif + endif !---------------------------------------------------------- !| Samegrid checks @@ -2051,7 +2063,7 @@ subroutine cime_init() call prep_atm_init(infodata, ocn_c2_atm, ice_c2_atm, lnd_c2_atm, iac_c2_lnd, wav_c2_atm) - call prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_lnd) + call prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_lnd, ocn_c2_lnd) call prep_ocn_init(infodata, atm_c2_ocn, atm_c2_ice, ice_c2_ocn, rof_c2_ocn, wav_c2_ocn, glc_c2_ocn, glcshelf_c2_ocn) @@ -4111,6 +4123,8 @@ subroutine cime_run_ocn_recv_post() if (ocn_c2_rof) call prep_rof_accum_ocn(timer='CPL:ocnpost_acco2r') + if (ocn_c2_lnd) call prep_lnd_accum_ocn(timer='CPL:ocnpost_acco2l') + call cime_run_ocnglc_coupling() if (drv_threading) call seq_comm_setnthreads(nthreads_GLOID) @@ -4326,6 +4340,11 @@ subroutine cime_run_lnd_setup_send() call prep_lnd_calc_z2x_lx(timer='CPL:lndprep_iac2lnd') endif + if (ocn_c2_lnd) then + call prep_lnd_accum_avg(timer='CPL:lndprep_o2xavg') + call prep_lnd_calc_o2x_lx(timer='CPL:lndprep_ocn2lnd') + endif + if (lnd_prognostic) then call prep_lnd_mrg(infodata, timer_mrg='CPL:lndprep_mrgx2l') diff --git a/driver-mct/main/prep_lnd_mod.F90 b/driver-mct/main/prep_lnd_mod.F90 index 0a99878a172b..32f94515ec8f 100644 --- a/driver-mct/main/prep_lnd_mod.F90 +++ b/driver-mct/main/prep_lnd_mod.F90 @@ -6,7 +6,7 @@ module prep_lnd_mod use shr_kind_mod , only: cxx => SHR_KIND_CXX use shr_sys_mod , only: shr_sys_abort, shr_sys_flush use seq_comm_mct , only: num_inst_atm, num_inst_rof, num_inst_glc, num_inst_iac - use seq_comm_mct , only: num_inst_lnd, num_inst_frc + use seq_comm_mct , only: num_inst_lnd, num_inst_frc, num_inst_ocn use seq_comm_mct , only: CPLID, LNDID, logunit use seq_comm_mct , only: seq_comm_getData=>seq_comm_setptrs use seq_infodata_mod, only: seq_infodata_type, seq_infodata_getdata @@ -17,7 +17,7 @@ module prep_lnd_mod use mct_mod use perf_mod use component_type_mod, only: component_get_x2c_cx, component_get_c2x_cx - use component_type_mod, only: lnd, atm, rof, glc, iac + use component_type_mod, only: lnd, atm, rof, glc, iac, ocn use map_glc2lnd_mod , only: map_glc2lnd_ec implicit none @@ -31,10 +31,14 @@ module prep_lnd_mod public :: prep_lnd_init public :: prep_lnd_mrg + public :: prep_lnd_accum_ocn + public :: prep_lnd_accum_avg + public :: prep_lnd_calc_a2x_lx public :: prep_lnd_calc_r2x_lx public :: prep_lnd_calc_g2x_lx public :: prep_lnd_calc_z2x_lx + public :: prep_lnd_calc_o2x_lx public :: prep_lnd_get_a2x_lx public :: prep_lnd_get_r2x_lx @@ -65,13 +69,21 @@ module prep_lnd_mod type(seq_map), pointer :: mapper_Fr2l ! needed in seq_frac_mct.F90 type(seq_map), pointer :: mapper_Sg2l ! currently unused (all g2l mappings use the flux mapper) type(seq_map), pointer :: mapper_Fg2l - type(seq_map), pointer :: mapper_Sz2l + type(seq_map), pointer :: mapper_Sz2l + type(seq_map), pointer :: mapper_So2l + type(seq_map), pointer :: mapper_Fo2l + ! attribute vectors type(mct_aVect), pointer :: a2x_lx(:) ! Atm export, lnd grid, cpl pes - allocated in driver type(mct_aVect), pointer :: r2x_lx(:) ! Rof export, lnd grid, lnd pes - allocated in lnd gc type(mct_aVect), pointer :: g2x_lx(:) ! Glc export, lnd grid, cpl pes - allocated in driver type(mct_aVect), pointer :: z2x_lx(:) ! Iac export, lnd grid, cpl pes - allocated in driver + type(mct_aVect), pointer :: o2x_lx(:) ! Ocn export, lnd grid, cpl pes - allocated in + + ! accumulation variables + type(mct_aVect), pointer :: o2lacc_ox(:) ! Ocn export, ocn grid, cpl pes + integer , target :: o2lacc_ox_cnt ! o2lacc_ox: number of time samples accumulated ! seq_comm_getData variables integer :: mpicom_CPLID ! MPI cpl communicator @@ -91,7 +103,7 @@ module prep_lnd_mod !================================================================================================ - subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_lnd) + subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_lnd, ocn_c2_lnd) !--------------------------------------------------------------- ! Description @@ -104,24 +116,30 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln logical , intent(in) :: rof_c2_lnd ! .true. => rof to lnd coupling on logical , intent(in) :: glc_c2_lnd ! .true. => glc to lnd coupling on logical , intent(in) :: iac_c2_lnd ! .true. => iac to lnd coupling on + logical , intent(in) :: ocn_c2_lnd ! .true. => ocn to lnd coupling on ! ! Local Variables - integer :: lsize_l - integer :: eai, eri, egi, ezi + integer :: lsize_l, lsize_o + integer :: eai, eri, egi, ezi, eoi logical :: samegrid_al ! samegrid atm and land logical :: samegrid_lr ! samegrid land and rof logical :: samegrid_lg ! samegrid land and glc logical :: samegrid_lz ! samegrid land and iac + logical :: samegrid_ol ! samegrid ocn and land logical :: esmf_map_flag ! .true. => use esmf for mapping logical :: lnd_present ! .true. => land is present logical :: iac_present ! .true. => iac is present + logical :: ocn_present ! .true. => ocean is present logical :: iamroot_CPLID ! .true. => CPLID masterproc character(CL) :: atm_gnam ! atm grid character(CL) :: lnd_gnam ! lnd grid character(CL) :: rof_gnam ! rof grid character(CL) :: glc_gnam ! glc grid character(CL) :: iac_gnam ! iac grid + character(CL) :: ocn_gnam ! ocn grid type(mct_avect), pointer :: l2x_lx + type(mct_avect), pointer :: o2x_ox + type(mct_avect), pointer :: x2l_lx character(*), parameter :: subname = '(prep_lnd_init)' character(*), parameter :: F00 = "('"//subname//" : ', 4A )" !--------------------------------------------------------------- @@ -132,6 +150,8 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln iac_present=iac_present, & atm_gnam=atm_gnam, & lnd_gnam=lnd_gnam, & + ocn_present=ocn_present, & + ocn_gnam=ocn_gnam, & rof_gnam=rof_gnam, & glc_gnam=glc_gnam, & iac_gnam=iac_gnam) @@ -142,6 +162,8 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln allocate(mapper_Sg2l) allocate(mapper_Fg2l) allocate(mapper_Sz2l) + allocate(mapper_So2l) + allocate(mapper_Fo2l) if (lnd_present) then @@ -176,6 +198,45 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln end do ! end if + if (ocn_present) then + o2x_ox => component_get_c2x_cx(ocn(1)) + x2l_lx => component_get_x2c_cx(lnd(1)) + lsize_o = mct_aVect_lsize(o2x_ox) + allocate(o2lacc_ox(num_inst_ocn)) + do eoi = 1,num_inst_ocn + call mct_aVect_initSharedFields(o2x_ox, x2l_lx, o2lacc_ox(eoi), lsize=lsize_o) + call mct_aVect_zero(o2lacc_ox(eoi)) + end do + o2lacc_ox_cnt = 0 + + allocate(o2x_lx(num_inst_ocn)) + do eoi = 1,num_inst_ocn + call mct_aVect_init(o2x_lx(eoi), rlist=seq_flds_o2x_fields_to_lnd, lsize=lsize_l) + call mct_aVect_zero(o2x_lx(eoi)) + end do + + samegrid_ol = .true. + if (trim(ocn_gnam) /= trim(lnd_gnam)) samegrid_ol = .false. + + if (ocn_c2_lnd) then + if (iamroot_CPLID) then + write(logunit,*) ' ' + write(logunit,F00) 'Initializing mapper_So2l' + end if + call seq_map_init_rcfile(mapper_So2l, ocn(1), lnd(1), & + 'seq_maps.rc','ocn2lnd_smapname:','ocn2lnd_smaptype:',samegrid_ol, & + string='mapper_So2l initialization', esmf_map=esmf_map_flag) + + call seq_map_init_rcfile(mapper_Fo2l, ocn(1), lnd(1), & + 'seq_maps.rc','ocn2lnd_fmapname:','ocn2lnd_fmaptype:',samegrid_ol, & + string='mapper_Fo2l initialization', esmf_map=esmf_map_flag) + + endif + + call shr_sys_flush(logunit) + + endif + samegrid_al = .true. samegrid_lr = .true. samegrid_lg = .true. @@ -305,7 +366,7 @@ subroutine prep_lnd_mrg(infodata, timer_mrg) character(len=*) , intent(in) :: timer_mrg ! ! Local Variables - integer :: eai, eri, egi, eli, ezi + integer :: eai, eri, egi, eli, ezi, eoi type(mct_aVect), pointer :: x2l_lx character(*), parameter :: subname = '(prep_lnd_mrg)' !--------------------------------------------------------------- @@ -317,9 +378,10 @@ subroutine prep_lnd_mrg(infodata, timer_mrg) eri = mod((eli-1),num_inst_rof) + 1 egi = mod((eli-1),num_inst_glc) + 1 ezi = mod((eli-1),num_inst_iac) + 1 + eoi = mod((eli-1),num_inst_ocn) + 1 x2l_lx => component_get_x2c_cx(lnd(eli)) ! This is actually modifying x2l_lx - call prep_lnd_merge( a2x_lx(eai), r2x_lx(eri), g2x_lx(egi), z2x_lx(ezi), x2l_lx ) + call prep_lnd_merge( a2x_lx(eai), r2x_lx(eri), g2x_lx(egi), z2x_lx(ezi), o2x_lx(eoi), x2l_lx ) enddo call t_drvstopf (trim(timer_mrg)) @@ -327,7 +389,7 @@ end subroutine prep_lnd_mrg !================================================================================================ - subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, x2l_l ) + subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, o2x_l, x2l_l ) !--------------------------------------------------------------- ! Description ! Create input land state directly from atm, runoff and glc outputs @@ -337,6 +399,7 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, x2l_l ) type(mct_aVect), intent(in) :: r2x_l type(mct_aVect), intent(in) :: g2x_l type(mct_aVect), intent(in) :: z2x_l + type(mct_aVect), intent(in) :: o2x_l type(mct_aVect), intent(inout) :: x2l_l !----------------------------------------------------------------------- integer :: nflds,i,i1,o1 @@ -348,6 +411,7 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, x2l_l ) type(mct_aVect_sharedindices),save :: r2x_sharedindices type(mct_aVect_sharedindices),save :: g2x_sharedindices type(mct_aVect_sharedindices),save :: z2x_sharedindices + type(mct_aVect_sharedindices),save :: o2x_sharedindices character(*), parameter :: subname = '(prep_lnd_merge) ' !----------------------------------------------------------------------- @@ -367,6 +431,7 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, x2l_l ) call mct_aVect_setSharedIndices(r2x_l, x2l_l, r2x_SharedIndices) call mct_aVect_setSharedIndices(g2x_l, x2l_l, g2x_SharedIndices) call mct_aVect_setSharedIndices(z2x_l, x2l_l, z2x_SharedIndices) + call mct_aVect_setSharedIndices(o2x_l, x2l_l, o2x_SharedIndices) !--- document copy operations --- do i=1,a2x_SharedIndices%shared_real%num_indices @@ -387,11 +452,19 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, x2l_l ) field = mct_aVect_getRList2c(i1, g2x_l) mrgstr(o1) = trim(mrgstr(o1))//' = g2x%'//trim(field) enddo + do i=1,z2x_SharedIndices%shared_real%num_indices i1=z2x_SharedIndices%shared_real%aVindices1(i) o1=z2x_SharedIndices%shared_real%aVindices2(i) field = mct_aVect_getRList2c(i1, z2x_l) mrgstr(o1) = trim(mrgstr(o1))//' = z2x%'//trim(field) + enddo + + do i=1,o2x_SharedIndices%shared_real%num_indices + i1=o2x_SharedIndices%shared_real%aVindices1(i) + o1=o2x_SharedIndices%shared_real%aVindices2(i) + field = mct_aVect_getRList2c(i1, o2x_l) + mrgstr(o1) = trim(mrgstr(o1))//' = o2x%'//trim(field) enddo endif @@ -399,6 +472,7 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, x2l_l ) call mct_aVect_copy(aVin=r2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=r2x_SharedIndices) call mct_aVect_copy(aVin=g2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=g2x_SharedIndices) call mct_aVect_copy(aVin=z2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=z2x_SharedIndices) + call mct_aVect_copy(aVin=o2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=o2x_SharedIndices) if (first_time) then if (iamroot) then @@ -546,6 +620,91 @@ end subroutine prep_lnd_calc_z2x_lx !================================================================================================ + subroutine prep_lnd_calc_o2x_lx(timer) + !--------------------------------------------------------------- + ! Description + ! Create o2x_lx (note that 2x_lx is a local module variable) + ! + ! Arguments + character(len=*), intent(in) :: timer + ! + ! Local Variables + integer :: eli, eoi + type(mct_avect), pointer :: l2x_lx + character(*), parameter :: subname = '(prep_lnd_calc_o2x_lx)' + !--------------------------------------------------------------- + + call t_drvstartf (trim(timer),barrier=mpicom_CPLID) + do eli = 1,num_inst_lnd + eoi = mod((eli-1),num_inst_ocn) + 1 + l2x_lx => component_get_c2x_cx(lnd(eli)) + call seq_map_map(mapper_So2l, o2lacc_ox(eoi), o2x_lx(eli), fldlist=seq_flds_o2x_states_to_lnd, norm=.true.) + end do + call t_drvstopf (trim(timer)) + + end subroutine prep_lnd_calc_o2x_lx + + !================================================================================================ + + subroutine prep_lnd_accum_ocn(timer) + !--------------------------------------------------------------- + ! Description + ! Accumulate ocean input to land component + ! + ! Arguments + character(len=*), intent(in) :: timer + ! + ! Local Variables + integer :: eoi + type(mct_aVect), pointer :: o2x_ox + character(*), parameter :: subname = '(prep_lnd_accum_ocn)' + !--------------------------------------------------------------- + + call t_drvstartf (trim(timer),barrier=mpicom_CPLID) + + do eoi = 1,num_inst_ocn + o2x_ox => component_get_c2x_cx(ocn(eoi)) + if (o2lacc_ox_cnt == 0) then + call mct_avect_copy(o2x_ox, o2lacc_ox(eoi)) + else + call mct_avect_accum(o2x_ox, o2lacc_ox(eoi)) + endif + end do + o2lacc_ox_cnt = o2lacc_ox_cnt + 1 + + call t_drvstopf (trim(timer)) + end subroutine prep_lnd_accum_ocn + + !================================================================================================ + + subroutine prep_lnd_accum_avg(timer) + !--------------------------------------------------------------- + ! Description + ! Finalize accumulation of ocean input to land component + ! + ! Arguments + character(len=*), intent(in) :: timer + ! + ! Local Variables + integer :: eli, eoi + character(*), parameter :: subname = '(prep_lnd_accum_avg)' + !--------------------------------------------------------------- + + call t_drvstartf (trim(timer),barrier=mpicom_CPLID) + if(o2lacc_ox_cnt > 1) then + do eli = 1,num_inst_lnd + eoi = mod((eli-1),num_inst_ocn) + 1 + call mct_avect_avg(o2lacc_ox(eoi),o2lacc_ox_cnt) + enddo + endif + o2lacc_ox_cnt = 0 + + call t_drvstopf (trim(timer)) + + end subroutine prep_lnd_accum_avg + + !================================================================================================ + function prep_lnd_get_a2x_lx() type(mct_aVect), pointer :: prep_lnd_get_a2x_lx(:) prep_lnd_get_a2x_lx => a2x_lx(:) diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 5004fd554b6c..ec838ce3de43 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -161,6 +161,7 @@ module seq_flds_mod logical :: rof2ocn_nutrients ! .true. if the runoff model passes nutrient fields to the ocn logical :: lnd_rof_two_way ! .true. if land-river two-way coupling turned on logical :: ocn_rof_two_way ! .true. if river-ocean two-way coupling turned on + logical :: ocn_lnd_one_way ! .true. if ocean to land one-way coupling turned on logical :: rof_sed ! .true. if river model includes sediment logical :: add_iac_to_cplstate ! .true. if iac fields are added to coupler history files character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on @@ -207,6 +208,8 @@ module seq_flds_mod character(CXX) :: seq_flds_x2o_fluxes character(CXX) :: seq_flds_o2x_states_to_rof character(CXX) :: seq_flds_o2x_fluxes_to_rof + character(CXX) :: seq_flds_o2x_states_to_lnd + character(CXX) :: seq_flds_o2x_fluxes_to_lnd character(CXX) :: seq_flds_g2x_states character(CXX) :: seq_flds_g2x_states_to_lnd @@ -270,6 +273,7 @@ module seq_flds_mod character(CXX) :: seq_flds_o2x_fields_to_rof character(CXX) :: seq_flds_z2x_fields character(CXX) :: seq_flds_x2z_fields + character(CXX) :: seq_flds_o2x_fields_to_lnd !---------------------------------------------------------------------------- ! component names @@ -346,6 +350,8 @@ subroutine seq_flds_set(nmlfile, ID, infodata) character(CXX) :: o2x_fluxes = '' character(CXX) :: o2x_states_to_rof = '' character(CXX) :: o2x_fluxes_to_rof = '' + character(CXX) :: o2x_states_to_lnd = '' + character(CXX) :: o2x_fluxes_to_lnd = '' character(CXX) :: x2o_states = '' character(CXX) :: x2o_fluxes = '' character(CXX) :: g2x_states = '' @@ -410,7 +416,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) flds_co2a, flds_co2b, flds_co2c, flds_co2_dmsa, flds_wiso, flds_polar, flds_tf, & glc_nec, glc_nzoc, ice_ncat, seq_flds_i2o_per_cat, flds_bgc_oi, & nan_check_component_fields, rof_heat, atm_flux_method, atm_gustiness, & - rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, rof_sed, & + rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, ocn_lnd_one_way, rof_sed, & wav_ocn_coup, wav_atm_coup, wav_ice_coup, add_iac_to_cplstate ! user specified new fields @@ -455,6 +461,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) rof2ocn_nutrients = .false. lnd_rof_two_way = .false. ocn_rof_two_way = .false. + ocn_lnd_one_way = .false. rof_sed = .false. wav_ocn_coup = 'none' wav_atm_coup = 'none' @@ -495,6 +502,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call shr_mpi_bcast(rof2ocn_nutrients, mpicom) call shr_mpi_bcast(lnd_rof_two_way, mpicom) call shr_mpi_bcast(ocn_rof_two_way, mpicom) + call shr_mpi_bcast(ocn_lnd_one_way, mpicom) call shr_mpi_bcast(rof_sed, mpicom) call shr_mpi_bcast(wav_ocn_coup, mpicom) call shr_mpi_bcast(wav_atm_coup, mpicom) @@ -1780,6 +1788,15 @@ subroutine seq_flds_set(nmlfile, ID, infodata) attname = 'So_ssh' call metadata_set(attname, longname, stdname, units) + call seq_flds_add(o2x_states,"So_frac_h2oocn") + call seq_flds_add(x2l_states,"So_frac_h2oocn") + call seq_flds_add(o2x_states_to_lnd,"So_frac_h2oocn") + longname = 'Oceanic inundation fraction' + stdname = 'oceanic_inundation_fraction' + units = '-' + attname = 'So_frac_h2oocn' + call metadata_set(attname, longname, stdname, units) + ! Meridional sea surface slope call seq_flds_add(o2x_states,"So_dhdy") call seq_flds_add(x2i_states,"So_dhdy") @@ -4233,6 +4250,8 @@ subroutine seq_flds_set(nmlfile, ID, infodata) seq_flds_r2o_ice_fluxes = trim(r2o_ice_fluxes) seq_flds_o2x_states_to_rof = trim(o2x_states_to_rof) seq_flds_o2x_fluxes_to_rof = trim(o2x_fluxes_to_rof) + seq_flds_o2x_states_to_lnd = trim(o2x_states_to_lnd) + seq_flds_o2x_fluxes_to_lnd = trim(o2x_fluxes_to_lnd) if (seq_comm_iamroot(ID)) then write(logunit,*) subname//': seq_flds_a2x_states= ',trim(seq_flds_a2x_states) @@ -4288,6 +4307,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) write(logunit,*) subname//': seq_flds_z2x_fluxes= ',trim(seq_flds_z2x_fluxes) write(logunit,*) subname//': seq_flds_x2z_states= ',trim(seq_flds_x2z_states) write(logunit,*) subname//': seq_flds_x2z_fluxes= ',trim(seq_flds_x2z_fluxes) + write(logunit,*) subname//': seq_flds_o2x_states_to_lnd=',trim(seq_flds_o2x_states_to_lnd) end if call catFields(seq_flds_dom_fields, seq_flds_dom_coord , seq_flds_dom_other ) @@ -4315,6 +4335,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call catFields(seq_flds_o2x_fields_to_rof, seq_flds_o2x_states_to_rof, seq_flds_o2x_fluxes_to_rof) call catFields(seq_flds_z2x_fields, seq_flds_z2x_states, seq_flds_z2x_fluxes) call catFields(seq_flds_x2z_fields, seq_flds_x2z_states, seq_flds_x2z_fluxes) + call catFields(seq_flds_o2x_fields_to_lnd, seq_flds_o2x_states_to_lnd, seq_flds_o2x_fluxes_to_lnd) end subroutine seq_flds_set diff --git a/driver-mct/shr/seq_infodata_mod.F90 b/driver-mct/shr/seq_infodata_mod.F90 index 545d543d451c..26b58dd8e37a 100644 --- a/driver-mct/shr/seq_infodata_mod.F90 +++ b/driver-mct/shr/seq_infodata_mod.F90 @@ -200,6 +200,7 @@ MODULE seq_infodata_mod logical :: rofice_present ! does rof have iceberg coupling on logical :: rof_prognostic ! does rof component need input data logical :: rofocn_prognostic ! does component need ocn data + logical :: lndocn_prognostic ! does component need ocn data logical :: flood_present ! does rof have flooding on logical :: ocn_present ! does component model exist logical :: ocn_prognostic ! does component model need input data from driver @@ -773,6 +774,7 @@ SUBROUTINE seq_infodata_Init( infodata, nmlfile, ID, pioid, cpl_tag) infodata%lnd_prognostic = .false. infodata%rof_prognostic = .false. infodata%rofocn_prognostic = .false. + infodata%lndocn_prognostic = .false. infodata%ocn_prognostic = .false. infodata%ocnrof_prognostic = .false. infodata%ocn_c2_glcshelf = .false. @@ -1018,7 +1020,7 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ single_column, scmlat,scmlon,logFilePostFix, outPathRoot,& scm_multcols, scm_nx, scm_ny, & atm_present, atm_prognostic, & - lnd_present, lnd_prognostic, & + lnd_present, lnd_prognostic, lndocn_prognostic, & rof_present, rof_prognostic, rofocn_prognostic, & ocn_present, ocn_prognostic, ocnrof_prognostic, & ocn_c2_glcshelf, ocn_c2_glctf, & @@ -1190,6 +1192,7 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ logical, optional, intent(OUT) :: atm_prognostic ! need data logical, optional, intent(OUT) :: lnd_present logical, optional, intent(OUT) :: lnd_prognostic + logical, optional, intent(OUT) :: lndocn_prognostic logical, optional, intent(OUT) :: rof_present logical, optional, intent(OUT) :: rofice_present logical, optional, intent(OUT) :: rof_prognostic @@ -1381,6 +1384,7 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ if ( present(atm_prognostic) ) atm_prognostic = infodata%atm_prognostic if ( present(lnd_present) ) lnd_present = infodata%lnd_present if ( present(lnd_prognostic) ) lnd_prognostic = infodata%lnd_prognostic + if ( present(lndocn_prognostic) ) lndocn_prognostic = infodata%lndocn_prognostic if ( present(rof_present) ) rof_present = infodata%rof_present if ( present(rofice_present) ) rofice_present = infodata%rofice_present if ( present(rof_prognostic) ) rof_prognostic = infodata%rof_prognostic @@ -1583,7 +1587,7 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ single_column, scmlat,scmlon,logFilePostFix, outPathRoot, & scm_multcols, scm_nx, scm_ny, & atm_present, atm_prognostic, & - lnd_present, lnd_prognostic, & + lnd_present, lnd_prognostic, lndocn_prognostic, & rof_present, rof_prognostic, rofocn_prognostic, & ocn_present, ocn_prognostic, ocnrof_prognostic, & ocn_c2_glcshelf, ocn_c2_glctf, & @@ -1755,6 +1759,7 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ logical, optional, intent(IN) :: atm_prognostic ! need data logical, optional, intent(IN) :: lnd_present logical, optional, intent(IN) :: lnd_prognostic + logical, optional, intent(IN) :: lndocn_prognostic logical, optional, intent(IN) :: rof_present logical, optional, intent(IN) :: rofice_present logical, optional, intent(IN) :: rof_prognostic @@ -1945,6 +1950,7 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ if ( present(atm_prognostic) ) infodata%atm_prognostic = atm_prognostic if ( present(lnd_present) ) infodata%lnd_present = lnd_present if ( present(lnd_prognostic) ) infodata%lnd_prognostic = lnd_prognostic + if ( present(lndocn_prognostic) ) infodata%lndocn_prognostic = lndocn_prognostic if ( present(rof_present) ) infodata%rof_present = rof_present if ( present(rofice_present) ) infodata%rofice_present = rofice_present if ( present(rof_prognostic) ) infodata%rof_prognostic = rof_prognostic @@ -2262,6 +2268,7 @@ subroutine seq_infodata_bcast(infodata,mpicom) call shr_mpi_bcast(infodata%atm_prognostic, mpicom) call shr_mpi_bcast(infodata%lnd_present, mpicom) call shr_mpi_bcast(infodata%lnd_prognostic, mpicom) + call shr_mpi_bcast(infodata%lndocn_prognostic, mpicom) call shr_mpi_bcast(infodata%rof_present, mpicom) call shr_mpi_bcast(infodata%rofice_present, mpicom) call shr_mpi_bcast(infodata%rof_prognostic, mpicom) @@ -2533,6 +2540,7 @@ subroutine seq_infodata_Exchange(infodata,ID,type) if (lnd2cpli) then call shr_mpi_bcast(infodata%lnd_present, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_prognostic, mpicom, pebcast=cmppe) + call shr_mpi_bcast(infodata%lndocn_prognostic, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_nx, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_ny, mpicom, pebcast=cmppe) ! dead_comps is true if it's ever set to true @@ -2629,6 +2637,7 @@ subroutine seq_infodata_Exchange(infodata,ID,type) call shr_mpi_bcast(infodata%atm_prognostic, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%lnd_present, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%lnd_prognostic, mpicom, pebcast=cplpe) + call shr_mpi_bcast(infodata%lndocn_prognostic, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%rof_present, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%rofice_present, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%rof_prognostic, mpicom, pebcast=cplpe) @@ -2992,6 +3001,7 @@ SUBROUTINE seq_infodata_print( infodata ) write(logunit,F0L) subname,'atm_prognostic = ', infodata%atm_prognostic write(logunit,F0L) subname,'lnd_present = ', infodata%lnd_present write(logunit,F0L) subname,'lnd_prognostic = ', infodata%lnd_prognostic + write(logunit,F0L) subname,'lndocn_prognostic = ', infodata%lndocn_prognostic write(logunit,F0L) subname,'rof_present = ', infodata%rof_present write(logunit,F0L) subname,'rofice_present = ', infodata%rofice_present write(logunit,F0L) subname,'rof_prognostic = ', infodata%rof_prognostic From 25ce36706daf0480f8cade1a3717cdf526587ed8 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Mon, 14 Nov 2022 11:08:40 -0800 Subject: [PATCH 142/398] ocn to lnd one way coupling continue Conflicts: components/data_comps/docn/src/docn_comp_mod.F90 components/elm/src/biogeophys/BalanceCheckMod.F90 components/elm/src/biogeophys/SoilHydrologyMod.F90 components/elm/src/biogeophys/SoilHydrologyType.F90 components/elm/src/data_types/ColumnDataType.F90 --- .../cime_config/namelist_definition_docn.xml | 1 + .../data_comps/docn/src/docn_comp_mod.F90 | 15 +- .../elm/src/biogeophys/BalanceCheckMod.F90 | 10 +- .../src/biogeophys/HydrologyDrainageMod.F90 | 18 +- .../elm/src/biogeophys/LakeHydrologyMod.F90 | 2 + .../elm/src/biogeophys/SoilHydrologyMod.F90 | 280 +++++++++++++++++- components/elm/src/cpl/elm_cpl_indices.F90 | 2 + components/elm/src/cpl/lnd_import_export.F90 | 4 + .../elm/src/data_types/ColumnDataType.F90 | 8 + components/elm/src/main/elm_driver.F90 | 4 +- components/elm/src/main/ocn2lndType.F90 | 17 +- driver-mct/shr/seq_flds_mod.F90 | 10 + 12 files changed, 334 insertions(+), 37 deletions(-) diff --git a/components/data_comps/docn/cime_config/namelist_definition_docn.xml b/components/data_comps/docn/cime_config/namelist_definition_docn.xml index 38b935f05359..8566fdd8f6a0 100644 --- a/components/data_comps/docn/cime_config/namelist_definition_docn.xml +++ b/components/data_comps/docn/cime_config/namelist_definition_docn.xml @@ -216,6 +216,7 @@ T t Inund frac_h2oocn + SSH ssh diff --git a/components/data_comps/docn/src/docn_comp_mod.F90 b/components/data_comps/docn/src/docn_comp_mod.F90 index a774c4b2729e..480d46ce3cf3 100644 --- a/components/data_comps/docn/src/docn_comp_mod.F90 +++ b/components/data_comps/docn/src/docn_comp_mod.F90 @@ -69,7 +69,7 @@ module docn_comp_mod real(R8),parameter :: latice = shr_const_latice ! latent heat of fusion real(R8),parameter :: ocnsalt = shr_const_ocn_ref_sal ! ocean reference salinity - integer(IN) :: kt,ks,ku,kv,kdhdx,kdhdy,kq,kswp,kh2o ! field indices + integer(IN) :: kt,ks,ku,kv,kdhdx,kdhdy,kq,kswp,kssh,kh2o ! field indices integer(IN) :: kswnet,klwup,klwdn,ksen,klat,kmelth,ksnow,krofi integer(IN) :: kh,kqbot,kfraz,kssh,kh2ot integer(IN) :: k10uu ! index for u10 @@ -90,16 +90,17 @@ module docn_comp_mod #endif !-------------------------------------------------------------------------- - integer(IN) , parameter :: ktrans = 9 + integer(IN) , parameter :: ktrans = 10 character(14) , parameter :: avifld(1:ktrans) = & (/ "t ","u ","v ","dhdx ",& "dhdy ","s ","h ","qbot ",& - "frac_h2oocn "/) + "ssh ","frac_h2oocn "/) character(14) , parameter :: avofld(1:ktrans) = & (/ "So_t ","So_u ","So_v ","So_dhdx ",& "So_dhdy ","So_s ","strm_h ","strm_qbot ",& - "So_frac_h2oocn"/) + "So_ssh ","So_frac_h2oocn"/) character(len=*),parameter :: flds_strm = 'strm_h:strm_qbot:So_t' + !-------------------------------------------------------------------------- !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -665,6 +666,9 @@ subroutine docn_comp_run(EClock, x2o, o2x, & o2x%rAttr(kq ,n) = 0.0_R8 ! make sure frazil is 0. MPAS-seaice will still use it. o2x%rAttr(kfraz,n) = 0.0_R8 + if (kh2o /= 0) then + o2x%rAttr(kssh, n) = 0.0_R8 + endif if (kh2o /= 0) then o2x%rAttr(kh2o, n) = 0.0_R8 endif @@ -922,6 +926,9 @@ subroutine docn_comp_run(EClock, x2o, o2x, & o2x%rAttr(kdhdx,n) = 0.0_R8 o2x%rAttr(kdhdy,n) = 0.0_R8 o2x%rAttr(kq ,n) = 0.0_R8 + if (kssh /= 0) then + o2x%rAttr(kssh, n) = o2x%rAttr(kssh, n) + endif if (kh2o /= 0) then if (o2x%rAttr(kh2o, n) < 0.0_R8) then o2x%rAttr(kh2o, n) = 0.0_R8 ! Inundation cannot be negative diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 index 951e65deb1fa..676b45f85946 100755 --- a/components/elm/src/biogeophys/BalanceCheckMod.F90 +++ b/components/elm/src/biogeophys/BalanceCheckMod.F90 @@ -251,8 +251,9 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & snow_sources => col_wf%snow_sources , & ! Output: [real(r8) (:) ] snow sources (mm H2O /s) snow_sinks => col_wf%snow_sinks , & ! Output: [real(r8) (:) ] snow sinks (mm H2O /s) qflx_lateral => col_wf%qflx_lateral , & ! Input: [real(r8) (:) ] lateral flux of water to neighboring column (mm H2O /s) - qflx_h2orof_drain => col_wf%qflx_h2orof_drain , & ! Input: [real(r8) (:) ] drainange from floodplain inundation volume (mm H2O/s) - qflx_h2oocn_drain => col_wf%qflx_h2oocn_drain , & ! Input: [real(r8) (:) ] drainange from floodplain inundation volume (mm H2O/s) + qflx_lnd2ocn => col_wf%qflx_lnd2ocn , & ! Input: [real(r8) (:) ] lateral flow from lnd to ocn (mm H2O /s) + qflx_h2orof_drain => col_wf%qflx_h2orof_drain , & ! Input: [real(r8) (:) ] drainange from floodplain inundation volume (mm H2O/s) + qflx_h2oocn_drain => col_wf%qflx_h2oocn_drain , & ! Input: [real(r8) (:) ] drainange from floodplain inundation volume (mm H2O/s) eflx_lwrad_out => veg_ef%eflx_lwrad_out , & ! Input: [real(r8) (:) ] emitted infrared (longwave) radiation (W/m**2) eflx_lwrad_net => veg_ef%eflx_lwrad_net , & ! Input: [real(r8) (:) ] net infrared (longwave) rad (W/m**2) [+ = to atm] @@ -337,7 +338,8 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & + qflx_surf_irrig_col(c) + qflx_over_supply_col(c) & - qflx_evap_tot(c) - qflx_surf(c) - qflx_h2osfc_surf(c) - qflx_to_downhill(c) & - qflx_qrgwl(c) - qflx_drain(c) - qflx_drain_perched(c) - qflx_snwcp_ice(c) - qflx_ice_runoff_xs(c) & - - qflx_lateral(c) + qflx_h2orof_drain(c) + qflx_h2oocn_drain(c)) * dtime + - qflx_lateral(c) + qflx_h2orof_drain(c) - qflx_lnd2ocn(c) + qflx_h2oocn_drain(c)) * dtime + dwb(c) = (endwb(c)-begwb(c))/dtime else @@ -406,6 +408,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & write(iulog,*)'qflx_drain = ',qflx_drain(indexc) write(iulog,*)'qflx_snwcp_ice = ',qflx_snwcp_ice(indexc) write(iulog,*)'qflx_lateral = ',qflx_lateral(indexc) + write(iulog,*)'qflx_lnd2ocn = ',qflx_lnd2ocn(indexc) write(iulog,*)'total_plant_stored_h2o_col = ',total_plant_stored_h2o_col(indexc) write(iulog,*)'qflx_h2orof_drain = ',qflx_h2orof_drain(indexc) write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc) @@ -438,6 +441,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & write(iulog,*)'qflx_glcice_melt = ',qflx_glcice_melt(indexc) write(iulog,*)'qflx_glcice_frz = ',qflx_glcice_frz(indexc) write(iulog,*)'qflx_lateral = ',qflx_lateral(indexc) + write(iulog,*)'qflx_lnd2ocn = ',qflx_lnd2ocn(indexc) write(iulog,*)'total_plant_stored_h2o_col = ',total_plant_stored_h2o_col(indexc) write(iulog,*)'qflx_h2orof_drain = ',qflx_h2orof_drain(indexc) write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc) diff --git a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 index e14c229160ce..13f7563b7343 100755 --- a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 @@ -35,12 +35,12 @@ module HydrologyDrainageMod contains !----------------------------------------------------------------------- - subroutine HydrologyDrainage(bounds, & - num_nolakec, filter_nolakec, & - num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc, & - num_do_smb_c, filter_do_smb_c, & - atm2lnd_vars, glc2lnd_vars, & + subroutine HydrologyDrainage(bounds, & + num_nolakec, filter_nolakec, & + num_hydrologyc, filter_hydrologyc, & + num_urbanc, filter_urbanc, & + num_do_smb_c, filter_do_smb_c, & + atm2lnd_vars, glc2lnd_vars, ocn2lnd_vars, & soilhydrology_vars, soilstate_vars ) ! !DESCRIPTION: ! Calculates soil/snow hydrology with drainage (subsurface runoff) @@ -56,6 +56,7 @@ subroutine HydrologyDrainage(bounds, & use TopounitType , only : top_pp use TopounitDataType , only : top_ws use atm2lndType , only : atm2lnd_type + use ocn2lndType , only : ocn2lnd_type use elm_varpar , only : nlevgrnd, nlevurb, nlevsoi use SoilHydrologyMod , only : ELMVICMap, Drainage use elm_varctl , only : use_vsfm, use_IM2_hillslope_hydrology @@ -72,6 +73,7 @@ subroutine HydrologyDrainage(bounds, & integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare land SMB columns type(atm2lnd_type) , intent(in) :: atm2lnd_vars type(glc2lnd_type) , intent(in) :: glc2lnd_vars + type(ocn2lnd_type) , intent(in) :: ocn2lnd_vars type(soilhydrology_type) , intent(inout) :: soilhydrology_vars type(soilstate_type) , intent(inout) :: soilstate_vars @@ -114,6 +116,7 @@ subroutine HydrologyDrainage(bounds, & qflx_drain_perched => col_wf%qflx_drain_perched , & ! Output: [real(r8) (:) ] sub-surface runoff from perched zwt (mm H2O /s) qflx_rsub_sat => col_wf%qflx_rsub_sat , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] qflx_drain => col_wf%qflx_drain , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) + qflx_lnd2ocn => col_wf%qflx_lnd2ocn , & ! Output: [real(r8) (:) ] lateral flow from lnd to ocn (mm H2O /s) qflx_surf => col_wf%qflx_surf , & ! Output: [real(r8) (:) ] surface runoff (mm H2O /s) qflx_infl => col_wf%qflx_infl , & ! Output: [real(r8) (:) ] infiltration (mm H2O /s) qflx_qrgwl => col_wf%qflx_qrgwl , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes @@ -147,7 +150,7 @@ subroutine HydrologyDrainage(bounds, & if (.not. use_vsfm) then call Drainage(bounds, num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& - soilhydrology_vars, soilstate_vars, dtime) + soilhydrology_vars, soilstate_vars, ocn2lnd_vars, dtime) endif #ifndef _OPENACC @@ -267,6 +270,7 @@ subroutine HydrologyDrainage(bounds, & qflx_h2osfc_surf(c) = 0._r8 qflx_surf(c) = 0._r8 qflx_infl(c) = 0._r8 + qflx_lnd2ocn(c) = 0._r8 qflx_qrgwl(c) = forc_rain(t) + forc_snow(t) + qflx_floodg(g) - qflx_evap_tot(c) - qflx_snwcp_ice(c) - & (endwb(c)-begwb(c))/dtime diff --git a/components/elm/src/biogeophys/LakeHydrologyMod.F90 b/components/elm/src/biogeophys/LakeHydrologyMod.F90 index f0bf1d373fcb..b11a1a93f57b 100644 --- a/components/elm/src/biogeophys/LakeHydrologyMod.F90 +++ b/components/elm/src/biogeophys/LakeHydrologyMod.F90 @@ -199,6 +199,7 @@ subroutine LakeHydrology(bounds, & qflx_rsub_sat => col_wf%qflx_rsub_sat , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] qflx_surf => col_wf%qflx_surf , & ! Output: [real(r8) (:) ] surface runoff (mm H2O /s) qflx_drain => col_wf%qflx_drain , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) + qflx_lnd2ocn => col_wf%qflx_lnd2ocn , & ! Output: [real(r8) (:) ] lateral flow from lnd to ocn (mm H2O /s) qflx_infl => col_wf%qflx_infl , & ! Output: [real(r8) (:) ] infiltration (mm H2O /s) qflx_qrgwl => col_wf%qflx_qrgwl , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes qflx_runoff => col_wf%qflx_runoff , & ! Output: [real(r8) (:) ] total runoff (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) @@ -712,6 +713,7 @@ subroutine LakeHydrology(bounds, & qflx_infl(c) = 0._r8 qflx_surf(c) = 0._r8 qflx_drain(c) = 0._r8 + qflx_lnd2ocn(c) = 0._r8 qflx_irrig(p) = 0._r8 qflx_irrig_col(c) = 0._r8 diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index 27af8585f78d..9354ad10f045 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -688,10 +688,10 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f h2osoi_left_vol1 = 0._r8 endif - if (frac_h2oocn(c) > 0._r8 .and. frac_h2oocn(c) > fsat(c)) then - h2osoi_left_vol1 = (frac_h2oocn(c) - fsat(c)) * h2osoi_left_vol1 + if (frac_h2oocn(c) > 0._r8) then + h2osoi_left_vol1 = frac_h2oocn(c) * h2osoi_left_vol1 ! no drainage from ocn inundation if the 1st layer soil is saturated - qflx_h2oocn_drain(c)=min((frac_h2oocn(c) - fsat(c))*qinmax, h2osoi_left_vol1/dtime) + qflx_h2oocn_drain(c)=min(frac_h2oocn(c)*qinmax, h2osoi_left_vol1/dtime) else qflx_h2oocn_drain(c)=0._r8 endif @@ -1082,7 +1082,7 @@ end subroutine WaterTable !----------------------------------------------------------------------- subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & - soilhydrology_vars, soilstate_vars, dtime) + soilhydrology_vars, soilstate_vars, ocn2lnd_vars, dtime) ! ! !DESCRIPTION: ! Calculate subsurface drainage @@ -1095,8 +1095,11 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte use elm_varctl , only : use_vsfm, use_var_soil_thick, use_firn_percolation_and_compaction use SoilWaterMovementMod, only : zengdecker_2009_with_var_soil_thick use pftvarcon , only : rsub_top_globalmax - use LandunitType , only : lun_pp + use LandunitType , only : lun_pp use landunit_varcon , only : istice_mec, istice + use domainMod , only : ldomain + use ocn2lndType , only : ocn2lnd_type + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -1106,11 +1109,12 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points type(soilstate_type) , intent(in) :: soilstate_vars type(soilhydrology_type) , intent(inout) :: soilhydrology_vars + type(ocn2lnd_type) , intent(in) :: ocn2lnd_vars real(r8), intent(in) :: dtime ! ! !LOCAL VARIABLES: !character(len=32) :: subname = 'Drainage' ! subroutine name - integer :: c,j,fc,i ! indices + integer :: c,g,j,fc,i ! indices integer :: nlevbed ! # layers to bedrock real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevgrnd) ! layer thickness (mm) @@ -1158,6 +1162,11 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte real(r8) :: frac ! temporary variable for ARNO subsurface runoff calculation real(r8) :: rel_moist ! relative moisture, temporary variable real(r8) :: wtsub_vic ! summation of hk*dzmm for layers in the third VIC layer + real(r8) :: T1 ! transmissivity of saturated portion of the soil column (m^2/s) + real(r8) :: T2 ! transmissivity for the depth below the bottom-most layer(m^2/s) + real(r8) :: f ! e-folding length representing the complexity of sediment-bedrock profile (Zeng et al., 2016) (m) + integer :: jtran ! from jth layer to count for transmissivity + real(r8) :: dz_jtran !----------------------------------------------------------------------- associate( & @@ -1165,7 +1174,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte zi => col_pp%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) dz => col_pp%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) snl => col_pp%snl , & ! Input: [integer (:) ] number of snow layers - nlev2bed => col_pp%nlevbed , & ! Input: [integer (:) ] number of layers to bedrock + nlev2bed => col_pp%nlevbed , & ! Input: [integer (:) ] number of layers to bedrock t_soisno => col_es%t_soisno , & ! Input: [real(r8) (:,:) ] soil temperature (Kelvin) @@ -1207,6 +1216,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte qflx_qrgwl => col_wf%qflx_qrgwl , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes (mm H2O /s) qflx_rsub_sat => col_wf%qflx_rsub_sat , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] qflx_drain_perched => col_wf%qflx_drain_perched , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) + qflx_lnd2ocn => col_wf%qflx_lnd2ocn , & ! Output: [real(r8) (:) ] lateral flow from lnd to ocn (mm H2O /s) h2osoi_liq => col_ws%h2osoi_liq , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) h2osoi_ice => col_ws%h2osoi_ice & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) @@ -1231,6 +1241,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) qflx_drain(c) = 0._r8 + qflx_lnd2ocn(c) = 0._r8 rsub_bot(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 @@ -1241,13 +1252,14 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte ! The layer index of the first unsaturated layer, i.e., the layer right above ! the water table - do fc = 1, num_hydrologyc + do fc = 1, num_hydrologyc !TODO: introduce a filter for coastline grid cells c = filter_hydrologyc(fc) + g = col_pp%gridcell(c) nlevbed = nlev2bed(c) jwt(c) = nlevbed ! allow jwt to equal zero when zwt is in top layer do j = 1,nlevbed - if(zwt(c) <= zi(c,j)) then + if (zwt(c) <= zi(c,j)) then if (zengdecker_2009_with_var_soil_thick .and. zwt(c) == zi(c,nlevbed)) then exit else @@ -1264,7 +1276,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte ! perched water table code do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - nlevbed = nlev2bed(c) + nlevbed = nlev2bed(c) ! specify maximum drainage rate q_perch_max = 1.e-5_r8 * sin(col_pp%topo_slope(c) * (rpi/180._r8)) @@ -1468,11 +1480,13 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte ! make sure baseflow isn't negative rsub_top(c) = max(0._r8, rsub_top(c)) else - if (jwt(c) == nlevbed .and. zengdecker_2009_with_var_soil_thick) then + + if (jwt(c) == nlevbed .and. zengdecker_2009_with_var_soil_thick) then rsub_top(c) = 0._r8 else rsub_top(c) = imped * rsub_top_max* exp(-fff(c)*zwt(c)) - end if + end if + end if if (use_vsfm) rsub_top(c) = 0._r8 @@ -1486,7 +1500,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte if(jwt(c) == nlevbed) then if (zengdecker_2009_with_var_soil_thick) then if (-1._r8 * smp_l(c,nlevbed) < 0.5_r8 * dzmm(c,nlevbed)) then - zwt(c) = z(c,nlevbed) - (smp_l(c,nlevbed) / 1000._r8) + zwt(c) = z(c,nlevbed) - (smp_l(c,nlevbed) / 1000._r8) end if rsub_top(c) = imped * rsub_top_max * exp(-fff(c) * zwt(c)) rsub_top_tot = - rsub_top(c) * dtime @@ -1506,6 +1520,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte rsub_top(c) = rsub_top(c) + rsub_top_tot / dtime rsub_top_tot = 0. end if + else wa(c) = wa(c) - rsub_top(c) * dtime zwt(c) = zwt(c) + (rsub_top(c) * dtime)/1000._r8/rous @@ -1594,12 +1609,39 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte end do + if (use_ocn_lnd_one_way) then + call Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & + soilhydrology_vars, soilstate_vars, ocn2lnd_vars, dtime) + + !-- recompute jwt for following calculations --------------------------------- + ! allow jwt to equal zero when zwt is in top layer + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + nlevbed = nlev2bed(c) + jwt(c) = nlevbed + do j = 1,nlevbed + if(zwt(c) <= zi(c,j)) then + if (zengdecker_2009_with_var_soil_thick .and. zwt(c) == zi(c,nlevbed)) then + exit + else + jwt(c) = j-1 + exit + end if + end if + enddo + zwt(c) = max(0.0_r8,zwt(c)) + zwt(c) = min(80._r8,zwt(c)) + enddo + + endif + ! excessive water above saturation added to the above unsaturated layer like a bucket ! if column fully saturated, excess water goes to runoff do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - nlevbed = nlev2bed(c) + nlevbed = nlev2bed(c) + do j = nlevbed,2,-1 xsi(c) = max(h2osoi_liq(c,j)-eff_porosity(c,j)*dzmm(c,j),0._r8) if (use_vsfm) then @@ -1717,9 +1759,10 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte do fc = 1, num_urbanc c = filter_urbanc(fc) if (col_pp%itype(c) /= icol_road_perv) then - qflx_drain(c) = 0._r8 + qflx_drain(c) = 0._r8 + qflx_lnd2ocn(c) = 0._r8 ! This must be done for roofs and impervious road (walls will be zero) - qflx_qrgwl(c) = qflx_snwcp_liq(c) + qflx_qrgwl(c) = qflx_snwcp_liq(c) end if end do @@ -1727,6 +1770,211 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte end subroutine Drainage + !----------------------------------------------------------------------- + subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & + soilhydrology_vars, soilstate_vars, ocn2lnd_vars, dtime) + ! + ! !DESCRIPTION: + ! Calculate subsurface drainage + ! + ! !USES: + !$acc routine seq + use elm_varpar , only : nlevsoi, nlevgrnd, nlayer, nlayert + use elm_varcon , only : pondmx, tfrz, watmin,rpi, secspday, nlvic, e_ice + use pftvarcon , only : rsub_top_globalmax + use domainMod , only : ldomain + use ocn2lndType , only : ocn2lnd_type + use SoilWaterMovementMod, only : zengdecker_2009_with_var_soil_thick + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter + integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points + type(soilstate_type) , intent(in) :: soilstate_vars + type(soilhydrology_type) , intent(inout) :: soilhydrology_vars + type(ocn2lnd_type) , intent(in) :: ocn2lnd_vars + real(r8) , intent(in) :: dtime + ! + ! !LOCAL VARIABLES: + !character(len=32) :: subname = 'Drainage_To_OCN' ! subroutine name + integer :: c,g,j,fc,i ! indices + integer :: nlevbed ! # layers to bedrock + integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) + integer :: jss(bounds%begc:bounds%endc) ! index of the soil layer right above the sea surface height + real(r8) :: dzsum, icefracsum, imped + real(r8) :: T1 ! transmissivity of saturated portion of the soil column (m^2/s) + real(r8) :: T2 ! transmissivity for the depth below the bottom-most layer(m^2/s) + real(r8) :: f ! e-folding length representing the complexity of sediment-bedrock profile (Zeng et al., 2016) (m) + real(r8) :: head ! water head between WTD and SSH (m) + integer :: jtran ! from jth layer to count for transmissivity + real(r8) :: dz_jtran, lateral_tot, lateral_layer, rous, s_y, h2osoi_left_vol + !----------------------------------------------------------------------- + + associate( & + z => col_pp%z , & ! Input: [real(r8) (:,:) ] layer depth (m) + zi => col_pp%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) + dz => col_pp%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) + nlev2bed => col_pp%nlevbed , & ! Input: [integer (:) ] number of layers to bedrock + bsw => soilstate_vars%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" + hksat => soilstate_vars%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) + sucsat => soilstate_vars%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) + watsat => soilstate_vars%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) + zwt => soilhydrology_vars%zwt_col , & ! Output: [real(r8) (:) ] water table depth (m) + wa => soilhydrology_vars%wa_col , & ! Output: [real(r8) (:) ] water in the unconfined aquifer (mm) + icefrac => soilhydrology_vars%icefrac_col, & ! Input: [real(r8) (:,:) ] fraction of ice in layer + qflx_lnd2ocn => col_wf%qflx_lnd2ocn , & ! Output: [real(r8) (:) ] lateral flow from lnd to ocn (mm H2O /s) + h2osoi_ice => col_ws%h2osoi_ice , & + h2osoi_liq => col_ws%h2osoi_liq & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) + ) + + do fc = 1, num_hydrologyc !TODO: introduce a filter for coastline grid cells + c = filter_hydrologyc(fc) + g = col_pp%gridcell(c) + nlevbed = nlev2bed(c) + + jwt(c) = nlevbed + ! allow jwt to equal zero when zwt is in top layer + do j = 1,nlevbed + if (zwt(c) <= zi(c,j)) then + if (zengdecker_2009_with_var_soil_thick .and. zwt(c) == zi(c,nlevbed)) then + exit + else + jwt(c) = j-1 + exit + end if + end if + enddo + + jss(c) = nlevbed + do j = 1,nlevbed + if(ocn2lnd_vars%ssh_grc(g) <= ldomain%topo(g) - zi(c,j)) then + jss(c) = j-1 + exit + end if + enddo + + dzsum = 0._r8 + icefracsum = 0._r8 + do j = max(jwt(c),1), nlevbed + dzsum = dzsum + dz(c,j)*1.e3_r8 + icefracsum = icefracsum + icefrac(c,j) * dz(c,j)*1.e3_r8 + end do + imped=10._r8**(-e_ice*(icefracsum/dzsum)) + + ! Lateral flow to ocean + T1 = 0._r8 + if (col_pp%topo_slope(c) > 0.16_r8) then + f = 5._r8 + else + f = 120._r8/(1._r8 + 150._r8*col_pp%topo_slope(c)) + endif + + if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then + jtran = jss(c) + 1 + dz_jtran = ocn2lnd_vars%ssh_grc(g)-(ldomain%topo(g)-zi(c,jtran)) + else + jtran = jwt(c) + 1 + dz_jtran = zi(c,jtran)-zwt(c) + endif + + ! Transmissivity equation from Fan et al., 2007, and + if (jtran <= nlevbed) then + ! SSH is within the soil column + do j = jtran, nlevbed + if (j == jtran) then + T1 = T1 + 1.e-3_r8*hksat(c,j)*dz_jtran + else + T1 = T1 + 1.e-3_r8*hksat(c,j)*dz(c,j) + endif + enddo + T2 = 1.e-3_r8*hksat(c,nlevbed)*f + else + ! SSH is below the soil column + if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then + T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp(((ldomain%topo(g)-zi(c,nlevbed))-ocn2lnd_vars%ssh_grc(g))/f) + else + T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp((zwt(c)-zi(c,nlevbed))/f) + endif + endif + ! positive: lnd->ocn, negative: ocn->lnd + if (ldomain%topo(g) - ocn2lnd_vars%ssh_grc(g) < 80._r8) then + head = ldomain%topo(g) - zwt(c) - ocn2lnd_vars%ssh_grc(g); + qflx_lnd2ocn(c) = imped*2._r8*(T1+T2)*(head)/ldomain%area(g)/1.e3_r8 + else + ! Land surface is much higher than the SSH, then there is no lateral flow + qflx_lnd2ocn(c) = 0._r8 + endif + + !scs: use analytical expression for aquifer specific yield + rous = watsat(c,nlevbed) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,nlevbed))**(-1./bsw(c,nlevbed))) + rous=max(rous,0.02_r8) + + if (jwt(c) == nlevbed) then + !-- water table is below the soil column --! + wa(c) = wa(c) - qflx_lnd2ocn(c) * dtime + zwt(c) = zwt(c) - (qflx_lnd2ocn(c) * dtime)/1000._r8/rous + h2osoi_liq(c,nlevsoi) = h2osoi_liq(c,nlevsoi) + max(0._r8,(wa(c)-5000._r8)) + wa(c) = min(wa(c), 5000._r8) + else + !-- water table within soil layers 1-9 --! + lateral_tot = -qflx_lnd2ocn(c) * dtime + if(lateral_tot > 0._r8) then !rising water table (posive qflx_lnd2ocn) + do j = jwt(c)+1, 1,-1 + !scs: use analytical expression for specific yield + s_y = watsat(c,j) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) + s_y = max(s_y,0.02_r8) + + lateral_layer = min(lateral_tot,(s_y*(zwt(c) - zi(c,j-1))*1.e3)) + lateral_layer = max(lateral_layer,0._r8) + h2osoi_left_vol = max(0._r8,(watsat(c,j)*dz(c,j)*1.e3_r8-h2osoi_ice(c,j)-watmin)) - & + max(0._r8,h2osoi_liq(c,j)-watmin) + + h2osoi_liq(c,j) = h2osoi_liq(c,j) + lateral_layer + if(s_y > 0._r8) zwt(c) = zwt(c) - lateral_layer/s_y/1000._r8 + lateral_tot = lateral_tot - lateral_layer + + if (lateral_tot <= 0._r8) exit + enddo + if (lateral_tot > 1.e-14_r8) then + qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime + endif + + else ! deepening water table (negative qflx_lnd2ocn) + do j = jwt(c)+1, nlevbed + !scs: use analytical expression for specific yield + s_y = watsat(c,j) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) + s_y = max(s_y,0.02_r8) + + lateral_layer = max(lateral_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) + lateral_layer = min(lateral_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + lateral_layer + + lateral_tot = lateral_tot - lateral_layer + if (lateral_tot >= 0.) then + zwt(c) = zwt(c) - lateral_layer/s_y/1000._r8 + exit + else + zwt(c) = zi(c,j) + endif + + enddo + !if (lateral_tot > 0.) zwt(c) = zwt(c) - lateral_tot/1000._r8/rous + if (lateral_tot < -1.e-14_r8) then + qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime + endif + endif + + endif + + end do + + end associate + + end subroutine Drainage_To_OCN + !----------------------------------------------------------------------- subroutine DrainageVSFM(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & soilhydrology_vars, soilstate_vars, dtime) diff --git a/components/elm/src/cpl/elm_cpl_indices.F90 b/components/elm/src/cpl/elm_cpl_indices.F90 index d3abcda0b8ca..0347469e396f 100644 --- a/components/elm/src/cpl/elm_cpl_indices.F90 +++ b/components/elm/src/cpl/elm_cpl_indices.F90 @@ -128,6 +128,7 @@ module elm_cpl_indices integer, public ::index_x2l_Flrr_deficit ! rtm->lnd supply deficit integer, public ::index_x2l_Sr_h2orof ! rtm->lnd floodplain inundation volume integer, public ::index_x2l_Sr_frac_h2orof ! rtm->lnd floodplain inundation fraction + integer, public ::index_x2l_So_ssh ! ocn->lnd sea surface height integer, public ::index_x2l_So_frac_h2oocn ! ocn->lnd coastal inundation fraction ! In the following, index 0 is bare land, other indices are glc elevation classes @@ -317,6 +318,7 @@ subroutine elm_cpl_indices_set( ) index_x2l_Sr_frac_h2orof= mct_avect_indexra(x2l,'Sr_frac_h2orof') endif if (ocn_lnd_one_way) then + index_x2l_So_ssh = mct_avect_indexra(x2l,'So_ssh') index_x2l_So_frac_h2oocn= mct_avect_indexra(x2l,'So_frac_h2oocn') endif diff --git a/components/elm/src/cpl/lnd_import_export.F90 b/components/elm/src/cpl/lnd_import_export.F90 index 1353b35ae1c5..c9c6d6475a2c 100644 --- a/components/elm/src/cpl/lnd_import_export.F90 +++ b/components/elm/src/cpl/lnd_import_export.F90 @@ -206,6 +206,10 @@ subroutine lnd_import( bounds, x2l, atm2lnd_vars, glc2lnd_vars, ocn2lnd_vars, ln atm2lnd_vars%frac_h2orof_grc(g) = x2l(index_x2l_Sr_frac_h2orof,i) endif + if (index_x2l_So_ssh /= 0) then + ocn2lnd_vars%ssh_grc(g) = x2l(index_x2l_So_ssh,i) + endif + if (index_x2l_So_frac_h2oocn /= 0) then ocn2lnd_vars%frac_h2oocn_grc(g) = x2l(index_x2l_So_frac_h2oocn,i) endif diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index 273458025a97..528d81b23385 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -520,6 +520,7 @@ module ColumnDataType real(r8), pointer :: qflx_h2osfc2topsoi (:) => null() ! liquid water coming from surface standing water top soil (mm H2O/s) real(r8), pointer :: qflx_snow2topsoi (:) => null() ! liquid water coming from residual snow to topsoil (mm H2O/s) real(r8), pointer :: qflx_lateral (:) => null() ! lateral subsurface flux (mm H2O /s) + real(r8), pointer :: qflx_lnd2ocn (:) => null() ! lateral flux between water table and sea surface height (mm H2O/s) real(r8), pointer :: snow_sources (:) => null() ! snow sources (mm H2O/s) real(r8), pointer :: snow_sinks (:) => null() ! snow sinks (mm H2O/s) @@ -5844,6 +5845,7 @@ subroutine col_wf_init(this, begc, endc) allocate(this%qflx_h2osfc2topsoi (begc:endc)) ; this%qflx_h2osfc2topsoi (:) = spval allocate(this%qflx_snow2topsoi (begc:endc)) ; this%qflx_snow2topsoi (:) = spval allocate(this%qflx_lateral (begc:endc)) ; this%qflx_lateral (:) = 0._r8 + allocate(this%qflx_lnd2ocn (begc:endc)) ; this%qflx_lnd2ocn (:) = spval allocate(this%snow_sources (begc:endc)) ; this%snow_sources (:) = spval allocate(this%snow_sinks (begc:endc)) ; this%snow_sinks (:) = spval allocate(this%qflx_irrig (begc:endc)) ; this%qflx_irrig (:) = spval @@ -5910,6 +5912,11 @@ subroutine col_wf_init(this, begc, endc) avgflag='A', long_name='sub-surface drainage', & ptr_col=this%qflx_drain, c2l_scale_type='urbanf') + this%qflx_lnd2ocn(begc:endc) = spval + call hist_addfld1d (fname='QLND2OCN', units='mm/s', & + avgflag='A', long_name='land to ocean drainage', & + ptr_col=this%qflx_lnd2ocn, c2l_scale_type='urbanf') + this%qflx_irr_demand(begc:endc) = spval call hist_addfld1d (fname='QIRRIG_WM', units='mm/s', & avgflag='A', long_name='Surface water irrigation demand sent to MOSART/WM', & @@ -6055,6 +6062,7 @@ subroutine col_wf_init(this, begc, endc) if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then this%qflx_drain(c) = 0._r8 this%qflx_surf(c) = 0._r8 + this%qflx_lnd2ocn(c) = 0._r8 end if end do diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 78fd71fb9cdf..92f7a799e42a 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -1229,7 +1229,7 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) filter(nc)%num_hydrononsoic, filter(nc)%hydrononsoic, & filter(nc)%num_urbanc, filter(nc)%urbanc, & filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - atm2lnd_vars, glc2lnd_vars, & + atm2lnd_vars, glc2lnd_vars, ocn2lnd_vars, & soilhydrology_vars, soilstate_vars) else @@ -1239,7 +1239,7 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & filter(nc)%num_urbanc, filter(nc)%urbanc, & filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - atm2lnd_vars, glc2lnd_vars, & + atm2lnd_vars, glc2lnd_vars, ocn2lnd_vars, & soilhydrology_vars, soilstate_vars) end if diff --git a/components/elm/src/main/ocn2lndType.F90 b/components/elm/src/main/ocn2lndType.F90 index c893de45ce19..aeef3ae883fe 100644 --- a/components/elm/src/main/ocn2lndType.F90 +++ b/components/elm/src/main/ocn2lndType.F90 @@ -28,7 +28,8 @@ module ocn2lndType ! type, public :: ocn2lnd_type - real(r8), pointer :: frac_h2oocn_grc(:) => null() ! sea surface height [m] + real(r8), pointer :: frac_h2oocn_grc(:) => null() ! coastal inundation fraction [-] + real(r8), pointer :: ssh_grc(:) => null() ! sea surface height [m] contains @@ -70,17 +71,18 @@ subroutine InitAllocate(this, bounds) integer :: begg, endg integer :: begc, endc integer :: begp, endp - !------------------------------------------------------------------------ + !------------------------------------------------------------------------- begg = bounds%begg; endg= bounds%endg begc = bounds%begc; endc= bounds%endc begp = bounds%begp; endp= bounds%endp - allocate(this%frac_h2oocn_grc(begg:endg)); this%frac_h2oocn_grc(:) = ival + allocate(this%frac_h2oocn_grc(begg:endg)); this%frac_h2oocn_grc(:) = ival + allocate(this%ssh_grc(begg:endg)); this%ssh_grc(:) = ival end subroutine InitAllocate - !------------------------------------------------------------------------ + !--------------------------------------------------------------------------- subroutine InitHistory(this, bounds) ! ! !USES: @@ -93,12 +95,17 @@ subroutine InitHistory(this, bounds) ! !LOCAL VARIABLES: integer :: begg, endg integer :: begp, endp - !--------------------------------------------------------------------- + !------------------------------------------------------------------------- begg = bounds%begg; endg= bounds%endg begp = bounds%begp; endp= bounds%endp if (ocn_lnd_one_way) then + this%ssh_grc(begg:endg) = spval + call hist_addfld1d (fname='SSH', units='meter' , & + avgflag='A', long_name='sea surface height' , & + ptr_lnd=this%ssh_grc) + this%frac_h2oocn_grc(begg:endg) = spval call hist_addfld1d (fname='FRAC_H2OOCN', units='-' , & avgflag='A', long_name='coastal inundation fraction', & diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index ec838ce3de43..7674ded52077 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -1788,6 +1788,16 @@ subroutine seq_flds_set(nmlfile, ID, infodata) attname = 'So_ssh' call metadata_set(attname, longname, stdname, units) + ! ocn -> lnd one-way coupling + call seq_flds_add(o2x_states,"So_ssh") + call seq_flds_add(x2l_states,"So_ssh") + call seq_flds_add(o2x_states_to_lnd,"So_ssh") + longname = 'Sea surface height' + stdname = 'sea_surface_height' + units = 'm' + attname = 'So_ssh' + call metadata_set(attname, longname, stdname, units) + call seq_flds_add(o2x_states,"So_frac_h2oocn") call seq_flds_add(x2l_states,"So_frac_h2oocn") call seq_flds_add(o2x_states_to_lnd,"So_frac_h2oocn") From 8a702476179bb82369b32d0fc2e96d42f791ed40 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Mon, 5 Dec 2022 17:27:40 -0800 Subject: [PATCH 143/398] add ocean inundation infiltration into outputs --- components/elm/src/data_types/ColumnDataType.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index 528d81b23385..f890e52b1433 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -5912,6 +5912,10 @@ subroutine col_wf_init(this, begc, endc) avgflag='A', long_name='sub-surface drainage', & ptr_col=this%qflx_drain, c2l_scale_type='urbanf') + call hist_addfld1d (fname='QH2OOCN', units='mm/s', & + avgflag='A', long_name='Ocean inundation infiltration', & + ptr_col=this%qflx_h2oocn_drain, c2l_scale_type='urbanf') + this%qflx_lnd2ocn(begc:endc) = spval call hist_addfld1d (fname='QLND2OCN', units='mm/s', & avgflag='A', long_name='land to ocean drainage', & From 89a2fd6ab2b77f8200113648d9882c6fc347ca58 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Thu, 29 Dec 2022 14:54:17 -0800 Subject: [PATCH 144/398] debug for lnd-ocn lateral flux --- .../elm/src/biogeophys/SoilHydrologyMod.F90 | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index 9354ad10f045..e91ffba0c022 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -1846,9 +1846,9 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & enddo jss(c) = nlevbed - do j = 1,nlevbed + do j = nlevbed,1,-1 if(ocn2lnd_vars%ssh_grc(g) <= ldomain%topo(g) - zi(c,j)) then - jss(c) = j-1 + jss(c) = j exit end if enddo @@ -1866,17 +1866,19 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & if (col_pp%topo_slope(c) > 0.16_r8) then f = 5._r8 else - f = 120._r8/(1._r8 + 150._r8*col_pp%topo_slope(c)) + f = 120._r8/(1._r8 + 150._r8*col_pp%topo_slope(c)) endif if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then - jtran = jss(c) + 1 - dz_jtran = ocn2lnd_vars%ssh_grc(g)-(ldomain%topo(g)-zi(c,jtran)) + jtran = jss(c) + dz_jtran = ldomain%topo(g)-zi(c,jtran) - ocn2lnd_vars%ssh_grc(g) else jtran = jwt(c) + 1 - dz_jtran = zi(c,jtran)-zwt(c) + dz_jtran = zi(c,jtran) - zwt(c) endif + dz_jtran = max(dz_jtran, 0.0_r8) + ! Transmissivity equation from Fan et al., 2007, and if (jtran <= nlevbed) then ! SSH is within the soil column @@ -1891,15 +1893,15 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & else ! SSH is below the soil column if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then - T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp(((ldomain%topo(g)-zi(c,nlevbed))-ocn2lnd_vars%ssh_grc(g))/f) + T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp((ocn2lnd_vars%ssh_grc(g)-(ldomain%topo(g)-80._r8))/f) else - T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp((zwt(c)-zi(c,nlevbed))/f) + T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp((80._r8 - zwt(c))/f) endif endif ! positive: lnd->ocn, negative: ocn->lnd if (ldomain%topo(g) - ocn2lnd_vars%ssh_grc(g) < 80._r8) then head = ldomain%topo(g) - zwt(c) - ocn2lnd_vars%ssh_grc(g); - qflx_lnd2ocn(c) = imped*2._r8*(T1+T2)*(head)/ldomain%area(g)/1.e3_r8 + qflx_lnd2ocn(c) = imped*2._r8*(T1+T2)*(head)/ (ldomain%frac(g) * ldomain%area(g) * 1.e6_r8) * 1.e3_r8 else ! Land surface is much higher than the SSH, then there is no lateral flow qflx_lnd2ocn(c) = 0._r8 From 7b23e9fe6fba5c1a06a85eaadef8fb05ba9ba702 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Fri, 15 Sep 2023 13:38:51 -0700 Subject: [PATCH 145/398] update for lnd-ocn lateral flux --- components/elm/src/biogeophys/SoilHydrologyMod.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index e91ffba0c022..0a34a1798838 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -1891,17 +1891,17 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & enddo T2 = 1.e-3_r8*hksat(c,nlevbed)*f else - ! SSH is below the soil column + ! SSH or ZWT is below the soil column if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then - T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp((ocn2lnd_vars%ssh_grc(g)-(ldomain%topo(g)-80._r8))/f) + T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp(-((ldomain%topo(g)-zi(c,nlevbed))-ocn2lnd_vars%ssh_grc(g))/f) else - T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp((80._r8 - zwt(c))/f) + T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp(-(zwt(c)-zi(c,nlevbed))/f) endif endif ! positive: lnd->ocn, negative: ocn->lnd if (ldomain%topo(g) - ocn2lnd_vars%ssh_grc(g) < 80._r8) then head = ldomain%topo(g) - zwt(c) - ocn2lnd_vars%ssh_grc(g); - qflx_lnd2ocn(c) = imped*2._r8*(T1+T2)*(head)/ (ldomain%frac(g) * ldomain%area(g) * 1.e6_r8) * 1.e3_r8 + qflx_lnd2ocn(c) = imped*2._r8*(T1+T2)*(head)/ (ldomain%frac(g) * ldomain%area(g) * 1.e6_r8) * 1.e3_r8 ! [mm H2O/s] else ! Land surface is much higher than the SSH, then there is no lateral flow qflx_lnd2ocn(c) = 0._r8 From 4af4071f761eb395c2eee3d852ef77141b144cf7 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Tue, 26 Mar 2024 14:52:35 -0700 Subject: [PATCH 146/398] use horizontal hydraulic conductivity for estimating lateral flow Conflicts: components/elm/src/biogeophys/SoilHydrologyType.F90 --- .../elm/src/biogeophys/SoilHydrologyMod.F90 | 20 ++++++++++++------- .../elm/src/biogeophys/SoilHydrologyType.F90 | 10 ++++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index 0a34a1798838..a7ddc4751fb8 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -1819,6 +1819,7 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & hksat => soilstate_vars%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) sucsat => soilstate_vars%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) watsat => soilstate_vars%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) + cellclay_col => soilstate_vars%cellclay_col , & ! Input: [real(r8) (:,:) ] clay percentage zwt => soilhydrology_vars%zwt_col , & ! Output: [real(r8) (:) ] water table depth (m) wa => soilhydrology_vars%wa_col , & ! Output: [real(r8) (:) ] water in the unconfined aquifer (mm) icefrac => soilhydrology_vars%icefrac_col, & ! Input: [real(r8) (:,:) ] fraction of ice in layer @@ -1884,18 +1885,18 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & ! SSH is within the soil column do j = jtran, nlevbed if (j == jtran) then - T1 = T1 + 1.e-3_r8*hksat(c,j)*dz_jtran + T1 = T1 + 1.e-3_r8*hksat(c,j)*cellclay_col(c,j)*dz_jtran else - T1 = T1 + 1.e-3_r8*hksat(c,j)*dz(c,j) + T1 = T1 + 1.e-3_r8*hksat(c,j)*cellclay_col(c,j)*dz(c,j) endif enddo - T2 = 1.e-3_r8*hksat(c,nlevbed)*f + T2 = 1.e-3_r8*hksat(c,nlevbed)*cellclay_col(c,nlevbed)*f else ! SSH or ZWT is below the soil column if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then - T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp(-((ldomain%topo(g)-zi(c,nlevbed))-ocn2lnd_vars%ssh_grc(g))/f) + T2 = 1.e-3_r8*hksat(c,nlevbed)*cellclay_col(c,nlevbed)*f*exp(-((ldomain%topo(g)-zi(c,nlevbed))-ocn2lnd_vars%ssh_grc(g))/f) else - T2 = 1.e-3_r8*hksat(c,nlevbed)*f*exp(-(zwt(c)-zi(c,nlevbed))/f) + T2 = 1.e-3_r8*hksat(c,nlevbed)*cellclay_col(c,nlevbed)*f*exp(-(zwt(c)-zi(c,nlevbed))/f) endif endif ! positive: lnd->ocn, negative: ocn->lnd @@ -1932,12 +1933,16 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & lateral_layer = max(lateral_layer,0._r8) h2osoi_left_vol = max(0._r8,(watsat(c,j)*dz(c,j)*1.e3_r8-h2osoi_ice(c,j)-watmin)) - & max(0._r8,h2osoi_liq(c,j)-watmin) + lateral_layer = min(lateral_layer, h2osoi_left_vol) h2osoi_liq(c,j) = h2osoi_liq(c,j) + lateral_layer if(s_y > 0._r8) zwt(c) = zwt(c) - lateral_layer/s_y/1000._r8 lateral_tot = lateral_tot - lateral_layer - if (lateral_tot <= 0._r8) exit + if (lateral_tot <= 0._r8) then + qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime + exit + endif enddo if (lateral_tot > 1.e-14_r8) then qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime @@ -1956,7 +1961,8 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & lateral_tot = lateral_tot - lateral_layer if (lateral_tot >= 0.) then - zwt(c) = zwt(c) - lateral_layer/s_y/1000._r8 + zwt(c) = zwt(c) - lateral_layer/s_y/1000._r8/rous + qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime exit else zwt(c) = zi(c,j) diff --git a/components/elm/src/biogeophys/SoilHydrologyType.F90 b/components/elm/src/biogeophys/SoilHydrologyType.F90 index 203e0a7d52b1..140f4385be8e 100644 --- a/components/elm/src/biogeophys/SoilHydrologyType.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyType.F90 @@ -67,7 +67,9 @@ Module SoilHydrologyType real(r8), pointer :: ice_col (:,:) => null()! col VIC soil ice (kg/m2) for VIC soil layers real(r8), pointer :: fover (:) => null()! decay factor for surface runoff real(r8), pointer :: pc (:) => null()! surface water threshold probability - + + real(r8), pointer :: ar_col (:,:) => null()! col anisotropic ratio + contains procedure, public :: Init @@ -160,6 +162,8 @@ subroutine InitAllocate(this, bounds) allocate(this%fover (begg:endg)) ; this%fover (:) = spval allocate(this%pc (begg:endg)) ; this%pc (:) = spval + allocate(this%ar_col (begc:endc,nlevgrnd)) ; this%ar_col (:,:) = 25.0_r8 + end subroutine InitAllocate !------------------------------------------------------------------------ @@ -466,7 +470,7 @@ subroutine InitCold(this, bounds) ! do nothing else if (lun_pp%urbpoi(l) .and. (col_pp%itype(c) /= icol_road_perv) .and. (col_pp%itype(c) /= icol_road_imperv) )then ! do nothing - else + else do lev = 1,nlevgrnd if ( more_vertlayers )then ! duplicate clay and sand values from last soil layer @@ -504,6 +508,8 @@ subroutine InitCold(this, bounds) claycol(c,lev) = clay sandcol(c,lev) = sand om_fraccol(c,lev) = om_frac + + this%ar_col(c,lev)= clay end do end if end if ! end of if not lake From f93e624f4b7097025fb38300233c5281be1c0e17 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Mon, 23 Sep 2024 11:34:36 -0700 Subject: [PATCH 147/398] address comments --- components/elm/src/biogeophys/SoilHydrologyMod.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index a7ddc4751fb8..c4c7f4d9bc28 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -1865,9 +1865,9 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & ! Lateral flow to ocean T1 = 0._r8 if (col_pp%topo_slope(c) > 0.16_r8) then - f = 5._r8 + f = 1._r8 else - f = 120._r8/(1._r8 + 150._r8*col_pp%topo_slope(c)) + f = 20._r8/(1._r8 + 125._r8*col_pp%topo_slope(c)) endif if (ldomain%topo(g)-zwt(c) > ocn2lnd_vars%ssh_grc(g)) then @@ -1961,15 +1961,15 @@ subroutine Drainage_To_OCN(bounds, num_hydrologyc, filter_hydrologyc, & lateral_tot = lateral_tot - lateral_layer if (lateral_tot >= 0.) then - zwt(c) = zwt(c) - lateral_layer/s_y/1000._r8/rous - qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime exit else zwt(c) = zi(c,j) endif enddo - !if (lateral_tot > 0.) zwt(c) = zwt(c) - lateral_tot/1000._r8/rous + if (lateral_tot > 0.) then + zwt(c) = zwt(c) - lateral_tot/1000._r8/rous + endif if (lateral_tot < -1.e-14_r8) then qflx_lnd2ocn(c) = qflx_lnd2ocn(c) + lateral_tot/dtime endif From 3e9963b176ccf21133448dc8ba32a7b0db2f18c1 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Wed, 18 Jun 2025 10:07:28 -0700 Subject: [PATCH 148/398] debug for the new fields --- driver-mct/shr/seq_flds_mod.F90 | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 7674ded52077..4127f3310d67 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -1781,17 +1781,9 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(o2x_states,"So_ssh") call seq_flds_add(x2r_states,"So_ssh") call seq_flds_add(o2x_states_to_rof,"So_ssh") - if (wav_ocn_coup .ne. 'none') call seq_flds_add(x2w_states,'So_ssh') - longname = 'Sea surface height' - stdname = 'sea_surface_height' - units = 'm' - attname = 'So_ssh' - call metadata_set(attname, longname, stdname, units) - - ! ocn -> lnd one-way coupling - call seq_flds_add(o2x_states,"So_ssh") - call seq_flds_add(x2l_states,"So_ssh") + call seq_flds_add(x2l_states,"So_ssh") ! ocn -> lnd one-way coupling call seq_flds_add(o2x_states_to_lnd,"So_ssh") + if (wav_ocn_coup .ne. 'none') call seq_flds_add(x2w_states,'So_ssh') longname = 'Sea surface height' stdname = 'sea_surface_height' units = 'm' From 6bdcdf2a64b9ba7f667019fd3261b79b07b37433 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Fri, 20 Jun 2025 07:00:54 -0700 Subject: [PATCH 149/398] debug for test --- driver-mct/main/prep_lnd_mod.F90 | 26 ++++++++++++++++++++------ driver-mct/shr/seq_flds_mod.F90 | 24 ++++++++++++++---------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/driver-mct/main/prep_lnd_mod.F90 b/driver-mct/main/prep_lnd_mod.F90 index 32f94515ec8f..33af01c37704 100644 --- a/driver-mct/main/prep_lnd_mod.F90 +++ b/driver-mct/main/prep_lnd_mod.F90 @@ -198,6 +198,12 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln end do ! end if + allocate(o2x_lx(num_inst_ocn)) + do eoi = 1,num_inst_ocn + call mct_aVect_init(o2x_lx(eoi), rlist=seq_flds_o2x_fields_to_lnd, lsize=lsize_l) + call mct_aVect_zero(o2x_lx(eoi)) + end do + if (ocn_present) then o2x_ox => component_get_c2x_cx(ocn(1)) x2l_lx => component_get_x2c_cx(lnd(1)) @@ -209,12 +215,6 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln end do o2lacc_ox_cnt = 0 - allocate(o2x_lx(num_inst_ocn)) - do eoi = 1,num_inst_ocn - call mct_aVect_init(o2x_lx(eoi), rlist=seq_flds_o2x_fields_to_lnd, lsize=lsize_l) - call mct_aVect_zero(o2x_lx(eoi)) - end do - samegrid_ol = .true. if (trim(ocn_gnam) /= trim(lnd_gnam)) samegrid_ol = .false. @@ -466,6 +466,17 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, o2x_l, x2l_l ) field = mct_aVect_getRList2c(i1, o2x_l) mrgstr(o1) = trim(mrgstr(o1))//' = o2x%'//trim(field) enddo + + if (ocn_lnd_one_way) then + call mct_aVect_setSharedIndices(o2x_l, x2l_l, o2x_SharedIndices) + do i=1,o2x_SharedIndices%shared_real%num_indices + i1=o2x_SharedIndices%shared_real%aVindices1(i) + o1=o2x_SharedIndices%shared_real%aVindices2(i) + field = mct_aVect_getRList2c(i1, o2x_l) + mrgstr(o1) = trim(mrgstr(o1))//' = o2x%'//trim(field) + enddo + endif + endif call mct_aVect_copy(aVin=a2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=a2x_SharedIndices) @@ -473,6 +484,9 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, o2x_l, x2l_l ) call mct_aVect_copy(aVin=g2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=g2x_SharedIndices) call mct_aVect_copy(aVin=z2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=z2x_SharedIndices) call mct_aVect_copy(aVin=o2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=o2x_SharedIndices) + if (ocn_lnd_one_way) then + call mct_aVect_copy(aVin=o2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=o2x_SharedIndices) + endif if (first_time) then if (iamroot) then diff --git a/driver-mct/shr/seq_flds_mod.F90 b/driver-mct/shr/seq_flds_mod.F90 index 4127f3310d67..a4487a08e7a3 100644 --- a/driver-mct/shr/seq_flds_mod.F90 +++ b/driver-mct/shr/seq_flds_mod.F90 @@ -1781,8 +1781,10 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(o2x_states,"So_ssh") call seq_flds_add(x2r_states,"So_ssh") call seq_flds_add(o2x_states_to_rof,"So_ssh") - call seq_flds_add(x2l_states,"So_ssh") ! ocn -> lnd one-way coupling - call seq_flds_add(o2x_states_to_lnd,"So_ssh") + if (ocn_lnd_one_way) then + call seq_flds_add(x2l_states,"So_ssh") ! ocn -> lnd one-way coupling + call seq_flds_add(o2x_states_to_lnd,"So_ssh") + endif if (wav_ocn_coup .ne. 'none') call seq_flds_add(x2w_states,'So_ssh') longname = 'Sea surface height' stdname = 'sea_surface_height' @@ -1790,14 +1792,16 @@ subroutine seq_flds_set(nmlfile, ID, infodata) attname = 'So_ssh' call metadata_set(attname, longname, stdname, units) - call seq_flds_add(o2x_states,"So_frac_h2oocn") - call seq_flds_add(x2l_states,"So_frac_h2oocn") - call seq_flds_add(o2x_states_to_lnd,"So_frac_h2oocn") - longname = 'Oceanic inundation fraction' - stdname = 'oceanic_inundation_fraction' - units = '-' - attname = 'So_frac_h2oocn' - call metadata_set(attname, longname, stdname, units) + if (ocn_lnd_one_way) then + call seq_flds_add(o2x_states,"So_frac_h2oocn") + call seq_flds_add(x2l_states,"So_frac_h2oocn") + call seq_flds_add(o2x_states_to_lnd,"So_frac_h2oocn") + longname = 'Oceanic inundation fraction' + stdname = 'oceanic_inundation_fraction' + units = '-' + attname = 'So_frac_h2oocn' + call metadata_set(attname, longname, stdname, units) + endif ! Meridional sea surface slope call seq_flds_add(o2x_states,"So_dhdy") From 8c6ae96e664ee5a76b6271bfe006dfc8c387adbd Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Tue, 8 Jul 2025 20:37:53 -0700 Subject: [PATCH 150/398] control output variable --- .../elm/src/data_types/ColumnDataType.F90 | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index f890e52b1433..85b4955a8efd 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -30,6 +30,7 @@ module ColumnDataType use elm_varctl , only : pf_hmode, nu_com use elm_varctl , only : use_extrasnowlayers, use_polygonal_tundra use elm_varctl , only : use_fan + use elm_varctl , only : use_ocn_lnd_one_way use ch4varcon , only : allowlakeprod use pftvarcon , only : VMAX_MINSURF_P_vr, KM_MINSURF_P_vr, pinit_beta1, pinit_beta2 use soilorder_varcon, only : smax, ks_sorption @@ -5912,14 +5913,16 @@ subroutine col_wf_init(this, begc, endc) avgflag='A', long_name='sub-surface drainage', & ptr_col=this%qflx_drain, c2l_scale_type='urbanf') - call hist_addfld1d (fname='QH2OOCN', units='mm/s', & - avgflag='A', long_name='Ocean inundation infiltration', & - ptr_col=this%qflx_h2oocn_drain, c2l_scale_type='urbanf') + if (use_ocn_lnd_one_way) then + call hist_addfld1d (fname='QH2OOCN', units='mm/s', & + avgflag='A', long_name='Ocean inundation infiltration', & + ptr_col=this%qflx_h2oocn_drain, c2l_scale_type='urbanf') - this%qflx_lnd2ocn(begc:endc) = spval - call hist_addfld1d (fname='QLND2OCN', units='mm/s', & - avgflag='A', long_name='land to ocean drainage', & - ptr_col=this%qflx_lnd2ocn, c2l_scale_type='urbanf') + this%qflx_lnd2ocn(begc:endc) = spval + call hist_addfld1d (fname='QLND2OCN', units='mm/s', & + avgflag='A', long_name='land to ocean drainage', & + ptr_col=this%qflx_lnd2ocn, c2l_scale_type='urbanf') + endif this%qflx_irr_demand(begc:endc) = spval call hist_addfld1d (fname='QIRRIG_WM', units='mm/s', & From 80239195debe49b8866f9043042b1804d88a8fe4 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Tue, 8 Jul 2025 20:38:28 -0700 Subject: [PATCH 151/398] add test for lnd-docn one-way coupling --- .../elm/lnd_docn_1way/shell_commands | 16 ++++++++++++++++ .../testmods_dirs/elm/lnd_docn_1way/user_nl_cpl | 1 + .../testmods_dirs/elm/lnd_docn_1way/user_nl_elm | 2 ++ 3 files changed, 19 insertions(+) create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_cpl create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands new file mode 100644 index 000000000000..f714889be12a --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands @@ -0,0 +1,16 @@ +./xmlchange DATM_MODE=CLMGSWP3v1 +./xmlchange LND_DOMAIN_FILE=domain_global_coastline_merit_90m.nc +./xmlchange ATM_DOMAIN_FILE=domain_global_coastline_merit_90m.nc +./xmlchange LND_DOMAIN_PATH=/compyfs/xudo627/lnd-docn-1way/inputdata +./xmlchange ATM_DOMAIN_PATH=/compyfs/xudo627/lnd-docn-1way/inputdata + +./xmlchange --file env_run.xml --id SSTICE_YEAR_START --val 1980 +./xmlchange --file env_run.xml --id SSTICE_YEAR_END --val 1981 +./xmlchange --file env_run.xml --id SSTICE_YEAR_ALIGN --val 1980 + +./xmlchange --file env_run.xml --id DATM_CLMNCEP_YR_START --val 1980 +./xmlchange --file env_run.xml --id DATM_CLMNCEP_YR_END --val 1981 +./xmlchange --file env_run.xml --id DATM_CLMNCEP_YR_ALIGN --val 1980 + +./xmlchange PIO_TYPENAME_OCN=netcdf # pnetcdf doesn't support NETCDF4 +./xmlchange NTASKS=600 \ No newline at end of file diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_cpl b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_cpl new file mode 100644 index 000000000000..29fe76ff4deb --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_cpl @@ -0,0 +1 @@ +ocn_lnd_one_way = .true. \ No newline at end of file diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm new file mode 100644 index 000000000000..b3facd4017df --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm @@ -0,0 +1,2 @@ +fsurdat = '/compyfs/xudo627/lnd-docn-1way/inputdata/surfdata_global_coastline_merit_90m_calibrated_c221109.nc' +flndtopo = '/compyfs/xudo627/lnd-docn-1way/inputdata/surfdata_global_coastline_merit_90m_fd2.5_c221109.nc' \ No newline at end of file From f0d165b81a7979e890cc2e4d4472015bc4a7b081 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Mon, 28 Jul 2025 13:39:25 -0700 Subject: [PATCH 152/398] add lnd-docn-1way test --- cime_config/tests.py | 3 ++- .../testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands | 6 ++++-- .../testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cime_config/tests.py b/cime_config/tests.py index 304227e0b871..b19aa929b02c 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -101,7 +101,8 @@ "ERS.ELM_USRDAT.I1850ELM.elm-usrdat", "ERS.r05_r05.IELM.elm-lnd_rof_2way", "ERS.r05_r05.IELM.elm-V2_ELM_MOSART_features", - "ERS.ELM_USRDAT.IELM.elm-surface_water_dynamics" + "ERS.ELM_USRDAT.IELM.elm-surface_water_dynamics", + "SMS.ELM_USRDAT.GTSM2ELM.elm-lnd_docn_1way" ) }, diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands index f714889be12a..af8ffaa149a6 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands @@ -1,8 +1,10 @@ ./xmlchange DATM_MODE=CLMGSWP3v1 ./xmlchange LND_DOMAIN_FILE=domain_global_coastline_merit_90m.nc ./xmlchange ATM_DOMAIN_FILE=domain_global_coastline_merit_90m.nc -./xmlchange LND_DOMAIN_PATH=/compyfs/xudo627/lnd-docn-1way/inputdata -./xmlchange ATM_DOMAIN_PATH=/compyfs/xudo627/lnd-docn-1way/inputdata +./xmlchange LND_DOMAIN_PATH="\$DIN_LOC_ROOT/share/domains" +./xmlchange ATM_DOMAIN_PATH="\$DIN_LOC_ROOT/share/domains" + +./xmlchange DOCN_GTSM_FILENAME=domain_global_coastline_merit_90m.nc ./xmlchange --file env_run.xml --id SSTICE_YEAR_START --val 1980 ./xmlchange --file env_run.xml --id SSTICE_YEAR_END --val 1981 diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm index b3facd4017df..350343cc0091 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/user_nl_elm @@ -1,2 +1,2 @@ -fsurdat = '/compyfs/xudo627/lnd-docn-1way/inputdata/surfdata_global_coastline_merit_90m_calibrated_c221109.nc' -flndtopo = '/compyfs/xudo627/lnd-docn-1way/inputdata/surfdata_global_coastline_merit_90m_fd2.5_c221109.nc' \ No newline at end of file +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/surfdata_global_coastline_merit_90m_calibrated_c221109.nc' +flndtopo = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/surfdata_global_coastline_merit_90m_calibrated_c221109.nc' \ No newline at end of file From d59fb4ded4e7c31278faa0425f3b8866576be2b0 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Fri, 5 Dec 2025 08:59:22 -0800 Subject: [PATCH 153/398] fix typo to change kh2o to kssh --- components/data_comps/docn/src/docn_comp_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/data_comps/docn/src/docn_comp_mod.F90 b/components/data_comps/docn/src/docn_comp_mod.F90 index 480d46ce3cf3..8fce72bf2c31 100644 --- a/components/data_comps/docn/src/docn_comp_mod.F90 +++ b/components/data_comps/docn/src/docn_comp_mod.F90 @@ -666,7 +666,7 @@ subroutine docn_comp_run(EClock, x2o, o2x, & o2x%rAttr(kq ,n) = 0.0_R8 ! make sure frazil is 0. MPAS-seaice will still use it. o2x%rAttr(kfraz,n) = 0.0_R8 - if (kh2o /= 0) then + if (kssh /= 0) then o2x%rAttr(kssh, n) = 0.0_R8 endif if (kh2o /= 0) then From 327986c05b477e3eda3a0d992df81538ca257c1d Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 5 Dec 2025 10:18:02 -0700 Subject: [PATCH 154/398] EAMXX: This test had fails in elm that we don't care about Changing to 1 thrd fixes the elm issue and doesn't really cost us any coverage (the eamxx stuff will run in parallel on GPU). [BFB] --- 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 304227e0b871..8908efea206a 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -740,7 +740,7 @@ # each test runs with 225 dynamics and 100 physics columns, roughly size of ne2 "tests" : ( "ERS_P16_Ln22.ne30pg2_ne30pg2.FIOP-SCREAMv1-DP.eamxx-dpxx-dycomsrf01", - "ERS_P16_Ln22.ne30pg2_ne30pg2.FIOP-SCREAMv1-DP.eamxx-dpxx-arm97", + "ERS_P16x1_Ln22.ne30pg2_ne30pg2.FIOP-SCREAMv1-DP.eamxx-dpxx-arm97", "ERS_P16_Ln22.ne30pg2_ne30pg2.FIOP-SCREAMv1-DP.eamxx-dpxx-comble", "ERS_P16_Ln22.ne30pg2_ne30pg2.FRCE-SCREAMv1-DP", ) From 1b814c4c3eed0ca4863f2624439e6aee3185fc6c Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Fri, 5 Dec 2025 12:46:19 -0600 Subject: [PATCH 155/398] Add variables for wave momentum coupling to moab seq_flds Need wav_atm_coup to be defined because its used in the common shr_flux_mod. Also add the other variables for wave momentum coupling that were added to MCT --- driver-moab/shr/seq_flds_mod.F90 | 108 +++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 14 deletions(-) diff --git a/driver-moab/shr/seq_flds_mod.F90 b/driver-moab/shr/seq_flds_mod.F90 index 9aa3be8d5b1a..ecb874dc0ee1 100644 --- a/driver-moab/shr/seq_flds_mod.F90 +++ b/driver-moab/shr/seq_flds_mod.F90 @@ -174,6 +174,8 @@ module seq_flds_mod logical :: rof_sed ! .true. if river model includes sediment character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on + character(len=CS) :: wav_atm_coup ! 'twoway' if wave-atm two-way coupling turned on + character(len=CS) :: wav_ice_coup ! 'twoway' if wave-ice two-way coupling turned on !---------------------------------------------------------------------------- ! metadata @@ -409,7 +411,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) glc_nec, glc_nzoc, ice_ncat, seq_flds_i2o_per_cat, flds_bgc_oi, & nan_check_component_fields, rof_heat, atm_flux_method, atm_gustiness, & rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, rof_sed, & - wav_ocn_coup + wav_ocn_coup,wav_atm_coup, wav_ice_coup ! user specified new fields integer, parameter :: nfldmax = 200 @@ -455,6 +457,8 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ocn_rof_two_way = .false. rof_sed = .false. wav_ocn_coup = 'none' + wav_atm_coup = 'none' + wav_ice_coup = 'none' unitn = shr_file_getUnit() write(logunit,"(A)") subname//': read seq_cplflds_inparm namelist from: '& @@ -492,6 +496,8 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call shr_mpi_bcast(ocn_rof_two_way, mpicom) call shr_mpi_bcast(rof_sed, mpicom) call shr_mpi_bcast(wav_ocn_coup, mpicom) + call shr_mpi_bcast(wav_atm_coup, mpicom) + call shr_mpi_bcast(wav_ice_coup, mpicom) call glc_elevclass_init(glc_nec) call glc_zocnclass_init(glc_nzoc) @@ -678,7 +684,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2r_states,"Sa_u") call seq_flds_add(a2x_states_to_rof,"Sa_u") endif - call seq_flds_add(x2w_states,"Sa_u") + if (wav_atm_coup .ne. 'none') call seq_flds_add(x2w_states,"Sa_u") longname = 'Zonal wind at the lowest model level' stdname = 'eastward_wind' units = 'm s-1' @@ -693,7 +699,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2r_states,"Sa_v") call seq_flds_add(a2x_states_to_rof,"Sa_v") endif - call seq_flds_add(x2w_states,"Sa_v") + if (wav_atm_coup .ne. 'none') call seq_flds_add(x2w_states,"Sa_v") longname = 'Meridional wind at the lowest model level' stdname = 'northward_wind' units = 'm s-1' @@ -742,7 +748,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2r_states,"Sa_tbot") call seq_flds_add(a2x_states_to_rof,"Sa_tbot") endif - call seq_flds_add(x2w_states,"Sa_tbot") + if (wav_atm_coup .ne. 'none') call seq_flds_add(x2w_states,"Sa_tbot") longname = 'Temperature at the lowest model level' stdname = 'air_temperature' units = 'K' @@ -1538,7 +1544,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ! Fractional ice coverage wrt ocean call seq_flds_add(i2x_states,"Si_ifrac") call seq_flds_add(x2o_states,"Si_ifrac") - call seq_flds_add(x2w_states,"Si_ifrac") + if (wav_ice_coup .ne. 'none') call seq_flds_add(x2w_states,"Si_ifrac") longname = 'Fractional ice coverage wrt ocean' stdname = 'sea_ice_area_fraction' units = '1' @@ -2195,7 +2201,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ! Sea ice thickness call seq_flds_add(i2x_states,"Si_ithick") - call seq_flds_add(x2w_states,"Si_ithick") + if (wav_ice_coup .ne. 'none') call seq_flds_add(x2w_states,"Si_ithick") longname = 'Sea ice thickness' stdname = 'sea_ice_thickness' units = 'm' @@ -2531,6 +2537,14 @@ subroutine seq_flds_set(nmlfile, ID, infodata) ! wav->ocn and ocn->wav !----------------------------- if (wav_ocn_coup == 'twoway') then + call seq_flds_add(w2x_states,'Sw_Hs') + call seq_flds_add(x2o_states,'Sw_Hs') + longname = 'Significant wave height' + stdname = 'significant_wave_height' + units = 'm' + attname = 'Sw_Hs' + call metadata_set(attname, longname, stdname, units) + call seq_flds_add(w2x_states,'Sw_ustokes_wavenumber_1') call seq_flds_add(x2o_states,'Sw_ustokes_wavenumber_1') longname = 'Partitioned Stokes drift u component, wavenumber 1' @@ -2627,14 +2641,6 @@ subroutine seq_flds_set(nmlfile, ID, infodata) attname = 'Sw_vstokes_wavenumber_6' call metadata_set(attname, longname, stdname, units) - call seq_flds_add(w2x_states,'Sw_Hs') - call seq_flds_add(x2o_states,'Sw_Hs') - longname = 'Significant wave height' - stdname = 'significant_wave_height' - units = 'm' - attname = 'Sw_Hs' - call metadata_set(attname, longname, stdname, units) - call seq_flds_add(w2x_states,'Sw_Fp') call seq_flds_add(x2o_states,'Sw_Fp') longname = 'Peak wave frequency' @@ -2650,6 +2656,80 @@ subroutine seq_flds_set(nmlfile, ID, infodata) units = 'deg' attname = 'Sw_Dp' call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faww_Tawx') + call seq_flds_add(x2o_fluxes,'Faww_Tawx') + longname = 'Zonal wave supported stress' + stdname = 'Zonal_wave_supported_stress' + units = 'N m-2' + attname = 'Faww_Tawx' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faww_Tawy') + call seq_flds_add(x2o_fluxes,'Faww_Tawy') + longname = 'Meridional wave supported wind stress' + stdname = 'Meridional_wave_supported_wind_stress' + units = 'N m-2' + attname = 'Faww_Tawy' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Fwow_Twox') + call seq_flds_add(x2o_fluxes,'Fwow_Twox') + longname = 'Zonal wave to ocean wind stress' + stdname = 'Zonal_wave_to_ocean_wind_stress' + units = 'N m-2' + attname = 'Fwow_Twox' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Fwow_Twoy') + call seq_flds_add(x2o_fluxes,'Fwow_Twoy') + longname = 'Meridional wave to ocean wind stress' + stdname = 'Meridional_wave_to_ocean_wind_stress' + units = 'N m-2' + attname = 'Fwow_Twoy' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faow_Tocx') + call seq_flds_add(x2o_fluxes,'Faow_Tocx') + longname = 'Zonal Net ocean wind stress by wave model' + stdname = 'Zonal_net_ocean_wind_stress_wavemodel' + units = 'N m-2' + attname = 'Faow_Tocx' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_fluxes,'Faow_Tocy') + call seq_flds_add(x2o_fluxes,'Faow_Tocy') + longname = 'Meridional Net ocean wind stress by wave model' + stdname = 'Meridional_net_ocean_wind_stress_wavemodel' + units = 'N m-2' + attname = 'Faow_Tocy' + call metadata_set(attname, longname, stdname, units) + endif + + if (wav_atm_coup == 'twoway' .or. wav_ocn_coup == 'twoway') then + call seq_flds_add(w2x_states,'Sw_Charn') + if (wav_ocn_coup == 'twoway') call seq_flds_add(x2o_states,'Sw_Charn') + longname = 'Charnock coefficent based on sea state' + stdname = 'Charnock_coefficent_based_on_sea_state' + units = '' + attname = 'Sw_Charn' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_states,'Sw_Ustar') + if (wav_ocn_coup == 'twoway') call seq_flds_add(x2o_states,'Sw_Ustar') + longname = 'Friction Velocity based on sea state' + stdname = 'Frcition_velocity_based_on_sea_state' + units = '' + attname = 'Sw_Ustar' + call metadata_set(attname, longname, stdname, units) + + call seq_flds_add(w2x_states,'Sw_Z0') + if (wav_ocn_coup == 'twoway') call seq_flds_add(x2o_states,'Sw_Z0') + longname = 'Surface Roughness Length based on wave state' + stdname = 'Surface_roughness_length_based_on_wave_state' + units = '' + attname = 'Sw_Z0' + call metadata_set(attname, longname, stdname, units) endif !----------------------------- From a31aa7afc7a75ab2a4e39a3ef270262384b6dbe6 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 12:22:21 -0800 Subject: [PATCH 156/398] lots of renaming --- components/eam/src/physics/cam/zm_conv.F90 | 362 ++++++++++----------- 1 file changed, 179 insertions(+), 183 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index da492c923d53..923021576416 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -97,7 +97,7 @@ end subroutine zm_convi !=================================================================================================== subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & - t_mid, qh, omega, p_mid_in, p_int_in, p_del_in, & + t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & geos, z_mid_in, z_int_in, pbl_hgt, & tpert, landfrac, t_star, q_star, & lengath, ideep, maxg, jctop, jcbot, jt, & @@ -115,7 +115,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & logical, intent(in ) :: is_first_step ! flag for first step of run real(r8), intent(in ) :: delt ! model time-step [s] real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] - real(r8), dimension(pcols,pver), intent(in ) :: qh ! specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(in ) :: q_mid_in ! specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: omega ! vertical pressure velocity [Pa/s] real(r8), dimension(pcols,pver), intent(in ) :: p_mid_in ! mid-point pressure [Pa] real(r8), dimension(pcols,pverp),intent(in ) :: p_int_in ! interface pressure [Pa] @@ -164,10 +164,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] real(r8), dimension(pcols) :: z_srf ! surface altitude [m] - real(r8), dimension(pcols,pver) :: dlg ! gathered detraining cld h2o tend - real(r8), dimension(pcols,pverp):: pflxg ! gathered precip flux at each level - real(r8), dimension(pcols,pver) :: cug ! gathered condensation rate - real(r8), dimension(pcols,pver) :: evpg ! gathered evap rate of rain in downdraft real(r8), dimension(pcols) :: mumax ! max value of mu/dp integer, dimension(pcols) :: pbl_top ! pbl top indices @@ -181,42 +177,41 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, dimension(pcols) :: lon ! index of onset level for deep convection integer, dimension(pcols) :: maxi ! index of level with largest moist static energy - real(r8), dimension(pcols,pver) :: tpm1 ! time n-1 parcel temperatures - real(r8), dimension(pcols,pver) :: qstpm1 ! time n-1 parcel saturation specific humidity - real(r8), dimension(pcols) :: tlm1 ! time n-1 parcel Temperature at LCL - integer, dimension(pcols) :: lclm1 ! time n-1 base level index of deep cumulus convection - integer, dimension(pcols) :: lelm1 ! time n-1 index of highest theoretical convective plume - integer, dimension(pcols) :: lonm1 ! time n-1 index of onset level for deep convection - integer, dimension(pcols) :: maxim1 ! time n-1 index of level with largest moist static energy - real(r8), dimension(pcols) :: capem1 ! time n-1 CAPE + real(r8), dimension(pcols,pver) :: tp_m1 ! time n-1 parcel temperatures + real(r8), dimension(pcols,pver) :: qstp_m1 ! time n-1 parcel saturation specific humidity + real(r8), dimension(pcols) :: tl_m1 ! time n-1 parcel Temperature at LCL + integer, dimension(pcols) :: lcl_m1 ! time n-1 base level index of deep cumulus convection + integer, dimension(pcols) :: lel_m1 ! time n-1 index of highest theoretical convective plume + integer, dimension(pcols) :: lon_m1 ! time n-1 index of onset level for deep convection + integer, dimension(pcols) :: maxi_m1 ! time n-1 index of level with largest moist static energy + real(r8), dimension(pcols) :: cape_m1 ! time n-1 CAPE logical cape_calc_msemax_klev ! flag for compute_dilute_cape() real(r8) cape_threshold_alt ! local cape_threshold to allow exceptions when calling zm_closure() with dcape trigger integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep - real(r8), dimension(pcols,pver) :: qg ! gathered mid-point env specific humidity - real(r8), dimension(pcols,pver) :: q_int ! gathered interface env specific humidity + real(r8), dimension(pcols,pver) :: q_mid_g ! gathered mid-point env specific humidity + real(r8), dimension(pcols,pver) :: q_int_g ! gathered interface env specific humidity real(r8), dimension(pcols,pver) :: t_mid_g ! gathered temperature at interface - real(r8), dimension(pcols,pver) :: pg ! gathered values of p + real(r8), dimension(pcols,pver) :: p_mid_g ! gathered values of p_mid real(r8), dimension(pcols,pver) :: z_mid_g ! gathered values of z_mid - real(r8), dimension(pcols,pver) :: sg ! gathered values of s - real(r8), dimension(pcols,pver) :: s_int ! gathered upper interface dry static energy - real(r8), dimension(pcols,pver) :: tpg ! gathered values of tp + real(r8), dimension(pcols,pver) :: s_mid_g ! gathered values of s + real(r8), dimension(pcols,pver) :: s_int_g ! gathered upper interface dry static energy + real(r8), dimension(pcols,pver) :: tp_g ! gathered values of tp real(r8), dimension(pcols,pverp):: z_int_g ! gathered values of z_int - real(r8), dimension(pcols,pver) :: qstpg ! gathered values of qstp - real(r8), dimension(pcols,pver) :: ug ! gathered values of u - real(r8), dimension(pcols,pver) :: vg ! gathered values of v - real(r8), dimension(pcols,pver) :: omegag ! gathered values of omega - real(r8), dimension(pcols,pver) :: rprdg ! gathered rain production rate - real(r8), dimension(pcols) :: capeg ! gathered convective available potential energy - real(r8), dimension(pcols) :: tlg ! gathered values of tl - real(r8), dimension(pcols) :: landfracg ! gathered landfrac - real(r8), dimension(pcols) :: tpertg ! gathered values of tpert (temperature perturbation from PBL) - integer, dimension(pcols) :: lclg ! gathered values of lcl level index - integer, dimension(pcols) :: lelg ! gathered values of equilibrium level index - - ! work fields arising from gathered calculations + real(r8), dimension(pcols,pver) :: qstp_g ! gathered values of qstp + real(r8), dimension(pcols,pver) :: omega_g ! gathered values of omega + real(r8), dimension(pcols,pver) :: rprd_g ! gathered rain production rate + real(r8), dimension(pcols,pver) :: ql_g ! gathered cloud liquid water + real(r8), dimension(pcols) :: cape_g ! gathered convective available potential energy + real(r8), dimension(pcols) :: tl_g ! gathered values of tl + real(r8), dimension(pcols) :: landfrac_g ! gathered landfrac + real(r8), dimension(pcols) :: tpert_g ! gathered values of tpert (temperature perturbation from PBL) + integer, dimension(pcols) :: lcl_g ! gathered values of lcl level index + integer, dimension(pcols) :: lel_g ! gathered values of equilibrium level index + + real(r8), dimension(pcols,pver) :: dqdt ! gathered specific humidity tendency real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy @@ -224,14 +219,18 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux real(r8), dimension(pcols,pver) :: qu ! gathered updraft specific humidity real(r8), dimension(pcols,pver) :: su ! gathered updraft dry static energy - real(r8), dimension(pcols,pver) :: qs ! gathered saturation specific humidity - real(r8), dimension(pcols,pver) :: qlg ! gathered cloud liquid water + real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity + real(r8), dimension(pcols,pver) :: dl_g ! gathered detraining cld h2o tend + real(r8), dimension(pcols,pverp):: pflx_g ! gathered precip flux at each level + real(r8), dimension(pcols,pver) :: cu_g ! gathered condensation rate + real(r8), dimension(pcols,pver) :: evp_g ! gathered evap rate of rain in downdraft - real(r8), dimension(pcols) :: mb ! cloud base mass flux integer, dimension(pcols) :: jlcl ! updraft lifting cond level integer, dimension(pcols) :: j0 ! detrainment initiation level index integer, dimension(pcols) :: jd ! downdraft initiation level index + real(r8), dimension(pcols) :: cld_bass_mass_flux ! cloud base mass flux determined from zm_closure() + type(zm_microp_st) :: loc_microp_st ! local (gathered) convective microphysics state and tendencies integer i, ii, k, kk ! loop iterators @@ -261,18 +260,18 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & dqdt(i,k) = 0._r8 dsdt(i,k) = 0._r8 pflx(i,k) = 0._r8 - pflxg(i,k) = 0._r8 + pflx_g(i,k)= 0._r8 rprd(i,k) = 0._r8 zdu(i,k) = 0._r8 ql(i,k) = 0._r8 - qlg(i,k) = 0._r8 + ql_g(i,k) = 0._r8 dlf(i,k) = 0._r8 - dlg(i,k) = 0._r8 + dl_g(i,k) = 0._r8 end do prec(i) = 0._r8 rliq(i) = 0._r8 pflx(i,pverp) = 0 - pflxg(i,pverp) = 0 + pflx_g(i,pverp)= 0 pbl_top(i) = pver dsubcld(i) = 0._r8 jctop(i) = pver @@ -290,8 +289,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & end if !---------------------------------------------------------------------------- - ! calculate local pressure (mbs) and height (m) for both interface and mid-point - + ! calculate local pressure [mb] and height [m] for both interface and mid-point do i = 1,ncol z_srf(i) = geos(i)*zm_const%rgrav p_int(i,pver+1) = p_int_in(i,pver+1)*0.01_r8 @@ -322,20 +320,20 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = 1,pver do i = 1,ncol - q_mid(i,k) = qh(i,k) - s_mid(i,k) = t_mid(i,k) + (zm_const%grav/zm_const%cpair)*z_mid(i,k) - tp(i,k) = 0.0_r8 - s_int(i,k) = s_mid(i,k) - q_int(i,k) = q_mid(i,k) + q_mid(i,k) = q_mid_in(i,k) + s_mid(i,k) = t_mid(i,k) + (zm_const%grav/zm_const%cpair)*z_mid(i,k) + tp(i,k) = 0.0_r8 + s_int_g(i,k) = s_mid(i,k) + q_int_g(i,k) = q_mid(i,k) end do end do do i = 1,ncol - capeg(i) = 0._r8 - lclg(i) = 1 - lelg(i) = pver + cape_g(i) = 0._r8 + lcl_g(i) = 1 + lel_g(i) = pver maxg(i) = 1 - tlg(i) = 400._r8 + tl_g(i) = 400._r8 dsubcld(i) = 0._r8 end do @@ -363,11 +361,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & zm_param%num_cin, msg, & q_star, t_star, z_mid, p_mid, p_int, & pbl_top, tpert, & - tpm1, qstpm1, maxim1, tlm1, & - lclm1, lelm1, capem1, & + tp_m1, qstp_m1, maxi_m1, tl_m1, & + lcl_m1, lel_m1, cape_m1, & zm_const, zm_param, & cape_calc_msemax_klev, prev_msemax_klev ) - dcape(:ncol) = (cape(:ncol)-capem1(:ncol))/(delt*2._r8) + dcape(:ncol) = (cape(:ncol)-cape_m1(:ncol))/(delt*2._r8) endif !---------------------------------------------------------------------------- @@ -401,43 +399,41 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & end if end do + do ii = 1,lengath + ideep(ii)=gather_index(ii) + end do + if (lengath.eq.0) then ! Deallocate local microphysics arrays before returning if (zm_param%zm_microp) call zm_microp_st_dealloc(loc_microp_st) return end if - do ii = 1,lengath - ideep(ii)=gather_index(ii) - end do - !---------------------------------------------------------------------------- ! copy data to gathered arrays do i = 1,lengath do k = 1,pver dp(i,k) = 0.01_r8*p_del_in(ideep(i),k) - qg(i,k) = q_mid(ideep(i),k) + q_mid_g(i,k) = q_mid(ideep(i),k) t_mid_g(i,k) = t_mid(ideep(i),k) - pg(i,k) = p_mid(ideep(i),k) + p_mid_g(i,k) = p_mid(ideep(i),k) z_mid_g(i,k) = z_mid(ideep(i),k) - sg(i,k) = s_mid(ideep(i),k) - tpg(i,k) = tp(ideep(i),k) + s_mid_g(i,k) = s_mid(ideep(i),k) + tp_g(i,k) = tp(ideep(i),k) z_int_g(i,k) = z_int(ideep(i),k) - qstpg(i,k) = qstp(ideep(i),k) - omegag(i,k) = omega(ideep(i),k) - ug(i,k) = 0._r8 - vg(i,k) = 0._r8 + qstp_g(i,k) = qstp(ideep(i),k) + omega_g(i,k) = omega(ideep(i),k) end do z_int_g(i,pverp) = z_int(ideep(i),pver+1) - capeg(i) = cape(ideep(i)) - lclg(i) = lcl(ideep(i)) - lelg(i) = lel(ideep(i)) + cape_g(i) = cape(ideep(i)) + lcl_g(i) = lcl(ideep(i)) + lel_g(i) = lel(ideep(i)) maxg(i) = maxi(ideep(i)) - tlg(i) = tl(ideep(i)) - landfracg(i) = landfrac(ideep(i)) + tl_g(i) = tl(ideep(i)) + landfrac_g(i) = landfrac(ideep(i)) pbl_top_g(i) = pbl_top(ideep(i)) - tpertg(i) = tpert(ideep(i)) + tpert_g(i) = tpert(ideep(i)) end do !---------------------------------------------------------------------------- @@ -483,19 +479,19 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,lengath sdifr = 0._r8 qdifr = 0._r8 - if (sg(i,k) > 0._r8 .or. sg(i,k-1) > 0._r8) & - sdifr = abs((sg(i,k)-sg(i,k-1))/max(sg(i,k-1),sg(i,k))) - if (qg(i,k) > 0._r8 .or. qg(i,k-1) > 0._r8) & - qdifr = abs((qg(i,k)-qg(i,k-1))/max(qg(i,k-1),qg(i,k))) + if (s_mid_g(i,k) > 0._r8 .or. s_mid_g(i,k-1) > 0._r8) & + sdifr = abs((s_mid_g(i,k)-s_mid_g(i,k-1))/max(s_mid_g(i,k-1),s_mid_g(i,k))) + if (q_mid_g(i,k) > 0._r8 .or. q_mid_g(i,k-1) > 0._r8) & + qdifr = abs((q_mid_g(i,k)-q_mid_g(i,k-1))/max(q_mid_g(i,k-1),q_mid_g(i,k))) if (sdifr > interp_diff_min) then - s_int(i,k) = log(sg(i,k-1)/sg(i,k))*sg(i,k-1)*sg(i,k)/(sg(i,k-1)-sg(i,k)) + s_int_g(i,k) = log(s_mid_g(i,k-1)/s_mid_g(i,k))*s_mid_g(i,k-1)*s_mid_g(i,k)/(s_mid_g(i,k-1)-s_mid_g(i,k)) else - s_int(i,k) = 0.5_r8* (sg(i,k)+sg(i,k-1)) + s_int_g(i,k) = 0.5_r8*(s_mid_g(i,k)+s_mid_g(i,k-1)) end if if (qdifr > interp_diff_min) then - q_int(i,k) = log(qg(i,k-1)/qg(i,k))*qg(i,k-1)*qg(i,k)/(qg(i,k-1)-qg(i,k)) + q_int_g(i,k) = log(q_mid_g(i,k-1)/q_mid_g(i,k))*q_mid_g(i,k-1)*q_mid_g(i,k)/(q_mid_g(i,k-1)-q_mid_g(i,k)) else - q_int(i,k) = 0.5_r8* (qg(i,k)+qg(i,k-1)) + q_int_g(i,k) = 0.5_r8*(q_mid_g(i,k)+q_mid_g(i,k-1)) end if end do end do @@ -504,12 +500,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! calculate updraft and downdraft properties call zm_cloud_properties(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & - pg, z_mid_g, z_int_g, t_mid_g, sg, s_int, qg, & - landfracg, tpertg, & - maxg, lelg, jt, jlcl, j0, jd, & + p_mid_g, z_mid_g, z_int_g, t_mid_g, s_mid_g, s_int_g, q_mid_g, & + landfrac_g, tpert_g, & + maxg, lel_g, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - su, qu, qlg, sd, qd, & - qs, cug, evpg, pflxg, rprdg, & + su, qu, ql_g, sd, qd, & + q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & aero, loc_microp_st ) !--------------------------------------------------------------------------- @@ -517,12 +513,12 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = msg+1, pver do i = 1,lengath - du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - ed (i,k) = ed (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - cug (i,k) = cug (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - rprdg(i,k) = rprdg(i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - evpg (i,k) = evpg (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + ed (i,k) = ed (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + cu_g (i,k) = cu_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + rprd_g(i,k) = rprd_g(i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + evp_g (i,k)= evp_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) if (zm_param%zm_microp) then loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) @@ -533,11 +529,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_alt, & - lclg, lelg, jt, maxg, dsubcld, & - z_mid_g, z_int_g, pg, dp, t_mid_g, & - sg, qg, qs, qlg, s_int, q_int, & - tlg, tpg, qstpg, su, qu, & - mc, du, mu, md, qd, sd, capeg, mb ) + lcl_g, lel_g, jt, maxg, dsubcld, & + z_mid_g, z_int_g, p_mid_g, dp, t_mid_g, & + s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & + tl_g, tp_g, qstp_g, su, qu, & + mc, du, mu, md, qd, sd, cape_g, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. @@ -548,11 +544,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & mumax(i) = max(mumax(i), mu(i,k)/dp(i,k)) end do if (mumax(i) > 0._r8) then - mb(i) = min(mb(i),0.5_r8/(delt*mumax(i))) + cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),0.5_r8/(delt*mumax(i))) else - mb(i) = 0._r8 + cld_bass_mass_flux(i) = 0._r8 endif - if (zm_param%clos_dyn_adj) mb(i) = max(mb(i) - omegag(i,pbl_top_g(i))*0.01_r8, 0._r8) + if (zm_param%clos_dyn_adj) then + cld_bass_mass_flux(i) = max(cld_bass_mass_flux(i) - omega_g(i,pbl_top_g(i))*0.01_r8, 0._r8) + end if end do !---------------------------------------------------------------------------- @@ -560,7 +558,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & if (zm_param%no_deep_pbl) then do i = 1,lengath - if (z_mid_in(ideep(i),jt(i)) < pbl_hgt(ideep(i))) mb(i) = 0 + if (z_mid_in(ideep(i),jt(i)) < pbl_hgt(ideep(i))) then + cld_bass_mass_flux(i) = 0 + end if end do end if @@ -570,25 +570,25 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,lengath ! zero out micro data for inactive columns - if ( zm_param%zm_microp .and. mb(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) + if ( zm_param%zm_microp .and. cld_bass_mass_flux(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) do k = msg+1,pver - mu (i,k) = mu (i,k)*mb(i) - md (i,k) = md (i,k)*mb(i) - mc (i,k) = mc (i,k)*mb(i) - du (i,k) = du (i,k)*mb(i) - eu (i,k) = eu (i,k)*mb(i) - ed (i,k) = ed (i,k)*mb(i) - rprdg(i,k) = rprdg(i,k)*mb(i) - cug (i,k) = cug (i,k)*mb(i) - evpg (i,k) = evpg (i,k)*mb(i) - pflxg(i,k+1)= pflxg(i,k+1)*mb(i)*100._r8/zm_const%grav + mu (i,k) = mu (i,k) *cld_bass_mass_flux(i) + md (i,k) = md (i,k) *cld_bass_mass_flux(i) + mc (i,k) = mc (i,k) *cld_bass_mass_flux(i) + du (i,k) = du (i,k) *cld_bass_mass_flux(i) + eu (i,k) = eu (i,k) *cld_bass_mass_flux(i) + ed (i,k) = ed (i,k) *cld_bass_mass_flux(i) + rprd_g(i,k) = rprd_g(i,k) *cld_bass_mass_flux(i) + cu_g (i,k) = cu_g (i,k) *cld_bass_mass_flux(i) + evp_g (i,k) = evp_g (i,k) *cld_bass_mass_flux(i) + pflx_g(i,k+1) = pflx_g(i,k+1)*cld_bass_mass_flux(i)*100._r8/zm_const%grav if (zm_param%zm_microp) then - loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k)*mb(i) - loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k)*mb(i) - if (mb(i).eq.0._r8) then - qlg (i,k) = 0._r8 + loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k)*cld_bass_mass_flux(i) + loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k)*cld_bass_mass_flux(i) + if (cld_bass_mass_flux(i).eq.0._r8) then + ql_g(i,k) = 0._r8 end if end if @@ -598,19 +598,18 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! compute temperature and moisture changes due to convection. - call zm_calc_output_tend(pcols, ncol, pver, pverp, & - dqdt, dsdt, qg, qs, qu, & - su, du, q_int, s_int, dp, & - mu, md, sd, qd, qlg, & - dsubcld, jt, maxg, 1, lengath, msg, & - dlg, evpg, cug, & - loc_microp_st) + call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & + jt, maxg, dsubcld, dp, & + q_mid_g, q_mid_sat_g, s_int_g, q_int_g, su, qu, & + mu, du, md, sd, qd, ql_g, evp_g, cu_g, & + dsdt, dqdt, dl_g, & + loc_microp_st) !---------------------------------------------------------------------------- ! conservation check and adjusment #ifndef SCREAM_CONFIG_IS_CMAKE if (zm_param%zm_microp) call zm_microphysics_adjust(pcols, lengath, pver, jt, msg, delt, zm_const, & - dp, qg, dlg, dsdt, dqdt, rprdg, loc_microp_st) + dp, q_mid_g, dl_g, dsdt, dqdt, rprd_g, loc_microp_st) #endif !---------------------------------------------------------------------------- @@ -622,22 +621,22 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & #endif do i = 1,lengath ! q is updated to compute net precip. - q_mid(ideep(i),k) = qh(ideep(i),k) + 2._r8*delt*dqdt(i,k) - qtnd(ideep(i),k) = dqdt (i,k) - rprd(ideep(i),k) = rprdg(i,k) - zdu (ideep(i),k) = du (i,k) - mcon(ideep(i),k) = mc (i,k) - heat(ideep(i),k) = dsdt (i,k)*zm_const%cpair - dlf (ideep(i),k) = dlg (i,k) - pflx(ideep(i),k) = pflxg(i,k) - ql (ideep(i),k) = qlg (i,k) + q_mid(ideep(i),k) = q_mid_in(ideep(i),k) + 2._r8*delt*dqdt(i,k) + qtnd(ideep(i),k) = dqdt (i,k) + rprd(ideep(i),k) = rprd_g (i,k) + zdu (ideep(i),k) = du (i,k) + mcon(ideep(i),k) = mc (i,k) + heat(ideep(i),k) = dsdt (i,k)*zm_const%cpair + dlf (ideep(i),k) = dl_g (i,k) + pflx(ideep(i),k) = pflx_g (i,k) + ql (ideep(i),k) = ql_g (i,k) end do end do do i = 1,lengath jctop(ideep(i)) = jt(i) jcbot(ideep(i)) = maxg(i) - pflx(ideep(i),pverp) = pflxg(i,pverp) + pflx(ideep(i),pverp) = pflx_g(i,pverp) end do !---------------------------------------------------------------------------- @@ -654,9 +653,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,ncol do k = pver, msg+1, -1 if (zm_param%zm_microp) then - prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-q_mid_in(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt else - prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-qh(i,k)) - p_del_in(i,k)*(dlf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-q_mid_in(i,k)) - p_del_in(i,k)*(dlf(i,k))*2._r8*delt end if end do ! obtain final precipitation rate in m/s @@ -941,7 +940,7 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & integer, intent(in ) :: ncol ! actual number of columns integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! missing moisture levels + integer, intent(in ) :: msg ! number of levels to ignore at model top integer, dimension(pcols), intent(in ) :: jb ! updraft base level integer, dimension(pcols), intent(in ) :: jt ! updraft top level integer, dimension(pcols), intent(inout) :: j0 ! level where updraft begins detraining @@ -1095,7 +1094,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & integer, intent(in ) :: ncol ! actual number of columns integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! missing moisture levels + integer, intent(in ) :: msg ! number of levels to ignore at model top integer, dimension(pcols), intent(in ) :: jb ! updraft base level integer, dimension(pcols), intent(inout) :: jt ! updraft top level integer, dimension(pcols), intent(in ) :: j0 ! level where updraft begins detraining @@ -1214,7 +1213,7 @@ end subroutine zm_downdraft_properties subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & p_mid, z_mid, z_int, t_mid, s_mid, s_int, q_mid, & - landfrac, tpertg, & + landfrac, tpert_g, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, ql, sd, qd, & @@ -1230,7 +1229,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & integer, intent(in ) :: ncol ! actual number of columns for iteration integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! missing moisture levels + integer, intent(in ) :: msg ! number of levels to ignore at model top integer, intent(in ) :: limcnv ! convection limiting level real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! env pressure at mid-point real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! env altitude at mid-point @@ -1240,7 +1239,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(in ) :: s_int ! interface values of dry stat energy real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! env specific humidity real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction - real(r8), dimension(pcols), intent(in ) :: tpertg ! PBL temperature perturbation + real(r8), dimension(pcols), intent(in ) :: tpert_g ! PBL temperature perturbation integer, dimension(pcols), intent(in ) :: jb ! updraft base level integer, dimension(pcols), intent(in ) :: lel ! updraft parcel launch level integer, dimension(pcols), intent(out) :: jt ! updraft plume top @@ -1435,8 +1434,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add else - hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i)) - su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpertg(i) + hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i)) + su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i) end if end if end do ! i @@ -1853,7 +1852,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & z_mid, z_int, p_mid, dp, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & tl, tp, qstp, su, qu, & - mc, du, mu, md, qd, sd, cape, mb ) + mc, du, mu, md, qd, sd, cape, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the ! revised quasi-equilibrium hypothesis of Z02, in which a @@ -1872,7 +1871,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & integer, intent(in ) :: ncol ! actual number of columns integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: msg ! ? + integer, intent(in ) :: msg ! number of levels to ignore at model top real(r8), intent(in ) :: cape_threshold_in ! CAPE threshold for "cloud work function" (i.e. A) integer, dimension(pcols), intent(in ) :: lcl ! index of lcl integer, dimension(pcols), intent(in ) :: lel ! index of launch leve @@ -1902,7 +1901,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: qd ! dndraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: sd ! dndraft dry static energy real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy - real(r8), dimension(pcols), intent(out) :: mb ! cloud base mass flux + real(r8), dimension(pcols), intent(out) :: cld_bass_mass_flux! cloud base mass flux !---------------------------------------------------------------------------- ! Local variables real(r8), dimension(pcols,pver) :: dboydt ! integrand of cape change @@ -1935,7 +1934,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & !---------------------------------------------------------------------------- ! Calculate sub-cloud tendencies of virtual temperature and humidity do i = 1,ncol - mb(i) = 0._r8 + cld_bass_mass_flux(i) = 0._r8 eb = p_mid(i,mx(i))*q_mid(i,mx(i))/ (zm_const%epsilo+q_mid(i,mx(i))) dtbdt(i) = (1._r8/dsubcld(i)) & *( mu(i,mx(i))*(s_int(i,mx(i))-su(i,mx(i))) & @@ -2016,10 +2015,10 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & do i = 1,ncol dltaa = -1._r8*( cape(i) - cape_threshold_in ) if (dadt(i) /= 0._r8) then - mb(i) = max( dltaa/zm_param%tau/dadt(i), 0._r8) + cld_bass_mass_flux(i) = max( dltaa/zm_param%tau/dadt(i), 0._r8) end if if (zm_param%zm_microp .and. mx(i)-jt(i) < 2._r8) then - mb(i) = 0.0_r8 + cld_bass_mass_flux(i) = 0.0_r8 end if end do @@ -2029,13 +2028,12 @@ end subroutine zm_closure !=================================================================================================== -subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & - dqdt, dsdt, q, qs, qu, & - su, du, q_int, s_int, dp, & - mu, md, sd, qd, ql, & - dsubcld, jt, mx, il1g, il2g, msg, & - dl, evp, cu, & - loc_microp_st) +subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & + jt, mx, dsubcld, dp, & + q, qs, s_int, q_int, su, qu, & + mu, du, md, sd, qd, ql, evp, cu, & + dsdt, dqdt, dl, & + loc_microp_st) !---------------------------------------------------------------------------- ! Purpose: calculate final output tendencies for the ZM convection scheme !---------------------------------------------------------------------------- @@ -2046,41 +2044,39 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & integer, intent(in ) :: ncol ! actual number of columns integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - integer, intent(in ) :: il1g ! - integer, intent(in ) :: il2g ! - integer, intent(in ) :: msg ! - real(r8), dimension(pcols,pver), intent(in ) :: q ! - real(r8), dimension(pcols,pver), intent(in ) :: qs ! - real(r8), dimension(pcols,pver), intent(in ) :: qu ! - real(r8), dimension(pcols,pver), intent(in ) :: su ! - real(r8), dimension(pcols,pver), intent(in ) :: du ! - real(r8), dimension(pcols,pver), intent(in ) :: q_int ! - real(r8), dimension(pcols,pver), intent(in ) :: s_int ! - real(r8), dimension(pcols,pver), intent(in ) :: dp ! - real(r8), dimension(pcols,pver), intent(in ) :: mu ! - real(r8), dimension(pcols,pver), intent(in ) :: md ! - real(r8), dimension(pcols,pver), intent(in ) :: sd ! - real(r8), dimension(pcols,pver), intent(in ) :: qd ! - real(r8), dimension(pcols,pver), intent(in ) :: ql ! - real(r8), dimension(pcols,pver), intent(in ) :: evp ! - real(r8), dimension(pcols,pver), intent(in ) :: cu ! - real(r8), dimension(pcols), intent(in ) :: dsubcld ! - real(r8), dimension(pcols,pver), intent( out) :: dqdt ! - real(r8), dimension(pcols,pver), intent( out) :: dsdt ! - real(r8), dimension(pcols,pver), intent( out) :: dl ! + integer, intent(in ) :: msg ! number of levels to ignore at model top + integer, dimension(pcols), intent(in ) :: jt ! level index of updraft top + integer, dimension(pcols), intent(in ) :: mx ! level index of updraft base + real(r8), dimension(pcols), intent(in ) :: dsubcld ! sub-cloud layer thickness + real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness + real(r8), dimension(pcols,pver), intent(in ) :: q ! ambient mid-point specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: qs ! ambient mid-point saturation specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: s_int ! ambient interface dry static energy + real(r8), dimension(pcols,pver), intent(in ) :: q_int ! ambient interface specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: su ! updraft dry static energy + real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: du ! updraft detrainment + real(r8), dimension(pcols,pver), intent(in ) :: md ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: sd ! downdraft dry static energy + real(r8), dimension(pcols,pver), intent(in ) :: qd ! downdraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: ql ! cloud liquid water + real(r8), dimension(pcols,pver), intent(in ) :: evp ! evaporation + real(r8), dimension(pcols,pver), intent(in ) :: cu ! updraft condensation + real(r8), dimension(pcols,pver), intent( out) :: dqdt ! output tendency for specific humidity + real(r8), dimension(pcols,pver), intent( out) :: dsdt ! output tendency for dry static energy + real(r8), dimension(pcols,pver), intent( out) :: dl ! output tendency for cloud liquid water type(zm_microp_st), intent(inout) :: loc_microp_st! convective microphysics state and tendencies !---------------------------------------------------------------------------- ! Local variables integer i,k integer kbm integer ktm - integer jt(pcols) - integer mx(pcols) real(r8) emc !---------------------------------------------------------------------------- ! initialize variables do k = msg+1, pver - do i = il1g,il2g + do i = 1,ncol dsdt(i,k) = 0._r8 dqdt(i,k) = 0._r8 dl(i,k) = 0._r8 @@ -2099,7 +2095,7 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & ! find the highest level top and bottom levels of convection ktm = pver kbm = pver - do i = il1g, il2g + do i = 1,ncol ktm = min(ktm,jt(i)) kbm = min(kbm,mx(i)) end do @@ -2107,7 +2103,7 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & !---------------------------------------------------------------------------- ! calculate large-scale tendencies do k = ktm,pver-1 - do i = il1g,il2g + do i = 1,ncol emc = -cu(i,k) + evp(i,k) ! condensation in updraft and evaporating rain in downdraft dsdt(i,k) = -zm_const%latvap/zm_const%cpair*emc + & @@ -2141,7 +2137,7 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, & !DIR$ NOINTERCHANGE! #endif do k = kbm,pver - do i = il1g,il2g + do i = 1,ncol if (k == mx(i)) then dsdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(su(i,k)-s_int(i,k)) & -md(i,k)*(sd(i,k)-s_int(i,k)) ) From b290ff12be9e873c770dd195a2b5e7d62dedc57e Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 13:27:06 -0800 Subject: [PATCH 157/398] create zm_gather() --- components/eam/src/physics/cam/zm_conv.F90 | 215 ++++++++++++--------- 1 file changed, 121 insertions(+), 94 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 923021576416..6c01e5ec058c 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -56,11 +56,12 @@ module zm_conv type(zm_param_t), public :: zm_param ! derived type to hold ZM tunable parameters !---------------------------------------------------------------------------- ! private variables - real(r8), parameter :: cape_threshold = 70._r8 ! threshold value of cape for deep convection - real(r8), parameter :: dcape_threshold = 0._r8 ! threshold value of dcape for deep convection - real(r8), parameter :: interp_diff_min = 1.E-6_r8 ! minimum threshold for interpolation method - see eq (4.109), (4.118), (4.119) - real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error - real(r8), parameter :: small = 1.e-20_r8 ! small number to limit blowup when normalizing by mass flux + real(r8), parameter :: cape_threshold_old = 70._r8 ! threshold value of cape for deep convection (old value before DCAPE) + real(r8), parameter :: cape_threshold_new = 0._r8 ! threshold value of cape for deep convection + real(r8), parameter :: dcape_threshold = 0._r8 ! threshold value of dcape for deep convection + real(r8), parameter :: interp_diff_min = 1.E-6_r8 ! minimum threshold for interpolation method - see eq (4.109), (4.118), (4.119) + real(r8), parameter :: omsm = 0.99999_r8 ! to prevent problems due to round off error + real(r8), parameter :: small = 1.e-20_r8 ! small number to limit blowup when normalizing by mass flux !=================================================================================================== contains !=================================================================================================== @@ -81,7 +82,7 @@ subroutine zm_convi(limcnv_in, no_deep_pbl_in) zm_param%no_deep_pbl = no_deep_pbl_in else zm_param%no_deep_pbl = .false. - endif + end if ! set zm_const using global values call zm_const_set_to_global(zm_const) @@ -96,13 +97,71 @@ end subroutine zm_convi !=================================================================================================== +subroutine zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & + cape_threshold_loc, ideep, lengath) + !---------------------------------------------------------------------------- + ! Purpose: determine length of gathered arrays + !---------------------------------------------------------------------------- + ! Arguments + integer, intent(in ) :: pcols ! maximum number of columns + integer, intent(in ) :: ncol ! actual number of columns + integer, intent(in ) :: pver ! number of mid-point vertical levels + integer, intent(in ) :: pverp ! number of interface vertical levels + logical, intent(in ) :: is_first_step ! flag for first step of run + real(r8), dimension(pcols), intent(in ) :: cape ! conv. avail. potential energy [J] + real(r8), dimension(pcols), intent(in ) :: dcape ! CAPE generated by dycor (dCAPE) [J] + real(r8), intent( out) :: cape_threshold_loc ! cape threshold + integer, dimension(pcols), intent( out) :: ideep ! flag for active columns + integer, intent( out) :: lengath ! number of columns for gathered arrays + !---------------------------------------------------------------------------- + ! Local variables + integer :: i, ii + integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep + !---------------------------------------------------------------------------- + ! set local threshold to be used for zm_closure() + if ( zm_param%trig_dcape .and. (.not.is_first_step) ) then + cape_threshold_loc = cape_threshold_new + else + cape_threshold_loc = cape_threshold_old + end if + + !---------------------------------------------------------------------------- + ! determine number of active columns + lengath = 0 + do i = 1,ncol + if ( zm_param%trig_dcape .and. (.not.is_first_step) ) then + if ( cape(i)>cape_threshold_loc .and. dcape(i)>dcape_threshold ) then + lengath = lengath + 1 + gather_index(lengath) = i + end if + else + if (cape(i) > cape_threshold_loc) then + lengath = lengath + 1 + gather_index(lengath) = i + end if + end if + end do + + !---------------------------------------------------------------------------- + ! set flag for active columns + do ii = 1,lengath + ideep(ii) = gather_index(ii) + end do + + !---------------------------------------------------------------------------- + return + +end subroutine zm_gather + +!=================================================================================================== + subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & geos, z_mid_in, z_int_in, pbl_hgt, & tpert, landfrac, t_star, q_star, & lengath, ideep, maxg, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & - mcon, pflx, zdu, mu, eu, du, md, ed, dp, dsubcld, & + mcon, pflx, zdu, mu, eu, du, md, ed, p_del, dsubcld, & ql, rliq, rprd, dlf, aero, microp_st ) !---------------------------------------------------------------------------- ! Purpose: Main driver for Zhang-Mcfarlane convection scheme @@ -147,7 +206,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8), dimension(pcols,pver), intent( out) :: du ! updraft detrainment [?] real(r8), dimension(pcols,pver), intent( out) :: md ! downdraft mass flux [?] real(r8), dimension(pcols,pver), intent( out) :: ed ! downdraft entrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: dp ! layer thickness [mb] + real(r8), dimension(pcols,pver), intent( out) :: p_del ! layer thickness [mb] real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and maxi [mb] real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep real(r8), dimension(pcols), intent( out) :: rliq ! reserved liquid (not yet in cldliq) for energy integrals @@ -186,10 +245,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, dimension(pcols) :: maxi_m1 ! time n-1 index of level with largest moist static energy real(r8), dimension(pcols) :: cape_m1 ! time n-1 CAPE - logical cape_calc_msemax_klev ! flag for compute_dilute_cape() - real(r8) cape_threshold_alt ! local cape_threshold to allow exceptions when calling zm_closure() with dcape trigger - - integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep + logical :: cape_calc_msemax_klev ! flag for compute_dilute_cape() + real(r8) :: cape_threshold_loc ! local CAPE threshold real(r8), dimension(pcols,pver) :: q_mid_g ! gathered mid-point env specific humidity real(r8), dimension(pcols,pver) :: q_int_g ! gathered interface env specific humidity @@ -211,7 +268,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, dimension(pcols) :: lcl_g ! gathered values of lcl level index integer, dimension(pcols) :: lel_g ! gathered values of equilibrium level index - real(r8), dimension(pcols,pver) :: dqdt ! gathered specific humidity tendency real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy @@ -366,42 +422,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & zm_const, zm_param, & cape_calc_msemax_klev, prev_msemax_klev ) dcape(:ncol) = (cape(:ncol)-cape_m1(:ncol))/(delt*2._r8) - endif + end if !---------------------------------------------------------------------------- ! determine whether ZM is active in each column (ideep=1) or not (ideep=0), - ! based on requirement that cape>0 and lel cape_threshold) then - lengath = lengath + 1 - gather_index(lengath) = i - end if - else - if (cape(i) > cape_threshold_alt .and. dcape(i) > dcape_threshold) then - ! use constant 0 or a separate threshold for capt because cape_threshold is for default trigger - lengath = lengath + 1 - gather_index(lengath) = i - end if - endif - else - if (cape(i) > cape_threshold) then - lengath = lengath + 1 - gather_index(lengath) = i - end if - end if - end do - - do ii = 1,lengath - ideep(ii)=gather_index(ii) - end do + call zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & + cape_threshold_loc, ideep, lengath) if (lengath.eq.0) then ! Deallocate local microphysics arrays before returning @@ -411,10 +438,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! copy data to gathered arrays - do i = 1,lengath do k = 1,pver - dp(i,k) = 0.01_r8*p_del_in(ideep(i),k) + p_del(i,k) = 0.01_r8*p_del_in(ideep(i),k) q_mid_g(i,k) = q_mid(ideep(i),k) t_mid_g(i,k) = t_mid(ideep(i),k) p_mid_g(i,k) = p_mid(ideep(i),k) @@ -438,7 +464,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! copy aerosol data to gathered arrays - if (zm_param%zm_microp) then if (aero%scheme == 'modal') then do m = 1, aero%nmodes @@ -468,7 +493,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = msg+1, pver do i = 1,lengath if (k >= maxg(i)) then - dsubcld(i) = dsubcld(i) + dp(i,k) + dsubcld(i) = dsubcld(i) + p_del(i,k) end if end do end do @@ -513,24 +538,24 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do k = msg+1, pver do i = 1,lengath - du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - ed (i,k) = ed (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - cu_g (i,k) = cu_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - rprd_g(i,k) = rprd_g(i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - evp_g (i,k)= evp_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + ed (i,k) = ed (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + cu_g (i,k) = cu_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + rprd_g(i,k) = rprd_g(i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + evp_g (i,k)= evp_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) if (zm_param%zm_microp) then - loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) - loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/dp(i,k) + loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) end if end do end do !---------------------------------------------------------------------------- - call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_alt, & + call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_loc, & lcl_g, lel_g, jt, maxg, dsubcld, & - z_mid_g, z_int_g, p_mid_g, dp, t_mid_g, & + z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & tl_g, tp_g, qstp_g, su, qu, & mc, du, mu, md, qd, sd, cape_g, cld_bass_mass_flux ) @@ -541,13 +566,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,lengath mumax(i) = 0 do k = msg+2, pver - mumax(i) = max(mumax(i), mu(i,k)/dp(i,k)) + mumax(i) = max(mumax(i), mu(i,k)/p_del(i,k)) end do if (mumax(i) > 0._r8) then cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),0.5_r8/(delt*mumax(i))) else cld_bass_mass_flux(i) = 0._r8 - endif + end if if (zm_param%clos_dyn_adj) then cld_bass_mass_flux(i) = max(cld_bass_mass_flux(i) - omega_g(i,pbl_top_g(i))*0.01_r8, 0._r8) end if @@ -599,7 +624,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & - jt, maxg, dsubcld, dp, & + jt, maxg, dsubcld, p_del, & q_mid_g, q_mid_sat_g, s_int_g, q_int_g, su, qu, & mu, du, md, sd, qd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & @@ -608,8 +633,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & !---------------------------------------------------------------------------- ! conservation check and adjusment #ifndef SCREAM_CONFIG_IS_CMAKE - if (zm_param%zm_microp) call zm_microphysics_adjust(pcols, lengath, pver, jt, msg, delt, zm_const, & - dp, q_mid_g, dl_g, dsdt, dqdt, rprd_g, loc_microp_st) + if (zm_param%zm_microp) then + call zm_microphysics_adjust(pcols, lengath, pver, jt, msg, delt, zm_const, & + p_del, q_mid_g, dl_g, dsdt, dqdt, rprd_g, loc_microp_st) + end if #endif !---------------------------------------------------------------------------- @@ -690,7 +717,7 @@ end subroutine zm_convr !=================================================================================================== subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & - pmid, pdel, t_mid, q_mid, prdprec, cldfrc, & + p_mid, p_del, t_mid, q_mid, prdprec, cldfrc, & tend_s, tend_q, tend_s_snwprd, tend_s_snwevmlt, & prec, snow, ntprprd, ntsnprd, flxprec, flxsnow, microp_st ) !---------------------------------------------------------------------------- @@ -711,8 +738,8 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels real(r8), intent(in ) :: deltat ! time step [s] - real(r8), dimension(pcols,pver), intent(in ) :: pmid ! midpoint pressure [Pa] - real(r8), dimension(pcols,pver), intent(in ) :: pdel ! layer thickness [Pa] + real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! midpoint pressure [Pa] + real(r8), dimension(pcols,pver), intent(in ) :: p_del ! layer thickness [Pa] real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! water vapor [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: prdprec ! precipitation production [kg/kg/s] @@ -766,7 +793,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & prec(:ncol) = prec(:ncol)*1000._r8 ! determine saturation vapor pressure - call qsat(t_mid(1:ncol, 1:pver), pmid(1:ncol, 1:pver), es(1:ncol, 1:pver), qs(1:ncol, 1:pver)) + call qsat( t_mid(1:ncol,1:pver), p_mid(1:ncol,1:pver), es(1:ncol,1:pver), qs(1:ncol,1:pver)) ! determine ice fraction in rain production (use cloud water parameterization fraction at present) call cldfrc_fice(ncol, t_mid, fice, fsnow_conv) @@ -783,7 +810,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & if (zm_param%old_snow) then if (t_mid(i,k) > zm_const%tfreez) then flxsntm(i) = 0._r8 - snowmlt(i) = flxsnow(i,k) * zm_const%grav/ pdel(i,k) + snowmlt(i) = flxsnow(i,k) * zm_const%grav/ p_del(i,k) else flxsntm(i) = flxsnow(i,k) snowmlt(i) = 0._r8 @@ -791,10 +818,10 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & else ! make sure melting snow doesn't reduce temperature below threshold if (t_mid(i,k) > zm_const%tfreez) then - dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/pdel(i,k)*deltat + dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/p_del(i,k)*deltat if (t_mid(i,k) + dum .le. zm_const%tfreez) then dum = (t_mid(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/deltat - dum = dum/(flxsnow(i,k)*zm_const%grav/pdel(i,k)) + dum = dum/(flxsnow(i,k)*zm_const%grav/p_del(i,k)) dum = max(0._r8,dum) dum = min(1._r8,dum) else @@ -802,7 +829,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & end if dum = dum*omsm flxsntm(i) = flxsnow(i,k)*(1.0_r8-dum) - snowmlt(i) = dum*flxsnow(i,k)*zm_const%grav/ pdel(i,k) + snowmlt(i) = dum*flxsnow(i,k)*zm_const%grav/ p_del(i,k) else flxsntm(i) = flxsnow(i,k) snowmlt(i) = 0._r8 @@ -824,10 +851,10 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! Don't evaporate rain formed in this layer, but if precip production ! is negative, remove from the available precip. Negative precip ! production occurs because of evaporation in downdrafts. - evplimit = min(evplimit, flxprec(i,k) * zm_const%grav / pdel(i,k)) + evplimit = min(evplimit, flxprec(i,k) * zm_const%grav / p_del(i,k)) ! Total evaporation cannot exceed input precipitation - evplimit = min(evplimit, (prec(i) - evpvint(i)) * zm_const%grav / pdel(i,k)) + evplimit = min(evplimit, (prec(i) - evpvint(i)) * zm_const%grav / p_del(i,k)) evpprec(i) = min(evplimit, evpprec(i)) @@ -847,7 +874,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & end if ! vertically integrated evaporation - evpvint(i) = evpvint(i) + evpprec(i) * pdel(i,k)/zm_const%grav + evpvint(i) = evpvint(i) + evpprec(i) * p_del(i,k)/zm_const%grav ! net precip production => production - evaporation ntprprd(i,k) = prdprec(i,k) - evpprec(i) @@ -866,7 +893,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & work1 = min(max(0._r8,flxsnow(i,k)/flxprec(i,k)),1._r8) else work1 = 0._r8 - endif + end if end if work2 = max(fsnow_conv(i,k), work1) if (snowmlt(i).gt.0._r8) work2 = 0._r8 @@ -874,14 +901,14 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & tend_s_snwprd (i,k) = prdprec(i,k)*work2*zm_const%latice tend_s_snwevmlt(i,k) = - ( evpsnow(i) + snowmlt(i) )*zm_const%latice else - ntsnprd(i,k) = prdsnow(i,k) - min(flxsnow(i,k)*zm_const%grav/pdel(i,k), evpsnow(i)+snowmlt(i)) + ntsnprd(i,k) = prdsnow(i,k) - min(flxsnow(i,k)*zm_const%grav/p_del(i,k), evpsnow(i)+snowmlt(i)) tend_s_snwprd (i,k) = prdsnow(i,k)*zm_const%latice - tend_s_snwevmlt(i,k) = -min(flxsnow(i,k)*zm_const%grav/pdel(i,k), evpsnow(i)+snowmlt(i) )*zm_const%latice + tend_s_snwevmlt(i,k) = -min(flxsnow(i,k)*zm_const%grav/p_del(i,k), evpsnow(i)+snowmlt(i) )*zm_const%latice end if ! precipitation fluxes - flxprec(i,k+1) = flxprec(i,k) + ntprprd(i,k) * pdel(i,k)/zm_const%grav - flxsnow(i,k+1) = flxsnow(i,k) + ntsnprd(i,k) * pdel(i,k)/zm_const%grav + flxprec(i,k+1) = flxprec(i,k) + ntprprd(i,k) * p_del(i,k)/zm_const%grav + flxsnow(i,k+1) = flxsnow(i,k) + ntsnprd(i,k) * p_del(i,k)/zm_const%grav ! protect against rounding error flxprec(i,k+1) = max(flxprec(i,k+1), 0._r8) @@ -907,9 +934,9 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & dum = (flxsnow(i,pverp)-flxprec(i,pverp))*zm_const%grav do k = pver, 1, -1 if (ntsnprd(i,k)>ntprprd(i,k).and. dum > 0._r8) then - ntsnprd(i,k) = ntsnprd(i,k) - dum/pdel(i,k) - tend_s_snwevmlt(i,k) = tend_s_snwevmlt(i,k) - dum/pdel(i,k)*zm_const%latice - tend_s(i,k) = tend_s(i,k) - dum/pdel(i,k)*zm_const%latice + ntsnprd(i,k) = ntsnprd(i,k) - dum/p_del(i,k) + tend_s_snwevmlt(i,k) = tend_s_snwevmlt(i,k) - dum/p_del(i,k)*zm_const%latice + tend_s(i,k) = tend_s(i,k) - dum/p_del(i,k)*zm_const%latice dum = 0._r8 end if end do @@ -1849,7 +1876,7 @@ end subroutine zm_cloud_properties subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & lcl, lel, jt, mx, dsubcld, & - z_mid, z_int, p_mid, dp, t_mid, & + z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & tl, tp, qstp, su, qu, & mc, du, mu, md, qd, sd, cape, cld_bass_mass_flux ) @@ -1881,7 +1908,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: z_mid ! altitude (m) real(r8), dimension(pcols,pverp),intent(in ) :: z_int ! height of interface levels real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! ambient pressure (mb) - real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness of layers + real(r8), dimension(pcols,pver), intent(in ) :: p_del ! pressure thickness of layers real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! ambient temperature real(r8), dimension(pcols,pver), intent(in ) :: s_mid ! ambient dry static energy (normalized) real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! ambient specific humidity @@ -1953,22 +1980,22 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & do i = 1,ncol ! cloud top if (k==jt(i)) then - dtmdt(i,k) = (1._r8/dp(i,k)) & + dtmdt(i,k) = (1._r8/p_del(i,k)) & *(mu(i,k+1)*(su(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & + md(i,k+1)*(sd(i,k+1)-s_int(i,k+1))) - dqmdt(i,k) = (1._r8/dp(i,k)) & + dqmdt(i,k) = (1._r8/p_del(i,k)) & *(mu(i,k+1)*(qu(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & + md(i,k+1)*(qd(i,k+1)-q_int(i,k+1))) end if ! below cloud top if ( k>jt(i) .and. k= lel(i) .and. k <= mx(i) - 1) then dadt(i) = dadt(i) + dboydt(i,k)*(z_int(i,k)-z_int(i,k+1)) - endif + end if end do end do @@ -2029,7 +2056,7 @@ end subroutine zm_closure !=================================================================================================== subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & - jt, mx, dsubcld, dp, & + jt, mx, dsubcld, p_del, & q, qs, s_int, q_int, su, qu, & mu, du, md, sd, qd, ql, evp, cu, & dsdt, dqdt, dl, & @@ -2048,7 +2075,7 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & integer, dimension(pcols), intent(in ) :: jt ! level index of updraft top integer, dimension(pcols), intent(in ) :: mx ! level index of updraft base real(r8), dimension(pcols), intent(in ) :: dsubcld ! sub-cloud layer thickness - real(r8), dimension(pcols,pver), intent(in ) :: dp ! pressure thickness + real(r8), dimension(pcols,pver), intent(in ) :: p_del ! pressure thickness real(r8), dimension(pcols,pver), intent(in ) :: q ! ambient mid-point specific humidity real(r8), dimension(pcols,pver), intent(in ) :: qs ! ambient mid-point saturation specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_int ! ambient interface dry static energy @@ -2109,12 +2136,12 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & dsdt(i,k) = -zm_const%latvap/zm_const%cpair*emc + & (+mu(i,k+1)*(su(i,k+1)-s_int(i,k+1)) - mu(i,k)*(su(i,k)-s_int(i,k)) & +md(i,k+1)*(sd(i,k+1)-s_int(i,k+1)) - md(i,k)*(sd(i,k)-s_int(i,k)) & - )/dp(i,k) + )/p_del(i,k) dqdt(i,k) = emc + & (+mu(i,k+1)*(qu(i,k+1)-q_int(i,k+1)) - mu(i,k)*(qu(i,k)-q_int(i,k)) & +md(i,k+1)*(qd(i,k+1)-q_int(i,k+1)) - md(i,k)*(qd(i,k)-q_int(i,k)) & - )/dp(i,k) + )/p_del(i,k) if (zm_param%zm_microp) then dsdt(i,k) = dsdt(i,k) + zm_const%latice/zm_const%cpair*loc_microp_st%frz(i,k) From 0abba5c595b0e90760b9d67dd2b2b16f6b8a24bc Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 13:34:00 -0800 Subject: [PATCH 158/398] rename ideep --- components/eam/src/physics/cam/zm_conv.F90 | 93 ++++++++++------------ 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 6c01e5ec058c..cefb12e30631 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -98,7 +98,7 @@ end subroutine zm_convi !=================================================================================================== subroutine zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & - cape_threshold_loc, ideep, lengath) + cape_threshold_loc, gather_index, lengath) !---------------------------------------------------------------------------- ! Purpose: determine length of gathered arrays !---------------------------------------------------------------------------- @@ -111,12 +111,11 @@ subroutine zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & real(r8), dimension(pcols), intent(in ) :: cape ! conv. avail. potential energy [J] real(r8), dimension(pcols), intent(in ) :: dcape ! CAPE generated by dycor (dCAPE) [J] real(r8), intent( out) :: cape_threshold_loc ! cape threshold - integer, dimension(pcols), intent( out) :: ideep ! flag for active columns + integer, dimension(pcols), intent( out) :: gather_index ! flag for active columns integer, intent( out) :: lengath ! number of columns for gathered arrays !---------------------------------------------------------------------------- ! Local variables integer :: i, ii - integer, dimension(pcols) :: gather_index ! temporary variable used to set ideep !---------------------------------------------------------------------------- ! set local threshold to be used for zm_closure() if ( zm_param%trig_dcape .and. (.not.is_first_step) ) then @@ -142,12 +141,6 @@ subroutine zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & end if end do - !---------------------------------------------------------------------------- - ! set flag for active columns - do ii = 1,lengath - ideep(ii) = gather_index(ii) - end do - !---------------------------------------------------------------------------- return @@ -159,7 +152,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & geos, z_mid_in, z_int_in, pbl_hgt, & tpert, landfrac, t_star, q_star, & - lengath, ideep, maxg, jctop, jcbot, jt, & + lengath, gather_index, maxg, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & mcon, pflx, zdu, mu, eu, du, md, ed, p_del, dsubcld, & ql, rliq, rprd, dlf, aero, microp_st ) @@ -188,7 +181,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & real(r8),pointer,dimension(:,:), intent(in ) :: t_star ! for DCAPE - prev temperature [K] real(r8),pointer,dimension(:,:), intent(in ) :: q_star ! for DCAPE - prev sp. humidity [kg/kg] integer, intent( out) :: lengath ! number of active columns in chunk for gathering - integer, dimension(pcols), intent( out) :: ideep ! flag for active columns + integer, dimension(pcols), intent( out) :: gather_index ! flag for active columns integer, dimension(pcols), intent( out) :: maxg ! gathered level indices of max MSE (maxi) integer, dimension(pcols), intent( out) :: jctop ! top-of-deep-convection indices integer, dimension(pcols), intent( out) :: jcbot ! base of cloud indices @@ -425,10 +418,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & end if !---------------------------------------------------------------------------- - ! determine whether ZM is active in each column (ideep=1) or not (ideep=0), + ! determine whether active columns for gathering call zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & - cape_threshold_loc, ideep, lengath) + cape_threshold_loc, gather_index, lengath) if (lengath.eq.0) then ! Deallocate local microphysics arrays before returning @@ -440,26 +433,26 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! copy data to gathered arrays do i = 1,lengath do k = 1,pver - p_del(i,k) = 0.01_r8*p_del_in(ideep(i),k) - q_mid_g(i,k) = q_mid(ideep(i),k) - t_mid_g(i,k) = t_mid(ideep(i),k) - p_mid_g(i,k) = p_mid(ideep(i),k) - z_mid_g(i,k) = z_mid(ideep(i),k) - s_mid_g(i,k) = s_mid(ideep(i),k) - tp_g(i,k) = tp(ideep(i),k) - z_int_g(i,k) = z_int(ideep(i),k) - qstp_g(i,k) = qstp(ideep(i),k) - omega_g(i,k) = omega(ideep(i),k) + p_del(i,k) = 0.01_r8*p_del_in(gather_index(i),k) + q_mid_g(i,k) = q_mid(gather_index(i),k) + t_mid_g(i,k) = t_mid(gather_index(i),k) + p_mid_g(i,k) = p_mid(gather_index(i),k) + z_mid_g(i,k) = z_mid(gather_index(i),k) + s_mid_g(i,k) = s_mid(gather_index(i),k) + tp_g(i,k) = tp(gather_index(i),k) + z_int_g(i,k) = z_int(gather_index(i),k) + qstp_g(i,k) = qstp(gather_index(i),k) + omega_g(i,k) = omega(gather_index(i),k) end do - z_int_g(i,pverp) = z_int(ideep(i),pver+1) - cape_g(i) = cape(ideep(i)) - lcl_g(i) = lcl(ideep(i)) - lel_g(i) = lel(ideep(i)) - maxg(i) = maxi(ideep(i)) - tl_g(i) = tl(ideep(i)) - landfrac_g(i) = landfrac(ideep(i)) - pbl_top_g(i) = pbl_top(ideep(i)) - tpert_g(i) = tpert(ideep(i)) + z_int_g(i,pverp) = z_int(gather_index(i),pver+1) + cape_g(i) = cape(gather_index(i)) + lcl_g(i) = lcl(gather_index(i)) + lel_g(i) = lel(gather_index(i)) + maxg(i) = maxi(gather_index(i)) + tl_g(i) = tl(gather_index(i)) + landfrac_g(i) = landfrac(gather_index(i)) + pbl_top_g(i) = pbl_top(gather_index(i)) + tpert_g(i) = tpert(gather_index(i)) end do !---------------------------------------------------------------------------- @@ -469,10 +462,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do m = 1, aero%nmodes do i = 1,lengath do k = 1,pver - aero%numg_a(i,k,m) = aero%num_a(m)%val(ideep(i),k) - aero%dgnumg(i,k,m) = aero%dgnum(m)%val(ideep(i),k) + aero%numg_a(i,k,m) = aero%num_a(m)%val(gather_index(i),k) + aero%dgnumg(i,k,m) = aero%dgnum(m)%val(gather_index(i),k) do l = 1, aero%nspec(m) - aero%mmrg_a(i,k,l,m) = aero%mmr_a(l,m)%val(ideep(i),k) + aero%mmrg_a(i,k,l,m) = aero%mmr_a(l,m)%val(gather_index(i),k) end do end do end do @@ -481,7 +474,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do m = 1, aero%nbulk do k = 1,pver do i = 1,lengath - aero%mmrg_bulk(i,k,m) = aero%mmr_bulk(m)%val(ideep(i),k) + aero%mmrg_bulk(i,k,m) = aero%mmr_bulk(m)%val(gather_index(i),k) end do end do end do @@ -583,7 +576,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & if (zm_param%no_deep_pbl) then do i = 1,lengath - if (z_mid_in(ideep(i),jt(i)) < pbl_hgt(ideep(i))) then + if (z_mid_in(gather_index(i),jt(i)) < pbl_hgt(gather_index(i))) then cld_bass_mass_flux(i) = 0 end if end do @@ -648,28 +641,28 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & #endif do i = 1,lengath ! q is updated to compute net precip. - q_mid(ideep(i),k) = q_mid_in(ideep(i),k) + 2._r8*delt*dqdt(i,k) - qtnd(ideep(i),k) = dqdt (i,k) - rprd(ideep(i),k) = rprd_g (i,k) - zdu (ideep(i),k) = du (i,k) - mcon(ideep(i),k) = mc (i,k) - heat(ideep(i),k) = dsdt (i,k)*zm_const%cpair - dlf (ideep(i),k) = dl_g (i,k) - pflx(ideep(i),k) = pflx_g (i,k) - ql (ideep(i),k) = ql_g (i,k) + q_mid(gather_index(i),k) = q_mid_in(gather_index(i),k) + 2._r8*delt*dqdt(i,k) + qtnd(gather_index(i),k) = dqdt (i,k) + rprd(gather_index(i),k) = rprd_g (i,k) + zdu (gather_index(i),k) = du (i,k) + mcon(gather_index(i),k) = mc (i,k) + heat(gather_index(i),k) = dsdt (i,k)*zm_const%cpair + dlf (gather_index(i),k) = dl_g (i,k) + pflx(gather_index(i),k) = pflx_g (i,k) + ql (gather_index(i),k) = ql_g (i,k) end do end do do i = 1,lengath - jctop(ideep(i)) = jt(i) - jcbot(ideep(i)) = maxg(i) - pflx(ideep(i),pverp) = pflx_g(i,pverp) + jctop(gather_index(i)) = jt(i) + jcbot(gather_index(i)) = maxg(i) + pflx(gather_index(i),pverp) = pflx_g(i,pverp) end do !---------------------------------------------------------------------------- ! scatter microphysics data (i.e. undo the gathering) - if (zm_param%zm_microp) call zm_microp_st_scatter(loc_microp_st,microp_st,pcols,lengath,pver,ideep) + if (zm_param%zm_microp) call zm_microp_st_scatter(loc_microp_st,microp_st,pcols,lengath,pver,gather_index) #ifdef CPRCRAY !DIR$ CONCURRENT From 1247836dd4702a6d49332532de9c1f2dd796cd98 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 13:42:00 -0800 Subject: [PATCH 159/398] remove unnecessary args --- components/eam/src/physics/cam/zm_conv.F90 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index cefb12e30631..3a203b47f2fb 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -617,8 +617,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & - jt, maxg, dsubcld, p_del, & - q_mid_g, q_mid_sat_g, s_int_g, q_int_g, su, qu, & + jt, maxg, dsubcld, p_del, s_int_g, q_int_g, su, qu, & mu, du, md, sd, qd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -2049,8 +2048,7 @@ end subroutine zm_closure !=================================================================================================== subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & - jt, mx, dsubcld, p_del, & - q, qs, s_int, q_int, su, qu, & + jt, mx, dsubcld, p_del, s_int, q_int, su, qu, & mu, du, md, sd, qd, ql, evp, cu, & dsdt, dqdt, dl, & loc_microp_st) @@ -2069,8 +2067,6 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & integer, dimension(pcols), intent(in ) :: mx ! level index of updraft base real(r8), dimension(pcols), intent(in ) :: dsubcld ! sub-cloud layer thickness real(r8), dimension(pcols,pver), intent(in ) :: p_del ! pressure thickness - real(r8), dimension(pcols,pver), intent(in ) :: q ! ambient mid-point specific humidity - real(r8), dimension(pcols,pver), intent(in ) :: qs ! ambient mid-point saturation specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_int ! ambient interface dry static energy real(r8), dimension(pcols,pver), intent(in ) :: q_int ! ambient interface specific humidity real(r8), dimension(pcols,pver), intent(in ) :: su ! updraft dry static energy From 0aeb4f0ba03a002a03244bf4a7fabbdfec364607 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 14:05:31 -0800 Subject: [PATCH 160/398] fix time step handling --- components/eam/src/physics/cam/zm_conv.F90 | 28 +++++++++---------- .../eam/src/physics/cam/zm_conv_intr.F90 | 2 +- .../eam/src/physics/cam/zm_microphysics.F90 | 4 +-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 3a203b47f2fb..2854b5715cb8 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -148,7 +148,7 @@ end subroutine zm_gather !=================================================================================================== -subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & +subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & geos, z_mid_in, z_int_in, pbl_hgt, & tpert, landfrac, t_star, q_star, & @@ -165,7 +165,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & integer, intent(in ) :: pver ! number of mid-point levels integer, intent(in ) :: pverp ! number of interface levels logical, intent(in ) :: is_first_step ! flag for first step of run - real(r8), intent(in ) :: delt ! model time-step [s] + real(r8), intent(in ) :: time_step ! model time-step [s] real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] real(r8), dimension(pcols,pver), intent(in ) :: q_mid_in ! specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(in ) :: omega ! vertical pressure velocity [Pa/s] @@ -414,7 +414,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & lcl_m1, lel_m1, cape_m1, & zm_const, zm_param, & cape_calc_msemax_klev, prev_msemax_klev ) - dcape(:ncol) = (cape(:ncol)-cape_m1(:ncol))/(delt*2._r8) + dcape(:ncol) = (cape(:ncol)-cape_m1(:ncol))/time_step end if !---------------------------------------------------------------------------- @@ -562,7 +562,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & mumax(i) = max(mumax(i), mu(i,k)/p_del(i,k)) end do if (mumax(i) > 0._r8) then - cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),0.5_r8/(delt*mumax(i))) + cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),1/(time_step*mumax(i))) else cld_bass_mass_flux(i) = 0._r8 end if @@ -626,7 +626,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & ! conservation check and adjusment #ifndef SCREAM_CONFIG_IS_CMAKE if (zm_param%zm_microp) then - call zm_microphysics_adjust(pcols, lengath, pver, jt, msg, delt, zm_const, & + call zm_microphysics_adjust(pcols, lengath, pver, jt, msg, time_step, zm_const, & p_del, q_mid_g, dl_g, dsdt, dqdt, rprd_g, loc_microp_st) end if #endif @@ -640,7 +640,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & #endif do i = 1,lengath ! q is updated to compute net precip. - q_mid(gather_index(i),k) = q_mid_in(gather_index(i),k) + 2._r8*delt*dqdt(i,k) + q_mid(gather_index(i),k) = q_mid_in(gather_index(i),k) + time_step*dqdt(i,k) qtnd(gather_index(i),k) = dqdt (i,k) rprd(gather_index(i),k) = rprd_g (i,k) zdu (gather_index(i),k) = du (i,k) @@ -672,13 +672,13 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, delt, & do i = 1,ncol do k = pver, msg+1, -1 if (zm_param%zm_microp) then - prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-q_mid_in(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-q_mid_in(i,k)) - p_del_in(i,k)*(dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*time_step else - prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-q_mid_in(i,k)) - p_del_in(i,k)*(dlf(i,k))*2._r8*delt + prec(i) = prec(i) - p_del_in(i,k)*(q_mid(i,k)-q_mid_in(i,k)) - p_del_in(i,k)*(dlf(i,k))*time_step end if end do ! obtain final precipitation rate in m/s - prec(i) = zm_const%rgrav*max(prec(i),0._r8)/ (2._r8*delt)/1000._r8 + prec(i) = zm_const%rgrav*max(prec(i),0._r8)/ time_step/1000._r8 end do !---------------------------------------------------------------------------- @@ -708,7 +708,7 @@ end subroutine zm_convr !=================================================================================================== -subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & +subroutine zm_conv_evap(pcols, ncol, pver, pverp, time_step, & p_mid, p_del, t_mid, q_mid, prdprec, cldfrc, & tend_s, tend_q, tend_s_snwprd, tend_s_snwevmlt, & prec, snow, ntprprd, ntsnprd, flxprec, flxsnow, microp_st ) @@ -729,7 +729,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & integer, intent(in ) :: ncol ! actual number of columns integer, intent(in ) :: pver ! number of mid-point vertical levels integer, intent(in ) :: pverp ! number of interface vertical levels - real(r8), intent(in ) :: deltat ! time step [s] + real(r8), intent(in ) :: time_step ! model time step [s] real(r8), dimension(pcols,pver), intent(in ) :: p_mid ! midpoint pressure [Pa] real(r8), dimension(pcols,pver), intent(in ) :: p_del ! layer thickness [Pa] real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] @@ -810,9 +810,9 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & else ! make sure melting snow doesn't reduce temperature below threshold if (t_mid(i,k) > zm_const%tfreez) then - dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/p_del(i,k)*deltat + dum = -zm_const%latice/zm_const%cpair*flxsnow(i,k)*zm_const%grav/p_del(i,k)*time_step if (t_mid(i,k) + dum .le. zm_const%tfreez) then - dum = (t_mid(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/deltat + dum = (t_mid(i,k)-zm_const%tfreez)*zm_const%cpair/zm_const%latice/time_step dum = dum/(flxsnow(i,k)*zm_const%grav/p_del(i,k)) dum = max(0._r8,dum) dum = min(1._r8,dum) @@ -837,7 +837,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, deltat, & ! Don't let evaporation supersaturate layer (approx). Layer may already be saturated. ! Currently does not include heating/cooling change to qs - evplimit = max(0._r8, (qs(i,k)-q_mid(i,k)) / deltat) + evplimit = max(0._r8, (qs(i,k)-q_mid(i,k)) / time_step) ! Don't evaporate more than is falling into the layer from above. ! Don't evaporate rain formed in this layer, but if precip production diff --git a/components/eam/src/physics/cam/zm_conv_intr.F90 b/components/eam/src/physics/cam/zm_conv_intr.F90 index 00f0fe8a4450..2f4dc274ee72 100644 --- a/components/eam/src/physics/cam/zm_conv_intr.F90 +++ b/components/eam/src/physics/cam/zm_conv_intr.F90 @@ -632,7 +632,7 @@ subroutine zm_conv_tend(pblh, mcon, cme, tpert, dlftot, pflx, zdu, & ! Call the primary Zhang-McFarlane convection parameterization call t_startf ('zm_convr') - call zm_convr( pcols, ncol, pver, pverp, is_first_step_loc, 0.5*ztodt, & + call zm_convr( pcols, ncol, pver, pverp, is_first_step_loc, ztodt, & state%t, state%q(:,:,1), state%omega, & state%pmid, state%pint, state%pdel, & state%phis, state%zm, state%zi, pblh, & diff --git a/components/eam/src/physics/cam/zm_microphysics.F90 b/components/eam/src/physics/cam/zm_microphysics.F90 index c067558d978e..a5b8cc5dbd2e 100644 --- a/components/eam/src/physics/cam/zm_microphysics.F90 +++ b/components/eam/src/physics/cam/zm_microphysics.F90 @@ -3243,8 +3243,8 @@ subroutine zm_microphysics_adjust(pcols, ncol, pver, jt, msg, delt, zm_const, & !DIR$ CONCURRENT #endif do i = 1,ncol - if (dqdt(i,k)*2._r8*delt+qv(i,k)<0._r8) then - negadq = dqdt(i,k)+0.5_r8*qv(i,k)/delt + if (dqdt(i,k)*delt+qv(i,k)<0._r8) then + negadq = dqdt(i,k)+qv(i,k)/delt dqdt(i,k) = dqdt(i,k)-negadq !---------------------------------------------------------------- ! First evaporate precipitation from k layer to cloud top assuming that the preciptation From 7d00dc4bb485251325ecfc0c3aa7504ef8595ddb Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 14:58:13 -0800 Subject: [PATCH 161/398] minor cleanup --- components/eam/src/physics/cam/zm_conv.F90 | 70 +++++++++++----------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm_conv.F90 index 2854b5715cb8..3500c2c9f71c 100644 --- a/components/eam/src/physics/cam/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm_conv.F90 @@ -516,7 +516,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! calculate updraft and downdraft properties - call zm_cloud_properties(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & p_mid_g, z_mid_g, z_int_g, t_mid_g, s_mid_g, s_int_g, q_mid_g, & landfrac_g, tpert_g, & @@ -527,8 +526,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & aero, loc_microp_st ) !--------------------------------------------------------------------------- - ! convert detrainment from units of "per length" [1/m] to "per pressure" [1/mb]. - + ! convert from units of "per length" [1/m] to "per pressure" [1/mb]. do k = msg+1, pver do i = 1,lengath du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) @@ -545,7 +543,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & end do !---------------------------------------------------------------------------- - + ! apply closure assumption to calculate cloud base mass flux call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_loc, & lcl_g, lel_g, jt, maxg, dsubcld, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & @@ -555,7 +553,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. - do i = 1,lengath mumax(i) = 0 do k = msg+2, pver @@ -573,7 +570,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! don't allow convection within PBL (suggestion of Bjorn Stevens, 8-2000) - if (zm_param%no_deep_pbl) then do i = 1,lengath if (z_mid_in(gather_index(i),jt(i)) < pbl_hgt(gather_index(i))) then @@ -584,12 +580,10 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! apply cloud base mass flux scaling - do i = 1,lengath - ! zero out micro data for inactive columns if ( zm_param%zm_microp .and. cld_bass_mass_flux(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) - + ! scale variables do k = msg+1,pver mu (i,k) = mu (i,k) *cld_bass_mass_flux(i) md (i,k) = md (i,k) *cld_bass_mass_flux(i) @@ -601,7 +595,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & cu_g (i,k) = cu_g (i,k) *cld_bass_mass_flux(i) evp_g (i,k) = evp_g (i,k) *cld_bass_mass_flux(i) pflx_g(i,k+1) = pflx_g(i,k+1)*cld_bass_mass_flux(i)*100._r8/zm_const%grav - + ! scale microphysics variables if (zm_param%zm_microp) then loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k)*cld_bass_mass_flux(i) loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k)*cld_bass_mass_flux(i) @@ -609,13 +603,11 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & ql_g(i,k) = 0._r8 end if end if - - end do - end do + end do ! k + end do ! i !---------------------------------------------------------------------------- ! compute temperature and moisture changes due to convection. - call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & jt, maxg, dsubcld, p_del, s_int_g, q_int_g, su, qu, & mu, du, md, sd, qd, ql_g, evp_g, cu_g, & @@ -633,7 +625,6 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! scatter data (i.e. undo the gathering) - do k = msg+1, pver #ifdef CPRCRAY !DIR$ CONCURRENT @@ -651,7 +642,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & ql (gather_index(i),k) = ql_g (i,k) end do end do - + ! scatter 1d variables do i = 1,lengath jctop(gather_index(i)) = jt(i) jcbot(gather_index(i)) = maxg(i) @@ -660,8 +651,9 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! scatter microphysics data (i.e. undo the gathering) - - if (zm_param%zm_microp) call zm_microp_st_scatter(loc_microp_st,microp_st,pcols,lengath,pver,gather_index) + if (zm_param%zm_microp) then + call zm_microp_st_scatter(loc_microp_st,microp_st,pcols,lengath,pver,gather_index) + end if #ifdef CPRCRAY !DIR$ CONCURRENT @@ -704,6 +696,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- return + end subroutine zm_convr !=================================================================================================== @@ -1055,6 +1048,7 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & end do ! i end do ! k + !---------------------------------------------------------------------------- ! move detrainment level downward if fractional entrainment is too low do i = 1,ncol if (j0(i) < jb(i)) then @@ -1064,6 +1058,7 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & end if end do ! i + !---------------------------------------------------------------------------- ! ensure that entrainment does not increase above the level that detrainment starts do k = msg+2, pver do i = 1,ncol @@ -1073,12 +1068,14 @@ subroutine zm_calc_fractional_entrainment(pcols, ncol, pver, pverp, msg, & end do ! i end do ! k + !---------------------------------------------------------------------------- ! specify maximum fractional entrainment do i = 1,ncol lambda_max(i) = lambda_tmp(i,j0(i)) lambda(i,jb(i)) = lambda_max(i) end do + !---------------------------------------------------------------------------- ! The modification below comes from: ! Rasch, P. J., J. E. Kristjánsson, A comparison of the CCM3 model climate ! using diagnosed and predicted condensate parameterizations, J. Clim., 1997. @@ -1258,7 +1255,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(in ) :: s_int ! interface values of dry stat energy real(r8), dimension(pcols,pver), intent(in ) :: q_mid ! env specific humidity real(r8), dimension(pcols), intent(in ) :: landfrac ! Land fraction - real(r8), dimension(pcols), intent(in ) :: tpert_g ! PBL temperature perturbation + real(r8), dimension(pcols), intent(in ) :: tpert_g ! PBL temperature perturbation integer, dimension(pcols), intent(in ) :: jb ! updraft base level integer, dimension(pcols), intent(in ) :: lel ! updraft parcel launch level integer, dimension(pcols), intent(out) :: jt ! updraft plume top @@ -1336,7 +1333,6 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), parameter :: hu_diff_min = -2000._r8 ! limit on hu(i,k)-hsthat(i,k) !---------------------------------------------------------------------------- - ! initialize 1D variables do i = 1,ncol totpcp(i) = 0._r8 @@ -1469,7 +1465,6 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & !---------------------------------------------------------------------------- ! iteration to set cloud properties - itnum = 1 if (zm_param%zm_microp) itnum = 2 @@ -1650,19 +1645,19 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end do ! k !------------------------------------------------------------------------- - ! microphysical calculation - + ! microphysical calculations if (zm_param%zm_microp) then + ! calculate updraft temperature tug(1:ncol,:) = t_mid(1:ncol,:) - fice(1:ncol,:) = 0._r8 - do k = pver, msg+2, -1 do i = 1, ncol tug(i,k) = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) end do ! i end do ! k + ! specify ice fraction + fice(1:ncol,:) = 0._r8 do k = 1, pver-1 do i = 1, ncol if (tug(i,k+1) > zm_const%tfreez) then @@ -1680,7 +1675,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = 1, pver do i = 1,ncol - loc_microp_st%cmei(i,k) = cu(i,k)* fice(i,k) + loc_microp_st%cmei(i,k) = cu(i,k) * fice(i,k) loc_microp_st%cmel(i,k) = cu(i,k) * (1._r8-fice(i,k)) end do ! i end do ! k @@ -1749,19 +1744,17 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! compute condensed liquid, rain production rate ! accumulate total precipitation (condensation - detrainment of liquid) - ! Note ql1 = ql(k) + rprd(k)*dz(k)/mu(k) - ! The differencing is somewhat strange (e.g. du(i,k)*ql(i,k+1)) but is - ! consistently applied. - ! mu, ql are interface quantities - ! cu, du, eu, rprd are midpoint quantites + ! Note: ql1 = ql(k) + rprd(k)*dz(k)/mu(k) + ! The differencing is somewhat strange (e.g. du(i,k)*ql(i,k+1)) but is consistently applied. + ! interface quantities => mu, ql are + ! mid-point quantities => cu, du, eu, rprd do k = pver, msg+2, -1 do i = 1,ncol rprd(i,k) = 0._r8 if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then if (mu(i,k) > 0._r8) then - ql1 = 1._r8/mu(i,k)* (mu(i,k+1)*ql(i,k+1)- & - dz(i,k)*du(i,k)*ql(i,k+1)+dz(i,k)*cu(i,k)) - ql(i,k) = ql1/ (1._r8+dz(i,k)*c0mask(i)) + ql1 = 1._r8/mu(i,k) * ( mu(i,k+1)*ql(i,k+1) - dz(i,k)*du(i,k)*ql(i,k+1) + dz(i,k)*cu(i,k) ) + ql(i,k) = ql1 / (1._r8+dz(i,k)*c0mask(i)) else ql(i,k) = 0._r8 end if @@ -1816,7 +1809,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = 2,pverp do i = 1,ncol pflx(i,k) = pflx(i,k-1) + rprd(i,k-1)*dz(i,k-1) - if (zm_param%zm_microp) pflxs(i,k) = pflxs(i,k-1) + loc_microp_st%sprd(i,k-1)*dz(i,k-1) + if (zm_param%zm_microp) then + pflxs(i,k) = pflxs(i,k-1) + loc_microp_st%sprd(i,k-1)*dz(i,k-1) + end if end do ! i end do ! k @@ -1861,7 +1856,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end do ! i end if ! zm_microp + !---------------------------------------------------------------------------- return + end subroutine zm_cloud_properties !=================================================================================================== @@ -2043,6 +2040,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & !---------------------------------------------------------------------------- return + end subroutine zm_closure !=================================================================================================== @@ -2165,8 +2163,10 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & end if end do end do + !---------------------------------------------------------------------------- return + end subroutine zm_calc_output_tend !=================================================================================================== From e820719bfb14e3a8cda8b14d2b524135ecc05d5f Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 5 Dec 2025 15:37:01 -0800 Subject: [PATCH 162/398] move ZM files to dedicated folder --- components/eam/bld/configure | 1 + components/eam/src/physics/cam/{ => zm}/zm_aero.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_aero_type.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_conv.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_conv_cape.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_conv_intr.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_conv_mcsp.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_conv_types.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_conv_util.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_microphysics.F90 | 0 .../eam/src/physics/cam/{ => zm}/zm_microphysics_history.F90 | 0 .../eam/src/physics/cam/{ => zm}/zm_microphysics_state.F90 | 0 components/eam/src/physics/cam/{ => zm}/zm_transport.F90 | 0 components/eamxx/src/physics/zm/CMakeLists.txt | 2 +- 14 files changed, 2 insertions(+), 1 deletion(-) rename components/eam/src/physics/cam/{ => zm}/zm_aero.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_aero_type.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_conv.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_conv_cape.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_conv_intr.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_conv_mcsp.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_conv_types.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_conv_util.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_microphysics.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_microphysics_history.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_microphysics_state.F90 (100%) rename components/eam/src/physics/cam/{ => zm}/zm_transport.F90 (100%) diff --git a/components/eam/bld/configure b/components/eam/bld/configure index af795a28049f..304d595522c3 100755 --- a/components/eam/bld/configure +++ b/components/eam/bld/configure @@ -2691,6 +2691,7 @@ sub write_filepath print $fh "$camsrcdir/eam/src/physics/cam\n"; print $fh "$camsrcdir/eam/src/physics/cam/gw\n"; + print $fh "$camsrcdir/eam/src/physics/cam/zm\n"; if ($clubb_sgs eq '1') { print $fh "$camsrcdir/eam/src/physics/clubb\n"; print $fh "$camsrcdir/eam/src/physics/silhs\n"; diff --git a/components/eam/src/physics/cam/zm_aero.F90 b/components/eam/src/physics/cam/zm/zm_aero.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_aero.F90 rename to components/eam/src/physics/cam/zm/zm_aero.F90 diff --git a/components/eam/src/physics/cam/zm_aero_type.F90 b/components/eam/src/physics/cam/zm/zm_aero_type.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_aero_type.F90 rename to components/eam/src/physics/cam/zm/zm_aero_type.F90 diff --git a/components/eam/src/physics/cam/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_conv.F90 rename to components/eam/src/physics/cam/zm/zm_conv.F90 diff --git a/components/eam/src/physics/cam/zm_conv_cape.F90 b/components/eam/src/physics/cam/zm/zm_conv_cape.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_conv_cape.F90 rename to components/eam/src/physics/cam/zm/zm_conv_cape.F90 diff --git a/components/eam/src/physics/cam/zm_conv_intr.F90 b/components/eam/src/physics/cam/zm/zm_conv_intr.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_conv_intr.F90 rename to components/eam/src/physics/cam/zm/zm_conv_intr.F90 diff --git a/components/eam/src/physics/cam/zm_conv_mcsp.F90 b/components/eam/src/physics/cam/zm/zm_conv_mcsp.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_conv_mcsp.F90 rename to components/eam/src/physics/cam/zm/zm_conv_mcsp.F90 diff --git a/components/eam/src/physics/cam/zm_conv_types.F90 b/components/eam/src/physics/cam/zm/zm_conv_types.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_conv_types.F90 rename to components/eam/src/physics/cam/zm/zm_conv_types.F90 diff --git a/components/eam/src/physics/cam/zm_conv_util.F90 b/components/eam/src/physics/cam/zm/zm_conv_util.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_conv_util.F90 rename to components/eam/src/physics/cam/zm/zm_conv_util.F90 diff --git a/components/eam/src/physics/cam/zm_microphysics.F90 b/components/eam/src/physics/cam/zm/zm_microphysics.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_microphysics.F90 rename to components/eam/src/physics/cam/zm/zm_microphysics.F90 diff --git a/components/eam/src/physics/cam/zm_microphysics_history.F90 b/components/eam/src/physics/cam/zm/zm_microphysics_history.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_microphysics_history.F90 rename to components/eam/src/physics/cam/zm/zm_microphysics_history.F90 diff --git a/components/eam/src/physics/cam/zm_microphysics_state.F90 b/components/eam/src/physics/cam/zm/zm_microphysics_state.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_microphysics_state.F90 rename to components/eam/src/physics/cam/zm/zm_microphysics_state.F90 diff --git a/components/eam/src/physics/cam/zm_transport.F90 b/components/eam/src/physics/cam/zm/zm_transport.F90 similarity index 100% rename from components/eam/src/physics/cam/zm_transport.F90 rename to components/eam/src/physics/cam/zm/zm_transport.F90 diff --git a/components/eamxx/src/physics/zm/CMakeLists.txt b/components/eamxx/src/physics/zm/CMakeLists.txt index cc499b5a1af2..a4d560261a00 100644 --- a/components/eamxx/src/physics/zm/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/CMakeLists.txt @@ -1,4 +1,4 @@ -set(PATH_TO_LEGACY_ZM ${SCREAM_BASE_DIR}/../eam/src/physics/cam/) +set(PATH_TO_LEGACY_ZM ${SCREAM_BASE_DIR}/../eam/src/physics/cam/zm/) set(ZM_F90_SRCS # ---------------------------------------------------------------------------- From 590b6ae4376457b895d5a1aab22614d4817cbea0 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 8 Dec 2025 09:09:25 -0800 Subject: [PATCH 163/398] fix depends files for new ZM location --- cime_config/machines/Depends.alvarez-cpu.gnu.cmake | 2 +- cime_config/machines/Depends.anlgce.gnu.cmake | 2 +- cime_config/machines/Depends.chicoma-cpu.gnu.cmake | 2 +- cime_config/machines/Depends.chrysalis.intel.cmake | 2 +- cime_config/machines/Depends.cray.cmake | 2 +- cime_config/machines/Depends.muller-cpu.gnu.cmake | 2 +- cime_config/machines/Depends.pgi.cmake | 2 +- cime_config/machines/Depends.pgigpu.cmake | 2 +- cime_config/machines/Depends.pm-cpu.gnu.cmake | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cime_config/machines/Depends.alvarez-cpu.gnu.cmake b/cime_config/machines/Depends.alvarez-cpu.gnu.cmake index 53f8b536651e..e1500fc407c7 100644 --- a/cime_config/machines/Depends.alvarez-cpu.gnu.cmake +++ b/cime_config/machines/Depends.alvarez-cpu.gnu.cmake @@ -1,6 +1,6 @@ # For this file, fixes non-BFB behavior of stealth feature on pm-cpu with -O2 set(NOOPT - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) if (NOT DEBUG) foreach(ITEM IN LISTS NOOPT) diff --git a/cime_config/machines/Depends.anlgce.gnu.cmake b/cime_config/machines/Depends.anlgce.gnu.cmake index 4b8e6d0fbbfb..dfd128a7bc09 100644 --- a/cime_config/machines/Depends.anlgce.gnu.cmake +++ b/cime_config/machines/Depends.anlgce.gnu.cmake @@ -1,6 +1,6 @@ # For this file, see internal compiler error on anlgce with -O2 set(NOOPT - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) if (NOT DEBUG) foreach(ITEM IN LISTS NOOPT) diff --git a/cime_config/machines/Depends.chicoma-cpu.gnu.cmake b/cime_config/machines/Depends.chicoma-cpu.gnu.cmake index 9ebd88ff8762..989b255f5b66 100644 --- a/cime_config/machines/Depends.chicoma-cpu.gnu.cmake +++ b/cime_config/machines/Depends.chicoma-cpu.gnu.cmake @@ -1,6 +1,6 @@ # For this file, fixes non-BFB behavior of stealth feature on pm-cpu with -O2 set(NOOPT - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) if (NOT DEBUG) foreach(ITEM IN LISTS NOOPT) diff --git a/cime_config/machines/Depends.chrysalis.intel.cmake b/cime_config/machines/Depends.chrysalis.intel.cmake index e14cc4d3a673..fcfa54aeb5e3 100644 --- a/cime_config/machines/Depends.chrysalis.intel.cmake +++ b/cime_config/machines/Depends.chrysalis.intel.cmake @@ -5,7 +5,7 @@ set(O2MODELSRC elm/src/data_types/VegetationDataType.F90 # ~ 930 seconds elm/src/external_models/fates/main/FatesHistoryInterfaceMod.F90 # ~ 1685 seconds elm/src/data_types/ColumnDataType.F90 # ~ 556 seconds - eam/src/physics/cam/zm_conv.F90 # for machine dependent behavior + eam/src/physics/cam/zm/zm_conv.F90 # for machine dependent behavior eam/src/physics/cam/zm_microphysics.F90 # for machine dependent behavior ) if (NOT DEBUG) diff --git a/cime_config/machines/Depends.cray.cmake b/cime_config/machines/Depends.cray.cmake index 459107cb3d7e..25dc764841f5 100644 --- a/cime_config/machines/Depends.cray.cmake +++ b/cime_config/machines/Depends.cray.cmake @@ -4,7 +4,7 @@ set(O0MODELSRC eam/src/chemistry/aerosol/dust_sediment_mod.F90 eam/src/chemistry/modal_aero/modal_aero_convproc.F90 eam/src/chemistry/utils/modal_aero_calcsize.F90 - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) if (NOT DEBUG) foreach(ITEM IN LISTS O0MODELSRC) diff --git a/cime_config/machines/Depends.muller-cpu.gnu.cmake b/cime_config/machines/Depends.muller-cpu.gnu.cmake index 53f8b536651e..e1500fc407c7 100644 --- a/cime_config/machines/Depends.muller-cpu.gnu.cmake +++ b/cime_config/machines/Depends.muller-cpu.gnu.cmake @@ -1,6 +1,6 @@ # For this file, fixes non-BFB behavior of stealth feature on pm-cpu with -O2 set(NOOPT - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) if (NOT DEBUG) foreach(ITEM IN LISTS NOOPT) diff --git a/cime_config/machines/Depends.pgi.cmake b/cime_config/machines/Depends.pgi.cmake index 0b6bbd571126..6bfbe446c342 100644 --- a/cime_config/machines/Depends.pgi.cmake +++ b/cime_config/machines/Depends.pgi.cmake @@ -3,7 +3,7 @@ set(O1MODELSRC eam/src/chemistry/aerosol/dust_sediment_mod.F90 eam/src/chemistry/modal_aero/modal_aero_convproc.F90 eam/src/chemistry/utils/modal_aero_calcsize.F90 - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) set(O0MODELSRC ../driver-mct/main/component_mod.F90 diff --git a/cime_config/machines/Depends.pgigpu.cmake b/cime_config/machines/Depends.pgigpu.cmake index 248d9adc2862..6d62bb8356a4 100644 --- a/cime_config/machines/Depends.pgigpu.cmake +++ b/cime_config/machines/Depends.pgigpu.cmake @@ -10,7 +10,7 @@ set(O1MODELSRC eam/src/chemistry/aerosol/dust_sediment_mod.F90 eam/src/chemistry/modal_aero/modal_aero_convproc.F90 eam/src/chemistry/utils/modal_aero_calcsize.F90 - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) set(O0MODELSRC ../driver-mct/main/component_mod.F90 diff --git a/cime_config/machines/Depends.pm-cpu.gnu.cmake b/cime_config/machines/Depends.pm-cpu.gnu.cmake index 9ebd88ff8762..989b255f5b66 100644 --- a/cime_config/machines/Depends.pm-cpu.gnu.cmake +++ b/cime_config/machines/Depends.pm-cpu.gnu.cmake @@ -1,6 +1,6 @@ # For this file, fixes non-BFB behavior of stealth feature on pm-cpu with -O2 set(NOOPT - eam/src/physics/cam/zm_conv.F90) + eam/src/physics/cam/zm/zm_conv.F90) if (NOT DEBUG) foreach(ITEM IN LISTS NOOPT) From bbe380519499d691f371fb0ec8538f54164bca51 Mon Sep 17 00:00:00 2001 From: Vijay Mahadevan Date: Mon, 8 Dec 2025 03:01:44 +0000 Subject: [PATCH 164/398] Add MOAB module to be loaded on Aurora setups --- cime_config/machines/config_machines.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 2c1a9593154a..88f6cf41ccf3 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3483,6 +3483,7 @@ netcdf/4.9.3c-4.6.2f pnetcdf/1.14.0 adios2/2.10.2 + moab/5.6.0 mpich-config/collective-tuning/1024 From a710f7d3188b01fbe6f87933d44633d780cddf72 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 8 Dec 2025 15:13:10 -0600 Subject: [PATCH 165/398] fix Chrysalis build --- cime_config/machines/Depends.chrysalis.intel.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/machines/Depends.chrysalis.intel.cmake b/cime_config/machines/Depends.chrysalis.intel.cmake index fcfa54aeb5e3..f53bd2de9c3c 100644 --- a/cime_config/machines/Depends.chrysalis.intel.cmake +++ b/cime_config/machines/Depends.chrysalis.intel.cmake @@ -6,7 +6,7 @@ set(O2MODELSRC elm/src/external_models/fates/main/FatesHistoryInterfaceMod.F90 # ~ 1685 seconds elm/src/data_types/ColumnDataType.F90 # ~ 556 seconds eam/src/physics/cam/zm/zm_conv.F90 # for machine dependent behavior - eam/src/physics/cam/zm_microphysics.F90 # for machine dependent behavior + eam/src/physics/cam/zm/zm_microphysics.F90 # for machine dependent behavior ) if (NOT DEBUG) foreach(ITEM IN LISTS O2MODELSRC) From 43965dd1d66a59c97f14de8e727dfbf5b7e512f3 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Mon, 8 Dec 2025 14:17:27 -0800 Subject: [PATCH 166/398] Update default PE layout for IG case using GIS 1to10km mesh --- components/elm/cime_config/config_pes.xml | 40 +++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/components/elm/cime_config/config_pes.xml b/components/elm/cime_config/config_pes.xml index 85741a632819..021a9fbac952 100644 --- a/components/elm/cime_config/config_pes.xml +++ b/components/elm/cime_config/config_pes.xml @@ -457,21 +457,21 @@ - - - + + + pm-cpu: IG-case testing config. using 1-to-10km (high-res) GIS init. cond. 128 128 - 128 - 128 - 128 - 128 - 128 - 960 - 128 - 128 + 256 + 256 + 256 + 256 + 256 + 256 + 256 + 256 1 @@ -496,19 +496,19 @@ - + chrysalis: IG-case testing config. using 1-to-10km (high-res) GIS init. cond. 64 64 - 64 - 64 - 64 - 64 - 64 - 960 - 64 - 64 + 256 + 256 + 256 + 256 + 256 + 256 + 256 + 256 1 From 580f9646048dd5f62dbb6ec8e44eee9f91c19329 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 8 Dec 2025 15:20:35 -0800 Subject: [PATCH 167/398] additional renaming --- components/eam/src/physics/cam/physpkg.F90 | 2 +- components/eam/src/physics/cam/zm/zm_conv.F90 | 54 +++++++++---------- .../eam/src/physics/cam/zm/zm_conv_intr.F90 | 32 +++++------ .../cam/zm/zm_microphysics_history.F90 | 2 +- .../fortran_bridge/zm_eamxx_bridge_main.F90 | 32 +++++------ 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/components/eam/src/physics/cam/physpkg.F90 b/components/eam/src/physics/cam/physpkg.F90 index 8dd6e16c5d60..d8dd59ed1954 100644 --- a/components/eam/src/physics/cam/physpkg.F90 +++ b/components/eam/src/physics/cam/physpkg.F90 @@ -3296,7 +3296,7 @@ subroutine add_fld_default_calls() !Add all existing ptend names for the addfld calls character(len=21), parameter :: vlist(28) = (/ 'topphysbc ' ,& - 'chkenergyfix ','dadadj ','zm_convr ','zm_conv_evap ',& + 'chkenergyfix ','dadadj ','zm_conv_main ','zm_conv_evap ',& 'zm_transport_momentum','zm_conv_tend ','UWSHCU ','convect_shallow ',& 'pcwdetrain_mac ','macro_park ','macrop ','micro_mg ',& 'cldwat_mic ','aero_model_wetdep_ma ','zm_transport_tracer_2','cam_radheat ',& diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 3500c2c9f71c..79d295f93464 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -47,8 +47,8 @@ module zm_conv private !---------------------------------------------------------------------------- ! public methods - public zm_convi ! ZM scheme initialization - public zm_convr ! ZM scheme calculations + public zm_conv_init ! ZM scheme initialization + public zm_conv_main ! ZM scheme calculations public zm_conv_evap ! ZM scheme evaporation of precip !---------------------------------------------------------------------------- ! public variables @@ -66,7 +66,7 @@ module zm_conv contains !=================================================================================================== -subroutine zm_convi(limcnv_in, no_deep_pbl_in) +subroutine zm_conv_init(limcnv_in, no_deep_pbl_in) !---------------------------------------------------------------------------- ! Purpose: initialize quantities for ZM convection scheme !---------------------------------------------------------------------------- @@ -93,12 +93,12 @@ subroutine zm_convi(limcnv_in, no_deep_pbl_in) !---------------------------------------------------------------------------- return -end subroutine zm_convi +end subroutine zm_conv_init !=================================================================================================== -subroutine zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & - cape_threshold_loc, gather_index, lengath) +subroutine zm_get_gather_index(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & + cape_threshold_loc, gather_index, lengath) !---------------------------------------------------------------------------- ! Purpose: determine length of gathered arrays !---------------------------------------------------------------------------- @@ -144,18 +144,18 @@ subroutine zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & !---------------------------------------------------------------------------- return -end subroutine zm_gather +end subroutine zm_get_gather_index !=================================================================================================== -subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & - t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & - geos, z_mid_in, z_int_in, pbl_hgt, & - tpert, landfrac, t_star, q_star, & - lengath, gather_index, maxg, jctop, jcbot, jt, & - prec, heat, qtnd, cape, dcape, & - mcon, pflx, zdu, mu, eu, du, md, ed, p_del, dsubcld, & - ql, rliq, rprd, dlf, aero, microp_st ) +subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & + t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & + geos, z_mid_in, z_int_in, pbl_hgt, & + tpert, landfrac, t_star, q_star, & + lengath, gather_index, maxg, jctop, jcbot, jt, & + prec, heat, qtnd, cape, dcape, & + mcon, pflx, zdu, mu, eu, du, md, ed, p_del, dsubcld, & + ql, rliq, rprd, dlf, aero, microp_st ) !---------------------------------------------------------------------------- ! Purpose: Main driver for Zhang-Mcfarlane convection scheme !---------------------------------------------------------------------------- @@ -420,8 +420,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! determine whether active columns for gathering - call zm_gather(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & - cape_threshold_loc, gather_index, lengath) + call zm_get_gather_index(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & + cape_threshold_loc, gather_index, lengath) if (lengath.eq.0) then ! Deallocate local microphysics arrays before returning @@ -676,8 +676,8 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! Compute reserved liquid (and ice) that is not yet in cldliq for energy integrals ! Treat rliq as flux out bottom, to be added back later - do k = 1, pver - do i = 1, ncol + do k = 1,pver + do i = 1,ncol if (zm_param%zm_microp) then rliq(i) = rliq(i) + (dlf(i,k)+microp_st%dif(i,k)+microp_st%dsf(i,k))*p_del_in(i,k)/zm_const%grav microp_st%rice(i) = microp_st%rice(i) & @@ -697,7 +697,7 @@ subroutine zm_convr( pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- return -end subroutine zm_convr +end subroutine zm_conv_main !=================================================================================================== @@ -788,8 +788,8 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, time_step, & flxsnow(:ncol,1) = 0._r8 evpvint(:ncol) = 0._r8 - do k = 1, pver - do i = 1, ncol + do k = 1,pver + do i = 1,ncol ! Melt snow falling into layer, if necessary. if (zm_param%old_snow) then @@ -914,7 +914,7 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, time_step, & ! protect against rounding error if (.not.zm_param%old_snow) then - do i = 1, ncol + do i = 1,ncol if (flxsnow(i,pverp).gt.flxprec(i,pverp)) then dum = (flxsnow(i,pverp)-flxprec(i,pverp))*zm_const%grav do k = pver, 1, -1 @@ -1651,15 +1651,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! calculate updraft temperature tug(1:ncol,:) = t_mid(1:ncol,:) do k = pver, msg+2, -1 - do i = 1, ncol + do i = 1,ncol tug(i,k) = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) end do ! i end do ! k ! specify ice fraction fice(1:ncol,:) = 0._r8 - do k = 1, pver-1 - do i = 1, ncol + do k = 1,pver-1 + do i = 1,ncol if (tug(i,k+1) > zm_const%tfreez) then ! If warmer than zm_const%tfreez then water phase fice(i,k) = 0._r8 @@ -1673,7 +1673,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end do ! i end do ! k - do k = 1, pver + do k = 1,pver do i = 1,ncol loc_microp_st%cmei(i,k) = cu(i,k) * fice(i,k) loc_microp_st%cmel(i,k) = cu(i,k) * (1._r8-fice(i,k)) diff --git a/components/eam/src/physics/cam/zm/zm_conv_intr.F90 b/components/eam/src/physics/cam/zm/zm_conv_intr.F90 index 2f4dc274ee72..cf140aad378b 100644 --- a/components/eam/src/physics/cam/zm/zm_conv_intr.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv_intr.F90 @@ -18,7 +18,7 @@ module zm_conv_intr use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_mode_num, rad_cnst_get_aer_mmr use rad_constituents, only: rad_cnst_get_aer_props, rad_cnst_get_mode_props use ndrop_bam, only: ndrop_bam_init - use zm_conv, only: zm_conv_evap, zm_convr + use zm_conv, only: zm_conv_evap, zm_conv_main use zm_transport, only: zm_transport_tracer, zm_transport_momentum use zm_aero_type, only: zm_aero_t use zm_microphysics_state, only: zm_microp_st @@ -238,7 +238,7 @@ subroutine zm_conv_init(pref_edge) !---------------------------------------------------------------------------- ! Purpose: declare output fields, initialize variables needed by convection !---------------------------------------------------------------------------- - use zm_conv, only: zm_convi + use zm_conv, only: zm_conv_init use pmgrid, only: plev,plevp use spmd_utils, only: masterproc use error_messages, only: alloc_err @@ -348,7 +348,7 @@ subroutine zm_conv_init(pref_edge) 'intfc ',limcnv,' which is ',pref_edge(limcnv),' pascals' no_deep_pbl = phys_deepconv_pbl() - call zm_convi( limcnv, no_deep_pbl_in=no_deep_pbl ) + call zm_conv_init( limcnv, no_deep_pbl_in=no_deep_pbl ) !---------------------------------------------------------------------------- ! print information about ZM configuration to the log file @@ -567,7 +567,7 @@ subroutine zm_conv_tend(pblh, mcon, cme, tpert, dlftot, pflx, zdu, & lq(:) = .FALSE. lq(1) = .TRUE. - call physics_ptend_init(ptend_loc, state%psetcols, 'zm_convr', ls=.true., lq=lq ) + call physics_ptend_init(ptend_loc, state%psetcols, 'zm_conv_main', ls=.true., lq=lq ) !---------------------------------------------------------------------------- ! Associate pointers with physics buffer fields @@ -631,17 +631,17 @@ subroutine zm_conv_tend(pblh, mcon, cme, tpert, dlftot, pflx, zdu, & is_first_step_loc = is_first_step() ! Call the primary Zhang-McFarlane convection parameterization - call t_startf ('zm_convr') - call zm_convr( pcols, ncol, pver, pverp, is_first_step_loc, ztodt, & - state%t, state%q(:,:,1), state%omega, & - state%pmid, state%pint, state%pdel, & - state%phis, state%zm, state%zi, pblh, & - tpert, landfrac, t_star, q_star, & - lengath, ideep, maxg, jctop, jcbot, jt, & - prec, ptend_loc%s, ptend_loc%q(:,:,1), cape, dcape, & - mcon, pflx, zdu, mu, eu, du, md, ed, dp, dsubcld, & - ql, rliq, rprd, dlf, aero(lchnk), microp_st ) - call t_stopf ('zm_convr') + call t_startf ('zm_conv_main') + call zm_conv_main(pcols, ncol, pver, pverp, is_first_step_loc, ztodt, & + state%t, state%q(:,:,1), state%omega, & + state%pmid, state%pint, state%pdel, & + state%phis, state%zm, state%zi, pblh, & + tpert, landfrac, t_star, q_star, & + lengath, ideep, maxg, jctop, jcbot, jt, & + prec, ptend_loc%s, ptend_loc%q(:,:,1), cape, dcape, & + mcon, pflx, zdu, mu, eu, du, md, ed, dp, dsubcld, & + ql, rliq, rprd, dlf, aero(lchnk), microp_st ) + call t_stopf ('zm_conv_main') if (zm_param%zm_microp) then ! update ZM micro variables in pbuf @@ -665,7 +665,7 @@ subroutine zm_conv_tend(pblh, mcon, cme, tpert, dlftot, pflx, zdu, & !---------------------------------------------------------------------------- ! mesoscale coherent structure parameterization (MCSP) - ! Note that this modifies the tendencies produced by zm_convr(), such that + ! Note that this modifies the tendencies produced by zm_conv_main(), such that ! history variables like ZMDT will include the effects of MCSP if (zm_param%mcsp_enabled) then diff --git a/components/eam/src/physics/cam/zm/zm_microphysics_history.F90 b/components/eam/src/physics/cam/zm/zm_microphysics_history.F90 index d425033d3a6b..6e26b5bad358 100644 --- a/components/eam/src/physics/cam/zm/zm_microphysics_history.F90 +++ b/components/eam/src/physics/cam/zm/zm_microphysics_history.F90 @@ -150,7 +150,7 @@ subroutine zm_microphysics_history_convert( ncol, microp_st, pmid, temperature ) integer :: msg ! number of missing moisture levels at the top of model real(r8) :: rho !---------------------------------------------------------------------------- - msg = zm_param%limcnv - 1 ! set this to match zm_convr() + msg = zm_param%limcnv - 1 ! set this to match zm_conv_main() do i = 1,ncol do k = msg + 1,pver diff --git a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 index 3ed33f800dc9..a93d9e160f39 100644 --- a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 +++ b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 @@ -82,7 +82,7 @@ subroutine zm_eamxx_bridge_run_c( ncol, dtime, is_first_step, & use zm_aero_type, only: zm_aero_t use zm_microphysics_state, only: zm_microp_st use zm_eamxx_bridge_methods, only: zm_tend_init, zm_physics_update - use zm_conv, only: zm_convr, zm_conv_evap + use zm_conv, only: zm_conv_main, zm_conv_evap use zm_conv_mcsp, only: zm_conv_mcsp_tend use zm_transport, only: zm_transport_momentum ! use zm_transport, only: zm_transport_tracer @@ -126,7 +126,7 @@ subroutine zm_eamxx_bridge_run_c( ncol, dtime, is_first_step, & logical :: loc_is_first_step - ! arguments for zm_convr - order somewhat consistent with current interface + ! arguments for zm_conv_main - order somewhat consistent with current interface integer :: lchnk = 0 integer, dimension(ncol) :: jctop ! output top-of-deep-convection indices @@ -232,20 +232,20 @@ subroutine zm_eamxx_bridge_run_c( ncol, dtime, is_first_step, & !----------------------------------------------------------------------------- ! Call the primary Zhang-McFarlane convection parameterization - call zm_convr( ncol, ncol, pver, pverp, loc_is_first_step, 0.5*dtime, & - state_t, state_qv, state_omega, & - state_p_mid, state_p_int, state_p_del, & - state_phis, state_zm, state_zi, state_pblh, & - tpert, landfrac, t_star, q_star, & - lengath, ideep, maxg, jctop, jcbot, jt, & - output_prec, output_tend_s, output_tend_q, & - output_cape, dcape, output_mass_flux, output_prec_flux, & - zdu, mu, eu, du, md, ed, dp, dsubcld, & - zm_qc, rliq, output_rain_prod, dlf, & - aero, microp_st ) + call zm_conv_main(ncol, ncol, pver, pverp, loc_is_first_step, 0.5*dtime, & + state_t, state_qv, state_omega, & + state_p_mid, state_p_int, state_p_del, & + state_phis, state_zm, state_zi, state_pblh, & + tpert, landfrac, t_star, q_star, & + lengath, ideep, maxg, jctop, jcbot, jt, & + output_prec, output_tend_s, output_tend_q, & + output_cape, dcape, output_mass_flux, output_prec_flux, & + zdu, mu, eu, du, md, ed, dp, dsubcld, & + zm_qc, rliq, output_rain_prod, dlf, & + aero, microp_st ) !----------------------------------------------------------------------------- - ! mesoscale coherent structure parameterization (MCSP)- modifies tendencies from zm_convr() prior to updating the state + ! mesoscale coherent structure parameterization (MCSP)- modifies tendencies from zm_conv_main() prior to updating the state if (zm_param%mcsp_enabled) then @@ -282,7 +282,7 @@ subroutine zm_eamxx_bridge_run_c( ncol, dtime, is_first_step, & end if !----------------------------------------------------------------------------- - ! apply tendencies from zm_convr() & MCSP to local copy of state variables + ! apply tendencies from zm_conv_main() & MCSP to local copy of state variables call zm_physics_update( ncol, dtime, & state_phis, local_state_zm, local_state_zi, & @@ -292,7 +292,7 @@ subroutine zm_eamxx_bridge_run_c( ncol, dtime, is_first_step, & !----------------------------------------------------------------------------- ! Compute the precipitation, rain evaporation, and snow formation/melting - ! Note - this routine expects an updated state following zm_convr() (+MCSP) + ! Note - this routine expects an updated state following zm_conv_main() (+MCSP) ! initialize local output tendencies for zm_conv_evap() call zm_tend_init( ncol, pver, local_tend_s, local_tend_q, local_tend_u, local_tend_v ) From 82ff036d83dcdb8430ba68caf217097bc22f4fa6 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Mon, 8 Dec 2025 15:41:24 -0800 Subject: [PATCH 168/398] bug fix --- components/eam/src/physics/cam/zm/zm_conv.F90 | 6 +++--- components/eam/src/physics/cam/zm/zm_conv_intr.F90 | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 79d295f93464..10982bf97e1f 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -47,7 +47,7 @@ module zm_conv private !---------------------------------------------------------------------------- ! public methods - public zm_conv_init ! ZM scheme initialization + public zm_conv_main_init ! ZM scheme initialization public zm_conv_main ! ZM scheme calculations public zm_conv_evap ! ZM scheme evaporation of precip !---------------------------------------------------------------------------- @@ -66,7 +66,7 @@ module zm_conv contains !=================================================================================================== -subroutine zm_conv_init(limcnv_in, no_deep_pbl_in) +subroutine zm_conv_main_init(limcnv_in, no_deep_pbl_in) !---------------------------------------------------------------------------- ! Purpose: initialize quantities for ZM convection scheme !---------------------------------------------------------------------------- @@ -93,7 +93,7 @@ subroutine zm_conv_init(limcnv_in, no_deep_pbl_in) !---------------------------------------------------------------------------- return -end subroutine zm_conv_init +end subroutine zm_conv_main_init !=================================================================================================== diff --git a/components/eam/src/physics/cam/zm/zm_conv_intr.F90 b/components/eam/src/physics/cam/zm/zm_conv_intr.F90 index cf140aad378b..6806cd08016c 100644 --- a/components/eam/src/physics/cam/zm/zm_conv_intr.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv_intr.F90 @@ -238,7 +238,7 @@ subroutine zm_conv_init(pref_edge) !---------------------------------------------------------------------------- ! Purpose: declare output fields, initialize variables needed by convection !---------------------------------------------------------------------------- - use zm_conv, only: zm_conv_init + use zm_conv, only: zm_conv_main_init use pmgrid, only: plev,plevp use spmd_utils, only: masterproc use error_messages, only: alloc_err @@ -348,7 +348,7 @@ subroutine zm_conv_init(pref_edge) 'intfc ',limcnv,' which is ',pref_edge(limcnv),' pascals' no_deep_pbl = phys_deepconv_pbl() - call zm_conv_init( limcnv, no_deep_pbl_in=no_deep_pbl ) + call zm_conv_main_init( limcnv, no_deep_pbl_in=no_deep_pbl ) !---------------------------------------------------------------------------- ! print information about ZM configuration to the log file From 8a3f3db81c32d67b711cafd7053eaa5c2ac04e07 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Tue, 9 Dec 2025 10:40:16 -0600 Subject: [PATCH 169/398] Update solver settings and grid reference for Greenland configurations Minor updates to albany solver settings (for Greenland only) to improve convergence; update reference for default 1-to-10km init. cond. grid to newer one with improved convergence on initial time step (thickness field has iceberges removed) --- .../bld/namelist_files/albany_input.gis_1to10km_r02.yaml | 8 ++++++-- .../bld/namelist_files/albany_input.gis_4to40km.yaml | 8 ++++++-- components/mpas-albany-landice/cime_config/buildnml | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_1to10km_r02.yaml b/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_1to10km_r02.yaml index 45539411756a..df63da84f143 100644 --- a/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_1to10km_r02.yaml +++ b/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_1to10km_r02.yaml @@ -11,6 +11,7 @@ ANONYMOUS: Regularization Value: 1.0e-4 LandIce BCs: BC 0: + Cubature Degree: 4 Basal Friction Coefficient: Type: Power Law Power Exponent: 1.0 @@ -30,7 +31,10 @@ ANONYMOUS: Line Search: Full Step: Full Step: 1.0e+00 - Method: Backtrack + Method: Polynomial + Polynomial: + Recovery Step: 1.0e-3 + Minimum Step: 1.0e-3 Solver Options: Status Test Check Type: Minimal Status Tests: @@ -140,7 +144,7 @@ ANONYMOUS: Aggregates: UncoupledAggregationFact2 myTogglePFact: factory: TogglePFactory - 'semicoarsen: number of levels': 2 + 'semicoarsen: number of levels': 1 TransferFactories: P1: mySemiCoarsenPFact1 P2: mySaPFact2 diff --git a/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_4to40km.yaml b/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_4to40km.yaml index 45539411756a..df63da84f143 100644 --- a/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_4to40km.yaml +++ b/components/mpas-albany-landice/bld/namelist_files/albany_input.gis_4to40km.yaml @@ -11,6 +11,7 @@ ANONYMOUS: Regularization Value: 1.0e-4 LandIce BCs: BC 0: + Cubature Degree: 4 Basal Friction Coefficient: Type: Power Law Power Exponent: 1.0 @@ -30,7 +31,10 @@ ANONYMOUS: Line Search: Full Step: Full Step: 1.0e+00 - Method: Backtrack + Method: Polynomial + Polynomial: + Recovery Step: 1.0e-3 + Minimum Step: 1.0e-3 Solver Options: Status Test Check Type: Minimal Status Tests: @@ -140,7 +144,7 @@ ANONYMOUS: Aggregates: UncoupledAggregationFact2 myTogglePFact: factory: TogglePFactory - 'semicoarsen: number of levels': 2 + 'semicoarsen: number of levels': 1 TransferFactories: P1: mySemiCoarsenPFact1 P2: mySaPFact2 diff --git a/components/mpas-albany-landice/cime_config/buildnml b/components/mpas-albany-landice/cime_config/buildnml index 1fa3ac9011e6..1ae80a563809 100755 --- a/components/mpas-albany-landice/cime_config/buildnml +++ b/components/mpas-albany-landice/cime_config/buildnml @@ -113,7 +113,7 @@ def buildnml(case, caseroot, compname): decomp_date += '051920' decomp_prefix += 'mpasli.graph.info.' elif glc_grid == 'mpas.gis1to10kmR2': - grid_date += '20240513' + grid_date += '20251209' grid_prefix += 'gis_1to10km_r02' decomp_date += '020223' decomp_prefix += 'mpasli.graph.info.' From fc4ecd858c037b1212117d94d0b261729dd20ae1 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Tue, 9 Dec 2025 12:28:30 -0800 Subject: [PATCH 170/398] Minor corrections and clean-up of default pe setting files. --- cime_config/allactive/config_pesall.xml | 8 +++---- components/elm/cime_config/config_pes.xml | 26 +++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index 5fad6a6a73d2..e8762b1cd20e 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -2365,7 +2365,7 @@ - pm-cpu: GIS 1-to-10km (high-res) baseline config + chrysalis: BG-case production config. using 1-to-10km (high-res) GIS init. cond. 128 128 @@ -2402,7 +2402,7 @@ - GIS 1-to-10km (high-res) baseline config + chrysalis: BG-case production config. using 1-to-10km (high-res) GIS init. cond. 64 64 @@ -2441,7 +2441,7 @@ - pm-cpu: GIS 4-to-40km (med-res) baseline config + pm-cpu: BG-case testing config. using 4-to-40km (med-res) GIS init. cond. 128 128 @@ -2478,7 +2478,7 @@ - chrys: GIS 4-to-40km (med-res) baseline config + chrysalis: BG-case testing config. using 4-to-40km (med-res) GIS init. cond. 64 64 diff --git a/components/elm/cime_config/config_pes.xml b/components/elm/cime_config/config_pes.xml index 021a9fbac952..dbcbe38bbaac 100644 --- a/components/elm/cime_config/config_pes.xml +++ b/components/elm/cime_config/config_pes.xml @@ -533,10 +533,10 @@ - + - - pm-cpu: GIS 4-to-40km (med-res) baseline config + + pm-cpu: IG-case testing config. using 4-to-40km (mde res) GIS init. cond. 128 128 @@ -572,19 +572,19 @@ - - chrys: GIS 4-to-40km (med-res) baseline config + + chrys: IG-case testing config. using 4-to-40km (mde res) GIS init. cond. 64 64 - 64 - 64 - 64 - 64 - 64 - 64 - 64 - 64 + 128 + 128 + 128 + 128 + 128 + 128 + 128 + 128 1 From c4f4920dc1e07ee8ea293c84f07957f0197d1f75 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Tue, 9 Dec 2025 13:01:33 -0800 Subject: [PATCH 171/398] fix duplicate declaration of kssh --- components/data_comps/docn/src/docn_comp_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/data_comps/docn/src/docn_comp_mod.F90 b/components/data_comps/docn/src/docn_comp_mod.F90 index 8fce72bf2c31..e10eb2bf8966 100644 --- a/components/data_comps/docn/src/docn_comp_mod.F90 +++ b/components/data_comps/docn/src/docn_comp_mod.F90 @@ -71,7 +71,7 @@ module docn_comp_mod integer(IN) :: kt,ks,ku,kv,kdhdx,kdhdy,kq,kswp,kssh,kh2o ! field indices integer(IN) :: kswnet,klwup,klwdn,ksen,klat,kmelth,ksnow,krofi - integer(IN) :: kh,kqbot,kfraz,kssh,kh2ot + integer(IN) :: kh,kqbot,kfraz,kh2ot integer(IN) :: k10uu ! index for u10 integer(IN) :: kRSO_bckgrd_sst ! index for background SST (relaxed slab ocean) integer(IN) :: index_lat, index_lon From 3d3266f17e56079c8e0093345ab591a642793669 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 26 Nov 2025 18:16:56 -0700 Subject: [PATCH 172/398] EAMxx: upgrade compare-nc-files script to accept a tolerance --- components/eamxx/scripts/compare-nc-files | 2 ++ components/eamxx/scripts/compare_nc_files.py | 23 ++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/components/eamxx/scripts/compare-nc-files b/components/eamxx/scripts/compare-nc-files index f8857b530ce5..2cfafc3607c0 100755 --- a/components/eamxx/scripts/compare-nc-files +++ b/components/eamxx/scripts/compare-nc-files @@ -44,6 +44,8 @@ OR help="Name of the source netcdf file") parser.add_argument("-t","--tgt-file", type=str, help="Name of the target netcdf file") + parser.add_argument("-tol","--tolerance", type=float, default=0, + help="Tolerance for the comparisons (used for both rel and abs)") # Variables comparison parser.add_argument("-c","--compare",nargs='+', default=[], diff --git a/components/eamxx/scripts/compare_nc_files.py b/components/eamxx/scripts/compare_nc_files.py index 130bc39d359f..07327fa92adc 100644 --- a/components/eamxx/scripts/compare_nc_files.py +++ b/components/eamxx/scripts/compare_nc_files.py @@ -12,7 +12,7 @@ class CompareNcFiles(object): ############################################################################### ########################################################################### - def __init__(self,src_file,tgt_file=None,compare=None): + def __init__(self,src_file,tgt_file=None,tolerance=0,compare=None): ########################################################################### self._src_file = pathlib.Path(src_file).resolve().absolute() @@ -20,6 +20,7 @@ def __init__(self,src_file,tgt_file=None,compare=None): "Error! File '{}' does not exist.".format(self._src_file)) self._compare = compare + self._tol = tolerance if tgt_file is None: self._tgt_file = self._src_file @@ -122,19 +123,17 @@ def compare_variables(self): lvals = self.slice_variable(lvar,lvar[:],lslices) rvals = self.slice_variable(rvar,rvar[:],rslices) - if not np.array_equal(lvals,rvals): - # print (f"lvals: {lvals}") - # print (f"rvals: {rvals}") - item = np.argwhere(lvals!=rvals)[0] - rval = self.slice_variable(rvar,rvals, - [[idim,slice] for idim,slice in enumerate(item)]) - lval = self.slice_variable(lvar,lvals, - [[idim,slice] for idim,slice in enumerate(item)]) - loc = ",".join([str(i+1) for i in item]) + diff = np.abs(lvals-rvals) + not_close = diff > (self._tol + self._tol*np.abs(rvals)) + where = np.argwhere(not_close) + if where.size > 0: + idx = where[0] + lval = lvals[tuple(idx)] + rval = rvals[tuple(idx)] print (f" Comparison failed. Values differ.\n" f" - input comparison: {expr}\n" - f' - upon slicing, {lname}({loc}) = {lval}\n' - f' - upon slicing, {rname}({loc}) = {rval}') + f' - upon slicing, {lname}({tuple(idx)}) = {lval}\n' + f' - upon slicing, {rname}({tuple(idx)}) = {rval}') success = False return success From e383518c43a12859f92e87879c4a7a5bea608748 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 16:55:54 -0700 Subject: [PATCH 173/398] EAMxx: fix micro bug in atm proc pyhelpers --- .../src/share/atm_process/atmosphere_process_pyhelpers.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_pyhelpers.hpp b/components/eamxx/src/share/atm_process/atmosphere_process_pyhelpers.hpp index 231482404540..e4fbf201b90e 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_pyhelpers.hpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_pyhelpers.hpp @@ -16,7 +16,6 @@ void AtmosphereProcess:: py_module_call (const std::string& name, const Args&... args) { const auto& py_module = std::any_cast(m_py_module); - py_module.attr(name.c_str())(args...); try { py_module.attr(name.c_str())(args...); } catch (const pybind11::error_already_set& e) { @@ -32,7 +31,7 @@ inline const pybind11::array& AtmosphereProcess:: get_py_field_impl (const strmap_t>& py_fields, const std::string& fname, const std::string& grid) const { - auto any_f = py_fields.at(fname).at(grid); + auto& any_f = py_fields.at(fname).at(grid); return std::any_cast(any_f); } From fd8bb5b21ca8a56f07f4fd7635b3ae1de4941ae4 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 15:34:24 -0700 Subject: [PATCH 174/398] EAMxx: extract cld frac emulator into its own atm process --- .../src/physics/cld_fraction/CMakeLists.txt | 4 ++ .../cld_fraction/cld_frac_net/CMakeLists.txt | 12 ++++ .../cld_frac_net/cld_frac_net.py} | 46 ++++++++----- .../cld_frac_net/cld_frac_net_weights.pth} | Bin .../eamxx_cld_frac_net_process_interface.cpp | 65 ++++++++++++++++++ .../eamxx_cld_frac_net_process_interface.hpp | 35 ++++++++++ .../eamxx_cld_fraction_process_interface.cpp | 43 ++++++------ .../eamxx_cld_fraction_process_interface.hpp | 6 -- .../eamxx/src/physics/register_physics.hpp | 6 ++ .../cld_fraction/CMakeLists.txt | 23 ++++--- .../single-process/cld_fraction/input_ml.yaml | 33 +++++++++ 11 files changed, 220 insertions(+), 53 deletions(-) create mode 100644 components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt rename components/eamxx/{tests/single-process/cld_fraction/cld_fraction_ml.py => src/physics/cld_fraction/cld_frac_net/cld_frac_net.py} (66%) rename components/eamxx/{tests/single-process/cld_fraction/cldfrac_net_weights.pth => src/physics/cld_fraction/cld_frac_net/cld_frac_net_weights.pth} (100%) create mode 100644 components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp create mode 100644 components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.hpp create mode 100644 components/eamxx/tests/single-process/cld_fraction/input_ml.yaml diff --git a/components/eamxx/src/physics/cld_fraction/CMakeLists.txt b/components/eamxx/src/physics/cld_fraction/CMakeLists.txt index 6a3cb2b0f886..687e8f740f9b 100644 --- a/components/eamxx/src/physics/cld_fraction/CMakeLists.txt +++ b/components/eamxx/src/physics/cld_fraction/CMakeLists.txt @@ -26,3 +26,7 @@ endif() # The BFB test will require some amount of work, as the specific ice cloud fraction scheme # here is just an option in a more involved F90 subroutine. Furture work would be to # include a BFB test with the F90 code, located in /components/eam/src/physics/cam/cldfrc2m.F90 + +if (NOT SCREAM_LIB_ONLY) + add_subdirectory(cld_frac_net) +endif() diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt b/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt new file mode 100644 index 000000000000..c632dc805e39 --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt @@ -0,0 +1,12 @@ +if (EAMXX_ENABLE_PYTHON) + # Process wrapping ML emulator via python hooks + add_library(cld_frac_net + eamxx_cld_frac_net_process_interface.cpp + ) + target_compile_definitions(cld_frac_net PUBLIC EAMXX_HAS_CLD_FRAC_NET) + target_link_libraries (cld_frac_net PUBLIC eamxx_atm_process) + if (TARGET eamxx_physics) + # Add this library to eamxx_physics + target_link_libraries(eamxx_physics INTERFACE cld_frac_net) + endif() +endif() diff --git a/components/eamxx/tests/single-process/cld_fraction/cld_fraction_ml.py b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.py similarity index 66% rename from components/eamxx/tests/single-process/cld_fraction/cld_fraction_ml.py rename to components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.py index 2b43d21eaa18..395c78f74bd8 100644 --- a/components/eamxx/tests/single-process/cld_fraction/cld_fraction_ml.py +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.py @@ -1,22 +1,23 @@ import os - import torch import torch.nn as nn class CldFracNet(nn.Module): - def __init__(self, input_size, output_size, neuron_count=64): + def __init__(self, nlevs, neuron_count=64): super(CldFracNet, self).__init__() # emulate cld_ice = (qi > 1e-5) - self.ice1 = nn.Linear(input_size, neuron_count) - self.ice2 = nn.Linear(neuron_count, output_size) + self.ice1 = nn.Linear(nlevs, neuron_count) + self.ice2 = nn.Linear(neuron_count, nlevs) # emulate cld_tot = max(cld_ice, cld_liq) - self.tot1 = nn.Linear(input_size*2, neuron_count) - self.tot2 = nn.Linear(neuron_count, output_size) + self.tot1 = nn.Linear(nlevs*2, neuron_count) + self.tot2 = nn.Linear(neuron_count, nlevs) # a relu for fun self.relu = nn.ReLU() # sigmoid for categorical ice output self.sigmoid = nn.Sigmoid() + self.nlevs = nlevs + def forward(self, qi, liq): # First, compute cld_ice from qi y11 = self.ice1(qi) @@ -35,29 +36,38 @@ def forward(self, qi, liq): # During inference, use hard binary values y13_categorical = (y13_probabilities > 0.5).float() + if liq.dim() == 1: # 1D input (no batch dimension) + cat_dim = 0 + elif liq.dim() == 2: # 2D input (with batch dimension) + cat_dim = 1 + else: + raise ValueError("Input tensors must be either 1D (without batch dim) or 2D (with batch dim).") + # Now compute cld_tot from cld_ice and cld_liq - y21 = self.tot1(torch.cat((liq, y13_categorical), dim=1)) + y21 = self.tot1(torch.cat((liq, y13_categorical), dim=cat_dim)) y22 = self.relu(y21) y23 = self.tot2(y22) return y13_categorical, y23 -model = None - -def init (): - global model +def create_cld_frac_net (): # For this test, hard code nlevs, as well as pth file name/path nlevs = 72 current_file_directory = os.path.dirname(os.path.abspath(__file__)) - model_file = f"{current_file_directory}/cldfrac_net_weights.pth" + model_file = f"{current_file_directory}/cld_frac_net_weights.pth" + + cld_frac_net_model = CldFracNet(nlevs) + cld_frac_net_model.load_state_dict(torch.load(model_file,map_location=torch.device('cpu'),weights_only=True)) + return cld_frac_net_model + +model = None + +def init (): + global model - model = CldFracNet(nlevs,nlevs) - model.load_state_dict(torch.load(model_file,map_location=torch.device('cpu'))) + model = create_cld_frac_net() -def main (ice_threshold, ice_4out_threshold, - qi, liq_cld_frac, - ice_cld_frac, tot_cld_frac, - ice_cld_frac_4out, tot_cld_frac_4out): +def forward (ice_threshold, qi, liq_cld_frac, ice_cld_frac, tot_cld_frac): global model # Convert numpy inputs to torch arrays diff --git a/components/eamxx/tests/single-process/cld_fraction/cldfrac_net_weights.pth b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net_weights.pth similarity index 100% rename from components/eamxx/tests/single-process/cld_fraction/cldfrac_net_weights.pth rename to components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net_weights.pth diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp new file mode 100644 index 000000000000..b2ae4c1e1622 --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp @@ -0,0 +1,65 @@ +#include "eamxx_cld_frac_net_process_interface.hpp" + +#include "share/atm_process/atmosphere_process_pyhelpers.hpp" + +namespace scream +{ + +CldFracNet::CldFracNet (const ekat::Comm& comm, const ekat::ParameterList& params) + : AtmosphereProcess(comm, params) +{ + EKAT_REQUIRE_MSG( has_py_module(), + "[CldFracNet] Error! Something went wrong while initializing the python module.\n"); + // Nothing to do here +} + +void CldFracNet::set_grids(const std::shared_ptr grids_manager) +{ + using namespace ekat::units; + + const auto nondim = Units::nondimensional(); + const auto grid = grids_manager->get_grid("physics"); + const auto grid_name = grid->name(); + const auto layout = grid->get_3d_scalar_layout(true); + + // Input fields + add_tracer("qi", grid, kg/kg); + add_field("cldfrac_liq", layout, nondim, grid_name); + + // Output fields + add_field("cldfrac_tot", layout, nondim, grid_name); + add_field("cldfrac_ice", layout, nondim, grid_name); +} + +void CldFracNet::initialize_impl (const RunType /* run_type */) +{ + py_module_call("init"); +} + +void CldFracNet::run_impl (const double /* dt */) +{ + // Calculate ice cloud fraction and total cloud fraction given the liquid cloud fraction + // and the ice mass mixing ratio. + auto qi = get_field_in("qi"); + auto liq = get_field_in("cldfrac_liq"); + auto ice = get_field_out("cldfrac_ice"); + auto tot = get_field_out("cldfrac_tot"); + + } else { + auto py_qi = get_py_field_dev("qi"); + auto py_liq = get_py_field_dev("cldfrac_liq"); + auto py_ice = get_py_field_dev("cldfrac_ice"); + auto py_tot = get_py_field_dev("cldfrac_tot"); + + double ice_threshold = m_params.get("ice_cloud_threshold"); + + py_module_call("forward",ice_threshold,py_qi,py_liq,py_ice,py_tot); + } +} + +void CldFracNet::finalize_impl() +{ + // Nothing to do here +} + +} // namespace scream diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.hpp b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.hpp new file mode 100644 index 000000000000..3b0da231adb0 --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.hpp @@ -0,0 +1,35 @@ +#ifndef SCREAM_CLD_FRAC_NET_HPP +#define SCREAM_CLD_FRAC_NET_HPP + +#include "share/atm_process/atmosphere_process.hpp" + +namespace scream +{ + +/* + * An ML emulator for the CldFraction process + * + * This process is NOT to be used in real runs, and is exclusively meant + * to be an example of how to wrap a torch model in an eamxx atm process +*/ + +class CldFracNet : public AtmosphereProcess +{ +public: + CldFracNet (const ekat::Comm& comm, const ekat::ParameterList& params); + + AtmosphereProcessType type () const { return AtmosphereProcessType::Physics; } + std::string name () const { return "cld_frac_net"; } + + void set_grids (const std::shared_ptr grids_manager); + +protected: + + void initialize_impl (const RunType run_type); + void run_impl (const double dt); + void finalize_impl (); +}; + +} // namespace scream + +#endif // SCREAM_CLD_FRAC_NET_HPP diff --git a/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.cpp b/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.cpp index 3eded911a339..ec0d871809d1 100644 --- a/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.cpp +++ b/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.cpp @@ -1,15 +1,13 @@ #include "eamxx_cld_fraction_process_interface.hpp" #include "share/property_checks/field_within_interval_check.hpp" - -#include -#include - -#include +#include "physics/cld_fraction/cld_fraction_functions.hpp" #ifdef EAMXX_HAS_PYTHON #include "share/atm_process/atmosphere_process_pyhelpers.hpp" #endif +#include + namespace scream { using namespace cld_fraction; @@ -24,7 +22,8 @@ CldFraction::CldFraction (const ekat::Comm& comm, const ekat::ParameterList& par void CldFraction::set_grids(const std::shared_ptr grids_manager) { using namespace ekat::units; - using namespace ShortFieldTagsNames; + using CldFractionFunc = cld_fraction::CldFractionFunctions; + using Spack = CldFractionFunc::Spack; // The units of mixing ratio Q are technically non-dimensional. // Nevertheless, for output reasons, we like to see 'kg/kg'. @@ -38,10 +37,10 @@ void CldFraction::set_grids(const std::shared_ptr grids_mana // Define the different field layouts that will be used for this process // Layout for 3D (2d horiz X 1d vertical) variable defined at mid-level and interfaces - FieldLayout scalar3d_layout_mid { {COL,LEV}, {m_num_cols,m_num_levs} }; + auto scalar3d_layout_mid = m_grid->get_3d_scalar_layout(true); // Set of fields used strictly as input - constexpr int ps = Pack::n; + constexpr int ps = Spack::n; add_tracer("qi", m_grid, kg/kg, ps); add_field("cldfrac_liq", scalar3d_layout_mid, nondim, grid_name,ps); @@ -93,6 +92,7 @@ void CldFraction::run_impl (const double /* dt */) auto tot_cld_frac = get_field_out("cldfrac_tot"); auto ice_cld_frac_4out = get_field_out("cldfrac_ice_for_analysis"); auto tot_cld_frac_4out = get_field_out("cldfrac_tot_for_analysis"); + #ifdef EAMXX_HAS_PYTHON if (has_py_module()) { pybind11::array py_qi, @@ -135,19 +135,22 @@ void CldFraction::run_impl (const double /* dt */) ice_cld_frac_4out.sync_to_dev(); tot_cld_frac_4out.sync_to_dev(); } - } else -#endif - { - auto qi_v = qi.get_view(); - auto liq_cld_frac_v = liq_cld_frac.get_view(); - auto ice_cld_frac_v = ice_cld_frac.get_view(); - auto tot_cld_frac_v = tot_cld_frac.get_view(); - auto ice_cld_frac_4out_v = ice_cld_frac_4out.get_view(); - auto tot_cld_frac_4out_v = tot_cld_frac_4out.get_view(); - - CldFractionFunc::main(m_num_cols,m_num_levs,m_icecloud_threshold,m_icecloud_for_analysis_threshold, - qi_v,liq_cld_frac_v,ice_cld_frac_v,tot_cld_frac_v,ice_cld_frac_4out_v,tot_cld_frac_4out_v); + return; } +#endif + + using CldFractionFunc = cld_fraction::CldFractionFunctions; + using Spack = CldFractionFunc::Spack; + + auto qi_v = qi.get_view(); + auto liq_cld_frac_v = liq_cld_frac.get_view(); + auto ice_cld_frac_v = ice_cld_frac.get_view(); + auto tot_cld_frac_v = tot_cld_frac.get_view(); + auto ice_cld_frac_4out_v = ice_cld_frac_4out.get_view(); + auto tot_cld_frac_4out_v = tot_cld_frac_4out.get_view(); + + CldFractionFunc::main(m_num_cols,m_num_levs,m_icecloud_threshold,m_icecloud_for_analysis_threshold, + qi_v,liq_cld_frac_v,ice_cld_frac_v,tot_cld_frac_v,ice_cld_frac_4out_v,tot_cld_frac_4out_v); } // ========================================================================================= diff --git a/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.hpp b/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.hpp index 12951bcb8cd3..ba85c3f81867 100644 --- a/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.hpp +++ b/components/eamxx/src/physics/cld_fraction/eamxx_cld_fraction_process_interface.hpp @@ -1,7 +1,6 @@ #ifndef SCREAM_CLD_FRACTION_HPP #define SCREAM_CLD_FRACTION_HPP -#include "physics/cld_fraction/cld_fraction_functions.hpp" #include "share/atm_process/atmosphere_process.hpp" #include @@ -21,11 +20,6 @@ namespace scream class CldFraction : public AtmosphereProcess { public: - using CldFractionFunc = cld_fraction::CldFractionFunctions; - using Spack = CldFractionFunc::Spack; - using Smask = CldFractionFunc::Smask; - using Pack = ekat::Pack; - // Constructors CldFraction (const ekat::Comm& comm, const ekat::ParameterList& params); diff --git a/components/eamxx/src/physics/register_physics.hpp b/components/eamxx/src/physics/register_physics.hpp index 9900a9b3888b..4261930ad200 100644 --- a/components/eamxx/src/physics/register_physics.hpp +++ b/components/eamxx/src/physics/register_physics.hpp @@ -47,6 +47,9 @@ #ifdef EAMXX_HAS_IOP_FORCING #include "physics/iop_forcing/eamxx_iop_forcing_process_interface.hpp" #endif +#ifdef EAMXX_HAS_CLD_FRAC_NET +#include "physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.hpp" +#endif namespace scream { @@ -94,6 +97,9 @@ inline void register_physics () { #ifdef EAMXX_HAS_IOP_FORCING proc_factory.register_product("iop_forcing",&create_atmosphere_process); #endif +#ifdef EAMXX_HAS_CLD_FRAC_NET + proc_factory.register_product("cld_frac_net",&create_atmosphere_process); +#endif // If no physics was enabled, silence compile warning about unused var (void) proc_factory; diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index 0e85d6f1b04e..d1153d94fc02 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -6,6 +6,7 @@ set (ATM_TIME_STEP 1800) set (RUN_T0 2021-10-12-45000) # Configure yaml files to run directory +set (PROCESS_NAME cld_fraction) set (POSTFIX cpp) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml ${CMAKE_CURRENT_BINARY_DIR}/input_cpp.yaml) @@ -80,17 +81,21 @@ if (EAMXX_ENABLE_PYTHON) endif() if (NOT EAMXX_ENABLE_GPU) - # Run an ml emulator for cld-fraction - set (PY_MODULE_NAME "cld_fraction_ml") - set (PY_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) - set (POSTFIX pyml) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml - ${CMAKE_CURRENT_BINARY_DIR}/input_pyml.yaml) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml - ${CMAKE_CURRENT_BINARY_DIR}/output_pyml.yaml) + # Create executable that runs cld_frac_net emulator + CreateADUnitTestExec(cld_frac_net_standalone + LIBS cld_frac_net) # Test the process with python ml emulator - CreateUnitTestFromExec(cld_fraction_standalone_pyml cld_fraction_standalone + set (PY_MODULE_NAME "cld_frac_net") + set (PY_MODULE_PATH ${SCREAM_BASE_DIR}/src/physics/cld_fraction/cld_frac_net) + set (POSTFIX ml_py) + set (WHICH_EMULATOR python) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/input_ml_py.yaml) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml + ${CMAKE_CURRENT_BINARY_DIR}/output_${POSTFIX}.yaml) + + CreateUnitTestFromExec(cld_frac_net_py cld_frac_net_standalone EXE_ARGS "--args -ifile=input_pyml.yaml" LABELS cld_fraction physics FIXTURES_SETUP cldfrac_pyml) diff --git a/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml b/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml new file mode 100644 index 000000000000..cb76be3a019c --- /dev/null +++ b/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml @@ -0,0 +1,33 @@ +%YAML 1.1 +--- +driver_options: + atmosphere_dag_verbosity_level: 5 + +time_stepping: + time_step: ${ATM_TIME_STEP} + run_t0: ${RUN_T0} # YYYY-MM-DD-XXXXX + number_of_steps: ${NUM_STEPS} + +eamxx: + atm_procs_list: [cld_frac_net] + cld_frac_net: + ice_cloud_threshold: 1e-12 + py_module_name: ${PY_MODULE_NAME} + py_module_path: ${PY_MODULE_PATH} + emulator: ${WHICH_EMULATOR} + +grids_manager: + type: mesh_free + grids_names: [point_grid] + point_grid: + aliases: [physics] + type: point_grid + number_of_global_columns: 218 + number_of_vertical_levels: 72 + +initial_conditions: + filename: ${SCREAM_DATA_DIR}/init/${EAMxx_tests_IC_FILE_72lev} + +scorpio: + output_yaml_files: [output_${POSTFIX}.yaml] +... From 2f5794e66955e928ee2aae3eb19dd84233b86ea5 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 16:55:39 -0700 Subject: [PATCH 175/398] EAMxx: add a version of the cld_frac_net test that uses a LAPIS-generated c++ emulator --- .../cld_fraction/cld_frac_net/CMakeLists.txt | 3 +- .../cld_frac_net/cld_frac_net.cpp | 80 ++++ .../cld_frac_net/cld_frac_net.hpp | 371 ++++++++++++++++++ .../eamxx_cld_frac_net_process_interface.cpp | 71 +++- .../cld_fraction/CMakeLists.txt | 14 + 5 files changed, 527 insertions(+), 12 deletions(-) create mode 100644 components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.cpp create mode 100644 components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.hpp diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt b/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt index c632dc805e39..4a42e1865458 100644 --- a/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt @@ -1,6 +1,7 @@ if (EAMXX_ENABLE_PYTHON) - # Process wrapping ML emulator via python hooks + # Process wrapping ML emulator (either via python or LAPIS-generated c++ code) add_library(cld_frac_net + cld_frac_net.cpp eamxx_cld_frac_net_process_interface.cpp ) target_compile_definitions(cld_frac_net PUBLIC EAMXX_HAS_CLD_FRAC_NET) diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.cpp b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.cpp new file mode 100644 index 000000000000..9e5a82fe88ed --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.cpp @@ -0,0 +1,80 @@ +#include "cld_frac_net.hpp" +Kokkos::View __constant_72x64xf32; +float __constant_72x64xf32_initial[4608] = {5.039675160e-02f, 1.816355620e-03f, -1.048519390e-03f, -3.129377960e-03f, -3.209809770e-03f, 1.132022590e-02f, 5.144340920e-03f, -6.449549920e-03f, 3.099210790e-03f, -1.448580160e-02f, 2.659639900e-02f, 4.984908920e-02f, 1.583657040e-02f, -4.572635140e-02f, -1.042348150e-02f, -1.443966480e-02f, 3.249641140e-02f, 4.329416530e-02f, -7.166212890e-03f, 1.837908850e-02f, 1.316535290e-03f, 3.426233310e-02f, -3.885491980e-03f, -2.297011580e-02f, -7.662199900e-03f, 1.416810320e-03f, -2.143757600e-02f, -3.127517180e-03f, -3.216482330e-02f, -5.772076550e-02f, 4.844619710e-02f, 1.711166090e-02f, 1.016895290e-02f, 1.531377200e-03f, -1.875928020e-03f, -1.607235150e-02f, -6.380710980e-04f, -1.918163340e-02f, 2.440743520e-02f, -1.493635770e-02f, 3.730115670e-02f, 2.118306700e-03f, 2.254833000e-03f, 6.139996930e-03f, 6.104545670e-02f, 3.988775610e-02f, 2.335721250e-02f, -2.621491910e-03f, 3.394498680e-02f, -2.233984410e-03f, 3.426165320e-03f, -4.432959020e-03f, 1.963996510e-02f, -1.409346470e-03f, -1.248045080e-02f, 1.610278520e-02f, 3.447010740e-02f, 5.494024230e-02f, 5.750342090e-02f, -1.177896980e-03f, -8.650802080e-03f, -2.361516470e-02f, -5.226240490e-03f, -2.573382300e-02f, -3.081547100e-03f, -9.050056100e-04f, 2.591983420e-02f, -1.447335930e-03f, 2.918047360e-03f, -1.048658700e-02f, 3.124891550e-03f, 6.183836610e-03f, 5.330257120e-04f, 1.790288840e-02f, 5.653236810e-02f, -7.671571800e-04f, 5.619513620e-02f, -1.942226290e-02f, 2.118010540e-03f, 1.652766020e-02f, 5.044241620e-02f, -1.203428370e-03f, 2.527920160e-02f, 7.505202660e-03f, -1.648539680e-03f, 2.558520060e-02f, -8.521040520e-02f, -3.755750830e-03f, 1.099147650e-02f, 3.258467880e-03f, 2.839207840e-02f, -1.153367920e-03f, -2.726361530e-02f, 2.402161250e-02f, 3.136486560e-02f, 1.613059080e-02f, 1.464977300e-02f, 2.942964430e-02f, 6.522262000e-03f, 3.268810730e-02f, -2.335576810e-03f, -3.120853570e-02f, 5.950650200e-02f, 1.545080260e-02f, -5.555931480e-02f, 2.988365710e-03f, -2.494763350e-03f, -4.873680420e-03f, 3.391852970e-02f, -5.114056920e-02f, 4.566877610e-03f, 1.057222210e-02f, -3.561048580e-02f, -2.994352950e-03f, -2.690321950e-02f, 1.332848450e-03f, 1.129507200e-03f, -3.035347160e-02f, -1.173543280e-02f, 3.486637030e-02f, -1.290700030e-02f, 4.112686590e-02f, -4.956072940e-02f, 3.861331190e-02f, -1.625982110e-02f, 1.706940490e-02f, 5.951320380e-02f, -7.972858850e-02f, 5.765192210e-02f, 3.802338030e-04f, 4.625268280e-03f, -7.098481990e-03f, 6.617832180e-02f, -9.667997940e-04f, -2.606295980e-03f, 3.413237630e-02f, -4.534265610e-04f, 2.322084080e-02f, -3.434502050e-03f, 4.454157870e-02f, 8.305963120e-03f, -2.692387070e-02f, -4.465280100e-03f, 9.696433320e-03f, 2.961070510e-03f, -5.300531910e-02f, 1.704993100e-02f, -4.101344850e-03f, -4.294428040e-03f, -2.482699420e-02f, -3.577945010e-02f, 2.908459490e-02f, -1.616835780e-02f, 3.113572950e-03f, -3.009995260e-02f, 2.304974480e-03f, 1.119262170e-02f, 2.830423230e-02f, 2.361708510e-02f, -1.428928320e-02f, -4.736150430e-02f, -4.208923500e-02f, -3.159225360e-02f, -5.526415070e-03f, -4.744212610e-03f, 2.297036720e-02f, 4.639003050e-02f, 3.274838440e-03f, -2.984566990e-02f, 6.690310780e-03f, 5.723270590e-03f, 3.394671900e-02f, 3.353772680e-02f, 1.526870670e-02f, 3.598477320e-02f, 9.387615720e-04f, 3.582923490e-02f, 3.576191840e-03f, -1.453284170e-02f, -5.670394280e-03f, 3.520348810e-03f, -3.011517790e-02f, -1.048252080e-02f, -3.873636200e-02f, -1.925917900e-02f, -4.346650090e-02f, 5.218527470e-02f, -3.869427000e-02f, 1.667373700e-03f, -2.997909860e-02f, 8.840157830e-02f, 5.181342360e-02f, -1.894328740e-02f, 4.151237200e-03f, 2.758203820e-02f, -1.096766540e-02f, 8.126351980e-02f, -1.286688350e-02f, 3.182893150e-03f, -2.053124640e-02f, 7.494864980e-04f, 3.123668430e-04f, -8.029472660e-04f, 3.568846730e-02f, -8.188276730e-02f, 5.743903290e-02f, -1.744500940e-03f, -1.919777880e-02f, -3.788208220e-02f, 5.217172580e-02f, -3.559024770e-03f, 1.645457000e-02f, -1.990116870e-04f, 5.644297690e-03f, -3.372668850e-02f, -7.846254850e-02f, 2.030065100e-02f, 8.709441870e-03f, 4.561629520e-02f, -6.139667700e-03f, -1.641184440e-03f, -1.424592450e-02f, -3.838796170e-02f, -2.419259590e-02f, -7.630231970e-02f, 1.236789210e-02f, 2.259099300e-02f, 1.835528060e-03f, -2.285451160e-03f, 5.241337050e-02f, -3.835476190e-02f, 2.257555750e-04f, 3.899342570e-02f, 1.194888910e-02f, 1.023695900e-02f, 1.189536320e-02f, 1.213074200e-02f, 5.609554420e-02f, -4.137536880e-02f, 3.365329700e-03f, 3.068879010e-03f, 4.958898060e-04f, 2.553366120e-02f, -2.951117930e-03f, 1.168822640e-03f, 1.660094780e-02f, -1.673045570e-02f, 1.805254440e-02f, 3.073873000e-02f, 2.122219090e-02f, -5.856660750e-02f, -2.110612390e-02f, 2.016045150e-02f, 1.074881010e-02f, 1.705846560e-02f, 5.006358400e-02f, 3.659699350e-03f, 7.131302260e-04f, 1.481007410e-02f, 1.468294770e-03f, -1.525773110e-02f, 1.395458010e-03f, -8.988429320e-04f, -4.936466920e-03f, 7.258275060e-03f, 5.680423230e-02f, 1.314441300e-02f, -4.828528690e-02f, -1.612272860e-02f, 3.357605640e-02f, 5.271332340e-03f, -2.071554400e-02f, 2.389941180e-02f, 9.709184060e-03f, -3.711768890e-03f, -5.038583280e-02f, 8.826300620e-04f, -5.342102050e-02f, -3.220348810e-02f, -4.802265390e-02f, -1.595497500e-02f, -1.320534150e-03f, 9.576974060e-02f, -1.671747070e-03f, 7.202965670e-03f, -3.674043340e-02f, 2.857184040e-02f, 4.155623170e-02f, -9.196789930e-03f, -3.039116970e-02f, -1.537246720e-02f, 1.203331910e-02f, -6.431367250e-03f, -2.800931040e-02f, 9.524404070e-03f, 1.885052960e-02f, 8.109636830e-04f, 3.379197790e-03f, 3.816189240e-03f, 3.929240260e-02f, 4.636329410e-02f, 4.833029210e-02f, -1.229378580e-02f, 6.409174300e-03f, 2.906179990e-02f, -5.041395780e-03f, 3.825965150e-02f, -1.632827680e-03f, 5.905829370e-03f, 2.426532100e-02f, -9.758697820e-03f, -3.308242190e-02f, -1.230390740e-02f, 4.763457550e-02f, -3.221245480e-02f, 5.866737660e-02f, 1.128719840e-02f, -2.680496500e-02f, -6.812535970e-02f, -5.641743170e-02f, 3.301103410e-02f, 3.461507850e-03f, 3.906198220e-02f, -5.543783310e-03f, 5.081664770e-02f, -8.061734030e-03f, 8.807209670e-04f, 2.218051810e-02f, -2.171750650e-03f, 2.839083600e-02f, -7.515546670e-02f, -3.175101240e-03f, -6.971214710e-02f, 4.239488770e-02f, -1.261194800e-02f, -2.193642220e-02f, 6.672054530e-02f, -4.856307060e-02f, -2.366399770e-02f, 3.619193290e-02f, 2.722184170e-03f, -2.215158380e-02f, -3.700258580e-02f, 2.454421110e-02f, -4.594663530e-02f, 8.024828500e-03f, 4.689074680e-02f, 1.293578190e-03f, 6.391227990e-02f, -4.567915570e-02f, 4.125043380e-02f, 1.172020470e-02f, -1.816998240e-02f, -4.343995080e-02f, -1.343804690e-02f, 2.044369230e-03f, -1.732009350e-03f, -2.755223770e-02f, -4.506603260e-02f, -7.722390440e-02f, 4.902357980e-02f, 8.900629350e-03f, 5.820656200e-03f, 3.385548670e-02f, 9.505311020e-03f, -2.045387030e-02f, -3.744955730e-02f, -6.682544950e-03f, -2.973090390e-03f, 2.365998920e-03f, 1.915840620e-02f, -3.755153390e-03f, 6.065275990e-03f, 3.768255560e-02f, -7.687830370e-04f, 3.221543880e-02f, 1.319960690e-02f, -5.882420390e-02f, 2.460983770e-02f, -1.148120410e-02f, -5.306487440e-03f, -2.302646260e-02f, 5.958523970e-02f, 2.522436720e-02f, -5.511559550e-03f, 9.007842160e-04f, -4.980782980e-03f, 3.339909950e-03f, -1.711743510e-02f, 1.424192160e-04f, -4.193261730e-03f, 3.008896720e-03f, -2.195785990e-03f, -4.930741710e-02f, 2.827842720e-02f, -4.196434470e-02f, -7.424659280e-02f, 1.143738350e-02f, 1.639710390e-03f, 3.868330640e-02f, -2.902516910e-02f, -4.762267230e-03f, 8.398548700e-03f, -2.093337100e-02f, -2.104847810e-04f, 4.557420310e-02f, 4.778900740e-02f, -4.288321360e-03f, -2.835764780e-03f, 5.566761360e-03f, -2.015782990e-03f, 1.408686510e-03f, -4.294202850e-02f, 4.070054740e-02f, -1.927753720e-02f, -9.645877400e-03f, 2.041579600e-02f, 3.592430430e-02f, 1.632720600e-02f, -2.347774800e-02f, 7.297344510e-03f, 6.498976050e-02f, -3.627172860e-02f, 5.888640510e-02f, -1.694434140e-02f, 7.636971770e-03f, 6.050275640e-03f, -3.598172220e-02f, -8.406409060e-03f, 3.940618600e-03f, 4.712230710e-02f, -1.106758950e-03f, 1.147411300e-03f, 8.830538010e-03f, -3.067912530e-02f, -2.482779090e-03f, -5.070656070e-03f, -2.228938510e-03f, 1.172764970e-02f, -4.008006300e-03f, -2.901419300e-03f, -8.448888550e-03f, -5.499703060e-02f, -7.288965580e-02f, 2.809320390e-02f, 4.881946370e-02f, 4.079927880e-02f, -2.514097650e-02f, 2.880299840e-02f, -4.063992760e-03f, 1.026312170e-02f, -7.225851530e-03f, 9.959567330e-02f, 1.322198100e-02f, 2.067165680e-03f, -3.134882540e-03f, 6.249997760e-03f, 2.682672070e-02f, 1.076470130e-02f, 4.371608790e-02f, 2.134795300e-03f, 1.431540820e-03f, 6.955363790e-03f, -3.693438320e-02f, 2.638042530e-02f, 5.143051590e-02f, -1.841061560e-02f, 7.472892850e-02f, -1.118847290e-03f, 6.019521130e-02f, 4.143662520e-04f, 6.646249910e-03f, -3.576827050e-02f, -6.266696840e-03f, 2.954204330e-03f, -2.605207850e-04f, 8.775758560e-03f, -4.956744980e-02f, -5.391005890e-03f, -3.090046350e-02f, -1.073335630e-01f, 3.511515260e-02f, 4.659116270e-02f, -9.479647500e-03f, 7.657987530e-03f, -1.009252480e-02f, -8.293569090e-03f, 6.552328910e-02f, 4.671332990e-02f, -6.062263620e-03f, -6.665321530e-03f, -3.700105100e-02f, -5.035180970e-02f, -4.733771460e-02f, 2.008502930e-02f, 2.132185730e-03f, -6.098417940e-02f, -6.920300890e-03f, -5.098272580e-03f, 3.822621190e-03f, -3.722737310e-03f, -4.483044890e-02f, 3.891426320e-02f, 2.825361490e-02f, -5.399093030e-03f, -8.098844430e-03f, 4.263988700e-03f, -2.186992950e-02f, -3.343366090e-02f, 9.119020770e-03f, -4.655666650e-02f, -3.669820730e-02f, -3.190216790e-02f, -1.818228050e-03f, -2.530037430e-02f, -5.673840130e-05f, -1.495815630e-02f, -7.866321830e-04f, -3.501242030e-04f, 2.193324080e-02f, 2.696640090e-03f, -3.926385940e-02f, -1.546891220e-02f, -4.619505260e-02f, -2.379132250e-02f, -2.053214800e-02f, 3.151174400e-03f, 3.847903760e-02f, -4.764529320e-02f, 2.360011450e-02f, 3.929880260e-02f, -3.898962590e-02f, 2.609633610e-03f, 1.479315850e-02f, 3.026345740e-03f, -9.038660670e-03f, -7.892581070e-02f, -2.994386940e-03f, 3.048753740e-02f, -5.507179540e-03f, -1.440040390e-02f, -2.278619820e-02f, -3.216497970e-02f, -3.387915340e-02f, -4.443476350e-02f, -3.610945490e-02f, 2.769696990e-03f, 2.881984230e-02f, 6.501260210e-03f, 2.771480200e-02f, 4.749839750e-02f, 1.019006220e-02f, -1.732750610e-02f, -2.087247560e-03f, -1.494963190e-03f, -1.022190550e-03f, 1.446328410e-02f, 1.843371990e-02f, -1.046873630e-03f, 1.155634690e-02f, -2.751376290e-02f, -2.050885460e-03f, -1.223505240e-03f, 4.117352890e-03f, 2.749771350e-03f, 5.213348780e-04f, 4.681213570e-02f, -4.549654570e-02f, 3.151456640e-02f, -7.055596260e-02f, -3.377077360e-02f, -4.538092390e-02f, -1.538570130e-02f, -8.982446040e-03f, -1.101289320e-02f, 2.466570960e-02f, 6.313927470e-02f, 8.773569710e-04f, -8.249338710e-03f, 2.227068410e-03f, -6.420890240e-02f, 1.960866150e-02f, 4.143589640e-03f, 3.465021030e-02f, 1.243220830e-02f, 2.145726790e-02f, -8.465066550e-02f, -2.119190800e-02f, -2.869074790e-02f, -1.419066360e-02f, -8.394721890e-03f, 2.809756990e-02f, -4.375211890e-02f, 2.081934180e-02f, 1.397063400e-02f, -1.243853290e-02f, 5.482490520e-04f, -1.947708240e-02f, -2.079188360e-03f, -5.171258000e-02f, 7.489013020e-03f, -3.961304670e-03f, 4.260176790e-02f, 3.579084060e-03f, -4.994657360e-03f, 1.330449620e-02f, 2.678862590e-02f, 3.638800980e-02f, 2.929294850e-02f, 6.509843460e-02f, -5.827464160e-02f, 3.774730860e-02f, -4.727325870e-03f, -1.455994790e-02f, 1.387763490e-02f, -4.171676560e-02f, 4.755815030e-03f, 2.111481500e-03f, 6.408945770e-04f, 1.719869490e-02f, 4.391235770e-03f, 2.807351390e-02f, -3.902306780e-02f, 6.624282800e-03f, 2.948093230e-03f, -1.486003860e-02f, 1.101314930e-02f, 3.593138540e-05f, 2.922513290e-03f, 2.567647770e-02f, -4.812373590e-02f, -7.378643750e-02f, 4.479020460e-02f, -1.041395360e-03f, -8.744820020e-03f, 2.320952710e-03f, 4.975449760e-03f, -7.770965340e-03f, 8.469079430e-02f, -4.360507060e-02f, -7.292720670e-02f, -4.999140510e-04f, 2.226322140e-02f, 9.830012910e-03f, 6.362102180e-02f, -4.946738480e-03f, 2.656274480e-03f, 7.771547880e-03f, -5.391955840e-03f, 1.399385560e-02f, -1.926689410e-02f, 5.673507230e-02f, -4.561771450e-02f, -5.604008680e-03f, -3.646739990e-03f, -3.351546450e-02f, -2.475067270e-03f, 2.049638140e-02f, -3.911843150e-02f, -1.246855590e-02f, 1.134646300e-04f, 8.876158860e-03f, 3.061755000e-02f, -6.294864420e-02f, -2.955546980e-02f, -5.408221040e-04f, -3.019200270e-02f, 1.860608750e-04f, -2.396381090e-02f, 3.917393460e-02f, 7.013621920e-02f, -1.411825420e-02f, 2.061858770e-02f, 1.653119740e-02f, 2.768938240e-02f, -4.654838520e-02f, -7.900834080e-03f, -2.040318210e-02f, -7.917126640e-03f, 1.899714210e-02f, -4.508694630e-02f, -5.426663910e-03f, -5.817846860e-03f, -1.705547420e-02f, -5.141012740e-02f, -7.531867920e-02f, -9.163252080e-03f, -1.179893270e-03f, -1.550412460e-02f, 2.077144100e-03f, 7.816698400e-02f, 4.017585420e-03f, -6.456176280e-03f, -4.501570390e-02f, -1.514051760e-02f, -6.230932100e-02f, 2.551472930e-02f, 6.025541950e-02f, 1.679725570e-02f, -2.547723240e-02f, 2.231115100e-02f, -1.476836860e-02f, -6.114861740e-02f, 2.159111760e-02f, 2.712344560e-02f, -1.239952510e-03f, 2.532825620e-02f, 1.900147530e-03f, 2.773852460e-02f, -9.189132250e-04f, 1.270509790e-03f, -1.204866080e-02f, 3.041205460e-03f, -4.150499030e-02f, 8.116883690e-05f, -5.915413610e-03f, -6.346714500e-02f, -1.568893340e-02f, 6.235597650e-03f, 2.658811030e-02f, 8.266559800e-03f, -1.616692050e-03f, -1.230631120e-02f, -1.796944250e-02f, 1.622307320e-04f, 1.078596620e-02f, 3.369166700e-02f, -1.881098560e-02f, -1.749147100e-02f, -6.228978280e-03f, -4.979809750e-03f, 1.204554110e-03f, 1.145905720e-02f, 2.814439680e-02f, 2.967616360e-02f, -3.552025930e-02f, 2.066826260e-02f, 5.208292510e-03f, -2.301172350e-02f, 9.896677920e-03f, -2.719245850e-03f, 3.535004330e-02f, 2.918902040e-02f, -4.635914040e-02f, -4.057498650e-02f, -6.223970560e-03f, -4.309909420e-03f, 9.921470650e-03f, -2.900942790e-02f, -8.512532710e-02f, -2.025807090e-02f, 1.825105750e-03f, -2.877496740e-02f, -2.090370540e-04f, -1.304264270e-02f, 1.053030860e-04f, -1.060891310e-03f, -4.475763440e-02f, 6.566921620e-02f, 3.700884520e-03f, 1.508713700e-02f, -4.541805010e-02f, -1.179576940e-02f, 5.787468330e-02f, 1.742930270e-03f, 9.542978370e-03f, -3.691721010e-03f, 8.446232970e-02f, -6.705857070e-02f, -4.239538220e-03f, 3.327493320e-03f, -2.358626110e-03f, 5.207167940e-02f, 8.105332960e-03f, -1.137094460e-03f, -4.209977110e-03f, -5.007493310e-03f, 4.111776650e-04f, -4.387975480e-02f, 3.156779710e-02f, -6.169014050e-02f, 1.854648440e-02f, -4.724222240e-03f, 4.013554190e-03f, -4.052213950e-02f, 2.087493050e-02f, -1.807299820e-02f, -2.319915920e-03f, 1.203442340e-03f, -2.464728620e-02f, -2.088896370e-02f, 6.880958380e-02f, -4.230538380e-02f, -4.270270470e-03f, -9.786073110e-03f, -8.190106600e-03f, -3.062810940e-02f, 3.455177320e-02f, -8.775789290e-03f, -1.198465470e-02f, -3.712506960e-02f, 3.897590190e-02f, -3.684068840e-02f, -1.628857110e-02f, 2.283197130e-03f, -9.465468120e-03f, -4.627868910e-02f, -3.038903700e-02f, -4.949972030e-02f, -2.636761640e-03f, -8.953106010e-04f, 3.332936670e-03f, 1.190346290e-02f, 3.543746840e-02f, -2.239014770e-02f, -2.536588580e-03f, -4.265435410e-02f, 1.715690710e-03f, -4.792936150e-02f, 2.853952120e-03f, -9.346836600e-04f, -3.119303660e-02f, -1.039772390e-02f, -2.487746250e-02f, 2.513594550e-02f, -2.058607290e-03f, -4.942055050e-02f, 4.411006720e-02f, 1.671042290e-02f, 2.718741820e-02f, -3.004332450e-02f, -3.239284460e-02f, -3.551207950e-03f, 2.179381850e-04f, -7.766479160e-03f, -1.101474390e-03f, -2.516768310e-02f, 3.270405800e-05f, -6.826174450e-03f, 4.426762930e-03f, -4.022252280e-03f, 5.813395230e-02f, -7.593764360e-02f, 8.290336280e-02f, 8.303711560e-02f, 1.410151270e-02f, -1.347623580e-02f, 3.365278620e-02f, 2.878378520e-02f, -2.872972940e-02f, -1.183235180e-02f, 3.735436130e-02f, -3.477450930e-03f, -3.336972370e-02f, 3.647560250e-02f, 2.028642410e-02f, 3.550109640e-02f, 1.361558770e-02f, 7.941473270e-03f, -1.232354160e-02f, 3.459867460e-02f, 2.370529060e-02f, 1.156633350e-02f, 1.404195190e-02f, 6.472793970e-02f, 1.165783680e-02f, 7.151358760e-03f, 2.393803930e-02f, -9.179661980e-03f, 2.881897990e-02f, -5.108999090e-02f, -2.625864000e-03f, -1.141329330e-01f, 1.269733720e-02f, 1.260001400e-02f, 4.057193170e-02f, 7.304789490e-03f, 3.919009580e-03f, -5.344666170e-02f, -3.733036110e-03f, 3.024448450e-02f, 1.022966210e-02f, 2.362943440e-02f, -3.719868370e-03f, 4.948065620e-03f, 5.323695390e-02f, 2.091215740e-02f, 3.735527020e-02f, -5.269033830e-02f, -3.081556220e-02f, 7.759757810e-03f, -2.258453700e-02f, -6.664565300e-03f, -4.195663710e-02f, 2.309901640e-02f, -6.746646760e-02f, 1.711969080e-02f, -5.075416990e-03f, -9.584521870e-03f, 7.499785160e-03f, 3.609405460e-02f, 4.807945810e-03f, 5.605806130e-03f, -9.338734670e-03f, 2.531619100e-04f, 5.161980540e-02f, 1.465779360e-02f, 1.817851510e-02f, -8.699479690e-02f, 5.130713810e-02f, 1.469368020e-02f, 1.829534770e-02f, 3.717953710e-02f, -9.669993070e-02f, -2.103350870e-02f, 3.452547640e-02f, -1.122796910e-03f, -8.608443660e-03f, 1.491166370e-02f, -3.693100810e-02f, 2.274328660e-02f, -3.109310520e-03f, 4.139795150e-02f, -3.628419250e-03f, -2.791908760e-02f, 1.622736450e-02f, -7.983432710e-02f, 1.816579330e-02f, -1.065023940e-03f, 2.118569800e-02f, 2.268052290e-02f, 5.424901380e-03f, 8.421513250e-03f, -1.471933630e-02f, 1.538158020e-02f, 1.912552680e-02f, 2.205987830e-02f, -8.626691070e-03f, -8.480149320e-03f, -1.605511640e-02f, 5.859018490e-02f, 1.830326510e-04f, 9.859704410e-03f, 7.000350860e-03f, -7.174257190e-03f, -8.316134100e-03f, -1.933151670e-02f, 3.265693550e-03f, -4.310267980e-03f, 2.044035680e-02f, -1.115304600e-02f, 1.101110830e-03f, -2.852529850e-02f, 3.184547650e-02f, 2.715831810e-02f, -1.567059010e-02f, -3.401511540e-02f, -9.378766640e-03f, -9.458338840e-03f, 3.391476350e-02f, -4.020601140e-02f, 1.823014930e-03f, -2.741823160e-02f, -4.828175530e-03f, 2.476353570e-02f, 1.749078630e-03f, 3.559621520e-03f, 3.313305090e-03f, -5.495729860e-03f, 5.621375050e-03f, -4.441493000e-02f, 3.853378820e-02f, 3.427402680e-02f, -1.490761710e-02f, 1.956152500e-03f, -1.659537850e-02f, 3.515008460e-02f, -1.058860590e-02f, 4.860813540e-02f, 6.277580560e-02f, -2.262435150e-03f, -5.692865700e-02f, -5.429433290e-02f, 4.399743680e-02f, 3.731172530e-02f, 3.008242700e-03f, -1.581891210e-03f, -2.443745970e-03f, -2.150297160e-02f, 6.412792490e-03f, -2.620317040e-02f, -2.481667700e-02f, -4.595422370e-02f, 4.993857070e-02f, -1.051283330e-03f, 1.639837210e-02f, 3.437667390e-03f, 2.377011630e-02f, -5.433973300e-02f, 2.123281920e-02f, -4.770533370e-02f, 2.862184770e-03f, -1.792805040e-03f, -3.718697230e-03f, 3.858123720e-02f, 3.620231900e-02f, 4.897040780e-03f, -3.182566490e-03f, 3.642556440e-02f, 1.284309660e-03f, 2.165406940e-03f, -2.382594390e-03f, 6.600909870e-03f, 3.149408100e-02f, 5.898993000e-03f, -1.995999550e-02f, -4.716376590e-02f, -3.383744510e-03f, -5.115054180e-02f, -4.475602880e-02f, 8.970193560e-03f, 2.994434540e-02f, -4.392652960e-02f, 1.617828010e-02f, 3.157832100e-02f, 2.054321580e-03f, -1.175284570e-02f, -1.087481440e-02f, 5.534980820e-02f, -9.750031870e-03f, -3.957288340e-03f, 4.784768450e-02f, -2.970278030e-03f, -1.352555580e-02f, 7.175601270e-02f, 4.193510860e-02f, -5.053842070e-02f, -3.780571000e-02f, -5.394490900e-03f, 1.886330170e-02f, -1.537127890e-02f, 1.080204320e-01f, 4.620061810e-02f, 4.118554670e-02f, 3.624905660e-04f, 1.281621120e-02f, 4.312766340e-02f, -2.745565210e-02f, 1.676523130e-02f, -1.507858280e-03f, 3.913101550e-02f, 7.998534130e-04f, -6.144391370e-03f, -4.160329230e-03f, 5.586208400e-02f, -4.664996640e-02f, 1.155362840e-02f, 2.130960670e-02f, -1.236364710e-02f, 3.713136540e-03f, 3.371288070e-03f, -3.552237150e-02f, -8.467390200e-03f, 4.610978440e-02f, -9.777619680e-02f, 4.365857690e-03f, 9.392194910e-04f, 1.043941710e-03f, 2.190944370e-02f, -3.540152680e-02f, 1.020382620e-02f, -3.325551520e-04f, 3.592551130e-02f, -4.666098860e-03f, -3.311741350e-02f, 5.006931020e-04f, 5.090936550e-03f, -6.172705440e-02f, 1.884701660e-03f, 2.555668540e-02f, 1.583478970e-02f, 3.086632120e-02f, -1.422150150e-02f, 3.486654530e-02f, 9.937540620e-03f, -8.274858810e-03f, -3.695719410e-03f, -1.072067580e-02f, 7.025482510e-02f, 2.557244150e-03f, 3.091893350e-02f, -2.111536220e-03f, -4.331588000e-02f, -1.217321400e-02f, 2.021936930e-03f, -6.696174390e-03f, 1.141193790e-02f, 3.547255420e-03f, -1.288645620e-02f, -4.296880960e-02f, 4.243818300e-02f, -3.215173630e-02f, -1.134362420e-03f, -4.497692450e-03f, 1.734388990e-02f, -2.847048640e-02f, -1.924064480e-03f, -8.087188000e-02f, 3.987800800e-03f, 3.395267950e-02f, -5.185601120e-02f, 2.447798660e-02f, 4.252571240e-02f, -3.980390900e-04f, 2.067768010e-02f, 5.676656030e-03f, 2.081970680e-02f, 4.385021700e-02f, 1.212724210e-02f, 1.680274310e-02f, 5.585604530e-02f, -2.461827170e-02f, 3.932116930e-02f, -2.821242060e-02f, -4.216879020e-04f, -2.159743010e-02f, -3.885848080e-02f, -2.529549880e-03f, -6.270855670e-03f, -7.240630220e-04f, -1.027765800e-03f, 1.220490410e-02f, 4.905771460e-02f, 2.257603030e-02f, 5.615994330e-02f, -1.400108450e-03f, 2.517087150e-03f, -3.817922670e-03f, -4.941258210e-02f, -4.524394170e-06f, 2.456396760e-04f, 9.539202790e-03f, -3.744669490e-03f, -4.102689400e-02f, -2.155645010e-02f, -4.986649750e-02f, 3.897002710e-02f, 2.319878530e-02f, 4.483596240e-02f, 3.083514420e-02f, -1.026513430e-02f, -2.299031800e-02f, 2.287860400e-02f, 1.862514410e-03f, 7.786830420e-03f, -3.720117030e-03f, 1.984784190e-02f, -5.020218900e-03f, -3.119618630e-03f, -1.858514040e-03f, -9.488712530e-04f, 2.028715560e-03f, 6.925190990e-02f, 9.274693200e-03f, 7.953861350e-02f, 2.255807070e-02f, 8.365539830e-03f, 1.074789000e-02f, -3.993473570e-02f, -4.273235430e-02f, 2.364899960e-03f, 6.678732480e-02f, 2.813397150e-04f, -2.144539170e-02f, -3.367085010e-02f, -2.456076260e-02f, -4.018720240e-02f, -8.332229220e-03f, 3.109552150e-02f, -7.398990450e-03f, 5.451650170e-02f, 5.566410350e-02f, -1.311151120e-02f, 1.480676980e-02f, 1.868895950e-03f, -1.660350900e-02f, 8.075127750e-02f, 1.639607360e-02f, -3.554227300e-03f, -5.189017210e-02f, -5.006548020e-04f, 3.698743880e-02f, 6.572099030e-02f, -5.860202480e-03f, -5.859955680e-03f, -9.616743190e-04f, -1.791705380e-02f, -5.066301300e-02f, -1.447824480e-02f, 9.050728750e-03f, -1.488617710e-02f, -2.992176220e-03f, 3.759764880e-02f, 2.970815870e-03f, -3.619717200e-03f, -1.574362070e-02f, -3.466504440e-02f, 1.922909540e-02f, 4.986486210e-02f, -6.654193990e-02f, -3.301447260e-02f, -3.928470610e-02f, 4.085647310e-02f, 1.365671520e-03f, 1.159528920e-02f, -2.805807630e-02f, 5.410515140e-02f, -3.110233690e-03f, -1.026745050e-02f, 3.746160770e-03f, 2.992511350e-02f, -1.565087770e-02f, 2.306226180e-03f, -2.190578170e-02f, 4.467499910e-03f, -2.080144550e-02f, -5.041148890e-02f, 2.251817290e-02f, -5.768527460e-02f, 3.019155000e-02f, -3.793546700e-03f, 2.115584540e-02f, 2.292894010e-02f, -3.202914070e-02f, 9.185754690e-03f, 6.196561270e-03f, 4.226667810e-04f, -6.879161300e-02f, 3.217987340e-02f, 4.529470580e-02f, 2.548273650e-02f, -8.066616950e-03f, 5.444742740e-03f, 3.329372730e-03f, 1.907960700e-02f, -4.131694510e-02f, 9.545203290e-03f, 1.141767670e-02f, 1.201852340e-01f, 3.484996040e-02f, -1.461716460e-02f, -6.889774650e-02f, 2.818252190e-03f, -5.986554080e-03f, -4.529212040e-02f, 2.378319950e-02f, -7.359243930e-02f, -5.169595590e-03f, -8.419843390e-03f, -3.125735000e-02f, 2.581006100e-02f, -6.659360230e-02f, -4.421668870e-02f, 1.946305040e-03f, -1.178066060e-02f, -1.715132380e-03f, 1.270791330e-02f, 8.362111980e-04f, 1.871443700e-03f, 2.507487680e-02f, -5.104877430e-02f, -1.389827230e-04f, -2.729392730e-04f, -1.307433380e-02f, 7.687909160e-02f, 4.858180880e-02f, 8.382479660e-03f, 2.125529390e-02f, -2.352677470e-02f, -6.537672130e-02f, -3.509742210e-03f, -2.186163790e-03f, 1.662906820e-02f, 8.075256830e-03f, 4.507776350e-02f, 1.097816790e-02f, -6.408737970e-03f, 3.044827280e-02f, -6.323807410e-03f, -1.387632360e-02f, 8.038165040e-03f, -2.249041200e-02f, -4.493029040e-02f, 2.407008220e-02f, 2.836893780e-03f, 4.270641510e-02f, -1.155424400e-02f, -7.049343730e-02f, -8.571554910e-03f, -2.739535830e-02f, 6.228660930e-04f, -3.200378270e-02f, -4.622963070e-02f, -5.339416490e-02f, 2.101906390e-02f, 1.547424700e-03f, 1.152957700e-02f, -9.132016570e-04f, 1.922263760e-02f, 5.806452410e-02f, -1.451967940e-02f, -7.097449620e-03f, -1.727088910e-02f, -5.152482170e-02f, 2.123043500e-02f, -3.628294450e-03f, 6.439326800e-03f, 3.232049570e-02f, 1.932292990e-02f, -3.577430920e-02f, 1.458944190e-02f, -5.662762560e-03f, -8.674891430e-04f, 2.619911540e-02f, -3.701648860e-02f, -1.357009350e-02f, -1.209570090e-03f, 2.772610630e-03f, -3.389005360e-02f, -4.507963890e-04f, 2.932000160e-02f, -7.720208380e-04f, 3.693375040e-03f, 1.655584320e-03f, 5.150641500e-02f, 1.646138730e-02f, -2.323505000e-03f, -3.304202850e-02f, -2.827545630e-02f, 4.052118960e-02f, 4.034825410e-02f, -5.462929230e-02f, -1.987346260e-02f, -5.043418330e-02f, 1.190877520e-03f, -2.216234800e-03f, 4.061116650e-02f, 1.122881190e-02f, 3.668302200e-03f, 1.912149830e-03f, 2.272811950e-03f, 3.719427810e-02f, -5.278067660e-03f, 4.387998950e-02f, 1.554790050e-02f, -3.869241480e-02f, -9.325043110e-02f, -5.242375660e-02f, -3.056169720e-03f, 3.805997970e-02f, 4.862207170e-02f, -5.185467380e-02f, -1.207941120e-02f, -4.388843100e-02f, 8.371421140e-04f, -3.598003530e-04f, 5.335976930e-02f, -2.038589490e-02f, -1.032481250e-02f, -3.824856600e-03f, -8.473492410e-02f, -3.393237940e-03f, 4.237885400e-02f, -3.030909970e-02f, -1.952685970e-02f, 1.938803490e-02f, -4.548656570e-02f, -2.876726910e-02f, 2.269162420e-02f, 8.461060930e-03f, -1.581376190e-03f, 2.475121620e-02f, -2.324012670e-02f, -5.858431010e-02f, -9.074709380e-03f, -1.189116480e-02f, -8.592883120e-03f, -1.981315390e-02f, -3.728621870e-03f, 2.224646510e-02f, 1.202784290e-02f, 1.560847970e-03f, -1.944829590e-03f, -1.012296510e-02f, -1.135661920e-02f, 6.319940560e-03f, 3.934864420e-03f, -4.159342130e-02f, 3.009716050e-02f, -1.832067220e-02f, 4.166230090e-03f, -2.310381080e-02f, 5.660264940e-02f, 1.296357440e-02f, -1.711842420e-02f, -5.816933230e-03f, -1.662300150e-02f, -2.087155170e-02f, 3.712892770e-03f, 1.088235180e-03f, 1.923890970e-02f, 2.265436810e-03f, -2.159075250e-02f, -7.758448830e-03f, -4.892821310e-04f, 3.801720960e-02f, 3.632185280e-03f, -2.075916710e-04f, 2.576062640e-02f, -2.435003410e-03f, -9.771198030e-02f, 2.521852400e-02f, 1.063503050e-02f, -4.470711570e-02f, -3.293324260e-02f, 3.250294180e-02f, 2.923363820e-02f, -3.900761530e-02f, -3.505481410e-03f, 1.655203850e-02f, -4.524481300e-02f, 2.177062440e-03f, -1.336238810e-02f, 5.866417660e-03f, 1.239566320e-02f, -3.760820720e-03f, -4.730705170e-03f, -1.174118840e-03f, 2.198290080e-02f, -2.201666680e-02f, 3.596761080e-02f, 1.307856760e-02f, -2.373122240e-02f, 2.339357880e-02f, -5.946520830e-04f, 2.242355610e-02f, 2.813605030e-02f, -7.168021790e-02f, -1.821207230e-03f, 8.604475300e-03f, 9.108362710e-04f, 3.350098800e-02f, -4.138385500e-02f, 2.339027820e-03f, 6.063846500e-02f, 1.006548530e-03f, 3.653470430e-02f, 7.611456790e-03f, -2.983000320e-02f, -2.712819490e-03f, -4.074191210e-03f, 4.327892090e-04f, 6.010736530e-02f, 6.385515630e-02f, 4.622291310e-03f, -3.346803830e-03f, 3.914630410e-02f, 1.125244420e-02f, 7.600900720e-03f, -1.540867050e-02f, -2.838239630e-02f, -4.723170030e-02f, 4.297084180e-03f, 4.430414180e-03f, -2.175891030e-02f, -2.315760820e-03f, 6.342164430e-02f, -3.662636040e-03f, -1.695577170e-03f, -1.661097820e-02f, -1.786788690e-03f, 4.788091780e-02f, -3.107706080e-02f, 1.886894550e-02f, 4.381231960e-02f, -4.240973850e-03f, -8.407318960e-03f, -1.062545180e-02f, -2.768572050e-02f, 3.179772200e-02f, -6.967093050e-02f, 1.531690920e-02f, 2.034551700e-03f, -4.745417830e-02f, 2.016496100e-02f, -8.193489900e-02f, 2.117726490e-03f, 6.217841870e-04f, -3.195573810e-03f, -4.069664050e-03f, -4.450956730e-02f, -1.298269160e-02f, 1.533788440e-02f, 1.565063370e-02f, 1.464226840e-02f, -4.868023100e-02f, 4.698202760e-02f, -1.611324960e-02f, 9.918483560e-05f, -6.956780320e-03f, -5.921459200e-02f, -2.451002780e-02f, 5.795719850e-02f, -3.917767670e-03f, 3.765115110e-04f, 3.382916380e-02f, -1.156927460e-02f, 4.364268850e-02f, 4.025448860e-02f, -6.276979580e-03f, -3.953052310e-02f, 1.637781620e-03f, -4.337121730e-03f, 1.694187410e-03f, 6.309907880e-03f, 3.225261350e-02f, -3.219775390e-03f, -3.852950780e-02f, 1.459195740e-02f, 1.307333070e-02f, 7.784473900e-02f, -6.487926100e-02f, -6.499049250e-03f, 2.823820570e-03f, 5.745613570e-02f, 2.704599870e-02f, -7.691920270e-03f, -2.448656600e-03f, -3.934324910e-02f, 4.913654180e-03f, 8.213952180e-03f, 5.090192430e-03f, -3.674744400e-03f, -4.085557160e-02f, 3.878107760e-03f, -6.028073370e-03f, 6.426519160e-02f, -6.544479630e-03f, -4.873194170e-02f, -7.054950110e-03f, -4.148474890e-03f, -2.165605870e-02f, -3.891737010e-02f, 5.682587250e-02f, -1.914464680e-02f, 8.894023490e-03f, -4.163051200e-05f, -1.027234180e-02f, -6.200561670e-02f, -1.943815870e-02f, -3.913722190e-02f, 2.273925110e-03f, 5.388890950e-02f, 8.369892020e-05f, 2.973640710e-02f, -5.437561780e-03f, 4.257797730e-03f, 8.598501790e-03f, -1.819936000e-02f, -7.013330230e-03f, -7.520034900e-02f, 8.497331290e-03f, -4.698491190e-03f, -8.094809950e-03f, -1.493788320e-02f, -7.841329280e-02f, 5.511793870e-02f, -8.000424130e-04f, -1.371599150e-03f, 1.308982820e-02f, 2.487149650e-02f, 5.078988150e-02f, 4.504480210e-02f, -4.154257010e-03f, -3.091014920e-02f, -4.160341340e-03f, -1.473246980e-02f, -3.224261160e-04f, -1.587355390e-03f, -2.929210600e-04f, 7.260508840e-02f, -5.230864140e-02f, -6.245425900e-03f, -2.127088420e-02f, 4.364259910e-02f, -7.484456890e-02f, -3.062497640e-02f, -3.698609020e-02f, -1.983190700e-02f, -4.930413510e-02f, 3.731412440e-02f, -9.300737290e-04f, 8.107892240e-03f, -2.133090050e-03f, -9.697699910e-03f, 2.166338260e-03f, 4.525074270e-03f, 2.313477360e-02f, 8.469978340e-03f, -4.055178260e-03f, 8.062960570e-03f, -3.445737530e-03f, -5.432067810e-02f, -1.858281090e-03f, 5.309116100e-03f, 1.861892640e-03f, 4.933553190e-02f, -2.247550900e-02f, 1.244754530e-02f, 6.561917810e-02f, -3.373187040e-03f, -1.929142020e-04f, -1.354008070e-02f, -5.307226630e-02f, 2.150670810e-02f, 8.838339710e-03f, -5.013955010e-02f, 9.247862730e-03f, 1.488873830e-02f, 3.465024750e-02f, 4.722512890e-02f, 9.210838000e-03f, -8.586962520e-02f, -7.163074610e-02f, -5.572455380e-02f, 2.095632630e-02f, 2.630197910e-03f, 1.142262950e-02f, -6.216963380e-02f, 1.924154910e-02f, -3.247185420e-02f, 4.832171840e-03f, 9.267710150e-03f, 1.559141090e-02f, -1.655690000e-02f, -7.160965350e-02f, 4.454819110e-02f, 2.435097700e-03f, 1.310842020e-02f, 1.580816000e-03f, 1.556893810e-02f, -4.197106230e-03f, -1.085804500e-02f, 2.417839130e-03f, 3.798387940e-03f, 1.674011540e-02f, 1.987238040e-02f, -6.433991340e-02f, -3.202704710e-02f, 1.293742470e-02f, -1.180336810e-03f, -1.659430380e-02f, -5.822267850e-03f, -3.256793320e-02f, -1.739785630e-02f, 1.526322100e-03f, 4.412051760e-03f, -3.586485980e-04f, -3.655352820e-02f, -2.405420410e-03f, 2.462610140e-03f, -9.400617330e-03f, -4.932239650e-03f, 3.036433600e-03f, -1.678622330e-02f, -7.103583210e-02f, -4.610180480e-02f, 3.777433930e-02f, -5.958465860e-03f, -6.405817690e-04f, 4.700809720e-02f, -3.832954910e-02f, -4.851358760e-02f, 9.868166590e-02f, 5.225078200e-04f, -2.231471430e-02f, 8.049470370e-03f, 2.510994210e-03f, -3.627987950e-02f, -1.867520740e-03f, 8.399445560e-03f, -3.753529160e-03f, -2.836850100e-02f, -3.621423620e-02f, 1.349040490e-02f, 3.626862540e-02f, -1.650843580e-02f, -6.908448040e-02f, 1.209087110e-02f, 2.646123760e-03f, 3.881745510e-03f, -1.347278620e-02f, 8.814835920e-03f, -3.077365460e-02f, -2.696424910e-02f, 2.630541100e-03f, 9.288733710e-04f, 3.886697810e-02f, -5.444620920e-02f, -6.276880950e-02f, 4.330833260e-02f, 1.630950250e-03f, -1.582395660e-02f, 6.179878490e-03f, 2.405992900e-02f, -1.170245580e-03f, -1.406256340e-03f, 2.531365720e-03f, -6.491853300e-02f, 2.141480330e-02f, 4.719005530e-02f, -7.816674180e-03f, 1.291947720e-02f, 6.218754120e-02f, 5.043601990e-02f, 3.958088640e-04f, 2.507580440e-02f, 3.356500340e-02f, 5.671808030e-04f, 1.419250500e-03f, -4.233605790e-02f, -3.086384390e-03f, 4.623293880e-02f, -3.734990020e-04f, -2.978665520e-03f, -1.345565920e-02f, -4.339302830e-04f, -1.509600970e-02f, -6.334655730e-02f, 8.762368550e-02f, 1.089473440e-02f, -3.816266730e-02f, -7.469614500e-03f, 4.149319720e-04f, 1.511023010e-02f, -7.464893910e-02f, 4.480576890e-02f, 6.504382940e-02f, -1.247973760e-03f, 6.467516720e-02f, -2.127105180e-02f, -1.147217120e-02f, -2.359104160e-02f, 4.328323060e-03f, 7.155365500e-02f, -3.400612860e-03f, -4.555951060e-02f, 2.886197720e-02f, -9.353045370e-03f, 2.747411840e-02f, 3.161168470e-02f, 1.173528840e-03f, 3.282252930e-03f, -2.476602980e-02f, -3.076172900e-03f, -7.193279450e-04f, 8.039730040e-02f, -1.674202040e-03f, -5.570969080e-03f, -4.268974010e-04f, 3.614472230e-03f, 3.419667480e-02f, 5.730967970e-03f, 1.734121700e-02f, 4.120158030e-02f, -1.008143180e-02f, -1.433000710e-02f, 1.242534350e-02f, -3.391746200e-03f, -3.322105480e-05f, -4.223661030e-03f, -2.426411580e-02f, 1.909140870e-02f, -5.791039020e-02f, -3.890645880e-02f, -4.176694430e-03f, -3.491192310e-02f, 1.881253720e-02f, -1.300436630e-02f, 2.843505140e-02f, 5.755228920e-02f, 6.580964480e-02f, 4.104146360e-02f, -5.207839420e-04f, 4.763136970e-04f, -4.193086640e-03f, -6.667633350e-02f, 1.046168520e-02f, 9.813851210e-04f, 2.247387540e-02f, -1.141639430e-03f, -3.655139360e-02f, -5.750890360e-03f, 3.386199850e-02f, -5.878683650e-03f, 3.006464060e-02f, -4.159211180e-03f, -7.078775670e-04f, 2.890802730e-02f, -3.123224480e-03f, 3.090273960e-02f, 6.258917600e-02f, 4.504979010e-04f, 4.684829340e-02f, -6.860595200e-02f, 4.566298050e-02f, 1.098609250e-02f, 7.159670930e-04f, 3.547119720e-02f, -7.806170730e-03f, 8.509265630e-02f, -1.664849000e-02f, 1.022440750e-02f, -2.971533310e-02f, -2.078647730e-02f, 4.295960810e-02f, -4.634685070e-02f, 1.002419550e-02f, -9.266441680e-03f, 1.286162530e-02f, 8.529949190e-02f, 2.231255920e-02f, -7.623841610e-02f, 7.819703310e-04f, 1.034167480e-03f, 4.006868690e-03f, -1.899218650e-03f, -6.013625300e-03f, 1.058738590e-02f, 1.720184340e-03f, -1.723070440e-02f, 4.764108450e-04f, -1.498972350e-02f, -3.610062880e-03f, 8.487466400e-05f, 4.999877140e-02f, 1.339258350e-02f, -2.146450240e-02f, -6.644435230e-03f, 5.365491290e-02f, 1.700353810e-02f, -1.083712840e-02f, -1.123131830e-03f, 2.719658990e-02f, -4.778020460e-02f, 2.822000720e-02f, 5.125959590e-02f, 3.482031170e-03f, -1.980406230e-02f, -5.818842910e-03f, 1.427691240e-02f, -3.319631100e-03f, -9.095874620e-03f, -1.522595440e-02f, 8.562238070e-04f, -3.121949360e-02f, 3.711513800e-02f, -1.375107370e-02f, 7.691923530e-03f, 2.814344880e-02f, -2.251036230e-03f, -1.387250240e-02f, 3.654098140e-02f, 8.817831050e-03f, -1.533645760e-02f, -4.869155590e-03f, 1.541762380e-03f, -1.029625770e-03f, -5.760989340e-02f, -2.600958760e-02f, 7.124195250e-02f, 8.411905730e-03f, -3.972961570e-03f, 5.062450190e-03f, 7.822114040e-03f, 4.507240280e-02f, -6.394921240e-02f, -4.404438290e-02f, -1.295564420e-02f, 1.262754480e-02f, 2.913880350e-02f, -9.548945350e-03f, -3.617417530e-03f, 7.217993490e-03f, 5.553243680e-02f, -2.439862300e-02f, -7.472042740e-02f, 1.222665610e-02f, 9.421033780e-03f, 4.946726190e-02f, 7.242605560e-03f, 2.395668250e-02f, 2.170839350e-02f, -8.024373090e-03f, -1.424760000e-02f, -5.972484130e-03f, -3.765206410e-02f, -2.110583940e-03f, -6.780133580e-03f, -2.174062840e-02f, 1.829885880e-02f, -1.846027000e-02f, 3.039865570e-02f, 3.716982160e-02f, -3.221557130e-04f, -3.516719490e-02f, 3.886592390e-02f, -5.211074840e-03f, -6.642681360e-02f, 9.756879880e-04f, -4.160620270e-02f, -2.287520790e-03f, 1.624536140e-02f, -5.019549750e-03f, 1.568413340e-02f, -1.086126360e-02f, -4.615721290e-03f, 1.421123740e-02f, -1.418525700e-03f, -4.122240470e-02f, -6.386548280e-03f, 4.651363190e-02f, 3.462640200e-02f, -3.908567880e-02f, 1.040603410e-02f, 1.401804290e-02f, 1.747720500e-02f, 3.292352330e-02f, 6.943812220e-02f, -5.084136870e-02f, -2.901443510e-03f, -1.978150570e-02f, 8.552180230e-02f, -7.261557880e-02f, -2.933489390e-03f, 6.251296020e-03f, -5.108833310e-02f, -3.040405460e-03f, 3.008605910e-02f, -2.267599660e-02f, 3.878720100e-02f, -4.806044700e-02f, 7.491363580e-02f, 4.378248750e-02f, -5.623472390e-04f, 5.085730180e-02f, -4.662915130e-03f, -3.788869600e-03f, 5.566348140e-02f, -8.203430100e-03f, 3.680811450e-02f, -5.300149790e-04f, 5.689943210e-03f, -5.449217280e-03f, -6.934495640e-03f, 8.567419640e-02f, 2.135914750e-02f, -2.794329080e-03f, 4.338235410e-02f, 2.501774580e-03f, -1.186388730e-02f, -2.978410340e-03f, -1.315289080e-02f, -4.004282500e-02f, 8.450815820e-02f, -2.046649530e-02f, 3.768446670e-02f, -2.164462770e-02f, 1.732762340e-02f, -5.517825110e-02f, -2.124365230e-02f, 3.911465030e-02f, -1.433893200e-02f, -9.778223930e-03f, 2.758294900e-02f, -1.288663600e-03f, 3.940492500e-02f, 2.883526500e-03f, -1.513791830e-02f, -8.832148160e-04f, 6.092620550e-03f, 4.697090760e-02f, 6.443461400e-03f, -5.849209850e-04f, -2.751488420e-02f, 7.937870920e-03f, -2.370046080e-02f, -2.997304870e-02f, -3.213564400e-03f, 1.688632180e-02f, 2.765200290e-02f, 3.911618140e-02f, -4.106472430e-02f, -4.294816030e-02f, -3.652270530e-04f, -1.301455590e-02f, 1.774139140e-02f, -7.975542550e-02f, 3.091619540e-02f, -3.302984640e-03f, -9.923359750e-02f, 8.254781360e-03f, 3.356385980e-03f, -1.612368780e-02f, -1.688628640e-02f, 8.389162830e-03f, 3.489443290e-02f, -8.648019280e-02f, 3.931469840e-02f, -1.127534270e-02f, 2.153764710e-03f, -1.815318130e-02f, -5.647951740e-02f, -5.760654810e-02f, 5.151987450e-02f, -4.791643940e-03f, -5.023656880e-03f, 2.023697270e-02f, 7.657608950e-04f, 3.368867190e-02f, 1.253264210e-02f, 8.073687550e-03f, -7.206426930e-03f, -6.295955270e-03f, 3.118950180e-03f, -1.256199550e-03f, 7.912270720e-03f, -3.729042780e-02f, -1.288066060e-02f, -3.700517860e-02f, 6.207875160e-02f, -7.074105550e-03f, -6.906484070e-02f, -5.883061510e-02f, 1.639522240e-02f, -3.250529620e-02f, -5.480637310e-03f, -2.198393460e-02f, 4.287882520e-02f, 5.564676250e-04f, -9.186748410e-03f, 2.883534180e-03f, -4.496934360e-03f, -1.347390750e-02f, -8.768492840e-04f, 7.935579050e-04f, 2.926654180e-03f, 8.930410260e-03f, -3.826294840e-02f, -4.364442450e-02f, 3.111403620e-02f, -2.894089930e-02f, 5.798993170e-03f, 1.087549420e-02f, -5.204841490e-02f, 3.435138240e-02f, 4.246247190e-02f, -2.759834940e-02f, -2.383386250e-03f, -1.851530750e-02f, 9.941676630e-03f, 3.039837810e-02f, 1.107097980e-02f, 3.414469770e-03f, 4.578773400e-03f, 2.627525940e-03f, -7.927266500e-02f, -4.028848840e-03f, 2.702909340e-02f, -4.680472980e-02f, -7.950933650e-03f, 4.583616550e-02f, -2.374873870e-02f, -1.249752010e-02f, 1.176770670e-04f, 2.479800580e-02f, 6.652598080e-02f, -8.194711050e-02f, 6.167480340e-02f, 2.921676500e-03f, 2.335014050e-03f, 3.288323800e-02f, 7.479834550e-02f, 9.160967540e-03f, 2.457610700e-02f, -3.523989580e-04f, -4.797737580e-03f, 8.600541390e-03f, 5.058209880e-03f, -3.769920210e-03f, -6.053167860e-03f, 5.074018990e-02f, -1.098638960e-02f, 2.378358880e-02f, 6.631463300e-03f, 2.685884200e-02f, -2.682911420e-02f, -5.416773260e-02f, -6.948037070e-03f, -2.910330430e-03f, -1.329525090e-02f, -1.784683760e-02f, 2.483558650e-02f, -8.294936560e-05f, -3.469179570e-02f, -1.689713330e-03f, 2.382227690e-03f, 4.303321710e-03f, 2.019041570e-04f, -9.257121940e-03f, 4.496482200e-03f, -4.322901000e-02f, -6.791407610e-02f, -1.510420350e-02f, -4.123553630e-02f, 6.256245540e-03f, 1.793756270e-03f, 3.487745300e-02f, -2.332279830e-02f, 1.861513590e-02f, -6.308015900e-03f, 1.342048960e-02f, -1.070055410e-03f, -9.005543780e-03f, -2.057494600e-03f, -4.427639770e-03f, 1.877851600e-02f, 2.864715930e-04f, 2.014615200e-02f, -8.135205720e-04f, -2.041932750e-02f, 4.012195770e-02f, 3.399864960e-02f, -1.233346670e-02f, -5.914889650e-02f, 4.844249410e-02f, -1.682673210e-02f, 2.241249760e-02f, -7.655174010e-03f, 1.257329480e-03f, 9.978841050e-03f, 3.225297850e-02f, -1.929491570e-02f, 5.382803270e-03f, 5.999816580e-03f, -1.500575800e-03f, -4.883013670e-02f, 4.819614440e-02f, -2.903939600e-02f, -1.340973420e-03f, 7.221595380e-03f, -1.678600670e-03f, 2.024041120e-02f, -2.408120550e-03f, 3.063347890e-03f, -7.574168590e-02f, 4.328232630e-02f, 1.881489530e-02f, -3.706325220e-02f, 4.097465050e-02f, 4.161161180e-02f, -6.490187350e-02f, -2.835777770e-02f, 2.978717540e-02f, 9.704700670e-03f, -2.564710940e-02f, -4.042970760e-02f, 7.027018000e-05f, 6.087570260e-02f, 1.926400580e-03f, -5.326611550e-02f, 1.373972740e-02f, 2.063878580e-03f, 1.570904440e-02f, 1.082199350e-02f, 3.294704110e-02f, -3.466879720e-03f, 4.594221710e-02f, 5.356640370e-02f, -1.434903130e-02f, -5.838467040e-04f, 3.468986230e-02f, 4.775513340e-02f, 4.240355270e-02f, -1.952311020e-02f, 5.443605040e-02f, 1.174847600e-03f, 4.809027910e-02f, 4.210486640e-02f, -6.790311630e-02f, -3.819134320e-03f, -4.245526620e-03f, 8.643964300e-03f, 7.501076910e-04f, 5.437623340e-02f, -1.049492420e-02f, 7.383804020e-02f, 2.257614400e-02f, -9.790163480e-03f, -4.135743160e-02f, -2.165686710e-02f, -3.127847610e-02f, -5.157843700e-03f, -3.954840820e-02f, 4.851581530e-02f, -5.896124990e-02f, -1.079427190e-03f, 2.295457060e-03f, 1.063283300e-03f, -5.991512910e-03f, -2.936530300e-02f, -7.986675940e-02f, -1.116003100e-02f, 1.491217640e-03f, -1.251456510e-02f, -2.887606390e-03f, 3.986012190e-02f, -3.627046940e-03f, -1.873809730e-03f, -9.257102380e-03f, 2.017588540e-02f, 7.459313420e-02f, 3.096505630e-02f, 1.202789320e-02f, 3.125864310e-03f, 5.069465940e-02f, -1.133431680e-02f, -6.990662780e-03f, 3.847448850e-03f, 5.481598150e-02f, -5.668427800e-02f, -3.523705060e-03f, 1.091095390e-03f, 3.846753680e-05f, -1.966736470e-02f, 2.303017120e-02f, 4.478268790e-03f, -2.379722330e-02f, 7.354478350e-03f, -3.708451240e-02f, -9.023094920e-02f, 1.068457310e-02f, -1.448429750e-02f, -8.465852580e-03f, 3.807501400e-03f, 2.379546130e-02f, -1.927850770e-02f, 2.144145410e-02f, 1.386984720e-02f, -1.352467110e-03f, 1.240992100e-03f, 3.121115500e-03f, -2.205497590e-02f, 9.664590470e-03f, 3.806114940e-02f, -4.831347150e-03f, 4.333231130e-03f, 1.081467020e-03f, -3.893845530e-02f, -4.543007540e-02f, -1.439921470e-04f, 2.526797730e-02f, -2.297016230e-02f, 5.855241420e-02f, -2.923710090e-02f, 2.078886700e-02f, -4.091868180e-03f, -2.402871100e-02f, 6.246596570e-02f, -1.614425700e-02f, -2.754577440e-02f, -4.526802800e-04f, -2.699195410e-03f, 3.324362260e-02f, -4.381001370e-02f, -1.353367510e-02f, -3.832742570e-03f, 1.333217950e-03f, 5.480815660e-03f, -3.744759360e-03f, 1.627310180e-02f, -6.239739010e-04f, -6.260875610e-03f, -3.375890480e-02f, -2.978773600e-02f, 4.152481630e-02f, 2.969585170e-02f, 9.848934600e-03f, -7.789945600e-02f, 1.629984750e-02f, -4.656448440e-04f, 3.697475050e-02f, 4.244731370e-02f, 5.601450340e-03f, -4.700826110e-02f, 1.463415920e-03f, -4.079234970e-02f, -8.750126580e-04f, 7.646650070e-03f, 7.008993990e-03f, 8.468429440e-04f, 5.687293040e-02f, 3.067333020e-03f, -9.620516560e-03f, -1.107260580e-02f, -8.210353550e-02f, -7.378605000e-02f, 3.888669610e-02f, 3.415215290e-03f, 2.182964790e-02f, 1.072086580e-02f, 8.867438880e-03f, 1.932916980e-02f, 2.999480440e-02f, 2.173043790e-03f, 3.039020860e-02f, -1.173421740e-02f, -5.892524120e-02f, -3.391329900e-03f, -4.513717720e-03f, -1.072581040e-03f, 3.837098600e-03f, 1.894201150e-02f, -9.913959540e-03f, -2.921423690e-02f, -1.921223940e-03f, -5.789580200e-02f, -2.087935570e-03f, -1.878120350e-03f, 3.483942520e-02f, -3.938172480e-03f, 1.163413980e-03f, 4.167561230e-02f, 2.723306040e-02f, 8.427012710e-02f, -6.848689170e-03f, -4.007816780e-03f, 2.304911430e-02f, -4.386290910e-02f, -2.902520820e-02f, -1.627241630e-02f, 3.712197070e-03f, -3.687301280e-02f, -7.829768580e-03f, -2.239455660e-02f, 2.584327010e-03f, -1.765081540e-03f, 3.442873810e-02f, 2.932092550e-02f, -1.520402450e-02f, -2.084925400e-02f, -3.428234160e-02f, -9.397722780e-03f, -2.930198610e-02f, -2.601997740e-02f, 2.431239190e-02f, 6.657451390e-02f, 1.469735990e-02f, 2.945146150e-02f, 7.795923150e-04f, 3.239342940e-02f, -1.925308140e-03f, 4.863673820e-02f, -4.182567350e-03f, -8.186298070e-04f, 3.938587010e-02f, 1.674710310e-03f, 1.768969930e-02f, 6.062702460e-02f, -4.255407680e-02f, 4.426814620e-02f, -6.595377340e-03f, 6.198347080e-03f, 4.988040780e-03f, 6.937167040e-02f, -1.477633420e-02f, 1.529700960e-02f, 4.690345000e-02f, -1.617949110e-03f, -4.836340990e-02f, 6.841626020e-02f, 5.232218650e-03f, 5.095557310e-03f, 2.511762550e-03f, -7.568099070e-03f, 1.630437440e-03f, -1.272444990e-02f, -5.042678490e-02f, 3.252641480e-02f, -1.275426890e-02f, 8.543486140e-02f, 8.629585800e-02f, -4.105234890e-02f, -2.400360300e-03f, -2.321070060e-03f, 2.562736910e-02f, -1.885864700e-02f, -6.168351320e-02f, 7.157481280e-03f, 3.774056680e-03f, 7.766681260e-03f, -8.338885380e-03f, 3.192627430e-02f, 1.182009090e-02f, -5.243946610e-02f, -2.301682250e-03f, -8.791417810e-03f, 5.186344960e-03f, 1.983469540e-02f, -7.124294640e-04f, 4.530109000e-03f, 4.473252220e-03f, -2.334566040e-02f, -4.668568820e-02f, 3.317300230e-02f, -3.406849880e-02f, -2.273385230e-02f, 3.202633560e-02f, -1.527464200e-02f, -1.987620070e-02f, 2.820152790e-02f, 8.504959750e-03f, 2.595042620e-02f, 5.079158580e-04f, -1.758260090e-02f, 8.259401660e-04f, -6.595543020e-02f, -8.208820590e-03f, 3.243859390e-03f, 5.666362120e-03f, 3.369385140e-03f, -2.071349510e-02f, 3.470896930e-02f, -6.285146620e-02f, 6.138223410e-02f, 7.187672430e-03f, -5.312429740e-03f, -2.665092610e-02f, 2.756832910e-02f, -6.398255380e-02f, 2.494188030e-02f, 1.873926260e-03f, 2.280863700e-04f, -2.733703140e-02f, 3.375617790e-02f, 9.562456980e-04f, -4.005332290e-02f, 1.778552540e-03f, -8.531121160e-02f, -6.485488730e-03f, -3.191730710e-03f, 2.754570540e-02f, 5.646456780e-02f, -1.671858320e-02f, -6.290858980e-02f, 2.674044670e-02f, 2.071847210e-02f, 1.676746090e-02f, -3.013597800e-03f, -1.522328330e-02f, -2.213227380e-02f, 6.244939570e-02f, 1.308445040e-01f, -4.629234610e-04f, 9.226250690e-04f, -1.724076270e-02f, 3.379896280e-02f, 1.775353770e-02f, 2.324440050e-03f, 1.571260160e-03f, -2.702133360e-02f, -3.962165680e-03f, -4.519254900e-03f, -1.905168060e-03f, 2.992799510e-03f, -1.736787330e-02f, 1.652983580e-02f, 4.396957900e-02f, 3.640012440e-02f, 1.225123460e-02f, 3.823444250e-03f, -2.588788230e-02f, 3.809816390e-02f, 2.572788860e-03f, 1.010849100e-01f, -3.118589710e-02f, -3.052140590e-02f, 9.650476860e-04f, 1.636508290e-02f, 2.486974990e-04f, -1.754601490e-02f, -6.966839080e-03f, -1.157367140e-03f, 1.352281400e-02f, 5.460488610e-04f, -3.383213650e-02f, -1.069542110e-02f, 5.140049760e-02f, 1.114853470e-02f, 3.848838430e-02f, 5.464464890e-03f, 5.543694830e-03f, 1.016034160e-03f, -9.937006980e-02f, 1.814588530e-02f, -4.380081970e-02f, -2.532034410e-03f, -2.134947290e-02f, -4.407603670e-02f, 2.412934970e-02f, -2.013042340e-03f, 1.205075350e-02f, -3.008424540e-03f, -1.122453020e-03f, -1.608827710e-02f, 2.233014440e-02f, 2.145588960e-02f, -5.319047350e-02f, -6.531505380e-03f, 5.727903920e-02f, 4.383262250e-02f, -3.192292530e-02f, -2.354733880e-03f, 1.913024670e-02f, 1.544350670e-02f, 2.239025200e-02f, 6.876996900e-02f, 7.267808540e-03f, 1.112413690e-02f, -2.004108390e-02f, 3.627727510e-03f, 8.015623680e-02f, 1.075629030e-03f, -5.505642390e-03f, -5.118698350e-03f, 6.589493710e-03f, -1.710055770e-02f, -5.683471910e-03f, 1.213969550e-03f, -2.797328680e-02f, 3.492067100e-03f, -4.614711930e-02f, 2.735555400e-03f, -5.690275690e-03f, 3.366051710e-03f, -2.815341760e-02f, -3.819319610e-02f, 4.633253910e-03f, -6.831739840e-02f, -2.241294270e-02f, 1.238875280e-02f, 1.155900300e-03f, 3.070208990e-02f, -5.615263250e-03f, -7.925591430e-03f, 1.224695800e-02f, 1.895729340e-03f, -1.251870390e-02f, 2.536747140e-03f, 1.232196860e-02f, 1.981324520e-02f, -7.279362530e-02f, -3.970011600e-03f, -5.089843650e-02f, 8.054999630e-03f, 3.459283340e-02f, 4.687514530e-02f, 2.913020550e-02f, 1.286972130e-02f, -4.726203900e-02f, -2.360421700e-03f, 6.007322580e-03f, 2.445221130e-02f, 1.946168390e-02f, -2.245278100e-02f, 9.439124730e-03f, 3.429674730e-02f, 9.589821100e-03f, -4.927555560e-03f, 8.931221440e-03f, 2.461788480e-03f, -6.104626510e-02f, -2.109348400e-02f, -7.969124240e-03f, 2.276078980e-02f, -2.666173970e-03f, 6.841174330e-03f, -1.892505770e-02f, 3.338022900e-02f, -1.055390690e-01f, -3.995620460e-02f, 1.283592270e-02f, 1.134812460e-02f, 6.493789840e-04f, -2.501100120e-02f, -1.874025790e-03f, -3.497877340e-02f, -9.790331120e-03f, -6.098764020e-03f, 7.622960020e-03f, -1.176113360e-02f, -7.445943540e-03f, 2.364686690e-03f, -3.942370880e-03f, -2.759803650e-02f, 4.751111190e-02f, -5.031184480e-02f, 5.920753260e-02f, -3.300613910e-02f, -4.673850160e-02f, -3.948991000e-02f, 5.764253810e-02f, -8.079569780e-03f, -2.233189900e-02f, 7.100440560e-02f, 2.046372040e-03f, -1.258044500e-03f, 7.476664150e-03f, -1.691452230e-02f, 3.541766200e-03f, 2.932608830e-03f, 2.359422110e-02f, 2.796931430e-03f, 2.250354180e-02f, 3.919624910e-02f, -2.552488630e-02f, 3.050041200e-02f, -5.421916020e-02f, 4.253319930e-03f, 3.266406430e-02f, -4.978640940e-03f, -6.250677260e-02f, -2.040591280e-02f, 4.064752910e-02f, -6.977820890e-04f, 7.747303690e-02f, 1.667164640e-02f, -2.809345260e-03f, 1.133205280e-02f, 8.769162000e-03f, 1.628108320e-02f, 3.253255270e-03f, 7.214926180e-02f, 3.041148000e-02f, 1.286637600e-02f, -2.047706020e-02f, 6.750508400e-02f, 2.082633230e-02f, -3.564341370e-02f, -3.973115980e-02f, 4.019347490e-03f, -3.291627160e-03f, 1.144728900e-02f, 6.520405410e-02f, 4.688437280e-02f, 6.498915610e-03f, 3.881686370e-03f, 1.545705370e-02f, -2.652627600e-02f, 2.347433380e-02f, -5.208466950e-02f, 2.446107570e-03f, 4.347690570e-02f, -4.473279700e-03f, -4.296227170e-02f, -5.086967260e-03f, 3.338397250e-03f, 3.787040710e-02f, -2.360184300e-02f, 1.874739300e-02f, -1.636436400e-02f, 3.651369740e-02f, -3.366028140e-02f, 1.801553650e-03f, 2.030110170e-02f, 1.033229100e-02f, -2.383309980e-02f, -2.371349000e-02f, 5.133952980e-06f, 1.391181140e-03f, 1.620334390e-02f, -4.515995270e-03f, 1.188559640e-02f, 4.468976690e-04f, 3.298019060e-03f, 5.065366630e-02f, 1.432083270e-02f, -1.267399830e-02f, -1.832914910e-02f, -8.029630030e-02f, -3.510963920e-02f, -1.849502700e-02f, -5.492358930e-03f, 3.214880080e-02f, 7.419228550e-02f, -1.836026650e-02f, 2.744594960e-02f, -5.759470910e-02f, 1.739892760e-03f, 6.487071510e-03f, -2.370746990e-02f, -4.036079160e-03f, 8.836621410e-03f, 1.761418770e-03f, -3.549555320e-02f, 4.700760360e-03f, -4.415224120e-02f, 4.635452850e-02f, 6.737493440e-03f, -4.379852120e-02f, 1.671381670e-02f, -8.722844530e-03f, -2.127605680e-02f, 1.839710210e-02f, 2.824431050e-03f, 1.880132780e-02f, 4.841947180e-02f, 6.597352770e-02f, 9.880148610e-02f, 1.150249040e-03f, 4.423904700e-03f, 5.971116950e-03f, -4.407398780e-02f, -1.177207660e-02f, 1.256852970e-02f, 9.784093120e-04f, 2.585981970e-02f, -1.513990690e-03f, 4.875718800e-02f, -3.891756760e-03f, 7.343914360e-03f, 4.781832550e-02f, -1.602695140e-02f, -4.145620020e-02f, 6.137671880e-03f, -5.352753210e-03f, 5.365132170e-02f, -6.565795840e-02f, -1.214490090e-02f, -4.026894270e-02f, -5.419291930e-02f, -1.280232430e-02f, 3.620954000e-03f, -4.729355690e-03f, -1.751689610e-02f, 2.944451290e-03f, -1.020109280e-01f, -5.648885390e-03f, -6.062984930e-03f, -1.570716500e-02f, 1.353048370e-03f, -3.264177960e-02f, 4.707590490e-02f, -3.547995540e-02f, -6.450786440e-02f, 3.248145800e-02f, -4.572631790e-03f, -2.499984200e-02f, -3.145255520e-02f, -1.000724450e-02f, 1.522000600e-02f, 4.099004720e-02f, -9.117376750e-04f, 1.248285920e-02f, 4.499465230e-02f, -6.592448060e-02f, -4.273112490e-02f, -5.365613850e-03f, 2.832633260e-02f, 2.649743110e-03f, -5.509326610e-02f, 3.724483030e-05f, -3.826399150e-02f, 4.034825790e-02f, 2.862333510e-02f, -3.572147110e-03f, -1.860832980e-02f, 1.196937640e-02f, -4.727477210e-04f, 1.960097630e-02f, 7.007453120e-03f, 6.666709480e-02f, 8.845647420e-02f, -1.063482000e-02f, -6.835904900e-03f, 6.584372370e-03f, -2.810207750e-02f, 2.837375740e-02f, -6.934170150e-03f, 2.258303340e-03f, -4.993626850e-03f, -4.662825730e-03f, 1.413132340e-02f, 6.782382730e-03f, 3.484842830e-03f, 5.756379110e-03f, -2.294148880e-02f, 3.741836180e-02f, 3.122782330e-02f, 6.720688190e-02f, 4.333472620e-02f, 1.477066240e-02f, -1.333477440e-02f, -2.230133160e-03f, -4.590503870e-02f, -3.761382400e-02f, -5.250571670e-02f, 4.093648870e-03f, 9.599702430e-03f, -2.447683830e-03f, 8.660142120e-02f, 2.652667700e-03f, 4.061058630e-03f, 6.726727630e-02f, -9.206926450e-03f, 3.628313540e-02f, 4.960792880e-02f, -5.734941920e-03f, -4.722818730e-02f, -1.051720810e-03f, -5.790505670e-04f, 4.792569580e-02f, 4.296722260e-02f, 3.231626940e-03f, 5.844811720e-02f, -2.463530050e-03f, -6.781937550e-05f, 5.216767270e-02f, 5.573249980e-02f, -4.851660130e-02f, 6.649898360e-03f, -4.703343850e-03f, -8.185089370e-02f, 5.021868740e-03f, -7.134519520e-02f, -2.592984960e-02f, -7.125841920e-03f, 1.669902350e-02f, -1.419451790e-03f, -2.160072140e-02f, -3.675862770e-02f, 1.290545800e-02f, 2.975878310e-03f, 1.425754000e-02f, -3.960678730e-02f, -1.837044400e-02f, 3.177876030e-02f, -7.336938870e-05f, 9.935727570e-04f, 4.752010110e-02f, -4.793994130e-02f, -3.011890690e-02f, 2.577218600e-02f, -1.161378690e-03f, -2.229266800e-02f, -3.767697610e-03f, -8.714237250e-03f, -7.605650460e-04f, -1.689929860e-03f, -3.499793630e-02f, -3.948703780e-02f, 4.391501470e-02f, -1.587150430e-02f, -8.836193940e-03f, 4.831669850e-02f, 1.514180190e-02f, -3.228459510e-02f, 3.711849220e-03f, -5.366097390e-02f, 3.344440460e-02f, 2.586408520e-02f, 3.667297420e-04f, -4.244368150e-02f, 3.750718200e-03f, -2.770712410e-02f, 1.614333710e-03f, -3.231219950e-03f, -2.680165130e-02f, -6.473810880e-03f, 4.568941520e-02f, 6.718532000e-02f, -1.667919940e-02f, -2.573001570e-02f, 1.064020020e-02f, -2.775165250e-03f, 1.854204390e-02f, -1.241338250e-02f, -2.251038700e-02f, -2.791773530e-02f, -2.058174460e-02f, 9.609413680e-04f, 1.057470870e-02f, 6.277764590e-02f, 2.934757990e-02f, -1.362370210e-03f, 2.231795340e-03f, -1.644866540e-02f, 1.037303360e-03f, -1.307389610e-02f, -1.369277390e-02f, 2.497152240e-02f, -3.788434340e-02f, 7.971224180e-02f, -4.878484830e-02f, 4.899556280e-03f, 5.234177040e-02f, -2.615919100e-03f, -4.185718670e-02f, 4.632245750e-02f, 1.475391160e-02f, -1.008787100e-02f, -8.806393480e-03f, -1.173981700e-03f, 2.164430730e-02f, 6.710453890e-03f, 3.194335850e-02f, -1.662987660e-02f, 2.445746450e-03f, -4.172491280e-02f, -4.969404540e-04f, 4.718579350e-02f, 5.256422330e-03f, -1.097361560e-03f, -2.673024500e-02f, 6.752233950e-02f, -5.852723490e-02f, -1.915679310e-02f, -2.253902520e-02f, 1.939895560e-02f, -1.569549930e-02f, -6.505195050e-03f, 4.037709910e-02f, 5.982501060e-02f, 4.923203960e-02f, -7.257248460e-02f, 1.299306280e-03f, -3.087039480e-02f, 3.962739370e-03f, 7.808575030e-02f, -1.679000910e-03f, 2.305614760e-04f, 2.403104680e-02f, -1.062095910e-02f, -3.273772080e-02f, 4.126387830e-02f, 4.889636860e-02f, 2.724346700e-03f, 6.423863120e-03f, 6.720067470e-03f, -1.881069130e-02f, 4.643044620e-02f, -5.056778340e-02f, 8.673473260e-03f, -9.904799980e-03f, 1.857147670e-03f, -6.237482190e-03f, -8.425229230e-03f, -3.581209110e-02f, -5.711334570e-02f, 6.677051420e-04f, 8.228731150e-02f, -5.829914940e-03f, -4.181873430e-02f, 3.652720900e-02f, 2.163751240e-02f, -3.078168820e-02f, 1.093557100e-02f, 2.583798390e-02f, 4.582349580e-02f, 1.757756620e-02f, -5.304231770e-03f, -2.623918840e-02f, 4.798430580e-02f, -2.156674680e-02f, -1.719633120e-02f, -1.283557970e-03f, -8.484408020e-04f, 1.989195360e-03f, -2.913291750e-02f, -4.722921550e-02f, -7.945693100e-03f, 9.427574690e-04f, 9.820998650e-03f, 9.065458550e-03f, -9.445865640e-03f, 3.062502660e-04f, 7.369332020e-04f, -1.207751590e-02f, 2.047653120e-02f, 1.984358950e-02f, 3.346181660e-02f, 9.474355720e-03f, -3.600384670e-02f, -1.146708800e-02f, -5.143722150e-02f, -3.819924970e-02f, 3.408323510e-03f, 2.600012910e-02f, -5.820517240e-02f, 6.625485830e-04f, 1.257618240e-02f, -9.302712050e-03f, -4.371004180e-02f, 1.363985710e-02f, -3.952809610e-03f, 1.511232930e-02f, -9.361545080e-04f, -3.683818500e-02f, -4.639394950e-02f, 4.583401230e-02f, -2.768227600e-03f, -1.146352760e-02f, 4.559178370e-03f, -1.348750290e-02f, 2.234456500e-02f, 7.691293210e-02f, 1.106955670e-02f, 8.168880640e-02f, 6.577351600e-04f, 3.863644230e-02f, 2.431854230e-02f, -1.603446340e-02f, -2.697560750e-02f, -2.922989890e-03f, 1.695688630e-02f, 5.834483310e-04f, 1.458699630e-02f, -1.816914040e-02f, 4.438746350e-02f, 2.502879590e-03f, 2.374889100e-03f, 7.743123450e-03f, 1.788888870e-02f, 2.974160200e-02f, -2.029008700e-03f, 5.614935890e-03f, 2.307431030e-02f, 6.345094000e-02f, 1.172039840e-02f, -2.400261290e-04f, -3.369634270e-03f, -2.072722840e-02f, 1.634255610e-02f, -6.181113050e-02f, 4.568727310e-02f, -3.985683430e-03f, -2.425207010e-02f, -1.661204380e-03f, 3.545714170e-02f, 2.071563390e-03f, -6.712316070e-03f, 1.317530220e-02f, 5.104520540e-02f, 4.683968420e-02f, -2.290891860e-02f, -7.788270710e-02f, 6.714713570e-02f, -2.368891800e-02f, -3.783148900e-02f, -2.231401390e-02f, -1.397876160e-02f, 4.281776400e-02f, 5.381461610e-02f, 9.528861840e-04f, 1.907617550e-03f, 6.504918910e-03f, -5.622912940e-02f, 1.506654080e-02f, 3.559990090e-03f, 4.927321150e-02f, -5.563132460e-03f, -3.924214280e-03f, -2.738273330e-02f, 2.986613100e-02f, 3.466146530e-03f, -6.191961930e-03f, -3.038107650e-03f, -9.263287300e-03f, 3.741595520e-02f, -2.043489930e-02f, -6.740064830e-03f, -1.021504980e-03f, 1.468279860e-03f, -9.429429330e-05f, -1.666057850e-02f, -4.938714950e-02f, 2.652778660e-02f, -4.447662500e-04f, -1.518321690e-02f, 7.887048640e-03f, 1.057947950e-01f, 3.859654530e-04f, -8.385598660e-03f, 2.558152380e-02f, 2.480457350e-02f, -2.376128920e-02f, -8.853619540e-02f, -1.943216470e-02f, 4.925402350e-03f, 2.346549740e-02f, 1.304070370e-02f, 4.126020150e-02f, -2.860591930e-02f, 2.860987560e-03f, -4.308907320e-03f, 1.652168110e-02f, -3.969502450e-02f, -6.062968820e-02f, -3.570928800e-02f, 3.087923160e-03f, 1.966588570e-02f, 2.923063700e-03f, 1.498533600e-02f, 1.267452030e-03f, -1.268133060e-03f, 3.367650880e-02f, 7.944900540e-03f, -4.991585390e-02f, 4.212079200e-02f, 4.097188640e-02f, 4.930301100e-03f, 5.671758580e-02f, 1.106103530e-03f, 3.066158110e-02f, -5.529918150e-02f, -1.826909560e-02f, -2.571758630e-02f, 1.539987570e-04f, 2.017360550e-02f, -4.231054480e-05f, -1.252851730e-02f, -9.401249700e-04f, -1.375181130e-03f, 5.345298720e-02f, 1.229706220e-02f, -2.124232800e-02f, -1.803813320e-02f, -2.655706550e-02f, -5.302039910e-03f, -2.191687560e-02f, 6.836027840e-03f, 3.508922090e-02f, 2.414084040e-02f, 6.418609620e-02f, -5.235313440e-03f, 2.640451680e-02f, 3.285354700e-03f, -4.141789300e-02f, 2.234472890e-02f, 4.766107540e-03f, 5.015507710e-02f, -1.692168530e-03f, -2.514041400e-02f, -2.122282050e-03f, -8.513307190e-03f, -5.950599910e-02f, 5.106401630e-03f, 6.455250080e-03f, -1.447099540e-02f, 1.793826740e-02f, 3.314204510e-03f, 3.951963780e-02f, 5.233533210e-03f, -2.379757820e-03f, 5.572696030e-02f, 3.404726460e-02f, 1.028257830e-04f, 1.960174270e-04f, -4.612750370e-03f, 3.594768420e-02f, -2.148590610e-02f, 3.106216150e-02f, 2.794145790e-02f, 7.787164300e-03f, -2.762454930e-02f, -8.219648150e-03f, -9.639438240e-03f, -3.735572680e-05f, -6.869649980e-03f, 4.909328000e-02f, 5.948178940e-03f, 2.002181670e-02f, 4.438953470e-02f, 2.182882840e-02f, 2.902681750e-02f, -3.881488370e-02f, -9.137809280e-03f, 3.513002770e-02f, 3.127675500e-03f, 2.843224070e-02f, 3.097730320e-02f, 1.942196050e-03f, 1.270888650e-02f, 9.094577980e-04f, -3.408918900e-02f, -1.039796420e-02f, 1.028431000e-03f, 1.248442940e-02f, 1.316859950e-02f, 1.575823870e-02f, -7.124448570e-02f, -3.191615270e-02f, -9.427874530e-02f, -6.060974210e-03f, 3.099096470e-03f, -5.434916820e-03f, -6.684625990e-03f, -4.941392320e-02f, 3.050345180e-02f, -6.800735000e-02f, 6.331661130e-04f, -1.615641270e-02f, 8.087337020e-03f, 1.234215590e-02f, 3.270656340e-03f, -2.088793550e-03f, 5.963984500e-02f, -1.106410750e-03f, 2.475056610e-02f, 3.034767880e-02f, -7.566118150e-03f, -1.623915160e-03f, 1.924117280e-02f, -4.984534530e-02f, 6.635332240e-04f, 1.619139310e-02f, -3.736673100e-04f, 3.327549990e-02f, 2.912031300e-02f, -8.248739880e-03f, -6.881052260e-02f, 1.476519390e-04f, 1.833142600e-03f, -3.211073580e-02f, 2.451808750e-02f, 2.777658030e-02f, 2.382516120e-02f, 3.049695170e-03f, -3.937913850e-02f, -7.546544070e-03f, -3.472788490e-03f, -1.918450930e-03f, -5.655714780e-03f, 1.612078400e-02f, 3.342948110e-02f, 2.790369330e-04f, -3.839904070e-02f, -3.315396230e-02f, 2.032825160e-02f, 3.770964220e-02f, -4.379874100e-02f, 2.238696630e-02f, -4.788723220e-02f, -3.002241440e-02f, 2.952573820e-02f, 1.985517800e-03f, -3.599424290e-02f, -1.222585680e-03f, -2.805080080e-02f, 5.138341340e-03f, 9.345012940e-04f, 2.685552280e-02f, 1.274943440e-02f, 5.749101280e-03f, -3.316006810e-02f, 1.843934060e-03f, 5.085854980e-02f, 3.527051580e-02f, 1.045136340e-02f, 2.898723070e-02f, 3.487444670e-02f, 8.964852240e-02f, -3.842503200e-02f, 1.602226120e-02f, -6.473842080e-04f, 5.908816590e-03f, -1.084263620e-02f, -1.688591200e-02f, -9.603112000e-03f, 1.188593800e-03f, 4.344449190e-02f, -1.559735040e-03f, -4.036122560e-02f, -3.264599290e-02f, 6.967828420e-02f, 3.370589020e-02f, 4.845399410e-02f, 2.166743950e-02f, 3.719312330e-02f, -1.676654260e-02f, -7.099421350e-04f, -5.898399280e-02f, 3.069549430e-02f, -4.454771800e-02f, -2.249571680e-02f, 3.099008930e-03f, 4.395186900e-03f, -8.781274780e-03f, -4.080551120e-02f, 4.302329570e-02f, 3.411848100e-02f, -5.098066290e-03f, -2.064946290e-02f, -1.067543400e-03f, -4.420475290e-02f, -5.634684580e-03f, -2.664457080e-03f, 4.289047420e-02f, 5.855574830e-02f, 7.982524480e-02f, 1.706445940e-03f, 2.059582060e-02f, 1.297469060e-02f, 5.117939040e-02f, -1.356483620e-02f, -1.006075740e-02f, 2.349469810e-02f, 7.845590260e-02f, -8.470424450e-03f, 2.900649560e-04f, -6.225050990e-02f, -3.283945150e-03f, -9.292298550e-02f, 5.797682800e-03f, 8.456726790e-04f, -1.881358620e-04f, -5.841123870e-03f, 9.089520200e-03f, 6.213327120e-02f, -3.100680930e-02f, 2.200805210e-02f, -4.528075830e-02f, 2.288258630e-03f, -1.246113890e-02f, -3.046793860e-02f, -2.562963030e-02f, 5.101181100e-03f, -1.977333050e-02f, 3.279367000e-03f, 3.646851700e-02f, 1.009096110e-02f, -4.655499380e-02f, -4.498207200e-02f, -6.523149080e-03f, 6.059260670e-02f, -1.040462170e-03f, 2.098400700e-02f, 1.877200210e-03f, -3.811969360e-04f, -3.582863510e-02f, -2.486028520e-02f, 1.170741390e-03f, -1.919768750e-02f, -2.221869680e-02f, 2.819962330e-03f, -2.796300920e-03f, 2.131817860e-02f, -6.105350700e-02f, -1.071688230e-01f, -1.163822690e-02f, -8.591491720e-03f, -2.449591460e-02f, -7.336428970e-04f, -5.929729710e-02f, -2.232757770e-02f, -1.825994000e-03f, 2.765674330e-02f, -5.593368780e-03f, -5.765771490e-04f, 7.795855870e-03f, 1.285973120e-03f, 1.211358120e-03f, -2.744265830e-02f, 3.035679650e-02f, -3.369831290e-02f, -2.296360400e-02f, -3.852839770e-02f, -2.439788170e-02f, -5.231607710e-02f, 2.206759340e-02f, -1.573269070e-02f, 6.286701650e-03f, 5.610712990e-02f, -9.189898840e-04f, -8.520815520e-03f, -4.011543000e-03f, 8.543696250e-02f, 1.276816710e-03f, 3.737590510e-03f, -2.664520960e-02f, 3.211556700e-03f, -4.914679560e-03f, -5.802339320e-02f, -6.436625120e-02f, -3.163176030e-02f, -2.260920780e-02f, 7.693326330e-04f, 6.994840500e-02f, -5.464399610e-02f, 1.502826810e-02f, -2.943320140e-04f, 8.572991190e-02f, 3.283176570e-03f, -4.635410380e-03f, -2.715820820e-02f, -4.022477940e-02f, 6.258893760e-02f, 6.747195720e-04f, -3.376970070e-02f, 7.634868380e-03f, -8.466122670e-03f, 5.232875420e-02f, 7.387056020e-03f, -8.332388470e-03f, 5.655833990e-03f, 2.057946290e-02f, 6.995330010e-02f, -1.875835840e-02f, 5.368298300e-05f, 1.412605490e-02f, 2.083637940e-02f, 5.999681350e-02f, -6.881779990e-03f, -2.927129390e-03f, 1.609171390e-03f, -1.537099600e-03f, 1.255291140e-02f, -2.188609730e-02f, 3.722310530e-03f, 8.723760020e-03f, -1.389376450e-02f, -8.691026830e-03f, -4.248191420e-02f, 6.109117380e-05f, -2.295874520e-03f, -4.703954610e-02f, 1.938642750e-02f, 5.682828650e-02f, -5.361003340e-03f, 1.661309970e-02f, -3.580462190e-02f, 7.058104870e-02f, 1.869167200e-02f, -4.548352960e-02f, 3.018935400e-02f, 2.548005800e-02f, -2.833029440e-02f, -5.214223640e-03f, 1.284048610e-02f, 4.157724790e-03f, -1.073479800e-01f, 8.501793260e-03f, 2.476270310e-03f, -8.850729090e-03f, 1.140910670e-03f, -2.088798400e-02f, 4.620499540e-02f, -5.395117770e-02f, 3.512823580e-02f, 4.691667850e-02f, 1.863035140e-03f, 1.436869800e-02f, -3.133846820e-02f, 3.471111510e-02f, -2.624529970e-02f, -5.765418710e-02f, -4.885057450e-03f, -1.310903390e-02f, 2.673882430e-02f, -4.482647780e-02f, 1.449640370e-02f, 2.735014540e-03f, 1.122093200e-02f, -2.196006010e-03f, 5.238985180e-03f, 1.492993910e-02f, -5.913340300e-02f, 2.983115430e-02f, 2.178830090e-02f, -4.255301880e-02f, -4.784901810e-02f, -6.890624300e-03f, 4.907989870e-03f, 2.265520020e-02f, 1.486766990e-02f, -4.712610510e-03f, 1.667292230e-02f, 4.894736690e-03f, 4.193640780e-04f, 1.025690460e-03f, -2.488396690e-02f, 5.719010160e-02f, 9.364997040e-03f, 4.121240690e-03f, 1.764772650e-02f, -7.332563400e-03f, 2.526229950e-04f, -2.473033270e-03f, -7.401432960e-04f, -2.196419050e-02f, -1.966075740e-03f, 1.358732210e-02f, -7.325491400e-03f, 3.452283890e-02f, 8.766671270e-02f, -4.289316760e-02f, 2.940214430e-02f, -4.015756770e-02f, -1.861492540e-02f, 4.528169990e-03f, 4.391842340e-02f, 1.854490490e-03f, -1.461083350e-02f, 6.018396930e-03f, 2.385727600e-03f, 1.734266990e-02f, -8.192558890e-04f, -1.462316510e-02f, 2.629158090e-03f, 2.116440800e-02f, -3.024265540e-02f, 3.090534130e-03f, -1.874511880e-02f, 3.182210770e-02f, 6.852521100e-03f, 4.516151170e-02f, 2.066031840e-02f, 4.157779370e-02f, 1.734424380e-02f, -7.003491370e-02f, -3.663542450e-03f, -5.723717810e-02f, 5.880602450e-02f, 4.866114260e-02f, -1.414202620e-03f, 1.731351830e-03f, 4.429862650e-02f, -3.121498970e-03f, -4.432159010e-03f, -3.111511660e-02f, 3.961854800e-02f, -2.334754170e-02f, 3.145348650e-02f, 2.829686180e-02f, -8.545083550e-02f, -1.050778760e-02f, 1.345043540e-02f, -3.694715680e-03f, 6.120086180e-03f, 2.099055420e-02f, 3.629815580e-02f, -8.469643650e-04f, 8.664710330e-04f, -2.524488230e-02f, -4.111741860e-02f, -4.723761230e-02f, 2.505212460e-02f, -8.151644840e-03f, -1.523685550e-02f, 5.445713180e-03f, 2.562474930e-03f, 4.001946950e-04f, -1.635198950e-03f, 6.643570210e-02f, -3.553215040e-02f, -8.968445470e-03f, -4.576390980e-02f, -4.041261600e-02f, 4.968753830e-02f, -2.095480820e-02f, -5.758845250e-03f, 5.052976310e-03f, 4.029495640e-02f, -4.913510010e-02f, 2.023356970e-02f, -1.971258780e-03f, 1.153543130e-02f, -1.101218720e-02f, -1.566118750e-02f, -2.328666860e-03f, -2.341592680e-03f, -1.106939650e-02f, -1.736329870e-03f, 1.599233220e-02f, 6.700237100e-02f, 1.334884200e-02f, -2.051477090e-03f, -5.726997180e-02f, 5.645317030e-03f, -2.833856830e-02f, 5.528369550e-02f, 1.257860850e-02f, -9.759996080e-03f, 6.254819780e-02f, -4.509466230e-03f, -3.164200860e-02f, -1.840820720e-02f, -4.918529650e-03f, 6.708086470e-03f, 7.518094030e-03f, 8.136828430e-03f, -3.836235190e-05f, 3.103561330e-02f, 8.360097180e-03f, -6.583584100e-02f, -3.809558980e-04f, 5.547175560e-02f, -1.934956570e-02f, 6.826034750e-03f, -4.188046230e-02f, 2.143856600e-03f, -1.171405990e-02f, -5.806287750e-02f, -5.217299610e-02f, -5.707123130e-02f, 4.492300560e-03f, 9.836555460e-03f, 1.791934250e-03f, -1.981665010e-02f, -2.161758020e-02f, -7.342262190e-03f, -9.995346880e-03f, 3.555397690e-02f, 7.544263270e-03f, 9.212925100e-03f, -4.917506130e-03f, 6.267577410e-03f, -3.827884050e-02f, -2.063236760e-02f, -9.618727490e-03f, -6.223858150e-02f, 8.067285670e-05f, 5.995094030e-02f, -7.689356800e-02f, 1.223088340e-02f, -1.278322660e-02f, 8.645300400e-04f, -9.613737460e-03f, 1.663743700e-02f, 1.659132540e-03f, -8.534638210e-03f, 6.418553650e-03f, -1.278218110e-03f, -9.592320770e-03f, -3.119117110e-03f, 7.972438820e-03f, -3.192075760e-03f, -9.353964710e-04f, 1.261019610e-03f, 4.156481470e-02f, 6.197612360e-02f, 1.338777130e-02f, 6.155249430e-04f, 8.871009570e-03f, -5.664345620e-02f, 3.432778270e-02f, -3.879401830e-02f, -2.454918620e-02f, 1.995032890e-03f, 2.605678890e-02f, 4.027722030e-02f, 2.668158710e-02f, 1.999503750e-02f, -7.373946720e-03f, 4.314101300e-03f, -7.050206420e-03f, -1.588957200e-02f, -3.569964690e-02f, 1.196224990e-02f, -2.071161940e-02f, 9.472292660e-02f, -1.381409540e-02f, -3.771991660e-02f, 6.638722030e-03f, 4.062340590e-03f, -1.136166040e-03f, 2.619435450e-02f, 3.145762910e-02f, 2.662760210e-02f, -9.410268630e-03f, -7.891566490e-03f, 2.339775670e-02f, 6.739961450e-03f, 8.161430060e-02f, 3.073649850e-02f, 4.704210910e-03f, 4.475604740e-02f, 4.033788280e-04f, -1.402319500e-02f, 2.076213020e-03f, 1.016118470e-02f, 4.226108270e-02f, 4.046717660e-02f, -5.856787790e-02f, -4.285274450e-02f, -5.770728360e-02f, 5.733016130e-02f, -1.828080600e-02f, -4.520073160e-02f, -3.210545700e-02f, -3.768273820e-02f, -3.375878930e-02f, -5.031196770e-02f, 4.045568930e-04f, -1.420663020e-02f, 2.792000070e-03f, 2.880396140e-02f, -7.696472110e-03f, 4.517511460e-03f, 3.277505560e-02f, -2.499347550e-03f, -5.111325070e-03f, 2.304348540e-02f, -5.821347240e-02f, -4.864861070e-02f, -2.899216670e-02f, -9.535260500e-03f, -1.914405820e-02f, 2.112160580e-04f, -2.638375010e-02f, 5.892091620e-02f, -1.766002920e-02f, 3.630628340e-03f, 3.792995960e-02f, 7.607859090e-03f, -1.856268010e-02f, 1.064385100e-02f, -3.236859110e-03f, 4.698667300e-02f, 6.897140290e-03f, 2.803745490e-02f, 2.741977760e-02f, -2.653643120e-02f, -2.868296760e-02f, -4.110377650e-02f, 7.306422290e-02f, -2.462418380e-02f, 4.003024850e-02f, -1.349972990e-05f, 1.737377370e-03f, 7.084996250e-02f, 2.188862120e-02f, 1.680792500e-02f, -7.564063650e-03f, -8.106642400e-03f, -3.605278950e-02f, -2.019646760e-02f, 9.590698780e-02f, 4.985344040e-02f, -2.407676070e-04f, 1.250909920e-02f, -5.433017850e-03f, -1.104679890e-02f, 6.929392930e-03f, 7.927430790e-03f, -3.128077460e-02f, -3.286539110e-03f, -2.780443430e-02f, 2.740789200e-02f, 2.232182310e-03f, -3.292945030e-02f, 1.263518720e-02f, 7.011624430e-02f, -4.516996070e-02f, 4.179941490e-02f, -1.854405740e-02f, 2.219249870e-02f, 1.452091150e-03f, 1.090758200e-02f, 5.776569380e-05f, 1.012248640e-02f, -1.528720370e-02f, -1.721647800e-03f, -1.909747910e-02f, 8.735285140e-03f, 7.918354120e-03f, 3.378833880e-03f, -2.320782650e-02f, 5.818394570e-02f, 4.869999740e-02f, 3.324678870e-03f, 5.556056280e-03f, 4.211431000e-02f, 1.831529100e-02f, -2.547695860e-02f, -1.848022640e-02f, 1.857337770e-03f, -1.788477410e-02f, -5.083156000e-02f, 1.866856220e-02f, -2.387321740e-02f, -1.409434710e-03f, 8.550014340e-03f, 2.977860860e-03f, -2.795131320e-02f, -3.891471030e-02f, 8.496685880e-03f, 2.244695790e-03f, 6.515534970e-02f, -3.788500280e-02f, -2.139958740e-02f, -5.043325570e-02f, 1.084516660e-02f, -4.084052980e-03f, -4.321925710e-02f, 5.792677780e-02f, -5.189890040e-02f, 5.761650390e-03f, 2.504077510e-03f, 2.906882020e-02f, -2.408257130e-02f, 3.249314800e-02f, 9.463819680e-03f, 8.060861730e-04f, -4.059077430e-02f, -2.806743840e-03f, 2.766433730e-02f, -5.849516020e-03f, -2.377563390e-03f, -2.106199790e-02f, -4.086342450e-02f, 1.717336660e-02f, -1.630774510e-02f, -3.080406230e-02f, -5.483206360e-02f, -6.055915260e-03f, 4.799923670e-02f, 2.518414710e-02f, 2.887902220e-02f, 3.243079040e-02f, -2.636519960e-03f, 6.129297540e-04f, -3.386714680e-02f, -6.247196810e-03f, 8.363816140e-02f, 1.993405630e-02f, -2.960535000e-03f, -6.334158590e-03f, 1.116303380e-03f, -1.392771770e-02f, 6.896992680e-03f, -7.789202770e-02f, 2.393276620e-02f, 1.976946740e-02f, 1.078524630e-02f, -3.608445820e-02f, -2.609040960e-02f, -4.947484280e-02f, 2.020511220e-02f, 1.589222230e-03f, -5.392766910e-04f, 4.999962080e-02f, 5.658996110e-02f, -2.011237110e-02f, -1.926362330e-02f, 4.657691810e-03f, 3.531816600e-02f, 4.044780970e-03f, -6.465414190e-04f, 1.435193790e-02f, 4.159884150e-02f, -9.767238980e-03f, 1.479083110e-02f, 8.759810590e-03f, 1.248022080e-03f, 8.112653160e-03f, 8.633559920e-04f, 6.732722370e-02f, 3.467376900e-02f, 3.642112390e-02f, 2.414721440e-02f, 6.798515560e-03f, 4.816547500e-03f, -2.268388680e-02f, 1.590972770e-02f, -5.475737150e-02f, -2.046804690e-02f, 5.483699500e-04f, 5.038801580e-03f, -2.148790010e-05f, -9.488084160e-02f, -1.491822300e-03f, -7.782467640e-03f, -3.681609170e-03f, 8.437044920e-02f, 8.756395420e-03f, 2.177484890e-02f, 6.136924770e-02f, -1.092307180e-02f, -9.048864240e-02f, -2.675539630e-02f, 6.008333710e-02f, -7.151070980e-03f, 6.120612100e-02f, -4.672144350e-02f, 9.073578400e-04f, 5.669910460e-03f, -2.928024160e-03f, -7.833423460e-02f, -2.040984850e-02f, -9.419101410e-04f, -3.012423030e-02f, -1.454650770e-03f, 5.987072830e-03f, 2.128566060e-02f, -2.271444720e-02f, 3.799461760e-03f, -1.910492310e-03f, 7.311580240e-03f, -2.328347230e-02f, -3.945749630e-02f, -2.540333760e-02f, 1.069971710e-03f, 5.612860620e-02f, 2.010351050e-03f, -1.731136440e-02f, 3.606690840e-02f, 2.434154410e-02f, 2.416929420e-02f, -6.089454520e-03f, 2.293828870e-02f, 7.241431620e-03f, -3.293552990e-02f, -5.302827810e-02f, 4.588666190e-02f, 3.719221800e-02f, -1.539845860e-02f, -4.762488230e-02f, -9.094385430e-03f, -3.939657290e-02f, 1.372893460e-03f, 6.688957100e-03f, -5.133204910e-02f, 6.012991820e-02f, 2.044109070e-02f, -7.865427990e-03f, -7.486211600e-03f, 2.755091150e-02f, 5.685222570e-04f, -5.493029950e-02f, -7.802344390e-03f, -2.913651990e-03f, -1.907189750e-02f, -5.029997320e-03f, -1.484033740e-02f, 3.969660960e-03f, 4.559627730e-03f, -2.360023930e-02f, -9.060537560e-04f, 4.548972010e-03f, -2.421363260e-02f, -2.965555710e-02f, -1.251017580e-02f, -6.488528840e-02f, 2.970594540e-02f, -5.060986730e-04f, 2.494964930e-02f, -3.887139260e-02f, -4.496577010e-02f, 1.196286410e-03f, -2.185276010e-03f, 1.253609430e-03f, 8.975773120e-03f, 4.740820730e-03f, -4.987203050e-03f, 1.559301750e-02f, -1.067740030e-03f, -2.574718370e-02f, -5.841333420e-02f, 4.913027960e-02f, -2.393573340e-02f, 1.188115220e-02f, 5.628247750e-03f, 5.287283290e-02f, 2.362848070e-02f, -2.069324440e-02f, -2.845187440e-03f, -4.653093220e-02f, -3.011669320e-04f, -1.807182470e-02f, 2.639551090e-02f, -8.007422830e-02f, 3.762638570e-02f, 5.479004470e-04f, -2.428794650e-02f, 2.581933280e-03f, 2.660759720e-03f, 1.351008660e-02f, -1.107826180e-02f, -6.525845270e-03f, -2.281459230e-02f, 4.500988410e-03f, -1.811639590e-02f, 3.113676050e-02f, -5.088844800e-03f, 6.893855330e-02f, -6.747120620e-02f, 2.111062590e-02f, 5.252618720e-02f, -9.276691120e-04f, 1.778472560e-03f, -3.586447240e-02f, 1.415303350e-02f, -5.241248010e-02f, -5.094961080e-02f, -2.536048650e-03f, 6.100446920e-03f, 5.013147370e-03f, 3.018262800e-02f, 7.694664530e-04f, -3.743123960e-03f, -4.096129540e-02f, 2.602501590e-02f, 7.326493970e-03f, -3.509173910e-02f, 1.382235530e-02f, 3.331509610e-02f, -5.955422300e-02f, -3.726300220e-02f, -2.065710350e-02f, 9.503109610e-04f, 2.319033820e-02f, -9.354731060e-03f, -1.354837320e-03f, -2.188793380e-02f, -3.567071630e-03f, 2.914916910e-02f, -1.174296250e-02f, 1.480558310e-03f, 2.538043630e-02f, 4.696556370e-03f, -1.679429780e-02f, -3.110903870e-02f, 5.624363200e-03f, 2.951461640e-02f, -1.378174750e-03f, 7.220728320e-03f, 8.727058760e-03f, 8.912873450e-03f, 1.090240850e-02f, -2.755384890e-02f, -4.331256080e-02f, -3.242364390e-03f, -3.976256030e-02f, 2.018691790e-02f, 1.744853890e-02f, 6.600609510e-03f, 2.239810540e-03f, 3.010922860e-02f, 1.175306360e-02f, 2.341205440e-02f, 1.926875300e-02f, -9.434547270e-03f, -1.072231680e-02f, -2.684430590e-02f, 7.196292750e-03f, 5.212139340e-03f, 8.015918550e-03f, 9.975907150e-04f, 4.994913560e-02f, -2.744361200e-02f, 5.762087180e-02f, 2.088611200e-02f, 2.541261260e-03f, 3.399870590e-03f, 2.352456380e-02f, -3.779107700e-02f, -5.677000430e-02f, 7.660222800e-02f, -3.832629650e-03f, 8.928632360e-03f, -7.975643500e-03f, 4.123609980e-03f, -4.795324520e-03f, -1.742109770e-03f, 9.510893370e-03f, -4.622726700e-04f, 2.393107860e-02f, -9.644212200e-03f, 4.557769370e-02f, -3.356145320e-02f, -8.106772600e-02f, 1.820208880e-02f, -7.208783650e-03f, -4.682521520e-02f, 4.825590180e-02f, 3.525158760e-02f, 1.074430880e-03f, -2.327273410e-02f, -3.377581710e-03f, -4.772647840e-02f, 1.525606490e-02f, -3.249018920e-03f, 3.104603100e-02f, -2.959184120e-03f, 3.353771190e-02f, 2.878197660e-02f, -2.700221540e-02f, 5.414744090e-02f, 1.124172560e-02f, 3.089128090e-06f, -3.352610770e-02f, -3.573784600e-02f, -5.138625200e-02f, 2.249375920e-02f, -8.357537530e-02f, -3.690221930e-04f, 5.599065220e-03f, -2.711291610e-02f, 5.049244500e-03f, -2.273077700e-02f, 2.771615050e-03f, 1.951769370e-02f, -7.102326960e-03f, -4.051324910e-03f, -2.117616680e-02f, -2.347075010e-02f, -4.396937420e-02f, -2.760967610e-02f, 2.665933040e-02f, -1.032539550e-02f, 2.542147790e-02f, -5.109986290e-03f, -9.041211570e-03f, -2.453315070e-02f, 3.387067840e-02f, 6.343004100e-02f, 2.744720320e-03f, 3.300628860e-03f, 3.022551160e-02f, -3.109348750e-02f, -4.531247540e-02f, 3.458890320e-02f, -4.524114080e-03f, 5.885040740e-04f, 6.306563970e-03f, -6.926111880e-02f, -3.031646130e-03f, 9.588459500e-03f, -3.635880720e-02f, -5.360053110e-02f, 7.261762020e-02f, 8.169014000e-03f, -1.189081460e-02f, 2.310299500e-02f, 7.428868860e-02f, 1.650516880e-02f, 5.126246720e-03f, 4.017508400e-02f, 6.145390860e-02f, -3.336694460e-02f, 2.823574240e-03f, -2.553656140e-02f, 3.644852430e-03f, -5.884427580e-02f, -5.250163380e-03f, 5.214397330e-03f, -3.015129640e-02f, 7.509803980e-04f, -4.484642670e-02f, -5.876502770e-02f, 1.299205240e-02f, 3.762504090e-02f, -9.093877860e-03f, -4.097777420e-03f, 1.172366650e-02f, 2.468102050e-02f, -2.032656220e-02f, 1.200273350e-02f, 1.475198470e-02f, -2.107024430e-03f, -9.040530770e-03f, 2.197589540e-02f, -3.359074890e-02f, 7.945360610e-03f, 2.319786230e-03f, 7.266973700e-02f, 2.782087540e-03f, -1.503670240e-03f, -3.061647530e-02f, 3.722242550e-03f, 4.126072860e-03f, 6.501810250e-02f, -1.838511790e-02f, 2.695276770e-02f, -5.621291230e-03f, -1.238067400e-03f, -2.739447170e-02f, 4.919216040e-02f, 6.178628650e-02f, -1.171936560e-02f, 1.774449720e-03f, 1.175044220e-03f, -3.572626780e-02f, 3.264598550e-02f, 2.511850930e-02f, -4.207975420e-02f, 3.633501010e-03f, 8.245714010e-03f, -6.276160480e-03f, 3.515060620e-02f, 1.875939080e-03f, -4.682717380e-03f, -2.835862150e-02f, -4.639306660e-02f, -2.968066740e-02f, 1.438293370e-03f, 1.533314770e-02f, -5.418409030e-02f, -2.219513430e-02f, 2.614224140e-02f, 4.806581140e-02f, 6.400547180e-02f, -1.009402800e-02f, -5.133323000e-02f, -2.902434440e-03f, -3.954632950e-02f, 1.816981240e-03f, 2.760053430e-02f, 8.080186320e-03f, -5.795439710e-03f, -3.633823250e-02f, -8.460544980e-03f, 7.734297310e-03f, 3.933147710e-02f, 2.169364600e-03f, 4.583071920e-02f, -1.374714910e-02f, -1.586249800e-03f, 1.220719520e-02f, -3.277078640e-02f, -6.632635740e-02f, 3.961715100e-02f, -3.685152160e-02f, -3.547911770e-03f, -1.989677550e-02f, -2.864018270e-02f, 5.616419760e-02f, -2.013264780e-02f, -5.196439100e-03f, -3.191624950e-02f, -1.616841650e-03f, -2.717107720e-02f, -1.916153240e-03f, -8.942567740e-03f, -5.171679660e-04f, -8.380967370e-02f, -6.952106210e-02f, -1.028567200e-03f, 1.251295580e-02f, 2.031220820e-03f, 1.339404940e-02f, 3.343141820e-02f, -2.357327380e-02f, -9.165529160e-03f, -5.256155970e-03f, -2.896815540e-03f, -7.375081540e-03f, -2.033069030e-03f, 5.489221960e-02f, -1.939983670e-02f, -7.908256720e-03f, -2.234969100e-02f, 1.064818630e-02f, 4.701997710e-02f, 4.194764420e-03f, -3.567579200e-03f, 2.640777830e-02f, -2.236028200e-02f, -3.186743710e-02f, -2.161449940e-02f, 7.221070680e-02f, 4.761685800e-02f, 4.074101150e-02f, 4.095151670e-04f, 2.393646350e-02f, -4.423810910e-02f, -4.368821900e-02f, 5.088021610e-02f, -2.898983890e-03f, 5.145735570e-03f, 2.938617950e-03f, -3.719567880e-02f, -3.506515870e-03f, 6.471018310e-03f, -2.994698470e-02f, 8.335119930e-04f, -2.412311170e-02f, 5.230046810e-04f, 1.673676630e-02f, -2.183248520e-03f, 5.285500670e-04f, 6.453047040e-03f, 5.950117110e-02f, -5.753187460e-02f, -2.602996300e-02f, -3.981405500e-02f, -4.609798270e-02f, -1.746755680e-03f, 5.608215930e-02f, 1.442354270e-02f, -1.712245680e-02f, 1.961124870e-02f, 3.850493580e-03f, 5.942931400e-02f, 2.697099230e-03f, -3.295879070e-02f, -7.097504570e-03f, 8.893525220e-03f, -1.621708270e-02f, -3.651546690e-02f, -5.213753510e-02f, 2.383115700e-02f, -1.019664760e-02f, 4.391411320e-03f, -1.442887260e-02f, -3.482666240e-02f, 1.622254030e-02f, -2.734377980e-02f, -8.272244010e-04f, 3.176160160e-03f, -5.565518890e-02f, 2.213773500e-02f, -5.660294370e-02f, 1.717438920e-02f, -1.159297300e-03f, -4.575571050e-02f, -5.061103030e-03f, -9.946362110e-03f, -3.828767220e-04f, -1.469231860e-02f, -2.592387240e-02f, 2.260127570e-03f, -3.115691240e-02f, -2.943120900e-02f, 3.918025640e-02f, -1.754362320e-02f, -4.109906410e-02f, -2.487329390e-02f, 8.895345960e-03f, 6.815770260e-02f, 3.685630110e-02f, 3.561935570e-02f, -2.536324610e-04f, 3.410072070e-03f, -1.601286930e-03f, -4.738945140e-02f, 4.172745160e-03f, -5.359257570e-03f, -1.566985620e-02f, -7.686833390e-03f, 5.958966910e-02f, 7.548131050e-02f, -9.875429790e-03f, 2.632670850e-02f, -1.927033650e-03f, 4.056892820e-03f, 1.288236580e-03f, -6.475357710e-02f, -2.899455470e-02f, 1.092733440e-02f, 7.664043460e-02f, -5.677196660e-03f, 4.045135530e-02f, 9.497256020e-03f, -4.866401850e-02f, 2.633410510e-02f, 6.219163530e-03f, -4.369451110e-02f, 5.078240300e-03f, -5.333763730e-02f, 3.903822970e-02f, -4.084858670e-02f, 2.684940210e-02f, 2.675251850e-02f, 9.091617530e-03f, 3.429884840e-02f, 2.134837020e-02f, 6.120798180e-03f, -1.010273300e-02f, -1.227910630e-03f, 2.334410140e-02f, 6.835059080e-02f, 6.515245880e-03f, 3.639568570e-03f, 2.594389210e-02f, 4.755854980e-02f, 3.713317590e-02f, 2.347937970e-02f, -3.463182370e-03f, -4.221335430e-02f, 8.752929040e-03f, 4.301011190e-02f, -5.315565970e-03f, -2.822397800e-04f, -3.771807630e-02f, -3.029798620e-03f, -3.203006460e-02f, -1.833555660e-02f, 5.027506130e-02f, -3.066398390e-02f, -8.737483620e-02f, 4.388136040e-02f, 5.147605020e-02f, -3.917769720e-02f, 4.817300290e-02f, -1.474215370e-02f, -1.627008900e-03f, -3.909355030e-02f, 2.269904220e-04f, -7.878497240e-03f, 5.624737120e-03f, -1.500102920e-03f, -6.242545790e-03f, 4.623542070e-03f, -2.331875500e-03f, 8.447051980e-03f, 8.023399110e-02f, -4.360727220e-02f, 6.499877780e-04f, -4.293703470e-03f, 1.882216330e-02f, 2.919018830e-02f, 7.468955220e-02f, -5.369362980e-02f, 3.593738000e-02f, -1.331862060e-03f, 2.979374300e-02f, -2.598678320e-02f, -7.933561690e-03f, -1.313556080e-02f, -1.488173030e-03f, -7.549279180e-02f, 4.926038910e-03f, 2.997406940e-02f, -1.626063140e-02f, -5.295597950e-03f, -1.269392950e-02f, -2.306240050e-02f, -6.730907410e-02f, 4.832980780e-02f, -1.649506950e-02f, -3.737105060e-03f, -2.246002900e-03f, 2.041696010e-02f, 1.581138190e-02f, 3.689135610e-02f, 6.005678330e-03f, 5.172921340e-03f, -1.192200840e-02f, -4.716647790e-02f, -9.598513130e-03f, 5.775222550e-02f, 9.444090540e-03f, 1.748105320e-02f, 3.593392440e-03f, -2.311277950e-02f, -2.201082420e-03f, -1.773905100e-04f, -2.100633830e-02f, 8.792588110e-02f, -4.355169090e-02f, 1.534667700e-02f, 3.770177810e-02f, -1.479663140e-02f, 5.459682640e-02f, 9.529235770e-03f, -2.169605340e-02f, 4.596643890e-02f, -2.043729280e-02f, -2.563850400e-02f, 2.285404130e-03f, -7.834679450e-03f, -8.984766320e-04f, 1.644762230e-02f, 1.429736380e-03f, 3.185918090e-03f, 4.265643190e-03f, 2.846077780e-03f, -4.407966040e-03f, 3.072464090e-02f, 7.463423530e-03f, -2.664317000e-02f, -4.738527160e-02f, 8.391975430e-03f, 2.497838250e-02f, 2.758498120e-02f, -6.610442700e-02f, 8.486947040e-03f, 1.180795950e-02f, 1.518189910e-03f, 1.955113370e-03f, 4.761798680e-02f, 2.405294960e-02f, -2.452220400e-02f, 6.192671130e-03f, 2.569450620e-02f, 9.175582090e-04f, -2.090302670e-02f, -8.787536060e-03f, 2.057707680e-02f, -1.378069070e-02f, -9.604656690e-02f, 4.299635530e-03f, 2.965906820e-02f, -1.495779140e-03f, -2.139347840e-03f, -2.437091620e-02f, -7.326867900e-03f, 6.436918400e-03f, -3.723148260e-02f, 5.519077650e-03f, 6.438842510e-03f, -1.936140280e-02f, -2.837876790e-02f, 5.907853320e-02f, 1.378191260e-02f, -5.986860490e-03f, 2.948898260e-02f, 2.522113970e-03f, -4.452568290e-02f, -8.012576960e-03f, -1.890227550e-03f, -3.626286240e-02f, -5.746567250e-02f, 5.338200830e-03f, 3.082369450e-03f, 3.868097440e-02f, 2.443856750e-02f, -4.498763380e-02f, -3.761732580e-02f, 2.171505620e-02f, 4.515881840e-02f, -1.676948930e-02f, 3.742467240e-02f, 1.730160900e-03f, 3.659835460e-02f, 1.970210110e-03f, -4.197837780e-02f, -7.114459290e-03f, 6.803533760e-04f, 1.707812580e-02f, 1.005847290e-02f, 3.886310380e-02f, -9.187010120e-03f, -3.987620400e-02f, -6.499210000e-02f, 4.162061210e-02f, 8.518164050e-03f, -1.161958280e-02f, 2.406558020e-02f, 1.893208180e-02f, 9.632038880e-03f, 6.928193380e-03f, 4.258214900e-04f, 3.267068650e-03f, 4.377605020e-02f, 4.925729330e-02f, -3.207638110e-02f, 5.728234070e-03f, -2.758517120e-02f, -9.385336310e-04f, 3.895572620e-03f, 9.243771430e-03f, 3.491950410e-02f, 1.172957570e-02f, -1.197095870e-02f, -3.872301430e-02f, 2.086478660e-02f, 1.140027770e-02f, 7.064889650e-03f, 4.398832470e-02f, 3.417999670e-02f, 6.881015370e-03f, 5.810732950e-03f, 8.657510390e-03f, 1.919404720e-03f, 2.985644530e-02f, 1.214369390e-02f, 6.195188680e-02f, -1.773928850e-02f, 3.210907800e-03f, 3.213601190e-02f, 2.275777980e-03f, 1.216460580e-02f, -3.398320400e-03f, -1.254707340e-03f, -1.768717920e-04f, -1.206156330e-02f, -2.389534750e-02f, -5.506167560e-02f, 1.091530450e-02f, 8.493356410e-02f, 7.268783640e-03f, -2.087397270e-03f, -5.421514160e-03f, -3.202918540e-02f, -1.963825900e-02f}; + +Kokkos::View __constant_72xf32_0; +float __constant_72xf32_0_initial[72] = {1.941794010e-01f, 1.407446410e-01f, 1.136200200e-01f, 7.981487360e-02f, 5.845708770e-02f, 8.084526650e-02f, 1.762152460e-01f, 1.397005470e-01f, 8.112805330e-02f, 7.925851640e-02f, 1.685659740e-01f, 1.970534770e-01f, 2.064662580e-01f, 9.247460960e-02f, 1.260788440e-01f, 2.551981210e-01f, 1.494548320e-01f, 1.870848690e-01f, 1.378273070e-01f, 7.998578250e-02f, 1.471374930e-01f, 7.143070550e-02f, 2.545621990e-01f, -2.045896090e-02f, 1.376211490e-01f, 6.960726530e-02f, 1.643777190e-01f, 1.138196440e-01f, 5.059690400e-02f, 8.876129980e-02f, 1.278923000e-01f, 1.089893280e-01f, 1.504782440e-01f, 1.040867190e-01f, 1.041722760e-02f, 1.179723290e-01f, -7.463661020e-03f, 1.664697970e-01f, 1.209137590e-01f, 5.034126710e-02f, 3.474099190e-02f, 3.078526260e-02f, 2.459381520e-02f, 4.027220980e-02f, 1.355161520e-01f, 1.620595160e-01f, 1.057946530e-01f, 6.281724570e-02f, 1.159959510e-01f, 1.369676740e-01f, 7.779481260e-02f, 1.864602420e-01f, 1.217728850e-01f, 1.882581710e-01f, 3.333995490e-02f, 1.438921540e-01f, 1.205163970e-01f, 9.753992400e-02f, 8.526513720e-02f, 1.047112050e-01f, 3.304959830e-02f, 1.135127620e-01f, 2.318463920e-01f, 4.632654410e-02f, 1.636927430e-01f, 1.664332450e-01f, 8.683469140e-02f, 1.169977490e-01f, 1.511581390e-01f, 1.893785780e-02f, 9.149081250e-02f, 9.993540490e-02f}; + +Kokkos::View __constant_64xf32_0; +float __constant_64xf32_0_initial[64] = {4.407171310e-01f, 4.380066390e-01f, 4.177297060e-01f, 5.783258680e-01f, 6.924784770e-01f, 5.870158080e-01f, 5.696659680e-01f, 5.372803210e-01f, 6.540395610e-01f, 3.952276110e-01f, 6.141207220e-01f, 5.117892030e-01f, 5.450556870e-01f, 6.047449700e-01f, 6.297603850e-01f, 5.377405880e-01f, 6.354920260e-01f, 5.485575800e-01f, 5.888242130e-01f, 5.730918050e-01f, 5.264205340e-01f, 6.113369460e-01f, 7.227578750e-01f, 5.683349370e-01f, 6.440999510e-01f, 5.550646190e-01f, 5.990238190e-01f, 1.576656550e-01f, 5.409642460e-01f, 4.962546230e-01f, 6.168214080e-01f, 5.909023880e-01f, 5.943702460e-01f, 5.979903940e-01f, 3.654850420e-01f, 6.339177480e-01f, 5.690110920e-01f, 5.366063710e-01f, 6.189574000e-01f, 5.694658760e-01f, 5.621519090e-01f, 4.442342820e-01f, 6.001862290e-01f, 5.710213180e-01f, 5.797515510e-01f, 4.847854080e-01f, 4.848721620e-01f, 5.735771660e-01f, 6.418812870e-01f, 5.946749450e-01f, 4.918539820e-01f, 6.281270380e-01f, 6.812222590e-01f, 5.679240230e-01f, 4.054338340e-01f, 5.890662670e-01f, 4.905608300e-01f, 5.314251780e-01f, 4.587394890e-01f, 6.007395980e-01f, 5.496234890e-01f, 5.268159510e-01f, 5.373584630e-01f, 5.212985870e-01f}; + +Kokkos::View __constant_72xf32; +float __constant_72xf32_initial[72] = {-6.693847010e-03f, 2.429191020e-03f, -5.393071330e-04f, 7.164590530e-03f, -2.657292880e-03f, 1.567764670e-03f, 1.398266640e-03f, -1.054503860e-02f, -5.320296160e-03f, 1.496526300e-03f, -2.623572010e-03f, -1.634793820e-03f, -2.552606630e-03f, -6.988195240e-03f, -3.522090990e-05f, -6.121112970e-03f, 7.242791470e-04f, -8.354722520e-03f, -6.065646650e-03f, 1.166367090e-03f, -7.320104630e-03f, 2.199457670e-04f, -8.089010600e-03f, 8.127211590e-03f, 7.803552320e-03f, 1.755110720e-04f, -5.317753650e-03f, 1.418948230e-04f, 7.800536700e-04f, -4.706359930e-03f, 1.926343190e-03f, -7.983022950e-04f, 2.129418720e-04f, -6.941184870e-03f, -6.119279190e-03f, 5.487688350e-03f, -5.894155710e-03f, -1.898436110e-03f, -1.728316190e-03f, -3.895834790e-03f, -7.730937210e-04f, 4.802599080e-03f, 1.234292290e-03f, -1.074849740e-03f, -7.313374900e-03f, 1.167141370e-03f, 2.397986360e-03f, 6.292047910e-03f, -2.376208310e-03f, -3.660895400e-03f, -3.021811430e-04f, -8.037881920e-03f, 9.369751430e-03f, -4.963668530e-03f, -3.458599330e-03f, 1.219130470e-03f, -1.774793260e-03f, -4.464745580e-04f, 4.092331980e-03f, -6.678106730e-03f, 2.030737930e-03f, -1.916083270e-03f, 2.837131030e-03f, -3.489896890e-03f, -9.996166450e-03f, 1.821944610e-03f, -6.288270470e-03f, -2.819635440e-03f, 6.187197290e-03f, 5.785847550e-03f, -1.480326170e-03f, -6.271576860e-04f}; + +Kokkos::View __constant_64xf32; +float __constant_64xf32_initial[64] = {-1.485736370e-01f, 5.776750300e-02f, -8.662290870e-02f, -1.738870890e-02f, -1.962018910e-01f, -3.576853500e-02f, -9.553355160e-03f, -1.053371500e-01f, -5.507965570e-03f, -1.058693680e-01f, -1.533834640e-01f, -1.505018470e-01f, -1.925576930e-01f, -1.212750600e-01f, -1.656593750e-02f, -1.160212310e-01f, -1.304780840e-01f, -2.094167620e-01f, -1.210544850e-01f, -1.617424490e-01f, 6.961071490e-02f, -1.378737690e-01f, -1.444678160e-01f, -1.719985750e-01f, -1.204381290e-01f, 9.252208980e-04f, -1.707939800e-01f, -1.383967980e-02f, -1.319277580e-01f, -1.056930270e-01f, -1.398128720e-01f, -1.028166560e-01f, -1.945570860e-01f, -1.742202040e-01f, -1.489757450e-01f, -1.011373620e-01f, -1.462911540e-02f, -9.440157560e-02f, -1.449001730e-01f, -1.765220170e-01f, -2.185015680e-01f, 5.079746710e-03f, 1.244777350e-03f, -1.177142710e-01f, -1.124331210e-01f, -1.919988100e-01f, -1.098279060e-01f, -9.624292140e-03f, -9.572131930e-02f, -1.043880540e-02f, -1.227019950e-01f, 1.124167910e-02f, -1.645432600e-02f, -1.367662850e-01f, -1.683352140e-01f, -1.649388220e-01f, -1.150112750e-01f, -1.456618910e-01f, -1.858360620e-01f, -1.881683920e-01f, -9.329134220e-02f, -8.973326530e-02f, -1.613321450e-01f, -1.590064020e-01f}; + +Kokkos::View __constant_64x72xf32_0; +float __constant_64x72xf32_0_initial[4608] = {3.426000100e-02f, -1.283215170e-02f, 2.973416450e-02f, 5.143857750e-02f, 2.476266960e-02f, -1.349905880e-01f, 5.392144250e-02f, 1.420650720e-02f, -8.759449420e-02f, 7.264244560e-02f, -4.127629100e-02f, 4.144949470e-02f, -1.367338150e-01f, 6.575902550e-02f, -3.939502310e-02f, 3.741387280e-02f, 1.199309450e-01f, -2.301222270e-02f, 9.360229220e-02f, -3.938241300e-02f, 7.952252030e-02f, -6.601510200e-02f, -4.690225790e-02f, 2.917203310e-02f, -1.088050830e-01f, 6.305870410e-02f, 6.031337010e-02f, -8.961884680e-02f, -5.440878500e-02f, 3.307889770e-02f, 1.207247940e-02f, 4.116934720e-03f, 1.128637980e-02f, -2.939446640e-02f, 3.224723790e-02f, 2.233896030e-02f, -5.558699000e-02f, 4.978972490e-03f, -5.921970680e-02f, 7.635327430e-02f, 3.831415250e-02f, -6.303447480e-02f, -9.247055270e-03f, -1.448456570e-02f, -2.570704180e-02f, 9.342493120e-02f, 6.051736700e-02f, -1.892545260e-02f, -6.347111610e-02f, 4.528541120e-02f, 4.729513820e-02f, -2.670084690e-02f, -3.303520010e-02f, 1.658241080e-02f, 2.566657400e-02f, 4.895884170e-02f, -2.293176760e-02f, 4.597128830e-03f, 4.512243720e-02f, 5.216035620e-02f, -6.074507910e-02f, -7.662637530e-02f, 7.774118330e-02f, 8.317020530e-02f, -8.096887170e-02f, -5.923910440e-02f, 5.786988140e-02f, 1.626002420e-02f, 1.270925160e-02f, -8.774162080e-02f, -1.115106570e-01f, -5.382017420e-02f, 5.759397520e-02f, -2.966144870e-02f, 6.085861940e-03f, -8.106887340e-02f, 2.241067770e-02f, -1.862068100e-02f, -1.477905430e-03f, 4.812151940e-02f, 3.805007040e-02f, -5.835610910e-03f, 3.341522070e-03f, 4.371512680e-03f, 3.931327910e-02f, 6.499388810e-02f, -3.130262720e-03f, 5.240254100e-02f, -1.846408290e-02f, 5.428247150e-02f, 2.431831510e-02f, -2.726005390e-02f, 6.601290400e-02f, -1.530787910e-02f, 4.287951810e-02f, -6.205460420e-02f, -5.186815930e-02f, 1.681274360e-02f, 3.882445020e-02f, 1.633297090e-02f, 8.897074500e-03f, 5.936064940e-02f, -5.001205210e-02f, 4.200631290e-03f, 5.018069870e-03f, 4.983191940e-02f, 4.478614400e-02f, -4.069142420e-02f, 4.343732070e-02f, 5.479045210e-03f, 1.260111200e-02f, 4.613980650e-02f, 2.141182120e-02f, -7.026945240e-03f, 1.603096910e-02f, 3.646975380e-02f, 6.104514750e-02f, -9.811180640e-04f, -2.452574110e-02f, -6.300023940e-02f, -3.188876440e-04f, -1.723251860e-02f, -3.143326940e-02f, 5.123422290e-02f, -1.037430540e-01f, 4.549441490e-02f, 4.295542840e-02f, 2.501569460e-03f, 4.093672340e-02f, 2.454396150e-02f, -4.727227990e-02f, 6.394969670e-02f, -1.975793860e-04f, 1.947421020e-02f, -2.515922860e-02f, -1.075479300e-02f, 4.286999260e-02f, -4.838066550e-02f, 2.390679340e-02f, 2.239334770e-02f, -7.432527100e-02f, -5.676376070e-02f, 3.323351590e-02f, 1.144453700e-02f, -1.339605080e-02f, 4.683770240e-02f, 1.090013140e-02f, -5.423137920e-02f, 1.362499320e-02f, 2.095632810e-02f, -1.123825460e-02f, 3.901660440e-02f, -1.516703050e-02f, -4.165709950e-03f, 4.184182360e-02f, 2.479832430e-02f, -7.299954440e-02f, 5.687006940e-02f, -1.886337620e-02f, 2.726286460e-02f, 6.233948470e-02f, 1.609249600e-02f, -2.489275670e-02f, -3.301253170e-02f, -2.338607800e-02f, -3.701385480e-02f, 6.604054570e-02f, -1.281627360e-02f, -6.427609180e-02f, -2.629491310e-02f, -3.310671020e-04f, -6.450971220e-02f, 5.246320370e-02f, 5.464178320e-02f, 1.394086700e-02f, -9.184858760e-03f, 5.257111040e-02f, -7.354226550e-04f, -7.073418050e-02f, -1.157854870e-01f, -5.110341310e-02f, -5.227940900e-02f, 3.257759290e-02f, 4.071264340e-02f, 2.310100570e-02f, -1.485592870e-01f, -2.636392410e-02f, -2.776104960e-03f, 3.198886290e-02f, 3.138430420e-02f, -1.728886920e-02f, 2.796205320e-02f, -3.113044240e-02f, -2.328470720e-02f, 3.405940160e-02f, 2.980340460e-02f, -4.444300760e-02f, 5.061877520e-02f, -4.702033100e-02f, -9.933723130e-03f, 6.880229710e-02f, 3.617786240e-02f, 1.916662980e-02f, 1.937897880e-03f, -4.874068310e-03f, -6.887605780e-02f, 1.272125450e-02f, -5.156797540e-02f, 3.956376390e-02f, 1.610017380e-02f, -2.606631260e-02f, -1.107344400e-02f, -7.312068710e-03f, -3.768132250e-02f, -1.511197820e-02f, 1.717428680e-02f, 1.620597210e-03f, 7.943285160e-04f, 3.309260360e-03f, -1.298739950e-02f, 8.041276600e-03f, -6.368455480e-03f, 1.902493300e-03f, -1.025724970e-02f, -7.056956180e-03f, -2.346506810e-03f, -4.142561000e-03f, -8.221088210e-04f, -1.847315110e-03f, 4.394281190e-03f, 7.006326220e-03f, -2.019157070e-02f, 2.555130750e-03f, -1.375923590e-02f, -6.865620610e-03f, 8.485639460e-03f, 1.250205790e-03f, 5.718382080e-03f, 2.571702000e-02f, -1.937010910e-03f, -4.181322640e-03f, -4.275792280e-03f, -2.016503600e-03f, 1.098194810e-02f, -1.107537840e-02f, 1.054341350e-02f, 2.775121950e-03f, 4.328703510e-03f, 7.299555460e-03f, -2.218936100e-03f, -2.461417580e-02f, -2.244166470e-02f, 4.496879410e-03f, 3.574495200e-03f, -5.649023690e-03f, 7.153968330e-03f, 1.628157870e-02f, -1.816988920e-02f, -3.895314180e-03f, -2.650492820e-03f, -8.381410500e-03f, -1.505237260e-02f, -6.025919230e-03f, 5.729716740e-03f, -6.686306090e-03f, -3.464316480e-03f, 8.905126710e-03f, 6.049815570e-03f, -1.863969120e-02f, -1.551104520e-02f, 8.665584960e-03f, 2.011811360e-02f, 4.206053910e-03f, 1.836491380e-02f, -1.277701460e-02f, 1.249995920e-02f, -1.567521320e-02f, -6.580419840e-03f, 2.688091020e-03f, -2.676671000e-02f, 3.074926880e-02f, 1.830092660e-04f, -1.346020730e-03f, -1.473134620e-03f, -3.439542140e-03f, -6.070636680e-03f, 9.598427450e-03f, 8.411860320e-04f, 3.407093140e-02f, 5.876105280e-02f, 8.695422110e-02f, -7.185105230e-02f, 2.054818350e-02f, -7.835739100e-02f, -3.683300220e-03f, 9.598280490e-02f, 2.321080770e-03f, 4.512339460e-02f, -4.630653190e-03f, 3.023434430e-02f, 5.920312180e-02f, -6.222626930e-02f, -2.393397690e-02f, -3.735374290e-02f, -4.209271450e-02f, 9.546411780e-02f, 8.450140800e-02f, -7.307554040e-02f, 6.913047280e-02f, 9.399986260e-02f, -1.301609130e-01f, 5.979616940e-02f, 5.086579550e-02f, 3.975761310e-02f, -1.686178150e-04f, -1.131367090e-01f, -5.801784250e-02f, -3.001273050e-02f, -5.985977500e-02f, 9.299812830e-03f, -6.349561270e-03f, 2.929803920e-03f, 4.283269490e-02f, -1.107259990e-01f, -1.019363700e-01f, 7.629577820e-02f, 4.753596340e-02f, -1.692140590e-03f, -7.487086950e-02f, -1.169612710e-01f, -8.357388520e-02f, -5.213468520e-02f, 8.337756240e-02f, -3.893823180e-02f, -6.718684730e-02f, 6.729898040e-03f, 4.961743210e-02f, 2.095988950e-03f, -2.269468640e-02f, -1.004676150e-01f, -6.217212880e-03f, 3.987247500e-02f, -5.989629780e-02f, 7.999690620e-02f, -8.120594920e-02f, -1.010359750e-01f, -2.185826560e-02f, -6.627475470e-02f, -6.907543540e-02f, -1.682601120e-02f, 8.761975160e-02f, -3.485698250e-02f, -5.931177740e-02f, -1.134020310e-01f, -8.440688990e-02f, -8.944437650e-02f, 2.127025840e-02f, 4.919434900e-03f, -9.502260390e-02f, 3.214129430e-02f, 6.249659230e-03f, 8.793240410e-03f, -6.356990900e-03f, 4.773023070e-03f, 2.197731290e-03f, 2.693114620e-02f, -9.197487500e-03f, 1.881866900e-02f, 7.119570860e-03f, 4.828360110e-04f, 1.666396270e-03f, 9.847327600e-04f, 9.628070510e-03f, 1.484262060e-03f, -4.650365560e-03f, 2.092727460e-02f, -7.880598300e-03f, -1.006511410e-02f, -1.061051850e-03f, -1.195411780e-03f, 1.462975980e-02f, 1.194194890e-02f, 1.596081650e-03f, 1.290466400e-03f, -1.850786620e-02f, 8.077155790e-03f, 2.540150890e-03f, -3.143719960e-02f, -9.184305560e-03f, 7.430398370e-03f, 2.443573440e-02f, 2.489430130e-03f, -7.523607000e-03f, -1.006439050e-02f, -4.575503060e-03f, -1.672906060e-02f, 8.679110550e-03f, -5.649523340e-03f, -6.534637070e-04f, -1.326958000e-02f, 2.563326150e-03f, -1.072741490e-02f, 2.000441590e-02f, -3.056255360e-02f, -5.102613940e-03f, -1.704088650e-04f, 1.105662620e-02f, -1.405288090e-02f, -4.292541180e-03f, -1.244027170e-02f, 7.996378460e-03f, -6.305137180e-03f, -3.199447320e-02f, 4.372524100e-03f, -1.830096170e-02f, -1.899133550e-03f, -1.664788650e-02f, -2.340603620e-02f, 1.279413610e-02f, -9.395590050e-03f, -2.206377500e-02f, 1.162744830e-03f, -1.031069360e-02f, -1.020709150e-02f, 2.459232140e-02f, 3.922431260e-03f, -1.436352640e-02f, -5.401550330e-03f, 3.155207260e-03f, 3.905448830e-03f, -5.759957250e-03f, 3.194879970e-03f, -6.740247370e-03f, 3.677684810e-03f, 5.792247600e-03f, 2.912610580e-02f, -1.497716640e-02f, -2.253412080e-02f, 1.151730210e-02f, -2.161978190e-02f, 5.873369520e-03f, 2.357404490e-02f, -1.472655030e-02f, 5.199096170e-03f, -9.691292500e-05f, 2.117150650e-02f, -2.541643570e-02f, -1.448342580e-02f, -1.692223010e-03f, 1.346278660e-02f, 4.153866320e-03f, -1.629671830e-02f, -1.194786930e-02f, 1.923074570e-02f, 1.454072350e-02f, -2.934979970e-03f, -3.423564880e-02f, -7.726510520e-03f, -1.546061500e-02f, -8.763439020e-03f, 1.206445970e-02f, -7.768096400e-04f, -2.202229760e-02f, 8.585317060e-03f, 5.239480180e-03f, 2.506211590e-02f, -1.854548790e-02f, 2.198095810e-02f, 6.843556650e-03f, -1.337011530e-02f, 5.775168540e-03f, 3.392615120e-03f, 4.654972350e-03f, 2.063882160e-02f, -3.647143390e-02f, -7.359770130e-03f, -1.815693270e-02f, -1.933415980e-02f, 3.872554280e-03f, -1.631229930e-02f, 1.394666820e-02f, -1.830786090e-02f, -2.214844150e-02f, 4.918798800e-03f, -1.864951290e-02f, 1.076316270e-02f, -4.193341360e-03f, -7.664893930e-05f, 1.632205020e-02f, -1.692897080e-02f, 1.773483680e-02f, 3.199227850e-03f, -1.989454960e-02f, -8.320386410e-05f, 1.742527630e-02f, -1.607979090e-02f, 1.807420490e-04f, -1.082556230e-02f, -1.870392450e-02f, -1.620427710e-02f, 4.808277880e-04f, -2.874357440e-02f, -9.760070590e-03f, -1.646454260e-02f, 9.349160640e-02f, 1.916776970e-02f, 5.937808380e-02f, 5.927887560e-02f, -4.423896220e-02f, 3.155725450e-02f, -3.053638710e-02f, -3.233616800e-02f, 6.822043660e-02f, 7.757566120e-02f, 3.066108000e-02f, 2.072840930e-02f, 5.588348020e-03f, -3.481306510e-02f, -4.501945900e-02f, 1.455417370e-02f, 1.148247200e-01f, -1.791494530e-02f, 7.468410580e-02f, -1.143047290e-01f, 3.136830780e-02f, 7.644719630e-02f, 9.705466770e-02f, -1.080764610e-01f, 1.342171570e-03f, -1.169799860e-01f, -3.642659260e-02f, -5.514309180e-02f, 6.773388390e-02f, 1.689939010e-02f, -4.740955680e-02f, -1.072767940e-02f, 1.894554440e-04f, 6.947363170e-02f, 9.335365890e-02f, 2.541443520e-02f, -9.391441940e-03f, -4.816441330e-03f, 1.332514450e-02f, 3.308809180e-02f, 5.314356460e-02f, -7.675506920e-02f, 2.860792910e-02f, -3.739334270e-02f, -4.223655540e-02f, 4.887332670e-03f, -4.739833620e-02f, 5.587119980e-02f, 4.649448770e-02f, -5.391104520e-02f, 2.050294170e-02f, 6.491148470e-02f, -4.563791300e-02f, 4.308824240e-02f, -1.702071730e-02f, -6.017281860e-02f, 2.376827040e-02f, -5.640388280e-02f, -4.907674710e-02f, 8.205924180e-02f, -3.024695810e-02f, -3.601149420e-03f, -5.857136850e-02f, 3.087680670e-04f, 4.243428260e-02f, -9.647132820e-03f, 1.161395530e-01f, 1.836625110e-02f, -1.094018670e-02f, 6.361895050e-02f, -3.412703800e-02f, 2.657623220e-02f, -6.151800510e-03f, 3.051200180e-03f, 1.586767500e-03f, 5.453763530e-03f, -4.585603250e-03f, -1.015453410e-02f, 6.149459160e-03f, -3.303678470e-03f, -1.624912020e-02f, 1.056375260e-02f, -4.223608410e-03f, 1.509490050e-02f, 6.591798730e-04f, 2.828736320e-03f, -1.319679900e-02f, -5.693312270e-03f, 3.067690880e-03f, -1.452257950e-02f, 3.756847930e-03f, -1.654469960e-04f, 1.518624950e-03f, 3.759705000e-03f, 4.662042020e-03f, -1.262885150e-02f, 1.363544450e-02f, 4.195041490e-03f, 5.245063800e-04f, -7.896902030e-03f, 6.546264050e-03f, 5.140579310e-03f, -9.252936580e-03f, 2.503223020e-03f, 5.740579680e-03f, 1.039063740e-02f, 1.055354490e-03f, -6.814608350e-03f, 2.026538180e-02f, -6.670881530e-03f, 1.558184860e-03f, 2.453453140e-03f, 1.482527000e-03f, 2.264337610e-03f, -5.427890460e-03f, 5.724297840e-03f, -1.351505520e-02f, 4.333204120e-03f, 1.261102130e-02f, -1.185467650e-02f, 8.799452330e-04f, -5.824501860e-04f, -1.667423920e-02f, -5.049047060e-03f, -1.944437060e-02f, 5.372496320e-03f, -7.699145940e-03f, 1.277198640e-02f, 9.357281960e-03f, -3.711640140e-03f, 4.826075380e-05f, -1.260688530e-02f, -1.460775030e-03f, -2.417223990e-03f, -4.168688610e-04f, -2.703742360e-03f, 7.684597280e-03f, -2.483776770e-03f, -3.747767540e-03f, 6.719520020e-05f, -1.917875370e-02f, 1.740369830e-03f, 4.814218260e-03f, -8.595623080e-03f, -1.057546310e-02f, -3.713246060e-02f, -1.494697410e-03f, -4.008932040e-02f, -1.132478560e-02f, 4.330763220e-02f, 2.985695380e-02f, -8.634087630e-03f, 6.604812110e-03f, 2.839461900e-02f, 4.169291630e-02f, -2.080449090e-02f, -1.096606400e-01f, 6.650198250e-03f, -3.320214900e-02f, -1.361109600e-02f, 6.756392120e-02f, -5.305519330e-02f, 2.346640270e-02f, -1.998376100e-02f, -6.794738020e-02f, 6.261691450e-02f, 2.407645340e-03f, -1.271175300e-01f, 4.225235430e-02f, -8.751852810e-02f, 1.996352710e-02f, -4.618879410e-02f, -8.777257800e-02f, -7.345647360e-02f, -1.045070440e-01f, -3.175121030e-03f, 3.517579520e-03f, 5.195937680e-02f, -2.518709380e-02f, -1.022016700e-01f, 4.213922100e-02f, -4.784083370e-02f, -3.095800620e-02f, 6.416831170e-02f, -5.570279810e-02f, 5.401430280e-02f, 5.242072050e-02f, 5.409020190e-02f, -5.009608340e-02f, -6.254497170e-02f, 4.774002360e-02f, 1.659253430e-02f, -5.241557580e-02f, 1.680422950e-02f, -3.054052410e-02f, -4.625353590e-02f, -1.435415600e-01f, -2.964433280e-02f, 5.329706890e-02f, 6.394190340e-02f, 5.274569990e-02f, 1.575851350e-03f, -7.270885260e-02f, -3.403375300e-02f, -1.757990010e-02f, -3.013260100e-02f, 4.196297000e-02f, 5.505066370e-02f, -3.300991650e-02f, -3.762878110e-02f, -1.209452280e-02f, -3.725971280e-02f, -1.256201040e-02f, -6.937888240e-05f, 3.729820250e-02f, 3.937772660e-02f, 7.602497190e-02f, -2.174331620e-02f, -7.216134660e-02f, 1.502155050e-02f, -2.350401880e-02f, -3.061035880e-03f, 2.302514020e-02f, -5.464202910e-02f, 1.067690330e-01f, 8.031630510e-02f, -7.523658870e-02f, -5.368289350e-02f, -8.480178560e-02f, -4.040010270e-02f, -8.981132500e-02f, -8.302811530e-02f, -3.254929560e-02f, 1.029427130e-01f, -7.967968290e-02f, 7.552788410e-02f, -7.950298490e-02f, -8.722405140e-02f, 8.746279400e-03f, -2.658636310e-02f, 6.627571580e-02f, -3.760983790e-02f, 5.683261160e-02f, 4.446733740e-02f, 4.734643270e-03f, 2.308693160e-02f, -1.221627670e-01f, -7.491911950e-02f, -2.264486250e-02f, 1.665660930e-02f, 3.820230070e-02f, -1.070801760e-01f, -2.940891310e-03f, -2.297766130e-02f, 5.457356940e-02f, -4.200731220e-02f, -1.028180570e-01f, -2.246777710e-02f, -9.937531500e-02f, 3.901908920e-02f, -1.416019220e-04f, 3.235833250e-03f, 3.430996460e-02f, -1.833863180e-02f, 1.198472550e-02f, -2.415308920e-02f, -1.073888690e-01f, -5.136030910e-02f, 3.544195320e-03f, -8.617561310e-02f, -3.190105780e-02f, 2.591870540e-02f, 6.876530500e-02f, -1.301239880e-01f, 2.196011510e-02f, -8.035627750e-02f, 3.433564680e-02f, -8.925791080e-02f, -1.337920870e-02f, 1.070116830e-01f, -7.453271740e-02f, -5.693124610e-02f, -2.762753330e-02f, 6.385818870e-02f, -4.664453860e-02f, 7.969723080e-03f, -3.729242830e-02f, 4.892576490e-02f, -1.054746730e-01f, 5.705189330e-02f, -4.533763970e-02f, -1.142220870e-01f, 6.967402990e-02f, -3.907947990e-02f, -4.242573860e-03f, 8.551535010e-02f, 5.544678870e-02f, -5.049765860e-02f, 5.442230400e-02f, 8.159818120e-03f, 5.853121360e-02f, -1.526079330e-02f, -7.990914580e-02f, -3.621587900e-02f, 2.314633130e-02f, -5.010793360e-02f, -5.105662720e-02f, 6.684862820e-02f, 4.662714150e-02f, -5.343849960e-02f, 8.343804620e-03f, 7.384480540e-02f, 1.067470760e-02f, 6.322884930e-03f, 7.304606590e-02f, -4.020178690e-03f, -3.499810030e-02f, 8.785020560e-03f, -1.188478100e-01f, 8.972347520e-02f, -6.295576690e-02f, 6.926556680e-02f, -4.972169920e-02f, -9.444811190e-02f, 3.186284010e-02f, 4.431521150e-02f, -4.607714710e-02f, -5.360315740e-02f, 1.369057780e-02f, 6.606110190e-02f, -3.289750220e-02f, -4.352164270e-02f, 5.922163280e-02f, -6.926828530e-03f, -5.825670060e-02f, -1.335750220e-01f, -6.190107760e-02f, -2.056944930e-02f, 8.754327890e-02f, 8.745262770e-02f, -6.509004530e-02f, 8.645309130e-03f, -3.025268200e-02f, -2.305856720e-02f, -3.325072680e-02f, -1.079405550e-01f, 7.097267360e-02f, -6.076879050e-02f, -4.250729460e-02f, 3.851259500e-02f, -2.907145070e-03f, -1.157530250e-01f, 1.187758450e-01f, -6.238331650e-02f, 5.547855420e-02f, 5.965161320e-02f, -4.252360760e-02f, 6.537888940e-02f, 4.363758490e-02f, -2.973264640e-02f, -7.984224700e-02f, 1.823811980e-02f, -4.777196050e-02f, 2.378421840e-02f, 2.699089240e-02f, -6.603366230e-03f, -8.735605320e-02f, 6.158057230e-02f, 8.209259060e-02f, 2.485178780e-02f, 7.449243220e-02f, 8.980029070e-02f, 3.916300090e-02f, 3.610699250e-02f, 3.215198590e-02f, -4.889966920e-03f, -7.196120170e-02f, 4.450671370e-02f, -6.961235400e-02f, -2.920238670e-02f, -6.651058050e-02f, -1.600341500e-02f, 7.213018090e-02f, -2.633380140e-02f, 1.195788620e-03f, 4.056001450e-02f, -9.012329580e-02f, -4.349691420e-02f, 1.501317420e-02f, 5.290966110e-02f, 1.797597300e-02f, 1.093252840e-02f, -2.525902350e-02f, 3.405093030e-02f, 1.400703040e-01f, -5.092096050e-03f, -6.782703850e-02f, -6.073635820e-02f, 9.315193440e-02f, 2.721302770e-02f, -6.020350380e-02f, -8.941255510e-02f, -8.204567710e-04f, 8.971215780e-02f, -4.005473110e-02f, -3.589928150e-02f, 3.653849290e-02f, -1.045911910e-01f, 1.392766270e-02f, -8.264072980e-02f, 3.542393820e-02f, -1.697903310e-02f, -1.226194200e-01f, -7.756485790e-02f, -5.234055590e-02f, 6.506388630e-02f, 2.515440340e-03f, -1.360805010e-03f, -1.496756220e-03f, -8.158293360e-02f, -7.326319810e-02f, -1.049394460e-01f, -1.030391010e-01f, 2.844137510e-02f, -2.615141310e-02f, 4.177790140e-02f, -3.762819250e-02f, -3.041850590e-02f, -2.282822130e-02f, -5.858293920e-02f, 7.521296390e-03f, -7.690020650e-02f, 1.389062220e-02f, -1.432170530e-02f, 7.555032520e-02f, 5.925319720e-02f, 5.514992030e-02f, 1.195216920e-02f, 6.451793760e-02f, -1.713154650e-02f, 1.064384640e-02f, -8.495741330e-02f, 1.163089460e-02f, -5.493977670e-02f, -7.732970990e-04f, 1.782457720e-02f, 4.756804560e-02f, -1.063278240e-01f, 9.195917090e-02f, -1.326725070e-02f, -8.236746490e-02f, -3.957165780e-02f, -9.388838710e-02f, 3.445937860e-02f, 1.347135660e-02f, -1.971424930e-02f, 4.763204980e-02f, 3.659367190e-02f, -9.483338890e-02f, -3.444088620e-02f, 8.241646920e-03f, 3.920214620e-02f, -9.886153780e-02f, -4.068015520e-02f, 1.151947490e-02f, 6.434831770e-02f, -1.808760500e-02f, -1.332125070e-01f, 4.531602560e-02f, -4.786712680e-02f, -8.720247450e-02f, 8.141790330e-02f, -3.729575780e-03f, 2.599403080e-02f, -1.218503040e-01f, 1.429578200e-02f, 1.512822230e-03f, 7.580232810e-03f, 3.240185790e-03f, -1.059920340e-01f, 9.500075130e-03f, -2.471052300e-02f, 4.326723890e-02f, -2.644315130e-03f, -5.064002050e-02f, 4.226076880e-03f, -2.008426000e-02f, -5.295986680e-02f, 1.945471760e-02f, 5.423448050e-03f, 6.505519900e-02f, 1.278420560e-03f, 3.021484050e-02f, 2.192058790e-02f, -1.082367900e-01f, 5.122824760e-02f, -6.033473830e-02f, -7.234690340e-02f, -8.221006020e-03f, -1.023343300e-02f, 9.663460770e-03f, -1.830783670e-02f, -7.308327410e-02f, 1.914943200e-02f, -1.388495790e-02f, 4.507397300e-03f, -4.745961630e-03f, 1.088658910e-02f, -4.607943120e-04f, -7.850617170e-03f, -4.473775160e-03f, -7.650097830e-03f, 7.803440680e-04f, 1.727735970e-03f, 1.971908200e-04f, 8.687074300e-03f, -1.355057680e-02f, -1.463931520e-02f, -1.175543570e-02f, -1.457824930e-02f, -1.725387760e-03f, 5.564487540e-03f, -6.052170410e-03f, 2.400815950e-03f, -1.041438900e-02f, -3.152094550e-03f, 1.812504790e-02f, -2.067571690e-02f, -9.707313960e-03f, 1.218534910e-02f, -9.013974110e-03f, -1.548850540e-02f, -7.135542100e-03f, -3.684150520e-03f, 1.247864500e-02f, 3.246928570e-03f, 1.802188690e-03f, -1.087612750e-02f, -1.198898720e-02f, 1.440633830e-02f, -3.462955360e-02f, -7.269378750e-03f, -1.414903160e-02f, -3.021654670e-03f, -1.682068590e-02f, -1.486363450e-02f, 1.259569540e-02f, 1.033541050e-03f, -5.838918030e-03f, -9.953216640e-03f, 2.578163750e-03f, -2.402649260e-02f, -5.726415200e-03f, 1.826379630e-02f, 8.227371140e-04f, 1.194848770e-02f, -3.392995340e-03f, -4.306450020e-03f, 5.823203360e-03f, -3.978196530e-03f, 9.042305870e-03f, 9.408248010e-04f, -6.555193570e-03f, 2.555409210e-03f, 1.305344050e-03f, -1.934952800e-03f, 1.306893770e-02f, 6.937986230e-03f, 1.237088160e-02f, 5.957582030e-03f, 3.387580160e-03f, -5.579318850e-03f, -5.525242070e-03f, 5.696256650e-03f, -9.491473430e-03f, 3.777184060e-03f, -6.750410050e-02f, -6.403458120e-02f, 5.011777950e-02f, -5.924245340e-02f, -9.889760610e-02f, -5.035699900e-02f, 2.858127650e-02f, -6.402150540e-02f, 7.584299150e-02f, 3.565975280e-02f, 8.219216010e-02f, 7.594560830e-02f, -3.183827550e-02f, 1.052033010e-01f, 6.758369040e-03f, -4.320388660e-02f, 1.438569560e-02f, -2.606000380e-02f, 1.297377700e-02f, -5.154519160e-02f, 8.516035220e-02f, -2.368670140e-02f, -4.037526990e-02f, -2.253700790e-02f, 7.731800430e-03f, -1.281127930e-01f, -7.633601870e-02f, -8.191356060e-02f, -6.472271680e-02f, 7.516030970e-02f, 1.952219380e-02f, 5.568881330e-02f, -3.510215550e-03f, 2.447395030e-02f, -5.019955340e-02f, 6.740024680e-02f, 2.085572110e-02f, -2.362382600e-02f, -3.201024140e-03f, 6.427627060e-02f, -3.087994270e-02f, 3.378564490e-02f, -1.292181310e-01f, -6.846638020e-02f, 5.624730890e-02f, -1.040458310e-02f, -1.771130600e-02f, 1.292385440e-02f, 5.129141360e-02f, -6.755871330e-02f, 5.045466500e-02f, 2.228629220e-02f, 2.156064290e-02f, -3.748577460e-02f, 6.074202430e-02f, 7.118470220e-02f, 5.216095600e-02f, 7.670179000e-02f, -1.284244840e-02f, 9.490485300e-03f, 8.742820360e-04f, 5.464325850e-02f, -2.855364230e-02f, 8.690308030e-02f, -1.368800180e-02f, -1.822369730e-02f, -1.363911580e-04f, -5.529937520e-02f, -9.661917390e-02f, -9.419068690e-02f, 4.619525000e-02f, -9.631601160e-03f, 9.221744720e-03f, 4.792104660e-02f, 5.041856690e-02f, -2.203401920e-02f, -8.909110720e-02f, -1.798790690e-02f, -1.900140570e-02f, 3.052427990e-02f, -5.941502750e-02f, -1.160899770e-04f, -1.135899500e-02f, 4.224823040e-02f, -1.014142260e-01f, 4.287429900e-02f, -2.767243980e-02f, -9.204205120e-02f, 9.672597790e-02f, 1.182388290e-01f, 2.947967500e-02f, -4.248342290e-02f, -2.577223630e-02f, -2.681736830e-02f, 5.842117220e-02f, -9.728826580e-02f, 6.595037880e-03f, 7.585672200e-03f, -4.445122930e-02f, -8.608666800e-02f, -4.499509930e-02f, 5.596458540e-02f, -1.033934580e-01f, 1.528337040e-02f, -3.538186480e-02f, -3.593059260e-02f, -3.682850670e-02f, 3.771745790e-02f, 8.692713820e-02f, 2.982499450e-02f, -1.452873000e-03f, -1.340846440e-02f, -1.238210690e-02f, -1.177408840e-01f, -1.118505300e-01f, -7.077300550e-02f, 1.049700850e-02f, 9.003186590e-03f, 1.093639710e-02f, 3.330996630e-02f, -1.968565020e-02f, -1.300439240e-03f, 5.455019700e-02f, 9.215208140e-02f, -5.520984900e-02f, -2.048668270e-02f, 1.310562440e-02f, 3.417908400e-02f, -7.243402300e-02f, 7.644475250e-02f, -1.252042350e-01f, -5.220492930e-02f, 6.017051640e-02f, 1.116992440e-02f, -1.043058840e-02f, 7.285329690e-02f, -4.101597890e-02f, -6.204085800e-02f, 5.808488650e-02f, -4.596605520e-02f, -9.093290560e-02f, 7.382099050e-03f, -1.140857120e-01f, 5.512220790e-02f, -5.733303730e-02f, -5.707166720e-02f, -9.241356700e-02f, -7.165544480e-02f, 3.767669950e-02f, 3.445437550e-02f, -6.781280040e-02f, 1.809024440e-02f, 2.103622440e-02f, -5.148289350e-02f, -5.986116080e-02f, 6.471269580e-02f, 4.685218630e-02f, -9.649417540e-02f, -3.913252800e-02f, 5.899873750e-02f, 2.413193510e-02f, 4.600629580e-02f, 7.817540310e-02f, -7.264734800e-02f, 4.144783690e-02f, -7.792953400e-03f, 9.386324880e-02f, -2.805756400e-03f, -8.334015310e-02f, 1.251833140e-02f, -7.599399540e-04f, -4.988789560e-03f, 6.073112130e-03f, -4.580472410e-02f, -1.029605340e-01f, 1.337693720e-02f, 2.949464320e-02f, 6.517451260e-02f, 7.645130160e-02f, -9.775630380e-02f, 4.925756530e-02f, -7.302011550e-02f, 4.466167460e-02f, 6.366776670e-02f, -6.136707590e-02f, -7.266110180e-02f, 1.958422130e-03f, -3.935853760e-02f, 2.437804450e-02f, -8.067258440e-02f, -9.779789490e-03f, 1.169063800e-02f, 2.465314230e-02f, 3.831083330e-02f, 3.261581440e-02f, 1.987444050e-02f, -5.829114840e-02f, 3.684771060e-02f, 2.086026590e-03f, 6.010776760e-02f, 2.710307020e-02f, -3.823691980e-02f, 7.807249200e-03f, -5.948388950e-02f, 5.809272830e-02f, 5.147991330e-02f, 7.338644560e-02f, -1.932404560e-02f, -8.259711410e-02f, 1.993446420e-02f, -4.463407400e-02f, 3.119093740e-02f, -7.705028360e-02f, 2.649277820e-02f, -8.030968900e-02f, 4.256069660e-02f, -2.144076860e-03f, -1.961539870e-02f, -6.017879400e-02f, -8.499871190e-02f, 1.804429290e-02f, -6.932782380e-02f, 6.314446030e-02f, -2.013844670e-03f, -2.229116110e-02f, 1.224754290e-02f, -3.204297740e-03f, 8.740361770e-02f, -1.078700940e-01f, -2.417570680e-03f, -3.104708900e-02f, -5.486811320e-02f, 6.343155350e-02f, 5.884756890e-02f, -4.198191310e-02f, 6.216414270e-02f, 4.084967450e-02f, -5.811433490e-02f, -6.324527410e-02f, -2.153063750e-02f, 2.015234720e-02f, 1.254137230e-02f, -3.543242440e-02f, -1.278998050e-02f, -5.496763810e-02f, 2.929206750e-02f, -1.123913230e-01f, -3.241580720e-02f, 2.502631770e-02f, 7.196042690e-03f, -3.729771080e-02f, -1.157829090e-01f, 6.720893830e-02f, 1.234040710e-03f, -5.689379200e-02f, 4.868216440e-02f, -2.671681720e-02f, -2.263295460e-02f, -2.577630620e-02f, 1.726116870e-03f, 7.145880160e-02f, 3.126265480e-02f, -4.189999770e-02f, -7.671684770e-02f, -4.951588060e-02f, 6.709214300e-02f, -7.929007710e-02f, 4.290061070e-02f, 4.755875840e-02f, 5.818587170e-02f, 1.026133820e-02f, 1.002100300e-02f, 1.555227490e-02f, 9.862876500e-03f, 4.568799210e-02f, -3.108057940e-02f, 4.501246660e-02f, -4.051246120e-02f, 9.302363730e-03f, -1.016085620e-03f, 4.879657640e-03f, 2.603572420e-02f, -2.310951990e-02f, -9.102763980e-02f, -8.491606260e-02f, 6.348653880e-02f, 7.054833230e-03f, -4.204545920e-02f, -2.504756440e-03f, 9.260708830e-02f, -6.350658830e-02f, 1.778257450e-02f, -2.227705530e-02f, -1.044532060e-01f, -1.240415680e-02f, 1.236635380e-03f, 1.315528600e-01f, 1.157087160e-01f, 1.055876840e-01f, -2.066341230e-02f, 6.675723940e-02f, 4.009045660e-02f, 3.695050630e-02f, 5.934124440e-02f, -4.853968970e-03f, 7.304037360e-02f, 5.301315340e-02f, -4.234734550e-02f, 1.044462100e-01f, 2.054028030e-02f, 9.441754220e-02f, -2.126008090e-02f, 3.197930010e-02f, -5.021950230e-03f, 1.477684360e-02f, 8.361178630e-02f, -1.752212880e-03f, -5.869280170e-02f, 1.266498120e-02f, 7.296810300e-02f, 1.076410260e-01f, -9.115619960e-02f, 2.617827800e-02f, 5.130517110e-02f, 8.805988730e-02f, 2.227874660e-02f, 6.575590370e-02f, 8.726488050e-02f, -3.976149860e-02f, 3.251224380e-02f, 1.538041330e-02f, 1.115883960e-01f, 6.628402320e-02f, -7.579871270e-02f, 7.235629110e-02f, -7.724394650e-02f, -5.615502600e-02f, -3.008293360e-02f, 4.944193740e-02f, 1.146917720e-01f, -9.570690980e-02f, -9.649175400e-02f, 6.455369760e-03f, -2.757529730e-02f, 8.787991110e-02f, -1.333497560e-02f, -5.388842520e-02f, -9.720938650e-02f, 2.853562500e-02f, -1.139568540e-01f, -2.944491240e-02f, -8.528885240e-02f, 6.431532650e-02f, -5.881119520e-03f, 5.948982390e-02f, 1.369442210e-03f, -3.093773870e-02f, 5.143775790e-02f, 4.129150880e-02f, -4.513653740e-02f, 4.660293460e-02f, -1.311193590e-02f, 3.048400860e-03f, -4.031856360e-02f, 2.125863730e-02f, -3.595509100e-03f, -1.930328270e-02f, 8.895386760e-02f, 4.360536860e-02f, -1.989728210e-02f, 1.556164400e-02f, 1.181300820e-02f, 1.070687360e-02f, 3.663434460e-02f, -6.787735970e-03f, 3.764971720e-02f, 1.207027580e-03f, 6.543838980e-02f, 5.416778480e-02f, 2.983797110e-03f, 4.269439350e-02f, -2.999742520e-03f, 6.588730210e-02f, -6.663453580e-02f, -8.503024280e-02f, -2.597186900e-02f, 4.674541210e-02f, -1.333373600e-02f, -3.284350410e-02f, 1.668646190e-02f, 1.102151810e-02f, 8.215529840e-03f, -8.488332850e-03f, 3.584213180e-02f, 3.854766490e-02f, -4.725159330e-02f, 3.927887600e-02f, 1.789260660e-02f, 1.413589810e-02f, 1.536979710e-02f, -6.781131030e-03f, -6.031898040e-02f, -3.399583320e-02f, -1.413247270e-02f, 5.692190300e-02f, -1.970797780e-02f, -1.844213900e-02f, -3.690427910e-02f, 2.077277940e-02f, 5.464940520e-02f, 3.230276700e-02f, 5.893416330e-02f, -5.317657810e-02f, 3.090428190e-02f, 1.004703810e-02f, -2.462555840e-02f, -1.693921720e-02f, -1.482943910e-02f, -2.779943120e-02f, 4.714009910e-02f, -2.822786010e-02f, 6.845096120e-03f, -2.637546320e-02f, 5.269756910e-02f, 9.068638080e-02f, 1.048046820e-02f, 5.739004160e-02f, 1.307038220e-02f, -3.536771240e-02f, -3.865052760e-02f, -8.814654310e-03f, 2.222727050e-03f, 3.358739610e-02f, -6.252390890e-02f, 3.698670120e-02f, -8.689314870e-02f, -1.501055060e-02f, -5.861650780e-02f, -2.416427250e-02f, 4.641232640e-02f, 3.503320370e-02f, -1.755780170e-02f, -6.025808300e-02f, -3.064695930e-02f, -6.634514780e-02f, 4.593458030e-03f, -4.993245940e-03f, 6.931788470e-02f, 3.650920090e-02f, 7.297207420e-02f, 1.828991440e-02f, -8.968985080e-02f, -6.594187020e-02f, 4.744030910e-02f, 1.672532040e-02f, -9.368625280e-02f, 1.870413870e-02f, 2.362247370e-02f, -9.096537720e-03f, 2.570001410e-02f, -6.627992540e-02f, 1.603790750e-02f, -9.352181850e-02f, -6.654202590e-04f, 7.220394910e-03f, 5.612415730e-03f, 2.248795890e-02f, -8.662533010e-02f, 9.740446110e-04f, 2.087618220e-02f, 1.740194670e-02f, 4.648420210e-02f, -5.629806970e-02f, -7.168630510e-02f, 5.245159570e-02f, -6.513865290e-02f, -5.685075740e-02f, 1.118590870e-02f, 1.212567840e-02f, 1.449225100e-02f, -1.463409890e-02f, 5.260953680e-02f, -1.314965910e-02f, 2.893036790e-02f, -1.153083370e-01f, -7.561444490e-02f, -3.769791500e-02f, -1.744323780e-02f, 3.897668420e-02f, 4.287293550e-02f, 2.497216130e-02f, 2.824442460e-02f, -7.042652370e-02f, 2.075283420e-02f, -3.611252080e-02f, 1.307575680e-02f, 2.100596020e-02f, 4.054420440e-02f, 7.272515450e-02f, -8.923714980e-03f, -1.109678450e-01f, -3.818826750e-02f, 1.564488190e-02f, -1.821983610e-02f, -3.448173030e-02f, -6.665344540e-02f, 7.507108900e-02f, 3.496067600e-02f, -3.452915700e-02f, 3.964212540e-02f, -1.092627370e-02f, -3.994664290e-04f, -1.796404270e-02f, 6.558893620e-02f, -7.584103940e-02f, 9.343128650e-02f, 5.687533690e-02f, -3.122398630e-02f, 7.758685940e-02f, 1.658568530e-02f, 4.021731020e-02f, 5.829363320e-02f, -2.315190430e-02f, 5.436555300e-02f, 7.040207090e-02f, -1.059519030e-02f, 1.809791290e-02f, -3.305203100e-02f, -7.426130030e-02f, -1.014094430e-01f, -1.758471880e-02f, -6.276833270e-02f, 8.551117030e-03f, 4.116608300e-03f, 4.754269870e-02f, 1.552953760e-02f, 1.354418320e-02f, -1.121488400e-02f, -3.560832520e-02f, -6.320170310e-02f, 3.405409310e-02f, 3.737077860e-02f, 6.015113000e-02f, 2.656390520e-02f, -7.799597220e-04f, -1.051861050e-01f, -1.311507670e-01f, 4.989057410e-02f, -5.312734750e-03f, -7.039956000e-02f, 6.846664100e-02f, 3.465235610e-02f, 9.094434790e-03f, 7.935860190e-03f, -1.652218960e-02f, -2.471181190e-02f, -1.079611030e-01f, -4.963681100e-02f, -8.761235320e-02f, -7.866801690e-03f, 6.813056020e-02f, 6.035262720e-03f, -1.524391860e-02f, -1.618172230e-02f, -6.848281620e-02f, -3.211802990e-02f, -1.160067130e-02f, 8.288823070e-03f, 3.559383000e-02f, -7.711146610e-04f, 9.119239440e-02f, -1.614980770e-02f, 7.080442460e-02f, 5.978660290e-02f, -1.219506100e-02f, -1.125441340e-01f, -1.692260430e-02f, 2.047846090e-02f, 2.754673360e-03f, 1.421995810e-03f, 1.014705000e-02f, -5.508972330e-02f, -5.646739900e-02f, -2.304907330e-02f, -7.331728190e-02f, 2.568046380e-02f, 2.094681560e-02f, -2.698316800e-02f, -3.065431300e-02f, -6.896635890e-02f, -5.631264670e-02f, -3.515816110e-02f, 3.683204950e-02f, -1.184827280e-02f, -4.711083700e-02f, 8.872012790e-02f, 2.943376450e-02f, 1.309681240e-01f, -9.520999340e-02f, -7.358352840e-02f, -9.690078340e-02f, -1.099209110e-01f, 1.742640630e-03f, -1.915191490e-02f, 2.771873030e-02f, -6.636319310e-02f, 2.024152320e-02f, 1.047039480e-01f, 5.702332780e-02f, 4.516961050e-02f, -1.003007220e-01f, -2.105384320e-02f, 5.677628140e-02f, 4.595592990e-02f, -8.312034600e-02f, -8.102866260e-02f, 6.778860840e-02f, -4.732509330e-02f, -1.378211830e-01f, 4.522397000e-02f, -8.681481330e-02f, -6.783484670e-02f, 1.064444110e-01f, -5.992614110e-02f, 8.035650840e-02f, -1.220924180e-01f, -8.397447310e-02f, -4.153015090e-02f, -1.136022730e-01f, -3.919486700e-02f, -4.477810490e-02f, 2.756465230e-02f, 3.019997660e-02f, 5.214875190e-02f, 8.152988550e-02f, -7.274553170e-02f, 3.826193140e-02f, 5.919741470e-02f, 9.327713400e-02f, 7.546816770e-02f, -5.000288410e-02f, 7.942777120e-02f, -1.812753270e-02f, -3.680052980e-02f, -7.544260470e-02f, 2.494442090e-02f, -6.525316830e-02f, -7.011006030e-02f, 2.544368380e-03f, -4.659275710e-02f, -1.939855630e-03f, -2.560636960e-02f, -5.955144760e-02f, 8.000096670e-02f, 7.002354600e-03f, 2.879568930e-02f, 6.001748520e-02f, -3.232370690e-02f, 1.504220070e-02f, 3.673963620e-02f, 2.703730950e-03f, 6.560955200e-02f, 2.376675230e-02f, 1.491844560e-02f, 3.154399250e-02f, 4.873479900e-02f, -5.754026030e-02f, 2.968420270e-02f, 7.059209790e-02f, -3.657703100e-02f, 5.653941260e-02f, -7.931196690e-02f, -5.187281220e-02f, -1.242536900e-01f, 2.793631570e-05f, 4.187766840e-02f, 7.693760840e-02f, -4.385789860e-02f, -5.921582690e-03f, -5.196064340e-02f, -1.460430400e-02f, 6.219430270e-02f, -8.228149960e-04f, -3.502302620e-02f, 7.878120240e-02f, 1.667459120e-02f, 3.626858440e-02f, -4.144972190e-02f, 5.953804780e-02f, -4.473480950e-02f, 3.624233600e-02f, 1.701092720e-02f, 4.036764800e-02f, 3.746863450e-02f, 3.886606920e-02f, -3.688030320e-02f, 9.483160820e-02f, 1.846564000e-02f, -5.132296310e-02f, -6.190897150e-02f, -1.257887780e-01f, 6.715028730e-02f, -1.306249390e-02f, -9.163272570e-03f, 4.997421430e-02f, -1.004413810e-01f, -1.846125160e-02f, -4.444899500e-03f, -6.594407560e-02f, -6.424586290e-03f, 2.065492240e-02f, 2.460218410e-02f, 2.481151560e-02f, -7.241164890e-02f, 7.814378290e-02f, 5.101552230e-02f, -6.068711730e-02f, -3.887577730e-02f, -1.003053930e-01f, 4.645469780e-02f, 4.536941650e-03f, 2.104874470e-03f, 5.250965710e-03f, 1.894043200e-02f, 1.253231340e-02f, 4.608618100e-03f, 1.374470190e-03f, 6.113942710e-03f, -1.601165350e-02f, -4.269224130e-03f, 1.280128260e-03f, 1.638310280e-05f, -3.647045470e-03f, 1.033874320e-02f, 6.070686970e-03f, -2.039023680e-02f, 2.152009870e-02f, -1.056763530e-02f, 7.871773090e-03f, 1.301268770e-02f, -1.253799630e-02f, -5.098645110e-03f, 1.347997510e-02f, -3.504763920e-02f, 2.058630440e-02f, -2.278024890e-02f, 6.523218940e-03f, -8.512055500e-04f, -1.814504530e-02f, -8.139642890e-03f, 1.100690760e-02f, 7.448677900e-03f, 7.232141220e-03f, 2.587534860e-02f, 2.324487080e-03f, -3.348702190e-02f, 2.128628640e-02f, 9.906689630e-03f, 9.031280870e-03f, -1.161278230e-02f, -5.766237150e-03f, 3.967301450e-03f, -1.843701490e-02f, 5.909244530e-03f, 2.126166780e-02f, -4.263788460e-03f, -2.320089140e-03f, 1.049080030e-02f, 8.153562430e-03f, 3.285841640e-02f, 1.113670690e-02f, -3.932605030e-03f, -1.542422450e-03f, -9.298962540e-03f, -2.475743410e-03f, -8.291756730e-03f, -1.065029860e-02f, -1.290922870e-03f, -8.407809770e-03f, -1.333589670e-03f, 1.486523540e-02f, -9.621926580e-03f, -5.041998810e-03f, 1.733000760e-02f, 2.173592710e-02f, 2.272083800e-02f, 9.532510300e-03f, -2.669256880e-03f, -1.969217700e-02f, 1.400656350e-02f, 6.101508620e-03f, 4.282136450e-03f, 3.057739140e-02f, 7.051556560e-02f, 2.096462810e-02f, -5.503299090e-02f, -7.394695280e-02f, -5.627139290e-02f, -2.866443990e-02f, -1.957429950e-02f, 1.117829820e-03f, -3.542771940e-02f, -1.866468600e-02f, -1.126735940e-02f, 6.040361520e-02f, 4.090140010e-02f, 3.008316830e-02f, 5.258221180e-02f, 1.266980640e-02f, 3.588072210e-02f, 5.759072300e-02f, -7.409788670e-02f, -7.567727570e-02f, 7.523057870e-04f, 8.143936840e-02f, -4.713522640e-02f, -8.241386710e-02f, -7.770957790e-02f, 3.624174740e-02f, 6.948973520e-03f, -3.372074290e-02f, -4.609811310e-02f, -1.272472440e-01f, 6.893817340e-02f, 4.879166190e-02f, -2.836691590e-02f, 6.701263780e-02f, 2.359134520e-02f, 2.449755740e-02f, -4.285828020e-02f, -3.747918830e-02f, 9.760525070e-02f, -6.887414960e-03f, -1.121604220e-01f, -1.645700260e-02f, -1.287761800e-02f, 6.530049440e-02f, 5.222558600e-02f, -4.233560340e-02f, -3.738943490e-04f, -8.455739170e-02f, 1.163140130e-02f, 9.782485660e-03f, 9.967666860e-02f, -9.183922410e-02f, 1.770531760e-02f, 3.568830710e-02f, -9.447020480e-03f, -1.602539420e-02f, -1.489944850e-02f, 7.701897620e-02f, 2.035164270e-02f, -1.303407100e-01f, -5.831335480e-02f, -1.996122860e-02f, -8.375497900e-02f, -6.897225230e-02f, -5.251763850e-03f, 6.539419290e-03f, -9.186737240e-02f, 2.564862180e-02f, 1.936211620e-02f, -7.276439670e-02f, 7.508188490e-02f, 1.333192270e-02f, -1.996110380e-02f, 3.100135950e-04f, -1.174290200e-02f, -7.787670010e-03f, -3.878999130e-02f, 2.622916600e-03f, -6.881582090e-03f, -2.165666410e-02f, -8.529450740e-03f, -6.028471980e-04f, -7.873243650e-03f, -3.769553730e-03f, -3.882716970e-02f, -3.398998830e-02f, -1.101352930e-02f, 1.437676700e-02f, 1.535116040e-02f, 2.676285240e-02f, 2.190735750e-02f, 2.387195130e-03f, 1.189898230e-02f, -2.489160560e-02f, -4.969908390e-03f, -3.219307210e-02f, -1.610019800e-02f, -7.395075170e-03f, 1.499338080e-03f, -6.820787680e-03f, 4.139372150e-03f, 9.690553880e-03f, 4.734461250e-04f, -9.554841560e-03f, 1.634806580e-02f, -2.928995710e-02f, -1.181640380e-02f, 2.202944090e-02f, 2.598412100e-03f, -2.595753180e-03f, 5.331284370e-03f, 2.474005570e-03f, -2.915637570e-02f, -4.713109510e-02f, -4.387912810e-03f, -7.152609990e-03f, 1.558885630e-02f, 1.222712920e-02f, 2.332840300e-02f, -8.027326310e-03f, 3.192725780e-02f, 1.587333530e-02f, 3.891029950e-02f, 3.835920990e-02f, -1.836343850e-02f, -2.343183380e-02f, 1.841039770e-02f, -1.473135780e-02f, 6.429838950e-03f, -2.796138080e-02f, -2.256599070e-02f, -1.121147910e-02f, 7.672642820e-04f, -1.290403960e-02f, -6.465774960e-03f, 1.859179510e-02f, 2.576556760e-03f, -1.809018480e-02f, 4.895777910e-03f, 2.270001550e-02f, 2.691347150e-03f, -1.266096070e-02f, -8.132581600e-03f, -5.769402910e-02f, 2.992946280e-02f, -5.980952080e-02f, -1.119058580e-01f, -3.714128580e-02f, -1.047018100e-01f, 2.592433240e-03f, 3.486038740e-02f, -4.705131430e-02f, 4.188387470e-02f, -5.130012710e-02f, -6.873229890e-02f, 4.536505790e-02f, 4.636928070e-02f, 4.842945930e-02f, -1.106528490e-01f, -9.557203950e-02f, -5.610239230e-03f, -3.712116180e-02f, -8.333765710e-02f, 1.005749550e-01f, -9.029099710e-03f, -3.250823540e-02f, 4.272661360e-02f, -8.335743090e-03f, 4.238140210e-02f, -5.590404570e-02f, -7.990151640e-02f, 4.540379350e-02f, 2.318247220e-02f, 6.670227740e-04f, 8.043630420e-02f, -9.211813650e-02f, 3.636584800e-02f, 2.283896690e-02f, 1.610850100e-03f, 9.072269500e-02f, 5.190803480e-02f, -2.101296750e-02f, 9.835942830e-02f, -3.466834130e-02f, -1.431008730e-01f, -2.167304610e-02f, -1.039692160e-01f, 3.844761060e-03f, -2.684065330e-02f, 2.682146430e-02f, -4.702115430e-02f, -2.862313760e-02f, -6.604527680e-02f, -1.075682640e-01f, 8.394882080e-03f, 8.579054470e-02f, -4.443504290e-02f, -8.267171680e-02f, 1.103337850e-01f, 1.641791310e-02f, -3.181001920e-02f, -4.063846170e-02f, -3.551620240e-02f, 6.947022680e-02f, 2.682336230e-02f, 6.337320060e-02f, 2.459818120e-02f, 2.142680440e-02f, -8.473952850e-02f, 9.371133150e-02f, 1.521540530e-02f, -1.167665200e-01f, 5.855803190e-02f, 2.878864850e-02f, -3.468368200e-02f, 1.439056590e-03f, -1.108761580e-01f, 3.600568320e-02f, -8.609076580e-02f, 5.763623860e-02f, 3.084846960e-02f, 2.059207110e-02f, 1.956906170e-02f, -7.052889460e-02f, -2.247317460e-03f, 2.466315220e-02f, 3.339234370e-02f, -2.624854450e-02f, -4.681582380e-02f, 4.032096640e-02f, -9.158464140e-03f, 9.281788020e-02f, 5.370423570e-02f, 4.562186820e-02f, -1.940573190e-02f, -2.470570150e-03f, 1.269782890e-02f, -6.006495650e-02f, 3.553896400e-02f, -4.096123200e-02f, -2.727251310e-02f, -3.831221540e-02f, -3.986033420e-02f, 3.789592530e-02f, -1.653930360e-02f, 1.155880000e-02f, 4.726429660e-02f, -7.561837140e-02f, -2.982119100e-02f, -5.831193550e-02f, -5.797891320e-02f, 8.415824260e-04f, -6.193191930e-02f, 6.302639840e-02f, -5.646134910e-02f, 1.524912010e-02f, -6.050788610e-02f, -1.227947700e-01f, -9.356509890e-03f, -4.500087350e-02f, 8.646041890e-02f, 2.331018260e-02f, 1.454230510e-04f, -6.484041360e-02f, 6.662184750e-02f, 2.285414000e-02f, -3.280835600e-02f, 4.992020500e-02f, 8.260767900e-02f, -7.853575790e-02f, -8.851097520e-02f, 9.657342730e-02f, -4.047452290e-02f, -8.148329700e-02f, 1.237742420e-02f, 2.568301560e-02f, -4.230443020e-02f, -5.329443140e-02f, -3.791726010e-02f, -1.559107010e-02f, -1.201677140e-02f, 8.502674100e-02f, 1.207230430e-02f, 6.561192870e-02f, 1.102509070e-02f, -1.139651700e-02f, 5.312211810e-02f, 6.644138690e-02f, -5.482187490e-02f, 3.115621770e-02f, -1.287406680e-01f, -9.199820460e-03f, -1.230915660e-03f, -6.447333100e-02f, 7.333268230e-02f, 3.276544440e-02f, -2.956128310e-02f, -8.251964300e-02f, 5.603397270e-02f, -1.248124240e-02f, 3.909491000e-02f, -1.979575490e-02f, -8.188916740e-02f, -2.568236740e-02f, 8.050823210e-02f, 2.660025840e-02f, -1.166049090e-01f, -4.371337590e-02f, 2.505899220e-02f, -5.792393540e-02f, -4.099886860e-03f, -5.015533790e-02f, -5.643336100e-02f, -1.920001580e-03f, 8.130759740e-02f, 5.996719000e-02f, -9.302049130e-02f, 2.805176000e-02f, -3.461113940e-02f, -7.801727200e-02f, 3.078555870e-02f, 6.283878540e-02f, -2.673678470e-02f, 1.132723540e-01f, -5.185178670e-02f, 9.495273970e-02f, 1.749491510e-02f, 3.041854690e-02f, -6.209582560e-03f, -9.759549050e-03f, 1.858353800e-02f, -7.195539770e-02f, -1.033535530e-01f, 2.369205470e-02f, -1.237832230e-01f, 3.292874250e-02f, -2.771702780e-02f, 5.244827640e-02f, 2.162028850e-02f, 2.750143970e-02f, -6.286770850e-02f, -1.477289570e-02f, -7.608255000e-02f, 9.878462550e-02f, -6.857118010e-02f, -3.864113610e-02f, -2.060878280e-02f, 7.896351060e-02f, 5.005420370e-02f, 8.183766150e-02f, 1.166246270e-02f, 2.490846070e-02f, 6.424091010e-02f, 4.842452240e-03f, 2.385092340e-02f, -1.191184150e-01f, 3.950627150e-02f, -1.216709540e-01f, 4.101262240e-02f, -6.285607070e-02f, -7.496026230e-04f, 5.036032760e-03f, -5.372842400e-02f, -1.197477520e-02f, 3.785884010e-02f, -8.315926040e-02f, -3.981069480e-02f, -2.187930750e-03f, 4.498068990e-02f, -2.374106460e-02f, 1.035350110e-01f, -3.795485940e-02f, -5.760893230e-03f, -1.044728460e-01f, 5.639005820e-02f, 8.062057940e-02f, 8.561957620e-02f, 8.991586040e-03f, -6.923370060e-02f, 9.247705340e-02f, 8.480771630e-02f, 3.869319710e-02f, 5.861152710e-02f, -4.312344270e-02f, -6.479227540e-02f, 1.799745300e-02f, -1.039451440e-01f, 6.226518010e-02f, 1.491317800e-02f, -5.802045340e-04f, -3.599198160e-02f, -1.233048390e-03f, -3.025484460e-02f, 3.301902490e-02f, 3.300498050e-02f, 4.807781430e-03f, -3.137734160e-02f, 4.195430500e-02f, -7.593306890e-02f, 2.735098640e-02f, 2.425325660e-02f, 6.614925710e-02f, -5.467037200e-03f, 1.063642090e-02f, 1.249629170e-02f, 8.857521410e-02f, -1.106430290e-01f, -3.651463990e-02f, -7.377839830e-02f, -2.310991100e-02f, -6.897216290e-02f, 4.368718340e-02f, 6.667454260e-03f, 1.400510410e-02f, -2.586559210e-02f, 9.823925790e-02f, 7.466899700e-03f, -6.304364650e-02f, -2.160125410e-02f, -9.531820540e-04f, 4.364421590e-02f, 1.186531220e-02f, 8.507655560e-02f, -7.357787340e-02f, 3.094097970e-02f, 3.353393080e-02f, 3.659055380e-02f, -8.759249750e-02f, 5.765755470e-02f, 3.943632170e-02f, -8.340163530e-02f, -1.973495260e-02f, 1.536364950e-02f, 7.279321090e-03f, -7.847500590e-02f, -8.777427670e-02f, 6.598367540e-02f, -2.925792710e-02f, -4.085955020e-02f, -5.130352450e-02f, -3.439266610e-02f, 6.158974390e-02f, 9.395947670e-03f, 5.464140330e-02f, -2.741204760e-02f, 4.238858070e-02f, -1.111001820e-01f, -5.156551950e-03f, 3.070013600e-02f, -3.006851300e-02f, -3.538629790e-02f, -3.154262530e-02f, -2.297510020e-02f, 8.255002640e-02f, 3.930310160e-02f, 1.201570130e-02f, 2.534042580e-04f, -7.505050300e-02f, 1.133605000e-02f, -1.121976450e-01f, 5.605772880e-02f, -1.182541030e-01f, 1.833867840e-02f, -1.465678960e-02f, -7.281914350e-02f, -1.009154880e-02f, -6.299430500e-03f, -1.601711100e-02f, 4.881749670e-02f, 1.253101510e-02f, 6.750755940e-03f, 1.428805290e-02f, 4.800101740e-02f, 6.248343360e-02f, -1.603899900e-02f, 3.224699570e-02f, 1.162851230e-02f, 4.613823440e-02f, -8.781474080e-02f, -4.840751740e-02f, 4.785959140e-03f, -1.655049810e-02f, 5.350331220e-02f, 7.937494660e-02f, -2.015189640e-02f, 8.269008240e-03f, 3.068467970e-02f, -3.787564860e-02f, 1.843985540e-02f, -9.194812920e-02f, 2.907666560e-02f, -9.527871010e-02f, -8.948595820e-02f, 5.676624180e-02f, -9.790876500e-02f, -1.639132390e-02f, 1.631558310e-02f, -7.180820220e-03f, -1.587986570e-02f, 7.549041420e-03f, 2.223799190e-02f, -8.038957420e-02f, 3.952651750e-03f, 8.519606290e-02f, 4.762676730e-02f, -1.307074730e-02f, 3.762171140e-03f, 2.949525230e-02f, -7.899437840e-02f, 1.666615720e-02f, 7.800329940e-03f, -4.759308880e-03f, -5.392765630e-02f, -2.190608340e-02f, -8.114729820e-02f, 8.641778490e-03f, 8.666666590e-02f, -4.789678850e-03f, -9.930370740e-02f, 2.225059460e-02f, -3.412329030e-02f, 4.482031610e-02f, -8.497321610e-02f, -5.337416380e-02f, 1.000115130e-01f, 8.285270630e-02f, -1.031439900e-01f, -1.259317850e-01f, 3.901426120e-02f, -3.965527560e-02f, -4.639879990e-02f, -3.742622580e-02f, -3.427251800e-02f, -5.489725250e-02f, 1.023660530e-01f, 5.473033710e-02f, 9.210412940e-02f, -3.357001390e-02f, 1.443301890e-02f, -6.375184650e-02f, -3.890673820e-02f, 1.963367130e-02f, 9.758698940e-02f, 2.236112390e-02f, -4.820513730e-02f, -1.131907780e-01f, 2.701692280e-02f, -5.383831640e-02f, 4.264074840e-03f, -5.750493330e-02f, 5.361178890e-02f, -5.476066470e-02f, -8.181087670e-02f, 6.346184020e-02f, 7.626071570e-02f, -9.238941970e-02f, -1.874246950e-04f, -5.551198500e-03f, -8.968447150e-02f, -8.537781240e-02f, 3.055840540e-02f, -6.551644950e-02f, 4.519767310e-02f, 2.274047770e-02f, -6.159163270e-02f, -6.382770090e-02f, -3.964767980e-02f, -6.345391270e-02f, -5.232215670e-02f, -6.125316020e-02f, -6.353069100e-02f, -5.420723930e-03f, 3.348283100e-02f, -7.425556330e-02f, -6.041495500e-02f, 1.851763200e-02f, 2.933555280e-02f, -5.832915010e-02f, -2.222803050e-02f, 3.811648120e-02f, -8.088462050e-02f, -3.723726790e-02f, -1.120082290e-02f, 4.683110120e-02f, -4.675841700e-02f, 5.560326200e-02f, -5.988147110e-02f, -1.612232440e-02f, 2.819660120e-02f, 1.484809910e-02f, 5.804600940e-02f, 8.671931920e-02f, -2.728863990e-02f, -1.159619690e-01f, -6.397339700e-02f, 9.119506180e-02f, 1.541179050e-02f, 4.234881330e-02f, 5.796191840e-02f, -3.089358290e-02f, -2.977636830e-02f, 3.374583270e-02f, -9.355328980e-02f, 3.144762670e-02f, 7.565202560e-02f, -6.866402180e-02f, 5.049371160e-03f, 4.535803570e-02f, 5.789041150e-02f, -7.451290640e-02f, -7.899110020e-02f, 8.972695460e-02f, 6.341541560e-02f, -3.917802500e-02f, 7.715086450e-03f, -6.542818160e-03f, 1.494776270e-02f, -5.607903000e-02f, -6.158189850e-02f, -5.732773990e-02f, -4.338430990e-02f, 2.430859390e-02f, -3.792100400e-02f, -2.950293010e-02f, -8.333449070e-02f, -7.977679370e-02f, 7.878547160e-02f, 9.164744410e-04f, 7.120503490e-02f, 6.377612800e-02f, 2.623196320e-02f, 8.786723010e-02f, -1.218284010e-02f, 5.683756620e-02f, -1.491697690e-02f, -4.437285010e-03f, -3.791983050e-02f, -1.126373650e-03f, 5.257332320e-02f, 7.224878660e-02f, -4.404791820e-02f, 3.610314430e-02f, 6.369260700e-02f, -2.036026680e-02f, 5.017516390e-02f, -1.933749210e-02f, 3.912019730e-02f, 1.106377230e-03f, 1.145294400e-02f, 5.626258630e-02f, -1.680438590e-02f, 1.827743840e-02f, -1.696651740e-04f, 4.154354710e-02f, 3.815991800e-02f, -4.565692970e-03f, -4.768951610e-02f, -1.743285920e-02f, -3.282657270e-02f, 2.701109280e-02f, 1.477001330e-02f, 2.528416180e-02f, -8.301160300e-03f, -3.599637370e-02f, -5.531897770e-02f, 9.122503920e-03f, 1.840730570e-02f, 4.876418040e-02f, -5.830829960e-02f, 5.095374580e-02f, -5.921510980e-02f, -5.992442740e-02f, 3.536710140e-02f, 5.299034340e-02f, -4.651293900e-02f, -7.912520310e-02f, 1.506153960e-02f, 2.290698330e-02f, -3.665965280e-03f, -2.133798230e-02f, 8.606692770e-03f, 2.330915630e-02f, 4.605889320e-03f, 5.868416280e-02f, 1.738767330e-02f, 6.140305100e-02f, -6.066370010e-02f, 4.553710110e-03f, -8.371241390e-02f, -4.231220110e-02f, 8.185093840e-02f, 2.105195450e-02f, 3.073025120e-02f, 1.999949850e-02f, -8.610594270e-02f, 6.954533610e-02f, 6.272105870e-02f, 2.615421080e-02f, -1.902801360e-02f, -8.701174700e-02f, 7.663385480e-03f, 1.481199540e-02f, -4.486046730e-02f, -4.573317990e-02f, -7.687161860e-02f, -1.113698260e-01f, -3.180074690e-02f, -2.743330970e-02f, 1.599690130e-02f, 1.776482540e-02f, 7.135759290e-02f, 8.253579580e-02f, -7.001189140e-02f, -2.241800910e-02f, 5.727700140e-02f, -3.309145800e-03f, -1.003393380e-01f, 5.181569140e-03f, -1.012290120e-01f, -7.375764190e-03f, -1.558993480e-03f, -3.060864280e-03f, -1.362366790e-02f, 3.324184800e-03f, -9.766886010e-03f, -2.802572680e-03f, -6.365060340e-03f, -1.193883180e-02f, -1.842057680e-04f, 4.314668010e-03f, 1.026416850e-02f, -8.882354010e-03f, -1.140537860e-02f, -8.193022570e-03f, 3.069800790e-03f, -1.825460470e-03f, -8.100450970e-03f, -3.147021630e-03f, 3.685452980e-03f, 8.849930010e-03f, -2.918580080e-03f, -4.019848420e-04f, -7.927614260e-03f, 1.217864640e-02f, 1.995405000e-02f, -2.857350980e-03f, 6.912350070e-04f, 1.817611280e-03f, 9.269692940e-03f, -3.559919310e-03f, -4.921650980e-03f, -3.970188550e-03f, -1.072678620e-02f, 6.635783240e-03f, 1.208369270e-03f, -1.022456120e-02f, -6.337322760e-03f, -3.299019300e-03f, 3.549014920e-03f, -1.020607350e-02f, -2.100733300e-02f, 1.375060620e-02f, 1.144189950e-02f, -1.007530930e-02f, 5.265319250e-03f, 7.951860320e-03f, -1.189447570e-02f, -8.405375290e-03f, 1.573438200e-02f, -1.023606750e-03f, 1.653028650e-02f, 5.479407030e-03f, -6.347761960e-03f, 4.078329080e-03f, 1.275052500e-02f, 1.011247190e-02f, 1.656708120e-02f, -2.269345520e-02f, -6.766786330e-03f, 2.278067400e-03f, -2.341675110e-03f, -4.858414180e-03f, -4.888442810e-03f, -2.923722380e-03f, -1.327737930e-03f, 6.098391950e-03f, 5.035446960e-03f, -7.768875920e-03f, 2.045631870e-03f, 3.826748800e-05f, 7.363981570e-04f, -4.910678040e-02f, -1.114467350e-02f, -9.094943290e-03f, -1.920032500e-02f, -1.282536520e-02f, -3.843677790e-02f, -3.870510310e-02f, 2.630184220e-02f, 2.916137460e-03f, -3.285575660e-03f, -3.839408980e-02f, -1.282645670e-02f, -5.096896740e-02f, 2.042396930e-02f, -1.082574670e-02f, 1.009465940e-02f, -2.537710410e-02f, 7.483283430e-02f, 2.792947740e-02f, -6.174676120e-02f, -6.253413110e-02f, 3.273198010e-02f, -1.103418970e-02f, -1.141405660e-02f, -9.780684110e-02f, -8.705046770e-02f, -8.259810510e-03f, 1.122063860e-02f, -5.433684960e-02f, -4.049541800e-02f, 2.555277200e-03f, 7.879974320e-03f, -1.987044140e-02f, -1.824895110e-02f, 1.128652780e-02f, 1.388684190e-02f, -2.047411720e-02f, -1.463754380e-02f, 1.508512810e-02f, 1.138656590e-02f, -6.402922420e-02f, -7.559141510e-02f, -3.459875940e-03f, 1.669874790e-02f, -1.170499720e-02f, -5.330316720e-02f, -7.456876340e-03f, 9.961534290e-03f, -1.509700440e-02f, -2.592545190e-02f, -3.562954070e-02f, -4.588828610e-02f, -4.156563800e-02f, -3.108994660e-02f, -6.136889100e-03f, 1.915642990e-02f, -1.896406340e-02f, -6.304396690e-02f, -7.528244050e-03f, -1.192309330e-02f, -9.188001600e-02f, 7.796620480e-03f, 1.839851590e-02f, -5.014624910e-03f, 5.279952190e-03f, 1.236629110e-02f, -1.201491430e-02f, -3.129189460e-02f, -8.409480750e-02f, -2.659802700e-02f, -1.468876940e-02f, -7.524888220e-02f, -6.577385220e-02f, 7.132963740e-03f, 5.281035230e-02f, 3.556680310e-02f, 5.327443410e-02f, -9.299525610e-02f, -1.027420540e-01f, 4.960799590e-02f, 2.753157630e-03f, 8.304569120e-02f, 1.867672610e-02f, -1.543590240e-02f, 4.563809560e-02f, 6.390805540e-02f, -1.396729500e-01f, -2.955776450e-02f, -4.616313060e-02f, -4.995925350e-02f, 7.534961400e-02f, -8.854901790e-02f, -1.851480640e-02f, -3.415998070e-02f, 8.507631720e-02f, -1.390898600e-02f, -1.021054760e-01f, -3.959912810e-02f, 4.612451050e-02f, -5.655996500e-02f, 7.184893640e-02f, -8.735013750e-02f, 5.717101690e-02f, 6.662319070e-04f, -3.739310800e-02f, 8.932805060e-02f, -7.132682950e-02f, -1.132689270e-01f, -1.954618100e-02f, -7.393254340e-02f, 2.701050230e-02f, 5.120553820e-02f, -5.395473910e-02f, 1.841439680e-02f, -5.442959820e-02f, 1.175480520e-02f, 5.463420230e-02f, -1.141662670e-01f, 8.791410170e-02f, -6.769212340e-02f, 4.594812170e-02f, -8.459614960e-02f, 7.657807320e-02f, -3.216652570e-02f, 6.490398200e-02f, -3.876904770e-02f, -4.225038740e-02f, 2.079425010e-02f, 3.430531550e-02f, -5.969511720e-02f, -1.066953130e-02f, -1.061840820e-02f, -5.718360470e-02f, -1.797616110e-02f, -1.015160380e-01f, -9.872063990e-03f, 9.633574630e-02f, -2.754173060e-02f, 1.694338210e-02f, -7.097509500e-02f, 4.621899130e-02f, -5.936149880e-02f, -6.153709720e-03f, 4.799601440e-02f, -2.720720130e-02f, -1.105163770e-01f, -6.050391120e-02f, -1.129978060e-02f, 4.742592950e-02f, -5.410008880e-02f, 1.086841150e-02f, -4.542984810e-02f, 9.538592400e-02f, 6.189199540e-02f, -8.380537480e-02f, 3.252742070e-02f, -2.945640120e-02f, 1.211642850e-01f, 2.336437440e-02f, -2.899761080e-03f, -5.638707060e-02f, -8.270695060e-02f, 1.129970330e-01f, -8.077365900e-02f, -1.036879790e-01f, 7.323551920e-02f, -3.793616220e-02f, 3.188375150e-03f, 6.557517500e-02f, 6.010395470e-03f, -3.309315440e-02f, 8.793857690e-02f, 4.411350940e-02f, 6.900493800e-02f, -9.779544540e-03f, 7.502150530e-02f, 4.361786690e-02f, 4.413781320e-02f, 1.026235150e-02f, 1.113883130e-02f, 4.032383490e-02f, -5.163838710e-02f, -4.323467610e-03f, 9.343679250e-02f, 8.459131420e-02f, -9.943746770e-02f, 7.068052880e-02f, 1.018157600e-01f, 1.970444430e-02f, -4.384617510e-02f, 1.273670980e-02f, -1.107488950e-01f, -8.904101690e-02f, -6.871525200e-02f, 2.306320330e-02f, 1.131358840e-02f, -8.256637300e-02f, 1.007624340e-01f, 9.180778630e-03f, -2.724017020e-02f, 1.779015730e-02f, 3.838062290e-02f, 7.861589640e-02f, 9.775892830e-03f, -2.114596400e-02f, -4.175904210e-03f, -2.127498760e-02f, -4.141087090e-02f, -4.700697960e-02f, -5.207786710e-02f, 3.470276670e-02f, 1.528139130e-02f, -5.682622640e-02f, -1.134932190e-01f, 6.839187810e-03f, 1.015613130e-02f, -3.289094940e-02f, -8.902602640e-02f, -7.056471890e-03f, 9.482785130e-03f, -1.423451770e-02f, -2.484705490e-02f, 4.290781170e-02f, -7.738901670e-02f, -6.025584790e-02f, 3.938515860e-02f, -7.857431470e-02f, 1.657874510e-02f, -5.710153280e-02f, -1.861819250e-02f, 5.208029970e-02f, -2.291125480e-03f, 3.134427220e-02f, -1.447534470e-02f, -5.865562330e-02f, 2.207094990e-02f, -5.006702620e-02f, -1.033327280e-01f, 4.414865000e-02f, 2.712592860e-02f, -1.347911950e-01f, 2.630763690e-03f, 2.593396980e-02f, 2.581998330e-02f, 8.922407030e-02f, -6.715646380e-02f, -2.144378980e-02f, -2.228207510e-02f, 3.385091200e-02f, 3.915440660e-02f, 6.862749900e-02f, -7.211732860e-02f, 2.745737690e-02f, -1.380234960e-02f, 5.252528940e-02f, 4.056931010e-03f, -3.767619650e-02f, 1.902640800e-02f, 7.115073500e-02f, -1.305363050e-02f, -3.313219170e-02f, 3.703329010e-03f, 3.389516100e-02f, -5.342062190e-02f, -8.422213790e-02f, -7.513126730e-02f, 6.108217690e-02f, 5.008897560e-02f, 3.518910710e-02f, 1.547415180e-02f, 5.343036730e-02f, 6.903930010e-02f, 3.405706580e-02f, 2.503616920e-02f, -1.083380880e-01f, 8.503043650e-02f, -1.058045550e-01f, 2.000345100e-02f, 1.762706900e-03f, -1.172914640e-02f, 3.528704870e-02f, 2.793597620e-02f, -3.296788780e-02f, -1.356281040e-01f, -2.462254090e-02f, -6.869678200e-02f, 8.473006160e-05f, 5.574376510e-02f, -3.192782630e-03f, -8.827731010e-03f, -5.482871550e-03f, 1.644717530e-02f, -1.788990760e-02f, -1.830529980e-02f, -7.336038160e-03f, 2.265149170e-02f, -9.530210520e-04f, 1.918818620e-02f, 5.430171730e-03f, -1.252565810e-02f, -2.736820650e-02f, 2.547184190e-02f, -2.878204920e-03f, 1.460630730e-02f, -2.519537230e-03f, 3.639962150e-02f, 9.278414770e-03f, 3.830679230e-03f, 8.930946700e-03f, 8.525676090e-03f, 2.278651480e-02f, -1.468871440e-02f, -2.626927380e-02f, -2.494211870e-02f, -6.999235600e-03f, -4.676033280e-03f, -5.973876920e-03f, -7.191698530e-04f, -5.496839530e-03f, -5.639635960e-03f, -1.470317250e-03f, 4.542185460e-03f, 7.829338310e-03f, 3.155532990e-03f, -1.775727230e-02f, 1.349550490e-02f, 2.374072210e-04f, 5.424795670e-03f, -1.722959990e-02f, 1.504746470e-04f, 2.176665930e-03f, -5.255225110e-03f, -1.694379750e-02f, 6.813375270e-03f, -1.161801120e-04f, -1.331348070e-02f, 1.635643840e-02f, 2.081681970e-02f, -9.053898040e-03f, 2.390435900e-02f, 1.029696970e-02f, -1.504245960e-02f, -1.546192220e-03f, 1.218052670e-02f, -8.917292000e-04f, 1.439076730e-04f, 6.842041040e-04f, 9.837654420e-03f, -1.883754690e-02f, -7.095223760e-03f, 9.113593020e-03f, 1.770759930e-02f, -1.207173800e-02f, 4.765855610e-03f, 2.182154730e-02f, -7.558719260e-03f, 8.774488230e-03f, -1.309017090e-02f, 2.615678120e-03f, -1.272346450e-02f, 8.348298260e-03f, 4.013668280e-03f, 1.379899680e-03f, -1.676539890e-02f, 3.097004080e-04f, 7.178186440e-03f, -4.075212400e-03f, 1.793060640e-02f, 1.499541380e-02f, -8.185057900e-03f, -5.061214320e-03f, 2.997459660e-02f, 1.093809490e-02f, -2.154991220e-02f, -1.585851420e-02f, 8.660209370e-03f, -9.765847590e-03f, -1.591615750e-02f, 1.729756410e-02f, -1.011550330e-02f, 5.195214410e-03f, 7.926324380e-03f, -7.839465400e-04f, 1.523044050e-02f, -2.811482360e-02f, 2.077163380e-02f, 1.125736530e-02f, -1.820928980e-02f, 6.935652810e-03f, 6.424661730e-03f, 1.500968450e-02f, 4.316658250e-03f, -9.660006500e-03f, -7.477087900e-03f, 3.379384290e-03f, 1.445295200e-02f, 1.418240000e-02f, -1.525685940e-02f, -3.109619250e-03f, 1.681183120e-03f, 6.777545430e-03f, -4.082462940e-02f, -2.335546350e-02f, -1.708864050e-02f, -2.658125480e-03f, -1.461914270e-02f, 7.930330930e-03f, -2.380927040e-04f, -1.111640380e-04f, -1.069514730e-02f, 1.198735370e-02f, -3.132586830e-03f, -2.050102130e-02f, 2.421184070e-02f, -1.984822750e-02f, -9.403600360e-03f, -5.658275450e-03f, -1.957944780e-02f, 9.558853690e-03f, -6.994204590e-03f, -2.116486060e-02f, 7.100403310e-03f, -1.009104030e-02f, 3.310558620e-03f, 4.272317510e-02f, -1.976432280e-03f, 2.032810820e-03f, 2.537042370e-03f, 7.403374180e-03f, -1.032633800e-02f, -2.521868610e-02f, -6.270894780e-03f, 1.585495470e-02f, -5.436187240e-02f, 5.101742220e-02f, 1.968711240e-02f, 4.012948830e-03f, -1.234393940e-01f, 3.520674540e-03f, -2.352627690e-03f, -3.397072110e-02f, -2.681704050e-02f, -7.743414490e-02f, 3.192303330e-02f, 2.424810080e-02f, 6.020494550e-02f, 3.027998840e-02f, -6.025004010e-02f, -2.119716630e-02f, -3.626569730e-02f, 6.032709780e-02f, -4.518628120e-02f, 4.649401080e-02f, -1.980178060e-02f, 6.877745690e-02f, -9.960288550e-02f, 6.102693730e-03f, 1.762603780e-02f, 1.103306280e-02f, -4.513422400e-02f, 1.239241380e-02f, -5.865376820e-02f, 2.760585960e-02f, 7.285063710e-02f, 1.391627360e-02f, 3.235466780e-02f, -4.316960650e-02f, -1.070071160e-01f, 9.051205960e-02f, -7.961794730e-03f, 5.397762730e-02f, -3.052890670e-02f, 8.429591540e-03f, 5.157170440e-02f, -1.092531610e-01f, -5.939553680e-02f, -4.667525060e-04f, 6.524058430e-02f, -2.339071590e-02f, -4.334482550e-02f, 4.736025630e-02f, 2.207872830e-02f, 1.864950920e-02f, 4.836488890e-02f, -6.675397600e-02f, 9.725669020e-02f, 2.605298160e-02f, -5.564348400e-02f, -1.967240500e-02f, 4.042603450e-02f, -6.274676320e-02f, 4.475755150e-03f, 4.425385590e-02f, -2.115413360e-02f, -4.901005700e-02f, 4.846609010e-02f, 1.024732890e-01f, 4.290572930e-02f, 1.059322210e-01f, 3.589672970e-02f, -1.174963340e-01f, -3.808400780e-02f, -3.016083130e-02f, 3.228389470e-02f, -6.237133210e-02f, -1.366909590e-02f, -8.637614660e-04f, -1.149441080e-01f, 3.273371230e-02f, -1.143691390e-01f, -6.620718540e-02f, -8.083194490e-03f, -7.590067390e-02f, -4.583824800e-02f, -9.172903740e-02f, -4.743924740e-02f, -4.971543790e-03f, -5.227279660e-02f, -3.024304470e-02f, -1.200241370e-01f, -1.224823670e-02f, 5.125055090e-02f, 7.296892260e-02f, -9.563932560e-02f, 1.636028660e-02f, -7.902447130e-02f, 3.384131190e-02f, -3.554975610e-02f, 5.871841310e-02f, -7.500103110e-02f, -5.649541320e-02f, 7.174587250e-02f, 8.238575600e-02f, -6.943081320e-02f, -6.080972030e-02f, -3.011264280e-02f, 3.261236850e-02f, 9.882465000e-02f, -3.281165660e-02f, 7.914771330e-03f, 2.320542750e-02f, -7.736659040e-02f, 1.931231470e-03f, -3.619423510e-02f, -3.530933340e-02f, 4.437195140e-02f, -3.732013700e-02f, -7.572376730e-02f, 5.945494030e-02f, -8.335989710e-02f, 2.035048600e-02f, -5.287789550e-02f, -3.049298750e-02f, 3.431895380e-02f, 5.341321230e-02f, -9.007855320e-03f, 9.788757190e-03f, 7.487286630e-02f, -3.600851450e-02f, 2.494704910e-02f, 3.468573470e-02f, 1.459963710e-02f, -8.198944470e-02f, 3.479841350e-02f, 4.764647780e-02f, 2.878457870e-02f, -1.349223220e-02f, 3.398701550e-03f, -3.425884250e-02f, -3.037021670e-04f, 5.541618910e-03f, -2.919397550e-03f, 7.513219120e-02f, 4.818337780e-02f, 9.189981960e-03f, 2.156180140e-02f, 2.723576700e-06f, -1.024528310e-02f, -2.482639440e-02f, -3.264126930e-02f, -2.998740230e-02f, -3.159892930e-02f, -6.491837650e-02f, 5.666877140e-03f, 6.443358210e-02f, -9.388141330e-03f, 2.354541790e-02f, 3.499178960e-02f, 2.657596580e-02f, -2.256155390e-02f, 2.213299270e-02f, 1.043346000e-01f, -3.095788880e-02f, -1.715070750e-02f, -5.014508220e-02f, 4.021715840e-03f, 5.209049580e-02f, -4.870029910e-02f, -6.526888160e-02f, 2.432321380e-02f, 3.559559960e-02f, -3.277416900e-02f, 8.156999200e-02f, -9.465543180e-02f, 5.138706420e-02f, 4.924860970e-02f, 7.179915900e-02f, 3.923544660e-02f, 1.557614370e-02f, 7.007173450e-02f, 1.199842430e-02f, 2.962869030e-02f, -8.395818620e-02f, 2.361833120e-02f, 6.693067020e-03f, 2.324467150e-02f, 6.185925380e-02f, -7.578656540e-03f, -1.175535100e-01f, -8.151769630e-02f, -4.783011600e-02f, -5.603451280e-02f, 8.629371410e-03f, -2.160704320e-02f, 4.331870750e-02f, -2.920747360e-02f, 7.294300940e-02f, 3.008328190e-02f, 5.513571950e-02f, 4.254554960e-02f, -4.504382240e-02f, -1.039314120e-01f, 7.665828620e-02f, 6.761049480e-02f, -3.298590700e-02f, 1.878466640e-02f, 1.537951520e-03f, -1.052467270e-04f, 7.520075890e-02f, 6.014918160e-02f, -1.156158300e-01f, 1.044724660e-01f, -9.044502680e-02f, 3.680531170e-03f, -3.084215150e-02f, -1.870711890e-02f, -4.755056280e-02f, -1.614294010e-02f, -1.594801990e-02f, -8.565834160e-02f, -6.997784970e-02f, 5.934983860e-02f, -2.432508770e-02f, 5.759549140e-02f, -3.150905300e-02f, 8.990465840e-02f, -5.620196090e-02f, 5.310416590e-02f, 4.431964080e-02f, 8.175257590e-02f, 4.697791490e-02f, 6.074330210e-02f, 3.206459430e-02f, -4.374013840e-02f, -9.675396140e-04f, -3.337373210e-02f, -4.959834370e-02f, -1.152766270e-01f, -8.358674490e-02f, 4.562164470e-02f, 4.241702330e-02f, 6.609384900e-03f, 5.552261700e-02f, -1.136590320e-01f, -3.867048400e-02f, -6.583872430e-02f, -4.943061620e-02f, 9.697465590e-02f, -7.469905070e-03f, 6.233775980e-02f, 2.749165890e-02f, -3.351631020e-02f, -6.596511600e-02f, -9.210206570e-02f, -2.186356300e-02f, -6.269229950e-02f, -8.114994310e-02f, 4.312582690e-02f, -1.174977570e-01f, 1.558329160e-02f, -1.133085140e-02f, 3.213023390e-02f, -5.143374200e-02f, -9.776276350e-02f, -8.560830610e-04f, 7.155163910e-04f, -7.389418780e-02f, 4.479670900e-02f, -2.192808130e-02f, -8.984304960e-02f, -7.078650590e-02f, 4.270081590e-02f, -7.170774790e-02f, 5.995286260e-02f, 3.646945580e-02f, -1.055178790e-02f, 5.427371360e-04f, -7.914562710e-03f, 7.487966120e-02f, -3.720004110e-02f, -9.073164310e-02f, 6.610359250e-02f, -5.322688070e-02f, -2.754735020e-02f, 8.065267650e-02f, 1.513805120e-03f, 3.803259510e-02f, -4.541153830e-02f, -6.549429150e-02f, 2.141968530e-02f, -3.265156880e-03f, 4.113083240e-03f, -7.805915080e-04f, -8.128657350e-04f, -4.408440550e-03f, 1.930240310e-03f, 8.554064670e-03f, 1.348987220e-02f, -2.616152400e-03f, 5.410600450e-03f, -1.804737370e-03f, 1.031453260e-02f, -6.652463230e-03f, 1.452342980e-02f, 3.378769620e-04f, -1.021942220e-02f, 2.328715750e-03f, -1.724902910e-02f, 7.448722610e-03f, -3.426524110e-03f, 5.705761260e-03f, -6.229597610e-03f, -2.487244320e-03f, 1.951296350e-03f, 2.011124230e-02f, 5.048096650e-03f, -1.660485170e-03f, 1.318913050e-02f, 1.409272660e-02f, -6.454979300e-04f, -1.340881180e-02f, -6.149809810e-03f, 2.371820390e-03f, -1.102962620e-02f, 1.760420580e-02f, 1.267944460e-02f, 6.141349210e-03f, -3.195461120e-03f, -6.077312860e-04f, 4.965838040e-03f, 6.555318830e-03f, -1.242096630e-02f, -3.113287500e-02f, 5.749367640e-03f, -4.915297500e-03f, -3.966595050e-03f, -2.408034630e-03f, 4.671335220e-03f, 1.323431730e-02f, -1.327087540e-02f, -9.197309610e-03f, -7.555464750e-03f, -7.002526890e-03f, 2.630175320e-03f, -1.418673900e-03f, 1.034922530e-02f, 9.921791960e-03f, 8.590054700e-03f, 3.479025330e-04f, -6.665887780e-03f, -8.748436340e-03f, -5.874416790e-03f, 5.359147680e-03f, 4.004180900e-03f, -1.716442780e-02f, -5.279230890e-03f, 4.787896760e-03f, 1.526432580e-03f, -8.349795830e-03f, -7.067795840e-03f, 8.635270060e-04f, -5.858277900e-03f, 2.044405970e-02f, -1.122505870e-02f, 1.060822160e-03f, 4.090466350e-02f, -1.521816010e-03f, -7.165674870e-02f, -3.357885410e-02f, 8.706149450e-02f, 2.076899070e-02f, -2.818403020e-02f, 4.757975790e-02f, -7.545190300e-02f, -1.191706510e-01f, 2.537163350e-02f, -1.090931670e-01f, 6.270039080e-02f, 5.169895660e-02f, -1.357171310e-02f, -1.559033150e-02f, 7.116026710e-03f, -2.850122190e-02f, 1.263977960e-02f, 4.700511690e-02f, -5.156457800e-02f, -2.718988060e-02f, -1.400840840e-02f, 1.544206960e-02f, 4.520249370e-02f, 4.361676050e-03f, -3.324020280e-02f, 2.857340310e-02f, -3.807577860e-02f, -6.128994280e-04f, 7.109875980e-02f, -2.709749900e-02f, -1.241973790e-02f, 2.377265690e-02f, 7.272560890e-02f, -1.375142670e-02f, 5.116264340e-03f, -6.211170180e-02f, -2.906141430e-02f, -6.881917270e-02f, -3.770498190e-02f, -3.313177450e-02f, -9.058898680e-02f, -3.114145440e-02f, -6.831260770e-02f, 2.237549800e-02f, 3.434339910e-02f, 4.699662700e-02f, 6.708951660e-03f, -6.035980580e-02f, -1.762520710e-02f, -4.576496780e-02f, -5.086348950e-02f, 7.890144730e-02f, 3.975575040e-02f, -7.303698450e-03f, -5.486212670e-02f, -1.142967210e-02f, -4.310863470e-02f, -4.767448460e-02f, 6.700446460e-02f, 6.444934760e-02f, -8.599192840e-03f, -3.608337040e-02f, -6.525545570e-02f, 2.930313720e-02f, -8.785916860e-02f, -1.047626790e-02f, -1.028587450e-01f, 3.960635050e-03f, -4.667359870e-03f, -1.019711960e-03f, -3.272594880e-03f, 3.829901810e-03f, -8.714044820e-04f, -7.544527760e-03f, -7.104284600e-03f, -3.535167780e-03f, -6.708203350e-03f, 1.306278170e-03f, -1.975050660e-03f, 6.464537700e-03f, -1.152899770e-02f, -2.694128080e-03f, 7.825976930e-04f, 5.590239310e-04f, 5.056389140e-03f, 1.507695650e-03f, 2.652255120e-03f, -3.692757800e-03f, -4.023063810e-04f, 1.672626090e-04f, -1.442730990e-02f, -5.793746560e-03f, -7.471767250e-03f, 3.111858850e-03f, -1.039214900e-02f, -1.291942320e-02f, 5.386158590e-04f, 1.015254020e-02f, 5.188426000e-03f, 1.822115970e-03f, 1.170636990e-02f, -1.154124270e-02f, -1.720933800e-02f, 8.075605150e-03f, 3.055423270e-03f, 1.411216100e-03f, -3.609190690e-03f, -1.161291150e-03f, -4.723645690e-04f, 1.128587870e-02f, 5.266973170e-04f, 3.895367030e-03f, 2.274994270e-03f, 4.588933080e-04f, -5.323550660e-03f, -9.115377440e-03f, 1.702793130e-02f, 6.633942480e-03f, 4.903078080e-03f, 5.234880950e-04f, -3.589206380e-03f, -3.868188710e-03f, -6.172562020e-03f, -6.042953580e-03f, -6.270985580e-03f, -4.645164120e-03f, -1.897991870e-03f, 1.022691560e-02f, 1.564639850e-03f, -9.964128020e-03f, -1.101167520e-03f, 2.279024940e-02f, 5.917928180e-03f, -3.874503540e-03f, -2.372583140e-03f, -1.947648820e-03f, 5.286225580e-03f, -2.633745320e-03f, 7.896178400e-03f, 4.105978830e-02f, -1.228302420e-01f, -2.902570930e-02f, -6.709216540e-02f, 7.185076250e-04f, 5.390077080e-02f, -4.282093050e-02f, -1.520284170e-02f, -1.187687650e-02f, -6.821898370e-02f, -6.518679860e-02f, -4.835936050e-02f, -1.481539940e-02f, -7.876873760e-02f, 4.150486360e-02f, 4.601151500e-02f, 7.121746240e-02f, 4.050583760e-02f, 3.160226350e-02f, -6.242625780e-02f, -1.511019840e-02f, 5.361797660e-02f, 1.822648570e-02f, 1.793548280e-02f, -1.298080530e-01f, -2.005453220e-02f, 4.941835250e-02f, 6.805286560e-02f, 1.875805300e-02f, 6.935422770e-03f, -2.389021540e-04f, 5.581282450e-02f, -6.085913630e-02f, 4.687566310e-02f, 2.971958370e-02f, 2.352560400e-03f, -3.339660910e-02f, 2.151323020e-03f, -9.799947030e-03f, 4.906940830e-02f, -7.186290620e-02f, 3.605475280e-02f, -6.176525350e-02f, -4.674195780e-03f, -1.609269340e-02f, -1.298610960e-02f, 3.933727740e-03f, -1.896627620e-02f, -4.036896300e-02f, 8.538960660e-02f, -1.191290560e-02f, -2.895901170e-02f, 2.417283690e-02f, -3.740882130e-02f, -7.597667720e-02f, -3.865435020e-03f, -2.271836060e-02f, -3.490350400e-02f, -1.128823160e-01f, 3.073446080e-02f, -1.102438050e-01f, 3.419131040e-02f, -1.051884370e-01f, 3.308197110e-02f, 3.766646140e-03f, -6.524474920e-02f, -4.177435110e-02f, -1.182366810e-02f, -1.775488260e-02f, 6.034080310e-02f, -8.297048510e-02f, 9.263150390e-03f, -3.932829480e-03f, -1.967848280e-03f, -2.911595390e-03f, 1.883614620e-02f, -1.686040130e-02f, -1.566453650e-02f, -3.900634820e-03f, 3.497980910e-02f, -5.699611270e-03f, 2.588478480e-02f, 1.149178600e-03f, 1.147273090e-02f, -2.496055330e-02f, 1.910774780e-02f, -2.057094870e-02f, 5.048931580e-03f, 6.412764550e-03f, 7.609636520e-03f, 2.699503120e-02f, 1.356584490e-03f, 7.170262750e-03f, 1.402172630e-02f, 2.908796820e-02f, -2.176947710e-02f, -2.281978170e-02f, -1.841990840e-02f, -1.055160420e-03f, -1.963975840e-02f, 3.257295610e-05f, 1.238634930e-03f, -1.090488400e-03f, -3.914986270e-03f, -4.967818500e-03f, 1.403458040e-02f, 1.205410250e-02f, -4.461958890e-04f, 1.091874200e-02f, -1.885762470e-04f, -1.214729270e-03f, -3.801424060e-03f, -1.468443130e-02f, -1.770364310e-02f, -2.254780380e-02f, -1.013687440e-02f, -2.546065300e-02f, 2.969042860e-03f, 1.153814140e-02f, -1.098765990e-02f, 2.426050420e-02f, 2.341576290e-02f, -6.554693450e-03f, 1.801232060e-02f, -3.097267120e-03f, -1.580286650e-03f, -1.669124330e-02f, 1.476269310e-02f, -8.796693140e-05f, -1.241059880e-02f, 6.353723820e-03f, -8.878899730e-03f, -2.666025240e-02f, -8.380140180e-03f, 4.230084360e-03f, 1.915289280e-02f, 1.414631310e-02f, 9.967577640e-03f, 2.386301380e-02f, -5.955495870e-03f, 5.981801660e-04f, -1.179278360e-02f, -5.451937670e-03f, -2.639837750e-02f, 8.261272680e-03f, -7.755979430e-03f, 5.570528100e-03f, -1.018015110e-02f, -3.024639100e-03f, -8.352776060e-03f, 7.840009400e-03f, -7.733336650e-03f, -2.187276720e-03f, -1.456085130e-03f, -4.016277380e-03f, -5.421417300e-03f, 2.009168640e-02f, 1.882074280e-03f, -2.750642600e-03f, 1.508389370e-03f, 2.484320430e-03f, -8.284284730e-03f, -1.060157430e-03f, -1.173805630e-02f, 6.460392380e-03f, 1.911847150e-03f, -1.650383320e-02f, 7.513379210e-03f, -1.218509490e-02f, -1.085305310e-02f, 1.551148130e-03f, 7.748275990e-03f, 7.773846850e-03f, 1.040443960e-02f, -1.735312120e-02f, 4.708609080e-03f, 4.201269710e-03f, 2.344377710e-02f, -3.991317940e-03f, -2.029820160e-02f, 3.896257650e-02f, 9.422906440e-04f, 8.252406490e-03f, 5.123257170e-03f, 2.457519620e-02f, 1.667637010e-02f, -1.772500200e-02f, 4.992024510e-03f, 4.344598390e-03f, 7.217959040e-03f, -5.792730490e-03f, 7.505105340e-03f, 8.855506890e-04f, -2.215053330e-02f, -1.022761690e-02f, -4.955165550e-03f, -8.327382620e-03f, 2.127385930e-03f, -6.673177700e-03f, 6.856327870e-03f, -1.355018500e-05f, 4.736650150e-04f, 4.439484910e-04f, -3.633816730e-03f, 2.241038720e-03f, 5.289968100e-03f, -1.813844220e-02f, -2.048282140e-02f, -3.090873360e-04f, -1.173261460e-02f, -1.890471580e-02f, 7.960531860e-03f, -2.821591220e-03f, -1.639632690e-02f, 1.007040310e-02f, -9.726707350e-04f, -2.142188880e-02f, 5.936694330e-03f, -8.004389700e-02f, -5.240336430e-02f, 4.909618570e-02f, 3.318199140e-02f, 5.222058670e-02f, -6.865821030e-02f, -3.728449340e-02f, -1.039669940e-02f, -9.739886960e-02f, 9.622944890e-02f, 5.896349250e-02f, -7.698055360e-02f, 5.391662940e-02f, -1.173088090e-04f, 1.559916230e-02f, -6.047806140e-02f, 2.592972850e-02f, -9.201744190e-02f, -2.532013690e-02f, -6.695579740e-02f, 6.589777020e-02f, -3.220641240e-02f, -8.203146600e-02f, -1.212572230e-01f, 6.738623970e-02f, 2.745623230e-03f, 4.513893280e-02f, -9.198296070e-02f, -1.092514990e-01f, -4.259116950e-02f, 2.176526930e-02f, -7.107172910e-02f, 1.220418420e-02f, 4.544628780e-02f, 7.751491660e-02f, -7.789797330e-02f, 4.909441990e-02f, 7.411141690e-02f, 7.814569020e-02f, -5.814259870e-02f, -2.650672340e-03f, -5.035115410e-02f, 9.931582950e-03f, -9.955592450e-03f, -3.044692990e-02f, -1.229132190e-01f, 4.185319320e-02f, 5.540454390e-02f, -1.135839300e-01f, 1.372667590e-02f, -1.083830970e-01f, 2.502501760e-02f, 8.058113600e-02f, 2.974429730e-02f, 4.813517630e-02f, -9.895928940e-02f, -1.259993170e-01f, 8.639827370e-02f, 1.723668910e-02f, 1.528959840e-03f, 4.692210350e-03f, 2.888793500e-02f, 8.401487950e-03f, -3.412241860e-02f, -6.776502720e-02f, 7.346571980e-02f, -3.108687700e-02f, 4.082687940e-02f, -4.037727420e-02f, 6.711486730e-02f, 1.280390940e-02f, -4.503838720e-02f, -8.522441980e-02f, 3.160291170e-02f, -8.435428880e-02f, 8.524483440e-02f, -6.145710870e-02f, 3.017723750e-02f, -6.429366770e-03f, 9.353455150e-02f, 1.429167020e-02f, 6.796000150e-02f, -1.780479220e-02f, 3.431884570e-02f, 4.706882870e-03f, -6.369060130e-04f, 7.008969040e-02f, 6.983242930e-02f, -6.906140600e-02f, 2.803597970e-02f, 1.718907990e-02f, -2.620889620e-02f, 6.956454370e-02f, -5.096388520e-03f, 3.443739940e-02f, 3.073393370e-02f, 7.087285070e-02f, 1.795720500e-02f, 7.940571750e-02f, 2.564399880e-02f, -1.202807760e-02f, -8.297394960e-02f, 9.017195550e-02f, 6.556649510e-02f, 9.028526950e-03f, 9.280587550e-03f, -2.654214950e-02f, 1.940470750e-02f, 6.540537630e-02f, -6.347536300e-02f, -2.012280930e-02f, -1.844027820e-02f, 5.489287900e-02f, 2.809465680e-02f, -7.469584050e-02f, -5.624436590e-02f, 4.439231940e-03f, 4.997481780e-02f, -1.597669720e-02f, -8.750266580e-02f, 7.206042860e-02f, 4.578406460e-03f, 5.796766280e-02f, 1.053331570e-01f, 4.682745780e-02f, 4.827569050e-02f, -9.169586740e-02f, -1.089974270e-01f, -9.614643640e-03f, 9.008871760e-02f, 3.574813160e-02f, -7.602864500e-02f, -7.399621600e-02f, -3.282273190e-02f, -7.536809150e-02f, -3.720840810e-02f, 5.734957010e-02f, -4.267604560e-03f, 8.469533170e-03f, -1.260641960e-01f, -6.870396440e-02f, 1.324061490e-02f, -3.389309570e-04f, -1.702366750e-03f, -2.340814470e-02f, -2.066916790e-02f, 6.406311880e-03f, -4.652995620e-02f, -5.619840700e-03f, 5.374733360e-02f, 3.254512320e-02f, 1.681457460e-02f, 3.756890660e-04f, 5.611669270e-02f, -1.246798780e-01f, 5.579895900e-02f, 5.327980970e-02f, -2.986440990e-02f, -1.202190570e-02f, 1.207611860e-01f, 4.815108700e-02f, 5.836024510e-02f, -4.744837810e-02f, 5.514001470e-02f, 4.619091380e-02f, -1.183626880e-01f, -8.356985440e-02f, -7.602258030e-02f, -6.140972670e-02f, -3.080440130e-02f, -3.482881190e-02f, 3.810647130e-02f, -2.413963340e-02f, 2.373466450e-02f, 3.444881360e-02f, 4.480117190e-02f, -3.491926940e-02f, -3.136531640e-02f, 3.891619670e-02f, 2.919042110e-02f, 8.302883050e-02f, 4.758433250e-02f, -5.273232610e-02f, -3.872270510e-02f, 1.500504000e-02f, 5.298214780e-02f, 2.345660330e-02f, 1.535240100e-03f, 3.166561950e-03f, -1.064524800e-01f, 7.846299550e-02f, 6.214360890e-02f, -1.394365540e-02f, 6.306071580e-02f, -3.323688730e-02f, -3.138012810e-02f, 5.211110790e-02f, 1.907755810e-02f, 3.244907600e-03f, -7.268201090e-03f, -7.205194980e-02f, 9.092257920e-02f, 5.391494930e-02f, 5.692328510e-02f, -1.958118570e-02f, -1.568597740e-03f, 1.793880200e-02f, 1.850382190e-03f, 2.944440580e-02f, -4.057002810e-02f, -5.483971910e-03f, 1.808348110e-02f, 4.930959270e-02f, -7.371673830e-03f, -2.506996690e-02f, -7.447271790e-02f, -2.656578650e-02f, 9.078446770e-03f, -4.696519300e-02f, 7.022620740e-02f, -4.732997720e-02f, 1.881154810e-02f, 3.555712100e-02f, -5.371514340e-02f, 4.093719270e-02f, 6.418941170e-02f, 6.236065920e-02f, 4.466363790e-02f, -2.422659660e-02f, 1.177694760e-03f, 1.522638560e-02f, -3.240450100e-02f, 9.758621450e-02f, -4.231430220e-02f, -2.513048050e-02f, -2.826252720e-03f, 8.254639800e-02f, -5.092648320e-03f, -7.299765200e-02f, -1.807622320e-04f, 8.478102080e-02f, -4.745926710e-02f, -8.539561180e-02f, -3.564377500e-02f, -1.267825070e-01f, 1.224751960e-02f, -7.187786690e-02f, 3.185732660e-02f, 7.206968960e-02f, -1.143865880e-01f, 5.258571360e-02f, -2.932980100e-02f, 3.050599010e-03f, -2.686700780e-02f, 3.553923590e-02f, -1.307632770e-01f, 3.361235190e-02f, -1.087869630e-01f, 4.764594880e-02f, -4.320000860e-02f, -8.873376060e-03f, 5.912840740e-02f, 3.333161770e-02f, 4.760579020e-02f, -5.665687100e-02f, -5.103600030e-02f, 6.438356640e-02f, 6.749251480e-02f, -1.577888990e-02f, 1.451539220e-03f, 1.354718020e-02f, -6.873339410e-02f, 3.896692400e-02f, 3.882862250e-02f, -5.756016080e-02f, 6.758264450e-02f, -9.623114760e-02f, 7.992815970e-02f, -9.584411050e-03f, -3.490914780e-02f, 5.081517620e-02f, 2.626084910e-02f, -7.934701440e-02f, -1.643729020e-02f, -2.158519630e-02f, 5.690518020e-02f, 4.436395690e-02f, 5.197782070e-02f, 3.885795550e-02f, 3.715046120e-02f, -3.902734820e-02f, -7.815794650e-02f, -3.513346980e-02f, -5.906473850e-02f, 6.949167700e-02f, 5.330962690e-02f, 6.634401530e-02f, -4.789537940e-02f, 5.764849480e-02f, 5.686235060e-02f, -3.027372060e-02f, 3.103035500e-02f, -3.181075680e-02f, -4.067428410e-02f, -8.073052010e-02f, -1.210750860e-01f, -8.109497270e-02f, -3.080262620e-02f, 6.878433380e-02f, 5.412412060e-02f, -3.918897730e-02f, -2.964044550e-02f, -9.751755740e-02f, 6.810444870e-03f, -7.928725330e-02f, -2.940250930e-02f, -6.316997860e-02f, 8.654861150e-02f, 4.081206770e-02f, 6.805572660e-02f, -4.337747770e-02f, -7.217656080e-02f, 2.235106750e-02f, 4.037259610e-03f, -6.455984710e-02f, 3.374575450e-02f, -1.007066370e-01f, -1.331430670e-01f, -8.658172930e-02f, 1.300763340e-02f, 5.570345370e-02f, 3.139703350e-02f, 3.415848690e-02f, 2.093181950e-02f, 9.189684690e-02f, 9.000036120e-02f, 7.836432000e-02f, -9.393783650e-02f, -1.940212770e-02f, 7.479016480e-02f, -2.848321200e-02f, 7.418544590e-02f, -6.064501400e-02f, 1.574806870e-02f, 5.399529640e-02f, 6.225952870e-02f, -1.181054040e-01f, -5.889446290e-02f, 7.657422680e-03f, -3.366715460e-02f, 8.519679300e-02f, -1.303194650e-02f, -7.679022100e-02f, -1.166395610e-03f, 4.507536440e-02f, 3.046592880e-02f, -7.464922960e-02f, 5.212636660e-02f, -3.210904820e-02f, -5.143662910e-02f, 2.884323340e-02f, 4.342606290e-02f, -6.791175900e-02f, 4.843869060e-02f, 4.278542470e-02f, -3.354310990e-02f, 9.711251400e-02f, -1.879275220e-02f, 9.268817490e-03f, 3.564557060e-02f, -6.635859600e-02f, 5.969241260e-02f, -4.566412790e-02f, -6.632809990e-03f, 4.413659130e-02f, 7.676085080e-02f, 1.650969870e-02f, -7.661721860e-02f, -8.048939520e-03f, -8.876557650e-02f, -1.091681610e-02f, 1.232554860e-02f, -7.298199090e-02f, -1.035958750e-01f, -7.937842600e-02f, -4.610090700e-02f, -8.335588870e-02f, 2.225094660e-02f, -2.963668290e-02f, 7.171756770e-02f, 1.014658160e-02f, 4.131449760e-02f, 3.858798370e-02f, -2.853694190e-02f, 2.590154110e-02f, -6.703461710e-02f, 8.748610320e-02f, -1.974534800e-02f, 5.776377390e-03f, 4.549424160e-03f, -3.908387570e-02f, -4.209044860e-03f, -3.354744990e-02f, -3.604415060e-02f, 2.090372700e-02f, -5.975916610e-02f, -3.294501450e-02f, 2.062405090e-02f, -7.455892120e-02f, -7.300029970e-03f, -4.831306260e-02f, -4.593625290e-02f, 2.896500940e-02f, -6.298305090e-02f, -4.866307600e-02f, -6.871209290e-02f, 4.732498150e-02f, -5.499538410e-02f, -1.112329890e-01f, 1.535139750e-04f, 2.553630250e-02f, 5.914336070e-02f, 4.470105470e-02f, 7.639534310e-04f, 7.818648960e-02f, 6.669021400e-02f, 3.033754880e-03f, -2.745882420e-02f, -5.570912730e-02f, -2.146550450e-02f, 5.288889630e-03f, 3.093384580e-02f, -5.921076980e-02f, -3.369439770e-02f, -1.814533580e-02f, -8.879172050e-02f, 6.848330140e-03f, 2.617477250e-02f, 6.380360570e-02f, 2.238076180e-02f, -3.037969210e-02f, 1.017277940e-03f, -1.071052180e-01f, 2.135688440e-02f, 2.205550480e-02f, -6.106717510e-02f, 6.064241290e-03f, 1.512610540e-02f, -3.292138500e-02f, -7.184978570e-02f, 7.200377430e-02f, -1.012497770e-01f, -2.179220690e-02f, 2.429537850e-02f, -1.017447110e-01f, 4.408129680e-02f, -6.077121200e-02f, -7.637833060e-02f, 5.229077490e-02f, -8.382640030e-02f, -4.124804590e-02f, 5.218826610e-02f, -2.866183220e-02f, 5.737647790e-02f, 1.648934740e-02f, -4.293021190e-02f, -5.239173020e-02f, -1.170784700e-02f, 5.240235480e-02f, -4.299186540e-02f, 6.855158600e-03f, 2.620531060e-02f, 2.597677990e-03f, -1.931566750e-02f, -6.592141090e-02f, -9.529575700e-02f, -2.301053520e-02f, -1.066256910e-01f, 2.383585090e-03f, -6.939373910e-02f, -9.925623980e-02f, 3.697419910e-02f, -1.094364000e-01f, -7.248621430e-02f, -3.728086500e-02f, -7.980843630e-02f, 5.320716650e-02f, 3.808399290e-02f, 6.383708110e-02f, -9.353842580e-02f, -9.619385940e-03f, 1.722883810e-02f, 2.965208330e-02f, 1.373116950e-02f, -8.641897140e-02f, -6.365435570e-02f, 2.545367370e-02f, -4.143470530e-02f, -7.630932330e-02f, 2.909391000e-02f, 9.767872840e-02f, -8.753067250e-02f, 2.170508910e-02f, 2.869757360e-03f, -1.470193640e-02f, -3.927729280e-02f, -3.012043420e-02f, -6.971801070e-02f, 1.918200400e-02f, 6.837647410e-02f, -1.648183910e-02f, 6.034354120e-02f, 1.664021800e-02f, -7.470846760e-04f, 2.641303840e-02f, -2.816856090e-02f, -6.718844640e-03f, 5.394764620e-02f, 3.882291170e-02f, 7.424525170e-02f, 6.784517780e-03f, -4.403803870e-02f, 7.175163180e-02f, 5.415892600e-02f, -1.067991740e-02f, -5.105356500e-02f, -3.338444980e-02f, -1.103163140e-01f, 3.842810910e-02f, 5.679168920e-02f, -6.824799630e-02f, 3.866397960e-02f, 8.867553440e-03f, -2.482476640e-02f, 5.551892890e-02f, 9.422473610e-02f, 5.849522720e-02f, -3.656648100e-02f, 9.307125210e-02f, 5.043644090e-02f, 5.050120880e-02f, 4.485423860e-02f, -5.985519380e-03f, -2.424353730e-02f, 9.383535010e-03f, 4.447418080e-02f, 5.515313150e-02f, -2.612051000e-02f, -5.204164980e-02f, -6.869233400e-02f, -6.688721940e-03f, -2.039829830e-02f, 9.174237960e-03f, 1.506845190e-02f, -3.861669450e-02f, -3.145140040e-02f, -3.170219440e-02f, -3.371089320e-02f, 6.168167290e-02f, -2.895921100e-02f, -4.653307800e-02f, -2.872773070e-02f, 5.518045280e-03f, 1.701777240e-02f, -1.878243130e-02f, -4.829559010e-03f, 2.949934270e-02f, 3.489487990e-02f, -2.979668790e-03f, 1.596662960e-02f, -6.664948910e-02f, -8.128097650e-02f, 1.404194630e-02f, -3.583844380e-02f, -2.129394560e-02f, -6.375125800e-02f, 7.961392400e-02f, -3.192228080e-02f, -8.277045930e-02f, 4.161886500e-02f, 4.834962080e-03f, -5.545770000e-02f, -3.894737360e-02f, 1.900218430e-02f, -5.106408890e-02f, -6.326084580e-02f, -1.208014120e-01f, -2.928714270e-02f, -7.098317890e-02f, 1.677556150e-02f, 8.730569480e-02f, 2.700285610e-02f, 3.438163180e-02f, 2.587848340e-02f, 1.919847560e-03f, 5.386312680e-02f, -6.156888230e-02f, -2.985147390e-02f, 7.262908670e-02f, 6.109167260e-02f, -9.238332500e-02f, 3.255849700e-02f, -6.232497460e-02f, 4.471867530e-02f, -8.987638350e-02f, 4.310350120e-02f, -2.932500090e-02f, -1.867008630e-03f, 7.221571360e-02f, -6.166187670e-02f, -2.646056560e-02f, 2.620022370e-02f, -5.691078680e-02f, 4.034192860e-02f, 4.504121470e-02f, -4.591077570e-02f, -1.053138230e-01f, -3.145679460e-02f, -4.729564860e-02f, -2.929994280e-02f, -1.437305940e-02f, 4.295385260e-02f, 1.046594830e-01f, -2.526838150e-02f, -7.198370250e-02f, -1.679099720e-02f, -1.203450110e-01f, -2.694052640e-03f, 2.829516600e-04f, 1.057464180e-01f, -1.356398030e-02f, -8.330541100e-02f, 2.564972450e-02f, 5.885033310e-02f, 9.193148460e-03f, 1.510706730e-02f, 3.311134500e-02f, 8.461526600e-03f, 5.760489400e-02f, -2.394974600e-02f, 1.744663340e-02f, -8.091610860e-03f, 4.843261840e-02f, -7.370150650e-03f, -6.701488980e-03f, -1.132309590e-01f, 1.332590640e-02f, 7.242768260e-02f, 3.282703830e-02f, 3.381564100e-02f, 6.915880740e-02f, 6.778169420e-02f, -6.446414630e-03f, -5.292224510e-02f, -1.806650500e-02f, -2.352263410e-02f, 4.502572860e-02f, -7.222437850e-02f, -8.263385300e-02f, -1.021323130e-01f, -1.079289710e-02f, -4.520893840e-02f, 8.930170540e-02f, 8.232930300e-02f, -1.081895230e-01f, -5.111262570e-02f, -2.642464820e-03f, 1.419712140e-02f, 7.117328040e-02f, 5.442482980e-02f, -9.628900140e-02f, -3.488533570e-02f, -8.077509700e-02f, 2.892100250e-02f, 8.047986770e-02f, 3.549041970e-02f, -1.100543590e-01f, 1.005537660e-01f, 1.848347860e-02f, -4.219417930e-03f, 1.006850670e-01f, 1.304191820e-02f, 1.181913690e-01f, -8.393119280e-02f, -2.413755660e-02f, -3.881193320e-02f, -1.042005610e-02f, -2.340202220e-02f, -2.323329260e-02f, -4.261596870e-02f, 2.767170030e-02f, 3.714779760e-02f, -2.342188730e-02f, 6.256995350e-02f, -7.129561160e-02f, -6.764114370e-03f, 1.867541670e-02f, -1.008743490e-01f, -1.442866120e-02f, 4.942652960e-02f, -8.711823070e-02f, 2.628730610e-02f, 1.317915230e-02f, 5.299250410e-02f, -1.156862750e-01f, -3.985985370e-02f, 1.027230450e-02f, 8.706782760e-02f, 5.687808990e-02f, -8.955758060e-02f, 9.040263290e-02f, 7.296062260e-02f, -6.864421070e-02f, -8.808095000e-02f, 1.692842880e-02f, -2.028438080e-02f, 1.046566670e-02f, -9.300945700e-02f, 3.354842960e-02f, -3.657948600e-02f, -2.438687530e-02f, -1.350411960e-02f, -5.005522820e-02f, -2.945873700e-02f, -1.021966560e-01f, 4.893712330e-02f, 2.049706880e-02f, 8.402419090e-02f, -4.263741520e-02f, -3.746763620e-02f, -3.620950880e-02f, 3.842106460e-02f, 5.932982550e-03f, 7.873687140e-02f, 8.154954760e-02f, 3.158415480e-02f, -2.428570020e-02f, 1.044994870e-02f, 6.701786820e-02f, 1.926000790e-02f, -3.896756100e-02f, 3.922626780e-04f, -7.666291300e-02f, -1.475705650e-01f, -4.990582910e-02f, -6.028029700e-02f, -5.434754860e-02f, 1.715241000e-02f, 3.409440440e-02f, -5.235833670e-02f, -7.778617730e-02f, 4.587109760e-02f, -3.383554890e-02f, 4.472303390e-02f, 2.331464920e-02f, 3.438312930e-02f, -6.370580200e-02f, 5.972187220e-02f, -1.104010190e-01f, -5.576169860e-02f, 4.150562360e-02f, -6.726568190e-02f, -2.108454150e-02f, -5.790528280e-02f, 6.404082480e-02f, -2.433357290e-03f, 7.163375620e-02f, 5.791238320e-02f, -7.092665880e-02f, -4.066722100e-02f, 4.633304200e-03f, -3.200107810e-02f, 3.347466140e-02f, 5.256377910e-02f, 3.566290950e-03f, 2.242139350e-02f, -6.899017100e-02f, 1.207859810e-01f, -4.948484530e-02f, -9.127819540e-02f, 3.902877450e-03f, 6.957023590e-02f, 9.092420330e-02f, 4.370727760e-02f, 5.309455100e-02f, -4.789860550e-02f, 1.618595790e-02f, -3.257099910e-02f, -1.035549270e-01f, -4.331195730e-02f}; + +Kokkos::View __constant_144x64xf32; +float __constant_144x64xf32_initial[9216] = {5.315088850e-02f, -5.539280550e-02f, 1.406939180e-01f, -3.756879270e-02f, -3.407692540e-02f, -5.630335210e-02f, -4.322223370e-02f, -2.298609170e-02f, 1.417845340e-01f, 3.939522430e-03f, 7.863004690e-03f, -4.558882860e-02f, -3.786612070e-04f, -5.735582860e-02f, -2.920057620e-02f, 3.725349900e-02f, -4.117017240e-02f, 1.174435170e-01f, -4.920261730e-02f, 4.640430210e-02f, 3.271802140e-02f, 4.594927280e-02f, 6.827098880e-02f, 4.283360390e-02f, 1.511753050e-01f, 2.792264520e-02f, -3.664299100e-02f, -1.570593570e-02f, 9.774298220e-02f, -2.656169610e-02f, 1.328264080e-02f, 2.392841500e-02f, 1.570566890e-01f, -1.276369210e-03f, 1.033857280e-02f, 1.999163440e-02f, -4.650753740e-02f, -1.192738120e-02f, 1.204921600e-01f, 8.380914800e-04f, 7.548831400e-02f, 1.754960230e-02f, 2.874526200e-02f, -1.059928440e-02f, 2.703927460e-02f, 5.498602610e-02f, -2.691229990e-02f, 1.913471710e-02f, 1.455157440e-02f, 2.072959950e-02f, -1.459079330e-02f, 1.081483810e-02f, 1.371787790e-01f, -8.312602340e-02f, -1.996194760e-02f, 2.033145540e-02f, 1.186395360e-01f, 5.084422600e-02f, 1.444700550e-02f, -1.470311450e-02f, -2.871473510e-02f, 6.624209880e-02f, -1.824084480e-02f, 2.213344420e-01f, 2.967969140e-02f, -8.313309400e-02f, -8.821961280e-02f, 1.066774870e-02f, 7.845801860e-02f, -7.057195160e-02f, 1.424898510e-04f, -3.276550400e-02f, -2.996906640e-03f, -2.728736210e-02f, -2.440665380e-03f, -1.326822580e-02f, 2.009500280e-03f, 2.328451160e-02f, 2.870127370e-02f, -2.172200940e-02f, 1.361359470e-02f, -8.989850430e-02f, -6.458944080e-02f, -4.206186530e-02f, -2.946516870e-02f, 1.514665500e-02f, 7.977982050e-03f, -1.436071100e-02f, 7.055103030e-02f, -5.857977080e-03f, 7.567896970e-03f, -2.667935570e-03f, -2.940734850e-02f, -3.058883360e-03f, -8.260492230e-02f, 2.075510620e-01f, -1.707089320e-02f, -2.061503010e-02f, 1.842967420e-02f, 3.606683760e-02f, 2.450105250e-01f, 2.970369720e-02f, -5.565513670e-02f, 2.372005770e-02f, -7.838837050e-02f, 7.520674910e-02f, -2.061413830e-03f, 4.585381220e-02f, -6.029058620e-02f, -8.330067240e-02f, -5.264806750e-02f, 2.869249880e-02f, 1.473917510e-01f, -1.589060390e-02f, -7.203464210e-02f, -3.925172240e-02f, -8.046916690e-03f, 2.698621530e-02f, 1.156854930e-01f, -1.702886630e-02f, -6.056265530e-02f, -2.284358440e-02f, 1.749679600e-01f, -1.670601410e-02f, 1.579854640e-02f, 2.764224070e-02f, -3.487261380e-02f, 5.985099080e-02f, 7.107723500e-02f, 2.360610110e-02f, 1.502238770e-02f, -1.022724430e-01f, 1.454667650e-02f, 6.207497790e-03f, -3.788215670e-02f, 2.276483180e-01f, 3.366207330e-02f, -3.118817690e-02f, 3.185781460e-02f, -1.985310760e-02f, -2.236581220e-02f, -2.875245550e-02f, 2.008833550e-02f, 3.134549780e-02f, 3.428677560e-03f, 3.032559160e-02f, 1.344907730e-01f, 2.821784280e-02f, -2.208102310e-02f, 1.193265690e-01f, -3.614743050e-02f, 1.266904770e-01f, -7.048255210e-02f, -2.646348250e-02f, -5.757248400e-02f, 2.494714920e-03f, -2.663378420e-02f, -4.393273590e-02f, 4.333018140e-02f, 4.770071430e-02f, 4.129136730e-02f, 6.008173900e-02f, -2.707935870e-02f, -4.451971130e-02f, 3.497034310e-01f, 8.825275120e-03f, 1.686918780e-03f, -1.561274100e-02f, 2.093207240e-01f, 5.895349010e-02f, -3.880743680e-02f, -4.368836810e-02f, 4.294547070e-02f, 1.283053760e-01f, 2.136649010e-02f, 7.682223340e-03f, -7.958945820e-03f, 1.153409180e-01f, -2.308188190e-02f, 4.248096790e-02f, -4.344783350e-02f, -4.934940490e-03f, 2.433673660e-02f, -2.961672610e-03f, 9.864015870e-02f, 6.308355370e-03f, -3.197329120e-02f, 6.625392470e-03f, 1.733726820e-02f, -8.251664230e-03f, -7.637618690e-04f, -2.744759620e-02f, 2.851128580e-03f, -8.851435970e-03f, 3.901567780e-03f, 8.772654830e-02f, -3.308781240e-02f, 4.498941820e-02f, 1.390991960e-01f, -1.507656930e-02f, -6.456785370e-03f, -4.382987690e-02f, 1.759144110e-02f, 1.160444990e-01f, 5.270599570e-02f, 2.564874110e-02f, 1.865300580e-03f, 4.909332470e-02f, -2.057497950e-02f, 2.222555220e-03f, -3.787858410e-02f, 1.046153230e-01f, -5.180248620e-02f, 1.092649850e-01f, 2.809855340e-02f, 1.016395690e-01f, -3.695286810e-02f, 1.448532570e-02f, -1.653493570e-02f, 1.040581030e-03f, -2.458173040e-02f, 1.416074210e-02f, 8.467421680e-02f, -2.453853940e-02f, -1.873806860e-02f, -3.698486460e-02f, -2.357896230e-02f, -5.560522900e-02f, 3.108738460e-03f, 6.726359580e-02f, -2.700108660e-02f, 5.058187990e-03f, -1.291149950e-02f, 8.313115680e-02f, 4.564816880e-02f, -7.953026890e-02f, 3.331310750e-01f, -4.878633100e-02f, -2.169941920e-02f, 9.228569260e-02f, -3.841059280e-02f, -2.474180800e-02f, -4.898623750e-02f, 2.585807350e-03f, 5.386406180e-02f, -4.811720920e-02f, 2.171636070e-01f, 8.208933470e-02f, 9.518433360e-02f, -3.275377680e-02f, -4.332776740e-02f, -4.230045150e-02f, 2.926202860e-02f, 5.790477620e-02f, -3.588404510e-02f, 6.591766140e-03f, 3.007042220e-02f, 6.892178950e-02f, -6.143793460e-03f, 6.589163090e-02f, 7.822807130e-02f, 1.143565180e-01f, -3.726446260e-02f, -9.230574590e-03f, -2.167356760e-02f, 5.089486020e-03f, 9.247390930e-02f, -3.125095740e-02f, 1.366245600e-01f, -7.388807090e-02f, -3.085849620e-02f, -6.973598900e-02f, -4.163679480e-02f, 1.190680860e-01f, -3.137033810e-02f, -3.840215880e-02f, 7.505236570e-02f, 6.967742740e-02f, 1.009898780e-01f, -1.556694040e-02f, -6.740085780e-02f, 9.611730280e-02f, 1.612662230e-01f, -4.753650170e-03f, 7.520493120e-02f, 1.410219670e-01f, -6.443300100e-02f, -4.809870200e-02f, 9.463877980e-02f, -9.106352920e-02f, -5.222975840e-02f, -2.767513320e-02f, 3.626802940e-02f, 5.862485620e-03f, -2.241716720e-02f, -3.009939570e-02f, 9.423317020e-02f, 2.224117980e-03f, -3.166917340e-02f, 9.074984110e-03f, 3.624960040e-02f, 4.021831600e-02f, 1.980679180e-01f, 5.462981760e-02f, 8.657407010e-02f, -4.406457770e-02f, 5.250749360e-02f, -4.805218430e-02f, -4.167127240e-02f, -2.437689710e-02f, 1.030786340e-01f, 2.333440070e-02f, 4.197730680e-03f, 3.069294990e-02f, -2.847319100e-02f, 1.162142080e-01f, -2.639501180e-04f, 4.222267490e-02f, -8.394730090e-02f, -2.850494910e-02f, 3.991183640e-02f, 8.878299960e-03f, 8.876381440e-03f, 1.260659010e-02f, -7.999426870e-02f, 5.070816260e-03f, -7.471501080e-02f, 3.972287100e-02f, -5.717937650e-02f, -5.031725390e-02f, 1.429311000e-02f, 4.333627220e-02f, 2.005980310e-01f, -1.190339680e-02f, 2.072854900e-02f, -3.946048770e-02f, -8.908977730e-03f, 1.096143130e-01f, 4.933189230e-02f, -5.145987500e-02f, -3.794317690e-02f, 9.327557680e-02f, -7.319770750e-02f, 1.013132090e-02f, -1.772418250e-02f, -3.438865020e-02f, 5.506157500e-02f, 4.722239100e-05f, -3.280100230e-02f, -4.787757250e-02f, 3.732762860e-02f, -1.182408540e-03f, 7.540714000e-02f, 7.407923040e-02f, 4.819222910e-02f, -1.028188320e-02f, -2.303299310e-02f, -2.949432470e-03f, 8.370313040e-02f, -5.010446160e-02f, -2.176798180e-03f, 6.566006690e-02f, 4.031654450e-02f, 2.255386260e-01f, -4.897127300e-02f, -1.868863590e-02f, -5.806843940e-02f, -1.594626340e-02f, -4.103193430e-02f, 2.848925260e-02f, -2.400124450e-02f, -1.254799220e-02f, 7.041683050e-02f, -1.406196130e-02f, -2.613609540e-04f, -1.609673720e-02f, -4.634986070e-02f, 8.399954060e-03f, -4.250840100e-02f, -4.354887460e-02f, 3.096467850e-01f, 5.766333640e-02f, 6.344465910e-02f, -5.103483050e-02f, -3.453084080e-02f, -6.205798690e-02f, -5.532201750e-02f, -2.801371180e-02f, 6.347502770e-02f, -1.070311570e-02f, 1.462460460e-01f, 5.519074620e-04f, 3.439474110e-02f, -4.150509460e-02f, 1.473031490e-01f, -9.862446230e-03f, 1.019403800e-02f, -3.556749970e-02f, 8.963292090e-02f, -1.500843370e-02f, 1.440816970e-01f, 5.290025470e-02f, -2.998237500e-02f, -2.812597710e-02f, -1.930469460e-02f, -5.016008760e-02f, -4.393173010e-02f, -3.039519490e-02f, -2.178862320e-02f, -6.297832730e-02f, 3.800705670e-01f, -9.093850850e-03f, -3.215120730e-02f, -3.493629400e-02f, 8.424442260e-03f, -2.516602720e-02f, -7.271840240e-03f, 7.757832110e-02f, 4.230547320e-02f, 1.176081950e-03f, -1.762988230e-02f, 2.573698760e-02f, 3.990915050e-02f, -2.519926240e-02f, 8.976313290e-03f, -2.013607140e-02f, 2.005758510e-02f, -3.637337310e-02f, -5.244733770e-02f, 7.288527480e-02f, -2.026519920e-02f, -6.481090180e-02f, 2.112748290e-02f, 7.253633440e-02f, 1.856069080e-02f, 2.525586260e-02f, 9.229964760e-02f, -7.519244680e-03f, 7.334440950e-02f, -4.122393580e-02f, 1.869158150e-01f, -2.119031550e-02f, 4.349124430e-02f, -3.427793460e-02f, -3.545107690e-02f, -1.072218180e-02f, -4.013281690e-02f, 6.478240340e-02f, 8.464922010e-02f, 2.354108540e-02f, 1.167204530e-01f, -3.679190580e-02f, 4.986504470e-02f, 7.203942540e-02f, -5.454093220e-02f, -4.359496380e-02f, 2.528517880e-02f, -3.652108830e-02f, -3.142476450e-02f, 1.234618200e-02f, -5.448295180e-02f, -8.472581390e-03f, -3.644240650e-02f, -2.932515370e-02f, -2.834979440e-02f, -4.314542930e-02f, -7.519291250e-03f, 3.237910200e-02f, 1.527893390e-01f, -6.766620270e-02f, -6.009628620e-02f, 2.391125260e-02f, 3.171333670e-02f, 7.112403210e-02f, 1.259256010e-01f, -1.343716220e-02f, 9.087642280e-02f, -2.295554990e-02f, -4.438300060e-02f, 1.129086320e-01f, -2.791455200e-02f, 1.088417790e-02f, -1.664002610e-02f, -2.849431340e-02f, 1.824149120e-02f, 3.944932520e-01f, 1.249406410e-01f, 4.741437730e-03f, -1.533103360e-02f, 7.897431030e-03f, 3.792830180e-02f, -2.049749720e-02f, 7.305242870e-02f, -2.668063530e-02f, -1.327838930e-02f, 1.915092700e-03f, -5.405009910e-02f, 2.983175400e-02f, 6.543906780e-02f, 5.096947770e-02f, -1.346388550e-02f, 6.962449100e-02f, -1.365580600e-02f, -6.562495600e-03f, 1.370810720e-02f, 9.856955700e-02f, -2.393730450e-03f, -8.372169730e-02f, 4.586385560e-02f, 9.683228280e-02f, -2.899691280e-02f, -8.106625080e-02f, 1.004453560e-02f, 4.697631670e-02f, -4.497176410e-02f, -2.074697610e-02f, -4.986144600e-02f, -8.609010840e-03f, -4.374061900e-02f, 2.848632260e-02f, -2.684580720e-02f, -3.561105810e-03f, 1.326621230e-02f, -8.856093880e-02f, -7.115540650e-02f, -2.401122820e-02f, 1.582022760e-01f, -7.693953070e-02f, 1.691648070e-01f, 1.868944620e-01f, -6.304439160e-02f, 8.112166070e-02f, 7.507229600e-02f, -1.916430660e-03f, 1.572245360e-02f, -3.467299420e-02f, 3.896445410e-02f, 1.063722670e-01f, -3.960846740e-02f, -4.097396040e-03f, 7.337336240e-02f, 4.655689370e-02f, 5.156630280e-02f, 4.040869420e-03f, 7.600345650e-03f, 9.074397390e-02f, -4.783198980e-02f, 1.144268890e-01f, 6.168171760e-02f, 2.459855280e-03f, 1.307410650e-02f, 1.015746780e-02f, -4.003597800e-02f, 1.936177910e-02f, -3.029458780e-02f, 1.546741280e-02f, 4.742242770e-02f, 7.635208960e-02f, 1.189175990e-02f, 3.259357440e-02f, 1.264641140e-01f, -5.986957620e-02f, -7.591597740e-02f, -6.238880570e-03f, -8.829347210e-04f, -5.285565180e-02f, 1.886746660e-02f, 7.632391060e-03f, 4.615334050e-02f, -1.497460900e-02f, -3.603226320e-02f, -4.097318280e-03f, -3.565846760e-02f, 1.758931730e-01f, 3.661682130e-03f, -4.822526500e-02f, 2.854298610e-02f, 8.890321850e-02f, -1.037431600e-02f, 4.417637360e-02f, 1.000418420e-02f, -1.248775610e-02f, 1.678373480e-02f, 6.376837850e-03f, -2.784176170e-02f, 2.063622510e-02f, -1.108947170e-01f, -3.439023350e-02f, 1.270171350e-02f, -3.848521780e-02f, -3.557115050e-02f, 2.563137330e-03f, 6.924652030e-03f, 8.124481880e-03f, 5.128008870e-02f, 1.240254570e-01f, 1.204340090e-01f, -9.095943710e-02f, 6.501383330e-02f, -3.312730040e-02f, -3.401788700e-02f, 1.766635110e-02f, 2.699626800e-02f, -9.928481650e-03f, -3.102282760e-03f, 4.871083050e-02f, -1.809784400e-02f, -7.182196530e-02f, 1.346932800e-01f, -2.126430160e-02f, 7.196231280e-03f, -1.880098880e-02f, 8.831503980e-02f, 6.605674050e-03f, -2.389641290e-02f, 4.574366660e-02f, -4.544151950e-02f, 6.205822150e-02f, 3.163597360e-02f, 5.720965190e-02f, -2.564332080e-02f, -5.130857230e-02f, 4.329521210e-02f, 4.800380770e-02f, 7.498321680e-02f, 2.010413680e-03f, -3.200326110e-02f, 3.880205010e-02f, -1.835505480e-02f, 1.440488700e-01f, 7.254541670e-02f, -7.699646520e-03f, 2.055442930e-01f, -1.926773790e-02f, -9.475672990e-02f, -9.737312790e-03f, 5.703283850e-02f, -5.987570430e-02f, 3.412808480e-01f, 8.340059960e-02f, 3.785829990e-02f, -1.875133630e-02f, -3.105684650e-03f, 1.690593360e-02f, 7.516512270e-02f, 7.171074300e-02f, 7.014800610e-02f, -3.027837720e-02f, 1.954769490e-01f, 5.695170260e-04f, -8.031923320e-02f, -7.868547690e-04f, 2.906840480e-02f, -5.340259520e-02f, 6.070740060e-03f, -3.254953770e-02f, 7.839868960e-02f, -5.926318470e-02f, 8.279258010e-02f, -3.949554260e-02f, -1.124184650e-01f, 6.855318320e-03f, 3.769326580e-02f, 4.499278590e-02f, -3.806360070e-02f, -4.799716920e-02f, -2.352098000e-02f, 1.373364500e-02f, 6.879940620e-02f, -3.744161500e-02f, -2.440003310e-02f, -2.416220120e-02f, 8.599515260e-02f, -8.224593100e-02f, -1.432971280e-02f, -5.379633610e-02f, 3.233940810e-03f, -9.108728170e-02f, -2.384745140e-02f, 7.921797030e-02f, -3.041891380e-03f, 2.650735340e-02f, -3.643383460e-02f, 1.104320290e-01f, -5.030415210e-02f, 7.713112510e-03f, 9.994545250e-04f, -1.454770100e-03f, 4.192208130e-02f, 8.727984130e-02f, 1.352884020e-01f, 7.445637880e-02f, 3.284523260e-04f, 7.553293370e-03f, -1.466727070e-02f, -2.181607860e-02f, -1.344755200e-02f, -1.846489680e-02f, 2.631862460e-02f, -6.422783430e-02f, -2.694797890e-02f, 1.909247930e-01f, -5.638712640e-02f, 2.194488050e-02f, -3.872209040e-02f, -3.580729290e-02f, 3.120599500e-02f, 1.026061770e-01f, 9.982196980e-02f, -6.012821200e-02f, 3.139111030e-02f, 4.363127430e-02f, 3.260161490e-03f, -1.655975360e-02f, 1.104317230e-01f, 1.030867550e-01f, 1.285658930e-01f, -4.072203860e-02f, -1.274997830e-03f, 1.108307390e-01f, -2.305669900e-02f, 2.752806430e-02f, 3.384185210e-02f, 4.364656660e-02f, 7.193778460e-02f, -4.306698220e-02f, -6.416802110e-02f, 9.834790970e-02f, 2.149084360e-01f, -1.255469300e-02f, -1.944493130e-02f, -2.938741820e-02f, 1.642734860e-01f, 4.295965280e-02f, -2.739955670e-02f, 2.895445000e-02f, -3.929147500e-02f, -5.710316450e-02f, -1.000278720e-02f, -1.082895320e-02f, 4.050241040e-02f, -3.434918080e-02f, -7.545548960e-03f, 6.538046150e-02f, 5.960280820e-02f, 1.836759750e-01f, 1.142925170e-01f, 4.338873920e-02f, 2.568818630e-02f, 1.837531330e-01f, 6.912472840e-02f, -2.328333260e-02f, 2.019423620e-02f, -9.236524250e-02f, 2.106910390e-02f, 1.101149710e-02f, 3.292457010e-02f, 1.179091860e-01f, -2.662712520e-02f, -2.147113160e-02f, 1.196331980e-01f, 2.869581240e-02f, 2.689250930e-02f, -6.069950010e-02f, 9.047590200e-02f, 2.365340010e-03f, 1.294279280e-02f, 1.680425930e-02f, -4.093992710e-02f, 1.572488100e-01f, 1.668897270e-02f, 8.418728410e-02f, 1.103621540e-02f, -1.427877320e-02f, 8.595830200e-02f, -9.686672130e-03f, -2.027950440e-02f, 1.585481130e-02f, 7.659146930e-02f, 8.277588520e-03f, -7.118836790e-02f, -7.637417000e-05f, -1.207519790e-02f, 1.866479810e-01f, -6.660409270e-02f, -4.663427550e-02f, -2.061849460e-02f, 1.727467220e-02f, 1.513269170e-02f, 8.472811430e-03f, 2.388304290e-02f, -5.647686870e-02f, -5.100713670e-02f, -5.469778930e-02f, 1.081935780e-02f, -1.987154600e-03f, -2.353313940e-02f, 1.916717740e-02f, -4.808242990e-02f, 1.049146350e-01f, 1.669689570e-01f, 1.016028450e-01f, -3.144608440e-02f, -6.801978500e-02f, 8.105147620e-03f, 4.813949580e-03f, 1.547570820e-01f, -6.694794450e-02f, 2.161839050e-03f, 1.725538370e-01f, 7.771958410e-02f, -3.768268230e-02f, -5.614024770e-02f, 4.944985360e-02f, 1.562134080e-02f, 4.832236470e-02f, 3.940257800e-02f, -1.508403660e-02f, -2.348872090e-02f, -2.051439320e-02f, 8.492210500e-02f, 1.825200020e-02f, 3.207306560e-02f, -8.583207610e-03f, -3.691820060e-02f, -7.333747300e-02f, -4.432692750e-02f, 1.762362120e-01f, 4.112877420e-03f, 2.296545210e-01f, -2.374713500e-02f, 1.532666200e-02f, 5.615277220e-02f, 1.127648350e-01f, 2.725246730e-02f, -1.497470030e-02f, 1.034706610e-01f, -6.144589560e-02f, 1.586896180e-01f, 1.525877420e-01f, -1.746740560e-02f, 1.145787460e-01f, 1.906221170e-02f, 1.975999590e-02f, -8.780286650e-03f, -1.438325830e-02f, -9.295667710e-02f, -1.023702790e-02f, -2.767271730e-02f, 7.458857450e-02f, -1.577179760e-03f, 8.446847090e-03f, 1.983591470e-01f, 1.272206290e-02f, -1.422716770e-02f, 7.369090620e-02f, 1.596435900e-02f, -1.951271110e-02f, -1.144477260e-02f, -5.235612390e-03f, -5.021244290e-02f, -5.081179740e-02f, 1.525380460e-01f, -4.055388270e-02f, -2.422468550e-02f, 1.098842990e-01f, 1.595611680e-02f, -3.908967230e-02f, -5.079726130e-02f, -1.515843070e-02f, -6.296832110e-02f, 1.701108930e-02f, 2.674480340e-02f, 8.065227410e-03f, 1.097235680e-01f, 7.332784680e-02f, -1.974034310e-02f, -2.538779010e-02f, -2.864883840e-02f, 1.490995880e-01f, 1.301553990e-01f, -3.370209780e-02f, 3.364031760e-02f, 3.222666680e-02f, 3.228839490e-02f, -6.131987270e-02f, 2.175506950e-02f, -3.456718470e-02f, -6.767842170e-02f, 1.152382870e-01f, 1.051056390e-01f, -3.883852440e-02f, 1.810883110e-04f, 2.586473340e-02f, -5.330590900e-02f, 2.440011500e-02f, -6.798361240e-02f, -6.528536320e-04f, -3.767371920e-02f, 5.078478530e-02f, -1.180736530e-02f, -1.106083950e-02f, 4.079400380e-02f, 8.348545430e-02f, 9.355593470e-02f, -1.882083530e-02f, -1.884593630e-02f, 2.429488300e-02f, 1.926871250e-03f, -4.012814910e-02f, -5.077747630e-02f, -3.520187740e-02f, 4.170953300e-03f, -1.130239740e-01f, 7.136300950e-02f, -4.911765830e-02f, 8.687242120e-02f, 5.433376880e-03f, 4.471129180e-02f, -7.678464050e-02f, 1.519115180e-02f, 3.762449320e-02f, 3.162872050e-02f, 2.423106230e-03f, 5.042038110e-02f, -5.304685610e-02f, 1.955921020e-02f, -4.784479740e-02f, 8.553875370e-04f, -4.056082670e-02f, 3.395246570e-03f, 9.306312350e-02f, 1.280575990e-03f, 1.038499850e-01f, -7.218829540e-02f, -6.725033370e-02f, 9.621506920e-02f, -2.932098320e-02f, -3.050789610e-02f, 5.502789280e-04f, 3.724398460e-02f, 2.379745060e-02f, -3.568542750e-02f, 5.805210770e-02f, 2.099430000e-02f, 2.295901250e-02f, -3.889035060e-02f, -3.887069600e-02f, -3.188245740e-02f, -6.347075850e-02f, -9.199907630e-02f, 5.225624520e-02f, 3.888892010e-02f, -5.766835440e-02f, 1.147394550e-01f, 1.264962850e-01f, 5.028777570e-02f, 1.331666110e-01f, 1.663918420e-02f, -3.456057240e-02f, 4.704797860e-01f, 1.040541980e-01f, 3.985605760e-02f, 1.515678360e-03f, -3.264565250e-03f, 1.965278760e-02f, 3.638869520e-02f, -4.721900450e-02f, -5.084063860e-02f, -3.214229640e-02f, 4.899527130e-02f, 2.091296020e-01f, -6.994011350e-03f, 3.853606810e-02f, -2.797486820e-02f, -4.180320720e-02f, 3.823940830e-02f, -2.797972600e-02f, 6.458137650e-03f, 5.122841150e-02f, 3.394361960e-02f, 2.886770670e-02f, 3.532993050e-02f, 5.323312430e-02f, 4.409385100e-02f, -1.147938240e-02f, 1.277854200e-02f, 1.293721140e-02f, 1.018469860e-01f, -1.646271350e-02f, 1.711052840e-02f, 6.145204600e-02f, -3.433631360e-02f, 8.250587430e-02f, -3.042244820e-03f, 3.915011140e-02f, -4.136530310e-02f, -6.223960220e-02f, 1.464908290e-02f, 3.182296180e-03f, -5.710180850e-02f, 1.431296670e-02f, -2.363124120e-02f, 1.087084040e-02f, -4.369949920e-02f, 1.451811050e-01f, -4.281983900e-02f, 2.443618700e-02f, -2.278089710e-02f, -2.886809590e-02f, 3.929055480e-02f, -3.475464510e-02f, 2.847913840e-02f, 5.379797890e-02f, 4.653564840e-02f, 4.640818760e-02f, 1.362899390e-01f, -3.904854880e-02f, 4.347287860e-02f, 1.372292190e-01f, -3.508873660e-02f, -2.804749460e-02f, -4.121769220e-03f, -6.499725580e-02f, 3.276849540e-02f, -5.392218750e-02f, 6.540511550e-02f, -6.912304460e-02f, -3.380544860e-02f, 1.188182090e-01f, 1.387779710e-01f, -5.614948270e-02f, -1.208008270e-02f, 2.747889050e-02f, 9.432060270e-02f, -6.487548350e-03f, 2.176796640e-01f, -3.086866810e-02f, -8.929170670e-03f, 1.091859490e-02f, 8.607434100e-03f, 1.162726060e-01f, -3.978257630e-02f, -2.715413640e-02f, -9.068620270e-04f, 1.008578240e-01f, -7.508643900e-03f, -1.861411150e-02f, 5.793165420e-03f, -1.848861950e-02f, -9.019830070e-02f, -5.098567340e-03f, -3.842876110e-02f, -1.431079020e-02f, 2.926940840e-02f, 5.636361430e-03f, -2.658064480e-02f, 3.284697980e-02f, 2.457410280e-02f, -2.305054110e-02f, 2.964913470e-02f, 1.811319290e-01f, 1.248769090e-01f, 5.934277920e-02f, 5.389659110e-02f, 8.721365030e-02f, -6.246883040e-02f, -1.213808920e-02f, 8.145761680e-03f, -2.372109330e-03f, 2.754408870e-02f, 4.519312080e-02f, 4.158832130e-02f, -4.410113770e-02f, 6.909231840e-02f, 6.059259550e-02f, 2.472079730e-02f, -8.726817560e-03f, -4.894550520e-02f, -2.948161210e-03f, 1.374222930e-01f, 1.869631560e-02f, 1.728020760e-01f, 2.063166650e-01f, 2.137334830e-02f, -2.592781740e-02f, 1.157656160e-01f, 9.929425260e-02f, -2.294198050e-02f, -3.949842970e-02f, 1.830860040e-02f, -7.168093320e-02f, -3.298943120e-02f, -6.037896130e-02f, -6.532860550e-02f, 1.143762390e-01f, -1.079844500e-02f, 9.915395630e-03f, -1.253925360e-02f, 3.841896950e-01f, -7.058359680e-03f, -2.995600740e-02f, 1.454753610e-02f, 5.408350750e-02f, 6.863613430e-02f, 5.615564440e-02f, -2.028165940e-02f, 5.715469830e-03f, 2.536680920e-02f, 2.343314890e-02f, -5.346879740e-02f, 2.053577080e-02f, -3.292904050e-02f, -1.212095660e-02f, -1.649252880e-02f, -1.561644110e-02f, -1.921318660e-02f, 2.166323210e-01f, -6.196271630e-02f, -6.245394700e-03f, 5.779578160e-02f, 1.824286020e-02f, 4.417324810e-02f, -2.462245150e-02f, -2.639832720e-02f, 7.164428380e-02f, -3.863866630e-02f, 5.345539660e-03f, -1.258850190e-02f, 4.075575150e-03f, -5.006823320e-02f, 6.380093100e-02f, -3.564585700e-03f, -4.995212330e-02f, -2.756651120e-02f, 1.582868020e-02f, 7.840909800e-02f, 1.936971400e-02f, -2.147934590e-02f, 2.105328140e-01f, -1.885973850e-03f, -2.303369340e-02f, 1.107118930e-02f, -8.786086920e-03f, 6.224039560e-02f, 3.703708060e-03f, 3.133824840e-02f, 3.260866550e-02f, -3.903352840e-02f, 2.682715280e-02f, -8.820897900e-03f, 6.150360030e-02f, 2.968517690e-02f, 2.277938720e-01f, -4.125453530e-02f, -4.783410580e-02f, -2.155903730e-02f, -2.861892800e-02f, 4.453068600e-02f, 3.714578970e-02f, 6.971815220e-02f, -3.823786040e-03f, -3.656431660e-02f, -5.254924670e-02f, -3.968542070e-02f, -2.187293400e-02f, -3.203140940e-02f, -6.533730780e-02f, 2.557148040e-02f, -3.206593170e-02f, -2.147571560e-02f, -1.408736780e-02f, -4.529248180e-02f, -2.420809680e-02f, 2.325241080e-02f, 2.313143010e-02f, 1.564714160e-01f, -4.666579890e-03f, 5.169394240e-02f, 9.576845910e-04f, -2.360819090e-02f, 8.042668550e-02f, -9.413567180e-02f, 8.972680190e-03f, -1.397788060e-02f, 1.949245180e-01f, 4.228481280e-02f, 3.499463200e-03f, -4.243929680e-02f, -5.449785290e-02f, 5.048228430e-02f, 9.034246200e-02f, 1.037537600e-01f, 1.382845640e-01f, -7.006862010e-02f, 1.670300510e-01f, 2.590670290e-01f, -2.686576360e-02f, 3.250105310e-02f, -5.334745720e-02f, -4.513407130e-02f, 6.578514720e-02f, -9.951989630e-04f, 4.466276240e-02f, -2.971702440e-02f, 4.117549210e-02f, -1.003523170e-02f, 8.529668300e-02f, 3.653332590e-02f, 9.584250300e-02f, 5.601679160e-02f, 8.736196160e-02f, 2.086981200e-02f, -3.670185430e-02f, -3.022105060e-02f, 5.310355500e-02f, -1.005582140e-01f, 2.417846960e-02f, -4.981270810e-02f, 3.675873950e-02f, 1.162119580e-01f, 1.851209070e-02f, 7.187628740e-02f, 2.388443050e-02f, -1.104397330e-02f, 3.065053190e-02f, -2.242951280e-02f, 1.859192250e-01f, 1.186484470e-02f, 5.882536250e-02f, -4.136556390e-02f, -5.254189300e-02f, -9.428169570e-03f, 4.687504260e-04f, -6.050155680e-02f, 1.044119450e-01f, 6.407521670e-02f, 1.798157460e-03f, 1.563464550e-01f, -6.873066720e-02f, -3.288430720e-02f, -2.860126460e-02f, -2.938021530e-02f, 1.726704460e-02f, 2.606145570e-03f, -1.846136150e-02f, -3.096439880e-03f, -5.284217000e-02f, -8.863743390e-03f, 2.356603740e-03f, -5.001223650e-03f, 4.590607250e-03f, 9.155675760e-02f, -9.954962870e-02f, 2.021436100e-01f, 1.544554160e-02f, 3.293753040e-02f, -6.707570700e-02f, -1.540464000e-03f, -4.854606460e-02f, -8.919118550e-04f, -1.541242240e-03f, -3.416904060e-02f, -6.118896600e-02f, -6.878286600e-02f, 1.169064640e-01f, -1.926753670e-02f, -4.003845530e-02f, -8.086990560e-02f, -1.265402420e-02f, -7.400514190e-02f, -4.086277260e-02f, 5.850762500e-02f, 8.468563100e-02f, -1.549479370e-02f, -6.860927490e-02f, 9.258192030e-02f, 1.090933450e-03f, -7.320642940e-03f, 2.386657290e-03f, -1.447668670e-02f, 6.413803990e-02f, -3.262472900e-02f, -5.228704960e-02f, 5.480074790e-03f, 2.350706610e-02f, 6.419727200e-02f, -4.004853310e-03f, 7.321609560e-02f, 5.879506840e-02f, -3.744927930e-03f, -5.125820260e-02f, -7.352474150e-03f, 2.755084040e-01f, -6.670875100e-02f, 1.566596030e-01f, 5.854212210e-03f, 1.453505610e-01f, -4.408768840e-03f, -4.103289540e-02f, 8.495059800e-03f, 6.764404480e-02f, 8.322260340e-03f, -2.621684220e-02f, -3.687777740e-02f, -4.692500830e-02f, 8.062896870e-02f, 7.046842940e-03f, 4.322892430e-02f, 6.230407950e-02f, 7.916593920e-03f, 6.003528830e-02f, -2.909450050e-02f, -7.326730340e-02f, -5.638185140e-02f, 1.230279510e-01f, -3.246056290e-02f, 3.850034250e-02f, -4.769011590e-02f, -9.386114780e-03f, -3.285552190e-02f, 7.798142730e-02f, -3.857812660e-02f, 1.288492380e-01f, -2.527695890e-02f, 1.467822050e-01f, -5.466088650e-02f, 1.778659670e-01f, -5.714579670e-02f, -6.990993390e-03f, 2.749416050e-02f, 8.693081140e-02f, -8.362704510e-02f, 3.138354050e-02f, 7.430116830e-02f, 3.095110690e-02f, 1.362914140e-01f, 9.802562740e-02f, -5.117074030e-02f, -2.109594640e-02f, 6.473194810e-02f, 1.217134580e-02f, -3.207798670e-02f, 3.592100370e-02f, -1.910595600e-02f, 1.721241510e-02f, -6.366743890e-02f, 1.071163220e-03f, 2.392359080e-03f, -3.251893450e-02f, -1.481648070e-02f, 6.111221850e-03f, -4.959044230e-02f, -6.303350440e-03f, 5.404086410e-02f, -2.692813050e-03f, 1.379931270e-01f, 9.331461040e-02f, -1.670253280e-02f, 6.696075950e-02f, 1.036531200e-02f, -2.430649660e-02f, 4.021840540e-02f, -1.079021670e-02f, 1.186028870e-02f, 3.210623190e-02f, -8.726752540e-02f, 1.870970990e-02f, -6.887117770e-02f, 6.061770950e-03f, 5.603559320e-02f, 3.330977630e-03f, 2.343013290e-01f, 2.175670490e-02f, -9.920951910e-03f, -7.546450200e-02f, -1.556363050e-02f, 1.731444600e-01f, 2.220999820e-02f, 8.396347980e-03f, 1.147399540e-01f, -1.217325330e-03f, 2.346623320e-02f, 4.912789910e-02f, -6.679023060e-02f, -4.234740140e-02f, -2.911474740e-02f, -8.150383080e-02f, 4.816807060e-02f, 9.577225890e-03f, -6.737049670e-02f, 5.178208650e-02f, -4.493913430e-02f, -1.291563550e-02f, 8.793500060e-02f, -7.137966900e-02f, 7.166703790e-02f, -5.872987680e-03f, -6.171537560e-03f, 5.256015060e-02f, -8.831983800e-02f, -3.427327610e-03f, -1.103276290e-02f, -2.012420820e-02f, -4.581312460e-02f, -2.804143730e-02f, 6.277858470e-02f, 2.377441530e-01f, -6.439550970e-02f, -7.849291900e-03f, 6.936153760e-02f, 5.512787400e-02f, -2.574558180e-02f, -1.709029640e-02f, 4.929049310e-02f, 7.966252040e-03f, 4.426707510e-03f, 6.377957020e-02f, 3.956936770e-03f, 1.781306970e-02f, -1.605423350e-02f, 3.917191550e-02f, -3.485972810e-02f, -5.990653760e-03f, 1.292766930e-01f, -3.936291860e-02f, 2.231185790e-03f, 8.639512210e-02f, 5.455710740e-02f, 3.930844740e-02f, -2.087474240e-02f, -7.807123470e-03f, 7.252452520e-02f, 3.796426110e-03f, -8.975096980e-03f, 5.108237380e-04f, 1.363801660e-01f, 4.709449410e-02f, 1.491499410e-02f, -2.145547790e-02f, -5.898349340e-04f, 4.717967660e-02f, -1.822694580e-02f, -3.342750300e-02f, -1.314817830e-02f, -6.939875890e-03f, 1.397898420e-02f, -3.557115420e-02f, 2.715697290e-01f, 4.118651150e-02f, 7.582305460e-03f, 1.041736600e-01f, -3.403131660e-02f, 3.440126030e-02f, -5.872444250e-03f, -5.006233980e-02f, -4.609410090e-02f, 1.685176420e-02f, 9.905477610e-02f, -1.023198660e-02f, 1.108410400e-02f, -4.499191790e-02f, 3.753950300e-01f, -1.463230140e-02f, 1.443422310e-02f, 4.476599400e-02f, 1.034421320e-01f, 3.705191980e-02f, -8.342519400e-03f, 4.771772030e-02f, 1.649618450e-01f, -3.276820110e-02f, 3.880745920e-02f, -2.084210520e-03f, -5.820064620e-02f, -4.705427590e-02f, 3.642670810e-02f, 4.641659560e-02f, -1.039631740e-01f, -3.037549560e-02f, -5.178245900e-02f, 5.926473530e-03f, -4.374276850e-02f, 2.173030000e-02f, -4.564438760e-02f, 2.187913660e-02f, -3.486759960e-02f, 1.571031660e-01f, -2.417402710e-02f, -2.421286330e-02f, 8.140663050e-02f, 4.166647790e-02f, -8.532879500e-02f, -9.048763660e-03f, -1.742185840e-02f, -7.654846460e-02f, 1.644880180e-01f, 3.219892080e-02f, 1.579687150e-01f, 1.067939870e-02f, -2.960763870e-02f, -6.312491740e-02f, 1.342049540e-01f, -3.845078870e-02f, -4.466687890e-02f, -5.656454710e-02f, -1.256116950e-02f, 8.423650630e-03f, 1.718012730e-03f, -4.188482460e-02f, -5.995195730e-02f, -2.500457130e-02f, 1.506315320e-01f, -5.186511580e-02f, -3.719737750e-02f, -2.534678760e-02f, 3.535379470e-02f, -7.920591530e-02f, -5.453261360e-02f, -5.338405720e-03f, 6.531934440e-02f, -4.405796060e-03f, -3.946398570e-02f, 6.155802680e-02f, 1.056178440e-01f, 3.189503770e-02f, -2.936060910e-02f, -4.601833970e-02f, -5.576258150e-02f, -8.742195360e-02f, -1.000113260e-01f, 1.394109730e-01f, 3.502395750e-02f, -4.142630100e-02f, -1.641381420e-03f, -6.092675500e-03f, 5.439577250e-02f, -2.153480430e-02f, -4.911096770e-02f, -4.753732680e-02f, 1.901512740e-01f, 6.192883010e-03f, -2.672302350e-02f, -8.496636520e-03f, 2.461351830e-02f, -3.523990510e-02f, -2.154449930e-03f, 9.135155380e-02f, -1.290611180e-02f, -2.043800610e-02f, 7.575619970e-02f, 5.785700680e-02f, 1.056935550e-02f, 1.337604220e-01f, -3.542136400e-03f, 2.349165270e-02f, -9.220941920e-03f, 2.120737170e-02f, 6.994304810e-02f, -1.846055310e-02f, 9.087952970e-02f, -1.831964780e-02f, -2.000520190e-02f, -4.585722460e-03f, 9.102657430e-02f, -4.734551910e-02f, -1.909440570e-02f, -8.273351010e-03f, 5.274910480e-02f, 1.301007350e-02f, 1.995867120e-02f, 1.215293260e-02f, -5.649001520e-02f, 9.616865220e-02f, -1.869583870e-02f, -1.549417530e-02f, 1.167260230e-03f, 1.853348910e-01f, -2.433190490e-02f, -2.142271030e-02f, -2.610435150e-02f, -4.740612580e-02f, 2.282516290e-02f, 8.269615470e-02f, -1.379544570e-02f, 1.070656330e-01f, 2.005480970e-02f, -3.073656930e-02f, -8.274174300e-03f, -8.272588990e-02f, 2.300876570e-02f, 2.588835360e-01f, -4.791996260e-02f, -1.214573860e-03f, -2.018347940e-02f, -4.646462200e-02f, -3.945224360e-02f, -4.562048610e-02f, 1.032920700e-01f, -2.661465110e-02f, -2.268638230e-03f, -1.780490950e-02f, 2.168095860e-02f, -5.574932320e-03f, -5.558866260e-02f, -8.405252540e-02f, -2.915769260e-02f, 6.981353460e-02f, -2.579104530e-02f, -4.477239770e-02f, -2.343270740e-02f, -3.269525240e-02f, -3.602571410e-02f, -2.336107010e-02f, -3.340603780e-02f, 8.959705380e-02f, 7.893811910e-02f, -3.848937570e-03f, 5.894723530e-02f, 5.711626630e-02f, -5.420256030e-02f, 5.440723150e-02f, 8.384472130e-02f, 8.254045240e-02f, -3.461842240e-02f, 2.450564130e-02f, 1.007802930e-01f, -8.018721830e-03f, 1.611029060e-01f, 1.982961600e-02f, 1.096874250e-01f, -3.468381240e-02f, 1.396278590e-01f, -6.517587600e-02f, 5.257156120e-02f, -2.657840400e-02f, -1.457502510e-02f, -1.904422820e-04f, 2.410546500e-02f, 1.551836170e-02f, -9.560678900e-02f, 1.812130210e-02f, -3.349633510e-02f, -2.179583350e-02f, 5.441367250e-02f, -2.262454480e-02f, -8.463568050e-03f, 4.036930580e-02f, 4.005732010e-02f, -4.767530130e-03f, 1.615945850e-01f, 9.160820390e-03f, -1.640020680e-02f, -4.471734910e-02f, -6.846964360e-03f, -1.408596060e-02f, 8.400204770e-02f, 8.498376600e-02f, 1.537281870e-01f, 2.221234330e-02f, 4.707506670e-02f, 7.673702390e-02f, 1.931211350e-02f, -3.029550050e-02f, 3.355938200e-02f, -6.483484750e-04f, -6.533575800e-02f, 8.743397890e-02f, 1.976696220e-02f, 5.826235280e-03f, 1.935713370e-02f, -9.184476920e-03f, -3.468734770e-02f, -3.878734770e-03f, -1.820706580e-02f, -1.577048530e-04f, 8.399147540e-03f, -3.617877510e-02f, -3.398208320e-02f, -3.695697060e-03f, -1.205399260e-02f, -6.887106600e-02f, 4.634028670e-02f, -1.682882430e-03f, -6.002535300e-02f, -5.230382080e-02f, -4.361355680e-03f, 3.650415320e-02f, -7.088823620e-02f, 2.995093760e-01f, -5.606788770e-02f, 8.082262240e-03f, -2.978516560e-02f, 2.418041420e-02f, 9.736654160e-02f, 5.315054210e-02f, 1.850638720e-02f, -2.016534840e-02f, 2.378962560e-02f, 7.751902190e-02f, -3.006879430e-02f, -1.269125940e-02f, 1.637337360e-01f, 4.175482690e-02f, 1.600989700e-02f, 5.020669850e-02f, -5.749488250e-02f, -8.783846160e-03f, -6.648290900e-02f, 3.821713480e-02f, -4.961660500e-02f, -7.072845850e-02f, 8.481872080e-02f, -4.566264900e-02f, -1.317241790e-02f, 1.019310580e-01f, -9.391991420e-03f, -7.318350950e-03f, 5.541057140e-02f, 2.077401580e-01f, 5.201822150e-02f, 1.616645230e-02f, -8.019176310e-03f, -6.945955750e-02f, 1.079696490e-01f, -3.059789540e-03f, -3.014137220e-02f, 5.553199720e-02f, -1.162514560e-02f, 8.498296140e-02f, 9.233853780e-03f, 3.705229610e-02f, 4.127623140e-02f, 5.176015200e-02f, 9.056556960e-03f, -4.902656000e-02f, -4.778355360e-03f, -3.109053940e-03f, -3.585218270e-02f, -2.033584560e-02f, -3.797642140e-02f, -1.850631090e-02f, 3.190246600e-02f, -3.716528420e-02f, -2.581083590e-02f, 1.081593800e-02f, -2.194745000e-03f, -2.022779360e-02f, -5.650393660e-03f, -6.013304000e-03f, -2.373202470e-03f, -1.847824450e-02f, 1.170994620e-02f, -8.305022490e-03f, -4.598664120e-02f, 1.768803040e-02f, 6.945888700e-02f, -2.935533880e-03f, 2.385000140e-02f, 2.554882880e-02f, -3.575893580e-03f, -2.466457900e-02f, 7.992209790e-01f, 3.367279470e-02f, 2.434632550e-02f, -1.808003340e-02f, -2.101750670e-02f, -2.570470050e-02f, 2.824624260e-02f, 1.810806240e-02f, 4.672863330e-02f, 5.703421680e-02f, 4.995772620e-02f, 5.638873950e-02f, 2.829044310e-02f, 7.906804230e-02f, -4.078483620e-04f, -2.371036260e-02f, 7.746513930e-03f, 1.753333210e-02f, -2.486513560e-02f, -6.713189650e-03f, 5.801316350e-02f, -1.484891870e-02f, 2.038214540e-02f, -3.472667190e-02f, -4.726232220e-02f, 9.268777440e-03f, -2.707905320e-02f, 6.496844350e-03f, -1.072924030e-02f, -2.009116860e-02f, -3.191015120e-02f, -4.535248500e-02f, -4.432793330e-02f, -8.409991860e-02f, 3.670146690e-02f, -3.710965440e-02f, -7.264321300e-02f, -6.171019380e-02f, 1.096949130e-01f, 1.388424910e-02f, 2.131567600e-01f, 6.169196220e-03f, 9.099773130e-03f, -4.324039440e-02f, -9.540311240e-02f, 5.086739730e-02f, -2.149984610e-02f, -2.578632720e-02f, -1.775357870e-02f, 4.798970740e-02f, -5.603066460e-02f, 3.546546400e-02f, 1.093339470e-01f, 4.645830020e-03f, -4.318245500e-02f, 6.582808490e-02f, -6.160001460e-02f, -7.896859190e-03f, 5.529318380e-02f, 7.727944110e-02f, 4.575024550e-02f, -6.419464940e-02f, -2.850008570e-02f, 1.631121340e-02f, 5.589299650e-02f, 2.320046540e-02f, -1.931758970e-02f, 7.497967780e-02f, 2.638430330e-02f, -5.638417970e-02f, -1.832258330e-02f, -1.189957860e-01f, 2.775965960e-03f, 1.516490430e-01f, 1.566978360e-02f, 4.416802900e-02f, -9.167818730e-02f, -6.496337800e-02f, 1.030870900e-01f, -1.766392770e-02f, -5.330621450e-02f, -3.631314260e-02f, -2.607092820e-02f, 1.574486200e-01f, -2.030319910e-02f, -2.191992940e-03f, -7.474780830e-02f, -3.091552110e-02f, -5.425672610e-02f, 4.252053050e-02f, 2.840780070e-04f, -7.625336200e-02f, -3.341333200e-02f, 1.589279810e-02f, 2.310259080e-02f, -3.249185530e-02f, 5.149060160e-04f, -1.661462590e-03f, -2.476169910e-02f, 7.134527900e-03f, -6.827113030e-02f, 3.956978670e-03f, 9.115554390e-03f, 6.486807460e-01f, 6.728094820e-02f, -1.480867150e-02f, 8.624172770e-03f, 4.736857490e-02f, 1.136247250e-02f, -2.680066040e-02f, -5.234085400e-02f, -2.594654450e-02f, 5.123962460e-02f, -1.224872380e-02f, -5.921762440e-02f, -6.097295510e-02f, -1.536632790e-02f, 1.041088480e-01f, -6.359156690e-03f, 2.562673200e-02f, 6.507182490e-03f, 6.282639520e-05f, 3.598676990e-02f, -8.851980790e-03f, -5.279274660e-02f, -2.506672400e-02f, -1.805743580e-02f, 1.054759230e-02f, 2.272399700e-02f, 1.815786470e-03f, -1.058097560e-02f, -1.443072590e-02f, 1.847956890e-02f, -6.597957760e-02f, -5.745058130e-02f, 1.716959660e-02f, -2.526209500e-02f, -5.475938690e-02f, 1.617335900e-02f, -4.226053130e-02f, 4.071246090e-02f, 2.475747650e-02f, 3.816687040e-03f, 1.284990010e-01f, -3.359052540e-02f, 9.693522000e-03f, 5.393321440e-02f, -9.409888650e-03f, 5.655840040e-03f, 1.243712190e-02f, 6.189602610e-02f, 3.167645310e-03f, 1.746789550e-02f, -3.168050570e-02f, 1.367583960e-02f, 5.843231450e-03f, 2.705755410e-03f, -5.111941700e-02f, -2.601635270e-02f, 2.645195420e-01f, 3.942678870e-02f, -1.783001420e-02f, 3.126700970e-02f, 7.711347930e-02f, -1.412560790e-02f, -3.448529540e-02f, 6.779317560e-02f, 4.866859320e-02f, 5.965307730e-02f, 1.654239950e-03f, 6.057186800e-02f, -2.555460480e-02f, -4.545033910e-03f, 1.034958290e-01f, 2.671851220e-01f, 7.929283190e-03f, -5.971762170e-02f, 1.541426780e-02f, 1.854174960e-02f, -2.773984520e-02f, -3.778695320e-02f, 8.253878350e-02f, 1.210930110e-02f, -5.706619470e-02f, -7.423701140e-02f, 2.950525840e-03f, -2.900613100e-02f, -4.896802080e-02f, 8.432850240e-02f, 8.699211470e-02f, 2.737395090e-02f, -6.964059170e-02f, -2.043640990e-02f, -3.873170540e-02f, 6.855009120e-03f, 2.035127770e-02f, 5.389715540e-03f, -5.752721430e-02f, -7.016046350e-02f, -7.629994770e-03f, -2.883226980e-02f, -5.287634950e-02f, 6.713083380e-02f, 3.473737840e-02f, -1.624483800e-02f, -6.308819350e-02f, 1.461107840e-02f, 1.606266450e-04f, 2.582752890e-02f, 3.460714220e-02f, -5.677868800e-02f, -1.943884040e-02f, 8.564518760e-03f, -5.146855490e-02f, -9.291453660e-02f, -1.982784080e-02f, -4.383653030e-02f, -6.559975450e-03f, 3.672933950e-02f, -2.939487620e-02f, 1.137729960e-01f, 8.906673640e-02f, 5.389475450e-02f, -1.925274730e-02f, -1.734489200e-02f, -6.768525340e-04f, 2.354248610e-02f, 5.716890100e-03f, -1.902552510e-02f, -3.271818910e-02f, 5.469647790e-02f, -4.843157250e-03f, 2.166357820e-02f, -1.370976030e-02f, -9.253235160e-02f, 9.162633120e-02f, 1.608703290e-01f, -1.765236960e-03f, -2.819563730e-03f, -1.552229470e-02f, -8.701293910e-02f, -6.946016850e-02f, 2.419291730e-01f, 1.391736050e-02f, 7.396773250e-02f, 4.370214420e-02f, -5.852440000e-02f, -1.523195020e-02f, -5.113879960e-02f, 1.001613210e-02f, 5.227143690e-02f, -5.131410810e-02f, -7.142700250e-02f, -3.874401380e-02f, -1.525325890e-02f, -3.940480570e-02f, -3.286934220e-03f, -2.852847050e-02f, -2.751804140e-02f, -2.983131070e-02f, -5.859105660e-02f, -2.681792710e-03f, 3.468281030e-02f, -3.274066370e-02f, -5.987955260e-02f, -3.284813840e-02f, -2.451111190e-02f, -5.583180110e-02f, -3.619426860e-02f, -1.441925480e-02f, -4.584040870e-02f, 1.253672670e-04f, 9.277517910e-03f, 9.735809260e-02f, 1.180060130e-01f, -9.279470890e-03f, 4.333227870e-02f, 3.805978920e-03f, 1.485998840e-02f, -3.992066900e-02f, 2.114931490e-02f, 9.593011440e-02f, 2.944842280e-01f, -2.599942870e-02f, -2.855540810e-02f, 1.249144080e-01f, -2.054000460e-02f, -2.774660660e-02f, -1.791090700e-02f, -4.699444860e-03f, -1.355009810e-02f, -2.155269310e-02f, -9.526959620e-03f, 1.068449390e-02f, -5.993403030e-03f, -9.304199360e-03f, 2.109763770e-02f, -1.715073730e-02f, -5.635016600e-03f, 9.289588770e-03f, 3.281801940e-03f, -9.874576700e-03f, -3.872569650e-03f, 6.641964430e-04f, 1.076025310e-03f, -1.048161650e-02f, -2.269526010e-02f, -1.164245510e-02f, -1.157480480e-02f, -7.481202020e-03f, 2.230473100e-03f, -1.509255360e-02f, -9.742594320e-03f, 9.151674500e-01f, 1.527094170e-03f, 8.503908290e-03f, -2.122829110e-02f, -1.620351710e-02f, 2.399980840e-02f, -1.975372060e-02f, -1.196351090e-02f, -1.658265290e-02f, 4.809212870e-03f, 6.208406010e-02f, 3.750332860e-03f, -1.101599730e-02f, -1.093979460e-02f, 5.308144260e-03f, 4.530552030e-02f, -1.102179940e-02f, 5.711811130e-03f, -1.014723260e-02f, 8.613764310e-03f, 1.922646160e-02f, -1.822782680e-02f, -2.195123210e-02f, 4.187108480e-03f, -1.672657020e-02f, 2.564122900e-02f, -1.057757060e-02f, -1.130167210e-02f, -1.877957770e-02f, -4.285873850e-03f, 3.348928320e-02f, -1.360069030e-02f, -2.178275400e-02f, -9.789302560e-05f, -2.406795700e-02f, 2.088047800e-03f, 5.902114320e-03f, -6.464250390e-02f, -6.238389760e-03f, 1.621804830e-01f, 4.352772980e-02f, 3.627736870e-02f, 1.077984500e-01f, -4.059088600e-02f, -9.306626020e-02f, 5.258117990e-02f, 6.011186170e-03f, 2.011363950e-02f, 7.847521450e-02f, -8.916144810e-02f, -4.258665070e-02f, -7.050742280e-04f, -5.705297740e-02f, -6.822636720e-02f, 1.536979710e-02f, -1.220929340e-02f, -5.593556910e-02f, -3.611648570e-05f, -6.663268060e-02f, 4.310079290e-02f, 9.384226790e-02f, -9.935815810e-03f, -8.127471430e-03f, 1.015426680e-02f, 1.497888010e-03f, -5.495429040e-02f, 1.158958210e-02f, 1.460101160e-01f, 4.304768520e-02f, 1.415943630e-02f, 1.687155510e-01f, -6.534595790e-02f, 3.590903430e-02f, 1.338669960e-01f, -2.705591030e-03f, -8.232854310e-02f, -7.095795120e-02f, 5.522117390e-02f, -4.941664640e-02f, 1.332425030e-01f, 9.163366260e-02f, -2.192006260e-02f, -4.492966090e-02f, 1.819134500e-02f, 1.657629390e-02f, -4.540258270e-02f, -4.388329760e-02f, 1.468835180e-01f, -3.514988350e-02f, -3.813327480e-02f, -2.132155560e-02f, 6.366391670e-03f, 1.051932050e-01f, 1.228015650e-01f, 7.737095000e-03f, -2.492790670e-02f, 3.218118330e-03f, -1.697812420e-02f, -2.528526450e-02f, -3.929449710e-03f, 1.326031240e-01f, -9.470749640e-03f, 1.102491020e-01f, 1.544786620e-02f, 1.698207410e-01f, 1.895193760e-02f, -3.339137140e-02f, 1.027975230e-01f, -5.528472740e-02f, -9.314721450e-03f, -2.921050230e-02f, 2.744848090e-02f, -6.583110430e-03f, -2.279982160e-02f, 1.025005990e-02f, -1.438938920e-02f, -7.284876700e-02f, 4.298686610e-02f, 4.656009750e-02f, 2.376092230e-01f, -7.736465330e-02f, 7.231783860e-02f, 1.598064300e-01f, 2.277913320e-02f, 5.239813770e-02f, 2.218196090e-01f, 3.230055790e-02f, 3.339073810e-02f, 4.829111510e-03f, -4.585871470e-02f, 1.544782070e-01f, -2.271715180e-02f, 2.561328930e-02f, -5.729286370e-02f, -7.988701760e-02f, 3.115578740e-02f, -3.754352410e-02f, 7.700535650e-02f, 2.518070300e-02f, 5.923134090e-02f, -1.208548840e-01f, -5.874526870e-02f, -6.444395330e-02f, -8.178354800e-02f, -4.492418840e-02f, -8.061266690e-02f, -1.053699290e-02f, -3.386567910e-02f, -1.892801370e-02f, -4.522014040e-02f, 2.599988690e-02f, 1.659093890e-03f, 2.256436460e-02f, 2.358988300e-02f, -2.778930590e-02f, -2.302485890e-02f, 5.153088360e-03f, -6.543039810e-03f, 4.526390140e-02f, -3.062233140e-02f, -4.016298060e-02f, -1.918260750e-02f, 3.126474330e-03f, 2.505849300e-02f, 7.124934350e-02f, -1.466236360e-02f, -3.780045730e-02f, -8.818716740e-03f, -2.488764750e-02f, 1.159945130e-02f, 9.578504600e-03f, 2.703494210e-02f, 1.997565480e-02f, -2.437691200e-02f, 1.087357010e-02f, 8.941926800e-02f, 4.498253390e-02f, -6.516589970e-02f, 8.478008210e-02f, 1.200020760e-01f, 1.010795590e-02f, 1.996613110e-03f, -6.389051680e-02f, 3.432042900e-02f, -7.004772870e-02f, 6.274316460e-02f, -3.764700140e-02f, -5.986550450e-02f, -8.313494170e-02f, 1.104472950e-01f, -3.110235180e-02f, -1.479903700e-02f, -1.973854190e-02f, -1.506293100e-02f, 2.095221540e-02f, 1.405381710e-01f, -6.206923350e-02f, 2.008114160e-01f, -5.347677040e-03f, -2.933659220e-02f, -3.154614570e-02f, 6.099217760e-02f, -3.516838330e-02f, 2.053947450e-01f, -5.740531160e-02f, 9.224546140e-03f, 2.411424740e-02f, -6.515491750e-02f, 9.641993790e-02f, 1.037018520e-01f, 1.001853500e-02f, 6.946889310e-02f, 2.238677440e-01f, -2.849095870e-02f, -4.878281060e-02f, 1.112054810e-01f, -2.412931250e-02f, -3.732202110e-03f, 1.361258030e-01f, 1.099725630e-02f, 2.370462010e-02f, 7.614088240e-03f, 3.606775780e-03f, 7.729779180e-02f, 1.659022060e-03f, 7.786674420e-03f, -7.384083420e-02f, 2.113229220e-02f, -1.470608170e-02f, -4.002809060e-03f, -2.693197880e-02f, -4.443289340e-02f, 4.664646090e-02f, 7.278755300e-02f, 2.600979060e-02f, -1.700096580e-02f, 5.647017810e-02f, 3.013690750e-02f, -3.398781640e-02f, 5.099894110e-02f, -1.031857260e-02f, -6.184661390e-02f, 1.854755730e-02f, -4.066496620e-03f, 1.117442550e-02f, -7.772483670e-02f, -5.602645500e-02f, -9.066233780e-02f, -7.257755100e-02f, -4.966907580e-02f, 6.865223500e-02f, 5.547399070e-02f, 8.103335270e-03f, -2.213813740e-02f, 3.569773960e-02f, -1.709184980e-02f, 2.230027920e-03f, -3.703919430e-02f, 2.207366190e-02f, 1.041245740e-02f, 1.219960950e-02f, -7.522208990e-02f, 3.769377620e-02f, 1.696875690e-02f, 2.655187620e-03f, -9.341672060e-02f, 2.257762850e-02f, 2.050114980e-02f, 5.477438490e-02f, 1.848328300e-02f, -8.775418990e-02f, 5.765450750e-02f, -3.250872340e-02f, -3.350806980e-02f, 1.003932130e-01f, 1.872221750e-02f, 7.358264180e-02f, -3.645987810e-02f, 1.105007720e-02f, -3.624850880e-02f, 3.577945380e-02f, 5.489194770e-03f, -5.423066020e-02f, -3.755062450e-02f, -3.262560070e-02f, -5.091606450e-02f, -3.305639700e-02f, 6.312534210e-02f, -8.503326770e-02f, -4.762316500e-02f, 2.678813410e-03f, 3.625964520e-01f, -4.729259010e-02f, 1.020422350e-01f, -6.562244890e-02f, -3.454080220e-02f, -1.588633470e-02f, 2.232887780e-03f, -3.173182900e-02f, -3.547939290e-02f, -4.688706990e-02f, -7.453101130e-02f, 1.815293540e-02f, 6.345541030e-02f, -4.356789590e-02f, 3.974179740e-03f, 8.963181820e-02f, -3.748299550e-02f, 7.389328630e-02f, 1.972673240e-01f, 9.459051300e-03f, -5.292468700e-03f, 7.035240530e-03f, -3.906838600e-02f, -3.777889070e-03f, 5.757585910e-02f, -4.156417210e-03f, 7.990342370e-02f, 1.516662390e-01f, -2.464627850e-02f, -7.276711980e-03f, -1.094400810e-01f, -8.830846290e-03f, -5.752084780e-02f, 3.181320800e-02f, 8.696576200e-02f, 3.624296980e-03f, 5.073766410e-02f, -7.223068180e-02f, -1.964852210e-03f, 3.135730280e-03f, -4.389109090e-02f, -3.425061330e-02f, 6.539478150e-02f, -3.706325220e-02f, 2.689025100e-01f, -2.448039870e-02f, 2.081276850e-02f, 3.327175230e-02f, -3.279231860e-02f, 1.967060010e-02f, -3.599602730e-02f, -1.427924910e-02f, 4.979480800e-02f, -1.579599640e-02f, -8.160573240e-02f, -1.401040980e-02f, -4.452732950e-02f, -1.725193490e-02f, 3.112131260e-03f, 1.575009150e-02f, 9.823122620e-02f, -5.503110590e-02f, 4.612746460e-02f, 1.088077300e-02f, -3.573418040e-02f, 1.085453390e-02f, 6.359529500e-02f, -2.714502630e-02f, 5.829092490e-02f, 4.109694060e-02f, 1.728167980e-01f, 8.979660270e-02f, -5.228187890e-02f, -1.557586530e-02f, -1.765033460e-03f, -1.053338400e-02f, -7.275378700e-02f, -1.324795650e-02f, 5.698124320e-02f, 2.968953360e-02f, 5.306263270e-02f, 4.355396700e-02f, -7.992937410e-02f, 1.292077600e-01f, 1.095925870e-01f, -1.630930040e-02f, 1.042545360e-01f, -3.532748300e-02f, -4.331269860e-02f, -4.716284570e-03f, -4.452381280e-02f, -1.368214030e-03f, -5.142388870e-02f, 2.800224350e-02f, -3.309706230e-02f, 1.174981070e-01f, 7.420822230e-02f, 5.566259470e-02f, 4.877179860e-02f, 3.222749010e-02f, -1.275910810e-02f, -8.142692960e-03f, -9.549599140e-02f, -2.874063890e-02f, 4.307636250e-02f, -6.099120250e-03f, 9.314901200e-03f, 2.347501930e-02f, -4.177851140e-03f, 2.535055620e-03f, 1.541814950e-01f, 2.139123830e-01f, -5.031682180e-02f, -2.746926810e-02f, 9.102658180e-02f, 1.902493390e-01f, 2.682425080e-03f, -4.289602860e-02f, 1.159725250e-02f, 1.020302920e-01f, 1.528790300e-01f, -6.064720450e-03f, 5.508143830e-02f, -5.935176280e-03f, 2.094641030e-01f, 4.284477230e-02f, 2.254779260e-02f, 5.408334360e-02f, -1.051797350e-02f, 9.206778550e-02f, -3.084360990e-02f, -1.247540950e-02f, 4.574323070e-02f, -3.149791810e-02f, -1.560857150e-02f, 1.388678890e-02f, 1.560738530e-01f, 1.922084390e-02f, 6.248715890e-02f, 2.457257730e-02f, -2.949173000e-02f, 2.710839170e-02f, 2.171993260e-02f, 5.360813810e-03f, 7.724767180e-02f, -8.950607850e-03f, -2.343682940e-02f, 5.079863220e-02f, 1.696915630e-01f, 1.758035390e-03f, -2.512978390e-02f, -6.562812630e-02f, 9.379793700e-02f, -5.580925570e-02f, 9.119547150e-02f, 9.891387070e-03f, -1.815885490e-02f, -1.315750370e-02f, 6.930609050e-02f, 9.414230290e-02f, -5.457454170e-02f, 4.535663870e-02f, 1.023589520e-01f, 1.511171160e-01f, -3.670095280e-02f, -5.120067300e-02f, -2.901641090e-02f, 1.144422290e-01f, -1.080167890e-01f, 9.027788040e-02f, -4.787222300e-02f, -7.573723790e-02f, 6.041009720e-02f, -2.992619760e-02f, 5.349074680e-02f, 4.497209560e-02f, 2.044730630e-02f, -5.431318280e-02f, -5.231074990e-02f, -3.031863830e-02f, -2.112739160e-02f, -4.041350630e-02f, -3.387295450e-02f, -5.009743200e-02f, 8.892416020e-03f, -1.582190980e-03f, -7.724894210e-03f, -7.226687670e-02f, 3.631716220e-02f, 3.007482740e-02f, 1.849138440e-01f, -3.104032020e-02f, 1.745050030e-02f, -6.309282030e-02f, -8.497804400e-03f, -1.303977150e-02f, -3.053893340e-02f, 2.300363030e-02f, -5.707993730e-02f, 3.210966290e-01f, 6.012653000e-03f, 3.543959860e-01f, -3.943615030e-02f, -1.588628070e-02f, -1.105246790e-02f, -4.075066370e-02f, -4.851848630e-02f, 8.662799370e-03f, 2.705998720e-02f, -5.365763600e-02f, 2.631507810e-02f, -6.736561650e-02f, -5.437197910e-02f, 5.240611360e-02f, -3.202430530e-02f, -3.069977970e-03f, -6.916757670e-02f, -3.942972420e-02f, 8.371090880e-02f, -3.931996970e-02f, 3.940325700e-03f, -1.319377590e-02f, 9.158133710e-02f, -2.550284940e-02f, -1.455700580e-02f, 2.808594520e-02f, -8.599692020e-03f, -6.867231430e-02f, 6.340066900e-03f, -6.760314850e-02f, -2.459327690e-02f, 9.400136770e-03f, 6.009103260e-03f, -4.705687610e-02f, -8.631392560e-02f, -2.442681230e-02f, 1.388169380e-01f, 3.108894640e-02f, -4.677517710e-02f, -1.155495830e-02f, -2.429196420e-02f, -2.778803370e-02f, 3.784284740e-02f, 2.596540000e-02f, -3.139572590e-02f, -1.003020070e-02f, -5.083835870e-02f, -1.918088880e-03f, 4.241486550e-03f, 1.203657690e-01f, 2.673315070e-02f, 3.662594780e-02f, -9.596396230e-03f, 1.040058210e-01f, 6.344690910e-03f, -4.537499040e-03f, -8.543421510e-03f, 1.261727810e-01f, 1.898099850e-02f, 5.457371100e-02f, 7.809779790e-02f, 8.184383060e-02f, -5.614409970e-02f, -3.419096810e-03f, 4.043816780e-02f, 1.233256240e-01f, 8.216672390e-02f, -4.223649950e-02f, 1.904419510e-01f, 4.647410940e-03f, -2.398074230e-02f, -2.847052180e-02f, -2.131141350e-02f, -3.308135640e-02f, -2.171967360e-02f, 1.190625280e-01f, -3.596368800e-02f, -5.209686230e-02f, -3.528241070e-02f, 5.138176490e-03f, 9.637509470e-03f, 1.837974600e-02f, -1.637881810e-02f, 3.108651190e-02f, -2.222663350e-02f, 8.878983560e-03f, 3.171122070e-02f, -6.186070670e-02f, -6.648034600e-02f, 6.752745060e-02f, 3.825545310e-02f, -4.323339830e-02f, -5.170814690e-03f, -3.636120260e-02f, -1.321396230e-02f, -4.271039370e-02f, -6.039876960e-03f, 1.647623180e-01f, 6.856466830e-02f, -4.436015710e-02f, -3.390107680e-02f, -3.944053870e-02f, 9.631762280e-03f, -6.665109100e-02f, -8.161127570e-02f, 1.415352820e-01f, 5.192309990e-02f, 6.519396600e-02f, 2.341387420e-02f, -1.326614430e-02f, 4.104787480e-02f, 2.074609400e-01f, 7.891905310e-02f, -1.504604520e-02f, -6.575707810e-03f, -6.867410990e-02f, -4.463588820e-02f, -4.241843520e-02f, -6.632302890e-03f, 3.903125410e-03f, 3.399943190e-02f, -3.017743120e-02f, -2.800332750e-02f, 3.409169240e-02f, 9.753671280e-02f, -3.668743370e-02f, 3.497232500e-02f, 2.672572250e-02f, -6.965326520e-02f, 8.785469450e-03f, 8.995682740e-02f, 1.193493700e-02f, -7.780547440e-02f, 5.726096220e-03f, 1.522643570e-01f, 9.247408060e-02f, -3.523497280e-02f, 9.922786610e-03f, -4.987461860e-02f, -2.860814150e-02f, -3.229200840e-02f, 6.266918770e-02f, 5.941716580e-02f, 1.589719800e-01f, 5.548004990e-04f, -1.921762900e-02f, 7.487824550e-02f, -7.722959850e-03f, 1.234303560e-01f, 3.527553750e-02f, -1.165067960e-02f, -6.113211440e-02f, -1.084845050e-02f, 1.053756550e-01f, 1.197756450e-01f, 5.669977980e-03f, 2.116631530e-02f, 7.653509830e-02f, 2.411854450e-02f, -9.718379370e-02f, 1.685079560e-02f, -4.696273240e-03f, -4.847359660e-02f, -6.662250310e-02f, 1.323659720e-02f, 5.435395050e-03f, 3.495388850e-02f, -6.204992900e-02f, -3.205488620e-02f, -6.469353290e-02f, -5.018115790e-02f, -4.343068600e-02f, -6.619711220e-02f, -3.406610340e-02f, -1.035246530e-02f, -2.800048520e-02f, 1.394912970e-02f, -2.471338960e-02f, 5.336993930e-02f, -7.953654970e-02f, 3.985691440e-02f, 5.468548740e-03f, -9.295213220e-02f, -1.485416950e-02f, 4.743218420e-03f, -5.655950310e-02f, -3.160161150e-02f, 2.219285820e-02f, -1.554171550e-02f, -3.871161490e-02f, -1.715390240e-03f, -3.768632190e-02f, -3.432860600e-02f, -4.538159070e-02f, 1.070996750e-01f, -2.029039710e-02f, -1.056170560e-02f, 8.957171440e-02f, 1.554000840e-02f, -4.038885980e-02f, 1.391006560e-01f, 3.848285970e-02f, -9.038358000e-03f, 1.515529400e-02f, 7.010841360e-02f, -5.912504160e-03f, -5.039413270e-02f, -2.186320720e-02f, -3.230606760e-02f, 3.570012750e-02f, -2.289351260e-02f, 1.321728680e-01f, 1.299571710e-02f, -3.347876710e-03f, -6.684090940e-02f, -5.047084760e-02f, -1.824121740e-02f, -1.047930310e-02f, -3.188202900e-02f, -3.279967610e-02f, 6.351185500e-03f, 1.769436520e-02f, -2.123233860e-03f, -2.483402010e-02f, -1.610527930e-02f, 4.796327560e-03f, -5.541245270e-02f, -4.728712140e-03f, 8.938710390e-02f, -1.004373650e-02f, -5.020931360e-03f, 2.463408560e-02f, -1.743314790e-02f, 2.380937340e-02f, -5.813726410e-02f, 1.890728060e-02f, -3.106743660e-02f, -6.832746420e-02f, 7.645708320e-02f, 6.055451930e-02f, 1.013468650e-01f, -4.808819290e-02f, -2.219701930e-02f, 4.429593380e-01f, -1.954123010e-02f, 2.078170330e-01f, -2.154662830e-02f, 4.654966670e-02f, 9.276540580e-02f, -3.242968350e-03f, -2.317700160e-02f, 2.166087270e-03f, 7.524335380e-02f, 4.295444490e-02f, 1.498171390e-01f, -6.340546910e-02f, -2.380624970e-02f, 9.417396970e-03f, 6.437047570e-02f, -4.523189740e-02f, -2.575453740e-02f, -7.649958130e-02f, 1.796260030e-01f, 7.713460180e-02f, -4.368052350e-03f, -6.257461760e-02f, 6.285202500e-02f, -3.589389100e-02f, 2.874337880e-02f, 8.680695660e-03f, -1.900207810e-02f, -8.997344220e-02f, -1.830839740e-02f, -2.235057950e-02f, 9.159047150e-03f, 7.495345180e-02f, -5.859559770e-02f, -9.866052310e-03f, 5.711886660e-02f, -3.880780560e-02f, 2.137376930e-02f, -3.669359160e-02f, -4.756749050e-02f, 8.111900830e-02f, -3.970962020e-02f, -2.708504910e-02f, 8.762713520e-03f, -3.663105890e-02f, 7.584805790e-02f, 4.313961790e-02f, -5.868862570e-02f, -1.883869800e-02f, 1.040512320e-01f, -4.796139900e-02f, -2.917503010e-02f, -2.419515330e-02f, -8.609721430e-03f, 1.339449580e-01f, -4.891344160e-02f, -3.870048370e-02f, -2.211722730e-02f, 2.654126580e-01f, -2.667748370e-02f, -3.721205520e-02f, 6.168526780e-02f, 1.320746260e-02f, -1.990288310e-02f, -5.893667040e-02f, -5.680062620e-02f, 1.498266460e-01f, -6.932567060e-02f, -2.206026760e-02f, -4.232231530e-02f, -6.122776490e-02f, 7.164548340e-02f, 2.515763510e-03f, 7.443027200e-02f, -6.034392400e-03f, 4.954969980e-03f, -9.097959840e-03f, -2.778735380e-02f, 6.889973300e-03f, 4.244710130e-02f, -2.563534300e-02f, 2.326115670e-01f, -5.815733970e-02f, 7.676556700e-03f, 9.553136760e-04f, 3.428217400e-02f, -2.991744130e-02f, -5.420051980e-03f, -2.310922560e-02f, 1.086283550e-01f, 2.733289600e-01f, 1.030841770e-01f, 5.191929640e-02f, 4.255893450e-02f, -5.861848220e-02f, -3.569313140e-02f, 1.521056890e-02f, 7.619025560e-02f, 6.849934350e-03f, -6.735303250e-02f, 2.699354660e-02f, -4.317564890e-02f, -1.348804680e-02f, -9.093401950e-03f, -2.360457370e-02f, -1.498902800e-03f, -6.130311640e-02f, 4.849286750e-03f, -4.870271310e-02f, -6.646032630e-02f, -2.270627020e-02f, -6.020786610e-02f, 1.902811970e-01f, 9.104913100e-03f, 5.489811300e-02f, 3.001759390e-02f, 6.742302330e-02f, 4.683959860e-02f, 1.923029680e-02f, -5.223467570e-02f, 6.495102490e-02f, 4.550212620e-02f, 1.226343510e-01f, -1.254907900e-02f, -5.025424440e-02f, 4.277027680e-03f, 8.336558190e-02f, -2.907183770e-02f, -2.029116730e-03f, 9.193049370e-02f, -5.891224370e-03f, 1.433381440e-02f, -1.749253460e-02f, 3.572206200e-02f, 9.007148440e-02f, -7.165687530e-02f, 4.118406400e-02f, 3.757361700e-02f, -6.970989050e-03f, 1.748730690e-01f, 1.197406460e-02f, 3.202166040e-02f, 5.974257950e-04f, -4.951801150e-02f, 1.310700920e-01f, 7.512287050e-02f, -4.482076500e-03f, -7.077758010e-02f, 5.482986940e-02f, 1.361364130e-01f, 1.118945700e-02f, 5.035780740e-02f, -1.428629740e-02f, 7.897707070e-02f, 7.945305100e-02f, -8.497528730e-03f, 1.793012170e-01f, -6.826044620e-02f, -7.962115110e-02f, -6.734400520e-03f, 3.392007950e-02f, -5.247579510e-02f, -1.315135230e-02f, -1.384441460e-02f, -4.677729680e-02f, 1.990083140e-03f, -2.194099870e-02f, -6.174961100e-03f, -2.555626440e-02f, -2.846057900e-02f, 1.476350150e-02f, -3.947658460e-02f, 3.178221360e-02f, -9.273944420e-03f, 2.098503410e-01f, -1.684724730e-02f, 1.793676060e-02f, -1.193839870e-02f, 9.705349800e-02f, 3.174133970e-02f, -2.575380910e-02f, -4.653633010e-02f, -7.057943200e-02f, 4.670004550e-02f, -7.535856220e-02f, 1.006563980e-01f, -7.389322670e-02f, 2.050161550e-02f, -1.482355590e-02f, -3.682890160e-02f, 1.096705160e-02f, 1.383522150e-01f, -1.066416600e-02f, -5.099675800e-02f, 2.389082500e-02f, -5.843165330e-03f, 4.080189760e-02f, 2.690239580e-03f, -4.464249690e-02f, -3.208516540e-02f, 4.456031320e-02f, -1.454444600e-02f, -2.159368060e-02f, -8.402507010e-02f, -7.694517820e-02f, 3.213139620e-02f, -4.726367440e-02f, -3.441892190e-02f, -1.976469530e-02f, -6.958117340e-02f, -6.421908730e-02f, 1.090392170e-01f, 3.391354160e-02f, 1.106471340e-01f, -4.668656270e-03f, 1.772606560e-02f, -1.642184520e-02f, -3.877611460e-02f, -5.931661280e-02f, 7.022164020e-02f, 1.396646800e-01f, 1.053338130e-01f, -1.401612910e-02f, 2.757113990e-02f, -5.107546970e-02f, -1.436309980e-02f, 3.714249940e-03f, 6.621884550e-02f, 1.342638770e-02f, 3.037104940e-02f, 2.032448070e-03f, -5.653474850e-02f, 2.387940700e-02f, -1.472379730e-02f, 1.584411250e-03f, 3.882798370e-03f, 2.115900070e-02f, -5.051044280e-04f, -5.995321270e-02f, 3.695034610e-02f, 7.437632230e-02f, 2.054396570e-01f, -2.599293370e-02f, 2.828011480e-02f, 3.109606730e-02f, -3.759713100e-02f, -6.849988550e-02f, 2.324116530e-01f, 1.368988750e-01f, 1.508209410e-01f, 7.438241690e-02f, 2.524180150e-02f, 1.337621060e-01f, -2.693711590e-02f, 9.858161210e-02f, 8.675484360e-02f, 7.735269520e-02f, -1.625500810e-02f, 1.042173710e-03f, -2.978101370e-02f, -5.131009970e-02f, 4.577241490e-04f, -9.760978810e-02f, -4.519383240e-02f, 2.141751350e-02f, 6.434852630e-02f, 4.278149460e-03f, -5.071812310e-03f, 2.569288610e-01f, -6.026191260e-02f, -9.714043700e-03f, 3.205527370e-02f, -5.280229080e-02f, 7.490716530e-04f, 1.471262080e-03f, 2.968273310e-02f, -9.746203190e-03f, 5.197058620e-02f, 1.537505090e-01f, 9.285564720e-02f, -2.655122800e-02f, 4.520572350e-02f, -4.231999810e-02f, 7.302448150e-02f, 2.037644570e-02f, 9.006246170e-02f, 1.541552100e-01f, 1.595218080e-03f, 5.545051770e-02f, 3.485763070e-02f, 1.290346220e-02f, 8.575523270e-03f, 6.523832670e-02f, -6.141283550e-03f, -4.139316450e-02f, -5.423348770e-02f, 1.638361510e-01f, 7.820138700e-03f, 2.829536800e-02f, -5.218740550e-02f, -8.849214020e-02f, 4.478852450e-02f, 3.594134000e-02f, 5.903895940e-02f, 1.872043310e-01f, -6.344074760e-02f, -3.973736610e-02f, -6.543959680e-02f, -6.021952620e-02f, -5.344456060e-03f, 9.815631800e-02f, 6.478848310e-02f, -3.506713360e-02f, -2.305577510e-02f, -5.849125610e-02f, -6.286493690e-02f, 4.109393060e-02f, -4.210009800e-02f, -3.439847750e-02f, 4.670358080e-02f, 2.774736660e-02f, 9.874954810e-02f, -5.235928300e-02f, 2.040008550e-03f, 2.226547900e-02f, -8.297462950e-03f, -2.374324020e-02f, 5.650189520e-02f, -7.336237470e-03f, 3.669805820e-02f, 4.063698950e-01f, 3.260446480e-03f, -5.919875580e-02f, -7.392287250e-02f, 7.130660860e-02f, 1.427317850e-03f, 1.741567070e-02f, 3.317077460e-02f, -3.834890200e-02f, 7.406590970e-03f, 3.717048090e-02f, 5.113372210e-02f, 1.163961590e-01f, -8.149565200e-03f, 1.049022080e-01f, -3.390094270e-02f, 2.076531570e-02f, -4.047543930e-02f, -4.083339870e-02f, 6.779752670e-02f, -6.325275450e-02f, 1.660428570e-02f, -4.150516170e-02f, -1.628429070e-02f, -9.063486940e-03f, -3.455885160e-04f, -6.534007940e-02f, 7.373971490e-02f, -6.760746240e-02f, -1.257363240e-02f, 8.388217530e-02f, 2.062907810e-02f, 1.168676990e-01f, 5.503451450e-02f, 1.375755970e-01f, -5.777684600e-02f, -4.751801860e-02f, -3.408479320e-02f, 5.980169770e-02f, -3.412061930e-02f, 8.097743990e-02f, 2.852277250e-04f, -4.000869020e-02f, 1.457221810e-02f, -4.616449770e-02f, -2.744376470e-02f, 6.219754370e-02f, -2.726938580e-03f, -4.397896120e-04f, -7.205431910e-02f, 4.790348930e-02f, -1.773109850e-02f, -5.080326270e-02f, 2.576652730e-02f, 3.676504640e-02f, 5.222830550e-02f, 4.531278090e-02f, -4.298901560e-02f, -1.408028620e-04f, -3.425463660e-02f, -4.675859590e-03f, 4.715261980e-02f, -2.770257180e-02f, 5.078706890e-02f, -4.285872360e-02f, 3.776795420e-02f, -1.307836730e-02f, 2.598525880e-01f, -1.835202430e-02f, -3.181811050e-02f, -1.907261830e-02f, 7.715476670e-03f, 4.964428490e-03f, 2.607193960e-02f, -4.718769710e-02f, 6.787885450e-03f, 1.647481170e-01f, -8.320088500e-03f, 4.115634410e-02f, -2.969669000e-04f, -4.283336180e-02f, 1.154244470e-01f, 6.919567290e-02f, -7.068985700e-02f, 6.737049670e-02f, -2.246413750e-02f, 2.796365920e-01f, 1.759511600e-02f, 2.790760990e-02f, 1.161606160e-01f, -2.521310560e-02f, 4.379585010e-02f, 1.111814010e-01f, 5.394125360e-02f, 3.120112980e-02f, -4.235934470e-02f, 7.542983440e-02f, -6.048277490e-03f, -6.801276650e-02f, -1.482605380e-02f, -2.794565070e-02f, -3.020935320e-02f, 4.769581560e-02f, 4.272453860e-02f, 1.217605840e-01f, 4.022947700e-02f, -3.100030680e-02f, 1.756131350e-01f, -1.417506490e-02f, -5.294278260e-02f, 2.016496810e-01f, 9.469553820e-03f, 6.905790880e-03f, -1.178182100e-02f, 1.326718650e-02f, -7.186375090e-03f, -1.180233530e-02f, 1.351747660e-02f, -3.998131300e-02f, -1.160298010e-02f, 2.451928700e-02f, -3.277219460e-02f, -3.684320300e-02f, 5.706213880e-03f, 1.807154340e-02f, -4.423727840e-02f, 2.938805520e-01f, 1.566658910e-02f, 2.303561570e-02f, -3.029748240e-02f, 1.411852890e-02f, -4.461567850e-02f, -4.566307740e-02f, -5.244350530e-03f, -3.974428030e-02f, 4.086280240e-02f, 2.697043310e-02f, -1.672173290e-02f, 1.438183520e-02f, 8.997870230e-02f, 7.650717350e-02f, -6.013653430e-02f, 1.131350250e-01f, 5.992417040e-02f, 7.494395970e-02f, -4.894641040e-02f, 1.889654620e-02f, -8.083955380e-03f, 7.337117190e-02f, -2.492175060e-02f, -1.151758060e-02f, 6.971538530e-03f, 3.280885980e-03f, 8.046659820e-02f, 3.943171350e-02f, 7.219483610e-03f, 6.049184130e-03f, -3.780856730e-02f, -4.695994410e-02f, -1.248212620e-02f, 2.511561850e-02f, 8.182223880e-02f, 7.501780060e-03f, 1.006183770e-01f, 2.469396590e-02f, 8.329821750e-03f, -4.702597110e-02f, 1.472675950e-01f, 6.636864690e-02f, -2.703295280e-02f, -4.091836140e-02f, 1.369434890e-01f, 1.433557830e-02f, 2.138398350e-03f, 2.230085620e-02f, -2.756248230e-02f, 8.683937040e-02f, 9.371011700e-02f, -7.287580990e-03f, 1.922701670e-02f, 2.141537140e-02f, 5.282199760e-02f, -5.125563960e-02f, 2.947055700e-01f, -2.902034860e-02f, 1.336224280e-02f, -3.693106400e-02f, -1.728177070e-02f, -2.594333510e-02f, -1.622299290e-02f, -4.973886910e-02f, -7.706866410e-02f, 1.593886870e-02f, -6.261183320e-02f, 5.908755210e-02f, -2.001029900e-03f, -3.298981490e-02f, 3.616524160e-03f, -3.123589980e-02f, 1.114230010e-01f, 2.079989200e-02f, 7.154183830e-02f, 3.377531660e-03f, 4.968563840e-02f, -2.094438670e-02f, -4.471776260e-02f, -7.444011420e-02f, 3.474318610e-02f, 1.178397240e-02f, 1.723785510e-02f, -9.143139420e-02f, -5.338177080e-02f, -7.660620030e-04f, -2.056279410e-02f, -4.117148370e-02f, -3.861871080e-03f, -7.479657420e-03f, -5.079314490e-02f, -3.294602780e-02f, -5.386110020e-02f, 1.353976880e-01f, 5.556302520e-02f, -3.149176020e-02f, -9.511277070e-03f, 2.069342880e-01f, -5.200913180e-02f, -7.910978790e-02f, -6.104058400e-02f, -9.325133260e-02f, 3.140858560e-02f, -6.149639560e-02f, -8.745069800e-02f, -1.022736540e-02f, 1.060183640e-01f, -1.050119010e-02f, -3.992321340e-02f, -2.113907040e-02f, 8.157765120e-02f, -8.442189540e-02f, 6.373903150e-02f, 7.972270990e-02f, -2.012508920e-02f, -5.262496320e-02f, -4.714431240e-02f, 4.044443740e-02f, -2.155522350e-03f, 8.057195690e-02f, -7.797382310e-03f, -3.260290250e-02f, -4.352558400e-02f, 1.069943420e-02f, 6.782197950e-02f, -9.477558730e-02f, 1.605299490e-02f, 8.852649480e-02f, -7.226951420e-02f, -3.842253700e-03f, -1.315160190e-02f, -4.181874450e-03f, 5.519144240e-02f, -3.733804080e-02f, -6.032758950e-02f, 8.137251250e-03f, -5.537158620e-02f, 2.838149110e-02f, 1.270065610e-01f, -3.920934720e-02f, 1.653785110e-01f, 1.396607330e-02f, -2.911734580e-02f, 1.146483050e-02f, 1.929585450e-02f, 2.031994160e-01f, -4.996485640e-02f, -5.122515190e-02f, 5.521391330e-02f, 1.042997740e-02f, 5.143921450e-02f, 3.419815750e-02f, 7.972558030e-03f, 1.303768340e-02f, 1.710820200e-02f, -2.104873400e-02f, -3.593168410e-02f, 9.180278330e-02f, -6.081946570e-02f, -1.519370920e-02f, -1.904671450e-02f, -2.935835530e-02f, -1.042901170e-02f, 9.844151880e-02f, 1.642842400e-02f, -6.479615690e-04f, 9.988377240e-02f, -6.315138930e-02f, -4.687799510e-02f, 8.255640410e-02f, -3.022924440e-02f, 4.763991010e-02f, -1.266329920e-02f, 2.034558500e-01f, -4.777948370e-03f, 7.940933100e-02f, 1.174872960e-01f, -2.585315890e-02f, -7.088932390e-02f, -9.679173120e-03f, -1.403094620e-03f, -5.026103180e-02f, 2.827936040e-02f, -2.589889620e-02f, -1.570157890e-02f, -5.577756460e-02f, -1.608911530e-02f, 9.669923780e-02f, -2.543467100e-02f, 1.480902280e-01f, 5.724316840e-02f, -4.185165090e-02f, 4.335565960e-03f, 4.723970590e-02f, 1.511561310e-02f, 6.382397380e-03f, -3.701301660e-02f, -1.543891800e-02f, 8.521286770e-03f, -7.367020010e-03f, -3.699989620e-02f, 2.621143870e-02f, -6.304559860e-02f, -1.362219080e-02f, -4.358962920e-02f, 3.287439420e-02f, -3.653629870e-02f, 3.492117670e-02f, 3.394285590e-02f, 2.694619630e-02f, -2.188215030e-02f, 1.193348320e-01f, -2.643620970e-02f, -4.694150390e-02f, 5.285555870e-02f, -8.275970070e-02f, 7.908506310e-03f, 1.676426040e-03f, 7.017752520e-02f, -6.132559850e-02f, -2.987944890e-02f, 5.189585690e-02f, -1.710408740e-02f, 1.177635270e-01f, 1.455278880e-02f, 6.457594030e-02f, -1.403683420e-02f, -3.963725640e-02f, 5.891653520e-02f, 7.758548110e-02f, -3.635996210e-02f, -5.831059440e-02f, -5.178555510e-05f, -5.868037420e-02f, 3.202136610e-02f, 5.324628200e-03f, 3.052583340e-01f, -2.738947050e-02f, 1.888310460e-01f, -1.472676360e-02f, 1.286763850e-01f, 9.174220260e-02f, -8.543670180e-02f, -4.069799930e-02f, 1.164891050e-01f, -4.608757420e-02f, -4.907118530e-02f, 8.996413650e-02f, -3.335511680e-02f, -1.226737910e-02f, 1.494455780e-01f, -6.128909530e-03f, -5.728354680e-03f, 5.726775900e-02f, 1.245107580e-01f, 1.385358120e-01f, 1.180153860e-01f, -4.426307230e-02f, 1.460959320e-01f, -1.855593730e-02f, 1.616343860e-02f, 6.620093440e-02f, -7.406105850e-02f, -3.672486920e-02f, 6.604254990e-02f, 2.139527350e-02f, 8.761575810e-02f, 1.053344610e-01f, 3.658237310e-02f, 2.475664210e-02f, -7.436750450e-03f, -5.589747060e-02f, 4.934545610e-02f, -6.569831820e-02f, -5.045371500e-02f, -5.950062720e-02f, 8.947271100e-02f, -4.452591760e-02f, -2.212967720e-02f, -5.011926590e-02f, -7.898182610e-03f, -4.940935410e-03f, 1.040155290e-01f, 5.906379970e-02f, 5.451375250e-02f, 4.685232790e-02f, 1.245814110e-01f, -3.623655440e-02f, -3.110113550e-03f, 7.402380560e-02f, -2.795468640e-02f, 6.093333290e-02f, -1.182431730e-02f, 2.723672990e-02f, 1.590279040e-01f, 3.617714720e-02f, -3.543072380e-03f, -6.242716310e-02f, -1.028603410e-02f, -6.174745780e-02f, 4.885541650e-02f, -6.615962830e-02f, 1.883790640e-02f, -1.977942140e-02f, -8.566757290e-02f, -1.217115950e-02f, 2.910752220e-02f, -2.227501380e-02f, 9.073071180e-03f, -9.984944940e-03f, 1.969579050e-02f, 1.820603610e-01f, 5.038140710e-02f, -5.496754870e-02f, -1.587411390e-02f, -1.711959020e-03f, 5.780303390e-03f, 9.956345700e-02f, 1.914914700e-01f, -4.432103040e-02f, -6.718821820e-02f, 1.311878410e-01f, 3.609887140e-02f, -2.147690770e-02f, -3.642362360e-02f, 4.751427470e-02f, 1.164376810e-01f, 3.837210690e-02f, -2.973696220e-02f, -8.118813480e-02f, 1.272049640e-02f, -6.984961780e-02f, 9.875010690e-02f, 3.092960640e-02f, 6.353678550e-02f, -5.661789330e-02f, -1.638991390e-02f, 3.951208670e-02f, 4.284152020e-02f, 9.393496810e-02f, -8.257192370e-02f, -9.424355810e-03f, -7.251854990e-02f, -6.802179660e-02f, -6.721179470e-03f, -5.750563000e-03f, -1.548006660e-02f, 2.443834840e-01f, -1.799427720e-02f, 2.544727920e-02f, -2.745325680e-02f, 2.010544950e-02f, -1.225633450e-02f, -8.315075180e-03f, -5.142108350e-02f, -3.541638330e-02f, 2.359556780e-02f, 3.321442050e-03f, 1.178876090e-01f, -3.641851990e-02f, 9.714139990e-02f, 4.091732950e-02f, 6.613149490e-02f, -6.833877410e-02f, 3.112514320e-02f, 3.317921240e-02f, -5.349596590e-02f, -2.218594770e-02f, 9.945975610e-03f, -1.585954990e-02f, 5.263791230e-02f, -1.757814550e-02f, -9.394777560e-02f, -3.230630230e-02f, 1.830086480e-02f, -1.653002760e-02f, -4.361025990e-02f, 3.554052860e-02f, 2.239854260e-02f, -2.771142500e-02f, 2.719200220e-03f, 3.202440220e-02f, 6.285986300e-02f, 5.819772840e-03f, -1.087488890e-02f, -3.339555110e-02f, -4.981463400e-02f, 6.563536360e-03f, 2.942487780e-02f, 1.914513480e-02f, 6.005997960e-02f, 4.134604330e-02f, -1.382037720e-02f, 1.057473270e-01f, -2.015369390e-02f, -2.457438970e-02f, -1.877668310e-02f, -3.703786060e-02f, 1.295700670e-01f, 1.794316810e-02f, 1.569176470e-01f, -4.725423830e-02f, 6.787924470e-02f, 4.085752370e-02f, 4.216935860e-02f, -7.156745340e-02f, -3.666609530e-02f, 1.372522670e-02f, -1.157579010e-02f, 7.397878450e-03f, 1.787377340e-02f, -3.680482130e-02f, -2.463504860e-02f, -6.885074080e-02f, -9.316341020e-03f, -5.087883400e-02f, -2.264437820e-02f, 2.747488620e-01f, 1.221621870e-03f, 7.494203750e-02f, 8.326717460e-02f, 2.272821780e-02f, 4.104230550e-02f, 1.547988950e-01f, 2.187684630e-01f, -2.334513000e-03f, 5.402635040e-02f, 5.136881400e-02f, 5.015952140e-02f, 4.197494690e-02f, -3.423390910e-02f, 1.771213300e-02f, -4.192319510e-02f, -2.859450690e-02f, 4.799462110e-02f, 2.736407520e-02f, 6.677486750e-02f, -4.409150030e-02f, -3.869558870e-02f, -7.988741990e-02f, 8.880698120e-03f, -1.010815430e-02f, -2.532253970e-02f, -5.150103940e-02f, -1.468431390e-02f, 1.349379120e-01f, -4.744410140e-02f, -6.508075450e-02f, 1.318810510e-02f, 6.180630250e-02f, -5.519397930e-02f, -1.183258740e-02f, 2.413303780e-02f, 1.139744840e-02f, -5.287008730e-02f, 6.712562400e-03f, -2.303637750e-02f, -4.598874600e-02f, -3.945092200e-03f, 4.529657960e-02f, -1.429486830e-02f, 7.182226330e-02f, 7.434020940e-02f, 1.057204830e-01f, 1.863462480e-01f, 6.328352540e-02f, 1.417323350e-01f, -1.618989740e-02f, 4.162550720e-02f, 1.640308090e-02f, -6.763887410e-02f, -5.695262920e-02f, -9.408549410e-03f, -2.409565960e-03f, 3.064953490e-03f, -7.253064960e-02f, -6.736452880e-02f, 1.869614120e-01f, 1.310076380e-02f, 1.260990840e-02f, 4.100249710e-02f, -1.454162780e-02f, -2.837995070e-02f, -6.983449220e-03f, 7.757354520e-02f, 9.313780810e-02f, 1.071007700e-01f, -6.080741060e-02f, 3.579502690e-03f, 5.280100550e-02f, -3.995361920e-02f, -5.533651640e-02f, -2.338134310e-02f, 2.162304150e-02f, -1.149530620e-02f, 1.138805320e-02f, -8.865734560e-03f, -1.696734690e-02f, -1.567793080e-02f, 3.434147310e-02f, -5.959690550e-03f, 1.351373050e-01f, -4.330461840e-02f, 8.075488350e-02f, -1.651067660e-02f, 6.789059190e-02f, -8.371692150e-02f, -8.533580600e-02f, -5.031340570e-02f, -1.497549560e-02f, 9.536909310e-02f, -2.909580800e-02f, 4.286856200e-02f, -5.178208000e-03f, -5.933634940e-02f, 1.502639150e-02f, 1.480469850e-01f, -1.652063240e-02f, 2.088448700e-01f, -2.740514280e-02f, 1.948243750e-02f, 4.312585290e-02f, -3.209259730e-02f, 2.666197720e-01f, 3.327476230e-02f, -4.531268400e-02f, -7.565998290e-02f, 1.002292340e-01f, -3.471108150e-03f, 1.523496360e-01f, -1.863008740e-02f, -5.655670910e-02f, -6.812109800e-02f, 5.283685030e-02f, 9.421333090e-04f, 5.329402910e-02f, 4.193212090e-02f, -2.442158570e-02f, 3.942148290e-03f, 1.246461050e-01f, 1.098521650e-01f, 4.335809500e-03f, 3.108945910e-03f, -2.304545980e-02f, 3.551186990e-02f, -2.715186220e-02f, 5.354996400e-02f, -3.126725320e-03f, 4.963659500e-02f, -4.657461120e-02f, 3.179312870e-02f, 1.261968610e-01f, 3.981407730e-02f, -2.184116650e-02f, -3.162803130e-02f, -3.894701970e-02f, -1.226432160e-02f, -3.116601520e-02f, 1.725366560e-01f, -3.728128970e-03f, 5.164245890e-02f, -7.186314460e-02f, 1.423133300e-03f, -2.495813560e-02f, -3.896930440e-02f, -3.923525660e-02f, -4.545933010e-02f, 3.634006720e-03f, -1.963983290e-02f, 3.893474860e-02f, -4.488032310e-03f, -4.682724180e-02f, 4.580354690e-02f, -3.088761310e-02f, -3.474831210e-02f, -2.137860840e-02f, -6.735577430e-02f, 1.906372790e-02f, 4.184547070e-02f, 8.455074570e-02f, 8.793018760e-02f, -5.882838370e-02f, -6.935393430e-03f, 3.945729140e-02f, -4.461095480e-02f, -1.194382180e-02f, -2.359787370e-02f, -6.203338870e-02f, -1.383191440e-03f, -5.653573570e-02f, 1.887484830e-02f, 1.116042030e-03f, -5.249697720e-02f, 1.748921130e-01f, -2.500199900e-02f, 1.623428170e-01f, -3.723257410e-02f, 9.157889330e-02f, 2.021729570e-02f, -3.003767880e-02f, -4.637004060e-02f, -1.812027950e-02f, 1.591735750e-03f, 1.211033480e-02f, 2.723179570e-02f, -2.113489810e-02f, 1.974755530e-01f, 8.642889560e-02f, 1.249526720e-02f, 8.327484870e-02f, -3.110321980e-02f, 1.139011090e-01f, -7.471966740e-02f, -3.637450190e-02f, 3.738132860e-02f, 2.494810150e-02f, 6.724402300e-03f, -5.313676220e-02f, -9.639625250e-02f, 3.513919190e-02f, -2.482474780e-02f, -5.330798680e-03f, -7.370548700e-02f, -3.767571970e-02f, -2.538499790e-02f, 1.561517420e-01f, 6.196926160e-02f, 2.571446900e-01f, -1.054365280e-02f, -5.638381090e-02f, -7.032488290e-02f, 5.941517280e-02f, 8.298662300e-02f, -2.136617900e-02f, -1.726464000e-02f, -3.025485950e-02f, -6.741648170e-02f, -4.718760400e-02f, -3.104134840e-02f, 1.430501580e-03f, 3.823765520e-01f, -2.727547850e-02f, 3.187818450e-02f, -2.102093030e-02f, 6.885382530e-02f, 8.560935970e-03f, -5.234109240e-02f, -7.666342890e-03f, -2.725888600e-02f, -3.917356950e-02f, 8.352329020e-03f, -2.807881120e-02f, -4.929272920e-03f, 3.165380660e-02f, 1.041796060e-01f, -7.426094260e-02f, -6.363131850e-02f, 1.190523280e-01f, -4.690480600e-02f, 7.411955860e-03f, -1.327169130e-02f, -2.142124440e-02f, -1.169243080e-02f, -1.543242480e-02f, -1.912328600e-02f, -2.889001740e-02f, -4.138779270e-02f, 9.791100020e-02f, -8.067991580e-02f, -5.099492150e-02f, -4.177882150e-02f, 2.368846910e-03f, 3.322600950e-02f, 1.558798850e-01f, 3.834987430e-02f, 1.362544760e-02f, -1.884611510e-02f, -2.164639530e-02f, -1.080753470e-02f, -1.946557130e-02f, -3.381162510e-02f, -2.716853660e-02f, -2.389512580e-02f, 8.681555090e-02f, 5.741540720e-02f, 1.549146770e-01f, 8.236600460e-02f, 1.404239830e-01f, -1.654691760e-03f, -5.790658300e-02f, 1.121729240e-01f, 2.639333900e-02f, 2.256595530e-03f, 7.993496950e-02f, -1.426172070e-02f, 6.218701220e-02f, -1.621596520e-02f, -3.937384170e-04f, 1.257846800e-01f, -3.587478770e-02f, -3.433914860e-02f, -3.263311830e-02f, 8.201121530e-02f, 9.946238240e-02f, -1.838374140e-02f, 1.501145210e-02f, -6.722378730e-02f, -3.962195010e-03f, 2.742060270e-02f, 7.160971870e-03f, 1.539917890e-01f, 8.058141910e-02f, -4.353719950e-02f, 5.523439120e-02f, 6.393455710e-02f, -7.769677040e-02f, 1.920204420e-02f, 1.829738170e-01f, 4.616012420e-02f, -1.580583680e-02f, -6.802513450e-02f, -4.033535250e-03f, 1.428288070e-01f, -1.063234920e-02f, -5.085870250e-02f, -8.817258470e-02f, 5.477532000e-02f, 3.870119900e-02f, 5.888797340e-02f, 3.671441230e-03f, -6.308112290e-02f, -7.947684270e-03f, 2.988402360e-02f, -6.890961520e-02f, 8.597171310e-02f, 1.502565950e-02f, 4.059601200e-02f, -3.366382330e-03f, 1.012714130e-01f, 3.335400300e-02f, -1.349246040e-02f, 1.492598500e-01f, 3.900798040e-02f, -8.310860950e-03f, -3.752347080e-02f, -3.205274050e-02f, -9.004951260e-02f, 1.101136950e-01f, 3.291672470e-02f, 1.328345950e-02f, 5.259931550e-03f, -1.063408890e-02f, 4.016191510e-02f, -2.993690410e-02f, 4.776754880e-03f, -2.396896110e-02f, 6.036813180e-02f, 2.141309080e-01f, -3.359114380e-02f, 2.159484480e-02f, 8.661849800e-02f, -5.050211770e-02f, 1.688860920e-02f, -2.823208640e-02f, -2.658559940e-02f, -3.864659370e-02f, 3.066470660e-02f, -3.864310310e-02f, -1.836833360e-02f, -5.659785490e-02f, -3.456730400e-02f, -2.972809410e-02f, 5.867297200e-02f, 1.193613710e-01f, 1.450941060e-02f, -2.376868390e-02f, 3.556465360e-02f, -4.009188710e-02f, 1.020130590e-01f, 6.000058350e-02f, 8.107840260e-02f, 4.788197580e-02f, -9.984562170e-03f, -7.737177610e-02f, 4.697973650e-02f, 3.640291750e-03f, 8.683557060e-02f, -1.542793770e-02f, 1.863246410e-01f, 8.764759450e-02f, 2.418517880e-02f, -5.198770020e-02f, -4.052370410e-02f, -1.830090300e-03f, -5.282956360e-02f, 6.820336450e-03f, 9.176696840e-02f, -5.753413770e-03f, -4.271804170e-02f, 4.326260460e-02f, 5.422199520e-02f, -2.227534730e-02f, -2.244229800e-02f, 9.919203070e-02f, 1.045261250e-01f, -3.164370080e-03f, -4.976394770e-02f, -1.535865850e-02f, -5.877302210e-02f, 8.134574440e-02f, -5.627424270e-02f, 4.121712600e-02f, 1.859086300e-01f, -2.238071520e-02f, -1.793896220e-02f, -2.317907290e-02f, -5.436998230e-02f, -3.381388730e-03f, 7.426416870e-02f, 3.784802560e-02f, 1.367724090e-01f, 7.490843530e-03f, 3.137404840e-02f, -1.102262080e-02f, -7.476389410e-02f, -4.786314820e-02f, -7.166776060e-02f, 3.456234560e-02f, -4.952047770e-02f, -5.545221730e-03f, -7.682637870e-02f, 6.219021230e-02f, -3.093536760e-02f, 1.068132740e-01f, -5.501797420e-02f, 1.357114500e-02f, -7.376986000e-02f, -2.976298700e-02f, 4.497207990e-04f, -4.820950700e-02f, -4.135253370e-03f, 7.078680390e-02f, 4.019299520e-02f, 2.595793310e-01f, -3.927013650e-02f, -7.529591020e-02f, 7.704971730e-02f, -6.524816900e-02f, 4.044095990e-03f, -1.747938250e-02f, 1.718676840e-02f, 1.921114510e-03f, -3.783340380e-02f, 6.554131950e-02f, -1.383155860e-02f, 7.780933380e-02f, -4.776561630e-02f, -1.001153610e-02f, -4.041935880e-02f, -4.404768350e-02f, -4.262065890e-02f, -1.756082290e-02f, 9.292788050e-02f, 6.247269730e-02f, -2.373705850e-03f, -5.289882050e-02f, -4.575352740e-02f, 1.165338980e-01f, -8.945735540e-02f, 9.272987390e-02f, 5.225184560e-02f, 3.782328960e-02f, -1.967579500e-02f, 3.776720910e-02f, -2.501191570e-02f, 1.308979690e-01f, 1.926297100e-01f, 1.321063660e-02f, 8.868837350e-02f, 1.148799880e-01f, -2.361949160e-02f, -2.600581200e-02f, 1.303752960e-01f, -1.763047460e-02f, -5.511216070e-02f, 4.935328380e-03f, 6.401167810e-02f, -1.246060430e-02f, -2.477378770e-02f, 1.980616710e-02f, -4.575463760e-02f, -1.108920390e-02f, -2.961983670e-03f, 4.694290830e-02f, 3.037663740e-02f, -1.427973340e-02f, 3.736356650e-02f, -6.203135840e-02f, -2.936557870e-03f, -2.288746280e-02f, 3.556466850e-02f, 4.115017130e-03f, 2.664468720e-03f, 2.665457320e-03f, 3.041936270e-02f, 8.264421490e-03f, 3.476098550e-02f, 7.032158970e-02f, -9.774621570e-03f, -2.541990580e-02f, 2.130371150e-02f, 8.215899770e-02f, -1.777091180e-03f, 2.530777080e-02f, 1.291850300e-02f, 7.573870480e-03f, -5.890943110e-02f, -7.021709350e-03f, -1.441914120e-02f, -2.924276700e-02f, 1.186030450e-02f, 5.872881970e-03f, -5.379887670e-02f, 2.647715850e-03f, 5.621831860e-03f, -6.322645400e-02f, -6.430004540e-02f, -7.543893290e-04f, 4.965834690e-02f, 3.680487350e-02f, -1.310074330e-02f, -3.347998480e-02f, -3.626265750e-02f, 2.097553010e-02f, 5.999000740e-02f, -2.207043210e-02f, 1.973738710e-02f, -5.313352500e-02f, -4.353674890e-04f, -7.167810950e-02f, 1.524358990e-01f, -7.013791050e-02f, -6.692741070e-02f, -3.036993930e-02f, 3.297056540e-03f, 1.830737290e-02f, -6.483221800e-02f, 2.509576680e-01f, -2.177168990e-02f, 1.790095270e-01f, -3.507876770e-03f, -2.698916380e-02f, 3.126867490e-02f, 4.934090190e-03f, 1.246456990e-02f, 3.701128960e-01f, 7.234615090e-02f, 5.813702200e-02f, 5.792906970e-03f, -1.379583030e-02f, 2.013479770e-01f, 8.229183400e-02f, -1.018951680e-01f, 1.006071180e-02f, 1.155851410e-02f, 1.526665500e-02f, -4.506389800e-02f, 1.105290650e-01f, -4.880674930e-02f, 8.800435810e-02f, -1.610431450e-02f, 2.480662060e-02f, 1.581147760e-01f, -2.906183340e-02f, -2.217023450e-02f, -5.503513380e-03f, -3.025566040e-02f, -5.596449970e-02f, -4.732542670e-03f, 6.507911530e-02f, 7.253645360e-02f, -8.813501890e-02f, 1.154859670e-03f, 7.572428140e-02f, 1.503100250e-01f, -4.967777990e-03f, 4.641142110e-02f, -1.260672230e-03f, 8.186446130e-02f, 5.267403650e-02f, -2.051089700e-02f, 1.343815960e-02f, -7.421120070e-03f, -1.056843100e-01f, 3.384326030e-02f, -1.669562790e-02f, 9.649244140e-03f, 6.850519030e-02f, 5.532962460e-02f, 6.954608860e-02f, -1.834066030e-02f, 1.716651390e-02f, 5.477498470e-02f, 1.542112980e-01f, -2.804242820e-02f, -1.704626340e-02f, -6.896093480e-03f, -5.136801300e-02f, -2.685010620e-02f, 1.062566340e-01f, -4.714442420e-02f, 5.242199450e-02f, -3.140568360e-02f, -4.196041080e-02f, -1.018385220e-01f, 2.708796230e-02f, -1.530541200e-02f, -3.892610220e-02f, -6.081547590e-02f, -8.006125570e-04f, 3.787386420e-02f, 8.894222220e-02f, 7.360608130e-02f, -7.302846010e-02f, 1.553540350e-03f, 4.715576020e-02f, 1.822185890e-02f, 1.470889450e-01f, 1.050745990e-01f, -7.274644820e-02f, -6.464405360e-02f, 1.310169580e-03f, -5.205312000e-02f, -1.002724380e-02f, -1.599509270e-02f, 1.390090210e-02f, -8.481055490e-02f, 5.669216810e-02f, 7.250897590e-02f, 7.380886380e-02f, 1.781209370e-02f, -5.934472200e-03f, -2.822301910e-02f, -7.262622570e-02f, 6.143435830e-02f, -5.869848650e-02f, -2.744934520e-02f, -5.761753400e-02f, -1.426576540e-02f, -3.213785590e-03f, 2.745767500e-02f, -9.644576350e-04f, -6.045399610e-02f, -3.477752580e-02f, -8.685899890e-03f, 1.117822430e-02f, -1.520510760e-02f, -4.345154760e-02f, 1.592614350e-01f, -2.363058920e-02f, 2.081169560e-02f, -3.510894250e-02f, 7.053221930e-04f, -4.165249690e-02f, -2.378591150e-02f, 1.351461110e-01f, 1.210287360e-01f, 1.541832000e-02f, 9.395305060e-03f, -1.599386890e-02f, 2.375323330e-02f, -3.389612210e-02f, -6.575728950e-02f, 8.061342680e-02f, 1.884195950e-01f, -5.880285800e-02f, -6.490882490e-02f, -3.036349550e-03f, -3.194450960e-02f, 8.148584510e-02f, -3.507290970e-04f, -3.370462360e-02f, -3.246898580e-02f, 3.801261260e-02f, 5.566322430e-02f, -6.584801520e-02f, -2.497984280e-02f, 1.436831520e-02f, 5.383211540e-04f, -4.995358360e-02f, 5.261883140e-02f, 4.159329090e-02f, -3.288962320e-02f, 2.204122250e-01f, 4.895413760e-03f, 7.498079910e-03f, -7.334110140e-02f, 3.088759260e-02f, -1.084377240e-02f, 2.703291740e-02f, -2.687888030e-02f, 1.877293180e-02f, 2.510733200e-03f, 8.123736820e-02f, -3.324420010e-02f, 2.880499510e-02f, -2.053752730e-02f, -4.368063060e-02f, 1.065646710e-01f, -5.116989460e-02f, -2.757307960e-04f, 1.077572030e-01f, -1.923517320e-02f, -1.587209110e-02f, -5.422897260e-02f, 4.781800140e-02f, -3.889391940e-02f, 6.661277260e-02f, -2.643414960e-02f, 1.154132470e-02f, -3.976302220e-03f, 8.093366020e-02f, 2.885356360e-02f, -5.086919760e-03f, 1.520418380e-02f, -2.898176200e-02f, -3.313645350e-02f, 8.668275180e-02f, -3.828446570e-02f, -6.985558570e-02f, 2.255024590e-04f, -9.106578300e-03f, 2.083689160e-02f, -6.723058220e-02f, -7.670085880e-02f, -3.744391350e-02f, 3.481621150e-01f, 1.224588320e-02f, 1.922555860e-01f, 1.543344280e-02f, 1.913423650e-02f, -5.859711390e-02f, -2.018836700e-02f, -6.885348260e-02f, 7.082117260e-03f, -7.267170590e-03f, -2.929327260e-02f, 6.099249000e-04f, -1.506479080e-02f, -4.142924770e-02f, -1.821537320e-02f, -3.948222850e-02f, 1.251375770e-02f, -1.914403170e-03f, 7.151038200e-02f, -5.339754370e-02f, 2.828582000e-02f, 2.438711000e-02f, -7.039099930e-02f, 3.971163560e-02f, -6.537820400e-02f, -1.800051150e-02f, -6.140564750e-02f, 1.870588960e-02f, 4.211743550e-02f, -4.015123470e-02f, 8.082836860e-04f, 5.037359150e-02f, -4.374134540e-02f, -2.403644470e-02f, -1.284581030e-03f, -4.814818870e-02f, 3.799435120e-02f, 3.901914950e-01f, 1.398662570e-02f, -8.739992970e-02f, 1.603694560e-01f, -2.523334460e-03f, -5.761311580e-02f, -2.416308780e-02f, -6.152221190e-02f, -4.268092660e-02f, 4.914082590e-02f, -7.994045320e-02f, -3.668553380e-02f, 8.544322100e-02f, -1.569019820e-02f, 4.758030180e-02f, 9.086306390e-02f, 9.481029210e-02f, 1.571650240e-02f, -2.166975290e-03f, 2.782239950e-02f, 6.632834670e-02f, 3.908315300e-02f, 9.611234060e-02f, 8.607568210e-03f, -2.147423660e-02f, 2.555457500e-02f, -6.289208680e-02f, 1.360890110e-03f, -2.114063500e-02f, -5.247052010e-02f, -4.368758950e-02f, -3.296696770e-02f, 5.874015390e-02f, -9.853483730e-02f, -6.253495810e-02f, -1.601490560e-02f, 1.275717620e-01f, -4.997905810e-03f, -3.336105500e-02f, 4.988906530e-02f, 3.038833380e-04f, -2.689081240e-02f, -2.145842090e-02f, -2.579080690e-02f, -8.555034170e-03f, -6.875874100e-02f, 7.361255590e-02f, -3.441404920e-02f, -6.672655050e-02f, -7.878965130e-02f, -1.715389640e-02f, 1.095798980e-01f, -3.015258720e-02f, 2.930128570e-02f, -2.988627550e-02f, -3.376733510e-02f, 3.332076830e-03f, 3.271408500e-04f, -1.191093960e-02f, -3.872315210e-02f, -2.332496460e-03f, 6.894143670e-02f, -5.555982140e-02f, 1.569845710e-02f, -7.565494160e-03f, 1.032432540e-01f, -5.709623170e-02f, -3.018986810e-02f, 6.042774770e-03f, -1.486172060e-02f, 1.786232140e-01f, 1.910445690e-01f, 3.570111840e-02f, 4.198237880e-02f, -3.837721420e-02f, 9.870236730e-03f, 8.517964920e-02f, 5.153474210e-02f, -9.618310250e-03f, -2.267269420e-02f, 2.797401550e-01f, -1.074657400e-02f, 3.373675790e-02f, 6.399711960e-02f, -1.801252920e-02f, -4.410605130e-02f, 1.933184220e-03f, -6.161724780e-02f, -1.214499400e-02f, -5.173332240e-02f, 2.146740700e-01f, 5.221839620e-02f, 5.418390410e-02f, 9.680861600e-03f, -7.341003410e-02f, 2.033626660e-02f, -6.148492540e-02f, -2.652806420e-02f, 8.461691440e-03f, -3.158685560e-02f, 6.323964890e-02f, -2.328022010e-02f, 7.575426250e-02f, -2.733036130e-02f, -3.130774950e-02f, -4.586641490e-02f, 1.391776280e-02f, -2.583467220e-02f, 2.402855270e-02f, 4.458522800e-02f, -5.842367190e-02f, -2.977167810e-02f, 1.445284860e-02f, 7.526558640e-02f, 4.629850760e-02f, -4.812410470e-02f, 4.468392580e-02f, 1.733361370e-02f, -6.024237350e-02f, -2.614284120e-02f, -5.804073810e-02f, 1.128330380e-01f, 4.727653040e-02f, -3.981344030e-02f, 3.197882320e-02f, -2.512510680e-02f, 8.261661050e-03f, 3.995759040e-02f, -4.648043960e-02f, -4.078283530e-02f, -5.129253490e-02f, 5.059600990e-02f, -5.035232290e-03f, 6.673076740e-02f, 4.881665480e-02f, 2.322300670e-01f, 3.030818100e-01f, -4.909327630e-02f, -9.568975310e-03f, -1.717791020e-04f, -5.785042050e-02f, -3.067455630e-02f, -2.406742050e-02f, -3.118856810e-03f, 3.172975780e-02f, -6.138061640e-03f, 1.065648870e-01f, -5.687251310e-02f, -4.922914320e-03f, -8.060451590e-03f, -9.727532160e-04f, 1.515680850e-01f, 8.438382290e-02f, -3.563432770e-02f, -2.286630500e-02f, -3.782368080e-02f, -7.293459770e-02f, 1.072720360e-01f, 5.482605470e-02f, -4.280462860e-02f, 5.905030300e-02f, 2.775179780e-02f, -5.491308870e-03f, 4.708891360e-02f, 2.796764860e-02f, 7.342950250e-02f, -4.544276000e-02f, 2.549398690e-02f, -4.179848470e-04f, 4.935831300e-03f, 2.066170420e-02f, 1.816588080e-02f, 2.767576280e-02f, 1.193142030e-02f, -4.530237990e-03f, 2.649938450e-03f, -7.539501410e-03f, -2.374215800e-02f, -3.058380450e-02f, 2.748519180e-02f, 3.350863610e-02f, -2.975154200e-03f, -2.751018290e-02f, -3.284013360e-03f, -7.345285270e-03f, 2.057926960e-03f, 1.285872330e-02f, 1.247178860e-02f, 2.404527740e-02f, 2.434210480e-02f, 1.250036810e-02f, -5.791834090e-03f, -1.129853350e-02f, 2.871615250e-02f, -2.486640770e-02f, 9.822251740e-06f, -1.351590180e-02f, -2.503880820e-04f, -1.053625900e-02f, 1.283161690e-03f, 3.551384810e-02f, -3.425803040e-03f, -2.526978780e-02f, -1.217797210e-02f, 1.199218630e-02f, 1.218845140e-02f, 4.354780540e-03f, 2.880459650e-02f, -2.762852700e-03f, -2.260210920e-03f, 4.898644980e-02f, 8.486819450e-03f, 3.663622480e-04f, -1.006159000e-02f, 1.009947900e-02f, -1.739907080e-02f, -1.084681020e-03f, -8.718404910e-03f, 1.920665990e-02f, 1.685395650e-02f, -4.010342060e-02f, 2.379495090e-02f, 2.274432780e-02f, 1.714175750e-02f, -1.853050660e-02f, 2.427642610e-02f, 1.269214510e-02f, -9.978476910e-03f, 1.855373940e-02f, -7.138160520e-03f, -1.044420430e-02f, 1.097716760e-02f, 1.367992160e-02f, 1.958703390e-03f, 7.504367080e-02f, 4.066187520e-02f, 5.979429120e-04f, 1.838453700e-03f, 1.859133320e-02f, 3.560291600e-02f, 1.115059390e-02f, -2.811865180e-03f, -9.120326480e-03f, 2.509798300e-02f, 1.794118620e-02f, 3.676490490e-02f, 1.243183300e-02f, 1.020308210e-02f, 1.095470230e-02f, 7.191462910e-03f, 1.589119810e-02f, 1.826325800e-02f, 2.605605680e-02f, 3.333641220e-02f, -1.740930140e-03f, 3.524944930e-02f, 1.637680830e-02f, -8.036641400e-03f, 7.964157500e-03f, 5.210942590e-03f, -2.411505210e-02f, 3.019083850e-02f, 3.456868980e-02f, 3.996144980e-02f, 1.266737190e-02f, 2.701014650e-02f, -1.108148140e-02f, -3.624478730e-02f, -5.564020020e-03f, 1.052707990e-02f, 3.784709420e-02f, 3.216587010e-02f, 2.447100730e-02f, -1.118335410e-02f, 6.197254360e-02f, 3.373038020e-02f, 2.786695490e-03f, 1.548547200e-02f, 4.365536940e-02f, 3.055282680e-02f, 6.307199590e-03f, 1.717334240e-02f, -1.546385420e-02f, 5.608999360e-02f, 3.701794150e-02f, 2.634259130e-02f, 1.794510330e-02f, 2.058036070e-02f, 3.735492010e-02f, 3.862167150e-02f, 7.385337720e-03f, 3.106092660e-02f, 3.220512720e-02f, -4.092492160e-03f, 1.827153750e-02f, 1.987052520e-02f, 5.892687290e-02f, -4.377448470e-03f, 4.216312990e-02f, 3.403483330e-02f, 2.254476770e-02f, -5.878163500e-03f, -8.183231570e-03f, 2.104600330e-02f, 3.706106920e-02f, 9.889797310e-03f, -1.362377590e-02f, 2.280396970e-02f, 1.634507250e-02f, -2.524267510e-02f, 7.106037810e-03f, 4.001880810e-02f, 4.720576480e-02f, 1.338346210e-02f, 4.184810440e-02f, 1.655822430e-02f, 2.231870590e-02f, 3.564121950e-02f, 4.392094540e-02f, 1.501316900e-03f, 2.174850550e-02f, 2.996500020e-02f, 2.574085260e-02f, 2.085769920e-02f, -3.273738550e-02f, -1.310333030e-03f, 2.097146960e-02f, -6.649480670e-03f, -1.719030840e-04f, 3.061912950e-02f, -7.431012110e-03f, -2.235835790e-02f, -2.705664840e-03f, 1.860336770e-02f, -2.124899810e-02f, 5.374547560e-03f, 2.898170430e-02f, 2.403115670e-02f, 3.280706700e-02f, 3.372872990e-02f, 1.981458810e-02f, 2.670153980e-02f, 3.331755470e-02f, 2.318813650e-02f, 2.535564640e-02f, 1.662116130e-02f, 3.023321930e-02f, 4.777335750e-02f, 2.029670770e-02f, -1.888666300e-03f, 2.055893470e-02f, 2.430535850e-02f, 1.798461750e-02f, 2.474856380e-02f, 1.270148340e-02f, 5.373106150e-02f, -9.559686300e-04f, 5.764726550e-03f, 4.225350170e-02f, 1.768853520e-02f, 1.545451670e-02f, 3.405751660e-02f, 3.653183210e-02f, 3.204186630e-02f, 3.967398030e-02f, 1.779316740e-02f, 2.903958040e-02f, 4.723147300e-02f, 2.778338830e-02f, 6.587666930e-03f, -2.500908260e-02f, 1.282948910e-02f, 5.800403650e-03f, 1.614507850e-02f, 5.420302040e-03f, 5.775200670e-03f, 3.107609970e-02f, 2.765757220e-02f, 3.539960600e-03f, 4.784765470e-02f, 4.852606730e-02f, 2.016387690e-02f, 5.299675090e-02f, 1.712676510e-02f, 1.495544150e-02f, 2.030425150e-02f, 3.036025540e-02f, 2.051549220e-02f, -7.133950010e-03f, 6.479081510e-02f, 4.400764030e-02f, 3.359099850e-02f, -1.419280000e-02f, 3.348967060e-02f, 2.828097340e-02f, -1.131818160e-02f, -1.112109420e-02f, 4.593744820e-04f, 6.595673030e-03f, 5.058740450e-02f, 1.696819090e-03f, 7.625840600e-02f, 2.075952110e-02f, 3.474779430e-02f, 1.438721830e-02f, -4.103512500e-03f, 5.133082350e-02f, 1.537652690e-02f, 2.625175010e-02f, -4.585520360e-03f, 3.828455510e-02f, 3.107150640e-02f, -1.023440810e-02f, 1.448217030e-02f, 3.056945510e-03f, 1.155094520e-02f, 3.685526780e-03f, 5.494887750e-02f, -9.091184470e-04f, 4.763197530e-02f, 1.065540590e-02f, 3.779715300e-02f, -1.938438070e-04f, 3.926785660e-03f, 4.306411740e-02f, 1.223108080e-02f, 4.500819740e-02f, 3.179799390e-02f, 1.949151050e-02f, -2.818474310e-03f, 4.684696910e-03f, 1.013720130e-02f, -3.057470780e-03f, 2.799789190e-03f, -2.718187680e-02f, 9.306108570e-03f, 2.864418920e-02f, 1.690822280e-02f, 7.236714590e-04f, 3.778421130e-02f, 4.465556890e-02f, 1.427816320e-02f, 3.070970620e-02f, 1.544643750e-02f, 1.706633530e-02f, 4.081632200e-02f, 4.597278310e-02f, 3.399430540e-03f, -1.413279210e-03f, -2.793819180e-03f, 2.028961670e-02f, -1.599861120e-02f, -2.315585500e-02f, 3.833243620e-02f, -2.358629830e-03f, -3.033684100e-03f, 3.109510800e-02f, 2.799801710e-02f, 1.218376960e-02f, -7.704458200e-03f, 1.534596920e-02f, 2.945051340e-02f, 9.950178670e-03f, 1.578378490e-02f, 3.084690120e-02f, 2.424854410e-02f, 6.011443590e-02f, 1.895814760e-02f, 4.360614340e-02f, -1.667910110e-04f, 4.430301490e-02f, 2.437244910e-02f, 3.035900740e-02f, 1.482318740e-03f, -2.145016940e-02f, 4.077086970e-02f, 7.292301390e-03f, 3.406194500e-03f, -8.231257090e-03f, -4.490686580e-03f, -8.622626770e-03f, 5.004632470e-02f, 9.833500720e-03f, 3.238302840e-02f, 1.429426200e-02f, 1.371601500e-02f, 2.338404210e-02f, -1.166664440e-02f, 2.942394650e-02f, 9.106907990e-03f, -4.727474410e-03f, 2.012379090e-02f, -1.775760200e-02f, 6.879103840e-03f, -1.276279430e-02f, 5.061667180e-04f, 5.930581600e-03f, 1.024109030e-02f, -1.357417740e-02f, 6.885480140e-03f, 4.067482050e-02f, 1.797911340e-02f, 8.012465200e-03f, 1.793717780e-02f, 2.664044130e-02f, 4.744399340e-03f, 3.362274540e-02f, -7.504777980e-03f, 8.068326860e-03f, 2.483491320e-03f, 1.490411530e-02f, 4.185225350e-03f, 6.176392080e-03f, -2.926163380e-03f, 1.949094240e-02f, 1.992599850e-02f, 1.453695350e-02f, 3.012296740e-02f, 7.976392280e-03f, -2.573438550e-02f, 3.910252820e-02f, -1.107120700e-02f, 9.570279510e-04f, -1.305616340e-03f, 1.481000800e-02f, 2.933644920e-03f, 6.036795210e-03f, 4.340038080e-02f, 1.377161780e-02f, 1.495247610e-02f, 4.958529030e-02f, 1.578060720e-02f, 1.266741570e-02f, 1.855567470e-02f, 4.000839590e-02f, 2.582191860e-02f, 9.997594170e-03f, 2.824538760e-02f, -2.546564860e-02f, 1.005781630e-02f, 6.255330510e-03f, -1.608813000e-02f, 3.033490480e-02f, 2.136086110e-02f, -1.705853040e-03f, 4.481163340e-03f, -7.148740810e-03f, 2.381431130e-02f, -2.503838020e-02f, 8.378424680e-03f, 2.695084920e-02f, 3.340081870e-02f, 1.936173810e-02f, 4.076638450e-02f, 5.082123350e-02f, 3.473343330e-02f, 2.930795770e-02f, -1.083642940e-03f, -6.130008490e-03f, 2.983168140e-02f, 8.395127950e-03f, 1.950600000e-02f, 5.143533000e-03f, 1.764857960e-02f, 4.053800550e-02f, 8.283992300e-03f, -2.742344280e-03f, -5.268620330e-03f, 2.645538190e-02f, 3.670022360e-03f, 4.821762820e-02f, 2.961323970e-02f, 1.805082340e-02f, 2.435261940e-02f, 3.078631310e-02f, -6.841384340e-03f, 1.355963850e-02f, 1.943741180e-02f, 3.350889310e-03f, 1.543504740e-02f, -2.433915620e-02f, 7.697426250e-03f, 4.908405240e-02f, -4.738040730e-04f, -8.118359370e-03f, 3.010424040e-02f, 4.234251380e-02f, -5.427877230e-02f, 3.222119990e-03f, 1.948184680e-03f, 1.836369930e-02f, 2.122716790e-02f, 1.663271710e-02f, 3.905959050e-02f, 4.142941160e-02f, 2.528903630e-02f, 2.260215210e-02f, 1.963646150e-02f, 7.088323680e-02f, 2.549047400e-02f, -1.366135480e-02f, -2.595554800e-03f, 4.587996380e-02f, 2.791927010e-02f, -2.035220530e-02f, 1.873741860e-02f, 2.400610220e-02f, 4.102095590e-02f, 5.497524890e-02f, 8.191573620e-02f, 3.635218370e-03f, 3.046199310e-02f, 1.808300430e-02f, 3.004757690e-03f, -3.683613150e-03f, 2.145187000e-03f, -1.649643640e-03f, -9.948347690e-03f, -1.622359830e-02f, 1.031841340e-02f, -1.323952150e-02f, 7.233917710e-03f, 4.768014420e-03f, 1.134118620e-02f, 1.301305650e-02f, -1.952406210e-02f, -8.121328420e-03f, 1.207860190e-03f, 2.210996860e-02f, 1.690590200e-02f, -3.791161250e-02f, -7.698865140e-03f, -2.542381920e-02f, -1.776383260e-02f, 3.823265670e-03f, -6.994288880e-03f, 9.198602280e-03f, -2.253795970e-02f, 1.065545530e-02f, 1.416773630e-02f, 1.383873730e-02f, 1.014398690e-02f, 2.813377790e-02f, 3.581816800e-03f, -2.506405670e-02f, 2.308972180e-02f, -6.629680280e-03f, -2.243616620e-02f, 6.064302750e-03f, 1.171062700e-02f, 1.077236420e-02f, -2.880941150e-02f, -1.774575790e-03f, 5.747077060e-03f, 6.777224600e-03f, 1.899306100e-02f, -1.650508730e-03f, 5.025393330e-03f, -1.914338770e-02f, -1.944410800e-02f, -7.395767140e-03f, -1.050314400e-02f, -2.656149210e-03f, -9.356359950e-03f, -2.563731740e-02f, -8.513164710e-03f, -1.280950480e-02f, -3.710071740e-02f, 6.242705970e-03f, 1.931331820e-03f, -4.449973810e-03f, -2.364755240e-02f, 9.254015980e-03f, -2.824352870e-02f, 1.079784520e-02f, -1.102345160e-02f, -2.266890000e-02f, 9.709802460e-03f, 6.761047520e-03f, 7.813056000e-03f, 1.716726460e-02f, -2.561967590e-03f, 1.546892150e-02f, 1.417204920e-02f, 9.046434420e-03f, -1.075213870e-02f, 4.452691410e-03f, 5.811395120e-03f, 7.960999380e-03f, 2.185603230e-02f, -2.179908750e-02f, 2.135921270e-03f, 5.659719930e-03f, 1.522674410e-02f, -7.783234120e-03f, 8.531444710e-03f, 2.612670880e-02f, 1.247266590e-02f, 4.398134720e-02f, 2.609056050e-02f, 1.948517000e-02f, 1.125291460e-02f, -2.411178310e-03f, 1.722184200e-02f, -4.706616050e-03f, -2.231920140e-02f, 4.456124730e-03f, 6.917104120e-03f, -2.839518520e-02f, 3.214693440e-02f, 9.736500680e-03f, -1.892524070e-03f, -7.738761600e-03f, 1.833174560e-02f, 1.992002870e-02f, -1.607548630e-02f, -5.846840330e-03f, 2.234959230e-02f, -1.112981140e-02f, 2.712871320e-02f, 1.746077840e-02f, 2.260253950e-02f, 3.789753090e-02f, 5.191172820e-04f, 1.469321080e-02f, 1.054792660e-02f, 1.695588420e-02f, 5.392965400e-03f, 3.268930320e-02f, 1.236616520e-04f, 1.704667320e-02f, 1.979421270e-02f, 1.041406490e-02f, -1.845655960e-02f, 3.739854320e-02f, 3.309693190e-02f, 2.552169190e-02f, 2.881390790e-02f, 2.673452910e-02f, 3.768488020e-02f, 1.147958920e-02f, 7.103354670e-03f, 2.291548760e-03f, 3.446168500e-03f, 1.952052300e-02f, 3.596758470e-02f, 5.912465600e-02f, 2.758274970e-02f, -2.058579770e-02f, 3.750111540e-02f, 2.373396980e-02f, 3.422971440e-02f, 1.053174590e-02f, 5.746592210e-02f, -1.316606810e-02f, 2.429224550e-02f, 4.259113690e-03f, 2.953504580e-02f, 2.536678870e-02f, 3.773035110e-02f, 5.362585560e-02f, 1.836138220e-02f, 3.714011980e-02f, 1.991621220e-02f, 1.986896430e-02f, 2.598683540e-02f, 2.266061490e-02f, -1.686098430e-02f, 8.317459720e-04f, 3.147558120e-02f, 8.728399870e-03f, 1.961461450e-02f, -1.490299960e-02f, 2.175076490e-02f, 4.013988000e-02f, 1.546760460e-02f, 1.718774620e-02f, -1.993430550e-03f, 1.906736750e-02f, -8.459043690e-03f, 1.363926570e-02f, -1.572989490e-02f, 2.773157880e-02f, 4.329390080e-02f, 2.243877390e-03f, 1.877305100e-02f, 6.861642750e-02f, 4.535587040e-03f, 1.077878200e-02f, 4.729445090e-03f, 5.360239740e-02f, 2.306316050e-02f, -1.055009940e-02f, 1.144478380e-02f, 1.546598600e-02f, 5.404101680e-03f, 3.152108940e-02f, 2.087465110e-02f, -6.889762350e-03f, 4.463666300e-02f, 2.833079360e-02f, 4.746830840e-02f, 1.524295100e-02f, 8.829547090e-03f, 3.771953750e-03f, 3.599638590e-03f, 2.248234860e-02f, -9.720633740e-03f, 2.809533480e-02f, 1.598179530e-02f, 4.051083700e-02f, 1.863398120e-03f, 4.041262900e-03f, 1.548163130e-02f, 3.605376930e-02f, 4.470782350e-02f, 5.700366110e-03f, 3.177804870e-02f, -1.754757200e-02f, 2.780863640e-02f, -6.265790200e-03f, 2.393566070e-02f, 2.001189630e-02f, -8.399346840e-03f, 9.781261900e-03f, 2.103191800e-04f, 1.091378550e-02f, 3.340118750e-02f, 2.703435720e-02f, 6.744882560e-03f, -1.320407730e-02f, 2.183092760e-02f, 1.600184480e-02f, -9.455567920e-04f, 1.374433840e-02f, 4.454861400e-03f, -3.341683370e-02f, 4.948901010e-02f, 5.412427130e-04f, 1.824598010e-02f, 3.753393890e-03f, -2.261266300e-02f, 3.332197290e-02f, -5.570953710e-03f, 1.574225540e-02f, 1.305144560e-02f, 2.626445890e-02f, 4.906000570e-03f, 2.739582400e-02f, 3.636970370e-02f, 4.811925810e-02f, 2.839476060e-02f, 2.436701390e-02f, 5.177105310e-03f, 4.167568310e-02f, 1.208980290e-02f, 2.013778690e-02f, 2.201036780e-03f, -1.057199990e-04f, 2.627517100e-02f, 3.679255950e-03f, 3.711106260e-02f, 6.370212880e-03f, 5.016381290e-02f, 1.068171020e-02f, 6.247326730e-02f, -5.350490100e-04f, 3.540322930e-02f, 9.334457110e-03f, -3.684845520e-03f, -6.392642850e-03f, -5.403260700e-03f, 2.148690450e-02f, 1.376354140e-02f, 2.990814300e-02f, -1.257727020e-02f, 1.796871420e-02f, 1.376599170e-02f, -6.960854810e-05f, 1.393527820e-02f, -9.481117120e-03f, 1.664880850e-02f, -1.864262860e-02f, -1.217467240e-02f, 2.877127380e-02f, 1.879303020e-03f, 8.263021700e-03f, 9.181819860e-03f, 6.399455480e-03f, 1.200616640e-02f, 5.459620430e-02f, 2.392541620e-02f, 1.951235930e-03f, 4.793278500e-02f, 1.654681940e-02f, 2.749392020e-02f, 9.444719180e-03f, 2.290847710e-02f, 2.568847130e-02f, 7.115608080e-03f, -2.285057490e-02f, 2.830481160e-02f, 2.729701060e-02f, 4.700612740e-03f, -5.952815060e-03f, 2.959081900e-04f, 8.831038140e-03f, -1.757904510e-02f, 3.138747420e-04f, -2.311401810e-02f, 1.632857140e-02f, 6.985441780e-03f, -2.913977720e-03f, 2.919922020e-02f, 4.141994190e-02f, 1.457202480e-03f, 2.328198960e-02f, 4.389387560e-03f, 2.834837320e-02f, 3.168466690e-02f, 4.020603960e-04f, -1.719511300e-02f, 3.502074630e-02f, 8.425037380e-03f, 8.839605370e-03f, 1.343170650e-02f, 3.820599240e-02f, 2.574919910e-02f, 1.000867780e-02f, 2.340137400e-02f, 3.298924860e-02f, 3.345102820e-02f, 7.602268360e-03f, 6.478768310e-03f, -1.603173650e-02f, 5.584625180e-04f, 1.791719530e-02f, -3.538855350e-03f, 3.445502740e-02f, 3.310377150e-02f, 1.095055700e-02f, 1.735549790e-02f, -7.982418870e-03f, 3.917666150e-02f, -4.098590460e-03f, -8.898118510e-03f, -1.110685340e-02f, 6.307209840e-04f, 9.870147330e-03f, 4.642133410e-02f, -2.006996420e-02f, 1.380301550e-02f, 5.164919790e-02f, 3.576500340e-02f, 4.190736640e-02f, 2.458713020e-02f, 3.043989090e-02f, 7.547459750e-02f, 3.163013610e-02f, -2.273712540e-03f, 6.515651940e-03f, 5.590161890e-06f, -1.483791040e-02f, 1.395945090e-03f, -1.702224840e-02f, 4.605655740e-02f, 3.226899730e-02f, 1.662303320e-02f, 5.877917170e-03f, 4.800186030e-03f, 2.012900450e-02f, 9.919600560e-03f, 4.048103290e-04f, 1.013501550e-02f, 3.035677360e-04f, 3.082012390e-02f, -4.238775000e-03f, 8.241968220e-03f, 5.617664010e-02f, 1.313804460e-02f, 1.691631790e-02f, 1.258146480e-03f, 2.181270900e-02f, 3.537472710e-02f, 3.522871060e-02f, -1.303453840e-02f, 1.913453270e-02f, 1.195482540e-02f, -2.655835080e-02f, 1.696958950e-02f, 2.281401490e-02f, 5.539782810e-03f, 5.271275060e-03f, 4.678847640e-02f, -1.803882230e-02f, 3.602151950e-02f, -1.682878100e-02f, 2.335649170e-02f, 3.829110040e-02f, -1.895306630e-02f, 3.285674380e-02f, -1.663701610e-02f, -8.425794540e-03f, -1.524109020e-02f, 8.370923810e-03f, -1.930188950e-02f, 7.132978640e-04f, -1.872144450e-02f, -5.747192540e-03f, 1.818048950e-02f, 2.429257850e-03f, 3.596207590e-03f, -1.827614940e-02f, 1.120975430e-02f, -2.283269730e-02f, 1.340773310e-03f, 8.126542900e-03f, 2.060198040e-02f, 3.684459720e-03f, -8.299604990e-03f, 6.954940030e-03f, -2.524965070e-02f, 3.020704720e-03f, 1.024704240e-02f, 2.445425090e-02f, -1.914492060e-02f, 1.267492960e-02f, 3.709669690e-03f, 3.370648480e-04f, 1.983922350e-02f, -1.732040010e-02f, 8.606329560e-03f, -1.431490290e-02f, 3.502377120e-02f, 2.401455680e-02f, 1.282779970e-03f, 1.235333270e-02f, -1.188459710e-02f, -8.948547760e-03f, 2.419451070e-02f, -1.720283550e-02f, -1.682461980e-02f, 2.386609280e-02f, 8.108462210e-03f, 4.523557050e-02f, -1.938578860e-02f, 7.512978740e-03f, 2.778346280e-02f, 1.017033310e-02f, -3.233940340e-03f, 1.251797080e-03f, -3.240053310e-03f, 9.531608780e-03f, 1.387250240e-02f, 4.437800500e-03f, 3.803396970e-02f, -1.296666920e-02f, 1.282791980e-02f, -8.419948630e-03f, 9.518077590e-03f, 3.016472420e-02f, -1.153315040e-02f, -1.776279320e-02f, -1.454069560e-02f, 3.976586270e-03f, -1.465972790e-02f, 2.326552010e-02f, 2.312731180e-02f, -8.308357560e-03f, 8.273178710e-03f, 2.471756560e-02f, -1.752683780e-03f, 6.155311130e-03f, 1.191406700e-02f, -2.356562950e-02f, 2.037213370e-02f, 1.424902120e-02f, -1.721735230e-03f, -3.441912680e-02f, -6.924417340e-03f, -2.081767890e-03f, 2.279407530e-02f, 1.757921840e-02f, -3.375022490e-02f, -4.285892940e-04f, 2.234415710e-02f, -1.874593650e-02f, 1.006768920e-02f, 1.264401060e-02f, 2.948013320e-02f, -6.185162810e-03f, -3.146435370e-03f, -2.752784080e-02f, -1.505087130e-02f, -5.925958980e-03f, -2.130332220e-02f, 8.194897320e-03f, 4.025347070e-03f, 4.180445340e-03f, -4.715428500e-02f, -6.580877580e-03f, -7.711657090e-04f, -7.101579100e-03f, -1.794197970e-02f, 2.061749810e-02f, 1.779767130e-02f, -6.223955660e-03f, -2.321119230e-02f, 1.232993320e-02f, -7.222745570e-03f, 2.022535730e-02f, 1.547029060e-02f, -2.308082390e-02f, 2.593749950e-02f, -1.020566190e-02f, 2.002966820e-03f, -8.132040500e-03f, -1.164436430e-02f, -1.889640470e-02f, 1.676797120e-02f, -1.940891890e-02f, -1.810938410e-04f, -3.632767870e-02f, 6.337929050e-03f, 2.264104780e-03f, -2.080161680e-02f, 2.253039930e-02f, -2.000107800e-02f, 2.643209180e-03f, 1.173461600e-02f, 1.261069440e-02f, -1.175938870e-03f, -2.196060310e-02f, 9.664298960e-03f, 2.522740700e-02f, 1.440659170e-02f, 7.464367430e-03f, 2.572822200e-02f, 1.699693270e-03f, 6.974325980e-03f, 2.322128970e-02f, 3.239302900e-03f, -9.566408580e-03f, 1.482667120e-02f, 5.124285350e-03f, 3.770228940e-03f, 5.866842340e-02f, 2.446330520e-02f, 1.303417610e-02f, -7.475402210e-03f, 9.492920710e-03f, 2.918793630e-02f, 2.847492690e-02f, 1.500748280e-02f, 7.346408440e-03f, 1.043107640e-02f, -7.040741850e-03f, 2.675492320e-02f, 1.326234270e-02f, -4.638144750e-03f, 2.622555760e-02f, 8.958327580e-03f, -9.963083080e-03f, 4.012158140e-03f, 9.381690990e-03f, 4.775036500e-02f, 2.893961970e-02f, 2.522655020e-02f, 3.625264390e-02f, 1.114362850e-02f, 3.699313480e-02f, 1.143367680e-02f, 1.232487800e-02f, 9.624455120e-03f, 3.721988570e-02f, 3.083696960e-02f, 3.124866080e-02f, 7.174737290e-03f, 1.299334690e-02f, -1.372892690e-02f, 1.051226720e-02f, 1.754429190e-02f, -6.363293150e-03f, -6.575117580e-04f, -2.328840640e-02f, 4.139913620e-02f, 7.231527010e-03f, 8.220556190e-03f, 7.569487210e-03f, 7.640570400e-06f, 7.147464900e-03f, 2.573891360e-02f, 3.325516730e-02f, 1.122662610e-02f, 2.402271140e-02f, 2.131883610e-02f, -7.975935000e-04f, -2.599679630e-03f, -4.501787480e-03f, 1.623545770e-02f, 3.459440920e-02f, 1.332036030e-02f, 8.283100090e-03f, -1.757891480e-02f, -1.167572450e-03f, 3.860552610e-02f, -1.204559490e-02f, 5.095206670e-03f, 2.363455850e-02f, -1.301215380e-04f, 2.365539220e-02f, 1.618368360e-02f, 2.202126940e-02f, 6.719415540e-03f, 2.286652660e-02f, 3.233924510e-02f, 1.427020600e-02f, -1.373562400e-02f, -1.324435580e-04f, 1.768783670e-02f, -2.673009220e-02f, 8.011439810e-03f, 1.485476920e-02f, 2.789379280e-02f, 1.975272600e-02f, 1.684651710e-02f, 1.465481800e-02f, -4.042216390e-02f, 6.781647450e-03f, -1.772600110e-03f, 8.869456120e-03f, 1.447725580e-02f, 8.564635180e-03f, 1.737993020e-02f, 3.181570770e-02f, 1.666495200e-02f, 1.846990360e-02f, 8.062615060e-03f, 3.544345870e-02f, 3.031443800e-02f, 8.458612710e-04f, 2.235457300e-02f, 6.805532150e-03f, 1.919131540e-02f, 3.193498120e-03f, 1.676129550e-02f, 1.653866470e-02f, 2.871267870e-02f, 1.725023610e-02f, 2.136493470e-02f, 2.960146030e-02f, 1.672443240e-03f, -2.019367550e-02f, 2.620464380e-02f, -1.152918670e-02f, 7.753681860e-03f, 5.033677910e-03f, -1.242154160e-03f, 1.873131280e-02f, 1.245086170e-02f, 1.382251080e-02f, 2.561342340e-02f, 1.144501850e-02f, 1.859063660e-02f, -1.633158700e-02f, -1.724432780e-02f, -2.804109080e-02f, 1.592573710e-02f, -2.602876400e-03f, 1.814927720e-02f, -4.799330140e-03f, 9.034777990e-03f, 3.258782630e-02f, 1.996336320e-02f, 5.809697510e-02f, 4.068439830e-02f, 2.742894180e-02f, 4.066993950e-03f, 2.267127860e-02f, -3.327793670e-03f, 2.524396780e-02f, -4.442277360e-03f, -1.609469950e-02f, -9.411275390e-03f, 4.346252420e-03f, 1.016299520e-02f, 2.606820130e-02f, 1.392163240e-02f, 6.287906780e-03f, 2.642051130e-02f, -1.533908680e-02f, -1.117816890e-03f, -6.953061090e-04f, -1.846843590e-02f, 3.001228910e-03f, 9.400359350e-03f, 3.524326160e-02f, 2.562697420e-02f, 4.779056830e-02f, 1.430874690e-03f, 1.273629350e-02f, 2.276941200e-02f, 2.653293680e-02f, 6.697377180e-03f, -1.955349730e-04f, -1.473701190e-02f, -4.434375090e-03f, 7.406250570e-03f, 8.950054650e-03f, 2.300613560e-02f, -5.579973110e-03f, 2.743099070e-02f, 2.554569950e-02f, 9.411428120e-03f, -1.153468250e-02f, 4.147338490e-02f, -2.185546790e-03f, -6.046512160e-03f, -7.687457370e-03f, 3.813694040e-02f, 1.759148950e-02f, 2.082009240e-02f, 2.747132910e-03f, -1.764822520e-03f, -1.600443010e-02f, -1.317834670e-02f, 8.253295910e-03f, -1.381380200e-02f, 1.930724480e-03f, -6.675844770e-04f, 4.689384250e-03f, -2.691545150e-02f, -3.980206330e-03f, 1.369011500e-02f, 9.897871870e-03f, -6.086729470e-03f, 9.145736690e-03f, 1.271950550e-03f, -4.025816450e-03f, 3.759507320e-03f, -1.119029990e-02f, 1.563093740e-03f, -2.518213540e-02f, 4.777966530e-03f, 7.326501890e-03f, 2.483448200e-02f, 2.499257400e-02f, 6.058350200e-03f, -3.168438330e-03f, 2.694110940e-02f, 2.644828330e-02f, -1.903068090e-02f, 1.174548450e-02f, -5.724096670e-03f, 9.663572530e-03f, 1.416316910e-02f, -1.536154930e-02f, -4.121150360e-03f, -3.150211410e-03f, -8.573009630e-03f, 2.210254550e-03f, 2.002219480e-02f, 8.609824810e-03f, 1.179235610e-02f, 1.826790910e-02f, 2.356227110e-02f, -8.712628850e-03f, 2.289943210e-02f, -6.543913850e-03f, -6.932343240e-05f, 1.154201480e-02f, 1.947931570e-02f, -1.331751420e-02f, -5.568172320e-03f, 1.026981420e-02f, -6.847821640e-04f, -1.443614250e-02f, 8.303268810e-03f, -1.488463720e-03f, 2.000737750e-02f, -9.589523070e-03f, -1.001094370e-02f, 3.122866150e-02f, -1.501055990e-02f, 1.863411260e-02f, 2.887624690e-02f, 4.111469910e-02f, 2.651782520e-02f, -3.489775700e-04f, 2.268010750e-02f, -2.673958080e-04f, 2.962026370e-02f, -1.088264490e-02f, 3.914331640e-02f, -1.591783760e-02f, 5.206438250e-03f, 2.741287090e-02f, 1.432945020e-03f, -4.697340070e-03f, 1.975804380e-02f, 5.285386370e-02f, 7.910949180e-03f, 2.013095280e-02f, 1.354061810e-02f, 1.763411980e-02f, 1.465582570e-02f, 1.423614660e-02f, 1.894503650e-02f, 7.200994530e-03f, 4.381463680e-02f, 1.569502520e-03f, -1.647794810e-02f, -1.165741960e-02f, 4.296975960e-02f, 1.867846770e-02f, 1.757341620e-02f, 9.987962430e-03f, 3.409201650e-02f, 3.155314920e-02f, -4.252986240e-02f, 1.570181920e-03f, -2.040444690e-02f, -2.897524270e-03f, 4.728643970e-02f, 2.372145280e-02f, -5.753315990e-03f, 7.218098640e-02f, -4.976097030e-03f, 4.216085750e-02f, 1.106854440e-02f, 5.122027550e-02f, 5.049865690e-02f, 5.094669760e-03f, 3.383069860e-02f, 1.547664960e-02f, 2.289641090e-02f, 2.259453570e-02f, 2.091000790e-02f, 3.580417480e-02f, 1.769907960e-02f, 3.783809020e-02f, 5.212020500e-02f, 1.857276450e-02f, 4.184050490e-02f, 2.791148980e-02f, 2.708330280e-03f, 1.750973610e-02f, 5.344030910e-03f, 2.817882690e-03f, -3.546724100e-02f, -1.168982780e-02f, -1.471812370e-03f, -1.122320260e-02f, 1.216845820e-03f, -2.231178060e-02f, 4.473325800e-03f, -2.387937160e-03f, 1.693536340e-02f, -2.483186870e-02f, 9.011289100e-03f, -5.180394740e-03f, 9.715806690e-03f, -2.136879790e-02f, 3.893242220e-03f, 2.702998560e-02f, -6.315761710e-03f, -1.848200340e-02f, -6.409126800e-04f, 1.176139060e-02f, 2.272351410e-03f, 3.770699490e-03f, 7.121520110e-03f, 1.188455340e-02f, -6.419138520e-04f, 2.264015940e-02f, -2.045924590e-02f, 3.567277920e-03f, 1.575508620e-03f, 2.772358800e-02f, -2.005184530e-03f, -2.062384600e-02f, 2.515930310e-02f, -2.391482330e-02f, -2.696403670e-02f, 2.078648420e-03f, -2.342914700e-03f, 1.609851050e-02f, -9.861619210e-03f, 1.613512080e-02f, 1.570441570e-02f, 1.956901700e-02f, 1.773489640e-02f, 2.011392820e-02f, 7.771425410e-03f, -1.223963030e-02f, 4.111109670e-02f, 8.113299500e-03f, 7.296450900e-03f, 1.455548030e-02f, 1.500170330e-03f, -1.110576370e-02f, 1.775274610e-02f, 1.161298710e-03f, -1.180764010e-02f, 1.754636320e-02f, 2.005356360e-02f, -4.912969190e-03f, 1.294370550e-02f, 2.412069780e-02f, 1.167552550e-02f, -1.339095270e-02f, 1.188858780e-02f, 1.244302000e-02f, -2.816458930e-03f, 4.040784760e-02f, 5.415853110e-02f, 8.249369450e-03f, -8.503409100e-03f, -1.551612090e-02f, 1.906596500e-02f, 2.289304880e-02f, 2.429030370e-03f, -1.534534150e-02f, 1.440568180e-02f, 3.549639880e-02f, 3.553316370e-02f, 1.506657810e-02f, 4.653366660e-02f, 2.496469770e-02f, 2.044554610e-02f, 4.205358030e-02f, 2.695724930e-02f, 5.391704620e-04f, 2.282178030e-02f, 1.342010310e-02f, -1.350601110e-02f, 1.459226660e-02f, 3.845480830e-02f, 2.694413300e-03f, 2.423126620e-02f, -4.771023240e-02f, 4.812800140e-02f, 8.756870400e-03f, 4.246285560e-02f, 1.306612600e-02f, 4.154684020e-02f, 3.429896010e-02f, -1.725078000e-02f, 3.669502450e-03f, 5.174957680e-03f, 6.820476150e-03f, 1.306276860e-02f, 1.727072520e-02f, 3.450482710e-02f, 7.028751080e-02f, 4.607110470e-02f, 1.447224340e-02f, -7.543832990e-03f, 5.251978340e-02f, 5.855293200e-02f, 2.146985200e-02f, -7.928478880e-04f, 2.647125720e-02f, 1.790267600e-02f, 2.653129590e-02f, 2.331469390e-02f, 1.119552650e-02f, 3.370730580e-02f, 3.063062390e-02f, 6.819698960e-02f, 1.543386840e-02f, 2.451508310e-02f, 7.618412840e-03f, 5.142759530e-02f, 2.084531820e-02f, 1.709379260e-02f, 4.209148510e-02f, 7.443271580e-03f, 5.734668110e-03f, -2.321398350e-03f, -1.128657350e-02f, -1.671461270e-03f, 4.433357620e-03f, 4.546955230e-03f, -7.431980690e-03f, 2.537322600e-02f, -4.307941530e-03f, -7.425118240e-03f, 3.466535710e-04f, -4.579692610e-03f, -1.720917990e-03f, -1.575829090e-02f, -1.339383240e-02f, -2.428120370e-02f, 2.854976240e-02f, 1.007510160e-02f, 2.802639450e-02f, 2.548756820e-02f, -2.491911640e-03f, 1.297929090e-03f, 1.229617190e-02f, -4.610874880e-02f, 2.119706570e-02f, 1.887222750e-03f, -6.697120610e-03f, -9.491442460e-04f, 3.811826230e-03f, 3.806292640e-02f, -3.531422840e-02f, 1.255263020e-02f, 2.154273910e-02f, 7.248395120e-04f, -4.065816100e-02f, -1.287367780e-03f, -3.990138420e-03f, 1.477254930e-02f, 1.069584120e-02f, 7.961020800e-03f, 8.637170310e-03f, 1.726811290e-03f, -3.534645070e-03f, 1.953248680e-02f, 2.096766610e-02f, -1.163244530e-02f, 1.148608630e-03f, 1.292025670e-03f, -2.406161280e-02f, -9.626584360e-04f, -1.485689640e-02f, 4.773624710e-03f, -1.555240160e-04f, -1.241949110e-02f, -3.627824410e-02f, 3.170414830e-03f, 1.140560020e-02f, 9.113692680e-03f, -7.125707340e-03f, -2.290793000e-03f, 3.674299640e-02f, 3.179364280e-02f, -1.829198190e-02f, -1.472721900e-02f, -6.709836420e-03f, -1.143891460e-02f, 6.152987010e-03f, 1.770003700e-03f, 6.128820130e-03f, 2.726866860e-02f, 1.522899980e-02f, -2.457390910e-02f, -1.424120370e-02f, -5.565434690e-03f, 4.638108420e-03f, 3.465515750e-02f, 7.142874530e-04f, 4.607234900e-02f, 2.059342900e-02f, -1.339592880e-02f, 1.483297720e-02f, -6.515338550e-03f, 4.326517510e-02f, 1.666183020e-02f, 1.130348630e-02f, 1.095739750e-02f, 1.477973540e-02f, 7.706013970e-03f, 5.280865590e-04f, -2.075052820e-02f, -2.850129640e-02f, -1.517347290e-03f, 1.570480690e-02f, 1.666435040e-02f, 2.390566100e-02f, 6.008058320e-03f, 1.614591920e-03f, -3.926411270e-02f, 5.256265870e-04f, 5.891426930e-03f, 5.172924140e-03f, 4.162934420e-02f, -2.655443740e-02f, 1.856371760e-02f, 3.415572640e-02f, 2.688806690e-02f, 2.482583930e-02f, 1.466794130e-02f, 2.673120610e-02f, 1.915680800e-02f, 2.767694180e-02f, 1.026368510e-02f, 1.546091210e-02f, -4.303107040e-03f, 6.754091940e-03f, 2.460662280e-03f, 1.432804390e-02f, 7.531580050e-03f, -1.245388760e-02f, 2.017974290e-02f, -1.351495830e-02f, 1.843756620e-02f, -9.255539620e-03f, -2.283641140e-03f, 2.001977150e-02f, -2.787784670e-03f, 2.682844920e-02f, -9.577117860e-03f, -4.101197700e-03f, -3.335392570e-03f, -2.934582760e-03f, -4.941316320e-03f, 2.735085040e-02f, 1.323334310e-02f, 1.272856720e-02f, 8.699601510e-03f, -1.564006690e-02f, -2.197070420e-02f, 1.160918920e-02f, -8.111936970e-03f, 7.551066110e-03f, 3.642551890e-04f, -7.215253080e-03f, 2.177364940e-02f, 8.344884030e-03f, 8.915817360e-03f, 2.022273280e-02f, -6.864911880e-03f, 4.536749040e-04f, 4.478214310e-03f, -1.077853700e-02f, -1.451813900e-02f, 1.936572600e-02f, 4.023117010e-03f, -2.000805360e-02f, -1.024304420e-02f, 1.057671010e-02f, -1.531356110e-02f, 8.583656510e-03f, -4.780975170e-03f, 2.728603590e-02f, -2.266471650e-02f, 2.559644920e-02f, 1.846578340e-02f, -3.069446980e-02f, 5.759148860e-03f, 5.516167730e-03f, -1.099672350e-02f, 1.484858430e-02f, 2.641886710e-03f, -1.017270420e-02f, -1.208671460e-02f, 1.329223440e-02f, 4.409435210e-03f, 2.063621580e-02f, -2.790429160e-03f, -2.171670090e-02f, 1.891919970e-02f, 3.520074860e-02f, -9.254679310e-04f, -5.179356780e-02f, 1.450905670e-02f, -1.517759450e-02f, 1.777816380e-02f, -4.869896450e-03f, 1.538290460e-02f, -1.199969280e-02f, 3.078392150e-02f, -2.235453950e-02f, 1.415417060e-02f, 6.451746440e-03f, 2.177043630e-02f, 2.834783680e-02f, 2.568571270e-02f, 8.531811650e-03f, -2.586377600e-02f, -1.743218490e-02f, 2.251940590e-02f, 1.321545800e-02f, 3.830628100e-02f, -2.080548370e-02f, 5.744365510e-03f, 4.191260780e-02f, 2.316130330e-02f, -1.079984470e-02f, 2.525050570e-02f, 2.272937260e-02f, 2.258660740e-03f, 1.015794930e-02f, 2.469430490e-02f, 4.523134320e-03f, 2.592494900e-02f, -4.123844210e-03f, -1.597722990e-03f, 5.612832960e-03f, 1.990818420e-02f, -5.587194580e-03f, 3.045514920e-03f, -2.414546720e-02f, 3.339445590e-02f, 1.783670860e-02f, 5.334489510e-03f, -3.143310920e-02f, 1.732561360e-02f, 5.496884510e-02f, 7.045584490e-04f, 3.853486850e-03f, -4.561416340e-03f, 1.463887280e-02f, -1.315762750e-02f, 1.792167900e-04f, 1.525823210e-02f, 4.537192360e-02f, 3.236808350e-03f, 5.468599870e-02f, 3.672079370e-02f, 3.733118620e-02f, 2.736315500e-02f, 4.826723410e-02f, 2.195768990e-02f, -7.337295450e-03f, 7.894056850e-03f, 1.238648590e-02f, -1.230324150e-02f, -2.279987790e-03f, 1.574088630e-02f, -1.957435630e-03f, 1.446751230e-02f, 3.170105440e-02f, 4.455746710e-02f, 1.043700610e-02f, 1.200890350e-02f, -9.941010730e-03f, -6.553330920e-03f, 2.280951290e-02f, -1.264811870e-02f, 1.073870900e-02f, -1.472098750e-02f, 1.492202050e-03f, -1.000537440e-02f, -8.666156790e-03f, 6.612266410e-03f, -7.039217270e-03f, 1.516302120e-02f, -2.235491760e-02f, 6.771458430e-04f, -5.098161750e-03f, 1.582113470e-02f, 6.198346150e-03f, -3.333674370e-02f, 1.522508360e-02f, 1.861277780e-02f, -1.287109960e-02f, 1.493662220e-02f, 1.323393450e-02f, 4.282427950e-03f, 6.625583390e-03f, 1.728933120e-02f, 1.401951440e-02f, 2.647903380e-02f, 2.900966210e-03f, 1.858293640e-02f, -1.178267600e-02f, -4.260129760e-03f, -1.657133740e-02f, 1.309991160e-02f, 8.976906530e-03f, -1.972105540e-02f, 1.464640810e-02f, -1.359311300e-02f, 4.323267380e-03f, -2.120421270e-02f, -4.050605000e-03f, -2.344311960e-02f, -1.978207380e-03f, -3.942813260e-03f, 5.622738390e-04f, -2.245297470e-02f, 2.299796040e-02f, -1.768863760e-02f, -1.910144490e-04f, -7.312307130e-03f, 3.502113740e-02f, 3.658891100e-02f, -1.224804390e-02f, -1.674172650e-02f, 1.022243520e-04f, 1.866515540e-02f, -4.659502300e-03f, -1.567577360e-03f, 2.636030880e-02f, 1.417723110e-02f, -2.838108500e-02f, 1.754417460e-02f, -3.190147130e-02f, 1.483480730e-02f, -3.009300680e-02f, -2.495910600e-02f, 6.791319700e-03f, -7.136639210e-03f, 1.385968360e-02f, 2.639914120e-02f, -1.737364570e-02f, 3.314709290e-02f, 1.108654680e-02f, 3.106045350e-02f, 1.185171770e-02f, 2.714541740e-02f, -1.670969770e-03f, 5.167183000e-03f, 2.615471930e-02f, 1.165642590e-02f, 1.748162880e-02f, -1.221624580e-02f, 4.414390030e-02f, -1.752597280e-03f, 2.526953440e-02f, 1.516304910e-02f, 1.199272930e-02f, 1.927918570e-02f, -1.284398790e-02f, 2.331084200e-02f, 8.655101990e-03f, -1.356649310e-02f, 3.154738250e-02f, -2.084308120e-02f, -1.276646550e-02f, 1.575699450e-02f, 3.742579740e-02f, 2.188256570e-02f, 1.376016070e-02f, -2.038520570e-02f, 7.297676520e-03f, -1.629357970e-02f, -4.396883770e-03f, -9.434096520e-03f, 3.078775710e-03f, 3.655189880e-03f, 2.640370470e-02f, 3.673763200e-02f, 4.204459860e-02f, -2.729637550e-02f, 8.933172560e-03f, 1.372272990e-02f, 6.049846300e-03f, -1.360734920e-02f, 2.693582700e-02f, 1.838397230e-03f, -6.141708000e-04f, 1.930602080e-02f, 3.904022510e-03f, 5.005400160e-03f, 1.933182960e-02f, 4.413239660e-02f, -5.320006980e-03f, 3.657657650e-02f, 2.009357330e-02f, 3.082081120e-02f, -1.224413890e-02f, 2.263305150e-02f, 4.354057830e-03f, 3.348190340e-02f, 8.884446690e-03f, 7.618758830e-03f, -3.286073220e-03f, 3.111655270e-02f, 3.140354900e-02f, 2.738096570e-02f, -2.910420070e-03f, 2.493087760e-02f, 1.145766210e-02f, 2.625930870e-02f, -1.417496240e-03f, 2.148423530e-02f, 2.638177010e-03f, 9.869972240e-03f, 1.212877340e-03f, 1.725733840e-02f, 2.684155480e-02f, 4.768577870e-03f, 6.298591200e-02f, 2.481872770e-02f, 3.839176520e-02f, 4.682445530e-02f, 3.051413970e-02f, 7.093525960e-03f, 1.729925720e-02f, 4.287219610e-03f, -1.415502370e-02f, -9.920353760e-04f, -1.358220070e-02f, 6.097304450e-02f, 1.512488260e-02f, 5.008963120e-02f, 1.695391160e-02f, 2.955049090e-02f, 2.571176740e-03f, -3.337538240e-02f, -3.587325660e-02f, 3.454235570e-02f, 3.487424550e-02f, 4.290077370e-03f, 4.790080340e-02f, 2.133305560e-02f, 7.314898820e-02f, 3.335373100e-02f, 1.345713720e-02f, 4.497108980e-02f, 6.852480020e-02f, 4.394751790e-02f, 1.455665660e-02f, -2.251128850e-02f, -6.191349590e-03f, 2.183029800e-02f, -5.161299370e-03f, 1.633647270e-02f, 2.525278930e-02f, 5.228675530e-02f, -3.865923030e-03f, 3.633730110e-02f, 8.577517230e-03f, 1.935430430e-02f, 1.564107460e-02f, 2.396409770e-02f, 3.282298520e-02f, 2.310702760e-02f, 1.534122420e-04f, 2.961343900e-02f, 1.626483540e-02f, 2.591428910e-02f, -1.029419430e-02f, -7.894507610e-03f, 7.475775200e-03f, 6.023325840e-04f, 4.450754730e-03f, -3.467327680e-03f, 1.968934010e-02f, 3.883189990e-03f, 1.504524150e-03f, 3.840496650e-04f, 3.251149900e-04f, -1.343647670e-02f, 7.924508300e-03f, 1.491853780e-02f, -3.637966000e-03f, 2.580755390e-02f, 1.440723430e-02f, 1.052553490e-02f, 4.545977340e-02f, 2.782474270e-03f, -1.487360800e-02f, 1.236595030e-02f, 6.284219680e-03f, 7.821970620e-03f, -7.260748650e-03f, -9.233260520e-03f, 5.576922560e-03f, 2.438720320e-02f, 1.204906220e-02f, -7.729243490e-03f, 1.193604620e-02f, -1.980047490e-02f, 1.629966680e-02f, 2.382409390e-02f, 3.277288000e-02f, 2.417016770e-02f, 2.779056690e-02f, -5.744365630e-04f, 1.949171350e-02f, 2.167567240e-02f, 4.663802220e-03f, 6.912615150e-03f, 5.174119030e-03f, 2.783658730e-02f, 2.912859900e-03f, -5.338241350e-03f, 7.864690390e-03f, 3.103658370e-02f, -1.949782860e-02f, 3.019290420e-02f, 1.228043160e-02f, -1.467748920e-02f, -5.763572640e-03f, 3.363818680e-02f, -4.421052060e-03f, 2.731720540e-02f, 8.743950170e-03f, -8.850089270e-03f, 8.264228700e-03f, -1.677176730e-02f, 2.282906510e-02f, 3.080409580e-02f, 3.233183550e-02f, 3.916089240e-02f, 2.779747170e-02f, 1.813231410e-02f, -1.427813150e-02f, 2.995714550e-02f, 3.544381630e-02f, 1.562243980e-02f, 1.066308750e-02f, 1.367538420e-02f, 6.499062870e-04f, 5.242503060e-02f, 2.820045920e-03f, 2.905498630e-02f, 2.200474780e-02f, 3.520062890e-03f, 1.662600790e-02f, 1.532102470e-02f, 2.799115140e-02f, 4.746861380e-02f, 2.880009260e-02f, -5.644712130e-03f, -1.280364110e-02f, 9.315984320e-03f, 1.494025530e-02f, 6.176737140e-03f, 5.035287230e-03f, 2.780328500e-02f, 1.695820690e-02f, 2.371497450e-02f, 4.990189340e-03f, 7.934359830e-03f, 6.548912080e-02f, -1.467039900e-02f, -1.421759930e-02f, 2.703608760e-02f, 3.104446830e-02f, 6.813178770e-03f, 2.422241490e-02f, 1.591926440e-02f, 3.867077080e-02f, 1.934138130e-02f, 2.645048690e-02f, -1.702997650e-02f, 2.554627320e-02f, 2.099269810e-02f, -2.061517910e-03f, -9.253978720e-03f, 1.416579820e-02f, 1.129764780e-02f, 1.137569080e-02f, -1.139453980e-02f, 1.168538540e-02f, 2.146696110e-02f, 3.545046230e-02f, 1.742774810e-02f, 1.441686410e-02f, 2.927622570e-02f, 1.372171940e-02f, 1.847839010e-04f, 2.755538000e-02f, -3.195719790e-02f, 6.792418190e-03f, 2.072088420e-02f, 2.275016530e-02f, 2.977820300e-02f, 1.375338810e-02f, 9.959550570e-03f, -1.404970980e-02f, 3.191893550e-02f, -1.291236470e-02f, 2.010757660e-02f, 3.055567210e-04f, 5.740337070e-02f, 8.253025820e-03f, 4.095979780e-02f, 1.896554250e-03f, 6.595470940e-03f, -2.343637640e-03f, -6.389790210e-03f, 5.476137620e-02f, -1.196327340e-02f, 4.213420670e-02f, 1.258442740e-02f, 1.773140390e-02f, 1.680533400e-02f, -1.677352190e-02f, -8.134829810e-03f, 1.112967730e-02f, 1.394132430e-02f, -2.268565070e-02f, 3.687456620e-02f, 1.827769540e-02f, -1.118526140e-02f, 4.578981550e-03f, 1.912634450e-02f, 7.826465180e-03f, -2.190923320e-02f, -1.051770900e-02f, 1.297451370e-02f, -3.611946710e-03f, 5.171926690e-02f, 5.263558400e-02f, 1.062362830e-02f, 4.968510940e-02f, 6.155824290e-03f, 1.716372180e-02f, 1.411587930e-02f, 3.263815860e-02f, 3.729587420e-02f, 7.815401070e-03f, 9.476467960e-03f, 4.005473850e-02f, 1.113463570e-02f, 3.065402390e-03f, -2.809152010e-02f, 1.311342420e-02f, 6.274259650e-03f, 2.735391070e-02f, 2.553477880e-02f, 3.194031540e-03f, 2.629261280e-02f, 2.826893520e-02f, -7.046286950e-03f, 2.291577120e-02f, -1.474374350e-02f, 4.147201780e-02f, 2.499822150e-02f, -1.053172400e-03f, 1.560287360e-02f, -1.455740350e-02f, 8.417663160e-03f, 3.877972490e-03f, 3.236250580e-02f, -4.618689420e-03f, 3.457370030e-02f, -2.183930200e-02f, -8.776614440e-03f, 2.186214920e-02f, 2.307114190e-02f, 1.846878980e-02f, 1.397386290e-02f, 1.884356140e-02f, 1.820618470e-02f, 2.014392060e-02f, 4.927634450e-02f, 6.839562210e-02f, 3.732143720e-02f, 1.609947530e-02f, -2.289534600e-04f, 1.344155990e-02f, 1.439506750e-02f, -5.089523040e-04f, -6.036329430e-04f, -1.408777010e-02f, 2.215615660e-02f, 2.682282220e-02f, 1.846017320e-02f, 7.650258950e-03f, 2.013487370e-02f, 3.060929480e-02f, -1.634589210e-02f, -3.886865450e-02f, 1.229821980e-02f, 1.467222530e-02f, 2.035068530e-02f, 2.015682680e-02f, 4.524513330e-02f, 2.537853080e-02f, 1.896683130e-02f, 4.793991520e-02f, 1.312564970e-02f, 3.388995300e-02f, 3.841631110e-02f, 1.671976970e-02f, 1.344214380e-02f, -1.453218700e-02f, 3.996395320e-02f, 6.729228890e-03f, 7.549423720e-03f, 4.257230090e-02f, 1.600205900e-02f, 2.573300340e-02f, 2.141609600e-02f, -4.265491850e-03f, 4.964434190e-04f, -6.363986990e-03f, 6.882733670e-03f, 1.502782480e-02f, 1.950985190e-02f, 3.007167020e-02f, 1.573916520e-02f, 8.914276030e-03f, -2.147919500e-03f, 1.372819670e-02f, -7.139039690e-03f, -2.681255530e-02f, 5.365916530e-03f, 8.556580170e-03f, -6.746666970e-03f, -1.673905370e-02f, 1.667883620e-02f, 9.347626010e-03f, 2.379986640e-02f, 2.138431740e-02f, 4.871479240e-03f, 2.718135340e-02f, -2.049474600e-02f, 2.700870670e-02f, -7.579962260e-03f, -8.667978460e-03f, 2.915765530e-02f, 1.363468170e-02f, 1.453481520e-02f, 2.038066650e-02f, 4.444208930e-03f, 1.035829170e-02f, -3.852906400e-03f, -1.481626180e-03f, 3.150866180e-02f, -2.357339250e-03f, -1.175307670e-03f, 3.447831050e-02f, 1.676431670e-02f, 7.213011850e-03f, -2.985142540e-02f, -2.108109420e-03f, -1.634396990e-02f, -1.863191460e-02f, 2.924765460e-03f, -5.524511910e-03f, -2.818439390e-04f, 4.474294560e-02f, -1.483530550e-02f, 6.547394670e-03f, -1.089774650e-03f, -8.025806390e-03f, 2.613233960e-02f, -1.489456560e-02f, -7.973100060e-03f, 3.185183550e-02f, 8.826203410e-04f, 1.067720120e-03f, 1.192487500e-02f, 1.510625120e-03f, 2.032202110e-02f, 7.834060110e-03f, 2.255368610e-02f, 1.332324560e-02f, 2.096803860e-02f, -4.156587650e-03f, -1.476238670e-02f, 1.239843570e-02f, 1.551772000e-02f, 1.612191090e-02f, 2.713796680e-02f, 1.484471560e-02f, 5.877648010e-03f, 1.263952160e-02f, 2.753918250e-02f, -1.561009140e-02f, 7.897892960e-03f, 4.552948290e-03f, 3.449718930e-04f, -1.298784930e-02f, -4.436387100e-04f, -1.027154920e-02f, 1.676720750e-02f, 8.296677840e-03f, 1.429419220e-02f, 2.080944180e-02f, -1.289044040e-02f, 3.266733880e-02f, 3.572682290e-02f, 2.168819680e-02f, 1.519831080e-02f, -1.247561820e-02f, -1.962523350e-02f, -2.985089550e-03f, 9.819130410e-03f, -1.407171510e-02f, -3.856574650e-03f, -1.127350890e-02f, 8.146015000e-03f, -8.805069140e-03f, 8.088557040e-03f, 2.002097430e-03f, 2.624084610e-02f, 8.032082580e-03f, -1.738546420e-03f, 5.094409920e-03f, 1.616362670e-02f, 3.180924060e-02f, -1.711436920e-02f, 1.472866070e-02f, -1.913422900e-02f, 3.949921580e-02f, -2.187592210e-03f, 1.173982120e-02f, 9.713964530e-03f, 2.168256980e-02f, 1.793796200e-02f, 6.110935470e-03f, 1.895559950e-02f, 2.071207760e-02f, -1.004680060e-02f, 1.417412980e-02f, -9.100382220e-03f, -1.566514370e-02f, 2.537098900e-02f, -1.407811700e-02f, 1.835725270e-02f, -4.960416820e-03f, 2.047423970e-03f, 2.833079550e-02f, -2.157950220e-02f, -5.415205840e-03f, -3.972859590e-03f, 1.822472360e-02f, 4.437657450e-02f, 2.556543050e-02f, 6.627220190e-03f, 4.349149390e-02f, 1.665870890e-03f, 1.640627160e-02f, 6.929133550e-03f, 5.701190330e-03f, 2.256309240e-02f, -1.782712530e-02f, 4.631936550e-03f, -3.336126100e-04f, 2.981323380e-02f, 8.346455870e-04f, 2.757418900e-02f, 2.646945230e-02f, 6.387913590e-03f, -5.623755980e-03f, 1.419941800e-02f, 1.970443130e-02f, 2.892975140e-02f, 2.648193020e-02f, 3.843961280e-03f, 1.165718590e-02f, 1.335834250e-02f, 6.656808770e-03f, -4.549219370e-05f, -2.492159050e-02f, 3.992974390e-02f, 5.396771060e-02f, -3.423157610e-03f, 9.510857980e-03f, 1.586904750e-02f, 8.791678590e-03f, -6.294345860e-02f, 7.165863640e-03f, 1.764369570e-02f, -3.077386130e-02f, 3.317246910e-03f, 1.007546210e-02f, 2.018450200e-02f, 3.962485490e-02f, -2.566317330e-03f, 2.621712540e-02f, 2.498817630e-02f, 3.514011950e-02f, 1.696562020e-02f, -3.038812430e-03f, 5.416566040e-03f, -8.981920780e-03f, 2.344249190e-02f, 2.111967090e-02f, 1.352793910e-02f, 5.861809940e-03f, 1.133734730e-02f, -6.602979730e-03f, 1.636761050e-02f, 4.404111300e-03f, 2.056317960e-02f, 4.815657620e-03f, -1.236487830e-02f, 9.169750850e-03f, 7.422605520e-03f, 5.765187000e-02f, 2.504353230e-02f, 1.519346240e-02f, 9.661984630e-03f, 1.792700960e-02f, -1.433516850e-02f, 7.349865510e-03f, -6.152849180e-03f, 1.035596240e-02f, 5.629713410e-04f, -1.788902100e-02f, 1.314326560e-02f, -1.198230590e-02f, 2.184434420e-02f, 2.429714990e-02f, -1.065955870e-02f, 5.454785660e-03f, 3.785332660e-03f, -2.567852850e-03f, 1.737986130e-02f, 1.396725140e-02f, -3.485466350e-03f, 1.695222410e-02f, -1.805058910e-03f, 9.567412550e-03f, -1.823332980e-03f, 2.351744850e-02f, 2.475888650e-02f, -1.829564940e-02f, 2.178221570e-02f, 3.439516950e-02f, -1.940035820e-02f, 7.359730550e-03f, 5.247251600e-03f, 9.376100260e-03f, -2.039468660e-02f, -1.868217440e-02f, 2.205201610e-02f, -5.272542590e-03f, -5.940668750e-03f, 8.840667080e-03f, -8.935787720e-03f, 1.247913760e-02f, 2.400565710e-02f, -1.109724400e-02f, 8.678804730e-04f, 1.567664740e-02f, 1.310158060e-02f, 5.155151240e-03f, 7.876020860e-03f, -8.891639300e-03f, 3.021097180e-02f, 3.451423950e-03f, -1.457089930e-02f, 1.759523150e-02f, -2.366524420e-03f, 2.556591290e-02f, 2.219203110e-02f, 8.802727800e-03f, 2.730514970e-04f, -2.754902840e-02f, -1.952152700e-02f, 1.828740580e-03f, -1.106679530e-02f, 2.812334150e-02f, 3.308556600e-02f, 1.312719470e-02f, 2.686105480e-02f, 3.054493290e-02f, 1.332462670e-02f, 1.971272570e-02f, 4.151121900e-02f, -5.366473460e-03f, -7.074829660e-03f, -1.055658980e-02f, -5.365678110e-03f, -2.527909820e-03f, 1.394827760e-02f, 4.422798010e-02f, 2.926077130e-02f, 3.494621440e-02f, 2.128846240e-04f, 1.066280900e-02f, 6.744022480e-03f, 6.122046150e-03f, 1.809009350e-02f, 1.337223130e-02f, 3.995106370e-02f, 4.527974410e-03f, 3.349217030e-02f, 7.897201920e-03f, 1.143384350e-02f, -1.320677340e-02f, 1.258203290e-02f, 3.908268730e-02f, 1.718993300e-02f, 2.038510330e-02f, 2.146592180e-02f, 5.660244450e-02f, -2.038548700e-02f, -2.884699730e-03f, -2.614261350e-03f, -1.150816490e-02f, 3.204185750e-03f, 6.682551000e-03f, 2.869646060e-02f, 4.924717920e-02f, -3.932577560e-03f, 9.444482620e-03f, 1.807403560e-02f, 3.028837220e-02f, 5.855550990e-03f, -1.133954150e-02f, 1.339150410e-02f, 2.609853820e-02f, 4.027203470e-02f, -1.245704850e-02f, 1.545858480e-02f, 1.717515480e-02f, 3.668417410e-02f, 1.166068950e-02f, 4.215239360e-02f, -1.284827590e-03f, 3.961632400e-02f, -1.201989780e-02f, -3.766264070e-03f, 1.015129130e-02f, -8.139197710e-03f, 3.500379250e-02f, -1.121483280e-02f, 3.903298830e-02f, 1.229296620e-02f, 1.079158670e-02f, 5.699149330e-03f, 1.688568670e-02f, -1.422488780e-02f, -8.167804220e-03f, 1.328872700e-02f, -2.504203700e-03f, -3.933598640e-04f, 2.255667370e-02f, 1.298811190e-02f, 2.905788370e-03f, 1.519434710e-02f, 9.487630790e-03f, 4.837578540e-02f, 3.109723520e-02f, 1.633296350e-02f, 1.823028180e-02f, 2.699607240e-02f, 3.450510650e-02f, 1.060758070e-02f, -1.890258490e-02f, 1.674909140e-02f, 3.007870170e-02f, 2.823258380e-02f, -1.396326810e-02f, 4.696104300e-02f, 3.454765680e-02f, 6.525725130e-03f, 5.302669480e-02f, 1.516790590e-02f, 3.303539010e-02f, -1.339510460e-02f, -1.595572940e-02f, 3.113001400e-02f, 1.897935990e-03f, -3.823975100e-03f, 2.661163360e-02f, 3.244121370e-02f, 4.583125560e-02f, 7.825367150e-03f, 2.174805850e-02f, 3.149321300e-02f, 1.859955120e-02f, 2.044686860e-02f, 3.528435530e-02f, -9.444409980e-03f, 2.935946360e-02f, 5.218354520e-03f, 2.515848540e-02f, 5.328215190e-04f, 1.085798540e-02f, 2.786881850e-02f, 2.095788340e-02f, 1.392590630e-02f, 1.439443440e-03f, 2.627241050e-02f, -7.847921920e-03f, -4.183221610e-03f, 2.985757400e-02f, 6.343750280e-03f, -2.902826060e-03f, 9.420045650e-03f, 1.665895800e-02f, 4.508580270e-02f, -7.200937720e-03f, 2.453495190e-02f, 3.016286160e-02f, 9.769898840e-03f, 8.778356950e-03f, 2.735810910e-02f, 2.092994560e-02f, -2.113651110e-02f, 2.891874310e-02f, -1.396877040e-02f, 1.669975180e-02f, 1.831600440e-02f, 2.209577900e-02f, -6.781396460e-03f, 1.661255960e-02f, 1.675118690e-02f, -1.195743490e-02f, 1.101375840e-02f, 1.328359360e-02f, 1.438338870e-02f, 2.328374420e-02f, -2.032486260e-03f, 2.755870860e-02f, 3.886152990e-03f, -2.899809740e-02f, 8.324519730e-03f, 3.811503950e-02f, 1.666677740e-02f, 1.860004480e-02f, 3.532889110e-02f, 2.317137080e-02f, -2.122517490e-02f, -7.045160980e-03f, -1.773681860e-02f, 1.241702590e-02f, -1.003243030e-02f, 1.949613100e-03f, 5.527682600e-03f, 2.530860530e-02f, 3.799550240e-02f, -2.934270540e-03f, -6.171799730e-03f, 1.077780690e-02f, 1.631256010e-02f, -1.635650870e-03f, 8.342543610e-03f, 1.124805770e-03f, 1.015423800e-02f, -1.994355210e-02f, 2.793006970e-02f, 1.511131880e-02f, 1.397457810e-02f, 1.120216210e-02f, 1.918466580e-02f, 1.911788990e-02f, 1.229444610e-02f, 3.210233150e-02f, -6.466762160e-03f, 3.029857020e-02f, 1.695885510e-02f, 2.764615420e-02f, 2.626057710e-02f, 2.365085300e-02f, 1.038301740e-02f, 8.569729510e-03f, 1.361711140e-02f, 3.847600660e-03f, 4.502552380e-02f, -2.644417340e-03f, -4.164579790e-03f, -1.639203350e-02f, -2.643663900e-03f, -1.604979110e-02f, 1.049533110e-02f, -1.674403900e-03f, -3.704856210e-04f, 1.231864090e-02f, 1.818274500e-03f, 1.546602420e-02f, 1.659659300e-02f, 5.060109870e-02f, 3.324707220e-02f, 3.617616000e-02f, 5.033509810e-03f, -9.412440470e-03f, 1.279217840e-02f, -5.010043270e-03f, 2.086253460e-02f, -2.909188720e-02f, 3.312270340e-02f, 5.005796910e-03f, 2.302660230e-02f, 6.329651460e-03f, 2.299679260e-02f, 7.243204400e-03f, -4.787094430e-03f, 1.083707440e-02f, 2.222592010e-02f, 1.279435960e-02f, 1.088499280e-02f, 1.336632300e-02f, 1.195893340e-02f, 3.524109350e-02f, 8.896663780e-03f, 1.031479570e-03f, 2.464496530e-02f, 1.287857720e-02f, 1.183974740e-02f, 2.523432110e-02f, 1.475826840e-02f, -5.897608590e-03f, 2.427540720e-02f, -4.171029200e-03f, -6.060697140e-03f, 2.598319200e-02f, 3.262945640e-02f, 1.118722280e-02f, 5.057343840e-02f, 2.147904970e-02f, 4.262618720e-02f, 7.000679620e-03f, -8.306748230e-03f, 2.053893920e-02f, -1.049100420e-02f, -3.466915800e-03f, 3.312145550e-02f, 9.243528360e-03f, 1.780811140e-02f, 9.387961590e-03f, 1.722848230e-02f, -2.416244150e-02f, 2.096149700e-02f, 1.035794990e-02f, 5.268592390e-03f, -2.587779980e-02f, 2.446847410e-02f, 1.865675490e-02f, 2.183078790e-02f, 1.621840340e-02f, 1.432075350e-02f, 7.307097310e-03f, -2.134507060e-03f, -4.144125150e-03f, 1.142631470e-02f, 3.197512780e-02f, 5.384142980e-03f, 2.706545640e-03f, 1.279748860e-03f, 1.975896770e-02f, 1.541033620e-03f, 1.469021760e-02f, 1.564332280e-02f, -2.821086910e-02f, 4.354160650e-02f, 7.468436380e-03f, 7.587991650e-03f, -3.915978600e-03f, -1.133512890e-02f, -2.298082230e-03f, -2.791287750e-02f, 3.859146090e-04f, 2.743397840e-03f, 4.723972080e-02f, 1.619140430e-02f, 2.265427730e-03f, 5.427320490e-03f, 1.459392160e-02f, 3.848742320e-02f, 8.983099830e-03f, -3.874757330e-03f, 1.892685520e-02f, 4.652705510e-03f, -6.418052130e-03f, 2.912642620e-02f, 1.307482950e-03f, 8.831864220e-03f, 2.570625210e-02f, 2.519351990e-02f, 1.115406960e-02f, 4.492787640e-02f, 3.019822990e-03f, 1.919404600e-02f, -3.347266470e-02f, 2.203175800e-02f, -5.996137860e-03f, 3.995625670e-02f, -1.773150820e-02f, 6.276867820e-03f, -5.921115630e-03f, 1.705373260e-02f, 3.057373690e-02f, 3.171941270e-02f, 2.297640960e-02f, -2.157797290e-02f, -2.045328730e-02f, 2.734989860e-02f, 1.667060140e-02f, 2.887007550e-03f, -1.530122480e-02f, 2.279018800e-02f, 2.021321470e-02f, 3.732513260e-02f, 6.841534740e-03f, 1.384005140e-02f, 5.510154370e-02f, -4.361494440e-03f, 2.304360270e-02f, -1.734377120e-03f, 1.714349910e-02f, 3.204204140e-02f, 1.286555640e-02f, 1.307547000e-02f, -3.666756440e-03f, 4.485256970e-03f, 2.495321820e-02f, 1.204089730e-02f, -1.284497040e-02f, 3.704852240e-02f, 2.108158360e-02f, 3.231329470e-02f, 1.825817860e-02f, 2.853642400e-02f, 5.694336720e-03f, -8.437365290e-03f, 2.265323510e-02f, 6.804438300e-04f, 2.581838980e-03f, 1.211222170e-02f, 2.502851930e-02f, 1.471227590e-02f, 2.870860140e-02f, 1.803674360e-02f, 1.040590550e-02f, 1.637792960e-02f, 3.088664450e-02f, 1.273233260e-02f, 2.053139360e-02f, 1.160728930e-02f, 2.133902350e-02f, -3.043392670e-02f, 6.679442710e-03f, 5.832887720e-03f, 8.257883600e-03f, 2.964914220e-02f, 1.380479430e-02f, -3.834237340e-03f, 1.095086990e-02f, 1.623739860e-02f, 3.352370490e-02f, 1.343835610e-02f, 5.246165670e-03f, 1.291068460e-02f, 3.867654130e-02f, 1.749496160e-02f, 3.151659670e-02f, 2.444997060e-02f, -2.434968390e-02f, 1.699929710e-03f, -2.693897810e-03f, 3.920878100e-02f, 2.367179280e-02f, 4.957127850e-03f, -7.628879510e-03f, 6.753021390e-03f, 1.842666420e-02f, -5.505492910e-03f, 2.342373690e-02f, 1.145393120e-02f, 1.752341350e-02f, 1.119832040e-02f, 3.604396430e-02f, 2.673686480e-02f, 1.527856850e-02f, 1.878004990e-03f, -1.631516030e-03f, 2.972973510e-03f, 6.730943920e-03f, -2.002364020e-02f, -1.920941290e-03f, 1.112200880e-02f, -2.758095970e-02f, 4.462417590e-02f, 2.401204780e-02f, 6.662477270e-03f, 2.027686870e-02f, 4.176014660e-02f, 2.111947910e-02f, -2.879450470e-02f, -1.824213750e-02f, 1.147010550e-02f, 4.061120380e-02f, 2.761039320e-02f, 1.442543600e-02f, 2.624255050e-02f, 3.377833590e-02f, 2.346377070e-02f, 6.859541400e-03f, 2.401640270e-02f, 8.689304440e-02f, 1.337096680e-03f, 2.930553630e-02f, 1.992687400e-02f, -5.914282050e-03f, 2.032401790e-02f, 2.441260590e-02f, 6.296225820e-03f, 3.997495030e-02f, 1.107639630e-02f, -3.726322200e-03f, 2.815041690e-02f, 2.576638360e-04f, 2.840415390e-02f, 2.025461010e-02f, 1.933809720e-03f, 4.719207440e-02f, 1.245560590e-02f, 4.437009250e-02f, -1.091410410e-02f, -5.206149070e-03f, 4.007093980e-02f, -1.876708870e-02f, 1.245384100e-02f, 2.271283230e-02f, 4.959969780e-03f, -1.940544880e-02f, -3.164449710e-03f, 2.333096970e-02f, 1.034313070e-02f, 4.286049870e-03f, 6.386713590e-03f, 2.654992980e-02f, 5.942321380e-03f, -3.295478880e-03f, 4.027927290e-03f, 2.457691170e-02f, 1.783871650e-02f, 3.260882570e-02f, 2.071538200e-02f, 7.361588530e-03f, -1.625008140e-02f, 2.450166740e-03f, -9.020154360e-03f, -1.471220520e-02f, -1.764718070e-02f, -1.494752990e-02f, -1.594841670e-02f, 1.034659220e-03f, 4.195111340e-03f, 1.578103560e-02f, -1.682868600e-02f, 1.788954250e-02f, 3.344160970e-03f, -1.540247820e-02f, -1.567939110e-02f, -6.556129080e-03f, -1.407855750e-02f, 7.571490480e-03f, 1.481774080e-02f, 4.308560120e-02f, 1.001235100e-02f, 4.690306630e-02f, -3.902984040e-02f, 3.143975050e-03f, 3.103181720e-02f, 2.671683020e-02f, -1.334316800e-03f, -2.291298290e-02f, 9.362153710e-03f, -4.126868210e-03f, -8.671454150e-03f, -3.994671630e-03f, -1.121572410e-02f, -2.654088100e-02f, 1.486438610e-02f, -1.254900850e-04f, 8.747988380e-03f, -3.038206370e-03f, 1.516100210e-02f, 2.325281130e-02f, -3.323047610e-02f, 1.883601210e-02f, 3.088799680e-02f, 4.362170030e-02f, 1.084334220e-02f, 1.517605560e-04f, 1.871737650e-02f, -1.441378800e-02f, 2.411401640e-02f, 2.412460000e-02f, 9.912450790e-03f, 2.009249480e-02f, 2.018366380e-02f, 8.006632330e-03f, 3.647639600e-02f, 1.217834000e-02f, 1.157241970e-02f, 3.420200200e-02f, 1.148973590e-02f, 2.045999840e-02f, 1.933543380e-02f, 6.999371690e-04f, 2.337029950e-02f, 1.922440900e-02f, -1.602902450e-02f, -1.959616690e-02f, 2.304125580e-03f, 2.747296730e-02f, 2.670541170e-03f, -2.353642690e-02f, 3.846783940e-02f, 2.893912610e-03f, -3.820549930e-03f, 1.050676410e-02f, 4.862014950e-02f, 1.008198220e-02f, -2.492134270e-02f, 1.442333450e-03f, 5.297547670e-03f, 1.417554170e-02f, 2.480616790e-02f, 1.987936910e-02f, 3.020357710e-02f, 4.421415180e-02f, 1.037520920e-02f, 7.123057260e-03f, 5.029470780e-04f, 2.016722040e-02f, -1.658731700e-02f, 2.583374640e-02f, 1.966628990e-02f, -8.365026680e-03f, 5.866166200e-03f, 2.855749430e-02f, -1.868979450e-02f, 1.411940060e-02f, 2.529644030e-02f, -6.046534980e-03f, 4.565843190e-02f, 1.656305040e-02f, 1.059802160e-02f, 2.385853790e-02f, 9.934138500e-03f, 1.268005460e-03f, 1.850826480e-02f, 3.305862100e-02f, 1.191173210e-02f, 4.651275280e-02f, 4.435421900e-02f, 1.429905460e-02f, 2.333824340e-02f, 1.328285220e-02f, 4.536699880e-02f, -1.620377790e-02f, 1.474874930e-02f, -1.929229680e-02f, 1.593093020e-02f, -1.102818060e-03f, 4.718855400e-02f, 5.115398210e-03f, 3.305296970e-02f, 6.607780700e-03f, 3.865962480e-02f, 4.337989540e-02f, -5.108099900e-03f, 2.412914480e-02f, 4.683491960e-02f, 2.047863980e-02f, 3.957565410e-03f, 3.575007990e-02f, 7.219795600e-03f, 1.579596470e-02f, 4.656953740e-03f, -3.424036880e-02f, 5.679008740e-02f, 3.825192150e-02f, 3.645066920e-02f, 2.819094430e-02f, -1.339143960e-03f, 4.974136500e-02f, -2.266974000e-02f, 1.715793090e-02f, 1.714238710e-02f, 1.212321220e-02f, 4.134836790e-02f, 3.016101940e-02f, 4.796256780e-03f, 6.233170620e-02f, 3.218539060e-02f, 2.491084670e-02f, 2.020994760e-02f, 3.233395520e-02f, 5.099476500e-02f, -2.747627210e-03f, 1.047002800e-02f, 1.820466290e-02f, 5.836095660e-02f, 3.829656870e-03f, 2.830656430e-02f, 2.397778440e-02f, 5.606474730e-02f, 1.465211440e-02f, 6.693125520e-02f, 1.241415650e-02f, 4.556364570e-02f, 5.281429740e-03f, 1.165523750e-02f, 6.632936750e-02f, -2.432203390e-03f, 2.196225900e-02f, -2.208290810e-02f, 4.078147560e-02f, 6.696600470e-03f, -1.784387860e-03f, -2.688894050e-02f, 1.308711620e-02f, 4.795524850e-02f, 2.283097620e-02f, 2.170022580e-02f, 4.242792260e-03f, 9.797045960e-03f, 1.364022680e-02f, 1.084567700e-02f, 2.418667080e-02f, 2.459006940e-02f, 2.021567150e-02f, 3.823129930e-03f, 1.194813750e-02f, 7.800355090e-03f, 2.489551720e-02f, 6.124284580e-03f, 6.245688070e-03f, -1.120508830e-02f, 1.219875920e-02f, 1.711026020e-02f, 1.315461380e-02f, 1.447841530e-02f, -9.736392640e-03f, 2.817792630e-02f, 4.441978880e-03f, -1.694568990e-02f, 1.568092030e-02f, -6.949568160e-03f, 1.646817290e-02f, -1.835309900e-02f, -1.279585160e-02f, 4.567711150e-03f, 2.065129210e-02f, -2.315198070e-04f, 3.220016600e-03f, 5.558966190e-03f, 2.297197100e-02f, 2.696894670e-02f, 1.361857540e-02f, 3.431293000e-02f, 3.138541060e-02f, 1.197805630e-02f, 1.864026300e-02f, 2.185552750e-02f, -1.405773100e-03f, -6.679185200e-03f, 5.592298110e-04f, 1.400421280e-02f, 3.047483230e-02f, 1.298133100e-02f, 7.552432360e-03f, 2.274380440e-02f, 2.406375480e-03f, 2.866400780e-02f, 1.894954780e-02f, 8.138323200e-03f, 1.633347760e-02f, 1.197963770e-02f, 6.151597020e-03f, -1.850758120e-02f, 4.555580770e-02f, 1.560207080e-02f, 3.860081310e-03f, 6.483594890e-03f, 5.895309150e-03f, 3.562064840e-02f, -2.173194430e-03f, 2.813532020e-02f, -1.195716670e-02f, 1.215090980e-02f, 2.190883270e-02f, -1.750205640e-02f, 3.521748260e-02f, -2.341397340e-03f, 3.954880870e-03f, 8.754867590e-04f, 1.674184020e-02f, 8.134325960e-03f, 1.577259230e-02f, -3.486963690e-03f, 2.134653550e-02f, 3.942688930e-03f, 1.013007390e-02f, 2.029722370e-02f, 2.621206450e-03f, -1.172062750e-02f, -2.076216790e-02f, -1.188512240e-02f, 9.975482700e-03f, 9.765319520e-03f, -2.214477630e-03f, 1.851969030e-02f, 3.819209060e-03f, -1.483711690e-02f, -1.046831720e-02f, 5.888218530e-03f, 8.924419990e-03f, 3.310255470e-03f, -4.778201230e-03f, 3.714592200e-03f, 2.755072710e-02f, -1.346257240e-02f, 1.155455780e-02f, 1.541292850e-02f, 1.198256210e-04f, 1.616938040e-02f, 1.401287690e-02f, -6.685941480e-04f, 1.594664900e-02f, 3.097639610e-02f, 6.457541600e-03f, 1.546247680e-02f, 9.803517720e-03f, 1.604861390e-02f, 2.795738910e-02f, 2.580462210e-02f, 4.406318070e-03f, 1.976353860e-02f, 1.125959680e-04f, -5.899780810e-05f, 8.776118970e-03f, 3.519698230e-02f, 1.210405770e-02f, -4.261609170e-03f, 1.934116120e-03f, 4.407256100e-02f, 8.393743080e-03f, -1.479162560e-02f, -1.456838940e-02f, 3.794946150e-02f, 9.827890430e-03f, -1.025119210e-03f, -2.769678090e-02f, -1.220604170e-03f, -7.548568530e-04f, 2.614359740e-02f, 1.848006250e-02f, 1.440382940e-02f, 2.054954880e-02f, -5.530111490e-03f, 2.517269550e-02f, -6.296671460e-03f, 6.454098970e-03f, 3.268641230e-02f, 3.860252350e-02f, 1.183421260e-02f, -8.579199200e-03f, 3.285676990e-02f, 1.584329640e-02f, -1.914809090e-02f, -3.122683990e-02f, 1.778970100e-02f, 1.157819010e-02f, 3.158823770e-02f, -4.779952580e-03f, 1.997477370e-02f, 4.593280610e-03f, -9.583615700e-03f, 1.754694990e-02f, 2.319613290e-02f, 1.977537760e-03f, 2.862270690e-03f, 2.022772790e-03f, 4.233725830e-03f, 3.039170800e-02f, 4.036165770e-02f, 1.917788390e-02f, 1.213548380e-04f, 1.073791270e-02f, 1.101478470e-02f, 2.060884420e-02f, 1.649796960e-02f, -1.261951290e-03f, 3.110092510e-02f, 4.986130820e-02f, 2.171172200e-02f, -9.757541120e-03f, 2.545653280e-02f, 1.943456750e-02f, 8.211394770e-03f, 1.115066930e-02f, 2.804818560e-02f, 1.557776150e-02f, -7.156054020e-03f, 1.274518760e-02f, 1.059093610e-02f, 1.723583040e-02f, 5.932449550e-02f, 1.522496900e-02f, 1.038479990e-02f, -2.002149350e-03f, 1.208043660e-02f, -1.920294580e-02f, 2.470866960e-02f, -2.276184040e-03f, 1.944576390e-02f, 1.730880700e-02f, -1.270751590e-03f, 4.882438110e-02f, 3.841460120e-02f, 4.121373970e-02f, -2.226785010e-02f, 3.048035690e-02f, 1.437696630e-02f, 3.185777370e-02f, 3.412958980e-02f, 6.553557240e-03f, 2.340535820e-02f, 3.060177530e-02f, 3.600459600e-04f, 3.825115790e-02f, 1.063442420e-02f, 2.308652920e-02f, 9.317785730e-04f, 2.678081160e-03f, 3.939898310e-02f, 2.095766740e-02f, 1.894387600e-02f, 1.497821230e-02f, 1.010371740e-02f, 3.433477880e-02f, -2.941886150e-02f, 2.358512390e-02f, 1.450769140e-02f, 2.199329990e-02f, 1.428802590e-02f, 2.886296440e-02f, 1.131382680e-02f, 4.848897080e-02f, 8.392399170e-03f, 1.998485250e-02f, 3.332892810e-02f, 4.301356900e-02f, 3.141601380e-02f, 2.166084950e-02f, 8.462300520e-03f, 3.273405510e-02f, 4.934861510e-02f, 2.236288600e-02f, 1.468991210e-02f, 3.015835210e-02f, 3.343461450e-02f, 1.600866390e-02f, 3.536886720e-02f, 4.501137880e-03f, 4.255069050e-02f, 1.083309760e-02f, 7.485021370e-03f, 3.019860710e-03f, 1.611302420e-02f, 2.585829980e-02f, 2.293056990e-02f, 7.181366520e-05f, 2.628331070e-02f, 1.086029810e-03f, -1.266150360e-02f, 1.893589830e-02f, 1.426002010e-02f, -1.149296110e-02f, 2.564818410e-02f, -3.288019680e-03f, 7.053491660e-03f, 8.168214000e-03f, 1.976018960e-02f, 6.667524110e-03f, -5.823907910e-03f, -1.364348830e-02f, 1.223308030e-02f, -1.482215150e-02f, 3.451608490e-02f, -2.019265670e-02f, -3.004262690e-03f, 6.957407110e-03f, 1.232614090e-02f, -2.217859260e-03f, 5.941695530e-03f, 2.563843040e-03f, -2.656885050e-02f, 1.378853220e-03f, -1.910503210e-02f, 1.970499570e-02f, 3.059417380e-02f, -3.925913940e-03f, 1.440899820e-02f, -2.257651650e-03f, -1.593620520e-03f, 2.265177850e-02f, 1.176560480e-02f, -7.536369380e-03f, 1.505132580e-02f, 1.006728600e-02f, 3.878332210e-03f, 1.081725400e-02f, 5.790049680e-03f, 9.597330350e-03f, 9.135069320e-03f, -1.906687390e-02f, 1.487217840e-02f, -1.826848650e-02f, -4.046046360e-02f, 8.629225190e-03f, 5.904736930e-03f, -1.998801950e-03f, -9.598553180e-03f, -1.944557580e-02f, -2.874112320e-02f, -3.681893460e-03f, -8.733307940e-03f, -5.813069640e-03f, 2.641483680e-03f, 2.648819050e-02f, 1.168013270e-02f, 5.897898230e-03f, -2.482338340e-03f, 5.635815210e-03f, 2.410728860e-02f, 3.015437540e-02f, 1.023900040e-02f, -3.255128100e-04f, -1.854488630e-02f, -1.003938260e-02f, 1.186285730e-02f, 8.075838900e-03f, -5.039311010e-03f, -2.069627400e-03f, -4.601432010e-03f, 2.076732180e-02f, -3.506081550e-02f, -3.960900650e-04f, -6.572214180e-04f, -1.018718260e-02f, 3.360511500e-03f, 1.011222040e-02f, -8.052926510e-03f, -1.357443440e-02f, 3.989265770e-03f, 2.659041990e-02f, 1.594436730e-02f, -3.616700880e-03f, -2.960511480e-03f, 2.492800540e-02f, 5.377629770e-03f, 4.590637980e-03f, 2.597023730e-02f, -9.575937870e-04f, 5.966892930e-03f, 1.130380950e-02f, 1.679207940e-02f, 3.283138200e-02f, -3.512241690e-02f, -2.996860070e-02f, 3.604456320e-03f, -1.617724820e-02f, -2.758310740e-02f, 2.785244030e-02f, 4.144087810e-02f, 2.898345890e-02f, 3.660086540e-02f, 1.532351320e-02f, 1.152887570e-02f, 6.203382280e-03f, 2.060074920e-02f, 1.200166440e-02f, -4.998497200e-03f, 1.901701470e-02f, 5.510050800e-03f, 2.104227430e-02f, 1.563438030e-02f, 9.245335120e-03f, 2.766889150e-02f, 2.260263450e-02f, 8.509602390e-03f, -2.967577890e-03f, 2.268845130e-04f, -8.899550880e-03f, -1.549681370e-02f, 3.598684450e-02f, 5.490462300e-03f, 3.485391380e-03f, 2.175538060e-02f, 9.331930420e-03f, 1.118924560e-02f, -3.086361480e-02f, 2.835747230e-02f, 1.761071380e-03f, -9.869001800e-03f, 8.824090470e-03f, 3.209218380e-02f, -3.039875630e-02f, -1.002815460e-02f, -4.692992950e-04f, 2.863167600e-02f, -1.400680560e-02f, -3.343327340e-02f, 4.021157700e-02f, 1.757886630e-02f, 6.439635060e-03f, 1.285527600e-03f, -2.111456590e-03f, 1.753320730e-02f, 4.142370820e-02f, 1.257685760e-02f, 1.087145880e-02f, -1.096634850e-02f, 1.261412450e-02f, -2.489117350e-02f, -2.389337120e-02f, 4.225929080e-02f, 2.496614350e-03f, 2.452186500e-02f, 3.028390700e-03f, -3.854176030e-04f, 2.277650500e-02f, -2.839665860e-02f, 7.258810100e-03f, 4.680864510e-03f, 1.880778370e-02f, -1.072415520e-02f, 2.202858030e-02f, 1.671260600e-02f, 3.039014290e-03f, 2.109045540e-02f, 1.918814150e-02f, -2.209319270e-03f, 4.066240410e-02f, 1.505242660e-02f, 1.190873240e-02f, 9.924266480e-04f, -6.309977730e-03f, 1.306729300e-02f, 1.372931620e-02f, 5.656310820e-04f, 1.061835700e-02f, 4.511151840e-02f, -6.602911740e-03f, 1.915299100e-03f, 1.976855800e-03f, 1.381288000e-02f, -2.030366100e-02f, -3.205047550e-02f, -1.589189100e-02f, 1.799961200e-03f, -2.381365280e-03f, 3.194511870e-03f, 4.674702510e-02f, 1.656834970e-02f, 1.085757180e-02f, -7.488384140e-04f, 1.298324300e-02f, 8.076150900e-03f, -1.662139410e-02f, -6.942419560e-04f, -3.514472020e-02f, -6.841091670e-04f, 8.582692590e-03f, 4.796318710e-02f, 2.384370380e-02f, 8.324689230e-03f, 4.228869080e-02f, -1.960576980e-03f, 9.302432650e-03f, 1.054478250e-02f, 1.383838060e-02f, 1.065815150e-02f, 4.324023800e-02f, -1.164682440e-03f, 2.505081890e-02f, 5.942140710e-03f, -2.432893960e-02f, 8.456927720e-03f, 1.079148520e-02f, 5.951458120e-03f, 1.443294440e-02f, 2.292351800e-03f, 1.507497300e-02f, -1.036611200e-02f, 2.547500100e-02f, 1.205294110e-02f, 2.445172150e-02f, -2.415995490e-02f, 1.955587790e-02f, -7.447291170e-03f, 1.350242920e-02f, 5.015010760e-02f, -8.481128140e-03f, 1.302331310e-02f, 4.668844860e-03f, 3.754985710e-02f, 2.488995720e-02f, 2.888309960e-02f, 2.912954430e-02f, 1.589999350e-02f, 2.067099880e-02f, 2.047563340e-02f, 2.615959570e-02f, 4.301590840e-02f, 1.180774900e-02f, 1.442495360e-02f, 4.444773870e-02f, 2.043999360e-02f, -9.501679800e-03f, 4.836072770e-02f, -2.243297920e-02f, 8.120290000e-03f, -7.502798460e-03f, 1.387861090e-02f, 3.562051800e-02f, 2.681327610e-02f, 1.082448290e-02f, 4.111624320e-03f, -3.047837880e-03f, 8.958039100e-04f, 1.014206470e-02f, 3.653449940e-02f, -4.340378570e-03f, 3.550760820e-02f, -2.764793670e-02f, -1.179573500e-02f, 2.037124710e-03f, 3.228677200e-03f, -1.867098360e-02f, 2.081258970e-02f, 3.448712830e-02f, 3.093954640e-03f, 2.601224180e-02f, 1.504388640e-02f, 2.646971680e-02f, 1.883271710e-02f, 6.037206390e-03f, -1.955085670e-03f, 4.021194950e-02f, 7.041201460e-03f, 5.365641550e-04f, -1.535332760e-02f, -4.747990520e-02f, 2.807166430e-02f, 5.404843830e-04f, 1.015370530e-02f, 1.165025630e-03f, 9.953037830e-03f, 2.867673710e-02f, -2.485003320e-02f, 1.245136470e-02f, 3.002632220e-02f, -3.091109680e-04f, 1.472057310e-02f, 5.724925080e-03f, 2.354594510e-02f, 1.403570180e-02f, 2.719231140e-02f, 2.234572920e-02f, 2.845069630e-03f, 4.635246840e-02f, 3.976542880e-02f, 1.100678280e-02f, 4.599566010e-02f, 2.159183470e-02f, 3.110095670e-02f, -2.194785980e-03f, 2.427703140e-02f, 1.173475850e-02f, 2.072474360e-02f, 1.174735090e-02f, 1.120368580e-02f, -5.860584790e-03f, 2.073783800e-02f, 4.315129290e-02f, -1.707608810e-02f, -2.273276480e-04f, 2.370040300e-02f, 3.266330440e-02f, -7.720756340e-03f, 2.007399130e-02f, 9.198984130e-03f, 9.423504580e-03f, 1.474819150e-02f, 1.102428050e-02f, 1.642648320e-02f, 1.167103530e-03f, 1.139357410e-02f, -2.245792370e-02f, 1.610381530e-02f, 2.713444080e-02f, 1.678898000e-02f, 1.248849000e-02f, 1.654877510e-02f, 3.338299320e-02f, 1.686949280e-02f, 6.204458420e-03f, -1.477800190e-03f, -1.074911100e-03f, 1.369115900e-02f, -2.712153080e-02f, 2.977965770e-02f, 3.753998130e-02f, 3.057981280e-02f, -8.142917420e-03f, -1.182618640e-02f, -2.325253750e-02f, 2.012213130e-02f, -7.924841710e-03f, 1.959726590e-02f, 2.716575520e-03f, 2.580963260e-02f, -1.069700620e-02f, -1.336361470e-02f, 2.707216890e-02f, 1.505350600e-02f, 6.829645020e-03f, 6.640281530e-03f, 1.092218790e-02f, 2.381673460e-02f, 1.738280990e-02f, 3.148122500e-02f, 2.152863890e-03f, 1.700988230e-02f, 1.445540690e-02f, 2.789991350e-02f, 1.234588770e-02f, -1.467833300e-02f, 2.616101880e-02f, 1.472123340e-02f, 2.348791250e-02f, -9.799159130e-03f, 2.306124940e-02f, 1.047620320e-03f, 1.037383170e-02f, 3.244187680e-02f, 8.331273680e-03f, 2.587136440e-02f, 2.765855290e-03f, -6.948688990e-03f, -1.228206330e-03f, 2.620646540e-02f, 1.395519640e-02f, 1.602094250e-02f, 5.692575500e-02f, 2.489089590e-02f, -1.119205380e-03f, 1.861693800e-03f, 2.655715680e-02f, -2.030993580e-03f, 1.716593470e-02f, 2.783531880e-02f, 3.281320680e-03f, 1.732723790e-02f, 5.897326860e-03f, 1.821196060e-03f, 3.004156290e-03f, 2.449624610e-02f, 1.722827180e-02f, 1.332904580e-02f, 2.148107810e-02f, 2.223643850e-02f, 3.470262510e-02f, 2.232259700e-02f, -1.814433000e-02f, 1.103390470e-02f, 5.198201630e-03f, 2.080142500e-02f, -1.390971710e-02f, 2.804038490e-02f, -2.307345160e-02f, 3.327628600e-02f, 3.489802410e-02f, 1.400108450e-02f, 2.919633500e-02f, 2.391652760e-02f, 4.460862280e-02f, -2.157139590e-02f, -1.628081500e-02f, 3.739699020e-04f, 2.286327770e-03f, 2.894040940e-02f, 1.319788300e-02f, -1.436192910e-02f, 2.692853850e-02f, 2.631627580e-02f, 1.799538920e-02f, -2.218296750e-02f, 1.283253360e-02f, 2.375816550e-02f, -1.855750200e-02f, 4.639995750e-03f, -2.015882360e-02f, -8.989752270e-03f, 3.112210150e-02f, 3.525394710e-04f, 2.683497970e-03f, 5.689533800e-02f, 7.938338440e-03f, 1.062498520e-02f, -1.139346510e-02f, 9.223495610e-03f, 9.725045410e-03f, 2.448564950e-02f, 7.356940770e-03f, -5.879465960e-03f, -6.516689900e-03f, 1.408051230e-02f, 1.546883680e-02f, -6.735122880e-04f, 1.241660680e-02f, -4.949557480e-04f, 4.361385110e-02f, 4.619328680e-02f, -3.803812430e-03f, 1.005401570e-04f, 8.428147990e-03f, 2.421988360e-02f, -2.070898940e-02f, 8.846214970e-03f, 7.193026600e-03f, -1.428467590e-02f, 2.517234160e-02f, -3.782582470e-03f, 4.163908210e-02f, 1.438878940e-03f, 3.962165210e-03f, 2.471417750e-02f, 1.657899470e-02f, -1.527328980e-02f, 1.263066100e-02f, -2.692640990e-03f, 1.629661580e-02f, -3.954956190e-04f, -2.268983980e-02f, 1.614939050e-02f, 2.776791340e-02f, 4.747661200e-02f, 1.160582250e-02f, 1.593860980e-02f, 2.286555620e-02f, -5.408887570e-02f, 1.999196410e-02f, 1.998926140e-02f, -9.269034480e-03f, 2.683751660e-02f, -1.599211430e-02f, 2.631773430e-02f, 6.688089670e-02f, 2.050636520e-02f, 1.729963720e-02f, -2.441217380e-02f, 3.435762970e-02f, 2.976338380e-02f, 3.307462480e-02f, 1.317405330e-02f, 3.563561290e-02f, 1.225536600e-02f, 1.082118510e-02f, 1.810290040e-03f, 3.229322280e-02f, 2.111603320e-02f, 2.937970870e-02f, 5.757072940e-02f, 4.512054850e-02f, 4.246397320e-02f, 2.500738580e-02f, 2.619322020e-02f, 2.775585090e-02f, 3.994293510e-03f, 3.617294130e-02f, 1.953112890e-02f, 7.195877380e-03f, 3.978870440e-02f, 4.328170330e-03f, 1.562920770e-02f, 1.365696080e-02f, 9.700288990e-03f, 4.539247600e-03f, 4.634646700e-02f, -1.530166810e-02f, 2.216494080e-02f, 6.737684830e-03f, 1.408111680e-02f, 1.702998950e-02f, 1.295844840e-02f, 5.044365300e-02f, -9.015786460e-03f, 4.645821450e-02f, 6.746076510e-03f, 1.101872420e-03f, 3.339160230e-02f, 1.938793810e-02f, 3.689908890e-03f, -4.414556550e-03f, -1.609248340e-03f, 2.066746590e-03f, 1.673835890e-02f, -6.950573060e-03f, 4.893952980e-03f, 2.732767350e-02f, 3.340540450e-02f, -1.410007100e-02f, 6.554599390e-03f, 3.261422370e-02f, -2.259415020e-02f, -1.443945150e-02f, 3.999743610e-03f, 4.245908930e-03f, -2.728522940e-02f, 8.451011030e-03f, 3.446195650e-02f, 1.693424210e-02f, 5.001720410e-02f, 1.412084420e-02f, 1.405985280e-02f, 1.260344220e-02f, 2.075690960e-02f, -1.691811160e-02f, -1.445988750e-02f, 1.534296290e-02f, 1.667324270e-02f, 1.872721500e-02f, 7.237574080e-03f, -4.864272780e-04f, 1.507858560e-02f, 2.214432320e-02f, 5.292223300e-03f, 1.829081960e-02f, 2.971376110e-02f, -1.090663760e-02f, 7.050198500e-03f, 6.790419570e-03f, 3.033728340e-02f, 8.688344380e-04f, 3.802605900e-03f, 2.170024440e-02f, 6.554657220e-02f, -1.761328240e-02f, 8.638274860e-03f, 3.565610150e-03f, 1.473803540e-02f, 3.668243810e-02f, 8.045334360e-03f, -2.573151510e-02f, 3.801821540e-02f, 2.451805960e-02f, 2.306800710e-02f, 5.434414840e-03f, -5.902369970e-03f, 6.170215090e-03f, -2.462081800e-02f, 1.070187520e-02f, 2.076311220e-02f, 1.111488790e-02f, 1.084371560e-02f, 1.217479630e-02f, 3.349445390e-02f, -4.262612670e-03f, -3.854198150e-03f, 9.364159200e-04f, 2.318696680e-02f, -2.417166340e-02f, 1.236332490e-02f, 2.459295790e-03f, 1.501456460e-02f, 6.419455630e-03f, 3.210139000e-03f, 7.712217510e-03f, -2.899344080e-03f, 1.001280640e-02f, 4.548367580e-03f, 1.463846960e-02f, -7.271260490e-03f, 3.923104140e-03f, -1.191408000e-02f, 5.358418820e-02f, 1.833365490e-02f, 1.706476700e-02f, -1.502240360e-02f, 1.843288310e-03f, 1.799520660e-02f, 1.047899480e-03f, 4.297203200e-02f, -1.240981560e-02f, 1.267425620e-02f, 1.324028610e-02f, -2.246734690e-02f, 2.454428000e-02f, 2.883759510e-02f, 1.008516990e-03f, 7.702211380e-03f, 9.704556310e-03f, 1.292675450e-02f, -1.177964880e-04f, 5.220390390e-03f, 3.125179560e-02f, -1.454897600e-02f, 1.074306390e-02f, 1.368466210e-02f, 3.338503840e-02f, 4.639736840e-03f, 1.999982260e-02f, 2.960318140e-02f, -2.208960940e-03f, 2.751388960e-02f, 2.021708150e-02f, 8.616309610e-03f, 3.320795660e-04f, -1.616654170e-02f, -1.562220510e-02f, 2.707978520e-02f, 4.514390600e-03f, 2.595944890e-02f, 5.500433500e-03f, 1.419591340e-02f, 4.567422350e-02f, 1.859161070e-02f, -1.648940890e-02f, 4.225878790e-02f, -9.601899420e-03f, -2.176820300e-03f, 2.341852900e-02f, 4.382896240e-03f, 1.261894220e-02f, 7.893532510e-03f, -2.348628640e-02f, 1.132623010e-02f, 4.641470310e-02f, 4.206073660e-02f, 1.532228100e-02f, 2.858744190e-02f, 8.871037510e-03f, -2.539539710e-02f, -1.667308430e-02f, 1.890398560e-02f, 6.188752130e-03f, -1.242907620e-02f, -1.435064620e-02f, 2.542950770e-02f, 5.389845740e-02f, 5.124087450e-03f, 6.673012390e-03f, -1.158072500e-03f, 2.032368630e-02f, 3.634605560e-02f, 9.353616270e-03f, -6.405521180e-03f, 3.299230710e-03f, 2.800191750e-03f, 2.578130180e-02f, 1.114450400e-02f, -8.456810380e-03f, 2.860128880e-02f, -1.213651380e-03f, 1.988022590e-02f, 1.901679790e-03f, 4.391781610e-02f, -2.059525620e-02f, 1.008084790e-02f, 1.390647800e-02f, -1.652992560e-03f, 1.759491670e-02f, 1.868502800e-02f, 3.018717650e-02f, 1.295947750e-02f, 2.366018020e-03f, 2.614980330e-03f, 2.296213620e-02f, 1.419545430e-02f, 3.565016390e-02f, -2.545492490e-03f, -5.941774700e-03f, 3.472676970e-03f, 2.449423630e-02f, 2.056322060e-02f, 2.944680120e-02f, 2.031580170e-02f, 2.233724850e-02f, -4.220944360e-03f, 4.915600640e-02f, 4.772364160e-03f, 2.315949650e-02f, 1.828246560e-02f, 1.733969150e-02f, 1.669169400e-02f, -2.461804640e-02f, -6.280295550e-03f, 5.697815680e-03f, -6.434023380e-03f, -2.835066240e-02f, 3.172849490e-02f, 3.318131720e-02f, 1.554577980e-02f, 5.270653400e-03f, -1.298390050e-02f, -1.047519220e-02f, -1.787675730e-02f, 7.636019490e-03f, 5.058758430e-03f, 9.200387630e-03f, -3.011737020e-02f, 2.177362700e-02f, 4.318859430e-02f, 3.913237530e-02f, -6.851935290e-03f, -3.185933830e-02f, -1.014967540e-02f, 1.047993270e-02f, -1.520847320e-03f, 1.567131840e-03f, 1.977236760e-02f, 1.106204470e-02f, 1.644726470e-02f, -6.638458460e-03f, 3.456143660e-03f, 9.632738070e-04f, 3.324563800e-02f, 3.749110040e-03f, 3.422939400e-02f, 3.952111680e-02f, 5.555082490e-02f, 2.510679330e-02f, 3.789145870e-02f, 1.144707480e-02f, 2.340705690e-02f, 1.540827840e-02f, 3.452664240e-02f, 1.920556090e-02f, 1.245117930e-02f, 4.093051890e-03f, 4.430682210e-02f, 1.167920420e-02f, 1.731611970e-02f, 1.143742820e-03f, 2.536764550e-02f, -4.549285400e-03f, 8.492818100e-03f, 2.304982020e-02f, 1.239748390e-02f, 7.746817080e-03f, -3.849067490e-03f, 3.160735960e-02f, 3.549862420e-03f, 2.388596530e-02f, 1.217072550e-02f, 2.505060100e-02f, 2.876743860e-02f, 3.973297770e-02f, 1.706454720e-02f, 1.131515480e-02f, 3.301149980e-02f, -6.220043170e-03f, 1.620551110e-03f, 1.025158820e-02f, 3.186739980e-02f, -1.617082390e-02f, 1.058479860e-02f, -2.931633410e-02f, 2.201365310e-02f, 6.410755680e-03f, -1.358456070e-02f, -1.697807010e-02f, 4.528626800e-02f, -1.235206050e-02f, 2.625992710e-02f, -7.960065270e-03f, -1.308403440e-02f, 4.349483920e-02f, -1.640540550e-02f, 1.225524400e-02f, 2.318706740e-02f, 2.678369540e-02f, 4.125222940e-02f, 2.362594940e-03f, 3.966683520e-03f, 2.847177540e-02f, 3.287185450e-03f, 1.023512890e-02f, -7.773669200e-04f, 2.786919290e-02f, 2.209742090e-03f, 2.407520450e-02f, 2.035293360e-02f, 3.156986090e-02f, 2.964854240e-02f, -4.846847620e-03f, 1.060200580e-02f, -1.861537060e-02f, -5.449169320e-03f, 5.958497900e-02f, 2.070384850e-02f, 2.580839580e-02f, 1.168858630e-02f, -1.317897630e-02f, -1.437686620e-03f, 3.804935610e-03f, -2.415301650e-02f, -2.207720650e-03f, 5.907714830e-03f, -2.264124530e-02f, 4.348478750e-03f, 1.744064500e-02f, 5.825203660e-02f, -1.551254470e-02f, 1.063524190e-02f, 1.805742460e-02f, 2.878630720e-02f, 2.588708890e-02f, 6.643086670e-03f, -7.127576510e-03f, 1.626263930e-02f, -2.186750250e-02f, 1.482722070e-02f, -2.544783520e-03f, 1.395176070e-02f, 1.642657260e-02f, -8.286151100e-03f, -2.407859270e-02f, -5.659162070e-03f, 2.206989380e-02f, -1.118874920e-02f, 1.741862670e-02f, 2.721575090e-02f, 9.813563890e-03f, -2.501876790e-03f, 1.067997890e-02f, 2.591688190e-03f, 1.420871260e-02f, 5.140886180e-03f, 1.290927080e-02f, 1.842096630e-02f, 8.633829650e-03f, 1.701135000e-02f, 9.110838170e-03f, -5.383658220e-03f, 3.745546800e-03f, 2.279610560e-02f, 1.943298990e-02f, 2.266354490e-02f, -2.742944100e-02f, 2.864522300e-02f, 2.098271440e-02f, 8.502398850e-04f, 6.952849220e-03f, 1.552488380e-02f, 9.687967250e-04f, 2.454362440e-02f, 1.462217890e-03f, -4.772869400e-03f, 2.349812910e-02f, 2.998224830e-02f, 2.446907010e-02f, 2.723184970e-02f, 2.538149430e-02f, 1.624639890e-02f, 3.751154620e-02f, 4.515195270e-02f, 3.700830280e-03f, 8.798020890e-03f, -1.349749320e-02f, 3.421644490e-02f, 8.420512080e-03f, 2.940097260e-02f, -5.453408510e-02f, 6.562814810e-04f, 9.556122120e-03f, 3.104454090e-02f, -2.216891010e-02f, 3.494446350e-02f, 2.518916130e-02f, 1.434114110e-02f, 1.754025740e-02f, 2.934496660e-02f, 4.437018560e-02f, 1.117826250e-02f, 1.730339420e-02f, -1.254691040e-03f, 3.470887990e-02f, -5.437260030e-03f, 2.576383950e-02f, 5.482327190e-03f, -1.168324890e-02f, 1.300924640e-02f, 6.626616420e-02f, 2.171543800e-02f, 1.326060200e-02f, 4.383637380e-02f, 3.865180160e-02f, -4.212100800e-02f, 1.089941430e-02f, 1.690268700e-02f, -1.087731590e-02f, 1.556843800e-02f, 2.155247890e-02f, 3.794980790e-02f, 5.902991820e-02f, 7.405779790e-03f, 2.859224190e-02f, 3.510214390e-02f, 2.199601380e-02f, 3.169992940e-02f, -2.470648610e-04f, 1.412893460e-02f, 2.482463050e-02f, 1.711272630e-02f, -3.077633450e-03f, 1.316527000e-02f, 7.299864660e-03f, 4.791275040e-02f, 1.072636340e-02f, 5.516284330e-02f, 2.683033790e-02f, 3.589516040e-03f, 3.377283360e-02f, 3.696654690e-03f, 2.819641680e-02f, -1.127287840e-02f, 2.402448280e-02f, -1.205648200e-02f, -1.379340700e-02f, 3.766153750e-02f, -8.342882610e-03f, -3.148783000e-02f, 3.761431900e-03f, 9.995896360e-03f, 1.535141000e-02f, 1.728867180e-02f, -2.494852060e-02f, 2.385195720e-02f, -7.703939450e-03f, -1.845196080e-02f, -5.036445330e-03f, -7.331108210e-03f, 2.679445970e-02f, 1.958098640e-02f, 8.331217800e-03f, -3.106221790e-03f, -5.163436290e-04f, 1.304272100e-03f, 2.598175220e-02f, -1.106502950e-02f, 5.368922840e-03f, 2.680312100e-02f, -1.178492330e-02f, -2.021718400e-02f, -1.673700850e-02f, 2.781568560e-03f, 1.998952960e-02f, 2.579555470e-02f, -6.283141210e-03f, -2.141902970e-02f, -1.884598660e-02f, -1.932161670e-02f, -1.372427400e-02f, 3.884382170e-02f, 2.101615260e-02f, 2.677585740e-02f, -1.754392500e-02f, -8.483331650e-03f, -1.141597420e-02f, 1.818588000e-02f, 2.714615690e-02f, 1.714059150e-02f, -2.139867660e-02f, 9.853987020e-03f, 1.856717400e-03f, 3.439395460e-03f, 1.152252310e-02f, 4.215550420e-02f, 3.245252000e-02f, -9.056258020e-03f, 2.579023130e-02f, -6.201841400e-03f, 1.269409340e-02f, 3.744655990e-03f, 3.798144310e-02f, 2.083237280e-02f, 4.884168970e-03f, 4.637967800e-02f, -1.317518760e-05f, 1.933685690e-02f, 6.487996320e-03f, -4.102087410e-04f, 1.972130310e-02f, 1.634222270e-02f, -5.272480660e-03f, 5.450714850e-03f, 2.471195070e-03f, -3.380586630e-03f, 5.140744150e-03f, 1.398426290e-02f, -1.585191120e-02f, -1.626453920e-02f, 1.417300850e-02f, 1.926173460e-02f, -3.152557180e-03f, 2.200010230e-02f, 2.933452280e-02f, -1.261717830e-02f, 2.927979270e-02f, -2.571916020e-02f, 2.476503510e-02f, 1.582584160e-02f, 5.350761580e-03f, 1.211800520e-02f, 1.823514890e-02f, 4.501406480e-02f, 3.108350560e-02f, 9.492116040e-03f, -2.029243860e-02f, 1.665088350e-02f, 4.873056710e-02f, 1.292399600e-02f, 6.119450550e-03f, 2.211730000e-02f, 2.293798890e-02f, -1.497552540e-02f, -1.679790670e-03f, 1.135180050e-02f, 1.072440020e-02f, 1.906545460e-02f, -1.553886570e-02f, 2.650987730e-02f, 5.749008060e-02f, -1.414656830e-02f, -7.734084970e-03f, 1.776721330e-02f, 2.183245870e-02f, 3.649978710e-02f, -4.991310180e-03f, 6.610703650e-03f, 2.301759460e-02f, 3.423631560e-02f, 9.534901940e-03f, -1.364007960e-02f, 1.598809850e-03f, 4.714894670e-02f, -7.014560980e-03f, 2.936879730e-02f, 8.219093080e-03f, 3.182591500e-02f, 5.130516830e-03f, -2.576941620e-02f, 1.651808430e-02f, -2.057094870e-02f, 7.071159200e-04f, 1.438869910e-02f, 1.694156970e-02f, 8.286248890e-03f, 2.137437090e-02f, 5.878877830e-03f, -2.076153830e-02f, 4.719868300e-02f, 4.008784890e-03f, -1.355636750e-03f, -1.005362160e-02f, -3.208698010e-03f, 8.299607780e-03f, -2.028032440e-03f, 2.036353950e-02f, 2.257190270e-02f, 2.991805230e-02f, 1.465577450e-02f, 2.599508870e-02f, -5.762610120e-03f, 2.568851230e-02f, 4.038352520e-03f, 1.576597060e-02f, 6.835542150e-03f, 2.840834300e-02f, -2.355185710e-02f, 3.911944480e-02f, 3.973898660e-02f, -9.286333810e-03f, 9.353172970e-03f, 1.523950230e-02f, 2.487025040e-02f, 1.338619270e-02f, 3.007972610e-02f, 5.181442950e-03f, -1.030159180e-02f, -2.488292750e-02f, 1.984112710e-02f, 8.559479380e-03f, 4.736148750e-03f, 1.948233320e-02f, 2.787836830e-03f, 3.956921770e-02f, 1.681251270e-02f, 2.010782480e-04f, 1.478260760e-02f, 1.605415530e-02f, -1.529083870e-02f, 1.992656660e-02f, -8.276290260e-03f, 7.938064630e-03f, 1.597861010e-02f, -1.627546880e-04f, -2.444775030e-02f, 3.493238240e-03f, 2.261861040e-02f, 5.988459570e-03f, 3.412906450e-02f, 8.996148590e-03f, 3.114793820e-02f, -4.902453630e-03f, -1.255266550e-02f, -1.504700720e-02f, -1.333130150e-02f, 1.792375560e-02f, 1.458544980e-03f, 1.965145390e-02f, -3.895280880e-03f, -3.789629790e-02f, 5.889554690e-02f, -1.455518140e-02f, 4.554030950e-03f, 2.581854720e-02f, 1.471850560e-02f, -1.103791130e-02f, 7.312686180e-03f, 1.319851350e-02f, 2.310669980e-03f, -8.255293590e-03f, -9.315423670e-03f, 1.596851270e-02f, 1.215423360e-02f, -1.943608190e-02f, 1.423762830e-02f, 4.089557380e-02f, 3.099351560e-02f, 4.836523440e-03f, -1.902476140e-02f, 6.180543450e-03f, -2.850113440e-03f, -1.980418150e-02f, 6.327657610e-04f, -6.586693230e-03f, 1.153818700e-02f, -1.585234890e-02f, -3.373886690e-03f, -3.887145080e-03f, 1.329030560e-02f, -4.373110710e-04f, -4.907033590e-02f, -1.672469820e-02f, -3.395342270e-03f, 1.092022280e-02f, 1.017347160e-02f, 1.209059260e-02f, 3.689773380e-02f, 3.167850520e-02f, 3.682086620e-02f, 2.841602640e-02f, 3.108882900e-02f, 1.511547160e-02f, 1.146384790e-02f, 4.064001550e-04f, -1.770717280e-02f, 6.119751370e-03f, -1.017234750e-02f, 2.265522260e-02f, 3.211062870e-04f, 8.938942100e-03f, 2.102346720e-02f, -1.195988430e-02f, 4.677351560e-02f, -8.940766570e-03f, 5.805717660e-04f, -1.033630220e-02f, 8.732338440e-03f, -1.171281650e-02f, 6.751778540e-03f, 1.352431810e-02f, 5.820667370e-03f, 1.122582700e-02f, 1.226798540e-02f, 2.348435110e-02f, 5.319133400e-03f, 1.130622350e-02f, 5.850895870e-02f, 8.804768320e-03f, 8.899696170e-03f, -1.659850590e-02f, 2.374088210e-02f, 1.357517210e-02f, 6.889784240e-03f, -2.051457020e-02f, 1.823996380e-02f, 1.760572010e-02f, 3.245417960e-03f, 4.172018170e-02f, -1.029647610e-02f, -4.997778450e-04f, 3.915715220e-02f, -1.656489630e-02f, 4.089826720e-03f, 1.037385040e-02f, 3.014181180e-02f, 1.424635020e-02f, 4.959813780e-03f, -2.047829520e-02f, -2.533080620e-02f, 1.345871480e-02f, -3.107167040e-02f, 8.395080450e-03f, 1.388387290e-02f, -1.886697110e-02f, -3.271906820e-02f, 1.907485720e-02f, -1.069903470e-02f, 1.278286990e-02f, 4.225407910e-02f, 1.127231310e-02f, 5.516340210e-02f, 2.703278140e-02f, 3.004284950e-02f, 1.394354370e-02f, -1.504896950e-02f, 5.534194410e-03f, 2.730651940e-02f, 3.050083850e-02f, 3.230155630e-02f, 2.867319430e-02f, 1.693855780e-02f, 2.631418410e-03f, -1.622735580e-04f, 1.055604960e-02f, -1.555829590e-02f, 3.878788320e-03f, 6.473338230e-03f, -1.397584940e-02f, 1.250352520e-02f, 1.228668630e-02f, 2.408533360e-02f, 8.195833300e-03f, 3.547426690e-02f, -2.536091770e-02f, 3.571095320e-02f, 1.186100210e-02f, -1.662911100e-02f, 5.592968080e-04f, -5.931392080e-04f, -2.418027960e-03f, 1.001817410e-03f, 3.133311400e-03f, 2.389749700e-02f, -1.707911680e-02f, -1.914154180e-02f, 2.104787710e-02f, 1.248086060e-02f, 1.046048380e-02f, 6.087888030e-03f, 2.709625290e-02f, 9.348785500e-03f, 2.166002620e-02f, 6.569676100e-03f, 1.749615740e-02f, 2.617324520e-02f, 3.109639980e-03f, 2.337932210e-02f, 2.606726250e-02f, -4.859507550e-03f, -2.080826830e-02f, 3.505796190e-04f, -1.712596420e-02f, 1.273616680e-02f, 5.595927590e-03f, 1.648755740e-02f, -1.655383780e-02f, -9.814835150e-03f, 2.145511840e-02f, -2.986394800e-02f, -1.201678530e-02f, 2.984502540e-02f, 1.918603110e-02f, -4.008850830e-02f, -2.859770790e-03f, 3.497894390e-03f, 1.197486180e-02f, 4.725308160e-03f, 1.510311660e-02f, 2.052472530e-02f, -5.117469930e-03f, 3.769041230e-02f, -2.237784680e-02f, -1.982321960e-02f, 3.481560570e-02f, 8.860874920e-03f, 9.410504250e-03f, -1.916377620e-02f, 4.273334150e-02f, 3.675021230e-02f, 1.392835190e-02f, 1.780551110e-02f, 8.787565860e-03f, 3.170273270e-03f, 3.582343830e-02f, 1.617957470e-02f, -1.823276470e-02f, -1.350943460e-02f, 7.777744440e-03f}; + +Kokkos::View __constant_64x72xf32; +float __constant_64x72xf32_initial[4608] = {5.781094730e-02f, 4.935115200e-02f, 8.499316870e-02f, -8.263972590e-03f, 1.770389270e-02f, 6.071018430e-02f, -5.518861860e-02f, 1.085310430e-01f, -4.146582630e-02f, 3.088587150e-02f, 3.812598440e-02f, -1.134396640e-01f, -9.663131830e-02f, 4.149495070e-02f, -8.642079680e-02f, 5.543451310e-01f, 1.862976140e-02f, -6.819485130e-02f, -7.279354150e-03f, -1.337921920e-01f, -5.554735660e-02f, -4.247188200e-02f, -1.480979320e-01f, 5.762558800e-02f, 5.506433550e-02f, -1.619768890e-02f, 3.448970620e-02f, -3.606370460e-02f, -4.607510190e-02f, 3.303149720e-02f, -5.085655950e-03f, 6.441904600e-02f, -6.551083640e-03f, -1.137541230e-01f, -3.454202790e-02f, -3.295184300e-02f, 1.229759960e-02f, 1.144955900e-01f, 3.014008330e-02f, -7.500582930e-02f, -2.490851280e-02f, 1.605476810e-02f, -5.386788030e-02f, -4.070151220e-02f, -4.635258390e-02f, 4.281386730e-02f, -1.107395290e-01f, -5.504985530e-02f, -9.544389690e-02f, 5.853418630e-02f, 3.484980390e-02f, -1.131031290e-01f, -3.335909170e-02f, 1.738892310e-02f, 5.767320100e-02f, 1.615143420e-01f, 2.504877750e-01f, 5.867379160e-02f, -7.637906820e-02f, 9.349997340e-02f, -5.108544980e-02f, -7.676743720e-02f, 1.007329670e-01f, 3.380625690e-02f, -1.444433330e-01f, 2.524190950e-02f, 5.484279250e-03f, 1.097069010e-01f, -5.430553850e-02f, -3.062913750e-02f, -1.884465110e-02f, -9.672553090e-02f, -1.060907690e-01f, -1.215335500e-01f, -7.725791540e-03f, -4.437761750e-02f, 8.981975910e-02f, 7.237649990e-03f, -9.383539860e-02f, 2.005659790e-02f, 3.692376610e-02f, 6.932634120e-02f, -3.954331580e-02f, -1.428241880e-01f, 1.635693160e-01f, 1.584878410e-01f, 1.628655710e-03f, 1.074899290e-01f, -1.229950410e-01f, -8.446572720e-02f, 2.517116370e-01f, 1.665793360e-02f, 5.379302800e-02f, -1.193538960e-02f, -6.894258410e-02f, 1.850969340e-02f, -4.226731510e-02f, -8.562082050e-02f, 1.264052700e-03f, 7.787364720e-02f, -4.212909940e-02f, -5.404848980e-02f, 3.474507630e-01f, -3.557521850e-02f, 6.402732340e-03f, -1.945453140e-02f, 1.203305050e-01f, -5.807174000e-02f, -3.098326740e-02f, -1.146634970e-01f, -9.957738960e-02f, -3.226041050e-02f, -4.322212930e-02f, 7.048766310e-02f, 1.485823000e-02f, 9.526229460e-03f, -1.028490720e-02f, -6.355122480e-02f, 4.909243430e-02f, 3.580004350e-02f, -1.322379620e-02f, -4.874143380e-02f, -7.058687510e-02f, 3.497864010e-01f, -5.272289740e-02f, 1.067308630e-01f, -7.241685690e-02f, 1.529850510e-01f, -7.466784110e-02f, 9.528071620e-03f, -1.225452130e-01f, -7.967231420e-02f, -5.619138940e-03f, -1.763061060e-02f, 8.476983750e-02f, -9.503556790e-02f, 7.741651680e-02f, -4.053918640e-02f, -5.048031730e-02f, -1.442922950e-01f, 2.627690880e-02f, -6.006879360e-02f, -3.566326570e-02f, -1.259102860e-02f, 1.242315470e-01f, -1.328812390e-01f, -1.154486840e-02f, -4.089378940e-02f, -2.717543770e-02f, 2.401486230e-02f, -1.136017520e-01f, 1.187398360e-01f, -9.145965420e-02f, -5.263776700e-02f, 2.516274530e-02f, -3.507919980e-02f, -2.959633800e-02f, 1.116303910e-02f, -6.163322550e-02f, 2.477720570e-02f, 3.772122790e-02f, 1.915745250e-02f, -9.272616350e-02f, -1.214454770e-01f, -6.602621820e-02f, -1.239292320e-01f, 5.417129400e-02f, -6.593252720e-02f, -1.015224310e-01f, 1.659163650e-02f, -9.672124680e-02f, 1.986875200e-03f, -5.569262430e-02f, 7.745120670e-03f, 6.336789580e-02f, -5.398660150e-02f, -5.305521190e-03f, 1.905639770e-01f, -4.006338310e-03f, -2.463241850e-02f, -5.217723920e-02f, -7.043312490e-02f, 1.476229910e-02f, 3.560372810e-02f, -3.437586500e-02f, 1.043970510e-01f, 1.299043150e-01f, -4.302508760e-02f, 9.721442310e-02f, 9.188732500e-02f, 7.378124450e-02f, -5.761216950e-02f, 4.576123510e-02f, 3.802184760e-02f, 1.672187260e-02f, -1.114251460e-02f, -7.998390500e-02f, -1.459842030e-01f, -3.131528940e-02f, 1.267102360e-01f, -9.794531010e-02f, -5.755418540e-02f, 9.510891510e-03f, 6.494610010e-02f, -1.479228590e-01f, 4.801399410e-01f, -5.549813430e-02f, -2.987748940e-02f, -5.545845260e-02f, 6.193732090e-02f, 2.498846950e-01f, -2.727172150e-02f, -7.247794420e-03f, 9.603212590e-03f, -6.864502280e-02f, -7.015500220e-02f, -8.604511610e-02f, 1.426718660e-02f, -1.598141340e-01f, 1.234287170e-01f, 6.125715370e-02f, 9.800137020e-03f, -3.329015900e-02f, -4.409419000e-02f, -4.010828580e-02f, 4.432844740e-02f, 2.254440260e-02f, 1.352252660e-01f, 1.154038980e-01f, -2.355778960e-02f, 6.137369570e-02f, 6.571890320e-03f, -1.154942360e-01f, -8.414144060e-02f, -7.156821340e-02f, 6.911403690e-02f, -9.650254240e-02f, 2.047601900e-02f, 3.997444360e-02f, -5.085450410e-02f, -5.682153630e-02f, -2.387606170e-02f, 1.474820670e-01f, 3.095932120e-02f, -1.232562140e-01f, -3.685933770e-03f, -2.835099770e-02f, 1.665007700e-02f, -2.241232430e-03f, 4.876466470e-02f, 2.344664630e-01f, -5.228942260e-02f, 5.388651420e-02f, -3.134670900e-03f, 3.700648620e-02f, -2.476232690e-02f, 5.611143630e-02f, 1.555629970e-01f, -2.186847850e-02f, -5.442596600e-02f, 6.528371570e-02f, -1.738262550e-02f, -4.163658990e-02f, -3.564018380e-02f, -5.095436700e-03f, 5.410040020e-01f, -6.336227050e-02f, -6.195802240e-03f, 5.808152260e-02f, 7.806885060e-03f, 6.062822420e-02f, -7.709388430e-02f, 1.683672220e-01f, -5.662656950e-02f, 8.453969660e-02f, -8.937856180e-05f, 3.579386700e-02f, -2.217235600e-02f, 8.570520200e-03f, -1.211080180e-01f, 1.481146370e-01f, -9.026020020e-02f, 9.723599250e-02f, 6.910934300e-02f, -6.374039500e-02f, 3.154755010e-02f, -2.763498760e-02f, 3.024778520e-02f, -9.980169680e-02f, 1.233900490e-01f, 2.185803280e-02f, -5.092132840e-02f, 9.592282020e-02f, -1.175256970e-01f, 9.979801620e-02f, 6.259961430e-02f, -5.106930430e-02f, -9.924094190e-03f, 1.296878460e-01f, 1.168672070e-01f, -2.379800430e-03f, 1.306303890e-01f, -1.245902480e-02f, -3.579068930e-02f, -6.963007900e-02f, -2.760472710e-02f, -4.715325680e-02f, 1.924278290e-01f, 2.747623480e-03f, -9.943816810e-03f, -4.352365060e-02f, 8.794388170e-02f, 2.821053560e-01f, -8.871550860e-02f, 9.254598990e-03f, 6.752224270e-02f, 7.224965840e-02f, -3.583131730e-02f, 5.483198910e-02f, 4.205123710e-02f, -2.739343610e-02f, 5.879119040e-02f, 3.499935570e-02f, -4.724836910e-03f, 1.296381350e-01f, 1.612801850e-02f, 2.299307290e-01f, -4.610791430e-02f, -6.191365420e-02f, -1.126574280e-01f, 8.620403710e-02f, 7.228480650e-03f, 2.530112270e-01f, -1.699207720e-02f, 2.859137950e-01f, -1.554155500e-01f, -6.565543360e-03f, 2.103395950e-02f, 3.209181500e-02f, -1.095471460e-01f, -9.001318360e-02f, -6.400489060e-02f, -8.516179390e-03f, 2.150624390e-01f, 6.673169880e-02f, -8.074401320e-02f, -1.030605660e-01f, -8.169214430e-02f, 7.339805360e-02f, 5.981096630e-02f, -1.078650800e-01f, -3.452700380e-02f, -6.816175580e-02f, -5.800519140e-03f, -1.749003830e-01f, 3.091475550e-02f, 6.985430420e-02f, 1.105668020e-01f, -1.134795100e-01f, 7.565473020e-02f, -9.197682140e-02f, -8.776345100e-02f, -3.522940730e-02f, 8.015196030e-02f, 1.796929390e-01f, 8.963286880e-03f, -2.940546160e-02f, 1.067178250e-01f, -1.517361380e-03f, -1.316895800e-02f, 1.097395940e-01f, -1.041604430e-01f, -2.524446320e-02f, -1.028048770e-01f, -5.833053960e-02f, 2.090379780e-02f, 1.666754630e-01f, -1.300100830e-01f, -9.452729670e-02f, 4.594251510e-02f, 5.474905670e-02f, -5.719710890e-02f, -1.603341290e-02f, 8.021046220e-02f, 1.845951940e-02f, -1.386578980e-01f, 4.514357080e-02f, 7.083849610e-02f, -3.453908490e-02f, -1.971295850e-02f, 1.239823330e-01f, 2.879299570e-04f, -1.875384150e-02f, 1.517808440e-01f, -5.146435650e-02f, 9.867535900e-03f, 4.434882100e-02f, -2.719499360e-02f, 1.135411040e-01f, 2.591639380e-02f, 4.313407240e-01f, -3.654588010e-02f, 6.593327970e-02f, -3.703543170e-02f, -1.016067560e-01f, -1.057556360e-02f, 3.038532100e-02f, -1.217985530e-01f, 3.715572660e-01f, -1.052308530e-01f, -1.558417360e-02f, 1.805960950e-02f, 8.040696380e-02f, -4.063148980e-03f, 4.054826130e-02f, -3.529753160e-02f, -5.319359900e-02f, 1.378520670e-02f, -1.625572330e-02f, 3.327678890e-02f, 1.513615250e-01f, -4.616148770e-02f, -4.988709460e-03f, -2.112629820e-02f, 4.871810230e-02f, -6.927232440e-02f, 1.719333980e-02f, 2.176321600e-01f, 5.461042370e-02f, -9.643758080e-02f, 1.105111240e-01f, -7.034829250e-02f, -1.108609660e-01f, 1.930205150e-02f, -8.450760690e-02f, 1.559640020e-01f, -6.832940130e-02f, -1.124830620e-01f, 1.836750660e-01f, -1.434021150e-01f, -8.308026930e-02f, 8.715258910e-03f, 9.514103830e-02f, -8.180099540e-03f, 9.060217440e-02f, 2.084279210e-01f, 6.518213450e-02f, 2.052495070e-02f, 1.611641200e-01f, -1.031838660e-01f, 3.746125470e-02f, 9.723884610e-02f, 4.589204860e-02f, -3.601214660e-02f, 2.258625630e-02f, -1.414729360e-01f, -7.367692140e-02f, -5.801399050e-02f, 2.615178380e-02f, 1.158172360e-02f, -8.772476760e-02f, -1.058134210e-01f, -2.852209100e-02f, 5.544921380e-03f, -6.415855140e-03f, -7.487776870e-02f, 1.327872280e-01f, 2.075592990e-02f, -3.007004600e-02f, -6.647086890e-02f, -1.295833290e-01f, 2.123761180e-01f, 2.818409170e-02f, 5.112587290e-02f, -1.149270530e-01f, -9.233036630e-02f, -4.132353510e-02f, -9.557098890e-02f, -4.471002150e-03f, 8.083545600e-03f, -1.321013570e-01f, -1.152481360e-01f, 3.054872450e-01f, -8.269750320e-02f, 1.328468970e-02f, 6.902112810e-02f, -4.769086840e-02f, 5.193125830e-02f, -5.988052860e-02f, -9.128381500e-03f, 9.515264070e-03f, 2.014965120e-01f, 1.217495870e-01f, 9.011869870e-02f, 2.870172450e-02f, 6.002726410e-02f, -1.259371940e-01f, 1.812538130e-02f, 2.390738580e-02f, 1.405073260e-01f, -3.989051650e-02f, 4.133364560e-02f, -5.362010000e-02f, -7.056671380e-02f, -1.976291650e-02f, -2.956794020e-02f, 2.651267350e-01f, -3.204040230e-02f, -3.561371940e-02f, 7.613481580e-02f, -5.611659490e-03f, -6.118629870e-02f, 3.960741310e-02f, -1.709350760e-02f, -5.966440590e-02f, 6.845200810e-02f, -4.218434910e-02f, 2.159314300e-01f, 1.321923430e-01f, -7.757152620e-02f, -1.084649640e-01f, 1.577102390e-01f, 5.384332310e-02f, 2.451035570e-02f, 4.600830140e-04f, 9.685766880e-03f, -1.758943130e-02f, -2.491213570e-02f, -3.372304890e-02f, 9.017547210e-02f, 8.266199380e-03f, -5.137557910e-02f, -6.410060820e-02f, -6.630796470e-03f, -3.327587990e-02f, -4.322326560e-02f, 1.635327000e-02f, -1.473951190e-01f, -3.852726890e-02f, 1.895806010e-02f, 9.543712440e-02f, -3.852732110e-02f, -3.120598380e-02f, 3.693007680e-02f, 4.535813030e-01f, 1.730430280e-01f, 1.430636550e-02f, -4.171694070e-02f, 2.412119140e-02f, -1.092014930e-02f, -1.404798400e-02f, -5.882045250e-02f, -4.554992910e-02f, 8.526653050e-02f, -2.542135680e-02f, -7.793132210e-02f, -4.517228810e-03f, -6.844684480e-02f, -3.481204810e-02f, 9.926399580e-02f, 6.863703580e-02f, 7.213757370e-03f, -3.277720880e-03f, -6.446485970e-02f, -8.154537520e-02f, 7.841968900e-04f, 2.875757400e-02f, 1.725666970e-01f, -3.436819090e-02f, 9.946093890e-03f, 2.162716350e-02f, -9.839853640e-02f, 2.687326370e-01f, 4.902228710e-02f, -1.087705790e-01f, 2.704062870e-02f, 2.080908720e-01f, -4.802721380e-04f, 3.656997530e-02f, -4.552676340e-03f, -5.390457440e-02f, -8.120469000e-02f, 5.894390490e-02f, 3.565227990e-02f, -4.709941890e-02f, -1.629159040e-02f, 3.026556370e-01f, -1.009516420e-02f, -5.353761840e-02f, -4.305893930e-02f, 1.570539030e-01f, -1.168222870e-01f, -3.261781860e-02f, -2.723841180e-02f, 9.070719030e-02f, 2.061399630e-02f, 1.041407290e-01f, -8.315818750e-02f, -3.021485360e-02f, -6.135122850e-02f, 3.227845580e-02f, -4.072849080e-02f, -7.751625030e-02f, -1.826580240e-02f, 1.707723140e-01f, 1.406673250e-02f, 1.108303960e-01f, 7.306659970e-02f, 2.196054440e-03f, 8.496361220e-02f, 5.124466960e-03f, -4.609351230e-02f, 7.058268040e-02f, -1.134019050e-01f, -2.816329710e-02f, 1.033008990e-01f, -4.997805130e-02f, 1.332544980e-01f, 1.562076810e-01f, 1.900525090e-01f, 8.297096930e-02f, 1.245535630e-02f, -6.789098680e-02f, -7.173918930e-02f, 5.477092420e-02f, 1.582537030e-02f, -8.518039430e-02f, -7.668467700e-03f, 2.508275960e-02f, -8.492090550e-02f, 1.697255110e-02f, -1.814441230e-01f, 2.164637740e-01f, 9.038259830e-02f, -6.947272270e-02f, 3.086632190e-01f, -7.520455980e-04f, -8.154993500e-02f, 2.149625420e-01f, 3.541165220e-02f, 1.616577380e-03f, -2.542858010e-02f, -6.860318030e-02f, -8.398889750e-02f, -2.325911630e-02f, -1.168976280e-01f, -1.360240730e-01f, 1.182517930e-01f, -1.591686160e-02f, -1.219021810e-02f, -6.853851670e-02f, -4.147067290e-02f, 2.020031400e-02f, -6.130497900e-02f, -8.368822930e-02f, -5.490602930e-02f, 7.035565100e-03f, 5.036360030e-02f, -1.306603570e-02f, -2.241124590e-02f, 6.928814950e-02f, 1.526167840e-01f, -1.641992480e-02f, -4.359981420e-02f, 3.861319650e-02f, 1.374760360e-02f, -3.489518910e-02f, 4.918257890e-02f, 9.902326010e-02f, 2.574062350e-02f, 7.631693040e-02f, 1.731077210e-02f, -4.533761740e-02f, -9.542575470e-02f, 3.161458760e-03f, 2.613915130e-03f, 2.200028860e-02f, 7.563534370e-01f, 7.192105800e-02f, 1.586485100e-02f, 1.010052300e-02f, 1.582853310e-02f, -2.866744060e-02f, 2.270846440e-02f, -6.273626540e-02f, 2.119719050e-02f, 3.024370410e-03f, 3.864351290e-02f, 1.847852770e-02f, -6.950113920e-02f, 2.769496290e-02f, -3.714185210e-02f, -7.933226970e-02f, -4.887956010e-02f, 1.662122610e-01f, -2.240773100e-02f, -8.747380970e-02f, 4.589269310e-02f, -2.667698540e-03f, -7.291834800e-02f, -3.730388730e-02f, 3.982106970e-02f, -5.479028450e-03f, -2.215582880e-02f, 6.192123510e-02f, 5.640862510e-02f, -8.033555930e-03f, -4.757292200e-02f, 6.910061830e-02f, -3.954883660e-02f, 1.215913970e-01f, -4.694205520e-02f, -5.964762720e-02f, 7.474473680e-03f, 1.524876650e-01f, 4.243372750e-02f, 2.624691650e-02f, 2.205169010e-02f, 5.401874430e-03f, 6.582337620e-02f, -3.405865650e-02f, -2.296728830e-02f, 2.651700560e-02f, 1.687929030e-02f, 1.156187580e-01f, 1.161996370e-02f, 2.273233530e-01f, -4.241421450e-02f, -1.039138900e-02f, -2.041258220e-01f, -1.159099860e-01f, 1.241651620e-01f, 1.154190600e-01f, -3.699016760e-03f, -2.694032900e-02f, 6.510265170e-02f, 1.040223910e-01f, -5.054733160e-02f, -7.203838970e-02f, -3.024621680e-02f, -1.255168770e-02f, 6.397205590e-02f, -2.223626900e-02f, -8.969144520e-02f, 4.406475930e-03f, -5.789409950e-02f, -3.529214110e-02f, -4.357067120e-02f, 2.952861790e-01f, 1.015536260e-01f, 9.204448760e-02f, 5.693966150e-02f, 4.102636500e-02f, 5.237376320e-02f, 3.915512560e-02f, 1.343251910e-01f, 7.935214040e-02f, 1.127070190e-01f, -1.479153340e-01f, -2.803943870e-02f, -1.805285360e-02f, 2.888998690e-01f, -8.406519880e-02f, -1.985750350e-02f, -4.002969710e-02f, 3.124722240e-01f, 9.697189180e-02f, -1.081294040e-01f, -3.120354940e-02f, 6.796497110e-02f, -3.114989490e-03f, 4.920947920e-02f, 1.982126240e-01f, -1.192932650e-01f, -2.251686900e-02f, 8.965386450e-02f, -6.851670890e-02f, -5.186373740e-02f, -4.049694540e-02f, 2.266210740e-03f, -5.526099730e-02f, -4.463488610e-02f, -7.565657790e-02f, 7.350137820e-02f, 1.473797490e-02f, 1.953365650e-02f, -1.025988390e-01f, -7.075457270e-02f, -1.113448590e-01f, -1.216636000e-01f, 1.455817370e-01f, -5.544082080e-02f, -1.115933360e-01f, -5.156180820e-03f, -6.374343480e-02f, 1.442091910e-01f, -4.670216520e-02f, 4.633593930e-02f, -3.481582920e-02f, -1.960568500e-02f, -1.121630890e-01f, -1.037513990e-01f, 8.922485630e-03f, 1.189387440e-01f, 1.935474200e-02f, 6.278622430e-03f, 3.613380720e-02f, 2.344594150e-01f, -5.973803620e-02f, 4.827853740e-01f, -9.397211670e-02f, 2.820675370e-01f, -1.166974900e-01f, -2.032735760e-02f, -8.945067410e-03f, 7.754647730e-02f, 1.138772140e-01f, -3.449131920e-02f, -3.903463860e-02f, -1.969072220e-02f, 1.767949760e-02f, -3.392393890e-02f, 1.345492350e-04f, -2.034588340e-02f, -1.635798810e-02f, 1.121691320e-01f, -1.231110280e-02f, 5.621196330e-02f, -9.559333550e-04f, -5.415141580e-02f, -5.663714560e-02f, 3.023679370e-02f, -3.589401770e-02f, 4.418976600e-03f, 1.336315270e-02f, 1.294253320e-01f, -8.620437230e-02f, -1.085165370e-01f, 3.247716000e-03f, -1.090943660e-01f, 1.479046510e-02f, -4.384478550e-02f, 9.004312570e-03f, 4.046446830e-02f, 5.115861450e-02f, 1.370318420e-02f, 4.140141230e-02f, -1.272052620e-02f, -1.540066900e-01f, 1.620004330e-01f, -2.132702430e-02f, 1.669774760e-02f, -4.079211500e-02f, -6.400382520e-02f, 5.387014150e-02f, -7.786756000e-02f, 1.017193350e-01f, 3.856263680e-02f, 1.324652430e-01f, -1.670364290e-02f, 4.140105470e-02f, -2.142536830e-02f, -1.867555640e-02f, 3.004793260e-02f, -5.716103320e-02f, 3.752822990e-03f, -4.496606440e-02f, 5.156547580e-02f, 1.935022030e-01f, 2.707144620e-01f, -9.570696390e-03f, -9.744400530e-02f, -1.360556930e-01f, 7.496029600e-03f, 3.980406370e-02f, 1.571897420e-01f, -1.471766980e-01f, -1.377816780e-02f, -1.849657860e-02f, -4.450837900e-02f, 2.450133120e-01f, -1.921085060e-04f, -8.064682030e-02f, 2.614878860e-02f, -7.553465660e-02f, 1.796746400e-01f, -6.633048500e-02f, -4.373840990e-02f, -5.953273550e-02f, -7.684490080e-02f, -3.207372130e-02f, -4.699126630e-02f, -1.159673000e-02f, 2.161979300e-02f, 8.215618870e-02f, -1.326144640e-01f, -5.778345750e-03f, -1.180540470e-01f, -4.954264310e-02f, -1.182958780e-01f, -9.754303840e-02f, -1.444105520e-02f, 5.000764880e-02f, 4.888315870e-02f, -6.800931690e-02f, -4.071946810e-02f, 2.493528720e-01f, 3.761301190e-02f, 2.418389920e-01f, -3.773784260e-02f, -1.167772710e-01f, 1.414412110e-01f, 2.655669120e-02f, 2.424403280e-02f, 3.183165390e-04f, -6.393212080e-02f, 1.374122050e-01f, 1.832009260e-01f, -1.311896740e-01f, 1.039757580e-01f, 3.575336930e-02f, -2.829956820e-02f, -1.149071290e-02f, -3.918551280e-02f, -4.182844980e-02f, -2.188049630e-02f, 8.994162820e-02f, 1.346494700e-01f, 4.030942920e-02f, 3.457467630e-02f, -3.030227680e-02f, -4.305296020e-02f, -1.866037490e-03f, -4.498745500e-02f, 2.288358470e-02f, 1.832428390e-02f, -9.789815540e-02f, 6.643480810e-02f, -3.774223100e-02f, 4.850561170e-02f, -1.091940630e-01f, -1.702260040e-02f, -6.309029450e-02f, -3.218658270e-02f, -6.602527570e-03f, -5.732275170e-02f, -8.092243970e-02f, -1.059914080e-01f, -3.205043450e-02f, -5.574323240e-02f, -7.253449410e-02f, 4.946216570e-02f, -6.889322400e-02f, -2.332246680e-02f, 9.121894830e-03f, 8.478104320e-02f, 3.662489350e-01f, 1.367185260e-01f, 2.806113100e-02f, 5.418663100e-02f, -3.188670050e-02f, 1.206254350e-03f, -3.366946430e-02f, -1.787398010e-02f, -3.072343210e-02f, 4.560793190e-02f, -5.371718480e-02f, 1.381633580e-01f, -1.211148690e-02f, -7.375319300e-02f, 3.705967680e-03f, 1.183446270e-01f, 5.231330170e-02f, 1.422444880e-01f, 1.722195190e-02f, 1.241706310e-02f, 4.407310390e-03f, -5.776679140e-02f, 1.428891120e-01f, -6.833934780e-02f, 1.286263170e-01f, -2.714552730e-02f, 5.148415640e-02f, 5.124786500e-02f, -3.374010560e-04f, 3.419391810e-02f, -5.577900260e-02f, 1.990835000e-02f, -6.106063960e-04f, -6.635785100e-02f, -4.393647610e-02f, 1.546933650e-01f, -8.230123660e-02f, -3.434139120e-02f, 7.125075910e-02f, 3.636709150e-01f, -7.186879220e-02f, -3.463311490e-02f, -1.185884480e-01f, 6.464694440e-02f, 3.521678450e-01f, 1.096087920e-01f, 3.049610740e-02f, 2.983502300e-02f, 5.775609980e-02f, 4.527312140e-02f, -1.975738630e-02f, -1.033170000e-01f, -8.505480730e-02f, 4.674784840e-02f, 1.661091480e-02f, -6.939169490e-03f, -6.263629350e-02f, 1.118344810e-02f, 1.415115450e-01f, -7.554613800e-02f, 2.475906760e-01f, -7.592074570e-02f, 6.102741700e-03f, -3.498096760e-02f, -3.747875990e-02f, -1.601071660e-01f, -6.487920880e-02f, -6.064289060e-02f, -5.801138280e-02f, 2.517321330e-02f, -5.137819050e-02f, -7.283926010e-02f, -1.505721060e-01f, -3.375843540e-02f, -8.731150620e-02f, -2.980109120e-02f, 1.124559570e-01f, -7.792775330e-02f, -7.051815840e-02f, 6.327016650e-02f, -1.427939830e-01f, 3.181536910e-03f, 8.568880150e-03f, 2.577473820e-01f, -8.278800170e-03f, 5.609078800e-03f, -5.957539380e-02f, 1.888666000e-01f, -1.088571730e-02f, -7.111237200e-02f, 3.815561160e-02f, 1.280970420e-01f, 5.650685360e-02f, -3.195280210e-02f, -5.015160890e-02f, 1.848020850e-01f, 5.470843520e-03f, 1.429257450e-02f, 1.991105380e-01f, 1.493221670e-01f, 4.839966450e-02f, 5.898481610e-02f, -2.959742440e-03f, 1.240559370e-01f, 1.069135670e-01f, 2.409479470e-01f, -7.346145060e-02f, 4.900105300e-02f, 1.441818180e-01f, -2.885914410e-02f, -2.823016790e-02f, 4.413479940e-02f, 8.475340900e-03f, -1.204846710e-02f, 8.034929050e-04f, 1.093715280e-01f, -8.408932390e-02f, -3.528249640e-02f, 2.621398570e-01f, -1.204962880e-01f, -5.754389240e-02f, 6.491480770e-02f, -4.949834570e-02f, -6.067389620e-02f, -6.707862010e-03f, -6.766736510e-02f, 4.618751630e-02f, 4.605544360e-02f, -1.459044070e-01f, -1.028428600e-01f, -3.072360530e-02f, -7.038962100e-02f, -1.520715800e-01f, -1.158376130e-02f, -6.686393920e-02f, 1.193929240e-01f, 2.452373950e-01f, -5.944232640e-02f, -3.236635030e-02f, -1.181577890e-01f, -3.143083300e-02f, 6.577707830e-02f, -1.408445090e-01f, -8.474904290e-02f, 1.978998780e-01f, 9.020294250e-02f, -5.651040380e-02f, 2.281965910e-01f, 4.401746390e-02f, 1.036998260e-01f, -1.807895860e-02f, -3.938068820e-02f, 6.597454850e-02f, -4.811736570e-02f, 1.500790120e-01f, 5.507712250e-03f, -1.560338770e-02f, -1.015189810e-01f, -1.339311150e-01f, -4.466119040e-02f, 4.762150720e-02f, 8.290901780e-02f, 2.126260470e-02f, -1.205370300e-02f, -5.986297880e-02f, -7.081075760e-02f, 8.184973840e-04f, 3.738331420e-02f, -1.124887470e-01f, -9.688538310e-02f, 2.129725180e-02f, -4.340852610e-03f, 1.973714080e-01f, 1.630531400e-01f, 2.142402080e-01f, 5.664980780e-02f, -2.126061170e-02f, 2.105005640e-02f, 4.606399690e-02f, -1.572368200e-03f, 6.301651900e-02f, -1.179840040e-01f, 9.546981000e-02f, -7.524298130e-02f, -1.194048820e-01f, 5.777765070e-02f, 2.515876590e-01f, 8.539412920e-02f, -1.608937980e-01f, -2.061770760e-03f, -3.056996690e-02f, 7.830478250e-02f, 5.031150300e-03f, -4.945873840e-02f, -1.786863430e-02f, -1.185568420e-01f, -9.061808880e-02f, 3.015747110e-02f, -1.967832260e-02f, -3.805835550e-02f, -5.008788030e-02f, -6.857446390e-03f, 1.997017860e-01f, -5.347886680e-02f, 2.440565380e-01f, -1.603980180e-02f, 9.911262980e-02f, -6.610672920e-02f, -1.438005270e-01f, -5.805247650e-02f, 1.824930500e-02f, 4.801543060e-02f, -4.766209520e-03f, 7.352489980e-02f, 1.113514420e-02f, 2.400384280e-02f, -4.351172600e-02f, 2.066682840e-02f, 1.693874900e-01f, -3.995007650e-02f, -1.396491940e-02f, 1.198324490e-01f, -3.748821470e-02f, -4.700122030e-02f, 3.458370220e-03f, -4.094518720e-02f, 3.673515620e-01f, 8.187717760e-03f, 1.053902410e-02f, -1.178987030e-01f, 6.275676190e-02f, 1.453960870e-02f, -1.200312900e-01f, 2.980871800e-01f, -1.427154390e-01f, -4.076394810e-02f, 3.961033370e-02f, -2.629280460e-02f, -9.201680860e-02f, -1.102988610e-02f, 1.029236840e-01f, -3.995595500e-02f, 6.932558120e-02f, 2.677906490e-02f, 1.207648890e-01f, 6.840972700e-03f, -1.312869140e-02f, -1.216310190e-01f, -4.803790150e-02f, -6.352579590e-02f, -6.765748560e-02f, -6.452164800e-02f, 7.742359480e-02f, 1.700116400e-01f, 1.254923640e-01f, -9.399346260e-02f, 5.099984700e-04f, 1.552377640e-01f, 2.872092840e-02f, -1.498101840e-02f, 1.090834960e-01f, 3.074277560e-02f, -3.562177720e-02f, 1.198605000e-01f, 1.479359340e-02f, -4.862629340e-03f, -3.447850790e-02f, 1.886810210e-01f, 1.584475640e-01f, -1.665009410e-01f, 1.565473710e-02f, -4.293312130e-02f, 1.399410960e-01f, 1.440680180e-01f, 4.689200970e-02f, -8.428509530e-02f, 2.377484890e-01f, -3.753281380e-02f, -1.276314110e-01f, -1.074881850e-02f, -1.358573440e-01f, 7.487703860e-02f, -1.854721750e-01f, -9.294854100e-02f, 1.203424930e-01f, 7.091456650e-02f, -8.349017050e-02f, -1.597573980e-03f, 1.554970000e-01f, -7.648552950e-02f, -1.119289250e-01f, -5.445453800e-03f, 1.943448190e-01f, -6.446082140e-02f, -1.242756400e-01f, -9.239600040e-03f, -3.819647800e-02f, -2.952539920e-02f, -2.699212540e-02f, -3.343294560e-02f, 5.712375040e-03f, -8.601465260e-03f, 5.602849270e-02f, -1.388969120e-01f, -7.268964500e-02f, 2.776387890e-02f, 1.376475240e-01f, 5.347784240e-02f, -9.564936160e-02f, 1.694717260e-01f, -5.476483700e-02f, -5.276177540e-04f, -5.503365770e-02f, -7.116785640e-02f, -6.505759060e-02f, -5.263819170e-02f, -7.387576250e-02f, 1.285127100e-01f, -5.125549160e-03f, 1.180954870e-01f, -1.343257280e-01f, -1.377771420e-02f, 2.589299720e-02f, -1.106866450e-01f, -1.171953530e-01f, 1.763834970e-03f, 1.613174380e-01f, 1.247762440e-01f, -6.865541920e-03f, -1.506022810e-01f, -4.881734770e-02f, -1.561059950e-01f, -1.596940760e-01f, 1.166533380e-01f, -3.328339010e-02f, 9.913408010e-02f, 9.283986680e-02f, 5.126273260e-02f, -4.681928080e-02f, 5.228822680e-02f, -1.005361600e-01f, -1.130869240e-01f, 1.706253890e-01f, -5.436351520e-02f, -1.119594200e-01f, 5.469654500e-02f, -5.057347570e-02f, -2.012277720e-03f, -1.183807180e-01f, 7.551419730e-02f, 1.410030720e-01f, -9.820730430e-03f, -4.465761780e-02f, 6.989433900e-03f, 1.015154640e-01f, 8.846578190e-03f, -1.020510640e-01f, -4.548061270e-02f, -5.917970840e-02f, -1.134726180e-01f, -3.062761760e-02f, 3.718494620e-02f, -4.443953560e-02f, 1.265675430e-01f, -2.600066180e-02f, 1.082198320e-01f, 5.219004680e-02f, -1.265532900e-02f, 5.850119050e-03f, 7.215005900e-02f, -7.335641980e-02f, -1.406003680e-01f, -9.775602950e-04f, -4.120676310e-03f, 3.199439640e-01f, 5.317293480e-02f, -1.300594510e-01f, -1.780973190e-02f, 1.438945980e-01f, 2.569908500e-01f, -7.342535260e-02f, -4.352620990e-02f, -6.596147270e-02f, 8.204909410e-02f, 2.958429230e-02f, 1.417630910e-01f, 1.347552690e-01f, -6.361637260e-02f, 9.828966110e-02f, -6.284357610e-02f, -5.315741900e-02f, 4.502524060e-02f, 8.011239760e-02f, 1.091770830e-02f, 4.108566420e-02f, 5.037595700e-02f, -4.530481620e-02f, 2.216194870e-01f, 2.594962720e-01f, -1.473294570e-02f, -7.872220120e-02f, -9.553189580e-02f, -1.332811120e-01f, 7.015234230e-02f, -4.263123960e-03f, -3.922129520e-03f, -5.193963650e-02f, 4.505182620e-03f, -4.063477370e-02f, -7.051911950e-02f, -6.825836750e-02f, -7.437233630e-02f, 3.566022960e-02f, -7.881176470e-02f, 4.041355570e-03f, 9.696427730e-02f, -1.030679870e-01f, -9.928133330e-02f, -4.375812780e-02f, 1.799363460e-02f, 9.860678010e-02f, 1.647300420e-01f, -1.004817040e-01f, 3.591139610e-02f, 8.127086800e-03f, 1.809177730e-02f, -5.905977260e-02f, 6.297345460e-02f, -1.012841460e-01f, -2.905696440e-02f, -7.218962160e-02f, 1.772524710e-01f, -1.110164900e-01f, 1.597107950e-02f, 9.261190890e-02f, 9.177846460e-02f, 1.587112430e-02f, 6.455777590e-02f, -2.191254870e-02f, -2.700443750e-02f, 8.880228540e-02f, -7.531232670e-03f, 1.741472450e-02f, -1.065196920e-01f, 1.475221380e-02f, -1.015980910e-01f, -1.560646300e-01f, -1.666699950e-01f, -9.788791830e-02f, 9.132720880e-05f, -5.940295760e-02f, -3.154936810e-02f, 9.634251140e-02f, -1.001281290e-01f, 1.057246550e-01f, -2.773802730e-03f, -3.043601520e-03f, 3.467605710e-01f, 9.937905520e-02f, -1.465870290e-01f, -6.101342290e-02f, 1.437018350e-02f, -8.444698150e-02f, 7.119008890e-02f, 3.118631990e-02f, 2.800518870e-01f, 1.995227670e-02f, -1.244819760e-01f, 4.950633650e-02f, -1.008410980e-01f, 1.019641160e-01f, 1.941819340e-01f, 2.373937670e-01f, 1.220200580e-01f, -1.171996910e-02f, 5.590413350e-04f, -2.386112700e-02f, 2.240518290e-02f, -8.994255210e-02f, -8.345112200e-03f, 3.393884750e-02f, -1.490582340e-02f, -3.068864530e-02f, 1.840710080e-02f, 1.022525500e-02f, -4.898889360e-02f, -7.393608240e-02f, -9.836339200e-02f, 7.215207820e-02f, -6.413317470e-02f, -7.217385620e-02f, 2.091783730e-01f, 8.202310650e-02f, 1.203997730e-01f, -1.789426800e-01f, 6.371603910e-02f, -2.118832060e-02f, 2.685349290e-01f, 1.349984560e-01f, -1.484940950e-02f, -5.096653850e-02f, 4.215592520e-02f, -1.086900310e-01f, 1.038344350e-01f, -3.710088510e-02f, 1.255365740e-02f, 2.933944390e-02f, -1.052554850e-01f, -6.367770580e-02f, -1.064084020e-01f, -9.142135820e-02f, 8.118773110e-04f, -8.205943550e-02f, -9.365382790e-02f, 4.630476980e-02f, 3.227998320e-01f, -2.774332650e-02f, -4.734293370e-02f, 8.051245650e-02f, 5.409975720e-02f, -5.704283710e-02f, -7.049904020e-02f, 9.230475130e-02f, -8.967734870e-02f, -5.367319660e-02f, -5.628118290e-02f, 1.178050640e-01f, -8.624257890e-02f, -4.497370500e-02f, 1.164865720e-01f, -3.234094380e-02f, 7.152649020e-02f, 1.002347320e-01f, -7.901442790e-02f, 1.129229140e-01f, -1.312368510e-01f, 7.178086790e-02f, -1.232573460e-01f, -7.362513240e-02f, -1.171024590e-01f, 2.715144490e-02f, 3.729523720e-02f, 1.787410680e-01f, -3.600365670e-02f, -5.638375130e-02f, -1.026989370e-01f, 1.272643950e-01f, 9.927590930e-02f, 1.558810940e-02f, 1.583146300e-02f, -3.296336900e-02f, -4.939818380e-02f, -2.468252930e-02f, 7.034558800e-04f, 1.020743850e-01f, -4.984702540e-02f, 3.451840580e-02f, 5.053377150e-02f, 1.338652820e-01f, 1.502740380e-01f, 5.774612350e-02f, 1.177239270e-01f, -8.650439970e-02f, -9.133181720e-02f, -1.823656260e-02f, -1.673591580e-01f, -2.221976970e-02f, -1.562668530e-01f, 3.178312680e-03f, -2.545187020e-03f, 1.559048190e-03f, 2.357882820e-02f, 1.246094550e-01f, 1.646942270e-02f, -6.616994730e-02f, -7.937133310e-03f, 8.094741400e-02f, 6.674023720e-02f, 3.610405700e-02f, -5.829649980e-03f, 3.940393400e-02f, 9.256848690e-02f, -8.211322130e-02f, -2.805014330e-02f, 4.917660360e-02f, -6.940418480e-02f, -7.286461440e-02f, 2.298744950e-02f, -1.292749310e-02f, -8.243384950e-02f, 2.491993310e-01f, -9.976456310e-02f, 1.269884560e-01f, -1.666169240e-02f, -1.132068040e-01f, -1.296107320e-01f, 4.811083900e-03f, -9.603041220e-03f, 2.282445580e-01f, -2.813910880e-02f, -1.380417050e-01f, 6.775606420e-02f, 2.418506000e-01f, 1.905567350e-01f, 2.347827890e-02f, -7.609315960e-02f, 7.827930150e-02f, -1.078080390e-02f, -1.291474550e-01f, -8.105756340e-02f, 1.732150020e-01f, -1.041004580e-01f, 1.196232290e-01f, 3.243085000e-02f, -1.938693600e-02f, -1.191463540e-01f, 2.352150530e-01f, -1.745002720e-02f, -2.332746800e-02f, -2.608666010e-02f, 5.113207740e-04f, -1.564829050e-02f, 1.009147470e-01f, -1.124864590e-01f, -8.481084550e-02f, -6.504635510e-02f, -8.155360070e-02f, 7.604726120e-03f, 9.194551410e-02f, 4.563169930e-02f, -6.646796320e-02f, 5.288485440e-02f, 1.566612120e-01f, -1.143874970e-01f, -9.576943510e-02f, -1.092460600e-01f, 4.048875720e-02f, 8.040512350e-02f, 8.859419820e-02f, -1.486910280e-01f, 6.386066970e-02f, -3.880241140e-02f, 6.638827910e-02f, 7.372935120e-02f, -3.140085190e-02f, -6.315595660e-02f, 5.667136980e-02f, 2.601981460e-01f, 2.637144180e-02f, -1.516921820e-01f, -4.703881960e-02f, 2.387244250e-03f, 1.032623430e-01f, 1.311157050e-01f, -1.214417980e-03f, -1.145188420e-02f, 2.109617140e-01f, -1.018349270e-02f, -5.752893910e-02f, 1.241365150e-01f, -1.991295070e-02f, 8.966299140e-02f, 1.268424560e-02f, -1.068261270e-01f, 1.185822780e-01f, 1.114138740e-01f, -1.139169630e-01f, 1.665471490e-01f, -1.088278740e-01f, 1.515822110e-02f, 3.700433670e-02f, -3.198666500e-02f, -4.306704270e-03f, 9.932198370e-02f, -1.268734630e-01f, 1.668957620e-01f, 1.201012660e-01f, 9.739768500e-02f, -1.110954140e-01f, -1.367144290e-03f, -7.089617840e-02f, 9.162969140e-02f, -4.241906480e-02f, 1.265760960e-01f, -1.310734450e-01f, 4.663009570e-02f, 8.496127270e-02f, -1.461044100e-01f, -3.859944640e-02f, -9.170450270e-03f, -7.003974910e-02f, 2.838769850e-01f, -6.942080710e-02f, -8.241268240e-02f, 1.498158570e-01f, 1.056514610e-01f, 1.627886590e-01f, 7.423795010e-02f, 5.425179000e-02f, 5.932975190e-02f, 4.081125560e-02f, 1.446209850e-02f, 1.461375950e-01f, 1.429676710e-01f, -3.641636670e-02f, 4.967250860e-03f, -4.790339990e-02f, 1.403631180e-02f, -4.501195620e-02f, -3.804010150e-02f, 5.918031930e-02f, 1.341066210e-01f, -8.988793190e-02f, 6.451662630e-02f, -9.267093980e-02f, 7.103831320e-02f, -4.054170100e-02f, 2.345189640e-02f, 3.023667490e-03f, -1.035296840e-01f, -5.064772440e-02f, 1.193063050e-02f, -2.454272100e-02f, -7.440685480e-02f, -7.075045720e-03f, 1.229483490e-01f, 4.972876610e-02f, -2.243530470e-03f, 5.001273470e-03f, 1.299327760e-01f, 1.389958860e-01f, 8.717946710e-02f, -5.223674700e-03f, 1.392405780e-01f, 6.631071120e-02f, -1.385615320e-01f, 2.082797510e-02f, -3.558993110e-03f, -3.837798160e-02f, -6.732827430e-02f, -5.291793500e-02f, 3.502949330e-02f, -2.552073080e-02f, 5.521870780e-02f, -2.665786820e-02f, -7.977421580e-02f, -1.356144400e-01f, -3.452261910e-02f, 1.865329890e-01f, -7.231479140e-02f, 7.178168000e-02f, 7.704181220e-02f, 3.054325100e-02f, 2.658693680e-02f, -5.500309540e-02f, -4.058402030e-02f, -9.271422160e-04f, -1.116912510e-01f, 3.776603190e-02f, 5.739241090e-02f, 1.247530950e-01f, -2.825334480e-02f, -1.273587050e-01f, 1.352452930e-01f, 8.428055040e-02f, 1.631132910e-03f, -1.278375540e-01f, -8.718885480e-02f, -5.643314500e-02f, 4.984921510e-01f, 1.260736490e-02f, -5.157423020e-02f, 2.121914770e-01f, 1.355170610e-01f, -1.181418000e-01f, -4.615142570e-02f, -1.202023770e-01f, -2.816577260e-02f, -5.526317280e-02f, 2.450775910e-02f, 6.725112350e-02f, -5.194359650e-02f, -6.379694490e-02f, 2.894304690e-01f, -9.663489460e-02f, 8.198812600e-03f, 1.385315790e-02f, 4.590816800e-02f, -7.168633750e-04f, -6.144629790e-02f, 2.263111030e-01f, -4.922827710e-02f, -4.476788640e-02f, -8.704752470e-02f, 8.860796680e-02f, 2.670458850e-01f, 1.221676170e-01f, -7.953483610e-02f, -1.124492880e-01f, -2.740548230e-03f, -5.350418760e-02f, 3.622824700e-02f, -1.767618120e-03f, -6.876885150e-02f, -2.589509590e-03f, -1.282373630e-02f, 3.213585620e-01f, 1.534122230e-01f, -1.896258440e-03f, 1.243795980e-01f, -8.263650530e-02f, 1.165807250e-01f, 1.434303520e-01f, -3.664911170e-02f, 1.424216030e-01f, -3.621726480e-02f, 2.736936510e-02f, -6.016550590e-02f, -1.422189640e-02f, 3.024234060e-02f, 1.598330210e-02f, 3.015189620e-02f, -3.921424600e-02f, -3.628823160e-02f, -5.917089060e-03f, 4.486047480e-02f, 7.919862860e-02f, -6.640956550e-02f, -1.317250280e-01f, -7.099717860e-02f, -1.166027490e-01f, -3.959392490e-04f, 1.747859080e-02f, 2.375061010e-04f, 6.972360610e-02f, 4.504381870e-02f, -1.542170810e-02f, -7.157922260e-03f, -1.405980340e-02f, -3.147440400e-02f, 3.067974470e-03f, 3.657771650e-02f, 1.679530590e-01f, -8.975947640e-02f, 4.003669690e-02f, -7.789654190e-03f, -3.081191520e-02f, -8.576215240e-03f, 1.525326520e-01f, -7.785539610e-03f, -8.374815430e-02f, 1.037049070e-01f, 1.568803340e-01f, -8.193931540e-03f, -9.085444360e-02f, -2.499156070e-02f, -9.851924320e-02f, -2.941729690e-02f, 5.385106430e-02f, -4.275827480e-02f, -2.715245450e-02f, -1.214419120e-02f, 1.813172180e-02f, -3.350211680e-02f, -7.876183090e-02f, -3.181335340e-04f, -3.516460210e-02f, 8.147771660e-02f, -4.757584630e-02f, 3.260890390e-02f, 3.935355840e-01f, -9.189198720e-03f, 1.071621920e-01f, 4.039907080e-02f, -7.997700570e-02f, 8.127897050e-03f, -1.193832420e-02f, -3.384594250e-02f, 4.885253310e-02f, -4.211632530e-02f, 8.488035940e-02f, 2.002867010e-01f, -7.344419130e-03f, 1.175112000e-02f, -2.073120880e-02f, 6.738457830e-02f, 1.368697450e-02f, 1.658169180e-01f, 1.101561410e-01f, 1.721388100e-02f, 4.086217280e-02f, -1.177511590e-01f, 5.862758310e-02f, -6.873828170e-02f, 3.690661190e-01f, -1.373507270e-02f, -4.244604330e-02f, 4.985758290e-02f, -1.196618830e-01f, -6.623735280e-02f, -6.891047210e-02f, -1.990515370e-02f, -1.140335050e-01f, 5.654476210e-02f, -2.962869220e-02f, -2.726216800e-02f, 3.775535900e-02f, -7.140100000e-02f, 1.155410330e-01f, -6.070885060e-02f, 1.034199150e-01f, -7.345701010e-02f, 1.776784960e-01f, -1.123835520e-01f, -8.116184920e-02f, -7.707388700e-02f, -1.001707240e-01f, 3.078948710e-03f, -6.549177320e-02f, -2.610892990e-02f, 2.005418990e-01f, 1.146635860e-01f, 4.888550340e-01f, 1.715867070e-01f, -6.588704140e-02f, 6.172291930e-02f, -3.215725350e-02f, -7.570971550e-02f, -7.609312890e-04f, -1.453997190e-02f, 3.902427110e-02f, 1.221771540e-02f, -1.717614980e-01f, -3.168222310e-02f, 7.339832930e-02f, 9.151360950e-03f, 9.649140380e-02f, 7.846296570e-02f, -4.512926190e-02f, 2.391285300e-01f, -5.820374940e-02f, 1.322115810e-01f, -5.420304090e-02f, -6.012795490e-02f, -6.211959190e-02f, 3.229671720e-02f, -1.073716130e-01f, -6.478056310e-02f, -2.843910830e-02f, 9.768519550e-03f, 5.236257990e-02f, -5.019403990e-02f, 1.523199770e-02f, -3.832190480e-02f, -7.028789070e-02f, -5.993467290e-03f, 2.612373610e-02f, -2.401286040e-03f, 1.856553110e-01f, -1.082612200e-02f, -5.602089690e-02f, 1.038321330e-01f, -5.966008080e-02f, -2.559987080e-02f, 3.696736690e-02f, -4.413400220e-02f, 1.898927060e-02f, 1.386846140e-02f, -6.251929320e-03f, 7.146982010e-03f, 4.571650180e-03f, -3.753766790e-02f, 5.091410130e-03f, 5.857200010e-04f, -1.987156270e-02f, 1.450431350e-02f, -7.682397960e-02f, -7.976438850e-03f, 6.821383540e-02f, -7.057779280e-02f, -5.481724070e-02f, 1.886416600e-02f, 1.705892830e-01f, -6.132876150e-04f, -2.525117810e-02f, 2.130495460e-01f, -2.625177610e-02f, 8.027777070e-02f, -1.815678550e-02f, -7.983406070e-03f, 9.925503980e-04f, -3.067191460e-03f, -1.756729440e-03f, 2.930329180e-03f, 3.873919840e-03f, -3.304101900e-02f, -8.624736800e-04f, 3.958649000e-03f, 4.375504700e-02f, -1.603610250e-02f, -6.544820500e-03f, -4.129361360e-03f, 5.552446940e-03f, 4.367445040e-02f, 8.720490150e-03f, 6.079358510e-03f, 2.441011740e-02f, 3.922502700e-02f, 1.005368400e-02f, 1.429162170e-02f, 2.752677770e-03f, 3.844314810e-02f, -2.775716780e-02f, -1.138461660e-02f, 1.383800990e-02f, 9.579985400e-03f, -1.104223080e-02f, -6.478240250e-03f, 1.945972680e-03f, 1.544619070e-02f, 9.412144420e-01f, 2.165070550e-02f, -1.067741490e-02f, -4.713486410e-03f, 1.229678090e-02f, -3.445455800e-02f, 6.792806830e-02f, -2.356663910e-02f, 9.274216360e-03f, 2.712357600e-02f, 5.317525570e-02f, -2.962475460e-02f, -1.957180720e-02f, 3.098087010e-02f, -9.506192050e-03f, 5.732288700e-04f, 5.160144720e-02f, 2.634184200e-03f, 6.054137270e-02f, -4.627850840e-03f, -1.539598410e-02f, -7.529346270e-03f, 9.597306140e-03f, -5.457201040e-03f, 1.308516040e-02f, 1.298037170e-02f, -5.559586450e-03f, -3.246322270e-02f, -2.827998250e-02f, -1.365520900e-02f, 6.157167720e-03f, 7.453132890e-03f, -1.199800520e-02f, 2.450171110e-02f, 1.370128620e-02f, -9.220432490e-03f, -1.624061730e-02f, 2.560202220e-02f, -5.124892110e-03f, 2.377996780e-02f, 9.089348460e-02f, -7.170712200e-02f, -6.341110170e-02f, -1.042697950e-01f, 6.313963980e-02f, -9.559213370e-02f, -1.017248850e-01f, 1.221752170e-01f, 1.061825380e-01f, -4.209313910e-02f, 9.681947520e-02f, 1.828513150e-01f, -5.701506880e-02f, -1.286400110e-01f, 7.821145650e-02f, 1.177098450e-01f, -1.081500050e-01f, -6.623168290e-02f, -9.719339750e-02f, -4.199664110e-03f, 3.833903370e-02f, 3.272413020e-01f, 1.767606440e-01f, -5.295901750e-02f, 1.050684820e-01f, 2.158805280e-01f, -6.985513120e-02f, 8.816812180e-02f, 1.065159290e-01f, 4.781067370e-02f, -5.922073870e-02f, 8.388376230e-02f, 1.966698650e-02f, -6.728790700e-02f, -9.328363090e-02f, -6.236580010e-02f, -7.094521820e-02f, -2.020077710e-01f, -1.292009800e-01f, 1.164187790e-01f, 1.162202130e-01f, 5.165146290e-02f, -3.837573160e-02f, -1.062805130e-01f, 8.673863850e-02f, -1.539139900e-01f, -8.252715310e-02f, 8.233004800e-02f, -1.629273520e-03f, -5.168622360e-02f, 1.350480770e-01f, 1.060787890e-01f, -1.948437650e-02f, -2.097454480e-02f, 5.470116440e-02f, 1.058837100e-01f, -4.622593150e-02f, -8.953796690e-03f, -1.933634840e-02f, -2.038364480e-02f, 1.221512160e-02f, -8.188925680e-02f, -1.263355760e-01f, -1.325786710e-01f, -5.972000210e-02f, -8.273173870e-02f, 5.935356390e-02f, 5.439171940e-02f, -1.518325950e-01f, -7.144414630e-02f, -4.037861900e-02f, 7.958147670e-02f, -1.090803520e-01f, 5.165330600e-03f, -7.604261490e-02f, 1.718235900e-03f, 1.918622110e-01f, -9.637983880e-02f, -7.304427770e-02f, -2.659160270e-02f, 5.076153200e-02f, 5.688673260e-02f, -8.446139090e-02f, -1.711887770e-03f, 2.388226800e-02f, -1.152069420e-01f, -9.535770860e-02f, -6.482903660e-02f, -7.150081550e-02f, 3.041508500e-01f, 8.605542770e-02f, -5.160269510e-02f, 8.390607680e-02f, 6.587657330e-02f, 3.515451030e-02f, -9.806605420e-02f, -7.511837780e-02f, 2.849292200e-02f, 2.128988500e-02f, -1.799406110e-02f, 1.214314850e-01f, -9.935664940e-03f, -9.002992510e-02f, -9.118048100e-02f, 3.401162480e-02f, 8.560279380e-03f, 2.324812560e-01f, 2.257739660e-03f, 5.162560190e-02f, 1.888274030e-02f, 1.110941920e-01f, 1.319299190e-01f, -2.755292880e-02f, -1.138244940e-01f, -8.320982000e-02f, -8.932448170e-02f, -7.762363550e-02f, 4.763114850e-04f, -7.539620990e-02f, -1.218250020e-02f, 9.303565320e-02f, -1.391958740e-01f, -6.862980130e-02f, 4.938679930e-02f, -3.673203660e-02f, -5.543398480e-02f, -1.304555980e-01f, 6.993909180e-02f, 3.692833480e-01f, -7.483713330e-02f, -1.041151360e-01f, 1.455792780e-01f, 2.522501720e-02f, 1.511693450e-01f, -2.651982940e-02f, -1.052988320e-02f, -1.007327360e-01f, -1.210767960e-02f, -3.729615730e-02f, -2.099779060e-02f, 8.756467700e-02f, -1.967647670e-02f, 2.344930920e-01f, 5.728296190e-02f, 1.500066650e-02f, -1.311201750e-01f, 5.171862240e-02f, 1.093100530e-01f, -1.070623100e-01f, 5.319978300e-02f, -7.271814390e-04f, -6.051852930e-02f, 7.976955920e-02f, -3.387099880e-02f, -4.800493270e-02f, -9.287164360e-02f, -9.458256510e-02f, 1.820122300e-01f, 4.430868100e-02f, -2.509980400e-04f, -8.310642090e-03f, -1.043376700e-01f, -1.634244920e-01f, -2.435269390e-02f, -2.302803660e-02f, -1.661545970e-02f, -1.582444460e-02f, 1.841667740e-01f, -5.632584170e-02f, 1.766586600e-01f, 1.312395930e-01f, 7.296250200e-03f, 6.835992630e-02f, -8.956818280e-02f, 1.094354020e-01f, -9.440305820e-02f, 2.893740310e-03f, 2.056950330e-01f, -1.925067600e-02f, 1.758283380e-01f, 3.363610710e-03f, -1.029643190e-01f, 7.531443980e-02f, -6.610531360e-02f, -1.797626170e-02f, -1.395393010e-01f, -1.507245280e-02f, -2.296057720e-02f, 3.691719100e-02f, -6.936054680e-02f, -1.534029610e-03f, 4.254506160e-02f, -6.613132350e-02f, 1.077631940e-01f, 4.025180270e-02f, -2.887651320e-02f, -6.462924180e-02f, -6.464284660e-02f, -3.777319190e-02f, 5.703217910e-02f, -2.686702830e-02f, -5.196876820e-02f, -1.140064820e-01f, 1.140931840e-01f, 6.048103050e-02f, -1.094479860e-01f, -2.732208930e-03f, 1.311173290e-01f, -5.994545670e-02f, 3.179856760e-02f, 1.137217430e-01f, -6.721559910e-02f, -7.358045880e-02f, -5.446276810e-02f, 2.628117500e-01f, 3.120934370e-01f, 8.952303790e-03f, 2.857587640e-01f, 4.873356600e-02f, -4.707985370e-02f, -8.683725440e-02f, -1.951711070e-02f, -4.647362230e-02f, 1.491771490e-01f, -2.001990380e-02f, -8.631736040e-02f, -5.887214090e-02f, 1.295142900e-02f, 1.441902670e-01f, -9.087029840e-02f, -6.989160930e-02f, 5.647160860e-02f, -1.575066520e-02f, 4.622652660e-03f, 2.268533970e-02f, -7.890617100e-02f, 7.416850330e-02f, -1.196173130e-01f, -3.826511280e-02f, -5.224581810e-02f, -3.429683670e-02f, -5.818631870e-02f, 3.509224950e-02f, 5.191849170e-02f, -6.966035810e-02f, -1.518638710e-02f, 1.168719680e-01f, -4.474139960e-02f, -1.631231050e-02f, 5.746647720e-02f, 2.473540600e-02f, -8.604661370e-02f, 4.911043870e-02f, 5.489589270e-02f, 5.525099860e-02f, 5.546359720e-02f, 5.154997110e-02f, 8.471164100e-02f, 1.531471610e-01f, -1.332159530e-02f, -4.404731470e-02f, -3.424939140e-02f, -3.733983260e-02f, -1.503536850e-02f, -9.340851750e-02f, -1.382034870e-01f, 1.285225600e-01f, -3.680220250e-02f, 2.393166720e-01f, 1.335139270e-01f, 4.510176550e-02f, 5.464346710e-02f, 2.531766890e-02f, -1.142300960e-01f, 2.726680640e-01f, -2.782239390e-02f, -3.741101180e-02f, -8.581989250e-02f, -1.475718620e-01f, -2.607214820e-02f, -2.951931580e-02f, -5.786233400e-02f, 7.396380600e-02f, -2.336023560e-02f, 7.769796250e-02f, -5.415214230e-02f, 2.773481050e-02f, 3.830799760e-01f, 2.068872300e-01f, -1.280387030e-02f, 1.918655080e-02f, -8.173097670e-02f, 1.261965930e-01f, 1.111261620e-01f, -2.132707460e-02f, -8.244002610e-02f, 2.542951380e-03f, 1.814471040e-01f, 1.279665380e-01f, -1.329508720e-01f, 2.062910050e-01f, -7.540819040e-02f, -2.081235870e-02f, -8.192717280e-02f, -7.655327770e-02f, 9.153386950e-02f, -4.895126070e-02f, -9.508929220e-03f, -8.386000240e-02f, -4.455307870e-02f, -6.908810140e-02f, -6.361153720e-02f, 8.181581640e-02f, 1.827970890e-01f, 2.182608700e-03f, -1.872335000e-02f, -6.349958480e-02f, -3.154669700e-02f, 2.934292150e-02f, -8.925833740e-03f, -8.147642010e-03f, 1.935768130e-02f, -9.852752830e-02f, 2.694970370e-01f, -1.011638570e-01f, 1.338613030e-01f, 2.559455110e-02f, 1.246101480e-01f, 4.736974840e-03f, 4.201819000e-02f, 1.790455430e-01f, -7.304294410e-02f, -5.418322240e-02f, -3.452662380e-02f, -5.200724120e-03f, -1.137085180e-01f, -1.290849600e-01f, -2.694239090e-02f, 6.377866120e-02f, -8.877818290e-02f, 1.252376290e-01f, -1.182248220e-01f, -4.625061900e-02f, 1.551503090e-01f, -3.746622430e-02f, -3.926265980e-02f, 1.462489830e-02f, 4.340353890e-03f, 2.789698840e-01f, -5.796996880e-02f, 1.092499270e-01f, -9.528061740e-02f, 1.284025010e-01f, -1.187156140e-01f, -2.110307100e-02f, -3.766269980e-02f, -5.078503120e-02f, 8.650624000e-02f, 4.230117430e-02f, -1.091600130e-01f, -3.582896900e-03f, -2.006387520e-02f, 7.429616150e-02f, -6.748002770e-02f, -1.647013870e-01f, 1.014980900e-01f, 1.235877570e-01f, -1.346403360e-02f, 1.546589140e-01f, -3.153908630e-02f, -1.274988350e-01f, -1.322695170e-01f, 1.462925970e-01f, 1.662318110e-01f, -3.118827010e-02f, 1.080386490e-01f, -5.494855810e-03f, 2.390383000e-02f, 2.673367560e-01f, -2.111497520e-02f, -1.356952640e-01f, 2.416517140e-01f, 3.313310440e-02f, -7.249883560e-02f, 9.369431990e-03f, -1.320643420e-01f, -4.212691260e-02f, -5.761038880e-02f, 3.280920910e-02f, 2.668719740e-02f, -1.183211130e-01f, -7.349919530e-02f, 2.241358910e-02f, 2.219902430e-01f, -1.149633900e-01f, -3.781363000e-02f, 8.919361230e-02f, -2.534801840e-03f, 2.175252880e-02f, 2.028845850e-01f, -1.130583290e-01f, -6.722897290e-02f, 3.469984230e-02f, -3.113571550e-02f, 1.379388120e-01f, -5.251684410e-02f, -4.759397360e-02f, -6.197096310e-03f, 2.367033660e-01f, 8.606546370e-02f, 2.346830070e-02f, -1.077575830e-01f, -2.203533050e-02f, -2.718211340e-02f, 1.802454890e-01f, -5.028386410e-02f, 6.371421730e-03f, -1.149134930e-01f, 2.635177600e-02f, -3.858731310e-02f, 1.462568940e-01f, -6.328426770e-03f, -1.803635810e-02f, 4.530934240e-02f, 7.569578280e-02f, -1.653395220e-02f, -1.991326550e-02f, 2.138187640e-03f, 2.960101520e-02f, -1.426904050e-01f, -3.727335110e-02f, -3.178047760e-02f, 2.878608930e-02f, 1.414085830e-02f, -3.084834480e-02f, -2.031377330e-02f, -5.134997140e-02f, 7.165697960e-02f, 8.224274220e-02f, -3.506048400e-02f, -5.885192750e-02f, 4.506558650e-03f, -3.915296490e-02f, -2.992680300e-02f, -4.160908980e-02f, 2.423945630e-02f, 2.664759380e-02f, -2.418766730e-02f, 4.624679680e-02f, 7.323929660e-02f, 4.736410080e-02f, -4.986334590e-03f, -7.295847680e-02f, 3.053477410e-02f, -4.038002710e-02f, -1.331342380e-03f, -8.400293290e-04f, 1.050189060e-01f, 2.532878890e-02f, 8.137504450e-01f, 6.052341310e-02f, 3.547477720e-02f, -1.262859260e-02f, -1.285415050e-02f, 3.043013620e-03f, -8.367897570e-02f, 2.461048960e-02f, -4.999632020e-02f, 7.478489540e-03f, 7.332136480e-02f, -1.768730020e-02f, -2.755830440e-02f, 7.311223070e-03f, -1.859454250e-02f, 2.447962570e-02f, 1.078378410e-02f, -5.394505340e-02f, 1.227979460e-02f, -1.356008930e-02f, -1.408793590e-02f, 2.585064430e-02f, 1.938342300e-02f, -2.442185580e-02f, -3.086149880e-02f, -8.642385710e-03f, -3.914093970e-02f, 9.596488440e-03f, 2.609766270e-02f, -1.037263680e-02f, -2.916235480e-02f, 7.779887310e-02f, 5.771633980e-02f, 2.783076600e-03f, 3.664335980e-02f, 7.569734010e-02f, 4.493821410e-02f, 3.131845730e-03f, 7.217242570e-02f, 1.094051170e-03f, -4.675992950e-02f, 5.123569630e-03f, -3.351926430e-02f, -2.283530780e-03f, 1.198200740e-03f, 3.128184750e-02f, 6.871081140e-02f, -6.548886750e-02f, -8.421333130e-02f, -6.242690980e-02f, 1.034871490e-02f, 2.712799930e-03f, -6.175819030e-02f, 1.829471890e-01f, -3.226144610e-02f, -7.135538010e-02f, -3.808106110e-02f, -8.211141070e-02f, -3.719693420e-02f, 1.519255490e-01f, 5.943089720e-02f, -2.598664910e-02f, -4.903325070e-02f, -1.672257320e-03f, 1.141824570e-02f, 1.899924130e-01f, 4.016381130e-02f, -5.169410630e-02f, 2.947727780e-02f, -2.435912380e-02f, -3.042088260e-02f, 1.129907740e-01f, 3.502856190e-02f, 4.280240090e-02f, -2.486894840e-03f, -4.567280410e-02f, -1.579293050e-02f, -2.493759060e-02f, 8.560394490e-02f, -5.543261770e-02f, -2.658811770e-02f, 4.663733390e-02f, -1.168129220e-01f, -3.668671470e-02f, -4.584300520e-02f, -6.161202490e-02f, -3.585849700e-02f, 1.250403080e-01f, 2.358174880e-02f, -5.952933060e-02f, -9.496766320e-02f, 2.095430530e-02f, -2.347577180e-02f, 5.480669900e-03f, 1.755622630e-01f, 9.513531630e-02f, 3.915501390e-02f, 3.390642110e-01f, -3.237120060e-02f, 8.770570150e-02f, 1.108755170e-01f, 9.930687020e-03f, 4.077442880e-01f, -2.586516740e-02f, -3.151393310e-02f, 1.599870320e-01f, 2.445955720e-01f, 7.000851910e-04f, -2.034022100e-02f, -1.080259610e-01f, 6.769874690e-02f, -1.318548020e-01f, -7.001839580e-02f, 1.296834650e-01f, 1.566585450e-01f, 1.382808830e-01f, -6.129361320e-02f, -9.170862280e-02f, 3.396759330e-01f, 4.280986790e-01f, -1.806635040e-02f, 5.796686190e-02f, 1.535615070e-03f, -3.187161310e-02f, 3.889742490e-02f, 8.601231870e-02f, 1.370237470e-01f, -8.308852090e-03f, 4.984965920e-02f, 8.980850690e-03f, -8.778811240e-02f, 2.746690440e-02f, -7.396778460e-02f, 1.247192450e-02f, -4.780766000e-02f, -7.369079440e-02f, 1.460636410e-01f, -3.116878490e-02f, 1.754277050e-01f, -7.901813090e-02f, -1.333330940e-02f, -8.544019600e-02f, -4.298288380e-02f, -3.751122210e-02f, 3.850932420e-02f, 8.069495670e-03f, -1.267290490e-02f, 2.804135150e-04f, -8.100347590e-03f, -7.269055120e-03f, 1.786796300e-01f, 9.108161180e-02f, 7.386755200e-02f, -1.084351020e-01f, 5.548691840e-03f, -1.586312200e-01f, -3.452319650e-02f, -7.144560660e-02f, -1.223839260e-02f, 3.512820600e-02f, 4.187420380e-02f, 3.611988570e-02f, 2.969978140e-03f, -3.689632560e-02f, 2.349881690e-03f, -5.579718200e-02f, 5.154877900e-02f, -2.043618260e-02f, 1.168986260e-01f, -5.567264560e-02f, -4.746032130e-02f, -6.385917220e-02f, -5.669319630e-02f, -9.111207720e-02f, -3.037385880e-03f, -5.575670300e-02f, 6.962811200e-02f, -2.902540750e-02f, 6.220450250e-02f, 1.463254240e-01f, -5.698763580e-02f, -7.425221800e-02f, 5.765803160e-03f, 4.427254200e-02f, 2.280310690e-01f, 4.669820520e-02f, 2.785962540e-03f, 9.055937830e-02f, -6.092413510e-02f, -1.938406010e-02f, 5.037306620e-02f, 7.096775810e-03f, 5.841175470e-02f, -2.323592270e-02f, -2.809935250e-02f, 1.699426030e-02f, 4.773203430e-01f, -3.920917210e-02f, 4.082165660e-03f, -1.011161730e-01f, -1.012267400e-01f, -8.987317790e-03f, -3.036293390e-02f, 1.352268460e-01f, -1.310485010e-01f, 2.188092620e-01f, 8.876087510e-02f, -8.996786180e-02f, -1.503465770e-01f, 7.371095940e-03f, -1.192806200e-02f, -2.699019570e-02f, -2.786945740e-02f, 7.920522240e-02f, -9.713618080e-03f, -1.579045500e-02f, -1.274044630e-02f, 1.283179070e-01f, 6.313456220e-03f, 4.280159250e-02f, -4.265784840e-02f, 4.211013390e-02f, -1.677168070e-03f, 6.321051620e-03f, -5.710643530e-02f, 3.028270600e-02f, 1.815911750e-02f, -6.674249470e-02f, 1.363751590e-01f, -9.101912370e-03f, -5.869660150e-02f, -1.241326780e-01f, -2.959426680e-02f, -5.760793760e-02f, -1.167371270e-01f, 5.077018220e-02f, 2.336735090e-02f, -1.308563350e-01f, 1.661632210e-01f, -1.102688310e-01f, -6.880722470e-03f, -1.015329810e-01f, 1.107532750e-01f, -3.466279060e-02f, 6.117537990e-02f, -2.296120110e-02f, 6.268267330e-02f, -1.646498400e-02f, -7.783246230e-03f, 1.246381630e-01f, -9.076448150e-03f, 4.719724510e-02f, 1.349451840e-01f, 1.383633760e-01f, -6.811625510e-02f, -5.073588340e-02f, -4.604412990e-02f, 2.418875690e-03f, 4.539746420e-02f, -2.236315420e-02f, -4.063007240e-02f, 1.297861780e-01f, -7.344032080e-02f, -1.534403120e-02f, -5.413502080e-02f, -7.034826280e-02f, 1.076226610e-01f, 3.945178540e-02f, 1.601466830e-01f, -3.217451040e-03f, -9.337761250e-02f, -6.039064380e-02f, -5.948681010e-02f, 2.146855590e-01f, -1.356820910e-01f, -1.081532020e-01f, -2.822623120e-03f, 1.287319210e-01f, -5.192276460e-02f, 3.721720350e-02f, 2.822558880e-01f, -1.046858430e-01f, 1.752176510e-02f, 3.482427080e-02f, -9.507630020e-02f, -2.318179790e-02f, 2.271631730e-02f, 2.347490790e-01f, -2.901060320e-02f, 5.299499630e-02f, 3.214709830e-02f, -6.168810190e-03f, -8.727005120e-02f, -9.821260340e-03f, -1.448846760e-01f, 8.761693540e-02f, 2.628447120e-01f, 5.095703900e-02f, -6.624022870e-02f, 4.002903400e-02f, -1.949471680e-01f, 2.294481170e-02f, -7.851195520e-03f, 4.751910640e-02f, -4.056816920e-02f, 1.419805290e-01f, -1.322093460e-01f, -2.235613950e-02f, -7.051663940e-03f, 4.340960460e-02f, -7.474152000e-02f, -7.247021790e-02f, 1.113401950e-01f, -7.522353520e-02f, 1.407763180e-02f, 1.096730830e-01f, -5.823314930e-02f, 8.753168580e-02f, 9.297093000e-02f, 1.131078820e-01f, 8.096812670e-02f, -1.167487950e-01f, -1.952408250e-02f, -5.453368650e-02f, 1.178934130e-01f, -1.621972020e-01f, -5.554093790e-02f, -2.069934500e-03f, 4.089745880e-02f, 2.133468910e-02f, 1.296140100e-01f, -3.065254540e-02f, -2.750849170e-02f, -1.766028630e-02f, 5.944953490e-02f, -4.220638420e-02f, -4.985451230e-03f, -4.864119370e-02f, -6.301778550e-02f, -4.470399020e-02f, 6.601066560e-04f, 1.594405060e-02f, 6.242839990e-02f, 8.941114690e-02f, 6.813876330e-02f, -1.187132080e-01f, 2.052341590e-02f, -1.226666790e-01f, -1.278151760e-02f, 7.149275390e-02f, -1.480812860e-02f, 1.322260050e-01f, 3.901117670e-02f, -5.854143300e-03f, 9.016792480e-02f, -8.287353060e-02f, -4.698117260e-03f, -6.970217080e-02f, 1.900054140e-02f, 8.502421520e-02f, -4.470438880e-02f, -5.866368490e-02f, -7.356501370e-02f, -1.197677180e-01f, -4.172230610e-03f, -1.042116430e-02f, -1.176032720e-01f, -1.773861650e-01f, -1.146791730e-01f, 8.948346220e-02f, -4.542586950e-02f, -6.112887710e-02f, 8.248785880e-02f, -5.298398440e-02f, 2.450528890e-01f, 4.593492020e-03f, 3.773076460e-03f, 6.029900160e-02f, -4.252583530e-02f, 3.026582000e-01f, -1.182230260e-01f, 3.000807760e-02f, -6.777364020e-02f, -7.962507750e-02f, 8.366907010e-03f, -1.285491730e-01f, -4.904362930e-02f, 1.121400740e-01f, 2.236995470e-02f, 2.391654630e-02f, 1.707503570e-02f, 1.488977520e-01f, -8.133177460e-02f, -1.837710850e-02f, -3.722987320e-02f, 2.123144420e-01f, -1.226426750e-02f, 8.866790680e-02f, 6.163090000e-03f, 1.005886120e-01f, -2.259467730e-02f, -6.230629600e-02f, 1.296004950e-01f, 3.772589560e-01f, 4.233671350e-02f, 7.125468550e-02f, -1.273436990e-01f, 2.456050810e-01f, -4.559820520e-02f, 1.089477840e-01f, -2.854345740e-02f, 1.326503050e-02f, -4.348962380e-02f, -7.270832360e-02f, -1.293077320e-01f, -1.982290110e-02f, 5.357534440e-02f, -6.447993680e-03f, 1.074122820e-02f, 1.502002920e-01f, -1.196147430e-01f, 3.905359280e-02f, -4.773189130e-02f, 9.764505920e-02f, 5.065860230e-02f, -9.140437840e-02f, -1.114642550e-01f, 3.491286340e-01f, 2.099519520e-01f, -9.273590520e-03f, -1.801022890e-01f, 3.372891620e-02f, 1.479195150e-02f, -7.223246610e-03f, -5.961659920e-02f, -1.192306650e-01f, 5.824784190e-02f, 3.851342010e-03f, 8.046328270e-02f, -9.058136490e-02f, 1.526708250e-03f, 3.870328520e-02f, 9.082230920e-02f, -6.952971970e-02f, -7.951442900e-02f, -1.332629170e-01f, 6.281148640e-02f, -8.057054130e-02f, -1.086628810e-01f, -7.687722150e-02f, -1.341284360e-01f, -4.690337930e-02f, 3.565779330e-02f, 7.335846130e-02f, -5.975458030e-02f, -7.580781730e-02f, -1.189702560e-02f, 7.405931500e-02f, 1.333846300e-01f, -8.144551510e-02f, 1.837744560e-01f, 1.515974550e-01f, 3.410694000e-02f, 1.347601710e-01f, 4.213258250e-02f, 5.663735790e-02f, -3.980661560e-02f, 4.181305320e-02f, -9.646697340e-02f, 5.684674900e-02f, 6.649839880e-02f, 8.117150510e-02f, 1.417326650e-02f, -5.202396210e-02f, -4.883530550e-03f, -1.215516310e-02f, -2.912360240e-02f, -5.859534070e-02f, 8.904878050e-02f, 3.406750270e-03f, 5.007902530e-02f, -6.966095420e-02f, 5.631037060e-02f, -6.287767740e-02f, -2.049119030e-02f, -2.495251970e-02f, 1.281272710e-02f, 1.667584110e-02f, 1.624315530e-01f, 1.975316550e-01f, -6.327375760e-02f, -2.549493130e-02f, -7.560063150e-02f, 5.246623230e-02f, -5.496431510e-02f, 1.300104710e-01f, -1.303376700e-01f, 3.263463450e-02f, -1.202092390e-01f, -1.516885590e-02f, -8.285255730e-02f, 1.847651450e-01f, -9.641483420e-03f, 4.236166920e-02f, 2.639516630e-02f, -1.688137200e-01f, 5.884817340e-03f, -5.061656980e-02f, -7.925497740e-02f, 1.652334260e-02f, -1.346826700e-01f, -1.302521380e-01f, -5.528451500e-02f, -1.542577300e-01f, -1.176715940e-01f, -9.729474780e-02f, -1.336162240e-01f, -7.044177500e-02f, -1.102333740e-01f, -1.278100910e-01f, -5.466386300e-02f, -4.349506270e-02f, 2.310165610e-01f, -3.921423850e-02f, 3.162890670e-02f, 1.975149070e-01f, 3.809730710e-02f, -2.671097220e-02f, -1.651775840e-01f, -9.937649960e-02f, -1.417809720e-01f, -1.281252210e-01f, 1.498348920e-02f, -1.123010070e-01f, 1.723480820e-01f, -1.587923170e-01f, 1.285984520e-01f, -2.151615920e-02f, -7.964518660e-02f, -7.883919030e-02f, -9.310674660e-02f, -6.818025370e-03f, -7.549011710e-02f, 5.376015230e-02f, -7.829520100e-02f, 6.894543760e-02f, -1.334407370e-03f, 2.610905840e-02f, 1.004805790e-01f, 4.499522500e-03f, 1.937191700e-04f, -6.385441120e-02f, 4.432567210e-02f, -4.464306680e-02f, 4.364181680e-02f, 1.634998990e-02f, 4.483027010e-02f, -6.035631900e-02f, 3.548398990e-02f, -3.876640650e-02f, 1.202725320e-01f, 1.329291310e-01f, 1.398882720e-01f, -3.295514730e-02f, -4.788012060e-02f, -1.107231380e-01f, -9.391162540e-02f, -1.378490920e-01f, -1.576196960e-04f, -6.028098990e-02f, -5.313913150e-02f, -3.971696270e-02f, -2.033039000e-02f, -5.538550390e-02f, -6.057970600e-02f, -6.880935280e-02f, 4.119714350e-02f, -1.272552180e-02f, -2.916770060e-02f, -5.861311030e-02f, -6.750701370e-02f, 1.974735220e-02f, 1.798603090e-01f, -1.400936990e-01f, -1.017743420e-01f, 1.138044220e-01f, 3.469457920e-01f, -2.268626730e-02f, 1.009007100e-01f, 1.845979690e-01f, -5.918310210e-02f, 3.897958250e-02f, 1.046426970e-01f, 1.182906110e-01f, -1.343791470e-02f, -2.435667630e-02f, 2.726042870e-01f, -1.103236820e-01f, -6.449663640e-02f, 3.770653900e-02f, 1.655253020e-01f, -1.093243060e-01f, -8.669281750e-02f, -2.365634960e-02f, -3.534030540e-02f, 1.387308090e-01f, 2.714927200e-01f, 1.430962330e-02f, 4.845132680e-02f, -2.113537120e-02f, -3.918521110e-02f, -6.082796310e-02f, -8.741516610e-02f, -3.606809680e-02f, 9.631435390e-03f, -2.976188250e-02f, -3.726581110e-02f, -8.196125920e-02f, 4.731152580e-02f, 6.986957790e-02f, -4.582611100e-02f, -6.660570200e-02f, 7.963682710e-02f, -1.070426930e-01f, -1.544523840e-01f, -2.704916520e-02f, 3.101586400e-01f, -1.096276570e-01f, -1.178093530e-02f, -8.671174760e-03f, 5.039677020e-02f, 1.649309840e-01f, 3.930942340e-02f, -7.375567410e-02f, 1.019732580e-01f, -1.244220510e-02f, -4.673672840e-03f, -7.268676910e-02f, 8.058513700e-02f, 2.024334370e-01f, -9.881184250e-02f, 1.375796790e-01f, -1.126106080e-01f, 1.524450480e-01f, -4.754039650e-02f, -5.029721560e-02f, -8.193097260e-02f, -3.238003700e-02f, 1.908310500e-02f, 2.574954930e-01f, -9.369903800e-02f, -9.194771200e-02f, -5.265001950e-02f, -1.429793700e-02f, 1.062680780e-01f, -8.290049430e-02f, 1.087920070e-01f, -3.662929310e-02f, -4.272153230e-02f, -4.750560220e-02f, -1.073535530e-01f, 7.735631610e-02f, -7.671023160e-02f, 2.103704960e-02f, -4.338222740e-02f, -7.786579430e-02f, 6.100999560e-02f, 1.522590070e-01f, -5.006895590e-02f, -8.399093150e-02f, 1.119294610e-01f, 1.556570380e-01f, 8.592043070e-02f, -1.136702300e-02f, 8.843199160e-02f, -9.966421870e-02f, -1.207039430e-01f, 6.718245140e-02f, -4.638949410e-02f, 6.902265550e-02f, -5.813098330e-02f, -9.715624890e-02f, -4.224073510e-02f, -4.591938480e-02f, 1.103583500e-01f, 4.675296690e-02f, -1.060657200e-01f, 9.157583110e-03f, 2.073813530e-01f, -1.087837000e-01f, 1.105199310e-01f, -4.515529050e-02f, -1.617991740e-02f, 2.803524020e-02f, -6.606045360e-02f, 4.358275610e-02f, 4.256529210e-01f, 4.834608730e-02f, -8.817963300e-02f, -1.051889360e-01f, 1.061829330e-01f, 5.970552190e-02f, -3.791338210e-02f, -7.492439450e-02f, -1.393734760e-02f, -9.489382050e-02f, -5.284090340e-02f, 5.834036320e-02f, -1.399754730e-01f, -1.433932410e-02f, -4.326387120e-02f, 3.151964250e-01f, 4.320833460e-02f, -8.508528020e-02f, 8.348090200e-02f, -9.979646650e-02f, 6.082212920e-02f, -7.122298330e-02f, 5.574127660e-02f, -1.110224130e-01f, 6.340926140e-02f, 5.167165030e-02f, 5.203384440e-03f, 1.148823500e-01f, -2.331013980e-02f, -8.711327800e-03f, -4.177651550e-02f, -1.315636040e-01f, 1.287236660e-01f, -1.271518320e-02f, 6.185146420e-02f, 1.847838610e-01f, 7.219175250e-02f, -6.257501990e-02f, 3.571297230e-02f, 5.533116310e-02f, -1.311706750e-02f, -4.700696840e-02f, 4.182666170e-02f, 4.327403010e-02f, 4.399606210e-02f, -1.178695480e-01f, 3.036009850e-03f, 4.504967850e-02f, -5.482348050e-02f, 1.649580600e-01f, -9.073909370e-02f, 5.878604950e-02f, -5.458976330e-02f, 8.261759580e-02f, 6.157740950e-02f, -5.626295130e-02f, -6.137568500e-02f, -1.377695200e-01f, -2.891614290e-02f, -1.294538380e-01f, -6.494706870e-02f, -3.452215720e-02f, -6.000406110e-03f, 6.179108470e-02f, 1.652100530e-01f, 1.316253650e-02f, 6.055007130e-02f, -7.384913410e-02f, -1.059325040e-02f, 3.541951250e-02f, -1.491044160e-01f, 1.353022460e-01f, -1.276331690e-01f, 7.283655460e-03f, -5.437891190e-02f, 6.291843950e-02f, -5.915827680e-02f, 8.663754170e-02f, -1.220987890e-01f, 6.822229830e-03f, 2.170533540e-01f, 7.197658720e-02f, -6.356410680e-02f, 5.183010920e-02f, 1.644392160e-01f, -3.698183970e-02f, -1.100772990e-01f, -8.100061860e-02f, 5.907067100e-03f, 1.649250390e-01f, -5.304610360e-03f, -2.439306490e-02f, -1.202237610e-01f, -1.186238230e-01f, -7.203304770e-02f, 2.065298150e-02f, 5.962751060e-02f, 7.793220130e-02f, -6.590663640e-02f, 3.311977910e-02f, -1.074311580e-01f, 2.310679110e-02f, -9.188425540e-02f, -2.588551120e-02f, -3.972282260e-02f, 1.643828000e-01f, 2.501917820e-02f, 2.627533970e-01f, 7.465478030e-02f, -2.647155340e-02f, -1.603544500e-01f, -9.279048440e-02f, 3.219546010e-02f, -6.170372660e-02f, 5.565557260e-02f, -6.255177410e-02f, 1.580136080e-02f, -1.525250230e-01f, -1.159404740e-01f, -1.334195880e-01f, -1.032797770e-01f, 3.274960820e-02f, 3.466526420e-02f, 2.314574780e-03f, -1.591567990e-01f, -1.171788280e-01f, -7.967610840e-03f, -1.051080080e-01f, -9.912811210e-02f, 4.486919190e-02f, 8.387523880e-02f, 1.478525550e-01f, -2.514058140e-04f, 1.641806960e-01f, -1.080134290e-01f, 1.993146540e-01f, 2.904309700e-02f, -1.606262290e-02f, 1.363784220e-01f, -4.584413390e-02f, 5.373544060e-03f, -5.718510600e-02f, -5.822846290e-02f, 2.410070040e-03f, -7.168520240e-02f, 2.302834390e-01f, -1.238001730e-01f, -2.012027610e-02f, -4.361319910e-02f, -3.150009740e-02f, 2.581590040e-02f, -2.012433110e-02f, 6.347522880e-02f, -5.283330380e-02f, -6.440760940e-02f, -6.016835570e-02f, -7.908780120e-02f, -9.716962460e-03f, -4.432619740e-02f, -8.129787750e-04f, -4.438065360e-02f, -1.223741920e-01f, -1.169863270e-01f, -5.640559270e-02f, -4.590348900e-02f, 1.234958600e-02f, -2.733425610e-02f, -1.177258040e-01f, 2.312500960e-02f, -1.297996940e-01f, 4.821078850e-02f, -4.670440780e-02f, -6.661852450e-02f, 1.669716650e-02f, 1.560818870e-02f, -3.169418130e-02f, 1.027927990e-01f, 3.262537350e-02f, -2.050017750e-02f, -1.489218030e-01f, 8.800893090e-03f, -3.720280900e-02f, -1.393560170e-01f, -4.553129150e-02f, -7.629192430e-03f, -1.341488770e-02f, 3.468826790e-02f, -6.813413650e-02f, -1.129368170e-01f, -3.751330080e-02f, 1.025499780e-03f, 1.851804410e-01f, 1.483534870e-01f, -5.726965520e-02f, -2.476603910e-02f, 3.917015790e-01f, 2.481744810e-02f, 5.348939820e-02f, 4.506634920e-02f, -5.847026410e-02f, -3.952263390e-03f, -4.664445300e-02f, 6.686110790e-02f, 1.623520070e-02f, 2.240048200e-01f, 2.329068780e-01f, 1.739515960e-01f, -5.983104180e-02f, 2.247769200e-02f, -1.775606190e-03f, -3.643877340e-03f, -8.313409980e-02f, 1.903967260e-01f, 2.170514500e-02f, 4.938589040e-02f, -2.685485040e-02f, 1.196541640e-01f, 6.616559620e-02f, -4.479730870e-02f, -9.827705470e-02f, -3.219773620e-02f, 2.955799920e-02f, 4.033704470e-02f, -1.009461380e-02f, -5.445482210e-02f, 2.734451180e-02f, 2.076743100e-01f, 1.023022900e-01f, 1.987520050e-02f, 3.071126710e-02f, 3.293377530e-02f, -1.006202620e-01f, -8.389054240e-02f, 2.209225150e-01f, 8.377794170e-02f, -1.241206450e-01f, 7.627146690e-02f, 7.529663290e-02f, 3.692612420e-02f, -9.659259020e-02f, 7.474428420e-02f, -1.013398690e-01f, 4.256598650e-02f, -1.164682130e-01f, -3.641425070e-02f, 1.144099140e-02f, 3.446362170e-02f, -1.999554040e-02f, 2.883717420e-01f, 1.055758970e-01f, 6.890146430e-02f, -8.442627630e-02f, -1.005524250e-01f, -2.936113630e-02f, 1.883609590e-01f, -9.377644210e-02f, 3.764276950e-02f, 1.728766560e-01f, 1.402250680e-02f, -1.315089760e-01f, -9.552451960e-02f, 1.344653820e-01f, -1.062336040e-01f, -8.892058580e-02f, -6.182565170e-02f, -2.457570100e-02f, 2.805065810e-01f, -3.780340400e-02f, -1.538791060e-01f, 5.312591050e-02f, 4.652089250e-02f, 2.261203150e-02f, -1.068178710e-01f, -1.702375340e-02f, 1.951687630e-01f, -2.763769590e-02f, -4.313041270e-02f, 1.267185060e-02f, -1.211875600e-01f, -5.418342720e-02f, -2.319737520e-02f, -1.377355310e-01f, -4.481059030e-03f, -4.293828830e-02f, 1.125539390e-01f, 1.490307040e-03f, 2.144433560e-01f, -2.137570830e-02f, -5.985781180e-02f, 9.653304520e-02f, -5.280613900e-02f, 4.576502740e-02f, -4.910514500e-02f, 1.630954890e-01f, 1.315031950e-01f, 5.002929640e-02f, 7.192813790e-03f, 5.615061150e-02f, 1.887865960e-01f, 3.303285320e-02f, -4.776756840e-02f, 4.787252840e-02f, 1.340400730e-01f, -9.376879040e-02f, -7.588774710e-02f, -1.611279990e-01f, -6.403164570e-02f, -9.320133920e-02f, 1.645439860e-01f, -3.663381930e-02f, 3.688097750e-02f, 1.209784150e-01f, -4.559051620e-02f, 1.852229240e-01f, 2.030884850e-02f, 5.488774930e-02f, -7.045978310e-02f, -2.210402630e-03f, -7.779671250e-02f, -3.370142360e-02f, -5.047992240e-02f, -3.285800670e-02f, -6.394833330e-02f, 1.080965770e-01f, -7.248478380e-02f, 6.371216480e-02f, 1.025879980e-01f, -5.870119480e-02f, -9.928458180e-02f, -5.881684650e-02f, -7.099809500e-02f, 5.085936190e-02f, 3.080938160e-01f, 1.011769770e-01f, -6.513246890e-02f, -1.128294540e-01f, -7.630875330e-03f, 1.290668700e-01f, 5.101840480e-03f, 2.711902560e-01f, 3.049307130e-02f, -8.411551260e-02f, -4.879781230e-02f, -5.727344190e-03f, 2.252665610e-01f, -1.266965420e-01f, 7.962071900e-02f, -4.850283730e-03f, -2.206741650e-02f, 1.173009720e-01f, -1.209823940e-01f, 7.712912280e-03f, 4.408441480e-02f, -9.966784710e-02f, 3.011564910e-02f, -9.073799840e-02f, -6.394088270e-02f, -2.026836200e-02f, 6.514702690e-04f, 1.562145500e-01f, -4.534414780e-02f, -8.315022290e-02f, 4.994611440e-02f, 9.342501310e-02f, 4.020154100e-02f, -9.149026120e-02f, -1.127018310e-02f, 1.019827130e-01f, -1.896892190e-01f, -6.476037200e-02f, -8.531137550e-02f, 4.223022240e-02f, -4.140706730e-02f, -8.220507940e-02f, 1.339806060e-02f, 8.275192230e-02f, 1.858666240e-01f, -6.262902170e-02f, -1.476951990e-03f, -2.218423970e-02f, 1.353407740e-02f, 1.954117860e-01f, -3.381326790e-02f, -9.173731510e-02f, -2.604169210e-02f, 1.277179220e-03f, 1.584943380e-01f, 2.540791220e-02f, -2.914321610e-03f, -2.465242890e-02f, -9.184541550e-02f, 1.493308130e-02f, -5.709263680e-02f, 4.160784180e-02f, -3.910624980e-02f, 2.291026260e-01f, -6.817325940e-02f, 7.088342300e-02f, 8.521439140e-02f, -5.827171730e-02f, 4.973900970e-03f, -6.639371810e-02f, 4.958428440e-02f, -1.507575060e-01f, 1.773077850e-01f, -5.902005730e-02f, 9.382950510e-02f, 2.634173040e-01f, 9.177392340e-03f, -8.676602690e-02f, 1.177518740e-01f, -1.401470690e-02f, -5.917327480e-02f, -3.787180040e-02f, -1.011282390e-02f, 7.028015330e-03f, -6.556136070e-04f, -4.756086320e-02f, 1.945606770e-01f, -3.410836680e-02f, -5.789696800e-02f, 1.632296140e-01f, -5.231251940e-02f, -9.474957730e-02f, -7.700948420e-02f, -7.404104620e-02f, -7.528156790e-02f, 2.993804810e-01f, -3.067417440e-02f, -7.711244370e-02f, -9.447386110e-02f, -6.350621580e-02f, -9.565892070e-02f, 4.885492850e-02f, -1.717520130e-02f, 6.245880850e-03f, 8.259473740e-02f, -1.645151230e-01f, -7.405516500e-02f, 1.681779620e-01f, -1.291015090e-02f, -3.540391850e-02f, 2.375352200e-02f, -9.599495670e-02f, 6.172417850e-02f, 6.389430160e-02f, -5.964233350e-02f, -1.582423970e-02f, -2.926665730e-02f, 9.098583830e-03f, 1.040786060e-01f, 8.385580770e-02f, -7.829087970e-02f, 5.736025050e-03f, 1.757548150e-01f, -3.007029000e-02f, 1.486612300e-02f, -6.771608440e-02f, -5.474331230e-02f, 5.907382820e-02f, 4.430993460e-03f, 6.064268290e-03f, 1.916092630e-01f, -9.434846230e-03f, 1.305762980e-01f, -3.051482890e-02f, 6.396798790e-02f, -3.812040390e-02f, -7.860299190e-02f, -6.541115050e-02f, 2.780405060e-02f, -1.079074590e-01f, -4.225643720e-02f, -3.012688090e-02f, 2.902521190e-02f, 1.174938230e-01f, 1.979914010e-01f, -8.486174050e-02f, 2.344472710e-02f, -1.456950420e-02f, -9.601641440e-02f, 8.059802650e-02f, 1.409108190e-01f, 1.600027980e-01f, -1.735847890e-01f, 9.691231880e-03f, -6.550613790e-02f, 9.928683280e-04f, 4.635287820e-02f, -3.982521590e-02f, -4.994821920e-02f, 5.221048000e-02f, -1.201450010e-01f, -2.349807510e-02f, 2.954950560e-03f, -5.590195950e-02f, -9.153342990e-02f, 4.725471140e-01f, 2.042965400e-02f, 6.273598970e-02f, -8.793028440e-02f, 1.555760390e-02f, -7.999872410e-02f, 8.339435600e-02f, -9.429907420e-03f, -9.374579040e-02f, -4.112624750e-02f, 5.982402340e-02f, 6.396263090e-02f, -4.365088050e-02f, 5.192891140e-02f, 1.121789220e-01f, -1.437166050e-02f, -5.350998420e-02f, 3.003993440e-02f, -3.541243080e-02f, -1.012866420e-01f, 5.346907300e-02f, 2.777650650e-01f, 6.546910850e-02f, -7.609222080e-02f, 1.460178940e-01f, -1.231905590e-01f, -2.501863430e-02f, 1.070073770e-01f, -5.199152230e-02f, -2.691350500e-02f, 1.442134680e-01f, 3.946863860e-02f, -5.718088150e-02f, 4.080003130e-02f, 7.363263520e-02f, 1.468089070e-01f, -1.616590470e-02f, -2.971408700e-02f, 2.696871200e-02f, -5.690131340e-02f, 8.603161570e-02f, -3.535539660e-02f, -8.729121080e-02f, -7.031060760e-02f, -1.926177740e-02f, -3.430452940e-02f, -2.425199750e-02f, -1.125221030e-01f, 3.774232270e-01f, 1.660114380e-01f, -1.534047870e-01f, 1.159239490e-01f, -1.036727430e-01f, 5.664833820e-03f, -1.648365150e-02f, 1.251370160e-01f, 1.363208740e-01f, -6.014391780e-02f, 1.409173310e-01f, -3.593834120e-02f, -3.344780210e-02f, -4.554719480e-02f, -3.170278300e-02f, -1.165465940e-01f, 2.229334560e-01f, -9.005537620e-02f, -5.282830450e-02f, 5.704053680e-03f, -5.651744080e-02f, 1.800104790e-02f, 1.407293830e-01f, 1.518028970e-01f, -3.026494060e-03f, -3.021867570e-02f, 9.633468830e-02f, -9.191603960e-02f, 1.886844340e-01f, 3.187735800e-03f, -1.038954850e-01f, 8.727184680e-02f, -9.960985180e-02f, 1.283811330e-01f, 1.107948420e-01f, -3.760924560e-02f, -2.181736750e-03f, -2.827181480e-02f, 3.378782050e-02f, 5.541912840e-02f, 1.176887080e-01f, 4.562088850e-02f, -4.889807850e-02f, 9.094254110e-03f, -8.575432000e-03f, -2.985637080e-02f, -6.481246650e-02f, -1.347393690e-01f, -1.545384080e-01f, 1.155207160e-01f, -2.186039280e-02f, 2.132100760e-01f, -1.353322620e-02f, -2.104218860e-02f, -3.001443480e-02f, -1.937283950e-02f, -3.321282570e-02f, 6.272106620e-02f, -1.030180680e-01f, 1.755981890e-01f, 1.957392880e-02f, -4.734005030e-02f, 4.877107960e-02f, -3.012188340e-02f, 4.021517930e-02f, -1.406920400e-01f, 5.244942850e-03f, -4.697530720e-02f, -5.521954220e-02f, 8.057405050e-02f, -3.025992960e-02f, 1.221921820e-01f, -6.348315630e-02f, -3.742178900e-02f, 3.701967370e-02f, 3.683533520e-02f, -1.090462130e-01f, -1.430377220e-01f, -5.739906430e-02f, 1.166210400e-01f, -1.481025360e-03f, -1.192567940e-01f, -1.667521600e-01f, 3.091524540e-02f, 5.887627600e-02f, 4.586014520e-02f, -2.956831360e-03f, -3.866497050e-02f, 1.026260550e-01f, 1.618810150e-01f, -6.902870720e-03f, 1.102851850e-01f, 2.151487470e-01f, -1.105188280e-01f, -8.072756970e-02f, 3.132687510e-01f, 2.672367990e-01f, -7.551503180e-02f, 2.478747630e-02f, 1.510271880e-01f, -1.274814750e-01f, 4.695739970e-02f, -2.353647350e-02f, -6.828805060e-02f, -2.451711330e-02f, -6.093870100e-02f, -4.259489010e-03f, 6.607934830e-02f, -8.786247670e-02f, 1.966802330e-01f, 2.936550040e-02f, 1.161023680e-01f, -1.237190790e-02f, -9.934745720e-02f, -9.208149460e-02f, 6.427287310e-02f, -7.367718960e-02f, -4.518035800e-02f, 7.990945130e-02f, 7.277863570e-03f, 2.433651310e-02f, 5.147361200e-03f, -1.034543740e-01f, 8.183532950e-02f, -1.153540160e-01f, -7.965207840e-02f, -5.803852810e-03f, -2.100765330e-02f, 2.179387960e-01f, -9.275280870e-03f, -2.585983090e-02f, 1.528220020e-03f, -6.071496290e-03f, -4.244554040e-02f, -3.103707920e-02f, 1.728734520e-01f, -7.886952160e-02f, 3.563577770e-03f, 1.211525050e-01f, -6.202827760e-02f, 1.823985250e-03f, 2.646283810e-01f, -2.956136690e-02f, 6.684387480e-02f, -4.317032550e-02f, -8.177239440e-02f, -5.743967740e-02f, 1.849188950e-01f, 5.866226550e-02f, 3.774701800e-02f, 1.863715430e-02f, -6.798057260e-02f, -9.213728450e-02f, -3.917795420e-02f, -8.163130280e-02f, -3.048925290e-02f, -3.417144340e-02f, 3.214985880e-02f, 4.396836460e-02f, -6.377837810e-02f, 3.406903740e-01f, 2.900814450e-02f, -6.453192980e-02f, 6.410934030e-02f, -4.358428720e-02f, 3.063983920e-01f, 8.317107700e-02f, -6.285231560e-02f, 4.599626730e-02f, -6.167289610e-02f, -1.134520990e-01f, 4.556827250e-02f, -5.637450520e-02f, 1.632862840e-01f, -1.847836380e-02f, 2.417114380e-01f, 8.375129100e-02f, -6.431815210e-03f, 7.469455900e-02f, -5.716868490e-02f, 3.125609600e-03f, 8.896732330e-02f, -4.933669420e-02f, -9.446647760e-02f, 1.211787670e-02f, -4.058498520e-02f, -1.431442950e-01f, 1.843609470e-02f, -1.640376450e-01f, -4.805744100e-04f, -8.481211210e-02f, -1.335760500e-01f, 7.505460080e-02f, -3.957760330e-02f, 4.390626850e-01f, -2.509161270e-02f, -4.637843000e-03f, -5.079869550e-02f, 5.155643080e-02f, 4.587837310e-02f, -3.008119950e-02f, -3.092604460e-03f, 1.331780390e-02f, 1.223894300e-02f, -1.026694940e-02f, -7.817752780e-04f, -5.148553480e-02f, -2.432832120e-02f, -6.005344540e-02f, -7.038456200e-02f, 1.822878720e-01f, -2.743378650e-02f, 1.316594720e-04f, 9.675724800e-02f, 3.635737300e-02f, 1.268052160e-01f, 7.216937840e-02f, -6.359113750e-02f, -8.647389710e-02f, -8.270219710e-02f, -1.074320670e-01f, -3.445768730e-02f, -7.228174800e-02f, -1.846628260e-02f, -6.269596520e-02f, -5.081693830e-02f, 1.242429760e-01f, -1.838476210e-02f, -1.592431070e-01f, 8.302608870e-02f, -2.112851480e-02f, -9.259057040e-02f, -4.677237570e-02f, -3.068910350e-02f, 8.413452650e-02f, 1.752968280e-01f, -1.065102220e-01f, -9.299115840e-02f, -6.499022250e-02f, -1.153679420e-01f, 7.415601520e-03f, -6.017673390e-02f, 2.154518850e-02f, -1.139054300e-01f, -1.742232780e-02f, -2.543218990e-02f, -3.743700310e-02f, 1.401526180e-01f, 3.275419770e-02f, -2.339495530e-02f, -5.391479660e-02f, -4.451093450e-02f, -2.990986970e-02f, -3.947201000e-02f, -2.917677720e-02f, -7.721634950e-02f, -1.648931390e-02f, -6.544423850e-02f, 8.065704250e-02f, 5.832491820e-02f, -4.733141050e-03f, -1.883053030e-02f, 9.013862160e-02f, -7.213326540e-02f, -1.680432030e-04f, 1.063356700e-01f, -3.326249500e-02f, -4.479930920e-02f, 3.532809320e-01f, -5.594594400e-02f, 2.716015580e-01f, -3.860247880e-02f, 2.699141200e-02f, 4.016639290e-02f, -7.866363230e-02f, -2.826625110e-02f, 2.098726110e-02f, 1.621146500e-01f, 2.386448530e-02f, 8.051454090e-03f, -3.112656810e-02f, -4.461658540e-04f, -2.571382190e-02f, 2.609126740e-03f, 1.708628830e-01f, -3.636744990e-02f, -3.673140330e-02f, -6.654124710e-02f, 2.289799790e-02f, 1.051690730e-01f, 4.349128340e-03f, 1.627124990e-01f, -1.063033570e-01f, -7.479587940e-02f, -7.856924080e-02f, 5.522544310e-02f, 8.961490540e-02f, -1.104433390e-01f, -9.098307790e-02f, -5.024623130e-02f, -3.578425570e-02f, -9.849171340e-02f, 1.815728990e-01f, -6.825593860e-02f, -7.086425270e-02f, 1.141510460e-01f, 3.049320580e-01f, 1.269057300e-02f, 1.059816960e-02f, 2.464921770e-01f, -6.683388350e-02f, 6.677040360e-03f, -9.703782200e-02f, 7.792222500e-02f, -7.185612620e-02f, 7.532192020e-02f, 1.499096750e-01f, -1.118058640e-01f, 8.495755490e-02f, 8.518117660e-02f, -5.965986480e-02f, -1.162404490e-01f, 2.314585750e-01f, -2.008067070e-02f, 3.102089280e-02f, 2.766549290e-01f, -4.880190270e-02f, 1.017664670e-01f, -8.912593120e-02f, -1.524659840e-01f, 3.267309070e-02f, 1.530572620e-01f, 1.132519390e-01f, 6.123947720e-02f, 2.082134410e-02f, 6.838160010e-02f, 1.565640720e-01f, -1.902818680e-01f, -7.244487850e-02f, -1.088867190e-01f, -1.474312840e-01f, 7.652833310e-02f, 6.374807660e-02f, 1.879871450e-02f, -1.244930180e-01f, 9.146250030e-02f, -1.796051560e-01f, -2.350436060e-03f, 2.005647870e-03f, 1.385036110e-01f, -2.690947800e-02f, -2.332909220e-02f, -8.136997370e-02f, -2.792862990e-02f, -3.002593850e-02f, -4.078468680e-02f, 1.948571950e-02f, -4.268416020e-02f, 5.794682350e-02f, -5.112982910e-02f, -3.388336670e-02f, -1.415162980e-01f, 1.848193410e-01f, 9.498614810e-02f, 1.667949180e-02f, 3.461322560e-02f, -3.496787700e-02f, 2.325237910e-02f, 1.334218590e-02f, 6.730023770e-03f, -9.793943910e-02f, -2.304056470e-02f, 7.728901690e-03f, -1.284001020e-01f, -5.464117230e-02f, -1.381355820e-01f, -1.475852580e-01f, -4.472943400e-02f, -1.093851180e-01f, 1.225263530e-02f, 7.007342580e-02f, -3.239586950e-02f, -2.066363390e-01f, -4.672746730e-02f, -5.035889520e-02f, -1.720228640e-01f, -5.220789090e-02f, 6.324827670e-03f, 5.660083140e-02f, -2.473141810e-02f, -1.533917150e-02f, -5.960299450e-02f, 6.110745670e-02f, 1.282819830e-02f, -2.551986280e-02f, 1.178511980e-01f, -4.123710470e-02f, -5.182072520e-02f, -4.412150380e-02f, 2.726851780e-02f, -8.944893620e-02f, 1.691897960e-01f, -1.108551620e-01f, -8.490215980e-02f, -2.925290350e-02f, -2.229041230e-02f, 1.027869510e-01f, 1.367140710e-01f, 1.090429950e-01f, 6.598363630e-03f, 1.220247710e-02f, -1.193050070e-01f, -3.027983010e-03f, 1.202605810e-01f, 1.946002060e-02f, -5.876889820e-02f, -3.201801330e-02f, 1.665638010e-02f, -4.107050600e-02f, -5.424967410e-02f, 2.238983660e-02f, -1.193734170e-02f, 6.281152360e-02f, 6.463199850e-03f, -3.807428480e-02f, 2.329827290e-02f, -7.897537940e-02f, -1.276791390e-01f, 5.499531330e-02f, -1.132831420e-01f, -1.034827460e-01f, 5.271554590e-01f, -8.866120120e-02f, 6.280594970e-03f, -3.400175270e-02f, 9.689652170e-02f, 1.912065970e-02f, 2.868551200e-02f, -5.087066070e-02f, -1.008633150e-01f, 1.264159680e-01f, -3.437878940e-02f, 1.122212480e-01f, 2.244176270e-01f, -1.560315400e-02f, -1.396402720e-01f, 8.870948100e-02f, 1.517778080e-02f, 9.170300510e-02f, 5.933799970e-02f, 1.875974800e-02f, -2.189099230e-02f, -3.742380810e-02f, -5.490169670e-02f, 3.714400530e-02f, 8.994057770e-02f, -9.548433870e-02f, -8.720246700e-02f, 2.787738850e-02f, 1.124651170e-03f, -4.141348230e-02f, 2.374341040e-01f, -1.108816340e-01f, -9.165960550e-02f, -7.701619710e-02f, -9.970317780e-02f, 4.768037420e-02f, -4.788947480e-02f, -9.374939650e-02f, -1.605349630e-01f, 3.228322840e-03f, -1.303637960e-02f, -1.500964910e-01f, 1.024913860e-01f, 1.448011400e-01f, 3.235363590e-02f, 1.919796020e-01f, 7.581515230e-03f, 3.976725040e-02f, -9.168303800e-04f, -1.227087450e-01f, -2.904425560e-02f, 8.946036540e-02f, -9.952373800e-02f, -9.341205660e-02f, 2.103281620e-01f, -1.720785720e-02f, -7.589480280e-02f, -5.995977670e-02f, 3.599463030e-02f, -1.051315220e-01f, 4.431034620e-02f, -1.844771210e-02f, -7.442326840e-02f, -9.512269490e-02f, 7.866491380e-02f, 8.241268990e-02f, 1.042119790e-01f, 2.249114810e-01f, 2.686936410e-02f, -2.787504720e-02f, -6.946990640e-02f, 5.514902990e-02f, -4.327293110e-02f, -8.140096060e-02f, 8.479646590e-02f, -8.408614240e-02f, -6.723855440e-02f, 1.144473550e-01f, 8.816450830e-02f, -6.269980970e-02f, 3.697051110e-01f, -1.847381700e-02f, -6.396971640e-02f, -6.870685520e-02f, 1.168521470e-03f, -8.019898830e-02f, -3.771951790e-02f, -1.842122710e-02f, -1.730052010e-02f, 7.879125320e-02f, -4.118991270e-02f, 7.836011790e-02f, -1.304978280e-01f, -5.360035600e-02f, 4.305479300e-02f, -2.877660280e-02f, 5.960984160e-03f, 2.062289280e-04f, -2.564256080e-02f, -7.525652650e-02f, 4.964661970e-02f, -5.511363970e-02f, -4.040697120e-03f, 1.153849900e-02f, -8.263261620e-02f, 1.394031940e-01f, -8.549568800e-02f, -6.528089200e-02f, -1.391123680e-01f, -1.902377230e-02f, 1.481448300e-02f, -8.085408800e-02f, -1.127665490e-01f, 2.191224550e-01f, -7.444956890e-02f, 1.774810550e-01f, 1.615892650e-01f, 2.879012230e-01f, 4.441858830e-02f, 1.056471990e-01f, -5.889111380e-02f, -2.620746010e-02f, -4.189019280e-02f, 3.620886060e-02f, 2.013681530e-01f, -5.401180680e-02f, 2.936587300e-02f, -1.150456890e-01f, 2.440494670e-02f, 6.903459880e-02f, -2.429814080e-02f, -1.576917990e-02f, 1.413593140e-01f, 2.568911300e-03f, 5.968121810e-03f, -2.959442320e-02f, -2.597908680e-02f, -1.116742790e-01f, -6.542944900e-02f, 1.491622070e-02f, 3.912554310e-02f, 1.322419350e-01f, -7.944831990e-02f, -8.650738740e-03f, 2.682724300e-01f, 2.093576190e-01f, -1.720657920e-03f, 4.197121040e-02f, -9.243533130e-04f, -1.150058580e-01f, 6.995149700e-02f, 5.110480640e-02f, -5.880141630e-02f, -5.392599110e-02f, -8.733739700e-02f, -8.471701290e-03f, -1.172958240e-01f, 2.307102270e-02f, -3.946545350e-02f, 9.989400200e-02f, 4.411069300e-02f, -2.961303480e-02f, 5.236579110e-03f, -1.101948100e-01f, -7.748529310e-02f, 2.640082870e-02f, -7.413662040e-03f, -5.761666970e-02f, -4.298925770e-02f, 1.182575800e-02f, 1.745466140e-01f, 9.983242300e-02f, 3.744544090e-02f, -7.487962390e-02f, 3.003230880e-02f, 3.932110590e-02f, 3.066428380e-02f, -1.568822380e-02f, 4.057940240e-01f, -6.082238630e-02f, 3.582233190e-02f, -5.215014140e-02f, 4.779703170e-02f, -5.205507580e-02f, 1.052134410e-01f, 5.348921290e-03f, -2.573925260e-02f, 8.591577410e-02f, -5.934751780e-02f, 5.335090100e-05f, -7.897897800e-02f, 3.183321650e-02f, 1.513454620e-01f, 1.151003610e-01f, -4.868426170e-02f, -1.400890020e-02f, 6.893316660e-02f, -8.643392470e-02f, 6.631356480e-02f, 1.559772640e-01f, -9.302395400e-03f, 2.842053960e-02f, 2.670123990e-02f, 7.351178680e-02f, 3.578096030e-01f, -5.699503240e-04f, 1.377376150e-03f, -4.376965020e-02f, -2.249882740e-02f, -5.302857240e-02f, 7.452938710e-02f, 1.756268740e-02f, 2.335802020e-01f, 9.162574080e-03f, 8.864974950e-04f, -1.297923330e-01f, -4.968820510e-02f, -7.803303000e-02f, -1.081567160e-02f, -9.344514450e-03f, -3.257972370e-02f, 7.507063560e-04f, -7.428985090e-02f, -7.236532870e-02f, -1.574610550e-02f, -3.782686220e-02f, 3.563578940e-03f, 2.198065220e-01f, -1.166439060e-02f, 2.578300420e-02f, -6.398602580e-02f, -1.160787190e-01f, -8.409061470e-03f, -1.801835190e-02f, 1.670398860e-01f, 1.440007590e-03f, -1.006812080e-01f, -6.427028030e-02f, 1.984949040e-02f, -9.280243510e-02f, -7.372713830e-02f, -2.356202710e-02f, -1.863621180e-02f, -1.585755030e-03f, 1.063985900e-01f, 6.869084390e-02f, 6.279184670e-02f, -4.561851550e-02f, 7.861099390e-02f, 2.272461170e-02f, 6.894712900e-02f, -2.658324130e-02f, 1.111288220e-01f, 2.252129320e-01f, -9.162241960e-02f, 2.636584040e-01f, -2.007349770e-02f, 2.991273700e-01f, 4.852047940e-02f, 1.772097200e-01f, -1.993905750e-02f, -5.048531670e-02f, 2.922823470e-02f, -7.068035750e-02f, -1.362551560e-02f, 6.050760860e-03f, -8.137370460e-03f, 4.164618250e-02f, -3.904518860e-02f, -6.593674420e-02f, 1.091916560e-01f, -3.413718570e-02f, -1.191701270e-02f, -7.064440840e-02f, 2.031148780e-02f, -3.216515110e-02f, -4.252276940e-02f, -6.114596500e-03f, -3.546971080e-02f, 4.005719350e-02f, -1.066699180e-01f, 1.804159950e-02f, 3.549709540e-02f, 3.829110040e-02f, -5.691817780e-02f, -1.407037950e-02f, -1.324376560e-02f, 1.715299860e-02f, 5.352770160e-02f, -2.119684030e-02f, -3.755963220e-02f, 5.963591860e-02f, -7.955341040e-02f, 3.408561000e-03f, 5.806631870e-03f, -5.842561270e-02f, -6.336913260e-02f, 4.028692470e-02f, 1.327877940e-01f, -2.161386240e-02f, -1.133042480e-02f, -2.942236510e-02f, -8.159575610e-02f, -1.305842400e-01f, -5.883112920e-02f, -9.134102610e-02f, -4.742389540e-02f, -6.720266490e-02f, 2.600918710e-02f, 6.779374090e-03f, 4.691093860e-01f, -8.208854120e-03f, 8.709223570e-02f, -2.126725760e-02f, -5.166615170e-02f, 1.186293440e-01f, -8.910043540e-02f, -4.917616020e-02f, -1.327888480e-02f, -2.038091790e-02f, -7.906661930e-02f, -1.243097410e-01f, 9.756176170e-02f, -4.531233760e-02f, -4.368125650e-02f, 9.138934310e-03f, 4.180051390e-01f, -7.670424880e-02f, -5.062558130e-02f, -3.898516300e-02f, -6.944754710e-02f, 4.627671090e-02f, -1.010536220e-02f, 1.465563770e-01f, -3.216226400e-02f, -4.859356950e-02f, -2.277551780e-02f, -7.534851130e-02f, 7.504246380e-02f, 1.964211760e-01f, 2.051525940e-02f, 1.410817210e-01f, 3.550156950e-02f, -6.680908050e-02f, -2.228910100e-02f, -4.755095760e-02f, 1.960803200e-02f, 1.744623330e-01f, -4.983681810e-02f, -9.815025140e-03f, -1.591109110e-02f, 5.933324990e-02f, 3.494029860e-02f, 4.876928630e-01f, -3.260122240e-02f, -2.773955460e-02f, 4.531113060e-02f, -2.601506190e-02f, 6.197831400e-02f, 7.908661850e-03f, 1.201164650e-01f, -7.804465290e-02f, 4.729482160e-02f, 3.946654500e-03f, 1.405550910e-02f, 6.452432830e-03f, -5.226561050e-02f, 1.378187720e-02f, -4.528855160e-02f, 1.030741560e-01f, -2.591849490e-02f, -1.491322650e-02f, 1.033917260e-02f, -4.467248920e-03f, 7.640033960e-03f, -6.496197730e-02f, 6.625939910e-02f, -8.875214300e-02f, -4.614113640e-02f, -7.134793700e-02f, -6.804838030e-02f, -1.904561560e-02f, 1.142980830e-01f, 4.949881880e-02f, 6.226904310e-02f, 1.509440690e-02f, 8.764223750e-02f, -2.751263980e-02f, 1.677665860e-02f, 2.681801020e-01f, 8.402796830e-02f, -8.374650780e-02f, -3.472946210e-02f, -6.746055930e-02f, -1.051484050e-01f, 6.460615990e-02f, -1.446441560e-01f, -9.775189310e-02f, 9.975289550e-02f, 2.869508420e-02f, -2.225310910e-02f, 5.721596070e-03f, -8.795169180e-03f, -6.849917020e-02f, -1.349763270e-01f, 1.121412520e-01f, 6.116457660e-02f, 5.888672920e-02f, 3.050266300e-03f, 7.365467960e-03f, 2.887176280e-01f, -8.632949730e-02f, 1.344059040e-02f, -8.181783550e-02f, -4.781216010e-02f, 8.790700880e-02f, -2.742723190e-02f, 5.098045990e-02f, -7.549532500e-02f, 1.125919670e-01f, 1.481312510e-01f, -1.637598500e-02f, 1.773988160e-01f, 9.625868500e-02f, -4.980068650e-02f, -7.231190060e-02f, 3.238162030e-02f, 1.001678780e-01f, -1.204307300e-01f, 1.527729180e-01f, -7.893680780e-02f, -6.735354660e-02f, -3.100181230e-03f, -1.168304160e-01f, 1.038345550e-01f, -7.804526390e-02f, -1.479594560e-01f, -6.633823360e-02f, -4.472670610e-03f, 4.052570090e-03f, -7.655723390e-02f, -1.161901880e-01f, 1.755278710e-01f, 8.769305790e-02f, 1.387942730e-01f, 2.335315760e-02f, 1.729834970e-01f, -1.792439820e-02f, -5.260344970e-02f, -7.620622960e-02f, -5.394041170e-02f, -7.269765440e-02f, -3.281053530e-02f, 5.475912240e-02f, 7.734664530e-02f, 1.198655520e-01f, -9.573853760e-02f, -4.717905450e-02f, 2.035591010e-02f, -4.380939530e-02f, -2.260988020e-02f}; + + +extern "C" void lapis_initialize() { + { + Kokkos::View__constant_72x64xf32_host(__constant_72x64xf32_initial); + __constant_72x64xf32 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_72x64xf32")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_72x64xf32, __constant_72x64xf32_host); + } + { + Kokkos::View__constant_72xf32_0_host(__constant_72xf32_0_initial); + __constant_72xf32_0 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_72xf32_0")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_72xf32_0, __constant_72xf32_0_host); + } + { + Kokkos::View__constant_64xf32_0_host(__constant_64xf32_0_initial); + __constant_64xf32_0 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_64xf32_0")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_64xf32_0, __constant_64xf32_0_host); + } + { + Kokkos::View__constant_72xf32_host(__constant_72xf32_initial); + __constant_72xf32 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_72xf32")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_72xf32, __constant_72xf32_host); + } + { + Kokkos::View__constant_64xf32_host(__constant_64xf32_initial); + __constant_64xf32 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_64xf32")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_64xf32, __constant_64xf32_host); + } + { + Kokkos::View__constant_64x72xf32_0_host(__constant_64x72xf32_0_initial); + __constant_64x72xf32_0 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_64x72xf32_0")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_64x72xf32_0, __constant_64x72xf32_0_host); + } + { + Kokkos::View__constant_144x64xf32_host(__constant_144x64xf32_initial); + __constant_144x64xf32 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_144x64xf32")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_144x64xf32, __constant_144x64xf32_host); + } + { + Kokkos::View__constant_64x72xf32_host(__constant_64x72xf32_initial); + __constant_64x72xf32 = Kokkos::View(Kokkos::view_alloc(Kokkos::WithoutInitializing, "__constant_64x72xf32")); + Kokkos::deep_copy(Kokkos::DefaultExecutionSpace(), __constant_64x72xf32, __constant_64x72xf32_host); + } +} + +extern "C" void lapis_finalize() +{ + __constant_72x64xf32 = Kokkos::View(); + __constant_72xf32_0 = Kokkos::View(); + __constant_64xf32_0 = Kokkos::View(); + __constant_72xf32 = Kokkos::View(); + __constant_64xf32 = Kokkos::View(); + __constant_64x72xf32_0 = Kokkos::View(); + __constant_144x64xf32 = Kokkos::View(); + __constant_64x72xf32 = Kokkos::View(); +} diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.hpp b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.hpp new file mode 100644 index 000000000000..909c2dab5e1e --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/cld_frac_net.hpp @@ -0,0 +1,371 @@ +#ifndef LAPIS_MODULE_H +#define LAPIS_MODULE_H +#include +extern Kokkos::View __constant_72x64xf32; +extern Kokkos::View __constant_72xf32_0; +extern Kokkos::View __constant_64xf32_0; +extern Kokkos::View __constant_72xf32; +extern Kokkos::View __constant_64xf32; +extern Kokkos::View __constant_64x72xf32_0; +extern Kokkos::View __constant_144x64xf32; +extern Kokkos::View __constant_64x72xf32; +struct GlobalViews_forward { + GlobalViews_forward() { + m__constant_72x64xf32 = __constant_72x64xf32; + m__constant_72xf32_0 = __constant_72xf32_0; + m__constant_64xf32_0 = __constant_64xf32_0; + m__constant_72xf32 = __constant_72xf32; + m__constant_64xf32 = __constant_64xf32; + m__constant_64x72xf32_0 = __constant_64x72xf32_0; + m__constant_144x64xf32 = __constant_144x64xf32; + m__constant_64x72xf32 = __constant_64x72xf32; + } + Kokkos::View m__constant_72x64xf32; + Kokkos::View m__constant_72xf32_0; + Kokkos::View m__constant_64xf32_0; + Kokkos::View m__constant_72xf32; + Kokkos::View m__constant_64xf32; + Kokkos::View m__constant_64x72xf32_0; + Kokkos::View m__constant_144x64xf32; + Kokkos::View m__constant_64x72xf32; +}; +// Return the total amount of scratch that the function uses +// This is the upper bound to what forward_L0_scratch_required can return +KOKKOS_INLINE_FUNCTION constexpr int forward_total_scratch_required() { + return 2024; +} + +// Find L1 address shift: for allocations spilling into level 1 scratch, +// this is subtracted from the allocation address to find its relative address within L1. +KOKKOS_INLINE_FUNCTION constexpr int forward_L1_shift(int L0_scratch_max) { + int tmp = 2024; + if(328 > L0_scratch_max && 72 < tmp) + tmp = 72; + if(584 > L0_scratch_max && 328 < tmp) + tmp = 328; + if(840 > L0_scratch_max && 584 < tmp) + tmp = 584; + if(872 > L0_scratch_max && 584 < tmp) + tmp = 584; + if(1160 > L0_scratch_max && 872 < tmp) + tmp = 872; + if(1160 > L0_scratch_max && 872 < tmp) + tmp = 872; + if(72 > L0_scratch_max && 0 < tmp) + tmp = 0; + if(1448 > L0_scratch_max && 872 < tmp) + tmp = 872; + if(2024 > L0_scratch_max && 1448 < tmp) + tmp = 1448; + if(1448 > L0_scratch_max && 872 < tmp) + tmp = 872; + return tmp; +} + +// Find the actual level 0 scratch required by the function, assuming this limit. +// The answer will be at most L0_scratch_max but never larger. +KOKKOS_INLINE_FUNCTION constexpr int forward_L0_scratch_required(int L0_scratch_max) { + int tmp = 0; + if(328 <= L0_scratch_max && 328 > tmp) + tmp = 328; + if(584 <= L0_scratch_max && 584 > tmp) + tmp = 584; + if(840 <= L0_scratch_max && 840 > tmp) + tmp = 840; + if(872 <= L0_scratch_max && 872 > tmp) + tmp = 872; + if(1160 <= L0_scratch_max && 1160 > tmp) + tmp = 1160; + if(1160 <= L0_scratch_max && 1160 > tmp) + tmp = 1160; + if(72 <= L0_scratch_max && 72 > tmp) + tmp = 72; + if(1448 <= L0_scratch_max && 1448 > tmp) + tmp = 1448; + if(2024 <= L0_scratch_max && 2024 > tmp) + tmp = 2024; + if(1448 <= L0_scratch_max && 1448 > tmp) + tmp = 1448; + return tmp; +} + +// Find the actual level 1 scratch required by the function, assuming this limit for L0 scratch. +// This has no strict upper bound. +KOKKOS_INLINE_FUNCTION constexpr int forward_L1_scratch_required(int L0_scratch_max) { + return 2024 - forward_L1_shift(L0_scratch_max); +} + +template +KOKKOS_INLINE_FUNCTION void forward(const typename Kokkos::TeamPolicy::member_type& team, const GlobalViews_forward& globals, const ViewArg0& v1, const ViewArg1& v2, const ViewArg2& v3, const ViewArg3& v4, char* scratch0, char* scratch1) { + constexpr int l1_cutoff = forward_L1_shift(L0_scratch_max); + const auto& v5 = globals.m__constant_64x72xf32; + const auto& v6 = globals.m__constant_144x64xf32; + const auto& v7 = globals.m__constant_64x72xf32_0; + const auto& v8 = globals.m__constant_64xf32; + const auto& v9 = globals.m__constant_72xf32; + const auto& v10 = globals.m__constant_64xf32_0; + const auto& v11 = globals.m__constant_72xf32_0; + const auto& v12 = globals.m__constant_72x64xf32; + constexpr bool v13_spill = 328 > L0_scratch_max; + Kokkos::View> v13((float*) (v13_spill ? (scratch1 + 72 - l1_cutoff) : (scratch0 + 72))); + ; + constexpr bool v14_spill = 584 > L0_scratch_max; + Kokkos::View> v14((float*) (v14_spill ? (scratch1 + 328 - l1_cutoff) : (scratch0 + 328))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 64), + [=](size_t v15) { + v14(v15) = 0.0e+00f; + }); + team.team_barrier(); + constexpr bool v16_spill = 840 > L0_scratch_max; + Kokkos::View> v16((float*) (v16_spill ? (scratch1 + 584 - l1_cutoff) : (scratch0 + 584))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 64), + [=](size_t v17) { + float v18 = v14(v17); + v16(v17) = v18; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, 0, 64), + [=](size_t v19) { + float v20 = v16(v19); + float v21; + Kokkos::parallel_reduce(Kokkos::ThreadVectorRange(team, 0, 72), + [=](size_t v22, float& lreduce1) { + float v23 = v3(v22); + float v24 = v12(v22, v19); + float v25 = v23 * v24; + float v26 = lreduce1 + v25; + lreduce1 = v26; + ; + }, (v21)); + Kokkos::Sum v21_joiner(v21); + v21_joiner.join(v21, v20); + ; + Kokkos::single(Kokkos::PerThread(team), [&]() { + v16(v19) = v21; + }); + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 64), + [=](size_t v27) { + float v28 = v16(v27); + float v29 = v8(v27); + float v30 = v28 + v29; + v13(v27) = v30; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 64), + [=](size_t v31) { + float v32 = v13(v31); + bool v33 = (Kokkos::isnan(v32) || Kokkos::isnan(0.0e+00f)) || (v32 > 0.0e+00f); + float v34 = v33? v32 : 0.0e+00f; + v13(v31) = v34; + }); + team.team_barrier(); + constexpr bool v35_spill = 872 > L0_scratch_max; + Kokkos::View> v35((float*) (v35_spill ? (scratch1 + 584 - l1_cutoff) : (scratch0 + 584))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v36) { + v35(v36) = 0.0e+00f; + }); + team.team_barrier(); + constexpr bool v37_spill = 1160 > L0_scratch_max; + Kokkos::View> v37((float*) (v37_spill ? (scratch1 + 872 - l1_cutoff) : (scratch0 + 872))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v38) { + float v39 = v35(v38); + v37(v38) = v39; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, 0, 72), + [=](size_t v40) { + float v41 = v37(v40); + float v42; + Kokkos::parallel_reduce(Kokkos::ThreadVectorRange(team, 0, 64), + [=](size_t v43, float& lreduce1) { + float v44 = v13(v43); + float v45 = v7(v43, v40); + float v46 = v44 * v45; + float v47 = lreduce1 + v46; + lreduce1 = v47; + ; + }, (v42)); + Kokkos::Sum v42_joiner(v42); + v42_joiner.join(v42, v41); + ; + Kokkos::single(Kokkos::PerThread(team), [&]() { + v37(v40) = v42; + }); + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v48) { + float v49 = v37(v48); + float v50 = v9(v48); + float v51 = v49 + v50; + v2(v48) = v51; + }); + team.team_barrier(); + constexpr bool v52_spill = 1160 > L0_scratch_max; + Kokkos::View> v52((float*) (v52_spill ? (scratch1 + 872 - l1_cutoff) : (scratch0 + 872))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v53) { + float v54 = v2(v53); + float v55 = -v54; + float v56 = Kokkos::exp(v55); + float v57 = v56 + 1.000000000e+00f; + float v58 = 1.000000000e+00f / v57; + v52(v53) = v58; + }); + team.team_barrier(); + constexpr bool v59_spill = 72 > L0_scratch_max; + Kokkos::View> v59((bool*) (v59_spill ? (scratch1 + 0 - l1_cutoff) : (scratch0 + 0))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v60) { + float v61 = v52(v60); + double v62 = (double) v61; + bool v63 = (v62 > 5.00000000000000000e-01); + v59(v60) = v63; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v64) { + bool v65 = v59(v64); + float v66 = (float) v65; + v2(v64) = v66; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v67) { + float v68 = v2(v67); + float v69 = v52(v67); + float v70 = v68 - v69; + v2(v67) = v70; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v71) { + float v72 = v2(v71); + float v73 = v52(v71); + float v74 = v72 + v73; + v1(v71) = v74; + }); + team.team_barrier(); + constexpr bool v75_spill = 1448 > L0_scratch_max; + Kokkos::View> v75((float*) (v75_spill ? (scratch1 + 872 - l1_cutoff) : (scratch0 + 872))); + ; + constexpr bool v76_spill = 2024 > L0_scratch_max; + Kokkos::View> v76((float*) (v76_spill ? (scratch1 + 1448 - l1_cutoff) : (scratch0 + 1448))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 144), + [=](size_t v77) { + float v78 = v75(v77); + v76(v77) = v78; + }); + team.team_barrier(); + Kokkos::LayoutStride v79_layout(72, 1); + Kokkos::View v79(v76.data() + 0, v79_layout); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v80) { + float v81 = v4(v80); + v79(v80) = v81; + }); + team.team_barrier(); + constexpr bool v82_spill = 1448 > L0_scratch_max; + Kokkos::View> v82((float*) (v82_spill ? (scratch1 + 872 - l1_cutoff) : (scratch0 + 872))); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 144), + [=](size_t v83) { + float v84 = v76(v83); + v82(v83) = v84; + }); + team.team_barrier(); + Kokkos::LayoutStride v85_layout(72, 1); + Kokkos::View v85(v82.data() + 72, v85_layout); + ; + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v86) { + float v87 = v1(v86); + v85(v86) = v87; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, 0, 64), + [=](size_t v88) { + float v89 = v14(v88); + float v90; + Kokkos::parallel_reduce(Kokkos::ThreadVectorRange(team, 0, 144), + [=](size_t v91, float& lreduce1) { + float v92 = v82(v91); + float v93 = v6(v91, v88); + float v94 = v92 * v93; + float v95 = lreduce1 + v94; + lreduce1 = v95; + ; + }, (v90)); + Kokkos::Sum v90_joiner(v90); + v90_joiner.join(v90, v89); + ; + Kokkos::single(Kokkos::PerThread(team), [&]() { + v14(v88) = v90; + }); + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 64), + [=](size_t v96) { + float v97 = v14(v96); + float v98 = v10(v96); + float v99 = v97 + v98; + v13(v96) = v99; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 64), + [=](size_t v100) { + float v101 = v13(v100); + bool v102 = (Kokkos::isnan(v101) || Kokkos::isnan(0.0e+00f)) || (v101 > 0.0e+00f); + float v103 = v102? v101 : 0.0e+00f; + v13(v100) = v103; + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, 0, 72), + [=](size_t v104) { + float v105 = v35(v104); + float v106; + Kokkos::parallel_reduce(Kokkos::ThreadVectorRange(team, 0, 64), + [=](size_t v107, float& lreduce1) { + float v108 = v13(v107); + float v109 = v5(v107, v104); + float v110 = v108 * v109; + float v111 = lreduce1 + v110; + lreduce1 = v111; + ; + }, (v106)); + Kokkos::Sum v106_joiner(v106); + v106_joiner.join(v106, v105); + ; + Kokkos::single(Kokkos::PerThread(team), [&]() { + v35(v104) = v106; + }); + }); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0, 72), + [=](size_t v112) { + float v113 = v35(v112); + float v114 = v11(v112); + float v115 = v113 + v114; + v2(v112) = v115; + }); + team.team_barrier(); + return; +} + + + +extern "C" void lapis_initialize(); +extern "C" void lapis_finalize(); +#endif diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp index b2ae4c1e1622..d5134b79ce61 100644 --- a/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp @@ -1,6 +1,9 @@ #include "eamxx_cld_frac_net_process_interface.hpp" #include "share/atm_process/atmosphere_process_pyhelpers.hpp" +#include "cld_frac_net.hpp" + +#include namespace scream { @@ -8,9 +11,12 @@ namespace scream CldFracNet::CldFracNet (const ekat::Comm& comm, const ekat::ParameterList& params) : AtmosphereProcess(comm, params) { - EKAT_REQUIRE_MSG( has_py_module(), - "[CldFracNet] Error! Something went wrong while initializing the python module.\n"); - // Nothing to do here + if (m_params.get("emulator")=="lapis") { + lapis_initialize(); + } else { + EKAT_REQUIRE_MSG( has_py_module(), + "[CldFracNet] Error! Something went wrong while initializing the python module.\n"); + } } void CldFracNet::set_grids(const std::shared_ptr grids_manager) @@ -33,7 +39,9 @@ void CldFracNet::set_grids(const std::shared_ptr grids_manag void CldFracNet::initialize_impl (const RunType /* run_type */) { - py_module_call("init"); + if (m_params.get("emulator")!="lapis") { + py_module_call("init"); + } } void CldFracNet::run_impl (const double /* dt */) @@ -45,21 +53,62 @@ void CldFracNet::run_impl (const double /* dt */) auto ice = get_field_out("cldfrac_ice"); auto tot = get_field_out("cldfrac_tot"); + if (m_params.get("emulator")=="lapis") { + // LAPIS-generated emulator is compiled in and was requested. Use it + using KT = KokkosTypes; + using ExeSpace = typename KT::ExeSpace; + using TPF = ekat::TeamPolicyFactory; + using MemberType = typename KT::MemberType; + + const auto dims = qi.get_header().get_identifier().get_layout().dims(); + auto policy = TPF::get_default_team_policy(dims[0], dims[1]); + + auto qi_v = qi.get_view(); + auto liq_v = liq.get_view(); + auto ice_v = ice.get_view(); + auto tot_v = tot.get_view(); + + constexpr int max_shared = 4096; + // This is a number that fits within all modern + // Determine L0 and L1 per-team scratch size + constexpr int scratch0_required = forward_L0_scratch_required(max_shared); + constexpr int scratch1_required = forward_L1_scratch_required(max_shared); + GlobalViews_forward globalViews; + policy.set_scratch_size(0, Kokkos::PerTeam(scratch0_required)); + policy.set_scratch_size(1, Kokkos::PerTeam(scratch1_required)); + + // Execute the appropriate specialization based on shared amount + auto lambda = KOKKOS_LAMBDA (const MemberType& team) { + int icol = team.league_rank(); + auto qi_col = ekat::subview(qi_v,icol); + auto liq_col = ekat::subview(liq_v,icol); + auto ice_col = ekat::subview(ice_v,icol); + auto tot_col = ekat::subview(tot_v,icol); + + char* scratch0 = (char*)(team.team_scratch(0).get_shmem(scratch0_required)); + char* scratch1 = (char*)(team.team_scratch(1).get_shmem(scratch1_required)); + + forward(team, globalViews, ice_col, tot_col, qi_col, liq_col, scratch0, scratch1); + }; + + Kokkos::parallel_for(policy,lambda); } else { - auto py_qi = get_py_field_dev("qi"); - auto py_liq = get_py_field_dev("cldfrac_liq"); - auto py_ice = get_py_field_dev("cldfrac_ice"); - auto py_tot = get_py_field_dev("cldfrac_tot"); + auto py_qi = get_py_field_dev("qi"); + auto py_liq = get_py_field_dev("cldfrac_liq"); + auto py_ice = get_py_field_dev("cldfrac_ice"); + auto py_tot = get_py_field_dev("cldfrac_tot"); - double ice_threshold = m_params.get("ice_cloud_threshold"); + double ice_threshold = m_params.get("ice_cloud_threshold"); - py_module_call("forward",ice_threshold,py_qi,py_liq,py_ice,py_tot); + py_module_call("forward",ice_threshold,py_qi,py_liq,py_ice,py_tot); } } void CldFracNet::finalize_impl() { - // Nothing to do here + if (m_params.get("emulator")=="lapis") { + lapis_finalize(); + } } } // namespace scream diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index d1153d94fc02..55a03f5f959c 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -99,5 +99,19 @@ if (EAMXX_ENABLE_PYTHON) EXE_ARGS "--args -ifile=input_pyml.yaml" LABELS cld_fraction physics FIXTURES_SETUP cldfrac_pyml) + + # Create test that runs lapis-generated emulator + unset (PY_MODULE_NAME) + set (POSTFIX ml_cpp) + set (WHICH_EMULATOR lapis) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/input_ml_cpp.yaml) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml + ${CMAKE_CURRENT_BINARY_DIR}/output_${POSTFIX}.yaml) + + CreateUnitTestFromExec(cld_frac_net_cpp cld_frac_net_standalone + EXE_ARGS "--args -ifile=input_cppml.yaml" + LABELS cld_fraction + FIXTURES_SETUP cldfrac_cppml) endif() endif() From 5378bf6df57c23c0ab95f4e4c31ebd32f454b598 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 17:34:47 -0700 Subject: [PATCH 176/398] EAMxx: better structure the cld frac net process and unit tests --- .../eamxx_cld_frac_net_process_interface.cpp | 22 ++++- .../cld_fraction/CMakeLists.txt | 87 +++++++++++++------ .../single-process/cld_fraction/input_ml.yaml | 4 +- .../cld_fraction/output_ml.yaml | 13 +++ 4 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 components/eamxx/tests/single-process/cld_fraction/output_ml.yaml diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp index d5134b79ce61..5a00600a4e1f 100644 --- a/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/eamxx_cld_frac_net_process_interface.cpp @@ -1,6 +1,8 @@ #include "eamxx_cld_frac_net_process_interface.hpp" +#ifdef EAMXX_HAS_PYTHON #include "share/atm_process/atmosphere_process_pyhelpers.hpp" +#endif #include "cld_frac_net.hpp" #include @@ -13,10 +15,16 @@ CldFracNet::CldFracNet (const ekat::Comm& comm, const ekat::ParameterList& param { if (m_params.get("emulator")=="lapis") { lapis_initialize(); - } else { + } +#ifdef EAMXX_HAS_PYTHON + else if (m_params.get("emulator")=="pytorch") { EKAT_REQUIRE_MSG( has_py_module(), "[CldFracNet] Error! Something went wrong while initializing the python module.\n"); } +#endif + else { + EKAT_ERROR_MSG("[CldFracNet] Error! No valid emulator type requested.\n"); + } } void CldFracNet::set_grids(const std::shared_ptr grids_manager) @@ -39,9 +47,11 @@ void CldFracNet::set_grids(const std::shared_ptr grids_manag void CldFracNet::initialize_impl (const RunType /* run_type */) { - if (m_params.get("emulator")!="lapis") { +#ifdef EAMXX_HAS_PYTHON + if (m_params.get("emulator")=="pytorch") { py_module_call("init"); } +#endif } void CldFracNet::run_impl (const double /* dt */) @@ -92,7 +102,9 @@ void CldFracNet::run_impl (const double /* dt */) }; Kokkos::parallel_for(policy,lambda); - } else { + } +#ifdef EAMXX_HAS_PYTHON + else if (m_params.get("emulator")=="pytorch") { auto py_qi = get_py_field_dev("qi"); auto py_liq = get_py_field_dev("cldfrac_liq"); auto py_ice = get_py_field_dev("cldfrac_ice"); @@ -102,6 +114,10 @@ void CldFracNet::run_impl (const double /* dt */) py_module_call("forward",ice_threshold,py_qi,py_liq,py_ice,py_tot); } +#endif + else { + EKAT_ERROR_MSG("[CldFracNet] Error! No valid emulator type requested.\n"); + } } void CldFracNet::finalize_impl() diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index 55a03f5f959c..50ba9742624e 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -1,26 +1,35 @@ include (ScreamUtils) -# Set AD configurable options +# Set common AD configurable options set (NUM_STEPS 1) set (ATM_TIME_STEP 1800) set (RUN_T0 2021-10-12-45000) +# Create executable for CldFraction standalone +CreateADUnitTestExec(cld_fraction_standalone + LIBS cld_fraction) + +##################################### +# CldFraction (CPP) # +##################################### + # Configure yaml files to run directory -set (PROCESS_NAME cld_fraction) set (POSTFIX cpp) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml ${CMAKE_CURRENT_BINARY_DIR}/input_cpp.yaml) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml ${CMAKE_CURRENT_BINARY_DIR}/output_cpp.yaml) -# Test the process -CreateADUnitTest(cld_fraction_standalone +CreateUnitTestFromExec(cld_fraction_standalone_cpp cld_fraction_standalone EXE_ARGS "--args -ifile=input_cpp.yaml" - LIBS cld_fraction LABELS cld_fraction physics FIXTURES_SETUP cldfrac_cpp) if (EAMXX_ENABLE_PYTHON) + ##################################### + # CldFraction (PY) # + ##################################### + include (BuildCprnc) BuildCprnc() @@ -77,10 +86,13 @@ if (EAMXX_ENABLE_PYTHON) set_tests_properties(${TEST_NAME} PROPERTIES LABELS "cldfrac;infrastructure" FIXTURES_REQUIRED "cldfrac_cupy;cldfrac_cpp") - endif() if (NOT EAMXX_ENABLE_GPU) + ##################################### + # CldFracNet (PY) # + ##################################### + # Create executable that runs cld_frac_net emulator CreateADUnitTestExec(cld_frac_net_standalone LIBS cld_frac_net) @@ -88,30 +100,53 @@ if (EAMXX_ENABLE_PYTHON) # Test the process with python ml emulator set (PY_MODULE_NAME "cld_frac_net") set (PY_MODULE_PATH ${SCREAM_BASE_DIR}/src/physics/cld_fraction/cld_frac_net) - set (POSTFIX ml_py) - set (WHICH_EMULATOR python) + set (POSTFIX py) + set (EMULATOR pytorch) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml - ${CMAKE_CURRENT_BINARY_DIR}/input_ml_py.yaml) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml - ${CMAKE_CURRENT_BINARY_DIR}/output_${POSTFIX}.yaml) + ${CMAKE_CURRENT_BINARY_DIR}/input_ml_${POSTFIX}.yaml) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/output_ml_${POSTFIX}.yaml) - CreateUnitTestFromExec(cld_frac_net_py cld_frac_net_standalone - EXE_ARGS "--args -ifile=input_pyml.yaml" + CreateUnitTestFromExec(cld_frac_net_${POSTFIX} cld_frac_net_standalone + EXE_ARGS "--args -ifile=input_ml_${POSTFIX}.yaml" LABELS cld_fraction physics - FIXTURES_SETUP cldfrac_pyml) + FIXTURES_SETUP cld_frac_net_${POSTFIX}) - # Create test that runs lapis-generated emulator - unset (PY_MODULE_NAME) - set (POSTFIX ml_cpp) - set (WHICH_EMULATOR lapis) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml - ${CMAKE_CURRENT_BINARY_DIR}/input_ml_cpp.yaml) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output.yaml - ${CMAKE_CURRENT_BINARY_DIR}/output_${POSTFIX}.yaml) + # So that we know, below, that we can run cpp-vs-py test for cld_frac_net output + set (HAS_CLD_FRAC_NET_PY TRUE) + endif() +endif() - CreateUnitTestFromExec(cld_frac_net_cpp cld_frac_net_standalone - EXE_ARGS "--args -ifile=input_cppml.yaml" - LABELS cld_fraction - FIXTURES_SETUP cldfrac_cppml) + +if (NOT EAMXX_ENABLE_GPU) + ##################################### + # CldFracNet (CPP) # + ##################################### + + # Create test that runs lapis-generated emulator + unset (PY_MODULE_NAME) + set (POSTFIX cpp) + set (EMULATOR lapis) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/input_ml_${POSTFIX}.yaml) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/output_ml_${POSTFIX}.yaml) + + CreateUnitTestFromExec(cld_frac_net_${POSTFIX} cld_frac_net_standalone + EXE_ARGS "--args -ifile=input_ml_${POSTFIX}.yaml" + LABELS cld_fraction + FIXTURES_SETUP cld_frac_net_${POSTFIX}) + + if (HAS_CLD_FRAC_NET_PY) + # Compare output of py and cpp tests of cld_frac_net + set (SRC_FILE "cld_frac_net_standalone_output_cpp.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") + set (TGT_FILE "cld_frac_net_standalone_output_py.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") + set (TEST_NAME cld_frac_net_standalone_cpp_vs_py) + add_test (NAME ${TEST_NAME} + COMMAND cmake -P ${CMAKE_BINARY_DIR}/bin/CprncTest.cmake ${SRC_FILE} ${TGT_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(${TEST_NAME} PROPERTIES + LABELS "cldfrac;infrastructure" + FIXTURES_REQUIRED "cld_frac_net_py;cld_frac_net_cpp") endif() endif() diff --git a/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml b/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml index cb76be3a019c..c92c468fef5f 100644 --- a/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml +++ b/components/eamxx/tests/single-process/cld_fraction/input_ml.yaml @@ -14,7 +14,7 @@ eamxx: ice_cloud_threshold: 1e-12 py_module_name: ${PY_MODULE_NAME} py_module_path: ${PY_MODULE_PATH} - emulator: ${WHICH_EMULATOR} + emulator: ${EMULATOR} grids_manager: type: mesh_free @@ -29,5 +29,5 @@ initial_conditions: filename: ${SCREAM_DATA_DIR}/init/${EAMxx_tests_IC_FILE_72lev} scorpio: - output_yaml_files: [output_${POSTFIX}.yaml] + output_yaml_files: [output_ml_${POSTFIX}.yaml] ... diff --git a/components/eamxx/tests/single-process/cld_fraction/output_ml.yaml b/components/eamxx/tests/single-process/cld_fraction/output_ml.yaml new file mode 100644 index 000000000000..36bbc7943581 --- /dev/null +++ b/components/eamxx/tests/single-process/cld_fraction/output_ml.yaml @@ -0,0 +1,13 @@ +%YAML 1.1 +--- +filename_prefix: cld_frac_net_standalone_output_${POSTFIX} +averaging_type: instant +field_names: + - qi + - cldfrac_liq + - cldfrac_ice + - cldfrac_tot +output_control: + frequency: 1 + frequency_units: nsteps +... From 4b5097c61e29a3faab88ddb3a903663732f67b6d Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 17:35:46 -0700 Subject: [PATCH 177/398] EAMxx: add py script to generate cpp version of cld_frac_net from pytorch model Requires installation of lapis in the PATH --- .../cld_frac_net/gen_cpp_cld_frac_net.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py b/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py new file mode 100755 index 000000000000..43871a3c8ee3 --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +from cld_frac_net import CldFracNet, create_cld_frac_net +import os +import sys +import torch +import torch_mlir +from torch_mlir.compiler_utils import TensorPlaceholder +from torch_mlir import torchscript + +CURR_FILE_PATH = os.path.dirname(os.path.abspath(__file__)) +EAMXX_SCRIPTS_PATH = os.path.join(os.path.abspath(CURR_FILE_PATH), '../../../../scripts') + +sys.path.append(EAMXX_SCRIPTS_PATH) +from utils import run_cmd_no_fail + +def main (): + + model = create_cld_frac_net() + + ph = TensorPlaceholder([model.nlevs],torch.float32) + + mlir_module = torchscript.compile(model, (ph, ph), output_type='linalg-on-tensors') + with open("cld_frac_net.mlir",'w') as fd: + fd.write(str(mlir_module)) + + # Lower to kokkos dialect + run_cmd_no_fail("lapis-opt --team-compiler-kokkos cld_frac_net.mlir -o cld_frac_net_lowered.mlir", from_dir=os.getcwd()) + + # Generate c++ code from kokkos mlir + run_cmd_no_fail("lapis-translate cld_frac_net_lowered.mlir --team-level -o cld_frac_net.cpp -hpp cld_frac_net.hpp", from_dir=os.getcwd()) + +if __name__ == "__main__": + main() From 4663a42229d2fc8ecea7fe896c65fdf53c660054 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 2 Dec 2025 17:48:47 -0700 Subject: [PATCH 178/398] EAMxx: switch cld_frac_net cpp-vs-py comparison to use compare-nc-files We need a tolerance based test --- .../eamxx/tests/single-process/cld_fraction/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index 50ba9742624e..c68b44febccc 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -143,7 +143,9 @@ if (NOT EAMXX_ENABLE_GPU) set (TGT_FILE "cld_frac_net_standalone_output_py.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") set (TEST_NAME cld_frac_net_standalone_cpp_vs_py) add_test (NAME ${TEST_NAME} - COMMAND cmake -P ${CMAKE_BINARY_DIR}/bin/CprncTest.cmake ${SRC_FILE} ${TGT_FILE} + COMMAND ${SCREAM_BASE_DIR}/scripts/compare-nc-files + -s ${SRC_FILE} -t ${TGT_FILE} --tol 1e-6 + -c cldfrac_ice=cldfrac_ice cldfrac_tot=cldfrac_tot WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set_tests_properties(${TEST_NAME} PROPERTIES LABELS "cldfrac;infrastructure" From 9c6cc663c2349a978712a33d598284a049de08d8 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 8 Dec 2025 13:15:23 -0700 Subject: [PATCH 179/398] EAMxx: do not compile cld_frac_net on GPU --- .../eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt b/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt index 4a42e1865458..8c8a9334088d 100644 --- a/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/CMakeLists.txt @@ -1,4 +1,4 @@ -if (EAMXX_ENABLE_PYTHON) +if (EAMXX_ENABLE_PYTHON AND NOT EAMXX_ENABLE_GPU) # Process wrapping ML emulator (either via python or LAPIS-generated c++ code) add_library(cld_frac_net cld_frac_net.cpp From fb039833003df7dadd4ac3ec6919d674250ff87f Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 9 Dec 2025 14:58:03 -0700 Subject: [PATCH 180/398] EAMxx: clean up gen_cpp_cld_frac_net.py script --- .../cld_frac_net/gen_cpp_cld_frac_net.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py b/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py index 43871a3c8ee3..c94e079e6014 100755 --- a/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/gen_cpp_cld_frac_net.py @@ -1,12 +1,10 @@ #!/usr/bin/env python3 -from cld_frac_net import CldFracNet, create_cld_frac_net +from cld_frac_net import create_cld_frac_net import os import sys import torch -import torch_mlir -from torch_mlir.compiler_utils import TensorPlaceholder -from torch_mlir import torchscript +import torch_mlir.torchscript CURR_FILE_PATH = os.path.dirname(os.path.abspath(__file__)) EAMXX_SCRIPTS_PATH = os.path.join(os.path.abspath(CURR_FILE_PATH), '../../../../scripts') @@ -17,10 +15,8 @@ def main (): model = create_cld_frac_net() - - ph = TensorPlaceholder([model.nlevs],torch.float32) - - mlir_module = torchscript.compile(model, (ph, ph), output_type='linalg-on-tensors') + col = torch.rand(model.nlevs) + mlir_module = torch_mlir.torchscript.compile(model, (col,col), output_type='linalg-on-tensors') with open("cld_frac_net.mlir",'w') as fd: fd.write(str(mlir_module)) From f44bab6cc606dac066a2d8aec9c0a41941c7c205 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Tue, 9 Dec 2025 15:29:11 -0800 Subject: [PATCH 181/398] fix issue where divq and divq3d were not being cast properly, resulting in uninitialized memory being treated as Nan --- components/eam/src/dynamics/se/se_iop_intr_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/dynamics/se/se_iop_intr_mod.F90 b/components/eam/src/dynamics/se/se_iop_intr_mod.F90 index ae29e5734a96..2c64fb8d5b28 100644 --- a/components/eam/src/dynamics/se/se_iop_intr_mod.F90 +++ b/components/eam/src/dynamics/se/se_iop_intr_mod.F90 @@ -192,7 +192,7 @@ subroutine iop_broadcast() call mpibcast(divt,plev,mpir8,0,mpicom) call mpibcast(divq,plev,mpir8,0,mpicom) call mpibcast(divt3d,plev,mpir8,0,mpicom) - call mpibcast(divq3d,plev,mpir8,0,mpicom) + call mpibcast(divq3d,plev*pcnst,mpir8,0,mpicom) call mpibcast(scmlat,1,mpir8,0,mpicom) #endif From d617ee7834135aba3ae439138771aeb310cf4e3e Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Tue, 9 Dec 2025 15:31:21 -0800 Subject: [PATCH 182/398] apply same fix for divq, which didn't make it to the last commit --- components/eam/src/dynamics/se/se_iop_intr_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/dynamics/se/se_iop_intr_mod.F90 b/components/eam/src/dynamics/se/se_iop_intr_mod.F90 index 2c64fb8d5b28..59de14b99f02 100644 --- a/components/eam/src/dynamics/se/se_iop_intr_mod.F90 +++ b/components/eam/src/dynamics/se/se_iop_intr_mod.F90 @@ -190,7 +190,7 @@ subroutine iop_broadcast() call mpibcast(wfld,plev,mpir8,0,mpicom) call mpibcast(divt,plev,mpir8,0,mpicom) - call mpibcast(divq,plev,mpir8,0,mpicom) + call mpibcast(divq,plev*pcnst,mpir8,0,mpicom) call mpibcast(divt3d,plev,mpir8,0,mpicom) call mpibcast(divq3d,plev*pcnst,mpir8,0,mpicom) call mpibcast(scmlat,1,mpir8,0,mpicom) From 742e280a295d3d82fdabbd6a38d3b41a8c413565 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 9 Dec 2025 17:19:16 -0700 Subject: [PATCH 183/398] EAMxx: add a README in the cld_frac_net folder --- .../cld_fraction/cld_frac_net/README.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md b/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md new file mode 100644 index 000000000000..7555fa34add6 --- /dev/null +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md @@ -0,0 +1,27 @@ +# CldFracNet: a dummy emulator for EAMxx's CldFraction atmosphere process + +This emulator serves the goal of illustrating how to wrap a torch model in EAMxx. +There are two ways to wrap a torch model in an atm process: + + - via pytorch: EAMxx can call an arbitrary python module, so one can write a small + py module that wraps a pytorch model + - via LAPIS: [LAPIS](https://github.com/sandialabs/lapis) is a lightweight library + that can be used to translate torch-mlir into pure c++/kokkos code. So one can + write a small py script that dumps a torch model as MLIR, and then use LAPIS to + generate a kokkos equivalent version of that model + +The files in this folder illustrate this process: + + - `cld_frac_net.py`: this file contains the model definition and a free function `forward`, + that can be called from C++ (via python bindings) + - `cld_frac_net_weights.pth`: contains the weights for the model + - `gen_cpp_cld_frac_net.py`: this script shows how one can load the model, dump it as MLIR, + and finally call lapis to generate the hpp/cpp file to build in the project + - `cld_frac_net.*pp`: these are the generated files + +We point out that, at the time of this writing (Dec 2025), LAPIS relies on a particular version +of LLVM as well as `torch_mlir`. Instructions on how to install these LAPIS dependencies +can be found on the LAPIS repo documentation. + +Current EAMxx testing uses all the `cld_frac_net*` files, while the `gen_cpp_fld_frac_net.py` file +is shipped just as an example for how to generate the hpp/cpp files with LAPIS From b4ca75d351d38cd1a6e4d71b9982a036b5f4f612 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Tue, 9 Dec 2025 19:20:37 -0800 Subject: [PATCH 184/398] remove duplicated line for debugging --- driver-mct/main/prep_lnd_mod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/driver-mct/main/prep_lnd_mod.F90 b/driver-mct/main/prep_lnd_mod.F90 index 33af01c37704..d968efd90fcd 100644 --- a/driver-mct/main/prep_lnd_mod.F90 +++ b/driver-mct/main/prep_lnd_mod.F90 @@ -483,7 +483,6 @@ subroutine prep_lnd_merge( a2x_l, r2x_l, g2x_l, z2x_l, o2x_l, x2l_l ) call mct_aVect_copy(aVin=r2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=r2x_SharedIndices) call mct_aVect_copy(aVin=g2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=g2x_SharedIndices) call mct_aVect_copy(aVin=z2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=z2x_SharedIndices) - call mct_aVect_copy(aVin=o2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=o2x_SharedIndices) if (ocn_lnd_one_way) then call mct_aVect_copy(aVin=o2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=o2x_SharedIndices) endif From d79496da6c72d6c246cc12f6c0e7da146bb64e24 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 9 Dec 2025 20:47:38 -0700 Subject: [PATCH 185/398] EAMxx: add a page in the docs for how to wrap a torch emulator in EAMxx --- .../eamxx/docs/developer/torch_support.md | 113 ++++++++++++++++++ components/eamxx/mkdocs.yml | 2 + 2 files changed, 115 insertions(+) create mode 100644 components/eamxx/docs/developer/torch_support.md diff --git a/components/eamxx/docs/developer/torch_support.md b/components/eamxx/docs/developer/torch_support.md new file mode 100644 index 000000000000..a08920d54338 --- /dev/null +++ b/components/eamxx/docs/developer/torch_support.md @@ -0,0 +1,113 @@ +# Support for Torch-based emulators + +In EAMxx, it is possible to wrap a ML emulator inside an atmosphere process (AP) relatively easily. +Currently, there are two ways to do so: + + - via python: EAMxx can call python functions via pybind11 interfaces, so one can write a small + py module that wraps a pytorch model + - via LAPIS: [LAPIS](https://github.com/sandialabs/lapis) is a lightweight library + that can be used to translate torch-mlir into pure c++/kokkos code, so one can + write a small py script that dumps a torch model as MLIR, and then use LAPIS to + generate a kokkos equivalent version of that model. + +In the folder `src/physics/cld_fraction/cld_frac_net` one can find example files for how to +wrap an emulator inside an AP. These files implement an AP called "CldFracNet", +which wraps a torch-based ML emulator. We emphasize that the emulator is for illustration purposes only, +and the quality of the emulator is beyond the scope of the example. + +## Python + +In order for EAMxx to call python, the code must be compiled with the cmake option `EAMXX_ENABLE_PYTHON=ON`. +For a CIME case, one can do `xmlchange --append SCREAM_CMAKE_OPTIONS='EAMXX_ENABLE PYTHON ON'` from the case dir. + +When python support is enabled, the AP base class will take care of creating python-compatible +arrays (from now on, "PyFields") for each of the process input/output `Field`'s, +provided that the process input parameters contain a non-null string for the option `py_module_name`. + +At runtime, the derived process implementation is in charge of gathering all PyField's, and call the +desired function from the python module. Here's an example from the `cld_frac_net` process: + +```c++ + auto py_qi = get_py_field_dev("qi"); + auto py_liq = get_py_field_dev("cldfrac_liq"); + auto py_ice = get_py_field_dev("cldfrac_ice"); + auto py_tot = get_py_field_dev("cldfrac_tot"); + + double ice_threshold = m_params.get("ice_cloud_threshold"); + + py_module_call("forward",ice_threshold,py_qi,py_liq,py_ice,py_tot); +``` +The function `get_py_field_dev` is implemented in AP base class, and retrieves the PyField +corresponding to the given input or output field. The function `py_module_call` is also implemented +in the AP base class, and wraps the call to the python function, with some exception +handling to ensure errors are nicely printed in case something goes wrong. + +A few comments: + + - Since Python does not have the concept of "const", it is technically possible to pass a const + field as an output when calling python, so care is needed to ensure arguments are passed in the correct + order. + - By default, the AP class looks for the module provided via `py_module_name` in the current working + directory. The user can override this by specifying the optional `py_module_path` parameter. + - The AP base class also provides `get_py_field_host`. When the model is running on GPU, this allows + to obtain a PyField that shares the same pointer of the Host view in the Field. There is NO + automatic synchronization of device and host views. Like for regular fields, it is the process + responsibility to copy to host at the beginning of `run_impl`, and make sure that the field is + sync-ed back to device upon return. + - The file `cld_frac_net.py` provides the definition of the torch model, as well as the initialization + and run routines that are called at runtime. The names of these routines are arbitrary, but they must + of course match what the process interface calls in the C++ interface. + +## C++/Kokkos + +In order to generate C++/Kokkos, we can make use of the LAPIS library. LAPIS is a lightweight C++ +library built on top of LLVM, which can interpret MLIR code and translate it to C++ with Kokkos. +At the time of this writing (Dec 2025), LAPIS relies on a particular version of LLVM (as well as +`torch_mlir`, which is optional). Instructions on how to install these LAPIS dependencies +can be found on the LAPIS documentation on GitHub. + +For the CldFracNet example, we used LAPIS built with torch-mlir support. The file `gen_cpp_cld_frac_net.py` +shows how to load a torch based model, dump it as MLIR, and then use lapis tools to convert this +to C++ and Kokkos. LAPIS can convert a model that is meant to be called as a "top-level" kernel, as well +as a function inside a kernel. In our example, we opted for the second strategy, since it is the most +versatile one (e.g., one could replace a small portion of a device kernel). In the process implementation, +we provide the syntactic sugar necessary to then wrap the converted model inside a `Kokkos::parallel_for`. + +The general structure of the code that calls the emulator is + +```c++ + auto policy = ...; + // Allow up to this much level 0 scratch (aka shared mem) per team + // when deciding which temporary views to spill into level 1 scratch (global pool). + constexpr int max_shared = 4096; + constexpr int scratch0_required = forward_L0_scratch_required(max_shared); + constexpr int scratch1_required = forward_L1_scratch_required(max_shared); + GlobalViews_forward globalViews; + policy.set_scratch_size(0, Kokkos::PerTeam(scratch0_required)); + policy.set_scratch_size(1, Kokkos::PerTeam(scratch1_required)); + + // Execute the appropriate specialization based on shared amount + auto lambda = KOKKOS_LAMBDA (const MemberType& team) { + // If needed, prepare inputs for the forward function. E.g., subview input/output + // views at a particular index corresponding to the league_rank + + char* scratch0 = (char*)(team.team_scratch(0).get_shmem(scratch0_required)); + char* scratch1 = (char*)(team.team_scratch(1).get_shmem(scratch1_required)); + + forward(team, globalViews, , , scratch0, scratch1); + }; + Kokkos::parallel_for(policy,lambda); +``` +where the function names `forward_L0_scratch_required`, `forward_L1_scratch_required`, and `forward` are +hard-coded by LAPIS, while `MemberType` and `ExeSpace` are typedefs similar to what is done in other +areas of EAMxx. + +Some comments: + + - The code needed to wrap the C++/Kokkos version of CldFracNet is larger. This is because we cannot provide + any "common" implementation in the AP base class (like it was done for the Python version), and all + the necessary plumbing must happen in the derived process implementation. + - The script `gen_cpp_cld_frac_net.py` illustrates how to convert the torch model to C++/Kokkos. The script + first creates and initializes the torch model (defined in `cld_frac_net.py`), then dumps MLIR code using + the torch-mlir package, and finally calls a couple of LAPIS executables to generate the hpp/cpp files. + These files must be included, built, and linked by the host project. diff --git a/components/eamxx/mkdocs.yml b/components/eamxx/mkdocs.yml index 03931135578d..d8edc87f3987 100644 --- a/components/eamxx/mkdocs.yml +++ b/components/eamxx/mkdocs.yml @@ -50,6 +50,8 @@ nav: - 'Atmosphere Processes': 'developer/processes.md' - 'Input/Output': 'developer/io.md' - 'Third-party Libraries': 'developer/TPLs.md' + - 'How to': + - 'Wrap Torch emulators': 'developer/torch_support.md' - 'Technical Guide': - 'Overview': 'technical/index.md' - 'AeroCom cloud top': 'technical/aerocom_cldtop.md' From 547692f73f7e6854a56af928fcf0f0299a1f425d Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 9 Dec 2025 20:55:47 -0700 Subject: [PATCH 186/398] EAMxx: make md linter happy --- .../eamxx/docs/developer/torch_support.md | 58 ++++++++++--------- .../cld_fraction/cld_frac_net/README.md | 24 ++++---- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/components/eamxx/docs/developer/torch_support.md b/components/eamxx/docs/developer/torch_support.md index a08920d54338..4c9b1524668f 100644 --- a/components/eamxx/docs/developer/torch_support.md +++ b/components/eamxx/docs/developer/torch_support.md @@ -3,12 +3,12 @@ In EAMxx, it is possible to wrap a ML emulator inside an atmosphere process (AP) relatively easily. Currently, there are two ways to do so: - - via python: EAMxx can call python functions via pybind11 interfaces, so one can write a small - py module that wraps a pytorch model - - via LAPIS: [LAPIS](https://github.com/sandialabs/lapis) is a lightweight library - that can be used to translate torch-mlir into pure c++/kokkos code, so one can - write a small py script that dumps a torch model as MLIR, and then use LAPIS to - generate a kokkos equivalent version of that model. +- via python: EAMxx can call python functions via pybind11 interfaces, so one can write a small + py module that wraps a pytorch model +- via LAPIS: [LAPIS](https://github.com/sandialabs/lapis) is a lightweight library + that can be used to translate torch-mlir into pure c++/kokkos code, so one can + write a small py script that dumps a torch model as MLIR, and then use LAPIS to + generate a kokkos equivalent version of that model. In the folder `src/physics/cld_fraction/cld_frac_net` one can find example files for how to wrap an emulator inside an AP. These files implement an AP called "CldFracNet", @@ -37,26 +37,27 @@ desired function from the python module. Here's an example from the `cld_frac_ne py_module_call("forward",ice_threshold,py_qi,py_liq,py_ice,py_tot); ``` + The function `get_py_field_dev` is implemented in AP base class, and retrieves the PyField corresponding to the given input or output field. The function `py_module_call` is also implemented in the AP base class, and wraps the call to the python function, with some exception handling to ensure errors are nicely printed in case something goes wrong. -A few comments: - - - Since Python does not have the concept of "const", it is technically possible to pass a const - field as an output when calling python, so care is needed to ensure arguments are passed in the correct - order. - - By default, the AP class looks for the module provided via `py_module_name` in the current working - directory. The user can override this by specifying the optional `py_module_path` parameter. - - The AP base class also provides `get_py_field_host`. When the model is running on GPU, this allows - to obtain a PyField that shares the same pointer of the Host view in the Field. There is NO - automatic synchronization of device and host views. Like for regular fields, it is the process - responsibility to copy to host at the beginning of `run_impl`, and make sure that the field is - sync-ed back to device upon return. - - The file `cld_frac_net.py` provides the definition of the torch model, as well as the initialization - and run routines that are called at runtime. The names of these routines are arbitrary, but they must - of course match what the process interface calls in the C++ interface. +Some comments: + +- Since Python does not have the concept of "const", it is technically possible to pass a const + field as an output when calling python, so care is needed to ensure arguments are passed in the correct + order. +- By default, the AP class looks for the module provided via `py_module_name` in the current working + directory. The user can override this by specifying the optional `py_module_path` parameter. +- The AP base class also provides `get_py_field_host`. When the model is running on GPU, this allows + to obtain a PyField that shares the same pointer of the Host view in the Field. There is NO + automatic synchronization of device and host views. Like for regular fields, it is the process + responsibility to copy to host at the beginning of `run_impl`, and make sure that the field is + sync-ed back to device upon return. +- The file `cld_frac_net.py` provides the definition of the torch model, as well as the initialization + and run routines that are called at runtime. The names of these routines are arbitrary, but they must + of course match what the process interface calls in the C++ interface. ## C++/Kokkos @@ -98,16 +99,17 @@ The general structure of the code that calls the emulator is }; Kokkos::parallel_for(policy,lambda); ``` + where the function names `forward_L0_scratch_required`, `forward_L1_scratch_required`, and `forward` are hard-coded by LAPIS, while `MemberType` and `ExeSpace` are typedefs similar to what is done in other areas of EAMxx. Some comments: - - The code needed to wrap the C++/Kokkos version of CldFracNet is larger. This is because we cannot provide - any "common" implementation in the AP base class (like it was done for the Python version), and all - the necessary plumbing must happen in the derived process implementation. - - The script `gen_cpp_cld_frac_net.py` illustrates how to convert the torch model to C++/Kokkos. The script - first creates and initializes the torch model (defined in `cld_frac_net.py`), then dumps MLIR code using - the torch-mlir package, and finally calls a couple of LAPIS executables to generate the hpp/cpp files. - These files must be included, built, and linked by the host project. +- The code needed to wrap the C++/Kokkos version of CldFracNet is larger. This is because we cannot provide + any "common" implementation in the AP base class (like it was done for the Python version), and all + the necessary plumbing must happen in the derived process implementation. +- The script `gen_cpp_cld_frac_net.py` illustrates how to convert the torch model to C++/Kokkos. The script + first creates and initializes the torch model (defined in `cld_frac_net.py`), then dumps MLIR code using + the torch-mlir package, and finally calls a couple of LAPIS executables to generate the hpp/cpp files. + These files must be included, built, and linked by the host project. diff --git a/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md b/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md index 7555fa34add6..249bc54b9c1d 100644 --- a/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md +++ b/components/eamxx/src/physics/cld_fraction/cld_frac_net/README.md @@ -3,21 +3,21 @@ This emulator serves the goal of illustrating how to wrap a torch model in EAMxx. There are two ways to wrap a torch model in an atm process: - - via pytorch: EAMxx can call an arbitrary python module, so one can write a small - py module that wraps a pytorch model - - via LAPIS: [LAPIS](https://github.com/sandialabs/lapis) is a lightweight library - that can be used to translate torch-mlir into pure c++/kokkos code. So one can - write a small py script that dumps a torch model as MLIR, and then use LAPIS to - generate a kokkos equivalent version of that model +- via pytorch: EAMxx can call an arbitrary python module, so one can write a small + py module that wraps a pytorch model +- via LAPIS: [LAPIS](https://github.com/sandialabs/lapis) is a lightweight library + that can be used to translate torch-mlir into pure c++/kokkos code. So one can + write a small py script that dumps a torch model as MLIR, and then use LAPIS to + generate a kokkos equivalent version of that model The files in this folder illustrate this process: - - `cld_frac_net.py`: this file contains the model definition and a free function `forward`, - that can be called from C++ (via python bindings) - - `cld_frac_net_weights.pth`: contains the weights for the model - - `gen_cpp_cld_frac_net.py`: this script shows how one can load the model, dump it as MLIR, - and finally call lapis to generate the hpp/cpp file to build in the project - - `cld_frac_net.*pp`: these are the generated files +- `cld_frac_net.py`: this file contains the model definition and a free function `forward`, + that can be called from C++ (via python bindings) +- `cld_frac_net_weights.pth`: contains the weights for the model +- `gen_cpp_cld_frac_net.py`: this script shows how one can load the model, dump it as MLIR, + and finally call lapis to generate the hpp/cpp file to build in the project +- `cld_frac_net.*pp`: these are the generated files We point out that, at the time of this writing (Dec 2025), LAPIS relies on a particular version of LLVM as well as `torch_mlir`. Instructions on how to install these LAPIS dependencies From 4215f4dbeb7091f7f26dfe003b323c72a54e5aac Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 08:59:14 -0800 Subject: [PATCH 187/398] more renaming --- components/eam/src/physics/cam/zm/zm_conv.F90 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 10982bf97e1f..fcd2b1c95670 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -181,7 +181,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8),pointer,dimension(:,:), intent(in ) :: t_star ! for DCAPE - prev temperature [K] real(r8),pointer,dimension(:,:), intent(in ) :: q_star ! for DCAPE - prev sp. humidity [kg/kg] integer, intent( out) :: lengath ! number of active columns in chunk for gathering - integer, dimension(pcols), intent( out) :: gather_index ! flag for active columns + integer, dimension(pcols), intent( out) :: gather_index ! flag for active columns integer, dimension(pcols), intent( out) :: maxg ! gathered level indices of max MSE (maxi) integer, dimension(pcols), intent( out) :: jctop ! top-of-deep-convection indices integer, dimension(pcols), intent( out) :: jcbot ! base of cloud indices @@ -300,7 +300,6 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! initialize various arrays - do i = 1,ncol do k = 1,pver qtnd(i,k) = 0._r8 @@ -391,7 +390,6 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! - call #1, cape_calc_msemax_klev=.true. standard calculation using state of current step ! - call #2, cape_calc_msemax_klev=.false. use launch level (msemax_klev) from previous call ! DCAPE is the difference in CAPE between the two calls using the same launch level - cape_calc_msemax_klev = .true. call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & @@ -419,7 +417,6 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! determine whether active columns for gathering - call zm_get_gather_index(pcols, ncol, pver, pverp, is_first_step, cape, dcape, & cape_threshold_loc, gather_index, lengath) @@ -733,8 +730,8 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, time_step, & real(r8), dimension(pcols,pver), intent(inout) :: tend_q ! water vapor tendency [kg/kg/s] real(r8), dimension(pcols,pver), intent(out ) :: tend_s_snwprd ! Heating rate of snow production [J/kg/s] real(r8), dimension(pcols,pver), intent(out ) :: tend_s_snwevmlt ! Heating rate of snow evap/melt [J/kg/s] - real(r8), dimension(pcols), intent(inout) :: prec(pcols) ! Convective-scale prec rate [m/s] - real(r8), dimension(pcols), intent(out ) :: snow(pcols) ! Convective-scale snow rate [m/s] + real(r8), dimension(pcols), intent(inout) :: prec ! Convective-scale prec rate [m/s] + real(r8), dimension(pcols), intent(out ) :: snow ! Convective-scale snow rate [m/s] real(r8), dimension(pcols,pver), intent(out ) :: ntprprd ! net precip production in layer [?] real(r8), dimension(pcols,pver), intent(out ) :: ntsnprd ! net snow production in layer [?] real(r8), dimension(pcols,pverp),intent(out ) :: flxprec ! Convective flux of prec at interfaces [kg/m2/s] @@ -1138,7 +1135,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & !---------------------------------------------------------------------------- ! Local variables integer :: i,k ! loop iterators - real(r8), dimension(pcols) :: ratmjb ! + real(r8), dimension(pcols) :: ratmjb ! ? real(r8) dz_tmp ! temporary vertical thickness for downdraft mass flux calculation real(r8) mdt ! temporary downdraft mass flux for normalization !---------------------------------------------------------------------------- From 736ab3bd14979299e178e2b582632bf4c1c7a617 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Wed, 10 Dec 2025 09:01:21 -0800 Subject: [PATCH 188/398] explicitly initialize large scale forcing of the wind components, which is more safe in the event that the IOP file does not contain these variables --- components/eam/src/control/iop_data_mod.F90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index 2f2bb9dace09..269901546850 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -1296,6 +1296,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) endif ! large scale / geostropic horizontal wind (for nudging) + uls = 0.0_r8 ! Initialize to zer call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'u_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, uls, status ) if ( status .ne. nf90_noerr ) then @@ -1329,6 +1330,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call shr_sys_flush( iulog ) ! large scale / geostropic meridional wind (for nudging) + vls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'v_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, vls, status ) if ( status .ne. nf90_noerr ) then @@ -1432,6 +1434,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_tg = .true. endif + wfld = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'omega', .true., ptend, fill_ends, dplevs, nlev,psobs, hyam, hybm, wfld, status ) if ( status .ne. nf90_noerr ) then From 1f26036093496aed29ae547b30dc4e54aabf4c55 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 09:06:02 -0800 Subject: [PATCH 189/398] rename qstp --- components/eam/src/physics/cam/zm/zm_conv.F90 | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index fcd2b1c95670..d9ba2e087db8 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -221,16 +221,16 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & integer, dimension(pcols) :: pbl_top ! pbl top indices integer, dimension(pcols) :: pbl_top_g ! gathered pbl top indices - real(r8), dimension(pcols,pver) :: tp ! parcel temperature [K] - real(r8), dimension(pcols,pver) :: qstp ! parcel saturation specific humidity [kg/kg] + real(r8), dimension(pcols,pver) :: t_pcl ! parcel temperature [K] + real(r8), dimension(pcols,pver) :: q_pcl_sat ! parcel saturation specific humidity [kg/kg] real(r8), dimension(pcols) :: tl ! parcel temperature at lcl [K] integer, dimension(pcols) :: lcl ! base level index of deep cumulus convection integer, dimension(pcols) :: lel ! index of highest theoretical convective plume integer, dimension(pcols) :: lon ! index of onset level for deep convection integer, dimension(pcols) :: maxi ! index of level with largest moist static energy - real(r8), dimension(pcols,pver) :: tp_m1 ! time n-1 parcel temperatures - real(r8), dimension(pcols,pver) :: qstp_m1 ! time n-1 parcel saturation specific humidity + real(r8), dimension(pcols,pver) :: t_pcl_m1 ! time n-1 parcel temperatures + real(r8), dimension(pcols,pver) :: q_pcl_sat_m1 ! time n-1 parcel saturation specific humidity real(r8), dimension(pcols) :: tl_m1 ! time n-1 parcel Temperature at LCL integer, dimension(pcols) :: lcl_m1 ! time n-1 base level index of deep cumulus convection integer, dimension(pcols) :: lel_m1 ! time n-1 index of highest theoretical convective plume @@ -248,9 +248,9 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: z_mid_g ! gathered values of z_mid real(r8), dimension(pcols,pver) :: s_mid_g ! gathered values of s real(r8), dimension(pcols,pver) :: s_int_g ! gathered upper interface dry static energy - real(r8), dimension(pcols,pver) :: tp_g ! gathered values of tp real(r8), dimension(pcols,pverp):: z_int_g ! gathered values of z_int - real(r8), dimension(pcols,pver) :: qstp_g ! gathered values of qstp + real(r8), dimension(pcols,pver) :: t_pcl_g ! gathered values of t_pcl + real(r8), dimension(pcols,pver) :: q_pcl_sat_g ! gathered values of q_pcl_sat real(r8), dimension(pcols,pver) :: omega_g ! gathered values of omega real(r8), dimension(pcols,pver) :: rprd_g ! gathered rain production rate real(r8), dimension(pcols,pver) :: ql_g ! gathered cloud liquid water @@ -370,7 +370,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & do i = 1,ncol q_mid(i,k) = q_mid_in(i,k) s_mid(i,k) = t_mid(i,k) + (zm_const%grav/zm_const%cpair)*z_mid(i,k) - tp(i,k) = 0.0_r8 + t_pcl(i,k) = 0.0_r8 s_int_g(i,k) = s_mid(i,k) q_int_g(i,k) = q_mid(i,k) end do @@ -395,7 +395,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & zm_param%num_cin, msg, & q_mid, t_mid, z_mid, p_mid, p_int, & pbl_top, tpert, & - tp, qstp, maxi, tl, & + t_pcl, q_pcl_sat, maxi, tl, & lcl, lel, cape, & zm_const, zm_param, & cape_calc_msemax_klev ) @@ -408,7 +408,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & zm_param%num_cin, msg, & q_star, t_star, z_mid, p_mid, p_int, & pbl_top, tpert, & - tp_m1, qstp_m1, maxi_m1, tl_m1, & + t_pcl_m1, q_pcl_sat_m1, maxi_m1, tl_m1, & lcl_m1, lel_m1, cape_m1, & zm_const, zm_param, & cape_calc_msemax_klev, prev_msemax_klev ) @@ -430,26 +430,26 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! copy data to gathered arrays do i = 1,lengath do k = 1,pver - p_del(i,k) = 0.01_r8*p_del_in(gather_index(i),k) - q_mid_g(i,k) = q_mid(gather_index(i),k) - t_mid_g(i,k) = t_mid(gather_index(i),k) - p_mid_g(i,k) = p_mid(gather_index(i),k) - z_mid_g(i,k) = z_mid(gather_index(i),k) - s_mid_g(i,k) = s_mid(gather_index(i),k) - tp_g(i,k) = tp(gather_index(i),k) - z_int_g(i,k) = z_int(gather_index(i),k) - qstp_g(i,k) = qstp(gather_index(i),k) - omega_g(i,k) = omega(gather_index(i),k) + p_del(i,k) = 0.01_r8*p_del_in(gather_index(i),k) + q_mid_g(i,k) = q_mid(gather_index(i),k) + t_mid_g(i,k) = t_mid(gather_index(i),k) + p_mid_g(i,k) = p_mid(gather_index(i),k) + z_mid_g(i,k) = z_mid(gather_index(i),k) + s_mid_g(i,k) = s_mid(gather_index(i),k) + t_pcl_g(i,k) = t_pcl(gather_index(i),k) + z_int_g(i,k) = z_int(gather_index(i),k) + q_pcl_sat_g(i,k) = q_pcl_sat(gather_index(i),k) + omega_g(i,k) = omega(gather_index(i),k) end do - z_int_g(i,pverp) = z_int(gather_index(i),pver+1) - cape_g(i) = cape(gather_index(i)) - lcl_g(i) = lcl(gather_index(i)) - lel_g(i) = lel(gather_index(i)) - maxg(i) = maxi(gather_index(i)) - tl_g(i) = tl(gather_index(i)) - landfrac_g(i) = landfrac(gather_index(i)) - pbl_top_g(i) = pbl_top(gather_index(i)) - tpert_g(i) = tpert(gather_index(i)) + z_int_g(i,pverp) = z_int(gather_index(i),pver+1) + cape_g(i) = cape(gather_index(i)) + lcl_g(i) = lcl(gather_index(i)) + lel_g(i) = lel(gather_index(i)) + maxg(i) = maxi(gather_index(i)) + tl_g(i) = tl(gather_index(i)) + landfrac_g(i) = landfrac(gather_index(i)) + pbl_top_g(i) = pbl_top(gather_index(i)) + tpert_g(i) = tpert(gather_index(i)) end do !---------------------------------------------------------------------------- @@ -545,7 +545,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & lcl_g, lel_g, jt, maxg, dsubcld, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & - tl_g, tp_g, qstp_g, su, qu, & + tl_g, t_pcl_g, q_pcl_sat_g, su, qu, & mc, du, mu, md, qd, sd, cape_g, cld_bass_mass_flux ) !---------------------------------------------------------------------------- @@ -1864,7 +1864,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & lcl, lel, jt, mx, dsubcld, & z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & - tl, tp, qstp, su, qu, & + tl, t_pcl, q_pcl_sat, su, qu, & mc, du, mu, md, qd, sd, cape, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the @@ -1903,8 +1903,8 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: s_int ! env. normalized dry static energy at intrfcs real(r8), dimension(pcols,pver), intent(in ) :: q_int ! environment specific humidity at interfaces real(r8), dimension(pcols), intent(in ) :: tl ! parcel temperature at lcl - real(r8), dimension(pcols,pver), intent(in ) :: tp ! parcel temperature - real(r8), dimension(pcols,pver), intent(in ) :: qstp ! parcel specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: t_pcl ! parcel temperature + real(r8), dimension(pcols,pver), intent(in ) :: q_pcl_sat ! parcel specific humidity real(r8), dimension(pcols,pver), intent(in ) :: su ! updraft dry static energy (normalized) real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux @@ -1993,7 +1993,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & do i = 1,ncol ! levels between parcel launch and LCL if ( k>lcl(i) .and. k=lel(i) .and. k<=lcl(i) ) then - thetavp = tp(i,k) * (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*qstp(i,k)-q_mid(i,mx(i))) + thetavp = t_pcl(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+1.608_r8*q_pcl_sat(i,k)-q_mid(i,mx(i))) thetavm = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q_mid(i,k)) - dqsdtp = qstp(i,k) * (1._r8+qstp(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*tp(i,k)**2) - dtpdt = tp(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp-qstp(i,k)/tp(i,k)))* & + dqsdtp = q_pcl_sat(i,k) * (1._r8+q_pcl_sat(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_pcl(i,k)**2) + dtpdt = t_pcl(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp-q_pcl_sat(i,k)/t_pcl(i,k)))* & (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q_mid(i,mx(i))/tl(i)**2*dtldt(i))) - dboydt(i,k) = ((dtpdt/tp(i,k)+1._r8/(1._r8+1.608_r8*qstp(i,k)-q_mid(i,mx(i)))* & + dboydt(i,k) = ((dtpdt/t_pcl(i,k)+1._r8/(1._r8+1.608_r8*q_pcl_sat(i,k)-q_mid(i,mx(i)))* & (1.608_r8 * dqsdtp * dtpdt -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & (1._r8+0.608_r8*q_mid(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp/thetavm end if From fcf52681c5304e96719c5a0bffbacf09158c98e7 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 09:08:34 -0800 Subject: [PATCH 190/398] rename tl --- components/eam/src/physics/cam/zm/zm_conv.F90 | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index d9ba2e087db8..13c7a28ddd41 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -223,7 +223,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: t_pcl ! parcel temperature [K] real(r8), dimension(pcols,pver) :: q_pcl_sat ! parcel saturation specific humidity [kg/kg] - real(r8), dimension(pcols) :: tl ! parcel temperature at lcl [K] + real(r8), dimension(pcols) :: t_pcl_lcl ! parcel temperature at lcl [K] integer, dimension(pcols) :: lcl ! base level index of deep cumulus convection integer, dimension(pcols) :: lel ! index of highest theoretical convective plume integer, dimension(pcols) :: lon ! index of onset level for deep convection @@ -231,7 +231,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: t_pcl_m1 ! time n-1 parcel temperatures real(r8), dimension(pcols,pver) :: q_pcl_sat_m1 ! time n-1 parcel saturation specific humidity - real(r8), dimension(pcols) :: tl_m1 ! time n-1 parcel Temperature at LCL + real(r8), dimension(pcols) :: t_pcl_lcl_m1 ! time n-1 parcel Temperature at LCL integer, dimension(pcols) :: lcl_m1 ! time n-1 base level index of deep cumulus convection integer, dimension(pcols) :: lel_m1 ! time n-1 index of highest theoretical convective plume integer, dimension(pcols) :: lon_m1 ! time n-1 index of onset level for deep convection @@ -255,7 +255,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: rprd_g ! gathered rain production rate real(r8), dimension(pcols,pver) :: ql_g ! gathered cloud liquid water real(r8), dimension(pcols) :: cape_g ! gathered convective available potential energy - real(r8), dimension(pcols) :: tl_g ! gathered values of tl + real(r8), dimension(pcols) :: t_pcl_lcl_g ! gathered values of t_pcl_lcl real(r8), dimension(pcols) :: landfrac_g ! gathered landfrac real(r8), dimension(pcols) :: tpert_g ! gathered values of tpert (temperature perturbation from PBL) integer, dimension(pcols) :: lcl_g ! gathered values of lcl level index @@ -377,12 +377,12 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & end do do i = 1,ncol - cape_g(i) = 0._r8 - lcl_g(i) = 1 - lel_g(i) = pver - maxg(i) = 1 - tl_g(i) = 400._r8 - dsubcld(i) = 0._r8 + cape_g(i) = 0._r8 + lcl_g(i) = 1 + lel_g(i) = pver + maxg(i) = 1 + t_pcl_lcl_g(i) = 400._r8 + dsubcld(i) = 0._r8 end do !---------------------------------------------------------------------------- @@ -395,7 +395,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & zm_param%num_cin, msg, & q_mid, t_mid, z_mid, p_mid, p_int, & pbl_top, tpert, & - t_pcl, q_pcl_sat, maxi, tl, & + t_pcl, q_pcl_sat, maxi, t_pcl_lcl, & lcl, lel, cape, & zm_const, zm_param, & cape_calc_msemax_klev ) @@ -408,7 +408,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & zm_param%num_cin, msg, & q_star, t_star, z_mid, p_mid, p_int, & pbl_top, tpert, & - t_pcl_m1, q_pcl_sat_m1, maxi_m1, tl_m1, & + t_pcl_m1, q_pcl_sat_m1, maxi_m1, t_pcl_lcl_m1, & lcl_m1, lel_m1, cape_m1, & zm_const, zm_param, & cape_calc_msemax_klev, prev_msemax_klev ) @@ -446,7 +446,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & lcl_g(i) = lcl(gather_index(i)) lel_g(i) = lel(gather_index(i)) maxg(i) = maxi(gather_index(i)) - tl_g(i) = tl(gather_index(i)) + t_pcl_lcl_g(i) = t_pcl_lcl(gather_index(i)) landfrac_g(i) = landfrac(gather_index(i)) pbl_top_g(i) = pbl_top(gather_index(i)) tpert_g(i) = tpert(gather_index(i)) @@ -545,7 +545,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & lcl_g, lel_g, jt, maxg, dsubcld, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & - tl_g, t_pcl_g, q_pcl_sat_g, su, qu, & + t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, su, qu, & mc, du, mu, md, qd, sd, cape_g, cld_bass_mass_flux ) !---------------------------------------------------------------------------- @@ -1864,7 +1864,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & lcl, lel, jt, mx, dsubcld, & z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & - tl, t_pcl, q_pcl_sat, su, qu, & + t_pcl_lcl, t_pcl, q_pcl_sat, su, qu, & mc, du, mu, md, qd, sd, cape, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the @@ -1902,7 +1902,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: ql ! ambient liquid water mixing ratio real(r8), dimension(pcols,pver), intent(in ) :: s_int ! env. normalized dry static energy at intrfcs real(r8), dimension(pcols,pver), intent(in ) :: q_int ! environment specific humidity at interfaces - real(r8), dimension(pcols), intent(in ) :: tl ! parcel temperature at lcl + real(r8), dimension(pcols), intent(in ) :: t_pcl_lcl ! parcel temperature at LCL real(r8), dimension(pcols,pver), intent(in ) :: t_pcl ! parcel temperature real(r8), dimension(pcols,pver), intent(in ) :: q_pcl_sat ! parcel specific humidity real(r8), dimension(pcols,pver), intent(in ) :: su ! updraft dry static energy (normalized) @@ -2005,7 +2005,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & thetavm = t_mid(i,k)* (1000._r8/p_mid(i,k))**(zm_const%rdair/zm_const%cpair)*(1._r8+0.608_r8*q_mid(i,k)) dqsdtp = q_pcl_sat(i,k) * (1._r8+q_pcl_sat(i,k)/zm_const%epsilo)*zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_pcl(i,k)**2) dtpdt = t_pcl(i,k)/ (1._r8+zm_const%latvap/zm_const%cpair* (dqsdtp-q_pcl_sat(i,k)/t_pcl(i,k)))* & - (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/tl(i)-q_mid(i,mx(i))/tl(i)**2*dtldt(i))) + (dtbdt(i)/t_mid(i,mx(i))+zm_const%latvap/zm_const%cpair* (dqbdt(i)/t_pcl_lcl(i)-q_mid(i,mx(i))/t_pcl_lcl(i)**2*dtldt(i))) dboydt(i,k) = ((dtpdt/t_pcl(i,k)+1._r8/(1._r8+1.608_r8*q_pcl_sat(i,k)-q_mid(i,mx(i)))* & (1.608_r8 * dqsdtp * dtpdt -dqbdt(i))) - (dtmdt(i,k)/t_mid(i,k)+0.608_r8/ & (1._r8+0.608_r8*q_mid(i,k))*dqmdt(i,k)))*zm_const%grav*thetavp/thetavm From 788cafe674393fd44ac1df0c81650039ff779247 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 09:14:13 -0800 Subject: [PATCH 191/398] rename maxi/maxg --- components/eam/src/physics/cam/zm/zm_conv.F90 | 231 +++++++++--------- 1 file changed, 116 insertions(+), 115 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 13c7a28ddd41..fb24495b0fba 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -152,7 +152,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & t_mid, q_mid_in, omega, p_mid_in, p_int_in, p_del_in, & geos, z_mid_in, z_int_in, pbl_hgt, & tpert, landfrac, t_star, q_star, & - lengath, gather_index, maxg, jctop, jcbot, jt, & + lengath, gather_index, msemax_klev_g, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & mcon, pflx, zdu, mu, eu, du, md, ed, p_del, dsubcld, & ql, rliq, rprd, dlf, aero, microp_st ) @@ -165,42 +165,42 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & integer, intent(in ) :: pver ! number of mid-point levels integer, intent(in ) :: pverp ! number of interface levels logical, intent(in ) :: is_first_step ! flag for first step of run - real(r8), intent(in ) :: time_step ! model time-step [s] - real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] - real(r8), dimension(pcols,pver), intent(in ) :: q_mid_in ! specific humidity [kg/kg] - real(r8), dimension(pcols,pver), intent(in ) :: omega ! vertical pressure velocity [Pa/s] - real(r8), dimension(pcols,pver), intent(in ) :: p_mid_in ! mid-point pressure [Pa] - real(r8), dimension(pcols,pverp),intent(in ) :: p_int_in ! interface pressure [Pa] - real(r8), dimension(pcols,pver), intent(in ) :: p_del_in ! pressure thickness [Pa] - real(r8), dimension(pcols), intent(in ) :: geos ! surface geopotential [m2/s2] - real(r8), dimension(pcols,pver), intent(in ) :: z_mid_in ! mid-point geopotential [m2/s2] - real(r8), dimension(pcols,pverp),intent(in ) :: z_int_in ! interface geopotential [m2/s2] - real(r8), dimension(pcols), intent(in ) :: pbl_hgt ! boundary layer height [m] - real(r8), dimension(pcols), intent(in ) :: tpert ! parcel temperature perturbation [K] - real(r8), dimension(pcols), intent(in ) :: landfrac ! land fraction - real(r8),pointer,dimension(:,:), intent(in ) :: t_star ! for DCAPE - prev temperature [K] - real(r8),pointer,dimension(:,:), intent(in ) :: q_star ! for DCAPE - prev sp. humidity [kg/kg] + real(r8), intent(in ) :: time_step ! model time-step [s] + real(r8), dimension(pcols,pver), intent(in ) :: t_mid ! temperature [K] + real(r8), dimension(pcols,pver), intent(in ) :: q_mid_in ! specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(in ) :: omega ! vertical pressure velocity [Pa/s] + real(r8), dimension(pcols,pver), intent(in ) :: p_mid_in ! mid-point pressure [Pa] + real(r8), dimension(pcols,pverp),intent(in ) :: p_int_in ! interface pressure [Pa] + real(r8), dimension(pcols,pver), intent(in ) :: p_del_in ! pressure thickness [Pa] + real(r8), dimension(pcols), intent(in ) :: geos ! surface geopotential [m2/s2] + real(r8), dimension(pcols,pver), intent(in ) :: z_mid_in ! mid-point geopotential [m2/s2] + real(r8), dimension(pcols,pverp),intent(in ) :: z_int_in ! interface geopotential [m2/s2] + real(r8), dimension(pcols), intent(in ) :: pbl_hgt ! boundary layer height [m] + real(r8), dimension(pcols), intent(in ) :: tpert ! parcel temperature perturbation [K] + real(r8), dimension(pcols), intent(in ) :: landfrac ! land fraction [] + real(r8),pointer,dimension(:,:), intent(in ) :: t_star ! for DCAPE - prev temperature [K] + real(r8),pointer,dimension(:,:), intent(in ) :: q_star ! for DCAPE - prev sp. humidity [kg/kg] integer, intent( out) :: lengath ! number of active columns in chunk for gathering integer, dimension(pcols), intent( out) :: gather_index ! flag for active columns - integer, dimension(pcols), intent( out) :: maxg ! gathered level indices of max MSE (maxi) + integer, dimension(pcols), intent( out) :: msemax_klev_g ! gathered level indices of max MSE (msemax_klev) integer, dimension(pcols), intent( out) :: jctop ! top-of-deep-convection indices integer, dimension(pcols), intent( out) :: jcbot ! base of cloud indices integer, dimension(pcols), intent( out) :: jt ! gathered top level index of deep cumulus convection real(r8), dimension(pcols), intent( out) :: prec ! output precipitation - real(r8), dimension(pcols,pver), intent( out) :: heat ! dry static energy tendency [W/kg] - real(r8), dimension(pcols,pver), intent( out) :: qtnd ! specific humidity tendency [kg/kg/s] - real(r8), dimension(pcols), intent( out) :: cape ! conv. avail. potential energy [J] - real(r8), dimension(pcols), intent( out) :: dcape ! CAPE generated by dycor (dCAPE) [J] - real(r8), dimension(pcols,pverp),intent( out) :: mcon ! convective mass flux [mb/s] - real(r8), dimension(pcols,pverp),intent( out) :: pflx ! precip flux at each level [?] - real(r8), dimension(pcols,pver), intent( out) :: zdu ! detraining mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: mu ! updraft mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: eu ! updraft entrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: du ! updraft detrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: md ! downdraft mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: ed ! downdraft entrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: p_del ! layer thickness [mb] - real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and maxi [mb] + real(r8), dimension(pcols,pver), intent( out) :: heat ! dry static energy tendency [W/kg] + real(r8), dimension(pcols,pver), intent( out) :: qtnd ! specific humidity tendency [kg/kg/s] + real(r8), dimension(pcols), intent( out) :: cape ! conv. avail. potential energy [J] + real(r8), dimension(pcols), intent( out) :: dcape ! CAPE generated by dycor (dCAPE) [J] + real(r8), dimension(pcols,pverp),intent( out) :: mcon ! convective mass flux [mb/s] + real(r8), dimension(pcols,pverp),intent( out) :: pflx ! precip flux at each level [?] + real(r8), dimension(pcols,pver), intent( out) :: zdu ! detraining mass flux [?] + real(r8), dimension(pcols,pver), intent( out) :: mu ! updraft mass flux [?] + real(r8), dimension(pcols,pver), intent( out) :: eu ! updraft entrainment [?] + real(r8), dimension(pcols,pver), intent( out) :: du ! updraft detrainment [?] + real(r8), dimension(pcols,pver), intent( out) :: md ! downdraft mass flux [?] + real(r8), dimension(pcols,pver), intent( out) :: ed ! downdraft entrainment [?] + real(r8), dimension(pcols,pver), intent( out) :: p_del ! layer thickness [mb] + real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and msemax_klev [mb] real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep real(r8), dimension(pcols), intent( out) :: rliq ! reserved liquid (not yet in cldliq) for energy integrals real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate @@ -209,74 +209,74 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- ! Local variables - real(r8), dimension(pcols,pver) :: s_mid ! scaled dry static energy (t+gz/cp) [K] - real(r8), dimension(pcols,pver) :: q_mid ! local copy of specific humidity [kg/kg] - real(r8), dimension(pcols,pver) :: p_mid ! local copy of mid-point pressure [mb] - real(r8), dimension(pcols,pverp):: p_int ! local copy of interface pressure [mb] - real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] - real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] - real(r8), dimension(pcols) :: z_srf ! surface altitude [m] - real(r8), dimension(pcols) :: mumax ! max value of mu/dp - - integer, dimension(pcols) :: pbl_top ! pbl top indices - integer, dimension(pcols) :: pbl_top_g ! gathered pbl top indices - - real(r8), dimension(pcols,pver) :: t_pcl ! parcel temperature [K] - real(r8), dimension(pcols,pver) :: q_pcl_sat ! parcel saturation specific humidity [kg/kg] - real(r8), dimension(pcols) :: t_pcl_lcl ! parcel temperature at lcl [K] - integer, dimension(pcols) :: lcl ! base level index of deep cumulus convection - integer, dimension(pcols) :: lel ! index of highest theoretical convective plume - integer, dimension(pcols) :: lon ! index of onset level for deep convection - integer, dimension(pcols) :: maxi ! index of level with largest moist static energy - - real(r8), dimension(pcols,pver) :: t_pcl_m1 ! time n-1 parcel temperatures - real(r8), dimension(pcols,pver) :: q_pcl_sat_m1 ! time n-1 parcel saturation specific humidity - real(r8), dimension(pcols) :: t_pcl_lcl_m1 ! time n-1 parcel Temperature at LCL - integer, dimension(pcols) :: lcl_m1 ! time n-1 base level index of deep cumulus convection - integer, dimension(pcols) :: lel_m1 ! time n-1 index of highest theoretical convective plume - integer, dimension(pcols) :: lon_m1 ! time n-1 index of onset level for deep convection - integer, dimension(pcols) :: maxi_m1 ! time n-1 index of level with largest moist static energy - real(r8), dimension(pcols) :: cape_m1 ! time n-1 CAPE - - logical :: cape_calc_msemax_klev ! flag for compute_dilute_cape() - real(r8) :: cape_threshold_loc ! local CAPE threshold - - real(r8), dimension(pcols,pver) :: q_mid_g ! gathered mid-point env specific humidity - real(r8), dimension(pcols,pver) :: q_int_g ! gathered interface env specific humidity - real(r8), dimension(pcols,pver) :: t_mid_g ! gathered temperature at interface - real(r8), dimension(pcols,pver) :: p_mid_g ! gathered values of p_mid - real(r8), dimension(pcols,pver) :: z_mid_g ! gathered values of z_mid - real(r8), dimension(pcols,pver) :: s_mid_g ! gathered values of s - real(r8), dimension(pcols,pver) :: s_int_g ! gathered upper interface dry static energy - real(r8), dimension(pcols,pverp):: z_int_g ! gathered values of z_int - real(r8), dimension(pcols,pver) :: t_pcl_g ! gathered values of t_pcl - real(r8), dimension(pcols,pver) :: q_pcl_sat_g ! gathered values of q_pcl_sat - real(r8), dimension(pcols,pver) :: omega_g ! gathered values of omega - real(r8), dimension(pcols,pver) :: rprd_g ! gathered rain production rate - real(r8), dimension(pcols,pver) :: ql_g ! gathered cloud liquid water - real(r8), dimension(pcols) :: cape_g ! gathered convective available potential energy - real(r8), dimension(pcols) :: t_pcl_lcl_g ! gathered values of t_pcl_lcl - real(r8), dimension(pcols) :: landfrac_g ! gathered landfrac - real(r8), dimension(pcols) :: tpert_g ! gathered values of tpert (temperature perturbation from PBL) - integer, dimension(pcols) :: lcl_g ! gathered values of lcl level index - integer, dimension(pcols) :: lel_g ! gathered values of equilibrium level index - - real(r8), dimension(pcols,pver) :: dqdt ! gathered specific humidity tendency - real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points - real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy - real(r8), dimension(pcols,pver) :: qd ! gathered downdraft specific humidity - real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux - real(r8), dimension(pcols,pver) :: qu ! gathered updraft specific humidity - real(r8), dimension(pcols,pver) :: su ! gathered updraft dry static energy - real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity - real(r8), dimension(pcols,pver) :: dl_g ! gathered detraining cld h2o tend - real(r8), dimension(pcols,pverp):: pflx_g ! gathered precip flux at each level - real(r8), dimension(pcols,pver) :: cu_g ! gathered condensation rate - real(r8), dimension(pcols,pver) :: evp_g ! gathered evap rate of rain in downdraft - - integer, dimension(pcols) :: jlcl ! updraft lifting cond level - integer, dimension(pcols) :: j0 ! detrainment initiation level index - integer, dimension(pcols) :: jd ! downdraft initiation level index + real(r8), dimension(pcols,pver) :: s_mid ! scaled dry static energy (t+gz/cp) [K] + real(r8), dimension(pcols,pver) :: q_mid ! local copy of specific humidity [kg/kg] + real(r8), dimension(pcols,pver) :: p_mid ! local copy of mid-point pressure [mb] + real(r8), dimension(pcols,pverp):: p_int ! local copy of interface pressure [mb] + real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] + real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] + real(r8), dimension(pcols) :: z_srf ! surface altitude [m] + real(r8), dimension(pcols) :: mumax ! max value of mu/dp + + integer, dimension(pcols) :: pbl_top ! pbl top indices + integer, dimension(pcols) :: pbl_top_g ! gathered pbl top indices + + real(r8), dimension(pcols,pver) :: t_pcl ! parcel temperature [K] + real(r8), dimension(pcols,pver) :: q_pcl_sat ! parcel saturation specific humidity [kg/kg] + real(r8), dimension(pcols) :: t_pcl_lcl ! parcel temperature at lcl [K] + integer, dimension(pcols) :: lcl ! base level index of deep cumulus convection + integer, dimension(pcols) :: lel ! index of highest theoretical convective plume + integer, dimension(pcols) :: lon ! index of onset level for deep convection + integer, dimension(pcols) :: msemax_klev ! index of level with largest moist static energy + + real(r8), dimension(pcols,pver) :: t_pcl_m1 ! time n-1 parcel temperatures + real(r8), dimension(pcols,pver) :: q_pcl_sat_m1 ! time n-1 parcel saturation specific humidity + real(r8), dimension(pcols) :: t_pcl_lcl_m1 ! time n-1 parcel Temperature at LCL + integer, dimension(pcols) :: lcl_m1 ! time n-1 base level index of deep cumulus convection + integer, dimension(pcols) :: lel_m1 ! time n-1 index of highest theoretical convective plume + integer, dimension(pcols) :: lon_m1 ! time n-1 index of onset level for deep convection + integer, dimension(pcols) :: msemax_klev_m1 ! time n-1 index of level with largest moist static energy + real(r8), dimension(pcols) :: cape_m1 ! time n-1 CAPE + + logical :: cape_calc_msemax_klev ! flag for compute_dilute_cape() + real(r8) :: cape_threshold_loc ! local CAPE threshold + + real(r8), dimension(pcols,pver) :: q_mid_g ! gathered mid-point env specific humidity + real(r8), dimension(pcols,pver) :: q_int_g ! gathered interface env specific humidity + real(r8), dimension(pcols,pver) :: t_mid_g ! gathered temperature at interface + real(r8), dimension(pcols,pver) :: p_mid_g ! gathered values of p_mid + real(r8), dimension(pcols,pver) :: z_mid_g ! gathered values of z_mid + real(r8), dimension(pcols,pver) :: s_mid_g ! gathered values of s + real(r8), dimension(pcols,pver) :: s_int_g ! gathered upper interface dry static energy + real(r8), dimension(pcols,pverp):: z_int_g ! gathered values of z_int + real(r8), dimension(pcols,pver) :: t_pcl_g ! gathered values of t_pcl + real(r8), dimension(pcols,pver) :: q_pcl_sat_g ! gathered values of q_pcl_sat + real(r8), dimension(pcols,pver) :: omega_g ! gathered values of omega + real(r8), dimension(pcols,pver) :: rprd_g ! gathered rain production rate + real(r8), dimension(pcols,pver) :: ql_g ! gathered cloud liquid water + real(r8), dimension(pcols) :: cape_g ! gathered convective available potential energy + real(r8), dimension(pcols) :: t_pcl_lcl_g ! gathered values of t_pcl_lcl + real(r8), dimension(pcols) :: landfrac_g ! gathered landfrac + real(r8), dimension(pcols) :: tpert_g ! gathered values of tpert (temperature perturbation from PBL) + integer, dimension(pcols) :: lcl_g ! gathered values of lcl level index + integer, dimension(pcols) :: lel_g ! gathered values of equilibrium level index + + real(r8), dimension(pcols,pver) :: dqdt ! gathered specific humidity tendency + real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points + real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy + real(r8), dimension(pcols,pver) :: qd ! gathered downdraft specific humidity + real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux + real(r8), dimension(pcols,pver) :: qu ! gathered updraft specific humidity + real(r8), dimension(pcols,pver) :: su ! gathered updraft dry static energy + real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity + real(r8), dimension(pcols,pver) :: dl_g ! gathered detraining cld h2o tend + real(r8), dimension(pcols,pverp):: pflx_g ! gathered precip flux at each level + real(r8), dimension(pcols,pver) :: cu_g ! gathered condensation rate + real(r8), dimension(pcols,pver) :: evp_g ! gathered evap rate of rain in downdraft + + integer, dimension(pcols) :: jlcl ! updraft lifting cond level + integer, dimension(pcols) :: j0 ! detrainment initiation level index + integer, dimension(pcols) :: jd ! downdraft initiation level index real(r8), dimension(pcols) :: cld_bass_mass_flux ! cloud base mass flux determined from zm_closure() @@ -377,16 +377,16 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & end do do i = 1,ncol - cape_g(i) = 0._r8 - lcl_g(i) = 1 - lel_g(i) = pver - maxg(i) = 1 - t_pcl_lcl_g(i) = 400._r8 - dsubcld(i) = 0._r8 + cape_g(i) = 0._r8 + lcl_g(i) = 1 + lel_g(i) = pver + msemax_klev_g(i) = 1 + t_pcl_lcl_g(i) = 400._r8 + dsubcld(i) = 0._r8 end do !---------------------------------------------------------------------------- - ! Evaluate Tparcel, qs(Tparcel), buoyancy, CAPE, lcl, lel, parcel launch level at index maxi()=hmax + ! Evaluate Tparcel, qs(Tparcel), buoyancy, CAPE, lcl, lel, parcel launch level at index msemax_klev()=hmax ! - call #1, cape_calc_msemax_klev=.true. standard calculation using state of current step ! - call #2, cape_calc_msemax_klev=.false. use launch level (msemax_klev) from previous call ! DCAPE is the difference in CAPE between the two calls using the same launch level @@ -395,7 +395,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & zm_param%num_cin, msg, & q_mid, t_mid, z_mid, p_mid, p_int, & pbl_top, tpert, & - t_pcl, q_pcl_sat, maxi, t_pcl_lcl, & + t_pcl, q_pcl_sat, msemax_klev, t_pcl_lcl, & lcl, lel, cape, & zm_const, zm_param, & cape_calc_msemax_klev ) @@ -403,12 +403,12 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! Calculate dcape trigger condition if ( .not.is_first_step .and. zm_param%trig_dcape ) then cape_calc_msemax_klev = .false. - prev_msemax_klev(:ncol) = maxi(:ncol) + prev_msemax_klev(:ncol) = msemax_klev(:ncol) call compute_dilute_cape( pcols, ncol, pver, pverp, & zm_param%num_cin, msg, & q_star, t_star, z_mid, p_mid, p_int, & pbl_top, tpert, & - t_pcl_m1, q_pcl_sat_m1, maxi_m1, t_pcl_lcl_m1, & + t_pcl_m1, q_pcl_sat_m1, msemax_klev_m1, t_pcl_lcl_m1, & lcl_m1, lel_m1, cape_m1, & zm_const, zm_param, & cape_calc_msemax_klev, prev_msemax_klev ) @@ -445,7 +445,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & cape_g(i) = cape(gather_index(i)) lcl_g(i) = lcl(gather_index(i)) lel_g(i) = lel(gather_index(i)) - maxg(i) = maxi(gather_index(i)) + msemax_klev_g(i) = msemax_klev(gather_index(i)) t_pcl_lcl_g(i) = t_pcl_lcl(gather_index(i)) landfrac_g(i) = landfrac(gather_index(i)) pbl_top_g(i) = pbl_top(gather_index(i)) @@ -482,7 +482,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! calculate sub-cloud layer pressure "thickness" for closure and tendency calculations do k = msg+1, pver do i = 1,lengath - if (k >= maxg(i)) then + if (k >= msemax_klev_g(i)) then dsubcld(i) = dsubcld(i) + p_del(i,k) end if end do @@ -516,7 +516,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & call zm_cloud_properties(pcols, lengath, pver, pverp, msg, zm_param%limcnv, & p_mid_g, z_mid_g, z_int_g, t_mid_g, s_mid_g, s_int_g, q_mid_g, & landfrac_g, tpert_g, & - maxg, lel_g, jt, jlcl, j0, jd, & + msemax_klev_g, lel_g, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & su, qu, ql_g, sd, qd, & q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & @@ -542,7 +542,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! apply closure assumption to calculate cloud base mass flux call zm_closure(pcols, lengath, pver, pverp, msg, cape_threshold_loc, & - lcl_g, lel_g, jt, maxg, dsubcld, & + lcl_g, lel_g, jt, msemax_klev_g, dsubcld, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, su, qu, & @@ -606,7 +606,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & - jt, maxg, dsubcld, p_del, s_int_g, q_int_g, su, qu, & + jt, msemax_klev_g, dsubcld, p_del, & + s_int_g, q_int_g, su, qu, & mu, du, md, sd, qd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -642,7 +643,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! scatter 1d variables do i = 1,lengath jctop(gather_index(i)) = jt(i) - jcbot(gather_index(i)) = maxg(i) + jcbot(gather_index(i)) = msemax_klev_g(i) pflx(gather_index(i),pverp) = pflx_g(i,pverp) end do From ff26ba8808178c4fd9e88680a9706dc604fdbc74 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 09:20:00 -0800 Subject: [PATCH 192/398] add comments --- components/eam/src/physics/cam/physpkg.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/eam/src/physics/cam/physpkg.F90 b/components/eam/src/physics/cam/physpkg.F90 index d8dd59ed1954..4b6572ad0a68 100644 --- a/components/eam/src/physics/cam/physpkg.F90 +++ b/components/eam/src/physics/cam/physpkg.F90 @@ -2387,12 +2387,12 @@ subroutine tphysbc (ztodt, & !BSINGH - Following variables are from zm_conv_intr, which are moved here as they are now used ! by aero_model_wetdep subroutine. - real(r8):: mu(pcols,pver) - real(r8):: eu(pcols,pver) - real(r8):: du(pcols,pver) - real(r8):: md(pcols,pver) - real(r8):: ed(pcols,pver) - real(r8):: dp(pcols,pver) + real(r8):: mu(pcols,pver) ! ZM deep convection gathered updraft mass flux + real(r8):: eu(pcols,pver) ! ZM deep convection gathered updraft entrainment + real(r8):: du(pcols,pver) ! ZM deep convection gathered updraft detrainment + real(r8):: md(pcols,pver) ! ZM deep convection gathered downdraft mass flux + real(r8):: ed(pcols,pver) ! ZM deep convection gathered downdraft entrainment + real(r8):: dp(pcols,pver) ! ZM deep convection gathered pressure thickness [mb] ! wg layer thickness in mbs (between upper/lower interface). real(r8):: dsubcld(pcols) From c3d61435ed162c95451b836a4efd9b76882680c7 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 09:35:16 -0800 Subject: [PATCH 193/398] rename su --- components/eam/src/physics/cam/zm/zm_conv.F90 | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index fb24495b0fba..66e9bc12138f 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -267,7 +267,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: qd ! gathered downdraft specific humidity real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux real(r8), dimension(pcols,pver) :: qu ! gathered updraft specific humidity - real(r8), dimension(pcols,pver) :: su ! gathered updraft dry static energy + real(r8), dimension(pcols,pver) :: s_upd ! gathered updraft dry static energy real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity real(r8), dimension(pcols,pver) :: dl_g ! gathered detraining cld h2o tend real(r8), dimension(pcols,pverp):: pflx_g ! gathered precip flux at each level @@ -518,7 +518,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & landfrac_g, tpert_g, & msemax_klev_g, lel_g, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - su, qu, ql_g, sd, qd, & + s_upd, qu, ql_g, sd, qd, & q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & aero, loc_microp_st ) @@ -545,7 +545,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & lcl_g, lel_g, jt, msemax_klev_g, dsubcld, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & - t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, su, qu, & + t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, qu, & mc, du, mu, md, qd, sd, cape_g, cld_bass_mass_flux ) !---------------------------------------------------------------------------- @@ -607,7 +607,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & jt, msemax_klev_g, dsubcld, p_del, & - s_int_g, q_int_g, su, qu, & + s_int_g, q_int_g, s_upd, qu, & mu, du, md, sd, qd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -1230,7 +1230,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & landfrac, tpert_g, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - su, qu, ql, sd, qd, & + s_upd, qu, ql, sd, qd, & qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) !---------------------------------------------------------------------------- @@ -1266,7 +1266,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(out) :: md ! downdraft mass flux real(r8), dimension(pcols,pver), intent(out) :: ed ! downdraft entrainment rate real(r8), dimension(pcols,pver), intent(out) :: mc ! net mass flux - real(r8), dimension(pcols,pver), intent(out) :: su ! updraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(out) :: s_upd ! updraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: qu ! updraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water real(r8), dimension(pcols,pver), intent(out) :: sd ! dndraft dry static energy [K] (normalized) @@ -1364,7 +1364,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & * zm_const%epsilo*zm_const%latvap/(zm_const%rdair*t_mid(i,k)**2) & * zm_const%latvap/zm_const%cpair ! cloud thermodynamic variables - su(i,k) = s_mid(i,k) + s_upd(i,k) = s_mid(i,k) sd(i,k) = s_mid(i,k) qd(i,k) = q_mid(i,k) qds(i,k) = q_mid(i,k) @@ -1445,10 +1445,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. if (zm_param%tpert_fix) then hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add - su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add + s_upd(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add else hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i)) - su(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i) + s_upd(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i) end if end if end do ! i @@ -1592,12 +1592,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do i = 1,ncol if (k == jb(i) .and. lambda_max(i) > 0._r8) then qu(i,k) = q_mid(i,jb(i)) - su(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair + s_upd(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. lambda_max(i) > 0._r8) then - su(i,k) = mu(i,k+1)/mu(i,k)*su(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s_mid(i,k) + s_upd(i,k) = mu(i,k+1)/mu(i,k)*s_upd(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s_mid(i,k) qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q_mid(i,k) - du(i,k)*qst(i,k)) - tu = su(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) + tu = s_upd(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) call qsat_hPa(tu, (p_mid(i,k)+p_mid(i,k-1))/2._r8, estu, qstu) if (qu(i,k) >= qstu) then jlcl(i) = k @@ -1614,7 +1614,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = msg+2, pver do i = 1,ncol if ((k > jt(i) .and. k <= jlcl(i)) .and. lambda_max(i) > 0._r8) then - su(i,k) = s_int(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) + s_upd(i,k) = s_int(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if end do ! i @@ -1628,10 +1628,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) if ( k>=jt(i) .and. k Date: Wed, 10 Dec 2025 09:40:40 -0800 Subject: [PATCH 194/398] rename qd --- components/eam/src/physics/cam/zm/zm_conv.F90 | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 66e9bc12138f..9f300c83280c 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -264,9 +264,9 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: dqdt ! gathered specific humidity tendency real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy - real(r8), dimension(pcols,pver) :: qd ! gathered downdraft specific humidity + real(r8), dimension(pcols,pver) :: q_dnd ! gathered downdraft specific humidity real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux - real(r8), dimension(pcols,pver) :: qu ! gathered updraft specific humidity + real(r8), dimension(pcols,pver) :: q_upd ! gathered updraft specific humidity real(r8), dimension(pcols,pver) :: s_upd ! gathered updraft dry static energy real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity real(r8), dimension(pcols,pver) :: dl_g ! gathered detraining cld h2o tend @@ -518,7 +518,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & landfrac_g, tpert_g, & msemax_klev_g, lel_g, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - s_upd, qu, ql_g, sd, qd, & + s_upd, q_upd, ql_g, sd, q_dnd, & q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & aero, loc_microp_st ) @@ -545,8 +545,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & lcl_g, lel_g, jt, msemax_klev_g, dsubcld, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & - t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, qu, & - mc, du, mu, md, qd, sd, cape_g, cld_bass_mass_flux ) + t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, q_upd, & + mc, du, mu, md, q_dnd, sd, cape_g, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. @@ -607,8 +607,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & jt, msemax_klev_g, dsubcld, p_del, & - s_int_g, q_int_g, s_upd, qu, & - mu, du, md, sd, qd, ql_g, evp_g, cu_g, & + s_int_g, q_int_g, s_upd, q_upd, & + mu, du, md, sd, q_dnd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -1094,7 +1094,7 @@ end subroutine zm_calc_fractional_entrainment subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mu, md, ed, sd, qd, hd, qds, evp, totevp ) + mu, md, ed, sd, q_dnd, hd, qds, evp, totevp ) !---------------------------------------------------------------------------- ! Purpose: Calculate properties of ZM downdrafts ! Notes: @@ -1128,9 +1128,9 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & real(r8), dimension(pcols,pver), intent(inout) :: md ! downdraft mass flux real(r8), dimension(pcols,pver), intent(inout) :: ed ! downdraft entrainment rate real(r8), dimension(pcols,pver), intent(inout) :: sd ! dndraft dry static energy [K] (normalized) - real(r8), dimension(pcols,pver), intent(inout) :: qd ! dndraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(inout) :: q_dnd ! dndraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(inout) :: hd ! dndraft moist static energy - real(r8), dimension(pcols,pver), intent(inout) :: qds ! dndraft saturation specific humdity + real(r8), dimension(pcols,pver), intent(inout) :: q_dnd_sat ! dndraft saturation specific humdity real(r8), dimension(pcols,pver), intent(inout) :: evp ! evaporation rate real(r8), dimension(pcols), intent(inout) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) !---------------------------------------------------------------------------- @@ -1186,7 +1186,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do k = msg+2, pver do i = 1,ncol if ((k >= jd(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8 .and. jd(i) < jb(i)) then - qds(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) + q_dnd_sat(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) end if end do ! i end do ! k @@ -1194,8 +1194,8 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & !---------------------------------------------------------------------------- ! downdraft quantities at source level do i = 1,ncol - qd(i,jd(i)) = qds(i,jd(i)) - sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*qd(i,jd(i)))/zm_const%cpair + q_dnd(i,jd(i)) = q_dnd_sat(i,jd(i)) + sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*q_dnd(i,jd(i)))/zm_const%cpair end do !---------------------------------------------------------------------------- @@ -1203,8 +1203,8 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do k = msg+2, pver do i = 1,ncol if (k >= jd(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8) then - qd(i,k+1) = qds(i,k+1) - evp(i,k) = -ed(i,k)*q_mid(i,k) + (md(i,k)*qd(i,k)-md(i,k+1)*qd(i,k+1))/dz(i,k) + q_dnd(i,k+1) = q_dnd_sat(i,k+1) + evp(i,k) = -ed(i,k)*q_mid(i,k) + (md(i,k)*q_dnd(i,k)-md(i,k+1)*q_dnd(i,k+1))/dz(i,k) evp(i,k) = max(evp(i,k),0._r8) mdt = min(md(i,k+1),-small) if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) @@ -1215,7 +1215,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & end do ! k do i = 1,ncol - totevp(i) = totevp(i) + md(i,jd(i))*qd(i,jd(i)) - md(i,jb(i))*qd(i,jb(i)) + totevp(i) = totevp(i) + md(i,jd(i))*q_dnd(i,jd(i)) - md(i,jb(i))*q_dnd(i,jb(i)) end do !---------------------------------------------------------------------------- @@ -1230,7 +1230,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & landfrac, tpert_g, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - s_upd, qu, ql, sd, qd, & + s_upd, q_upd, ql, sd, q_dnd, & qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) !---------------------------------------------------------------------------- @@ -1267,10 +1267,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(out) :: ed ! downdraft entrainment rate real(r8), dimension(pcols,pver), intent(out) :: mc ! net mass flux real(r8), dimension(pcols,pver), intent(out) :: s_upd ! updraft dry static energy [K] (normalized) - real(r8), dimension(pcols,pver), intent(out) :: qu ! updraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(out) :: q_upd ! updraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water real(r8), dimension(pcols,pver), intent(out) :: sd ! dndraft dry static energy [K] (normalized) - real(r8), dimension(pcols,pver), intent(out) :: qd ! dndraft specific humidity [kg/kg] + real(r8), dimension(pcols,pver), intent(out) :: q_dnd ! dndraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: qst ! env saturation mixing ratio real(r8), dimension(pcols,pver), intent(out) :: cu ! condensation rate real(r8), dimension(pcols,pver), intent(out) :: evp ! evaporation rate @@ -1290,7 +1290,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst real(r8), dimension(pcols,pver) :: hsthat ! interface interpolated hst real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma - real(r8), dimension(pcols,pver) :: qds ! dndraft saturation specific humdity + real(r8), dimension(pcols,pver) :: q_dnd_sat ! dndraft saturation specific humdity real(r8), dimension(pcols) :: c0mask ! land/ocean modification real(r8), dimension(pcols) :: totpcp ! total precip for dndraft proportionality factor - see eq (4.106) real(r8), dimension(pcols) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) @@ -1366,9 +1366,9 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! cloud thermodynamic variables s_upd(i,k) = s_mid(i,k) sd(i,k) = s_mid(i,k) - qd(i,k) = q_mid(i,k) - qds(i,k) = q_mid(i,k) - qu(i,k) = q_mid(i,k) + q_dnd(i,k) = q_mid(i,k) + q_dnd_sat(i,k) = q_mid(i,k) + q_upd(i,k) = q_mid(i,k) h_env(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q_mid(i,k) h_env_sat(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*qst(i,k) hu(i,k) = h_env(i,k) @@ -1591,15 +1591,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+2, -1 do i = 1,ncol if (k == jb(i) .and. lambda_max(i) > 0._r8) then - qu(i,k) = q_mid(i,jb(i)) - s_upd(i,k) = (hu(i,k)-zm_const%latvap*qu(i,k))/zm_const%cpair + q_upd(i,k) = q_mid(i,jb(i)) + s_upd(i,k) = (hu(i,k)-zm_const%latvap*q_upd(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. lambda_max(i) > 0._r8) then s_upd(i,k) = mu(i,k+1)/mu(i,k)*s_upd(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s_mid(i,k) - qu(i,k) = mu(i,k+1)/mu(i,k)*qu(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q_mid(i,k) - du(i,k)*qst(i,k)) + q_upd(i,k) = mu(i,k+1)/mu(i,k)*q_upd(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q_mid(i,k) - du(i,k)*qst(i,k)) tu = s_upd(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) call qsat_hPa(tu, (p_mid(i,k)+p_mid(i,k-1))/2._r8, estu, qstu) - if (qu(i,k) >= qstu) then + if (q_upd(i,k) >= qstu) then jlcl(i) = k kount = kount + 1 done(i) = .true. @@ -1615,7 +1615,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do i = 1,ncol if ((k > jt(i) .and. k <= jlcl(i)) .and. lambda_max(i) > 0._r8) then s_upd(i,k) = s_int(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) - qu(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) + q_upd(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if end do ! i end do ! k @@ -1682,7 +1682,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_mphy( pcols, ncol, msg, & zm_const%grav, zm_const%cpair, zm_const%rdair, & zm_param%auto_fac, zm_param%accr_fac, zm_param%micro_dcs, & - jb, jt, jlcl, s_upd, qu, mu, du, eu, z_int, p_mid, t_mid, q_mid, gamhat, lambda_max, & + jb, jt, jlcl, s_upd, q_upd, mu, du, eu, z_int, p_mid, t_mid, q_mid, gamhat, lambda_max, & loc_microp_st%cmel, loc_microp_st%cmei, aero, & loc_microp_st%qliq, loc_microp_st%qice, loc_microp_st%qnl, loc_microp_st%qni, & loc_microp_st%qcde, loc_microp_st%qide, loc_microp_st%ncde, loc_microp_st%nide, & @@ -1771,7 +1771,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mu, md, ed, sd, qd, hd, qds, evp, totevp) + mu, md, ed, sd, q_dnd, hd, q_dnd_sat, evp, totevp) !---------------------------------------------------------------------------- ! ensure totpcp and totevp are non-negative @@ -1865,8 +1865,8 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & lcl, lel, jt, mx, dsubcld, & z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & - t_pcl_lcl, t_pcl, q_pcl_sat, s_upd, qu, & - mc, du, mu, md, qd, sd, cape, cld_bass_mass_flux ) + t_pcl_lcl, t_pcl, q_pcl_sat, s_upd, q_upd, & + mc, du, mu, md, q_dnd, sd, cape, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the ! revised quasi-equilibrium hypothesis of Z02, in which a @@ -1907,12 +1907,12 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: t_pcl ! parcel temperature real(r8), dimension(pcols,pver), intent(in ) :: q_pcl_sat ! parcel specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_upd ! updraft dry static energy (normalized) - real(r8), dimension(pcols,pver), intent(in ) :: qu ! updraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: q_upd ! updraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux real(r8), dimension(pcols,pver), intent(in ) :: du ! detrainment from updraft real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux real(r8), dimension(pcols,pver), intent(in ) :: md ! dndraft mass flux - real(r8), dimension(pcols,pver), intent(in ) :: qd ! dndraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! dndraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: sd ! dndraft dry static energy real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy real(r8), dimension(pcols), intent(out) :: cld_bass_mass_flux! cloud base mass flux @@ -1954,8 +1954,8 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & *( mu(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & +md(i,mx(i))*(s_int(i,mx(i))-sd(i,mx(i))) ) dqbdt(i) = (1._r8/dsubcld(i)) & - *( mu(i,mx(i))*(q_int(i,mx(i))-qu(i,mx(i))) & - +md(i,mx(i))*(q_int(i,mx(i))-qd(i,mx(i))) ) + *( mu(i,mx(i))*(q_int(i,mx(i))-q_upd(i,mx(i))) & + +md(i,mx(i))*(q_int(i,mx(i))-q_dnd(i,mx(i))) ) debdt = zm_const%epsilo*p_mid(i,mx(i)) / (zm_const%epsilo+q_mid(i,mx(i)))**2 * dqbdt(i) dtldt(i) = -2840._r8 * (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 @@ -1971,18 +1971,18 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & *(mu(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & + md(i,k+1)*(sd(i,k+1)-s_int(i,k+1))) dqmdt(i,k) = (1._r8/p_del(i,k)) & - *(mu(i,k+1)*(qu(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & - + md(i,k+1)*(qd(i,k+1)-q_int(i,k+1))) + *(mu(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & + + md(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1))) end if ! below cloud top if ( k>jt(i) .and. k mx(i)) then dsdt(i,k) = dsdt(i,k-1) dqdt(i,k) = dqdt(i,k-1) From b192953da0e62110925a8b818fe6d4c867e10553 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 09:42:58 -0800 Subject: [PATCH 195/398] rename sd --- components/eam/src/physics/cam/zm/zm_conv.F90 | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 9f300c83280c..764538b08104 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -263,7 +263,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: dqdt ! gathered specific humidity tendency real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points - real(r8), dimension(pcols,pver) :: sd ! gathered downdraft dry static energy + real(r8), dimension(pcols,pver) :: s_dnd ! gathered downdraft dry static energy real(r8), dimension(pcols,pver) :: q_dnd ! gathered downdraft specific humidity real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux real(r8), dimension(pcols,pver) :: q_upd ! gathered updraft specific humidity @@ -518,7 +518,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & landfrac_g, tpert_g, & msemax_klev_g, lel_g, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - s_upd, q_upd, ql_g, sd, q_dnd, & + s_upd, q_upd, ql_g, s_dnd, q_dnd, & q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & aero, loc_microp_st ) @@ -546,7 +546,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, q_upd, & - mc, du, mu, md, q_dnd, sd, cape_g, cld_bass_mass_flux ) + mc, du, mu, md, q_dnd, s_dnd, cape_g, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. @@ -608,7 +608,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & jt, msemax_klev_g, dsubcld, p_del, & s_int_g, q_int_g, s_upd, q_upd, & - mu, du, md, sd, q_dnd, ql_g, evp_g, cu_g, & + mu, du, md, s_dnd, q_dnd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -1094,7 +1094,7 @@ end subroutine zm_calc_fractional_entrainment subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mu, md, ed, sd, q_dnd, hd, qds, evp, totevp ) + mu, md, ed, s_dnd, q_dnd, hd, qds, evp, totevp ) !---------------------------------------------------------------------------- ! Purpose: Calculate properties of ZM downdrafts ! Notes: @@ -1127,7 +1127,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux real(r8), dimension(pcols,pver), intent(inout) :: md ! downdraft mass flux real(r8), dimension(pcols,pver), intent(inout) :: ed ! downdraft entrainment rate - real(r8), dimension(pcols,pver), intent(inout) :: sd ! dndraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(inout) :: s_dnd ! dndraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(inout) :: q_dnd ! dndraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(inout) :: hd ! dndraft moist static energy real(r8), dimension(pcols,pver), intent(inout) :: q_dnd_sat ! dndraft saturation specific humdity @@ -1195,7 +1195,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & ! downdraft quantities at source level do i = 1,ncol q_dnd(i,jd(i)) = q_dnd_sat(i,jd(i)) - sd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*q_dnd(i,jd(i)))/zm_const%cpair + s_dnd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*q_dnd(i,jd(i)))/zm_const%cpair end do !---------------------------------------------------------------------------- @@ -1208,7 +1208,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & evp(i,k) = max(evp(i,k),0._r8) mdt = min(md(i,k+1),-small) if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) - sd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s_mid(i,k))*dz(i,k) + md(i,k)*sd(i,k))/mdt + s_dnd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s_mid(i,k))*dz(i,k) + md(i,k)*s_dnd(i,k))/mdt totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q_mid(i,k) end if end do ! i @@ -1230,7 +1230,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & landfrac, tpert_g, & jb, lel, jt, jlcl, j0, jd, & mu, eu, du, md, ed, mc, & - s_upd, q_upd, ql, sd, q_dnd, & + s_upd, q_upd, ql, s_dnd, q_dnd, & qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) !---------------------------------------------------------------------------- @@ -1269,7 +1269,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver), intent(out) :: s_upd ! updraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: q_upd ! updraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water - real(r8), dimension(pcols,pver), intent(out) :: sd ! dndraft dry static energy [K] (normalized) + real(r8), dimension(pcols,pver), intent(out) :: s_dnd ! dndraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: q_dnd ! dndraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: qst ! env saturation mixing ratio real(r8), dimension(pcols,pver), intent(out) :: cu ! condensation rate @@ -1365,7 +1365,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & * zm_const%latvap/zm_const%cpair ! cloud thermodynamic variables s_upd(i,k) = s_mid(i,k) - sd(i,k) = s_mid(i,k) + s_dnd(i,k) = s_mid(i,k) q_dnd(i,k) = q_mid(i,k) q_dnd_sat(i,k) = q_mid(i,k) q_upd(i,k) = q_mid(i,k) @@ -1771,7 +1771,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mu, md, ed, sd, q_dnd, hd, q_dnd_sat, evp, totevp) + mu, md, ed, s_dnd, q_dnd, hd, q_dnd_sat, evp, totevp) !---------------------------------------------------------------------------- ! ensure totpcp and totevp are non-negative @@ -1866,7 +1866,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & t_pcl_lcl, t_pcl, q_pcl_sat, s_upd, q_upd, & - mc, du, mu, md, q_dnd, sd, cape, cld_bass_mass_flux ) + mc, du, mu, md, q_dnd, s_dnd, cape, cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the ! revised quasi-equilibrium hypothesis of Z02, in which a @@ -1913,7 +1913,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux real(r8), dimension(pcols,pver), intent(in ) :: md ! dndraft mass flux real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! dndraft specific humidity - real(r8), dimension(pcols,pver), intent(in ) :: sd ! dndraft dry static energy + real(r8), dimension(pcols,pver), intent(in ) :: s_dnd ! dndraft dry static energy real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy real(r8), dimension(pcols), intent(out) :: cld_bass_mass_flux! cloud base mass flux !---------------------------------------------------------------------------- @@ -1952,7 +1952,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & eb = p_mid(i,mx(i))*q_mid(i,mx(i))/ (zm_const%epsilo+q_mid(i,mx(i))) dtbdt(i) = (1._r8/dsubcld(i)) & *( mu(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & - +md(i,mx(i))*(s_int(i,mx(i))-sd(i,mx(i))) ) + +md(i,mx(i))*(s_int(i,mx(i))-s_dnd(i,mx(i))) ) dqbdt(i) = (1._r8/dsubcld(i)) & *( mu(i,mx(i))*(q_int(i,mx(i))-q_upd(i,mx(i))) & +md(i,mx(i))*(q_int(i,mx(i))-q_dnd(i,mx(i))) ) @@ -1969,7 +1969,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & if (k==jt(i)) then dtmdt(i,k) = (1._r8/p_del(i,k)) & *(mu(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & - + md(i,k+1)*(sd(i,k+1)-s_int(i,k+1))) + + md(i,k+1)*(s_dnd(i,k+1)-s_int(i,k+1))) dqmdt(i,k) = (1._r8/p_del(i,k)) & *(mu(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & + md(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1))) @@ -1981,8 +1981,8 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & - zm_const%latvap/zm_const%cpair * du(i,k)*( beta*ql(i,k) + (1-beta)*ql(i,k+1) ) dqmdt(i,k) = ( mu(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+zm_const%cpair/zm_const%latvap*(s_upd(i,k+1)-s_mid(i,k))) & -mu(i,k )*(q_upd(i,k )-q_int(i,k )+zm_const%cpair/zm_const%latvap*(s_upd(i,k )-s_mid(i,k))) & - +md(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1)+zm_const%cpair/zm_const%latvap*(sd(i,k+1)-s_mid(i,k))) & - -md(i,k )*(q_dnd(i,k )-q_int(i,k )+zm_const%cpair/zm_const%latvap*(sd(i,k )-s_mid(i,k))))/p_del(i,k) & + +md(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1)+zm_const%cpair/zm_const%latvap*(s_dnd(i,k+1)-s_mid(i,k))) & + -md(i,k )*(q_dnd(i,k )-q_int(i,k )+zm_const%cpair/zm_const%latvap*(s_dnd(i,k )-s_mid(i,k))))/p_del(i,k) & + du(i,k)*(beta*ql(i,k)+(1-beta)*ql(i,k+1)) end if end do @@ -2045,7 +2045,7 @@ end subroutine zm_closure subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & jt, mx, dsubcld, p_del, s_int, q_int, s_upd, q_upd, & - mu, du, md, sd, q_dnd, ql, evp, cu, & + mu, du, md, s_dnd, q_dnd, ql, evp, cu, & dsdt, dqdt, dl, & loc_microp_st) !---------------------------------------------------------------------------- @@ -2070,8 +2070,8 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux real(r8), dimension(pcols,pver), intent(in ) :: du ! updraft detrainment real(r8), dimension(pcols,pver), intent(in ) :: md ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(in ) :: sd ! downdraft dry static energy - real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! downdraft specific humidity + real(r8), dimension(pcols,pver), intent(in ) :: s_dnd ! downdraft dry static energy + real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! downdraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: ql ! cloud liquid water real(r8), dimension(pcols,pver), intent(in ) :: evp ! evaporation real(r8), dimension(pcols,pver), intent(in ) :: cu ! updraft condensation @@ -2120,7 +2120,7 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & dsdt(i,k) = -zm_const%latvap/zm_const%cpair*emc + & (+mu(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)) - mu(i,k)*(s_upd(i,k)-s_int(i,k)) & - +md(i,k+1)*(sd(i,k+1)-s_int(i,k+1)) - md(i,k)*(sd(i,k)-s_int(i,k)) & + +md(i,k+1)*(s_dnd(i,k+1)-s_int(i,k+1)) - md(i,k)*(s_dnd(i,k)-s_int(i,k)) & )/p_del(i,k) dqdt(i,k) = emc + & @@ -2152,7 +2152,7 @@ subroutine zm_calc_output_tend(pcols, ncol, pver, pverp, msg, & do i = 1,ncol if (k == mx(i)) then dsdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(s_upd(i,k)-s_int(i,k)) & - -md(i,k)*(sd(i,k)-s_int(i,k)) ) + -md(i,k)*(s_dnd(i,k)-s_int(i,k)) ) dqdt(i,k) = (1._r8/dsubcld(i))* (-mu(i,k)*(q_upd(i,k)-q_int(i,k)) & -md(i,k)*(q_dnd(i,k)-q_int(i,k)) ) else if (k > mx(i)) then From 4e4b92793a4d00cae7cc321d5c029ca9fbb8a509 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 11:40:10 -0800 Subject: [PATCH 196/398] lots more renaming --- components/eam/src/physics/cam/zm/zm_conv.F90 | 377 +++++++++--------- 1 file changed, 190 insertions(+), 187 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 764538b08104..8a0ab211510d 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -154,7 +154,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & tpert, landfrac, t_star, q_star, & lengath, gather_index, msemax_klev_g, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & - mcon, pflx, zdu, mu, eu, du, md, ed, p_del, dsubcld, & + mcon, pflx, zdu, mfx_upd, ent_upd, det_upd, mfx_dnd, ent_dnd, p_del, dsubcld, & ql, rliq, rprd, dlf, aero, microp_st ) !---------------------------------------------------------------------------- ! Purpose: Main driver for Zhang-Mcfarlane convection scheme @@ -194,11 +194,11 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pverp),intent( out) :: mcon ! convective mass flux [mb/s] real(r8), dimension(pcols,pverp),intent( out) :: pflx ! precip flux at each level [?] real(r8), dimension(pcols,pver), intent( out) :: zdu ! detraining mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: mu ! updraft mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: eu ! updraft entrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: du ! updraft detrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: md ! downdraft mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: ed ! downdraft entrainment [?] + real(r8), dimension(pcols,pver), intent( out) :: mfx_upd ! updraft mass flux [?] + real(r8), dimension(pcols,pver), intent( out) :: ent_upd ! updraft entrainment [?] + real(r8), dimension(pcols,pver), intent( out) :: det_upd ! updraft detrainment [?] + real(r8), dimension(pcols,pver), intent( out) :: mfx_dnd ! downdraft mass flux [?] + real(r8), dimension(pcols,pver), intent( out) :: ent_dnd ! downdraft entrainment [?] real(r8), dimension(pcols,pver), intent( out) :: p_del ! layer thickness [mb] real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and msemax_klev [mb] real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep @@ -216,7 +216,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] real(r8), dimension(pcols) :: z_srf ! surface altitude [m] - real(r8), dimension(pcols) :: mumax ! max value of mu/dp + real(r8), dimension(pcols) :: mfx_upd_max ! max value of mfx_upd/dp integer, dimension(pcols) :: pbl_top ! pbl top indices integer, dimension(pcols) :: pbl_top_g ! gathered pbl top indices @@ -265,7 +265,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points real(r8), dimension(pcols,pver) :: s_dnd ! gathered downdraft dry static energy real(r8), dimension(pcols,pver) :: q_dnd ! gathered downdraft specific humidity - real(r8), dimension(pcols,pver) :: mc ! gathered net upward (scaled by mb) cloud mass flux + real(r8), dimension(pcols,pver) :: mfx_net ! gathered net upward (scaled by mb) cloud mass flux real(r8), dimension(pcols,pver) :: q_upd ! gathered updraft specific humidity real(r8), dimension(pcols,pver) :: s_upd ! gathered updraft dry static energy real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity @@ -517,7 +517,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & p_mid_g, z_mid_g, z_int_g, t_mid_g, s_mid_g, s_int_g, q_mid_g, & landfrac_g, tpert_g, & msemax_klev_g, lel_g, jt, jlcl, j0, jd, & - mu, eu, du, md, ed, mc, & + mfx_upd, ent_upd, det_upd, mfx_dnd, ent_dnd, mfx_net, & s_upd, q_upd, ql_g, s_dnd, q_dnd, & q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & aero, loc_microp_st ) @@ -526,12 +526,12 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! convert from units of "per length" [1/m] to "per pressure" [1/mb]. do k = msg+1, pver do i = 1,lengath - du (i,k) = du (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - eu (i,k) = eu (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - ed (i,k) = ed (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - cu_g (i,k) = cu_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - rprd_g(i,k) = rprd_g(i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - evp_g (i,k)= evp_g (i,k)* (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + det_upd(i,k)= det_upd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + ent_upd(i,k)= ent_upd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + ent_dnd(i,k)= ent_dnd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + cu_g(i,k) = cu_g(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + rprd_g(i,k) = rprd_g(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + evp_g(i,k) = evp_g(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) if (zm_param%zm_microp) then loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) @@ -546,17 +546,18 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, q_upd, & - mc, du, mu, md, q_dnd, s_dnd, cape_g, cld_bass_mass_flux ) + mfx_net, det_upd, mfx_upd, mfx_dnd, q_dnd, s_dnd, cape_g, & + cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. do i = 1,lengath - mumax(i) = 0 + mfx_upd_max(i) = 0 do k = msg+2, pver - mumax(i) = max(mumax(i), mu(i,k)/p_del(i,k)) + mfx_upd_max(i) = max(mfx_upd_max(i), mfx_upd(i,k)/p_del(i,k)) end do - if (mumax(i) > 0._r8) then - cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),1/(time_step*mumax(i))) + if (mfx_upd_max(i) > 0._r8) then + cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),1/(time_step*mfx_upd_max(i))) else cld_bass_mass_flux(i) = 0._r8 end if @@ -582,16 +583,16 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & if ( zm_param%zm_microp .and. cld_bass_mass_flux(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) ! scale variables do k = msg+1,pver - mu (i,k) = mu (i,k) *cld_bass_mass_flux(i) - md (i,k) = md (i,k) *cld_bass_mass_flux(i) - mc (i,k) = mc (i,k) *cld_bass_mass_flux(i) - du (i,k) = du (i,k) *cld_bass_mass_flux(i) - eu (i,k) = eu (i,k) *cld_bass_mass_flux(i) - ed (i,k) = ed (i,k) *cld_bass_mass_flux(i) - rprd_g(i,k) = rprd_g(i,k) *cld_bass_mass_flux(i) - cu_g (i,k) = cu_g (i,k) *cld_bass_mass_flux(i) - evp_g (i,k) = evp_g (i,k) *cld_bass_mass_flux(i) - pflx_g(i,k+1) = pflx_g(i,k+1)*cld_bass_mass_flux(i)*100._r8/zm_const%grav + mfx_upd(i,k) = mfx_upd(i,k) *cld_bass_mass_flux(i) + mfx_dnd(i,k) = mfx_dnd(i,k) *cld_bass_mass_flux(i) + mfx_net(i,k) = mfx_net(i,k) *cld_bass_mass_flux(i) + det_upd(i,k) = det_upd(i,k) *cld_bass_mass_flux(i) + ent_upd(i,k) = ent_upd(i,k) *cld_bass_mass_flux(i) + ent_dnd(i,k) = ent_dnd(i,k) *cld_bass_mass_flux(i) + rprd_g(i,k) = rprd_g(i,k) *cld_bass_mass_flux(i) + cu_g(i,k) = cu_g(i,k) *cld_bass_mass_flux(i) + evp_g(i,k) = evp_g(i,k) *cld_bass_mass_flux(i) + pflx_g(i,k+1) = pflx_g(i,k+1) *cld_bass_mass_flux(i)*100._r8/zm_const%grav ! scale microphysics variables if (zm_param%zm_microp) then loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k)*cld_bass_mass_flux(i) @@ -607,8 +608,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & jt, msemax_klev_g, dsubcld, p_del, & - s_int_g, q_int_g, s_upd, q_upd, & - mu, du, md, s_dnd, q_dnd, ql_g, evp_g, cu_g, & + s_int_g, q_int_g, s_upd, q_upd, mfx_upd, det_upd, & + mfx_dnd, s_dnd, q_dnd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -630,14 +631,14 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & do i = 1,lengath ! q is updated to compute net precip. q_mid(gather_index(i),k) = q_mid_in(gather_index(i),k) + time_step*dqdt(i,k) - qtnd(gather_index(i),k) = dqdt (i,k) - rprd(gather_index(i),k) = rprd_g (i,k) - zdu (gather_index(i),k) = du (i,k) - mcon(gather_index(i),k) = mc (i,k) - heat(gather_index(i),k) = dsdt (i,k)*zm_const%cpair - dlf (gather_index(i),k) = dl_g (i,k) - pflx(gather_index(i),k) = pflx_g (i,k) - ql (gather_index(i),k) = ql_g (i,k) + qtnd(gather_index(i),k) = dqdt(i,k) + rprd(gather_index(i),k) = rprd_g(i,k) + zdu(gather_index(i),k) = det_upd(i,k) + mcon(gather_index(i),k) = mfx_net(i,k) + heat(gather_index(i),k) = dsdt(i,k)*zm_const%cpair + dlf(gather_index(i),k) = dl_g(i,k) + pflx(gather_index(i),k) = pflx_g(i,k) + ql(gather_index(i),k) = ql_g(i,k) end do end do ! scatter 1d variables @@ -1094,7 +1095,7 @@ end subroutine zm_calc_fractional_entrainment subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mu, md, ed, s_dnd, q_dnd, hd, qds, evp, totevp ) + mfx_upd, mfx_dnd, ent_dnd, s_dnd, q_dnd, h_dnd, q_dnd_sat, evp, totevp ) !---------------------------------------------------------------------------- ! Purpose: Calculate properties of ZM downdrafts ! Notes: @@ -1124,12 +1125,12 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & real(r8), dimension(pcols,pver), intent(in ) :: hsthat ! interface interpolated hst real(r8), dimension(pcols,pver), intent(in ) :: gamhat ! interface interpolated gamma real(r8), dimension(pcols,pver), intent(in ) :: rprd ! rate of production of precip at that layer - real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux - real(r8), dimension(pcols,pver), intent(inout) :: md ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(inout) :: ed ! downdraft entrainment rate + real(r8), dimension(pcols,pver), intent(in ) :: mfx_upd ! updraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: mfx_dnd ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: ent_dnd ! downdraft entrainment rate real(r8), dimension(pcols,pver), intent(inout) :: s_dnd ! dndraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(inout) :: q_dnd ! dndraft specific humidity [kg/kg] - real(r8), dimension(pcols,pver), intent(inout) :: hd ! dndraft moist static energy + real(r8), dimension(pcols,pver), intent(inout) :: h_dnd ! dndraft moist static energy real(r8), dimension(pcols,pver), intent(inout) :: q_dnd_sat ! dndraft saturation specific humdity real(r8), dimension(pcols,pver), intent(inout) :: evp ! evaporation rate real(r8), dimension(pcols), intent(inout) :: totevp ! total evap for dndraft proportionality factor - see eq (4.106) @@ -1145,26 +1146,26 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jt(i) = min(jt(i),jb(i)-1) jd(i) = max(j0(i),jt(i)+1) jd(i) = min(jd(i),jb(i)) - hd(i,jd(i)) = h_env(i,jd(i)-1) + h_dnd(i,jd(i)) = h_env(i,jd(i)-1) if (jd(i) < jb(i) .and. lambda_max(i) > 0._r8) then ! NOTE - this nonsensical lambda_max/lambda_max factor ! was retained to preserve BFB results during ZM refactoring - md(i,jd(i)) = -zm_param%alfa * lambda_max(i) / lambda_max(i) + mfx_dnd(i,jd(i)) = -zm_param%alfa * lambda_max(i) / lambda_max(i) end if end do ! i do k = msg+1, pver do i = 1,ncol if ((k > jd(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8) then dz_tmp = z_int(i,jd(i)) - z_int(i,k) - md(i,k) = -zm_param%alfa / (2._r8*lambda_max(i))*(exp(2._r8*lambda_max(i)*dz_tmp)-1._r8)/dz_tmp + mfx_dnd(i,k) = -zm_param%alfa / (2._r8*lambda_max(i))*(exp(2._r8*lambda_max(i)*dz_tmp)-1._r8)/dz_tmp end if end do ! i end do ! k do k = msg+1, pver do i = 1,ncol if ((k >= jt(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8 .and. jd(i) < jb(i)) then - ratmjb(i) = min(abs(mu(i,jb(i))/md(i,jb(i))),1._r8) - md(i,k) = md(i,k)*ratmjb(i) + ratmjb(i) = min(abs(mfx_upd(i,jb(i))/mfx_dnd(i,jb(i))),1._r8) + mfx_dnd(i,k) = mfx_dnd(i,k)*ratmjb(i) end if end do ! i end do ! k @@ -1174,9 +1175,9 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do k = msg+1, pver do i = 1,ncol if ((k >= jt(i) .and. k <= pver) .and. lambda_max(i) > 0._r8) then - ed(i,k-1) = (md(i,k-1)-md(i,k))/dz(i,k-1) - mdt = min(md(i,k),-small) - hd(i,k) = (md(i,k-1)*hd(i,k-1) - dz(i,k-1)*ed(i,k-1)*h_env(i,k-1))/mdt + ent_dnd(i,k-1) = (mfx_dnd(i,k-1)-mfx_dnd(i,k))/dz(i,k-1) + mdt = min(mfx_dnd(i,k),-small) + h_dnd(i,k) = (mfx_dnd(i,k-1)*h_dnd(i,k-1) - dz(i,k-1)*ent_dnd(i,k-1)*h_env(i,k-1))/mdt end if end do ! i end do ! k @@ -1186,7 +1187,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do k = msg+2, pver do i = 1,ncol if ((k >= jd(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8 .and. jd(i) < jb(i)) then - q_dnd_sat(i,k) = qsthat(i,k) + gamhat(i,k)*(hd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) + q_dnd_sat(i,k) = qsthat(i,k) + gamhat(i,k)*(h_dnd(i,k)-hsthat(i,k)) / (zm_const%latvap*(1._r8+gamhat(i,k))) end if end do ! i end do ! k @@ -1195,7 +1196,7 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & ! downdraft quantities at source level do i = 1,ncol q_dnd(i,jd(i)) = q_dnd_sat(i,jd(i)) - s_dnd(i,jd(i)) = (hd(i,jd(i)) - zm_const%latvap*q_dnd(i,jd(i)))/zm_const%cpair + s_dnd(i,jd(i)) = (h_dnd(i,jd(i)) - zm_const%latvap*q_dnd(i,jd(i)))/zm_const%cpair end do !---------------------------------------------------------------------------- @@ -1204,18 +1205,18 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do i = 1,ncol if (k >= jd(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8) then q_dnd(i,k+1) = q_dnd_sat(i,k+1) - evp(i,k) = -ed(i,k)*q_mid(i,k) + (md(i,k)*q_dnd(i,k)-md(i,k+1)*q_dnd(i,k+1))/dz(i,k) + evp(i,k) = -ent_dnd(i,k)*q_mid(i,k) + (mfx_dnd(i,k)*q_dnd(i,k)-mfx_dnd(i,k+1)*q_dnd(i,k+1))/dz(i,k) evp(i,k) = max(evp(i,k),0._r8) - mdt = min(md(i,k+1),-small) + mdt = min(mfx_dnd(i,k+1),-small) if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) - s_dnd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ed(i,k)*s_mid(i,k))*dz(i,k) + md(i,k)*s_dnd(i,k))/mdt - totevp(i) = totevp(i) - dz(i,k)*ed(i,k)*q_mid(i,k) + s_dnd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ent_dnd(i,k)*s_mid(i,k))*dz(i,k) + mfx_dnd(i,k)*s_dnd(i,k))/mdt + totevp(i) = totevp(i) - dz(i,k)*ent_dnd(i,k)*q_mid(i,k) end if end do ! i end do ! k do i = 1,ncol - totevp(i) = totevp(i) + md(i,jd(i))*q_dnd(i,jd(i)) - md(i,jb(i))*q_dnd(i,jb(i)) + totevp(i) = totevp(i) + mfx_dnd(i,jd(i))*q_dnd(i,jd(i)) - mfx_dnd(i,jb(i))*q_dnd(i,jb(i)) end do !---------------------------------------------------------------------------- @@ -1229,7 +1230,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & p_mid, z_mid, z_int, t_mid, s_mid, s_int, q_mid, & landfrac, tpert_g, & jb, lel, jt, jlcl, j0, jd, & - mu, eu, du, md, ed, mc, & + mfx_upd, ent_upd, det_upd, mfx_dnd, ent_dnd, mfx_net, & s_upd, q_upd, ql, s_dnd, q_dnd, & qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) @@ -1260,12 +1261,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level integer, dimension(pcols), intent(out) :: j0 ! level where detrainment begins (starting at h_env_min) integer, dimension(pcols), intent(out) :: jd ! level of downdraft - real(r8), dimension(pcols,pver), intent(out) :: mu ! updraft mass flux - real(r8), dimension(pcols,pver), intent(out) :: eu ! entrainment rate of updraft - real(r8), dimension(pcols,pver), intent(out) :: du ! detrainement rate of updraft - real(r8), dimension(pcols,pver), intent(out) :: md ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(out) :: ed ! downdraft entrainment rate - real(r8), dimension(pcols,pver), intent(out) :: mc ! net mass flux + real(r8), dimension(pcols,pver), intent(out) :: mfx_upd ! updraft mass flux + real(r8), dimension(pcols,pver), intent(out) :: ent_upd ! entrainment rate of updraft + real(r8), dimension(pcols,pver), intent(out) :: det_upd ! detrainement rate of updraft + real(r8), dimension(pcols,pver), intent(out) :: mfx_dnd ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(out) :: ent_dnd ! downdraft entrainment rate + real(r8), dimension(pcols,pver), intent(out) :: mfx_net ! net mass flux real(r8), dimension(pcols,pver), intent(out) :: s_upd ! updraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: q_upd ! updraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water @@ -1285,8 +1286,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & real(r8), dimension(pcols,pver) :: h_env ! ambient env moist stat energy real(r8), dimension(pcols,pver) :: h_env_sat ! ambient env saturated moist stat energy real(r8), dimension(pcols) :: h_env_min ! mid-tropospheric MSE minimum - real(r8), dimension(pcols,pver) :: hu ! updraft moist static energy - real(r8), dimension(pcols,pver) :: hd ! dndraft moist static energy + real(r8), dimension(pcols,pver) :: h_upd ! updraft moist static energy + real(r8), dimension(pcols,pver) :: h_dnd ! dndraft moist static energy real(r8), dimension(pcols,pver) :: qsthat ! interface interpolated qst real(r8), dimension(pcols,pver) :: hsthat ! interface interpolated hst real(r8), dimension(pcols,pver) :: gamhat ! interface interpolated gamma @@ -1342,12 +1343,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = 1,pver do i = 1,ncol ! mass fluxes & mixing variables - mu(i,k) = 0._r8 - eu(i,k) = 0._r8 - du(i,k) = 0._r8 - mc(i,k) = 0._r8 - md(i,k) = 0._r8 - ed(i,k) = 0._r8 + mfx_upd(i,k) = 0._r8 + ent_upd(i,k) = 0._r8 + det_upd(i,k) = 0._r8 + mfx_net(i,k) = 0._r8 + mfx_dnd(i,k) = 0._r8 + ent_dnd(i,k) = 0._r8 ! cloud process variables ql(i,k) = 0._r8 evp(i,k) = 0._r8 @@ -1371,8 +1372,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & q_upd(i,k) = q_mid(i,k) h_env(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*q_mid(i,k) h_env_sat(i,k) = zm_const%cpair*t_mid(i,k) + zm_const%grav*z_mid(i,k) + zm_const%latvap*qst(i,k) - hu(i,k) = h_env(i,k) - hd(i,k) = h_env(i,k) + h_upd(i,k) = h_env(i,k) + h_dnd(i,k) = h_env(i,k) ! convective microphysics pflxs(i,k) = 0._r8 fice(i,k) = 0._r8 @@ -1444,10 +1445,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! new tunable parameter tpert_fac was introduced. This introduced new uncertainties into ! the ZM scheme. The original code of ZM scheme will be used when tpert_fix=.true. if (zm_param%tpert_fix) then - hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add + h_upd(i,k) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add s_upd(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add else - hu(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i)) + h_upd(i,k) = h_env(i,jb(i)) + zm_const%cpair*(zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i)) s_upd(i,k) = s_mid(i,jb(i)) + zm_param%tiedke_add+zm_param%tpert_fac*tpert_g(i) end if end if @@ -1481,24 +1482,24 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & end do ! k do i = 1,ncol totpcp(i) = 0._r8 - if (zm_param%zm_microp) hu(i,jb(i)) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add + if (zm_param%zm_microp) h_upd(i,jb(i)) = h_env(i,jb(i)) + zm_const%cpair*zm_param%tiedke_add end do do k = pver, msg+1, -1 do i = 1,ncol ! intialize updraft mass flux variables - here and below all normalized by cloud base mass flux (mb) if (lambda_max(i) > 0._r8) then - mu(i,jb(i)) = 1._r8 - eu(i,jb(i)) = mu(i,jb(i))/dz(i,jb(i)) + mfx_upd(i,jb(i)) = 1._r8 + ent_upd(i,jb(i)) = mfx_upd(i,jb(i))/dz(i,jb(i)) if ( zm_param%zm_microp) tmp_k_limit = lel(i) if (.not.zm_param%zm_microp) tmp_k_limit = jt(i) ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) if ( k>=tmp_k_limit .and. k0._r8 end do ! i @@ -1514,20 +1515,20 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = klowest-1,khighest,-1 do i = 1,ncol if (k <= jb(i)-1 .and. k >= lel(i) .and. lambda_max(i) > 0._r8) then - if (mu(i,k) < 0.02_r8) then - hu(i,k) = h_env(i,k) - mu(i,k) = 0._r8 - eu(i,k) = 0._r8 - du(i,k) = mu(i,k+1)/dz(i,k) + if (mfx_upd(i,k) < 0.02_r8) then + h_upd(i,k) = h_env(i,k) + mfx_upd(i,k) = 0._r8 + ent_upd(i,k) = 0._r8 + det_upd(i,k) = mfx_upd(i,k+1)/dz(i,k) else if (zm_param%zm_microp) then - hu(i,k) = ( mu(i,k+1)*hu(i,k+1) & - +dz(i,k)*( eu(i,k)*h_env(i,k) & - +zm_const%latice*tmp_frz(i,k) ) & - ) / ( mu(i,k) + dz(i,k)*du(i,k) ) + h_upd(i,k) = ( mfx_upd(i,k+1)*h_upd(i,k+1) & + +dz(i,k)*( ent_upd(i,k)*h_env(i,k) & + +zm_const%latice*tmp_frz(i,k) ) & + ) / ( mfx_upd(i,k) + dz(i,k)*det_upd(i,k) ) else - hu(i,k) = mu(i,k+1)/mu(i,k)*hu(i,k+1) + & - dz(i,k)/mu(i,k)* (eu(i,k)*h_env(i,k)- du(i,k)*h_env_sat(i,k)) + h_upd(i,k) = mfx_upd(i,k+1)/mfx_upd(i,k)*h_upd(i,k+1) + & + dz(i,k)/mfx_upd(i,k)* (ent_upd(i,k)*h_env(i,k)- det_upd(i,k)*h_env_sat(i,k)) end if end if end if @@ -1547,17 +1548,17 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = klowest-2, khighest-1, -1 do i = 1,ncol if (doit(i) .and. k <= jb(i)-2 .and. k >= lel(i)-1) then - if (hu(i,k) <= hsthat(i,k) .and. & - hu(i,k+1) > hsthat(i,k+1) .and. & - mu(i,k) >= mu_min) then - if ( hu(i,k)-hsthat(i,k) < hu_diff_min) then + if (h_upd(i,k) <= hsthat(i,k) .and. & + h_upd(i,k+1) > hsthat(i,k+1) .and. & + mfx_upd(i,k) >= mu_min) then + if ( h_upd(i,k)-hsthat(i,k) < hu_diff_min) then jt(i) = k + 1 doit(i) = .false. else jt(i) = k doit(i) = .false. end if - else if ( (hu(i,k) > hu(i,jb(i)) .and. tot_frz(i)<=0._r8) .or. mu(i,k) < mu_min) then + else if ( (h_upd(i,k) > h_upd(i,jb(i)) .and. tot_frz(i)<=0._r8) .or. mfx_upd(i,k) < mu_min) then jt(i) = k + 1 doit(i) = .false. end if @@ -1572,15 +1573,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+1, -1 do i = 1,ncol if (k >= lel(i) .and. k <= jt(i) .and. lambda_max(i) > 0._r8) then - mu(i,k) = 0._r8 - eu(i,k) = 0._r8 - du(i,k) = 0._r8 - hu(i,k) = h_env(i,k) + mfx_upd(i,k) = 0._r8 + ent_upd(i,k) = 0._r8 + det_upd(i,k) = 0._r8 + h_upd(i,k) = h_env(i,k) end if if (k == jt(i) .and. lambda_max(i) > 0._r8) then - du(i,k) = mu(i,k+1)/dz(i,k) - eu(i,k) = 0._r8 - mu(i,k) = 0._r8 + det_upd(i,k) = mfx_upd(i,k+1)/dz(i,k) + ent_upd(i,k) = 0._r8 + mfx_upd(i,k) = 0._r8 end if end do ! i end do ! k @@ -1592,11 +1593,11 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do i = 1,ncol if (k == jb(i) .and. lambda_max(i) > 0._r8) then q_upd(i,k) = q_mid(i,jb(i)) - s_upd(i,k) = (hu(i,k)-zm_const%latvap*q_upd(i,k))/zm_const%cpair + s_upd(i,k) = (h_upd(i,k)-zm_const%latvap*q_upd(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. lambda_max(i) > 0._r8) then - s_upd(i,k) = mu(i,k+1)/mu(i,k)*s_upd(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)-du(i,k))*s_mid(i,k) - q_upd(i,k) = mu(i,k+1)/mu(i,k)*q_upd(i,k+1) + dz(i,k)/mu(i,k)* (eu(i,k)*q_mid(i,k) - du(i,k)*qst(i,k)) + s_upd(i,k) = mfx_upd(i,k+1)/mfx_upd(i,k)*s_upd(i,k+1) + dz(i,k)/mfx_upd(i,k)* (ent_upd(i,k)-det_upd(i,k))*s_mid(i,k) + q_upd(i,k) = mfx_upd(i,k+1)/mfx_upd(i,k)*q_upd(i,k+1) + dz(i,k)/mfx_upd(i,k)* (ent_upd(i,k)*q_mid(i,k) - det_upd(i,k)*qst(i,k)) tu = s_upd(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) call qsat_hPa(tu, (p_mid(i,k)+p_mid(i,k-1))/2._r8, estu, qstu) if (q_upd(i,k) >= qstu) then @@ -1614,8 +1615,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = msg+2, pver do i = 1,ncol if ((k > jt(i) .and. k <= jlcl(i)) .and. lambda_max(i) > 0._r8) then - s_upd(i,k) = s_int(i,k) + (hu(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) - q_upd(i,k) = qsthat(i,k) + gamhat(i,k)*(hu(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) + s_upd(i,k) = s_int(i,k) + (h_upd(i,k)-hsthat(i,k)) / (zm_const%cpair* (1._r8+gamhat(i,k))) + q_upd(i,k) = qsthat(i,k) + gamhat(i,k)*(h_upd(i,k)-hsthat(i,k)) / (zm_const%latvap* (1._r8+gamhat(i,k))) end if end do ! i end do ! k @@ -1628,10 +1629,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) if ( k>=jt(i) .and. k= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then - totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-du(i,k)*( loc_microp_st%qcde(i,k+1) & - +loc_microp_st%qide(i,k+1) & - +loc_microp_st%qsde(i,k+1) )) + if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mfx_upd(i,k) >= 0.0_r8) then + totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-det_upd(i,k)*( loc_microp_st%qcde(i,k+1) & + +loc_microp_st%qide(i,k+1) & + +loc_microp_st%qsde(i,k+1) )) end if end do ! i end do ! k @@ -1742,22 +1743,22 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! compute condensed liquid, rain production rate ! accumulate total precipitation (condensation - detrainment of liquid) - ! Note: ql1 = ql(k) + rprd(k)*dz(k)/mu(k) - ! The differencing is somewhat strange (e.g. du(i,k)*ql(i,k+1)) but is consistently applied. - ! interface quantities => mu, ql are - ! mid-point quantities => cu, du, eu, rprd + ! Note: ql1 = ql(k) + rprd(k)*dz(k)/mfx_upd(k) + ! The differencing is somewhat strange (e.g. det_upd(i,k)*ql(i,k+1)) but is consistently applied. + ! interface quantities => mfx_upd, ql are + ! mid-point quantities => cu, det_upd, ent_upd, rprd do k = pver, msg+2, -1 do i = 1,ncol rprd(i,k) = 0._r8 - if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mu(i,k) >= 0.0_r8) then - if (mu(i,k) > 0._r8) then - ql1 = 1._r8/mu(i,k) * ( mu(i,k+1)*ql(i,k+1) - dz(i,k)*du(i,k)*ql(i,k+1) + dz(i,k)*cu(i,k) ) + if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mfx_upd(i,k) >= 0.0_r8) then + if (mfx_upd(i,k) > 0._r8) then + ql1 = 1._r8/mfx_upd(i,k) * ( mfx_upd(i,k+1)*ql(i,k+1) - dz(i,k)*det_upd(i,k)*ql(i,k+1) + dz(i,k)*cu(i,k) ) ql(i,k) = ql1 / (1._r8+dz(i,k)*c0mask(i)) else ql(i,k) = 0._r8 end if - totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-du(i,k)*ql(i,k+1)) - rprd(i,k) = c0mask(i)*mu(i,k)*ql(i,k) + totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-det_upd(i,k)*ql(i,k+1)) + rprd(i,k) = c0mask(i)*mfx_upd(i,k)*ql(i,k) end if end do ! i end do ! k @@ -1771,7 +1772,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mu, md, ed, s_dnd, q_dnd, hd, q_dnd_sat, evp, totevp) + mfx_upd, mfx_dnd, ent_dnd, s_dnd, q_dnd, h_dnd, q_dnd_sat, evp, totevp) !---------------------------------------------------------------------------- ! ensure totpcp and totevp are non-negative @@ -1784,12 +1785,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do i = 1,ncol ! also ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then - md(i,k) = md (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) - ed(i,k) = ed (i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) + mfx_dnd(i,k) = mfx_dnd(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) + ent_dnd(i,k) = ent_dnd(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) evp(i,k) = evp(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) else - md(i,k) = 0._r8 - ed(i,k) = 0._r8 + mfx_dnd(i,k) = 0._r8 + ent_dnd(i,k) = 0._r8 evp(i,k) = 0._r8 end if ! rprd is the cloud water converted to rain - (rain evaporated) @@ -1816,7 +1817,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! calculate net mass flux do k = msg+1, pver do i = 1,ncol - mc(i,k) = mu(i,k) + md(i,k) + mfx_net(i,k) = mfx_upd(i,k) + mfx_dnd(i,k) end do ! i end do ! k @@ -1837,17 +1838,17 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! disable columns if top is at or below LCL if using ZM microphysics if ( jt(i)>=jlcl(i) ) then do k = msg+1, pver - mu(i,k) = 0._r8 - eu(i,k) = 0._r8 - du(i,k) = 0._r8 - ql(i,k) = 0._r8 - cu(i,k) = 0._r8 - evp(i,k) = 0._r8 - md(i,k) = 0._r8 - ed(i,k) = 0._r8 - mc(i,k) = 0._r8 - rprd(i,k) = 0._r8 - fice(i,k) = 0._r8 + mfx_upd(i,k) = 0._r8 + ent_upd(i,k) = 0._r8 + det_upd(i,k) = 0._r8 + ql(i,k) = 0._r8 + cu(i,k) = 0._r8 + evp(i,k) = 0._r8 + mfx_dnd(i,k) = 0._r8 + ent_dnd(i,k) = 0._r8 + mfx_net(i,k) = 0._r8 + rprd(i,k) = 0._r8 + fice(i,k) = 0._r8 end do ! k call zm_microp_st_zero(loc_microp_st,i,pver) end if @@ -1866,7 +1867,8 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & t_pcl_lcl, t_pcl, q_pcl_sat, s_upd, q_upd, & - mc, du, mu, md, q_dnd, s_dnd, cape, cld_bass_mass_flux ) + mfx_net, det_upd, mfx_upd, mfx_dnd, q_dnd, s_dnd, cape, & + cld_bass_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the ! revised quasi-equilibrium hypothesis of Z02, in which a @@ -1908,10 +1910,10 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: q_pcl_sat ! parcel specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_upd ! updraft dry static energy (normalized) real(r8), dimension(pcols,pver), intent(in ) :: q_upd ! updraft specific humidity - real(r8), dimension(pcols,pver), intent(in ) :: mc ! net convective mass flux - real(r8), dimension(pcols,pver), intent(in ) :: du ! detrainment from updraft - real(r8), dimension(pcols,pver), intent(in ) :: mu ! updraft mass flux - real(r8), dimension(pcols,pver), intent(in ) :: md ! dndraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: mfx_net ! net convective mass flux + real(r8), dimension(pcols,pver), intent(in ) :: det_upd ! detrainment from updraft + real(r8), dimension(pcols,pver), intent(in ) :: mfx_upd ! updraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: mfx_dnd ! dndraft mass flux real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! dndraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_dnd ! dndraft dry static energy real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy @@ -1951,11 +1953,11 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & cld_bass_mass_flux(i) = 0._r8 eb = p_mid(i,mx(i))*q_mid(i,mx(i))/ (zm_const%epsilo+q_mid(i,mx(i))) dtbdt(i) = (1._r8/dsubcld(i)) & - *( mu(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & - +md(i,mx(i))*(s_int(i,mx(i))-s_dnd(i,mx(i))) ) + *( mfx_upd(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & + +mfx_dnd(i,mx(i))*(s_int(i,mx(i))-s_dnd(i,mx(i))) ) dqbdt(i) = (1._r8/dsubcld(i)) & - *( mu(i,mx(i))*(q_int(i,mx(i))-q_upd(i,mx(i))) & - +md(i,mx(i))*(q_int(i,mx(i))-q_dnd(i,mx(i))) ) + *( mfx_upd(i,mx(i))*(q_int(i,mx(i))-q_upd(i,mx(i))) & + +mfx_dnd(i,mx(i))*(q_int(i,mx(i))-q_dnd(i,mx(i))) ) debdt = zm_const%epsilo*p_mid(i,mx(i)) / (zm_const%epsilo+q_mid(i,mx(i)))**2 * dqbdt(i) dtldt(i) = -2840._r8 * (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 @@ -1968,22 +1970,22 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & ! cloud top if (k==jt(i)) then dtmdt(i,k) = (1._r8/p_del(i,k)) & - *(mu(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & - + md(i,k+1)*(s_dnd(i,k+1)-s_int(i,k+1))) + *(mfx_upd(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & + + mfx_dnd(i,k+1)*(s_dnd(i,k+1)-s_int(i,k+1))) dqmdt(i,k) = (1._r8/p_del(i,k)) & - *(mu(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & - + md(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1))) + *(mfx_upd(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & + + mfx_dnd(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1))) end if ! below cloud top if ( k>jt(i) .and. k mx(i)) then dsdt(i,k) = dsdt(i,k-1) dqdt(i,k) = dqdt(i,k-1) From 6c47165602265c89b26404cef14bd2ad469b6033 Mon Sep 17 00:00:00 2001 From: Donghui Xu Date: Wed, 10 Dec 2025 13:26:48 -0800 Subject: [PATCH 197/398] move lnd_docn_1way test to e3sm_land_exenoshare --- 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 b19aa929b02c..aa88d29daf7a 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -66,6 +66,7 @@ "ERS_Ld20.f45_f45.IELMFATES.elm-fates", "ERS.f09_g16.IELMBC.elm-simple_decomp", "ERS.hcru_hcru.IELM.elm-multi_inst", + "SMS.ELM_USRDAT.GTSM2ELM.elm-lnd_docn_1way", ) }, @@ -102,7 +103,6 @@ "ERS.r05_r05.IELM.elm-lnd_rof_2way", "ERS.r05_r05.IELM.elm-V2_ELM_MOSART_features", "ERS.ELM_USRDAT.IELM.elm-surface_water_dynamics", - "SMS.ELM_USRDAT.GTSM2ELM.elm-lnd_docn_1way" ) }, From 0b649f58d4d9e8bd2ffefc8a8acd7296cbfc5d60 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 14:43:25 -0800 Subject: [PATCH 198/398] fixes from PR review --- components/eam/src/physics/cam/zm/zm_conv.F90 | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 8a0ab211510d..1e9a4b2c39bf 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -185,26 +185,26 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & integer, dimension(pcols), intent( out) :: msemax_klev_g ! gathered level indices of max MSE (msemax_klev) integer, dimension(pcols), intent( out) :: jctop ! top-of-deep-convection indices integer, dimension(pcols), intent( out) :: jcbot ! base of cloud indices - integer, dimension(pcols), intent( out) :: jt ! gathered top level index of deep cumulus convection - real(r8), dimension(pcols), intent( out) :: prec ! output precipitation + integer, dimension(pcols), intent( out) :: jt ! gathered top level index of convection + real(r8), dimension(pcols), intent( out) :: prec ! output precipitation [m/s] real(r8), dimension(pcols,pver), intent( out) :: heat ! dry static energy tendency [W/kg] real(r8), dimension(pcols,pver), intent( out) :: qtnd ! specific humidity tendency [kg/kg/s] real(r8), dimension(pcols), intent( out) :: cape ! conv. avail. potential energy [J] real(r8), dimension(pcols), intent( out) :: dcape ! CAPE generated by dycor (dCAPE) [J] real(r8), dimension(pcols,pverp),intent( out) :: mcon ! convective mass flux [mb/s] - real(r8), dimension(pcols,pverp),intent( out) :: pflx ! precip flux at each level [?] - real(r8), dimension(pcols,pver), intent( out) :: zdu ! detraining mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: mfx_upd ! updraft mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: ent_upd ! updraft entrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: det_upd ! updraft detrainment [?] - real(r8), dimension(pcols,pver), intent( out) :: mfx_dnd ! downdraft mass flux [?] - real(r8), dimension(pcols,pver), intent( out) :: ent_dnd ! downdraft entrainment [?] + real(r8), dimension(pcols,pverp),intent( out) :: pflx ! precip flux at each level [kg/m2/s] + real(r8), dimension(pcols,pver), intent( out) :: zdu ! detraining mass flux [1/s] + real(r8), dimension(pcols,pver), intent( out) :: mfx_upd ! updraft mass flux [mb/s] + real(r8), dimension(pcols,pver), intent( out) :: ent_upd ! updraft entrainment [1/s] + real(r8), dimension(pcols,pver), intent( out) :: det_upd ! updraft detrainment [1/s] + real(r8), dimension(pcols,pver), intent( out) :: mfx_dnd ! downdraft mass flux [mb/s] + real(r8), dimension(pcols,pver), intent( out) :: ent_dnd ! downdraft entrainment [1/s] real(r8), dimension(pcols,pver), intent( out) :: p_del ! layer thickness [mb] real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and msemax_klev [mb] - real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep + real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep [?] real(r8), dimension(pcols), intent( out) :: rliq ! reserved liquid (not yet in cldliq) for energy integrals - real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate - real(r8), dimension(pcols,pver), intent( out) :: dlf ! detrained cloud liq mixing ratio + real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate [?] + real(r8), dimension(pcols,pver), intent( out) :: dlf ! detrained cloud liq mixing ratio [kg/kg] type(zm_aero_t), intent(inout) :: aero ! aerosol object type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- @@ -278,7 +278,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & integer, dimension(pcols) :: j0 ! detrainment initiation level index integer, dimension(pcols) :: jd ! downdraft initiation level index - real(r8), dimension(pcols) :: cld_bass_mass_flux ! cloud base mass flux determined from zm_closure() + real(r8), dimension(pcols) :: cld_base_mass_flux ! cloud base mass flux determined from zm_closure() type(zm_microp_st) :: loc_microp_st ! local (gathered) convective microphysics state and tendencies @@ -547,7 +547,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, q_upd, & mfx_net, det_upd, mfx_upd, mfx_dnd, q_dnd, s_dnd, cape_g, & - cld_bass_mass_flux ) + cld_base_mass_flux ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. @@ -557,12 +557,12 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & mfx_upd_max(i) = max(mfx_upd_max(i), mfx_upd(i,k)/p_del(i,k)) end do if (mfx_upd_max(i) > 0._r8) then - cld_bass_mass_flux(i) = min(cld_bass_mass_flux(i),1/(time_step*mfx_upd_max(i))) + cld_base_mass_flux(i) = min(cld_base_mass_flux(i),1/(time_step*mfx_upd_max(i))) else - cld_bass_mass_flux(i) = 0._r8 + cld_base_mass_flux(i) = 0._r8 end if if (zm_param%clos_dyn_adj) then - cld_bass_mass_flux(i) = max(cld_bass_mass_flux(i) - omega_g(i,pbl_top_g(i))*0.01_r8, 0._r8) + cld_base_mass_flux(i) = max(cld_base_mass_flux(i) - omega_g(i,pbl_top_g(i))*0.01_r8, 0._r8) end if end do @@ -571,7 +571,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & if (zm_param%no_deep_pbl) then do i = 1,lengath if (z_mid_in(gather_index(i),jt(i)) < pbl_hgt(gather_index(i))) then - cld_bass_mass_flux(i) = 0 + cld_base_mass_flux(i) = 0 end if end do end if @@ -580,24 +580,24 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! apply cloud base mass flux scaling do i = 1,lengath ! zero out micro data for inactive columns - if ( zm_param%zm_microp .and. cld_bass_mass_flux(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) + if ( zm_param%zm_microp .and. cld_base_mass_flux(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) ! scale variables do k = msg+1,pver - mfx_upd(i,k) = mfx_upd(i,k) *cld_bass_mass_flux(i) - mfx_dnd(i,k) = mfx_dnd(i,k) *cld_bass_mass_flux(i) - mfx_net(i,k) = mfx_net(i,k) *cld_bass_mass_flux(i) - det_upd(i,k) = det_upd(i,k) *cld_bass_mass_flux(i) - ent_upd(i,k) = ent_upd(i,k) *cld_bass_mass_flux(i) - ent_dnd(i,k) = ent_dnd(i,k) *cld_bass_mass_flux(i) - rprd_g(i,k) = rprd_g(i,k) *cld_bass_mass_flux(i) - cu_g(i,k) = cu_g(i,k) *cld_bass_mass_flux(i) - evp_g(i,k) = evp_g(i,k) *cld_bass_mass_flux(i) - pflx_g(i,k+1) = pflx_g(i,k+1) *cld_bass_mass_flux(i)*100._r8/zm_const%grav + mfx_upd(i,k) = mfx_upd(i,k) *cld_base_mass_flux(i) + mfx_dnd(i,k) = mfx_dnd(i,k) *cld_base_mass_flux(i) + mfx_net(i,k) = mfx_net(i,k) *cld_base_mass_flux(i) + det_upd(i,k) = det_upd(i,k) *cld_base_mass_flux(i) + ent_upd(i,k) = ent_upd(i,k) *cld_base_mass_flux(i) + ent_dnd(i,k) = ent_dnd(i,k) *cld_base_mass_flux(i) + rprd_g(i,k) = rprd_g(i,k) *cld_base_mass_flux(i) + cu_g(i,k) = cu_g(i,k) *cld_base_mass_flux(i) + evp_g(i,k) = evp_g(i,k) *cld_base_mass_flux(i) + pflx_g(i,k+1) = pflx_g(i,k+1) *cld_base_mass_flux(i)*100._r8/zm_const%grav ! scale microphysics variables if (zm_param%zm_microp) then - loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k)*cld_bass_mass_flux(i) - loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k)*cld_bass_mass_flux(i) - if (cld_bass_mass_flux(i).eq.0._r8) then + loc_microp_st%sprd(i,k) = loc_microp_st%sprd(i,k)*cld_base_mass_flux(i) + loc_microp_st%frz (i,k) = loc_microp_st%frz (i,k)*cld_base_mass_flux(i) + if (cld_base_mass_flux(i).eq.0._r8) then ql_g(i,k) = 0._r8 end if end if @@ -1868,7 +1868,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & s_mid, q_mid, qs, ql, s_int, q_int, & t_pcl_lcl, t_pcl, q_pcl_sat, s_upd, q_upd, & mfx_net, det_upd, mfx_upd, mfx_dnd, q_dnd, s_dnd, cape, & - cld_bass_mass_flux ) + cld_base_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the ! revised quasi-equilibrium hypothesis of Z02, in which a @@ -1917,7 +1917,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! dndraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_dnd ! dndraft dry static energy real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy - real(r8), dimension(pcols), intent(out) :: cld_bass_mass_flux! cloud base mass flux + real(r8), dimension(pcols), intent(out) :: cld_base_mass_flux! cloud base mass flux !---------------------------------------------------------------------------- ! Local variables real(r8), dimension(pcols,pver) :: dboydt ! integrand of cape change @@ -1950,7 +1950,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & !---------------------------------------------------------------------------- ! Calculate sub-cloud tendencies of virtual temperature and humidity do i = 1,ncol - cld_bass_mass_flux(i) = 0._r8 + cld_base_mass_flux(i) = 0._r8 eb = p_mid(i,mx(i))*q_mid(i,mx(i))/ (zm_const%epsilo+q_mid(i,mx(i))) dtbdt(i) = (1._r8/dsubcld(i)) & *( mfx_upd(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & @@ -2031,10 +2031,10 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & do i = 1,ncol dltaa = -1._r8*( cape(i) - cape_threshold_in ) if (dadt(i) /= 0._r8) then - cld_bass_mass_flux(i) = max( dltaa/zm_param%tau/dadt(i), 0._r8) + cld_base_mass_flux(i) = max( dltaa/zm_param%tau/dadt(i), 0._r8) end if if (zm_param%zm_microp .and. mx(i)-jt(i) < 2._r8) then - cld_bass_mass_flux(i) = 0.0_r8 + cld_base_mass_flux(i) = 0.0_r8 end if end do From 042d421138d81bd96fa8b834faa3fe18c837a44c Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Wed, 10 Dec 2025 15:40:54 -0800 Subject: [PATCH 199/398] update mass flux names --- components/eam/src/physics/cam/zm/zm_conv.F90 | 294 +++++++++--------- 1 file changed, 147 insertions(+), 147 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 1e9a4b2c39bf..8492d6ffdbd3 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -154,7 +154,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & tpert, landfrac, t_star, q_star, & lengath, gather_index, msemax_klev_g, jctop, jcbot, jt, & prec, heat, qtnd, cape, dcape, & - mcon, pflx, zdu, mfx_upd, ent_upd, det_upd, mfx_dnd, ent_dnd, p_del, dsubcld, & + mcon, pflx, zdu, mflx_up, entr_up, detr_up, mflx_dn, entr_dn, p_del, dsubcld, & ql, rliq, rprd, dlf, aero, microp_st ) !---------------------------------------------------------------------------- ! Purpose: Main driver for Zhang-Mcfarlane convection scheme @@ -194,11 +194,11 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pverp),intent( out) :: mcon ! convective mass flux [mb/s] real(r8), dimension(pcols,pverp),intent( out) :: pflx ! precip flux at each level [kg/m2/s] real(r8), dimension(pcols,pver), intent( out) :: zdu ! detraining mass flux [1/s] - real(r8), dimension(pcols,pver), intent( out) :: mfx_upd ! updraft mass flux [mb/s] - real(r8), dimension(pcols,pver), intent( out) :: ent_upd ! updraft entrainment [1/s] - real(r8), dimension(pcols,pver), intent( out) :: det_upd ! updraft detrainment [1/s] - real(r8), dimension(pcols,pver), intent( out) :: mfx_dnd ! downdraft mass flux [mb/s] - real(r8), dimension(pcols,pver), intent( out) :: ent_dnd ! downdraft entrainment [1/s] + real(r8), dimension(pcols,pver), intent( out) :: mflx_up ! updraft mass flux [mb/s] + real(r8), dimension(pcols,pver), intent( out) :: entr_up ! updraft entrainment [1/s] + real(r8), dimension(pcols,pver), intent( out) :: detr_up ! updraft detrainment [1/s] + real(r8), dimension(pcols,pver), intent( out) :: mflx_dn ! downdraft mass flux [mb/s] + real(r8), dimension(pcols,pver), intent( out) :: entr_dn ! downdraft entrainment [1/s] real(r8), dimension(pcols,pver), intent( out) :: p_del ! layer thickness [mb] real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and msemax_klev [mb] real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep [?] @@ -216,7 +216,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: z_mid ! local copy of mid-point altitude [m] real(r8), dimension(pcols,pverp):: z_int ! local copy of interface altitude [m] real(r8), dimension(pcols) :: z_srf ! surface altitude [m] - real(r8), dimension(pcols) :: mfx_upd_max ! max value of mfx_upd/dp + real(r8), dimension(pcols) :: mflx_up_max ! max value of mflx_up/dp integer, dimension(pcols) :: pbl_top ! pbl top indices integer, dimension(pcols) :: pbl_top_g ! gathered pbl top indices @@ -265,7 +265,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver) :: dsdt ! gathered dry static energy ("temp") tendency at gathered points real(r8), dimension(pcols,pver) :: s_dnd ! gathered downdraft dry static energy real(r8), dimension(pcols,pver) :: q_dnd ! gathered downdraft specific humidity - real(r8), dimension(pcols,pver) :: mfx_net ! gathered net upward (scaled by mb) cloud mass flux + real(r8), dimension(pcols,pver) :: mflx_net ! gathered net upward (scaled by mb) cloud mass flux real(r8), dimension(pcols,pver) :: q_upd ! gathered updraft specific humidity real(r8), dimension(pcols,pver) :: s_upd ! gathered updraft dry static energy real(r8), dimension(pcols,pver) :: q_mid_sat_g ! gathered mid-point saturation specific humidity @@ -517,7 +517,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & p_mid_g, z_mid_g, z_int_g, t_mid_g, s_mid_g, s_int_g, q_mid_g, & landfrac_g, tpert_g, & msemax_klev_g, lel_g, jt, jlcl, j0, jd, & - mfx_upd, ent_upd, det_upd, mfx_dnd, ent_dnd, mfx_net, & + mflx_up, entr_up, detr_up, mflx_dn, entr_dn, mflx_net, & s_upd, q_upd, ql_g, s_dnd, q_dnd, & q_mid_sat_g, cu_g, evp_g, pflx_g, rprd_g, & aero, loc_microp_st ) @@ -526,9 +526,9 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! convert from units of "per length" [1/m] to "per pressure" [1/mb]. do k = msg+1, pver do i = 1,lengath - det_upd(i,k)= det_upd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - ent_upd(i,k)= ent_upd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) - ent_dnd(i,k)= ent_dnd(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + detr_up(i,k)= detr_up(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + entr_up(i,k)= entr_up(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) + entr_dn(i,k)= entr_dn(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) cu_g(i,k) = cu_g(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) rprd_g(i,k) = rprd_g(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) evp_g(i,k) = evp_g(i,k) * (z_int_g(i,k)-z_int_g(i,k+1))/p_del(i,k) @@ -546,18 +546,18 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & z_mid_g, z_int_g, p_mid_g, p_del, t_mid_g, & s_mid_g, q_mid_g, q_mid_sat_g, ql_g, s_int_g, q_int_g, & t_pcl_lcl_g, t_pcl_g, q_pcl_sat_g, s_upd, q_upd, & - mfx_net, det_upd, mfx_upd, mfx_dnd, q_dnd, s_dnd, cape_g, & + mflx_net, detr_up, mflx_up, mflx_dn, q_dnd, s_dnd, cape_g, & cld_base_mass_flux ) !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. do i = 1,lengath - mfx_upd_max(i) = 0 + mflx_up_max(i) = 0 do k = msg+2, pver - mfx_upd_max(i) = max(mfx_upd_max(i), mfx_upd(i,k)/p_del(i,k)) + mflx_up_max(i) = max(mflx_up_max(i), mflx_up(i,k)/p_del(i,k)) end do - if (mfx_upd_max(i) > 0._r8) then - cld_base_mass_flux(i) = min(cld_base_mass_flux(i),1/(time_step*mfx_upd_max(i))) + if (mflx_up_max(i) > 0._r8) then + cld_base_mass_flux(i) = min(cld_base_mass_flux(i),1/(time_step*mflx_up_max(i))) else cld_base_mass_flux(i) = 0._r8 end if @@ -583,12 +583,12 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & if ( zm_param%zm_microp .and. cld_base_mass_flux(i).eq.0._r8) call zm_microp_st_zero(loc_microp_st,i,pver) ! scale variables do k = msg+1,pver - mfx_upd(i,k) = mfx_upd(i,k) *cld_base_mass_flux(i) - mfx_dnd(i,k) = mfx_dnd(i,k) *cld_base_mass_flux(i) - mfx_net(i,k) = mfx_net(i,k) *cld_base_mass_flux(i) - det_upd(i,k) = det_upd(i,k) *cld_base_mass_flux(i) - ent_upd(i,k) = ent_upd(i,k) *cld_base_mass_flux(i) - ent_dnd(i,k) = ent_dnd(i,k) *cld_base_mass_flux(i) + mflx_up(i,k) = mflx_up(i,k) *cld_base_mass_flux(i) + mflx_dn(i,k) = mflx_dn(i,k) *cld_base_mass_flux(i) + mflx_net(i,k) = mflx_net(i,k) *cld_base_mass_flux(i) + detr_up(i,k) = detr_up(i,k) *cld_base_mass_flux(i) + entr_up(i,k) = entr_up(i,k) *cld_base_mass_flux(i) + entr_dn(i,k) = entr_dn(i,k) *cld_base_mass_flux(i) rprd_g(i,k) = rprd_g(i,k) *cld_base_mass_flux(i) cu_g(i,k) = cu_g(i,k) *cld_base_mass_flux(i) evp_g(i,k) = evp_g(i,k) *cld_base_mass_flux(i) @@ -608,8 +608,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & ! compute temperature and moisture changes due to convection. call zm_calc_output_tend(pcols, lengath, pver, pverp, msg, & jt, msemax_klev_g, dsubcld, p_del, & - s_int_g, q_int_g, s_upd, q_upd, mfx_upd, det_upd, & - mfx_dnd, s_dnd, q_dnd, ql_g, evp_g, cu_g, & + s_int_g, q_int_g, s_upd, q_upd, mflx_up, detr_up, & + mflx_dn, s_dnd, q_dnd, ql_g, evp_g, cu_g, & dsdt, dqdt, dl_g, & loc_microp_st) @@ -633,8 +633,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & q_mid(gather_index(i),k) = q_mid_in(gather_index(i),k) + time_step*dqdt(i,k) qtnd(gather_index(i),k) = dqdt(i,k) rprd(gather_index(i),k) = rprd_g(i,k) - zdu(gather_index(i),k) = det_upd(i,k) - mcon(gather_index(i),k) = mfx_net(i,k) + zdu(gather_index(i),k) = detr_up(i,k) + mcon(gather_index(i),k) = mflx_net(i,k) heat(gather_index(i),k) = dsdt(i,k)*zm_const%cpair dlf(gather_index(i),k) = dl_g(i,k) pflx(gather_index(i),k) = pflx_g(i,k) @@ -1095,7 +1095,7 @@ end subroutine zm_calc_fractional_entrainment subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mfx_upd, mfx_dnd, ent_dnd, s_dnd, q_dnd, h_dnd, q_dnd_sat, evp, totevp ) + mflx_up, mflx_dn, entr_dn, s_dnd, q_dnd, h_dnd, q_dnd_sat, evp, totevp ) !---------------------------------------------------------------------------- ! Purpose: Calculate properties of ZM downdrafts ! Notes: @@ -1125,9 +1125,9 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & real(r8), dimension(pcols,pver), intent(in ) :: hsthat ! interface interpolated hst real(r8), dimension(pcols,pver), intent(in ) :: gamhat ! interface interpolated gamma real(r8), dimension(pcols,pver), intent(in ) :: rprd ! rate of production of precip at that layer - real(r8), dimension(pcols,pver), intent(in ) :: mfx_upd ! updraft mass flux - real(r8), dimension(pcols,pver), intent(inout) :: mfx_dnd ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(inout) :: ent_dnd ! downdraft entrainment rate + real(r8), dimension(pcols,pver), intent(in ) :: mflx_up ! updraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: mflx_dn ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(inout) :: entr_dn ! downdraft entrainment rate real(r8), dimension(pcols,pver), intent(inout) :: s_dnd ! dndraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(inout) :: q_dnd ! dndraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(inout) :: h_dnd ! dndraft moist static energy @@ -1150,22 +1150,22 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & if (jd(i) < jb(i) .and. lambda_max(i) > 0._r8) then ! NOTE - this nonsensical lambda_max/lambda_max factor ! was retained to preserve BFB results during ZM refactoring - mfx_dnd(i,jd(i)) = -zm_param%alfa * lambda_max(i) / lambda_max(i) + mflx_dn(i,jd(i)) = -zm_param%alfa * lambda_max(i) / lambda_max(i) end if end do ! i do k = msg+1, pver do i = 1,ncol if ((k > jd(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8) then dz_tmp = z_int(i,jd(i)) - z_int(i,k) - mfx_dnd(i,k) = -zm_param%alfa / (2._r8*lambda_max(i))*(exp(2._r8*lambda_max(i)*dz_tmp)-1._r8)/dz_tmp + mflx_dn(i,k) = -zm_param%alfa / (2._r8*lambda_max(i))*(exp(2._r8*lambda_max(i)*dz_tmp)-1._r8)/dz_tmp end if end do ! i end do ! k do k = msg+1, pver do i = 1,ncol if ((k >= jt(i) .and. k <= jb(i)) .and. lambda_max(i) > 0._r8 .and. jd(i) < jb(i)) then - ratmjb(i) = min(abs(mfx_upd(i,jb(i))/mfx_dnd(i,jb(i))),1._r8) - mfx_dnd(i,k) = mfx_dnd(i,k)*ratmjb(i) + ratmjb(i) = min(abs(mflx_up(i,jb(i))/mflx_dn(i,jb(i))),1._r8) + mflx_dn(i,k) = mflx_dn(i,k)*ratmjb(i) end if end do ! i end do ! k @@ -1175,9 +1175,9 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do k = msg+1, pver do i = 1,ncol if ((k >= jt(i) .and. k <= pver) .and. lambda_max(i) > 0._r8) then - ent_dnd(i,k-1) = (mfx_dnd(i,k-1)-mfx_dnd(i,k))/dz(i,k-1) - mdt = min(mfx_dnd(i,k),-small) - h_dnd(i,k) = (mfx_dnd(i,k-1)*h_dnd(i,k-1) - dz(i,k-1)*ent_dnd(i,k-1)*h_env(i,k-1))/mdt + entr_dn(i,k-1) = (mflx_dn(i,k-1)-mflx_dn(i,k))/dz(i,k-1) + mdt = min(mflx_dn(i,k),-small) + h_dnd(i,k) = (mflx_dn(i,k-1)*h_dnd(i,k-1) - dz(i,k-1)*entr_dn(i,k-1)*h_env(i,k-1))/mdt end if end do ! i end do ! k @@ -1205,18 +1205,18 @@ subroutine zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & do i = 1,ncol if (k >= jd(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8) then q_dnd(i,k+1) = q_dnd_sat(i,k+1) - evp(i,k) = -ent_dnd(i,k)*q_mid(i,k) + (mfx_dnd(i,k)*q_dnd(i,k)-mfx_dnd(i,k+1)*q_dnd(i,k+1))/dz(i,k) + evp(i,k) = -entr_dn(i,k)*q_mid(i,k) + (mflx_dn(i,k)*q_dnd(i,k)-mflx_dn(i,k+1)*q_dnd(i,k+1))/dz(i,k) evp(i,k) = max(evp(i,k),0._r8) - mdt = min(mfx_dnd(i,k+1),-small) + mdt = min(mflx_dn(i,k+1),-small) if (zm_param%zm_microp) evp(i,k) = min(evp(i,k),rprd(i,k)) - s_dnd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-ent_dnd(i,k)*s_mid(i,k))*dz(i,k) + mfx_dnd(i,k)*s_dnd(i,k))/mdt - totevp(i) = totevp(i) - dz(i,k)*ent_dnd(i,k)*q_mid(i,k) + s_dnd(i,k+1) = ((zm_const%latvap/zm_const%cpair*evp(i,k)-entr_dn(i,k)*s_mid(i,k))*dz(i,k) + mflx_dn(i,k)*s_dnd(i,k))/mdt + totevp(i) = totevp(i) - dz(i,k)*entr_dn(i,k)*q_mid(i,k) end if end do ! i end do ! k do i = 1,ncol - totevp(i) = totevp(i) + mfx_dnd(i,jd(i))*q_dnd(i,jd(i)) - mfx_dnd(i,jb(i))*q_dnd(i,jb(i)) + totevp(i) = totevp(i) + mflx_dn(i,jd(i))*q_dnd(i,jd(i)) - mflx_dn(i,jb(i))*q_dnd(i,jb(i)) end do !---------------------------------------------------------------------------- @@ -1230,7 +1230,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & p_mid, z_mid, z_int, t_mid, s_mid, s_int, q_mid, & landfrac, tpert_g, & jb, lel, jt, jlcl, j0, jd, & - mfx_upd, ent_upd, det_upd, mfx_dnd, ent_dnd, mfx_net, & + mflx_up, entr_up, detr_up, mflx_dn, entr_dn, mflx_net, & s_upd, q_upd, ql, s_dnd, q_dnd, & qst, cu, evp, pflx, rprd, & aero, loc_microp_st ) @@ -1261,12 +1261,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & integer, dimension(pcols), intent(out) :: jlcl ! updraft lifting cond level integer, dimension(pcols), intent(out) :: j0 ! level where detrainment begins (starting at h_env_min) integer, dimension(pcols), intent(out) :: jd ! level of downdraft - real(r8), dimension(pcols,pver), intent(out) :: mfx_upd ! updraft mass flux - real(r8), dimension(pcols,pver), intent(out) :: ent_upd ! entrainment rate of updraft - real(r8), dimension(pcols,pver), intent(out) :: det_upd ! detrainement rate of updraft - real(r8), dimension(pcols,pver), intent(out) :: mfx_dnd ! downdraft mass flux - real(r8), dimension(pcols,pver), intent(out) :: ent_dnd ! downdraft entrainment rate - real(r8), dimension(pcols,pver), intent(out) :: mfx_net ! net mass flux + real(r8), dimension(pcols,pver), intent(out) :: mflx_up ! updraft mass flux + real(r8), dimension(pcols,pver), intent(out) :: entr_up ! entrainment rate of updraft + real(r8), dimension(pcols,pver), intent(out) :: detr_up ! detrainement rate of updraft + real(r8), dimension(pcols,pver), intent(out) :: mflx_dn ! downdraft mass flux + real(r8), dimension(pcols,pver), intent(out) :: entr_dn ! downdraft entrainment rate + real(r8), dimension(pcols,pver), intent(out) :: mflx_net ! net mass flux real(r8), dimension(pcols,pver), intent(out) :: s_upd ! updraft dry static energy [K] (normalized) real(r8), dimension(pcols,pver), intent(out) :: q_upd ! updraft specific humidity [kg/kg] real(r8), dimension(pcols,pver), intent(out) :: ql ! updraft liq water @@ -1343,12 +1343,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = 1,pver do i = 1,ncol ! mass fluxes & mixing variables - mfx_upd(i,k) = 0._r8 - ent_upd(i,k) = 0._r8 - det_upd(i,k) = 0._r8 - mfx_net(i,k) = 0._r8 - mfx_dnd(i,k) = 0._r8 - ent_dnd(i,k) = 0._r8 + mflx_up(i,k) = 0._r8 + entr_up(i,k) = 0._r8 + detr_up(i,k) = 0._r8 + mflx_net(i,k) = 0._r8 + mflx_dn(i,k) = 0._r8 + entr_dn(i,k) = 0._r8 ! cloud process variables ql(i,k) = 0._r8 evp(i,k) = 0._r8 @@ -1489,17 +1489,17 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do i = 1,ncol ! intialize updraft mass flux variables - here and below all normalized by cloud base mass flux (mb) if (lambda_max(i) > 0._r8) then - mfx_upd(i,jb(i)) = 1._r8 - ent_upd(i,jb(i)) = mfx_upd(i,jb(i))/dz(i,jb(i)) + mflx_up(i,jb(i)) = 1._r8 + entr_up(i,jb(i)) = mflx_up(i,jb(i))/dz(i,jb(i)) if ( zm_param%zm_microp) tmp_k_limit = lel(i) if (.not.zm_param%zm_microp) tmp_k_limit = jt(i) ! compute profiles of updraft mass fluxes - see eq (4.79) - (4.81) if ( k>=tmp_k_limit .and. k0._r8 end do ! i @@ -1515,20 +1515,20 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = klowest-1,khighest,-1 do i = 1,ncol if (k <= jb(i)-1 .and. k >= lel(i) .and. lambda_max(i) > 0._r8) then - if (mfx_upd(i,k) < 0.02_r8) then + if (mflx_up(i,k) < 0.02_r8) then h_upd(i,k) = h_env(i,k) - mfx_upd(i,k) = 0._r8 - ent_upd(i,k) = 0._r8 - det_upd(i,k) = mfx_upd(i,k+1)/dz(i,k) + mflx_up(i,k) = 0._r8 + entr_up(i,k) = 0._r8 + detr_up(i,k) = mflx_up(i,k+1)/dz(i,k) else if (zm_param%zm_microp) then - h_upd(i,k) = ( mfx_upd(i,k+1)*h_upd(i,k+1) & - +dz(i,k)*( ent_upd(i,k)*h_env(i,k) & + h_upd(i,k) = ( mflx_up(i,k+1)*h_upd(i,k+1) & + +dz(i,k)*( entr_up(i,k)*h_env(i,k) & +zm_const%latice*tmp_frz(i,k) ) & - ) / ( mfx_upd(i,k) + dz(i,k)*det_upd(i,k) ) + ) / ( mflx_up(i,k) + dz(i,k)*detr_up(i,k) ) else - h_upd(i,k) = mfx_upd(i,k+1)/mfx_upd(i,k)*h_upd(i,k+1) + & - dz(i,k)/mfx_upd(i,k)* (ent_upd(i,k)*h_env(i,k)- det_upd(i,k)*h_env_sat(i,k)) + h_upd(i,k) = mflx_up(i,k+1)/mflx_up(i,k)*h_upd(i,k+1) + & + dz(i,k)/mflx_up(i,k)* (entr_up(i,k)*h_env(i,k)- detr_up(i,k)*h_env_sat(i,k)) end if end if end if @@ -1550,7 +1550,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (doit(i) .and. k <= jb(i)-2 .and. k >= lel(i)-1) then if (h_upd(i,k) <= hsthat(i,k) .and. & h_upd(i,k+1) > hsthat(i,k+1) .and. & - mfx_upd(i,k) >= mu_min) then + mflx_up(i,k) >= mu_min) then if ( h_upd(i,k)-hsthat(i,k) < hu_diff_min) then jt(i) = k + 1 doit(i) = .false. @@ -1558,7 +1558,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & jt(i) = k doit(i) = .false. end if - else if ( (h_upd(i,k) > h_upd(i,jb(i)) .and. tot_frz(i)<=0._r8) .or. mfx_upd(i,k) < mu_min) then + else if ( (h_upd(i,k) > h_upd(i,jb(i)) .and. tot_frz(i)<=0._r8) .or. mflx_up(i,k) < mu_min) then jt(i) = k + 1 doit(i) = .false. end if @@ -1573,15 +1573,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do k = pver, msg+1, -1 do i = 1,ncol if (k >= lel(i) .and. k <= jt(i) .and. lambda_max(i) > 0._r8) then - mfx_upd(i,k) = 0._r8 - ent_upd(i,k) = 0._r8 - det_upd(i,k) = 0._r8 + mflx_up(i,k) = 0._r8 + entr_up(i,k) = 0._r8 + detr_up(i,k) = 0._r8 h_upd(i,k) = h_env(i,k) end if if (k == jt(i) .and. lambda_max(i) > 0._r8) then - det_upd(i,k) = mfx_upd(i,k+1)/dz(i,k) - ent_upd(i,k) = 0._r8 - mfx_upd(i,k) = 0._r8 + detr_up(i,k) = mflx_up(i,k+1)/dz(i,k) + entr_up(i,k) = 0._r8 + mflx_up(i,k) = 0._r8 end if end do ! i end do ! k @@ -1596,8 +1596,8 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & s_upd(i,k) = (h_upd(i,k)-zm_const%latvap*q_upd(i,k))/zm_const%cpair end if if (( .not. done(i) .and. k > jt(i) .and. k < jb(i)) .and. lambda_max(i) > 0._r8) then - s_upd(i,k) = mfx_upd(i,k+1)/mfx_upd(i,k)*s_upd(i,k+1) + dz(i,k)/mfx_upd(i,k)* (ent_upd(i,k)-det_upd(i,k))*s_mid(i,k) - q_upd(i,k) = mfx_upd(i,k+1)/mfx_upd(i,k)*q_upd(i,k+1) + dz(i,k)/mfx_upd(i,k)* (ent_upd(i,k)*q_mid(i,k) - det_upd(i,k)*qst(i,k)) + s_upd(i,k) = mflx_up(i,k+1)/mflx_up(i,k)*s_upd(i,k+1) + dz(i,k)/mflx_up(i,k)* (entr_up(i,k)-detr_up(i,k))*s_mid(i,k) + q_upd(i,k) = mflx_up(i,k+1)/mflx_up(i,k)*q_upd(i,k+1) + dz(i,k)/mflx_up(i,k)* (entr_up(i,k)*q_mid(i,k) - detr_up(i,k)*qst(i,k)) tu = s_upd(i,k) - zm_const%grav/zm_const%cpair*z_int(i,k) call qsat_hPa(tu, (p_mid(i,k)+p_mid(i,k-1))/2._r8, estu, qstu) if (q_upd(i,k) >= qstu) then @@ -1629,10 +1629,10 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & if (.not.zm_param%zm_microp) tmp_k_limit = jb(i) if ( k>=jt(i) .and. k= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mfx_upd(i,k) >= 0.0_r8) then - totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-det_upd(i,k)*( loc_microp_st%qcde(i,k+1) & + if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mflx_up(i,k) >= 0.0_r8) then + totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-detr_up(i,k)*( loc_microp_st%qcde(i,k+1) & +loc_microp_st%qide(i,k+1) & +loc_microp_st%qsde(i,k+1) )) end if @@ -1743,22 +1743,22 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! compute condensed liquid, rain production rate ! accumulate total precipitation (condensation - detrainment of liquid) - ! Note: ql1 = ql(k) + rprd(k)*dz(k)/mfx_upd(k) - ! The differencing is somewhat strange (e.g. det_upd(i,k)*ql(i,k+1)) but is consistently applied. - ! interface quantities => mfx_upd, ql are - ! mid-point quantities => cu, det_upd, ent_upd, rprd + ! Note: ql1 = ql(k) + rprd(k)*dz(k)/mflx_up(k) + ! The differencing is somewhat strange (e.g. detr_up(i,k)*ql(i,k+1)) but is consistently applied. + ! interface quantities => mflx_up, ql are + ! mid-point quantities => cu, detr_up, entr_up, rprd do k = pver, msg+2, -1 do i = 1,ncol rprd(i,k) = 0._r8 - if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mfx_upd(i,k) >= 0.0_r8) then - if (mfx_upd(i,k) > 0._r8) then - ql1 = 1._r8/mfx_upd(i,k) * ( mfx_upd(i,k+1)*ql(i,k+1) - dz(i,k)*det_upd(i,k)*ql(i,k+1) + dz(i,k)*cu(i,k) ) + if (k >= jt(i) .and. k < jb(i) .and. lambda_max(i) > 0._r8 .and. mflx_up(i,k) >= 0.0_r8) then + if (mflx_up(i,k) > 0._r8) then + ql1 = 1._r8/mflx_up(i,k) * ( mflx_up(i,k+1)*ql(i,k+1) - dz(i,k)*detr_up(i,k)*ql(i,k+1) + dz(i,k)*cu(i,k) ) ql(i,k) = ql1 / (1._r8+dz(i,k)*c0mask(i)) else ql(i,k) = 0._r8 end if - totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-det_upd(i,k)*ql(i,k+1)) - rprd(i,k) = c0mask(i)*mfx_upd(i,k)*ql(i,k) + totpcp(i) = totpcp(i) + dz(i,k)*(cu(i,k)-detr_up(i,k)*ql(i,k+1)) + rprd(i,k) = c0mask(i)*mflx_up(i,k)*ql(i,k) end if end do ! i end do ! k @@ -1772,7 +1772,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & call zm_downdraft_properties(pcols, ncol, pver, pverp, msg, & jb, jt, j0, jd, z_int, dz, s_mid, q_mid, h_env, & lambda, lambda_max, qsthat, hsthat, gamhat, rprd, & - mfx_upd, mfx_dnd, ent_dnd, s_dnd, q_dnd, h_dnd, q_dnd_sat, evp, totevp) + mflx_up, mflx_dn, entr_dn, s_dnd, q_dnd, h_dnd, q_dnd_sat, evp, totevp) !---------------------------------------------------------------------------- ! ensure totpcp and totevp are non-negative @@ -1785,12 +1785,12 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & do i = 1,ncol ! also ensure that downdraft strength is consistent with precipitation availability - see eq (4.106) if (totevp(i) > 0._r8 .and. totpcp(i) > 0._r8) then - mfx_dnd(i,k) = mfx_dnd(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) - ent_dnd(i,k) = ent_dnd(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) + mflx_dn(i,k) = mflx_dn(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) + entr_dn(i,k) = entr_dn(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) evp(i,k) = evp(i,k)*min(1._r8, totpcp(i)/(totevp(i)+totpcp(i))) else - mfx_dnd(i,k) = 0._r8 - ent_dnd(i,k) = 0._r8 + mflx_dn(i,k) = 0._r8 + entr_dn(i,k) = 0._r8 evp(i,k) = 0._r8 end if ! rprd is the cloud water converted to rain - (rain evaporated) @@ -1817,7 +1817,7 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! calculate net mass flux do k = msg+1, pver do i = 1,ncol - mfx_net(i,k) = mfx_upd(i,k) + mfx_dnd(i,k) + mflx_net(i,k) = mflx_up(i,k) + mflx_dn(i,k) end do ! i end do ! k @@ -1838,15 +1838,15 @@ subroutine zm_cloud_properties(pcols, ncol, pver, pverp, msg, limcnv, & ! disable columns if top is at or below LCL if using ZM microphysics if ( jt(i)>=jlcl(i) ) then do k = msg+1, pver - mfx_upd(i,k) = 0._r8 - ent_upd(i,k) = 0._r8 - det_upd(i,k) = 0._r8 + mflx_up(i,k) = 0._r8 + entr_up(i,k) = 0._r8 + detr_up(i,k) = 0._r8 ql(i,k) = 0._r8 cu(i,k) = 0._r8 evp(i,k) = 0._r8 - mfx_dnd(i,k) = 0._r8 - ent_dnd(i,k) = 0._r8 - mfx_net(i,k) = 0._r8 + mflx_dn(i,k) = 0._r8 + entr_dn(i,k) = 0._r8 + mflx_net(i,k) = 0._r8 rprd(i,k) = 0._r8 fice(i,k) = 0._r8 end do ! k @@ -1867,7 +1867,7 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & z_mid, z_int, p_mid, p_del, t_mid, & s_mid, q_mid, qs, ql, s_int, q_int, & t_pcl_lcl, t_pcl, q_pcl_sat, s_upd, q_upd, & - mfx_net, det_upd, mfx_upd, mfx_dnd, q_dnd, s_dnd, cape, & + mflx_net, detr_up, mflx_up, mflx_dn, q_dnd, s_dnd, cape, & cld_base_mass_flux ) !---------------------------------------------------------------------------- ! Purpose: calculate closure condition for ZM convection scheme using the @@ -1910,10 +1910,10 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & real(r8), dimension(pcols,pver), intent(in ) :: q_pcl_sat ! parcel specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_upd ! updraft dry static energy (normalized) real(r8), dimension(pcols,pver), intent(in ) :: q_upd ! updraft specific humidity - real(r8), dimension(pcols,pver), intent(in ) :: mfx_net ! net convective mass flux - real(r8), dimension(pcols,pver), intent(in ) :: det_upd ! detrainment from updraft - real(r8), dimension(pcols,pver), intent(in ) :: mfx_upd ! updraft mass flux - real(r8), dimension(pcols,pver), intent(in ) :: mfx_dnd ! dndraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: mflx_net ! net convective mass flux + real(r8), dimension(pcols,pver), intent(in ) :: detr_up ! detrainment from updraft + real(r8), dimension(pcols,pver), intent(in ) :: mflx_up ! updraft mass flux + real(r8), dimension(pcols,pver), intent(in ) :: mflx_dn ! dndraft mass flux real(r8), dimension(pcols,pver), intent(in ) :: q_dnd ! dndraft specific humidity real(r8), dimension(pcols,pver), intent(in ) :: s_dnd ! dndraft dry static energy real(r8), dimension(pcols), intent(in ) :: cape ! convective available potential energy @@ -1953,11 +1953,11 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & cld_base_mass_flux(i) = 0._r8 eb = p_mid(i,mx(i))*q_mid(i,mx(i))/ (zm_const%epsilo+q_mid(i,mx(i))) dtbdt(i) = (1._r8/dsubcld(i)) & - *( mfx_upd(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & - +mfx_dnd(i,mx(i))*(s_int(i,mx(i))-s_dnd(i,mx(i))) ) + *( mflx_up(i,mx(i))*(s_int(i,mx(i))-s_upd(i,mx(i))) & + +mflx_dn(i,mx(i))*(s_int(i,mx(i))-s_dnd(i,mx(i))) ) dqbdt(i) = (1._r8/dsubcld(i)) & - *( mfx_upd(i,mx(i))*(q_int(i,mx(i))-q_upd(i,mx(i))) & - +mfx_dnd(i,mx(i))*(q_int(i,mx(i))-q_dnd(i,mx(i))) ) + *( mflx_up(i,mx(i))*(q_int(i,mx(i))-q_upd(i,mx(i))) & + +mflx_dn(i,mx(i))*(q_int(i,mx(i))-q_dnd(i,mx(i))) ) debdt = zm_const%epsilo*p_mid(i,mx(i)) / (zm_const%epsilo+q_mid(i,mx(i)))**2 * dqbdt(i) dtldt(i) = -2840._r8 * (3.5_r8/t_mid(i,mx(i))*dtbdt(i)-debdt/eb)/ & (3.5_r8*log(t_mid(i,mx(i)))-log(eb)-4.805_r8)**2 @@ -1970,22 +1970,22 @@ subroutine zm_closure(pcols, ncol, pver, pverp, msg, cape_threshold_in, & ! cloud top if (k==jt(i)) then dtmdt(i,k) = (1._r8/p_del(i,k)) & - *(mfx_upd(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & - + mfx_dnd(i,k+1)*(s_dnd(i,k+1)-s_int(i,k+1))) + *(mflx_up(i,k+1)*(s_upd(i,k+1)-s_int(i,k+1)-zm_const%latvap/zm_const%cpair*ql(i,k+1)) & + + mflx_dn(i,k+1)*(s_dnd(i,k+1)-s_int(i,k+1))) dqmdt(i,k) = (1._r8/p_del(i,k)) & - *(mfx_upd(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & - + mfx_dnd(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1))) + *(mflx_up(i,k+1)*(q_upd(i,k+1)-q_int(i,k+1)+ql(i,k+1) ) & + + mflx_dn(i,k+1)*(q_dnd(i,k+1)-q_int(i,k+1))) end if ! below cloud top if ( k>jt(i) .and. k mx(i)) then dsdt(i,k) = dsdt(i,k-1) dqdt(i,k) = dqdt(i,k-1) From f5ef1c6e7ff97bb4b31e8b4a32965ded547deb87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:55:12 +0000 Subject: [PATCH 200/398] Initial plan From 38ecca8a434248ab9ffcca1a9222ee5e650601d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 16:00:09 +0000 Subject: [PATCH 201/398] Fix NINST > 1 memory logging bug by including driver_id in filename - Modified driver-mct/main/cime_comp_mod.F90 to include driver_id in memory log filename - Modified driver-moab/main/cime_comp_mod.F90 to include driver_id in memory log filename - Changed filename format from memory.{0,1,2,3,4}.$nsecs.log to memory_$driver_id.{0,1,2,3,4}.$nsecs.log - Increased c_mprof_file character length from 18 to 28 to accommodate longer filenames - Updated comments to reflect new naming convention This prevents file name collisions when running with NINST > 1, where multiple driver instances would otherwise try to write to the same memory log file. Co-authored-by: mahf708 <122953255+mahf708@users.noreply.github.com> --- driver-mct/main/cime_comp_mod.F90 | 6 +++--- driver-moab/main/cime_comp_mod.F90 | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/driver-mct/main/cime_comp_mod.F90 b/driver-mct/main/cime_comp_mod.F90 index 4d177e4c4d5f..f880958c3dff 100644 --- a/driver-mct/main/cime_comp_mod.F90 +++ b/driver-mct/main/cime_comp_mod.F90 @@ -2583,7 +2583,7 @@ subroutine cime_run() logical :: prep_glc_accum_avg_called ! Whether prep_glc_accum_avg has been called this timestep integer :: i, nodeId character(len=15) :: c_ymdtod - character(len=18) :: c_mprof_file + character(len=28) :: c_mprof_file 101 format( A, i10.8, i8, 12A, A, F8.2, A, F8.2 ) 102 format( A, i10.8, i8, A, 8L3 ) @@ -2673,8 +2673,8 @@ subroutine cime_run() ! write to standalone file if ( iamroot_CPLID) then mlog = shr_file_getUnit() - ! log-name: memory.{0,1,2,3,4}.$nsecs.log - write(c_mprof_file,'(a7,i1,a1,i0,a4)') 'memory.',info_mprof,'.',info_mprof_dt,'.log' + ! log-name: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log + write(c_mprof_file,'(a7,i0,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' inquire(file=trim(c_mprof_file),exist=exists) if (exists) then open(mlog, file=trim(c_mprof_file), status='old', position='append') diff --git a/driver-moab/main/cime_comp_mod.F90 b/driver-moab/main/cime_comp_mod.F90 index 4975d767622c..dec7f3b42f1c 100644 --- a/driver-moab/main/cime_comp_mod.F90 +++ b/driver-moab/main/cime_comp_mod.F90 @@ -2707,7 +2707,7 @@ subroutine cime_run() logical :: prep_glc_accum_avg_called ! Whether prep_glc_accum_avg has been called this timestep integer :: i, nodeId character(len=15) :: c_ymdtod - character(len=18) :: c_mprof_file + character(len=28) :: c_mprof_file integer :: cur_step_no ! step number 101 format( A, i10.8, i8, 12A, A, F8.2, A, F8.2 ) @@ -2797,8 +2797,8 @@ subroutine cime_run() ! write to standalone file if ( iamroot_CPLID) then mlog = shr_file_getUnit() - ! log-name: memory.{0,1,2,3,4}.$nsecs.log - write(c_mprof_file,'(a7,i1,a1,i0,a4)') 'memory.',info_mprof,'.',info_mprof_dt,'.log' + ! log-name: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log + write(c_mprof_file,'(a7,i0,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' inquire(file=trim(c_mprof_file),exist=exists) if (exists) then open(mlog, file=trim(c_mprof_file), status='old', position='append') From 60f78bfea18217787c62055670438f7b8c85ad7d Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 11 Dec 2025 08:05:59 -0800 Subject: [PATCH 202/398] make zero initialization more consistent --- components/eam/src/physics/cam/zm/zm_conv.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 8492d6ffdbd3..13117760af89 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -318,8 +318,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & end do prec(i) = 0._r8 rliq(i) = 0._r8 - pflx(i,pverp) = 0 - pflx_g(i,pverp)= 0 + pflx(i,pverp) = 0._r8 + pflx_g(i,pverp)= 0._r8 pbl_top(i) = pver dsubcld(i) = 0._r8 jctop(i) = pver @@ -552,7 +552,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & !---------------------------------------------------------------------------- ! limit cloud base mass flux to theoretical upper bound. do i = 1,lengath - mflx_up_max(i) = 0 + mflx_up_max(i) = 0._r8 do k = msg+2, pver mflx_up_max(i) = max(mflx_up_max(i), mflx_up(i,k)/p_del(i,k)) end do @@ -571,7 +571,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & if (zm_param%no_deep_pbl) then do i = 1,lengath if (z_mid_in(gather_index(i),jt(i)) < pbl_hgt(gather_index(i))) then - cld_base_mass_flux(i) = 0 + cld_base_mass_flux(i) = 0._r8 end if end do end if From f9e79769f3c963c908f21fcd92dc1f3dedb02cc0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 16:59:26 +0000 Subject: [PATCH 203/398] Use zero-padded 4-digit format for driver_id in memory log filenames Changed format specifier from i0 to i4.4 for driver_id to ensure consistent 4-digit zero-padded formatting (e.g., memory_0001.3.86400.log instead of memory_1.3.86400.log). This addresses feedback from @ndkeen to improve filename consistency and readability across multiple driver instances. Co-authored-by: mahf708 <122953255+mahf708@users.noreply.github.com> --- driver-mct/main/cime_comp_mod.F90 | 2 +- driver-moab/main/cime_comp_mod.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-mct/main/cime_comp_mod.F90 b/driver-mct/main/cime_comp_mod.F90 index f880958c3dff..745a64dcc54a 100644 --- a/driver-mct/main/cime_comp_mod.F90 +++ b/driver-mct/main/cime_comp_mod.F90 @@ -2674,7 +2674,7 @@ subroutine cime_run() if ( iamroot_CPLID) then mlog = shr_file_getUnit() ! log-name: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log - write(c_mprof_file,'(a7,i0,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' + write(c_mprof_file,'(a7,i4.4,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' inquire(file=trim(c_mprof_file),exist=exists) if (exists) then open(mlog, file=trim(c_mprof_file), status='old', position='append') diff --git a/driver-moab/main/cime_comp_mod.F90 b/driver-moab/main/cime_comp_mod.F90 index dec7f3b42f1c..49a9ac004f64 100644 --- a/driver-moab/main/cime_comp_mod.F90 +++ b/driver-moab/main/cime_comp_mod.F90 @@ -2798,7 +2798,7 @@ subroutine cime_run() if ( iamroot_CPLID) then mlog = shr_file_getUnit() ! log-name: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log - write(c_mprof_file,'(a7,i0,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' + write(c_mprof_file,'(a7,i4.4,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' inquire(file=trim(c_mprof_file),exist=exists) if (exists) then open(mlog, file=trim(c_mprof_file), status='old', position='append') From d7bd2fd4e0e971a99b5d9168ead7a1f8cc745f96 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 17:05:43 +0000 Subject: [PATCH 204/398] Update memory log file patterns in provenance.py for new filename format Updated glob patterns in cime_config/customize/provenance.py to match the new memory log filename format (memory_####.[0-4].*.log) instead of the old format (memory.[0-4].*.log). Changes: - Line 687: Updated pattern for archiving memory profile logs - Line 741: Updated pattern for copying memory log archives This ensures the archiving and copying functions correctly handle memory log files with the new zero-padded driver_id prefix. Co-authored-by: mahf708 <122953255+mahf708@users.noreply.github.com> --- cime_config/customize/provenance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/customize/provenance.py b/cime_config/customize/provenance.py index 85ed99c86daf..e63060853e60 100644 --- a/cime_config/customize/provenance.py +++ b/cime_config/customize/provenance.py @@ -684,7 +684,7 @@ def _archive_atm_costs(lid, rundir): def _archive_memory_profile(lid, rundir): # gzip memory profile log - glob_to_copy = "memory.[0-4].*.log" + glob_to_copy = "memory_*.[0-4].*.log" for item in glob.glob(os.path.join(rundir, glob_to_copy)): mprof_dst_path = os.path.join( os.path.dirname(item), (os.path.basename(item) + ".{}").format(lid) @@ -738,7 +738,7 @@ def _copy_performance_archive_files( globs_to_copy.append(os.path.join(rundir, "e3sm.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "cpl.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "atm_chunk_costs.{}.gz".format(lid))) - globs_to_copy.append(os.path.join(rundir, "memory.[0-4].*.log.{}.gz".format(lid))) + globs_to_copy.append(os.path.join(rundir, "memory_*.[0-4].*.log.{}.gz".format(lid))) globs_to_copy.append("timing/*.{}*".format(lid)) globs_to_copy.append("CaseStatus") globs_to_copy.append(os.path.join(rundir, "spio_stats.{}.tar.gz".format(lid))) From b96ae8765d040a429eaae13d13074bcb5fd24582 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Dec 2025 17:17:52 +0000 Subject: [PATCH 205/398] Only add driver_id suffix when num_inst_driver > 1 Modified memory log filename generation to conditionally include driver_id: - When num_inst_driver == 1: Use original format memory.{0,1,2,3,4}.$nsecs.log - When num_inst_driver > 1: Use new format memory_####.{0,1,2,3,4}.$nsecs.log This follows the existing pattern used elsewhere in the code (e.g., cpl_inst_tag) where the instance suffix is only added when there are multiple instances. Updated provenance.py to handle both filename patterns during archiving and copying operations. Changes in driver-mct and driver-moab: - Added conditional check for num_inst_driver > 1 - Use appropriate format string for each case Changes in provenance.py: - Updated _archive_memory_profile to handle both patterns - Updated _copy_performance_archive_files to include both patterns Co-authored-by: mahf708 <122953255+mahf708@users.noreply.github.com> --- cime_config/customize/provenance.py | 18 +++++++++++------- driver-mct/main/cime_comp_mod.F90 | 9 +++++++-- driver-moab/main/cime_comp_mod.F90 | 9 +++++++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cime_config/customize/provenance.py b/cime_config/customize/provenance.py index e63060853e60..d7901830e990 100644 --- a/cime_config/customize/provenance.py +++ b/cime_config/customize/provenance.py @@ -684,13 +684,15 @@ def _archive_atm_costs(lid, rundir): def _archive_memory_profile(lid, rundir): # gzip memory profile log - glob_to_copy = "memory_*.[0-4].*.log" - for item in glob.glob(os.path.join(rundir, glob_to_copy)): - mprof_dst_path = os.path.join( - os.path.dirname(item), (os.path.basename(item) + ".{}").format(lid) - ) - shutil.move(item, mprof_dst_path) - utils.gzip_existing_file(mprof_dst_path) + # Handle both single instance (memory.[0-4].*.log) and multiple instances (memory_*.[0-4].*.log) + glob_patterns = ["memory.[0-4].*.log", "memory_*.[0-4].*.log"] + for glob_to_copy in glob_patterns: + for item in glob.glob(os.path.join(rundir, glob_to_copy)): + mprof_dst_path = os.path.join( + os.path.dirname(item), (os.path.basename(item) + ".{}").format(lid) + ) + shutil.move(item, mprof_dst_path) + utils.gzip_existing_file(mprof_dst_path) def _archive_spio_stats(lid, rundir): @@ -738,6 +740,8 @@ def _copy_performance_archive_files( globs_to_copy.append(os.path.join(rundir, "e3sm.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "cpl.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "atm_chunk_costs.{}.gz".format(lid))) + # Handle both single instance and multiple instances memory log files + globs_to_copy.append(os.path.join(rundir, "memory.[0-4].*.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "memory_*.[0-4].*.log.{}.gz".format(lid))) globs_to_copy.append("timing/*.{}*".format(lid)) globs_to_copy.append("CaseStatus") diff --git a/driver-mct/main/cime_comp_mod.F90 b/driver-mct/main/cime_comp_mod.F90 index 745a64dcc54a..15bee2225dc1 100644 --- a/driver-mct/main/cime_comp_mod.F90 +++ b/driver-mct/main/cime_comp_mod.F90 @@ -2673,8 +2673,13 @@ subroutine cime_run() ! write to standalone file if ( iamroot_CPLID) then mlog = shr_file_getUnit() - ! log-name: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log - write(c_mprof_file,'(a7,i4.4,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' + ! log-name: memory.{0,1,2,3,4}.$nsecs.log (single instance) + ! or: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log (multiple instances) + if (num_inst_driver > 1) then + write(c_mprof_file,'(a7,i4.4,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' + else + write(c_mprof_file,'(a7,i1,a1,i0,a4)') 'memory.',info_mprof,'.',info_mprof_dt,'.log' + endif inquire(file=trim(c_mprof_file),exist=exists) if (exists) then open(mlog, file=trim(c_mprof_file), status='old', position='append') diff --git a/driver-moab/main/cime_comp_mod.F90 b/driver-moab/main/cime_comp_mod.F90 index 49a9ac004f64..053a6d4459a8 100644 --- a/driver-moab/main/cime_comp_mod.F90 +++ b/driver-moab/main/cime_comp_mod.F90 @@ -2797,8 +2797,13 @@ subroutine cime_run() ! write to standalone file if ( iamroot_CPLID) then mlog = shr_file_getUnit() - ! log-name: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log - write(c_mprof_file,'(a7,i4.4,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' + ! log-name: memory.{0,1,2,3,4}.$nsecs.log (single instance) + ! or: memory_$ninst_driver.{0,1,2,3,4}.$nsecs.log (multiple instances) + if (num_inst_driver > 1) then + write(c_mprof_file,'(a7,i4.4,a1,i1,a1,i0,a4)') 'memory_',driver_id,'.',info_mprof,'.',info_mprof_dt,'.log' + else + write(c_mprof_file,'(a7,i1,a1,i0,a4)') 'memory.',info_mprof,'.',info_mprof_dt,'.log' + endif inquire(file=trim(c_mprof_file),exist=exists) if (exists) then open(mlog, file=trim(c_mprof_file), status='old', position='append') From b948938c11f3b568dce472c1aab2711f4e4f1a44 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 11 Dec 2025 09:34:03 -0800 Subject: [PATCH 206/398] update units --- components/eam/src/physics/cam/zm/zm_conv.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 13117760af89..1173fb7cdd01 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -203,8 +203,8 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols), intent( out) :: dsubcld ! thickness between lcl and msemax_klev [mb] real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep [?] real(r8), dimension(pcols), intent( out) :: rliq ! reserved liquid (not yet in cldliq) for energy integrals - real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate [?] - real(r8), dimension(pcols,pver), intent( out) :: dlf ! detrained cloud liq mixing ratio [kg/kg] + real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate [kg/kg/s] + real(r8), dimension(pcols,pver), intent( out) :: dlf ! detrained cloud liq mixing ratio [kg/kg/s] type(zm_aero_t), intent(inout) :: aero ! aerosol object type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- @@ -734,8 +734,8 @@ subroutine zm_conv_evap(pcols, ncol, pver, pverp, time_step, & real(r8), dimension(pcols,pver), intent(out ) :: tend_s_snwevmlt ! Heating rate of snow evap/melt [J/kg/s] real(r8), dimension(pcols), intent(inout) :: prec ! Convective-scale prec rate [m/s] real(r8), dimension(pcols), intent(out ) :: snow ! Convective-scale snow rate [m/s] - real(r8), dimension(pcols,pver), intent(out ) :: ntprprd ! net precip production in layer [?] - real(r8), dimension(pcols,pver), intent(out ) :: ntsnprd ! net snow production in layer [?] + real(r8), dimension(pcols,pver), intent(out ) :: ntprprd ! net precip production in layer [kg/kg/s] + real(r8), dimension(pcols,pver), intent(out ) :: ntsnprd ! net snow production in layer [kg/kg/s] real(r8), dimension(pcols,pverp),intent(out ) :: flxprec ! Convective flux of prec at interfaces [kg/m2/s] real(r8), dimension(pcols,pverp),intent(out ) :: flxsnow ! Convective flux of snow at interfaces [kg/m2/s] type(zm_microp_st), intent(inout) :: microp_st ! ZM microphysics data structure From a0ad8180ad4062759708e0c84dd58acb01470c45 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 11 Dec 2025 09:36:14 -0800 Subject: [PATCH 207/398] fix time step handling in EAMxx fortran bridge to ZM --- .../src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 index a93d9e160f39..5165463d860b 100644 --- a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 +++ b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge_main.F90 @@ -232,7 +232,7 @@ subroutine zm_eamxx_bridge_run_c( ncol, dtime, is_first_step, & !----------------------------------------------------------------------------- ! Call the primary Zhang-McFarlane convection parameterization - call zm_conv_main(ncol, ncol, pver, pverp, loc_is_first_step, 0.5*dtime, & + call zm_conv_main(ncol, ncol, pver, pverp, loc_is_first_step, dtime, & state_t, state_qv, state_omega, & state_p_mid, state_p_int, state_p_del, & state_phis, state_zm, state_zi, state_pblh, & From 754fdbb6a43910e689c75f64f61b13a9f76c9f93 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 11 Dec 2025 09:51:42 -0800 Subject: [PATCH 208/398] fix variable description --- components/eam/src/physics/cam/zm/zm_conv.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 1173fb7cdd01..b53210500fe1 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -204,7 +204,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep [?] real(r8), dimension(pcols), intent( out) :: rliq ! reserved liquid (not yet in cldliq) for energy integrals real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate [kg/kg/s] - real(r8), dimension(pcols,pver), intent( out) :: dlf ! detrained cloud liq mixing ratio [kg/kg/s] + real(r8), dimension(pcols,pver), intent( out) :: dlf ! etrainment rate of cloud liquid [kg/kg/s] type(zm_aero_t), intent(inout) :: aero ! aerosol object type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- From 09aa41a7ec5b908960520e5c71ee97766ed64d8e Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 11 Dec 2025 09:53:49 -0800 Subject: [PATCH 209/398] fix typo --- components/eam/src/physics/cam/zm/zm_conv.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index b53210500fe1..7c30a93c0adb 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -204,7 +204,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & real(r8), dimension(pcols,pver), intent( out) :: ql ! cloud liquid water for chem/wetdep [?] real(r8), dimension(pcols), intent( out) :: rliq ! reserved liquid (not yet in cldliq) for energy integrals real(r8), dimension(pcols,pver), intent( out) :: rprd ! rain production rate [kg/kg/s] - real(r8), dimension(pcols,pver), intent( out) :: dlf ! etrainment rate of cloud liquid [kg/kg/s] + real(r8), dimension(pcols,pver), intent( out) :: dlf ! detrainment rate of cloud liquid water [kg/kg/s] type(zm_aero_t), intent(inout) :: aero ! aerosol object type(zm_microp_st), intent(inout) :: microp_st ! convective microphysics state and tendencies !---------------------------------------------------------------------------- From a7a509cb967d299c77ef5d1f7fa29d7147a6b19d Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 11 Dec 2025 11:28:15 -0800 Subject: [PATCH 210/398] minor fix --- components/eam/src/physics/cam/zm/zm_conv.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv.F90 b/components/eam/src/physics/cam/zm/zm_conv.F90 index 7c30a93c0adb..c61ddd4f80f3 100644 --- a/components/eam/src/physics/cam/zm/zm_conv.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv.F90 @@ -557,7 +557,7 @@ subroutine zm_conv_main(pcols, ncol, pver, pverp, is_first_step, time_step, & mflx_up_max(i) = max(mflx_up_max(i), mflx_up(i,k)/p_del(i,k)) end do if (mflx_up_max(i) > 0._r8) then - cld_base_mass_flux(i) = min(cld_base_mass_flux(i),1/(time_step*mflx_up_max(i))) + cld_base_mass_flux(i) = min(cld_base_mass_flux(i),1._r8/(time_step*mflx_up_max(i))) else cld_base_mass_flux(i) = 0._r8 end if From 53d4d88b0968a400366913c7bcf5ed21d8a257bc Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 11 Dec 2025 15:01:02 -0500 Subject: [PATCH 211/398] Add support for frontier's debug queue This is useful for running small jobs and it exists, so why not support it. [BFB] --- cime_config/machines/config_batch.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/machines/config_batch.xml b/cime_config/machines/config_batch.xml index d5809e2fd9c3..faada0cd8d40 100644 --- a/cime_config/machines/config_batch.xml +++ b/cime_config/machines/config_batch.xml @@ -800,6 +800,7 @@ batch batch batch + debug From bef7f507dcd11c559aec529ae342ed06f8d51701 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 11 Dec 2025 16:11:01 -0500 Subject: [PATCH 212/398] Fixes --- cime_config/machines/config_batch.xml | 31 +++++++++++++++++++++++- cime_config/machines/config_machines.xml | 2 +- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/cime_config/machines/config_batch.xml b/cime_config/machines/config_batch.xml index faada0cd8d40..97aafc482bc8 100644 --- a/cime_config/machines/config_batch.xml +++ b/cime_config/machines/config_batch.xml @@ -311,6 +311,32 @@ + + squeue + sbatch + scancel + #SBATCH + (\d+)$ + --dependency=afterok:jobid + --dependency=afterany:jobid + : + %H:%M:%S + --mail-user + --mail-type + none, all, begin, end, fail + + + + + + + --job-name={{ job_id }} + --nodes={{ num_nodes }} + --output={{ job_id }}.%j + --exclusive + + + squeue sbatch @@ -791,11 +817,14 @@ - + sbatch --core-spec=$SHELL{tpn=`./xmlquery --value MAX_TASKS_PER_NODE`; if [[ $tpn > 56 ]]; then echo "64-$tpn"|bc; else echo 8; fi; } + + -q debug + batch batch diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 2c1a9593154a..b11d0dff393b 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -1295,7 +1295,7 @@ /lustre/orion/cli115/world-shared/e3sm/tools/cprnc/cprnc 8 1 - slurm + frontier_slurm e3sm 56 8 From 1352ba778a25a0d77ed6601f6f2e95dae7102eaa Mon Sep 17 00:00:00 2001 From: Jon Wolfe Date: Thu, 11 Dec 2025 15:24:55 -0600 Subject: [PATCH 213/398] Clean up testdef --- .../testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands index af8ffaa149a6..c03d6b52e431 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/lnd_docn_1way/shell_commands @@ -13,6 +13,3 @@ ./xmlchange --file env_run.xml --id DATM_CLMNCEP_YR_START --val 1980 ./xmlchange --file env_run.xml --id DATM_CLMNCEP_YR_END --val 1981 ./xmlchange --file env_run.xml --id DATM_CLMNCEP_YR_ALIGN --val 1980 - -./xmlchange PIO_TYPENAME_OCN=netcdf # pnetcdf doesn't support NETCDF4 -./xmlchange NTASKS=600 \ No newline at end of file From 8b41de35c0a388cdfc71bc1326f76b33377fe4c4 Mon Sep 17 00:00:00 2001 From: noel Date: Thu, 11 Dec 2025 14:33:31 -0800 Subject: [PATCH 214/398] Only set openmp variables when building threaded. Reduce the max total tasks for pm-gpu to reflect there is only one CPU (where pm-cpu has 2 CPU's) Do the same for muller and alvarez to be consistent. Use same version of cmake for muller and alvarez as perlmutter. bfb --- cime_config/machines/config_machines.xml | 58 ++++++++++++++---------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 2c1a9593154a..3dfa97663871 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -353,8 +353,8 @@ nersc_slurm e3sm 128 - 256 - 256 + 128 + 128 4 64 64 @@ -456,9 +456,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -466,6 +463,11 @@ $ENV{CRAY_NETCDF_HDF5PARALLEL_PREFIX} $ENV{CRAY_PARALLEL_NETCDF_PREFIX} + + 128M + spread + threads + 1 @@ -615,9 +617,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -628,6 +627,11 @@ $ENV{CRAY_LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH} CMA + + 128M + spread + threads + /global/cfs/cdirs/e3sm/3rdparty/protobuf/21.6/intel-2023.2.0/lib/pkgconfig:$ENV{PKG_CONFIG_PATH} $SHELL{if [ -z "$ADIOS2_ROOT" ]; then echo /global/cfs/cdirs/e3sm/3rdparty/adios2/2.10.2/cray-mpich-8.1.28/intel-2023.2.0; else echo "$ADIOS2_ROOT"; fi} @@ -708,8 +712,8 @@ nersc_slurm e3sm 128 - 256 - 256 + 128 + 128 4 64 64 @@ -798,8 +802,7 @@ cray-hdf5-parallel/1.14.3.1 cray-netcdf-hdf5parallel/4.9.0.13 cray-parallel-netcdf/1.12.3.13 - cmake/3.24.3 - + cmake/3.30.2 @@ -812,9 +815,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -822,6 +822,11 @@ $ENV{CRAY_NETCDF_HDF5PARALLEL_PREFIX} $ENV{CRAY_PARALLEL_NETCDF_PREFIX} + + 128M + spread + threads + 1 @@ -970,9 +975,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -983,6 +985,11 @@ $ENV{CRAY_LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH} CMA + + 128M + spread + threads + /global/cfs/cdirs/e3sm/3rdparty/protobuf/21.6/intel-2023.2.0/lib/pkgconfig:$ENV{PKG_CONFIG_PATH} $SHELL{if [ -z "$ADIOS2_ROOT" ]; then echo /global/cfs/cdirs/e3sm/3rdparty/adios2/2.10.2/cray-mpich-8.1.28/intel-2023.2.0; else echo "$ADIOS2_ROOT"; fi} @@ -1063,8 +1070,8 @@ nersc_slurm e3sm 128 - 256 - 256 + 128 + 128 4 64 64 @@ -1153,8 +1160,7 @@ cray-hdf5-parallel/1.14.3.1 cray-netcdf-hdf5parallel/4.9.0.13 cray-parallel-netcdf/1.12.3.13 - cmake/3.24.3 - + cmake/3.30.2 @@ -1167,9 +1173,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -1177,6 +1180,11 @@ $ENV{CRAY_NETCDF_HDF5PARALLEL_PREFIX} $ENV{CRAY_PARALLEL_NETCDF_PREFIX} + + 128M + spread + threads + 1 From 4f238fe95f4ae8ee450b93b94069468730183b58 Mon Sep 17 00:00:00 2001 From: Emily Katherine de Jong Date: Wed, 26 Nov 2025 12:40:50 -0800 Subject: [PATCH 215/398] Check for duplicate outputs in the yaml processing --- .../eamxx/cime_config/eamxx_buildnml.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/components/eamxx/cime_config/eamxx_buildnml.py b/components/eamxx/cime_config/eamxx_buildnml.py index 721cc5d3aa7a..6031ceeca847 100644 --- a/components/eamxx/cime_config/eamxx_buildnml.py +++ b/components/eamxx/cime_config/eamxx_buildnml.py @@ -1083,6 +1083,7 @@ def do_cime_vars_on_yaml_output_files(case, caseroot): # We will also change the 'output_yaml_files' entry in scream_input.yaml, # to point to the copied files in $rundir/data output_yaml_files = [] + file_signatures = [] scream_input_file = os.path.join(rundir,'data','scream_input.yaml') scream_input = yaml.load(open(scream_input_file,"r"),Loader=yaml.SafeLoader) @@ -1138,6 +1139,26 @@ def do_cime_vars_on_yaml_output_files(case, caseroot): f" frequency_units: {units}\n" f" ATM_NCPL: {case.get_value('ATM_NCPL')}\n" f" This yields dt_atm={dt_atm} > dt_output={dt_out}. Please, adjust 'frequency' and/or 'frequency_units'\n") + + # Check for duplicate output file signatures + prefix = content['filename_prefix'] + avg_type = content['averaging_type'].upper() + freq = content['output_control']['frequency'] + units = content['output_control']['frequency_units'] + signature = (prefix, avg_type, freq, units) + for prev_fn, prev_sig in file_signatures: + expect(signature != prev_sig, + f"Duplicate output file configuration detected!\n" + f" File 1: {prev_fn}\n" + f" File 2: {fn}\n" + f" Both would generate files with:\n" + f" - averaging_type: {avg_type}\n" + f" - frequency: {freq}\n" + f" - frequency_units: {units}\n" + f" - filename_prefix: {prefix}\n" + f" This would cause both outputs to write to the same NetCDF file.\n" + f" Please modify one of the YAML files to use a different prefix or output frequency.") + file_signatures.append((fn, signature)) ordered_dump(content, open(dst_yaml, "w")) From 6c7a3d96e44afa6675de8457c706b6268982bed5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 18:30:23 +0000 Subject: [PATCH 216/398] Initial plan From 2a0941d43243c5001981c7e2ad3018987c664a68 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 18:39:25 +0000 Subject: [PATCH 217/398] Fix e3sm_timing_stats handling for multi-instance cases (NINST > 1) Co-authored-by: mahf708 <122953255+mahf708@users.noreply.github.com> --- cime_config/customize/provenance.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cime_config/customize/provenance.py b/cime_config/customize/provenance.py index d7901830e990..d7ce7ebcb5af 100644 --- a/cime_config/customize/provenance.py +++ b/cime_config/customize/provenance.py @@ -607,9 +607,13 @@ def save_postrun_provenance(case, lid=None): _archive_spio_stats(lid, rundir) - utils.gzip_existing_file( - os.path.join(caseroot, "timing", "e3sm_timing_stats.%s" % lid) - ) + # Handle both single instance and multi-instance timing stats files + # For NINST=1: e3sm_timing_stats.{lid} + # For NINST>1: e3sm_timing_0001_stats.{lid}, e3sm_timing_0002_stats.{lid}, etc. + timing_stats_pattern = os.path.join(caseroot, "timing", "e3sm_timing*stats.%s" % lid) + timing_stats_files = glob.glob(timing_stats_pattern) + for timing_stats_file in timing_stats_files: + utils.gzip_existing_file(timing_stats_file) # JGF: not sure why we do this timing_saved_file = "timing.%s.saved" % lid From 22dcb2136a79dc0a960af8fd8cbf2d8ec442d714 Mon Sep 17 00:00:00 2001 From: Naser Mahfouz Date: Sun, 14 Dec 2025 11:02:05 -0500 Subject: [PATCH 218/398] Handle multi-instancing for logs --- cime_config/customize/provenance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/customize/provenance.py b/cime_config/customize/provenance.py index d7ce7ebcb5af..ea98e966f967 100644 --- a/cime_config/customize/provenance.py +++ b/cime_config/customize/provenance.py @@ -743,8 +743,8 @@ def _copy_performance_archive_files( globs_to_copy.append("logs/run_environment.txt.{}".format(lid)) globs_to_copy.append(os.path.join(rundir, "e3sm.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "cpl.log.{}.gz".format(lid))) + globs_to_copy.append(os.path.join(rundir, "cpl_*.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "atm_chunk_costs.{}.gz".format(lid))) - # Handle both single instance and multiple instances memory log files globs_to_copy.append(os.path.join(rundir, "memory.[0-4].*.log.{}.gz".format(lid))) globs_to_copy.append(os.path.join(rundir, "memory_*.[0-4].*.log.{}.gz".format(lid))) globs_to_copy.append("timing/*.{}*".format(lid)) From cbc751fafc59f75fc4fa7336a4b7db98be1b0f9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:08:22 +0000 Subject: [PATCH 219/398] Bump actions/upload-artifact from 5 to 6 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/e3sm-gh-ci-cime-tests.yml | 2 +- .github/workflows/e3sm-gh-ci-w-cime-tests.yml | 2 +- .github/workflows/eamxx-gh-clang-format.yml | 2 +- .github/workflows/eamxx-v1-testing.yml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e3sm-gh-ci-cime-tests.yml b/.github/workflows/e3sm-gh-ci-cime-tests.yml index 78f015a919d8..f72ea673d47e 100644 --- a/.github/workflows/e3sm-gh-ci-cime-tests.yml +++ b/.github/workflows/e3sm-gh-ci-cime-tests.yml @@ -58,7 +58,7 @@ jobs: ./create_test ${{ matrix.test }} --wait --debug - name: Artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: ${{ always() }} with: name: ${{ matrix.test }} diff --git a/.github/workflows/e3sm-gh-ci-w-cime-tests.yml b/.github/workflows/e3sm-gh-ci-w-cime-tests.yml index ac851788e24a..0f124f698510 100644 --- a/.github/workflows/e3sm-gh-ci-w-cime-tests.yml +++ b/.github/workflows/e3sm-gh-ci-w-cime-tests.yml @@ -46,7 +46,7 @@ jobs: ./create_test ${{ matrix.test }} --wait --debug - name: Artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: ${{ always() }} with: name: ${{ matrix.test }} diff --git a/.github/workflows/eamxx-gh-clang-format.yml b/.github/workflows/eamxx-gh-clang-format.yml index df8ac6910d17..d016e4d472c5 100644 --- a/.github/workflows/eamxx-gh-clang-format.yml +++ b/.github/workflows/eamxx-gh-clang-format.yml @@ -138,7 +138,7 @@ jobs: fi - name: upload diff patch if: ${{ env.status_fail == 'true' }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: ${{ env.fname }} path: "components/eamxx/${{ env.fname }}" diff --git a/.github/workflows/eamxx-v1-testing.yml b/.github/workflows/eamxx-v1-testing.yml index be96f5ef7ab1..81b55edb2a64 100644 --- a/.github/workflows/eamxx-v1-testing.yml +++ b/.github/workflows/eamxx-v1-testing.yml @@ -112,7 +112,7 @@ jobs: ./cime/scripts/create_test ${{ matrix.test.full_name }} ${{ env.flags }} --wait - name: Upload log files if: ${{ always() }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: logs.${{ matrix.test.short_name }} path: | @@ -126,7 +126,7 @@ jobs: NODE_EXTRA_CA_CERTS: ${{ env.NODE_EXTRA_CA_CERTS }} - name: Upload nc files if: ${{ failure() && steps.run-tests.outcome == 'failure' }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: outputs.${{ matrix.test.short_name }} path: | From b0a0d899848166a58dd60acbddf272d8600064fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 10:08:27 +0000 Subject: [PATCH 220/398] Bump DavidAnson/markdownlint-cli2-action from 21 to 22 Bumps [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action) from 21 to 22. - [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases) - [Commits](https://github.com/davidanson/markdownlint-cli2-action/compare/v21...v22) --- updated-dependencies: - dependency-name: DavidAnson/markdownlint-cli2-action dependency-version: '22' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/e3sm-gh-md-linter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e3sm-gh-md-linter.yml b/.github/workflows/e3sm-gh-md-linter.yml index d657d6a04805..4b523f2ac56f 100644 --- a/.github/workflows/e3sm-gh-md-linter.yml +++ b/.github/workflows/e3sm-gh-md-linter.yml @@ -25,7 +25,7 @@ jobs: with: files: '**/*.md' separator: "," - - uses: DavidAnson/markdownlint-cli2-action@v21 + - uses: DavidAnson/markdownlint-cli2-action@v22 if: steps.changed-files.outputs.any_changed == 'true' with: config: 'docs/.markdownlint.json' From 35928d342ced2fce3955de4bb861f69877a977f4 Mon Sep 17 00:00:00 2001 From: "Jeffrey N. Johnson" Date: Mon, 15 Dec 2025 10:17:12 -0800 Subject: [PATCH 221/398] Forcefully disables Haero tests when building mam4xx. --- components/eamxx/src/physics/mam/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/mam/CMakeLists.txt b/components/eamxx/src/physics/mam/CMakeLists.txt index 1db92678176c..5932ae91b961 100644 --- a/components/eamxx/src/physics/mam/CMakeLists.txt +++ b/components/eamxx/src/physics/mam/CMakeLists.txt @@ -9,7 +9,7 @@ endif() # Haero (Kokkos-based aerosol interface library) set(HAERO_ENABLE_GPU ${EAMXX_ENABLE_GPU}) set(HAERO_ENABLE_MPI ON) -set(HAERO_ENABLE_TESTS OFF) +set(HAERO_ENABLE_TESTS OFF CACHE BOOL "Disable Haero tests within E3SM" FORCE) if (SCREAM_DOUBLE_PRECISION) set(HAERO_PRECISION "double") else() From 99e5bdcd773969933b1f4bdcb6a172aa29c9be79 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Mon, 15 Dec 2025 19:54:54 +0000 Subject: [PATCH 222/398] Update RCS test pe-counts Default to machine-specific XML-based pe-counts --- cime_config/tests.py | 4 ++-- components/eamxx/cime_config/config_pes.xml | 15 ++++++++++++++- .../testmods_dirs/eamxx/perturb/shell_commands | 2 ++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cime_config/tests.py b/cime_config/tests.py index 8908efea206a..19791a401c7b 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -795,8 +795,8 @@ "inherit" : ( ), "tests" : ( - "RCS_P8_C4.ne30pg2_ne30pg2.F2010-SCREAMv1.eamxx-perturb", # 8 nodes, about 1.9 hours on pm-gpu - "RCS_P1_C4.ne4pg2_ne4pg2.F2010-SCREAMv1.eamxx-perturb", # 1 node, about 22min on pm-gpu + "RCS_C4.ne30pg2_ne30pg2.F2010-SCREAMv1.eamxx-perturb", # 8 nodes, about 1.9 hours on pm-gpu + "RCS_C4.ne4pg2_ne4pg2.F2010-SCREAMv1.eamxx-perturb", # 1 node, about 22min on pm-gpu "ERP_D_Lh182.ne4pg2_ne4pg2.F2010-SCREAMv1", "ERS_Ln362.ne30pg2_ne30pg2.F2010-SCREAMv1" ) diff --git a/components/eamxx/cime_config/config_pes.xml b/components/eamxx/cime_config/config_pes.xml index ecf5b4a3abbf..4a2f8079054d 100644 --- a/components/eamxx/cime_config/config_pes.xml +++ b/components/eamxx/cime_config/config_pes.xml @@ -2,7 +2,7 @@ - + default eamxx, 1 node, no threads -1 @@ -171,6 +171,19 @@ + + + aurora: ne30 eamxx 2 nodes + + -2 + -2 + -2 + -2 + -2 + -2 + + + diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands index b89877f30f35..b95f6722dc92 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands @@ -13,6 +13,8 @@ if [[ $machine == "frontier" ]]; then export http_proxy=http://proxy.ccs.ornl.gov:3128/ export https_proxy=http://proxy.ccs.ornl.gov:3128/ export no_proxy='localhost,127.0.0.0/8,*.ccs.ornl.gov' +elif [[ $machine == "aurora" ]]; then + ./xmlchange JOB_QUEUE=prod # need >1-hr wall-time fi # Change run start From 7782c8e99cbaf21e38fe49df8b884926ff70c29f Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Tue, 16 Dec 2025 10:18:07 -0600 Subject: [PATCH 223/398] Removing non-working 1950 and 4xCO2 compsets --- cime_config/allactive/config_compsets.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cime_config/allactive/config_compsets.xml b/cime_config/allactive/config_compsets.xml index 5cdf2fc67025..cbff5a3b290d 100755 --- a/cime_config/allactive/config_compsets.xml +++ b/cime_config/allactive/config_compsets.xml @@ -421,11 +421,6 @@ 1850SOI_EAM%CMIP6-4xCO2_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV - - CRYO1850-CMIP7-4xCO2 - 1850SOI%CMIP7-4xCO2_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV - - CRYO1850-1pctCO2 1850SOI_EAM%CMIP6-1pctCO2_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV @@ -441,11 +436,6 @@ 1950SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV - - CRYO1950-CMIP7 - 1950SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV - - CRYO1850-DISMF 1850SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV From aff36b3edeb7b892584f6cb827973e998176f4c3 Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Tue, 16 Dec 2025 10:26:33 -0600 Subject: [PATCH 224/398] Removing CRYO1950-CMIP7-DISMF compset, not working --- cime_config/allactive/config_compsets.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cime_config/allactive/config_compsets.xml b/cime_config/allactive/config_compsets.xml index cbff5a3b290d..0c66bf3e22b9 100755 --- a/cime_config/allactive/config_compsets.xml +++ b/cime_config/allactive/config_compsets.xml @@ -451,11 +451,6 @@ 1950SOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV - - CRYO1950-CMIP7-DISMF - 1950SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV - - CRYO20TR 20TRSOI_EAM%CMIP6_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBPISMF_MOSART_SGLC_SWAV From a9e615efc270c44ec33821fda7bf06705b870b07 Mon Sep 17 00:00:00 2001 From: Darin Comeau Date: Tue, 16 Dec 2025 10:35:26 -0600 Subject: [PATCH 225/398] Rename CRYO1850-DISMF-CMIP7 alias --- cime_config/allactive/config_compsets.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/allactive/config_compsets.xml b/cime_config/allactive/config_compsets.xml index 0c66bf3e22b9..b31e1eeade7b 100755 --- a/cime_config/allactive/config_compsets.xml +++ b/cime_config/allactive/config_compsets.xml @@ -442,7 +442,7 @@ - CRYO1850-CMIP7-DISMF + CRYO1850-DISMF-CMIP7 1850SOI%CMIP7_EAM_ELM%CNPRDCTCBCTOP_MPASSI%DIB_MPASO%IBDISMF_MOSART_SGLC_SWAV From 877d83be19ab2fd8c9b54f332afc91b018e2ff6c Mon Sep 17 00:00:00 2001 From: "Jeffrey N. Johnson" Date: Tue, 16 Dec 2025 09:10:25 -0800 Subject: [PATCH 226/398] Haero no longer configures the OpenMP Kokkos backend for E3SM. --- externals/haero | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/haero b/externals/haero index 091124c40ce6..8f9b61aed425 160000 --- a/externals/haero +++ b/externals/haero @@ -1 +1 @@ -Subproject commit 091124c40ce63b1ec7549fa6c6a27528ba7d049b +Subproject commit 8f9b61aed4252461d76eb7c206927e4a005930f5 From bb85ebbb39de4242fdc28168d3c3b43287c8c132 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Tue, 16 Dec 2025 11:25:31 -0600 Subject: [PATCH 227/398] address implicit capture warnings in ZM --- .../eamxx/src/physics/zm/zm_functions.hpp | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 9c77fc274c69..f89b87d17e33 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -143,20 +143,32 @@ struct Functions { auto nlev_mid_packs = ekat::npack(nlev_mid); auto nlev_int_packs = ekat::npack(nlev_int); if (D == ekat::TransposeDirection::c2f) { + // create temporaries to avoid "Implicit capture" warning + const auto loc_f_z_mid = f_z_mid; + const auto loc_f_p_mid = f_p_mid; + const auto loc_f_p_del = f_p_del; + const auto loc_f_T_mid = f_T_mid; + const auto loc_f_qv = f_qv; + const auto loc_f_uwind = f_uwind; + const auto loc_f_vwind = f_vwind; + const auto loc_f_omega = f_omega; + const auto loc_f_cldfrac = f_cldfrac; + const auto loc_f_z_int = f_z_int; + const auto loc_f_p_int = f_p_int; //---------------------------------------------------------------------- // mid-point level variables Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { const int icol = i/nlev_mid_packs; const int klev = i%nlev_mid_packs; - f_z_mid (icol,klev) = z_mid (icol,klev/Spack::n)[klev%Spack::n]; - f_p_mid (icol,klev) = p_mid (icol,klev/Spack::n)[klev%Spack::n]; - f_p_del (icol,klev) = p_del (icol,klev/Spack::n)[klev%Spack::n]; - f_T_mid (icol,klev) = T_mid (icol,klev/Spack::n)[klev%Spack::n]; - f_qv (icol,klev) = qv (icol,klev/Spack::n)[klev%Spack::n]; - f_uwind (icol,klev) = uwind (icol,klev/Spack::n)[klev%Spack::n]; - f_vwind (icol,klev) = vwind (icol,klev/Spack::n)[klev%Spack::n]; - f_omega (icol,klev) = omega (icol,klev/Spack::n)[klev%Spack::n]; - f_cldfrac (icol,klev) = cldfrac (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_z_mid (icol,klev) = z_mid (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_p_mid (icol,klev) = p_mid (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_p_del (icol,klev) = p_del (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_T_mid (icol,klev) = T_mid (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_qv (icol,klev) = qv (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_uwind (icol,klev) = uwind (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_vwind (icol,klev) = vwind (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_omega (icol,klev) = omega (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_cldfrac (icol,klev) = cldfrac (icol,klev/Spack::n)[klev%Spack::n]; }); // interface level variables Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { @@ -332,24 +344,35 @@ struct Functions { Kokkos::deep_copy(cape, h_cape); Kokkos::deep_copy(activity, h_activity); //---------------------------------------------------------------------- + // create temporaries to avoid "Implicit capture" warning + const auto loc_tend_t = tend_t; + const auto loc_tend_qv = tend_qv; + const auto loc_tend_u = tend_u; + const auto loc_tend_v = tend_v; + const auto loc_rain_prod = rain_prod; + const auto loc_snow_prod = snow_prod; + const auto loc_prec_flux = prec_flux; + const auto loc_snow_flux = snow_flux; + const auto loc_mass_flux = mass_flux; + //---------------------------------------------------------------------- // mid-point level variables Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { const int icol = i/nlev_mid_packs; const int klev = i%nlev_mid_packs; - tend_t (icol,klev/Spack::n)[klev%Spack::n] = f_tend_t (icol,klev); - tend_qv (icol,klev/Spack::n)[klev%Spack::n] = f_tend_qv (icol,klev); - tend_u (icol,klev/Spack::n)[klev%Spack::n] = f_tend_u (icol,klev); - tend_v (icol,klev/Spack::n)[klev%Spack::n] = f_tend_v (icol,klev); - rain_prod(icol,klev/Spack::n)[klev%Spack::n] = f_rain_prod(icol,klev); - snow_prod(icol,klev/Spack::n)[klev%Spack::n] = f_snow_prod(icol,klev); + loc_tend_t (icol,klev/Spack::n)[klev%Spack::n] = f_tend_t (icol,klev); + loc_tend_qv (icol,klev/Spack::n)[klev%Spack::n] = f_tend_qv (icol,klev); + loc_tend_u (icol,klev/Spack::n)[klev%Spack::n] = f_tend_u (icol,klev); + loc_tend_v (icol,klev/Spack::n)[klev%Spack::n] = f_tend_v (icol,klev); + loc_rain_prod(icol,klev/Spack::n)[klev%Spack::n] = f_rain_prod(icol,klev); + loc_snow_prod(icol,klev/Spack::n)[klev%Spack::n] = f_snow_prod(icol,klev); }); // interface level variables Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { const int icol = i/nlev_int_packs; const int klev = i%nlev_int_packs; - prec_flux(icol,klev/Spack::n)[klev%Spack::n] = f_prec_flux(icol,klev); - snow_flux(icol,klev/Spack::n)[klev%Spack::n] = f_snow_flux(icol,klev); - mass_flux(icol,klev/Spack::n)[klev%Spack::n] = f_mass_flux(icol,klev); + loc_prec_flux(icol,klev/Spack::n)[klev%Spack::n] = f_prec_flux(icol,klev); + loc_snow_flux(icol,klev/Spack::n)[klev%Spack::n] = f_snow_flux(icol,klev); + loc_mass_flux(icol,klev/Spack::n)[klev%Spack::n] = f_mass_flux(icol,klev); }); } // *********************************************************************** From fb295f7400c3acfd22380fe63d9de1d2794f77ac Mon Sep 17 00:00:00 2001 From: James Foucar Date: Tue, 16 Dec 2025 10:38:41 -0700 Subject: [PATCH 228/398] Update CIME submodule from c64260ed94aff167a59635ed4a9ae5af16824e91 to d1acd48b77f9708c49d65f7246a101b08de08b6f Fixes: 1) Fix ADIOS archiving issues in short term archiving script 2) Fix handling of namelist variables with uppercase characters 3) Set FORCE_BUILD_SMP in the python, not in the XML This prevents testcases from turning on SMP when it's not needed 4) Update cprnc from v1.1.3 to v1.1.4 (includes CMake fixes) 5) fix for create_clone issue #4878 Changes: 1) Add EXCL_STRIDE to XML PE configs 2) Made ERI F1850C test work with gregorian calendar 3) wget server spider mode disabled 4) Changes needed for CESM to define an FUNITSHARE system test in the allactive area 5) Avoid creation of rpointer.*NINST_STRING files during short term archiving [BFB] --- cime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime b/cime index c64260ed94af..d1acd48b77f9 160000 --- a/cime +++ b/cime @@ -1 +1 @@ -Subproject commit c64260ed94aff167a59635ed4a9ae5af16824e91 +Subproject commit d1acd48b77f9708c49d65f7246a101b08de08b6f From 9a1a3179cce8089c36fd1c4bde461a709a873c7a Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 11:47:43 -0700 Subject: [PATCH 229/398] Update EKAT submodule --- externals/ekat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/ekat b/externals/ekat index 7156c944701f..7733e184ec3b 160000 --- a/externals/ekat +++ b/externals/ekat @@ -1 +1 @@ -Subproject commit 7156c944701fd19fa5e27ffcb86819f12851ae67 +Subproject commit 7733e184ec3b0266ec461c21677ac06c8c76219d From 0e0afae8ae63bbfecfa6393ec235eb87e1dcece4 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 14:20:32 -0700 Subject: [PATCH 230/398] EAMxx: create Quantity object to store constants with units --- .../eamxx/src/share/util/eamxx_quantity.hpp | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 components/eamxx/src/share/util/eamxx_quantity.hpp diff --git a/components/eamxx/src/share/util/eamxx_quantity.hpp b/components/eamxx/src/share/util/eamxx_quantity.hpp new file mode 100644 index 000000000000..82f3f8115f79 --- /dev/null +++ b/components/eamxx/src/share/util/eamxx_quantity.hpp @@ -0,0 +1,63 @@ +#ifndef EAMXX_QUANTITY_HPP +#define EAMXX_QUANTITY_HPP + +#include +#include + +namespace scream { + +template +struct Quantity +{ + using Units = ekat::units::Units; + + constexpr Quantity() : Quantity(ekat::invalid()) {} + constexpr Quantity(const Scalar v) : value(v), units(Units::invalid()) {} + constexpr Quantity(const Scalar v, const Units& u) : value(v), units(u) {} + + Scalar value; + Units units; +}; + +// Nano-util, that allows one to not having to bother to figure out the exact type +// of the scalar when creating a quantity object +template +constexpr Quantity create_quantity(const S s, const ekat::units::Units& u) +{ + return Quantity(s,u); +} +// ---------------- Operators overloads ------------------ // + +template +constexpr auto operator* (const Quantity& l, const Quantity& r) +{ + return create_quantity(l.value*r.value,l.units*r.units); +} +template +constexpr auto operator* (const S1& l, const Quantity& r) +{ + return create_quantity(l*r.value,r.units); +} +template +constexpr auto operator* (const Quantity& l, const S2 r) +{ + return create_quantity(l.value*r,l.units); +} +template +constexpr auto operator/ (const Quantity& l, const Quantity& r) +{ + return create_quantity(l.value/r.value,l.units*r.units); +} +template +constexpr auto operator/ (const S1 l, const Quantity& r) +{ + return create_quantity(l/r.value,r.units); +} +template +constexpr auto operator/ (const Quantity& l, const S2 r) { + return create_quantity(l.value/r,l.units); +} + +} // namespace scream + +#endif // EAMXX_QUANTITY_HPP From 7a629ffd9641f7998c28354297526df0a15e2a30 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 15:21:33 -0700 Subject: [PATCH 231/398] EAMxx: convert some constants in physics::Constant to Quantity --- .../src/share/physics/physics_constants.hpp | 155 ++++++++++-------- 1 file changed, 87 insertions(+), 68 deletions(-) diff --git a/components/eamxx/src/share/physics/physics_constants.hpp b/components/eamxx/src/share/physics/physics_constants.hpp index 1d7b6972bd81..af6885c4baab 100644 --- a/components/eamxx/src/share/physics/physics_constants.hpp +++ b/components/eamxx/src/share/physics/physics_constants.hpp @@ -1,19 +1,18 @@ #ifndef EAMXX_PHYSICS_CONSTANTS_HPP #define EAMXX_PHYSICS_CONSTANTS_HPP +#include "share/util/eamxx_quantity.hpp" #include "share/core/eamxx_types.hpp" #include #include - -#include -#include +#include namespace scream { namespace physics { /* - * Mathematical constants used by atmosphere processes. + * Physical/math constants used in EAMxx. * * Note that a potential optimization could be to change the type of * Scalar constants that have integer values to int. @@ -22,60 +21,90 @@ namespace physics { template struct Constants { - using ci_string = ekat::CaseInsensitiveString; - - static constexpr Scalar Cpair = 1004.64; - static constexpr Scalar Rair = 287.042; - static constexpr Scalar RH2O = 461.505; - static constexpr Scalar RV = RH2O; // Water vapor gas constant ~ J/K/kg !461.51 - static constexpr Scalar RHO_H2O = 1000.0; - static constexpr Scalar INV_RHO_H2O = 1.0/RHO_H2O; - static constexpr Scalar RhoIce = 917.0; // Ice density at 0 C from Wallace+Hobbes 1977 - static constexpr Scalar MWH2O = 18.016; - static constexpr Scalar MWdry = 28.966; - static constexpr Scalar o2mmr = 0.23143; // o2 mass mixing ratio - static constexpr Scalar ep_2 = MWH2O/MWdry; // ratio of molecular mass of water to the molecular mass of dry air !0.622 - static constexpr Scalar gravit = 9.80616; - static constexpr Scalar LatVap = 2501000.0; - static constexpr Scalar LatIce = 333700.0; - static constexpr Scalar CpLiq = 4188.0; - static constexpr Scalar Tmelt = 273.15; - static constexpr Scalar T_zerodegc = Tmelt; - static constexpr Scalar T_homogfrz = Tmelt - 40; - static constexpr Scalar T_rainfrz = Tmelt - 4; - static constexpr Scalar Pi = 3.14159265358979323; - static constexpr Scalar RHOW = RHO_H2O; - static constexpr Scalar INV_RHOW = 1.0/RHOW; + using quantity_t = Quantity; + using ci_string = ekat::CaseInsensitiveString; + using Units = ekat::units::Units; + + // Some predefined units + static constexpr auto m = ekat::units::m; + static constexpr auto s = ekat::units::s; + static constexpr auto mol = ekat::units::mol; + static constexpr auto kg = ekat::units::kg; + static constexpr auto g = ekat::units::g; + static constexpr auto Pa = ekat::units::Pa; + static constexpr auto K = ekat::units::K; + static constexpr auto J = ekat::units::J; + static constexpr auto W = ekat::units::W; + + // Some shorthand units + static constexpr auto m2 = Units(m*m,"m2"); + static constexpr auto m3 = Units(m*m*m,"m3"); + static constexpr auto s2 = Units(s*s,"s2"); + static constexpr auto nondim = Units::nondimensional(); + static constexpr auto rad = Units(nondim,"rad"); + + // Commonly used numeric constants + static constexpr Scalar ZERO = 0.0; + static constexpr Scalar ONE = 1; + static constexpr Scalar THIRD = 1.0/3.0; + static constexpr Scalar SXTH = 1.0/6.0; + static constexpr Scalar Pi = 3.14159265358979323; + static constexpr Scalar PIOV3 = Pi*THIRD; + static constexpr Scalar PIOV6 = Pi*SXTH; + static constexpr Scalar macheps = std::numeric_limits::epsilon(); + + // Physical constants + static constexpr auto Cpair = quantity_t(1004.64, J/kg/K); + static constexpr auto CP = Cpair; // heat constant of air at constant pressure, J/kg + static constexpr auto INV_CP = ONE/CP; + static constexpr auto Rair = quantity_t(287.042, J/kg/K); // gas constant for dry air + static constexpr auto RD = Rair; + static constexpr auto RH2O = quantity_t(461.505, J/kg/K); // Water vapor gas constant + static constexpr auto RV = RH2O; + + static constexpr auto RHO_H2O = quantity_t(1000.0,kg/m3); + static constexpr auto INV_RHO_H2O = 1/RHO_H2O; + static constexpr auto RHOW = RHO_H2O; + static constexpr auto INV_RHOW = 1/RHOW; + static constexpr auto RhoIce = quantity_t(917.0,kg/m3); // Ice density at 0 C from Wallace+Hobbes 1977 + + static constexpr auto MWH2O = quantity_t(18.016, g/mol); // water molar mass + static constexpr auto MWWV = MWH2O; + static constexpr auto MWdry = quantity_t(28.966, g/mol); // dry air molar mass + static constexpr auto ep_2 = MWH2O / MWdry; // dimensionless (MWH2O/MWdry) + static constexpr auto o2mmr = quantity_t(0.23143,nondim); // o2 mass mixing ratio (dimensionless) + + static constexpr auto gravit = quantity_t(9.80616, m/s2); + + static constexpr auto LatVap = quantity_t(2501000.0, J/kg); + static constexpr auto LatIce = quantity_t(333700.0, J/kg); + static constexpr auto CpLiq = quantity_t(4188.0, J/kg/K); + + static constexpr auto Tmelt = quantity_t(273.15, K); + static constexpr auto T_zerodegc = Tmelt; + static constexpr auto T_homogfrz = quantity_t(Tmelt.value - 40,K); + static constexpr auto T_rainfrz = quantity_t(Tmelt.value - 4,K); + static constexpr Scalar RHO_RIMEMIN = 50.0; //Min limit for rime density [kg m-3] static constexpr Scalar RHO_RIMEMAX = 900.0; //Max limit for rime density [kg m-3] static constexpr Scalar INV_RHO_RIMEMAX = 1.0/RHO_RIMEMAX; // Inverse for limits for rime density [kg m-3] - static constexpr Scalar THIRD = 1.0/3.0; - static constexpr Scalar SXTH = 1.0/6.0; - static constexpr Scalar PIOV3 = Pi*THIRD; - static constexpr Scalar PIOV6 = Pi*SXTH; static constexpr Scalar BIMM = 2.0; - static constexpr Scalar CONS1 = PIOV6*RHOW; - static constexpr Scalar CONS2 = 4.*PIOV3*RHOW; + static constexpr Scalar CONS1 = PIOV6*RHOW.value; + static constexpr Scalar CONS2 = 4.*PIOV3*RHOW.value; static constexpr Scalar CONS3 = 1.0/(CONS2*1.562500000000000e-14); // 1./(CONS2*pow(25.e-6,3.0)); static constexpr Scalar CONS5 = PIOV6*BIMM; - static constexpr Scalar CONS6 = PIOV6*PIOV6*RHOW*BIMM; - static constexpr Scalar CONS7 = 4.*PIOV3*RHOW*1.e-18; + static constexpr Scalar CONS6 = PIOV6*PIOV6*RHOW.value*BIMM; + static constexpr Scalar CONS7 = 4.*PIOV3*RHOW.value*1.e-18; static constexpr Scalar QSMALL = 1.e-14; static constexpr Scalar QTENDSMALL = 1e-20; static constexpr Scalar BSMALL = 1.e-15; static constexpr Scalar NSMALL = 1.e-16; - static constexpr Scalar ZERO = 0.0; - static constexpr Scalar ONE = 1.0; - static constexpr Scalar P0 = 100000.0; // reference pressure, Pa - static constexpr Scalar RD = Rair; // gas constant for dry air, J/kg/K - static constexpr Scalar RHOSUR = P0/(RD*Tmelt); - static constexpr Scalar rhosui = 60000/(RD*253.15); - static constexpr Scalar RHO_1000MB = P0/(RD*Tmelt); - static constexpr Scalar RHO_600MB = 60000/(RD*253.15); - static constexpr Scalar CP = Cpair; // heat constant of air at constant pressure, J/kg - static constexpr Scalar INV_CP = 1.0/CP; + static constexpr auto P0 = quantity_t(100000.0,Pa); // reference pressure, Pa + static constexpr auto RHOSUR = P0/(RD*Tmelt); + static constexpr Scalar rhosui = 60000/(RD.value*253.15); + static constexpr auto RHO_1000MB = P0/(RD*Tmelt); + static constexpr Scalar RHO_600MB = 60000/(RD.value*253.15); // static constexpr Scalar Tol = ekat::is_single_precision::value ? 2e-5 : 1e-14; - static constexpr Scalar macheps = std::numeric_limits::epsilon(); static constexpr Scalar dt_left_tol = 1.e-4; static constexpr Scalar bcn = 2.; static constexpr Scalar dropmass = 5.2e-7; @@ -83,19 +112,18 @@ struct Constants static constexpr Scalar incloud_limit = 5.1e-3; static constexpr Scalar precip_limit = 1.0e-2; static constexpr Scalar Karman = 0.4; - static constexpr Scalar Avogad = 6.02214e26; - static constexpr Scalar Boltz = 1.38065e-23; - static constexpr Scalar Rgas = Avogad * Boltz; - static constexpr Scalar MWWV = MWH2O; - static constexpr Scalar RWV = Rgas / MWWV; - static constexpr Scalar ZVIR = (RWV / Rair) - 1.0; + static constexpr auto Avogad = quantity_t (6.02214e26,1/mol); + static constexpr auto Boltz = quantity_t (1.38065e-23,J/K); + static constexpr auto Rgas = Avogad * Boltz; + static constexpr auto RWV = Rgas / MWWV; + static constexpr Scalar ZVIR = (RWV.value / Rair.value) - 1.0; static constexpr Scalar f1r = 0.78; static constexpr Scalar f2r = 0.32; static constexpr Scalar nmltratio = 1.0; // ratio of rain number produced to ice number loss from melting static constexpr Scalar basetemp = 300.0; - static constexpr Scalar r_earth = 6.376e6; // Radius of the earth in m - static constexpr Scalar stebol = 5.670374419e-8; // Stefan-Boltzmann's constant (W/m^2/K^4) - static constexpr Scalar omega = 7.292e-5; // Earth's rotation (rad/sec) + static constexpr auto r_earth = quantity_t(6.376e6,m); // Radius of the earth in m + static constexpr auto stebol = quantity_t(5.670374419e-8,W/m2/pow(K,4)); // Stefan-Boltzmann's constant (W/m^2/K^4) + static constexpr auto omega = quantity_t(7.292e-5,rad/s); // Earth's rotation (rad/sec) // Table dimension constants static constexpr int VTABLE_DIM0 = 300; @@ -103,8 +131,8 @@ struct Constants static constexpr int MU_R_TABLE_DIM = 150; // Turbulent Mountain Stress constants - static constexpr Scalar orocnst = 1; // Converts from standard deviation to height [ no unit ] - static constexpr Scalar z0fac = 0.075; // Factor determining z_0 from orographic standard deviation [ no unit ] + static constexpr Scalar orocnst = 1; // Converts from standard deviation to height [ no unit ] + static constexpr Scalar z0fac = 0.075; // Factor determining z_0 from orographic standard deviation [ no unit ] // switch for warm-rain parameterization // = 1 Seifert and Beheng 2001 @@ -129,7 +157,7 @@ template Scalar Constants::get_gas_mol_weight(ci_string gas_name) { //TODO: Possible improvement would be to design a device friendly function if (gas_name == "h2o") { - return Scalar(Constants::MWH2O); + return MWH2O.value; } else if (gas_name == "co2") { return 44.0095; } else if (gas_name == "o3" ) { @@ -161,15 +189,6 @@ constexpr Scalar Constants::QSMALL; template constexpr Scalar Constants::QTENDSMALL; -template -constexpr Scalar Constants::ZERO; - -template -constexpr Scalar Constants::Tmelt; - -template -constexpr Scalar Constants::macheps; - } // namespace physics } // namespace scream From 5033f77bf2a11c820b5ce18165972cca9f5b42db Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 15:16:53 -0700 Subject: [PATCH 232/398] EAMxx: fix usage of physics constants in share folder Some constants are now Quantity objects --- .../algorithm/eamxx_data_interpolation.cpp | 2 +- .../data_managers/mesh_free_grids_manager.cpp | 2 +- .../src/share/diagnostics/aerocom_cld.cpp | 2 +- .../src/share/diagnostics/number_path.cpp | 2 +- .../diagnostics/precip_surf_mass_flux.cpp | 2 +- .../surf_upward_latent_heat_flux.cpp | 2 +- .../diagnostics/tests/atm_density_test.cpp | 2 +- .../tests/dry_static_energy_test.cpp | 2 +- .../share/diagnostics/tests/exner_test.cpp | 2 +- .../diagnostics/tests/number_paths_tests.cpp | 2 +- .../tests/potential_temperature_test.cpp | 4 +- .../tests/precip_surf_mass_flux_tests.cpp | 2 +- .../tests/relative_humidity_tests.cpp | 2 +- .../tests/sea_level_pressure_test.cpp | 2 +- .../surf_upward_latent_heat_flux_tests.cpp | 2 +- .../diagnostics/tests/vapor_flux_tests.cpp | 2 +- .../diagnostics/tests/vert_contract_test.cpp | 2 +- .../tests/vertical_layer_tests.cpp | 6 +-- .../diagnostics/tests/water_path_tests.cpp | 2 +- .../src/share/diagnostics/vapor_flux.cpp | 2 +- .../src/share/diagnostics/vert_contract.cpp | 2 +- .../src/share/diagnostics/vertical_layer.cpp | 2 +- .../src/share/diagnostics/water_path.cpp | 2 +- .../eamxx_common_physics_functions_impl.hpp | 40 +++++++++---------- .../eamxx/src/share/physics/eamxx_trcmix.cpp | 12 +++--- .../share/physics/physics_saturation_impl.hpp | 6 +-- .../tests/common_physics_functions_tests.cpp | 18 ++++----- .../tests/physics_saturation_run_and_cmp.cpp | 2 +- .../mass_and_energy_conservation_check.cpp | 22 +++++----- 29 files changed, 76 insertions(+), 76 deletions(-) diff --git a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp index 6d81acee7444..fcb09f02cb14 100644 --- a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp +++ b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp @@ -117,7 +117,7 @@ void DataInterpolation::run (const util::TimeStamp& ts) auto hyam = m_vert_remapper->get_src_grid()->get_geometry_data("hyam").get_view(); auto hybm = m_vert_remapper->get_src_grid()->get_geometry_data("hybm").get_view(); - constexpr auto P0 = C::P0; + constexpr Real P0 = C::P0.value; const int ncols = ps_v.extent(0); const int num_vert_packs = p_v.extent(1); diff --git a/components/eamxx/src/share/data_managers/mesh_free_grids_manager.cpp b/components/eamxx/src/share/data_managers/mesh_free_grids_manager.cpp index fc215ab9d4ee..0a5fdcb246bd 100644 --- a/components/eamxx/src/share/data_managers/mesh_free_grids_manager.cpp +++ b/components/eamxx/src/share/data_managers/mesh_free_grids_manager.cpp @@ -264,7 +264,7 @@ load_vertical_coordinates (const nonconstgrid_ptr_type& grid, const std::string& // Build lev and ilev from hyam and hybm, and ilev from hyai and hybi using PC = scream::physics::Constants; - const Real ps0 = PC::P0; + const Real ps0 = PC::P0.value; auto num_lev = grid->get_num_vertical_levels(); for (int ii=0;ii; - constexpr Real g = PC::gravit; + constexpr Real g = PC::gravit.value; const auto np = m_diagnostic_output.get_view(); const auto q = get_field_in(m_qname).get_view(); diff --git a/components/eamxx/src/share/diagnostics/precip_surf_mass_flux.cpp b/components/eamxx/src/share/diagnostics/precip_surf_mass_flux.cpp index ab1ae27db089..d4ce12d7aa08 100644 --- a/components/eamxx/src/share/diagnostics/precip_surf_mass_flux.cpp +++ b/components/eamxx/src/share/diagnostics/precip_surf_mass_flux.cpp @@ -98,7 +98,7 @@ void PrecipSurfMassFlux::compute_diagnostic_impl() return; } - auto rhodt = PC::RHO_H2O*dt; + Real rhodt = PC::RHO_H2O.value*dt; const auto& flux_view = m_diagnostic_output.get_view(); Kokkos::parallel_for(m_name, KT::RangePolicy(0,m_num_cols), diff --git a/components/eamxx/src/share/diagnostics/surf_upward_latent_heat_flux.cpp b/components/eamxx/src/share/diagnostics/surf_upward_latent_heat_flux.cpp index 920e072ed1ab..4d9fc3519d3d 100644 --- a/components/eamxx/src/share/diagnostics/surf_upward_latent_heat_flux.cpp +++ b/components/eamxx/src/share/diagnostics/surf_upward_latent_heat_flux.cpp @@ -49,7 +49,7 @@ void SurfaceUpwardLatentHeatFlux::compute_diagnostic_impl() using KT = ekat::KokkosTypes; using PC = scream::physics::Constants; - constexpr auto latent_heat_evap = PC::LatVap; // [J/kg] + constexpr Real latent_heat_evap = PC::LatVap.value; // [J/kg] Field::view_dev_t evap_view_d; diff --git a/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp b/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp index 4274a3b3aa2e..94ffad17d925 100644 --- a/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp @@ -65,7 +65,7 @@ void run(std::mt19937_64& engine) using RPDF = std::uniform_real_distribution; RPDF pdf_qv(1e-6,1e-3), pdf_pseudodens(1.0,100.0), - pdf_pres(0.0,PC::P0), + pdf_pres(0.0,PC::P0.value), pdf_temp(200.0,400.0); // A time stamp diff --git a/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp b/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp index e9928a726e4c..c2a525728707 100644 --- a/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp @@ -66,7 +66,7 @@ void run(std::mt19937_64& engine) using RPDF = std::uniform_real_distribution; RPDF pdf_qv(1e-6,1e-3), pdf_pseudodens(1.0,100.0), - pdf_pres(0.0,PC::P0), + pdf_pres(0.0,PC::P0.value), pdf_temp(200.0,400.0), pdf_surface(100.0,400.0); diff --git a/components/eamxx/src/share/diagnostics/tests/exner_test.cpp b/components/eamxx/src/share/diagnostics/tests/exner_test.cpp index 42c25fcdd864..934bc7001862 100644 --- a/components/eamxx/src/share/diagnostics/tests/exner_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/exner_test.cpp @@ -63,7 +63,7 @@ void run(std::mt19937_64& engine) // Construct random input data using RPDF = std::uniform_real_distribution; - RPDF pdf_pres(0.0,PC::P0); + RPDF pdf_pres(0.0,PC::P0.value); // A time stamp util::TimeStamp t0 ({2022,1,1},{0,0,0}); diff --git a/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp b/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp index ad4bef4123ec..afa955e018c9 100644 --- a/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp @@ -40,7 +40,7 @@ void run(std::mt19937_64 &engine) { using view_1d = typename KT::template view_1d; constexpr int num_levs = 33; - constexpr Real g = PC::gravit; + constexpr Real g = PC::gravit.value; constexpr Real macheps = PC::macheps; // A world comm diff --git a/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp b/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp index 6e620cf82597..5f1134654f54 100644 --- a/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp @@ -63,7 +63,7 @@ void run(std::mt19937_64& engine, int int_ptype) // Construct random input data using RPDF = std::uniform_real_distribution; - RPDF pdf_pres(0.0,PC::P0), + RPDF pdf_pres(0.0,PC::P0.value), pdf_temp(200.0,400.0); // A time stamp @@ -131,7 +131,7 @@ void run(std::mt19937_64& engine, int int_ptype) Kokkos::parallel_for(Kokkos::TeamVectorRange(team,num_levs), [&] (const Int& ilev) { auto theta = PF::calculate_theta_from_T(T_mid_v(icol,ilev),p_mid_v(icol,ilev)); if (int_ptype==1) { - theta_v(icol,ilev) = theta - (theta/T_mid_v(icol,ilev)) * (PC::LatVap/PC::Cpair) * q_mid_v(icol,ilev); + theta_v(icol,ilev) = theta - (theta/T_mid_v(icol,ilev)) * (PC::LatVap.value/PC::Cpair.value) * q_mid_v(icol,ilev); } else { theta_v(icol,ilev) = theta; } }); team.team_barrier(); diff --git a/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp b/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp index 983a7b06716d..e338508bdae3 100644 --- a/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp @@ -128,7 +128,7 @@ void run(std::mt19937_64& engine) auto precip_total_v = precip_total_f.get_view(); auto precip_liq_v = precip_liq_f.get_view(); auto precip_ice_v = precip_ice_f.get_view(); - const auto rhodt = PC::RHO_H2O*dt; + const Real rhodt = PC::RHO_H2O.value*dt; Kokkos::parallel_for("precip_total_surf_mass_flux_test", typename KT::RangePolicy(0,ncols), KOKKOS_LAMBDA(const int& icol) { diff --git a/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp b/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp index 332bbf17a337..205ae61f01a3 100644 --- a/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp @@ -78,7 +78,7 @@ void run(std::mt19937_64& engine) // Construct random input data using RPDF = std::uniform_real_distribution; - RPDF pdf_pres(10.0,PC::P0), + RPDF pdf_pres(10.0,PC::P0.value), pdf_temp(200.0,400.0), pdf_qv(0.0,1e-2), pdf_pseudo_density(1.0,100.0); diff --git a/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp b/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp index 51b8544be5ee..24ce74ce43b1 100644 --- a/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp @@ -58,7 +58,7 @@ void run(std::mt19937_64& engine) // Construct random input data using RPDF = std::uniform_real_distribution; - RPDF pdf_pres(0.0,PC::P0), + RPDF pdf_pres(0.0,PC::P0.value), pdf_temp(200.0,400.0), pdf_surface(100.0,400.0); diff --git a/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp b/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp index 43c31a69d350..f0c022ec5d88 100644 --- a/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp @@ -85,7 +85,7 @@ void run(std::mt19937_64& engine, const ekat::Comm& comm, LoggerType& logger) Field surf_lhf = diag_latent_heat_out.clone(); surf_lhf.deep_copy(0); const auto& surf_lhf_v = surf_lhf.get_view(); - constexpr auto latent_heat_evap = PC::LatVap; // [J/kg] + constexpr Real latent_heat_evap = PC::LatVap.value; // [J/kg] Kokkos::parallel_for("surf_upward_latent_heat_flux_test", typename KT::RangePolicy(0, ncols), KOKKOS_LAMBDA (const int& icol) { diff --git a/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp b/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp index 18cac066eb6f..9786e9bf7b79 100644 --- a/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp @@ -135,7 +135,7 @@ void run(std::mt19937_64& engine) Field qv_vert_integrated_flux_u_f = diag_out.clone(); qv_vert_integrated_flux_u_f.deep_copy(0); const auto& qv_vert_integrated_flux_u_v = qv_vert_integrated_flux_u_f.get_view(); - constexpr Real g = PC::gravit; + constexpr Real g = PC::gravit.value; int comp = which_comp=="Zonal" ? 0 : 1; Kokkos::parallel_for("", policy, KOKKOS_LAMBDA(const MemberType& team) { diff --git a/components/eamxx/src/share/diagnostics/tests/vert_contract_test.cpp b/components/eamxx/src/share/diagnostics/tests/vert_contract_test.cpp index f28d940771ce..4a53dead370b 100644 --- a/components/eamxx/src/share/diagnostics/tests/vert_contract_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/vert_contract_test.cpp @@ -168,7 +168,7 @@ TEST_CASE("vert_contract") { auto dp_scaled = dp.clone("dp_scaled"); // auto dz_scaled = dz.clone("dz_scaled"); - dp_scaled.scale(sp(1.0) / scream::physics::Constants::gravit); + dp_scaled.scale(sp(1.0) / scream::physics::Constants::gravit.value); vert_contraction(dps, dp_scaled, dp_ones); diff --git a/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp b/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp index 5e5ede90428c..cc8ad2134d2b 100644 --- a/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp @@ -77,14 +77,14 @@ void run (const std::string& diag_name, const std::string& location) // Note: we are not testing the calculate_dz utility. We are testing // the diag class, so use some inputs that make checking results easier // With these inputs, T_virt=T, and dz=8*rd/g - const Real g = PC::gravit; + const Real g = PC::gravit.value; const Real rho_val = 4; const Real qv_val = 0; const Real p_val = 2; const Real T_val = 4; - const Real c1 = -PC::ONE + PC::ONE / PC::ep_2; + const Real c1 = -PC::ONE + PC::ONE / PC::ep_2.value; const Real Tvirt_val = T_val*(PC::ONE + c1*qv_val); - const Real dz_val = (PC::RD/g) * rho_val*Tvirt_val / p_val; + const Real dz_val = (PC::RD.value/g) * rho_val*Tvirt_val / p_val; const Real phis_val = 3; input_fields["T_mid"].deep_copy(T_val); diff --git a/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp b/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp index 5e1a78f09440..ba7e7b40e372 100644 --- a/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp @@ -48,7 +48,7 @@ void run(std::mt19937_64& engine) using view_1d = typename KT::template view_1d; constexpr int num_levs = 33; - constexpr Real gravit = PC::gravit; + constexpr Real gravit = PC::gravit.value; constexpr Real macheps = PC::macheps; // A world comm diff --git a/components/eamxx/src/share/diagnostics/vapor_flux.cpp b/components/eamxx/src/share/diagnostics/vapor_flux.cpp index bcc0862ac4e9..545cc2011ebb 100644 --- a/components/eamxx/src/share/diagnostics/vapor_flux.cpp +++ b/components/eamxx/src/share/diagnostics/vapor_flux.cpp @@ -58,7 +58,7 @@ void VaporFluxDiagnostic::compute_diagnostic_impl() using MT = typename KT::MemberType; using TPF = ekat::TeamPolicyFactory; - constexpr Real g = PC::gravit; + constexpr Real g = PC::gravit.value; const auto diag = m_diagnostic_output.get_view(); const auto qv = get_field_in("qv").get_view(); diff --git a/components/eamxx/src/share/diagnostics/vert_contract.cpp b/components/eamxx/src/share/diagnostics/vert_contract.cpp index bf03e1d085fb..8b660e9ce664 100644 --- a/components/eamxx/src/share/diagnostics/vert_contract.cpp +++ b/components/eamxx/src/share/diagnostics/vert_contract.cpp @@ -185,7 +185,7 @@ void VertContractDiag::compute_diagnostic_impl() { // update the weights; if weighting by dp, we need to scale by 1/g if (m_weighting_method == "dp") { - auto g = scream::physics::Constants::gravit; + auto g = scream::physics::Constants::gravit.value; m_weighting.update(get_field_in("pseudo_density"), 1 / g, sp(0.0)); } else if (m_weighting_method == "dz") { // TODO: for some reason the dz field keeps getting set to 0 diff --git a/components/eamxx/src/share/diagnostics/vertical_layer.cpp b/components/eamxx/src/share/diagnostics/vertical_layer.cpp index 0e37ead71254..4a24ab811ceb 100644 --- a/components/eamxx/src/share/diagnostics/vertical_layer.cpp +++ b/components/eamxx/src/share/diagnostics/vertical_layer.cpp @@ -185,7 +185,7 @@ void VerticalLayerDiagnostic::do_compute_diagnostic_impl() const bool from_sea_level = m_from_sea_level; const bool geopotential = m_geopotential; const int num_levs = m_num_levs; - constexpr auto g = scream::physics::Constants::gravit; + constexpr Real g = scream::physics::Constants::gravit.value; // Alias correct view for diagnostic output and for tmp class views auto tmp_mid = m_tmp_midpoint.get_view(); diff --git a/components/eamxx/src/share/diagnostics/water_path.cpp b/components/eamxx/src/share/diagnostics/water_path.cpp index e82a25293cfb..59bfc5ec2b3b 100644 --- a/components/eamxx/src/share/diagnostics/water_path.cpp +++ b/components/eamxx/src/share/diagnostics/water_path.cpp @@ -64,7 +64,7 @@ void WaterPathDiagnostic::compute_diagnostic_impl() using MT = typename KT::MemberType; using TPF = ekat::TeamPolicyFactory; - constexpr Real g = PC::gravit; + constexpr Real g = PC::gravit.value; const auto wp = m_diagnostic_output.get_view(); const auto q = get_field_in(m_qname).get_view(); diff --git a/components/eamxx/src/share/physics/eamxx_common_physics_functions_impl.hpp b/components/eamxx/src/share/physics/eamxx_common_physics_functions_impl.hpp index 935179bd6e86..4f7d95e4472c 100644 --- a/components/eamxx/src/share/physics/eamxx_common_physics_functions_impl.hpp +++ b/components/eamxx/src/share/physics/eamxx_common_physics_functions_impl.hpp @@ -37,7 +37,7 @@ ScalarT PhysicsFunctions::calculate_density(const ScalarT& pseudo_densi { using C = scream::physics::Constants; - static constexpr auto g = C::gravit; + static constexpr auto g = C::gravit.value; return pseudo_density/dz/g; } @@ -63,7 +63,7 @@ ScalarT PhysicsFunctions::calculate_vertical_velocity(const ScalarT& om { using C = scream::physics::Constants; - static constexpr auto g = C::gravit; + static constexpr auto g = C::gravit.value; return -omega/(density * g); } @@ -89,9 +89,9 @@ ScalarT PhysicsFunctions::exner_function(const ScalarT& pressure) { using C = scream::physics::Constants; - static constexpr auto p0 = C::P0; - static constexpr auto rd = C::RD; - static constexpr auto inv_cp = C::INV_CP; + static constexpr auto p0 = C::P0.value; + static constexpr auto rd = C::RD.value; + static constexpr auto inv_cp = C::INV_CP.value; return pow( pressure/p0, rd*inv_cp ); } @@ -124,7 +124,7 @@ ScalarT PhysicsFunctions::calculate_thetal_from_theta(const ScalarT& th { using C = scream::physics::Constants; - return theta - (theta / temperature) * (C::LatVap/C::Cpair) * qc; + return theta - (theta / temperature) * (C::LatVap.value/C::Cpair.value) * qc; } template @@ -186,7 +186,7 @@ calculate_temperature_from_virtual_temperature(const ScalarT& T_virtual, const S { using C = scream::physics::Constants; - static constexpr auto ep_2 = C::ep_2; + static constexpr auto ep_2 = C::ep_2.value; static constexpr auto one = C::ONE; static constexpr auto c1 = - one + one/ep_2; @@ -215,7 +215,7 @@ ScalarT PhysicsFunctions::calculate_virtual_temperature(const ScalarT& { using C = scream::physics::Constants; - static constexpr auto ep_2 = C::ep_2; + static constexpr auto ep_2 = C::ep_2.value; static constexpr auto one = C::ONE; static constexpr auto c1 = - one + one/ep_2; @@ -245,8 +245,8 @@ calculate_dse(const ScalarT& temperature, const ScalarT& z, const Real surf_geop { using C = scream::physics::Constants; - static constexpr auto cp = C::CP; - static constexpr auto g = C::gravit; + static constexpr auto cp = C::CP.value; + static constexpr auto g = C::gravit.value; return cp*temperature + g*z + surf_geopotential; } @@ -275,8 +275,8 @@ calculate_temperature_from_dse(const ScalarT& dse, const ScalarT& z, const Real { using C = scream::physics::Constants; - static constexpr auto cp = C::CP; - static constexpr auto g = C::gravit; + static constexpr auto cp = C::CP.value; + static constexpr auto g = C::gravit.value; return (dse - g*z - surf_geopotential)/cp; } @@ -403,8 +403,8 @@ calculate_dz(const ScalarT& pseudo_density, const ScalarT& p_mid, const ScalarT& const ScalarT& T_virtual = calculate_virtual_temperature(T_mid,qv); - static constexpr auto rd = C::RD; - static constexpr auto g = C::gravit; + static constexpr auto rd = C::RD.value; + static constexpr auto g = C::gravit.value; return (rd/g)*pseudo_density*T_virtual / p_mid; } @@ -460,7 +460,7 @@ KOKKOS_INLINE_FUNCTION ScalarT PhysicsFunctions::calculate_vmr_from_mmr(const Real& gas_mol_weight, const ScalarT& qv, const ScalarT& mmr) { using C = scream::physics::Constants; - constexpr Real air_mol_weight = C::MWdry; + constexpr Real air_mol_weight = C::MWdry.value; return mmr / (1.0 - qv) * air_mol_weight/gas_mol_weight; @@ -487,7 +487,7 @@ KOKKOS_INLINE_FUNCTION ScalarT PhysicsFunctions::calculate_mmr_from_vmr(const Real& gas_mol_weight, const ScalarT& qv, const ScalarT& vmr) { using C = scream::physics::Constants; - constexpr Real air_mol_weight = C::MWdry; + constexpr Real air_mol_weight = C::MWdry.value; const Real mol_weight_ratio = gas_mol_weight/air_mol_weight; return mol_weight_ratio * vmr * (1.0 - qv); @@ -541,7 +541,7 @@ void PhysicsFunctions::lapse_T_for_psl(const Real& T_ground, const Real */ using C = scream::physics::Constants; - constexpr Real gravit = C::gravit; + constexpr Real gravit = C::gravit.value; //Get preliminary surface and sea level temperature to decide on lapse rate auto T_sl = T_ground + sp(0.0065)*phi_ground/gravit; //start by assuming lapse rate is 6.5 K/km @@ -577,8 +577,8 @@ Real PhysicsFunctions::calculate_psl(const Real& T_ground, const Real& using C = scream::physics::Constants; - constexpr Real gravit = C::gravit; - constexpr Real Rair = C::Rair; + constexpr Real gravit = C::gravit.value; + constexpr Real Rair = C::Rair.value; Real psl; // if phi_ground is very close to sea level already, set psl to existing p_ground @@ -604,7 +604,7 @@ void PhysicsFunctions::apply_rayleigh_friction(const Real dt, const Sca ScalarT& u_wind, ScalarT& v_wind, ScalarT& T_mid) { using C = scream::physics::Constants; - constexpr Real cp = C::CP; + constexpr Real cp = C::CP.value; const Real dt_inv = 1.0/dt; diff --git a/components/eamxx/src/share/physics/eamxx_trcmix.cpp b/components/eamxx/src/share/physics/eamxx_trcmix.cpp index b17b07460665..ad72c713fe42 100644 --- a/components/eamxx/src/share/physics/eamxx_trcmix.cpp +++ b/components/eamxx/src/share/physics/eamxx_trcmix.cpp @@ -36,11 +36,11 @@ void trcmix( const auto mwf12 = C::get_gas_mol_weight("cfc12"); const auto mwco2 = C::get_gas_mol_weight("co2"); - const auto rmwn2o = mwn2o/C::MWdry; - const auto rmwch4 = mwch4/C::MWdry; - const auto rmwf11 = mwf11/C::MWdry; - const auto rmwf12 = mwf12/C::MWdry; - const auto rmwco2 = mwco2/C::MWdry; + const auto rmwn2o = mwn2o/C::MWdry.value; + const auto rmwch4 = mwch4/C::MWdry.value; + const auto rmwf11 = mwf11/C::MWdry.value; + const auto rmwf12 = mwf12/C::MWdry.value; + const auto rmwco2 = mwco2/C::MWdry.value; // Constants map: gas_name -> [trop_mmr, scale1_base, scale1_fact, scale2_base, scale2_fact] std::map > const_map = { @@ -53,7 +53,7 @@ void trcmix( const auto policy = ekat::TeamPolicyFactory::get_default_team_policy(ncols, nlevs); if (name == "o2" || name == "co2") { - const auto val = name == "o2" ? C::o2mmr : rmwco2 * co2vmr; + const Real val = name == "o2" ? C::o2mmr.value : rmwco2 * co2vmr; Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { const Int i = team.league_rank(); Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlevs), [&] (const Int& k) { diff --git a/components/eamxx/src/share/physics/physics_saturation_impl.hpp b/components/eamxx/src/share/physics/physics_saturation_impl.hpp index e5707fa25cf2..937ebdd0f52d 100644 --- a/components/eamxx/src/share/physics/physics_saturation_impl.hpp +++ b/components/eamxx/src/share/physics/physics_saturation_impl.hpp @@ -50,7 +50,7 @@ Functions::MurphyKoop_svp(const Spack& t_atm, const bool ice, const Smask& //Soc., 131(608), 1539–1565, Spack result; - static constexpr auto tmelt = C::Tmelt; + static constexpr auto tmelt = C::Tmelt.value; const Smask ice_mask = (t_atm < tmelt) && ice; const Smask liq_mask = !ice_mask; @@ -93,7 +93,7 @@ Functions::polysvp1(const Spack& t, const bool ice, const Smask& range_mask const Spack dt = max(t - sp(273.15), sp(-80)); Spack result; - static constexpr auto tmelt = C::Tmelt; + static constexpr auto tmelt = C::Tmelt.value; const Smask ice_mask = (t < tmelt) && ice; const Smask liq_mask = !ice_mask; @@ -152,7 +152,7 @@ Functions::qv_sat_dry(const Spack& t_atm, const Spack& p_atm_dry, const boo EKAT_KERNEL_ERROR_MSG("Error! Invalid func_idx supplied to qv_sat_dry."); } - static constexpr auto ep_2 = C::ep_2; + static constexpr auto ep_2 = C::ep_2.value; return ep_2 * e_pres / max(p_atm_dry, sp(1.e-3)); } diff --git a/components/eamxx/src/share/physics/tests/common_physics_functions_tests.cpp b/components/eamxx/src/share/physics/tests/common_physics_functions_tests.cpp index 83c8e921aea4..dc493c6c9e04 100644 --- a/components/eamxx/src/share/physics/tests/common_physics_functions_tests.cpp +++ b/components/eamxx/src/share/physics/tests/common_physics_functions_tests.cpp @@ -12,7 +12,7 @@ #include -namespace{ +namespace scream { template struct ChecksHelpers { @@ -73,8 +73,8 @@ void run_scalar_valued_fns(std::mt19937_64& engine) using Check = ChecksHelpers; //1 is for number of levels. static constexpr auto pi = PC::Pi; - static constexpr auto Rd = PC::RD; - static constexpr auto g = PC::gravit; + static constexpr auto Rd = PC::RD.value; + static constexpr auto g = PC::gravit.value; static constexpr auto test_tol = PC::macheps*1e3; static constexpr auto coeff_1 = PC::earth_ellipsoid1; static constexpr auto coeff_2 = PC::earth_ellipsoid2; @@ -185,10 +185,10 @@ void run(std::mt19937_64& engine) using rview_1d = typename KT::template view_1d; using TPF = ekat::TeamPolicyFactory; - static constexpr auto Rd = PC::RD; - static constexpr auto cp = PC::CP; - static constexpr auto inv_cp = PC::INV_CP; - static constexpr auto g = PC::gravit; + static constexpr auto Rd = PC::RD.value; + static constexpr auto cp = PC::CP.value; + static constexpr auto inv_cp = PC::INV_CP.value; + static constexpr auto g = PC::gravit.value; static constexpr auto test_tol = PC::macheps*1e3; constexpr int pack_size = sizeof(ScalarT) / sizeof(RealType); @@ -238,7 +238,7 @@ void run(std::mt19937_64& engine) using RPDF = std::uniform_real_distribution; RPDF pdf_qv(1e-6,1e-3), pdf_dp(1.0,100.0), - pdf_pres(0.0,PC::P0), + pdf_pres(0.0,PC::P0.value), pdf_temp(200.0,400.0), pdf_height(0.0,1e5), pdf_dz(1.0,1e5), @@ -270,7 +270,7 @@ void run(std::mt19937_64& engine) // ---- Single-scalar functions tests ---- // - const ScalarT p0 = PC::P0; + const ScalarT p0 = PC::P0.value; const ScalarT zero = 0.0; const ScalarT one = 1.0; diff --git a/components/eamxx/src/share/physics/tests/physics_saturation_run_and_cmp.cpp b/components/eamxx/src/share/physics/tests/physics_saturation_run_and_cmp.cpp index 7a8807bb70a5..7734e47f2be7 100644 --- a/components/eamxx/src/share/physics/tests/physics_saturation_run_and_cmp.cpp +++ b/components/eamxx/src/share/physics/tests/physics_saturation_run_and_cmp.cpp @@ -63,7 +63,7 @@ struct UnitWrap::UnitTest::TestSaturation } static constexpr auto atm_pres = 1e5; - static constexpr auto tmelt = C::Tmelt; + static constexpr auto tmelt = C::Tmelt.value; /* Originally written by Kyle Pressel, updated by Peter Caldwell on 4/5/20 and diff --git a/components/eamxx/src/share/property_checks/mass_and_energy_conservation_check.cpp b/components/eamxx/src/share/property_checks/mass_and_energy_conservation_check.cpp index e6b7059cf510..98b49ac2e446 100644 --- a/components/eamxx/src/share/property_checks/mass_and_energy_conservation_check.cpp +++ b/components/eamxx/src/share/property_checks/mass_and_energy_conservation_check.cpp @@ -435,7 +435,7 @@ void MassAndEnergyConservationCheck::global_fixer(const bool air_sea_surface_wat } using PC = scream::physics::Constants; - const Real cpdry = PC::Cpair; + const Real cpdry = PC::Cpair.value; m_pb_fixer /= (cpdry*m_total_gas_mass_after); // T change due to fixer //add the fixer to temperature @@ -494,7 +494,7 @@ compute_total_mass_on_column (const KT::MemberType& team, using PC = scream::physics::Constants; using RU = ekat::ReductionUtils; - const Real gravit = PC::gravit; + const Real gravit = PC::gravit.value; return RU::parallel_reduce(team, 0, nlevs, [&] (const int lev, Real& local_mass) { @@ -513,7 +513,7 @@ compute_gas_mass_on_column (const KT::MemberType& team, { using RU = ekat::ReductionUtils; using PC = scream::physics::Constants; - const Real gravit = PC::gravit; + const Real gravit = PC::gravit.value; return RU::parallel_reduce(team, 0, nlevs, [&] (const int lev, Real& local_mass) { @@ -527,7 +527,7 @@ compute_mass_boundary_flux_on_column (const Real vapor_flux, const Real water_flux) { using PC = scream::physics::Constants; - const Real RHO_H2O = PC::RHO_H2O; + const Real RHO_H2O = PC::RHO_H2O.value; return vapor_flux - water_flux*RHO_H2O; } @@ -548,10 +548,10 @@ compute_total_energy_on_column (const KT::MemberType& team, using PC = scream::physics::Constants; using RU = ekat::ReductionUtils; - const Real LatVap = PC::LatVap; - const Real LatIce = PC::LatIce; - const Real gravit = PC::gravit; - const Real Cpair = PC::Cpair; + const Real LatVap = PC::LatVap.value; + const Real LatIce = PC::LatIce.value; + const Real gravit = PC::gravit.value; + const Real Cpair = PC::Cpair.value; Real total_energy = RU::parallel_reduce(team, 0, nlevs, @@ -577,9 +577,9 @@ compute_energy_boundary_flux_on_column (const Real vapor_flux, const Real heat_flux) { using PC = scream::physics::Constants; - const Real LatVap = PC::LatVap; - const Real LatIce = PC::LatIce; - const Real RHO_H2O = PC::RHO_H2O; + const Real LatVap = PC::LatVap.value; + const Real LatIce = PC::LatIce.value; + const Real RHO_H2O = PC::RHO_H2O.value; return vapor_flux*(LatVap+LatIce) - (water_flux-ice_flux)*RHO_H2O*LatIce + heat_flux; } From 085ce989deac9c9cc24e0bae4234b2c1cb0e87b1 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 17 Dec 2025 11:18:31 -0700 Subject: [PATCH 233/398] EAMxx: fix some warnings in shoc tests that are likely typos/bugs --- .../shoc/tests/shoc_clip_third_moms_tests.cpp | 6 +++--- .../shoc/tests/shoc_energy_integral_tests.cpp | 4 ++-- .../physics/shoc/tests/shoc_main_tests.cpp | 20 +++++++++---------- .../shoc/tests/shoc_pblintd_height_tests.cpp | 4 ++-- .../shoc/tests/shoc_pdf_computetemp_tests.cpp | 2 +- .../tests/shoc_pdf_qw_parameters_tests.cpp | 10 +++++----- .../tests/shoc_pdf_thl_parameters_tests.cpp | 10 +++++----- .../tests/shoc_pdf_vv_parameters_tests.cpp | 4 ++-- ...shoc_update_prognostics_implicit_tests.cpp | 4 ++-- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/components/eamxx/src/physics/shoc/tests/shoc_clip_third_moms_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_clip_third_moms_tests.cpp index 4158fe5f5af5..e7525a4651bb 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_clip_third_moms_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_clip_third_moms_tests.cpp @@ -70,7 +70,7 @@ struct UnitWrap::UnitTest::TestClipThirdMoms : public UnitWrap::UnitTest:: const auto offset = n + s * nlevi; REQUIRE(SDS.w_sec_zi[offset] <= 1); - if (abs(SDS.w3[offset]) > 1000){ + if (std::abs(SDS.w3[offset]) > 1000){ w3_large = true; } SDS.w_sec_zi[offset] = w_sec_zi[n]; @@ -88,8 +88,8 @@ struct UnitWrap::UnitTest::TestClipThirdMoms : public UnitWrap::UnitTest:: for(Int n = 0; n < nlevi; ++n) { const auto offset = n + s * nlevi; - if (abs(w3_in[n]) > 1000){ - REQUIRE(abs(SDS.w3[offset]) < abs(w3_in[n])); + if (std::abs(w3_in[n]) > 1000){ + REQUIRE(std::abs(SDS.w3[offset]) < std::abs(w3_in[n])); } } diff --git a/components/eamxx/src/physics/shoc/tests/shoc_energy_integral_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_energy_integral_tests.cpp index d8eeb51e1063..811555d9fa0c 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_energy_integral_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_energy_integral_tests.cpp @@ -96,8 +96,8 @@ struct UnitWrap::UnitTest::TestShocEnergyInt : public UnitWrap::UnitTest:: if (s == 0){ const auto offsets = n + (s+1) * nlev; - REQUIRE(abs(SDS.u_wind[offsets]) > abs(SDS.u_wind[offset])); - REQUIRE(abs(SDS.v_wind[offsets]) > abs(SDS.v_wind[offset])); + REQUIRE(std::abs(SDS.u_wind[offsets]) > std::abs(SDS.u_wind[offset])); + REQUIRE(std::abs(SDS.v_wind[offsets]) > std::abs(SDS.v_wind[offset])); REQUIRE(SDS.rcm[offset] == 0); REQUIRE(SDS.rcm[offsets] > SDS.rcm[offset]); } diff --git a/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp index 6bbf0822481f..45a383671ce2 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp @@ -268,8 +268,8 @@ struct UnitWrap::UnitTest::TestShocMain : public UnitWrap::UnitTest::Base REQUIRE( (SDS.qw[offset] > qw_lbound && SDS.qw[offset] < qw_ubound) ); REQUIRE( (SDS.tke[offset] > tke_lbound && SDS.tke[offset] < tke_ubound) ); // Increase wind bounds by 2 m/s to allow for surface flux effects - REQUIRE(std::abs(SDS.u_wind[offset] < wind_bounds+2)); - REQUIRE(std::abs(SDS.v_wind[offset] < wind_bounds+2)); + REQUIRE(std::abs(SDS.u_wind[offset]) < wind_bounds+2); + REQUIRE(std::abs(SDS.v_wind[offset]) < wind_bounds+2); REQUIRE( (SDS.shoc_mix[offset] >= minlen && SDS.shoc_mix[offset] <= maxlen) ); REQUIRE( (SDS.isotropy[offset] >= 0 && SDS.isotropy[offset] < maxiso) ); @@ -278,7 +278,7 @@ struct UnitWrap::UnitTest::TestShocMain : public UnitWrap::UnitTest::Base REQUIRE( (SDS.tk[offset] >= 0 && SDS.tk[offset] < 100) ); REQUIRE( (SDS.tkh[offset] >= 0 && SDS.tkh[offset] < 100) ); REQUIRE(std::abs(SDS.wthv_sec[offset]) < 1); - REQUIRE(std::abs(SDS.brunt[offset] < 1)); + REQUIRE(std::abs(SDS.brunt[offset]) < 1); // Make sure there are no "empty" clouds if (SDS.shoc_cldfrac[offset] > 0){ @@ -298,7 +298,7 @@ struct UnitWrap::UnitTest::TestShocMain : public UnitWrap::UnitTest::Base REQUIRE(SDS.host_dse[offset] < dse_upper); // Verify that w2 is less than tke - REQUIRE(std::abs(SDS.w_sec[offset] < SDS.tke[offset])); + REQUIRE(std::abs(SDS.w_sec[offset]) < SDS.tke[offset]); // Verify tracer output is reasonable for (Int t = 0; t < num_qtracers; ++t){ @@ -314,12 +314,12 @@ struct UnitWrap::UnitTest::TestShocMain : public UnitWrap::UnitTest::Base // Make sure turbulence output is appropriate REQUIRE( (SDS.thl_sec[offset] >= 0 && SDS.thl_sec[offset] < 1e2 ) ); REQUIRE( (SDS.qw_sec[offset] >= 0 && SDS.qw_sec[offset] < 1e-3) ); - REQUIRE(std::abs(SDS.wthl_sec[offset] < 1)); - REQUIRE(std::abs(SDS.wqw_sec[offset] < 1e-3)); - REQUIRE(std::abs(SDS.w3[offset] < 10)); - REQUIRE(std::abs(SDS.qwthl_sec[offset] < 1)); - REQUIRE(std::abs(SDS.uw_sec[offset] < 1)); - REQUIRE(std::abs(SDS.vw_sec[offset] < 1)); + REQUIRE(std::abs(SDS.wthl_sec[offset]) < 1); + REQUIRE(std::abs(SDS.wqw_sec[offset]) < 1e-3); + REQUIRE(std::abs(SDS.w3[offset]) < 10); + REQUIRE(std::abs(SDS.qwthl_sec[offset]) < 1); + REQUIRE(std::abs(SDS.uw_sec[offset]) < 1); + REQUIRE(std::abs(SDS.vw_sec[offset]) < 1); } } diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pblintd_height_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pblintd_height_tests.cpp index 23e428e4e444..4c2210400fcb 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pblintd_height_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pblintd_height_tests.cpp @@ -71,8 +71,8 @@ struct UnitWrap::UnitTest::TestPblintdHeight : public UnitWrap::UnitTest:: for(Int n = 0; n < nlev; ++n) { const auto offset = n + s * nlev; REQUIRE(SDS.z[offset] > 0); - REQUIRE(std::abs(SDS.u[offset] < 100)); - REQUIRE(std::abs(SDS.v[offset] < 100)); + REQUIRE(std::abs(SDS.u[offset]) < 100); + REQUIRE(std::abs(SDS.v[offset]) < 100); REQUIRE(SDS.thv[offset] < 1000); REQUIRE(SDS.thv[offset] > 150); } diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp index f9f680b6605c..412967f7e378 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp @@ -54,7 +54,7 @@ struct UnitWrap::UnitTest::TestShocPdfComputeTemp { SDS.thl1 = thl1; SDS.pval = pval; - Int num_tests = SDS.pval/abs(presincr); + Int num_tests = SDS.pval/std::abs(presincr); REQUIRE(num_tests > 1); REQUIRE(presincr < 0); diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pdf_qw_parameters_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pdf_qw_parameters_tests.cpp index 0f9b46b5531a..c4f3435bcb8e 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pdf_qw_parameters_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pdf_qw_parameters_tests.cpp @@ -84,15 +84,15 @@ struct UnitWrap::UnitTest::TestShocQwParameters { REQUIRE(SDS.w1_1 > 0); REQUIRE(SDS.w1_2 < 0); if (SDS.skew_w > 0){ - REQUIRE(abs(SDS.w1_1) > abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) > std::abs(SDS.w1_2)); REQUIRE(SDS.a < 0.5); } else if (SDS.skew_w < 0){ - REQUIRE(abs(SDS.w1_1) < abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) < std::abs(SDS.w1_2)); REQUIRE(SDS.a > 0.5); } else if (SDS.skew_w == 0){ - REQUIRE(abs(SDS.w1_1) == abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) == std::abs(SDS.w1_2)); REQUIRE(SDS.a == 0); } @@ -100,7 +100,7 @@ struct UnitWrap::UnitTest::TestShocQwParameters { shoc_assumed_pdf_qw_parameters(SDS); // Save absolute difference between the two gaussian moistures - Real qwgaus_diff_result1 = abs(qvconv*SDS.qw1_2 - qvconv*SDS.qw1_1); + Real qwgaus_diff_result1 = std::abs(qvconv*SDS.qw1_2 - qvconv*SDS.qw1_1); // Now laod up value for the large wqwsec test SDS.wqwsec = wqwsec_large; @@ -109,7 +109,7 @@ struct UnitWrap::UnitTest::TestShocQwParameters { shoc_assumed_pdf_qw_parameters(SDS); // Save absolute difference between the two gaussian temps - Real qwgaus_diff_result2 = abs(qvconv*SDS.qw1_2 - qvconv*SDS.qw1_1); + Real qwgaus_diff_result2 = std::abs(qvconv*SDS.qw1_2 - qvconv*SDS.qw1_1); // Now check the result REQUIRE(qwgaus_diff_result2 > qwgaus_diff_result1); diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pdf_thl_parameters_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pdf_thl_parameters_tests.cpp index 45607ffdc403..72db10be6b38 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pdf_thl_parameters_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pdf_thl_parameters_tests.cpp @@ -81,15 +81,15 @@ struct UnitWrap::UnitTest::TestShocThlParameters { REQUIRE(SDS.w1_1 > 0); REQUIRE(SDS.w1_2 < 0); if (SDS.skew_w > 0){ - REQUIRE(abs(SDS.w1_1) > abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) > std::abs(SDS.w1_2)); REQUIRE(SDS.a < 0.5); } else if (SDS.skew_w < 0){ - REQUIRE(abs(SDS.w1_1) < abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) < std::abs(SDS.w1_2)); REQUIRE(SDS.a > 0.5); } else if (SDS.skew_w == 0){ - REQUIRE(abs(SDS.w1_1) == abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) == std::abs(SDS.w1_2)); REQUIRE(SDS.a == 0); } @@ -144,7 +144,7 @@ struct UnitWrap::UnitTest::TestShocThlParameters { shoc_assumed_pdf_thl_parameters(SDS); // Save absolute difference between the two gaussian temps - Real thlgaus_diff_result1 = abs(SDS.thl1_2 - SDS.thl1_1); + Real thlgaus_diff_result1 = std::abs(SDS.thl1_2 - SDS.thl1_1); // Now laod up value for the large wthlsec test SDS.wthlsec = wthlsec_large; @@ -153,7 +153,7 @@ struct UnitWrap::UnitTest::TestShocThlParameters { shoc_assumed_pdf_thl_parameters(SDS); // Save absolute difference between the two gaussian temps - Real thlgaus_diff_result2 = abs(SDS.thl1_2 - SDS.thl1_1); + Real thlgaus_diff_result2 = std::abs(SDS.thl1_2 - SDS.thl1_1); // Now check the result REQUIRE(thlgaus_diff_result2 > thlgaus_diff_result1); diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pdf_vv_parameters_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pdf_vv_parameters_tests.cpp index cfdb3b53e3fd..2a4325552afe 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pdf_vv_parameters_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pdf_vv_parameters_tests.cpp @@ -90,7 +90,7 @@ struct UnitWrap::UnitTest::TestShocVVParameters { // Verify that first gaussian absolute value is larger // than second gaussian - REQUIRE(abs(SDS.w1_1) > abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) > std::abs(SDS.w1_2)); // TEST THREE // Given highly negative skewed distribution, verify that the gaussian @@ -123,7 +123,7 @@ struct UnitWrap::UnitTest::TestShocVVParameters { // Verify that second gaussian absolute value is larger // than first gaussian - REQUIRE(abs(SDS.w1_1) < abs(SDS.w1_2)); + REQUIRE(std::abs(SDS.w1_1) < std::abs(SDS.w1_2)); } static void run_bfb() diff --git a/components/eamxx/src/physics/shoc/tests/shoc_update_prognostics_implicit_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_update_prognostics_implicit_tests.cpp index 01e8f615653e..ccf9e7ca1ab1 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_update_prognostics_implicit_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_update_prognostics_implicit_tests.cpp @@ -277,8 +277,8 @@ struct UnitWrap::UnitTest::TestUpdatePrognosticsImplicit : public UnitWrap::U REQUIRE( (SDS.qw[offset] > qw_lbound && SDS.qw[offset] < qw_ubound) ); REQUIRE( (SDS.tke[offset] > tke_lbound && SDS.tke[offset] < tke_ubound) ); // Increase wind bounds by 2 m/s to allow for surface flux effects - REQUIRE(std::abs(SDS.u_wind[offset] < wind_bounds+2)); - REQUIRE(std::abs(SDS.v_wind[offset] < wind_bounds+2)); + REQUIRE(std::abs(SDS.u_wind[offset]) < wind_bounds+2); + REQUIRE(std::abs(SDS.v_wind[offset]) < wind_bounds+2); // Compute integrals of end result // Output total water integral From 67610cd96a527f65960414d84cc8730968093803 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 16:35:29 -0700 Subject: [PATCH 234/398] EAMxx: fix usage of physics constants in physics folder Some constants are now Quantity objects --- components/eamxx/src/physics/cosp/eamxx_cosp.cpp | 2 +- components/eamxx/src/physics/gw/gw_functions.hpp | 2 +- ...te_tendencies_from_stress_divergence_impl.hpp | 4 ++-- .../eamxx/src/physics/gw/impl/gw_ediff_impl.hpp | 2 +- .../gw_momentum_energy_conservation_impl.hpp | 2 +- .../src/physics/gw/impl/gw_oro_src_impl.hpp | 4 ++-- .../src/physics/gw/impl/gw_precalc_rhoi_impl.hpp | 6 +++--- .../eamxx/src/physics/gw/impl/gw_prof_impl.hpp | 10 +++++----- .../src/physics/gw/impl/gw_vd_lu_decomp_impl.hpp | 2 +- .../src/physics/gw/tests/infra/gw_test_data.cpp | 6 +++--- .../eamxx_iop_forcing_process_interface.cpp | 8 ++++---- .../src/physics/mam/eamxx_mam_aci_functions.hpp | 4 ++-- .../eamxx_mam_constituent_fluxes_functions.hpp | 2 +- .../physics/p3/eamxx_p3_process_interface.hpp | 4 ++-- .../p3/impl/p3_calc_rime_density_impl.hpp | 2 +- .../p3/impl/p3_cldliq_imm_freezing_impl.hpp | 10 +++++----- .../src/physics/p3/impl/p3_cloud_sed_impl.hpp | 2 +- .../eamxx/src/physics/p3/impl/p3_dsd2_impl.hpp | 2 +- .../physics/p3/impl/p3_evaporate_rain_impl.hpp | 8 ++++---- .../p3_get_time_space_phys_variables_impl.hpp | 8 ++++---- .../p3/impl/p3_ice_classical_nucleation_impl.hpp | 2 +- .../p3/impl/p3_ice_cldliq_wet_growth_impl.hpp | 8 ++++---- .../physics/p3/impl/p3_ice_collection_impl.hpp | 4 ++-- .../impl/p3_ice_deposition_sublimation_impl.hpp | 2 +- .../src/physics/p3/impl/p3_ice_melting_impl.hpp | 6 +++--- .../physics/p3/impl/p3_ice_nucleation_impl.hpp | 12 ++++++------ .../p3/impl/p3_ice_relaxation_timescale_impl.hpp | 6 +++--- .../src/physics/p3/impl/p3_ice_sed_impl.hpp | 8 ++++---- .../impl/p3_ice_supersat_conservation_impl.hpp | 8 ++++---- .../src/physics/p3/impl/p3_main_impl_part1.hpp | 14 +++++++------- .../src/physics/p3/impl/p3_main_impl_part2.hpp | 8 ++++---- .../src/physics/p3/impl/p3_main_impl_part3.hpp | 6 +++--- .../impl/p3_prevent_liq_supersaturation_impl.hpp | 8 ++++---- .../p3/impl/p3_rain_imm_freezing_impl.hpp | 10 +++++----- .../src/physics/p3/impl/p3_rain_sed_impl.hpp | 2 +- .../p3/impl/p3_rain_self_collection_impl.hpp | 2 +- .../src/physics/p3/impl/p3_table_ice_impl.hpp | 2 +- .../p3/impl/p3_update_prognostics_impl.hpp | 10 +++++----- .../src/physics/p3/tests/infra/p3_ic_cases.cpp | 4 ++-- .../p3/tests/p3_calc_rime_density_unit_tests.cpp | 4 ++-- .../tests/p3_cldliq_imm_freezing_unit_tests.cpp | 4 ++-- .../p3/tests/p3_evaporate_rain_unit_tests.cpp | 4 ++-- .../p3_ice_cldliq_wet_growth_unit_tests.cpp | 4 ++-- .../p3_ice_deposition_sublimation_tests.cpp | 4 ++-- .../p3/tests/p3_ice_melting_unit_tests.cpp | 4 ++-- .../physics/p3/tests/p3_ice_sed_unit_tests.cpp | 4 ++-- .../tests/p3_ice_supersat_conservation_tests.cpp | 4 ++-- .../src/physics/p3/tests/p3_main_unit_tests.cpp | 16 ++++++++-------- .../p3_prevent_liq_supersaturation_tests.cpp | 10 +++++----- .../p3/tests/p3_rain_imm_freezing_unit_tests.cpp | 4 ++-- .../eamxx/src/physics/p3/tests/p3_unit_tests.cpp | 10 +++++----- .../physics/rrtmgp/eamxx_rrtmgp_interface.hpp | 4 ++-- .../rrtmgp/eamxx_rrtmgp_process_interface.cpp | 4 ++-- .../eamxx/src/physics/rrtmgp/rrtmgp_utils.hpp | 2 +- .../physics/rrtmgp/tests/rrtmgp_unit_tests.cpp | 8 ++++---- .../shoc/eamxx_shoc_process_interface.cpp | 4 ++-- .../shoc/eamxx_shoc_process_interface.hpp | 4 ++-- .../physics/shoc/impl/shoc_adv_sgs_tke_impl.hpp | 2 +- ...oc_assumed_pdf_compute_buoyancy_flux_impl.hpp | 12 ++++++------ .../impl/shoc_assumed_pdf_compute_qs_impl.hpp | 8 ++++---- .../impl/shoc_assumed_pdf_compute_s_impl.hpp | 10 +++++----- ...shoc_assumed_pdf_compute_temperature_impl.hpp | 6 +++--- .../impl/shoc_compute_brunt_shoc_length_impl.hpp | 2 +- .../shoc_compute_diag_third_shoc_moment_impl.hpp | 2 +- .../impl/shoc_compute_shoc_temperature_impl.hpp | 4 ++-- .../physics/shoc/impl/shoc_compute_tmpi_impl.hpp | 2 +- .../physics/shoc/impl/shoc_diag_obklen_impl.hpp | 6 +++--- .../impl/shoc_diag_second_moments_srf_impl.hpp | 2 +- .../physics/shoc/impl/shoc_dp_inverse_impl.hpp | 2 +- .../physics/shoc/impl/shoc_energy_fixer_impl.hpp | 8 ++++---- .../shoc/impl/shoc_energy_integrals_impl.hpp | 2 +- .../src/physics/shoc/impl/shoc_grid_impl.hpp | 2 +- .../physics/shoc/impl/shoc_isotropic_ts_impl.hpp | 2 +- .../shoc/impl/shoc_pblintd_height_impl.hpp | 2 +- .../shoc/impl/shoc_pblintd_init_pot_impl.hpp | 8 ++++---- .../shoc/impl/shoc_tridiag_solver_impl.hpp | 2 +- .../shoc/impl/shoc_update_host_dse_impl.hpp | 6 +++--- .../shoc_update_prognostics_implicit_impl.hpp | 2 +- .../physics/shoc/tests/infra/shoc_ic_cases.cpp | 12 ++++++------ .../physics/shoc/tests/infra/shoc_test_data.hpp | 14 +++++++------- .../shoc/tests/shoc_energy_fixer_tests.cpp | 4 ++-- .../src/physics/shoc/tests/shoc_grid_tests.cpp | 2 +- .../src/physics/shoc/tests/shoc_main_tests.cpp | 10 +++++----- .../shoc/tests/shoc_pdf_computetemp_tests.cpp | 2 +- .../src/physics/tms/impl/compute_tms_impl.hpp | 16 ++++++++-------- .../physics/zm/eamxx_zm_process_interface.cpp | 4 ++-- components/eamxx/src/physics/zm/zm_functions.hpp | 4 ++-- .../rrtmgp/rrtmgp_standalone_unit.cpp | 8 ++++---- 88 files changed, 239 insertions(+), 239 deletions(-) diff --git a/components/eamxx/src/physics/cosp/eamxx_cosp.cpp b/components/eamxx/src/physics/cosp/eamxx_cosp.cpp index 04c1808b2f8b..039c23e1165b 100644 --- a/components/eamxx/src/physics/cosp/eamxx_cosp.cpp +++ b/components/eamxx/src/physics/cosp/eamxx_cosp.cpp @@ -178,7 +178,7 @@ void Cosp::run_impl (const double dt) using PF = scream::PhysicsFunctions; const auto scan_policy = TPF::get_thread_range_parallel_scan_team_policy(ncol, nlev); - const auto g = physics::Constants::gravit; + const Real g = physics::Constants::gravit.value; Kokkos::parallel_for(scan_policy, KOKKOS_LAMBDA (const KT::MemberType& team) { const int i = team.league_rank(); const auto p_mid_s = ekat::subview(p_mid_d, i); diff --git a/components/eamxx/src/physics/gw/gw_functions.hpp b/components/eamxx/src/physics/gw/gw_functions.hpp index 1873adf471ab..6750ebd7d823 100644 --- a/components/eamxx/src/physics/gw/gw_functions.hpp +++ b/components/eamxx/src/physics/gw/gw_functions.hpp @@ -74,7 +74,7 @@ struct Functions static inline constexpr int north = 3; // rair/gravit - static inline constexpr Real rog = C::Rair / C::gravit; + static inline constexpr Real rog = C::Rair.value / C::gravit.value; // Background diffusivity. static inline constexpr Real dback = 0.05; diff --git a/components/eamxx/src/physics/gw/impl/gw_compute_tendencies_from_stress_divergence_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_compute_tendencies_from_stress_divergence_impl.hpp index 05bf1ada15f1..041cc611a13e 100644 --- a/components/eamxx/src/physics/gw/impl/gw_compute_tendencies_from_stress_divergence_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_compute_tendencies_from_stress_divergence_impl.hpp @@ -68,7 +68,7 @@ void Functions::gwd_compute_tendencies_from_stress_divergence( // Determine the wind tendency, including excess stress carried down // from above. - Real ubtl = C::gravit * (tau(pl_idx,k+1)-tau(pl_idx,k)) * rdpm(k); + Real ubtl = C::gravit.value * (tau(pl_idx,k+1)-tau(pl_idx,k)) * rdpm(k); if (init.orographic_only) { // Require that the tendency be no larger than the analytic @@ -106,7 +106,7 @@ void Functions::gwd_compute_tendencies_from_stress_divergence( // causing stress divergence in the next layer down. This // smoothes large stress divergences downward while conserving // total stress. - tau(pl_idx,k+1) = tau(pl_idx,k) + ubtl * dpm(k) / C::gravit; + tau(pl_idx,k+1) = tau(pl_idx,k) + ubtl * dpm(k) / C::gravit.value; } } }); diff --git a/components/eamxx/src/physics/gw/impl/gw_ediff_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_ediff_impl.hpp index b03bdf935fe6..8b13f4bad7b0 100644 --- a/components/eamxx/src/physics/gw/impl/gw_ediff_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_ediff_impl.hpp @@ -101,7 +101,7 @@ void Functions::gw_ediff( // Calculate dt * (gravit*rho)^2/dp at interior interfaces. Kokkos::parallel_for( Kokkos::TeamVectorRange(team, ktop+2, kbot+2), [&] (const int k) { - tmpi2(k) = dt * bfb_square(C::gravit * rho(k)) / (pmid(k) - pmid(k-1)); + tmpi2(k) = dt * bfb_square(C::gravit.value * rho(k)) / (pmid(k) - pmid(k-1)); }); team.team_barrier(); diff --git a/components/eamxx/src/physics/gw/impl/gw_momentum_energy_conservation_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_momentum_energy_conservation_impl.hpp index 335e4f49657d..e7db4a5521ed 100644 --- a/components/eamxx/src/physics/gw/impl/gw_momentum_energy_conservation_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_momentum_energy_conservation_impl.hpp @@ -36,7 +36,7 @@ void Functions::momentum_energy_conservation( Real dz = 0; Kokkos::parallel_reduce( Kokkos::TeamVectorRange(team, tend_level+1, pver), [&] (const int k, Real& lsum) { - lsum += pdel(k) / C::gravit; + lsum += pdel(k) / C::gravit.value; }, Kokkos::Sum(dz)); // Tendency for U & V below source level. diff --git a/components/eamxx/src/physics/gw/impl/gw_oro_src_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_oro_src_impl.hpp index e62c47643d16..02d7417be144 100644 --- a/components/eamxx/src/physics/gw/impl/gw_oro_src_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_oro_src_impl.hpp @@ -54,7 +54,7 @@ void Functions::gw_oro_src( Int k = pver-1; // Averages over source region. - Real rsrc = pmid(k)/(C::Rair*t(k)) * dpm(k); // Density. + Real rsrc = pmid(k)/(C::Rair.value*t(k)) * dpm(k); // Density. Real usrc = u(k) * dpm(k); // Zonal wind. Real vsrc = v(k) * dpm(k); // Meridional wind. Real nsrc = nm(k)* dpm(k); // B-V frequency. @@ -63,7 +63,7 @@ void Functions::gw_oro_src( Kokkos::parallel_reduce( Kokkos::TeamVectorRange(team, pver/2 - 1, pver-1), [&] (const int k, Real& lrsrc, Real& lusrc, Real& lvsrc, Real& lnsrc) { if (hdsp > std::sqrt(zm(k)*zm(k+1))) { - lrsrc += pmid(k) / (C::Rair*t(k))* dpm(k); + lrsrc += pmid(k) / (C::Rair.value*t(k))* dpm(k); lusrc += u(k) * dpm(k); lvsrc += v(k) * dpm(k); lnsrc += (nm(k)* dpm(k)); diff --git a/components/eamxx/src/physics/gw/impl/gw_precalc_rhoi_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_precalc_rhoi_impl.hpp index d46ca35c093a..0d7f024d8600 100644 --- a/components/eamxx/src/physics/gw/impl/gw_precalc_rhoi_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_precalc_rhoi_impl.hpp @@ -47,12 +47,12 @@ void Functions::gwd_precalc_rhoi( {"rhoi_kludge", "decomp_ca", "decomp_cc", "decomp_dnom", "decomp_ze", "q_nostride", "qtgw_nostride"}, {&rhoi_kludge, &decomp_ca, &decomp_cc, &decomp_dnom, &decomp_ze, &q_nostride, &qtgw_nostride}); - rhoi_kludge(0) = pint(0) / (C::Rair * t(0)); + rhoi_kludge(0) = pint(0) / (C::Rair.value * t(0)); Kokkos::parallel_for( Kokkos::TeamVectorRange(team, 1, pver), [&] (const int k) { - rhoi_kludge(k) = pint(k) * 2 / (C::Rair * (t(k) + t(k-1))); + rhoi_kludge(k) = pint(k) * 2 / (C::Rair.value * (t(k) + t(k-1))); }); - rhoi_kludge(pver) = pint(pver) / (C::Rair * t(pver-1)); + rhoi_kludge(pver) = pint(pver) / (C::Rair.value * t(pver-1)); // Calculate effective diffusivity and LU decomposition for the // vertical diffusion solver. diff --git a/components/eamxx/src/physics/gw/impl/gw_prof_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_prof_impl.hpp index e6b87ef87a07..e79b02def7d6 100644 --- a/components/eamxx/src/physics/gw/impl/gw_prof_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_prof_impl.hpp @@ -37,8 +37,8 @@ void Functions::gw_prof( // atmosphere above the top level. Kokkos::single(Kokkos::PerTeam(team), [&] { ti(0) = t(0); - rhoi(0) = pint(0) / (C::Rair*ti(0)); - ni(0) = sqrt(C::gravit*C::gravit / (cpair*ti(0))); + rhoi(0) = pint(0) / (C::Rair.value*ti(0)); + ni(0) = sqrt(C::gravit.value*C::gravit.value / (cpair*ti(0))); }); // Interior points use centered differences. @@ -47,9 +47,9 @@ void Functions::gw_prof( static constexpr Real n2min = GWC::n2min; Kokkos::parallel_for( Kokkos::TeamVectorRange(team, 1, pver), [&] (const int k) { - rhoi(k) = pint(k) / (C::Rair*ti(k)); + rhoi(k) = pint(k) / (C::Rair.value*ti(k)); const Real dtdp = (t(k)-t(k-1)) / (pmid(k)-pmid(k-1)); - const Real n2 = C::gravit*C::gravit/ti(k) * (1/cpair - rhoi(k)*dtdp); + const Real n2 = C::gravit.value*C::gravit.value/ti(k) * (1/cpair - rhoi(k)*dtdp); ni(k) = std::sqrt(ekat::impl::max(n2min, n2)); }); @@ -58,7 +58,7 @@ void Functions::gw_prof( team.team_barrier(); Kokkos::single(Kokkos::PerTeam(team), [&] { ti(pver) = t(pver-1); - rhoi(pver) = pint(pver) / (C::Rair*ti(pver)); + rhoi(pver) = pint(pver) / (C::Rair.value*ti(pver)); ni(pver) = ni(pver-1); }); diff --git a/components/eamxx/src/physics/gw/impl/gw_vd_lu_decomp_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_vd_lu_decomp_impl.hpp index 616674923444..0e518fa02c01 100644 --- a/components/eamxx/src/physics/gw/impl/gw_vd_lu_decomp_impl.hpp +++ b/components/eamxx/src/physics/gw/impl/gw_vd_lu_decomp_impl.hpp @@ -53,7 +53,7 @@ void Functions::vd_lu_decomp( // tridiagonal matrix as defined by the implicit diffusion equation. team.team_barrier(); Kokkos::single(Kokkos::PerTeam(team), [&] { - const Real dnom = 1 / (1 + decomp_cc(nbot) + ksrf*ztodt*C::gravit*rpdel(nbot)); + const Real dnom = 1 / (1 + decomp_cc(nbot) + ksrf*ztodt*C::gravit.value*rpdel(nbot)); decomp_dnom(nbot) = dnom; decomp_ze(nbot) = decomp_cc(nbot) * dnom; diff --git a/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp b/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp index d549e377305d..8f92481698c8 100644 --- a/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp +++ b/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp @@ -87,7 +87,7 @@ namespace { void gw_common_init_f(GwCommonInit& init) { // Expects init has already been transitioned to f90 - gw_common_init_bridge_f(init.pver, init.pgwv, init.dc, init.cref, init.orographic_only, init.do_molec_diff, init.tau_0_ubc, init.nbot_molec, init.ktop, init.kbotbg, init.fcrit2, init.kwv, GWC::gravit, GWC::Rair, init.alpha); + gw_common_init_bridge_f(init.pver, init.pgwv, init.dc, init.cref, init.orographic_only, init.do_molec_diff, init.tau_0_ubc, init.nbot_molec, init.ktop, init.kbotbg, init.fcrit2, init.kwv, GWC::gravit.value, GWC::Rair.value, init.alpha); } // Wrapper around gw_init for cxx @@ -1659,7 +1659,7 @@ void gw_ediff_f(GwEdiffData& d) { d.transition(); gw_common_init_f(d.init); - gw_ediff_bridge_f(d.ncol, d.kbot, d.ktop, d.tend_level, d.gwut, d.ubm, d.nm, d.rho, d.dt, GWC::gravit, d.pmid, d.rdpm, d.c, d.egwdffi, d.decomp_ca, d.decomp_cc, d.decomp_dnom, d.decomp_ze); + gw_ediff_bridge_f(d.ncol, d.kbot, d.ktop, d.tend_level, d.gwut, d.ubm, d.nm, d.rho, d.dt, GWC::gravit.value, d.pmid, d.rdpm, d.c, d.egwdffi, d.decomp_ca, d.decomp_cc, d.decomp_dnom, d.decomp_ze); d.transition(); } @@ -1964,7 +1964,7 @@ void vd_lu_decomp_f(VdLuDecompData& d) { d.transition(); gw_common_init_f(d.init); - vd_lu_decomp_bridge_f(d.ncol, d.ksrf, d.kv, d.tmpi, d.rpdel, d.ztodt, GWC::gravit, d.cc_top, d.ntop, d.nbot, d.decomp_ca, d.decomp_cc, d.decomp_dnom, d.decomp_ze); + vd_lu_decomp_bridge_f(d.ncol, d.ksrf, d.kv, d.tmpi, d.rpdel, d.ztodt, GWC::gravit.value, d.cc_top, d.ntop, d.nbot, d.decomp_ca, d.decomp_cc, d.decomp_dnom, d.decomp_ze); d.transition(); } diff --git a/components/eamxx/src/physics/iop_forcing/eamxx_iop_forcing_process_interface.cpp b/components/eamxx/src/physics/iop_forcing/eamxx_iop_forcing_process_interface.cpp index 0cc955cde143..eb21de5637c5 100644 --- a/components/eamxx/src/physics/iop_forcing/eamxx_iop_forcing_process_interface.cpp +++ b/components/eamxx/src/physics/iop_forcing/eamxx_iop_forcing_process_interface.cpp @@ -163,8 +163,8 @@ advance_iop_subsidence(const MemberType& team, const view_1d& T, const view_2d& Q) { - constexpr Real Rair = C::Rair; - constexpr Real Cpair = C::Cpair; + constexpr Real Rair = C::Rair.value; + constexpr Real Cpair = C::Cpair.value; const auto n_q_tracers = Q.extent_int(0); const auto nlev_packs = ekat::npack(nlevs); @@ -321,7 +321,7 @@ iop_apply_coriolis(const MemberType& team, const view_1d& v) { constexpr Real pi = C::Pi; - constexpr Real earth_rotation = C::omega; + constexpr Real earth_rotation = C::omega.value; // Compute coriolis force const auto fcor = 2*earth_rotation*std::sin(lat*pi/180); @@ -343,7 +343,7 @@ void IOPForcing::run_impl (const double dt) const auto nlev_packs = ekat::npack(m_num_levs); // Hybrid coord values - const auto ps0 = C::P0; + const Real ps0 = C::P0.value; const auto hyam = m_grid->get_geometry_data("hyam").get_view(); const auto hybm = m_grid->get_geometry_data("hybm").get_view(); const auto hyai = m_grid->get_geometry_data("hyai").get_view(); diff --git a/components/eamxx/src/physics/mam/eamxx_mam_aci_functions.hpp b/components/eamxx/src/physics/mam/eamxx_mam_aci_functions.hpp index 54c1ae9f733c..05e8f4b534a1 100644 --- a/components/eamxx/src/physics/mam/eamxx_mam_aci_functions.hpp +++ b/components/eamxx/src/physics/mam/eamxx_mam_aci_functions.hpp @@ -22,9 +22,9 @@ void compute_w0_and_rho(haero::ThreadTeamPolicy team_policy, const int icol = team.league_rank(); // Get physical constants using C = physics::Constants; - static constexpr auto gravit = C::gravit; // Gravity [m/s2] + static constexpr auto gravit = C::gravit.value; // Gravity [m/s2] // Gas constant for dry air [J/(kg*K) or J/Kg/K] - static constexpr auto rair = C::Rair; + static constexpr auto rair = C::Rair.value; Kokkos::parallel_for(Kokkos::TeamVectorRange(team, 0u, top_lev), [&](int kk) { w0(icol, kk) = 0; diff --git a/components/eamxx/src/physics/mam/eamxx_mam_constituent_fluxes_functions.hpp b/components/eamxx/src/physics/mam/eamxx_mam_constituent_fluxes_functions.hpp index 6ef4d5e03e9b..03d85ba59e1e 100644 --- a/components/eamxx/src/physics/mam/eamxx_mam_constituent_fluxes_functions.hpp +++ b/components/eamxx/src/physics/mam/eamxx_mam_constituent_fluxes_functions.hpp @@ -15,7 +15,7 @@ void update_gas_aerosols_using_constituents( // output const mam_coupling::AerosolState &wet_aero) { using C = physics::Constants; - static constexpr auto gravit = C::gravit; // Gravity [m/s2] + static constexpr auto gravit = C::gravit.value; // Gravity [m/s2] static constexpr int pcnst = mam4::aero_model::pcnst; // Declare local variables diff --git a/components/eamxx/src/physics/p3/eamxx_p3_process_interface.hpp b/components/eamxx/src/physics/p3/eamxx_p3_process_interface.hpp index 9da35911e413..f40b11a411ca 100644 --- a/components/eamxx/src/physics/p3/eamxx_p3_process_interface.hpp +++ b/components/eamxx/src/physics/p3/eamxx_p3_process_interface.hpp @@ -276,8 +276,8 @@ class P3Microphysics : public AtmosphereProcess // Note: we need to ensure that only a single thread within the team is // updating the mass value. Kokkos::single(Kokkos::PerTeam(team), [&] { - precip_liq_surf_mass(icol) += precip_liq_surf_flux(icol) * PC::RHO_H2O * m_dt; - precip_ice_surf_mass(icol) += precip_ice_surf_flux(icol) * PC::RHO_H2O * m_dt; + precip_liq_surf_mass(icol) += precip_liq_surf_flux(icol) * PC::RHO_H2O.value * m_dt; + precip_ice_surf_mass(icol) += precip_ice_surf_flux(icol) * PC::RHO_H2O.value * m_dt; }); // If necessary, set appropriate boundary fluxes for energy and mass diff --git a/components/eamxx/src/physics/p3/impl/p3_calc_rime_density_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_calc_rime_density_impl.hpp index ed4cc6884109..8738dd2cd2a4 100644 --- a/components/eamxx/src/physics/p3/impl/p3_calc_rime_density_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_calc_rime_density_impl.hpp @@ -23,7 +23,7 @@ ::calc_rime_density( const Smask& context) { constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar T_zerodegc = C::T_zerodegc; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; constexpr Scalar bcn = C::bcn; const auto qc2qi_collect_tend_not_small_and_t_freezing = (qc2qi_collect_tend >= qsmall) && diff --git a/components/eamxx/src/physics/p3/impl/p3_cldliq_imm_freezing_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_cldliq_imm_freezing_impl.hpp index c23e9e00e634..14d27b825dbf 100644 --- a/components/eamxx/src/physics/p3/impl/p3_cldliq_imm_freezing_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_cldliq_imm_freezing_impl.hpp @@ -23,11 +23,11 @@ ::cldliq_immersion_freezing( const P3Runtime& runtime_options, const Smask& context) { - constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar T_rainfrz = C::T_rainfrz; - constexpr Scalar T_zerodegc = C::T_zerodegc; - constexpr Scalar CONS5 = C::CONS5; - constexpr Scalar CONS6 = C::CONS6; + constexpr Scalar qsmall = C::QSMALL; + constexpr Scalar T_rainfrz = C::T_rainfrz.value; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; + constexpr Scalar CONS5 = C::CONS5; + constexpr Scalar CONS6 = C::CONS6; const Scalar immersion_freezing_exponent = runtime_options.immersion_freezing_exponent; diff --git a/components/eamxx/src/physics/p3/impl/p3_cloud_sed_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_cloud_sed_impl.hpp index 43cc8095ed51..d1c0a756f5e9 100644 --- a/components/eamxx/src/physics/p3/impl/p3_cloud_sed_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_cloud_sed_impl.hpp @@ -131,7 +131,7 @@ ::cloud_sedimentation( Kokkos::single( Kokkos::PerTeam(team), [&] () { - precip_liq_surf = prt_accum * C::INV_RHO_H2O * inv_dt; + precip_liq_surf = prt_accum * C::INV_RHO_H2O.value * inv_dt; }); } diff --git a/components/eamxx/src/physics/p3/impl/p3_dsd2_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_dsd2_impl.hpp index 68814db34790..b40be90e9346 100644 --- a/components/eamxx/src/physics/p3/impl/p3_dsd2_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_dsd2_impl.hpp @@ -64,7 +64,7 @@ get_cloud_dsd2( lamc.set(lamc_lt_min, lammin); lamc.set(lamc_gt_max, lammax); - nc.set(min_or_max, 6 * (lamc * lamc * lamc) * qc / (C::Pi * C::RHO_H2O * (mu_c + 3) * (mu_c + 2) * (mu_c + 1))); + nc.set(min_or_max, 6 * (lamc * lamc * lamc) * qc / (C::Pi * C::RHO_H2O.value * (mu_c + 3) * (mu_c + 2) * (mu_c + 1))); cdist.set(qc_gt_small, nc * (mu_c+1) / lamc); cdist1.set(qc_gt_small, nc / tgamma(mu_c + 1)); diff --git a/components/eamxx/src/physics/p3/impl/p3_evaporate_rain_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_evaporate_rain_impl.hpp index 9e9919771082..90c193ca8da5 100644 --- a/components/eamxx/src/physics/p3/impl/p3_evaporate_rain_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_evaporate_rain_impl.hpp @@ -90,10 +90,10 @@ ::evaporate_rain( nr_evap_tend = 0; const Scalar inv_dt = 1/dt; constexpr Scalar QSMALL = C::QSMALL; - constexpr Scalar Tmelt = C::Tmelt; - constexpr Scalar inv_cp = 1/C::Cpair; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar Tmelt = C::Tmelt.value; + constexpr Scalar inv_cp = 1/C::Cpair.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; //Compute absolute supersaturation. //Ignore the difference between clear-sky and cell-ave qv and T diff --git a/components/eamxx/src/physics/p3/impl/p3_get_time_space_phys_variables_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_get_time_space_phys_variables_impl.hpp index bfa481cf17e8..646a1b324ba7 100644 --- a/components/eamxx/src/physics/p3/impl/p3_get_time_space_phys_variables_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_get_time_space_phys_variables_impl.hpp @@ -21,10 +21,10 @@ ::get_time_space_phys_variables( dv.set(context, sp(8.794e-5) * pow(T_atm,sp(1.81))/pres); sc.set(context, mu/(rho*dv)); - constexpr Scalar RV = C::RV; - constexpr Scalar INV_CP = C::INV_CP; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar RV = C::RV.value; + constexpr Scalar INV_CP = C::INV_CP.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; constexpr Scalar tval1 = 253.15; constexpr Scalar tval2 = 273.15; constexpr Scalar dtval = 20; //this is tval2-tval1, but specifying here as int to be BFB with F90. diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_classical_nucleation_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_classical_nucleation_impl.hpp index 9673252d957c..93f8933abf08 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_classical_nucleation_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_classical_nucleation_impl.hpp @@ -22,7 +22,7 @@ ::ice_classical_nucleation( Spack& ninuc_cnt, Spack& qinuc_cnt) { constexpr Scalar pi = C::Pi; - constexpr Scalar rho_h2o = C::RHO_H2O; + constexpr Scalar rho_h2o = C::RHO_H2O.value; // TODO: Verify if qsmall can be unified with other "small" numeric literals constexpr Scalar qsmall = 1.0e-18; diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_cldliq_wet_growth_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_cldliq_wet_growth_impl.hpp index 95ac7b4590b0..25118e2ccf9b 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_cldliq_wet_growth_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_cldliq_wet_growth_impl.hpp @@ -21,13 +21,13 @@ ::ice_cldliq_wet_growth( using physics = scream::physics::Functions; constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar tmelt = C::Tmelt; + constexpr Scalar tmelt = C::Tmelt.value; constexpr Scalar twopi = C::Pi*2; constexpr Scalar zero = C::ZERO; constexpr Scalar one = C::ONE; - constexpr Scalar cpw = C::CpLiq; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar cpw = C::CpLiq.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; const auto t_is_negative = temp < tmelt; const auto qi_incld_ge_small = qi_incld >= qsmall; diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_collection_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_collection_impl.hpp index d7250b2d9f2b..83d07cc870b8 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_collection_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_collection_impl.hpp @@ -19,7 +19,7 @@ ::ice_cldliq_collection( const Smask& context) { constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar tmelt = C::Tmelt; + constexpr Scalar tmelt = C::Tmelt.value; // set up masks const auto t_is_negative = temp <= tmelt; @@ -65,7 +65,7 @@ ::ice_rain_collection( const Smask& context) { constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar tmelt = C::Tmelt; + constexpr Scalar tmelt = C::Tmelt.value; // Set up masks const auto t_is_negative = temp <= tmelt; diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_deposition_sublimation_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_deposition_sublimation_impl.hpp index 7c5bbb2d7f1e..1546c682c222 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_deposition_sublimation_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_deposition_sublimation_impl.hpp @@ -17,7 +17,7 @@ ::ice_deposition_sublimation( const Smask& context) { constexpr Scalar QSMALL = C::QSMALL; - constexpr Scalar T_zerodegc = C::T_zerodegc; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; Spack qi_tend; //temporary var for mass tend before splitting into sublim or depos diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_melting_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_melting_impl.hpp index 25aa0c06ba91..975e1f540fa3 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_melting_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_melting_impl.hpp @@ -28,9 +28,9 @@ ::ice_melting( const auto Pi = C::Pi; const auto QSMALL = C::QSMALL; - const auto Tmelt = C::Tmelt; - const auto latvap = C::LatVap; - const auto latice = C::LatIce; + const auto Tmelt = C::Tmelt.value; + const auto latvap = C::LatVap.value; + const auto latice = C::LatIce.value; //Find cells above freezing AND which have ice const auto has_melt_qi = (qi_incld >= QSMALL ) && (T_atm > Tmelt) && context; diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_nucleation_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_nucleation_impl.hpp index cb8d961c523f..c887f7e58a2d 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_nucleation_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_nucleation_impl.hpp @@ -16,12 +16,12 @@ ::ice_nucleation( const P3Runtime& runtime_options, const Smask& context) { - constexpr Scalar nsmall = C::NSMALL; - constexpr Scalar tmelt = C::Tmelt; - constexpr Scalar T_icenuc = C::Tmelt-sp(15.0); - constexpr Scalar zero = C::ZERO; - constexpr Scalar piov3 = C::PIOV3; - constexpr Scalar mi0 = sp(4.0)*piov3*sp(900.0)*sp(1.e-18); + constexpr Scalar nsmall = C::NSMALL; + constexpr Scalar tmelt = C::Tmelt.value; + constexpr Scalar T_icenuc = C::Tmelt.value-sp(15.0); + constexpr Scalar zero = C::ZERO; + constexpr Scalar piov3 = C::PIOV3; + constexpr Scalar mi0 = sp(4.0)*piov3*sp(900.0)*sp(1.e-18); const Scalar deposition_nucleation_exponent = runtime_options.deposition_nucleation_exponent; diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_relaxation_timescale_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_relaxation_timescale_impl.hpp index 53fa1168bc15..64d18ed918df 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_relaxation_timescale_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_relaxation_timescale_impl.hpp @@ -17,9 +17,9 @@ ::ice_relaxation_timescale( const Smask& context) { constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar tmelt = C::Tmelt; - constexpr Scalar zero = C::ZERO; - constexpr Scalar pi = C::Pi; + constexpr Scalar tmelt = C::Tmelt.value; + constexpr Scalar zero = C::ZERO; + constexpr Scalar pi = C::Pi; const auto t_is_negative = temp < tmelt; const auto qi_incld_ge_small = qi_incld >= qsmall; diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_sed_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_sed_impl.hpp index 6be83a900aff..0c1c3baf1d84 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_sed_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_sed_impl.hpp @@ -189,7 +189,7 @@ ::ice_sedimentation( Kokkos::single( Kokkos::PerTeam(team), [&] () { - precip_ice_surf += prt_accum * C::INV_RHO_H2O * inv_dt; + precip_ice_surf += prt_accum * C::INV_RHO_H2O.value * inv_dt; }); } @@ -224,10 +224,10 @@ ::homogeneous_freezing( { constexpr Scalar qsmall = C::QSMALL; constexpr Scalar nsmall = C::NSMALL; - constexpr Scalar T_homogfrz = C::T_homogfrz; + constexpr Scalar T_homogfrz = C::T_homogfrz.value; constexpr Scalar inv_rho_rimeMax = C::INV_RHO_RIMEMAX; - constexpr Scalar inv_cp = C::INV_CP; - constexpr Scalar latice = C::LatIce; + constexpr Scalar inv_cp = C::INV_CP.value; + constexpr Scalar latice = C::LatIce.value; const Int kmin_scalar = ( kdir == 1 ? kbot : ktop); const Int kmax_scalar = ( kdir == 1 ? ktop : kbot); diff --git a/components/eamxx/src/physics/p3/impl/p3_ice_supersat_conservation_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_ice_supersat_conservation_impl.hpp index 78775c3426fe..1225c4876cbb 100644 --- a/components/eamxx/src/physics/p3/impl/p3_ice_supersat_conservation_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_ice_supersat_conservation_impl.hpp @@ -16,10 +16,10 @@ KOKKOS_FUNCTION void Functions::ice_supersat_conservation(Spack& qv2qi_vapdep_tend, Spack& qv2qi_nucleat_tend, Spack& qinuc_cnt, const Spack& cld_frac_i, const Spack& qv, const Spack& qv_sat_i, const Spack& t_atm, const Real& dt, const Spack& qi2qv_sublim_tend, const Spack& qr2qv_evap_tend, const bool& use_hetfrz_classnuc, const Smask& context) { constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar cp = C::CP; - constexpr Scalar rv = C::RH2O; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar cp = C::CP.value; + constexpr Scalar rv = C::RH2O.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; constexpr Scalar latsublim2 = (latvap+latice)*(latvap+latice); Spack qv_sink; diff --git a/components/eamxx/src/physics/p3/impl/p3_main_impl_part1.hpp b/components/eamxx/src/physics/p3/impl/p3_main_impl_part1.hpp index 1e57f74cf3ec..930cea6cde85 100644 --- a/components/eamxx/src/physics/p3/impl/p3_main_impl_part1.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_main_impl_part1.hpp @@ -69,16 +69,16 @@ ::p3_main_part1( using physics = scream::physics::Functions; // load constants into local vars - constexpr Scalar g = C::gravit; - constexpr Scalar rho_1000mb = C::RHO_1000MB; + constexpr Scalar g = C::gravit.value; + constexpr Scalar rho_1000mb = C::RHO_1000MB.value; constexpr Scalar rho_600mb = C::RHO_600MB; - constexpr Scalar rho_h2o = C::RHO_H2O; + constexpr Scalar rho_h2o = C::RHO_H2O.value; constexpr Scalar nccnst = C::NCCNST; - constexpr Scalar T_zerodegc = C::T_zerodegc; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar inv_cp = C::INV_CP; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar inv_cp = C::INV_CP.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; const Scalar spa_ccn_to_nc_factor = runtime_options.spa_ccn_to_nc_factor; const Scalar spa_ccn_to_nc_exponent = runtime_options.spa_ccn_to_nc_exponent; diff --git a/components/eamxx/src/physics/p3/impl/p3_main_impl_part2.hpp b/components/eamxx/src/physics/p3/impl/p3_main_impl_part2.hpp index c1e203568ab0..532d3bf943b7 100644 --- a/components/eamxx/src/physics/p3/impl/p3_main_impl_part2.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_main_impl_part2.hpp @@ -111,13 +111,13 @@ ::p3_main_part2( { constexpr Scalar qsmall = C::QSMALL; constexpr Scalar nsmall = C::NSMALL; - constexpr Scalar T_zerodegc = C::T_zerodegc; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; constexpr Scalar f1r = C::f1r; constexpr Scalar f2r = C::f2r; constexpr Scalar nmltratio = C::nmltratio; - constexpr Scalar inv_cp = C::INV_CP; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar inv_cp = C::INV_CP.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; const bool do_ice_production = runtime_options.do_ice_production; const bool use_hetfrz_classnuc = runtime_options.use_hetfrz_classnuc; diff --git a/components/eamxx/src/physics/p3/impl/p3_main_impl_part3.hpp b/components/eamxx/src/physics/p3/impl/p3_main_impl_part3.hpp index dc1015b4eba4..367159d02a61 100644 --- a/components/eamxx/src/physics/p3/impl/p3_main_impl_part3.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_main_impl_part3.hpp @@ -59,10 +59,10 @@ ::p3_main_part3( const P3Runtime& runtime_options) { constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar inv_cp = C::INV_CP; + constexpr Scalar inv_cp = C::INV_CP.value; constexpr Scalar nsmall = C::NSMALL; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; Kokkos::parallel_for( Kokkos::TeamVectorRange(team, nk_pack), [&] (Int k) { diff --git a/components/eamxx/src/physics/p3/impl/p3_prevent_liq_supersaturation_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_prevent_liq_supersaturation_impl.hpp index 3ca351a2546f..b3c3ffaad791 100644 --- a/components/eamxx/src/physics/p3/impl/p3_prevent_liq_supersaturation_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_prevent_liq_supersaturation_impl.hpp @@ -20,11 +20,11 @@ void Functions::prevent_liq_supersaturation(const Spack& pres, const Spack& { using physics = scream::physics::Functions; - constexpr Scalar inv_cp = C::INV_CP; - constexpr Scalar rv = C::RV; + constexpr Scalar inv_cp = C::INV_CP.value; + constexpr Scalar rv = C::RV.value; constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; Spack qv_sinks, qv_sources, qv_endstep, T_endstep, A, frac; diff --git a/components/eamxx/src/physics/p3/impl/p3_rain_imm_freezing_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_rain_imm_freezing_impl.hpp index f42daad861c8..1b5f136beced 100644 --- a/components/eamxx/src/physics/p3/impl/p3_rain_imm_freezing_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_rain_imm_freezing_impl.hpp @@ -20,11 +20,11 @@ ::rain_immersion_freezing(const Spack& T_atm, const Spack& lamr, const P3Runtime& runtime_options, const Smask& context) { - constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar T_rainfrz = C::T_rainfrz; - constexpr Scalar T_zerodegc = C::T_zerodegc; - constexpr Scalar CONS5 = C::CONS5; - constexpr Scalar CONS6 = C::CONS6; + constexpr Scalar qsmall = C::QSMALL; + constexpr Scalar T_rainfrz = C::T_rainfrz.value; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; + constexpr Scalar CONS5 = C::CONS5; + constexpr Scalar CONS6 = C::CONS6; const Scalar immersion_freezing_exponent = runtime_options.immersion_freezing_exponent; diff --git a/components/eamxx/src/physics/p3/impl/p3_rain_sed_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_rain_sed_impl.hpp index d35fe1a3f1d4..e63ac761cd9b 100644 --- a/components/eamxx/src/physics/p3/impl/p3_rain_sed_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_rain_sed_impl.hpp @@ -154,7 +154,7 @@ ::rain_sedimentation( } Kokkos::single( Kokkos::PerTeam(team), [&] () { - precip_liq_surf += prt_accum * C::INV_RHO_H2O * inv_dt; + precip_liq_surf += prt_accum * C::INV_RHO_H2O.value * inv_dt; }); } diff --git a/components/eamxx/src/physics/p3/impl/p3_rain_self_collection_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_rain_self_collection_impl.hpp index f61aa7f6f0cc..21d329c09067 100644 --- a/components/eamxx/src/physics/p3/impl/p3_rain_self_collection_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_rain_self_collection_impl.hpp @@ -19,7 +19,7 @@ ::rain_self_collection( // (breakup following modified Verlinde and Cotton scheme) constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar rho_h2o = C::RHO_H2O; + constexpr Scalar rho_h2o = C::RHO_H2O.value; constexpr Scalar pi = C::Pi; const Scalar rain_selfcollection_breakup_diameter = diff --git a/components/eamxx/src/physics/p3/impl/p3_table_ice_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_table_ice_impl.hpp index 9b28a4988bc3..7063531c4654 100644 --- a/components/eamxx/src/physics/p3/impl/p3_table_ice_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_table_ice_impl.hpp @@ -98,7 +98,7 @@ ::lookup_rain(const Spack& qr, const Spack& nr, TableRain& tab, // calculate scaled mean size for consistency with ice lookup table Spack dumlr(1); if (gt_small.any()) { - dumlr.set(gt_small, cbrt(qr/(C::Pi * C::RHO_H2O * nr))); + dumlr.set(gt_small, cbrt(qr/(C::Pi * C::RHO_H2O.value * nr))); } tab.dum3 = (log10(1*dumlr) + 5)*sp(10.70415); tab.dumj = IntSmallPack(tab.dum3); diff --git a/components/eamxx/src/physics/p3/impl/p3_update_prognostics_impl.hpp b/components/eamxx/src/physics/p3/impl/p3_update_prognostics_impl.hpp index 3f8893ba50da..208558b5645f 100644 --- a/components/eamxx/src/physics/p3/impl/p3_update_prognostics_impl.hpp +++ b/components/eamxx/src/physics/p3/impl/p3_update_prognostics_impl.hpp @@ -24,8 +24,8 @@ ::update_prognostic_ice( { constexpr Scalar QSMALL = C::QSMALL; constexpr Scalar INV_RHO_RIMEMAX = C::INV_RHO_RIMEMAX; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; if(use_hetfrz_classnuc){ qc.set(context, qc + (-qcheti_cnt-qicnt-qc2qi_collect_tend-qc2qr_ice_shed_tend-qc2qi_berg_tend)*dt); @@ -97,7 +97,7 @@ ::update_prognostic_ice( // and bm such that rho_rim (qm/bm) --> rho_liq during melting. // == - constexpr Scalar INV_CP = C::INV_CP; + constexpr Scalar INV_CP = C::INV_CP.value; if(use_hetfrz_classnuc){ qv.set(context, qv + (-qv2qi_vapdep_tend+qi2qv_sublim_tend-qv2qi_nucleat_tend-qinuc_cnt)*dt); th_atm.set(context, th_atm + inv_exner * ((qv2qi_vapdep_tend - qi2qv_sublim_tend + qv2qi_nucleat_tend+qinuc_cnt) * (latvap+latice) * INV_CP + @@ -125,8 +125,8 @@ ::update_prognostic_liquid( { constexpr Scalar NCCNST = C::NCCNST; constexpr int IPARAM = C::IPARAM; - constexpr Scalar INV_CP = C::INV_CP; - constexpr Scalar latvap = C::LatVap; + constexpr Scalar INV_CP = C::INV_CP.value; + constexpr Scalar latvap = C::LatVap.value; qc.set(context, qc + (-qc2qr_accret_tend-qc2qr_autoconv_tend)*dt); qr.set(context, qr + (qc2qr_accret_tend+qc2qr_autoconv_tend-qr2qv_evap_tend)*dt); diff --git a/components/eamxx/src/physics/p3/tests/infra/p3_ic_cases.cpp b/components/eamxx/src/physics/p3/tests/infra/p3_ic_cases.cpp index 163f736444dd..51cd25511c5e 100644 --- a/components/eamxx/src/physics/p3/tests/infra/p3_ic_cases.cpp +++ b/components/eamxx/src/physics/p3/tests/infra/p3_ic_cases.cpp @@ -70,7 +70,7 @@ P3Data::Ptr make_mixed (const Int ncol, const Int nlev) { for (k = 0; k < nk; ++k) { T_atm(k) = 150 + 150/double(nk)*k; if (i > 0) T_atm(k) += ((i % 3) - 0.5)/double(nk)*k; - d.th_atm(i,k) = T_atm(k)*std::pow(Real(consts::P0/d.pres(i,k)), Real(consts::RD/consts::CP)); + d.th_atm(i,k) = T_atm(k)*std::pow(Real(consts::P0.value/d.pres(i,k)), Real(consts::RD.value/consts::CP.value)); } // The next section modifies inout variables to satisfy weird conditions @@ -112,7 +112,7 @@ P3Data::Ptr make_mixed (const Int ncol, const Int nlev) { d.pres(i,nk-1) + 0.5*(d.pres(i,nk-1) - d.pres(i,nk-2))/(1 - 0) : 0.5*(d.pres(i,k) + d.pres(i,k+1)); const auto dpres = phi - plo; - d.dz(i,k) = consts::RD*T_atm(k)/(g*d.pres(i,k))*dpres; + d.dz(i,k) = consts::RD.value*T_atm(k)/(g*d.pres(i,k))*dpres; } for (k = 0; k < nk; ++k) { d.hetfrz_immersion_nucleation_tend(i,k) = 0.01; diff --git a/components/eamxx/src/physics/p3/tests/p3_calc_rime_density_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_calc_rime_density_unit_tests.cpp index 6fa925a4f375..ce95f4f559ba 100644 --- a/components/eamxx/src/physics/p3/tests/p3_calc_rime_density_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_calc_rime_density_unit_tests.cpp @@ -37,8 +37,8 @@ void run_bfb() // We need to test the calculation under freezing and not-freezing // conditions. - constexpr Scalar t_freezing = 0.9 * C::T_rainfrz, - t_not_freezing = 2.0 * C::T_rainfrz; + constexpr Scalar t_freezing = 0.9 * C::T_rainfrz.value, + t_not_freezing = 2.0 * C::T_rainfrz.value; // Ideally, we'd also test the calculation based on the mass-weighted mean // size Ri--whether it's above or below 8, specifically. Unfortunately, diff --git a/components/eamxx/src/physics/p3/tests/p3_cldliq_imm_freezing_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_cldliq_imm_freezing_unit_tests.cpp index 84edae978aff..4e770e7dcfd9 100644 --- a/components/eamxx/src/physics/p3/tests/p3_cldliq_imm_freezing_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_cldliq_imm_freezing_unit_tests.cpp @@ -29,8 +29,8 @@ void run_bfb() // large enough to affect the warm-phase process rates qc2qr_accret_tend and nc_accret_tend. constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar t_freezing = 0.9 * C::T_rainfrz, - t_not_freezing = 2.0 * C::T_rainfrz; + constexpr Scalar t_freezing = 0.9 * C::T_rainfrz.value, + t_not_freezing = 2.0 * C::T_rainfrz.value; constexpr Scalar qc_incld_small = 0.9 * qsmall; constexpr Scalar qc_incld_not_small = 2.0 * qsmall; constexpr Scalar lamc1 = 0.1, lamc2 = 0.2, lamc3 = 0.3, lamc4 = 0.4; diff --git a/components/eamxx/src/physics/p3/tests/p3_evaporate_rain_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_evaporate_rain_unit_tests.cpp index 20726ea42803..9f8af6f6a30b 100644 --- a/components/eamxx/src/physics/p3/tests/p3_evaporate_rain_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_evaporate_rain_unit_tests.cpp @@ -127,8 +127,8 @@ struct UnitWrap::UnitTest::TestEvapSublPrecip : public UnitWrap::UnitTest: } //end run_property void run_bfb() { - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; //baseline generated data is input to the following //This subroutine has 20 args, only 18 are supplied here for invoking it as last 2 are intent-outs diff --git a/components/eamxx/src/physics/p3/tests/p3_ice_cldliq_wet_growth_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_ice_cldliq_wet_growth_unit_tests.cpp index a4597a3bd986..12d27609663d 100644 --- a/components/eamxx/src/physics/p3/tests/p3_ice_cldliq_wet_growth_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_ice_cldliq_wet_growth_unit_tests.cpp @@ -23,8 +23,8 @@ struct UnitWrap::UnitTest::TestIceCldliqWetGrowth : public UnitWrap::UnitTest { using KTH = KokkosTypes; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; IceWetGrowthData self[max_pack_size] = { // rho,temp,pres,rhofaci,table_val_qi2qr_melting,table_val_qi2qr_vent_melt,latent_heat_vapor,latent_heat_fusion,dv,kap,mu,sc,qv,qc_incld,qi_incld,ni_incld,qr_incld,log_wetgrowth,qr2qi_collect_tend,qc2qi_collect_tend,qc_growth_rate,nr_ice_shed_tend,qc2qr_ice_shed_tend diff --git a/components/eamxx/src/physics/p3/tests/p3_ice_deposition_sublimation_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_ice_deposition_sublimation_tests.cpp index 333676a76268..04259b18a48d 100644 --- a/components/eamxx/src/physics/p3/tests/p3_ice_deposition_sublimation_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_ice_deposition_sublimation_tests.cpp @@ -144,8 +144,8 @@ struct UnitWrap::UnitTest::TestIceDepositionSublimation : public UnitWrap::Un REQUIRE( (d_cxx.qi2qv_sublim_tend==0 || d_cxx.qv + d_cxx.qi2qv_sublim_tend*d_cxx.inv_dt <= d_cxx.qv_sat_i) ); //if T>frz, berg and vapdep should be 0: - REQUIRE( (d_cxx.T_atmm_baseline_action == GENERATE) { diff --git a/components/eamxx/src/physics/p3/tests/p3_ice_melting_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_ice_melting_unit_tests.cpp index 754ff6b5d896..92ffe02102a6 100644 --- a/components/eamxx/src/physics/p3/tests/p3_ice_melting_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_ice_melting_unit_tests.cpp @@ -21,8 +21,8 @@ struct UnitWrap::UnitTest::TestP3IceMelting : public UnitWrap::UnitTest::B { void ice_melting_bfb() { - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; // make array of input data (why not pass actual variables?). Copied 1st 4 rows 4x to fill pack size. IceMeltingData IceMelt[max_pack_size] = { diff --git a/components/eamxx/src/physics/p3/tests/p3_ice_sed_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_ice_sed_unit_tests.cpp index b412d5596876..84367b0bad54 100644 --- a/components/eamxx/src/physics/p3/tests/p3_ice_sed_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_ice_sed_unit_tests.cpp @@ -198,7 +198,7 @@ void run_bfb_ice_sed() void run_bfb_homogeneous_freezing() { - constexpr Scalar latice = C::LatIce; + constexpr Scalar latice = C::LatIce.value; auto engine = Base::get_engine(); @@ -215,7 +215,7 @@ void run_bfb_homogeneous_freezing() // Set up random input data for (auto& d : hfds_baseline) { const auto qsmall_r = std::make_pair(C::QSMALL/2, C::QSMALL*2); - d.randomize(engine, { {d.T_atm, {C::T_homogfrz - 10, C::T_homogfrz + 10}}, {d.qc, qsmall_r}, {d.qr, qsmall_r} }); + d.randomize(engine, { {d.T_atm, {C::T_homogfrz.value - 10, C::T_homogfrz.value + 10}}, {d.qc, qsmall_r}, {d.qr, qsmall_r} }); // C++ impl uses constants for latent_heat values. Manually set here // so F90 can match diff --git a/components/eamxx/src/physics/p3/tests/p3_ice_supersat_conservation_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_ice_supersat_conservation_tests.cpp index 410e59e19cc4..4c5869f0e743 100644 --- a/components/eamxx/src/physics/p3/tests/p3_ice_supersat_conservation_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_ice_supersat_conservation_tests.cpp @@ -15,8 +15,8 @@ struct UnitWrap::UnitTest::TestIceSupersatConservation : public UnitWrap::Uni void run_bfb() { - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; auto engine = Base::get_engine(); diff --git a/components/eamxx/src/physics/p3/tests/p3_main_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_main_unit_tests.cpp index 583a39330c3d..a717ceff50c8 100644 --- a/components/eamxx/src/physics/p3/tests/p3_main_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_main_unit_tests.cpp @@ -51,11 +51,11 @@ void run_bfb_p3_main_part1() auto engine = Base::get_engine(); constexpr Scalar qsmall = C::QSMALL; //PMC wouldn't it make more sense to define qsmall at a higher level since used in part1, part2, and part3? - constexpr Scalar T_zerodegc = C::T_zerodegc; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; constexpr Scalar sup_upper = -0.05; constexpr Scalar sup_lower = -0.1; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; P3MainPart1Data isds_baseline[] = { // kts, kte, ktop, kbot, kdir, do_predict_nc, do_prescribed_CCN, dt @@ -159,11 +159,11 @@ void run_bfb_p3_main_part2() auto engine = Base::get_engine(); constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar T_zerodegc = C::T_zerodegc; + constexpr Scalar T_zerodegc = C::T_zerodegc.value; constexpr Scalar sup_upper = -0.05; constexpr Scalar sup_lower = -0.1; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; P3MainPart2Data isds_baseline[] = { // kts, kte, ktop, kbot, kdir, do_predict_nc, do_prescribed_CCN, dt @@ -297,8 +297,8 @@ void run_bfb_p3_main_part2() void run_bfb_p3_main_part3() { - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; auto engine = Base::get_engine(); diff --git a/components/eamxx/src/physics/p3/tests/p3_prevent_liq_supersaturation_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_prevent_liq_supersaturation_tests.cpp index df3fd222ea26..3f672064f88a 100644 --- a/components/eamxx/src/physics/p3/tests/p3_prevent_liq_supersaturation_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_prevent_liq_supersaturation_tests.cpp @@ -21,9 +21,9 @@ struct UnitWrap::UnitTest::TestPreventLiqSupersaturation : public UnitWrap::U using physics = scream::physics::Functions; - constexpr Scalar inv_cp = C::INV_CP; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar inv_cp = C::INV_CP.value; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; //Start with reasonable values //============================ @@ -87,8 +87,8 @@ struct UnitWrap::UnitTest::TestPreventLiqSupersaturation : public UnitWrap::U void run_bfb() { - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; auto engine = Base::get_engine(); diff --git a/components/eamxx/src/physics/p3/tests/p3_rain_imm_freezing_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_rain_imm_freezing_unit_tests.cpp index d41d30770ce9..7b688ba6ac27 100644 --- a/components/eamxx/src/physics/p3/tests/p3_rain_imm_freezing_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_rain_imm_freezing_unit_tests.cpp @@ -29,8 +29,8 @@ void run_bfb() // large enough to affect the warm-phase process rates qc2qr_accret_tend and nc_accret_tend. constexpr Scalar qsmall = C::QSMALL; - constexpr Scalar t_freezing = 0.9 * C::T_rainfrz, - t_not_freezing = 2.0 * C::T_rainfrz; + constexpr Scalar t_freezing = 0.9 * C::T_rainfrz.value, + t_not_freezing = 2.0 * C::T_rainfrz.value; constexpr Scalar qr_incld_small = 0.9 * qsmall; constexpr Scalar qr_incld_not_small = 2.0 * qsmall; constexpr Scalar lamr1 = 0.1, lamr2 = 0.2, lamr3 = 0.3, lamr4 = 0.4; diff --git a/components/eamxx/src/physics/p3/tests/p3_unit_tests.cpp b/components/eamxx/src/physics/p3/tests/p3_unit_tests.cpp index 03a4462a7049..33baa8746816 100644 --- a/components/eamxx/src/physics/p3/tests/p3_unit_tests.cpp +++ b/components/eamxx/src/physics/p3/tests/p3_unit_tests.cpp @@ -528,8 +528,8 @@ struct UnitWrap::UnitTest::TestP3UpdatePrognosticIce : public UnitWrap::UnitT constexpr Scalar nmltratio = C::nmltratio; constexpr Scalar dt = 1.8000E+03; constexpr bool do_predict_nc = true; - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; //baseline generated data is input to the following P3UpdatePrognosticIceData pupidc[max_pack_size] = { @@ -766,8 +766,8 @@ template struct UnitWrap::UnitTest::TestGetTimeSpacePhysVariables : public UnitWrap::UnitTest::Base { void get_time_space_phys_variables_unit_bfb_tests() { - constexpr Scalar latvap = C::LatVap; - constexpr Scalar latice = C::LatIce; + constexpr Scalar latvap = C::LatVap.value; + constexpr Scalar latice = C::LatIce.value; //baseline generated data is input to the following GetTimeSpacePhysVarsData gtspvd[max_pack_size] = { @@ -886,7 +886,7 @@ template struct UnitWrap::UnitTest::TestP3UpdatePrognosticLiq : public UnitWrap::UnitTest::Base { void update_prognostic_liquid_unit_bfb_tests() { - constexpr Scalar latvap = C::LatVap; + constexpr Scalar latvap = C::LatVap.value; //baseline generated data is input to the following P3UpdatePrognosticLiqData pupldc[max_pack_size] = { diff --git a/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_interface.hpp b/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_interface.hpp index 4bd8a9ef258d..13131fa070b8 100644 --- a/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_interface.hpp +++ b/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_interface.hpp @@ -1217,7 +1217,7 @@ static void compute_aerocom_cloudtop( * from grid-mean to in-cloud, but after that, the * calculation follows the general logic */ auto cdnc = nc(icol, ilay) * p_del(icol, ilay) / - z_del(icol, ilay) / physconst::gravit / + z_del(icol, ilay) / physconst::gravit.value / cldfrac_tot(icol, ilay); cdnc_at_cldtop(icol) += cdnc * aerocom_phi * aerocom_wts; // eff_radius_qc_at_cldtop @@ -1264,7 +1264,7 @@ static void mixing_ratio_to_cloud_mass( if (cloud_fraction(icol,ilay) > 0) { // Compute layer-integrated cloud mass (per unit area) auto incloud_mixing_ratio = std::min(mixing_ratio(icol,ilay) / std::max(0.0001, cloud_fraction(icol,ilay)), 0.005); - cloud_mass(icol,ilay) = incloud_mixing_ratio * dp(icol,ilay) / physconst::gravit; + cloud_mass(icol,ilay) = incloud_mixing_ratio * dp(icol,ilay) / physconst::gravit.value; } else { cloud_mass(icol,ilay) = 0; } diff --git a/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_process_interface.cpp b/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_process_interface.cpp index 5591c7491e5d..301f810c5f78 100644 --- a/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_process_interface.cpp +++ b/components/eamxx/src/physics/rrtmgp/eamxx_rrtmgp_process_interface.cpp @@ -631,7 +631,7 @@ void RRTMGPRadiation::run_impl (const double dt) { auto d_eff_radius_qi_at_cldtop = get_field_out("eff_radius_qi_at_cldtop").get_view(); - constexpr auto stebol = PC::stebol; + constexpr auto stebol = PC::stebol.value; const auto nlay = m_nlay; const auto nlwbands = m_nlwbands; const auto nswbands = m_nswbands; @@ -713,7 +713,7 @@ void RRTMGPRadiation::run_impl (const double dt) { m_co2vmr, m_n2ovmr, m_ch4vmr, m_f11vmr, m_f12vmr ); // Back out volume mixing ratios - const auto air_mol_weight = PC::MWdry; + const auto air_mol_weight = PC::MWdry.value; const auto policy = TPF::get_default_team_policy(m_ncol, m_nlay); Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { const int i = team.league_rank(); diff --git a/components/eamxx/src/physics/rrtmgp/rrtmgp_utils.hpp b/components/eamxx/src/physics/rrtmgp/rrtmgp_utils.hpp index 33ab496c1141..e257beaec87d 100644 --- a/components/eamxx/src/physics/rrtmgp/rrtmgp_utils.hpp +++ b/components/eamxx/src/physics/rrtmgp/rrtmgp_utils.hpp @@ -33,7 +33,7 @@ void compute_heating_rate ( heating_rate(icol,ilay) = ( flux_up(icol,ilay+1) - flux_up(icol,ilay) - flux_dn(icol,ilay+1) + flux_dn(icol,ilay) - ) * physconst::gravit / (physconst::Cpair * pdel(icol,ilay)); + ) * physconst::gravit.value / (physconst::Cpair.value * pdel(icol,ilay)); )); } diff --git a/components/eamxx/src/physics/rrtmgp/tests/rrtmgp_unit_tests.cpp b/components/eamxx/src/physics/rrtmgp/tests/rrtmgp_unit_tests.cpp index e60b14b20d3f..047e4621125c 100644 --- a/components/eamxx/src/physics/rrtmgp/tests/rrtmgp_unit_tests.cpp +++ b/components/eamxx/src/physics/rrtmgp/tests/rrtmgp_unit_tests.cpp @@ -60,8 +60,8 @@ TEST_CASE("rrtmgp_test_heating_k") { flux_dn(0, 1) = 0.5; }); using physconst = scream::physics::Constants; - auto g = physconst::gravit; //9.81; - auto cp_air = physconst::Cpair; //1005.0; + auto g = physconst::gravit.value; //9.81; + auto cp_air = physconst::Cpair.value; //1005.0; auto pdel = chc(dp)(0,0); auto heating_ref = 1.0 * g / (cp_air * pdel); scream::rrtmgp::compute_heating_rate(flux_up, flux_dn, dp, heating); @@ -103,7 +103,7 @@ TEST_CASE("rrtmgp_test_mixing_ratio_to_cloud_mass_k") { mixing_ratio(0,0) = 0.0001; cloud_fraction(0,0) = 1.0; }); - auto cloud_mass_ref = chc(mixing_ratio)(0,0) / chc(cloud_fraction)(0,0) * chc(dp)(0,0) / physconst::gravit; + auto cloud_mass_ref = chc(mixing_ratio)(0,0) / chc(cloud_fraction)(0,0) * chc(dp)(0,0) / physconst::gravit.value; interface_t::mixing_ratio_to_cloud_mass(mixing_ratio, cloud_fraction, dp, cloud_mass); REQUIRE(chc(cloud_mass)(0,0) == cloud_mass_ref); @@ -135,7 +135,7 @@ TEST_CASE("rrtmgp_test_mixing_ratio_to_cloud_mass_k") { mixing_ratio(0,0) = 0.0001; cloud_fraction(0,0) = 0.5; }); - cloud_mass_ref = chc(mixing_ratio)(0,0) / chc(cloud_fraction)(0,0) * chc(dp)(0,0) / physconst::gravit; + cloud_mass_ref = chc(mixing_ratio)(0,0) / chc(cloud_fraction)(0,0) * chc(dp)(0,0) / physconst::gravit.value; interface_t::mixing_ratio_to_cloud_mass(mixing_ratio, cloud_fraction, dp, cloud_mass); REQUIRE(chc(cloud_mass)(0,0) == cloud_mass_ref); diff --git a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp index 22a244babc52..09b16d77c1e7 100644 --- a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp +++ b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp @@ -456,7 +456,7 @@ void SHOCMacrophysics::initialize_impl (const RunType run_type) const auto s_pref_mid = ekat::scalarize(pref_mid); const auto hyam = m_grid->get_geometry_data("hyam").get_view(); const auto hybm = m_grid->get_geometry_data("hybm").get_view(); - const auto ps0 = C::P0; + const auto ps0 = C::P0.value; const auto psref = ps0; Kokkos::parallel_for(Kokkos::RangePolicy<>(0, m_num_levs), KOKKOS_LAMBDA (const int lev) { s_pref_mid(lev) = ps0*hyam(lev) + psref*hybm(lev); @@ -610,7 +610,7 @@ void SHOCMacrophysics::check_flux_state_consistency(const double dt) using RU = ekat::ReductionUtils; using TPF = ekat::TeamPolicyFactory; - const Real gravit = PC::gravit; + const Real gravit = PC::gravit.value; const Real qmin = 1e-12; // minimum permitted constituent concentration (kg/kg) const auto& pseudo_density = get_field_in ("pseudo_density").get_view(); diff --git a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.hpp b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.hpp index b94806a0033e..4f46b4575541 100644 --- a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.hpp +++ b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.hpp @@ -78,8 +78,8 @@ class SHOCMacrophysics : public scream::AtmosphereProcess const int i = team.league_rank(); const Real zvir = C::ZVIR; - const Real cpair = C::Cpair; - const Real ggr = C::gravit; + const Real cpair = C::Cpair.value; + const Real ggr = C::gravit.value; const Real inv_ggr = 1/ggr; const Real mintke = SC::mintke; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_adv_sgs_tke_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_adv_sgs_tke_impl.hpp index 0f03b72ca238..0a94896d7a39 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_adv_sgs_tke_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_adv_sgs_tke_impl.hpp @@ -29,7 +29,7 @@ ::adv_sgs_tke( { //Shared constants - static constexpr Scalar ggr = C::gravit; + static constexpr Scalar ggr = C::gravit.value; static constexpr Scalar basetemp = C::basetemp; static constexpr Scalar mintke = scream::shoc::Constants::mintke; static constexpr Scalar maxtke = scream::shoc::Constants::maxtke; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_buoyancy_flux_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_buoyancy_flux_impl.hpp index 7a0633fe7f34..c897ca319d1e 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_buoyancy_flux_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_buoyancy_flux_impl.hpp @@ -22,13 +22,13 @@ void Functions::shoc_assumed_pdf_compute_buoyancy_flux( const Spack& wqls, Spack& wthv_sec) { - const Scalar basepres = C::P0; - const Scalar rair = C::Rair; - const Scalar rv = C::RV; - const Scalar cp = C::CP; - const Scalar lcond = C::LatVap; + const Scalar basepres = C::P0.value; + const Scalar rair = C::Rair.value; + const Scalar rv = C::RV.value; + const Scalar cp = C::CP.value; + const Scalar lcond = C::LatVap.value; const Scalar basetemp = C::basetemp; - const Scalar epsterm = rair/rv; + const Scalar epsterm = rair/rv; wthv_sec = wthlsec + ((1 - epsterm)/epsterm)*basetemp*wqwsec + ((lcond/cp)*ekat::pow(basepres/pval, (rair/cp)) diff --git a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_qs_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_qs_impl.hpp index 867ffe3fed3a..87fd45575a78 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_qs_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_qs_impl.hpp @@ -26,10 +26,10 @@ void Functions::shoc_assumed_pdf_compute_qs( Spack& qs2, Spack& beta2) { - const Scalar rair = C::Rair; - const Scalar rv = C::RV; - const Scalar cp = C::CP; - const Scalar lcond = C::LatVap; + const Scalar rair = C::Rair.value; + const Scalar rv = C::RV.value; + const Scalar cp = C::CP.value; + const Scalar lcond = C::LatVap.value; // Compute MurphyKoop_svp const int liquid = 0; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_s_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_s_impl.hpp index 5794e21456f7..e0c1655ee150 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_s_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_s_impl.hpp @@ -30,11 +30,11 @@ void Functions::shoc_assumed_pdf_compute_s( Spack& qn, Spack& C) { - const Scalar rair = C::Rair; - const Scalar basepres = C::P0; - const Scalar cp = C::CP; - const Scalar lcond = C::LatVap; - const Scalar pi = C::Pi; + const Scalar rair = C::Rair.value; + const Scalar basepres = C::P0.value; + const Scalar cp = C::CP.value; + const Scalar lcond = C::LatVap.value; + const Scalar pi = C::Pi; const Scalar sqrt2(std::sqrt(Scalar(2.0))), sqrt2pi(std::sqrt(2*pi)); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_temperature_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_temperature_impl.hpp index e60a744ae93f..afa9ab022722 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_temperature_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_assumed_pdf_compute_temperature_impl.hpp @@ -20,9 +20,9 @@ void Functions::shoc_assumed_pdf_compute_temperature( const Spack& pval, Spack& Tl1) { - constexpr Scalar basepres = C::P0; - constexpr Scalar rair = C::Rair; - constexpr Scalar cp = C::CP; + constexpr Scalar basepres = C::P0.value; + constexpr Scalar rair = C::Rair.value; + constexpr Scalar cp = C::CP.value; Tl1 = thl1/(ekat::pow(basepres/pval,(rair/cp))); } diff --git a/components/eamxx/src/physics/shoc/impl/shoc_compute_brunt_shoc_length_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_compute_brunt_shoc_length_impl.hpp index ead80527ebea..43dc57462aec 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_compute_brunt_shoc_length_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_compute_brunt_shoc_length_impl.hpp @@ -17,7 +17,7 @@ void Functions::compute_brunt_shoc_length( const uview_1d& thv_zi, const uview_1d& brunt) { - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const auto s_thv_zi = scalarize(thv_zi); const Int nlev_pack = ekat::npack(nlev); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_compute_diag_third_shoc_moment_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_compute_diag_third_shoc_moment_impl.hpp index 7fdd402e4486..0c1105fb160d 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_compute_diag_third_shoc_moment_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_compute_diag_third_shoc_moment_impl.hpp @@ -27,7 +27,7 @@ ::compute_diag_third_shoc_moment( const uview_1d& thetal_zi, const uview_1d& w3) { - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const Int nlev_pack = ekat::npack(nlev); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_compute_shoc_temperature_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_compute_shoc_temperature_impl.hpp index c8f269a0662f..cb28eadfc8c9 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_compute_shoc_temperature_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_compute_shoc_temperature_impl.hpp @@ -25,8 +25,8 @@ void Functions::compute_shoc_temperature( const uview_1d& tabs) { - const Scalar cp = C::CP; - const Scalar lcond = C::LatVap; + const Scalar cp = C::CP.value; + const Scalar lcond = C::LatVap.value; const Int nlev_pack = ekat::npack(nlev); Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev_pack), [&] (const Int& k) { diff --git a/components/eamxx/src/physics/shoc/impl/shoc_compute_tmpi_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_compute_tmpi_impl.hpp index 9978424c858c..a4017b4b15f5 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_compute_tmpi_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_compute_tmpi_impl.hpp @@ -17,7 +17,7 @@ ::compute_tmpi( const uview_1d& dz_zi, const uview_1d& tmpi) { - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; tmpi(0)[0] = 0; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_diag_obklen_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_diag_obklen_impl.hpp index 65ccff147fdd..f79cc7013bb6 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_diag_obklen_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_diag_obklen_impl.hpp @@ -26,11 +26,11 @@ void Functions::shoc_diag_obklen( Scalar& obklen) { // Constants - const auto cp = C::CP; - const auto lcond = C::LatVap; + const auto cp = C::CP.value; + const auto lcond = C::LatVap.value; const auto eps = C::ZVIR; const auto ustar_min = SC::ustar_min; - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const auto vk = C::Karman; // Local variables diff --git a/components/eamxx/src/physics/shoc/impl/shoc_diag_second_moments_srf_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_diag_second_moments_srf_impl.hpp index ce7809a725da..25e282b7cdc2 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_diag_second_moments_srf_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_diag_second_moments_srf_impl.hpp @@ -23,7 +23,7 @@ ::shoc_diag_second_moments_srf( const auto one = C::ONE; const auto zero = C::ZERO; const auto third = C::THIRD; - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const auto basetemp = C::basetemp; ustar2 = std::sqrt(uw_sfc*uw_sfc+vw_sfc*vw_sfc); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_dp_inverse_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_dp_inverse_impl.hpp index 8aa372b4e6aa..036dfd848f99 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_dp_inverse_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_dp_inverse_impl.hpp @@ -16,7 +16,7 @@ ::dp_inverse( const uview_1d& dz_zt, const uview_1d& rdp_zt) { - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const Int nlev_pack = ekat::npack(nlev); Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev_pack), [&] (const Int& k) { diff --git a/components/eamxx/src/physics/shoc/impl/shoc_energy_fixer_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_energy_fixer_impl.hpp index 72d3560ae234..9031a9a0675d 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_energy_fixer_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_energy_fixer_impl.hpp @@ -45,11 +45,11 @@ void Functions::shoc_energy_fixer( auto rho_zi = workspace.take("rho_zi"); // Constants - const auto cp = C::CP; - const auto lcond = C::LatVap; - const auto lice = C::LatIce; + const auto cp = C::CP.value; + const auto lcond = C::LatVap.value; + const auto lice = C::LatIce.value; const auto mintke = SC::mintke; - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; // Local variables Scalar te_a = 0; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_energy_integrals_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_energy_integrals_impl.hpp index 558f2663d6ce..a2806a92289d 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_energy_integrals_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_energy_integrals_impl.hpp @@ -27,7 +27,7 @@ ::shoc_energy_integrals( { using RU = ekat::ReductionUtils; - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; // The team_barriers protect what we think is unexpected behavior in // Kokkos::parallel_reduce. We expect not to need these based on the semantics diff --git a/components/eamxx/src/physics/shoc/impl/shoc_grid_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_grid_impl.hpp index 353d4dd99bd1..545797d7601e 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_grid_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_grid_impl.hpp @@ -30,7 +30,7 @@ void Functions::shoc_grid( const uview_1d& dz_zi, const uview_1d& rho_zt) { - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const auto s_zi_grid = ekat::scalarize(zi_grid); const auto s_zt_grid = ekat::scalarize(zt_grid); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_isotropic_ts_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_isotropic_ts_impl.hpp index 40f6ef1e2740..a934a6ab31ff 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_isotropic_ts_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_isotropic_ts_impl.hpp @@ -29,7 +29,7 @@ ::isotropic_ts( { //constants from share/physics - static constexpr Scalar ggr = C::gravit; + static constexpr Scalar ggr = C::gravit.value; //Declare constants const Scalar lambda_low = lambda_low_in; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_pblintd_height_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_pblintd_height_impl.hpp index 19c83c48446f..c450ddfca88f 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_pblintd_height_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_pblintd_height_impl.hpp @@ -33,7 +33,7 @@ void Functions::pblintd_height( if (!check) return; - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const Scalar tiny = 1e-36; const Scalar fac = 100; const Scalar ricr = 0.3; diff --git a/components/eamxx/src/physics/shoc/impl/shoc_pblintd_init_pot_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_pblintd_init_pot_impl.hpp index 4a53c9816263..3b9ed04093ea 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_pblintd_init_pot_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_pblintd_init_pot_impl.hpp @@ -17,10 +17,10 @@ ::shoc_pblintd_init_pot( const view_1d& thv) { // Compute virtual potential temperature - const auto lcond = C::LatVap; - const auto cp = C::Cpair; - const auto eps = C::ZVIR; - const auto one = C::ONE; + const auto lcond = C::LatVap.value; + const auto cp = C::Cpair.value; + const auto eps = C::ZVIR; + const auto one = C::ONE; const Int nlev_pack = ekat::npack(nlev); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_tridiag_solver_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_tridiag_solver_impl.hpp index 1ec45e481d70..ee21aa49c88f 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_tridiag_solver_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_tridiag_solver_impl.hpp @@ -22,7 +22,7 @@ void Functions::vd_shoc_decomp( const uview_1d& dl, const uview_1d& d) { - const auto ggr = C::gravit; + const auto ggr = C::gravit.value; const auto skv_term = scalarize(kv_term); const auto stmpi = scalarize(tmpi); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_update_host_dse_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_update_host_dse_impl.hpp index ddebe8ab588a..e54da1c31e82 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_update_host_dse_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_update_host_dse_impl.hpp @@ -22,9 +22,9 @@ ::update_host_dse( const Int nlev_pack = ekat::npack(nlev); // Constants used - const auto lcond = C::LatVap; - const auto cp = C::CP; - const auto ggr = C::gravit; + const auto lcond = C::LatVap.value; + const auto cp = C::CP.value; + const auto ggr = C::gravit.value; Kokkos::parallel_for(Kokkos::TeamVectorRange(team, nlev_pack), [&] (const Int& k) { Spack temp = (thlm(k)/inv_exner(k))+(lcond/cp)*shoc_ql(k); diff --git a/components/eamxx/src/physics/shoc/impl/shoc_update_prognostics_implicit_impl.hpp b/components/eamxx/src/physics/shoc/impl/shoc_update_prognostics_implicit_impl.hpp index 68ffa9e6265b..6f11b43f3308 100644 --- a/components/eamxx/src/physics/shoc/impl/shoc_update_prognostics_implicit_impl.hpp +++ b/components/eamxx/src/physics/shoc/impl/shoc_update_prognostics_implicit_impl.hpp @@ -132,7 +132,7 @@ void Functions::update_prognostics_implicit( // compute surface fluxes for liq. potential temp, water and tke { - const auto cmnfac = dtime*(C::gravit*rho_zi_s(nlevi-1)*rdp_zt_s(nlev-1)); + const auto cmnfac = dtime*(C::gravit.value*rho_zi_s(nlevi-1)*rdp_zt_s(nlev-1)); Kokkos::single(Kokkos::PerTeam(team), [&] () { thetal_s(nlev-1) += cmnfac*wthl_sfc; qw_s(nlev-1) += cmnfac*wqw_sfc; diff --git a/components/eamxx/src/physics/shoc/tests/infra/shoc_ic_cases.cpp b/components/eamxx/src/physics/shoc/tests/infra/shoc_ic_cases.cpp index e551ef3d8498..13b97eb68db6 100644 --- a/components/eamxx/src/physics/shoc/tests/infra/shoc_ic_cases.cpp +++ b/components/eamxx/src/physics/shoc/tests/infra/shoc_ic_cases.cpp @@ -112,8 +112,8 @@ void compute_column_pressure(Int col, Int nlev, const Array2& z, Array2& pres) { using consts = scream::physics::Constants; const Int i = col; - const Real k = consts::Rair / consts::Cpair; - const Real c = -consts::gravit * pow(consts::P0, k) / consts::Rair; + const Real k = consts::Rair.value / consts::Cpair.value; + const Real c = -consts::gravit.value * pow(consts::P0.value, k) / consts::Rair.value; const Real p_s = surface_pressure; // Move up the column, computing the pressures at each elevation. @@ -167,7 +167,7 @@ FortranData::Ptr make_standard(const Int shcol, Int nlev, Int num_qtracers) { const Real ql = interpolate_data(z_ref, ql_ref, zt); d.qw(i, k) = qw; d.shoc_ql(i, k) = ql; - Real zvir = (consts::RH2O / consts::Rair) - 1.0; + Real zvir = (consts::RH2O.value / consts::Rair.value) - 1.0; d.thv(i, k) = theta_zt * (1.0 + zvir * qw); d.thetal(i, k) = theta_zt; @@ -202,9 +202,9 @@ FortranData::Ptr make_standard(const Int shcol, Int nlev, Int num_qtracers) { // Compute pressure differences and host_dse * exner. for (Int k = 0; k < nlev; ++k) { d.pdel(i, k) = std::abs(d.presi(i, k+1) - d.presi(i, k)); - d.inv_exner(i, k) = 1/pow(d.pres(i, k)/consts::P0, consts::Rair/consts::Cpair); - d.host_dse(i, k) = consts::Cpair * d.thv(i, k)/d.inv_exner(i, k) + - consts::gravit * d.zt_grid(i, k); + d.inv_exner(i, k) = 1/pow(d.pres(i, k)/consts::P0.value, consts::Rair.value/consts::Cpair.value); + d.host_dse(i, k) = consts::Cpair.value * d.thv(i, k)/d.inv_exner(i, k) + + consts::gravit.value * d.zt_grid(i, k); } // Zero the other input fields. diff --git a/components/eamxx/src/physics/shoc/tests/infra/shoc_test_data.hpp b/components/eamxx/src/physics/shoc/tests/infra/shoc_test_data.hpp index 9e9aeb6d9a5c..75aca9b82e34 100644 --- a/components/eamxx/src/physics/shoc/tests/infra/shoc_test_data.hpp +++ b/components/eamxx/src/physics/shoc/tests/infra/shoc_test_data.hpp @@ -750,8 +750,8 @@ struct ShocMainData : public ShocTestGridDataBase { void compute_column_pressure(Int shcol, Int nlev, const Real* z, Real* pres) { using consts = scream::physics::Constants; - const Real k = consts::Rair / consts::Cpair; - const Real c = -consts::gravit * pow(consts::P0, k) / consts::Rair; + const Real k = consts::Rair.value / consts::Cpair.value; + const Real c = -consts::gravit.value * pow(consts::P0.value, k) / consts::Rair.value; const Real p_s = 1015e2; const std::array z_ref = {0.0, 520.0, 1480.0, 2000.0, 3000.0}; @@ -801,14 +801,14 @@ struct ShocMainData : public ShocTestGridDataBase { const auto nlevi_offset = i * nlevi; for (auto k = decltype(nlev){0}; k < nlev; ++k) { pdel[nlev_offset + k] = std::abs(presi[nlevi_offset + k] - presi[nlevi_offset + k+1]); - inv_exner[nlev_offset + k] = pow(pres[nlev_offset + k]/consts::P0, consts::Rair/consts::Cpair); - host_dse[nlev_offset + k] = consts::Cpair * inv_exner[nlev_offset + k] * thv[nlev_offset + k] + - consts::gravit * zt_grid[nlev_offset + k]; + inv_exner[nlev_offset + k] = pow(pres[nlev_offset + k]/consts::P0.value, consts::Rair.value/consts::Cpair.value); + host_dse[nlev_offset + k] = consts::Cpair.value * inv_exner[nlev_offset + k] * thv[nlev_offset + k] + + consts::gravit.value * zt_grid[nlev_offset + k]; const Real qv = qw[nlev_offset+k] - shoc_ql[nlev_offset+k]; - thetal[nlev_offset+k] = pot_temp - (consts::LatVap/consts::Cpair)*shoc_ql[nlev_offset+k]; + thetal[nlev_offset+k] = pot_temp - (consts::LatVap.value/consts::Cpair.value)*shoc_ql[nlev_offset+k]; thv[nlev_offset+k] = pot_temp * (1 + 0.61*qv - shoc_ql[nlev_offset+k]); - inv_exner[nlev_offset+k] = 1/std::pow(pres[nlev_offset+k]/consts::P0,consts::Rair/consts::Cpair); + inv_exner[nlev_offset+k] = 1/std::pow(pres[nlev_offset+k]/consts::P0.value,consts::Rair.value/consts::Cpair.value); } } diff --git a/components/eamxx/src/physics/shoc/tests/shoc_energy_fixer_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_energy_fixer_tests.cpp index 41815f6dfd28..aa64ad55ee81 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_energy_fixer_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_energy_fixer_tests.cpp @@ -24,8 +24,8 @@ struct UnitWrap::UnitTest::TestShocEnergyFixer : public UnitWrap::UnitTest void run_property() { - static constexpr Real gravit = scream::physics::Constants::gravit; - static constexpr Real Cpair = scream::physics::Constants::Cpair; + static constexpr Real gravit = scream::physics::Constants::gravit.value; + static constexpr Real Cpair = scream::physics::Constants::Cpair.value; static constexpr Real mintke = scream::shoc::Constants::mintke; static constexpr Int shcol = 3; static constexpr Int nlev = 5; diff --git a/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp index 09bb520b1f60..3d92f52e3575 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp @@ -24,7 +24,7 @@ struct UnitWrap::UnitTest::TestShocGrid : public UnitWrap::UnitTest::Base void run_property() { - static constexpr Real gravit = scream::physics::Constants::gravit; + static constexpr Real gravit = scream::physics::Constants::gravit.value; static constexpr Int shcol = 2; static constexpr Int nlev = 5; static constexpr auto nlevi = nlev + 1; diff --git a/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp index 6bbf0822481f..f3d78be4ab76 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_main_tests.cpp @@ -20,11 +20,11 @@ struct UnitWrap::UnitTest::TestShocMain : public UnitWrap::UnitTest::Base static constexpr Real minlen = scream::shoc::Constants::minlen; static constexpr Real maxlen = scream::shoc::Constants::maxlen; static constexpr Real maxiso = scream::shoc::Constants::maxiso; - static constexpr Real Cpair = scream::physics::Constants::Cpair; - static constexpr Real gravit = scream::physics::Constants::gravit; - static constexpr Real LatVap = scream::physics::Constants::LatVap; - static constexpr Real Rair = scream::physics::Constants::Rair; - static constexpr Real p0 = scream::physics::Constants::P0; + static constexpr Real Cpair = scream::physics::Constants::Cpair.value; + static constexpr Real gravit = scream::physics::Constants::gravit.value; + static constexpr Real LatVap = scream::physics::Constants::LatVap.value; + static constexpr Real Rair = scream::physics::Constants::Rair.value; + static constexpr Real p0 = scream::physics::Constants::P0.value; static constexpr Int shcol = 5; static constexpr Int nlev = 5; diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp index f9f680b6605c..3ceb0fcf8fbd 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp @@ -34,7 +34,7 @@ struct UnitWrap::UnitTest::TestShocPdfComputeTemp { // Input liquid water potential temperature [K] static constexpr Real thl1 = 305; // Input basepressure [Pa] - static constexpr Real basepres = C::P0; + static constexpr Real basepres = C::P0.value; // Input value of pval [Pa] Real pval = 110000; diff --git a/components/eamxx/src/physics/tms/impl/compute_tms_impl.hpp b/components/eamxx/src/physics/tms/impl/compute_tms_impl.hpp index 3ab7b8844beb..2b5488a405f0 100644 --- a/components/eamxx/src/physics/tms/impl/compute_tms_impl.hpp +++ b/components/eamxx/src/physics/tms/impl/compute_tms_impl.hpp @@ -23,14 +23,14 @@ void Functions::compute_tms( using C = physics::Constants; // Define some constants used - const Scalar horomin = 1; // Minimum value of subgrid orographic height for mountain stress [ m ] - const Scalar z0max = 100; // Maximum value of z_0 for orography [ m ] - const Scalar dv2min = 0.01; // Minimum shear squared [ m2/s2 ] - const Scalar orocnst = C::orocnst; // Converts from standard deviation to height [ no unit ] - const Scalar z0fac = C::z0fac; // Factor determining z_0 from orographic standard deviation [ no unit ] - const Scalar karman = C::Karman; // von Karman constant - const Scalar gravit = C::gravit; // Acceleration due to gravity - const Scalar rair = C::Rair; // Gas constant for dry air + const Scalar horomin = 1; // Minimum value of subgrid orographic height for mountain stress [ m ] + const Scalar z0max = 100; // Maximum value of z_0 for orography [ m ] + const Scalar dv2min = 0.01; // Minimum shear squared [ m2/s2 ] + const Scalar orocnst = C::orocnst; // Converts from standard deviation to height [ no unit ] + const Scalar z0fac = C::z0fac; // Factor determining z_0 from orographic standard deviation [ no unit ] + const Scalar karman = C::Karman; // von Karman constant + const Scalar gravit = C::gravit.value; // Acceleration due to gravity + const Scalar rair = C::Rair.value; // Gas constant for dry air // Loop over columns const typename KT::RangePolicy policy (0,ncols); diff --git a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp index 37a435426fec..6c854f5b1200 100644 --- a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp +++ b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp @@ -259,8 +259,8 @@ void ZMDeepConvection::run_impl (const double dt) // accumulate surface precipitation fluxes Kokkos::parallel_for("zm_update_precip",KT::RangePolicy(0, m_ncol), KOKKOS_LAMBDA (const int i) { auto prec_liq = loc_zm_output_prec(i) - loc_zm_output_snow(i); - precip_liq_surf_mass(i) += ekat::impl::max(0.0,prec_liq) * PC::RHO_H2O * dt; - precip_ice_surf_mass(i) += loc_zm_output_snow(i) * PC::RHO_H2O * dt; + precip_liq_surf_mass(i) += ekat::impl::max(0.0,prec_liq) * PC::RHO_H2O.value * dt; + precip_ice_surf_mass(i) += loc_zm_output_snow(i) * PC::RHO_H2O.value * dt; }); Kokkos::parallel_for("zm_update_prognostic",KT::RangePolicy(0, m_ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int idx) { diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 9c77fc274c69..d079195df0d2 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -207,8 +207,8 @@ struct Functions { } // ------------------------------------------------------------------------- void calculate_tpert(int ncol,int nlev,bool is_first_step) { - const Real cpair = PC::Cpair; - const Real latvap = PC::LatVap; + const Real cpair = PC::Cpair.value; + const Real latvap = PC::LatVap.value; // create temporaries to avoid "Implicit capture" warning auto loc_tpert = tpert; diff --git a/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp b/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp index c6a9fbfcc66d..b93f657e127a 100644 --- a/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp +++ b/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp @@ -209,8 +209,8 @@ TEST_CASE("rrtmgp_scream_standalone_k", "") { auto nc = real2dk("nc", ncol, nlay); auto qi = real2dk("qi", ncol, nlay); Kokkos::parallel_for(MDRP::template get<2>({nlay,ncol}), KOKKOS_LAMBDA(int ilay, int icol) { - qc(icol,ilay) = 1e-3 * lwp(icol,ilay) * cld(icol,ilay) * PC::gravit / p_del(icol,ilay); - qi(icol,ilay) = 1e-3 * iwp(icol,ilay) * cld(icol,ilay) * PC::gravit / p_del(icol,ilay); + qc(icol,ilay) = 1e-3 * lwp(icol,ilay) * cld(icol,ilay) * PC::gravit.value / p_del(icol,ilay); + qi(icol,ilay) = 1e-3 * iwp(icol,ilay) * cld(icol,ilay) * PC::gravit.value / p_del(icol,ilay); }); // Copy gases from gas_concs to gas_vmr array @@ -283,7 +283,7 @@ TEST_CASE("rrtmgp_scream_standalone_k", "") { d_cld(i,k) = cld(i,k); d_pint(i,k) = p_lev(i,k); // qv specified as a wet mixing ratio - Real qv_dry = gas_vmr(i,k,0)*PC::ep_2; + Real qv_dry = gas_vmr(i,k,0)*PC::ep_2.value; Real qv_wet = qv_dry/(1.0+qv_dry); d_qv(i,k) = qv_wet; // rest of active gases are specified as volume mixing ratios @@ -300,7 +300,7 @@ TEST_CASE("rrtmgp_scream_standalone_k", "") { // Compute surface flux from surface temperature auto ibot = (p_lay(0,0) > p_lay(0,nlay-1)) ? 0 : nlay; - d_surf_lw_flux_up(i) = PC::stebol * pow(t_lev(i,ibot), 4.0); + d_surf_lw_flux_up(i) = PC::stebol.value * pow(t_lev(i,ibot), 4.0); }); } Kokkos::fence(); From fe972d960452088e2072db7c699083f7410f46db Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 16:54:27 -0700 Subject: [PATCH 235/398] EAMxx: fix usage of physics constants in remaining folders --- components/eamxx/src/control/atmosphere_driver.cpp | 2 +- .../src/control/atmosphere_surface_coupling_exporter.cpp | 6 +++--- .../src/control/atmosphere_surface_coupling_importer.cpp | 4 ++-- .../single-process/surface_coupling/surface_coupling.cpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 0eb4ca4438ef..2ec7cea3acab 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -1418,7 +1418,7 @@ void AtmosphereDriver::set_initial_conditions () const auto gll_grid = m_grids_manager->get_grid("physics_gll"); const auto hyam_h = gll_grid->get_geometry_data("hyam").get_view(); const auto hybm_h = gll_grid->get_geometry_data("hybm").get_view(); - constexpr auto ps0 = physics::Constants::P0; + constexpr auto ps0 = physics::Constants::P0.value; const auto min_pressure = ic_pl.get("perturbation_minimum_pressure", 1050.0); const auto& pmask_lt = gll_grid->get_vertical_layout(true); diff --git a/components/eamxx/src/control/atmosphere_surface_coupling_exporter.cpp b/components/eamxx/src/control/atmosphere_surface_coupling_exporter.cpp index be4b585af279..eda813dd428d 100644 --- a/components/eamxx/src/control/atmosphere_surface_coupling_exporter.cpp +++ b/components/eamxx/src/control/atmosphere_surface_coupling_exporter.cpp @@ -498,7 +498,7 @@ void SurfaceCouplingExporter::compute_eamxx_exports(const double dt, const bool // provide theta based on an exner function that evaluates to 1 at the bottom interface. // To accomplish this we calculate a theta that replaces the reference pressure (P0) for exner // with the pressure of the lowest interface level => s_p_int_i(num_levs) - Sa_ptem(i) = s_T_mid_i(num_levs-1) / pow( s_p_mid_i(num_levs-1)/s_p_int_i(num_levs), PC::RD*PC::INV_CP); + Sa_ptem(i) = s_T_mid_i(num_levs-1) / pow( s_p_mid_i(num_levs-1)/s_p_int_i(num_levs), PC::RD.value*PC::INV_CP.value); } if (export_source(idx_Sa_pbot)==FROM_MODEL) { @@ -529,8 +529,8 @@ void SurfaceCouplingExporter::compute_eamxx_exports(const double dt, const bool // Precipitation has units of kg/m2, and Faxa_rainl/snowl // need units mm/s. Here, 1000 converts m->mm, dt has units s, and // rho_h2o has units kg/m3. - if (export_source(idx_Faxa_rainl)==FROM_MODEL) { Faxa_rainl(i) = precip_liq_surf_mass(i)/dt*(1000.0/PC::RHO_H2O); } - if (export_source(idx_Faxa_snowl)==FROM_MODEL) { Faxa_snowl(i) = precip_ice_surf_mass(i)/dt*(1000.0/PC::RHO_H2O); } + if (export_source(idx_Faxa_rainl)==FROM_MODEL) { Faxa_rainl(i) = precip_liq_surf_mass(i)/dt*(1000.0/PC::RHO_H2O.value); } + if (export_source(idx_Faxa_snowl)==FROM_MODEL) { Faxa_snowl(i) = precip_ice_surf_mass(i)/dt*(1000.0/PC::RHO_H2O.value); } } }); // Variables that are already surface vars in the ATM can just be copied directly. diff --git a/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp b/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp index 36672dd3ed0c..381d2d74ac37 100644 --- a/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp +++ b/components/eamxx/src/control/atmosphere_surface_coupling_importer.cpp @@ -231,8 +231,8 @@ void SurfaceCouplingImporter::overwrite_iop_imports (const bool called_during_in // TODO: this is using the TS from the beg of the step. Should it use end_of_step_ts() instead? m_iop_data_manager->read_iop_file_data(start_of_step_ts()); - static constexpr Real latvap = C::LatVap; - static constexpr Real stebol = C::stebol; + static constexpr Real latvap = C::LatVap.value; + static constexpr Real stebol = C::stebol.value; const auto& col_info_h = m_column_info_h; const auto& col_info_d = m_column_info_d; diff --git a/components/eamxx/tests/single-process/surface_coupling/surface_coupling.cpp b/components/eamxx/tests/single-process/surface_coupling/surface_coupling.cpp index 06868604c439..317b13faa633 100644 --- a/components/eamxx/tests/single-process/surface_coupling/surface_coupling.cpp +++ b/components/eamxx/tests/single-process/surface_coupling/surface_coupling.cpp @@ -369,11 +369,11 @@ void test_exports(const FieldManager& fm, // provide theta based on an exner function that evaluates to 1 at the bottom interface. // To accomplish this we calculate a theta that replaces the reference pressure (P0) for exner // with the pressure of the lowest interface level => p_int_i(nlevs) - Sa_ptem(i) = T_mid_i(nlevs-1) / pow( p_mid_i(nlevs-1)/p_int_i(nlevs), PC::RD*PC::INV_CP); + Sa_ptem(i) = T_mid_i(nlevs-1) / pow( p_mid_i(nlevs-1)/p_int_i(nlevs), PC::RD.value*PC::INV_CP.value); if (not called_directly_after_init) { - Faxa_rainl(i) = precip_liq_surf_mass(i)/dt*(1000.0/PC::RHO_H2O); - Faxa_snowl(i) = precip_ice_surf_mass(i)/dt*(1000.0/PC::RHO_H2O); + Faxa_rainl(i) = precip_liq_surf_mass(i)/dt*(1000.0/PC::RHO_H2O.value); + Faxa_snowl(i) = precip_ice_surf_mass(i)/dt*(1000.0/PC::RHO_H2O.value); } }); From 53fbbd40a07e9f0ca5a0257c43415e8ef852e635 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 15:21:58 -0700 Subject: [PATCH 236/398] EAMxx: add string->Quantity dictionary for physics::Constants --- .../src/share/physics/physics_constants.hpp | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/components/eamxx/src/share/physics/physics_constants.hpp b/components/eamxx/src/share/physics/physics_constants.hpp index af6885c4baab..f7802a4a236d 100644 --- a/components/eamxx/src/share/physics/physics_constants.hpp +++ b/components/eamxx/src/share/physics/physics_constants.hpp @@ -148,6 +148,48 @@ struct Constants static constexpr Scalar earth_ellipsoid1 = 111132.92; // first coefficient, meters per degree longitude at equator static constexpr Scalar earth_ellipsoid2 = 559.82; // second expansion coefficient for WGS84 ellipsoid static constexpr Scalar earth_ellipsoid3 = 1.175; // third expansion coefficient for WGS84 ellipsoid + + static const std::map& dictionary() { + static std::map dict; + if (dict.size()==0) { + dict["Cpair"] = Cpair; + dict["CP"] = CP; + dict["INV_CP"] = INV_CP; + dict["Rair"] = Rair; + dict["RH2O"] = RH2O; + dict["RV"] = RV; + dict["RD"] = RD; + dict["RHO_H2O"] = RHO_H2O; + dict["INV_RHO_H2O"] = INV_RHO_H2O; + dict["RHOW"] = RHOW; + dict["INV_RHOW"] = INV_RHOW; + dict["RhoIce"] = RhoIce; + dict["MWH2O"] = MWH2O; + dict["MWWV"] = MWWV; + dict["MWdry"] = MWdry; + dict["ep_2"] = ep_2; + dict["o2mmr"] = o2mmr; + dict["gravit"] = gravit; + dict["LatVap"] = LatVap; + dict["LatIce"] = LatIce; + dict["CpLiq"] = CpLiq; + dict["Tmelt"] = Tmelt; + dict["T_zerodegc"] = T_zerodegc; + dict["T_homogfrz"] = T_homogfrz; + dict["T_rainfrz"] = T_rainfrz; + + dict["P0"] = P0; + dict["RHOSUR"] = RHOSUR; + dict["Avogad"] = Avogad; + dict["Boltz"] = Boltz; + dict["Rgas"] = Rgas; + dict["RWV"] = RWV; + dict["r_earth"] = r_earth; + dict["stebol"] = stebol; + dict["omega"] = omega; + } + return dict; + } }; // Gases From 3cecceb9c4ff6729f238cea600bb8dffdffdf905 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 16:20:50 -0700 Subject: [PATCH 237/398] EAMxx: upgrade BinaryOps diag to accept physics constants as args --- .../atm_process/atmosphere_diagnostic.cpp | 37 +-- .../src/share/diagnostics/binary_ops.cpp | 247 +++++++++++++----- .../src/share/diagnostics/binary_ops.hpp | 20 +- .../diagnostics/tests/binary_ops_test.cpp | 67 +++-- .../eamxx/src/share/io/eamxx_io_utils.cpp | 4 +- 5 files changed, 261 insertions(+), 114 deletions(-) diff --git a/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp b/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp index 65bf5546a3c3..823b8cce8c24 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp @@ -22,24 +22,31 @@ void AtmosphereDiagnostic::compute_diagnostic (const double dt) { // Some diagnostics need the timestep, store in case. m_dt = dt; - // Set the timestamp of the diagnostic to the most - // recent timestamp among the inputs + // Set the timestamp of the diagnostic to the most recent timestamp among the inputs + // NOTE: it's a corner case, but it can happen that the diag has NO input fields. + // This can happen for BinaryOpsDiag, in the case where both args are physics + // constants. In that case, we assume the diagnostic can be pre-computed + // during initialiation, so that every call to compute_diagnostic sees + // ts==m_last_eval_ts, and does nothing. const auto& inputs = get_fields_in(); - util::TimeStamp ts; - for (const auto& f : inputs) { - const auto& fts = f.get_header().get_tracking().get_time_stamp(); - if (not ts.is_valid() || ts0) { + for (const auto& f : inputs) { + const auto& fts = f.get_header().get_tracking().get_time_stamp(); + if (not ts.is_valid() || ts("field_1"); - m_field_2 = m_params.get("field_2"); - m_binary_op = m_params.get("binary_op"); + m_arg1_name = m_params.get("arg1"); + m_arg2_name = m_params.get("arg2"); + m_binary_op_str = m_params.get("binary_op"); + m_binary_op_code= get_binary_operator_code(m_binary_op_str); // Validate operator - EKAT_REQUIRE_MSG(get_binary_operator_code(m_binary_op) >= 0, - "Error! Invalid binary operator: '" + m_binary_op + "'\n" + EKAT_REQUIRE_MSG(m_binary_op_code >= 0, + "Error! Invalid binary operator: '" + m_binary_op_str + "'\n" "Valid operators are: plus, minus, times, over\n"); } @@ -52,61 +138,88 @@ void BinaryOpsDiag:: set_grids(const std::shared_ptr grids_manager) { const auto &gname = m_params.get("grid_name"); - add_field(m_field_1, gname); - add_field(m_field_2, gname); + const auto& pc_dict = physics::Constants::dictionary(); + m_arg1_is_field = pc_dict.count(m_arg1_name)==0; + m_arg2_is_field = pc_dict.count(m_arg2_name)==0; + if (m_arg1_is_field) + add_field(m_arg1_name, gname); + if (m_arg2_is_field) + add_field(m_arg2_name, gname); } -void BinaryOpsDiag::initialize_impl(const RunType /*run_type*/) { - // get the input fields - const auto &f1 = get_field_in(m_field_1); - const auto &f2 = get_field_in(m_field_2); +void BinaryOpsDiag::initialize_impl(const RunType /*run_type*/) +{ + // get the inputs specs - const auto &l1 = f1.get_header().get_identifier().get_layout(); - const auto &l2 = f2.get_header().get_identifier().get_layout(); - // Must be on same layout, same datatype - EKAT_REQUIRE_MSG( - l1 == l2, - "Error! BinaryOpsDiag requires both input fields to have the same layout.\n" - " - field 1 name: " + f1.get_header().get_identifier().name() + "\n" - " - field 1 layout: " + l1.to_string() + "\n" - " - field 2 name: " + f2.get_header().get_identifier().name() + "\n" - " - field 2 layout: " + l2.to_string() + "\n"); - EKAT_REQUIRE_MSG( - f1.data_type() == f2.data_type(), - "Error! BinaryOpsDiag requires both input fields to have the same data type.\n" - " - field 1 name: " + f1.get_header().get_identifier().name() + "\n" - " - field 1 data type: " + e2str(f1.data_type()) + "\n" - " - field 2 name: " + f2.get_header().get_identifier().name() + "\n" - " - field 2 data type: " + e2str(f2.data_type()) + "\n"); + const auto& dict = physics::Constants::dictionary(); - const auto &gn1 = f1.get_header().get_identifier().get_grid_name(); - const auto &gn2 = f2.get_header().get_identifier().get_grid_name(); - // Must be on same grid too - EKAT_REQUIRE_MSG( - gn1 == gn2, - "Error! BinaryOpsDiag requires both input fields to be on the same grid.\n" - " - field 1 name: " + f1.get_header().get_identifier().name() + "\n" - " - field 1 grid name: " + gn1 + "\n" - " - field 2 name: " + f2.get_header().get_identifier().name() + "\n" - " - field 2 grid name: " + gn2 + "\n"); - - const auto &u1 = f1.get_header().get_identifier().get_units(); - const auto &u2 = f2.get_header().get_identifier().get_units(); + if (m_arg1_is_field and m_arg2_is_field) { + const auto& fid1 = get_field_in(m_arg1_name).get_header().get_identifier(); + const auto& fid2 = get_field_in(m_arg2_name).get_header().get_identifier(); + + // Must be on same layout, same datatype, same grid + EKAT_REQUIRE_MSG (fid1.get_layout() == fid2.get_layout(), + "Error! BinaryOpsDiag requires both input fields to have the same layout.\n" + " - field 1 name: " + fid1.name() + "\n" + " - field 1 layout: " + fid1.get_layout().to_string() + "\n" + " - field 2 name: " + fid2.name() + "\n" + " - field 2 layout: " + fid2.get_layout().to_string() + "\n"); + EKAT_REQUIRE_MSG (fid1.data_type() == fid2.data_type(), + "Error! BinaryOpsDiag requires both input fields to have the same data type.\n" + " - field 1 name: " + fid1.name() + "\n" + " - field 1 data type: " + e2str(fid1.data_type()) + "\n" + " - field 2 name: " + fid2.name() + "\n" + " - field 2 data type: " + e2str(fid2.data_type()) + "\n"); + EKAT_REQUIRE_MSG (fid1.get_grid_name() == fid1.get_grid_name(), + "Error! BinaryOpsDiag requires both input fields to be on the same grid.\n" + " - field 1 name: " + fid1.name() + "\n" + " - field 1 grid name: " + fid1.get_grid_name() + "\n" + " - field 2 name: " + fid2.name() + "\n" + " - field 2 grid name: " + fid2.get_grid_name() + "\n"); + } // All good, create the diag output - auto diag_units = apply_binary_op(u1, u2, get_binary_operator_code(m_binary_op)); - auto diag_name = m_field_1 + "_" + m_binary_op + "_" + m_field_2; - FieldIdentifier d_fid(diag_name, l1.clone(), diag_units, gn1); - m_diagnostic_output = Field(d_fid); - m_diagnostic_output.allocate_view(); -} + auto dl = m_arg1_is_field ? get_field_in(m_arg1_name).get_header().get_identifier().get_layout() + : (m_arg2_is_field ? get_field_in(m_arg2_name).get_header().get_identifier().get_layout() + : FieldLayout({},{})); + const auto& u1 = m_arg1_is_field ? get_field_in(m_arg1_name).get_header().get_identifier().get_units() + : dict.at(m_arg1_name).units; + const auto& u2 = m_arg2_is_field ? get_field_in(m_arg2_name).get_header().get_identifier().get_units() + : dict.at(m_arg2_name).units; + auto diag_units = apply_binary_op(u1, u2, m_binary_op_code); + auto gn = m_params.get("grid_name"); + auto diag_name = m_arg1_name + "_" + m_binary_op_str + "_" + m_arg2_name; + FieldIdentifier d_fid(diag_name, dl, diag_units, gn); + m_diagnostic_output = Field(d_fid,true); -void BinaryOpsDiag::compute_diagnostic_impl() { + if (not m_arg1_is_field and not m_arg2_is_field) { + // We can pre-compute the diag now + compute_diagnostic_impl(); + m_diagnostic_output.get_header().get_tracking().update_time_stamp(start_of_step_ts()); + } +} - const auto &f1 = get_field_in(m_field_1); - const auto &f2 = get_field_in(m_field_2); - m_diagnostic_output.deep_copy(f1); - apply_binary_op(m_diagnostic_output, f2, get_binary_operator_code(m_binary_op)); +void BinaryOpsDiag::compute_diagnostic_impl() +{ + const auto& dict = physics::Constants::dictionary(); + if (m_arg1_is_field and m_arg2_is_field) { + const auto& f1 = get_field_in(m_arg1_name); + const auto& f2 = get_field_in(m_arg2_name); + apply_binary_op(m_diagnostic_output, f1, f2, m_binary_op_code); + } else if (m_arg1_is_field) { + const auto& f1 = get_field_in(m_arg1_name); + const auto c2 = dict.at(m_arg2_name).value; + apply_binary_op(m_diagnostic_output, f1, c2, m_binary_op_code); + } else if (m_arg2_is_field) { + // We can do scale/scale_inv for * and /, but for + and - we must deep copy arg2 first + const auto c1 = physics::Constants::dictionary().at(m_arg1_name).value; + const auto& f2 = get_field_in(m_arg2_name); + apply_binary_op(m_diagnostic_output, c1, f2, m_binary_op_code); + } else { + const auto c1 = dict.at(m_arg1_name).value; + const auto c2 = dict.at(m_arg2_name).value; + apply_binary_op(m_diagnostic_output, c1, c2, m_binary_op_code); + } } } // namespace scream diff --git a/components/eamxx/src/share/diagnostics/binary_ops.hpp b/components/eamxx/src/share/diagnostics/binary_ops.hpp index f9fc89bc81a4..eb6aa01f0627 100644 --- a/components/eamxx/src/share/diagnostics/binary_ops.hpp +++ b/components/eamxx/src/share/diagnostics/binary_ops.hpp @@ -7,7 +7,7 @@ namespace scream { /* * This diagnostic will perform binary ops - * like +, -, *, ÷ on two input fields. + * like +, -, *, ÷ on two input fields or on an input field and a known physical constant. */ class BinaryOpsDiag : public AtmosphereDiagnostic { @@ -16,23 +16,23 @@ class BinaryOpsDiag : public AtmosphereDiagnostic { BinaryOpsDiag(const ekat::Comm &comm, const ekat::ParameterList ¶ms); // The name of the diagnostic CLASS (not the computed field) - std::string name() const { return "BinaryOpsDiag"; } + std::string name() const override{ return "BinaryOpsDiag"; } // Set the grid - void set_grids(const std::shared_ptr grids_manager); + void set_grids(const std::shared_ptr grids_manager) override; protected: -#ifdef KOKKOS_ENABLE_CUDA - public: -#endif - void compute_diagnostic_impl(); + void compute_diagnostic_impl() override; void initialize_impl(const RunType /*run_type*/) override; - std::string m_field_1; - std::string m_field_2; - std::string m_binary_op; + std::string m_arg1_name; + std::string m_arg2_name; + std::string m_binary_op_str; + int m_binary_op_code; + bool m_arg1_is_field; + bool m_arg2_is_field; }; // class BinaryOpsDiag } // namespace scream diff --git a/components/eamxx/src/share/diagnostics/tests/binary_ops_test.cpp b/components/eamxx/src/share/diagnostics/tests/binary_ops_test.cpp index e66ffa0f77a1..88e02cf6bd0b 100644 --- a/components/eamxx/src/share/diagnostics/tests/binary_ops_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/binary_ops_test.cpp @@ -1,6 +1,7 @@ #include #include "share/diagnostics/register_diagnostics.hpp" +#include "share/physics/physics_constants.hpp" #include "share/field/field_utils.hpp" #include "share/data_managers/mesh_free_grids_manager.hpp" #include "share/core/eamxx_setup_random_test.hpp" @@ -48,11 +49,11 @@ TEST_CASE("binary_ops") { FieldLayout scalar2d_layout{{COL, LEV}, {ngcols, nlevs}}; FieldIdentifier qc_fid("qc", scalar2d_layout, kg / kg, grid->name()); FieldIdentifier qv_fid("qv", scalar2d_layout, kg / kg, grid->name()); + FieldIdentifier m_fid("m", scalar2d_layout, kg, grid->name()); - Field qc(qc_fid); - Field qv(qv_fid); - qc.allocate_view(); - qv.allocate_view(); + Field qc(qc_fid, true); + Field qv(qv_fid, true); + Field m(m_fid, true); // Random number generator seed int seed = get_random_test_seed(); @@ -62,52 +63,78 @@ TEST_CASE("binary_ops") { auto &diag_factory = AtmosphereDiagnosticFactory::instance(); register_diagnostics(); - ekat::ParameterList params; + ekat::ParameterList params_plus, params_times, params_scl_scl; REQUIRE_THROWS(diag_factory.create("BinaryOpsDiag", comm, - params)); // No 'field_1', 'field_2', or 'binary_op' + params_plus)); // No 'arg1', 'arg2', or 'binary_op' // Set time for qc and randomize its values qc.get_header().get_tracking().update_time_stamp(t0); qv.get_header().get_tracking().update_time_stamp(t0); - randomize_uniform(qc, seed++, 0, 200); qc.sync_to_dev(); - randomize_uniform(qv, seed++, 0, 200); qv.sync_to_dev(); + m.get_header().get_tracking().update_time_stamp(t0); + randomize_uniform(qc, seed++, 0, 200); + randomize_uniform(qv, seed++, 0, 200); + randomize_uniform(m, seed++, 0, 200); // Create and set up the diagnostic - params.set("grid_name", grid->name()); - params.set("field_1", "qc"); - params.set("field_2", "qv"); - params.set("binary_op", "plus"); - auto plus_diag = diag_factory.create("BinaryOpsDiag", comm, params); - params.set("binary_op", "times"); - auto prod_diag = diag_factory.create("BinaryOpsDiag", comm, params); + params_plus.set("grid_name", grid->name()); + params_plus.set("arg1", "qc"); + params_plus.set("arg2", "qv"); + params_plus.set("binary_op", "starcraft"); + REQUIRE_THROWS(diag_factory.create("BinaryOpsDiag", comm, params_plus)); // Unknown binary_op + params_plus.set("binary_op", "plus"); + auto plus_diag = diag_factory.create("BinaryOpsDiag", comm, params_plus); + + params_times.set("grid_name", grid->name()); + params_times.set("arg1", "m"); + params_times.set("arg2", "gravit"); + params_times.set("binary_op", "times"); + auto prod_diag = diag_factory.create("BinaryOpsDiag", comm, params_times); + + params_scl_scl.set("grid_name", grid->name()); + params_scl_scl.set("arg1", "Avogad"); + params_scl_scl.set("arg2", "boltz"); + params_scl_scl.set("binary_op", "times"); + auto prod_scl_scl = diag_factory.create("BinaryOpsDiag", comm, params_scl_scl); + plus_diag->set_grids(gm); - prod_diag->set_grids(gm); plus_diag->set_required_field(qc); - prod_diag->set_required_field(qc); plus_diag->set_required_field(qv); - prod_diag->set_required_field(qv); plus_diag->initialize(t0, RunType::Initial); + + prod_diag->set_grids(gm); + prod_diag->set_required_field(m); prod_diag->initialize(t0, RunType::Initial); + prod_scl_scl->set_grids(gm); + prod_scl_scl->initialize(t0, RunType::Initial); + // Run diag plus_diag->compute_diagnostic(); - auto plus_diag_f = plus_diag->get_diagnostic(); plus_diag_f.sync_to_host(); prod_diag->compute_diagnostic(); + prod_scl_scl->compute_diagnostic(); + + auto plus_diag_f = plus_diag->get_diagnostic(); plus_diag_f.sync_to_host(); auto prod_diag_f = prod_diag->get_diagnostic(); prod_diag_f.sync_to_host(); + auto rgas_diag_f = prod_scl_scl->get_diagnostic(); rgas_diag_f.sync_to_host(); // Check that the output fields have the right values const auto &plus_v = plus_diag_f.get_view(); const auto &prod_v = prod_diag_f.get_view(); + const auto &rgas_v = rgas_diag_f.get_view(); const auto &qc_v = qc.get_view(); const auto &qv_v = qv.get_view(); + const auto &m_v = m.get_view(); + const auto g = physics::Constants::gravit.value; for (int icol = 0; icol < ngcols; ++icol) { for (int ilev = 0; ilev < nlevs; ++ilev) { // Check plus REQUIRE(plus_v(icol, ilev) == qc_v(icol, ilev) + qv_v(icol, ilev)); // Check product - REQUIRE(prod_v(icol, ilev) == qc_v(icol, ilev) * qv_v(icol, ilev)); + REQUIRE(prod_v(icol, ilev) == (m_v(icol,ilev)*g)); } } + // The diag_scl_scl shoould compute the prod of avogadro's number and boltzman's constant, which is Rgas + REQUIRE (rgas_v()==physics::Constants::dictionary().at("Rgas").value); // redundant, why not qc.update(qv, 1, 1); diff --git a/components/eamxx/src/share/io/eamxx_io_utils.cpp b/components/eamxx/src/share/io/eamxx_io_utils.cpp index 7439f82689a2..030a00160d67 100644 --- a/components/eamxx/src/share/io/eamxx_io_utils.cpp +++ b/components/eamxx/src/share/io/eamxx_io_utils.cpp @@ -248,8 +248,8 @@ create_diagnostic (const std::string& diag_field_name, else if (std::regex_search(diag_field_name,matches,binary_ops)) { diag_name = "BinaryOpsDiag"; params.set("grid_name", grid->name()); - params.set("field_1", matches[1].str()); - params.set("field_2", matches[3].str()); + params.set("arg1", matches[1].str()); + params.set("arg2", matches[3].str()); params.set("binary_op", matches[2].str()); } else if (std::regex_search(diag_field_name,matches,histogram)) { From 2b643870c3a14ceb458054462e26c4370a579afa Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 16 Dec 2025 16:37:08 -0700 Subject: [PATCH 238/398] EAMxx: fix a few compiler warnings --- .../eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp | 2 +- components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp | 2 +- .../eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp | 2 +- .../src/share/algorithm/tests/time_interpolation_tests.cpp | 1 - components/eamxx/src/share/field/utils/compute_mask.cpp | 2 ++ .../tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp index 09b16d77c1e7..ec1711db30ea 100644 --- a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp +++ b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp @@ -637,7 +637,7 @@ void SHOCMacrophysics::check_flux_state_consistency(const double dt) // the moisture in the lowest model level. If so, apply fixer. const auto condition = surf_evap(i) - (qmin - qv_i(last_pack_idx)[last_pack_entry])/(dt*gravit*rpdel); if (condition < 0) { - const auto cc = abs(surf_evap(i)*dt*gravit); + const auto cc = ekat::abs(surf_evap(i)*dt*gravit); auto tracer_mass = [&](const int k) { return qv_i(k)*pseudo_density_i(k); diff --git a/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp index 3d92f52e3575..575a00ad2234 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_grid_tests.cpp @@ -115,7 +115,7 @@ struct UnitWrap::UnitTest::TestShocGrid : public UnitWrap::UnitTest::Base const auto offset = n + s * nlev; // check that the density is consistent with the hydrostatic approximation - REQUIRE(abs(SDS.rho_zt[offset] - density_zt[n]) <= std::numeric_limits::epsilon()); + REQUIRE(std::abs(SDS.rho_zt[offset] - density_zt[n]) <= std::numeric_limits::epsilon()); // check that the density has physically realistic values REQUIRE(SDS.rho_zt[offset] <= 2); diff --git a/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp b/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp index 3ceb0fcf8fbd..11572825c413 100644 --- a/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp +++ b/components/eamxx/src/physics/shoc/tests/shoc_pdf_computetemp_tests.cpp @@ -54,7 +54,7 @@ struct UnitWrap::UnitTest::TestShocPdfComputeTemp { SDS.thl1 = thl1; SDS.pval = pval; - Int num_tests = SDS.pval/abs(presincr); + Int num_tests = SDS.pval/std::abs(presincr); REQUIRE(num_tests > 1); REQUIRE(presincr < 0); diff --git a/components/eamxx/src/share/algorithm/tests/time_interpolation_tests.cpp b/components/eamxx/src/share/algorithm/tests/time_interpolation_tests.cpp index e07d0ee0ce41..082757829c02 100644 --- a/components/eamxx/src/share/algorithm/tests/time_interpolation_tests.cpp +++ b/components/eamxx/src/share/algorithm/tests/time_interpolation_tests.cpp @@ -21,7 +21,6 @@ namespace scream { // Test Constants constexpr Real tol = std::numeric_limits::epsilon()*1e5; -constexpr int slp_switch = 4; // The frequency that we change the slope of the data written to file. constexpr int dt = 100; constexpr int total_snaps = 10; constexpr int snap_freq = 4; diff --git a/components/eamxx/src/share/field/utils/compute_mask.cpp b/components/eamxx/src/share/field/utils/compute_mask.cpp index ecc38156cc67..c335a0cdb3f9 100644 --- a/components/eamxx/src/share/field/utils/compute_mask.cpp +++ b/components/eamxx/src/share/field/utils/compute_mask.cpp @@ -29,6 +29,8 @@ bool compare (const ST lhs, const ST rhs, Comparison CMP) } else { EKAT_KERNEL_ERROR_MSG ("Error! Unsupported CMP\n"); } + // Silence NVCC warning "missing return statement at end of non-void function" + return false; } template diff --git a/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp b/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp index b93f657e127a..8d3d069e4436 100644 --- a/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp +++ b/components/eamxx/tests/single-process/rrtmgp/rrtmgp_standalone_unit.cpp @@ -200,7 +200,7 @@ TEST_CASE("rrtmgp_scream_standalone_k", "") { // Need to calculate a dummy pseudo_density for our test problem Kokkos::parallel_for(MDRP::template get<2>({nlay,ncol}), KOKKOS_LAMBDA(int ilay, int icol) { - p_del(icol,ilay) = abs(p_lev(icol,ilay+1) - p_lev(icol,ilay)); + p_del(icol,ilay) = ekat::abs(p_lev(icol,ilay+1) - p_lev(icol,ilay)); }); // We do not want to pass lwp and iwp through the FM, so back out qc and qi for this test From 8c29f63c465e711bd6f7bee6e3ce7af37b156afa Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 17 Dec 2025 12:18:05 -0700 Subject: [PATCH 239/398] EAMxx: fix typo in diagnostic header guard --- components/eamxx/src/share/diagnostics/histogram.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/share/diagnostics/histogram.hpp b/components/eamxx/src/share/diagnostics/histogram.hpp index dcfdbd8335e9..609471810881 100644 --- a/components/eamxx/src/share/diagnostics/histogram.hpp +++ b/components/eamxx/src/share/diagnostics/histogram.hpp @@ -1,4 +1,4 @@ -#ifndef EAMXX_HISTOTGRAM_HPP +#ifndef EAMXX_HISTOGRAM_HPP #define EAMXX_HISTOGRAM_HPP #include "share/atm_process/atmosphere_diagnostic.hpp" From 47f06915173d0f16c947863702f87c4c7ee6cd01 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Wed, 17 Dec 2025 18:59:48 -0600 Subject: [PATCH 240/398] Add newer coupling capability namelist and flags Add newer coupling capability namelist and flags to driver-moab. This includes changes for one-way ocean-to-land, iac and glacier-wave coupling Also adds abilit to add more coupling fields for these configs. This adds some logical flags that are now expected in other components and in the namelist. Does not yet implement the new couplings. Need to remove build errors on master associated with ocean-to-land additions. [BFB] --- driver-moab/cime_config/buildnml | 4 + driver-moab/cime_config/config_component.xml | 122 +++++++ .../cime_config/namelist_definition_drv.xml | 300 ++++++++++++++++-- driver-moab/shr/seq_flds_mod.F90 | 194 ++++++++++- driver-moab/shr/seq_infodata_mod.F90 | 14 +- 5 files changed, 594 insertions(+), 40 deletions(-) diff --git a/driver-moab/cime_config/buildnml b/driver-moab/cime_config/buildnml index 3805b61e8cec..351477af44c0 100755 --- a/driver-moab/cime_config/buildnml +++ b/driver-moab/cime_config/buildnml @@ -274,6 +274,10 @@ def write_seq_maps_file(case, nmlgen, confdir): if "rof2ocn_" in name: if case.get_value("COMP_OCN") == 'docn': logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) + elif "ocn2lnd_" in name: + logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) + elif "lnd2ocn_" in name: + logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) else: expect(gridvalue[component1] == gridvalue[component2], "Need to provide valid mapping file between {} and {} in xml variable {} ".\ diff --git a/driver-moab/cime_config/config_component.xml b/driver-moab/cime_config/config_component.xml index 66ce520f7c3c..986c19698b51 100644 --- a/driver-moab/cime_config/config_component.xml +++ b/driver-moab/cime_config/config_component.xml @@ -1985,6 +1985,60 @@ ocn2glc state mapping file decomp type + + char + idmap_ignore + run_domain + env_run.xml + ocn2glc shelf flux mapping file - the default value idmap_ignore, if set, will be ignored by buildnml and + will generate a runtime error if in fact a file is required for the given compset + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2glc shelf flux mapping file decomp type + + + + char + idmap_ignore + run_domain + env_run.xml + ocn2glc shelf state mapping file - the default value idmap_ignore, if set, will be ignored by buildnml and + will generate a runtime error if in fact a file is required for the given compset + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2glc shelf state mapping file decomp type + + + + char + idmap_ignore + run_domain + env_run.xml + ocn2glc state mapping file for thermal forcing - the default value idmap_ignore, if set, will be ignored by buildnml and + will generate a runtime error if in fact a file is required for the given compset + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2glc thermal forcing state mapping file decomp type + + char idmap @@ -2138,6 +2192,74 @@ iac2lnd state mapping file decomp type + + char + idmap + run_domain + env_run.xml + ocn2lnd state mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2lnd state mapping file decomp type + + + + char + idmap + run_domain + env_run.xml + ocn2lnd flux mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + ocn2lnd flux mapping file decomp type + + + + char + idmap + run_domain + env_run.xml + lnd2ocn state mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + lnd2ocn state mapping file decomp type + + + + char + idmap + run_domain + env_run.xml + lnd2ocn flux mapping file + + + + char + X,Y + Y + run_domain + env_run.xml + lnd2ocn flux mapping file decomp type + + char none,npfix,cart3d,cart3d_diag,cart3d_uvw,cart3d_uvw_diag diff --git a/driver-moab/cime_config/namelist_definition_drv.xml b/driver-moab/cime_config/namelist_definition_drv.xml index 1310e5cd558f..83d6a262dfc7 100644 --- a/driver-moab/cime_config/namelist_definition_drv.xml +++ b/driver-moab/cime_config/namelist_definition_drv.xml @@ -137,15 +137,15 @@ - + logical seq_flds seq_cplflds_inparm - Pass water isotopes between components + If set to .true. Polar fields will be passed from the ocean to the coupler. - $FLDS_WISO + $FLDS_POLAR @@ -161,15 +161,15 @@ - + logical seq_flds seq_cplflds_inparm - If set to .true. Polar fields will be passed from the ocean to the coupler. + Pass water isotopes between components - $FLDS_POLAR + $FLDS_WISO @@ -198,7 +198,7 @@ seq_flds seq_cplflds_inparm - Number of cism elevation classes. Set by the xml variable GLC_NEC in env_run.xml + Number of GLC elevation classes. Set by the xml variable GLC_NEC in env_run.xml $GLC_NEC @@ -216,7 +216,7 @@ $GLC_NZOC - + integer seq_flds @@ -302,6 +302,18 @@ + + logical + seq_flds + seq_cplflds_inparm + + If set to .true., adds fields needed to calculate ocean-land one-way coupling + + + .false. + + + logical seq_flds @@ -313,7 +325,7 @@ .false. - + char seq_flds @@ -349,6 +361,16 @@ + + logical + seq_flds + seq_cplflds_inparm + Flag to control adding IAC component variable to the coupler history files. + + .false. + + + @@ -661,7 +683,7 @@ seq_infodata_inparm Constant solar zenith angle value in degrees for idealized configurations - such as radiative-convective equilibrium experiments. This is disabled when + such as radiative-convective equilibrium experiments. This is disabled when the value is less than 0 Default: -1 @@ -857,7 +879,7 @@ control seq_infodata_inparm - 0: standard surface flux calculation as in E3SMv1 + 0: standard surface flux calculation as in E3SMv1 1: COAREv3.0 flux computation (Fairall et al., 2003) 2: University of Arizona algorithm (Zeng et al., 1998) default: 0 @@ -1389,17 +1411,17 @@ - logical - history - seq_infodata_inparm - - turns on coupler history stream for instantaneous iac to coupler fields. - default: false - - - .false. - - + logical + history + seq_infodata_inparm + + turns on coupler history stream for instantaneous iac to coupler fields. + default: false + + + .false. + + logical @@ -1597,6 +1619,7 @@ 1.e-10 1.e-10 1.e-10 + 1.e-10 @@ -3340,7 +3363,7 @@ cime_pes cime_pes - level of task-to-node mapping output for the whole model + level of task-to-node mapping output for the whole model (0: no output; 1: compact; 2: verbose) @@ -4317,6 +4340,36 @@ + + char + mapping + abs + seq_maps + + lnd to iac mapping file for states + + + $LND2IAC_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $LND2IAC_SMAPTYPE + X + + + char mapping @@ -4570,20 +4623,20 @@ - + char mapping abs seq_maps - ocn to glc flux mapping file for fluxes + ocn to glc shelf mapping file for fluxes - $OCN2GLC_FMAPNAME + $OCN2GLC_SHELF_FMAPNAME - + char mapping seq_maps @@ -4595,25 +4648,25 @@ grid. - $OCN2GLC_FMAPTYPE + $OCN2GLC_SHELF_FMAPTYPE X - + char mapping abs seq_maps - ocn to glc state mapping file for states + ocn to glc shelf mapping file for states - $OCN2GLC_SMAPNAME + $OCN2GLC_SHELF_SMAPNAME - + char mapping seq_maps @@ -4625,7 +4678,37 @@ grid. - $OCN2GLC_SMAPTYPE + $OCN2GLC_SHELF_SMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to glc state mapping file for thermal forcing state fields + + + $OCN2GLC_TF_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $OCN2GLC_TF_SMAPTYPE X @@ -4961,6 +5044,7 @@ + char mapping @@ -5096,6 +5180,36 @@ + + char + mapping + abs + seq_maps + + atm to iac mapping file for states + + + $ATM2IAC_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $ATM2IAC_SMAPTYPE + X + + + char mapping @@ -5246,6 +5360,126 @@ + + char + mapping + abs + seq_maps + + ocn to lnd mapping file for states + + + $OCN2LND_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $OCN2LND_SMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to rof mapping file for fluxes + + + $OCN2LND_FMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $OCN2LND_FMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to rof mapping file for states + + + $LND2OCN_SMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $LND2OCN_SMAPTYPE + X + + + + + char + mapping + abs + seq_maps + + ocn to rof mapping file for fluxes + + + $LND2OCN_FMAPNAME + + + + + char + mapping + seq_maps + + The type of mapping desired, either "source" or "destination" mapping. + X is associated with rearrangement of the source grid to the + destination grid and then local mapping. Y is associated with mapping + on the source grid and then rearrangement and sum to the destination + grid. + + + $LND2OCN_FMAPTYPE + X + + + logical data_assimilation diff --git a/driver-moab/shr/seq_flds_mod.F90 b/driver-moab/shr/seq_flds_mod.F90 index ecb874dc0ee1..12df5919287d 100644 --- a/driver-moab/shr/seq_flds_mod.F90 +++ b/driver-moab/shr/seq_flds_mod.F90 @@ -18,6 +18,7 @@ module seq_flds_mod ! g => glc ! r => rof ! w => wav + ! z => iac ! ! state-name ! what follows state prefix @@ -164,6 +165,7 @@ module seq_flds_mod logical :: rof_heat ! .true. if river model includes temperature logical :: add_ndep_fields ! .true. => add ndep fields logical :: fan_have_fields ! .true. if FAN coupled to atmosphere + logical :: add_iac_to_cplstate ! .true. if iac fields are added to coupler history files character(len=CS) :: atm_flux_method ! explicit => no extra fields needed ! implicit_stress => atm provides wsresp and tau_est @@ -171,6 +173,7 @@ module seq_flds_mod logical :: rof2ocn_nutrients ! .true. if the runoff model passes nutrient fields to the ocn logical :: lnd_rof_two_way ! .true. if land-river two-way coupling turned on logical :: ocn_rof_two_way ! .true. if river-ocean two-way coupling turned on + logical :: ocn_lnd_one_way ! .true. if ocean to land one-way coupling turned on logical :: rof_sed ! .true. if river model includes sediment character(len=CS) :: wav_ocn_coup ! 'twoway' if wave-ocean two-way coupling turned on @@ -218,6 +221,8 @@ module seq_flds_mod character(CXX) :: seq_flds_x2o_fluxes character(CXX) :: seq_flds_o2x_states_to_rof character(CXX) :: seq_flds_o2x_fluxes_to_rof + character(CXX) :: seq_flds_o2x_states_to_lnd + character(CXX) :: seq_flds_o2x_fluxes_to_lnd character(CXX) :: seq_flds_g2x_states character(CXX) :: seq_flds_g2x_states_to_lnd @@ -249,8 +254,8 @@ module seq_flds_mod character(CXX) :: seq_flds_r2o_liq_fluxes character(CXX) :: seq_flds_r2o_ice_fluxes - !character(CXX) :: seq_flds_x2z_states - !character(CXX) :: seq_flds_z2x_states + character(CXX) :: seq_flds_x2z_states + character(CXX) :: seq_flds_z2x_states character(CXX) :: seq_flds_z2x_fluxes character(CXX) :: seq_flds_x2z_fluxes @@ -279,6 +284,9 @@ module seq_flds_mod character(CXX) :: seq_flds_w2x_fields character(CXX) :: seq_flds_x2w_fields character(CXX) :: seq_flds_o2x_fields_to_rof + character(CXX) :: seq_flds_o2x_fields_to_lnd + character(CXX) :: seq_flds_z2x_fields + character(CXX) :: seq_flds_x2z_fields !---------------------------------------------------------------------------- ! component names @@ -291,6 +299,7 @@ module seq_flds_mod character(32) :: glcname='glc' character(32) :: wavname='wav' character(32) :: rofname='rof' + character(32) :: iacname='iac' ! namelist variables logical :: nan_check_component_fields @@ -356,6 +365,8 @@ subroutine seq_flds_set(nmlfile, ID, infodata) character(CXX) :: o2x_fluxes = '' character(CXX) :: o2x_states_to_rof = '' character(CXX) :: o2x_fluxes_to_rof = '' + character(CXX) :: o2x_states_to_lnd = '' + character(CXX) :: o2x_fluxes_to_lnd = '' character(CXX) :: x2o_states = '' character(CXX) :: x2o_fluxes = '' character(CXX) :: g2x_states = '' @@ -385,6 +396,11 @@ subroutine seq_flds_set(nmlfile, ID, infodata) character(CXX) :: r2o_liq_fluxes = '' character(CXX) :: r2o_ice_fluxes = '' + character(CXX) :: z2x_states = '' + character(CXX) :: z2x_fluxes = '' + character(CXX) :: x2z_states = '' + character(CXX) :: x2z_fluxes = '' + character(CXX) :: stringtmp = '' !------ namelist ----- @@ -392,7 +408,9 @@ subroutine seq_flds_set(nmlfile, ID, infodata) type(mct_string) :: mctOStr ! mct string for output outfield logical :: is_state, is_flux - integer :: i,n + integer :: i,n,m + character(len=3) :: pftstr = '' + character(len=2) :: monstr = '' ! use cases namelists logical :: flds_co2a @@ -406,12 +424,17 @@ subroutine seq_flds_set(nmlfile, ID, infodata) integer :: glc_nec integer :: glc_nzoc + ! set these here because the cplflds namelist is not the right place + ! this namelist is called only under special circumstances + integer :: iac_npft = 17 + integer :: iac_nharvest = 5 + namelist /seq_cplflds_inparm/ & flds_co2a, flds_co2b, flds_co2c, flds_co2_dmsa, flds_wiso, flds_polar, flds_tf, & glc_nec, glc_nzoc, ice_ncat, seq_flds_i2o_per_cat, flds_bgc_oi, & nan_check_component_fields, rof_heat, atm_flux_method, atm_gustiness, & - rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, rof_sed, & - wav_ocn_coup,wav_atm_coup, wav_ice_coup + rof2ocn_nutrients, lnd_rof_two_way, ocn_rof_two_way, ocn_lnd_one_way, rof_sed, & + wav_ocn_coup, wav_atm_coup, wav_ice_coup, add_iac_to_cplstate ! user specified new fields integer, parameter :: nfldmax = 200 @@ -455,10 +478,12 @@ subroutine seq_flds_set(nmlfile, ID, infodata) rof2ocn_nutrients = .false. lnd_rof_two_way = .false. ocn_rof_two_way = .false. + ocn_lnd_one_way = .false. rof_sed = .false. wav_ocn_coup = 'none' wav_atm_coup = 'none' wav_ice_coup = 'none' + add_iac_to_cplstate = .false. unitn = shr_file_getUnit() write(logunit,"(A)") subname//': read seq_cplflds_inparm namelist from: '& @@ -494,10 +519,12 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call shr_mpi_bcast(rof2ocn_nutrients, mpicom) call shr_mpi_bcast(lnd_rof_two_way, mpicom) call shr_mpi_bcast(ocn_rof_two_way, mpicom) + call shr_mpi_bcast(ocn_lnd_one_way, mpicom) call shr_mpi_bcast(rof_sed, mpicom) call shr_mpi_bcast(wav_ocn_coup, mpicom) call shr_mpi_bcast(wav_atm_coup, mpicom) call shr_mpi_bcast(wav_ice_coup, mpicom) + call shr_mpi_bcast(add_iac_to_cplstate, mpicom) call glc_elevclass_init(glc_nec) call glc_zocnclass_init(glc_nzoc) @@ -590,6 +617,12 @@ subroutine seq_flds_set(nmlfile, ID, infodata) case('x2g') if (is_state) call seq_flds_add(x2g_states,trim(fldname)) if (is_flux ) call seq_flds_add(x2g_fluxes,trim(fldname)) + case('z2x') + if (add_iac_to_cplstate .and. is_state) call seq_flds_add(z2x_states,trim(fldname)) + if (add_iac_to_cplstate .and. is_flux ) call seq_flds_add(z2x_fluxes,trim(fldname)) + case('x2z') + if (add_iac_to_cplstate .and. is_state) call seq_flds_add(x2z_states,trim(fldname)) + if (add_iac_to_cplstate .and. is_flux ) call seq_flds_add(x2z_fluxes,trim(fldname)) case default write(logunit,*) subname//'ERROR: ',trim(cplflds_custom(n)),& ' not a recognized value' @@ -1120,6 +1153,7 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(x2a_states,'Sf_lfrac') call seq_flds_add(x2a_states,'Sf_ifrac') call seq_flds_add(x2a_states,'Sf_ofrac') + if(add_iac_to_cplstate)call seq_flds_add(x2a_states,'Sf_zfrac') longname = 'Surface land fraction' stdname = 'land_area_fraction' units = '1' @@ -1133,6 +1167,10 @@ subroutine seq_flds_set(nmlfile, ID, infodata) stdname = 'sea_area_fraction' attname = 'Sf_ofrac' call metadata_set(attname, longname, stdname, units) + longname = 'Surface iac fraction' + stdname = 'iac_area_fraction' + attname = 'Sf_zfrac' + call metadata_set(attname, longname, stdname, units) ! Direct albedo (visible radiation) call seq_flds_add(i2x_states,"Si_avsdr") @@ -1759,6 +1797,10 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call seq_flds_add(o2x_states,"So_ssh") call seq_flds_add(x2r_states,"So_ssh") call seq_flds_add(o2x_states_to_rof,"So_ssh") + if (ocn_lnd_one_way) then + call seq_flds_add(x2l_states,"So_ssh") ! ocn -> lnd one-way coupling + call seq_flds_add(o2x_states_to_lnd,"So_ssh") + endif if (wav_ocn_coup .ne. 'none') call seq_flds_add(x2w_states,'So_ssh') longname = 'Sea surface height' stdname = 'sea_surface_height' @@ -1766,6 +1808,17 @@ subroutine seq_flds_set(nmlfile, ID, infodata) attname = 'So_ssh' call metadata_set(attname, longname, stdname, units) + if (ocn_lnd_one_way) then + call seq_flds_add(o2x_states,"So_frac_h2oocn") + call seq_flds_add(x2l_states,"So_frac_h2oocn") + call seq_flds_add(o2x_states_to_lnd,"So_frac_h2oocn") + longname = 'Oceanic inundation fraction' + stdname = 'oceanic_inundation_fraction' + units = '-' + attname = 'So_frac_h2oocn' + call metadata_set(attname, longname, stdname, units) + endif + ! Meridional sea surface slope call seq_flds_add(o2x_states,"So_dhdy") call seq_flds_add(x2i_states,"So_dhdy") @@ -2732,6 +2785,123 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call metadata_set(attname, longname, stdname, units) endif + !---------------------------- + ! lnd->iac, iac->lnd, iac->atm + !---------------------------- + + ! lnd/iac coupling needs one field in each class per pft + ! Note that this ends up as 17*4=68 coupled fields... + ! also send harvest fraction from iac to land + ! use the same loop and index string + + ! these two variables are hardcoded above because there is not an appropriate + ! namelist to put them in: iac_npft and iac_nharvest + + do i = 1,iac_npft + + ! Zero offset the tags, since that's how we access them in lnd and iac + write(pftstr,'(I0)') i-1 + pftstr=trim(pftstr) + + ! Only hr and npp matter, for now + if(add_iac_to_cplstate)call seq_flds_add(l2x_states,trim('Sl_hr_pft' // pftstr)) + call seq_flds_add(x2z_states,trim('Sl_hr_pft' // pftstr)) + longname = 'Total heterotrophic respiration' // pftstr + stdname = 'lnd_total_heterotrophic_respiration' // pftstr + units = 'gC/m^2/s' + attname = 'Sl_hr_pft' // pftstr + attname = trim(attname) + call metadata_set(attname, longname, stdname, units) + + if(add_iac_to_cplstate)call seq_flds_add(l2x_states,'Sl_npp_pft' // pftstr) + call seq_flds_add(x2z_states,'Sl_npp_pft' // pftstr) + longname = 'Net primary production for pft ' // pftstr + stdname = 'lnd_net_primary_production_pft' // pftstr + units = 'gC/m^2/s' + attname = 'Sl_npp_pft' // pftstr + call metadata_set(attname, longname, stdname, units) + + ! Review + if(add_iac_to_cplstate)call seq_flds_add(l2x_states,'Sl_pftwgt_pft' //pftstr) + call seq_flds_add(x2z_states,'Sl_pftwgt_pft' //pftstr) + longname = 'PFT weight relative to gridcell for pft ' //pftstr + stdname = 'lnd_pft_weight_pft' //pftstr + units = '' + attname = 'Sl_pftwgt_pft' //pftstr + call metadata_set(attname, longname, stdname, units) + + ! iac->lnd + + ! This is pft for beginning of model year + 1 + ! ts wonders if landfrac should go as well - just to + ! verify that we are all using the same values. + if(add_iac_to_cplstate)call seq_flds_add(z2x_states,trim('Sz_pct_pft' //pftstr)) + if(add_iac_to_cplstate)call seq_flds_add(x2l_states,trim('Sz_pct_pft' //pftstr)) + longname = 'Percent pft of vegetated land unit for pft ' //pftstr + stdname = 'iac_pct_pft' //pftstr + stdname = trim(stdname) + units = 'percent' + attname = 'Sz_pct_pft' //pftstr + attname = trim(attname) + call metadata_set(attname, longname, stdname, units) + + ! Need to send the beginning model year pft data as well + if(add_iac_to_cplstate)call seq_flds_add(z2x_states,trim('Sz_pct_pft_prev' //pftstr)) + if(add_iac_to_cplstate)call seq_flds_add(x2l_states,trim('Sz_pct_pft_prev' //pftstr)) + longname = 'Previous percent pft of vegetated land unit for pft ' //pftstr + stdname = 'iac_pct_pft_prev' //pftstr + stdname = trim(stdname) + units = 'percent' + attname = 'Sz_pct_pft_prev' //pftstr + attname = trim(attname) + call metadata_set(attname, longname, stdname, units) + + ! send the harvest data also, these are for model year + if (i <= iac_nharvest) then + call seq_flds_add(z2x_states,trim('Sz_harvest_frac' //pftstr)) + if(add_iac_to_cplstate)call seq_flds_add(x2l_states,trim('Sz_harvest_frac' //pftstr)) + longname = 'Harvest fraction of vegetated land unit for category ' //pftstr + stdname = 'iac_harvest_frac' //pftstr + stdname = trim(stdname) + units = 'fraction' + attname = 'Sz_harvest_frac' //pftstr + attname = trim(attname) + call metadata_set(attname, longname, stdname, units) + end if + + end do + ! iac->atm flux. + ! Monthly values of surface, low alt, high alt co2 fluxes, so we + ! loop over 36 total fields. + do m=1,12 + ! Month index tag + write(monstr,'(I0)') m + monstr=trim(monstr) + + if(add_iac_to_cplstate)call seq_flds_add(z2x_fluxes,trim("Fazz_co2sfc_mon" //monstr)) + if(add_iac_to_cplstate)call seq_flds_add(x2a_fluxes,trim("Fazz_co2sfc_mon" //monstr)) + longname = trim('Surface flux of CO2 from iac for month' //monstr) + stdname = trim('surface_upward_flux_of_carbon_dioxide_from_iac_mon' //monstr) + units = 'moles m-2 s-1' + attname = trim('Fazz_co2sfc_mon' //monstr) + call metadata_set(attname, longname, stdname, units) + + if(add_iac_to_cplstate)call seq_flds_add(z2x_fluxes,trim("Fazz_co2airlo_mon" //monstr)) + if(add_iac_to_cplstate)call seq_flds_add(x2a_fluxes,trim("Fazz_co2airlo_mon" //monstr)) + longname = trim('Low altitude flux of CO2 from iac for month' //monstr) + stdname = trim('low_alt_upward_flux_of_carbon_dioxide_from_iac_mon' //monstr) + units = 'moles m-2 s-1' + attname = trim('Fazz_co2airlo_mon' //monstr) + call metadata_set(attname, longname, stdname, units) + + if(add_iac_to_cplstate)call seq_flds_add(z2x_fluxes,trim("Fazz_co2airhi_mon" //monstr)) + if(add_iac_to_cplstate)call seq_flds_add(x2a_fluxes,trim("Fazz_co2airhi_mon" //monstr)) + longname = trim('High altitude flux of CO2 from iac for month' //monstr) + stdname = trim('high_alt_upward_flux_of_carbon_dioxide_from_iac_mon' //monstr) + units = 'moles m-2 s-1' + attname = trim('Fazz_co2airhi_mon' //monstr) + call metadata_set(attname, longname, stdname, units) + end do !----------------------------- ! New xao_states diagnostic ! fields for history output only @@ -4067,6 +4237,8 @@ subroutine seq_flds_set(nmlfile, ID, infodata) seq_flds_x2r_states = trim(x2r_states) seq_flds_w2x_states = trim(w2x_states) seq_flds_x2w_states = trim(x2w_states) + seq_flds_x2z_states = trim(x2z_states) + seq_flds_z2x_states = trim(z2x_states) seq_flds_dom_other = trim(dom_other ) seq_flds_a2x_fluxes = trim(a2x_fluxes) @@ -4092,10 +4264,14 @@ subroutine seq_flds_set(nmlfile, ID, infodata) seq_flds_x2r_fluxes = trim(x2r_fluxes) seq_flds_w2x_fluxes = trim(w2x_fluxes) seq_flds_x2w_fluxes = trim(x2w_fluxes) + seq_flds_z2x_fluxes = trim(z2x_fluxes) + seq_flds_x2z_fluxes = trim(x2z_fluxes) seq_flds_r2o_liq_fluxes = trim(r2o_liq_fluxes) seq_flds_r2o_ice_fluxes = trim(r2o_ice_fluxes) seq_flds_o2x_states_to_rof = trim(o2x_states_to_rof) seq_flds_o2x_fluxes_to_rof = trim(o2x_fluxes_to_rof) + seq_flds_o2x_states_to_lnd = trim(o2x_states_to_lnd) + seq_flds_o2x_fluxes_to_lnd = trim(o2x_fluxes_to_lnd) if (seq_comm_iamroot(ID)) then write(logunit,*) subname//': seq_flds_a2x_states= ',trim(seq_flds_a2x_states) @@ -4147,6 +4323,11 @@ subroutine seq_flds_set(nmlfile, ID, infodata) write(logunit,*) subname//': seq_flds_x2w_states= ',trim(seq_flds_x2w_states) write(logunit,*) subname//': seq_flds_x2w_fluxes= ',trim(seq_flds_x2w_fluxes) write(logunit,*) subname//': seq_flds_o2x_states_to_rof=',trim(seq_flds_o2x_states_to_rof) + write(logunit,*) subname//': seq_flds_z2x_states= ',trim(seq_flds_z2x_states) + write(logunit,*) subname//': seq_flds_z2x_fluxes= ',trim(seq_flds_z2x_fluxes) + write(logunit,*) subname//': seq_flds_x2z_states= ',trim(seq_flds_x2z_states) + write(logunit,*) subname//': seq_flds_x2z_fluxes= ',trim(seq_flds_x2z_fluxes) + write(logunit,*) subname//': seq_flds_o2x_states_to_lnd=',trim(seq_flds_o2x_states_to_lnd) end if call catFields(seq_flds_dom_fields, seq_flds_dom_coord , seq_flds_dom_other ) @@ -4172,6 +4353,9 @@ subroutine seq_flds_set(nmlfile, ID, infodata) call catFields(seq_flds_w2x_fields, seq_flds_w2x_states, seq_flds_w2x_fluxes) call catFields(seq_flds_x2w_fields, seq_flds_x2w_states, seq_flds_x2w_fluxes) call catFields(seq_flds_o2x_fields_to_rof, seq_flds_o2x_states_to_rof, seq_flds_o2x_fluxes_to_rof) + call catFields(seq_flds_z2x_fields, seq_flds_z2x_states, seq_flds_z2x_fluxes) + call catFields(seq_flds_x2z_fields, seq_flds_x2z_states, seq_flds_x2z_fluxes) + call catFields(seq_flds_o2x_fields_to_lnd, seq_flds_o2x_states_to_lnd, seq_flds_o2x_fluxes_to_lnd) if (seq_comm_iamroot(ID)) then write(logunit,*) subname//': seq_flds_dom_fields= ',trim(seq_flds_dom_fields) diff --git a/driver-moab/shr/seq_infodata_mod.F90 b/driver-moab/shr/seq_infodata_mod.F90 index 35a1723e8bb8..3a173686cf3c 100644 --- a/driver-moab/shr/seq_infodata_mod.F90 +++ b/driver-moab/shr/seq_infodata_mod.F90 @@ -195,6 +195,7 @@ MODULE seq_infodata_mod logical :: rofice_present ! does rof have iceberg coupling on logical :: rof_prognostic ! does rof component need input data logical :: rofocn_prognostic ! does component need ocn data + logical :: lndocn_prognostic ! does component need ocn data logical :: flood_present ! does rof have flooding on logical :: ocn_present ! does component model exist logical :: ocn_prognostic ! does component model need input data from driver @@ -771,6 +772,7 @@ SUBROUTINE seq_infodata_Init( infodata, nmlfile, ID, pioid, cpl_tag) infodata%lnd_prognostic = .false. infodata%rof_prognostic = .false. infodata%rofocn_prognostic = .false. + infodata%lndocn_prognostic = .false. infodata%ocn_prognostic = .false. infodata%ocnrof_prognostic = .false. infodata%ocn_c2_glcshelf = .false. @@ -1023,7 +1025,7 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ single_column, scmlat,scmlon,logFilePostFix, outPathRoot,& scm_multcols, scm_nx, scm_ny, & atm_present, atm_prognostic, & - lnd_present, lnd_prognostic, & + lnd_present, lnd_prognostic, lndocn_prognostic, & rof_present, rof_prognostic, rofocn_prognostic, & ocn_present, ocn_prognostic, ocnrof_prognostic, & ocn_c2_glcshelf, ocn_c2_glctf, & @@ -1193,6 +1195,7 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ logical, optional, intent(OUT) :: atm_prognostic ! need data logical, optional, intent(OUT) :: lnd_present logical, optional, intent(OUT) :: lnd_prognostic + logical, optional, intent(OUT) :: lndocn_prognostic logical, optional, intent(OUT) :: rof_present logical, optional, intent(OUT) :: rofice_present logical, optional, intent(OUT) :: rof_prognostic @@ -1389,6 +1392,7 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ if ( present(atm_prognostic) ) atm_prognostic = infodata%atm_prognostic if ( present(lnd_present) ) lnd_present = infodata%lnd_present if ( present(lnd_prognostic) ) lnd_prognostic = infodata%lnd_prognostic + if ( present(lndocn_prognostic) ) lndocn_prognostic = infodata%lndocn_prognostic if ( present(rof_present) ) rof_present = infodata%rof_present if ( present(rofice_present) ) rofice_present = infodata%rofice_present if ( present(rof_prognostic) ) rof_prognostic = infodata%rof_prognostic @@ -1597,7 +1601,7 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ single_column, scmlat,scmlon,logFilePostFix, outPathRoot, & scm_multcols, scm_nx, scm_ny, & atm_present, atm_prognostic, & - lnd_present, lnd_prognostic, & + lnd_present, lnd_prognostic, lndocn_prognostic, & rof_present, rof_prognostic, rofocn_prognostic, & ocn_present, ocn_prognostic, ocnrof_prognostic, & ocn_c2_glcshelf, ocn_c2_glctf, & @@ -1768,6 +1772,7 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ logical, optional, intent(IN) :: atm_prognostic ! need data logical, optional, intent(IN) :: lnd_present logical, optional, intent(IN) :: lnd_prognostic + logical, optional, intent(IN) :: lndocn_prognostic logical, optional, intent(IN) :: rof_present logical, optional, intent(IN) :: rofice_present logical, optional, intent(IN) :: rof_prognostic @@ -1963,6 +1968,7 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ if ( present(atm_prognostic) ) infodata%atm_prognostic = atm_prognostic if ( present(lnd_present) ) infodata%lnd_present = lnd_present if ( present(lnd_prognostic) ) infodata%lnd_prognostic = lnd_prognostic + if ( present(lndocn_prognostic) ) infodata%lndocn_prognostic = lndocn_prognostic if ( present(rof_present) ) infodata%rof_present = rof_present if ( present(rofice_present) ) infodata%rofice_present = rofice_present if ( present(rof_prognostic) ) infodata%rof_prognostic = rof_prognostic @@ -2281,6 +2287,7 @@ subroutine seq_infodata_bcast(infodata,mpicom) call shr_mpi_bcast(infodata%atm_prognostic, mpicom) call shr_mpi_bcast(infodata%lnd_present, mpicom) call shr_mpi_bcast(infodata%lnd_prognostic, mpicom) + call shr_mpi_bcast(infodata%lndocn_prognostic, mpicom) call shr_mpi_bcast(infodata%rof_present, mpicom) call shr_mpi_bcast(infodata%rofice_present, mpicom) call shr_mpi_bcast(infodata%rof_prognostic, mpicom) @@ -2558,6 +2565,7 @@ subroutine seq_infodata_Exchange(infodata,ID,type) if (lnd2cpli) then call shr_mpi_bcast(infodata%lnd_present, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_prognostic, mpicom, pebcast=cmppe) + call shr_mpi_bcast(infodata%lndocn_prognostic, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_nx, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_ny, mpicom, pebcast=cmppe) call shr_mpi_bcast(infodata%lnd_domain, mpicom, pebcast=cmppe) @@ -2659,6 +2667,7 @@ subroutine seq_infodata_Exchange(infodata,ID,type) call shr_mpi_bcast(infodata%atm_prognostic, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%lnd_present, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%lnd_prognostic, mpicom, pebcast=cplpe) + call shr_mpi_bcast(infodata%lndocn_prognostic, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%rof_present, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%rofice_present, mpicom, pebcast=cplpe) call shr_mpi_bcast(infodata%rof_prognostic, mpicom, pebcast=cplpe) @@ -3015,6 +3024,7 @@ SUBROUTINE seq_infodata_print( infodata ) write(logunit,F0L) subname,'atm_prognostic = ', infodata%atm_prognostic write(logunit,F0L) subname,'lnd_present = ', infodata%lnd_present write(logunit,F0L) subname,'lnd_prognostic = ', infodata%lnd_prognostic + write(logunit,F0L) subname,'lndocn_prognostic = ', infodata%lndocn_prognostic write(logunit,F0L) subname,'rof_present = ', infodata%rof_present write(logunit,F0L) subname,'rofice_present = ', infodata%rofice_present write(logunit,F0L) subname,'rof_prognostic = ', infodata%rof_prognostic From 0b7a7fb92f678bce760b734fb44600defab5f81a Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 17 Dec 2025 18:43:39 -0700 Subject: [PATCH 241/398] EAMxx: fix typo in Quantity operator overload --- components/eamxx/src/share/util/eamxx_quantity.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/share/util/eamxx_quantity.hpp b/components/eamxx/src/share/util/eamxx_quantity.hpp index 82f3f8115f79..0dd68b2f0ee9 100644 --- a/components/eamxx/src/share/util/eamxx_quantity.hpp +++ b/components/eamxx/src/share/util/eamxx_quantity.hpp @@ -46,7 +46,7 @@ constexpr auto operator* (const Quantity& l, const S2 r) template constexpr auto operator/ (const Quantity& l, const Quantity& r) { - return create_quantity(l.value/r.value,l.units*r.units); + return create_quantity(l.value/r.value,l.units/r.units); } template constexpr auto operator/ (const S1 l, const Quantity& r) From 4ba07d8fdf01ef256e11be1e1140c4c4c1c10a25 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 18 Dec 2025 16:52:36 +0100 Subject: [PATCH 242/398] Fix undefined behavior in MPAS registry parser With `gcc` v13.3.0, I'm seeing unparsable `if (Active .or. analysisModeActive)` clauses in the file `components/mpas-ocean/src/inc/structs_and_variables.inc` generated by the registry parser. The issue appears to be that the registry parser is reading from and writing to the same string in statements like: ``` sprintf(out_packages, "%s;%s", out_packages, token); ``` This is not allowed, as it can lead to race conditions and bad output like I am seeing. This fix avoids this undefined behavior when appending to `out_packages` in the registry parser. --- .../src/tools/registry/gen_inc.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/components/mpas-framework/src/tools/registry/gen_inc.c b/components/mpas-framework/src/tools/registry/gen_inc.c index 03403e0d0dda..5caf4049a283 100644 --- a/components/mpas-framework/src/tools/registry/gen_inc.c +++ b/components/mpas-framework/src/tools/registry/gen_inc.c @@ -176,6 +176,7 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ const char *name; char *token, *string, *tofree; + char out_packages_tmp[2048]; int empty_packages; int empty_struct; @@ -227,12 +228,14 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ if(out_packages[0] == '\0'){ sprintf(out_packages, "%s", token); } else if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + snprintf(out_packages_tmp, sizeof(out_packages_tmp), "%s;%s", out_packages, token); + snprintf(out_packages, 2048, "%s", out_packages_tmp); } while( (token = strsep(&string, ";")) != NULL){ if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + snprintf(out_packages_tmp, sizeof(out_packages_tmp), "%s;%s", out_packages, token); + snprintf(out_packages, 2048, "%s", out_packages_tmp); } } @@ -251,12 +254,14 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ if(out_packages[0] == '\0'){ sprintf(out_packages, "%s", token); } else if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + snprintf(out_packages_tmp, sizeof(out_packages_tmp), "%s;%s", out_packages, token); + snprintf(out_packages, 2048, "%s", out_packages_tmp); } while( (token = strsep(&string, ";")) != NULL){ if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + snprintf(out_packages_tmp, sizeof(out_packages_tmp), "%s;%s", out_packages, token); + snprintf(out_packages, 2048, "%s", out_packages_tmp); } } @@ -277,12 +282,14 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ if(out_packages[0] == '\0'){ sprintf(out_packages, "%s", token); } else if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + snprintf(out_packages_tmp, sizeof(out_packages_tmp), "%s;%s", out_packages, token); + snprintf(out_packages, 2048, "%s", out_packages_tmp); } while( (token = strsep(&string, ";")) != NULL){ if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + snprintf(out_packages_tmp, sizeof(out_packages_tmp), "%s;%s", out_packages, token); + snprintf(out_packages, 2048, "%s", out_packages_tmp); } } From 6b2926b874366b6e2026e60b9bddc01c55c731f6 Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Thu, 18 Dec 2025 12:12:10 -0800 Subject: [PATCH 243/398] Fix typo in PE layout description. --- components/elm/cime_config/config_pes.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/cime_config/config_pes.xml b/components/elm/cime_config/config_pes.xml index dbcbe38bbaac..5b03e2ce3db7 100644 --- a/components/elm/cime_config/config_pes.xml +++ b/components/elm/cime_config/config_pes.xml @@ -536,7 +536,7 @@ - pm-cpu: IG-case testing config. using 4-to-40km (mde res) GIS init. cond. + pm-cpu: IG-case testing config. using 4-to-40km (med-res) GIS init. cond. 128 128 @@ -573,7 +573,7 @@ - chrys: IG-case testing config. using 4-to-40km (mde res) GIS init. cond. + chrys: IG-case testing config. using 4-to-40km (med-res) GIS init. cond. 64 64 From 2ed318fed2070f526590d175c7033d4e018a42ff Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 18 Dec 2025 16:12:25 -0500 Subject: [PATCH 244/398] Use better way of setting offload-arch --- .../machines/cmake_macros/crayamd-mphipcc_frontier.cmake | 3 ++- cime_config/machines/cmake_macros/craygnu-mphipcc.cmake | 4 +++- cime_config/machines/cmake_macros/gnugpu_frontier.cmake | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake b/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake index 1deebdac85dc..e82871185881 100644 --- a/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake +++ b/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake @@ -13,7 +13,8 @@ string(APPEND CMAKE_C_FLAGS_RELEASE " -O2") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") string(APPEND CMAKE_Fortran_FLAGS_RELEASE " -O2") -string(APPEND CMAKE_CXX_FLAGS " --offload-arch=gfx90a") +set(AMDGPU_TARGETS "gfx90a") +set(GPU_TARGETS "gfx90a") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/cray/pe/gcc/12.2.0/snos/lib64 -lgfortran -lstdc++") string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On") diff --git a/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake b/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake index b8cb9fb3ca44..efae431ebff9 100644 --- a/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake +++ b/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake @@ -40,4 +40,6 @@ endif() string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=Off") set(USE_HIP "TRUE") -string(APPEND CMAKE_HIP_FLAGS "$ENV{CXXFLAGS} --offload-arch=gfx90a -munsafe-fp-atomics") +set(AMDGPU_TARGETS "gfx90a") +set(GPU_TARGETS "gfx90a") +string(APPEND CMAKE_HIP_FLAGS "$ENV{CXXFLAGS} -munsafe-fp-atomics") diff --git a/cime_config/machines/cmake_macros/gnugpu_frontier.cmake b/cime_config/machines/cmake_macros/gnugpu_frontier.cmake index 7a29a5ca1546..7ef68f1b4d6c 100644 --- a/cime_config/machines/cmake_macros/gnugpu_frontier.cmake +++ b/cime_config/machines/cmake_macros/gnugpu_frontier.cmake @@ -15,7 +15,8 @@ string(APPEND CMAKE_C_FLAGS_RELEASE " -O2") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") string(APPEND CMAKE_Fortran_FLAGS_RELEASE " -O2") -string(APPEND CMAKE_CXX_FLAGS " --offload-arch=gfx90a") +set(AMDGPU_TARGETS "gfx90a") +set(GPU_TARGETS "gfx90a") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{ROCM_PATH}/lib -lamdhip64") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/cray/pe/gcc/12.2.0/snos/lib64 -lgfortran -lstdc++") From 40ffd321f87ed5ea47c5a6a1f1ef81603b47d333 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 18 Dec 2025 16:12:57 -0500 Subject: [PATCH 245/398] Add frontier_slurm as a valid batch value --- driver-mct/cime_config/config_component.xml | 2 +- driver-moab/cime_config/config_component.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-mct/cime_config/config_component.xml b/driver-mct/cime_config/config_component.xml index 75469c5babd6..60e5034bb87f 100644 --- a/driver-mct/cime_config/config_component.xml +++ b/driver-mct/cime_config/config_component.xml @@ -556,7 +556,7 @@ char none - miller_slurm,nersc_slurm,lc_slurm,moab,pbs,pbspro,lsf,slurm,cobalt,cobalt_theta,slurm_single_node,none + frontier_slurm,miller_slurm,nersc_slurm,lc_slurm,moab,pbs,pbspro,lsf,slurm,cobalt,cobalt_theta,slurm_single_node,none config_batch env_batch.xml The batch system type to use for this machine. diff --git a/driver-moab/cime_config/config_component.xml b/driver-moab/cime_config/config_component.xml index b6dbd33f033b..8af38ad31071 100644 --- a/driver-moab/cime_config/config_component.xml +++ b/driver-moab/cime_config/config_component.xml @@ -556,7 +556,7 @@ char none - miller_slurm,nersc_slurm,lc_slurm,moab,pbs,pbspro,lsf,slurm,cobalt,cobalt_theta,slurm_single_node,none + frontier_slurm,miller_slurm,nersc_slurm,lc_slurm,moab,pbs,pbspro,lsf,slurm,cobalt,cobalt_theta,slurm_single_node,none config_batch env_batch.xml The batch system type to use for this machine. From 9acd5b43ef52a4889b64bd3272555286b5f702ce Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Thu, 18 Dec 2025 17:11:56 -0600 Subject: [PATCH 246/398] Add temporary paths to new runoff spreading files for testing. --- cime_config/config_grids.xml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index 27b26e2a9702..36882ac9352a 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -6466,8 +6466,18 @@ cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_esmfaave.20240403.nc cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_esmfaave.20240403.nc cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_esmfaave.20240403.nc - cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_nn.20250326.nc - cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5-nomask_nn.20250403.nc + + + /home/ac.sprice/temp/runoffSpreadingMaps/map_gis1to10kmR2_to_IcoswISC30E3r5_r50e100.cstmnn.20250326.nc + /home/ac.sprice/temp/runoffSpreadingMaps/map_gis1to10kmR2_to_IcoswISC30E3r5-nomask_r50e100.cstmnn.20250403.nc + + + From 1caa5cad8130377871262f5e855732b0203998e8 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 19 Dec 2025 14:52:10 -0500 Subject: [PATCH 247/398] Set GPU target for craycray-mphipcc --- cime_config/machines/cmake_macros/craycray-mphipcc.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cime_config/machines/cmake_macros/craycray-mphipcc.cmake b/cime_config/machines/cmake_macros/craycray-mphipcc.cmake index 0346104eda30..cb2df6134e22 100644 --- a/cime_config/machines/cmake_macros/craycray-mphipcc.cmake +++ b/cime_config/machines/cmake_macros/craycray-mphipcc.cmake @@ -26,3 +26,6 @@ set(MPIFC "ftn") set(SCC "cc") set(SCXX "CC") set(SFC "ftn") + +set(AMDGPU_TARGETS "gfx90a") +set(GPU_TARGETS "gfx90a") From d3ded93dbd4c6ce2532383438a23629c630b4409 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 19 Dec 2025 15:01:16 -0500 Subject: [PATCH 248/398] Try bumping up PES on frontier --- components/eamxx/cime_config/config_pes.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/eamxx/cime_config/config_pes.xml b/components/eamxx/cime_config/config_pes.xml index ecf5b4a3abbf..b51a46d52426 100644 --- a/components/eamxx/cime_config/config_pes.xml +++ b/components/eamxx/cime_config/config_pes.xml @@ -259,14 +259,14 @@ - frontier conus 2 nodes, 8x1 except 7 threads in LND + frontier conus 4 nodes, 8x1 except 7 threads in LND - -2 - -2 - -2 - -2 - -2 - -2 + -4 + -4 + -4 + -4 + -4 + -4 -1 -1 From d85287a77c6d93c87697d35de7ff87c7ef97391e Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 19 Dec 2025 15:34:15 -0700 Subject: [PATCH 249/398] EAMxx: allow requesting physics constants in output streams --- .../eamxx/src/share/io/eamxx_output_manager.cpp | 10 ++++++++++ .../eamxx/src/share/io/tests/io_basic.cpp | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/components/eamxx/src/share/io/eamxx_output_manager.cpp b/components/eamxx/src/share/io/eamxx_output_manager.cpp index 7bee9e085c1a..5ed701992149 100644 --- a/components/eamxx/src/share/io/eamxx_output_manager.cpp +++ b/components/eamxx/src/share/io/eamxx_output_manager.cpp @@ -2,6 +2,7 @@ #include "share/scorpio_interface/eamxx_scorpio_interface.hpp" #include "share/io/scorpio_input.hpp" +#include "share/physics/physics_constants.hpp" #include "share/util/eamxx_timing.hpp" #include "share/core/eamxx_config.hpp" @@ -854,6 +855,15 @@ setup_file ( IOFileSpecs& filespecs, } scorpio::set_attribute(filename,"GLOBAL","fp_precision",fp_precision); set_file_header(filespecs); + + const auto& pc_names = m_params.get>("constants",{}); + const auto& pc_dict = physics::Constants::dictionary(); + for (const auto& n: pc_names) { + const auto& c = pc_dict.at(n); + scorpio::define_var (filename, n, c.units.to_string(), {}, + "real", "real", false); + scorpio::write_var (filename, n, &c.value); + } } // Make all output streams register their dims/vars diff --git a/components/eamxx/src/share/io/tests/io_basic.cpp b/components/eamxx/src/share/io/tests/io_basic.cpp index 3cd83633336c..ef0230875ebb 100644 --- a/components/eamxx/src/share/io/tests/io_basic.cpp +++ b/components/eamxx/src/share/io/tests/io_basic.cpp @@ -11,6 +11,7 @@ #include "share/util/eamxx_universal_constants.hpp" #include "share/core/eamxx_setup_random_test.hpp" +#include "share/physics/physics_constants.hpp" #include "share/util/eamxx_time_stamp.hpp" #include "share/core/eamxx_types.hpp" @@ -143,6 +144,8 @@ void write (const std::string& avg_type, const std::string& freq_units, ctrl_pl.set("frequency_units",freq_units); ctrl_pl.set("frequency",freq); ctrl_pl.set("save_grid_data",false); + // Also test writing physics constants to file + om_pl.set("constants",std::vector{"gravit","Rgas"}); // While setting this is in practice irrelevant (we would close // the file anyways at the end of the run), we can test that the OM closes @@ -270,6 +273,20 @@ void read (const std::string& avg_type, const std::string& freq_units, auto att_str = scorpio::get_attribute(filename,fn,"test"); REQUIRE (att_str==fn); } + + // Check constants + Real Rgas_v, gravit_v; + + auto Rgas_u = scorpio::get_attribute(filename,"Rgas","units"); + auto gravit_u = scorpio::get_attribute(filename,"gravit","units"); + scorpio::read_var(filename,"Rgas",&Rgas_v); + scorpio::read_var(filename,"gravit",&gravit_v); + + const auto& dict = physics::Constants::dictionary(); + REQUIRE (Rgas_u==dict.at("Rgas").units.to_string()); + REQUIRE (gravit_u==dict.at("gravit").units.to_string()); + REQUIRE (Rgas_v==dict.at("Rgas").value); + REQUIRE (gravit_v==dict.at("gravit").value); } TEST_CASE ("io_basic") { From cfc21750fd80a44320b755969d6bfafed13f1781 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 10:23:01 -0700 Subject: [PATCH 250/398] Removes execute permission on files --- components/elm/src/biogeochem/FanMod.F90 | 0 components/elm/src/biogeophys/BalanceCheckMod.F90 | 0 components/elm/src/biogeophys/CanopyFluxesMod.F90 | 0 components/elm/src/biogeophys/CanopyHydrologyMod.F90 | 0 components/elm/src/biogeophys/HydrologyDrainageMod.F90 | 0 components/elm/src/cpl/lnd_disagg_forc.F90 | 0 components/elm/src/dyn_subgrid/dyncropFileMod.F90 | 0 components/elm/src/main/controlMod.F90 | 0 components/elm/src/main/elm_initializeMod.F90 | 0 components/elm/src/main/elm_varsur.F90 | 0 components/elm/src/main/initVerticalMod.F90 | 0 components/elm/src/main/subgridRestMod.F90 | 0 components/elm/src/main/subgridWeightsMod.F90 | 0 components/elm/src/main/surfrdMod.F90 | 0 components/elm/src/utils/domainMod.F90 | 0 15 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 components/elm/src/biogeochem/FanMod.F90 mode change 100755 => 100644 components/elm/src/biogeophys/BalanceCheckMod.F90 mode change 100755 => 100644 components/elm/src/biogeophys/CanopyFluxesMod.F90 mode change 100755 => 100644 components/elm/src/biogeophys/CanopyHydrologyMod.F90 mode change 100755 => 100644 components/elm/src/biogeophys/HydrologyDrainageMod.F90 mode change 100755 => 100644 components/elm/src/cpl/lnd_disagg_forc.F90 mode change 100755 => 100644 components/elm/src/dyn_subgrid/dyncropFileMod.F90 mode change 100755 => 100644 components/elm/src/main/controlMod.F90 mode change 100755 => 100644 components/elm/src/main/elm_initializeMod.F90 mode change 100755 => 100644 components/elm/src/main/elm_varsur.F90 mode change 100755 => 100644 components/elm/src/main/initVerticalMod.F90 mode change 100755 => 100644 components/elm/src/main/subgridRestMod.F90 mode change 100755 => 100644 components/elm/src/main/subgridWeightsMod.F90 mode change 100755 => 100644 components/elm/src/main/surfrdMod.F90 mode change 100755 => 100644 components/elm/src/utils/domainMod.F90 diff --git a/components/elm/src/biogeochem/FanMod.F90 b/components/elm/src/biogeochem/FanMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/biogeophys/CanopyFluxesMod.F90 b/components/elm/src/biogeophys/CanopyFluxesMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/cpl/lnd_disagg_forc.F90 b/components/elm/src/cpl/lnd_disagg_forc.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/dyn_subgrid/dyncropFileMod.F90 b/components/elm/src/dyn_subgrid/dyncropFileMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/elm_initializeMod.F90 b/components/elm/src/main/elm_initializeMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/elm_varsur.F90 b/components/elm/src/main/elm_varsur.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/subgridRestMod.F90 b/components/elm/src/main/subgridRestMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/subgridWeightsMod.F90 b/components/elm/src/main/subgridWeightsMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/main/surfrdMod.F90 b/components/elm/src/main/surfrdMod.F90 old mode 100755 new mode 100644 diff --git a/components/elm/src/utils/domainMod.F90 b/components/elm/src/utils/domainMod.F90 old mode 100755 new mode 100644 From 4c6ec9521ff91661f101060a0cd4eccd01439f2c Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 07:39:25 -0700 Subject: [PATCH 251/398] Uses a locally defined variable for landunit index --- components/elm/src/biogeochem/FanUpdateMod.F90 | 14 ++++++++------ components/elm/src/biogeophys/SoilHydrologyMod.F90 | 10 ++++++---- components/elm/src/biogeophys/SurfaceAlbedoMod.F90 | 5 +++-- components/elm/src/main/initGridCellsMod.F90 | 7 ++++--- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/components/elm/src/biogeochem/FanUpdateMod.F90 b/components/elm/src/biogeochem/FanUpdateMod.F90 index fbb0e0467ab9..d09889294e28 100644 --- a/components/elm/src/biogeochem/FanUpdateMod.F90 +++ b/components/elm/src/biogeochem/FanUpdateMod.F90 @@ -319,7 +319,7 @@ subroutine fan_eval(bounds, num_soilc, filter_soilc, & ! Find and average the atmospheric resistances Rb and Ra. ! - if (lun_pp%itype(col_pp%landunit(c)) == istcrop) then + if (lun_pp%itype(l) == istcrop) then ! Crop column, only one patch p = col_pp%pfti(c) if (p /= col_pp%pftf(c)) call endrun(msg='Strange patch for crop') @@ -885,11 +885,12 @@ subroutine update_summary(filter_soilc, num_soilc) integer, intent(in) :: num_soilc ! number of soil columns in filter integer, intent(in) :: filter_soilc(:) ! filter for soil columns - integer :: c, fc + integer :: c, l, fc real(r8) :: total, fluxout, fluxin, flux_loss do fc = 1, num_soilc c = filter_soilc(fc) + l = col_pp%landunit(c) if (.not. col_pp%active(c) .or. col_pp%wtgcell(c) < 1.e-15_r8) cycle total = col_ns%tan_g1(c) + col_ns%tan_g2(c) + col_ns%tan_g3(c) total = total + col_ns%manure_u_grz(c) + col_ns%manure_a_grz(c) + col_ns%manure_r_grz(c) @@ -900,7 +901,7 @@ subroutine update_summary(filter_soilc, num_soilc) total = total + col_ns%manure_n_stored(c) col_ns%fan_totn(c) = total - if (lun_pp%itype(col_pp%landunit(c)) == istcrop) then + if (lun_pp%itype(l) == istcrop) then ! no grazing, manure_n_appl is from the same column and not counted as input fluxin = col_nf%manure_n_mix(c) + col_nf%fert_n_appl(c) else @@ -939,7 +940,7 @@ subroutine fan_to_sminn(bounds, filter_soilc, num_soilc, nfertilization) ! patch level fertilizer application + manure production real(r8), intent(inout) :: nfertilization(bounds%begp:) - integer :: c, fc, p + integer :: c, l, fc, p real(r8) :: flux_manure, flux_fert, manure_prod logical :: included @@ -947,12 +948,13 @@ subroutine fan_to_sminn(bounds, filter_soilc, num_soilc, nfertilization) do fc = 1, num_soilc c = filter_soilc(fc) + l = col_pp%landunit(c) flux_manure = col_nf%manure_no3_to_soil(c) + col_nf%manure_nh4_to_soil(c) flux_fert = col_nf%fert_no3_to_soil(c) + col_nf%fert_nh4_to_soil(c) manure_prod = col_nf%manure_n_barns(c) + col_nf%manure_n_grz(c) - included = (lun_pp%itype(col_pp%landunit(c)) == istcrop .and. fan_to_bgc_crop) & - .or. (lun_pp%itype(col_pp%landunit(c)) == istsoil .and. fan_to_bgc_veg) + included = (lun_pp%itype(l) == istcrop .and. fan_to_bgc_crop) & + .or. (lun_pp%itype(l) == istsoil .and. fan_to_bgc_veg) if (included) then col_nf%fert_to_sminn(c) = flux_fert + flux_manure diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index c4c7f4d9bc28..a5e7118e079d 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -444,10 +444,11 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) g = cgridcell(c) + l = col_pp%landunit(c) pc = pc_grid(g) ! partition moisture fluxes between soil and h2osfc - if (lun_pp%itype(col_pp%landunit(c)) == istsoil .or. lun_pp%itype(col_pp%landunit(c))==istcrop) then + if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l)==istcrop) then ! explicitly use frac_sno=0 if snl=0 if (snl(c) >= 0) then @@ -1114,7 +1115,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte ! ! !LOCAL VARIABLES: !character(len=32) :: subname = 'Drainage' ! subroutine name - integer :: c,g,j,fc,i ! indices + integer :: c,g,l,j,fc,i ! indices integer :: nlevbed ! # layers to bedrock real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevgrnd) ! layer thickness (mm) @@ -1655,6 +1656,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) + l = lun_pp%landuse(c) !scs: watmin addition to fix water balance errors xs1(c) = max(max(h2osoi_liq(c,1)-watmin,0._r8)- & @@ -1662,7 +1664,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte if (use_vsfm) xs1(c) = 0._r8 h2osoi_liq(c,1) = h2osoi_liq(c,1) - xs1(c) - if (lun_pp%urbpoi(col_pp%landunit(c))) then + if (lun_pp%urbpoi(l)) then qflx_rsub_sat(c) = xs1(c) / dtime else if(h2osfcflag == 1) then @@ -1680,7 +1682,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte ! add in ice check xs1(c) = max(max(h2osoi_ice(c,1),0._r8)-max(0._r8,(pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_liq(c,1))),0._r8) h2osoi_ice(c,1) = min(max(0._r8,pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_liq(c,1)), h2osoi_ice(c,1)) - if ( (lun_pp%itype(col_pp%landunit(c)) == istice .or. lun_pp%itype(col_pp%landunit(c)) == istice_mec) .or. (.not. use_firn_percolation_and_compaction)) then + if ( (lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec) .or. (.not. use_firn_percolation_and_compaction)) then qflx_snwcp_ice(c) = qflx_snwcp_ice(c) + xs1(c) / dtime else qflx_ice_runoff_xs(c) = qflx_ice_runoff_xs(c) + xs1(c) / dtime diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 4aed983b0ae0..f04a2fdb7bda 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -116,7 +116,7 @@ subroutine SurfaceAlbedo(bounds, & integer :: i ! index for layers [idx] integer :: aer ! index for sno_nbr_aer real(r8) :: extkn ! nitrogen allocation coefficient - integer :: fp,fc,g,c,p,iv ! indices + integer :: fp,fc,g,c,l,p,iv ! indices integer :: ib ! band index integer :: ic ! 0=unit incoming direct; 1=unit incoming diffuse real(r8) :: dinc ! lai+sai increment for canopy layer @@ -652,6 +652,7 @@ subroutine SurfaceAlbedo(bounds, & do ib = 1, nband do fc = 1,num_nourbanc c = filter_nourbanc(fc) + l = lun_pp%landunit(c) if (coszen_col(c) > 0._r8) then ! ground albedo was originally computed in SoilAlbedo, but is now computed here ! because the order of SoilAlbedo and SNICAR_RT/SNICAR_AD_RT was switched for SNICAR/SNICAR_AD_RT. @@ -683,7 +684,7 @@ subroutine SurfaceAlbedo(bounds, & ! weight snow layer radiative absorption factors based on snow fraction and soil albedo ! (NEEDED FOR ENERGY CONSERVATION) do i = -nlevsno+1,1,1 - if (subgridflag == 0 .or. lun_pp%itype(col_pp%landunit(c)) == istdlak) then + if (subgridflag == 0 .or. lun_pp%itype(l) == istdlak) then if (ib == 1) then flx_absdv(c,i) = flx_absd_snw(c,i,ib)*frac_sno(c) + & ((1.-frac_sno(c))*(1-albsod(c,ib))*(flx_absd_snw(c,i,ib)/(1.-albsnd(c,ib)))) diff --git a/components/elm/src/main/initGridCellsMod.F90 b/components/elm/src/main/initGridCellsMod.F90 index 2d8547334eea..61e8e175c260 100644 --- a/components/elm/src/main/initGridCellsMod.F90 +++ b/components/elm/src/main/initGridCellsMod.F90 @@ -1165,10 +1165,11 @@ subroutine initGhostPatch() grid_count(:) = 0.d0 last_lun_type = -1 do c = bounds_proc%begc_all, bounds_proc%endc_all - g = col_pp%gridcell(c) - if (last_lun_type /= lun_pp%itype(col_pp%landunit(c))) then + g = col_pp%gridcell(c) + l = col_pp%landunit(c) + if (last_lun_type /= lun_pp%itype(l)) then grid_count(:) = 0.d0 - last_lun_type = lun_pp%itype(col_pp%landunit(c)) + last_lun_type = lun_pp%itype(l) endif grid_count(g) = grid_count(g) + 1.d0 col_rank(c) = grid_count(g) From 5f9337a008c58f6a8c69deee89aca7c0af15c2d8 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 07:42:06 -0700 Subject: [PATCH 252/398] Adds spaces to make it more consitent for future refactor --- .../elm/src/biogeophys/CanopyHydrologyMod.F90 | 8 ++++---- .../elm/src/biogeophys/CanopyTemperatureMod.F90 | 2 +- .../elm/src/biogeophys/HydrologyDrainageMod.F90 | 14 +++++++------- .../elm/src/biogeophys/HydrologyNoDrainageMod.F90 | 2 +- components/elm/src/biogeophys/SedYieldMod.F90 | 2 +- components/elm/src/biogeophys/SnowHydrologyMod.F90 | 4 ++-- components/elm/src/biogeophys/SoilFluxesMod.F90 | 2 +- components/elm/src/biogeophys/SoilHydrologyMod.F90 | 2 +- .../elm/src/biogeophys/SoilHydrologyType.F90 | 4 ++-- components/elm/src/biogeophys/SoilStateType.F90 | 6 +++--- .../elm/src/biogeophys/SoilTemperatureMod.F90 | 4 ++-- .../elm/src/biogeophys/SurfaceRadiationMod.F90 | 6 +++--- .../elm/src/biogeophys/TotalWaterAndHeatMod.F90 | 2 +- components/elm/src/biogeophys/WaterfluxType.F90 | 2 +- components/elm/src/data_types/ColumnDataType.F90 | 2 +- .../elm/src/data_types/VegetationDataType.F90 | 2 +- components/elm/src/main/elm_instMod.F90 | 10 +++++----- .../elm/src/main/elm_interface_pflotranMod.F90 | 8 ++++---- components/elm/src/main/initVerticalMod.F90 | 6 +++--- 19 files changed, 44 insertions(+), 44 deletions(-) diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 index 343380fa18fb..19b9d07f16c5 100644 --- a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 +++ b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 @@ -278,8 +278,8 @@ subroutine CanopyHydrology(bounds, & ! Canopy interception and precipitation onto ground surface ! Add precipitation to leaf water - if (ltype(l)==istsoil .or. ltype(l)==istwet .or. urbpoi(l) .or. & - ltype(l)==istcrop) then + if (ltype(l) == istsoil .or. ltype(l) == istwet .or. urbpoi(l) .or. & + ltype(l) == istcrop) then qflx_candrip(p) = 0._r8 ! rate of canopy runoff qflx_through_snow(p) = 0._r8 ! snow precipitation direct through canopy @@ -334,7 +334,7 @@ subroutine CanopyHydrology(bounds, & end if end if - else if (ltype(l)==istice .or. ltype(l)==istice_mec) then + else if (ltype(l) == istice .or. ltype(l) == istice_mec) then h2ocan(p) = 0._r8 qflx_candrip(p) = 0._r8 @@ -652,7 +652,7 @@ subroutine CanopyHydrology(bounds, & frac_sno_eff(c) = 1._r8 endif - if (ltype(l)==istwet .and. t_grnd(c)>tfrz) then + if (ltype(l) == istwet .and. t_grnd(c)>tfrz) then h2osno(c)=0._r8 snow_depth(c)=0._r8 end if diff --git a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 index 017c3770a91d..d03e5c401343 100644 --- a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 +++ b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 @@ -354,7 +354,7 @@ subroutine CanopyTemperature(bounds, & ! Urban emissivities are currently read in from data file if (.not. urbpoi(l)) then - if (lun_pp%itype(l)==istice .or. lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec) then emg(c) = 0.97_r8 else emg(c) = (1._r8-frac_sno(c))*0.96_r8 + frac_sno(c)*0.97_r8 diff --git a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 index 13f7563b7343..77ce2610d9bb 100644 --- a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 @@ -225,7 +225,7 @@ subroutine HydrologyDrainage(bounds, & qflx_glcice_frz(c) = 0._r8 qflx_glcice_frz_diag(c) = 0._r8 - if (lun_pp%itype(l)==istice .and. qflx_snwcp_ice(c) > 0.0_r8) then + if (lun_pp%itype(l) == istice .and. qflx_snwcp_ice(c) > 0.0_r8) then qflx_glcice_frz_diag(c) = qflx_snwcp_ice(c) qflx_glcice_diag(c) = qflx_glcice_diag(c) + qflx_glcice_frz_diag(c) endif @@ -242,7 +242,7 @@ subroutine HydrologyDrainage(bounds, & if (glc_dyn_runoff_routing(g)) qflx_snwcp_ice(c) = 0._r8 end if - !if (lun_pp%itype(l)==istice) then + !if (lun_pp%itype(l) == istice) then ! qflx_glcice_frz_diag(c) = qflx_snwcp_ice(c) ! qflx_glcice_diag(c) = qflx_glcice_diag(c) + qflx_glcice_frz_diag(c) !endif @@ -262,8 +262,8 @@ subroutine HydrologyDrainage(bounds, & tpu_ind = top_pp%topo_grc_ind(t) !Get topounit index on the grid g = col_pp%gridcell(c) - if (lun_pp%itype(l)==istwet .or. lun_pp%itype(l)==istice & - .or. lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istwet .or. lun_pp%itype(l) == istice & + .or. lun_pp%itype(l) == istice_mec) then qflx_drain(c) = 0._r8 qflx_drain_perched(c) = 0._r8 @@ -280,7 +280,7 @@ subroutine HydrologyDrainage(bounds, & ! glc_dyn_runoff_routing = true: in this case, melting ice runs off, and excess ! snow is sent to CISM, where it is converted to ice. These corrections are ! done here: - if (glc_dyn_runoff_routing(g) .and. lun_pp%itype(l)==istice_mec) then + if (glc_dyn_runoff_routing(g) .and. lun_pp%itype(l) == istice_mec) then ! this allows GLC melt to runoff to qflx_qrgwl! ! If glc_dyn_runoff_routing=T, add meltwater from istice_mec ice columns to the runoff. @@ -337,12 +337,12 @@ subroutine HydrologyDrainage(bounds, & qflx_runoff(c) = qflx_drain(c) + qflx_surf(c) + qflx_h2osfc_surf(c) + qflx_qrgwl(c) + qflx_drain_perched(c) - if ((lun_pp%itype(l)==istsoil .or. lun_pp%itype(l)==istcrop) .and. col_pp%active(c)) then + if ((lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) .and. col_pp%active(c)) then qflx_irr_demand(c) = -1.0_r8 * f_surf(g,tpu_ind)*qflx_irrig(c) !surface water demand send to MOSART end if if (lun_pp%urbpoi(l)) then qflx_runoff_u(c) = qflx_runoff(c) - else if (lun_pp%itype(l)==istsoil .or. lun_pp%itype(l)==istcrop) then + else if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then qflx_runoff_r(c) = qflx_runoff(c) end if diff --git a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 index 763bf8772b44..3d47d695f06b 100644 --- a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -451,7 +451,7 @@ subroutine HydrologyNoDrainage(bounds, & t_soi_10cm(c) = t_soi_10cm(c)/0.1_r8 tsoi17(c) = tsoi17(c)/0.17_r8 ! F. Li and S. Levis end if - if (lun_pp%itype(l)==istsoil .or. lun_pp%itype(l)==istcrop) then + if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then t_grnd_r(c) = t_soisno(c,snl(c)+1) end if diff --git a/components/elm/src/biogeophys/SedYieldMod.F90 b/components/elm/src/biogeophys/SedYieldMod.F90 index 250929f4a423..62f2db4b4565 100644 --- a/components/elm/src/biogeophys/SedYieldMod.F90 +++ b/components/elm/src/biogeophys/SedYieldMod.F90 @@ -157,7 +157,7 @@ subroutine SoilErosion (bounds, num_soilc, filter_soilc, & flx_sed_yld(c) = 0._r8 ! check landunit type and ground covered by snow/ice - if ( lun_pp%itype(l)/=istsoil .and. lun_pp%itype(l)/=istcrop ) then + if ( lun_pp%itype(l) /= istsoil .and. lun_pp%itype(l) /= istcrop ) then cycle end if diff --git a/components/elm/src/biogeophys/SnowHydrologyMod.F90 b/components/elm/src/biogeophys/SnowHydrologyMod.F90 index 57e486d0ce90..5191d96f6366 100644 --- a/components/elm/src/biogeophys/SnowHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SnowHydrologyMod.F90 @@ -650,7 +650,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & 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 + if (ltype(l) == istice_mec .and. void < 0._r8) then dz(c,j) = h2osoi_ice(c,j)/denice + h2osoi_liq(c,j)/denh2o void = 0._r8 endif @@ -1014,7 +1014,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (ltype(l) == istwet) then h2osoi_liq(c,0) = 0.0_r8 endif - if (ltype(l) == istice .or. ltype(l)==istice_mec) then + if (ltype(l) == istice .or. ltype(l) == istice_mec) then h2osoi_liq(c,0) = 0.0_r8 endif endif diff --git a/components/elm/src/biogeophys/SoilFluxesMod.F90 b/components/elm/src/biogeophys/SoilFluxesMod.F90 index 1b221a617a83..d7c64e80b0a3 100644 --- a/components/elm/src/biogeophys/SoilFluxesMod.F90 +++ b/components/elm/src/biogeophys/SoilFluxesMod.F90 @@ -377,7 +377,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & errsoi_patch(p) = errsoi_patch(p)+eflx_h2osfc_to_snow_col(c) ! For urban sunwall, shadewall, and roof columns, the "soil" energy balance check ! must include the heat flux from the interior of the building. - if (col_pp%itype(c)==icol_sunwall .or. col_pp%itype(c)==icol_shadewall .or. col_pp%itype(c)==icol_roof) then + if (col_pp%itype(c) == icol_sunwall .or. col_pp%itype(c) == icol_shadewall .or. col_pp%itype(c) == icol_roof) then errsoi_patch(p) = errsoi_patch(p) + eflx_building_heat(c) end if end do diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index a5e7118e079d..c027632aee73 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -448,7 +448,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f pc = pc_grid(g) ! partition moisture fluxes between soil and h2osfc - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l)==istcrop) then + if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then ! explicitly use frac_sno=0 if snl=0 if (snl(c) >= 0) then diff --git a/components/elm/src/biogeophys/SoilHydrologyType.F90 b/components/elm/src/biogeophys/SoilHydrologyType.F90 index 140f4385be8e..30bdd96fe6ab 100644 --- a/components/elm/src/biogeophys/SoilHydrologyType.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyType.F90 @@ -466,7 +466,7 @@ subroutine InitCold(this, bounds) ti = t - topi + 1 if (lun_pp%itype(l) /= istdlak) then ! soil columns of both urban and non-urban types - if (lun_pp%itype(l)==istwet .or. lun_pp%itype(l)==istice .or. lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istwet .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec) then ! do nothing else if (lun_pp%urbpoi(l) .and. (col_pp%itype(c) /= icol_road_perv) .and. (col_pp%itype(c) /= icol_road_imperv) )then ! do nothing @@ -516,7 +516,7 @@ subroutine InitCold(this, bounds) if (lun_pp%itype(l) /= istdlak) then ! soil columns of both urban and non-urban types if (lun_pp%urbpoi(l)) then - if (col_pp%itype(c)==icol_sunwall .or. col_pp%itype(c)==icol_shadewall .or. col_pp%itype(c)==icol_roof) then + if (col_pp%itype(c) == icol_sunwall .or. col_pp%itype(c) == icol_shadewall .or. col_pp%itype(c) == icol_roof) then ! do nothing else this%depth_col(c, 1:nlayer) = dzvic diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index c2c125af854f..1cb1d3388cec 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -611,7 +611,7 @@ subroutine InitCold(this, bounds) topi = grc_pp%topi(g) ti = t - topi + 1 - if (lun_pp%itype(l)==istwet .or. lun_pp%itype(l)==istice .or. lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istwet .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec) then do lev = 1,nlevgrnd this%bsw_col(c,lev) = spval @@ -636,7 +636,7 @@ subroutine InitCold(this, bounds) this%tkmg_col(c,lev) = spval this%tksatu_col(c,lev) = spval this%tkdry_col(c,lev) = spval - if (lun_pp%itype(l)==istwet .and. lev > nlevbed) then + if (lun_pp%itype(l) == istwet .and. lev > nlevbed) then this%csol_col(c,lev) = csol_bedrock else this%csol_col(c,lev)= spval @@ -833,7 +833,7 @@ subroutine InitCold(this, bounds) g = col_pp%gridcell(c) l = col_pp%landunit(c) - if (lun_pp%itype(l)==istdlak) then + if (lun_pp%itype(l) == istdlak) then do lev = 1,nlevgrnd if ( lev <= nlevsoi )then diff --git a/components/elm/src/biogeophys/SoilTemperatureMod.F90 b/components/elm/src/biogeophys/SoilTemperatureMod.F90 index 6826b3e22e63..9c94a6d86e6b 100644 --- a/components/elm/src/biogeophys/SoilTemperatureMod.F90 +++ b/components/elm/src/biogeophys/SoilTemperatureMod.F90 @@ -1648,7 +1648,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & ! as computed in HydrologyDrainageMod.F90. l = col_pp%landunit(c) - if ( lun_pp%itype(l)==istice_mec) then + if ( lun_pp%itype(l) == istice_mec) then if (j>=1 .and. h2osoi_liq(c,j) > 0._r8) then ! ice layer with meltwater ! melting corresponds to a negative ice flux qflx_glcice_melt(c) = qflx_glcice_melt(c) + h2osoi_liq(c,j)/dtime @@ -1662,7 +1662,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & endif ! istice_mec ! for diagnostic QICE SMB output only - ! these are to calculate SMB even without MECs - if ( lun_pp%itype(l)==istice) then + if ( lun_pp%itype(l) == istice) then if (j>=1 .and. h2osoi_liq(c,j) > 0._r8) then ! ice layer with meltwater ! melting corresponds to a negative ice flux qflx_glcice_melt_diag(c) = qflx_glcice_melt_diag(c) + h2osoi_liq(c,j)/dtime diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index 47fe244c530e..46309f0cff6c 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -484,7 +484,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & sabg(p) = 0._r8 sabv(p) = 0._r8 fsa(p) = 0._r8 - if (lun_pp%itype(l)==istsoil .or. lun_pp%itype(l)==istcrop) then + if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then fsa_r(p) = 0._r8 end if sabg_lyr(p,:) = 0._r8 @@ -521,7 +521,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & if (ib == 1) then parveg(p) = cad(p,ib) + cai(p,ib) end if - if (lun_pp%itype(l)==istsoil .or. lun_pp%itype(l)==istcrop) then + if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then fsa_r(p) = fsa_r(p) + cad(p,ib) + cai(p,ib) end if @@ -538,7 +538,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & absrad = trd(p,ib)*(1._r8-albgrd(c,ib)) + tri(p,ib)*(1._r8-albgri(c,ib)) sabg(p) = sabg(p) + absrad fsa(p) = fsa(p) + absrad - if (lun_pp%itype(l)==istsoil .or. lun_pp%itype(l)==istcrop) then + if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then fsa_r(p) = fsa_r(p) + absrad end if if (snl(c) == 0) then diff --git a/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 b/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 index f222dca037e2..376f0026c462 100644 --- a/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 +++ b/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 @@ -564,7 +564,7 @@ subroutine ComputeHeatNonLake(bounds, num_nolakec, filter_nolakec, & c = filter_nolakec(fc) l = col_pp%landunit(c) - if (col_pp%itype(c)==icol_sunwall .or. col_pp%itype(c)==icol_shadewall) then + if (col_pp%itype(c) == icol_sunwall .or. col_pp%itype(c) == icol_shadewall) then has_h2o = .false. if (j <= nlevurb) then heat_dry_mass(c) = heat_dry_mass(c) + & diff --git a/components/elm/src/biogeophys/WaterfluxType.F90 b/components/elm/src/biogeophys/WaterfluxType.F90 index 8dfb1fb00c80..404ce283d501 100644 --- a/components/elm/src/biogeophys/WaterfluxType.F90 +++ b/components/elm/src/biogeophys/WaterfluxType.F90 @@ -383,7 +383,7 @@ subroutine InitCold(this, bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) - if (lun_pp%itype(l)==istsoil) then + if (lun_pp%itype(l) == istsoil) then this%n_irrig_steps_left_patch(p) = 0 this%irrig_rate_patch(p) = 0.0_r8 end if diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index 85b4955a8efd..3a7253b436ee 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -1240,7 +1240,7 @@ subroutine col_es_init(this, begc, endc) ! Below snow temperatures - nonlake points (lake points are set below) if (.not. lun_pp%lakpoi(l)) then - if (lun_pp%itype(l)==istice .or. lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec) then this%t_soisno(c,1:nlevgrnd) = 250._r8 else if (lun_pp%itype(l) == istwet) then diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index 51670426d926..e0d90f987442 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -5588,7 +5588,7 @@ subroutine veg_wf_init(this, begp, endp) do p = begp, endp l = veg_pp%landunit(p) - if (lun_pp%itype(l)==istsoil) then + if (lun_pp%itype(l) == istsoil) then this%n_irrig_steps_left(p) = 0 this%irrig_rate(p) = 0.0_r8 end if diff --git a/components/elm/src/main/elm_instMod.F90 b/components/elm/src/main/elm_instMod.F90 index dd133e23e7b7..906325f23ec8 100644 --- a/components/elm/src/main/elm_instMod.F90 +++ b/components/elm/src/main/elm_instMod.F90 @@ -316,10 +316,10 @@ subroutine elm_inst_biogeophys(bounds_proc) g = col_pp%gridcell(c) if (.not. use_extrasnowlayers) then ! original 5 layer shallow snowpack model - if (lun_pp%itype(l)==istice) then + if (lun_pp%itype(l) == istice) then h2osno_col(c) = h2osno_max - elseif (lun_pp%itype(l)==istice_mec .or. & - (lun_pp%itype(l)==istsoil .and. ldomain%glcmask(g) > 0._r8)) then + elseif (lun_pp%itype(l) == istice_mec .or. & + (lun_pp%itype(l) == istsoil .and. ldomain%glcmask(g) > 0._r8)) then ! Initialize a non-zero snow thickness where the ice sheet can/potentially operate. ! Using glcmask to capture all potential vegetated points around GrIS (ideally ! we would use icemask from CISM, but that isn't available until after initialization.) @@ -348,11 +348,11 @@ subroutine elm_inst_biogeophys(bounds_proc) ! a small amount of snow in places that are likely to be snow-covered for much or ! all of the year. ! amschnei@uci.edu: Initializing "deep firn" for glacier columns - if (lun_pp%itype(l)==istice .or. lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec) then ! land ice (including multiple elevation classes, i.e. glacier_mec) h2osno_col(c) = 0.5_r8*h2osno_max ! start with half full snow column, representing deep firn snow_depth_col(c) = h2osno_col(c) / bdfirn - else if (lun_pp%itype(l)==istsoil .and. grc_pp%latdeg(g) >= 44._r8) then + else if (lun_pp%itype(l) == istsoil .and. grc_pp%latdeg(g) >= 44._r8) then ! Northern hemisphere seasonal snow h2osno_col(c) = 50._r8 snow_depth_col(c) = h2osno_col(c) / bdsno diff --git a/components/elm/src/main/elm_interface_pflotranMod.F90 b/components/elm/src/main/elm_interface_pflotranMod.F90 index 4298107c0a06..aedb85c26b91 100644 --- a/components/elm/src/main/elm_interface_pflotranMod.F90 +++ b/components/elm/src/main/elm_interface_pflotranMod.F90 @@ -484,7 +484,7 @@ subroutine interface_init(bounds) !write (iulog,*) 'WARNING: SOIL/CROP column with wtgcell <= 0 or inactive... within the domain' !write (iulog,*) 'ELM-- PFLOTRAN does not include such a SOIL/CROP column, AND will skip it' - elseif ( .not.(ltype(l)==istsoil .or. ltype(l)==istcrop) ) then + elseif ( .not.(ltype(l) == istsoil .or. ltype(l) == istcrop) ) then !write (iulog,*) 'WARNING: non-SOIL/CROP column found in filter%num_soilc: nc, l, ltype', nc, l, ltype(l) !write (iulog,*) 'ELM-- PFLOTRAN does not include such a SOIL/CROP column, AND will skip it' @@ -548,7 +548,7 @@ subroutine interface_init(bounds) g = cgridcell(c) gcount = g - bounds%begg + 1 - if ((.not.(ltype(l)==istsoil)) .and. (.not.(ltype(l)==istcrop)) ) then + if ((.not.(ltype(l) == istsoil)) .and. (.not.(ltype(l) == istcrop)) ) then !write (iulog,*) 'WARNING: Land Unit type of Non-SOIL/CROP... within the domain' !write (iulog,*) 'ELM-- PFLOTRAN does not support this land unit at present, AND will skip it' @@ -598,7 +598,7 @@ subroutine interface_init(bounds) g = cgridcell(c) gcount = g-bounds%begg+1 - if( (ltype(l)==istsoil .or. ltype(l)==istcrop) .and. & + if( (ltype(l) == istsoil .or. ltype(l) == istcrop) .and. & (cactive(c) .and. cwtgcell(c)>0._r8) ) then mapped_gid(gcount) = grc_pp%gindex(g) ! this is the globally grid-index, i.e. 'an' in its original calculation @@ -1856,7 +1856,7 @@ subroutine get_elm_soil_properties(elm_interface_data, bounds, filters) g = cgridcell(c) l = clandunit(c) - if ( (ltype(l)==istsoil .or. ltype(l)==istcrop) .and. & + if ( (ltype(l) == istsoil .or. ltype(l) == istcrop) .and. & (cactive(c) .and. cwtgcell(c)>0._r8) ) then ! skip inactive or zero-weighted column (may be not needed, but in case) #ifdef COLUMN_MODE diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index b504e60d3809..3199c4f1d8da 100644 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -358,7 +358,7 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) l = col_pp%landunit(c) if (lun_pp%urbpoi(l)) then - if (col_pp%itype(c)==icol_sunwall .or. col_pp%itype(c)==icol_shadewall) then + if (col_pp%itype(c) == icol_sunwall .or. col_pp%itype(c) == icol_shadewall) then col_pp%z(c,1:nlevurb) = zurb_wall(l,1:nlevurb) col_pp%zi(c,0:nlevurb) = ziurb_wall(l,0:nlevurb) col_pp%dz(c,1:nlevurb) = dzurb_wall(l,1:nlevurb) @@ -367,7 +367,7 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) col_pp%zi(c,nlevurb+1:nlevgrnd) = spval col_pp%dz(c,nlevurb+1:nlevgrnd) = spval end if - else if (col_pp%itype(c)==icol_roof) then + else if (col_pp%itype(c) == icol_roof) then col_pp%z(c,1:nlevurb) = zurb_roof(l,1:nlevurb) col_pp%zi(c,0:nlevurb) = ziurb_roof(l,0:nlevurb) col_pp%dz(c,1:nlevurb) = dzurb_roof(l,1:nlevurb) @@ -745,7 +745,7 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) do c = begc,endc l = col_pp%landunit(c) - if (lun_pp%itype(l)==istice_mec) then + if (lun_pp%itype(l) == istice_mec) then ! ice_mec columns already account for subgrid topographic variability through ! their use of multiple elevation classes; thus, to avoid double-accounting for ! topographic variability in these columns, we ignore topo_std and use a value From b2d35b28584689bd0e4940570cb952137c7388e8 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 14:09:50 -0700 Subject: [PATCH 253/398] Fixes bug --- components/elm/src/biogeophys/SoilHydrologyMod.F90 | 2 +- components/elm/src/biogeophys/SurfaceAlbedoMod.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index c027632aee73..394cab8fa720 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -1656,7 +1656,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - l = lun_pp%landuse(c) + l = col_pp%landunit(c) !scs: watmin addition to fix water balance errors xs1(c) = max(max(h2osoi_liq(c,1)-watmin,0._r8)- & diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index f04a2fdb7bda..980ecad6efe5 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -652,7 +652,7 @@ subroutine SurfaceAlbedo(bounds, & do ib = 1, nband do fc = 1,num_nourbanc c = filter_nourbanc(fc) - l = lun_pp%landunit(c) + l = col_pp%landunit(c) if (coszen_col(c) > 0._r8) then ! ground albedo was originally computed in SoilAlbedo, but is now computed here ! because the order of SoilAlbedo and SNICAR_RT/SNICAR_AD_RT was switched for SNICAR/SNICAR_AD_RT. From b56a3c880a766e9d143a56f9f8a8b511df968a61 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 14:39:14 -0700 Subject: [PATCH 254/398] Changes the check from landunit itype to column itype --- components/elm/src/biogeochem/CH4Mod.F90 | 4 ++-- .../elm/src/biogeochem/CNCarbonFluxType.F90 | 7 +++--- .../elm/src/biogeochem/CNCarbonStateType.F90 | 5 ++-- .../src/biogeochem/CNNitrogenStateType.F90 | 5 ++-- components/elm/src/biogeochem/DUSTMod.F90 | 2 +- .../elm/src/biogeochem/FanUpdateMod.F90 | 2 +- components/elm/src/data_types/CNStateType.F90 | 5 ++-- .../elm/src/data_types/ColumnDataType.F90 | 16 ++++++------- .../elm/src/data_types/VegetationDataType.F90 | 23 ++++++++++++------- 9 files changed, 40 insertions(+), 29 deletions(-) diff --git a/components/elm/src/biogeochem/CH4Mod.F90 b/components/elm/src/biogeochem/CH4Mod.F90 index a5cbd2f041c2..be2e81bb1d73 100644 --- a/components/elm/src/biogeochem/CH4Mod.F90 +++ b/components/elm/src/biogeochem/CH4Mod.F90 @@ -790,7 +790,7 @@ subroutine InitCold(this, bounds, cellorg_col) this%o2_decomp_depth_unsat_col(c,:)= spval l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%conc_ch4_sat_col (c,1:nlevsoi) = 0._r8 this%conc_ch4_unsat_col (c,1:nlevsoi) = 0._r8 @@ -851,7 +851,7 @@ subroutine InitCold(this, bounds, cellorg_col) this%ch4stress_unsat_col (c,nlevsoi+1:nlevgrnd) = 0._r8 this%ch4stress_sat_col (c,nlevsoi+1:nlevgrnd) = 0._r8 - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%conc_ch4_lake_col (c,:) = spval this%conc_o2_lake_col (c,:) = spval diff --git a/components/elm/src/biogeochem/CNCarbonFluxType.F90 b/components/elm/src/biogeochem/CNCarbonFluxType.F90 index a6c56a935f05..a955ed9f6293 100644 --- a/components/elm/src/biogeochem/CNCarbonFluxType.F90 +++ b/components/elm/src/biogeochem/CNCarbonFluxType.F90 @@ -1018,6 +1018,7 @@ subroutine InitCold(this, bounds) do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) + c = veg_pp%column(p) this%gpp_patch(p) = 0._r8 this%gpp_before_downreg_patch(p) = 0._r8 @@ -1035,7 +1036,7 @@ subroutine InitCold(this, bounds) this%xsmrpool_c13ratio_patch(p) = spval endif end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%tempsum_npp_patch(p) = 0._r8 this%annsum_npp_patch(p) = 0._r8 this%availc_patch(p) = 0._r8 @@ -1057,7 +1058,7 @@ subroutine InitCold(this, bounds) end if this%fphr_col(c,nlevdecomp+1:nlevgrnd) = 0._r8 !used to be in CH4Mod - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%fphr_col(c,nlevdecomp+1:nlevgrnd) = 0._r8 else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then this%fphr_col(c,:) = spval @@ -1067,7 +1068,7 @@ subroutine InitCold(this, bounds) ! also initialize dynamic landcover fluxes so that they have ! real values on first timestep, prior to calling pftdyn_cnbal - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%dwt_conv_cflux_col(c) = 0._r8 this%dwt_prod10c_gain_col(c) = 0._r8 this%dwt_prod100c_gain_col(c) = 0._r8 diff --git a/components/elm/src/biogeochem/CNCarbonStateType.F90 b/components/elm/src/biogeochem/CNCarbonStateType.F90 index 4453ebcd4cc9..77849861aeda 100644 --- a/components/elm/src/biogeochem/CNCarbonStateType.F90 +++ b/components/elm/src/biogeochem/CNCarbonStateType.F90 @@ -450,7 +450,8 @@ subroutine InitCold(this, bounds, ratio, c12_carbonstate_vars) this%leafcmax_patch(p) = 0._r8 l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + c = veg_pp%column(p) + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (veg_pp%itype(p) == noveg) then this%leafc_patch(p) = 0._r8 @@ -569,7 +570,7 @@ subroutine InitCold(this, bounds, ratio, c12_carbonstate_vars) ! initialize column-level variables do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%cwdc_col(c) = 0._r8 diff --git a/components/elm/src/biogeochem/CNNitrogenStateType.F90 b/components/elm/src/biogeochem/CNNitrogenStateType.F90 index a7f7315c6c83..8631e153e92f 100644 --- a/components/elm/src/biogeochem/CNNitrogenStateType.F90 +++ b/components/elm/src/biogeochem/CNNitrogenStateType.F90 @@ -562,7 +562,8 @@ subroutine InitCold(this, bounds, & do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + c = veg_pp%column(p) + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (veg_pp%itype(p) == noveg) then this%leafn_patch(p) = 0._r8 this%leafn_storage_patch(p) = 0._r8 @@ -635,7 +636,7 @@ subroutine InitCold(this, bounds, & do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! column nitrogen state variables this%ntrunc_col(c) = 0._r8 diff --git a/components/elm/src/biogeochem/DUSTMod.F90 b/components/elm/src/biogeochem/DUSTMod.F90 index f53e970423be..fb4d1e3d4958 100644 --- a/components/elm/src/biogeochem/DUSTMod.F90 +++ b/components/elm/src/biogeochem/DUSTMod.F90 @@ -350,7 +350,7 @@ subroutine DustEmission (bounds, & ! linearly from 1 to 0 as VAI(=tlai+tsai) increases from 0 to vai_mbl_thr ! if ice sheet, wetland, or lake, no dust allowed - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (tlai_lu(l) < vai_mbl_thr) then lnd_frc_mbl(p) = 1.0_r8 - (tlai_lu(l))/vai_mbl_thr else diff --git a/components/elm/src/biogeochem/FanUpdateMod.F90 b/components/elm/src/biogeochem/FanUpdateMod.F90 index d09889294e28..6fe597ca2e6e 100644 --- a/components/elm/src/biogeochem/FanUpdateMod.F90 +++ b/components/elm/src/biogeochem/FanUpdateMod.F90 @@ -314,7 +314,7 @@ subroutine fan_eval(bounds, num_soilc, filter_soilc, & c = filter_soilc(fc) l = col_pp%landunit(c) g = col_pp%gridcell(c) - if (.not. (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop)) cycle + if (.not. (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop)) cycle if (.not. col_pp%active(c) .or. col_pp%wtgcell(c) < 1e-15_r8) cycle ! Find and average the atmospheric resistances Rb and Ra. diff --git a/components/elm/src/data_types/CNStateType.F90 b/components/elm/src/data_types/CNStateType.F90 index 2f880568f30d..fb8d98920c8d 100644 --- a/components/elm/src/data_types/CNStateType.F90 +++ b/components/elm/src/data_types/CNStateType.F90 @@ -1020,7 +1020,7 @@ subroutine initCold(this, bounds) end do end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%annsum_counter_col(c) = 0._r8 this%annavg_t2m_col(c) = 280._r8 @@ -1098,7 +1098,8 @@ subroutine initCold(this, bounds) do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + c = veg_pp%column(p) + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%rc14_atm_patch(p) = c14ratio diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index 3a7253b436ee..8786feb4734b 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -1742,7 +1742,7 @@ subroutine col_ws_init(this, begc, endc, h2osno_input, snow_depth_input, watsat_ if (.not. lun_pp%lakpoi(l)) then !not lake nlevbed = col_pp%nlevbed(c) ! volumetric water - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then nlevs = nlevgrnd do j = 1, nlevs if (j > nlevbed) then @@ -2077,7 +2077,7 @@ subroutine col_ws_restart(this, bounds, ncid, flag, watsat_input) end if do j = 1,nlevs l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%h2osoi_liq(c,j) = max(0._r8,this%h2osoi_liq(c,j)) this%h2osoi_ice(c,j) = max(0._r8,this%h2osoi_ice(c,j)) this%h2osoi_vol(c,j) = this%h2osoi_liq(c,j)/(col_pp%dz(c,j)*denh2o) & @@ -2488,7 +2488,7 @@ subroutine col_cs_init(this, begc, endc, carbon_type, ratio, c12_carbonstate_var do c = begc, endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (.not. present(c12_carbonstate_vars)) then ! initializing a c12 type do j = 1, nlevdecomp do k = 1, ndecomp_pools @@ -3709,7 +3709,7 @@ subroutine col_ns_init(this, begc, endc, col_cs) do c = begc, endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! column nitrogen state variables this%ntrunc(c) = 0._r8 @@ -4864,7 +4864,7 @@ subroutine col_ps_init(this, begc, endc, col_cs) do c = begc, endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! column phosphorus state variables this%ptrunc(c) = 0._r8 @@ -6066,7 +6066,7 @@ subroutine col_wf_init(this, begc, endc) ! needed for CNNLeaching do c = begc, endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%qflx_drain(c) = 0._r8 this%qflx_surf(c) = 0._r8 this%qflx_lnd2ocn(c) = 0._r8 @@ -7229,7 +7229,7 @@ subroutine col_cf_init(this, begc, endc, carbon_type) end if this%fphr(c,nlevdecomp+1:nlevgrnd) = 0._r8 !used to be in ch4Mod - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%fphr(c,nlevdecomp+1:nlevgrnd) = 0._r8 else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then this%fphr(c,:) = spval @@ -7239,7 +7239,7 @@ subroutine col_cf_init(this, begc, endc, carbon_type) ! also initialize dynamic landcover fluxes so that they have ! real values on first timestep, prior to calling pftdyn_cnbal - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%dwt_conv_cflux(c) = 0._r8 this%dwt_prod10c_gain(c) = 0._r8 this%dwt_prod100c_gain(c) = 0._r8 diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index e0d90f987442..515152442b53 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -29,6 +29,7 @@ module VegetationDataType use CNStateType , only: cnstate_type use SpeciesMod , only : species_from_string use VegetationType , only : veg_pp + use ColumnType , only : col_pp use VegetationPropertiesType , only : veg_vp use LandunitType , only : lun_pp use GridcellType , only : grc_pp @@ -2460,7 +2461,8 @@ subroutine veg_cs_init(this, begp, endp, carbon_type, ratio) this%leafcmax(p) = 0._r8 l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + c = veg_pp%column(p) + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (veg_pp%itype(p) == noveg) then this%leafc(p) = 0._r8 @@ -3935,7 +3937,8 @@ subroutine veg_ns_init(this, begp, endp, veg_cs) do p = begp,endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + c = veg_pp%column(p) + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (veg_pp%itype(p) == noveg) then this%leafn(p) = 0._r8 this%leafn_storage(p) = 0._r8 @@ -4417,7 +4420,7 @@ subroutine veg_ps_init(this, begp, endp, veg_cs) type(vegetation_carbon_state), intent(in) :: veg_cs ! ! !LOCAL VARIABLES: - integer :: fp,l,p ! indices + integer :: fp,l,c,p ! indices integer :: num_special_patch ! number of good values in special_patch filter integer :: special_patch (endp-begp+1) ! special landunit filter - patches !------------------------------------------------------------------------ @@ -4619,7 +4622,8 @@ subroutine veg_ps_init(this, begp, endp, veg_cs) do p = begp,endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + c = veg_pp%column(p) + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (veg_pp%itype(p) == noveg) then this%leafp(p) = 0._r8 @@ -7937,6 +7941,7 @@ subroutine veg_cf_init(this, begp, endp, carbon_type) if (.not.use_fates) then do p = begp,endp l = veg_pp%landunit(p) + c = veg_pp%column(p) this%gpp(p) = 0._r8 this%gpp_before_downreg(p) = 0._r8 @@ -7954,7 +7959,7 @@ subroutine veg_cf_init(this, begp, endp, carbon_type) this%xsmrpool_c13ratio(p) = spval endif end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%tempsum_npp(p) = 0._r8 this%annsum_npp(p) = 0._r8 this%availc(p) = 0._r8 @@ -9490,6 +9495,7 @@ subroutine veg_nf_init(this, begp, endp) do p = begp,endp l = veg_pp%landunit(p) + c = veg_pp%column(p) this%prev_leafn_to_litter(p) = 0._r8 this%prev_frootn_to_litter(p) = 0._r8 @@ -9502,7 +9508,7 @@ subroutine veg_nf_init(this, begp, endp) this%soyfixn(p) = 0._r8 end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%fert_counter(p) = 0._r8 end if @@ -9897,7 +9903,7 @@ subroutine veg_pf_init(this, begp, endp) integer, intent(in) :: begp,endp ! ! !LOCAL VARIABLES: - integer :: p,l ! indices + integer :: p,c,l ! indices integer :: fp ! filter indices integer :: num_special_patch ! number of good values in special_patch filter integer :: special_patch(endp-begp+1) ! special landunit filter - patches @@ -10566,6 +10572,7 @@ subroutine veg_pf_init(this, begp, endp) end do do p = begp,endp l = veg_pp%landunit(p) + c = veg_pp%column(p) this%prev_leafp_to_litter (p) = 0._r8 this%prev_frootp_to_litter(p) = 0._r8 @@ -10576,7 +10583,7 @@ subroutine veg_pf_init(this, begp, endp) end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%fert_p_counter(p) = 0._r8 end if From 6fef00bbfe9358c8a3f1677913b9d3d973ba2b52 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 18:22:10 -0700 Subject: [PATCH 255/398] More changes the check from landunit itype to column itype --- components/elm/src/biogeophys/BalanceCheckMod.F90 | 2 +- .../elm/src/biogeophys/BareGroundFluxesMod.F90 | 2 +- components/elm/src/biogeophys/CanopyHydrologyMod.F90 | 2 +- components/elm/src/biogeophys/CanopyStateType.F90 | 5 +++-- .../elm/src/biogeophys/CanopyTemperatureMod.F90 | 12 +++++++----- .../elm/src/biogeophys/HydrologyDrainageMod.F90 | 4 ++-- .../elm/src/biogeophys/HydrologyNoDrainageMod.F90 | 2 +- components/elm/src/biogeophys/PhotosynthesisType.F90 | 10 ++++++---- components/elm/src/biogeophys/SoilFluxesMod.F90 | 6 +++--- components/elm/src/biogeophys/SoilHydrologyMod.F90 | 2 +- components/elm/src/biogeophys/SoilStateType.F90 | 2 +- components/elm/src/biogeophys/SoilTemperatureMod.F90 | 8 ++++---- components/elm/src/biogeophys/SurfaceAlbedoMod.F90 | 2 +- .../elm/src/biogeophys/SurfaceRadiationMod.F90 | 9 +++++---- .../elm/src/biogeophys/SurfaceResistanceMod.F90 | 2 +- .../elm/src/biogeophys/TotalWaterAndHeatMod.F90 | 4 ++-- components/elm/src/biogeophys/WaterfluxType.F90 | 2 +- 17 files changed, 41 insertions(+), 35 deletions(-) diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 index 676b45f85946..560fed5533b6 100644 --- a/components/elm/src/biogeophys/BalanceCheckMod.F90 +++ b/components/elm/src/biogeophys/BalanceCheckMod.F90 @@ -497,7 +497,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & endif endif - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop .or. lun_pp%itype(l) == istwet ) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop .or. lun_pp%itype(l) == istwet ) 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) ) & diff --git a/components/elm/src/biogeophys/BareGroundFluxesMod.F90 b/components/elm/src/biogeophys/BareGroundFluxesMod.F90 index 03ecff38f137..939fae055b80 100644 --- a/components/elm/src/biogeophys/BareGroundFluxesMod.F90 +++ b/components/elm/src/biogeophys/BareGroundFluxesMod.F90 @@ -414,7 +414,7 @@ subroutine BareGroundFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & rh_ref2m(p) = min(100._r8, q_ref2m(p) / qsat_ref2m * 100._r8) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then rh_ref2m_r(p) = rh_ref2m(p) t_ref2m_r(p) = t_ref2m(p) end if diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 index 19b9d07f16c5..c935dabd605a 100644 --- a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 +++ b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 @@ -826,7 +826,7 @@ subroutine FracH2OSfc(bounds, num_h2osfc, filter_h2osfc, & l = col_pp%landunit(c) qflx_h2osfc2topsoi(c) = 0._r8 ! h2osfc only calculated for soil vegetated land units - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! Use newton-raphson method to iteratively determine frac_h20sfc ! based on amount of surface water storage (h2osfc) and diff --git a/components/elm/src/biogeophys/CanopyStateType.F90 b/components/elm/src/biogeophys/CanopyStateType.F90 index 803366c05000..650191999e34 100644 --- a/components/elm/src/biogeophys/CanopyStateType.F90 +++ b/components/elm/src/biogeophys/CanopyStateType.F90 @@ -503,6 +503,7 @@ subroutine InitCold(this, bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) + c = veg_pp%column(p) this%frac_veg_nosno_patch(p) = 0._r8 this%tlai_patch(p) = 0._r8 @@ -514,7 +515,7 @@ subroutine InitCold(this, bounds) this%dewmx_patch(p) = 0.1_r8 this%vegwp_patch(p,:) = -2.5e4_r8 - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%laisun_patch(p) = 0._r8 this%laisha_patch(p) = 0._r8 end if @@ -531,7 +532,7 @@ subroutine InitCold(this, bounds) do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%alt_col(c) = 0._r8 this%altmax_col(c) = 0._r8 this%altmax_lastyear_col(c) = 0._r8 diff --git a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 index d03e5c401343..d1e9185b40e1 100644 --- a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 +++ b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 @@ -244,7 +244,7 @@ subroutine CanopyTemperature(bounds, & if (lun_pp%itype(l)/=istwet .AND. lun_pp%itype(l)/=istice & .AND. lun_pp%itype(l)/=istice_mec) then - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then wx = (h2osoi_liq(c,1)/denh2o+h2osoi_ice(c,1)/denice)/dz(c,1) fac = min(1._r8, wx/watsat(c,1)) fac = max( fac, 0.01_r8 ) @@ -297,7 +297,7 @@ subroutine CanopyTemperature(bounds, & end if ! compute humidities individually for snow, soil, h2osfc for vegetated landunits - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then call QSat(t_soisno(c,snl(c)+1), forc_pbot(t), eg, degdT, qsatg, qsatgdT) if (qsatg > forc_q(t) .and. forc_q(t) > qsatg) then @@ -414,15 +414,17 @@ subroutine CanopyTemperature(bounds, & eflx_sh_tot(p) = 0._r8 l = veg_pp%landunit(p) + c = veg_pp%column(p) + if (urbpoi(l)) then eflx_sh_tot_u(p) = 0._r8 - else if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then eflx_sh_tot_r(p) = 0._r8 end if eflx_lh_tot(p) = 0._r8 if (urbpoi(l)) then eflx_lh_tot_u(p) = 0._r8 - else if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then eflx_lh_tot_r(p) = 0._r8 end if eflx_sh_veg(p) = 0._r8 @@ -454,7 +456,7 @@ subroutine CanopyTemperature(bounds, & t = veg_pp%topounit(p) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then if (frac_veg_nosno(p) == 0) then forc_hgt_u_patch(p) = forc_hgt_u(t) + z0mg(c) + displa(p) forc_hgt_t_patch(p) = forc_hgt_t(t) + z0mg(c) + displa(p) diff --git a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 index 77ce2610d9bb..c110d2e386d2 100644 --- a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 @@ -337,12 +337,12 @@ subroutine HydrologyDrainage(bounds, & qflx_runoff(c) = qflx_drain(c) + qflx_surf(c) + qflx_h2osfc_surf(c) + qflx_qrgwl(c) + qflx_drain_perched(c) - if ((lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) .and. col_pp%active(c)) then + if ((col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) .and. col_pp%active(c)) then qflx_irr_demand(c) = -1.0_r8 * f_surf(g,tpu_ind)*qflx_irrig(c) !surface water demand send to MOSART end if if (lun_pp%urbpoi(l)) then qflx_runoff_u(c) = qflx_runoff(c) - else if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then qflx_runoff_r(c) = qflx_runoff(c) end if diff --git a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 index 3d47d695f06b..2dd303e7be21 100644 --- a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -451,7 +451,7 @@ subroutine HydrologyNoDrainage(bounds, & t_soi_10cm(c) = t_soi_10cm(c)/0.1_r8 tsoi17(c) = tsoi17(c)/0.17_r8 ! F. Li and S. Levis end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then t_grnd_r(c) = t_soisno(c,snl(c)+1) end if diff --git a/components/elm/src/biogeophys/PhotosynthesisType.F90 b/components/elm/src/biogeophys/PhotosynthesisType.F90 index 5cb94628d8d2..8490bb90b804 100644 --- a/components/elm/src/biogeophys/PhotosynthesisType.F90 +++ b/components/elm/src/biogeophys/PhotosynthesisType.F90 @@ -420,11 +420,12 @@ subroutine TimeStepInit (this, bounds) type(bounds_type) , intent(in) :: bounds ! ! !LOCAL VARIABLES: - integer :: p,l ! indices + integer :: p,c,l ! indices !----------------------------------------------------------------------- do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) + c = veg_pp%column(p) if (.not. lun_pp%lakpoi(l)) then this%psnsun_patch(p) = 0._r8 this%psnsun_wc_patch(p) = 0._r8 @@ -454,7 +455,7 @@ subroutine TimeStepInit (this, bounds) this%c14_psnsha_patch(p) = 0._r8 endif end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop & + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop & .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec & .or. lun_pp%itype(l) == istwet) then if (use_c13) then @@ -480,11 +481,12 @@ subroutine photosyns_vars_TimeStepInit (photosyns_vars, bounds) type(bounds_type) , intent(in) :: bounds ! ! !LOCAL VARIABLES: - integer :: p,l ! indices + integer :: p,c,l ! indices !----------------------------------------------------------------------- do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) + c = veg_pp%column(p) if (.not. lun_pp%lakpoi(l)) then photosyns_vars%psnsun_patch(p) = 0._r8 photosyns_vars%psnsun_wc_patch(p) = 0._r8 @@ -512,7 +514,7 @@ subroutine photosyns_vars_TimeStepInit (photosyns_vars, bounds) photosyns_vars%c14_psnsha_patch(p) = 0._r8 endif end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop & + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop & .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec & .or. lun_pp%itype(l) == istwet) then if (use_c13) then diff --git a/components/elm/src/biogeophys/SoilFluxesMod.F90 b/components/elm/src/biogeophys/SoilFluxesMod.F90 index d7c64e80b0a3..d4ce4c185a6c 100644 --- a/components/elm/src/biogeophys/SoilFluxesMod.F90 +++ b/components/elm/src/biogeophys/SoilFluxesMod.F90 @@ -288,7 +288,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & - emg(c)*sb*lw_grnd - emg(c)*sb*t_grnd0(c)**3*(4._r8*tinc(c)) & - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then eflx_soil_grnd_r(p) = eflx_soil_grnd(p) end if else @@ -312,7 +312,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & eflx_sh_tot(p) = eflx_sh_veg(p) + eflx_sh_grnd(p) qflx_evap_tot(p) = qflx_evap_veg(p) + qflx_evap_soi(p) eflx_lh_tot(p)= hvap*qflx_evap_veg(p) + htvp(c)*qflx_evap_soi(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then eflx_lh_tot_r(p)= eflx_lh_tot(p) eflx_sh_tot_r(p)= eflx_sh_tot(p) else if (lun_pp%urbpoi(l)) then @@ -432,7 +432,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & + 4._r8*emg(c)*sb*t_grnd0(c)**3*tinc(c) eflx_lwrad_net(p) = eflx_lwrad_out(p) - forc_lwrad(t) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then eflx_lwrad_net_r(p) = eflx_lwrad_out(p) - forc_lwrad(t) eflx_lwrad_out_r(p) = eflx_lwrad_out(p) end if diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index 394cab8fa720..a33eae43fc5e 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -448,7 +448,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f pc = pc_grid(g) ! partition moisture fluxes between soil and h2osfc - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! explicitly use frac_sno=0 if snl=0 if (snl(c) >= 0) then diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index 1cb1d3388cec..3be8b2a9d7d8 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -409,7 +409,7 @@ subroutine InitCold(this, bounds) do c = bounds%begc,bounds%endc this%rootfr_col (c,nlevsoi+1:nlevgrnd) = 0._r8 - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%rootfr_col (c,nlevsoi+1:nlevgrnd) = 0._r8 else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then this%rootfr_col (c,:) = spval diff --git a/components/elm/src/biogeophys/SoilTemperatureMod.F90 b/components/elm/src/biogeophys/SoilTemperatureMod.F90 index 9c94a6d86e6b..225e2d22be0d 100644 --- a/components/elm/src/biogeophys/SoilTemperatureMod.F90 +++ b/components/elm/src/biogeophys/SoilTemperatureMod.F90 @@ -677,9 +677,9 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte if (j == 1) then ! this only needs to be done once eflx_fgr12(c) = -cnfac*fn(c,1) - (1._r8-cnfac)*fn1(c,1) end if - if (j > 0 .and. j < nlevgrnd .and. (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop)) then + if (j > 0 .and. j < nlevgrnd .and. (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop)) then eflx_fgr(c,j) = -cnfac*fn(c,j) - (1._r8-cnfac)*fn1(c,j) - else if (j == nlevgrnd .and. (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop)) then + else if (j == nlevgrnd .and. (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop)) then eflx_fgr(c,j) = 0._r8 end if @@ -1465,7 +1465,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & ! from Zhao (1997) and Koren (1999) supercool(c,j) = 0.0_r8 - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop .or. col_pp%itype(c) == icol_road_perv) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop .or. col_pp%itype(c) == icol_road_perv) then if(t_soisno(c,j) < tfrz) then smp = hfus*(tfrz-t_soisno(c,j))/(grav*t_soisno(c,j)) * 1000._r8 !(mm) supercool(c,j) = watsat(c,j)*(smp/sucsat(c,j))**(-1._r8/bsw(c,j)) @@ -1682,7 +1682,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & l = col_pp%landunit(c) if (lun_pp%urbpoi(l)) then eflx_snomelt_u(c) = eflx_snomelt(c) - else if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then eflx_snomelt_r(c) = eflx_snomelt(c) end if end do diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 980ecad6efe5..834a82bb704f 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -1052,7 +1052,7 @@ subroutine SoilAlbedo (bounds, & pi = ldomain%pftm(g) if (coszen(c) > 0._r8) then l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop .and. top_pp%active(t)) then ! soil + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop .and. top_pp%active(t)) then ! soil inc = max(0.11_r8-0.40_r8*h2osoi_vol(c,1), 0._r8) soilcol = isoicol(c) ! changed from local variable to elm_type: diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index 46309f0cff6c..3ae75d0a9d2f 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -479,12 +479,13 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & do fp = 1,num_nourbanp p = filter_nourbanp(fp) l = veg_pp%landunit(p) + c = veg_pp%column(p) sabg_soil(p) = 0._r8 sabg_snow(p) = 0._r8 sabg(p) = 0._r8 sabv(p) = 0._r8 fsa(p) = 0._r8 - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then fsa_r(p) = 0._r8 end if sabg_lyr(p,:) = 0._r8 @@ -521,7 +522,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & if (ib == 1) then parveg(p) = cad(p,ib) + cai(p,ib) end if - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then fsa_r(p) = fsa_r(p) + cad(p,ib) + cai(p,ib) end if @@ -538,7 +539,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & absrad = trd(p,ib)*(1._r8-albgrd(c,ib)) + tri(p,ib)*(1._r8-albgri(c,ib)) sabg(p) = sabg(p) + absrad fsa(p) = fsa(p) + absrad - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then fsa_r(p) = fsa_r(p) + absrad end if if (snl(c) == 0) then @@ -678,7 +679,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & endif ! Diagnostic: shortwave penetrating ground (e.g. top layer) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then sabg_pen(p) = sabg(p) - sabg_lyr(p, snl(c)+1) end if diff --git a/components/elm/src/biogeophys/SurfaceResistanceMod.F90 b/components/elm/src/biogeophys/SurfaceResistanceMod.F90 index b4217890fca3..e0cfa145852b 100644 --- a/components/elm/src/biogeophys/SurfaceResistanceMod.F90 +++ b/components/elm/src/biogeophys/SurfaceResistanceMod.F90 @@ -141,7 +141,7 @@ subroutine calc_beta_leepielke1992(bounds, num_nolakec, filter_nolakec, & l = col_pp%landunit(c) if (lun_pp%itype(l)/=istwet .AND. lun_pp%itype(l)/=istice & .AND. lun_pp%itype(l)/=istice_mec) then - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then wx = (h2osoi_liq(c,1)/denh2o+h2osoi_ice(c,1)/denice)/col_pp%dz(c,1) fac = min(1._r8, wx/watsat(c,1)) fac = max( fac, 0.01_r8 ) diff --git a/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 b/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 index 376f0026c462..061fb6f7289c 100644 --- a/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 +++ b/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 @@ -267,7 +267,7 @@ subroutine ComputeLiqIceMassNonLake(bounds, num_nolakec, filter_nolakec, & do fc = 1, num_nolakec c = filter_nolakec(fc) l = col_pp%landunit(c) - if ( (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop ) & + if ( (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop ) & .or. (lun_pp%itype(l) == istwet ) & .or. (lun_pp%itype(l) == istice ) & .or. (lun_pp%itype(l) == istice_mec ) & @@ -276,7 +276,7 @@ subroutine ComputeLiqIceMassNonLake(bounds, num_nolakec, filter_nolakec, & end if l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then ! note: soil specified at LU level + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! note: soil specified at LU level do p = col_pp%pfti(c),col_pp%pftf(c) ! loop over patches if (veg_pp%active(p)) then liquid_mass(c) = liquid_mass(c) + h2ocan_patch(p) * veg_pp%wtcol(p) diff --git a/components/elm/src/biogeophys/WaterfluxType.F90 b/components/elm/src/biogeophys/WaterfluxType.F90 index 404ce283d501..73b9f01975ee 100644 --- a/components/elm/src/biogeophys/WaterfluxType.F90 +++ b/components/elm/src/biogeophys/WaterfluxType.F90 @@ -373,7 +373,7 @@ subroutine InitCold(this, bounds) ! needed for NitrogenLeaching do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then this%qflx_drain_col(c) = 0._r8 this%qflx_surf_col(c) = 0._r8 this%qflx_irr_demand_col(c) = 0._r8 From 34ba5fe7b49ebe3ec905d93a58846940fc19dcb9 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 18:29:37 -0700 Subject: [PATCH 256/398] Minor fix --- components/elm/src/biogeophys/PhotosynthesisType.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/components/elm/src/biogeophys/PhotosynthesisType.F90 b/components/elm/src/biogeophys/PhotosynthesisType.F90 index 8490bb90b804..af5f01d01ba3 100644 --- a/components/elm/src/biogeophys/PhotosynthesisType.F90 +++ b/components/elm/src/biogeophys/PhotosynthesisType.F90 @@ -10,6 +10,7 @@ module PhotosynthesisType use elm_varcon , only : spval use LandunitType , only : lun_pp use VegetationType , only : veg_pp + use ColumnDataType ,only : col_pp ! implicit none save From 10532883086175e6279117df078a2aca4cd68d13 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 18:39:27 -0700 Subject: [PATCH 257/398] Even more changes the check from landunit itype to column itype --- components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 | 2 +- components/elm/src/main/filterMod.F90 | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 b/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 index b8db8144bb87..9983f7f70899 100644 --- a/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 +++ b/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 @@ -245,7 +245,7 @@ subroutine dyn_cnbal_patch(bounds, & p = filter_soilp_with_inactive(fp) c = veg_pp%column(p) l = veg_pp%landunit(p) - if (.not.(lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) ) Then + if (.not.(col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) ) Then print *, "istsoil,istcrop",istsoil, istcrop print *, lun_pp%itype(l) end if diff --git a/components/elm/src/main/filterMod.F90 b/components/elm/src/main/filterMod.F90 index e1dde9445598..8fa341dbdd00 100644 --- a/components/elm/src/main/filterMod.F90 +++ b/components/elm/src/main/filterMod.F90 @@ -358,7 +358,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (top_pp%active(t)) then if (col_pp%active(c) .or. include_inactive) then l =col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then fs = fs + 1 this_filter(nc)%soilc(fs) = c end if @@ -372,10 +372,11 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc fs = 0 do p = bounds%begp,bounds%endp t =veg_pp%topounit(p) + c = veg_pp%column(p) if (top_pp%active(t)) then if (veg_pp%active(p) .or. include_inactive) then l =veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then fs = fs + 1 this_filter(nc)%soilp(fs) = p end if @@ -418,11 +419,12 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc fnc = 0 do p = bounds%begp,bounds%endp t =veg_pp%topounit(p) + c = veg_pp%column(p) if (top_pp%active(t)) then if (veg_pp%active(p) .or. include_inactive) then if (.not. iscft(veg_pp%itype(p))) then l =veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then fnc = fnc + 1 this_filter(nc)%soilnopcropp(fnc) = p end if From fb00b0f29107197f68fa62d27c0328530ceccf64 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 10:53:41 -0700 Subject: [PATCH 258/398] Adds code to set if column is soil or crop --- components/elm/src/data_types/ColumnType.F90 | 9 +++++++++ components/elm/src/main/initGridCellsMod.F90 | 6 +++--- components/elm/src/main/initSubgridMod.F90 | 9 +++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/components/elm/src/data_types/ColumnType.F90 b/components/elm/src/data_types/ColumnType.F90 index 21e9d24bd8f4..efd8ff9eb8cf 100644 --- a/components/elm/src/data_types/ColumnType.F90 +++ b/components/elm/src/data_types/ColumnType.F90 @@ -76,6 +76,10 @@ module ColumnType logical, pointer :: is_fates(:) => null() ! True if this column is associated with a FATES active column ! False if otherwise. If fates is turned off, this array is ! all false + + logical, pointer :: is_soil(:) => null() ! True if the column is a soil + logical, pointer :: is_crop(:) => null() ! True if the column is a crop + contains procedure, public :: Init => col_pp_init @@ -139,6 +143,9 @@ subroutine col_pp_init(this, begc, endc) ! Assume that columns are not fates columns until fates initialization begins allocate(this%is_fates(begc:endc)); this%is_fates(:) = .false. + allocate(this%is_soil (begc:endc)); this%is_soil (:) = .false. + allocate(this%is_crop (begc:endc)); this%is_crop (:) = .false. + end subroutine col_pp_init !------------------------------------------------------------------------ @@ -178,6 +185,8 @@ subroutine col_pp_clean(this) deallocate(this%meangradz ) deallocate(this%hydrologically_active) deallocate(this%is_fates) + deallocate(this%is_soil) + deallocate(this%is_crop) end subroutine col_pp_clean diff --git a/components/elm/src/main/initGridCellsMod.F90 b/components/elm/src/main/initGridCellsMod.F90 index 61e8e175c260..f01d30924b8e 100644 --- a/components/elm/src/main/initGridCellsMod.F90 +++ b/components/elm/src/main/initGridCellsMod.F90 @@ -391,7 +391,7 @@ subroutine set_landunit_veg_compete (ltype, gi, ti,topo_ind, li, ci, pi, setdata call add_landunit(li=li, ti=ti, ltype=ltype, wttopounit=wtlunit2topounit) ! Assume one column on the landunit - call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8) + call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8, is_soil=.true.) do m = natpft_lb,natpft_ub if(use_fates .and. .not.use_fates_sp)then p_wt = 1.0_r8/real(natpft_size,r8) @@ -409,7 +409,7 @@ subroutine set_landunit_veg_compete (ltype, gi, ti,topo_ind, li, ci, pi, setdata ! get new weight for wttopounit: wtpoly2lndunit = wt_lunit(gi, topo_ind, z) call add_polygon_landunit(li=li, ti=ti, ltype=ltype, wttopounit=wtpoly2lndunit, polytype = z - max_non_poly_lunit) - call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8) + call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8, is_soil=.true.) ! add patch: do m = natpft_lb,natpft_ub if(use_fates .and. .not.use_fates_sp) then @@ -591,7 +591,7 @@ subroutine set_landunit_crop_noncompete (ltype, gi, ti,topo_ind, li, ci, pi, set if (create_crop_landunit) then do m = cft_lb, cft_ub - call add_column(ci=ci, li=li, ctype=((istcrop*100) + m), wtlunit=wt_cft(gi,topo_ind,m)) + call add_column(ci=ci, li=li, ctype=((istcrop*100) + m), wtlunit=wt_cft(gi,topo_ind,m), is_crop=.true.) call add_patch(pi=pi, ci=ci, ptype=m, wtcol=1.0_r8) end do end if diff --git a/components/elm/src/main/initSubgridMod.F90 b/components/elm/src/main/initSubgridMod.F90 index 1dddae8fee97..13b3d3979789 100644 --- a/components/elm/src/main/initSubgridMod.F90 +++ b/components/elm/src/main/initSubgridMod.F90 @@ -537,7 +537,7 @@ end subroutine add_polygon_landunit !----------------------------------------------------------------------- - subroutine add_column(ci, li, ctype, wtlunit) + subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop) ! ! !DESCRIPTION: ! Add an entry in the column-level arrays. ci gives the index of the last column @@ -549,6 +549,8 @@ subroutine add_column(ci, li, ctype, wtlunit) integer , intent(in) :: li ! landunit index on which this column should be placed (assumes this landunit has already been created) integer , intent(in) :: ctype ! column type real(r8) , intent(in) :: wtlunit ! weight of the column relative to the landunit + logical , optional :: is_soil ! true for a soil column + logical , optional :: is_crop ! true for a crop column ! ! !LOCAL VARIABLES: character(len=*), parameter :: subname = 'add_column' @@ -562,7 +564,10 @@ subroutine add_column(ci, li, ctype, wtlunit) col_pp%wtlunit(ci) = wtlunit col_pp%itype(ci) = ctype - + + if (present(is_soil)) col_pp%is_soil = is_soil + if (present(is_crop)) col_pp%is_crop = is_crop + end subroutine add_column !----------------------------------------------------------------------- From ce4cdb179887ad4e16feb64507790086cfcf6132 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 19:02:45 -0700 Subject: [PATCH 259/398] Changes to use logicals --- components/elm/src/biogeochem/CH4Mod.F90 | 4 ++-- components/elm/src/biogeochem/CNCarbonFluxType.F90 | 6 +++--- components/elm/src/biogeochem/CNCarbonStateType.F90 | 4 ++-- components/elm/src/biogeochem/CNNitrogenStateType.F90 | 4 ++-- components/elm/src/biogeochem/DUSTMod.F90 | 2 +- components/elm/src/biogeochem/FanUpdateMod.F90 | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/components/elm/src/biogeochem/CH4Mod.F90 b/components/elm/src/biogeochem/CH4Mod.F90 index be2e81bb1d73..0450a44e6203 100644 --- a/components/elm/src/biogeochem/CH4Mod.F90 +++ b/components/elm/src/biogeochem/CH4Mod.F90 @@ -790,7 +790,7 @@ subroutine InitCold(this, bounds, cellorg_col) this%o2_decomp_depth_unsat_col(c,:)= spval l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%conc_ch4_sat_col (c,1:nlevsoi) = 0._r8 this%conc_ch4_unsat_col (c,1:nlevsoi) = 0._r8 @@ -851,7 +851,7 @@ subroutine InitCold(this, bounds, cellorg_col) this%ch4stress_unsat_col (c,nlevsoi+1:nlevgrnd) = 0._r8 this%ch4stress_sat_col (c,nlevsoi+1:nlevgrnd) = 0._r8 - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%conc_ch4_lake_col (c,:) = spval this%conc_o2_lake_col (c,:) = spval diff --git a/components/elm/src/biogeochem/CNCarbonFluxType.F90 b/components/elm/src/biogeochem/CNCarbonFluxType.F90 index a955ed9f6293..00d6528831a0 100644 --- a/components/elm/src/biogeochem/CNCarbonFluxType.F90 +++ b/components/elm/src/biogeochem/CNCarbonFluxType.F90 @@ -1036,7 +1036,7 @@ subroutine InitCold(this, bounds) this%xsmrpool_c13ratio_patch(p) = spval endif end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%tempsum_npp_patch(p) = 0._r8 this%annsum_npp_patch(p) = 0._r8 this%availc_patch(p) = 0._r8 @@ -1058,7 +1058,7 @@ subroutine InitCold(this, bounds) end if this%fphr_col(c,nlevdecomp+1:nlevgrnd) = 0._r8 !used to be in CH4Mod - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%fphr_col(c,nlevdecomp+1:nlevgrnd) = 0._r8 else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then this%fphr_col(c,:) = spval @@ -1068,7 +1068,7 @@ subroutine InitCold(this, bounds) ! also initialize dynamic landcover fluxes so that they have ! real values on first timestep, prior to calling pftdyn_cnbal - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%dwt_conv_cflux_col(c) = 0._r8 this%dwt_prod10c_gain_col(c) = 0._r8 this%dwt_prod100c_gain_col(c) = 0._r8 diff --git a/components/elm/src/biogeochem/CNCarbonStateType.F90 b/components/elm/src/biogeochem/CNCarbonStateType.F90 index 77849861aeda..6ecf1995a3b4 100644 --- a/components/elm/src/biogeochem/CNCarbonStateType.F90 +++ b/components/elm/src/biogeochem/CNCarbonStateType.F90 @@ -451,7 +451,7 @@ subroutine InitCold(this, bounds, ratio, c12_carbonstate_vars) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (veg_pp%itype(p) == noveg) then this%leafc_patch(p) = 0._r8 @@ -570,7 +570,7 @@ subroutine InitCold(this, bounds, ratio, c12_carbonstate_vars) ! initialize column-level variables do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%cwdc_col(c) = 0._r8 diff --git a/components/elm/src/biogeochem/CNNitrogenStateType.F90 b/components/elm/src/biogeochem/CNNitrogenStateType.F90 index 8631e153e92f..cbd4d8eefc5e 100644 --- a/components/elm/src/biogeochem/CNNitrogenStateType.F90 +++ b/components/elm/src/biogeochem/CNNitrogenStateType.F90 @@ -563,7 +563,7 @@ subroutine InitCold(this, bounds, & l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (veg_pp%itype(p) == noveg) then this%leafn_patch(p) = 0._r8 this%leafn_storage_patch(p) = 0._r8 @@ -636,7 +636,7 @@ subroutine InitCold(this, bounds, & do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then ! column nitrogen state variables this%ntrunc_col(c) = 0._r8 diff --git a/components/elm/src/biogeochem/DUSTMod.F90 b/components/elm/src/biogeochem/DUSTMod.F90 index fb4d1e3d4958..78571e39bba4 100644 --- a/components/elm/src/biogeochem/DUSTMod.F90 +++ b/components/elm/src/biogeochem/DUSTMod.F90 @@ -350,7 +350,7 @@ subroutine DustEmission (bounds, & ! linearly from 1 to 0 as VAI(=tlai+tsai) increases from 0 to vai_mbl_thr ! if ice sheet, wetland, or lake, no dust allowed - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (tlai_lu(l) < vai_mbl_thr) then lnd_frc_mbl(p) = 1.0_r8 - (tlai_lu(l))/vai_mbl_thr else diff --git a/components/elm/src/biogeochem/FanUpdateMod.F90 b/components/elm/src/biogeochem/FanUpdateMod.F90 index 6fe597ca2e6e..81bb7983273a 100644 --- a/components/elm/src/biogeochem/FanUpdateMod.F90 +++ b/components/elm/src/biogeochem/FanUpdateMod.F90 @@ -314,7 +314,7 @@ subroutine fan_eval(bounds, num_soilc, filter_soilc, & c = filter_soilc(fc) l = col_pp%landunit(c) g = col_pp%gridcell(c) - if (.not. (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop)) cycle + if (.not. (col_pp%is_soil(c) .or. col_pp%is_crop(c))) cycle if (.not. col_pp%active(c) .or. col_pp%wtgcell(c) < 1e-15_r8) cycle ! Find and average the atmospheric resistances Rb and Ra. From a5310aef747e4d6e94281a24bb40a62960901319 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sat, 11 Oct 2025 19:15:00 -0700 Subject: [PATCH 260/398] More code changes to use logicals --- components/elm/src/data_types/CNStateType.F90 | 4 ++-- components/elm/src/data_types/ColumnDataType.F90 | 16 ++++++++-------- .../elm/src/data_types/VegetationDataType.F90 | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/components/elm/src/data_types/CNStateType.F90 b/components/elm/src/data_types/CNStateType.F90 index fb8d98920c8d..2e33cea96e73 100644 --- a/components/elm/src/data_types/CNStateType.F90 +++ b/components/elm/src/data_types/CNStateType.F90 @@ -1020,7 +1020,7 @@ subroutine initCold(this, bounds) end do end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%annsum_counter_col(c) = 0._r8 this%annavg_t2m_col(c) = 280._r8 @@ -1099,7 +1099,7 @@ subroutine initCold(this, bounds) do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%rc14_atm_patch(p) = c14ratio diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index 8786feb4734b..cb0f9a1e95c9 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -1742,7 +1742,7 @@ subroutine col_ws_init(this, begc, endc, h2osno_input, snow_depth_input, watsat_ if (.not. lun_pp%lakpoi(l)) then !not lake nlevbed = col_pp%nlevbed(c) ! volumetric water - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then nlevs = nlevgrnd do j = 1, nlevs if (j > nlevbed) then @@ -2077,7 +2077,7 @@ subroutine col_ws_restart(this, bounds, ncid, flag, watsat_input) end if do j = 1,nlevs l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%h2osoi_liq(c,j) = max(0._r8,this%h2osoi_liq(c,j)) this%h2osoi_ice(c,j) = max(0._r8,this%h2osoi_ice(c,j)) this%h2osoi_vol(c,j) = this%h2osoi_liq(c,j)/(col_pp%dz(c,j)*denh2o) & @@ -2488,7 +2488,7 @@ subroutine col_cs_init(this, begc, endc, carbon_type, ratio, c12_carbonstate_var do c = begc, endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (.not. present(c12_carbonstate_vars)) then ! initializing a c12 type do j = 1, nlevdecomp do k = 1, ndecomp_pools @@ -3709,7 +3709,7 @@ subroutine col_ns_init(this, begc, endc, col_cs) do c = begc, endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then ! column nitrogen state variables this%ntrunc(c) = 0._r8 @@ -4864,7 +4864,7 @@ subroutine col_ps_init(this, begc, endc, col_cs) do c = begc, endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then ! column phosphorus state variables this%ptrunc(c) = 0._r8 @@ -6066,7 +6066,7 @@ subroutine col_wf_init(this, begc, endc) ! needed for CNNLeaching do c = begc, endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%qflx_drain(c) = 0._r8 this%qflx_surf(c) = 0._r8 this%qflx_lnd2ocn(c) = 0._r8 @@ -7229,7 +7229,7 @@ subroutine col_cf_init(this, begc, endc, carbon_type) end if this%fphr(c,nlevdecomp+1:nlevgrnd) = 0._r8 !used to be in ch4Mod - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%fphr(c,nlevdecomp+1:nlevgrnd) = 0._r8 else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then this%fphr(c,:) = spval @@ -7239,7 +7239,7 @@ subroutine col_cf_init(this, begc, endc, carbon_type) ! also initialize dynamic landcover fluxes so that they have ! real values on first timestep, prior to calling pftdyn_cnbal - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%dwt_conv_cflux(c) = 0._r8 this%dwt_prod10c_gain(c) = 0._r8 this%dwt_prod100c_gain(c) = 0._r8 diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index 515152442b53..ab9508565670 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -2462,7 +2462,7 @@ subroutine veg_cs_init(this, begp, endp, carbon_type, ratio) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (veg_pp%itype(p) == noveg) then this%leafc(p) = 0._r8 @@ -3938,7 +3938,7 @@ subroutine veg_ns_init(this, begp, endp, veg_cs) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (veg_pp%itype(p) == noveg) then this%leafn(p) = 0._r8 this%leafn_storage(p) = 0._r8 @@ -4623,7 +4623,7 @@ subroutine veg_ps_init(this, begp, endp, veg_cs) do p = begp,endp l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (veg_pp%itype(p) == noveg) then this%leafp(p) = 0._r8 @@ -7959,7 +7959,7 @@ subroutine veg_cf_init(this, begp, endp, carbon_type) this%xsmrpool_c13ratio(p) = spval endif end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%tempsum_npp(p) = 0._r8 this%annsum_npp(p) = 0._r8 this%availc(p) = 0._r8 @@ -9508,7 +9508,7 @@ subroutine veg_nf_init(this, begp, endp) this%soyfixn(p) = 0._r8 end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%fert_counter(p) = 0._r8 end if @@ -10583,7 +10583,7 @@ subroutine veg_pf_init(this, begp, endp) end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%fert_p_counter(p) = 0._r8 end if From b37f84c7003b315791ad3bd150ba09cf3e8093ee Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 07:39:31 -0700 Subject: [PATCH 261/398] Changes few biophysics code changes to use logicals --- components/elm/src/biogeophys/BalanceCheckMod.F90 | 2 +- components/elm/src/biogeophys/BareGroundFluxesMod.F90 | 2 +- components/elm/src/biogeophys/CanopyHydrologyMod.F90 | 2 +- components/elm/src/biogeophys/CanopyStateType.F90 | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 index 560fed5533b6..2f4b9a31de24 100644 --- a/components/elm/src/biogeophys/BalanceCheckMod.F90 +++ b/components/elm/src/biogeophys/BalanceCheckMod.F90 @@ -497,7 +497,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & endif endif - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop .or. lun_pp%itype(l) == istwet ) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c) .or. lun_pp%itype(l) == istwet ) 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) ) & diff --git a/components/elm/src/biogeophys/BareGroundFluxesMod.F90 b/components/elm/src/biogeophys/BareGroundFluxesMod.F90 index 939fae055b80..517689b2f416 100644 --- a/components/elm/src/biogeophys/BareGroundFluxesMod.F90 +++ b/components/elm/src/biogeophys/BareGroundFluxesMod.F90 @@ -414,7 +414,7 @@ subroutine BareGroundFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & rh_ref2m(p) = min(100._r8, q_ref2m(p) / qsat_ref2m * 100._r8) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then rh_ref2m_r(p) = rh_ref2m(p) t_ref2m_r(p) = t_ref2m(p) end if diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 index c935dabd605a..ddf966de74a0 100644 --- a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 +++ b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 @@ -826,7 +826,7 @@ subroutine FracH2OSfc(bounds, num_h2osfc, filter_h2osfc, & l = col_pp%landunit(c) qflx_h2osfc2topsoi(c) = 0._r8 ! h2osfc only calculated for soil vegetated land units - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then ! Use newton-raphson method to iteratively determine frac_h20sfc ! based on amount of surface water storage (h2osfc) and diff --git a/components/elm/src/biogeophys/CanopyStateType.F90 b/components/elm/src/biogeophys/CanopyStateType.F90 index 650191999e34..ee158482674b 100644 --- a/components/elm/src/biogeophys/CanopyStateType.F90 +++ b/components/elm/src/biogeophys/CanopyStateType.F90 @@ -515,7 +515,7 @@ subroutine InitCold(this, bounds) this%dewmx_patch(p) = 0.1_r8 this%vegwp_patch(p,:) = -2.5e4_r8 - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%laisun_patch(p) = 0._r8 this%laisha_patch(p) = 0._r8 end if @@ -532,7 +532,7 @@ subroutine InitCold(this, bounds) do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%alt_col(c) = 0._r8 this%altmax_col(c) = 0._r8 this%altmax_lastyear_col(c) = 0._r8 From 13ce812c526048a07e572fb413a9ebcd0c1abb61 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:00:37 -0700 Subject: [PATCH 262/398] Fixes the setting of logicals --- components/elm/src/main/initSubgridMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/src/main/initSubgridMod.F90 b/components/elm/src/main/initSubgridMod.F90 index 13b3d3979789..6694910fcb59 100644 --- a/components/elm/src/main/initSubgridMod.F90 +++ b/components/elm/src/main/initSubgridMod.F90 @@ -565,8 +565,8 @@ subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop) col_pp%wtlunit(ci) = wtlunit col_pp%itype(ci) = ctype - if (present(is_soil)) col_pp%is_soil = is_soil - if (present(is_crop)) col_pp%is_crop = is_crop + if (present(is_soil)) col_pp%is_soil(ci) = is_soil + if (present(is_crop)) col_pp%is_crop(ci) = is_crop end subroutine add_column From 843e9abe5acae29042552825f2cfe96795cd6130 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:05:17 -0700 Subject: [PATCH 263/398] Changes more biophysics code changes to use logicals --- components/elm/src/biogeophys/CanopyTemperatureMod.F90 | 10 +++++----- components/elm/src/biogeophys/HydrologyDrainageMod.F90 | 4 ++-- .../elm/src/biogeophys/HydrologyNoDrainageMod.F90 | 2 +- components/elm/src/biogeophys/PhotosynthesisType.F90 | 4 ++-- components/elm/src/biogeophys/SoilFluxesMod.F90 | 6 +++--- components/elm/src/biogeophys/SoilHydrologyMod.F90 | 2 +- components/elm/src/biogeophys/SoilStateType.F90 | 2 +- components/elm/src/biogeophys/SoilTemperatureMod.F90 | 8 ++++---- components/elm/src/biogeophys/SurfaceAlbedoMod.F90 | 2 +- components/elm/src/biogeophys/SurfaceRadiationMod.F90 | 8 ++++---- components/elm/src/biogeophys/SurfaceResistanceMod.F90 | 2 +- components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 | 4 ++-- components/elm/src/biogeophys/WaterfluxType.F90 | 2 +- 13 files changed, 28 insertions(+), 28 deletions(-) diff --git a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 index d1e9185b40e1..1898839692ed 100644 --- a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 +++ b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 @@ -244,7 +244,7 @@ subroutine CanopyTemperature(bounds, & if (lun_pp%itype(l)/=istwet .AND. lun_pp%itype(l)/=istice & .AND. lun_pp%itype(l)/=istice_mec) then - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then wx = (h2osoi_liq(c,1)/denh2o+h2osoi_ice(c,1)/denice)/dz(c,1) fac = min(1._r8, wx/watsat(c,1)) fac = max( fac, 0.01_r8 ) @@ -297,7 +297,7 @@ subroutine CanopyTemperature(bounds, & end if ! compute humidities individually for snow, soil, h2osfc for vegetated landunits - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then call QSat(t_soisno(c,snl(c)+1), forc_pbot(t), eg, degdT, qsatg, qsatgdT) if (qsatg > forc_q(t) .and. forc_q(t) > qsatg) then @@ -418,13 +418,13 @@ subroutine CanopyTemperature(bounds, & if (urbpoi(l)) then eflx_sh_tot_u(p) = 0._r8 - else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then eflx_sh_tot_r(p) = 0._r8 end if eflx_lh_tot(p) = 0._r8 if (urbpoi(l)) then eflx_lh_tot_u(p) = 0._r8 - else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then eflx_lh_tot_r(p) = 0._r8 end if eflx_sh_veg(p) = 0._r8 @@ -456,7 +456,7 @@ subroutine CanopyTemperature(bounds, & t = veg_pp%topounit(p) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (frac_veg_nosno(p) == 0) then forc_hgt_u_patch(p) = forc_hgt_u(t) + z0mg(c) + displa(p) forc_hgt_t_patch(p) = forc_hgt_t(t) + z0mg(c) + displa(p) diff --git a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 index c110d2e386d2..d3f307400775 100644 --- a/components/elm/src/biogeophys/HydrologyDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyDrainageMod.F90 @@ -337,12 +337,12 @@ subroutine HydrologyDrainage(bounds, & qflx_runoff(c) = qflx_drain(c) + qflx_surf(c) + qflx_h2osfc_surf(c) + qflx_qrgwl(c) + qflx_drain_perched(c) - if ((col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) .and. col_pp%active(c)) then + if ((col_pp%is_soil(c) .or. col_pp%is_crop(c)) .and. col_pp%active(c)) then qflx_irr_demand(c) = -1.0_r8 * f_surf(g,tpu_ind)*qflx_irrig(c) !surface water demand send to MOSART end if if (lun_pp%urbpoi(l)) then qflx_runoff_u(c) = qflx_runoff(c) - else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then qflx_runoff_r(c) = qflx_runoff(c) end if diff --git a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 index 2dd303e7be21..218838b130e5 100644 --- a/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/components/elm/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -451,7 +451,7 @@ subroutine HydrologyNoDrainage(bounds, & t_soi_10cm(c) = t_soi_10cm(c)/0.1_r8 tsoi17(c) = tsoi17(c)/0.17_r8 ! F. Li and S. Levis end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then t_grnd_r(c) = t_soisno(c,snl(c)+1) end if diff --git a/components/elm/src/biogeophys/PhotosynthesisType.F90 b/components/elm/src/biogeophys/PhotosynthesisType.F90 index af5f01d01ba3..754a85b95203 100644 --- a/components/elm/src/biogeophys/PhotosynthesisType.F90 +++ b/components/elm/src/biogeophys/PhotosynthesisType.F90 @@ -456,7 +456,7 @@ subroutine TimeStepInit (this, bounds) this%c14_psnsha_patch(p) = 0._r8 endif end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop & + if (col_pp%is_soil(c) .or. col_pp%is_crop(c) & .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec & .or. lun_pp%itype(l) == istwet) then if (use_c13) then @@ -515,7 +515,7 @@ subroutine photosyns_vars_TimeStepInit (photosyns_vars, bounds) photosyns_vars%c14_psnsha_patch(p) = 0._r8 endif end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop & + if (col_pp%is_soil(c) .or. col_pp%is_crop(c) & .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec & .or. lun_pp%itype(l) == istwet) then if (use_c13) then diff --git a/components/elm/src/biogeophys/SoilFluxesMod.F90 b/components/elm/src/biogeophys/SoilFluxesMod.F90 index d4ce4c185a6c..df70ff7ba863 100644 --- a/components/elm/src/biogeophys/SoilFluxesMod.F90 +++ b/components/elm/src/biogeophys/SoilFluxesMod.F90 @@ -288,7 +288,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & - emg(c)*sb*lw_grnd - emg(c)*sb*t_grnd0(c)**3*(4._r8*tinc(c)) & - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then eflx_soil_grnd_r(p) = eflx_soil_grnd(p) end if else @@ -312,7 +312,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & eflx_sh_tot(p) = eflx_sh_veg(p) + eflx_sh_grnd(p) qflx_evap_tot(p) = qflx_evap_veg(p) + qflx_evap_soi(p) eflx_lh_tot(p)= hvap*qflx_evap_veg(p) + htvp(c)*qflx_evap_soi(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then eflx_lh_tot_r(p)= eflx_lh_tot(p) eflx_sh_tot_r(p)= eflx_sh_tot(p) else if (lun_pp%urbpoi(l)) then @@ -432,7 +432,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & + 4._r8*emg(c)*sb*t_grnd0(c)**3*tinc(c) eflx_lwrad_net(p) = eflx_lwrad_out(p) - forc_lwrad(t) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then eflx_lwrad_net_r(p) = eflx_lwrad_out(p) - forc_lwrad(t) eflx_lwrad_out_r(p) = eflx_lwrad_out(p) end if diff --git a/components/elm/src/biogeophys/SoilHydrologyMod.F90 b/components/elm/src/biogeophys/SoilHydrologyMod.F90 index a33eae43fc5e..51f1dd28711f 100644 --- a/components/elm/src/biogeophys/SoilHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SoilHydrologyMod.F90 @@ -448,7 +448,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f pc = pc_grid(g) ! partition moisture fluxes between soil and h2osfc - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then ! explicitly use frac_sno=0 if snl=0 if (snl(c) >= 0) then diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index 3be8b2a9d7d8..73573209823a 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -409,7 +409,7 @@ subroutine InitCold(this, bounds) do c = bounds%begc,bounds%endc this%rootfr_col (c,nlevsoi+1:nlevgrnd) = 0._r8 - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%rootfr_col (c,nlevsoi+1:nlevgrnd) = 0._r8 else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then this%rootfr_col (c,:) = spval diff --git a/components/elm/src/biogeophys/SoilTemperatureMod.F90 b/components/elm/src/biogeophys/SoilTemperatureMod.F90 index 225e2d22be0d..37878d4e77ab 100644 --- a/components/elm/src/biogeophys/SoilTemperatureMod.F90 +++ b/components/elm/src/biogeophys/SoilTemperatureMod.F90 @@ -677,9 +677,9 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte if (j == 1) then ! this only needs to be done once eflx_fgr12(c) = -cnfac*fn(c,1) - (1._r8-cnfac)*fn1(c,1) end if - if (j > 0 .and. j < nlevgrnd .and. (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop)) then + if (j > 0 .and. j < nlevgrnd .and. (col_pp%is_soil(c) .or. col_pp%is_crop(c))) then eflx_fgr(c,j) = -cnfac*fn(c,j) - (1._r8-cnfac)*fn1(c,j) - else if (j == nlevgrnd .and. (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop)) then + else if (j == nlevgrnd .and. (col_pp%is_soil(c) .or. col_pp%is_crop(c))) then eflx_fgr(c,j) = 0._r8 end if @@ -1465,7 +1465,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & ! from Zhao (1997) and Koren (1999) supercool(c,j) = 0.0_r8 - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop .or. col_pp%itype(c) == icol_road_perv) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c) .or. col_pp%itype(c) == icol_road_perv) then if(t_soisno(c,j) < tfrz) then smp = hfus*(tfrz-t_soisno(c,j))/(grav*t_soisno(c,j)) * 1000._r8 !(mm) supercool(c,j) = watsat(c,j)*(smp/sucsat(c,j))**(-1._r8/bsw(c,j)) @@ -1682,7 +1682,7 @@ subroutine Phasechange_beta (bounds, num_nolakec, filter_nolakec, dhsdT, & l = col_pp%landunit(c) if (lun_pp%urbpoi(l)) then eflx_snomelt_u(c) = eflx_snomelt(c) - else if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + else if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then eflx_snomelt_r(c) = eflx_snomelt(c) end if end do diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 834a82bb704f..89b5d0abddc1 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -1052,7 +1052,7 @@ subroutine SoilAlbedo (bounds, & pi = ldomain%pftm(g) if (coszen(c) > 0._r8) then l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop .and. top_pp%active(t)) then ! soil + if (col_pp%is_soil(c) .or. col_pp%is_crop(c) .and. top_pp%active(t)) then ! soil inc = max(0.11_r8-0.40_r8*h2osoi_vol(c,1), 0._r8) soilcol = isoicol(c) ! changed from local variable to elm_type: diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index 3ae75d0a9d2f..fd862d7c651f 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -485,7 +485,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & sabg(p) = 0._r8 sabv(p) = 0._r8 fsa(p) = 0._r8 - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then fsa_r(p) = 0._r8 end if sabg_lyr(p,:) = 0._r8 @@ -522,7 +522,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & if (ib == 1) then parveg(p) = cad(p,ib) + cai(p,ib) end if - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then fsa_r(p) = fsa_r(p) + cad(p,ib) + cai(p,ib) end if @@ -539,7 +539,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & absrad = trd(p,ib)*(1._r8-albgrd(c,ib)) + tri(p,ib)*(1._r8-albgri(c,ib)) sabg(p) = sabg(p) + absrad fsa(p) = fsa(p) + absrad - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then fsa_r(p) = fsa_r(p) + absrad end if if (snl(c) == 0) then @@ -679,7 +679,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & endif ! Diagnostic: shortwave penetrating ground (e.g. top layer) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then sabg_pen(p) = sabg(p) - sabg_lyr(p, snl(c)+1) end if diff --git a/components/elm/src/biogeophys/SurfaceResistanceMod.F90 b/components/elm/src/biogeophys/SurfaceResistanceMod.F90 index e0cfa145852b..27b9dccd90fa 100644 --- a/components/elm/src/biogeophys/SurfaceResistanceMod.F90 +++ b/components/elm/src/biogeophys/SurfaceResistanceMod.F90 @@ -141,7 +141,7 @@ subroutine calc_beta_leepielke1992(bounds, num_nolakec, filter_nolakec, & l = col_pp%landunit(c) if (lun_pp%itype(l)/=istwet .AND. lun_pp%itype(l)/=istice & .AND. lun_pp%itype(l)/=istice_mec) then - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then wx = (h2osoi_liq(c,1)/denh2o+h2osoi_ice(c,1)/denice)/col_pp%dz(c,1) fac = min(1._r8, wx/watsat(c,1)) fac = max( fac, 0.01_r8 ) diff --git a/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 b/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 index 061fb6f7289c..5287b74c13c6 100644 --- a/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 +++ b/components/elm/src/biogeophys/TotalWaterAndHeatMod.F90 @@ -267,7 +267,7 @@ subroutine ComputeLiqIceMassNonLake(bounds, num_nolakec, filter_nolakec, & do fc = 1, num_nolakec c = filter_nolakec(fc) l = col_pp%landunit(c) - if ( (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop ) & + if ( (col_pp%is_soil(c) .or. col_pp%is_crop(c) ) & .or. (lun_pp%itype(l) == istwet ) & .or. (lun_pp%itype(l) == istice ) & .or. (lun_pp%itype(l) == istice_mec ) & @@ -276,7 +276,7 @@ subroutine ComputeLiqIceMassNonLake(bounds, num_nolakec, filter_nolakec, & end if l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then ! note: soil specified at LU level + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then ! note: soil specified at LU level do p = col_pp%pfti(c),col_pp%pftf(c) ! loop over patches if (veg_pp%active(p)) then liquid_mass(c) = liquid_mass(c) + h2ocan_patch(p) * veg_pp%wtcol(p) diff --git a/components/elm/src/biogeophys/WaterfluxType.F90 b/components/elm/src/biogeophys/WaterfluxType.F90 index 73b9f01975ee..56586b2932b5 100644 --- a/components/elm/src/biogeophys/WaterfluxType.F90 +++ b/components/elm/src/biogeophys/WaterfluxType.F90 @@ -373,7 +373,7 @@ subroutine InitCold(this, bounds) ! needed for NitrogenLeaching do c = bounds%begc, bounds%endc l = col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%qflx_drain_col(c) = 0._r8 this%qflx_surf_col(c) = 0._r8 this%qflx_irr_demand_col(c) = 0._r8 From 011a629897892417b07f0d022dbd098221f3d5b6 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:08:25 -0700 Subject: [PATCH 264/398] Changes remaining code changes to use logicals --- components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 | 2 +- components/elm/src/main/filterMod.F90 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 b/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 index 9983f7f70899..f4bcc0631218 100644 --- a/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 +++ b/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 @@ -245,7 +245,7 @@ subroutine dyn_cnbal_patch(bounds, & p = filter_soilp_with_inactive(fp) c = veg_pp%column(p) l = veg_pp%landunit(p) - if (.not.(col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) ) Then + if (.not.(col_pp%is_soil(c) .or. col_pp%is_crop(c)) ) Then print *, "istsoil,istcrop",istsoil, istcrop print *, lun_pp%itype(l) end if diff --git a/components/elm/src/main/filterMod.F90 b/components/elm/src/main/filterMod.F90 index 8fa341dbdd00..a92b7079e576 100644 --- a/components/elm/src/main/filterMod.F90 +++ b/components/elm/src/main/filterMod.F90 @@ -358,7 +358,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (top_pp%active(t)) then if (col_pp%active(c) .or. include_inactive) then l =col_pp%landunit(c) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then fs = fs + 1 this_filter(nc)%soilc(fs) = c end if @@ -376,7 +376,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (top_pp%active(t)) then if (veg_pp%active(p) .or. include_inactive) then l =veg_pp%landunit(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then fs = fs + 1 this_filter(nc)%soilp(fs) = p end if @@ -424,7 +424,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (veg_pp%active(p) .or. include_inactive) then if (.not. iscft(veg_pp%itype(p))) then l =veg_pp%landunit(p) - if (col_pp%itype(c) == istsoil .or. lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then fnc = fnc + 1 this_filter(nc)%soilnopcropp(fnc) = p end if From a9cf42813dd4440ddfb5032fecb2d30ef2b0ecd3 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:18:27 -0700 Subject: [PATCH 265/398] Adds code to set if veg is on a soil or crop column --- components/elm/src/data_types/VegetationType.F90 | 9 +++++++++ components/elm/src/main/initGridCellsMod.F90 | 6 +++--- components/elm/src/main/initSubgridMod.F90 | 7 ++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/components/elm/src/data_types/VegetationType.F90 b/components/elm/src/data_types/VegetationType.F90 index 5fc127fbb0f3..4de65776f47c 100644 --- a/components/elm/src/data_types/VegetationType.F90 +++ b/components/elm/src/data_types/VegetationType.F90 @@ -70,6 +70,9 @@ module VegetationType integer , pointer :: mxy (:) => null() ! m index for laixy(i,j,m),etc. (undefined for special landunits) logical , pointer :: active (:) => null() ! true=>do computations on this patch + logical, pointer :: is_on_soil_col(:) => null() ! true, if it is on a column that is soil + logical, pointer :: is_on_crop_col(:) => null() ! ture, if it is on a column that is assocaited with crops + ! Fates relevant types logical , pointer :: is_veg (:) => null() ! This is an ACTIVE fates patch logical , pointer :: is_bareground (:) => null() ! ? @@ -122,6 +125,9 @@ subroutine veg_pp_init(this, begp, endp) allocate(this%mxy (begp:endp)); this%mxy (:) = ispval allocate(this%active (begp:endp)); this%active (:) = .false. + allocate(this%is_on_soil_col(begp:endp)); this%is_on_soil_col(:) = .false. + allocate(this%is_on_crop_col(begp:endp)); this%is_on_crop_col(:) = .false. + allocate(this%is_fates (begp:endp)); this%is_fates (:) = .false. if (use_fates) then allocate(this%is_veg (begp:endp)); this%is_veg (:) = .false. @@ -154,6 +160,9 @@ subroutine veg_pp_clean(this) deallocate(this%mxy ) deallocate(this%active ) + deallocate(this%is_on_soil_col) + deallocate(this%is_on_crop_col) + deallocate(this%is_fates) if (use_fates) then deallocate(this%is_veg) diff --git a/components/elm/src/main/initGridCellsMod.F90 b/components/elm/src/main/initGridCellsMod.F90 index f01d30924b8e..ecf034d3679a 100644 --- a/components/elm/src/main/initGridCellsMod.F90 +++ b/components/elm/src/main/initGridCellsMod.F90 @@ -398,7 +398,7 @@ subroutine set_landunit_veg_compete (ltype, gi, ti,topo_ind, li, ci, pi, setdata else p_wt = wt_nat_patch(gi,topo_ind,m) end if - call add_patch(pi=pi, ci=ci, ptype=m, wtcol=p_wt) + call add_patch(pi=pi, ci=ci, ptype=m, wtcol=p_wt, is_on_soil_col=.true.) end do ! add polygonal landunits and columns if feature turned on @@ -417,7 +417,7 @@ subroutine set_landunit_veg_compete (ltype, gi, ti,topo_ind, li, ci, pi, setdata else p_wt = wt_nat_patch(gi,topo_ind,m) end if - call add_patch(pi=pi, ci=ci, ptype=m, wtcol=p_wt) + call add_patch(pi=pi, ci=ci, ptype=m, wtcol=p_wt, is_on_soil_col=.true.) end do end do end if @@ -592,7 +592,7 @@ subroutine set_landunit_crop_noncompete (ltype, gi, ti,topo_ind, li, ci, pi, set if (create_crop_landunit) then do m = cft_lb, cft_ub call add_column(ci=ci, li=li, ctype=((istcrop*100) + m), wtlunit=wt_cft(gi,topo_ind,m), is_crop=.true.) - call add_patch(pi=pi, ci=ci, ptype=m, wtcol=1.0_r8) + call add_patch(pi=pi, ci=ci, ptype=m, wtcol=1.0_r8, is_on_crop_col=.true.) end do end if diff --git a/components/elm/src/main/initSubgridMod.F90 b/components/elm/src/main/initSubgridMod.F90 index 6694910fcb59..8b13bea1ffd5 100644 --- a/components/elm/src/main/initSubgridMod.F90 +++ b/components/elm/src/main/initSubgridMod.F90 @@ -571,7 +571,7 @@ subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop) end subroutine add_column !----------------------------------------------------------------------- - subroutine add_patch(pi, ci, ptype, wtcol) + subroutine add_patch(pi, ci, ptype, wtcol, is_on_soil_col, is_on_crop_col) ! ! !DESCRIPTION: ! Add an entry in the patch-level arrays. pi gives the index of the last patch added; the @@ -587,6 +587,8 @@ subroutine add_patch(pi, ci, ptype, wtcol) integer , intent(in) :: ci ! column index on which this patch should be placed (assumes this column has already been created) integer , intent(in) :: ptype ! patch type real(r8) , intent(in) :: wtcol ! weight of the patch relative to the column + logical, optional :: is_on_soil_col + logical, optional :: is_on_crop_col ! ! !LOCAL VARIABLES: integer :: li ! landunit index, for convenience @@ -613,6 +615,9 @@ subroutine add_patch(pi, ci, ptype, wtcol) veg_pp%mxy(pi) = ispval end if + if (present(is_on_soil_col)) veg_pp%is_on_soil_col(pi) = is_on_soil_col + if (present(is_on_crop_col)) veg_pp%is_on_crop_col(pi) = is_on_crop_col + end subroutine add_patch From ac07f76fbf3ec17a3fe789998d28860ddf099c93 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:29:03 -0700 Subject: [PATCH 266/398] Adds biogeochem code changes to use veg_pp logicals --- components/elm/src/biogeochem/CNCarbonFluxType.F90 | 2 +- components/elm/src/biogeochem/CNCarbonStateType.F90 | 2 +- components/elm/src/biogeochem/CNNitrogenStateType.F90 | 2 +- components/elm/src/biogeochem/DUSTMod.F90 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/elm/src/biogeochem/CNCarbonFluxType.F90 b/components/elm/src/biogeochem/CNCarbonFluxType.F90 index 00d6528831a0..36e747a2b832 100644 --- a/components/elm/src/biogeochem/CNCarbonFluxType.F90 +++ b/components/elm/src/biogeochem/CNCarbonFluxType.F90 @@ -1036,7 +1036,7 @@ subroutine InitCold(this, bounds) this%xsmrpool_c13ratio_patch(p) = spval endif end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%tempsum_npp_patch(p) = 0._r8 this%annsum_npp_patch(p) = 0._r8 this%availc_patch(p) = 0._r8 diff --git a/components/elm/src/biogeochem/CNCarbonStateType.F90 b/components/elm/src/biogeochem/CNCarbonStateType.F90 index 6ecf1995a3b4..e768163bc3fc 100644 --- a/components/elm/src/biogeochem/CNCarbonStateType.F90 +++ b/components/elm/src/biogeochem/CNCarbonStateType.F90 @@ -451,7 +451,7 @@ subroutine InitCold(this, bounds, ratio, c12_carbonstate_vars) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafc_patch(p) = 0._r8 diff --git a/components/elm/src/biogeochem/CNNitrogenStateType.F90 b/components/elm/src/biogeochem/CNNitrogenStateType.F90 index cbd4d8eefc5e..8e10a5398a91 100644 --- a/components/elm/src/biogeochem/CNNitrogenStateType.F90 +++ b/components/elm/src/biogeochem/CNNitrogenStateType.F90 @@ -563,7 +563,7 @@ subroutine InitCold(this, bounds, & l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafn_patch(p) = 0._r8 this%leafn_storage_patch(p) = 0._r8 diff --git a/components/elm/src/biogeochem/DUSTMod.F90 b/components/elm/src/biogeochem/DUSTMod.F90 index 78571e39bba4..69a50040ef47 100644 --- a/components/elm/src/biogeochem/DUSTMod.F90 +++ b/components/elm/src/biogeochem/DUSTMod.F90 @@ -350,7 +350,7 @@ subroutine DustEmission (bounds, & ! linearly from 1 to 0 as VAI(=tlai+tsai) increases from 0 to vai_mbl_thr ! if ice sheet, wetland, or lake, no dust allowed - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (tlai_lu(l) < vai_mbl_thr) then lnd_frc_mbl(p) = 1.0_r8 - (tlai_lu(l))/vai_mbl_thr else From 9bfe76de484923724351e956d2d609ce0162106b Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:38:16 -0700 Subject: [PATCH 267/398] Adds biogeophys code changes to use veg_pp logicals --- components/elm/src/biogeophys/BareGroundFluxesMod.F90 | 2 +- components/elm/src/biogeophys/CanopyStateType.F90 | 2 +- components/elm/src/biogeophys/CanopyTemperatureMod.F90 | 6 +++--- components/elm/src/biogeophys/PhotosynthesisType.F90 | 4 ++-- components/elm/src/biogeophys/SoilFluxesMod.F90 | 6 +++--- components/elm/src/biogeophys/SurfaceRadiationMod.F90 | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/components/elm/src/biogeophys/BareGroundFluxesMod.F90 b/components/elm/src/biogeophys/BareGroundFluxesMod.F90 index 517689b2f416..aff2447831b6 100644 --- a/components/elm/src/biogeophys/BareGroundFluxesMod.F90 +++ b/components/elm/src/biogeophys/BareGroundFluxesMod.F90 @@ -414,7 +414,7 @@ subroutine BareGroundFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & rh_ref2m(p) = min(100._r8, q_ref2m(p) / qsat_ref2m * 100._r8) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then rh_ref2m_r(p) = rh_ref2m(p) t_ref2m_r(p) = t_ref2m(p) end if diff --git a/components/elm/src/biogeophys/CanopyStateType.F90 b/components/elm/src/biogeophys/CanopyStateType.F90 index ee158482674b..9b05cc2b6713 100644 --- a/components/elm/src/biogeophys/CanopyStateType.F90 +++ b/components/elm/src/biogeophys/CanopyStateType.F90 @@ -515,7 +515,7 @@ subroutine InitCold(this, bounds) this%dewmx_patch(p) = 0.1_r8 this%vegwp_patch(p,:) = -2.5e4_r8 - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%laisun_patch(p) = 0._r8 this%laisha_patch(p) = 0._r8 end if diff --git a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 index 1898839692ed..12344898f9e5 100644 --- a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 +++ b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 @@ -418,13 +418,13 @@ subroutine CanopyTemperature(bounds, & if (urbpoi(l)) then eflx_sh_tot_u(p) = 0._r8 - else if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + else if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then eflx_sh_tot_r(p) = 0._r8 end if eflx_lh_tot(p) = 0._r8 if (urbpoi(l)) then eflx_lh_tot_u(p) = 0._r8 - else if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + else if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then eflx_lh_tot_r(p) = 0._r8 end if eflx_sh_veg(p) = 0._r8 @@ -456,7 +456,7 @@ subroutine CanopyTemperature(bounds, & t = veg_pp%topounit(p) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (frac_veg_nosno(p) == 0) then forc_hgt_u_patch(p) = forc_hgt_u(t) + z0mg(c) + displa(p) forc_hgt_t_patch(p) = forc_hgt_t(t) + z0mg(c) + displa(p) diff --git a/components/elm/src/biogeophys/PhotosynthesisType.F90 b/components/elm/src/biogeophys/PhotosynthesisType.F90 index 754a85b95203..40da9836b291 100644 --- a/components/elm/src/biogeophys/PhotosynthesisType.F90 +++ b/components/elm/src/biogeophys/PhotosynthesisType.F90 @@ -456,7 +456,7 @@ subroutine TimeStepInit (this, bounds) this%c14_psnsha_patch(p) = 0._r8 endif end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c) & + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p) & .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec & .or. lun_pp%itype(l) == istwet) then if (use_c13) then @@ -515,7 +515,7 @@ subroutine photosyns_vars_TimeStepInit (photosyns_vars, bounds) photosyns_vars%c14_psnsha_patch(p) = 0._r8 endif end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c) & + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p) & .or. lun_pp%itype(l) == istice .or. lun_pp%itype(l) == istice_mec & .or. lun_pp%itype(l) == istwet) then if (use_c13) then diff --git a/components/elm/src/biogeophys/SoilFluxesMod.F90 b/components/elm/src/biogeophys/SoilFluxesMod.F90 index df70ff7ba863..f18ead86f1e2 100644 --- a/components/elm/src/biogeophys/SoilFluxesMod.F90 +++ b/components/elm/src/biogeophys/SoilFluxesMod.F90 @@ -288,7 +288,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & - emg(c)*sb*lw_grnd - emg(c)*sb*t_grnd0(c)**3*(4._r8*tinc(c)) & - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then eflx_soil_grnd_r(p) = eflx_soil_grnd(p) end if else @@ -312,7 +312,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & eflx_sh_tot(p) = eflx_sh_veg(p) + eflx_sh_grnd(p) qflx_evap_tot(p) = qflx_evap_veg(p) + qflx_evap_soi(p) eflx_lh_tot(p)= hvap*qflx_evap_veg(p) + htvp(c)*qflx_evap_soi(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then eflx_lh_tot_r(p)= eflx_lh_tot(p) eflx_sh_tot_r(p)= eflx_sh_tot(p) else if (lun_pp%urbpoi(l)) then @@ -432,7 +432,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & + 4._r8*emg(c)*sb*t_grnd0(c)**3*tinc(c) eflx_lwrad_net(p) = eflx_lwrad_out(p) - forc_lwrad(t) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then eflx_lwrad_net_r(p) = eflx_lwrad_out(p) - forc_lwrad(t) eflx_lwrad_out_r(p) = eflx_lwrad_out(p) end if diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index fd862d7c651f..5843803da0f4 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -485,7 +485,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & sabg(p) = 0._r8 sabv(p) = 0._r8 fsa(p) = 0._r8 - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then fsa_r(p) = 0._r8 end if sabg_lyr(p,:) = 0._r8 @@ -522,7 +522,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & if (ib == 1) then parveg(p) = cad(p,ib) + cai(p,ib) end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then fsa_r(p) = fsa_r(p) + cad(p,ib) + cai(p,ib) end if @@ -539,7 +539,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & absrad = trd(p,ib)*(1._r8-albgrd(c,ib)) + tri(p,ib)*(1._r8-albgri(c,ib)) sabg(p) = sabg(p) + absrad fsa(p) = fsa(p) + absrad - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then fsa_r(p) = fsa_r(p) + absrad end if if (snl(c) == 0) then @@ -679,7 +679,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & endif ! Diagnostic: shortwave penetrating ground (e.g. top layer) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then sabg_pen(p) = sabg(p) - sabg_lyr(p, snl(c)+1) end if From 5128c7c4512bafd55f009b1ab382683bb492ff30 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 08:42:26 -0700 Subject: [PATCH 268/398] More code changes to use veg_pp logicals --- components/elm/src/data_types/CNStateType.F90 | 2 +- components/elm/src/data_types/VegetationDataType.F90 | 12 ++++++------ .../elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 | 2 +- components/elm/src/main/filterMod.F90 | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/elm/src/data_types/CNStateType.F90 b/components/elm/src/data_types/CNStateType.F90 index 2e33cea96e73..13327f4b537b 100644 --- a/components/elm/src/data_types/CNStateType.F90 +++ b/components/elm/src/data_types/CNStateType.F90 @@ -1099,7 +1099,7 @@ subroutine initCold(this, bounds) do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%rc14_atm_patch(p) = c14ratio diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index ab9508565670..738ce98e325e 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -2462,7 +2462,7 @@ subroutine veg_cs_init(this, begp, endp, carbon_type, ratio) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafc(p) = 0._r8 @@ -3938,7 +3938,7 @@ subroutine veg_ns_init(this, begp, endp, veg_cs) l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafn(p) = 0._r8 this%leafn_storage(p) = 0._r8 @@ -4623,7 +4623,7 @@ subroutine veg_ps_init(this, begp, endp, veg_cs) do p = begp,endp l = veg_pp%landunit(p) c = veg_pp%column(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafp(p) = 0._r8 @@ -7959,7 +7959,7 @@ subroutine veg_cf_init(this, begp, endp, carbon_type) this%xsmrpool_c13ratio(p) = spval endif end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%tempsum_npp(p) = 0._r8 this%annsum_npp(p) = 0._r8 this%availc(p) = 0._r8 @@ -9508,7 +9508,7 @@ subroutine veg_nf_init(this, begp, endp) this%soyfixn(p) = 0._r8 end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%fert_counter(p) = 0._r8 end if @@ -10583,7 +10583,7 @@ subroutine veg_pf_init(this, begp, endp) end if - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%fert_p_counter(p) = 0._r8 end if diff --git a/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 b/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 index f4bcc0631218..5f8fb02a4cc1 100644 --- a/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 +++ b/components/elm/src/dyn_subgrid/dynConsBiogeochemMod.F90 @@ -245,7 +245,7 @@ subroutine dyn_cnbal_patch(bounds, & p = filter_soilp_with_inactive(fp) c = veg_pp%column(p) l = veg_pp%landunit(p) - if (.not.(col_pp%is_soil(c) .or. col_pp%is_crop(c)) ) Then + if (.not.(veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) ) Then print *, "istsoil,istcrop",istsoil, istcrop print *, lun_pp%itype(l) end if diff --git a/components/elm/src/main/filterMod.F90 b/components/elm/src/main/filterMod.F90 index a92b7079e576..0ec701e9a3e9 100644 --- a/components/elm/src/main/filterMod.F90 +++ b/components/elm/src/main/filterMod.F90 @@ -376,7 +376,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (top_pp%active(t)) then if (veg_pp%active(p) .or. include_inactive) then l =veg_pp%landunit(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then fs = fs + 1 this_filter(nc)%soilp(fs) = p end if @@ -424,7 +424,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (veg_pp%active(p) .or. include_inactive) then if (.not. iscft(veg_pp%itype(p))) then l =veg_pp%landunit(p) - if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then + if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then fnc = fnc + 1 this_filter(nc)%soilnopcropp(fnc) = p end if From e42bdbbe87b1d5b304608b1cecef6ade90a9c583 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 12:17:48 -0700 Subject: [PATCH 269/398] Deletes changes that are not needed --- components/elm/src/biogeochem/CNCarbonFluxType.F90 | 1 - components/elm/src/biogeochem/CNCarbonStateType.F90 | 1 - components/elm/src/biogeochem/CNNitrogenStateType.F90 | 1 - components/elm/src/biogeophys/CanopyStateType.F90 | 1 - components/elm/src/biogeophys/CanopyTemperatureMod.F90 | 1 - components/elm/src/biogeophys/PhotosynthesisType.F90 | 2 -- components/elm/src/biogeophys/SurfaceRadiationMod.F90 | 1 - components/elm/src/data_types/CNStateType.F90 | 1 - components/elm/src/data_types/VegetationDataType.F90 | 6 ------ components/elm/src/main/filterMod.F90 | 2 -- 10 files changed, 17 deletions(-) diff --git a/components/elm/src/biogeochem/CNCarbonFluxType.F90 b/components/elm/src/biogeochem/CNCarbonFluxType.F90 index 36e747a2b832..b1c2e4fb5e62 100644 --- a/components/elm/src/biogeochem/CNCarbonFluxType.F90 +++ b/components/elm/src/biogeochem/CNCarbonFluxType.F90 @@ -1018,7 +1018,6 @@ subroutine InitCold(this, bounds) do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) - c = veg_pp%column(p) this%gpp_patch(p) = 0._r8 this%gpp_before_downreg_patch(p) = 0._r8 diff --git a/components/elm/src/biogeochem/CNCarbonStateType.F90 b/components/elm/src/biogeochem/CNCarbonStateType.F90 index e768163bc3fc..a1794e3d0181 100644 --- a/components/elm/src/biogeochem/CNCarbonStateType.F90 +++ b/components/elm/src/biogeochem/CNCarbonStateType.F90 @@ -450,7 +450,6 @@ subroutine InitCold(this, bounds, ratio, c12_carbonstate_vars) this%leafcmax_patch(p) = 0._r8 l = veg_pp%landunit(p) - c = veg_pp%column(p) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then diff --git a/components/elm/src/biogeochem/CNNitrogenStateType.F90 b/components/elm/src/biogeochem/CNNitrogenStateType.F90 index 8e10a5398a91..93911c4f6390 100644 --- a/components/elm/src/biogeochem/CNNitrogenStateType.F90 +++ b/components/elm/src/biogeochem/CNNitrogenStateType.F90 @@ -562,7 +562,6 @@ subroutine InitCold(this, bounds, & do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) - c = veg_pp%column(p) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafn_patch(p) = 0._r8 diff --git a/components/elm/src/biogeophys/CanopyStateType.F90 b/components/elm/src/biogeophys/CanopyStateType.F90 index 9b05cc2b6713..b07db4b7ad04 100644 --- a/components/elm/src/biogeophys/CanopyStateType.F90 +++ b/components/elm/src/biogeophys/CanopyStateType.F90 @@ -503,7 +503,6 @@ subroutine InitCold(this, bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) - c = veg_pp%column(p) this%frac_veg_nosno_patch(p) = 0._r8 this%tlai_patch(p) = 0._r8 diff --git a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 index 12344898f9e5..63083feb42f9 100644 --- a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 +++ b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 @@ -414,7 +414,6 @@ subroutine CanopyTemperature(bounds, & eflx_sh_tot(p) = 0._r8 l = veg_pp%landunit(p) - c = veg_pp%column(p) if (urbpoi(l)) then eflx_sh_tot_u(p) = 0._r8 diff --git a/components/elm/src/biogeophys/PhotosynthesisType.F90 b/components/elm/src/biogeophys/PhotosynthesisType.F90 index 40da9836b291..e00e725ef96b 100644 --- a/components/elm/src/biogeophys/PhotosynthesisType.F90 +++ b/components/elm/src/biogeophys/PhotosynthesisType.F90 @@ -426,7 +426,6 @@ subroutine TimeStepInit (this, bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) - c = veg_pp%column(p) if (.not. lun_pp%lakpoi(l)) then this%psnsun_patch(p) = 0._r8 this%psnsun_wc_patch(p) = 0._r8 @@ -487,7 +486,6 @@ subroutine photosyns_vars_TimeStepInit (photosyns_vars, bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) - c = veg_pp%column(p) if (.not. lun_pp%lakpoi(l)) then photosyns_vars%psnsun_patch(p) = 0._r8 photosyns_vars%psnsun_wc_patch(p) = 0._r8 diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index 5843803da0f4..8c645b1ee86d 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -479,7 +479,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & do fp = 1,num_nourbanp p = filter_nourbanp(fp) l = veg_pp%landunit(p) - c = veg_pp%column(p) sabg_soil(p) = 0._r8 sabg_snow(p) = 0._r8 sabg(p) = 0._r8 diff --git a/components/elm/src/data_types/CNStateType.F90 b/components/elm/src/data_types/CNStateType.F90 index 13327f4b537b..660f3eac1e40 100644 --- a/components/elm/src/data_types/CNStateType.F90 +++ b/components/elm/src/data_types/CNStateType.F90 @@ -1098,7 +1098,6 @@ subroutine initCold(this, bounds) do p = bounds%begp,bounds%endp l = veg_pp%landunit(p) - c = veg_pp%column(p) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then this%rc14_atm_patch(p) = c14ratio diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index 738ce98e325e..353d0b883228 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -2461,7 +2461,6 @@ subroutine veg_cs_init(this, begp, endp, carbon_type, ratio) this%leafcmax(p) = 0._r8 l = veg_pp%landunit(p) - c = veg_pp%column(p) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then @@ -3937,7 +3936,6 @@ subroutine veg_ns_init(this, begp, endp, veg_cs) do p = begp,endp l = veg_pp%landunit(p) - c = veg_pp%column(p) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then this%leafn(p) = 0._r8 @@ -4622,7 +4620,6 @@ subroutine veg_ps_init(this, begp, endp, veg_cs) do p = begp,endp l = veg_pp%landunit(p) - c = veg_pp%column(p) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then if (veg_pp%itype(p) == noveg) then @@ -7941,7 +7938,6 @@ subroutine veg_cf_init(this, begp, endp, carbon_type) if (.not.use_fates) then do p = begp,endp l = veg_pp%landunit(p) - c = veg_pp%column(p) this%gpp(p) = 0._r8 this%gpp_before_downreg(p) = 0._r8 @@ -9495,7 +9491,6 @@ subroutine veg_nf_init(this, begp, endp) do p = begp,endp l = veg_pp%landunit(p) - c = veg_pp%column(p) this%prev_leafn_to_litter(p) = 0._r8 this%prev_frootn_to_litter(p) = 0._r8 @@ -10572,7 +10567,6 @@ subroutine veg_pf_init(this, begp, endp) end do do p = begp,endp l = veg_pp%landunit(p) - c = veg_pp%column(p) this%prev_leafp_to_litter (p) = 0._r8 this%prev_frootp_to_litter(p) = 0._r8 diff --git a/components/elm/src/main/filterMod.F90 b/components/elm/src/main/filterMod.F90 index 0ec701e9a3e9..0975c01bf90f 100644 --- a/components/elm/src/main/filterMod.F90 +++ b/components/elm/src/main/filterMod.F90 @@ -372,7 +372,6 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc fs = 0 do p = bounds%begp,bounds%endp t =veg_pp%topounit(p) - c = veg_pp%column(p) if (top_pp%active(t)) then if (veg_pp%active(p) .or. include_inactive) then l =veg_pp%landunit(p) @@ -419,7 +418,6 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc fnc = 0 do p = bounds%begp,bounds%endp t =veg_pp%topounit(p) - c = veg_pp%column(p) if (top_pp%active(t)) then if (veg_pp%active(p) .or. include_inactive) then if (.not. iscft(veg_pp%itype(p))) then From 9749298cfdeba766a67082f0d45c6e100ff2b93b Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 12:27:15 -0700 Subject: [PATCH 270/398] Changes few not conditional comparisions --- components/elm/src/biogeophys/SedYieldMod.F90 | 2 +- components/elm/src/biogeophys/SnowHydrologyMod.F90 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/elm/src/biogeophys/SedYieldMod.F90 b/components/elm/src/biogeophys/SedYieldMod.F90 index 62f2db4b4565..83c6ae220fa5 100644 --- a/components/elm/src/biogeophys/SedYieldMod.F90 +++ b/components/elm/src/biogeophys/SedYieldMod.F90 @@ -157,7 +157,7 @@ subroutine SoilErosion (bounds, num_soilc, filter_soilc, & flx_sed_yld(c) = 0._r8 ! check landunit type and ground covered by snow/ice - if ( lun_pp%itype(l) /= istsoil .and. lun_pp%itype(l) /= istcrop ) then + if ( .not.col_pp%is_soil(c) .and. .not.col_pp%is_crop(c) ) then cycle end if diff --git a/components/elm/src/biogeophys/SnowHydrologyMod.F90 b/components/elm/src/biogeophys/SnowHydrologyMod.F90 index 5191d96f6366..2158eac1ecf6 100644 --- a/components/elm/src/biogeophys/SnowHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SnowHydrologyMod.F90 @@ -911,7 +911,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & mss_dst4(c,j+1) = mss_dst4(c,j+1) + mss_dst4(c,j) end if - else if (ltype(l) /= istsoil .and. .not. urbpoi(l) .and. ltype(l) /= istcrop .and. j /= 0) then + else if (.not.col_pp%is_soil(c) .and. .not. urbpoi(l) .and. .not.col_pp%is_crop(c) .and. j /= 0) then h2osoi_liq(c,j+1) = h2osoi_liq(c,j+1) + h2osoi_liq(c,j) h2osoi_ice(c,j+1) = h2osoi_ice(c,j+1) + h2osoi_ice(c,j) @@ -935,7 +935,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & ! urban, soil or crop, the h2osoi_liq and h2osoi_ice associated with this layer is sent ! to qflx_qrgwl later on in the code. To keep track of this for the snow balance ! error check, we add this to qflx_sl_top_soil here - if (ltype(l) /= istsoil .and. ltype(l) /= istcrop .and. .not. urbpoi(l) .and. i == 0) then + if (.not.col_pp%is_soil(c) .and. .not.col_pp%is_crop(c) .and. .not. urbpoi(l) .and. i == 0) then qflx_sl_top_soil(c) = (h2osoi_liq(c,i) + h2osoi_ice(c,i))/dtime end if From 791e1bd07a55be719d576152047598c1a41bcf3c Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Sun, 12 Oct 2025 12:49:03 -0700 Subject: [PATCH 271/398] Even more changes to use logicals --- components/elm/src/biogeochem/FanUpdateMod.F90 | 8 ++++---- components/elm/src/biogeophys/CanopyHydrologyMod.F90 | 4 ++-- components/elm/src/biogeophys/SnowHydrologyMod.F90 | 6 +++--- components/elm/src/biogeophys/SurfaceAlbedoMod.F90 | 4 ++-- components/elm/src/biogeophys/WaterfluxType.F90 | 2 +- components/elm/src/data_types/VegetationDataType.F90 | 2 +- components/elm/src/dyn_subgrid/dynEDMod.F90 | 2 +- components/elm/src/dyn_subgrid/dynpftFileMod.F90 | 2 +- .../emi/src/emi/ExternalModelInterfaceMod.F90 | 4 ++-- components/elm/src/main/elm_instMod.F90 | 4 ++-- components/elm/src/main/elm_interface_pflotranMod.F90 | 8 ++++---- components/elm/src/main/elmfates_interfaceMod.F90 | 2 +- components/elm/src/main/filterMod.F90 | 6 +++--- components/elm/src/main/lnd2glcMod.F90 | 2 +- components/elm/src/main/subgridRestMod.F90 | 2 +- components/elm/src/main/subgridWeightsMod.F90 | 2 +- 16 files changed, 30 insertions(+), 30 deletions(-) diff --git a/components/elm/src/biogeochem/FanUpdateMod.F90 b/components/elm/src/biogeochem/FanUpdateMod.F90 index 81bb7983273a..a3cfafc80183 100644 --- a/components/elm/src/biogeochem/FanUpdateMod.F90 +++ b/components/elm/src/biogeochem/FanUpdateMod.F90 @@ -264,7 +264,7 @@ subroutine fan_eval(bounds, num_soilc, filter_soilc, & if (.not. col_pp%active(c) .or. col_pp%wtgcell(c) < 1e-6_r8) cycle g = col_pp%gridcell(c) - if (lun_pp%itype(l) == istsoil) then + if (col_pp%is_soil(c)) then col_nf%manure_n_grz(c) & = atm2lnd_vars%forc_ndep_past_grc(g) / col_pp%wtgcell(c) * 1e3_r8 ! kg to g if (col_nf%manure_n_grz(c) > 1e12 .or. isnan(col_nf%manure_n_grz(c))) then @@ -775,7 +775,7 @@ subroutine handle_storage(bounds, frictionvel_vars, dt, & col_grass = ispval l = grc_pp%landunit_indices(istsoil, g) do c = lun_pp%coli(l), lun_pp%colf(l) - if (col_pp%itype(c) == istsoil) then + if (col_pp%is_soil(c)) then col_grass = c exit end if @@ -953,8 +953,8 @@ subroutine fan_to_sminn(bounds, filter_soilc, num_soilc, nfertilization) flux_fert = col_nf%fert_no3_to_soil(c) + col_nf%fert_nh4_to_soil(c) manure_prod = col_nf%manure_n_barns(c) + col_nf%manure_n_grz(c) - included = (lun_pp%itype(l) == istcrop .and. fan_to_bgc_crop) & - .or. (lun_pp%itype(l) == istsoil .and. fan_to_bgc_veg) + included = (col_pp%is_crop(c) .and. fan_to_bgc_crop) & + .or. (col_pp%is_soil(c) .and. fan_to_bgc_veg) if (included) then col_nf%fert_to_sminn(c) = flux_fert + flux_manure diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 index ddf966de74a0..4a2cd4a5fd7a 100644 --- a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 +++ b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 @@ -278,7 +278,7 @@ subroutine CanopyHydrology(bounds, & ! Canopy interception and precipitation onto ground surface ! Add precipitation to leaf water - if (ltype(l) == istsoil .or. ltype(l) == istwet .or. urbpoi(l) .or. & + if (veg_pp%is_on_soil_col(p) .or. ltype(l) == istwet .or. urbpoi(l) .or. & ltype(l) == istcrop) then qflx_candrip(p) = 0._r8 ! rate of canopy runoff @@ -642,7 +642,7 @@ subroutine CanopyHydrology(bounds, & end if !end of do_capsnow construct ! set frac_sno_eff variable - if (ltype(l) == istsoil .or. ltype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then if (subgridflag ==1) then frac_sno_eff(c) = frac_sno(c) else diff --git a/components/elm/src/biogeophys/SnowHydrologyMod.F90 b/components/elm/src/biogeophys/SnowHydrologyMod.F90 index 2158eac1ecf6..8db730cd698c 100644 --- a/components/elm/src/biogeophys/SnowHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SnowHydrologyMod.F90 @@ -705,7 +705,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! Compaction occurring during melt if (imelt(c,j) == 1) then - if(subgridflag==1 .and. (ltype(col_pp%landunit(c)) == istsoil .or. ltype(col_pp%landunit(c)) == istcrop)) then + if(subgridflag==1 .and. (col_pp%is_soil(c) .or. col_pp%is_crop(c))) then ! first term is delta mass over mass ddz3 = max(0._r8,min(1._r8,(swe_old(c,j) - wx)/wx)) @@ -884,7 +884,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & do j = msn_old(c)+1,0 ! use 0.01 to avoid runaway ice buildup if (h2osoi_ice(c,j) <= .01_r8) then - if (ltype(l) == istsoil .or. urbpoi(l) .or. ltype(l) == istcrop) then + if (col_pp%is_soil(c) .or. urbpoi(l) .or. col_pp%is_crop(c)) then h2osoi_liq(c,j+1) = h2osoi_liq(c,j+1) + h2osoi_liq(c,j) h2osoi_ice(c,j+1) = h2osoi_ice(c,j+1) + h2osoi_ice(c,j) @@ -1005,7 +1005,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (h2osno(c) <= 0._r8) snow_depth(c) = 0._r8 ! this is where water is transfered from layer 0 (snow) to layer 1 (soil) - if (ltype(l) == istsoil .or. urbpoi(l) .or. ltype(l) == istcrop) then + if (col_pp%is_soil(c) .or. urbpoi(l) .or. col_pp%is_crop(c)) then h2osoi_liq(c,0) = 0.0_r8 h2osoi_liq(c,1) = h2osoi_liq(c,1) + zwliq(c) qflx_snow2topsoi(c) = zwliq(c)/dtime diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 89b5d0abddc1..137cdeedbe95 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -734,8 +734,8 @@ subroutine SurfaceAlbedo(bounds, & do fp = 1,num_nourbanp p = filter_nourbanp(fp) if (coszen_patch(p) > 0._r8) then - if ((lun_pp%itype(veg_pp%landunit(p)) == istsoil .or. & - lun_pp%itype(veg_pp%landunit(p)) == istcrop ) & + if ((veg_pp%is_on_soil_col(p) .or. & + veg_pp%is_on_crop_col(p) ) & .and. (elai(p) + esai(p)) > 0._r8) then num_vegsol = num_vegsol + 1 filter_vegsol(num_vegsol) = p diff --git a/components/elm/src/biogeophys/WaterfluxType.F90 b/components/elm/src/biogeophys/WaterfluxType.F90 index 56586b2932b5..d165c0750c61 100644 --- a/components/elm/src/biogeophys/WaterfluxType.F90 +++ b/components/elm/src/biogeophys/WaterfluxType.F90 @@ -383,7 +383,7 @@ subroutine InitCold(this, bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil) then + if (veg_pp%is_on_soil_col(p)) then this%n_irrig_steps_left_patch(p) = 0 this%irrig_rate_patch(p) = 0.0_r8 end if diff --git a/components/elm/src/data_types/VegetationDataType.F90 b/components/elm/src/data_types/VegetationDataType.F90 index 353d0b883228..a43e5f142f2d 100644 --- a/components/elm/src/data_types/VegetationDataType.F90 +++ b/components/elm/src/data_types/VegetationDataType.F90 @@ -5589,7 +5589,7 @@ subroutine veg_wf_init(this, begp, endp) do p = begp, endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil) then + if (veg_pp%is_on_soil_col(p)) then this%n_irrig_steps_left(p) = 0 this%irrig_rate(p) = 0.0_r8 end if diff --git a/components/elm/src/dyn_subgrid/dynEDMod.F90 b/components/elm/src/dyn_subgrid/dynEDMod.F90 index 29882dedb4c7..1cfde410e718 100644 --- a/components/elm/src/dyn_subgrid/dynEDMod.F90 +++ b/components/elm/src/dyn_subgrid/dynEDMod.F90 @@ -30,7 +30,7 @@ subroutine dyn_ED( bounds ) do p = bounds%begp,bounds%endp c = veg_pp%column(p) - if (col_pp%itype(c) == istsoil .and. col_pp%active(c) ) then + if (col_pp%is_soil(c) .and. col_pp%active(c) ) then if ( veg_pp%is_veg(p) .or. veg_pp%is_bareground(p)) then veg_pp%wtcol(p) = veg_pp%wt_ed(p) else diff --git a/components/elm/src/dyn_subgrid/dynpftFileMod.F90 b/components/elm/src/dyn_subgrid/dynpftFileMod.F90 index 69a3535fd51a..b01c72515c30 100644 --- a/components/elm/src/dyn_subgrid/dynpftFileMod.F90 +++ b/components/elm/src/dyn_subgrid/dynpftFileMod.F90 @@ -283,7 +283,7 @@ subroutine dynpft_interp(bounds) ! (if there is one) ! (However, currently [as of 5-9-13] the code won't let you run with transient ! Patches combined with create_crop_landunit anyway, so it's a moot point.) - if (lun_pp%itype(l) == istsoil) then + if (veg_pp%is_on_soil_col(p)) then m = veg_pp%itype(p) ! Note that the following assignment assumes that all Patches share a single column diff --git a/components/elm/src/external_models/emi/src/emi/ExternalModelInterfaceMod.F90 b/components/elm/src/external_models/emi/src/emi/ExternalModelInterfaceMod.F90 index c2c5c7d20642..46476a8ed9d2 100644 --- a/components/elm/src/external_models/emi/src/emi/ExternalModelInterfaceMod.F90 +++ b/components/elm/src/external_models/emi/src/emi/ExternalModelInterfaceMod.F90 @@ -371,8 +371,8 @@ subroutine EMI_Init_EM(em_id) do c = bounds_clump%begc,bounds_clump%endc if (col_pp%active(c)) then l = col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. col_pp%itype(c) == icol_road_perv .or. & - lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%itype(c) == icol_road_perv .or. & + col_pp%is_crop(c)) then num_e2l_filter_col = num_e2l_filter_col + 1 tmp_col(c) = 1 end if diff --git a/components/elm/src/main/elm_instMod.F90 b/components/elm/src/main/elm_instMod.F90 index 906325f23ec8..bdf5147186dc 100644 --- a/components/elm/src/main/elm_instMod.F90 +++ b/components/elm/src/main/elm_instMod.F90 @@ -319,7 +319,7 @@ subroutine elm_inst_biogeophys(bounds_proc) if (lun_pp%itype(l) == istice) then h2osno_col(c) = h2osno_max elseif (lun_pp%itype(l) == istice_mec .or. & - (lun_pp%itype(l) == istsoil .and. ldomain%glcmask(g) > 0._r8)) then + (col_pp%is_soil(c) .and. ldomain%glcmask(g) > 0._r8)) then ! Initialize a non-zero snow thickness where the ice sheet can/potentially operate. ! Using glcmask to capture all potential vegetated points around GrIS (ideally ! we would use icemask from CISM, but that isn't available until after initialization.) @@ -352,7 +352,7 @@ subroutine elm_inst_biogeophys(bounds_proc) ! land ice (including multiple elevation classes, i.e. glacier_mec) h2osno_col(c) = 0.5_r8*h2osno_max ! start with half full snow column, representing deep firn snow_depth_col(c) = h2osno_col(c) / bdfirn - else if (lun_pp%itype(l) == istsoil .and. grc_pp%latdeg(g) >= 44._r8) then + else if (col_pp%is_soil(c) .and. grc_pp%latdeg(g) >= 44._r8) then ! Northern hemisphere seasonal snow h2osno_col(c) = 50._r8 snow_depth_col(c) = h2osno_col(c) / bdsno diff --git a/components/elm/src/main/elm_interface_pflotranMod.F90 b/components/elm/src/main/elm_interface_pflotranMod.F90 index aedb85c26b91..f3303afb4f96 100644 --- a/components/elm/src/main/elm_interface_pflotranMod.F90 +++ b/components/elm/src/main/elm_interface_pflotranMod.F90 @@ -484,7 +484,7 @@ subroutine interface_init(bounds) !write (iulog,*) 'WARNING: SOIL/CROP column with wtgcell <= 0 or inactive... within the domain' !write (iulog,*) 'ELM-- PFLOTRAN does not include such a SOIL/CROP column, AND will skip it' - elseif ( .not.(ltype(l) == istsoil .or. ltype(l) == istcrop) ) then + elseif ( .not.(col_pp%is_soil(c) .or. col_pp%is_crop(c)) ) then !write (iulog,*) 'WARNING: non-SOIL/CROP column found in filter%num_soilc: nc, l, ltype', nc, l, ltype(l) !write (iulog,*) 'ELM-- PFLOTRAN does not include such a SOIL/CROP column, AND will skip it' @@ -548,7 +548,7 @@ subroutine interface_init(bounds) g = cgridcell(c) gcount = g - bounds%begg + 1 - if ((.not.(ltype(l) == istsoil)) .and. (.not.(ltype(l) == istcrop)) ) then + if ((.not.(col_pp%is_soil(c))) .and. (.not.(col_pp%is_crop(c))) ) then !write (iulog,*) 'WARNING: Land Unit type of Non-SOIL/CROP... within the domain' !write (iulog,*) 'ELM-- PFLOTRAN does not support this land unit at present, AND will skip it' @@ -598,7 +598,7 @@ subroutine interface_init(bounds) g = cgridcell(c) gcount = g-bounds%begg+1 - if( (ltype(l) == istsoil .or. ltype(l) == istcrop) .and. & + if( (col_pp%is_soil(c) .or. col_pp%is_crop(c)) .and. & (cactive(c) .and. cwtgcell(c)>0._r8) ) then mapped_gid(gcount) = grc_pp%gindex(g) ! this is the globally grid-index, i.e. 'an' in its original calculation @@ -1856,7 +1856,7 @@ subroutine get_elm_soil_properties(elm_interface_data, bounds, filters) g = cgridcell(c) l = clandunit(c) - if ( (ltype(l) == istsoil .or. ltype(l) == istcrop) .and. & + if ( (col_pp%is_soil(c) .or. col_pp%is_crop(c)) .and. & (cactive(c) .and. cwtgcell(c)>0._r8) ) then ! skip inactive or zero-weighted column (may be not needed, but in case) #ifdef COLUMN_MODE diff --git a/components/elm/src/main/elmfates_interfaceMod.F90 b/components/elm/src/main/elmfates_interfaceMod.F90 index 17b808337aa1..7c7643404d56 100644 --- a/components/elm/src/main/elmfates_interfaceMod.F90 +++ b/components/elm/src/main/elmfates_interfaceMod.F90 @@ -932,7 +932,7 @@ subroutine init(this, bounds_proc, flandusepftdat) ! INTERF-TODO: WE HAVE NOT FILTERED OUT FATES SITES ON INACTIVE COLUMNS.. YET ! NEED A RUN-TIME ROUTINE THAT CLEARS AND REWRITES THE SITE LIST - if ( (lun_pp%itype(l) == istsoil) .and. (col_pp%active(c)) ) then + if ( (col_pp%is_soil(c)) .and. (col_pp%active(c)) ) then s = s + 1 collist(s) = c this%f2hmap(nc)%hsites(c) = s diff --git a/components/elm/src/main/filterMod.F90 b/components/elm/src/main/filterMod.F90 index 0975c01bf90f..80d376abd889 100644 --- a/components/elm/src/main/filterMod.F90 +++ b/components/elm/src/main/filterMod.F90 @@ -393,8 +393,8 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc if (top_pp%active(t)) then if (col_pp%active(c) .or. include_inactive) then l =col_pp%landunit(c) - if (lun_pp%itype(l) == istsoil .or. col_pp%itype(c) == icol_road_perv .or. & - lun_pp%itype(l) == istcrop) then + if (col_pp%is_soil(c) .or. col_pp%itype(c) == icol_road_perv .or. & + col_pp%is_crop(c)) then f = f + 1 this_filter(nc)%hydrologyc(f) = c @@ -530,7 +530,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, icemask_grc l = col_pp%landunit(c) g = col_pp%gridcell(c) if ( lun_pp%itype(l) == istice_mec .or. & - (lun_pp%itype(l) == istsoil .and. icemask_grc(g) > 0.)) then + (col_pp%is_soil(c) .and. icemask_grc(g) > 0.)) then f = f + 1 this_filter(nc)%do_smb_c(f) = c end if diff --git a/components/elm/src/main/lnd2glcMod.F90 b/components/elm/src/main/lnd2glcMod.F90 index f938bb7abf23..9b9b4673f737 100644 --- a/components/elm/src/main/lnd2glcMod.F90 +++ b/components/elm/src/main/lnd2glcMod.F90 @@ -182,7 +182,7 @@ subroutine update_lnd2glc(this, bounds, num_do_smb_c, filter_do_smb_c, init) if (lun_pp%itype(l) == istice_mec) then n = col_itype_to_icemec_class(col_pp%itype(c)) flux_normalization = 1.0_r8 - else if (lun_pp%itype(l) == istsoil) then + else if (col_pp%is_soil(c)) then n = 0 !0-level index (bareland information) flux_normalization = bareland_normalization(c) else diff --git a/components/elm/src/main/subgridRestMod.F90 b/components/elm/src/main/subgridRestMod.F90 index b12c71ca66f4..855d8ccc7ade 100644 --- a/components/elm/src/main/subgridRestMod.F90 +++ b/components/elm/src/main/subgridRestMod.F90 @@ -702,7 +702,7 @@ subroutine check_weights(bounds) do p = bounds%begp, bounds%endp l = veg_pp%landunit(p) - if (lun_pp%itype(l) == istsoil) then + if (veg_pp%is_on_soil_col(p)) then diff = abs(veg_pp%wtlunit(p) - pft_wtlunit_before_rest_read(p)) if (diff > tol) then write(iulog,*) 'ERROR: PFT weights are SIGNIFICANTLY different between the restart (finidat) file' diff --git a/components/elm/src/main/subgridWeightsMod.F90 b/components/elm/src/main/subgridWeightsMod.F90 index 0367efd71cbe..0e0219771b02 100644 --- a/components/elm/src/main/subgridWeightsMod.F90 +++ b/components/elm/src/main/subgridWeightsMod.F90 @@ -958,7 +958,7 @@ subroutine set_pct_pft_diagnostics(bounds) !topi = grc_pp%topi(g) !ti = t - topi + 1 ptype = veg_pp%itype(p) - if (lun_pp%itype(l) == istsoil) then + if (veg_pp%is_on_soil_col(p)) then ptype_1indexing = ptype + (1 - natpft_lb) subgrid_weights_diagnostics%pct_nat_pft(t, ptype_1indexing) = veg_pp%wtlunit(p) * 100._r8 else if (lun_pp%itype(l) == istcrop) then From ddef90e5640b6fec2c4befb7ebedffacf9a08f44 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Mon, 13 Oct 2025 14:24:50 -0700 Subject: [PATCH 272/398] Adds new member to identify if the column is a lake --- components/elm/src/data_types/ColumnType.F90 | 3 +++ components/elm/src/main/initGridCellsMod.F90 | 5 ++++- components/elm/src/main/initSubgridMod.F90 | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/components/elm/src/data_types/ColumnType.F90 b/components/elm/src/data_types/ColumnType.F90 index efd8ff9eb8cf..8edc53511d3e 100644 --- a/components/elm/src/data_types/ColumnType.F90 +++ b/components/elm/src/data_types/ColumnType.F90 @@ -79,6 +79,7 @@ module ColumnType logical, pointer :: is_soil(:) => null() ! True if the column is a soil logical, pointer :: is_crop(:) => null() ! True if the column is a crop + logical, pointer :: is_lake(:) => null() ! True if the column is a lake contains @@ -145,6 +146,7 @@ subroutine col_pp_init(this, begc, endc) allocate(this%is_soil (begc:endc)); this%is_soil (:) = .false. allocate(this%is_crop (begc:endc)); this%is_crop (:) = .false. + allocate(this%is_lake (begc:endc)); this%is_lake (:) = .false. end subroutine col_pp_init @@ -187,6 +189,7 @@ subroutine col_pp_clean(this) deallocate(this%is_fates) deallocate(this%is_soil) deallocate(this%is_crop) + deallocate(this%is_lake) end subroutine col_pp_clean diff --git a/components/elm/src/main/initGridCellsMod.F90 b/components/elm/src/main/initGridCellsMod.F90 index ecf034d3679a..a0e99dd2102d 100644 --- a/components/elm/src/main/initGridCellsMod.F90 +++ b/components/elm/src/main/initGridCellsMod.F90 @@ -459,6 +459,7 @@ subroutine set_landunit_wet_ice_lake (ltype, gi, ti,topo_ind, li, ci, pi, setdat integer :: npfts ! number of pfts in landunit real(r8) :: wtlunit2topounit ! landunit weight in topounit real(r8) :: wtcol2lunit ! col weight in landunit + logical :: is_lake_col !------------------------------------------------------------------------ ! Set decomposition properties @@ -467,9 +468,11 @@ subroutine set_landunit_wet_ice_lake (ltype, gi, ti,topo_ind, li, ci, pi, setdat ! gridcell as the new landunit weights on each topounit. ! Later, this information will come from new surface datasat. + is_lake_col = .false. if (ltype == istwet) then call subgrid_get_topounitinfo(ti, gi,tgi=topo_ind, nwetland=npfts) else if (ltype == istdlak) then + is_lake_col = .true. call subgrid_get_topounitinfo(ti, gi,tgi=topo_ind, nlake=npfts) else if (ltype == istice) then call subgrid_get_topounitinfo(ti, gi,tgi=topo_ind, nglacier=npfts) @@ -522,7 +525,7 @@ subroutine set_landunit_wet_ice_lake (ltype, gi, ti,topo_ind, li, ci, pi, setdat ! and that each column has its own pft call add_landunit(li=li, ti=ti, ltype=ltype, wttopounit=wtlunit2topounit) - call add_column(ci=ci, li=li, ctype=ltype, wtlunit=1.0_r8) + call add_column(ci=ci, li=li, ctype=ltype, wtlunit=1.0_r8, is_lake=is_lake_col) call add_patch(pi=pi, ci=ci, ptype=noveg, wtcol=1.0_r8) end if ! ltype = istice_mec diff --git a/components/elm/src/main/initSubgridMod.F90 b/components/elm/src/main/initSubgridMod.F90 index 8b13bea1ffd5..e496bce442eb 100644 --- a/components/elm/src/main/initSubgridMod.F90 +++ b/components/elm/src/main/initSubgridMod.F90 @@ -537,7 +537,7 @@ end subroutine add_polygon_landunit !----------------------------------------------------------------------- - subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop) + subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop, is_lake) ! ! !DESCRIPTION: ! Add an entry in the column-level arrays. ci gives the index of the last column @@ -551,6 +551,7 @@ subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop) real(r8) , intent(in) :: wtlunit ! weight of the column relative to the landunit logical , optional :: is_soil ! true for a soil column logical , optional :: is_crop ! true for a crop column + logical , optional :: is_lake ! true for a lake column ! ! !LOCAL VARIABLES: character(len=*), parameter :: subname = 'add_column' @@ -567,6 +568,7 @@ subroutine add_column(ci, li, ctype, wtlunit, is_soil, is_crop) if (present(is_soil)) col_pp%is_soil(ci) = is_soil if (present(is_crop)) col_pp%is_crop(ci) = is_crop + if (present(is_lake)) col_pp%is_lake(ci) = is_lake end subroutine add_column From 7de34087c90ec6f16b3ba05b79e955b3c5ce3b64 Mon Sep 17 00:00:00 2001 From: Gautam Bisht Date: Mon, 13 Oct 2025 14:32:37 -0700 Subject: [PATCH 273/398] Uses logicals for lake columns --- components/elm/src/biogeochem/CH4Mod.F90 | 4 ++-- components/elm/src/biogeochem/CNCarbonFluxType.F90 | 2 +- components/elm/src/biogeophys/BalanceCheckMod.F90 | 2 +- components/elm/src/biogeophys/SnowHydrologyMod.F90 | 4 ++-- components/elm/src/biogeophys/SoilStateType.F90 | 6 +++--- components/elm/src/biogeophys/SurfaceAlbedoMod.F90 | 8 ++++---- components/elm/src/biogeophys/SurfaceRadiationMod.F90 | 2 +- components/elm/src/data_types/ColumnDataType.F90 | 2 +- components/elm/src/main/initVerticalMod.F90 | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/components/elm/src/biogeochem/CH4Mod.F90 b/components/elm/src/biogeochem/CH4Mod.F90 index 0450a44e6203..f6203665b7ad 100644 --- a/components/elm/src/biogeochem/CH4Mod.F90 +++ b/components/elm/src/biogeochem/CH4Mod.F90 @@ -806,7 +806,7 @@ subroutine InitCold(this, bounds, cellorg_col) ! Note that finundated will be overwritten with this%fsat_bef_col upon reading ! a restart file - either in a continuation, branch or startup spun-up case - else if (lun_pp%itype(l) == istdlak) then + else if (col_pp%is_lake(c)) then this%conc_ch4_sat_col(c,1:nlevsoi) = 0._r8 this%conc_o2_sat_col (c,1:nlevsoi) = 0._r8 @@ -860,7 +860,7 @@ subroutine InitCold(this, bounds, cellorg_col) this%ch4_prod_depth_lake_col (c,:) = spval this%ch4_oxid_depth_lake_col (c,:) = spval - else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then + else if (col_pp%is_lake(c) .and. allowlakeprod) then this%ch4_prod_depth_unsat_col (c,:) = spval this%ch4_oxid_depth_unsat_col (c,:) = spval diff --git a/components/elm/src/biogeochem/CNCarbonFluxType.F90 b/components/elm/src/biogeochem/CNCarbonFluxType.F90 index b1c2e4fb5e62..f2af432a869b 100644 --- a/components/elm/src/biogeochem/CNCarbonFluxType.F90 +++ b/components/elm/src/biogeochem/CNCarbonFluxType.F90 @@ -1059,7 +1059,7 @@ subroutine InitCold(this, bounds) this%fphr_col(c,nlevdecomp+1:nlevgrnd) = 0._r8 !used to be in CH4Mod if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%fphr_col(c,nlevdecomp+1:nlevgrnd) = 0._r8 - else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then + else if (col_pp%is_lake(c) .and. allowlakeprod) then this%fphr_col(c,:) = spval else ! Inactive CH4 columns this%fphr_col(c,:) = spval diff --git a/components/elm/src/biogeophys/BalanceCheckMod.F90 b/components/elm/src/biogeophys/BalanceCheckMod.F90 index 2f4b9a31de24..f46091972852 100644 --- a/components/elm/src/biogeophys/BalanceCheckMod.F90 +++ b/components/elm/src/biogeophys/BalanceCheckMod.F90 @@ -469,7 +469,7 @@ subroutine ColWaterBalanceCheck( bounds, num_do_smb_c, filter_do_smb_c, & snow_sinks(c) = qflx_sub_snow(c) + qflx_evap_grnd(c) + qflx_snow_melt(c) & + qflx_snwcp_ice(c) + qflx_snwcp_liq(c) + qflx_sl_top_soil(c) - if (lun_pp%itype(l) == istdlak) then + if (col_pp%is_lake(c)) then if (.not. use_firn_percolation_and_compaction) then if ( do_capsnow(c)) then snow_sources(c) = qflx_snow_grnd_col(c) & diff --git a/components/elm/src/biogeophys/SnowHydrologyMod.F90 b/components/elm/src/biogeophys/SnowHydrologyMod.F90 index 8db730cd698c..da648f88ca2c 100644 --- a/components/elm/src/biogeophys/SnowHydrologyMod.F90 +++ b/components/elm/src/biogeophys/SnowHydrologyMod.F90 @@ -858,7 +858,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (num_snowc > 0) then c = filter_snowc(1) l = col_pp%landunit(c) - if (ltype(l) == istdlak) then ! Called from LakeHydrology + if (col_pp%is_lake(c)) then ! Called from LakeHydrology if (.not. use_extrasnowlayers) then dzminloc(:) = dzmin(:) + lsadz else @@ -987,7 +987,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & c = filter_snowc(fc) l = col_pp%landunit(c) if (snow_depth(c) > 0._r8) then - if ((ltype(l) == istdlak .and. snow_depth(c) < 0.01_r8 + lsadz ) .or. & + if ((col_pp%is_lake(c) .and. snow_depth(c) < 0.01_r8 + lsadz ) .or. & ((ltype(l) /= istdlak) .and. ((frac_sno_eff(c)*snow_depth(c) < 0.01_r8) & .or. (h2osno(c)/(frac_sno_eff(c)*snow_depth(c)) < 50._r8)))) then diff --git a/components/elm/src/biogeophys/SoilStateType.F90 b/components/elm/src/biogeophys/SoilStateType.F90 index 73573209823a..ff4a100141ed 100644 --- a/components/elm/src/biogeophys/SoilStateType.F90 +++ b/components/elm/src/biogeophys/SoilStateType.F90 @@ -411,7 +411,7 @@ subroutine InitCold(this, bounds) this%rootfr_col (c,nlevsoi+1:nlevgrnd) = 0._r8 if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%rootfr_col (c,nlevsoi+1:nlevgrnd) = 0._r8 - else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then + else if (col_pp%is_lake(c) .and. allowlakeprod) then this%rootfr_col (c,:) = spval else ! Inactive CH4 columns this%rootfr_col (c,:) = spval @@ -713,7 +713,7 @@ subroutine InitCold(this, bounds) endif end if - if (lun_pp%itype(l) == istdlak) then + if (col_pp%is_lake(c)) then if (lev <= nlevsoi) then this%cellsand_col(c,lev) = sand @@ -833,7 +833,7 @@ subroutine InitCold(this, bounds) g = col_pp%gridcell(c) l = col_pp%landunit(c) - if (lun_pp%itype(l) == istdlak) then + if (col_pp%is_lake(c)) then do lev = 1,nlevgrnd if ( lev <= nlevsoi )then diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 137cdeedbe95..9bcf1e4df24e 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -684,7 +684,7 @@ subroutine SurfaceAlbedo(bounds, & ! weight snow layer radiative absorption factors based on snow fraction and soil albedo ! (NEEDED FOR ENERGY CONSERVATION) do i = -nlevsno+1,1,1 - if (subgridflag == 0 .or. lun_pp%itype(l) == istdlak) then + if (subgridflag == 0 .or. col_pp%is_lake(c)) then if (ib == 1) then flx_absdv(c,i) = flx_absd_snw(c,i,ib)*frac_sno(c) + & ((1.-frac_sno(c))*(1-albsod(c,ib))*(flx_absd_snw(c,i,ib)/(1.-albsnd(c,ib)))) @@ -1067,7 +1067,7 @@ subroutine SoilAlbedo (bounds, & albsod(c,ib) = albice(ib) albsoi(c,ib) = albsod(c,ib) ! unfrozen lake, wetland - else if (t_grnd(c) > tfrz .or. (lakepuddling .and. lun_pp%itype(l) == istdlak .and. t_grnd(c) == tfrz .and. & + else if (t_grnd(c) > tfrz .or. (lakepuddling .and. col_pp%is_lake(c) .and. t_grnd(c) == tfrz .and. & lake_icefrac(c,1) < 1._r8 .and. lake_icefrac(c,2) > 0._r8) .and. top_pp%active(t)) then albsod(c,ib) = 0.05_r8/(max(0.001_r8,coszen(c)) + 0.15_r8) @@ -1079,7 +1079,7 @@ subroutine SoilAlbedo (bounds, & ! ZMS: Attn EK, currently restoring this for wetlands even though it is wrong in order to try to get ! bfb baseline comparison when no lakes are present. I'm assuming wetlands will be phased out anyway. - if (lun_pp%itype(l) == istdlak) then + if (col_pp%is_lake(c)) then albsoi(c,ib) = 0.10_r8 else albsoi(c,ib) = albsod(c,ib) @@ -1091,7 +1091,7 @@ subroutine SoilAlbedo (bounds, & ! Tenatively I'm restricting this to lakes because I haven't tested it for wetlands. But if anything ! the albedo should be lower when melting over frozen ground than a solid frozen lake. ! - if (lun_pp%itype(l) == istdlak .and. .not. lakepuddling .and. snl(c) == 0 .and. top_pp%active(t)) then + if (col_pp%is_lake(c) .and. .not. lakepuddling .and. snl(c) == 0 .and. top_pp%active(t)) then ! Need to reference snow layers here because t_grnd could be over snow or ice ! but we really want the ice surface temperature with no snow sicefr = 1._r8 - exp(-calb * (tfrz - t_grnd(c))/tfrz) diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index 8c645b1ee86d..d4a25c54192c 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -637,7 +637,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! If shallow snow depth, all solar radiation absorbed in top or top two snow layers ! to prevent unrealistic timestep soil warming - if (subgridflag == 0 .or. lun_pp%itype(l) == istdlak) then + if (subgridflag == 0 .or. col_pp%is_lake(c)) then if (snow_depth(c) < 0.10_r8) then if (snl(c) == 0) then sabg_lyr(p,-nlevsno+1:0) = 0._r8 diff --git a/components/elm/src/data_types/ColumnDataType.F90 b/components/elm/src/data_types/ColumnDataType.F90 index cb0f9a1e95c9..6582814c416c 100644 --- a/components/elm/src/data_types/ColumnDataType.F90 +++ b/components/elm/src/data_types/ColumnDataType.F90 @@ -7231,7 +7231,7 @@ subroutine col_cf_init(this, begc, endc, carbon_type) this%fphr(c,nlevdecomp+1:nlevgrnd) = 0._r8 !used to be in ch4Mod if (col_pp%is_soil(c) .or. col_pp%is_crop(c)) then this%fphr(c,nlevdecomp+1:nlevgrnd) = 0._r8 - else if (lun_pp%itype(l) == istdlak .and. allowlakeprod) then + else if (col_pp%is_lake(c) .and. allowlakeprod) then this%fphr(c,:) = spval else ! Inactive CH4 columns this%fphr(c,:) = spval diff --git a/components/elm/src/main/initVerticalMod.F90 b/components/elm/src/main/initVerticalMod.F90 index 3199c4f1d8da..0f28aa3887c2 100644 --- a/components/elm/src/main/initVerticalMod.F90 +++ b/components/elm/src/main/initVerticalMod.F90 @@ -474,7 +474,7 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) do c = bounds%begc,bounds%endc l = col_pp%landunit(c) - if (lun_pp%itype(l) == istdlak) then + if (col_pp%is_lake(c)) then if (col_pp%lakedepth(c) == spval) then col_pp%lakedepth(c) = zlak(nlevlak) + 0.5_r8*dzlak(nlevlak) @@ -705,7 +705,7 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof) if (lun_pp%urbpoi(l) .and. col_pp%itype(c) /= icol_road_imperv .and. col_pp%itype(c) /= icol_road_perv) then col_pp%nlevbed(c) = nlevurb - else if (lun_pp%itype(l) == istdlak) then + else if (col_pp%is_lake(c)) then col_pp%nlevbed(c) = nlevlak else if (lun_pp%itype(l) == istice_mec) then col_pp%nlevbed(c) = 5 From e6affb3a2ee58efaf1277901fee2e405df8bc300 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 12:00:30 -0600 Subject: [PATCH 274/398] Add comments to seq_domain_check Add comments to seq_domain_check with help from claude. Done as part of creating MOAB version. --- driver-mct/main/seq_domain_mct.F90 | 99 +++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/driver-mct/main/seq_domain_mct.F90 b/driver-mct/main/seq_domain_mct.F90 index faec8365c704..1147328f1b19 100644 --- a/driver-mct/main/seq_domain_mct.F90 +++ b/driver-mct/main/seq_domain_mct.F90 @@ -45,6 +45,31 @@ module seq_domain_mct contains !================================================================================ + !================================================================================ + ! subroutine seq_domain_check + ! + ! Purpose: Comprehensive domain validation for E3SM coupled model components + ! + ! This routine validates grid consistency across all climate model components + ! by checking: + ! 1. Component domain extraction and mapping to atmosphere grid + ! 2. Mask/fraction compatibility within each component + ! 3. Coordinate consistency between components sharing grids + ! 4. Fraction sum validation (land+ice+ocean = 1.0) on atmosphere grid + ! 5. Memory cleanup of temporary arrays and domain objects + ! + ! The validation ensures that: + ! - Grid coordinates match within tolerance for same-grid components + ! - Component fractions are physically consistent + ! - Mask and fraction arrays are compatible + ! - Domain mappings are correctly initialized + ! + ! Arguments: + ! infodata - Model configuration data including tolerance values + ! atm,ice,lnd,ocn,rof,glc,iac - Component type structures + ! samegrid_* - Flags indicating which components share identical grids + ! + ! Called from: cime_comp_mod.F90 during CPL initialization when domain_check=true !================================================================================ subroutine seq_domain_check( infodata, & @@ -166,6 +191,12 @@ subroutine seq_domain_check( infodata, & character(*),parameter :: subName = '(seq_domain_check) ' !----------------------------------------------------------- + !--- Initialize component mappers for grid transformations --- + ! These mappers handle regridding between component decompositions: + ! mapper_i2a: ice -> atmosphere, mapper_i2o: ice -> ocean + ! mapper_o2a: ocean -> atmosphere, mapper_l2g: land -> glacier + ! mapper_a2l: atmosphere -> land, mapper_l2a: land -> atmosphere + ! mapper_z2a: iac -> atmosphere mapper_i2a => prep_atm_get_mapper_Fi2a() mapper_i2o => prep_ocn_get_mapper_SFi2o() mapper_o2a => prep_atm_get_mapper_Fo2a() @@ -176,6 +207,13 @@ subroutine seq_domain_check( infodata, & call seq_comm_setptrs(CPLID,iamroot=iamroot, mpicom=mpicom_cplid) + !--- Extract component configuration and validation tolerances --- + ! Get presence flags for each component and tolerance values for: + ! - eps_frac: acceptable error in fraction sums + ! - eps_*mask: acceptable error in mask values + ! - eps_*grid: acceptable error in coordinate values + ! - eps_*area: acceptable error in grid cell areas + call seq_infodata_GetData( infodata, & lnd_present=lnd_present, & ocn_present=ocn_present, & @@ -215,6 +253,10 @@ subroutine seq_domain_check( infodata, & call shr_sys_abort(subname//' atm and lnd grid must have the same global size') end if if (iamroot) write(logunit,F00) ' --- checking land maskfrac ---' + + !--- Process land component domain --- + ! Extract land domain data, validate mask/fraction compatibility, + ! then map to atmosphere grid for intercomparison with other components call seq_domain_check_fracmask(lnddom_l%data) call mct_gGrid_init(oGGrid=lnddom_a, iGGrid=lnddom_l, lsize=atmsize) call mct_aVect_zero(lnddom_a%data) @@ -240,6 +282,10 @@ subroutine seq_domain_check( infodata, & call shr_sys_abort(subname//' atm and ocn grid must have the same global size') end if if (iamroot) write(logunit,F00) ' --- checking ocean maskfrac ---' + + !--- Process ocean component domain --- + ! Similar to land: extract, validate, and map to atmosphere grid. + ! For different grids, use mask as fraction (conservative assumption) call seq_domain_check_fracmask(ocndom_o%data) call mct_gGrid_init(oGGrid=ocndom_a, iGGrid=ocndom_o, lsize=atmsize) call mct_aVect_zero(ocndom_a%data) @@ -270,6 +316,10 @@ subroutine seq_domain_check( infodata, & call shr_sys_abort(subname//' atm and ice grid must have the same global size') end if if (iamroot) write(logunit,F00) ' --- checking ice maskfrac ---' + + !--- Process ice component domain --- + ! Extract ice domain data, validate mask/fraction compatibility, + ! then map to atmosphere grid for fraction validation call seq_domain_check_fracmask(icedom_i%data) call mct_gGrid_init(oGGrid=icedom_a, iGGrid=icedom_i, lsize=atmsize) call mct_aVect_zero(icedom_a%data) @@ -302,6 +352,10 @@ subroutine seq_domain_check( infodata, & 'must have the same global size') end if if (iamroot) write(logunit,F00) ' --- checking iac maskfrac ---' + + !--- Process iac component domain --- + ! IAC domain is relative to atmosphere domain, extract and validate + ! mask/fraction compatibility, then map to atmosphere grid call seq_domain_check_fracmask(iacdom_z%data) call mct_gGrid_init(oGGrid=iacdom_a, iGGrid=iacdom_z, lsize=atmsize) call mct_aVect_zero(iacdom_a%data) @@ -397,6 +451,9 @@ subroutine seq_domain_check( infodata, & if (ocn_present .and. ice_present) then ! if (samegrid_oi) then ! doesn't yet exist + !--- Validate ocean-ice grid consistency --- + ! Ocean and ice must use identical grids. Check that masks, coordinates, + ! and areas match within tolerance on the ocean decomposition npts = ocnsize allocate(mask(npts),stat=rcode) if(rcode /= 0) call shr_sys_abort(subname//' allocate mask') @@ -421,6 +478,9 @@ subroutine seq_domain_check( infodata, & !------------------------------------------------------------------------------ if (atm_present .and. lnd_present .and. samegrid_al) then + !--- Validate atmosphere-land grid consistency (if samegrid_al) --- + ! When atmosphere and land share grids, verify coordinates match + ! within tolerance on the atmosphere decomposition if (iamroot) write(logunit,F00) ' --- checking atm/land domains ---' call seq_domain_check_grid(atmdom_a%data, lnddom_a%data, 'lat' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=maskl) call seq_domain_check_grid(atmdom_a%data, lnddom_a%data, 'lon' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=maskl) @@ -464,6 +524,11 @@ subroutine seq_domain_check( infodata, & !------------------------------------------------------------------------------ if (atm_present) then + !--- Validate fraction sums on atmosphere grid --- + ! Ensure physical consistency: land + ice + ocean fractions = 1.0 + ! at each atmosphere grid point. Use different tolerances based on: + ! - samegrid_ao: tighter tolerance for identical grids + ! - not samegrid_al: relaxed tolerance for different grids my_eps_frac = eps_frac if (samegrid_ao) my_eps_frac = eps_frac_samegrid if (.not. samegrid_al) my_eps_frac = eps_big @@ -518,6 +583,10 @@ subroutine seq_domain_check( infodata, & ! Clean up allocated memory !------------------------------------------------------------------------------ + !--- Clean up temporary arrays and domain objects --- + ! Deallocate fraction/mask arrays and MCT grid objects created + ! during validation to prevent memory leaks + if (atm_present .and. lnd_present) then deallocate(fracl,stat=rcode) if(rcode /= 0) call shr_sys_abort(subname//' deallocate fracl') @@ -596,7 +665,17 @@ subroutine seq_domain_compare(dom1, dom2, mpicom, eps) end subroutine seq_domain_compare - !=============================================================================== + !================================================================================ + + !================================================================================ + ! subroutine seq_domain_check_fracmask + ! + ! Purpose: Validate mask and fraction compatibility within a component + ! + ! Ensures that where fraction > 0, mask must also be > 0. This catches + ! inconsistencies where a component claims to exist somewhere (fraction > 0) + ! but is masked out (mask = 0). + !================================================================================ subroutine seq_domain_check_fracmask(dom1) @@ -650,7 +729,23 @@ subroutine seq_domain_check_fracmask(dom1) end subroutine seq_domain_check_fracmask - !=============================================================================== + !================================================================================ + + !================================================================================ + ! subroutine seq_domain_check_grid + ! + ! Purpose: Compare grid attributes between two domains + ! + ! Validates that the specified grid attribute (lat, lon, area, mask) matches + ! between two domains within tolerance. Handles longitude wraparound for + ! geographic coordinate comparison. + ! + ! Key features: + ! - Longitude periodicity adjustment (360° wraparound) + ! - Optional masking to limit validation to active grid cells + ! - MPI reduction to find maximum difference across all processors + ! - Detailed error reporting with grid point indices + !================================================================================ subroutine seq_domain_check_grid(dom1, dom2, attr, eps, mpicom, mask) From a361502cd0499dbe6512d2d02cc446d919f6cd00 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 12:01:45 -0600 Subject: [PATCH 275/398] Add comments to MOAB seq_map_map Add comments to MOAB seq_map_map with help from claude. Also clean up indenting for readability. --- driver-moab/main/seq_map_mod.F90 | 606 +++++++++++++++++++------------ 1 file changed, 376 insertions(+), 230 deletions(-) diff --git a/driver-moab/main/seq_map_mod.F90 b/driver-moab/main/seq_map_mod.F90 index 845e5269af0b..35cced1c462a 100644 --- a/driver-moab/main/seq_map_mod.F90 +++ b/driver-moab/main/seq_map_mod.F90 @@ -344,6 +344,47 @@ subroutine seq_map_init_rearrolap(mapper, comp_s, comp_d, string, no_match) end subroutine seq_map_init_rearrolap + !======================================================================= + !> + !> @brief Maps attribute vector fields from source to destination grid. + !> + !> This subroutine is the primary mapping interface for transferring field + !> data between component grids. It supports THREE mapping strategies: + !> + !> 1. COPY (mapper%copy_only=.true.) + !> - Used when source and destination grids are IDENTICAL + !> - Simply copies data without any transformation + !> - only in MCT mode + !> + !> 2. REARRANGE (mapper%rearrange_only=.true.) + !> - Used when grids have the SAME points but DIFFERENT MPI distribution + !> - Performs MPI communication to redistribute data + !> + !> 3. MAP (neither copy_only nor rearrange_only) + !> - Full interpolation/regridding between DIFFERENT grids + !> - Uses sparse matrix multiplication with pre-computed weights + !> - Supports optional normalization for conservation + !> + !> *** MOAB Integration *** + !> This subroutine maintains DUAL data paths: + !> - MCT path: Traditional mct_aVect operations (always executed) + !> - MOAB path: Parallel iMOAB operations (executed when valid_moab_context=.true.) + !> + !> The MOAB path uses iMOAB API calls to: + !> - Transfer data between MOAB application instances + !> - Apply projection weights for regridding + !> - Handle normalization for conservative mapping + !> + !> @param mapper Mapping data structure containing weights and grid info + !> @param av_s Source attribute vector (input fields) + !> @param av_d Destination attribute vector (output fields) + !> @param fldlist Optional: specific fields to map (default: all fields) + !> @param norm Optional: enable normalization (default: .true.) + !> @param avwts_s Optional: source weights for normalization + !> @param avwtsfld_s Optional: field name in avwts_s to use as weight + !> @param string Optional: description string for logging + !> @param msgtag Optional: MPI message tag for rearrangement + !> !======================================================================= subroutine seq_map_map( mapper, av_s, av_d, fldlist, norm, avwts_s, avwtsfld_s, & @@ -425,51 +466,70 @@ subroutine seq_map_map( mapper, av_s, av_d, fldlist, norm, avwts_s, avwtsfld_s, call shr_sys_abort(subname//' ERROR: avwtsfld present') endif - ! check whether the application ID is defined on the current process - if ( mapper%src_mbid .lt. 0 .or. mapper%tgt_mbid .lt. 0 ) then - valid_moab_context = .FALSE. + !*** MOAB: Check if MOAB context is valid on this process + !*** A valid MOAB context requires both source and target MOAB app IDs >= 0. + !*** When valid, MOAB operations run IN PARALLEL with MCT operations, + !*** maintaining data consistency between both representations. + if ( mapper%src_mbid .lt. 0 .or. mapper%tgt_mbid .lt. 0 ) then + valid_moab_context = .FALSE. + else + valid_moab_context = .TRUE. + endif + + !*** MOAB: Build field list for MOAB operations + !*** This section constructs a colon-delimited field list string that will + !*** be passed to iMOAB functions. The list is built from either: + !*** - The explicit fldlist argument, or + !*** - All real attributes in the source attribute vector + !*** If normalization is enabled (mbnorm=.true.), "norm8wt" is appended + !*** to carry normalization weights through the mapping. + if ( valid_moab_context ) then + nfields = 1 + ! first get data from source tag and store in a temporary + ! then set it back to target tag to mimic a copy + if (present(fldlist)) then + ! find the number of fields in the list + ! Or should we decipher based on fldlist? + call mct_list_init(temp_list, fldlist) + nfields=mct_list_nitem (temp_list) + call mct_list_clean(temp_list) + fldlist_moab= trim(fldlist) else - valid_moab_context = .TRUE. + ! Extract character strings from attribute vector + nfields = mct_aVect_nRAttr(av_s) + fldlist_moab = '' + if ( nfields /= 0 ) fldlist_moab = trim(mct_aVect_exportRList2c(av_s)) endif - if ( valid_moab_context ) then - nfields = 1 - ! first get data from source tag and store in a temporary - ! then set it back to target tag to mimic a copy - if (present(fldlist)) then - ! find the number of fields in the list - ! Or should we decipher based on fldlist? - call mct_list_init(temp_list, fldlist) - nfields=mct_list_nitem (temp_list) - call mct_list_clean(temp_list) - fldlist_moab= trim(fldlist) - else - ! Extract character strings from attribute vector - nfields = mct_aVect_nRAttr(av_s) - fldlist_moab = '' - if ( nfields /= 0 ) fldlist_moab = trim(mct_aVect_exportRList2c(av_s)) - endif - - if (mbnorm) then - fldlist_moab = trim(fldlist_moab)//":norm8wt"//C_NULL_CHAR - nfields=nfields + 1 - else - fldlist_moab = trim(fldlist_moab)//C_NULL_CHAR - endif + if (mbnorm) then + fldlist_moab = trim(fldlist_moab)//":norm8wt"//C_NULL_CHAR + nfields=nfields + 1 + else + fldlist_moab = trim(fldlist_moab)//C_NULL_CHAR + endif #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit,*) subname, 'iMOAB mapper ',trim(mapper%mbname), ' iMOAB_mapper nfields', & - nfields, ' fldlist_moab=', trim(fldlist_moab), ' moab step ', num_moab_exports - call shr_sys_flush(logunit) - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit,*) subname, 'iMOAB mapper ',trim(mapper%mbname), ' iMOAB_mapper nfields', & + nfields, ' fldlist_moab=', trim(fldlist_moab), ' moab step ', num_moab_exports + call shr_sys_flush(logunit) + endif #endif - endif ! valid_moab_context + endif ! valid_moab_context + + !========================================================================= + ! STRATEGY SELECTION: MCT Path + ! The following three branches handle the MCT-based mapping operations. + ! MOAB operations for these strategies are handled AFTER this section. + !========================================================================= if (mapper%copy_only) then !------------------------------------------- - ! COPY data + ! STRATEGY 1: COPY + ! Source and destination grids are IDENTICAL (same gsmap). + ! No interpolation needed - just copy field values directly. + ! MCT: Uses mct_aVect_copy for efficient memory copy. !------------------------------------------- if (present(fldlist)) then call mct_aVect_copy(aVin=av_s,aVout=av_d,rList=fldlist,vector=mct_usevector) @@ -479,7 +539,11 @@ subroutine seq_map_map( mapper, av_s, av_d, fldlist, norm, avwts_s, avwtsfld_s, else if (mapper%rearrange_only) then !------------------------------------------- - ! REARRANGE data + ! STRATEGY 2: REARRANGE + ! Source and destination grids have SAME grid points but + ! DIFFERENT MPI decomposition (different gsmap). + ! MCT: Uses mct_rearr_rearrange for MPI all-to-all communication + ! to redistribute data across processors. !------------------------------------------- if (present(fldlist)) then call mct_rearr_rearrange_fldlist(av_s, av_d, mapper%rearr, tag=ltag, VECTOR=mct_usevector, & @@ -491,7 +555,14 @@ subroutine seq_map_map( mapper, av_s, av_d, fldlist, norm, avwts_s, avwtsfld_s, else !------------------------------------------- - ! MAP data + ! STRATEGY 3: MAP (Full Interpolation/Regridding) + ! Source and destination are DIFFERENT grids. + ! MCT: Uses sparse matrix-vector multiplication (sMatP) with + ! pre-computed interpolation weights from mapping files. + ! Supports optional normalization via seq_map_avNorm: + ! - If avwts_s provided: multiply source by weights before mapping, + ! then divide result by mapped weights (conservative mapping) + ! - If norm=.true.: apply self-normalization !------------------------------------------- if (present(avwts_s)) then if (present(fldlist)) then @@ -511,227 +582,302 @@ subroutine seq_map_map( mapper, av_s, av_d, fldlist, norm, avwts_s, avwtsfld_s, endif + !========================================================================= + ! MOAB PATH: Copy/Rearrange Operations + ! For COPY and REARRANGE strategies, MOAB uses point-to-point + ! communication between MOAB app instances instead of MCT rearranger. + !========================================================================= if (mapper%copy_only .or. mapper%rearrange_only) then + !*** MOAB: Send/Receive for Copy or Rearrange + !*** For identical or same-grid mappings, MOAB transfers data directly + !*** between source and target MOAB apps using iMOAB_SendElementTag + !*** and iMOAB_ReceiveElementTag. This is analogous to MCT's copy or + !*** rearrange but operates on MOAB mesh data structures. if ( valid_moab_context ) then #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit, *) subname,' iMOAB mapper rearrange or copy ', mapper%mbname, ' send/recv tags ', trim(fldlist_moab), & - ' mbpresent=', mbpresent, ' mbnorm=', mbnorm, ' moab step:', num_moab_exports - call shr_sys_flush(logunit) - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit, *) subname,' iMOAB mapper rearrange or copy ', mapper%mbname, ' send/recv tags ', trim(fldlist_moab), & + ' mbpresent=', mbpresent, ' mbnorm=', mbnorm, ' moab step:', num_moab_exports + call shr_sys_flush(logunit) + endif #endif - ierr = iMOAB_SendElementTag( mapper%src_mbid, fldlist_moab, mapper%mpicom, mapper%intx_context ); - if (ierr .ne. 0) then - write(logunit, *) subname,' iMOAB mapper ', mapper%mbname, ' error in sending tags ', trim(fldlist_moab), ierr - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' ERROR in sending tags') - endif - ! receive in the target app - ierr = iMOAB_ReceiveElementTag( mapper%tgt_mbid, fldlist_moab, mapper%mpicom, mapper%src_context ); - if (ierr .ne. 0) then - write(logunit,*) subname,' error in receiving tags iMOAB mapper ', mapper%mbname, trim(fldlist_moab) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' ERROR in receiving tags') - endif - ! now free buffers - ierr = iMOAB_FreeSenderBuffers( mapper%src_mbid, mapper%intx_context ) - if (ierr .ne. 0) then - write(logunit,*) subname,' error in freeing buffers ', trim(fldlist_moab) - call shr_sys_abort(subname//' ERROR in freeing buffers') ! serious enough - endif + !*** MOAB: iMOAB_SendElementTag - Send field data from source MOAB app + !*** Parameters: + !*** src_mbid: Source MOAB application ID + !*** fldlist_moab: Colon-delimited list of tag names to send + !*** mpicom: MPI communicator + !*** intx_context: Context ID for the intersection/target app + ierr = iMOAB_SendElementTag( mapper%src_mbid, fldlist_moab, mapper%mpicom, mapper%intx_context ); + if (ierr .ne. 0) then + write(logunit, *) subname,' iMOAB mapper ', mapper%mbname, ' error in sending tags ', trim(fldlist_moab), ierr + call shr_sys_flush(logunit) + call shr_sys_abort(subname//' ERROR in sending tags') + endif + !*** MOAB: iMOAB_ReceiveElementTag - Receive field data into target MOAB app + !*** Parameters: + !*** tgt_mbid: Target MOAB application ID + !*** fldlist_moab: Colon-delimited list of tag names to receive + !*** mpicom: MPI communicator + !*** src_context: Context ID for the source app + ierr = iMOAB_ReceiveElementTag( mapper%tgt_mbid, fldlist_moab, mapper%mpicom, mapper%src_context ); + if (ierr .ne. 0) then + write(logunit,*) subname,' error in receiving tags iMOAB mapper ', mapper%mbname, trim(fldlist_moab) + call shr_sys_flush(logunit) + call shr_sys_abort(subname//' ERROR in receiving tags') + endif + !*** MOAB: iMOAB_FreeSenderBuffers - Release MPI send buffers + !*** Must be called after receive completes to free memory. + ierr = iMOAB_FreeSenderBuffers( mapper%src_mbid, mapper%intx_context ) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in freeing buffers ', trim(fldlist_moab) + call shr_sys_abort(subname//' ERROR in freeing buffers') ! serious enough + endif endif ! if (valid_moab_context) - else - + else + !========================================================================= + ! MOAB PATH: Full Mapping Operations (Strategy 3) + ! For full interpolation/regridding between different grids. + ! This is more complex than copy/rearrange and involves: + ! 1. Pre-normalization: Multiply source fields by normalization weight + ! 2. Send/Receive: Transfer data to intersection mesh + ! 3. Apply weights: Apply projection/interpolation weights + ! 4. Post-normalization: Divide by mapped normalization weight + !========================================================================= + + !*** MOAB: Pre-normalization (source side) + !*** For conservative mapping, we need to: + !*** 1. Set norm8wt tag to 1.0 on all source cells + !*** 2. If a weight field (avwtsfld_s) is specified, multiply all fields by it + !*** 3. Map both the fields AND the weights + !*** 4. Post-map: divide fields by mapped weights to restore proper scaling if ( valid_moab_context ) then - ! NORMALIZATION - if (mbnorm .or. mbpresent) then - ! initialize the weight tag and multiply it by the input tags. - ! get target mesh info - ierr = iMOAB_GetMeshInfo ( mapper%src_mbid, nvert, nvise, nbl, nsurf, nvisBC ); - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting mesh info for ', mapper%mbname - call shr_sys_abort(subname//' ERROR getting mesh info') ! serious enough - endif - lsize_src = nvise(1) ! number of active cells - - ! init normalization weight - allocate(wghts(lsize_src)) - wghts = 1.0_r8 - tagname = "norm8wt"//C_NULL_CHAR - ! set the normalization factor to 1 - ierr = iMOAB_SetDoubleTagStorage (mapper%src_mbid, tagname, lsize_src , mapper%tag_entity_type, wghts) - if (ierr .ne. 0) then - write(logunit,*) subname,' error setting init value for mapping norm factor ',ierr,trim(tagname) - call shr_sys_abort(subname//' ERROR setting norm init value') ! serious enough - endif + !*** MOAB: Pre-normalization setup + !*** When normalization is requested (mbnorm=.true.) or a weight field + !*** is provided (mbpresent=.true.), we prepare source data for mapping. + if (mbnorm .or. mbpresent) then + !*** MOAB: iMOAB_GetMeshInfo - Get source mesh dimensions + !*** nvise(1) returns the number of visible (owned) elements + ierr = iMOAB_GetMeshInfo ( mapper%src_mbid, nvert, nvise, nbl, nsurf, nvisBC ); + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting mesh info for ', mapper%mbname + call shr_sys_abort(subname//' ERROR getting mesh info') ! serious enough + endif + lsize_src = nvise(1) ! number of active cells + + !*** MOAB: Initialize norm8wt tag to 1.0 on all source cells + !*** This tag will be mapped along with the data fields. + !*** After mapping, dividing by the mapped norm8wt gives proper normalization. + allocate(wghts(lsize_src)) + wghts = 1.0_r8 + tagname = "norm8wt"//C_NULL_CHAR + !*** MOAB: iMOAB_SetDoubleTagStorage - Set tag values on mesh elements + ierr = iMOAB_SetDoubleTagStorage (mapper%src_mbid, tagname, lsize_src , mapper%tag_entity_type, wghts) + if (ierr .ne. 0) then + write(logunit,*) subname,' error setting init value for mapping norm factor ',ierr,trim(tagname) + call shr_sys_abort(subname//' ERROR setting norm init value') ! serious enough + endif #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit, *) subname,' iMOAB mapper ', mapper%mbname, ' set norm8wt 1 on source with app id: ', & - mapper%src_mbid, ' moab step:', num_moab_exports - call shr_sys_flush(logunit) - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit, *) subname,' iMOAB mapper ', mapper%mbname, ' set norm8wt 1 on source with app id: ', & + mapper%src_mbid, ' moab step:', num_moab_exports + call shr_sys_flush(logunit) + endif #endif - ! if a normalization factor was specified, get it and multiply src tags by it - if(mbpresent) then - tagname = avwtsfld_s//C_NULL_CHAR - ierr = iMOAB_GetDoubleTagStorage (mapper%src_mbid, tagname, lsize_src , mapper%tag_entity_type, wghts) - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting value for mapping norm factor ', trim(tagname) - call shr_sys_abort(subname//' ERROR getting norm factor') ! serious enough - endif - - ! get the fieldlist including weight - allocate(targtags(lsize_src,nfields)) - allocate(targtags_ini(lsize_src,nfields)) - arrsize_src=lsize_src*(nfields) - - ! get the current values of all source tags including the norm8wt currently set to 1 - ierr = iMOAB_GetDoubleTagStorage (mapper%src_mbid, fldlist_moab, arrsize_src , mapper%tag_entity_type, targtags) - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting source tag values ', mapper%mbname, mapper%src_mbid, trim(fldlist_moab), arrsize_src, mapper%tag_entity_type - call shr_sys_abort(subname//' ERROR getting source tag values') ! serious enough - endif - - targtags_ini = targtags - ! multiply by the value of the avwtsfld_s field. - ! norm8wt is 1 so it will record the value of the weight. - do j = 1, lsize_src - targtags(j,:)= targtags(j,:)*wghts(j) - enddo + !*** MOAB: Optional pre-multiplication by user-specified weights + !*** If avwtsfld_s was provided, multiply all source fields by this weight. + !*** This is used for flux-weighted mapping (e.g., area-weighted averages). + if(mbpresent) then + !*** MOAB: iMOAB_GetDoubleTagStorage - Get weight field values + tagname = avwtsfld_s//C_NULL_CHAR + ierr = iMOAB_GetDoubleTagStorage (mapper%src_mbid, tagname, lsize_src , mapper%tag_entity_type, wghts) + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting value for mapping norm factor ', trim(tagname) + call shr_sys_abort(subname//' ERROR getting norm factor') ! serious enough + endif + + !*** MOAB: Get all source field values and save original values + !*** targtags_ini stores original values to restore after mapping + allocate(targtags(lsize_src,nfields)) + allocate(targtags_ini(lsize_src,nfields)) + arrsize_src=lsize_src*(nfields) + + !*** MOAB: iMOAB_GetDoubleTagStorage - Get current field values + ierr = iMOAB_GetDoubleTagStorage (mapper%src_mbid, fldlist_moab, arrsize_src , mapper%tag_entity_type, targtags) + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting source tag values ', mapper%mbname, mapper%src_mbid, trim(fldlist_moab), arrsize_src, mapper%tag_entity_type + call shr_sys_abort(subname//' ERROR getting source tag values') ! serious enough + endif + + targtags_ini = targtags + !*** MOAB: Multiply all fields by the normalization weight + !*** Since norm8wt starts at 1.0, after this multiplication: + !*** - Data fields contain: field_value * weight + !*** - norm8wt contains: 1.0 * weight = weight + !*** After mapping and dividing by mapped norm8wt, we get proper normalization. + do j = 1, lsize_src + targtags(j,:)= targtags(j,:)*wghts(j) + enddo #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit, *) subname,' iMOAB projection mapper: ', mapper%mbname, ' normalize nfields=', & - nfields, ' arrsize_src on root:', arrsize_src, ' shape(targtags_ini)=', shape(targtags_ini), & - ' moab step:', num_moab_exports - call shr_sys_flush(logunit) - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit, *) subname,' iMOAB projection mapper: ', mapper%mbname, ' normalize nfields=', & + nfields, ' arrsize_src on root:', arrsize_src, ' shape(targtags_ini)=', shape(targtags_ini), & + ' moab step:', num_moab_exports + call shr_sys_flush(logunit) + endif #endif - ! put the new values on the mesh for later mapping - ierr = iMOAB_SetDoubleTagStorage (mapper%src_mbid, fldlist_moab, arrsize_src , mapper%tag_entity_type, targtags) - if (ierr .ne. 0) then - write(logunit,*) subname,' error setting normed source tag values ', mapper%mbname - call shr_sys_abort(subname//' ERROR setting normed source tag values') ! serious enough - endif - deallocate(targtags) - endif ! end multiplication by norm factor - deallocate(wghts) - endif ! end NORMALIZATION - - ! - ierr = iMOAB_SendElementTag( mapper%src_mbid, fldlist_moab, mapper%mpicom, mapper%intx_context ) - if (ierr .ne. 0) then - write(logunit, *) subname,' iMOAB mapper error in sending tags ', mapper%mbname, trim(fldlist_moab) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' ERROR in sending tags') - endif + !*** MOAB: iMOAB_SetDoubleTagStorage - Store weighted values back to source + !*** These weighted values will be sent and mapped to the target grid. + ierr = iMOAB_SetDoubleTagStorage (mapper%src_mbid, fldlist_moab, arrsize_src , mapper%tag_entity_type, targtags) + if (ierr .ne. 0) then + write(logunit,*) subname,' error setting normed source tag values ', mapper%mbname + call shr_sys_abort(subname//' ERROR setting normed source tag values') ! serious enough + endif + deallocate(targtags) + endif ! end multiplication by norm factor + deallocate(wghts) + endif ! end NORMALIZATION + + !*** MOAB: Send source data to intersection/coverage mesh + !*** For full mapping, data goes to the intersection app (intx_context) + !*** where projection weights will be applied. + ierr = iMOAB_SendElementTag( mapper%src_mbid, fldlist_moab, mapper%mpicom, mapper%intx_context ) + if (ierr .ne. 0) then + write(logunit, *) subname,' iMOAB mapper error in sending tags ', mapper%mbname, trim(fldlist_moab) + call shr_sys_flush(logunit) + call shr_sys_abort(subname//' ERROR in sending tags') + endif endif + + !*** MOAB: Receive data into intersection mesh for weight application + !*** The data is received by the intersection app (intx_mbid), which holds + !*** the projection weights. Note: for true intersection cases, tgt_mbid + !*** may be the same as intx_mbid. if ( valid_moab_context ) then - ! receive in the intx app, because it is redistributed according to coverage (trick) - ! for true intx cases, tgt_mbid is set to be the same as intx_mbid #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit, *) subname,' iMOAB mapper receiving tags with intx and intx_mbid: ', & - mapper%mbname, trim(fldlist_moab), ' moab step:', num_moab_exports - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit, *) subname,' iMOAB mapper receiving tags with intx and intx_mbid: ', & + mapper%mbname, trim(fldlist_moab), ' moab step:', num_moab_exports + endif #endif - ierr = iMOAB_ReceiveElementTag( mapper%intx_mbid, fldlist_moab, mapper%mpicom, mapper%src_context ) - if (ierr .ne. 0) then - write(logunit,*) subname,' error in receiving tags ', mapper%mbname, 'recv:', mapper%intx_mbid, trim(fldlist_moab) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' ERROR in receiving tags') - !valid_moab_context = .false. ! do not attempt to project - endif - ! now free buffers - ierr = iMOAB_FreeSenderBuffers( mapper%src_mbid, mapper%intx_context ) - if (ierr .ne. 0) then - write(logunit,*) subname,' error in freeing buffers ', trim(fldlist_moab) - call shr_sys_abort(subname//' ERROR in freeing buffers') ! serious enough - endif + ierr = iMOAB_ReceiveElementTag( mapper%intx_mbid, fldlist_moab, mapper%mpicom, mapper%src_context ) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in receiving tags ', mapper%mbname, 'recv:', mapper%intx_mbid, trim(fldlist_moab) + call shr_sys_flush(logunit) + call shr_sys_abort(subname//' ERROR in receiving tags') + !valid_moab_context = .false. ! do not attempt to project + endif + !*** MOAB: iMOAB_FreeSenderBuffers - Release MPI send buffers + ierr = iMOAB_FreeSenderBuffers( mapper%src_mbid, mapper%intx_context ) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in freeing buffers ', trim(fldlist_moab) + call shr_sys_abort(subname//' ERROR in freeing buffers') ! serious enough + endif endif + + !*** MOAB: Apply projection weights to interpolate source data to target grid + !*** This is the core remapping operation using iMOAB_ApplyScalarProjectionWeights. + !*** The weights were loaded earlier via moab_map_init_rcfile. if ( valid_moab_context ) then #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit, *) subname,' iMOAB projection mapper: ',trim(mapper%mbname), ' between ', mapper%src_mbid, ' and ', mapper%tgt_mbid, trim(fldlist_moab), & - ' moab step:', num_moab_exports - call shr_sys_flush(logunit) - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit, *) subname,' iMOAB projection mapper: ',trim(mapper%mbname), ' between ', mapper%src_mbid, ' and ', mapper%tgt_mbid, trim(fldlist_moab), & + ' moab step:', num_moab_exports + call shr_sys_flush(logunit) + endif #endif - filter_type = 0 ! no - ierr = iMOAB_ApplyScalarProjectionWeights ( mapper%intx_mbid, filter_type, mapper%weight_identifier, fldlist_moab, fldlist_moab) - if (ierr .ne. 0) then - write(logunit,*) subname,' error in applying weights ' - call shr_sys_abort(subname//' ERROR in applying weights') - endif - - ! complete the normalization process - if (mbnorm) then - ierr = iMOAB_GetMeshInfo ( mapper%tgt_mbid, nvert, nvise, nbl, nsurf, nvisBC ); - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting mesh info for target ', mapper%mbname - call shr_sys_abort(subname//' ERROR getting mesh info') ! serious enough - endif - - lsize_tgt = nvise(1) ! number of active cells - tagname = "norm8wt"//C_NULL_CHAR - allocate(wghts(lsize_tgt)) - - ! get values of weights after mapping - ierr = iMOAB_GetDoubleTagStorage (mapper%tgt_mbid, tagname, lsize_tgt , mapper%tag_entity_type, wghts) - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting value for mapping norm factor post-map ', ierr, trim(tagname) - call shr_sys_abort(subname//' ERROR getting norm factor') ! serious enough - endif - - ! get values of target tags after mapping - allocate(targtags(lsize_tgt,nfields)) - arrsize_tgt=lsize_tgt*(nfields) - ierr = iMOAB_GetDoubleTagStorage (mapper%tgt_mbid, fldlist_moab, arrsize_tgt , mapper%tag_entity_type, targtags) - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting destination tag values ', mapper%mbname - call shr_sys_abort(subname//' ERROR getting source tag values') ! serious enough - endif - - ! do the post mapping normalization - ! TODO: add some check for wghts < puny - do j = 1, lsize_tgt - factor = wghts(j) - if (wghts(j) .ne. 0) factor = 1.0_r8/wghts(j) ! should we compare to a small value instead ? - targtags(j,:)= targtags(j,:)*factor - enddo - - ! put the values back on the mesh - ierr = iMOAB_SetDoubleTagStorage (mapper%tgt_mbid, fldlist_moab, arrsize_tgt , mapper%tag_entity_type, targtags) - if (ierr .ne. 0) then - write(logunit,*) subname,' error getting destination tag values ', mapper%mbname - call shr_sys_abort(subname//' ERROR getting source tag values') ! serious enough - endif - - deallocate(wghts, targtags) - if (mbpresent) then + !*** MOAB: iMOAB_ApplyScalarProjectionWeights - Apply interpolation/projection + !*** Parameters: + !*** intx_mbid: Intersection mesh app ID (holds the weights) + !*** filter_type: 0=no filter, other values for CAAS projection + !*** weight_identifier: Name of the weight matrix (e.g., "scalar", "flux") + !*** fldlist_moab: Input and output field names (can be different) + filter_type = 0 ! no filter + ierr = iMOAB_ApplyScalarProjectionWeights ( mapper%intx_mbid, filter_type, mapper%weight_identifier, fldlist_moab, fldlist_moab) + if (ierr .ne. 0) then + write(logunit,*) subname,' error in applying weights ' + call shr_sys_abort(subname//' ERROR in applying weights') + endif + + !*** MOAB: Post-normalization (target side) + !*** After mapping, we need to divide by the mapped normalization weight. + !*** This completes the conservative mapping: mapped_field / mapped_weight + !*** gives the properly normalized field value on the target grid. + if (mbnorm) then + !*** MOAB: Get target mesh dimensions + ierr = iMOAB_GetMeshInfo ( mapper%tgt_mbid, nvert, nvise, nbl, nsurf, nvisBC ); + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting mesh info for target ', mapper%mbname + call shr_sys_abort(subname//' ERROR getting mesh info') ! serious enough + endif + + lsize_tgt = nvise(1) ! number of active cells + tagname = "norm8wt"//C_NULL_CHAR + allocate(wghts(lsize_tgt)) + + !*** MOAB: Get mapped normalization weights on target grid + ierr = iMOAB_GetDoubleTagStorage (mapper%tgt_mbid, tagname, lsize_tgt , mapper%tag_entity_type, wghts) + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting value for mapping norm factor post-map ', ierr, trim(tagname) + call shr_sys_abort(subname//' ERROR getting norm factor') ! serious enough + endif + + !*** MOAB: Get mapped field values on target grid + allocate(targtags(lsize_tgt,nfields)) + arrsize_tgt=lsize_tgt*(nfields) + ierr = iMOAB_GetDoubleTagStorage (mapper%tgt_mbid, fldlist_moab, arrsize_tgt , mapper%tag_entity_type, targtags) + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting destination tag values ', mapper%mbname + call shr_sys_abort(subname//' ERROR getting source tag values') ! serious enough + endif + + !*** MOAB: Divide mapped fields by mapped normalization weight + !*** For each target cell: + !*** factor = 1/norm8wt if norm8wt != 0, else factor = norm8wt + !*** final_value = mapped_value * factor + !*** This gives the properly normalized field values. + ! TODO: add some check for wghts < puny + do j = 1, lsize_tgt + factor = wghts(j) + if (wghts(j) .ne. 0) factor = 1.0_r8/wghts(j) ! should we compare to a small value instead ? + targtags(j,:)= targtags(j,:)*factor + enddo + + !*** MOAB: Store normalized field values back to target mesh + ierr = iMOAB_SetDoubleTagStorage (mapper%tgt_mbid, fldlist_moab, arrsize_tgt , mapper%tag_entity_type, targtags) + if (ierr .ne. 0) then + write(logunit,*) subname,' error getting destination tag values ', mapper%mbname + call shr_sys_abort(subname//' ERROR getting source tag values') ! serious enough + endif + + deallocate(wghts, targtags) + !*** MOAB: Restore original source field values + !*** If we multiplied source fields by weights before mapping, + !*** restore the original values so the source mesh is unchanged. + if (mbpresent) then #ifdef MOABDEBUG - if (seq_comm_iamroot(CPLID)) then - write(logunit, *) subname,' iMOAB projection mapper: ', mapper%mbname, ' shape(targtags_ini)=', shape(targtags_ini) - call shr_sys_flush(logunit) - endif + if (seq_comm_iamroot(CPLID)) then + write(logunit, *) subname,' iMOAB projection mapper: ', mapper%mbname, ' shape(targtags_ini)=', shape(targtags_ini) + call shr_sys_flush(logunit) + endif #endif - ! put the values back on the source mesh - ierr = iMOAB_SetDoubleTagStorage (mapper%src_mbid, fldlist_moab, arrsize_src , mapper%tag_entity_type, targtags_ini) - if (ierr .ne. 0) then - write(logunit,*) subname,' error setting source tag values ', mapper%mbname - call shr_sys_abort(subname//' ERROR setting source tag values') ! serious enough - endif - deallocate(targtags_ini) - endif + !*** MOAB: Restore original values to source mesh + ierr = iMOAB_SetDoubleTagStorage (mapper%src_mbid, fldlist_moab, arrsize_src , mapper%tag_entity_type, targtags_ini) + if (ierr .ne. 0) then + write(logunit,*) subname,' error setting source tag values ', mapper%mbname + call shr_sys_abort(subname//' ERROR setting source tag values') ! serious enough + endif + deallocate(targtags_ini) + endif - endif ! end normalization + endif ! end normalization endif - endif ! end of mapping type if else + endif ! end of mapping type if else end subroutine seq_map_map From ca8f80a95267b9972c510aafff0877dc4a0b6ab0 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 12:03:12 -0600 Subject: [PATCH 276/398] Implement MOAB seq_domain_check Implement MOAB version of part of seq_domain_check. Does mask and frac checks. Leave notes for implementing grid check and fraction consistency. --- driver-moab/main/cime_comp_mod.F90 | 11 +- driver-moab/main/seq_domain_mct.F90 | 620 +++++++++------------------- 2 files changed, 204 insertions(+), 427 deletions(-) diff --git a/driver-moab/main/cime_comp_mod.F90 b/driver-moab/main/cime_comp_mod.F90 index 053a6d4459a8..fc7db5e83aa0 100644 --- a/driver-moab/main/cime_comp_mod.F90 +++ b/driver-moab/main/cime_comp_mod.F90 @@ -120,7 +120,7 @@ module cime_comp_mod use seq_infodata_mod, only: seq_infodata_print, seq_infodata_init2 ! domain related routines - use seq_domain_mct, only : seq_domain_check + use seq_domain_mct, only : seq_domain_check_moab ! history file routines use seq_hist_mod, only : seq_hist_write, seq_hist_writeavg, seq_hist_writeaux @@ -1853,9 +1853,6 @@ subroutine cime_init() if (single_column ) domain_check = .false. if (dead_comps ) domain_check = .false. - ! for MOAB - domain_check = .false. - ! set skip_ocean_run flag, used primarily for ocn run on first timestep ! use reading a restart as a surrogate from whether this is a startup run @@ -2137,12 +2134,12 @@ subroutine cime_init() if (domain_check) then if (iamroot_CPLID) then write(logunit,*) ' ' - write(logunit,F00) 'Performing domain checking' + write(logunit,F00) 'Performing MOAB domain checking' call shr_sys_flush(logunit) endif - call seq_domain_check( infodata, & - atm(ens1), ice(ens1), lnd(ens1), ocn(ens1), rof(ens1), glc(ens1), & + ! MOAB-based domain checking + call seq_domain_check_moab( infodata, & samegrid_al, samegrid_ao, samegrid_ro, samegrid_lg) endif diff --git a/driver-moab/main/seq_domain_mct.F90 b/driver-moab/main/seq_domain_mct.F90 index 8a124d768676..105110f06e9f 100644 --- a/driver-moab/main/seq_domain_mct.F90 +++ b/driver-moab/main/seq_domain_mct.F90 @@ -22,7 +22,7 @@ module seq_domain_mct ! Public interfaces !-------------------------------------------------------------------------- - public :: seq_domain_check + public :: seq_domain_check_moab public :: seq_domain_compare public :: seq_domain_areafactinit @@ -39,36 +39,49 @@ module seq_domain_mct !-------------------------------------------------------------------------- private :: seq_domain_check_grid + private :: seq_domain_check_fracmask_moab !================================================================================ contains !================================================================================ + !=============================================================================== + !================================================================================ + ! MOAB-based domain checking subroutines !================================================================================ - subroutine seq_domain_check( infodata, & - atm, ice, lnd, ocn, rof, glc, & + !================================================================================ + ! subroutine seq_domain_check_moab + ! + ! Purpose: Comprehensive domain validation using MOAB data structures + ! + ! This routine validates grid consistency across all climate model components + ! using MOAB tag data. It checks + ! 1. Mask/fraction compatibility within each component + ! NOT YET FOR + ! 2. Coordinate consistency between components sharing grids + ! 3. Fraction sum validation (land+ice+ocean = 1.0) on atmosphere grid + ! + ! The validation ensures that: + ! - Grid coordinates match within tolerance for same-grid components + ! - Component fractions are physically consistent + ! - Mask and fraction arrays are compatible + ! - Domain mappings are correctly initialized + + subroutine seq_domain_check_moab( infodata, & samegrid_al, samegrid_ao, samegrid_ro, samegrid_lg) !----------------------------------------------------------- - ! Uses + ! MOAB version of seq_domain_check + ! Checks domain consistency using MOAB tag data instead of MCT data structures ! - use prep_atm_mod, only: prep_atm_get_mapper_Fi2a - use prep_atm_mod, only: prep_atm_get_mapper_Fl2a - use prep_atm_mod, only: prep_atm_get_mapper_Fo2a - use prep_lnd_mod, only: prep_lnd_get_mapper_Fa2l - use prep_ocn_mod, only: prep_ocn_get_mapper_SFi2o - use prep_glc_mod, only: prep_glc_get_mapper_Fl2g + use seq_comm_mct, only: mbaxid, mblxid, mboxid, mbixid, mbrxid + use shr_moab_mod, only: mbGetnCells, mbGetCellTagVals + use iso_c_binding, only: C_NULL_CHAR ! ! Arguments ! type (seq_infodata_type) , intent(inout) :: infodata - type(component_type) , intent(in) :: atm - type(component_type) , intent(in) :: ice - type(component_type) , intent(in) :: lnd - type(component_type) , intent(in) :: ocn - type(component_type) , intent(in) :: rof - type(component_type) , intent(in) :: glc logical , intent(in) :: samegrid_al ! atm lnd grid same logical , intent(in) :: samegrid_ao ! atm ocn grid same logical , intent(in) :: samegrid_ro ! rof ocn grid same @@ -76,41 +89,7 @@ subroutine seq_domain_check( infodata, & ! ! Local variables ! - type(seq_map) , pointer :: mapper_i2a ! inout needed for lower methods - type(seq_map) , pointer :: mapper_i2o ! inout needed for lower methods - type(seq_map) , pointer :: mapper_o2a ! - type(seq_map) , pointer :: mapper_l2g ! - type(seq_map) , pointer :: mapper_a2l ! - type(seq_map) , pointer :: mapper_l2a ! - ! - type(mct_gGrid) , pointer :: atmdom_a ! atm domain - type(mct_gGrid) , pointer :: icedom_i ! ice domain - type(mct_gGrid) , pointer :: lnddom_l ! lnd domain - type(mct_gGrid) , pointer :: ocndom_o ! ocn domain - type(mct_gGrid) , pointer :: glcdom_g ! glc domain - ! - type(mct_gsMap) , pointer :: gsMap_a ! atm global seg map - type(mct_gsMap) , pointer :: gsMap_i ! ice global seg map - type(mct_gsMap) , pointer :: gsMap_l ! lnd global seg map - type(mct_gsMap) , pointer :: gsMap_o ! ocn global seg map - type(mct_gsMap) , pointer :: gsMap_r ! ocn global seg map - type(mct_gsMap) , pointer :: gsMap_g ! glc global seg map - ! - type(mct_gGrid) :: lnddom_a ! lnd domain info on atm decomp - type(mct_gGrid) :: lnddom_g ! lnd domain info on glc decomp - type(mct_gGrid) :: icedom_a ! ice domain info on atm decomp (all grids same) - type(mct_gGrid) :: ocndom_a ! ocn domain info on atm decomp (all grids same) - type(mct_gGrid) :: icedom_o ! ocn domain info on ocn decomp (atm/ocn grid different) - ! - real(R8), pointer :: fracl(:) ! land fraction on atm decomp - real(R8), pointer :: fraco(:) ! ocn fraction on atm decomp - real(R8), pointer :: fraci(:) ! ice fraction on atm decomp - real(R8), pointer :: maskl(:) ! land mask on atm decomp (all grids same) - real(R8), pointer :: maski(:) ! ice mask on atm decomp (all grids same) - real(R8), pointer :: masko(:) ! ocn mask on atm decomp (all grids same) - ! integer(IN) :: n ! indicies - ! integer(IN) :: mpicom_cplid ! logical :: atm_present ! atm present flag @@ -125,14 +104,6 @@ subroutine seq_domain_check( infodata, & integer(IN) :: lndsize ! local size of land grid integer(IN) :: ocnsize ! local size of ocn grid integer(IN) :: icesize ! local size of ice grid - integer(IN) :: glcsize ! local size of glc grid - integer(IN) :: gatmsize ! global size of atm grid - integer(IN) :: glndsize ! global size of land grid - integer(IN) :: gocnsize ! global size of ocn grid - integer(IN) :: grofsize ! global size of ocn grid - integer(IN) :: gicesize ! global size of ice grid - integer(IN) :: gglcsize ! global size of glc grid - integer(IN) :: npts ! local size temporary real(R8) :: diff,dmaxo,dmaxi ! difference tracker logical :: iamroot ! local masterproc real(R8) :: eps_frac ! epsilon for fractions @@ -144,21 +115,28 @@ subroutine seq_domain_check( infodata, & real(R8) :: eps_oiarea ! epsilon for areas, ocn/ice real(R8) :: my_eps_frac ! local eps_frac value ! - real(R8),allocatable :: mask (:) ! temporary real vector, domain mask + real(R8),allocatable :: fracl(:) ! land fraction + real(R8),allocatable :: fraco(:) ! ocn fraction + real(R8),allocatable :: fraci(:) ! ice fraction + real(R8),allocatable :: maskl(:) ! land mask + real(R8),allocatable :: maski(:) ! ice mask + real(R8),allocatable :: masko(:) ! ocn mask ! - character(*),parameter :: F00 = "('(seq_domain_check) ',4a)" - character(*),parameter :: F01 = "('(seq_domain_check) ',a,i6,a)" - character(*),parameter :: F02 = "('(seq_domain_check) ',a,g23.15)" - character(*),parameter :: F0R = "('(seq_domain_check) ',2A,2g23.15,A )" - character(*),parameter :: subName = '(seq_domain_check) ' + character(*),parameter :: F00 = "('(seq_domain_check_moab) ',4a)" + character(*),parameter :: F01 = "('(seq_domain_check_moab) ',a,i6,a)" + character(*),parameter :: F02 = "('(seq_domain_check_moab) ',a,g23.15)" + character(*),parameter :: F0R = "('(seq_domain_check_moab) ',2A,2g23.15,A )" + character(*),parameter :: subName = '(seq_domain_check_moab) ' !----------------------------------------------------------- - mapper_i2a => prep_atm_get_mapper_Fi2a() - mapper_i2o => prep_ocn_get_mapper_SFi2o() - mapper_o2a => prep_atm_get_mapper_Fo2a() - mapper_l2g => prep_glc_get_mapper_Fl2g() - mapper_a2l => prep_lnd_get_mapper_Fa2l() - mapper_l2a => prep_atm_get_mapper_Fl2a() + !-------------------------------------------------------------------------- + ! Section 1: Get coupler communication info and configuration parameters + ! + ! Retrieve MPI communicator and root process flag for the coupler. + ! Also extract component presence flags and tolerance parameters from + ! infodata. The epsilon values control how strict the grid comparisons + ! are for different attributes (mask, coordinates, areas). + !-------------------------------------------------------------------------- call seq_comm_setptrs(CPLID,iamroot=iamroot, mpicom=mpicom_cplid) @@ -178,320 +156,115 @@ subroutine seq_domain_check( infodata, & eps_ogrid=eps_oigrid, & eps_oarea=eps_oiarea ) - ! Get info - - if (atm_present) then - gsmap_a => component_get_gsmap_cx(atm) ! gsmap_ax - atmdom_a => component_get_dom_cx(atm) ! dom_ax - atmsize = mct_avect_lsize(atmdom_a%data) - gatmsize = mct_gsMap_gsize(gsMap_a) - end if - - if (atm_present .and. lnd_present) then - gsmap_l => component_get_gsmap_cx(lnd) ! gsmap_lx - lnddom_l => component_get_dom_cx(lnd) ! dom_lx - lndsize = mct_avect_lsize(lnddom_l%data) - glndsize = mct_gsMap_gsize(gsMap_l) - - if (samegrid_al .and. gatmsize /= glndsize) then - write(logunit,*) subname,' error: global atmsize = ',& - gatmsize,' global lndsize= ',glndsize - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' atm and lnd grid must have the same global size') - end if - if (iamroot) write(logunit,F00) ' --- checking land maskfrac ---' - call seq_domain_check_fracmask(lnddom_l%data) - call mct_gGrid_init(oGGrid=lnddom_a, iGGrid=lnddom_l, lsize=atmsize) - call mct_aVect_zero(lnddom_a%data) - call seq_map_map(mapper_l2a, lnddom_l%data, lnddom_a%data, norm=.false.) - allocate(maskl(atmsize),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate maskl') - allocate(fracl(atmsize),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate fracl') - call mct_aVect_exportRAttr(lnddom_a%data, 'mask', maskl, atmsize) - call mct_aVect_exportRAttr(lnddom_a%data, 'frac', fracl, atmsize) - endif - - if (atm_present .and. ocn_present) then - gsmap_o => component_get_gsmap_cx(ocn) ! gsmap_ox - ocndom_o => component_get_dom_cx(ocn) ! dom_ox - ocnsize = mct_avect_lsize(ocndom_o%data) - gocnsize = mct_gsMap_gsize(gsMap_o) - - if (samegrid_ao .and. gatmsize /= gocnsize) then - write(logunit,*) subname,' error: global atmsize = ',gatmsize,' global ocnsize= ',gocnsize - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' atm and ocn grid must have the same global size') - end if - if (iamroot) write(logunit,F00) ' --- checking ocean maskfrac ---' - call seq_domain_check_fracmask(ocndom_o%data) - call mct_gGrid_init(oGGrid=ocndom_a, iGGrid=ocndom_o, lsize=atmsize) - call mct_aVect_zero(ocndom_a%data) - call seq_map_map(mapper_o2a, ocndom_o%data, ocndom_a%data, norm=.false.) - allocate(masko(atmsize),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate masko') - allocate(fraco(atmsize),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate fraco') - call mct_aVect_exportRAttr(ocndom_a%data, 'mask', masko, atmsize) - if (samegrid_ao) then - call mct_aVect_exportRattr(ocndom_a%data, 'frac', fraco, atmsize) - else - call mct_aVect_exportRattr(ocndom_a%data, 'mask', fraco, atmsize) - endif - endif - - if (atm_present .and. ice_present) then - gsmap_i => component_get_gsmap_cx(ice) ! gsmap_ix - icedom_i => component_get_dom_cx(ice) ! dom_ix - icesize = mct_avect_lsize(icedom_i%data) - gicesize = mct_gsMap_gsize(gsMap_i) - - if (samegrid_ao .and. gatmsize /= gicesize) then - write(logunit,*) subname,' error: global atmsize = ',& - gatmsize,' global icesize= ',gicesize - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' atm and ice grid must have the same global size') - end if - if (iamroot) write(logunit,F00) ' --- checking ice maskfrac ---' - call seq_domain_check_fracmask(icedom_i%data) - call mct_gGrid_init(oGGrid=icedom_a, iGGrid=icedom_i, lsize=atmsize) - call mct_aVect_zero(icedom_a%data) - call seq_map_map(mapper_i2a, icedom_i%data, icedom_a%data, norm=.false.) - allocate(maski(atmsize),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate maski') - allocate(fraci(atmsize),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate fraci') - call mct_aVect_exportRAttr(icedom_a%data, 'mask', maski, atmsize) - if (samegrid_ao) then - call mct_aVect_exportRattr(icedom_a%data, 'frac', fraci, atmsize) - else - call mct_aVect_exportRattr(icedom_a%data, 'mask', fraci, atmsize) - endif - endif - - if (lnd_present .and. glc_present) then - gsmap_l => component_get_gsmap_cx(lnd) ! gsmap_lx - lnddom_l => component_get_dom_cx(lnd) ! dom_lx - lndsize = mct_avect_lsize(lnddom_l%data) - glndsize = mct_gsMap_gsize(gsMap_l) - - gsmap_g => component_get_gsmap_cx(glc) ! gsmap_gx - glcdom_g => component_get_dom_cx(glc) ! dom_gx - glcsize = mct_avect_lsize(glcdom_g%data) - gglcsize = mct_gsMap_gsize(gsMap_g) - - if (samegrid_lg .and. gglcsize /= glndsize) then - write(logunit,*) subname,' error: global glcsize = ',gglcsize,' global lndsize= ',glndsize - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' glc and lnd grid must have the same global size') - end if - - if (iamroot) write(logunit,F00) ' --- checking glc maskfrac ---' - call seq_domain_check_fracmask(glcdom_g%data) - if (iamroot) write(logunit,F00) ' --- checking lnd maskfrac ---' - call seq_domain_check_fracmask(lnddom_l%data) - - if (samegrid_lg) then - call mct_gGrid_init(oGGrid=lnddom_g, iGGrid=lnddom_l, lsize=glcsize) - call mct_aVect_zero(lnddom_g%data) - call seq_map_map(mapper_l2g, lnddom_l%data, lnddom_g%data, norm=.false.) - if (iamroot) write(logunit,F00) ' --- checking glc/lnd domains ---' - npts = glcsize - allocate(mask(npts),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate mask') - call mct_aVect_getRAttr(lnddom_g%data,"mask",mask,rcode) - where (mask < eps_axmask) mask = 0.0_R8 - call seq_domain_check_grid(glcdom_g%data, lnddom_g%data, 'mask', eps=eps_axmask, mpicom=mpicom_cplid, mask=mask) - call seq_domain_check_grid(glcdom_g%data, lnddom_g%data, 'lat' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=mask) - call seq_domain_check_grid(glcdom_g%data, lnddom_g%data, 'lon' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=mask) - call seq_domain_check_grid(glcdom_g%data, lnddom_g%data, 'area', eps=eps_axarea, mpicom=mpicom_cplid, mask=mask) - deallocate(mask,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate mask') - end if - - endif - - if (ice_present .and. ocn_present) then - gsmap_i => component_get_gsmap_cx(ice) ! gsmap_ix - icedom_i => component_get_dom_cx(ice) ! dom_ix - icesize = mct_avect_lsize(icedom_i%data) - gicesize = mct_gsMap_gsize(gsMap_i) - - gsmap_o => component_get_gsmap_cx(ocn) ! gsmap_ox - ocndom_o => component_get_dom_cx(ocn) ! dom_ox - ocnsize = mct_avect_lsize(ocndom_o%data) - gocnsize = mct_gsMap_gsize(gsMap_o) - - if (gocnsize /= gicesize) then - write(logunit,*) subname,' error: global ocnsize = ',gocnsize,' global icesize= ',gicesize - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' ocean and ice grid must have the same global size') - endif - call mct_gGrid_init(oGGrid=icedom_o, iGGrid=icedom_i, lsize=ocnsize) - call mct_aVect_zero(icedom_o%data) - call seq_map_map(mapper_i2o, icedom_i%data, icedom_o%data, norm=.false.) - end if - - if (rof_present .and. ocnrof_prognostic .and. samegrid_ro) then - gsmap_r => component_get_gsmap_cx(glc) ! gsmap_gx - grofsize = mct_gsMap_gsize(gsMap_r) - - if (gocnsize /= grofsize) then - write(logunit,*) subname,' error: global ocnsize = ',gocnsize,' global rofsize= ',grofsize - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' ocean and rof grid must have the same global size') - endif - end if - - !------------------------------------------------------------------------------ - ! Check ice/ocean grid consistency - !------------------------------------------------------------------------------ - - if (ocn_present .and. ice_present) then - ! if (samegrid_oi) then ! doesn't yet exist - - npts = ocnsize - allocate(mask(npts),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate mask') - - if (iamroot) write(logunit,F00) ' --- checking ocn/ice domains ---' - call seq_domain_check_grid(ocndom_o%data, icedom_o%data,'mask', eps=eps_oigrid, mpicom=mpicom_cplid) - call mct_aVect_getRAttr(ocndom_o%data,"mask",mask,rcode) - where (mask < eps_oimask) mask = 0.0_R8 - - call seq_domain_check_grid(ocndom_o%data, icedom_o%data,'lat' , eps=eps_oigrid, mpicom=mpicom_cplid, mask=mask) - call seq_domain_check_grid(ocndom_o%data, icedom_o%data,'lon' , eps=eps_oigrid, mpicom=mpicom_cplid, mask=mask) - call seq_domain_check_grid(ocndom_o%data, icedom_o%data,'area', eps=eps_oiarea, mpicom=mpicom_cplid, mask=mask) - - deallocate(mask,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate mask') - - ! endif + ! Get sizes from MOAB apps + if (atm_present .and. mbaxid >= 0) then + atmsize = mbGetnCells(mbaxid) + else + atmsize = 0 endif - !------------------------------------------------------------------------------ - ! Check atm/lnd grid consistency - !------------------------------------------------------------------------------ - - if (atm_present .and. lnd_present .and. samegrid_al) then - if (iamroot) write(logunit,F00) ' --- checking atm/land domains ---' - call seq_domain_check_grid(atmdom_a%data, lnddom_a%data, 'lat' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=maskl) - call seq_domain_check_grid(atmdom_a%data, lnddom_a%data, 'lon' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=maskl) - call seq_domain_check_grid(atmdom_a%data, lnddom_a%data, 'area', eps=eps_axarea, mpicom=mpicom_cplid, mask=maskl) + if (lnd_present .and. mblxid >= 0) then + lndsize = mbGetnCells(mblxid) + else + lndsize = 0 endif - !------------------------------------------------------------------------------ - ! Check atm/ocn and atm/ice grid consistency (if samegrid) - !------------------------------------------------------------------------------ - - if (atm_present .and. ice_present .and. samegrid_ao) then - if (iamroot) write(logunit,F00) ' --- checking atm/ice domains ---' - call seq_domain_check_grid(atmdom_a%data, icedom_a%data, 'lat' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=maski) - call seq_domain_check_grid(atmdom_a%data, icedom_a%data, 'lon' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=maski) - call seq_domain_check_grid(atmdom_a%data, icedom_a%data, 'area', eps=eps_axarea, mpicom=mpicom_cplid, mask=maski) + if (ocn_present .and. mboxid >= 0) then + ocnsize = mbGetnCells(mboxid) + else + ocnsize = 0 endif - if (atm_present .and. ocn_present .and. samegrid_ao) then - if (iamroot) write(logunit,F00) ' --- checking atm/ocn domains ---' - call seq_domain_check_grid(atmdom_a%data, ocndom_a%data, 'lat' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=masko) - call seq_domain_check_grid(atmdom_a%data, ocndom_a%data, 'lon' , eps=eps_axgrid, mpicom=mpicom_cplid, mask=masko) - call seq_domain_check_grid(atmdom_a%data, ocndom_a%data, 'area', eps=eps_axarea, mpicom=mpicom_cplid, mask=masko) + if (ice_present .and. mbixid >= 0) then + icesize = mbGetnCells(mbixid) + else + icesize = 0 endif - !------------------------------------------------------------------------------ - ! Check consistency of land fraction with ocean mask on grid - !------------------------------------------------------------------------------ - - if (atm_present) then - my_eps_frac = eps_frac - if (samegrid_ao) my_eps_frac = eps_frac_samegrid - if (.not. samegrid_al) my_eps_frac = eps_big - - if (iamroot) write(logunit,F00) ' --- checking fractions in domains ---' - dmaxi = 0.0_R8 - dmaxo = 0.0_R8 - do n = 1,atmsize - if (lnd_present .and. ice_present) then - diff = abs(1._R8 - fracl(n) - fraci(n)) - dmaxi = max(diff,dmaxi) - if (diff > my_eps_frac) then - write(logunit,*)'inconsistency between land fraction and sea ice fraction' - write(logunit,*)'n= ',n,' fracl= ',fracl(n),' fraci= ',fraci(n),' sum= ',fracl(n)+fraci(n) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' inconsistency between land fraction and sea ice fraction') - end if - if ((1._R8-fraci(n)) > eps_frac .and. fracl(n) < eps_tiny) then - write(logunit,*)'inconsistency between land mask and sea ice mask' - write(logunit,*)'n= ',n,' fracl= ',fracl(n),' fraci= ',fraci(n) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' inconsistency between land mask and sea ice mask') - end if - endif - if (lnd_present .and. ocn_present) then - diff = abs(1._R8 - fracl(n) - fraco(n)) - dmaxo = max(diff,dmaxo) - if (diff > my_eps_frac) then - write(logunit,*)'inconsistency between land fraction and ocn land fraction' - write(logunit,*)'n= ',n,' fracl= ',fracl(n),' fraco= ',fraco(n),' sum= ',fracl(n)+fraco(n) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' inconsistency between land fraction and ocn land fraction') - end if - if ((1._R8-fraco(n)) > eps_frac .and. fracl(n) < eps_tiny) then - write(logunit,*)'inconsistency between land mask and ocn land mask' - write(logunit,*)'n= ',n,' fracl= ',fracl(n),' fraco= ',fraco(n) - call shr_sys_flush(logunit) - call shr_sys_abort(subname//' inconsistency between land mask and ocn land mask') - end if - endif - end do - if (iamroot) then - write(logunit,F02) ' maximum difference for ofrac sum ',dmaxo - write(logunit,F02) ' maximum difference for ifrac sum ',dmaxi - write(logunit,F02) ' maximum allowable difference for frac sum ',my_eps_frac - write(logunit,F02) ' maximum allowable tolerance for valid frac ',eps_frac - call shr_sys_flush(logunit) - end if - end if + !-------------------------------------------------------------------------- + ! Section 2: Validate mask/fraction consistency + ! + ! Check mask/fraction consistency using MOAB tags (frac>0 requires mask>0) + !-------------------------------------------------------------------------- - !------------------------------------------------------------------------------ - ! Clean up allocated memory - !------------------------------------------------------------------------------ - - if (atm_present .and. lnd_present) then - deallocate(fracl,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate fracl') - deallocate(maskl,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate maskl') - call mct_gGrid_clean(lnddom_a, rcode) - if(rcode /= 0) call shr_sys_abort(subname//' clean lnddom_a') + ! Check land domain + if (atm_present .and. lnd_present .and. mbaxid >= 0 .and. mblxid >= 0) then + if (iamroot) write(logunit,F00) ' --- checking land mask and frac (MOAB) ---' + call seq_domain_check_fracmask_moab(mblxid) endif - if (atm_present .and. ocn_present) then - deallocate(fraco,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate fraco') - deallocate(masko,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate masko') - call mct_gGrid_clean(ocndom_a, rcode) - if(rcode /= 0) call shr_sys_abort(subname//' clean ocndom_a') + ! Check ocean domain + if (atm_present .and. ocn_present .and. mbaxid >= 0 .and. mboxid >= 0) then + if (iamroot) write(logunit,F00) ' --- checking ocean mask and frac (MOAB) ---' + call seq_domain_check_fracmask_moab(mboxid) endif - if (atm_present .and. ice_present) then - deallocate(fraci,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate fraci') - deallocate(maski,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate maski') - call mct_gGrid_clean(icedom_a, rcode) - if(rcode /= 0) call shr_sys_abort(subname//' clean icedom_o') + ! Check ice domain + if (atm_present .and. ice_present .and. mbaxid >= 0 .and. mbixid >= 0) then + if (iamroot) write(logunit,F00) ' --- checking ice maskand frac (MOAB) ---' + call seq_domain_check_fracmask_moab(mbixid) endif - if (ocn_present .and. ice_present) then - call mct_gGrid_clean(icedom_o, rcode) - if(rcode /= 0) call shr_sys_abort(subname//' clean icedom_o') - endif + !-------------------------------------------------------------------------- + ! + ! MOAB TODO: when samegrid_xy is true, check that the global sizes of the grids are the same. + ! + ! MOAB TODO: check_grid + ! + ! The MCT version of this first declared local Avs and mapped DOMAIN vars to those + ! local Avs, specifcally: mask, lat, lon, area. It mapped most grids to atm. + ! + ! IF SAMEGRID for a pair is true, the seq_domain_check_grid call would then check if the native value and + ! copied or rearranged values from the other grid were the same within a tolerance. This was done in parallel and + ! the total number of diffs was gathered to node 0. If more then 0, an error resulted. + ! + ! THIS WON'T WORK IN MOAB because the way seq_map_map is implemented, the mesh values in the target app + ! are REPLACED by the mapped versions (for both rearrange and actual map). We don't want that. + ! Also the mapping to atm happens even if samegrid is not true which would replace the real values with mapped values. + ! To implement this correctly, would need to copy the domain vars to new tags which can be mapped + ! without overwriting the real domain data and then compared. + ! + ! The domain variables mapped are + ! if (atm_present .and. lnd_present) l2a mappping done + ! if (atm_present .and. ocn_present) o2a mapping done + ! if (atm_present .and. ice_present) i2a mapping done + ! if (atm_present .and. iac_present) z2a mapping done + ! if (ice_present .and. ocn_present) i2o mapping done + ! + ! checking and additional mapping: + ! if( samegrid_lg) + ! l2g mapping done, mask, lat, lon, area checked + ! if (ocn_present .and. ice_present) (assumes they are sme grid) + ! using ice mapped to ocn, check mask, lat, lon, area + ! if (atm_present .and. lnd_present .and. samegrid_al + ! using lnd mapped to atm, check lat, lon, area + ! if (atm_present .and. iac_present .and. samegrid_az) + ! using iac mapped to atm, check lat, lon, area + ! if (atm_present .and. ice_present .and. samegrid_ao) + ! using ice mapped to atm, check lat, lon, area + ! if (atm_present .and. ocn_present .and. samegrid_ao) + ! using ocn mapped to atm, check lat, lon, area + ! + ! MOAB TODO: check fractions + ! + ! After that checking, the values mapped to atm are used to check fraction consistency + ! with fracl = frac from land-mapped-to-atm + ! fraci = mask from seaice-mapped-to-atm + ! fraco = mask from ocean-mapped-to-atm + ! looping over local points + ! if (lnd_present .and. ice_present) then + ! (1. - fracl - fraci) is checked to be within my_eps_frac of 0. + ! 1 - fraci must be > eps_frac AND fracl < eps_tiny + ! if (lnd_present .and. ocn_present) + ! (1. - fracl(n) - fraco(n) is checked to be within my_eps_frac of 0. + ! 1. - fraco(n)) > eps_frac AND fracl(n) < eps_tiny + ! error out if any of the above are violated. Report the max difference otherwise + ! (note the MCT version of max diff reporting does not do a gather) + ! call shr_sys_flush(logunit) - end subroutine seq_domain_check + end subroutine seq_domain_check_moab !=============================================================================== @@ -528,60 +301,6 @@ end subroutine seq_domain_compare !=============================================================================== - subroutine seq_domain_check_fracmask(dom1) - - !----------------------------------------------------------- - - ! Arguments - - type(mct_aVect) , intent(in) :: dom1 - - ! Local variables - integer(in) :: n,npts,ndiff - integer(in) :: rcode - real(R8), pointer :: dmask(:) ! temporaries - real(R8), pointer :: dfrac(:) ! temporaries - - character(*),parameter :: F00 = "('(seq_domain_check_fracmask) ',4a)" - character(*),parameter :: F01 = "('(seq_domain_check_fracmask) ',a,i12,a)" - character(*),parameter :: F02 = "('(seq_domain_check_fracmask) ',2a,g23.15)" - character(*),parameter :: F0R = "('(seq_domain_check_fracmask) ',2A,2g23.15,A )" - character(*),parameter :: subName = '(seq_domain_check_fracmask) ' - !----------------------------------------------------------- - - npts = mct_aVect_lsize(dom1) - - allocate(dmask(npts),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate dmask') - allocate(dfrac(npts),stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' allocate dfrac') - - call mct_aVect_exportRAttr(dom1, 'mask', dmask, npts) - call mct_aVect_exportRAttr(dom1, 'frac', dfrac, npts) - - ndiff = 0 - do n = 1,npts - if (abs(dfrac(n)) > eps_tiny .and. abs(dmask(n)) < eps_tiny) then - !debug write(logunit,*)'n= ',n,' dfrac= ',dfrac(n),' dmask= ',dmask(n) - ndiff = ndiff + 1 - endif - enddo - - if (ndiff > 0) then - write(logunit,*) trim(subname)," ERROR: incompatible domain mask and frac values" - call shr_sys_flush(logunit) - call shr_sys_abort(subName//" incompatible domain mask and frac values") - endif - - deallocate(dmask,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate dmask') - deallocate(dfrac,stat=rcode) - if(rcode /= 0) call shr_sys_abort(subname//' deallocate dfrac') - - end subroutine seq_domain_check_fracmask - - !=============================================================================== - subroutine seq_domain_check_grid(dom1, dom2, attr, eps, mpicom, mask) !----------------------------------------------------------- @@ -788,4 +507,65 @@ end subroutine seq_domain_areafactinit !=============================================================================== + subroutine seq_domain_check_fracmask_moab(mbid) + + !----------------------------------------------------------- + ! MOAB version of seq_domain_check_fracmask + ! Checks that fraction and mask are consistent in MOAB mesh + ! + use shr_moab_mod, only: mbGetnCells, mbGetCellTagVals + use iso_c_binding, only: C_NULL_CHAR + ! + ! Arguments + ! + integer(IN), intent(in) :: mbid ! MOAB app id + + ! Local variables + integer(in) :: n,npts,ndiff + integer(in) :: rcode + real(R8), allocatable :: dmask(:) ! temporaries + real(R8), allocatable :: dfrac(:) ! temporaries + + character(*),parameter :: F00 = "('(seq_domain_check_fracmask_moab) ',4a)" + character(*),parameter :: F01 = "('(seq_domain_check_fracmask_moab) ',a,i12,a)" + character(*),parameter :: F02 = "('(seq_domain_check_fracmask_moab) ',2a,g23.15)" + character(*),parameter :: F0R = "('(seq_domain_check_fracmask_moab) ',2A,2g23.15,A )" + character(*),parameter :: subName = '(seq_domain_check_fracmask_moab) ' + !----------------------------------------------------------- + + if (mbid < 0) return + + npts = mbGetnCells(mbid) + if (npts <= 0) return + + allocate(dmask(npts),stat=rcode) + if(rcode /= 0) call shr_sys_abort(subname//' allocate dmask') + allocate(dfrac(npts),stat=rcode) + if(rcode /= 0) call shr_sys_abort(subname//' allocate dfrac') + + call mbGetCellTagVals(mbid, 'mask'//C_NULL_CHAR, dmask, npts) + call mbGetCellTagVals(mbid, 'frac'//C_NULL_CHAR, dfrac, npts) + + ndiff = 0 + do n = 1,npts + if (abs(dfrac(n)) > eps_tiny .and. abs(dmask(n)) < eps_tiny) then + ndiff = ndiff + 1 + endif + enddo + + if (ndiff > 0) then + write(logunit,*) trim(subname)," ERROR: incompatible domain mask and frac values" + call shr_sys_flush(logunit) + call shr_sys_abort(subName//" incompatible domain mask and frac values") + endif + + deallocate(dmask,stat=rcode) + if(rcode /= 0) call shr_sys_abort(subname//' deallocate dmask') + deallocate(dfrac,stat=rcode) + if(rcode /= 0) call shr_sys_abort(subname//' deallocate dfrac') + + end subroutine seq_domain_check_fracmask_moab + + !=============================================================================== + end module seq_domain_mct From 9a8a0802b2e26b1e3154825d384ed7254a8cb27d Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 13:41:55 -0600 Subject: [PATCH 277/398] Add PEM to e3sm_moab_dev e3sm_moab_dev is redefined to be a combination of the ERS and PEM tests with driver-moab --- cime_config/tests.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cime_config/tests.py b/cime_config/tests.py index 279b8457fc83..42ec768e8b76 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -886,6 +886,11 @@ }, "e3sm_moab_dev" : { + "inherit" : ("e3sm_moab_ers", + "e3sm_moab_pem"), + }, + + "e3sm_moab_ers" : { "time" : "01:00:00", "tests" : ( "ERS_Vmoab_Ld3.ne4pg2_r05_oQU480.WCYCL1850NS", From c3652aea804177a3e1925dc032053a252bceeddb Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 14:45:40 -0600 Subject: [PATCH 278/398] Remove some whitespace Remove some whitespace from driver-mct/cime_config files that was showing up in diffs with driver-moab --- driver-mct/cime_config/buildnml | 6 +++--- driver-mct/cime_config/namelist_definition_drv_flds.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index d5831ee20717..58fc00576bd0 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -274,9 +274,9 @@ def write_seq_maps_file(case, nmlgen, confdir): if "rof2ocn_" in name: if case.get_value("COMP_OCN") == 'docn': logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) - elif "ocn2lnd_" in name: + elif "ocn2lnd_" in name: logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) - elif "lnd2ocn_" in name: + elif "lnd2ocn_" in name: logger.warning(" NOTE: ignoring setting of {}=idmap in seq_maps.rc".format(name)) else: expect(gridvalue[component1] == gridvalue[component2], @@ -431,7 +431,7 @@ def buildnml(case, caseroot, component): if "aquaplanet" in cam_config_opts: infile_text = "aqua_planet = .true. \n aqua_planet_sst = 1" - # add dust_emis_scheme + # add dust_emis_scheme dust_emis_scheme = case.get_value('dust_emis_scheme') infile_text += " dust_emis_scheme = {}".format(dust_emis_scheme) diff --git a/driver-mct/cime_config/namelist_definition_drv_flds.xml b/driver-mct/cime_config/namelist_definition_drv_flds.xml index 7fd5adb94d9f..64d2d099f1c1 100644 --- a/driver-mct/cime_config/namelist_definition_drv_flds.xml +++ b/driver-mct/cime_config/namelist_definition_drv_flds.xml @@ -146,7 +146,7 @@ - + logical From 7d4f98c30d153dcb944382eeade1f161c17310a5 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 16:35:18 -0600 Subject: [PATCH 279/398] Catch driver-moab/cime_config up with driver-mct Catch driver-moab/cime_config up with driver-mct. Adds rest of nlmaps variables (but doesn't use them). Add some CMIP7 compsets. Also add same changes from bafb7a0 to make CPL_ALBAV default on only for CORE-II forcing. Changes answers for C and G-cases to match MCT. --- driver-moab/cime_config/buildexe | 21 ++--- driver-moab/cime_config/buildnml | 12 ++- driver-moab/cime_config/config_component.xml | 38 +-------- .../cime_config/config_component_e3sm.xml | 84 +++++++++++++++---- .../cime_config/namelist_definition_drv.xml | 47 +++++++++++ 5 files changed, 134 insertions(+), 68 deletions(-) diff --git a/driver-moab/cime_config/buildexe b/driver-moab/cime_config/buildexe index 6f0ef6010017..8dcaea6af40c 100644 --- a/driver-moab/cime_config/buildexe +++ b/driver-moab/cime_config/buildexe @@ -13,6 +13,7 @@ from standard_script_setup import * from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import expect, run_cmd +from CIME.build import get_standard_makefile_args logger = logging.getLogger(__name__) @@ -20,36 +21,36 @@ logger = logging.getLogger(__name__) def _main_func(): ############################################################################### - caseroot, libroot, _ = parse_input(sys.argv) + caseroot, _, _ = parse_input(sys.argv) logger.info("Building a single executable version of target coupled model") with Case(caseroot) as case: casetools = case.get_value("CASETOOLS") cimeroot = case.get_value("CIMEROOT") - exeroot = case.get_value("EXEROOT") gmake = case.get_value("GMAKE") gmake_j = case.get_value("GMAKE_J") - model = case.get_value("MODEL") num_esp = case.get_value("NUM_COMP_INST_ESP") - os.environ["PIO_VERSION"] = str(case.get_value("PIO_VERSION")) + ocn_model = case.get_value("COMP_OCN") + atm_model = case.get_value("COMP_ATM") + gmake_opts = get_standard_makefile_args(case) + blddir = os.path.join(case.get_value("EXEROOT"),"cpl","obj") expect((num_esp is None) or (int(num_esp) == 1), "ESP component restricted to one instance") - - with open('Filepath', 'w') as out: + with open(os.path.join(blddir,'Filepath'), 'w') as out: out.write(os.path.join(caseroot, "SourceMods", "src.drv") + "\n") out.write(os.path.join(cimeroot, "src", "drivers", "moab", "main") + "\n") # build model executable makefile = os.path.join(casetools, "Makefile") - exename = os.path.join(exeroot, model + ".exe") + exename = os.path.join(case.get_value("EXEROOT"), case.get_value("MODEL") + ".exe") - cmd = "%s exec_se -j %d EXEC_SE=%s COMP_NAME=%s LIBROOT=%s -f %s "\ - % (gmake, gmake_j, exename, "driver", libroot, makefile) + cmd = "{gmake} exec_se -j {gmake_j} EXEC_SE={exename} COMP_NAME=driver {gmake_opts} -f {makefile} ".format(gmake=gmake, gmake_j=gmake_j, exename=exename, + gmake_opts=gmake_opts, makefile=makefile) - rc, out, _ = run_cmd(cmd, combine_output=True) + rc, out, _ = run_cmd(cmd, combine_output=True, from_dir=blddir) expect(rc==0,"Command %s failed rc=%d\nout=%s"%(cmd,rc,out)) logger.info(out) diff --git a/driver-moab/cime_config/buildnml b/driver-moab/cime_config/buildnml index 351477af44c0..a5725410b451 100755 --- a/driver-moab/cime_config/buildnml +++ b/driver-moab/cime_config/buildnml @@ -70,7 +70,7 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): elif case.get_value('RUN_TYPE') == 'branch': config['run_type'] = 'branch' - # --------------------------------------------------- + # --------------------------------------------------- # set wave coupling settings based on compset: # --------------------------------------------------- if case.get_value('COMP_WAV') == 'ww3': @@ -89,11 +89,11 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): if case.get_value('COMP_ICE') == 'mpassi': config['WAV_ICE_COUP'] = 'oneway' elif case.get_value('COMP_WAV') == 'dwav': - config['WAVSPEC'] = 'sp36x36' + config['WAVSPEC'] = 'sp36x36' else: - config['WAVSPEC'] = 'none' + config['WAVSPEC'] = 'none' - #---------------------------------------------------- + #---------------------------------------------------- # Initialize namelist defaults #---------------------------------------------------- nmlgen.init_defaults(infile, config) @@ -435,6 +435,10 @@ def buildnml(case, caseroot, component): dust_emis_scheme = case.get_value('dust_emis_scheme') infile_text += " dust_emis_scheme = {}".format(dust_emis_scheme) + # add nlmaps_atm2srf_conserve flag + nlmaps_atm2srf_conserve = case.get_value('nlmaps_atm2srf_conserve') + infile_text += " nlmaps_atm2srf_conserve = {}".format(nlmaps_atm2srf_conserve) + user_nl_file = os.path.join(caseroot, "user_nl_cpl") namelist_infile = os.path.join(confdir, "namelist_infile") create_namelist_infile(case, user_nl_file, namelist_infile, infile_text) diff --git a/driver-moab/cime_config/config_component.xml b/driver-moab/cime_config/config_component.xml index 986c19698b51..9eb9705e74a8 100644 --- a/driver-moab/cime_config/config_component.xml +++ b/driver-moab/cime_config/config_component.xml @@ -1501,7 +1501,7 @@ atm2rof state mapping file decomp type - + char idmap run_domain @@ -1949,42 +1949,6 @@ glc2ocn runoff mapping file decomp type for ice runoff - - char - idmap_ignore - run_domain - env_run.xml - ocn2glc flux mapping file - the default value idmap_ignore, if set, will be ignored by buildnml and - will generate a runtime error if in fact a file is required for the given compset - - - - char - X,Y - Y - run_domain - env_run.xml - ocn2glc flux mapping file decomp type - - - - char - idmap_ignore - run_domain - env_run.xml - ocn2glc state mapping file - the default value idmap_ignore, if set, will be ignored by buildnml and - will generate a runtime error if in fact a file is required for the given compset - - - - char - X,Y - Y - run_domain - env_run.xml - ocn2glc state mapping file decomp type - - char idmap_ignore diff --git a/driver-moab/cime_config/config_component_e3sm.xml b/driver-moab/cime_config/config_component_e3sm.xml index 628892595365..3c74dda07ca5 100644 --- a/driver-moab/cime_config/config_component_e3sm.xml +++ b/driver-moab/cime_config/config_component_e3sm.xml @@ -240,6 +240,18 @@ + + char + .true.,.false. + .false. + + .true. + + seq_infodata_inparm + env_run.xml + Conservative nlmaps from atm to surface + + @@ -288,10 +300,10 @@ run_coupling env_run.xml - User option to specify whether MOAB coupler maps should be computed + User option to specify whether MOAB coupler maps should be computed online or to load precomputed maps from disk at runtime (similar to MCT). - Note that this option enforces the same behavior for all coupler maps - (A-O, A-L, R-L, I-O etc) except R2O at the moment + Note that this option enforces the same behavior for all coupler maps + (A-O, A-L, R-L, I-O etc) except R2O at the moment (which is always loaded from disk). Default is false to replicate behavior of existing MCT coupler. @@ -407,7 +419,6 @@ 48 1 1 - 24 12 12 12 @@ -420,6 +431,9 @@ 1440 48 48 + 48 + 48 + 48 96 96 96 @@ -480,7 +494,6 @@ 1 1 1 - $ATM_NCPL 48 $ATM_NCPL $ATM_NCPL @@ -502,7 +515,6 @@ 1 1 1 - $ATM_NCPL $ATM_NCPL run_coupling @@ -528,7 +540,6 @@ 1 1 1 - 24 6 12 12 @@ -537,6 +548,9 @@ 48 48 48 + 48 + 48 + 48 48 48 96 @@ -608,7 +622,8 @@ 8 6 4 - 8 + 24 + 24 $ATM_NCPL run_coupling @@ -645,21 +660,19 @@ TRUE,FALSE FALSE - TRUE - TRUE + TRUE + TRUE run_component_cpl env_run.xml - Only used for compsets with DATM and POP (currently C, G and J): - If true, compute albedos to work with daily avg SW down - If false (default), albedos are computed with the assumption that downward + Only used for compsets with DATM and MPASO (currently C, G and J): + If FALSE (default), albedos are computed with the assumption that downward solar radiation from the atm component has a diurnal cycle and zenith-angle dependence. This is normally the case when using an active atm component - If true, albedos are computed with the assumption that downward + If TRUE, albedos are computed with the assumption that downward solar radiation from the atm component is a daily average quantity and - does not have a zenith-angle dependence. This is often the case when - using a data atm component. Only used for compsets with DATM and POP (currently C, G and J). + does not have a zenith-angle dependence. NOTE: This should really depend on the datm forcing and not the compset per se. So, for example, whether it is set in a J compset should depend on what datm forcing is used. @@ -791,11 +804,16 @@ 284.317 284.317 0.000001 + 0.000001 + 0.000001 284.317 284.317 284.317 284.317 284.317 + 284.297 + 1137.188 + 388.901 0.000001 0.000001 @@ -844,7 +862,7 @@ run_glc env_run.xml Glacier model number of elevation classes, 0 implies no glacier land unit in clm - Used by both ELM and CISM (even if CISM is not running, and only SGLC is used). + Used by both ELM and MALI (even if MALI is not running, and only SGLC is used). @@ -887,6 +905,35 @@ compsets. + + char + none,data_mpaso,data_mali,internal_mpaso,tf,coupler + none + + none + data_mpaso + data_mali + internal_mpaso + tf + coupler + + case_comp + env_case.xml + How OCN/GLC ice-shelf melt flux (ISMF) coupling is calculated: + 'none': ISMF is not represented in MPAS-O or MALI + 'data_mpaso': ISMF is represented as a data field in MPAS-O; + ISMF is not represented in MALI or MALI is inactive + 'data_mali': ISMF is represented as a data field in MALI; + ISMF is not represented in MPAS-O or MPAS-O is inactive + 'internal_mpaso': ISMF is calculated prognostically in MPAS-O; + ISMF is not represented in MALI or MALI is inactive + 'tf': MPAS-O passes 3d thermal forcing to MALI and MALI calculates ISMF + and passes it back to MPAS-O + 'coupler': ISMF is calculated in the coupler on the MALI + grid and at the MPAS-O coupling interval, and then passed to both + MPAS-O and MALI + + integer @@ -911,6 +958,8 @@ 1 2 + 2 + 2 2 shr_dust_nl @@ -933,6 +982,7 @@ AMIP for stand-alone cam: Future transient using CMIP6 SSP5_8.5 scenario: Future transient using CMIP6 SSP3_7.0 scenario: + Future transient using CMIP6 SSP2_4.5 scenario: CCMI REFC2 1950 to 2100 transient: CCMI REFC2 2004 to 2100 transient: 1948 to 2004 transient: diff --git a/driver-moab/cime_config/namelist_definition_drv.xml b/driver-moab/cime_config/namelist_definition_drv.xml index 83d6a262dfc7..a6a72866e3ea 100644 --- a/driver-moab/cime_config/namelist_definition_drv.xml +++ b/driver-moab/cime_config/namelist_definition_drv.xml @@ -1811,6 +1811,53 @@ + + integer + nlmaps + seq_infodata_inparm + + Measure and print information about nonlinearly mapped fields. 0 means no + analysis is done or printed. >= 1 triggers analysis written to + cpl.log. Modify user_nl_cpl to edit this. + default: 0 + + + 0 + + + + + logical + nlmaps + seq_infodata_inparm + + Use various source and destination grid area fractions in the + atmosphere-to-surface nonlinear maps so that an atmosphere-to-surface flux + integrates to the same value on the atmosphere grid and on the land + + ocean + ice grids. + default: .false. + + + .false. + + + + + char(20) + nlmaps + seq_infodata_inparm + + List of fields that are to be excluded from the set that are nonlinearly + mapped. For these excluded fields, the low-order linear map is used, + instead. Modify user_nl_cpl to edit this. This option is ignored if + nlmaps_atm2srf_conserve is .true. + default: 'Faxa_rainc', 'Faxa_rainl', 'Faxa_snowc', 'Faxa_snowl' + + + 'Faxa_rainc', 'Faxa_rainl', 'Faxa_snowc', 'Faxa_snowl' + + + From f37aca6951231bad419cb7e5b696eb65d5973747 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 16:40:15 -0600 Subject: [PATCH 280/398] Add more nlmaps variables to namelist Add nlmaps_atm2srf_conserve, nlmaps_exclude_fields to the namelist since buildnml now adds them. Read and report them but don't yet use them. --- driver-moab/shr/seq_infodata_mod.F90 | 45 +++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/driver-moab/shr/seq_infodata_mod.F90 b/driver-moab/shr/seq_infodata_mod.F90 index 3a173686cf3c..fdc896f0c8e0 100644 --- a/driver-moab/shr/seq_infodata_mod.F90 +++ b/driver-moab/shr/seq_infodata_mod.F90 @@ -60,6 +60,10 @@ MODULE seq_infodata_mod character(len=*), public, parameter :: seq_infodata_orb_variable_year = 'variable_year' character(len=*), public, parameter :: seq_infodata_orb_fixed_parameters = 'fixed_parameters' + ! For seq_nlmap_mod. + integer, public, parameter :: nlmaps_exclude_max_number = 20 + integer, public, parameter :: nlmaps_exclude_nchar = SHR_KIND_CS + ! InputInfo derived type type seq_infodata_type @@ -174,6 +178,8 @@ MODULE seq_infodata_mod logical :: mct_usealltoall ! flag for mct alltoall logical :: mct_usevector ! flag for mct vector integer :: nlmaps_verbosity ! see seq_nlmap_mod + logical :: nlmaps_atm2srf_conserve ! see seq_nlmap_mod + character(nlmaps_exclude_nchar) :: nlmaps_exclude_fields(nlmaps_exclude_max_number) ! see seq_nlmap_mod logical :: reprosum_use_ddpdd ! use ddpdd algorithm logical :: reprosum_allow_infnan ! allow INF and NaN summands @@ -447,6 +453,9 @@ SUBROUTINE seq_infodata_Init( infodata, nmlfile, ID, pioid, cpl_tag) real(shr_kind_r8) :: max_cplstep_time ! abort if cplstep time exceeds this value character(SHR_KIND_CL) :: model_doi_url integer(SHR_KIND_IN) :: nlmaps_verbosity ! see seq_nlmap_mod + logical :: nlmaps_atm2srf_conserve ! see seq_nlmap_mod + character(nlmaps_exclude_nchar) :: nlmaps_exclude_fields(nlmaps_exclude_max_number) ! see seq_nlmap_mod + namelist /seq_infodata_inparm/ & cime_model, case_desc, case_name, start_type, tchkpt_dir, & @@ -487,7 +496,7 @@ SUBROUTINE seq_infodata_Init( infodata, nmlfile, ID, pioid, cpl_tag) reprosum_use_ddpdd, reprosum_allow_infnan, & reprosum_diffmax, reprosum_recompute, & mct_usealltoall, mct_usevector, max_cplstep_time, model_doi_url, & - nlmaps_verbosity + nlmaps_verbosity, nlmaps_atm2srf_conserve, nlmaps_exclude_fields !------------------------------------------------------------------------------- @@ -611,6 +620,8 @@ SUBROUTINE seq_infodata_Init( infodata, nmlfile, ID, pioid, cpl_tag) max_cplstep_time = 0.0 model_doi_url = 'unset' nlmaps_verbosity = 0 + nlmaps_atm2srf_conserve = .false. + nlmaps_exclude_fields(:) = ' ' !--------------------------------------------------------------------------- ! Read in namelist @@ -748,6 +759,8 @@ SUBROUTINE seq_infodata_Init( infodata, nmlfile, ID, pioid, cpl_tag) infodata%mct_usealltoall = mct_usealltoall infodata%mct_usevector = mct_usevector infodata%nlmaps_verbosity = nlmaps_verbosity + infodata%nlmaps_atm2srf_conserve = nlmaps_atm2srf_conserve + infodata%nlmaps_exclude_fields = nlmaps_exclude_fields infodata%info_debug = info_debug infodata%bfbflag = bfbflag @@ -1066,7 +1079,8 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ reprosum_use_ddpdd, reprosum_allow_infnan, & reprosum_diffmax, reprosum_recompute, & mct_usealltoall, mct_usevector, max_cplstep_time, model_doi_url, & - glc_valid_input, nlmaps_verbosity, rmean_rmv_ice_runoff) + glc_valid_input, nlmaps_verbosity, nlmaps_atm2srf_conserve, & + nlmaps_exclude_fields, rmean_rmv_ice_runoff) implicit none @@ -1185,6 +1199,8 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ logical, optional, intent(OUT) :: mct_usealltoall ! flag for mct alltoall logical, optional, intent(OUT) :: mct_usevector ! flag for mct vector integer(SHR_KIND_IN), optional, intent(OUT) :: nlmaps_verbosity + logical, optional, intent(OUT) :: nlmaps_atm2srf_conserve + character(nlmaps_exclude_nchar), optional, intent(OUT) :: nlmaps_exclude_fields(nlmaps_exclude_max_number) integer(SHR_KIND_IN), optional, intent(OUT) :: info_debug logical, optional, intent(OUT) :: bfbflag @@ -1382,6 +1398,8 @@ SUBROUTINE seq_infodata_GetData_explicit( infodata, cime_model, case_name, case_ if ( present(mct_usealltoall)) mct_usealltoall = infodata%mct_usealltoall if ( present(mct_usevector) ) mct_usevector = infodata%mct_usevector if ( present(nlmaps_verbosity)) nlmaps_verbosity = infodata%nlmaps_verbosity + if ( present(nlmaps_atm2srf_conserve)) nlmaps_atm2srf_conserve = infodata%nlmaps_atm2srf_conserve + if ( present(nlmaps_exclude_fields)) nlmaps_exclude_fields = infodata%nlmaps_exclude_fields if ( present(info_debug) ) info_debug = infodata%info_debug if ( present(bfbflag) ) bfbflag = infodata%bfbflag @@ -1642,10 +1660,12 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ eps_aarea, eps_omask, eps_ogrid, eps_oarea, & reprosum_use_ddpdd, reprosum_allow_infnan, & reprosum_diffmax, reprosum_recompute, & - mct_usealltoall, mct_usevector, glc_valid_input, nlmaps_verbosity, & + mct_usealltoall, mct_usevector, glc_valid_input, & + nlmaps_verbosity, nlmaps_atm2srf_conserve, nlmaps_exclude_fields, & rmean_rmv_ice_runoff) + implicit none ! !INPUT/OUTPUT PARAMETERS: @@ -1762,6 +1782,8 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ logical, optional, intent(IN) :: mct_usealltoall ! flag for mct alltoall logical, optional, intent(IN) :: mct_usevector ! flag for mct vector integer(SHR_KIND_IN), optional, intent(IN) :: nlmaps_verbosity + logical, optional, intent(IN) :: nlmaps_atm2srf_conserve + character(nlmaps_exclude_nchar), optional, intent(IN) :: nlmaps_exclude_fields(nlmaps_exclude_max_number) integer(SHR_KIND_IN), optional, intent(IN) :: info_debug logical, optional, intent(IN) :: bfbflag @@ -1958,6 +1980,8 @@ SUBROUTINE seq_infodata_PutData_explicit( infodata, cime_model, case_name, case_ if ( present(mct_usealltoall)) infodata%mct_usealltoall = mct_usealltoall if ( present(mct_usevector) ) infodata%mct_usevector = mct_usevector if ( present(nlmaps_verbosity)) infodata%nlmaps_verbosity = nlmaps_verbosity + if ( present(nlmaps_atm2srf_conserve)) infodata%nlmaps_atm2srf_conserve = nlmaps_atm2srf_conserve + if ( present(nlmaps_exclude_fields)) infodata%nlmaps_exclude_fields = nlmaps_exclude_fields if ( present(info_debug) ) infodata%info_debug = info_debug if ( present(bfbflag) ) infodata%bfbflag = bfbflag @@ -2163,6 +2187,7 @@ subroutine seq_infodata_bcast(infodata,mpicom) !EOP !----- local ----- + integer :: i !------------------------------------------------------------------------------- ! Notes: @@ -2277,6 +2302,10 @@ subroutine seq_infodata_bcast(infodata,mpicom) call shr_mpi_bcast(infodata%mct_usealltoall, mpicom) call shr_mpi_bcast(infodata%mct_usevector, mpicom) call shr_mpi_bcast(infodata%nlmaps_verbosity, mpicom) + call shr_mpi_bcast(infodata%nlmaps_atm2srf_conserve, mpicom) + do i = 1, nlmaps_exclude_max_number + call shr_mpi_bcast(infodata%nlmaps_exclude_fields(i), mpicom) + end do call shr_mpi_bcast(infodata%info_debug, mpicom) call shr_mpi_bcast(infodata%bfbflag, mpicom) @@ -2867,7 +2896,7 @@ SUBROUTINE seq_infodata_print( infodata ) !EOP !----- local ----- - integer :: ind + integer :: ind,i character(len=*), parameter :: subname = '(seq_infodata_print) ' character(len=*), parameter :: F0A = "(2A,A)" character(len=*), parameter :: F0L = "(2A,L3)" @@ -3013,6 +3042,14 @@ SUBROUTINE seq_infodata_print( infodata ) write(logunit,F0L) subname,'mct_usevector = ', infodata%mct_usevector write(logunit,F0I) subname,'nlmaps_verbosity = ', infodata%nlmaps_verbosity + write(logunit,F0L) subname,'nlmaps_atm2srf_conserve = ', infodata%nlmaps_atm2srf_conserve + + write(logunit,'(2A)',advance='no') subname,'nlmaps_exclude_fields = ' + do i = 1, size(infodata%nlmaps_exclude_fields) + if (len(trim(infodata%nlmaps_exclude_fields(i))) == 0) cycle + write(logunit,'(3A)',advance='no') ' ', trim(infodata%nlmaps_exclude_fields(i)) + end do + write(logunit,'(A)') '' write(logunit,F0S) subname,'info_debug = ', infodata%info_debug write(logunit,F0L) subname,'bfbflag = ', infodata%bfbflag From c4b41b6fbcebbb6513d1f3ccdb79d563b16ff82d Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 5 Jan 2026 17:44:39 -0500 Subject: [PATCH 281/398] Kokkos must also be told about GPU targets --- .../machines/cmake_macros/crayamd-mphipcc_frontier.cmake | 2 +- .../machines/cmake_macros/craycray-mphipcc_frontier.cmake | 2 +- cime_config/machines/cmake_macros/craygnu-mphipcc.cmake | 2 +- cime_config/machines/cmake_macros/gnugpu_frontier.cmake | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake b/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake index e82871185881..9ce7c6e0b928 100644 --- a/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake +++ b/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake @@ -17,7 +17,7 @@ set(AMDGPU_TARGETS "gfx90a") set(GPU_TARGETS "gfx90a") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/cray/pe/gcc/12.2.0/snos/lib64 -lgfortran -lstdc++") -string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On") +string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DAMDGPU_TARGETS=gfx90a -DGPU_TARGETS=gfx90a") set(USE_HIP "TRUE") string(APPEND CMAKE_HIP_FLAGS "${CXXFLAGS} -munsafe-fp-atomics -x hip") diff --git a/cime_config/machines/cmake_macros/craycray-mphipcc_frontier.cmake b/cime_config/machines/cmake_macros/craycray-mphipcc_frontier.cmake index ed37b6e80258..0d1db9dbd09f 100644 --- a/cime_config/machines/cmake_macros/craycray-mphipcc_frontier.cmake +++ b/cime_config/machines/cmake_macros/craycray-mphipcc_frontier.cmake @@ -33,7 +33,7 @@ if (COMP_NAME STREQUAL gptl) endif() set(PIO_FILESYSTEM_HINTS "lustre") -string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=OFF") +string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=OFF -DAMDGPU_TARGETS=gfx90a -DGPU_TARGETS=gfx90a") set(USE_HIP "TRUE") # Work around a compiler-side issue (register allocation) in diff --git a/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake b/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake index efae431ebff9..815eaeb4be0e 100644 --- a/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake +++ b/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake @@ -37,7 +37,7 @@ if (compile_threaded) string(APPEND CMAKE_EXE_LINKER_FLAGS " -fopenmp") endif() -string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=Off") +string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=Off -DAMDGPU_TARGETS=gfx90a -DGPU_TARGETS=gfx90a") set(USE_HIP "TRUE") set(AMDGPU_TARGETS "gfx90a") diff --git a/cime_config/machines/cmake_macros/gnugpu_frontier.cmake b/cime_config/machines/cmake_macros/gnugpu_frontier.cmake index 7ef68f1b4d6c..fa9d3159993d 100644 --- a/cime_config/machines/cmake_macros/gnugpu_frontier.cmake +++ b/cime_config/machines/cmake_macros/gnugpu_frontier.cmake @@ -23,10 +23,9 @@ string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/cray/pe/gcc/12.2.0/snos/lib64 -lgf # #string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/rocm-5.4.0/lib -lhsa-runtime64 -L$ENV{CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa ") -string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=Off") +string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=Off -DAMDGPU_TARGETS=gfx90a -DGPU_TARGETS=gfx90a") set(USE_HIP "TRUE") string(APPEND CMAKE_HIP_FLAGS "${CXXFLAGS} -munsafe-fp-atomics -x hip") - set(E3SM_LINK_WITH_FORTRAN "TRUE") From ef9b151c08a517189925da87281bf61a920bc0c0 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 21:44:34 -0600 Subject: [PATCH 282/398] Fix white space Fix white space, making sure mct and moab stay the same --- driver-mct/cime_config/buildnml | 2 +- driver-mct/main/seq_domain_mct.F90 | 1 - driver-moab/cime_config/buildnml | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/driver-mct/cime_config/buildnml b/driver-mct/cime_config/buildnml index 58fc00576bd0..d7b2e91e08a3 100755 --- a/driver-mct/cime_config/buildnml +++ b/driver-mct/cime_config/buildnml @@ -93,7 +93,7 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): else: config['WAVSPEC'] = 'none' - #---------------------------------------------------- + #---------------------------------------------------- # Initialize namelist defaults #---------------------------------------------------- nmlgen.init_defaults(infile, config) diff --git a/driver-mct/main/seq_domain_mct.F90 b/driver-mct/main/seq_domain_mct.F90 index 1147328f1b19..b06c7b1ad41c 100644 --- a/driver-mct/main/seq_domain_mct.F90 +++ b/driver-mct/main/seq_domain_mct.F90 @@ -213,7 +213,6 @@ subroutine seq_domain_check( infodata, & ! - eps_*mask: acceptable error in mask values ! - eps_*grid: acceptable error in coordinate values ! - eps_*area: acceptable error in grid cell areas - call seq_infodata_GetData( infodata, & lnd_present=lnd_present, & ocn_present=ocn_present, & diff --git a/driver-moab/cime_config/buildnml b/driver-moab/cime_config/buildnml index a5725410b451..5beb016bd5dd 100755 --- a/driver-moab/cime_config/buildnml +++ b/driver-moab/cime_config/buildnml @@ -89,11 +89,11 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files): if case.get_value('COMP_ICE') == 'mpassi': config['WAV_ICE_COUP'] = 'oneway' elif case.get_value('COMP_WAV') == 'dwav': - config['WAVSPEC'] = 'sp36x36' + config['WAVSPEC'] = 'sp36x36' else: - config['WAVSPEC'] = 'none' + config['WAVSPEC'] = 'none' - #---------------------------------------------------- + #---------------------------------------------------- # Initialize namelist defaults #---------------------------------------------------- nmlgen.init_defaults(infile, config) From e631be7d5ec3110c268cf946440aa1763aa5b6fb Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Mon, 5 Jan 2026 21:46:15 -0600 Subject: [PATCH 283/398] Remove doxygen style comments Remove doxygen style comments --- driver-moab/main/seq_map_mod.F90 | 81 ++++++++++++++++---------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/driver-moab/main/seq_map_mod.F90 b/driver-moab/main/seq_map_mod.F90 index 35cced1c462a..7f53e441e7a0 100644 --- a/driver-moab/main/seq_map_mod.F90 +++ b/driver-moab/main/seq_map_mod.F90 @@ -345,46 +345,47 @@ subroutine seq_map_init_rearrolap(mapper, comp_s, comp_d, string, no_match) end subroutine seq_map_init_rearrolap !======================================================================= - !> - !> @brief Maps attribute vector fields from source to destination grid. - !> - !> This subroutine is the primary mapping interface for transferring field - !> data between component grids. It supports THREE mapping strategies: - !> - !> 1. COPY (mapper%copy_only=.true.) - !> - Used when source and destination grids are IDENTICAL - !> - Simply copies data without any transformation - !> - only in MCT mode - !> - !> 2. REARRANGE (mapper%rearrange_only=.true.) - !> - Used when grids have the SAME points but DIFFERENT MPI distribution - !> - Performs MPI communication to redistribute data - !> - !> 3. MAP (neither copy_only nor rearrange_only) - !> - Full interpolation/regridding between DIFFERENT grids - !> - Uses sparse matrix multiplication with pre-computed weights - !> - Supports optional normalization for conservation - !> - !> *** MOAB Integration *** - !> This subroutine maintains DUAL data paths: - !> - MCT path: Traditional mct_aVect operations (always executed) - !> - MOAB path: Parallel iMOAB operations (executed when valid_moab_context=.true.) - !> - !> The MOAB path uses iMOAB API calls to: - !> - Transfer data between MOAB application instances - !> - Apply projection weights for regridding - !> - Handle normalization for conservative mapping - !> - !> @param mapper Mapping data structure containing weights and grid info - !> @param av_s Source attribute vector (input fields) - !> @param av_d Destination attribute vector (output fields) - !> @param fldlist Optional: specific fields to map (default: all fields) - !> @param norm Optional: enable normalization (default: .true.) - !> @param avwts_s Optional: source weights for normalization - !> @param avwtsfld_s Optional: field name in avwts_s to use as weight - !> @param string Optional: description string for logging - !> @param msgtag Optional: MPI message tag for rearrangement - !> + ! + ! seq_map_map - Maps attribute vector fields from source to destination grid. + ! + ! This subroutine is the primary mapping interface for transferring field + ! data between component grids. It supports THREE mapping strategies: + ! + ! 1. COPY (mapper%copy_only=.true.) + ! - Used when source and destination grids are IDENTICAL + ! - Simply copies data without any transformation + ! - only in MCT mode + ! + ! 2. REARRANGE (mapper%rearrange_only=.true.) + ! - Used when grids have the SAME points but DIFFERENT MPI distribution + ! - Performs MPI communication to redistribute data + ! + ! 3. MAP (neither copy_only nor rearrange_only) + ! - Full interpolation/regridding between DIFFERENT grids + ! - Uses sparse matrix multiplication with pre-computed weights + ! - Supports optional normalization for conservation + ! + ! *** MOAB Integration *** + ! This subroutine maintains DUAL data paths: + ! - MCT path: Traditional mct_aVect operations (always executed) + ! - MOAB path: Parallel iMOAB operations (executed when valid_moab_context=.true.) + ! + ! The MOAB path uses iMOAB API calls to: + ! - Transfer data between MOAB application instances + ! - Apply projection weights for regridding + ! - Handle normalization for conservative mapping + ! + ! Arguments: + ! mapper - Mapping data structure containing weights and grid info + ! av_s - Source attribute vector (input fields) + ! av_d - Destination attribute vector (output fields) + ! fldlist - Optional: specific fields to map (default: all fields) + ! norm - Optional: enable normalization (default: .true.) + ! avwts_s - Optional: source weights for normalization + ! avwtsfld_s - Optional: field name in avwts_s to use as weight + ! string - Optional: description string for logging + ! msgtag - Optional: MPI message tag for rearrangement + ! !======================================================================= subroutine seq_map_map( mapper, av_s, av_d, fldlist, norm, avwts_s, avwtsfld_s, & From f7d4781fdaa0ad859dbc0f02e82f5a3d301d06c1 Mon Sep 17 00:00:00 2001 From: Wuyin Lin Date: Tue, 6 Jan 2026 10:46:24 -0600 Subject: [PATCH 284/398] Limit warning messages on STDEV_ELEV and manunitro to masterproc --- components/elm/src/main/pftvarcon.F90 | 1 + components/elm/src/main/surfrdMod.F90 | 1 + 2 files changed, 2 insertions(+) diff --git a/components/elm/src/main/pftvarcon.F90 b/components/elm/src/main/pftvarcon.F90 index b4b7be1a35bd..82e9f1968c2d 100644 --- a/components/elm/src/main/pftvarcon.F90 +++ b/components/elm/src/main/pftvarcon.F90 @@ -782,6 +782,7 @@ subroutine pftconrd if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(__FILE__, __LINE__)) call ncd_io('manunitro',manunitro, 'read', ncid, readvar=readv, posNOTonfile=.true.) if (.not. readv) then + if (masterproc) & write(iulog,*) trim(subname),' WARNING: manunitro NOT in parameter file. Try to use fertnitro instead.' call ncd_io('fertnitro',manunitro, 'read', ncid, readvar=readv, posNOTonfile=.true.) if ( .not. readv ) call endrun(msg=' ERROR: both manunitro and fertnitro not in parameter file'//errMsg(__FILE__, __LINE__)) diff --git a/components/elm/src/main/surfrdMod.F90 b/components/elm/src/main/surfrdMod.F90 index 48cd79c91f36..e8f81e7a9ab9 100755 --- a/components/elm/src/main/surfrdMod.F90 +++ b/components/elm/src/main/surfrdMod.F90 @@ -1680,6 +1680,7 @@ subroutine surfrd_get_topo_for_solar_rad(domain,filename) call ncd_io(ncid=ncid, varname='STDEV_ELEV', flag='read', data=domain%stdev_elev, & dim1name=grlnd, readvar=readvar) if (.not. readvar) then + if (masterproc) & write(iulog,*) trim(subname),' WARNING: STDEV_ELEV NOT on fsurdat file. Try to use STD_ELEV instead.' call ncd_io(ncid=ncid, varname='STD_ELEV', flag='read', data=domain%stdev_elev, & dim1name=grlnd, readvar=readvar) From 8a692ba8b36f35d913b5d479e98291d446a574d7 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Tue, 6 Jan 2026 14:55:53 -0500 Subject: [PATCH 285/398] These need to be set as CACHE values --- .../machines/cmake_macros/crayamd-mphipcc_frontier.cmake | 4 ++-- cime_config/machines/cmake_macros/craycray-mphipcc.cmake | 4 ++-- cime_config/machines/cmake_macros/craygnu-mphipcc.cmake | 4 ++-- cime_config/machines/cmake_macros/gnugpu_frontier.cmake | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake b/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake index 9ce7c6e0b928..0d1ffb580ac8 100644 --- a/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake +++ b/cime_config/machines/cmake_macros/crayamd-mphipcc_frontier.cmake @@ -13,8 +13,8 @@ string(APPEND CMAKE_C_FLAGS_RELEASE " -O2") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") string(APPEND CMAKE_Fortran_FLAGS_RELEASE " -O2") -set(AMDGPU_TARGETS "gfx90a") -set(GPU_TARGETS "gfx90a") +set(AMDGPU_TARGETS "gfx90a" CACHE STRING "") +set(GPU_TARGETS "gfx90a" CACHE STRING "") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/cray/pe/gcc/12.2.0/snos/lib64 -lgfortran -lstdc++") string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DAMDGPU_TARGETS=gfx90a -DGPU_TARGETS=gfx90a") diff --git a/cime_config/machines/cmake_macros/craycray-mphipcc.cmake b/cime_config/machines/cmake_macros/craycray-mphipcc.cmake index cb2df6134e22..4732f44f28cb 100644 --- a/cime_config/machines/cmake_macros/craycray-mphipcc.cmake +++ b/cime_config/machines/cmake_macros/craycray-mphipcc.cmake @@ -27,5 +27,5 @@ set(SCC "cc") set(SCXX "CC") set(SFC "ftn") -set(AMDGPU_TARGETS "gfx90a") -set(GPU_TARGETS "gfx90a") +set(AMDGPU_TARGETS "gfx90a" CACHE STRING "") +set(GPU_TARGETS "gfx90a" CACHE STRING "") diff --git a/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake b/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake index 815eaeb4be0e..c0396b7c6b09 100644 --- a/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake +++ b/cime_config/machines/cmake_macros/craygnu-mphipcc.cmake @@ -40,6 +40,6 @@ endif() string(APPEND KOKKOS_OPTIONS " -DKokkos_ENABLE_HIP=On -DKokkos_ARCH_ZEN3=On -DKokkos_ARCH_VEGA90A=On -DKokkos_ENABLE_OPENMP=Off -DAMDGPU_TARGETS=gfx90a -DGPU_TARGETS=gfx90a") set(USE_HIP "TRUE") -set(AMDGPU_TARGETS "gfx90a") -set(GPU_TARGETS "gfx90a") +set(AMDGPU_TARGETS "gfx90a" CACHE STRING "") +set(GPU_TARGETS "gfx90a" CACHE STRING "") string(APPEND CMAKE_HIP_FLAGS "$ENV{CXXFLAGS} -munsafe-fp-atomics") diff --git a/cime_config/machines/cmake_macros/gnugpu_frontier.cmake b/cime_config/machines/cmake_macros/gnugpu_frontier.cmake index fa9d3159993d..716e06685b3a 100644 --- a/cime_config/machines/cmake_macros/gnugpu_frontier.cmake +++ b/cime_config/machines/cmake_macros/gnugpu_frontier.cmake @@ -15,8 +15,8 @@ string(APPEND CMAKE_C_FLAGS_RELEASE " -O2") string(APPEND CMAKE_CXX_FLAGS_RELEASE " -O2") string(APPEND CMAKE_Fortran_FLAGS_RELEASE " -O2") -set(AMDGPU_TARGETS "gfx90a") -set(GPU_TARGETS "gfx90a") +set(AMDGPU_TARGETS "gfx90a" CACHE STRING "") +set(GPU_TARGETS "gfx90a" CACHE STRING "") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{ROCM_PATH}/lib -lamdhip64") string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/opt/cray/pe/gcc/12.2.0/snos/lib64 -lgfortran -lstdc++") From 7f19daa6f06c55c2c8fbc0a31473eb0836547de7 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 8 Jan 2026 09:44:08 -0800 Subject: [PATCH 286/398] EAMxx: fix link error in homme f90 interface --- .../eamxx/src/dynamics/homme/interface/homme_grid_mod.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/eamxx/src/dynamics/homme/interface/homme_grid_mod.F90 b/components/eamxx/src/dynamics/homme/interface/homme_grid_mod.F90 index 28dfed502f8f..5ecc56547726 100644 --- a/components/eamxx/src/dynamics/homme/interface/homme_grid_mod.F90 +++ b/components/eamxx/src/dynamics/homme/interface/homme_grid_mod.F90 @@ -12,12 +12,13 @@ module homme_grid_mod public :: finalize_geometry_f90 ! Routines to get information - ! public :: get_cols_gids_f90, get_cols_indices_f90 public :: get_num_local_columns_f90, get_num_global_columns_f90 public :: get_num_local_elems_f90, get_num_global_elems_f90 public :: get_np_f90, get_nlev_f90 public :: is_planar_geometry_f90 + public :: check_grids_inited + contains function is_planar_geometry_f90 () result(planar) bind(c) From c3dedc21ae60ae9734a4cc66220e462bc2e6bf3a Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Thu, 20 Nov 2025 11:24:02 -0800 Subject: [PATCH 287/398] Adding call to update fates internal albedos for specific circumstances --- components/elm/src/main/elm_driver.F90 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 92f7a799e42a..92f4f73d986a 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -17,6 +17,9 @@ module elm_driver use elm_varctl , only : use_erosion, use_fates_sp, use_fan use elm_varctl , only : iac_present use elm_varctl , only : mpi_sync_nstep_freq + use elm_varctl , only : nsrest, nsrStartup + use elm_varctl , only : fates_radiation_model + use elm_varctl , only : finidat use elm_time_manager , only : get_step_size, get_curr_date, get_ref_date, get_nstep, is_beg_curr_day, get_curr_time_string use elm_time_manager , only : get_curr_calday, get_days_per_year use elm_varpar , only : nlevsno, nlevgrnd, crop_prog @@ -244,6 +247,7 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) character(len=256) :: dateTimeString type(bounds_type) :: bounds_clump type(bounds_type) :: bounds_proc + logical :: is_cold_start ! is this a true cold start, both nsrStartup and finidat=' '? !----------------------------------------------------------------------- call get_curr_time_string(dateTimeString) @@ -1366,7 +1370,20 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) ! ============================================================================ ! Determine albedos for next time step ! ============================================================================ + + if (use_fates .and. .not.doalb ) then + + is_cold_start = (nsrest == nsrStartup .and. finidat == ' ') + + if ( (is_cold_start .and. get_nstep() == 1) .or. & + ((fates_radiation_model == 'twostream') .and. (get_nstep()== 1) .and. (.not.use_fates_sp) & + .and. (.not.is_cold_start) .and. (nsrest == nsrStartup)) ) then + + call alm_fates%wrap_canopy_radiation(bounds_clump,surfalb_vars,nextsw_cday,declinp1) + end if + end if + if ( doalb ) then ! Albedos for non-urban columns From d2ed7b8bb2d78fbbf1b49c24a5e213af609f5d89 Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Tue, 30 Dec 2025 12:36:19 -0500 Subject: [PATCH 288/398] simplified logic related to that extra albedo calculation for fates on the first time-step. --- components/elm/src/main/elm_driver.F90 | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 92f4f73d986a..09a49e418975 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -247,7 +247,6 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) character(len=256) :: dateTimeString type(bounds_type) :: bounds_clump type(bounds_type) :: bounds_proc - logical :: is_cold_start ! is this a true cold start, both nsrStartup and finidat=' '? !----------------------------------------------------------------------- call get_curr_time_string(dateTimeString) @@ -1371,16 +1370,10 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) ! Determine albedos for next time step ! ============================================================================ - if (use_fates .and. .not.doalb ) then - - is_cold_start = (nsrest == nsrStartup .and. finidat == ' ') - - if ( (is_cold_start .and. get_nstep() == 1) .or. & - ((fates_radiation_model == 'twostream') .and. (get_nstep()== 1) .and. (.not.use_fates_sp) & - .and. (.not.is_cold_start) .and. (nsrest == nsrStartup)) ) then - + if (use_fates .and. .not.doalb .and. get_nstep() == 1 .and. nsrest == nsrStartup) then + if ( (finidat == ' ') .or. & + (fates_radiation_model=='twostream') .and. .not.use_fates_sp) ) then call alm_fates%wrap_canopy_radiation(bounds_clump,surfalb_vars,nextsw_cday,declinp1) - end if end if From cf18e618240079cc010de147b4c82e6a65149342 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 5 Jan 2026 14:36:30 -0800 Subject: [PATCH 289/398] add comments explaining elm_driver update for FATES two stream --- components/elm/src/main/elm_driver.F90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 09a49e418975..763a2fc44957 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -1370,6 +1370,8 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) ! Determine albedos for next time step ! ============================================================================ + ! On the first step, send the solar zenith angles to FATES on non-continue restarts + ! for the two-stream radiation scheme. if (use_fates .and. .not.doalb .and. get_nstep() == 1 .and. nsrest == nsrStartup) then if ( (finidat == ' ') .or. & (fates_radiation_model=='twostream') .and. .not.use_fates_sp) ) then From 22a38455698482c5562cea4e030ced162e356baf Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Tue, 6 Jan 2026 09:19:34 -0800 Subject: [PATCH 290/398] fix typo causing minor build issue --- components/elm/src/main/elm_driver.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 763a2fc44957..2d0e9a625b95 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -1374,7 +1374,7 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) ! for the two-stream radiation scheme. if (use_fates .and. .not.doalb .and. get_nstep() == 1 .and. nsrest == nsrStartup) then if ( (finidat == ' ') .or. & - (fates_radiation_model=='twostream') .and. .not.use_fates_sp) ) then + (fates_radiation_model=='twostream') .and. .not.use_fates_sp ) then call alm_fates%wrap_canopy_radiation(bounds_clump,surfalb_vars,nextsw_cday,declinp1) end if end if From de71648d54b9ff6bde1dc01d523a47bbea79906a Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Thu, 8 Jan 2026 13:42:11 -0700 Subject: [PATCH 291/398] Modify CMake options for homme_tool build Updated CMake command options for building homme_tool. --- .../generate-topo-file.md | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 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 808278782f59..2db86a83faa8 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 @@ -48,16 +48,22 @@ eval $(${e3sm_root}/cime/CIME/Tools/get_case_env) mach_file=${e3sm_root}/components/homme/cmake/machineFiles/pm-cpu.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 \ +cmake -C ${mach_file} \ +-DBUILD_HOMME_WITHOUT_PIOLIBRARY=OFF \ +-DPREQX_PLEV=26 \ ${e3sm_root}/components/homme +# NOTE - if you run into problems building with the above CMake command you can try adding additional options as shown below +# 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 ``` From 4171bc2b0a6848fcf6547207fb48fc980522abef Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 8 Jan 2026 15:52:46 -0700 Subject: [PATCH 292/398] EAMxx: fix handling of data dims in data interpolation If input files contain only surface data, no nlev info may be available, and similarly for ncol if the data is only 1d in the vertical direction. --- .../algorithm/eamxx_data_interpolation.cpp | 34 +++++++++++++++---- .../algorithm/eamxx_data_interpolation.hpp | 5 ++- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp index fcb09f02cb14..a953f5246322 100644 --- a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp +++ b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp @@ -34,10 +34,16 @@ DataInterpolation (const std::shared_ptr& model_grid, m_comm = model_grid->get_comm(); using namespace ShortFieldTagsNames; + for (const auto& f : fields) { + const auto& fl = f.get_header().get_identifier().get_layout(); + m_fields_have_col_dim |= fl.has_tag(COL); + m_fields_have_lev_dim |= fl.has_tag(LEV); + m_fields_have_lev_dim |= fl.has_tag(ILEV); + } + m_input_files_dimnames[COL] = "ncol"; m_input_files_dimnames[LEV] = "lev"; m_input_files_dimnames[ILEV] = "ilev"; - e2str(LEV); // Initialize logger with a console logger for warnings (logs on all ranks) m_logger = console_logger(ekat::logger::LogLevel::warn); @@ -409,13 +415,22 @@ create_horiz_remappers (const std::string& map_file) EKAT_REQUIRE_MSG (m_horiz_remapper_beg==nullptr, "[DataInterpolation] Error! Horizontal remappers were already setup.\n"); + int ncols_model = m_model_grid->get_num_global_dofs(); + int nlevs_model = m_model_grid->get_num_vertical_levels(); + // Create hremap tgt grid - int nlevs_data = get_input_files_dimlen (m_input_files_dimnames[LEV]); - int ncols_data = get_input_files_dimlen (m_input_files_dimnames[COL]); + int nlevs_data = nlevs_model; + int ncols_data = m_fields_have_col_dim ? get_input_files_dimlen (m_input_files_dimnames[COL]) : ncols_model; + + if (m_fields_have_lev_dim) { + nlevs_data = get_input_files_dimlen (m_input_files_dimnames[LEV]); + } else if (m_fields_have_ilev_dim) { + nlevs_data = get_input_files_dimlen(m_input_files_dimnames[ILEV]); + } + m_grid_after_hremap = m_model_grid->clone("after_hremap",true); m_grid_after_hremap->reset_num_vertical_lev(nlevs_data); - int ncols_model = m_model_grid->get_num_global_dofs(); if (map_file!="") { m_horiz_remapper_beg = std::make_shared(m_grid_after_hremap,map_file); m_horiz_remapper_end = std::make_shared(m_grid_after_hremap,map_file); @@ -462,8 +477,12 @@ create_horiz_remappers (const Real iop_lat, const Real iop_lon) " - iop_lat: " << iop_lat << "\n" " - iop_lon: " << iop_lon << "\n"); - int nlevs_data = get_input_files_dimlen (m_input_files_dimnames[LEV]); - int ncols_data = get_input_files_dimlen (m_input_files_dimnames[COL]); + int ncols_model = m_model_grid->get_num_global_dofs(); + int nlevs_model = m_model_grid->get_num_vertical_levels(); + + // Create hremap tgt grid + int nlevs_data = m_fields_have_lev_dim ? get_input_files_dimlen (m_input_files_dimnames[LEV]) : nlevs_model; + int ncols_data = m_fields_have_col_dim ? get_input_files_dimlen (m_input_files_dimnames[COL]) : ncols_model; // Create grid for IO and load lat/lon field in IO grid from any data file auto data_grid = create_point_grid("data",ncols_data,nlevs_data,m_model_grid->get_comm()); @@ -499,13 +518,14 @@ create_vert_remapper (const VertRemapData& data) m_vr_type = data.vr_type; + int model_nlevs = m_model_grid->get_num_vertical_levels(); + if (m_vr_type==VRemapType::None) { // Not much to do. Set up a do-nothing remapper and return using IDR = IdentityRemapper; constexpr auto SAT = IDR::SrcAliasTgt; // If no vert remap is requested, model_grid and grid_after_hremap MUST have same nlevs - int model_nlevs = m_model_grid->get_num_vertical_levels(); int data_nlevs = m_grid_after_hremap->get_num_vertical_levels(); EKAT_REQUIRE_MSG (model_nlevs==data_nlevs, "[DataInterpolation] Error! No vertical remap was requested, but the 'lev' dim from file does not match the model grid one.\n" diff --git a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp index da2a8cbf6afb..ae517d75ab3e 100644 --- a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp +++ b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp @@ -127,11 +127,14 @@ class DataInterpolation TimeDatabase m_time_database; ekat::Comm m_comm; - ekat::ParameterList m_params; bool m_time_db_created = false; bool m_data_initialized = false; + bool m_fields_have_col_dim = false; + bool m_fields_have_lev_dim = false; + bool m_fields_have_ilev_dim = false; + std::shared_ptr m_logger; }; From fb997784be3b9bbe4177fed5432f796848adef62 Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Thu, 8 Jan 2026 15:53:52 -0800 Subject: [PATCH 293/398] initialize variables that need ends filled at first step and do it in iop_data_mod instead of shoehorning it into getinterpnetcdfdata which does not work for all variables --- .../eam/src/control/getinterpnetcdfdata.F90 | 4 --- components/eam/src/control/iop_data_mod.F90 | 25 +++++++++++++++---- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/components/eam/src/control/getinterpnetcdfdata.F90 b/components/eam/src/control/getinterpnetcdfdata.F90 index 3d41b0ca9857..4f7182ec3dab 100644 --- a/components/eam/src/control/getinterpnetcdfdata.F90 +++ b/components/eam/src/control/getinterpnetcdfdata.F90 @@ -76,10 +76,6 @@ subroutine getinterpncdata( NCID, camlat, camlon, TimeIdx, & ! ------- code --------- -! If fill ends is not applied, then initialize all values to zero to -! prevent uninitialized memory for the leves where there is no data. - if (.not. fill_ends) outData(:) = 0.0_r8 - call shr_scam_GetCloseLatLon(ncid,camlat,camlon,closelat,closelon,latidx,lonidx) ! diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index 269901546850..4ae375e66979 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -645,6 +645,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) use error_messages, only : handle_ncerr use netcdf use shr_const_mod, only : SHR_CONST_PI + use time_manager, only : is_first_step !----------------------------------------------------------------------- implicit none #if ( defined RS6000 ) @@ -1036,6 +1037,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q=.true. endif + if ( is_first_step() ) cldobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'cld', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, cldobs, status ) if ( status .ne. nf90_noerr ) then @@ -1044,6 +1046,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_cld = .true. endif + if ( is_first_step() ) clwpobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'clwp', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, clwpobs, status ) if ( status .ne. nf90_noerr ) then @@ -1062,7 +1065,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - divq(:,:) = 0.0_r8 ! Initialize all to zero + if ( is_first_step() ) divq(:,:) = 0.0_r8 ! Initialize all to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1081,7 +1084,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - vertdivq(:,:) = 0.0_r8 ! Initialize all to zero + if (is_first_step() ) vertdivq(:,:) = 0.0_r8 ! Initialize all to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1106,6 +1109,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq3d(:,m), status ) if ( status .ne. nf90_noerr ) then have_cnst(m) = .false. + !divq3d(1:,m)=0._r8 else have_cnst(m) = .true. endif @@ -1131,6 +1135,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('NUMLIQ', inumliq, abrtf=.false.) if ( inumliq > 0 ) then have_srf = .false. + if ( is_first_step() ) numliqobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMLIQ', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numliqobs, status ) if ( status .ne. nf90_noerr ) then @@ -1143,6 +1148,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('CLDLIQ', icldliq) have_srf = .false. + if ( is_first_step() ) cldliqobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDLIQ', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldliqobs, status ) if ( status .ne. nf90_noerr ) then @@ -1153,6 +1159,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('CLDICE', icldice) + if ( is_first_step() ) cldiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1165,6 +1172,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) if ( inumice > 0 ) then have_srf = .false. + if ( is_first_step() ) numiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1184,6 +1192,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + if ( is_first_step() ) divu = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divu', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divu, status ) if ( status .ne. nf90_noerr ) then @@ -1202,6 +1211,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + if ( is_first_step() ) divv = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divv', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divv, status ) if ( status .ne. nf90_noerr ) then @@ -1220,6 +1230,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + if ( is_first_step() ) divt = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'divT', have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt, status ) if ( status .ne. nf90_noerr ) then @@ -1238,6 +1249,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + if ( is_first_step() ) vertdivt = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivT', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivt, status ) if ( status .ne. nf90_noerr ) then @@ -1257,6 +1269,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif + if ( is_first_step() ) divt3d = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divT3d', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt3d, status ) if ( status .ne. nf90_noerr ) then @@ -1296,7 +1309,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) endif ! large scale / geostropic horizontal wind (for nudging) - uls = 0.0_r8 ! Initialize to zer + if ( is_first_step() ) uls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'u_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, uls, status ) if ( status .ne. nf90_noerr ) then @@ -1330,7 +1343,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call shr_sys_flush( iulog ) ! large scale / geostropic meridional wind (for nudging) - vls = 0.0_r8 ! Initialize to zero + if ( is_first_step() ) vls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'v_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, vls, status ) if ( status .ne. nf90_noerr ) then @@ -1353,6 +1366,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_prec = .true. endif + if ( is_first_step() ) q1obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q1', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q1obs, status ) if ( status .ne. nf90_noerr ) then @@ -1361,6 +1375,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q1 = .true. endif + if ( is_first_step() ) q2obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q2', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q2obs, status ) if ( status .ne. nf90_noerr ) then @@ -1434,7 +1449,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_tg = .true. endif - wfld = 0.0_r8 ! Initialize to zero + if ( is_first_step() ) wfld = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'omega', .true., ptend, fill_ends, dplevs, nlev,psobs, hyam, hybm, wfld, status ) if ( status .ne. nf90_noerr ) then From 30a8bcf911b3205bd425bedcc844da6e2fb8f638 Mon Sep 17 00:00:00 2001 From: Dalei Hao Date: Wed, 19 Jun 2024 13:09:23 -0700 Subject: [PATCH 294/398] add finetop debug & define cosinc_col add model outputs; & modify surface area correction for longwave radiation & debug correct surface area for thermal radiation for soilT module update snowsnicar_AD model change COSINC output name to avoid duplicate fix a small bug in variable name fix small bugs debug debug fix bugs set SZA<85 limit fix small bugs fix one bug and add initialization for few variables fix small bugs delete log output and add control to adjust albedo delete log output delete write output add more outputs like MODIS daytime and nighttime ST debug fix a small bug add MODIS FSNO output fix a bug clean up the code in biogeophys clean up the code in main clean up the code fix urban bug add code to calculate apparent surface albedo for EAM fix a small bug debug debug & modify code to not change for urban landunits debug fix typo debug consider the top effects on upward radaiton to sky debug Conflicts: components/elm/src/biogeophys/SoilFluxesMod.F90 components/elm/src/biogeophys/SurfaceAlbedoMod.F90 components/elm/src/main/atm2lndType.F90 components/elm/src/main/elm_initializeMod.F90 fix a LAI bug delete ; debug & add test add restart variables fix a bug debug debug restart issues remove log output --- cime_config/tests.py | 1 + .../bld/namelist_files/namelist_defaults.xml | 3 + .../namelist_files/namelist_definition.xml | 7 + .../elm/finetop_rad/shell_commands | 10 + .../testmods_dirs/elm/finetop_rad/user_nl_elm | 3 + .../elm/snowveg_arctic/shell_commands | 2 +- .../elm/src/biogeophys/CanopyFluxesMod.F90 | 39 ++-- .../elm/src/biogeophys/CanopyHydrologyMod.F90 | 4 +- .../src/biogeophys/CanopyTemperatureMod.F90 | 14 +- .../elm/src/biogeophys/SnowSnicarMod.F90 | 12 +- .../elm/src/biogeophys/SoilFluxesMod.F90 | 53 ++++-- .../elm/src/biogeophys/SoilTemperatureMod.F90 | 20 +- .../elm/src/biogeophys/SolarAbsorbedType.F90 | 36 +++- .../elm/src/biogeophys/SurfaceAlbedoMod.F90 | 112 ++++++++---- .../elm/src/biogeophys/SurfaceAlbedoType.F90 | 16 +- .../src/biogeophys/SurfaceRadiationMod.F90 | 38 ++-- .../elm/src/biogeophys/UrbanRadiationMod.F90 | 17 +- components/elm/src/cpl/lnd_comp_mct.F90 | 19 +- components/elm/src/cpl/lnd_import_export.F90 | 19 +- .../elm/src/data_types/GridcellType.F90 | 20 +- .../elm/src/data_types/TopounitDataType.F90 | 12 ++ components/elm/src/main/atm2lndMod.F90 | 171 +++++++++++++++++- components/elm/src/main/atm2lndType.F90 | 99 +++++++++- components/elm/src/main/controlMod.F90 | 16 +- components/elm/src/main/elm_driver.F90 | 9 +- components/elm/src/main/elm_initializeMod.F90 | 25 ++- components/elm/src/main/elm_varctl.F90 | 3 +- components/elm/src/main/elm_varpar.F90 | 2 + components/elm/src/main/lnd2atmMod.F90 | 95 +++++++++- components/elm/src/main/lnd2atmType.F90 | 28 ++- components/elm/src/main/surfrdMod.F90 | 106 +++++++++++ share/util/shr_orb_mod.F90 | 37 ++++ 32 files changed, 924 insertions(+), 124 deletions(-) create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/shell_commands create mode 100644 components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/user_nl_elm diff --git a/cime_config/tests.py b/cime_config/tests.py index 42ec768e8b76..8cc3ba0e7d8a 100644 --- a/cime_config/tests.py +++ b/cime_config/tests.py @@ -103,6 +103,7 @@ "ERS.r05_r05.IELM.elm-lnd_rof_2way", "ERS.r05_r05.IELM.elm-V2_ELM_MOSART_features", "ERS.ELM_USRDAT.IELM.elm-surface_water_dynamics", + "ERS.ELM_USRDAT.IELM.elm-finetop_rad" ) }, diff --git a/components/elm/bld/namelist_files/namelist_defaults.xml b/components/elm/bld/namelist_files/namelist_defaults.xml index bbd68b2c0843..aebc38a9c978 100644 --- a/components/elm/bld/namelist_files/namelist_defaults.xml +++ b/components/elm/bld/namelist_files/namelist_defaults.xml @@ -661,6 +661,9 @@ this mask will have smb calculated over the entire global land surface .false. + +.false. + lnd/clm2/snicardata/snicar_optics_5bnd_mam_c160322.nc diff --git a/components/elm/bld/namelist_files/namelist_definition.xml b/components/elm/bld/namelist_files/namelist_definition.xml index fddc5cbbc8bf..89bef37719a2 100644 --- a/components/elm/bld/namelist_files/namelist_definition.xml +++ b/components/elm/bld/namelist_files/namelist_definition.xml @@ -760,6 +760,13 @@ If TRUE, TOP solar radiation parameterization will be activated, which considers + + +If TRUE, fineTOP radiation parameterization will be activated, which considers the effects of fine(grid)-scale topography. + + + diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/shell_commands new file mode 100644 index 000000000000..f27bbc407386 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/shell_commands @@ -0,0 +1,10 @@ +./xmlchange DATM_MODE=CLMMOSARTTEST + +./xmlchange LND_DOMAIN_FILE=domain.lnd.1km_SierraNevada.c240628.nc +./xmlchange ATM_DOMAIN_FILE=domain.lnd.1km_SierraNevada.c240628.nc +./xmlchange LND_DOMAIN_PATH="\$DIN_LOC_ROOT/share/domains/domain.clm" +./xmlchange ATM_DOMAIN_PATH="\$DIN_LOC_ROOT/share/domains/domain.clm" + +./xmlchange -file env_run.xml -id DATM_CLMNCEP_YR_END -val 2000 +./xmlchange -file env_run.xml -id DATM_CLMNCEP_YR_START -val 2000 +./xmlchange -file env_run.xml -id DATM_CLMNCEP_YR_ALIGN -val 1 \ No newline at end of file diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/user_nl_elm b/components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/user_nl_elm new file mode 100644 index 000000000000..f91db8e1da33 --- /dev/null +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/finetop_rad/user_nl_elm @@ -0,0 +1,3 @@ +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/surfdata_1km_SierraNevada_simyr2010_c240628.nc' +use_finetop_rad = .true. +use_top_solar_rad = .false. diff --git a/components/elm/cime_config/testdefs/testmods_dirs/elm/snowveg_arctic/shell_commands b/components/elm/cime_config/testdefs/testmods_dirs/elm/snowveg_arctic/shell_commands index 396d8cea8d66..4b467e35f9ac 100644 --- a/components/elm/cime_config/testdefs/testmods_dirs/elm/snowveg_arctic/shell_commands +++ b/components/elm/cime_config/testdefs/testmods_dirs/elm/snowveg_arctic/shell_commands @@ -7,4 +7,4 @@ ./xmlchange DATM_CLMNCEP_YR_END=2000 ./xmlchange ELM_USRDAT_NAME=42_FLUXNETSITES ./xmlchange NTASKS=1 -./xmlchange NTHRDS=1 +./xmlchange NTHRDS=1 \ No newline at end of file diff --git a/components/elm/src/biogeophys/CanopyFluxesMod.F90 b/components/elm/src/biogeophys/CanopyFluxesMod.F90 index 47d4558990f9..1c278c75ce97 100644 --- a/components/elm/src/biogeophys/CanopyFluxesMod.F90 +++ b/components/elm/src/biogeophys/CanopyFluxesMod.F90 @@ -14,7 +14,7 @@ module CanopyFluxesMod use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun use elm_varctl , only : iulog, use_cn, use_lch4, use_c13, use_c14, use_fates - use elm_varctl , only : use_hydrstress + use elm_varctl , only : use_hydrstress, use_finetop_rad use elm_varpar , only : nlevgrnd, nlevsno use elm_varcon , only : namep use elm_varcon , only : mm_epsilon @@ -100,6 +100,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & use elm_varcon , only : isecspday, degpsec use pftvarcon , only : irrigated use elm_varcon , only : c14ratio + use shr_const_mod , only : SHR_CONST_PI !NEW use elm_varsur , only : firrig @@ -314,7 +315,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & real(r8) :: tau_diff(bounds%begp:bounds%endp) ! Difference from previous iteration tau real(r8) :: prev_tau(bounds%begp:bounds%endp) ! Previous iteration tau real(r8) :: prev_tau_diff(bounds%begp:bounds%endp) ! Previous difference in iteration tau - + real(r8) :: slope_rad, deg2rad character(len=64) :: event !! timing event ! Indices for raw and rah @@ -329,6 +330,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & snl => col_pp%snl , & ! Input: [integer (:) ] number of snow layers dayl => grc_pp%dayl , & ! Input: [real(r8) (:) ] daylength (s) max_dayl => grc_pp%max_dayl , & ! Input: [real(r8) (:) ] maximum daylength for this grid cell (s) + slope_deg => grc_pp%slope_deg , & forc_lwrad => top_af%lwrad , & ! Input: [real(r8) (:) ] downward infrared (longwave) radiation (W/m**2) forc_q => top_as%qbot , & ! Input: [real(r8) (:) ] atmospheric specific humidity (kg/kg) @@ -516,7 +518,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & end if #endif - + deg2rad = SHR_CONST_PI/180._r8 ! Initialize do f = 1, fn p = filterp(f) @@ -701,6 +703,11 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & bir(p) = - (2._r8-emv(p)*(1._r8-emg(c))) * emv(p) * sb cir(p) = emv(p)*emg(c)*sb + if (use_finetop_rad) then + slope_rad = slope_deg(g) * deg2rad + bir(p) = bir(p) / cos(slope_rad) + cir(p) = cir(p) / cos(slope_rad) + endif ! Saturated vapor pressure, specific humidity, and their derivatives ! at the leaf surface @@ -1269,15 +1276,25 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, & ! Downward longwave radiation below the canopy - dlrad(p) = (1._r8-emv(p))*emg(c)*forc_lwrad(t) + & - emv(p)*emg(c)*sb*tlbef(p)**3*(tlbef(p) + 4._r8*dt_veg(p)) - + if (use_finetop_rad) then + slope_rad = slope_deg(g) * deg2rad + dlrad(p) = (1._r8-emv(p))*emg(c)*forc_lwrad(t) + & + emv(p)*emg(c)*sb*tlbef(p)**3*(tlbef(p) + 4._r8*dt_veg(p))/cos(slope_rad) + else + dlrad(p) = (1._r8-emv(p))*emg(c)*forc_lwrad(t) + & + emv(p)*emg(c)*sb*tlbef(p)**3*(tlbef(p) + 4._r8*dt_veg(p)) + endif ! Upward longwave radiation above the canopy - - ulrad(p) = ((1._r8-emg(c))*(1._r8-emv(p))*(1._r8-emv(p))*forc_lwrad(t) & - + emv(p)*(1._r8+(1._r8-emg(c))*(1._r8-emv(p)))*sb*tlbef(p)**3*(tlbef(p) + & - 4._r8*dt_veg(p)) + emg(c)*(1._r8-emv(p))*sb*lw_grnd) - + if (use_finetop_rad) then + slope_rad = slope_deg(g) * deg2rad + ulrad(p) = ((1._r8-emg(c))*(1._r8-emv(p))*(1._r8-emv(p))*forc_lwrad(t) & + + emv(p)*(1._r8+(1._r8-emg(c))*(1._r8-emv(p)))*sb*tlbef(p)**3*(tlbef(p) + & + 4._r8*dt_veg(p))/cos(slope_rad) + emg(c)*(1._r8-emv(p))*sb*lw_grnd/cos(slope_rad)) + else + ulrad(p) = ((1._r8-emg(c))*(1._r8-emv(p))*(1._r8-emv(p))*forc_lwrad(t) & + + emv(p)*(1._r8+(1._r8-emg(c))*(1._r8-emv(p)))*sb*tlbef(p)**3*(tlbef(p) + & + 4._r8*dt_veg(p)) + emg(c)*(1._r8-emv(p))*sb*lw_grnd) + endif ! Derivative of soil energy flux with respect to soil temperature cgrnds(p) = cgrnds(p) + cpair*forc_rho(t)*wtg(p)*wtal(p) diff --git a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 index 4a2cd4a5fd7a..3d2751f88cd9 100644 --- a/components/elm/src/biogeophys/CanopyHydrologyMod.F90 +++ b/components/elm/src/biogeophys/CanopyHydrologyMod.F90 @@ -29,7 +29,7 @@ module CanopyHydrologyMod use elm_varcon , only : snw_rds_min use pftvarcon , only : irrigated use GridcellType , only : grc_pp - use timeinfoMod, only : dtime_mod + use timeinfoMod , only : dtime_mod ! ! !PUBLIC TYPES: implicit none @@ -713,7 +713,7 @@ subroutine CanopyHydrology(bounds, & call FracH2oSfc(bounds, num_nolakec, filter_nolakec, & col_wf%qflx_h2osfc2topsoi, dtime) - end associate + end associate end subroutine CanopyHydrology diff --git a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 index 63083feb42f9..808d69af92c2 100644 --- a/components/elm/src/biogeophys/CanopyTemperatureMod.F90 +++ b/components/elm/src/biogeophys/CanopyTemperatureMod.F90 @@ -13,7 +13,7 @@ module CanopyTemperatureMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_const_mod , only : SHR_CONST_PI use decompMod , only : bounds_type - use elm_varctl , only : iulog, use_fates + use elm_varctl , only : iulog, use_fates, use_finetop_rad use PhotosynthesisMod , only : Photosynthesis, PhotosynthesisTotal, Fractionation use elm_instMod , only : alm_fates use SurfaceResistanceMod , only : calc_soilevap_stress @@ -29,6 +29,7 @@ module CanopyTemperatureMod use ColumnDataType , only : col_es, col_ef, col_ws use VegetationType , only : veg_pp use VegetationDataType , only : veg_es, veg_ef, veg_wf + use GridcellType , only : grc_pp ! ! !PUBLIC TYPES: implicit none @@ -74,6 +75,7 @@ subroutine CanopyTemperature(bounds, & use column_varcon , only : icol_road_imperv, icol_road_perv use landunit_varcon , only : istice, istice_mec, istwet, istsoil, istdlak, istcrop, istdlak use elm_varpar , only : nlevgrnd, nlevurb, nlevsno, nlevsoi + use shr_const_mod , only : SHR_CONST_PI ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -109,6 +111,7 @@ subroutine CanopyTemperature(bounds, & real(r8) :: vol_ice ! partial volume of ice lens in layer real(r8) :: vol_liq ! partial volume of liquid water in layer real(r8) :: fh2o_eff(bounds%begc:bounds%endc) ! effective surface water fraction (i.e. seen by atm) + real(r8) :: slope_rad, deg2rad !------------------------------------------------------------------------------ associate( & @@ -200,6 +203,7 @@ subroutine CanopyTemperature(bounds, & tssbef => col_es%t_ssbef & ! Output: [real(r8) (:,:) ] soil/snow temperature before update (K) ) + deg2rad = SHR_CONST_PI/180._r8 do j = -nlevsno+1, nlevgrnd do fc = 1,num_nolakec c = filter_nolakec(fc) @@ -409,6 +413,7 @@ subroutine CanopyTemperature(bounds, & do fp = 1,num_nolakep p = filter_nolakep(fp) + g = veg_pp%gridcell(p) ! Initial set (needed for history tape fields) @@ -440,7 +445,12 @@ subroutine CanopyTemperature(bounds, & ! Vegetation Emissivity avmuir = 1._r8 - emv(p) = 1._r8-exp(-(elai(p)+esai(p))/avmuir) + if (use_finetop_rad .and. (.not. lun_pp%urbpoi(l))) then + slope_rad = grc_pp%slope_deg(g) * deg2rad + emv(p) = 1._r8-exp(-(elai(p)+esai(p))*cos(slope_rad)/avmuir) + else + emv(p) = 1._r8-exp(-(elai(p)+esai(p))/avmuir) + endif z0mv(p) = z0m(p) z0hv(p) = z0mv(p) diff --git a/components/elm/src/biogeophys/SnowSnicarMod.F90 b/components/elm/src/biogeophys/SnowSnicarMod.F90 index de161c1d4c9d..61397261e496 100644 --- a/components/elm/src/biogeophys/SnowSnicarMod.F90 +++ b/components/elm/src/biogeophys/SnowSnicarMod.F90 @@ -1812,7 +1812,7 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & use elm_varpar , only : nlevsno, numrad use elm_time_manager , only : get_nstep use shr_const_mod , only : SHR_CONST_PI - use elm_varctl , only : snow_shape, snicar_atm_type, use_dust_snow_internal_mixing + use elm_varctl , only : snow_shape, snicar_atm_type, use_dust_snow_internal_mixing, use_finetop_rad ! ! !ARGUMENTS: integer , intent(in) :: flg_snw_ice ! flag: =1 when called from CLM, =2 when called from CSIM @@ -1868,6 +1868,7 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & !integer :: trip ! flag: =1 to redo RT calculation if result is unrealistic !integer :: flg_dover ! defines conditions for RT redo (explained below) + real(r8):: slope_rad, deg2rad real(r8):: albedo ! temporary snow albedo [frc] real(r8):: flx_sum ! temporary summation variable for NIR weighting real(r8):: albout_lcl(numrad_snw) ! snow albedo by band [frc] @@ -2140,6 +2141,7 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & ! Define constants pi = SHR_CONST_PI nint_snw_rds_min = nint(snw_rds_min) + deg2rad = SHR_CONST_PI/180._r8 ! always use Delta approximation for snow DELTA = 1 @@ -2202,6 +2204,7 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & ! (when called from CSIM, there is only one column) do fc = 1,num_nourbanc c_idx = filter_nourbanc(fc) + g_idx = col_pp%gridcell(c_idx) ! Zero absorbed radiative fluxes: do i=-nlevsno+1,1,1 @@ -2266,6 +2269,13 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & lon_coord = 0 endif ! end if flg_snw_ice == 1 + if (use_finetop_rad) then + slope_rad = grc_pp%slope_deg(g_idx) * deg2rad + h2osno_liq_lcl = h2osno_liq_lcl * cos(slope_rad) + h2osno_ice_lcl = h2osno_ice_lcl * cos(slope_rad) + h2osno_lcl = h2osno_lcl * cos(slope_rad) + endif + #ifdef MODAL_AER !mgf++ ! diff --git a/components/elm/src/biogeophys/SoilFluxesMod.F90 b/components/elm/src/biogeophys/SoilFluxesMod.F90 index f18ead86f1e2..f3f3df8a9db8 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_firn_percolation_and_compaction + use elm_varctl , only : iulog, use_firn_percolation_and_compaction, use_finetop_rad use perfMod_GPU use elm_varpar , only : nlevsno, nlevgrnd, nlevurb, max_patch_per_col use atm2lndType , only : atm2lnd_type @@ -21,6 +21,7 @@ module SoilFluxesMod use ColumnDataType , only : col_es, col_ef, col_ws use VegetationType , only : veg_pp use VegetationDataType, only : veg_ef, veg_wf + use GridcellType , only : grc_pp use timeinfoMod , only : dtime_mod ! @@ -49,6 +50,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & use landunit_varcon , only : istsoil, istcrop use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, icol_road_perv use subgridAveMod , only : p2c + use shr_const_mod , only : SHR_CONST_PI ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -63,7 +65,7 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & type(canopystate_type) , intent(in) :: canopystate_vars type(energyflux_type) , intent(inout) :: energyflux_vars real(r8) :: dtime ! land model time step (sec) - + real(r8) :: slope_rad, deg2rad ! ! !LOCAL VARIABLES: @@ -159,10 +161,13 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & eflx_lh_vege => veg_ef%eflx_lh_vege , & ! Output: [real(r8) (:) ] veg evaporation heat flux (W/m**2) [+ to atm] eflx_lh_vegt => veg_ef%eflx_lh_vegt , & ! Output: [real(r8) (:) ] veg transpiration heat flux (W/m**2) [+ to atm] eflx_lh_grnd => veg_ef%eflx_lh_grnd , & ! Output: [real(r8) (:) ] ground evaporation heat flux (W/m**2) [+ to atm] - errsoi_col => col_ef%errsoi , & ! Output: [real(r8) (:) ] column-level soil/lake energy conservation error (W/m**2) - errsoi_patch => veg_ef%errsoi & ! Output: [real(r8) (:) ] pft-level soil/lake energy conservation error (W/m**2) + errsoi_col => col_ef%errsoi , & ! Output: [real(r8) (:) ] column-level soil/lake energy conservation error (W/m**2) + errsoi_patch => veg_ef%errsoi , & ! Output: [real(r8) (:) ] pft-level soil/lake energy conservation error (W/m**2) + slope_deg => grc_pp%slope_deg & ) + deg2rad = SHR_CONST_PI/180._r8 + dtime = dtime_mod event = 'bgp2_loop_1' call t_start_lnd(event) @@ -282,11 +287,19 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & lw_grnd=(frac_sno_eff(c)*tssbef(c,col_pp%snl(c)+1)**4 & +(1._r8-frac_sno_eff(c)-frac_h2osfc(c))*tssbef(c,1)**4 & +frac_h2osfc(c)*t_h2osfc_bef(c)**4) - - eflx_soil_grnd(p) = ((1._r8- frac_sno_eff(c))*sabg_soil(p) + frac_sno_eff(c)*sabg_snow(p)) + dlrad(p) & - + (1-frac_veg_nosno(p))*emg(c)*forc_lwrad(t) & - - emg(c)*sb*lw_grnd - emg(c)*sb*t_grnd0(c)**3*(4._r8*tinc(c)) & - - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) + + if (use_finetop_rad) then + slope_rad = slope_deg(g) * deg2rad + eflx_soil_grnd(p) = ((1._r8- frac_sno_eff(c))*sabg_soil(p) + frac_sno_eff(c)*sabg_snow(p)) + dlrad(p) & + + (1-frac_veg_nosno(p))*emg(c)*forc_lwrad(t) & + - emg(c)*sb*lw_grnd/cos(slope_rad)- emg(c)*sb*t_grnd0(c)**3*(4._r8*tinc(c))/cos(slope_rad) & + - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) + else + eflx_soil_grnd(p) = ((1._r8- frac_sno_eff(c))*sabg_soil(p) + frac_sno_eff(c)*sabg_snow(p)) + dlrad(p) & + + (1-frac_veg_nosno(p))*emg(c)*forc_lwrad(t) & + - emg(c)*sb*lw_grnd - emg(c)*sb*t_grnd0(c)**3*(4._r8*tinc(c)) & + - (eflx_sh_grnd(p)+qflx_evap_soi(p)*htvp(c)) + endif if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then eflx_soil_grnd_r(p) = eflx_soil_grnd(p) @@ -301,9 +314,9 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & ! Include transpiration term because needed for pervious road ! and wasteheat and traffic flux eflx_soil_grnd(p) = sabg(p) + dlrad(p) & - - eflx_lwrad_net(p) - eflx_lwrad_del(p) & - - (eflx_sh_grnd(p) + qflx_evap_soi(p)*htvp(c) + qflx_tran_veg(p)*hvap) & - + eflx_wasteheat_patch(p) + eflx_heat_from_ac_patch(p) + eflx_traffic_patch(p) + - eflx_lwrad_net(p) - eflx_lwrad_del(p) & + - (eflx_sh_grnd(p) + qflx_evap_soi(p)*htvp(c) + qflx_tran_veg(p)*hvap) & + + eflx_wasteheat_patch(p) + eflx_heat_from_ac_patch(p) + eflx_traffic_patch(p) eflx_soil_grnd_u(p) = eflx_soil_grnd(p) end if @@ -426,10 +439,18 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & +(1._r8-frac_sno_eff(c)-frac_h2osfc(c))*tssbef(c,1)**4 & +frac_h2osfc(c)*t_h2osfc_bef(c)**4) - eflx_lwrad_out(p) = ulrad(p) & - + (1-frac_veg_nosno(p))*(1.-emg(c))*forc_lwrad(t) & - + (1-frac_veg_nosno(p))*emg(c)*sb*lw_grnd & - + 4._r8*emg(c)*sb*t_grnd0(c)**3*tinc(c) + if (use_finetop_rad) then + slope_rad = slope_deg(g) * deg2rad + eflx_lwrad_out(p) = ulrad(p) & + + (1-frac_veg_nosno(p))*(1.-emg(c))*forc_lwrad(t) & + + (1-frac_veg_nosno(p))*emg(c)*sb*lw_grnd / cos(slope_rad) & + + 4._r8*emg(c)*sb*t_grnd0(c)**3*tinc(c) / cos(slope_rad) + else + eflx_lwrad_out(p) = ulrad(p) & + + (1-frac_veg_nosno(p))*(1.-emg(c))*forc_lwrad(t) & + + (1-frac_veg_nosno(p))*emg(c)*sb*lw_grnd & + + 4._r8*emg(c)*sb*t_grnd0(c)**3*tinc(c) + endif eflx_lwrad_net(p) = eflx_lwrad_out(p) - forc_lwrad(t) if (veg_pp%is_on_soil_col(p) .or. veg_pp%is_on_crop_col(p)) then diff --git a/components/elm/src/biogeophys/SoilTemperatureMod.F90 b/components/elm/src/biogeophys/SoilTemperatureMod.F90 index 37878d4e77ab..27a7206b6b7e 100644 --- a/components/elm/src/biogeophys/SoilTemperatureMod.F90 +++ b/components/elm/src/biogeophys/SoilTemperatureMod.F90 @@ -12,7 +12,7 @@ module SoilTemperatureMod use shr_infnan_mod , only : nan => shr_infnan_nan use decompMod , only : bounds_type use abortutils , only : endrun - use elm_varctl , only : iulog + use elm_varctl , only : iulog, use_finetop_rad use elm_varcon , only : spval use UrbanParamsType , only : urbanparams_type use atm2lndType , only : atm2lnd_type @@ -32,6 +32,8 @@ module SoilTemperatureMod use ExternalModelConstants , only : EM_ID_PTM use ExternalModelConstants , only : EM_PTM_TBASED_SOLVE_STAGE use ExternalModelInterfaceMod, only : EMI_Driver + use shr_const_mod , only : SHR_CONST_PI + use GridcellType , only : grc_pp !! Needed beacuse EMI is still using them as arguments use WaterstateType , only : waterstate_type @@ -1750,6 +1752,7 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & real(r8) :: eflx_gnet_snow ! real(r8) :: eflx_gnet_soil ! real(r8) :: eflx_gnet_h2osfc ! + real(r8) :: slope_rad, deg2rad !----------------------------------------------------------------------- ! Enforce expected array sizes @@ -1800,7 +1803,8 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & sabg_lyr => solarabs_vars%sabg_lyr_patch , & ! Output: [real(r8) (:,:) ] absorbed solar radiation (pft,lyr) [W/m2] begc => bounds%begc , & ! Input: [integer ] beginning column index - endc => bounds%endc & ! Input: [integer ] ending column index + endc => bounds%endc , & ! Input: [integer ] ending column index + slope_deg => grc_pp%slope_deg & ) ! Net ground heat flux into the surface and its temperature derivative @@ -1809,6 +1813,8 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & do fc = 1,num_nolakec c = filter_nolakec(fc) + g = col_pp%gridcell(c) + l = col_pp%landunit(c) lwrad_emit(c) = emg(c) * sb * t_grnd(c)**4 dlwrad_emit(c) = 4._r8*emg(c) * sb * t_grnd(c)**3 @@ -1816,6 +1822,16 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & lwrad_emit_snow(c) = emg(c) * sb * t_soisno(c,snl(c)+1)**4 lwrad_emit_soil(c) = emg(c) * sb * t_soisno(c,1)**4 lwrad_emit_h2osfc(c) = emg(c) * sb * t_h2osfc(c)**4 + + if (use_finetop_rad .and. (.not. lun_pp%urbpoi(l))) then + deg2rad = SHR_CONST_PI/180._r8 + slope_rad = slope_deg(g) * deg2rad + lwrad_emit(c) = lwrad_emit(c) / cos(slope_rad) + dlwrad_emit(c) = dlwrad_emit(c) / cos(slope_rad) + lwrad_emit_snow(c) = lwrad_emit_snow(c) / cos(slope_rad) + lwrad_emit_soil(c) = lwrad_emit_soil(c) / cos(slope_rad) + lwrad_emit_h2osfc(c) = lwrad_emit_h2osfc(c) / cos(slope_rad) + endif end do hs_soil(begc:endc) = 0._r8 diff --git a/components/elm/src/biogeophys/SolarAbsorbedType.F90 b/components/elm/src/biogeophys/SolarAbsorbedType.F90 index 75e985b858cd..03f26403401d 100644 --- a/components/elm/src/biogeophys/SolarAbsorbedType.F90 +++ b/components/elm/src/biogeophys/SolarAbsorbedType.F90 @@ -54,6 +54,8 @@ module SolarAbsorbedType real(r8), pointer :: fsr_nir_d_patch (:) => null() ! patch reflected direct beam nir solar radiation (W/m**2) real(r8), pointer :: fsr_nir_i_patch (:) => null() ! patch reflected diffuse nir solar radiation (W/m**2) real(r8), pointer :: fsr_nir_d_ln_patch (:) => null() ! patch reflected direct beam nir solar radiation at local noon (W/m**2) + real(r8), pointer :: fsr_vis_d_patch (:) => null() ! patch reflected direct beam vis solar radiation (W/m**2) + real(r8), pointer :: fsr_vis_i_patch (:) => null() ! patch reflected diffuse vis solar radiation (W/m**2) contains @@ -131,6 +133,8 @@ subroutine InitAllocate(this, bounds) allocate(this%fsds_nir_d_patch (begp:endp)) ; this%fsds_nir_d_patch (:) = spval allocate(this%fsds_nir_i_patch (begp:endp)) ; this%fsds_nir_i_patch (:) = spval allocate(this%fsds_nir_d_ln_patch (begp:endp)) ; this%fsds_nir_d_ln_patch (:) = spval + allocate(this%fsr_vis_d_patch (begp:endp)) ; this%fsr_vis_d_patch (:) = spval + allocate(this%fsr_vis_i_patch (begp:endp)) ; this%fsr_vis_i_patch (:) = spval end subroutine InitAllocate @@ -256,9 +260,11 @@ subroutine InitCold(this, bounds) ! ! !LOCAL VARIABLES: integer :: begl, endl + integer :: begp, endp !----------------------------------------------------------------------- - + begl = bounds%begl; endl = bounds%endl + begp = bounds%begp; endp= bounds%endp this%sabs_roof_dir_lun (begl:endl, :) = 0._r8 this%sabs_roof_dif_lun (begl:endl, :) = 0._r8 @@ -270,6 +276,10 @@ subroutine InitCold(this, bounds) this%sabs_improad_dif_lun (begl:endl, :) = 0._r8 this%sabs_perroad_dir_lun (begl:endl, :) = 0._r8 this%sabs_perroad_dif_lun (begl:endl, :) = 0._r8 + this%fsr_nir_d_patch (begp:endp) = 0._r8 + this%fsr_nir_i_patch (begp:endp) = 0._r8 + this%fsr_vis_d_patch (begp:endp) = 0._r8 + this%fsr_vis_i_patch (begp:endp) = 0._r8 end subroutine InitCold @@ -281,7 +291,7 @@ subroutine Restart(this, bounds, ncid, flag) ! ! !USES: use shr_infnan_mod , only : shr_infnan_isnan - use elm_varctl , only : use_snicar_frc, iulog + use elm_varctl , only : use_snicar_frc, iulog, use_finetop_rad use spmdMod , only : masterproc use abortutils , only : endrun use ncdio_pio , only : file_desc_t, ncd_defvar, ncd_io, ncd_double, ncd_int, ncd_inqvdlen @@ -347,6 +357,28 @@ subroutine Restart(this, bounds, ncid, flag) dim2name='numrad', switchdim=.true., & long_name='diffuse solar absorbed by pervious road per unit ground area per unit incident flux', units='', & interpinic_flag='interp', readvar=readvar, data=this%sabs_perroad_dif_lun) + + if (use_finetop_rad) then + call restartvar(ncid=ncid, flag=flag, varname='fsr_nir_d', xtype=ncd_double, & + dim1name='pft', & + long_name='direct nir reflected solar radiation', units='W/m^2', & + interpinic_flag='interp', readvar=readvar, data=this%fsr_nir_d_patch) + + call restartvar(ncid=ncid, flag=flag, varname='fsr_nir_i', xtype=ncd_double, & + dim1name='pft', & + long_name='diffuse nir reflected solar radiation', units='W/m^2', & + interpinic_flag='interp', readvar=readvar, data=this%fsr_nir_i_patch) + + call restartvar(ncid=ncid, flag=flag, varname='fsr_vis_d', xtype=ncd_double, & + dim1name='pft', & + long_name='direct vis reflected solar radiation', units='W/m^2', & + interpinic_flag='interp', readvar=readvar, data=this%fsr_vis_d_patch) + + call restartvar(ncid=ncid, flag=flag, varname='fsr_vis_i', xtype=ncd_double, & + dim1name='pft', & + long_name='diffuse vis reflected solar radiation', units='W/m^2', & + interpinic_flag='interp', readvar=readvar, data=this%fsr_vis_i_patch) + end if end subroutine Restart diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index 9bcf1e4df24e..acc652a319be 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -14,7 +14,7 @@ module SurfaceAlbedoMod use landunit_varcon , only : istsoil, istcrop, istdlak use elm_varcon , only : grlnd, namep, namet use elm_varpar , only : numrad, nlevcan, nlevsno, nlevcan - use elm_varctl , only : fsurdat, iulog, subgridflag, use_snicar_frc, use_fates, use_snicar_ad, use_top_solar_rad + use elm_varctl , only : fsurdat, iulog, subgridflag, use_snicar_frc, use_fates, use_snicar_ad, use_top_solar_rad, use_finetop_rad use VegetationPropertiesType , only : veg_vp use SnowSnicarMod , only : sno_nbr_aer, SNICAR_RT, SNICAR_AD_RT, DO_SNO_AER, DO_SNO_OC use AerosolType , only : aerosol_type @@ -93,6 +93,7 @@ subroutine SurfaceAlbedo(bounds, & !$acc routine seq use elm_varctl , only : iulog, subgridflag, use_snicar_frc, use_fates, use_snicar_ad, use_top_solar_rad use shr_orb_mod + use shr_const_mod , only : SHR_CONST_PI ! ! !ARGUMENTS: @@ -134,8 +135,12 @@ subroutine SurfaceAlbedo(bounds, & real(r8) :: ws (bounds%begp:bounds%endp) ! fraction of LAI+SAI that is SAI real(r8) :: blai(bounds%begp:bounds%endp) ! lai buried by snow: tlai - elai real(r8) :: bsai(bounds%begp:bounds%endp) ! sai buried by snow: tsai - esai + real(r8) :: sza,saa,deg2rad,slope_rad,aspect_rad + real(r8) :: coszen_gcell (bounds%begg:bounds%endg) ! cosine solar zenith angle for next time step (grc) real(r8) :: coszen_patch (bounds%begp:bounds%endp) ! cosine solar zenith angle for next time step (pft) + real(r8) :: cosinc_gcell (bounds%begg:bounds%endg) ! cosine solar incidence angle to local surface for next time step (grc) + real(r8) :: cosinc_patch (bounds%begp:bounds%endp) ! cosine solar incidence angle to local surface for next time step (pft) real(r8) :: rho(bounds%begp:bounds%endp,numrad) ! leaf/stem refl weighted by fraction LAI and SAI real(r8) :: tau(bounds%begp:bounds%endp,numrad) ! leaf/stem tran weighted by fraction LAI and SAI real(r8) :: albsfc (bounds%begc:bounds%endc,numrad) ! albedo of surface underneath snow (col,bnd) @@ -198,6 +203,7 @@ subroutine SurfaceAlbedo(bounds, & ncan => surfalb_vars%ncan_patch , & ! Output: [integer (:) ] number of canopy layers nrad => surfalb_vars%nrad_patch , & ! Output: [integer (:) ] number of canopy layers, above snow for radiative transfer coszen_col => surfalb_vars%coszen_col , & ! Output: [real(r8) (:) ] cosine of solar zenith angle + cosinc_col => surfalb_vars%cosinc_col , & ! Output: [real(r8) (:) ] cosine of solar zenith angle albgrd => surfalb_vars%albgrd_col , & ! Output: [real(r8) (:,:) ] ground albedo (direct) albgri => surfalb_vars%albgri_col , & ! Output: [real(r8) (:,:) ] ground albedo (diffuse) albsod => surfalb_vars%albsod_col , & ! Output: [real(r8) (:,:) ] direct-beam soil albedo (col,bnd) [frc] @@ -235,17 +241,38 @@ subroutine SurfaceAlbedo(bounds, & ! Cosine solar zenith angle for next time step + deg2rad = SHR_CONST_PI/180._r8 do g = bounds%begg,bounds%endg coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1) + + if (use_finetop_rad) then + ! solar zenith angle + sza = acos(coszen_gcell(g)) + ! solar azimuth angle + saa = shr_orb_azimuth(nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1, sza) + + slope_rad = grc_pp%slope_deg(g) * deg2rad + aspect_rad = grc_pp%aspect_deg(g) * deg2rad + + cosinc_gcell(g) = cos(slope_rad) * coszen_gcell(g) + sin(slope_rad) * sin(sza) * cos(aspect_rad - saa) + cosinc_gcell(g) = max(-1._r8, min(cosinc_gcell(g), 1._r8)) + !write(iulog,*) 'cosinc_gcell',cosinc_gcell(g) + !write(iulog,*) 'coszen_gcell',coszen_gcell(g) + if (cosinc_gcell(g) <= 0._r8) cosinc_gcell(g) = 0.1_r8 ! although direct solar radiation is zero, we need to calculate diffuse albedo in this case + else + cosinc_gcell(g) = coszen_gcell(g) + endif end do do c = bounds%begc,bounds%endc g = col_pp%gridcell(c) coszen_col(c) = coszen_gcell(g) + cosinc_col(c) = cosinc_gcell(g) end do do fp = 1,num_nourbanp p = filter_nourbanp(fp) g = veg_pp%gridcell(p) - coszen_patch(p) = coszen_gcell(g) + coszen_patch(p) = coszen_gcell(g) + cosinc_patch(p) = cosinc_gcell(g) end do ! Initialize output because solar radiation only done if coszen > 0 @@ -305,7 +332,7 @@ subroutine SurfaceAlbedo(bounds, & call SoilAlbedo(bounds, & num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & albsnd(bounds%begc:bounds%endc, :), & albsni(bounds%begc:bounds%endc, :), & lakestate_vars, surfalb_vars) @@ -373,7 +400,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 1; ! direct-beam if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -384,7 +411,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -399,7 +426,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 2; ! diffuse if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -410,7 +437,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -435,7 +462,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 1; ! direct-beam if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -446,7 +473,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -460,7 +487,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 2; ! diffuse if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -471,7 +498,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -496,7 +523,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 1; ! direct-beam if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -507,7 +534,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -521,7 +548,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 2; ! diffuse if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -532,7 +559,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -548,7 +575,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 1; ! direct-beam if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -559,7 +586,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -573,7 +600,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 2; ! diffuse if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -584,7 +611,7 @@ subroutine SurfaceAlbedo(bounds, & foo_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -601,7 +628,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 1; ! direct-beam if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -612,7 +639,7 @@ subroutine SurfaceAlbedo(bounds, & flx_absd_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -626,7 +653,7 @@ subroutine SurfaceAlbedo(bounds, & flg_slr = 2; ! diffuse if (use_snicar_ad) then call SNICAR_AD_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -637,7 +664,7 @@ subroutine SurfaceAlbedo(bounds, & flx_absi_snw(bounds%begc:bounds%endc, :, :) ) else call SNICAR_RT(flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & - coszen_col(bounds%begc:bounds%endc), & + cosinc_col(bounds%begc:bounds%endc), & flg_slr, & h2osno_liq(bounds%begc:bounds%endc, :), & h2osno_ice(bounds%begc:bounds%endc, :), & @@ -948,12 +975,11 @@ subroutine SurfaceAlbedo(bounds, & endif call TwoStream (bounds, filter_vegsol, num_vegsol, & - coszen_patch(bounds%begp:bounds%endp), & + cosinc_patch(bounds%begp:bounds%endp), & rho(bounds%begp:bounds%endp, :), & tau(bounds%begp:bounds%endp, :), & canopystate_vars, surfalb_vars, & nextsw_cday, declinp1) - endif ! Determine values for non-vegetated patches where coszen > 0 @@ -981,7 +1007,7 @@ subroutine SurfaceAlbedo(bounds, & coszen_patch(bounds%begp:bounds%endp), declinp1, surfalb_vars, .false.) endif - end associate + end associate end subroutine SurfaceAlbedo @@ -1139,6 +1165,7 @@ subroutine TwoStream(bounds, & use elm_varpar, only : numrad, nlevcan use elm_varcon, only : omegas, tfrz, betads, betais use elm_varctl, only : iulog, use_top_solar_rad + use shr_const_mod , only : SHR_CONST_PI ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -1154,7 +1181,7 @@ subroutine TwoStream(bounds, & ! ! !LOCAL VARIABLES: - integer :: fp,p,c,iv ! array indices + integer :: fp,p,c,iv,g ! array indices integer :: ib ! waveband number real(r8) :: cosz ! 0.001 <= coszen <= 1.000 real(r8) :: asu ! single scattering albedo @@ -1188,6 +1215,9 @@ subroutine TwoStream(bounds, & real(r8) :: laisum ! cumulative lai+sai for canopy layer (at middle of layer) real(r8) :: extkb ! direct beam extinction coefficient real(r8) :: extkn ! nitrogen allocation coefficient + real(r8) :: deg2rad,slope_rad + real(r8) :: elaislope(bounds%begp:bounds%endp) ! elai projected to slope + real(r8) :: esaislope(bounds%begp:bounds%endp) ! esai projected to slope !----------------------------------------------------------------------- ! Enforce expected array sizes @@ -1235,11 +1265,23 @@ subroutine TwoStream(bounds, & ftii => surfalb_vars%ftii_patch & ! Output: [real(r8) (:,:) ] down diffuse flux below canopy per unit diffuse flx ) + deg2rad = SHR_CONST_PI/180._r8 ! Calculate two-stream parameters that are independent of waveband: ! chil, gdir, twostext, avmu, and temp0 and temp2 (used for asu) do fp = 1,num_vegsol p = filter_vegsol(fp) + g = veg_pp%gridcell(p) + + slope_rad = grc_pp%slope_deg(g) * deg2rad + + if (use_finetop_rad) then + elaislope(p) = elai(p) * cos(slope_rad) + esaislope(p) = esai(p) * cos(slope_rad) + else + elaislope(p) = elai(p) + esaislope(p) = esai(p) + endif ! note that the following limit only acts on cosz values > 0 and less than ! 0.001, not on values cosz = 0, since these zero have already been filtered @@ -1344,9 +1386,9 @@ subroutine TwoStream(bounds, & ! Absorbed, reflected, transmitted fluxes per unit incoming radiation ! for full canopy - t1 = min(h*(elai(p)+esai(p)), 40._r8) + t1 = min(h*(elaislope(p)+esaislope(p)), 40._r8) s1 = exp(-t1) - t1 = min(twostext(p)*(elai(p)+esai(p)), 40._r8) + t1 = min(twostext(p)*(elaislope(p)+esaislope(p)), 40._r8) s2 = exp(-t1) ! Direct beam @@ -1469,7 +1511,7 @@ subroutine TwoStream(bounds, & fsun_z(p,1) = (1._r8 - s2) / t1 ! absorbed PAR (per unit sun/shade lai+sai) - laisum = elai(p)+esai(p) + laisum = elaislope(p)+esaislope(p) fabd_sun_z(p,1) = fabd_sun(p,ib) / (fsun_z(p,1)*laisum) fabi_sun_z(p,1) = fabi_sun(p,ib) / (fsun_z(p,1)*laisum) fabd_sha_z(p,1) = fabd_sha(p,ib) / ((1._r8 - fsun_z(p,1))*laisum) @@ -1478,11 +1520,11 @@ subroutine TwoStream(bounds, & ! leaf to canopy scaling coefficients extkn = 0.30_r8 extkb = twostext(p) - vcmaxcintsun(p) = (1._r8 - exp(-(extkn+extkb)*elai(p))) / (extkn + extkb) - vcmaxcintsha(p) = (1._r8 - exp(-extkn*elai(p))) / extkn - vcmaxcintsun(p) - if (elai(p) > 0._r8) then - vcmaxcintsun(p) = vcmaxcintsun(p) / (fsun_z(p,1)*elai(p)) - vcmaxcintsha(p) = vcmaxcintsha(p) / ((1._r8 - fsun_z(p,1))*elai(p)) + vcmaxcintsun(p) = (1._r8 - exp(-(extkn+extkb)*elaislope(p))) / (extkn + extkb) + vcmaxcintsha(p) = (1._r8 - exp(-extkn*elaislope(p))) / extkn - vcmaxcintsun(p) + if (elaislope(p) > 0._r8) then + vcmaxcintsun(p) = vcmaxcintsun(p) / (fsun_z(p,1)*elaislope(p)) + vcmaxcintsha(p) = vcmaxcintsha(p) / ((1._r8 - fsun_z(p,1))*elaislope(p)) else vcmaxcintsun(p) = 0._r8 vcmaxcintsha(p) = 0._r8 diff --git a/components/elm/src/biogeophys/SurfaceAlbedoType.F90 b/components/elm/src/biogeophys/SurfaceAlbedoType.F90 index 10c148df7bff..c57a0efdaf9b 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoType.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoType.F90 @@ -8,7 +8,7 @@ module SurfaceAlbedoType use decompMod , only : bounds_type use elm_varpar , only : numrad, nlevcan, nlevsno use abortutils , only : endrun - use elm_varctl , only : fsurdat, iulog + use elm_varctl , only : fsurdat, iulog, use_finetop_rad use elm_varcon , only : grlnd use ColumnType , only : col_pp @@ -59,6 +59,7 @@ module SurfaceAlbedoType type, public :: surfalb_type real(r8), pointer :: coszen_col (:) => null() ! col cosine of solar zenith angle + real(r8), pointer :: cosinc_col (:) => null() ! col cosine of solar incident angle (local) real(r8), pointer :: albd_patch (:,:) => null() ! patch surface albedo (direct) (numrad) real(r8), pointer :: albi_patch (:,:) => null() ! patch surface albedo (diffuse) (numrad) real(r8), pointer :: albgrd_pur_col (:,:) => null() ! col pure snow ground direct albedo (numrad) @@ -255,6 +256,7 @@ subroutine InitAllocate(this, bounds) begc = bounds%begc; endc = bounds%endc allocate(this%coszen_col (begc:endc)) ; this%coszen_col (:) = spval + allocate(this%cosinc_col (begc:endc)) ; this%cosinc_col (:) = spval allocate(this%albgrd_col (begc:endc,numrad)) ; this%albgrd_col (:,:) =spval allocate(this%albgri_col (begc:endc,numrad)) ; this%albgri_col (:,:) =spval allocate(this%albsnd_hst_col (begc:endc,numrad)) ; this%albsnd_hst_col (:,:) = spval @@ -334,6 +336,11 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='cosine of solar zenith angle', & ptr_col=this%coszen_col, default='inactive') + this%cosinc_col(begc:endc) = spval + call hist_addfld1d (fname='COSINC', units='1', & + avgflag='A', long_name='cosine of solar incident angle (local surface)', & + ptr_col=this%cosinc_col, default='inactive') + this%albgri_col(begc:endc,:) = spval call hist_addfld2d (fname='ALBGRD', units='proportion', type2d='numrad', & avgflag='A', long_name='ground albedo (direct)', & @@ -450,6 +457,13 @@ subroutine Restart(this, bounds, ncid, flag, & long_name='cosine of solar zenith angle', units='1', & interpinic_flag='interp', readvar=readvar, data=this%coszen_col) + if (use_finetop_rad) then + call restartvar(ncid=ncid, flag=flag, varname='cosinc', xtype=ncd_double, & + dim1name='column', & + long_name='cosine of solar incident angle (local surface)', units='1', & + interpinic_flag='interp', readvar=readvar, data=this%cosinc_col) + end if + call restartvar(ncid=ncid, flag=flag, varname='albd', xtype=ncd_double, & dim1name='pft', dim2name='numrad', switchdim=.true., & long_name='surface albedo (direct) (0 to 1)', units='', & diff --git a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 index d4a25c54192c..1b041243595c 100644 --- a/components/elm/src/biogeophys/SurfaceRadiationMod.F90 +++ b/components/elm/src/biogeophys/SurfaceRadiationMod.F90 @@ -328,7 +328,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & use elm_varpar , only : numrad, nlevsno use elm_varcon , only : spval, degpsec, isecspday use landunit_varcon , only : istsoil, istcrop - use elm_varctl , only : subgridflag, use_snicar_frc + use elm_varctl , only : subgridflag, use_snicar_frc, use_finetop_rad use SnowSnicarMod , only : DO_SNO_OC ! ! !ARGUMENTS: @@ -388,6 +388,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & forc_solad => top_af%solad , & ! Input: [real(r8) (:,:) ] direct beam radiation (W/m**2) forc_solai => top_af%solai , & ! Input: [real(r8) (:,:) ] diffuse radiation (W/m**2) + forc_solad_pp => top_af%solad_pp , & ! Input: [real(r8) (:,:) ] direct beam radiation under PP (W/m**2) + forc_solai_pp => top_af%solai_pp , & ! Input: [real(r8) (:,:) ] diffuse radiation under PP (W/m**2) snow_depth => col_ws%snow_depth , & ! Input: [real(r8) (:) ] snow height (m) frac_sno => col_ws%frac_sno , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1) @@ -475,6 +477,12 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & dtime = dtime_mod secs = secs_curr + + if (.not. use_finetop_rad) then + forc_solad_pp(:,:) = forc_solad(:,:) + forc_solai_pp(:,:) = forc_solai(:,:) + end if + ! Initialize fluxes do fp = 1,num_nourbanp p = filter_nourbanp(fp) @@ -736,6 +744,9 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & fsr_vis_i(p) = albi(p,1)*forc_solai(t,1) fsr_nir_i(p) = albi(p,2)*forc_solai(t,2) + solarabs_vars%fsr_vis_d_patch(p) = fsr_vis_d(p) + solarabs_vars%fsr_vis_i_patch(p) = fsr_vis_i(p) + local_secp1 = secs + nint((grc_pp%londeg(g)/degpsec)/dtime)*dtime local_secp1 = mod(local_secp1,isecspday) if (local_secp1 == isecspday/2) then @@ -794,16 +805,16 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & endif ! Solar incident - fsds_vis_d(p) = forc_solad(t,1) - fsds_nir_d(p) = forc_solad(t,2) - fsds_vis_i(p) = forc_solai(t,1) - fsds_nir_i(p) = forc_solai(t,2) + fsds_vis_d(p) = forc_solad_pp(t,1) + fsds_nir_d(p) = forc_solad_pp(t,2) + fsds_vis_i(p) = forc_solai_pp(t,1) + fsds_nir_i(p) = forc_solai_pp(t,2) ! Determine local noon incident solar if (local_secp1 == noonsec) then - fsds_vis_d_ln(p) = forc_solad(t,1) - fsds_nir_d_ln(p) = forc_solad(t,2) - fsds_vis_i_ln(p) = forc_solai(t,1) + fsds_vis_d_ln(p) = forc_solad_pp(t,1) + fsds_nir_d_ln(p) = forc_solad_pp(t,2) + fsds_vis_i_ln(p) = forc_solai_pp(t,1) parveg_ln(p) = 0._r8 else fsds_vis_d_ln(p) = spval @@ -815,10 +826,13 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Solar reflected ! per unit ground area (roof, road) and per unit wall area (sunwall, shadewall) - fsr_vis_d(p) = albd(p,1) * forc_solad(t,1) - fsr_nir_d(p) = albd(p,2) * forc_solad(t,2) - fsr_vis_i(p) = albi(p,1) * forc_solai(t,1) - fsr_nir_i(p) = albi(p,2) * forc_solai(t,2) + fsr_vis_d(p) = albd(p,1) * forc_solad_pp(t,1) + fsr_nir_d(p) = albd(p,2) * forc_solad_pp(t,2) + fsr_vis_i(p) = albi(p,1) * forc_solai_pp(t,1) + fsr_nir_i(p) = albi(p,2) * forc_solai_pp(t,2) + + solarabs_vars%fsr_vis_d_patch(p) = fsr_vis_d(p) + solarabs_vars%fsr_vis_i_patch(p) = fsr_vis_i(p) ! Determine local noon reflected solar if (local_secp1 == noonsec) then diff --git a/components/elm/src/biogeophys/UrbanRadiationMod.F90 b/components/elm/src/biogeophys/UrbanRadiationMod.F90 index 8cccc4e9ac32..22313fc85f29 100644 --- a/components/elm/src/biogeophys/UrbanRadiationMod.F90 +++ b/components/elm/src/biogeophys/UrbanRadiationMod.F90 @@ -13,7 +13,7 @@ module UrbanRadiationMod use decompMod , only : bounds_type use elm_varpar , only : numrad use elm_varcon , only : isecspday, degpsec, namel - use elm_varctl , only : iulog + use elm_varctl , only : iulog, use_finetop_rad use abortutils , only : endrun use UrbanParamsType , only : urbanparams_type use atm2lndType , only : atm2lnd_type @@ -116,10 +116,10 @@ subroutine UrbanRadiation (bounds , & canyon_hwr => lun_pp%canyon_hwr , & ! Input: [real(r8) (:) ] ratio of building height to street width wtroad_perv => lun_pp%wtroad_perv , & ! Input: [real(r8) (:) ] weight of pervious road wrt total road - forc_solad => top_af%solad , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) (W/m**2) - forc_solai => top_af%solai , & ! Input: [real(r8) (:,:) ] diffuse beam radiation (vis=forc_sols , nir=forc_soll ) (W/m**2) - forc_solar => top_af%solar , & ! Input: [real(r8) (:) ] incident solar radiation (W/m**2) - forc_lwrad => top_af%lwrad , & ! Input: [real(r8) (:) ] downward infrared (longwave) radiation (W/m**2) + forc_solad => top_af%solad_pp , & ! Input: [real(r8) (:,:) ] direct beam radiation under PP (vis=forc_sols , nir=forc_soll ) (W/m**2) + forc_solai => top_af%solai_pp , & ! Input: [real(r8) (:,:) ] diffuse beam radiation under PP (vis=forc_sols , nir=forc_soll ) (W/m**2) + forc_solar => top_af%solar_pp , & ! Input: [real(r8) (:) ] incident solar radiation under PP (W/m**2) + forc_lwrad => top_af%lwrad_pp , & ! Input: [real(r8) (:) ] downward infrared (longwave) radiation under PP (W/m**2) frac_sno => col_ws%frac_sno , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1) @@ -157,6 +157,13 @@ subroutine UrbanRadiation (bounds , & endl => bounds%endl & ) + if (.not. use_finetop_rad) then + forc_solad(:,:) = top_af%solad(:,:) + forc_solai(:,:) = top_af%solai(:,:) + forc_solar(:) = top_af%solar(:) + forc_lwrad(:) = top_af%lwrad(:) + end if + ! Define fields that appear on the restart file for non-urban landunits do fl = 1,num_nourbanl diff --git a/components/elm/src/cpl/lnd_comp_mct.F90 b/components/elm/src/cpl/lnd_comp_mct.F90 index 6bfabe91f1ed..a2b1c7216f35 100644 --- a/components/elm/src/cpl/lnd_comp_mct.F90 +++ b/components/elm/src/cpl/lnd_comp_mct.F90 @@ -1051,7 +1051,7 @@ subroutine lnd_export_moab(EClock, bounds, lnd2atm_vars, lnd2glc_vars) ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_kind_mod , only : CXX => SHR_KIND_CXX - use elm_varctl , only : iulog, create_glacier_mec_landunit + use elm_varctl , only : iulog, create_glacier_mec_landunit, use_finetop_rad use elm_time_manager , only : get_nstep, get_step_size use domainMod , only : ldomain use seq_drydep_mod , only : n_drydep @@ -1088,10 +1088,19 @@ subroutine lnd_export_moab(EClock, bounds, lnd2atm_vars, lnd2glc_vars) i = 1 + (g-bounds%begg) l2x_lm(i,index_l2x_Sl_t) = lnd2atm_vars%t_rad_grc(g) l2x_lm(i,index_l2x_Sl_snowh) = lnd2atm_vars%h2osno_grc(g) - l2x_lm(i,index_l2x_Sl_avsdr) = lnd2atm_vars%albd_grc(g,1) - l2x_lm(i,index_l2x_Sl_anidr) = lnd2atm_vars%albd_grc(g,2) - l2x_lm(i,index_l2x_Sl_avsdf) = lnd2atm_vars%albi_grc(g,1) - l2x_lm(i,index_l2x_Sl_anidf) = lnd2atm_vars%albi_grc(g,2) + + if (use_finetop_rad) then + l2x_lm(i,index_l2x_Sl_avsdr) = lnd2atm_vars%apparent_albd_grc(g,1) + l2x_lm(i,index_l2x_Sl_anidr) = lnd2atm_vars%apparent_albd_grc(g,2) + l2x_lm(i,index_l2x_Sl_avsdf) = lnd2atm_vars%apparent_albi_grc(g,1) + l2x_lm(i,index_l2x_Sl_anidf) = lnd2atm_vars%apparent_albi_grc(g,2) + else + l2x_lm(i,index_l2x_Sl_avsdr) = lnd2atm_vars%albd_grc(g,1) + l2x_lm(i,index_l2x_Sl_anidr) = lnd2atm_vars%albd_grc(g,2) + l2x_lm(i,index_l2x_Sl_avsdf) = lnd2atm_vars%albi_grc(g,1) + l2x_lm(i,index_l2x_Sl_anidf) = lnd2atm_vars%albi_grc(g,2) + end if + l2x_lm(i,index_l2x_Sl_tref) = lnd2atm_vars%t_ref2m_grc(g) l2x_lm(i,index_l2x_Sl_qref) = lnd2atm_vars%q_ref2m_grc(g) l2x_lm(i,index_l2x_Sl_u10) = lnd2atm_vars%u_ref10m_grc(g) diff --git a/components/elm/src/cpl/lnd_import_export.F90 b/components/elm/src/cpl/lnd_import_export.F90 index c9c6d6475a2c..dc8bea16c2b6 100644 --- a/components/elm/src/cpl/lnd_import_export.F90 +++ b/components/elm/src/cpl/lnd_import_export.F90 @@ -1412,7 +1412,7 @@ subroutine lnd_export( bounds, lnd2atm_vars, lnd2glc_vars, lnd2iac_vars, l2x) ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 - use elm_varctl , only : iulog, create_glacier_mec_landunit, iac_present + use elm_varctl , only : iulog, create_glacier_mec_landunit, iac_present, use_finetop_rad use elm_time_manager , only : get_nstep, get_step_size use domainMod , only : ldomain use seq_drydep_mod , only : n_drydep @@ -1446,10 +1446,19 @@ subroutine lnd_export( bounds, lnd2atm_vars, lnd2glc_vars, lnd2iac_vars, l2x) i = 1 + (g-bounds%begg) l2x(index_l2x_Sl_t,i) = lnd2atm_vars%t_rad_grc(g) l2x(index_l2x_Sl_snowh,i) = lnd2atm_vars%h2osno_grc(g) - l2x(index_l2x_Sl_avsdr,i) = lnd2atm_vars%albd_grc(g,1) - l2x(index_l2x_Sl_anidr,i) = lnd2atm_vars%albd_grc(g,2) - l2x(index_l2x_Sl_avsdf,i) = lnd2atm_vars%albi_grc(g,1) - l2x(index_l2x_Sl_anidf,i) = lnd2atm_vars%albi_grc(g,2) + + if (use_finetop_rad) then + l2x(index_l2x_Sl_avsdr,i) = lnd2atm_vars%apparent_albd_grc(g,1) + l2x(index_l2x_Sl_anidr,i) = lnd2atm_vars%apparent_albd_grc(g,2) + l2x(index_l2x_Sl_avsdf,i) = lnd2atm_vars%apparent_albi_grc(g,1) + l2x(index_l2x_Sl_anidf,i) = lnd2atm_vars%apparent_albi_grc(g,2) + else + l2x(index_l2x_Sl_avsdr,i) = lnd2atm_vars%albd_grc(g,1) + l2x(index_l2x_Sl_anidr,i) = lnd2atm_vars%albd_grc(g,2) + l2x(index_l2x_Sl_avsdf,i) = lnd2atm_vars%albi_grc(g,1) + l2x(index_l2x_Sl_anidf,i) = lnd2atm_vars%albi_grc(g,2) + end if + l2x(index_l2x_Sl_tref,i) = lnd2atm_vars%t_ref2m_grc(g) l2x(index_l2x_Sl_qref,i) = lnd2atm_vars%q_ref2m_grc(g) l2x(index_l2x_Sl_u10,i) = lnd2atm_vars%u_ref10m_grc(g) diff --git a/components/elm/src/data_types/GridcellType.F90 b/components/elm/src/data_types/GridcellType.F90 index e33800256e60..3ecabfb0cb89 100644 --- a/components/elm/src/data_types/GridcellType.F90 +++ b/components/elm/src/data_types/GridcellType.F90 @@ -15,6 +15,7 @@ module GridcellType use landunit_varcon, only : max_lunit use elm_varcon , only : ispval, spval use topounit_varcon, only : max_topounits + use elm_varpar , only : ndir_horizon_angle ! ! !PUBLIC TYPES: implicit none @@ -50,6 +51,12 @@ module GridcellType real(r8), pointer :: terrain_config (:) => null() ! mean of (terrain configuration factor / cos(slope)) real(r8), pointer :: sinsl_cosas (:) => null() ! sin(slope)*cos(aspect) / cos(slope) real(r8), pointer :: sinsl_sinas (:) => null() ! sin(slope)*sin(aspect) / cos(slope) + + real(r8), pointer :: slope_deg (:) => null() ! gridcell slope in degree (0-90) + real(r8), pointer :: aspect_deg (:) => null() ! gridcell aspect in degree (0-360) + real(r8), pointer :: horizon_angle_deg (:,:) => null() ! horizon angles in degree (0-90) + real(r8), pointer :: sky_view_factor (:) => null() ! sky view factor (unitless, 0-1) + real(r8), pointer :: terrain_config_factor (:) => null() ! terrain configuration factor (unitless, 0-1) ! Daylength real(r8) , pointer :: max_dayl (:) => null() ! maximum daylength for this grid cell (seconds) @@ -115,6 +122,12 @@ subroutine grc_pp_init(this, begg, endg) allocate(this%sinsl_cosas(begg:endg)) ; this%sinsl_cosas(:) = ispval ! sin(slope)*cos(aspect) / cos(slope) allocate(this%sinsl_sinas(begg:endg)) ; this%sinsl_sinas(:) = ispval ! sin(slope)*sin(aspect) / cos(slope) + allocate(this%slope_deg (begg:endg)) ; this%slope_deg (:) = ispval + allocate(this%aspect_deg (begg:endg)) ; this%aspect_deg (:) = ispval + allocate(this%horizon_angle_deg (begg:endg,1:ndir_horizon_angle)) ; this%horizon_angle_deg(:,:) = ispval + allocate(this%sky_view_factor (begg:endg)) ; this%sky_view_factor (:) = ispval + allocate(this%terrain_config_factor(begg:endg)) ; this%terrain_config_factor(:) = ispval + ! This is initiailized in module DayLength allocate(this%max_dayl (begg:endg)) ; this%max_dayl (:) = spval allocate(this%dayl (begg:endg)) ; this%dayl (:) = spval @@ -167,7 +180,12 @@ subroutine grc_pp_clean(this) deallocate(this%terrain_config ) deallocate(this%sinsl_cosas ) deallocate(this%sinsl_sinas ) - + deallocate(this%slope_deg ) + deallocate(this%aspect_deg ) + deallocate(this%horizon_angle_deg ) + deallocate(this%sky_view_factor ) + deallocate(this%terrain_config_factor) + end subroutine grc_pp_clean end module GridcellType diff --git a/components/elm/src/data_types/TopounitDataType.F90 b/components/elm/src/data_types/TopounitDataType.F90 index 33de4bb73542..7683b62f376d 100644 --- a/components/elm/src/data_types/TopounitDataType.F90 +++ b/components/elm/src/data_types/TopounitDataType.F90 @@ -63,6 +63,10 @@ module TopounitDataType real(r8), pointer :: solai (:,:) => null() ! diffuse radiation (numrad) (vis=forc_solsd, nir=forc_solld) (W/m**2) real(r8), pointer :: solar (:) => null() ! incident solar radiation (W/m**2) real(r8), pointer :: lwrad (:) => null() ! atm downwrd IR longwave radiation (W/m**2) + real(r8), pointer :: solad_pp (:,:) => null() ! direct beam radiation under PP (numrad)(vis=forc_sols , nir=forc_soll) (W/m**2) + real(r8), pointer :: solai_pp (:,:) => null() ! diffuse radiation under PP (numrad) (vis=forc_solsd, nir=forc_solld) (W/m**2) + real(r8), pointer :: solar_pp (:) => null() ! incident solar radiation under PP (W/m**2) + real(r8), pointer :: lwrad_pp (:) => null() ! atm downwrd IR longwave radiation under PP (W/m**2) ! Accumulated fields real(r8), pointer :: prec24h (:) => null() ! 24-hour mean precip rate (kg H2O/m**2/s, equivalent to mm liquid H2O/s) real(r8), pointer :: prec10d (:) => null() ! 10-day mean precip rate (kg H2O/m**2/s, equivalent to mm liquid H2O/s) @@ -367,6 +371,10 @@ subroutine init_top_af(this, begt, endt) allocate(this%solai (begt:endt, numrad)) ; this%solai (:,:) = spval allocate(this%solar (begt:endt)) ; this%solar (:) = spval allocate(this%lwrad (begt:endt)) ; this%lwrad (:) = spval + allocate(this%solad_pp (begt:endt, numrad)) ; this%solad_pp (:,:) = spval + allocate(this%solai_pp (begt:endt, numrad)) ; this%solai_pp (:,:) = spval + allocate(this%solar_pp (begt:endt)) ; this%solar_pp (:) = spval + allocate(this%lwrad_pp (begt:endt)) ; this%lwrad_pp (:) = spval if (use_fates) then allocate(this%prec24h (begt:endt)) ; this%prec24h (:) = spval end if @@ -416,6 +424,10 @@ subroutine clean_top_af(this, begt, endt) deallocate(this%solai) deallocate(this%solar) deallocate(this%lwrad) + deallocate(this%solad_pp) + deallocate(this%solai_pp) + deallocate(this%solar_pp) + deallocate(this%lwrad_pp) if (use_fates) then deallocate(this%prec24h) end if diff --git a/components/elm/src/main/atm2lndMod.F90 b/components/elm/src/main/atm2lndMod.F90 index 27d18c89e867..239972003af1 100644 --- a/components/elm/src/main/atm2lndMod.F90 +++ b/components/elm/src/main/atm2lndMod.F90 @@ -19,7 +19,10 @@ module atm2lndMod use decompMod , only : bounds_type use atm2lndType , only : atm2lnd_type use LandunitType , only : lun_pp - use ColumnType , only : col_pp + use ColumnType , only : col_pp + use GridCellType , only : grc_pp + use TopounitDataType, only: top_af + use lnd2atmType , only : lnd2atm_type ! ! !PUBLIC TYPES: implicit none @@ -28,6 +31,7 @@ module atm2lndMod ! ! !PUBLIC MEMBER FUNCTIONS: public :: downscale_forcings ! Downscale atm forcing fields from gridcell to column + public :: topographic_effects_on_radiation ! Topographic effects on shortwave/longwave radiation ! ! !PRIVATE MEMBER FUNCTIONS: private :: downscale_longwave ! Downscale longwave radiation from gridcell to column @@ -447,4 +451,169 @@ subroutine check_downscale_consistency(bounds, atm2lnd_vars) end subroutine check_downscale_consistency + !----------------------------------------------------------------------- + subroutine topographic_effects_on_radiation(bounds, atm2lnd_vars, nextsw_cday, declin, lnd2atm_vars) + ! + ! !DESCRIPTION: + ! Calculate fine-scale topographic effects on shortwave and longwave radiation + ! + ! !USES: + use domainMod , only : ldomain + use shr_orb_mod + use shr_const_mod , only : SHR_CONST_PI + use elm_varpar , only : numrad, ndir_horizon_angle + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + type(atm2lnd_type) , intent(inout) :: atm2lnd_vars + type(lnd2atm_type) , intent(in) :: lnd2atm_vars + real(r8) , intent(in) :: nextsw_cday ! calendar day at Greenwich (1.00, ..., days/year) + real(r8) , intent(in) :: declin ! declination angle (radians) for next time step + + ! + ! !LOCAL VARIABLES: + integer :: g,topo ! indices + integer :: dd,ib + real(r8) :: cossza + real(r8) :: slope_rad + real(r8) :: aspect_rad + real(r8) :: deg2rad + real(r8) :: horizon_angle_twd_sun_rad + + character(len=*), parameter :: subname = 'topographic_effects_on_radiation' + !----------------------------------------------------------------------- + + associate(& + ! Gridcell-level fields: + lat => grc_pp%lat , & ! Input: latitude + lon => grc_pp%lon , & ! Input: longitude + slope_deg => grc_pp%slope_deg , & + aspect_deg => grc_pp%aspect_deg , & + horizon_angle_deg => grc_pp%horizon_angle_deg , & + sky_view_factor => grc_pp%sky_view_factor , & + terrain_config_factor => grc_pp%terrain_config_factor , & + f_short_dir => atm2lnd_vars%f_short_dir , & + f_short_dif => atm2lnd_vars%f_short_dif , & + f_short_refl => atm2lnd_vars%f_short_refl , & + f_long_dif => atm2lnd_vars%f_long_dif , & + f_long_refl => atm2lnd_vars%f_long_refl , & + sza => atm2lnd_vars%sza , & + saa => atm2lnd_vars%saa , & + cosinc => atm2lnd_vars%cosinc , & + albd => lnd2atm_vars%albd_grc , & ! Input: [real(r8) (:,:) ] surface albedo (direct) + albi => lnd2atm_vars%albi_grc , & ! Input: [real(r8) (:,:) ] surface albedo (diffuse) + eflx_lwrad_out_grc => lnd2atm_vars%eflx_lwrad_out_grc , & + forc_solad_grc => atm2lnd_vars%forc_solad_grc , & + forc_solai_grc => atm2lnd_vars%forc_solai_grc , & + forc_solar_grc => atm2lnd_vars%forc_solar_grc , & + forc_lwrad_grc => atm2lnd_vars%forc_lwrad_not_downscaled_grc , & + forc_solad_pp_grc => atm2lnd_vars%forc_solad_pp_grc , & + forc_solai_pp_grc => atm2lnd_vars%forc_solai_pp_grc , & + forc_solar_pp_grc => atm2lnd_vars%forc_solar_pp_grc , & + forc_lwrad_pp_grc => atm2lnd_vars%forc_lwrad_not_downscaled_pp_grc & + ) + + deg2rad = SHR_CONST_PI/180._r8 + + ! Initialize column forcing (needs to be done for ALL active columns) + do g = bounds%begg, bounds%endg + + forc_solad_pp_grc(g,:) = forc_solad_grc(g,:) + forc_solai_pp_grc(g,:) = forc_solai_grc(g,:) + forc_solar_pp_grc(g) = forc_solar_grc(g) + forc_lwrad_pp_grc(g) = forc_lwrad_grc(g) + + ! copy radiation values from gridcell to topounit + do topo = grc_pp%topi(g), grc_pp%topf(g) + top_af%solad_pp(topo,:) = forc_solad_pp_grc(g,:) + top_af%solai_pp(topo,:) = forc_solai_pp_grc(g,:) + top_af%solar_pp(topo) = forc_solar_pp_grc(g) + top_af%lwrad_pp(topo) = forc_lwrad_pp_grc(g) + end do + + ! calculate cosine of solar zenith angle + cossza = shr_orb_cosz(nextsw_cday, lat(g), lon(g), declin) + + slope_rad = slope_deg(g) * deg2rad + aspect_rad = aspect_deg(g) * deg2rad + + f_short_dir(g) = 1._r8 + f_short_dif(g) = 1._r8 + f_short_refl(g,:) = 0._r8 + sza(g) = nan + saa(g) = nan + cosinc(g) = nan + ! scale shortwave radiation + if (cossza > 0.0872_r8) then ! just modify when SZA > 85 degree 0.0872_r8 + + ! solar zenith angle + sza(g) = acos(cossza) + + ! solar azimuth angle + saa(g) = shr_orb_azimuth(nextsw_cday, lat(g), lon(g), declin,sza(g)) + + ! calculat local solar zenith angle + cosinc(g) = cos(slope_rad) * cossza + sin(slope_rad) * sin(sza(g)) * cos(aspect_rad - saa(g)) + cosinc(g) = max(-1._r8, min(cosinc(g), 1._r8)) + + if (cosinc(g) < 0._r8) then + f_short_dir(g) = 0._r8 + else + f_short_dir(g) = cosinc(g) / cossza / cos(slope_rad) + endif + + ! Find horizion angle towards the sun + dd = nint(saa(g) / (2._r8*SHR_CONST_PI) * ndir_horizon_angle) + 1 + if (dd > ndir_horizon_angle) dd = 1 + horizon_angle_twd_sun_rad = horizon_angle_deg(g,dd) * deg2rad + + ! Check if sun is above horizon angle + if (cossza < sin(horizon_angle_twd_sun_rad)) then + f_short_dir(g) = 0._r8 + endif + + f_short_dif(g) = sky_view_factor(g) / cos(slope_rad) + if (f_short_dif(g) < 0._r8) f_short_dif(g) = 0._r8 + + forc_solar_grc(g) = 0._r8 + do ib = 1, numrad + ! Calculate reflected radiation from adjacent terrain + f_short_refl(g,ib) = terrain_config_factor(g) / cos(slope_rad) * (albd(g,ib) * forc_solad_grc(g,ib) + albi(g,ib) * forc_solai_grc(g,ib)) + + if (f_short_refl(g,ib) < 0._r8) f_short_refl(g,ib) = 0._r8 + + ! scale direct solar radiation: vis & nir + forc_solad_grc(g,ib) = forc_solad_grc(g,ib) * f_short_dir(g) + ! scale diffuse solar radiation: vis & nir + forc_solai_grc(g,ib) = forc_solai_grc(g,ib) * f_short_dif(g) + f_short_refl(g,ib) + + forc_solar_grc(g) = forc_solar_grc(g) + forc_solad_grc(g,ib) + forc_solai_grc(g,ib) + end do + + end if + + f_long_dif(g) = 1._r8 + f_long_refl(g) = 0._r8 + ! scale longwave radiation + f_long_dif(g) = sky_view_factor(g) / cos(slope_rad) + if (f_long_dif(g) < 0._r8) f_long_dif(g) = 0._r8 + f_long_refl(g) = terrain_config_factor(g) * eflx_lwrad_out_grc(g) + if (f_long_refl(g) < 0._r8) f_long_refl(g) = 0._r8 + + forc_lwrad_grc(g) = forc_lwrad_grc(g) * f_long_dif(g) + f_long_refl(g) + + ! copy radiation values from gridcell to topounit + do topo = grc_pp%topi(g), grc_pp%topf(g) + top_af%solad(topo,:) = forc_solad_grc(g,:) + top_af%solai(topo,:) = forc_solai_grc(g,:) + top_af%solar(topo) = forc_solar_grc(g) + top_af%lwrad(topo) = forc_lwrad_grc(g) + end do + + end do + + end associate + + end subroutine topographic_effects_on_radiation + end module atm2lndMod diff --git a/components/elm/src/main/atm2lndType.F90 b/components/elm/src/main/atm2lndType.F90 index f2facc776224..2a650e1f321f 100644 --- a/components/elm/src/main/atm2lndType.F90 +++ b/components/elm/src/main/atm2lndType.F90 @@ -11,7 +11,7 @@ module atm2lndType use shr_megan_mod , only : shr_megan_mechcomps_n use elm_varpar , only : numrad, ndst, nlevgrnd !ndst = number of dust bins. use elm_varcon , only : rair, grav, cpair, hfus, tfrz, spval - use elm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_fates, use_fan + use elm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_fates, use_fan, use_finetop_rad use seq_drydep_mod, only : n_drydep, drydep_method, DD_XLND use decompMod , only : bounds_type use abortutils , only : endrun @@ -148,7 +148,20 @@ module atm2lndType ! Needed for FNM precip downscaling, when used within CPL_BYPASS real(r8), pointer :: forc_uovern (:) => null() ! Froude number (dimensionless) - + + real(r8), pointer :: sza (:) => null() ! solar zenith angle + real(r8), pointer :: saa (:) => null() ! solar azmith angle + real(r8), pointer :: cosinc (:) => null() ! cosine of the local incident angle + real(r8), pointer :: f_short_dir (:) => null() ! adjust factor for direct shortwave radiation + real(r8), pointer :: f_short_dif (:) => null() ! adjust factor for diffuse shortwave radiation + real(r8), pointer :: f_short_refl (:,:) => null() ! adjust factor for reflected shortwave radiation + real(r8), pointer :: f_long_dif (:) => null() ! adjust factor for diffuse longwave radiation + real(r8), pointer :: f_long_refl (:) => null() ! adjust factor for reflected longwave radiation + + real(r8), pointer :: forc_solad_pp_grc (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) under PP + real(r8), pointer :: forc_solai_pp_grc (:,:) => null() ! diffuse radiation (numrad) (vis=forc_solsd, nir=forc_solld) under PP + real(r8), pointer :: forc_solar_pp_grc (:) => null() ! incident solar radiation under PP + real(r8), pointer :: forc_lwrad_not_downscaled_pp_grc(:) => null() ! not downscaled atm downwrd IR longwave radiation (W/m**2) under PP contains @@ -314,7 +327,23 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_ndep_nitr_grc (begg:endg)) ; this%forc_ndep_nitr_grc (:) = ival allocate(this%forc_soilph_grc (begg:endg)) ; this%forc_soilph_grc (:) = ival end if + allocate(this%forc_uovern (begg:endg)) ; this%forc_uovern (:) = ival + + if ( use_finetop_rad ) then + allocate(this%f_short_dir (begg:endg)) ; this%f_short_dir (:) = nan + allocate(this%f_short_dif (begg:endg)) ; this%f_short_dif (:) = nan + allocate(this%f_short_refl (begg:endg,numrad)) ; this%f_short_refl (:,:) = nan + allocate(this%f_long_dif (begg:endg)) ; this%f_long_dif (:) = nan + allocate(this%f_long_refl (begg:endg)) ; this%f_long_refl (:) = nan + allocate(this%sza (begg:endg)) ; this%sza (:) = nan + allocate(this%saa (begg:endg)) ; this%saa (:) = nan + allocate(this%cosinc (begg:endg)) ; this%cosinc (:) = nan + allocate(this%forc_solad_pp_grc (begg:endg,numrad)) ; this%forc_solad_pp_grc (:,:) = ival + allocate(this%forc_solai_pp_grc (begg:endg,numrad)) ; this%forc_solai_pp_grc (:,:) = ival + allocate(this%forc_solar_pp_grc (begg:endg)) ; this%forc_solar_pp_grc (:) = ival + allocate(this%forc_lwrad_not_downscaled_pp_grc (begg:endg)) ; this%forc_lwrad_not_downscaled_pp_grc (:)= ival + endif end subroutine InitAllocate @@ -322,7 +351,7 @@ end subroutine InitAllocate subroutine InitHistory(this, bounds) ! ! !USES: - use histFileMod, only : hist_addfld1d + use histFileMod, only : hist_addfld1d, hist_addfld2d ! ! !ARGUMENTS: class(atm2lnd_type) :: this @@ -504,6 +533,58 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='direct radiation (last 240hrs)', & ptr_patch=this%fsd240_patch, default='inactive') + if ( use_finetop_rad ) then + this%f_short_dir(begg:endg) = spval + call hist_addfld1d (fname='F_SHORT_DIR', units='unitless', & + avgflag='A', long_name='f_short_dir', & + ptr_gcell=this%f_short_dir, default='inactive') + + this%f_short_dif(begg:endg) = spval + call hist_addfld1d (fname='F_SHORT_DIF', units='unitless', & + avgflag='A', long_name='f_short_dif', & + ptr_gcell=this%f_short_dif, default='inactive') + + this%f_short_refl(begg:endg,:) = spval + call hist_addfld2d (fname='F_SHORT_REFL', units='unitless', type2d='numrad', & + avgflag='A', long_name='f_short_refl', & + ptr_gcell=this%f_short_refl, default='inactive') + + this%f_long_dif(begg:endg) = spval + call hist_addfld1d (fname='F_LONG_DIF', units='unitless', & + avgflag='A', long_name='f_long_dif', & + ptr_gcell=this%f_long_dif, default='inactive') + + this%f_long_refl(begg:endg) = spval + call hist_addfld1d (fname='F_LONG_REFL', units='unitless', & + avgflag='A', long_name='f_long_refl', & + ptr_gcell=this%f_long_refl, default='inactive') + + this%forc_solad_pp_grc(begg:endg,:) = spval + call hist_addfld2d (fname='forc_solad_pp_grc', units='unitless', type2d='numrad', & + avgflag='A', long_name='forc_solad_pp_grc', & + ptr_gcell=this%forc_solad_pp_grc, default='inactive') + + this%forc_solai_pp_grc(begg:endg,:) = spval + call hist_addfld2d (fname='forc_solai_pp_grc', units='unitless', type2d='numrad', & + avgflag='A', long_name='forc_solai_pp_grc', & + ptr_gcell=this%forc_solai_pp_grc, default='inactive') + + this%forc_solar_pp_grc(begg:endg) = spval + call hist_addfld1d (fname='SWdown_PP', units='W/m^2', & + avgflag='A', long_name='atmospheric incident solar radiation (PP)', & + ptr_gcell=this%forc_solar_pp_grc, default='inactive') + + this%forc_lwrad_not_downscaled_pp_grc(begg:endg) = spval + call hist_addfld1d (fname='LWdown_PP', units='W/m^2', & + avgflag='A', long_name='atmospheric longwave radiation (PP)', & + ptr_gcell=this%forc_lwrad_not_downscaled_pp_grc, default='inactive') + endif + + if ( use_finetop_rad ) then + this%forc_solad_pp_grc(begg:endg, :) = 0._r8 + this%forc_solai_pp_grc(begg:endg, :) = 0._r8 + endif + end subroutine InitHistory !----------------------------------------------------------------------- @@ -760,6 +841,18 @@ subroutine Restart(this, bounds, ncid, flag) this%forc_flood_grc = 0._r8 endif + if ( use_finetop_rad ) then + call restartvar(ncid=ncid, flag=flag, varname='forc_solad_pp', xtype=ncd_double, & + dim1name='gridcell', dim2name='numrad', switchdim=.true., & + long_name='direct beam radiation (numrad)', units='W/m^2', & + interpinic_flag='interp', readvar=readvar, data=this%forc_solad_pp_grc) + + call restartvar(ncid=ncid, flag=flag, varname='forc_solai_pp', xtype=ncd_double, & + dim1name='gridcell', dim2name='numrad', switchdim=.true., & + long_name='diffuse radiation (numrad)', units='W/m^2', & + interpinic_flag='interp', readvar=readvar, data=this%forc_solai_pp_grc) + endif + end subroutine Restart end module atm2lndType diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index f21eb1ffd8e7..2c4f703f1dcb 100644 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -53,7 +53,7 @@ module controlMod use elm_varctl , only: startdate_add_temperature, startdate_add_co2 use elm_varctl , only: add_temperature, add_co2 use elm_varctl , only: const_climate_hist - use elm_varctl , only: use_top_solar_rad + use elm_varctl , only: use_top_solar_rad, use_finetop_rad use elm_varctl , only: snow_shape, snicar_atm_type, use_dust_snow_internal_mixing use EcosystemBalanceCheckMod, only: bgc_balance_check_tolerance => balance_check_tolerance @@ -342,7 +342,7 @@ subroutine control_init( ) use_erosion, ero_ccycle namelist /elm_inparm/ & - use_top_solar_rad + use_top_solar_rad, use_finetop_rad namelist /elm_mosart/ & lnd_rof_coupling_nstep @@ -925,6 +925,7 @@ subroutine control_spmd() call mpi_bcast (more_vertlayers,1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (const_climate_hist, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_top_solar_rad, 1, MPI_LOGICAL, 0, mpicom, ier) ! TOP solar radiation parameterization + call mpi_bcast (use_finetop_rad, 1, MPI_LOGICAL, 0, mpicom, ier) ! fineTOP radiation parameterization ! glacier_mec variables call mpi_bcast (create_glacier_mec_landunit, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -1124,7 +1125,13 @@ subroutine control_print () else write(iulog,*) ' use_top_solar_rad is False, so do not run TOP solar radiation parameterization' end if - + + if (use_finetop_rad) then + write(iulog,*) ' use fineTOP radiation parameterization instead of PP' + else + write(iulog,*) ' use_finetop_rad is False, so do not run fineTOP radiation parameterization' + end if + if (use_cn) then if (suplnitro /= suplnNon)then write(iulog,*) ' Supplemental Nitrogen mode is set to run over Patches: ', & @@ -1243,7 +1250,8 @@ subroutine control_print () write(iulog,*) ' more vertical layers = ', more_vertlayers write(iulog,*) ' Sub-grid topographic effects on solar radiation = ', use_top_solar_rad ! TOP solar radiation parameterization - + write(iulog,*) ' Grid-scale topographic effects on radiation (fineTOP) = ', use_finetop_rad ! fineTOP radiation parameterization + if (nsrest == nsrContinue) then write(iulog,*) 'restart warning:' write(iulog,*) ' Namelist not checked for agreement with initial run.' diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 92f7a799e42a..37e8a9547747 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -83,7 +83,7 @@ module elm_driver ! use filterMod , only : setFilters ! - use atm2lndMod , only : downscale_forcings + use atm2lndMod , only : downscale_forcings, topographic_effects_on_radiation use lnd2atmMod , only : lnd2atm use lnd2glcMod , only : lnd2glc_type use lnd2iacMod , only : lnd2iac_type @@ -182,6 +182,7 @@ module elm_driver use CNPBudgetMod , only : CNPBudget_SetBeginningMonthlyStates, CNPBudget_SetEndingMonthlyStates use elm_varctl , only : do_budgets, budget_inst, budget_daily, budget_month use elm_varctl , only : budget_ann, budget_ltann, budget_ltend + use elm_varctl , only : use_finetop_rad use timeinfoMod ! @@ -688,6 +689,12 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) filter(nc)%num_soilp , filter(nc)%soilp, & canopystate_vars, energyflux_vars) + if (use_finetop_rad) then + call topographic_effects_on_radiation(bounds_clump, & + atm2lnd_vars, nextsw_cday, declinp1, & + lnd2atm_vars) + endif + call downscale_forcings(bounds_clump, & filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & atm2lnd_vars) diff --git a/components/elm/src/main/elm_initializeMod.F90 b/components/elm/src/main/elm_initializeMod.F90 index 73158d198b81..715621cd2911 100644 --- a/components/elm/src/main/elm_initializeMod.F90 +++ b/components/elm/src/main/elm_initializeMod.F90 @@ -12,7 +12,7 @@ module elm_initializeMod use elm_varctl , only : nsrest, nsrStartup, nsrContinue, nsrBranch use elm_varctl , only : create_glacier_mec_landunit, iulog, iac_present use elm_varctl , only : use_lch4, use_cn, use_voc, use_c13, use_c14 - use elm_varctl , only : use_fates, use_betr, use_fates_sp, use_fan, use_fates_luh + use elm_varctl , only : use_fates, use_betr, use_fates_sp, use_fan, use_fates_luh, use_finetop_rad use elm_varsur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, wt_glc_mec, topo_glc_mec,firrig,f_surf,f_grd use elm_varsur , only : fert_cft, fert_p_cft, wt_polygon use elm_varsur , only : wt_tunit, elv_tunit, slp_tunit,asp_tunit,num_tunit_per_grd @@ -82,7 +82,7 @@ subroutine initialize1( ) use decompInitMod , only: decompInit_moab #endif use domainMod , only: domain_check, ldomain, domain_init - use surfrdMod , only: surfrd_get_globmask, surfrd_get_grid, surfrd_get_topo, surfrd_get_data,surfrd_get_topo_for_solar_rad + use surfrdMod , only: surfrd_get_globmask, surfrd_get_grid, surfrd_get_topo, surfrd_get_data, surfrd_get_topo_for_solar_rad, surfrd_finetop_data use controlMod , only: control_init, control_print, NLFilename use ncdio_pio , only: ncd_pio_init use initGridCellsMod , only: initGridCells, initGhostGridCells @@ -276,9 +276,10 @@ subroutine initialize1( ) write(iulog,*) 'Attempting to read topo parameters for TOP solar radiation parameterization from ',trim(fsurdat) call shr_sys_flush(iulog) endif - call surfrd_get_topo_for_solar_rad(ldomain, fsurdat) - endif + call surfrd_get_topo_for_solar_rad(ldomain, fsurdat) + endif + !------------------------------------------------------------------------- ! Topounit !------------------------------------------------------------------------- @@ -422,6 +423,14 @@ subroutine initialize1( ) call initGridCells() + if (fsurdat /= " " .and. use_finetop_rad) then + if (masterproc) then + write(iulog,*) 'Attempting to read topo parameters for fineTOP parameterization from ',trim(fsurdat) + call shr_sys_flush(iulog) + endif + call surfrd_finetop_data(ldomain, fsurdat) + endif + ! Set global seg maps for gridcells, topounits, landlunits, columns and patches !if(max_topounits > 1) then ! if (create_glacier_mec_landunit) then @@ -1035,10 +1044,16 @@ subroutine initialize2( ) if (nsrest == nsrStartup) then call t_startf('init_map2gc') - call lnd2atm_minimal(bounds_proc, surfalb_vars, energyflux_vars, lnd2atm_vars) + call lnd2atm_minimal(bounds_proc, surfalb_vars, solarabs_vars, energyflux_vars, atm2lnd_vars, lnd2atm_vars) + call t_stopf('init_map2gc') + else if ( use_finetop_rad .and. ((nsrest == nsrContinue) .or. (nsrest == nsrBranch))) then + call t_startf('init_map2gc') + call lnd2atm_minimal(bounds_proc, surfalb_vars, solarabs_vars, energyflux_vars, atm2lnd_vars, lnd2atm_vars) call t_stopf('init_map2gc') end if + + !------------------------------------------------------------ ! Initialize sno export state to send to glc !------------------------------------------------------------ diff --git a/components/elm/src/main/elm_varctl.F90 b/components/elm/src/main/elm_varctl.F90 index 317b15796edd..92c8ca64c652 100644 --- a/components/elm/src/main/elm_varctl.F90 +++ b/components/elm/src/main/elm_varctl.F90 @@ -401,7 +401,8 @@ module elm_varctl character(len = SHR_KIND_CS), public :: precip_downscaling_method = 'ERMM' ! Precip downscaling method values can be ERMM or FNM logical, public :: use_lake_wat_storage = .false. logical, public :: use_top_solar_rad = .false. ! TOP : sub-grid topographic effect on surface solar radiation - + logical, public :: use_finetop_rad = .false. ! fineTOP : fine(grid)-scale topographic effect on surface radiation balance (longwave + shortwave) + !---------------------------------------------------------- ! Fan controls (use_fan) !---------------------------------------------------------- diff --git a/components/elm/src/main/elm_varpar.F90 b/components/elm/src/main/elm_varpar.F90 index 36be64825abc..fa9c38005471 100644 --- a/components/elm/src/main/elm_varpar.F90 +++ b/components/elm/src/main/elm_varpar.F90 @@ -83,6 +83,8 @@ module elm_varpar real(r8), parameter :: scalez = 0.025_r8 real(r8), parameter :: zecoeff = 0.50_r8 + integer, parameter :: ndir_horizon_angle = 8 ! number of directions for horizon angle + ! constants for decomposition cascade integer :: i_met_lit diff --git a/components/elm/src/main/lnd2atmMod.F90 b/components/elm/src/main/lnd2atmMod.F90 index 978be5a1b6ff..49d052d1e4d3 100644 --- a/components/elm/src/main/lnd2atmMod.F90 +++ b/components/elm/src/main/lnd2atmMod.F90 @@ -13,7 +13,7 @@ module lnd2atmMod use elm_varpar , only : numrad, ndst, nlevgrnd, nlevsno, nlevsoi !ndst = number of dust bins. use elm_varcon , only : rair, grav, cpair, hfus, tfrz, spval use elm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_voc, use_fates, use_atm_downscaling_to_topunit, use_fan - use elm_varctl , only : use_lnd_rof_two_way + use elm_varctl , only : use_lnd_rof_two_way, use_finetop_rad use tracer_varcon , only : is_active_betr_bgc use seq_drydep_mod , only : n_drydep, drydep_method, DD_XLND use decompMod , only : bounds_type @@ -55,7 +55,7 @@ module lnd2atmMod !------------------------------------------------------------------------ subroutine lnd2atm_minimal(bounds, & - surfalb_vars, energyflux_vars, lnd2atm_vars) + surfalb_vars, solarabs_vars, energyflux_vars, atm2lnd_vars, lnd2atm_vars) ! ! !DESCRIPTION: ! Compute elm_l2a_vars component of gridcell derived type. This routine computes @@ -70,11 +70,13 @@ subroutine lnd2atm_minimal(bounds, & ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds type(surfalb_type) , intent(in) :: surfalb_vars + type(solarabs_type) , intent(in) :: solarabs_vars type(energyflux_type) , intent(in) :: energyflux_vars + type(atm2lnd_type) , intent(in) :: atm2lnd_vars type(lnd2atm_type) , intent(inout) :: lnd2atm_vars ! ! !LOCAL VARIABLES: - integer :: g, t ! index + integer :: g, t, ib ! index !------------------------------------------------------------------------ associate( & h2osno => col_ws%h2osno , & @@ -83,10 +85,23 @@ subroutine lnd2atm_minimal(bounds, & h2osoi_vol_grc => lnd2atm_vars%h2osoi_vol_grc , & albd_patch => surfalb_vars%albd_patch , & albd_grc => lnd2atm_vars%albd_grc , & + apparent_albd_grc => lnd2atm_vars%apparent_albd_grc , & albi_patch => surfalb_vars%albi_patch , & albi_grc => lnd2atm_vars%albi_grc , & + apparent_albi_grc => lnd2atm_vars%apparent_albi_grc , & eflx_lwrad_out => veg_ef%eflx_lwrad_out , & - eflx_lwrad_out_grc => lnd2atm_vars%eflx_lwrad_out_grc & + eflx_lwrad_out_grc => lnd2atm_vars%eflx_lwrad_out_grc , & + forc_solad_pp_grc => atm2lnd_vars%forc_solad_pp_grc , & + forc_solai_pp_grc => atm2lnd_vars%forc_solai_pp_grc , & + fsr_vis_d_patch => solarabs_vars%fsr_vis_d_patch , & + fsr_vis_i_patch => solarabs_vars%fsr_vis_i_patch , & + fsr_nir_d_patch => solarabs_vars%fsr_nir_d_patch , & + fsr_nir_i_patch => solarabs_vars%fsr_nir_i_patch , & + fsr_vis_d_grc => lnd2atm_vars%fsr_vis_d_grc , & + fsr_vis_i_grc => lnd2atm_vars%fsr_vis_i_grc , & + fsr_nir_d_grc => lnd2atm_vars%fsr_nir_d_grc , & + fsr_nir_i_grc => lnd2atm_vars%fsr_nir_i_grc , & + sky_view_factor => grc_pp%sky_view_factor & ) call c2g(bounds, & @@ -118,10 +133,16 @@ subroutine lnd2atm_minimal(bounds, & eflx_lwrad_out_grc (bounds%begg:bounds%endg), & p2c_scale_type=unity, c2l_scale_type= urbanf, l2g_scale_type=unity) + if (use_finetop_rad) then + do g = bounds%begg,bounds%endg + eflx_lwrad_out_grc(g) = eflx_lwrad_out_grc(g)*sky_view_factor(g) + end do + end if + do g = bounds%begg,bounds%endg lnd2atm_vars%t_rad_grc(g) = sqrt(sqrt(eflx_lwrad_out_grc(g)/sb)) end do - + ! Calculate topounit level eflx_lwrad_out_topo for downscaling purpose if (use_atm_downscaling_to_topunit) then call p2t(bounds, & @@ -134,6 +155,68 @@ subroutine lnd2atm_minimal(bounds, & end do end if + if (use_finetop_rad) then + ! calculate gridcell level reflected radiation + call p2g(bounds, & + fsr_vis_d_patch(bounds%begp:bounds%endp) , & + fsr_vis_d_grc (bounds%begg:bounds%endg) , & + p2c_scale_type=unity, c2l_scale_type= urbanf, l2g_scale_type=unity) + + call p2g(bounds, & + fsr_vis_i_patch(bounds%begp:bounds%endp) , & + fsr_vis_i_grc (bounds%begg:bounds%endg) , & + p2c_scale_type=unity, c2l_scale_type= urbanf, l2g_scale_type=unity) + + call p2g(bounds, & + fsr_nir_d_patch(bounds%begp:bounds%endp) , & + fsr_nir_d_grc (bounds%begg:bounds%endg) , & + p2c_scale_type=unity, c2l_scale_type= urbanf, l2g_scale_type=unity) + + call p2g(bounds, & + fsr_nir_i_patch(bounds%begp:bounds%endp) , & + fsr_nir_i_grc (bounds%begg:bounds%endg) , & + p2c_scale_type=unity, c2l_scale_type= urbanf, l2g_scale_type=unity) + + ! calculate gridcell level apparent albedo + do g = bounds%begg,bounds%endg + do ib = 1, numrad + apparent_albd_grc(g,ib) = 1._r8 + apparent_albi_grc(g,ib) = 1._r8 + end do + + ! calculate direct albedo + ib = 1 + if (forc_solad_pp_grc(g,ib) > 0._r8) then + apparent_albd_grc(g,ib) = fsr_vis_d_grc(g)/forc_solad_pp_grc(g,ib)*sky_view_factor(g) + end if + ib = 2 + if (forc_solad_pp_grc(g,ib) > 0._r8) then + apparent_albd_grc(g,ib) = fsr_nir_d_grc(g)/forc_solad_pp_grc(g,ib)*sky_view_factor(g) + end if + + ! calculate diffuse albedo + ib = 1 + if (forc_solai_pp_grc(g,ib) > 0._r8) then + apparent_albi_grc(g,ib) = fsr_vis_i_grc(g)/forc_solai_pp_grc(g,ib)*sky_view_factor(g) + end if + ib = 2 + if (forc_solai_pp_grc(g,ib) > 0._r8) then + apparent_albi_grc(g,ib) = fsr_nir_i_grc(g)/forc_solai_pp_grc(g,ib)*sky_view_factor(g) + end if + + ! limit albedo to be <= 1 + do ib = 1, numrad + if (apparent_albd_grc(g,ib) > 1._r8) then + apparent_albd_grc(g,ib) = 1._r8 + end if + + if (apparent_albi_grc(g,ib) > 1._r8) then + apparent_albi_grc(g,ib) = 1._r8 + end if + end do + end do + end if + end associate end subroutine lnd2atm_minimal @@ -246,7 +329,7 @@ subroutine lnd2atm(bounds, & ! First, compute the "minimal" set of fields. call lnd2atm_minimal(bounds, & - surfalb_vars, energyflux_vars, lnd2atm_vars) + surfalb_vars, solarabs_vars, energyflux_vars, atm2lnd_vars, lnd2atm_vars) call p2g(bounds, & t_ref2m (bounds%begp:bounds%endp), & diff --git a/components/elm/src/main/lnd2atmType.F90 b/components/elm/src/main/lnd2atmType.F90 index 64bffe47925a..4396256a0a88 100644 --- a/components/elm/src/main/lnd2atmType.F90 +++ b/components/elm/src/main/lnd2atmType.F90 @@ -13,7 +13,7 @@ module lnd2atmType use abortutils , only : endrun use elm_varpar , only : numrad, ndst, nlevsno, nlevgrnd !ndst = number of dust bins. use elm_varcon , only : rair, grav, cpair, hfus, tfrz, spval - use elm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_fan + use elm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_fan, use_finetop_rad use seq_drydep_mod, only : n_drydep, drydep_method, DD_XLND use decompMod , only : bounds_type ! @@ -37,6 +37,8 @@ module lnd2atmType real(r8), pointer :: h2osoi_vol_grc (:,:) => null() ! volumetric soil water (0~watsat, m3/m3, nlevgrnd) (for dust model) real(r8), pointer :: albd_grc (:,:) => null() ! (numrad) surface albedo (direct) real(r8), pointer :: albi_grc (:,:) => null() ! (numrad) surface albedo (diffuse) + real(r8), pointer :: apparent_albd_grc (:,:) => null() ! (numrad) apparent surface albedo (direct) + real(r8), pointer :: apparent_albi_grc (:,:) => null() ! (numrad) apparent surface albedo (diffuse) real(r8), pointer :: taux_grc (:) => null() ! wind stress: e-w (kg/m/s**2) real(r8), pointer :: tauy_grc (:) => null() ! wind stress: n-s (kg/m/s**2) real(r8), pointer :: eflx_lh_tot_grc (:) => null() ! total latent HF (W/m**2) [+ to atm] @@ -44,6 +46,10 @@ module lnd2atmType real(r8), pointer :: eflx_lwrad_out_grc (:) => null() ! IR (longwave) radiation (W/m**2) real(r8), pointer :: qflx_evap_tot_grc (:) => null() ! qflx_evap_soi + qflx_evap_can + qflx_tran_veg real(r8), pointer :: fsa_grc (:) => null() ! solar rad absorbed (total) (W/m**2) + real(r8), pointer :: fsr_vis_d_grc (:) => null() ! reflected direct beam vis solar radiation (W/m**2) + real(r8), pointer :: fsr_vis_i_grc (:) => null() ! reflected diffuse vis solar radiation (W/m**2) + real(r8), pointer :: fsr_nir_d_grc (:) => null() ! reflected direct beam nir solar radiation (W/m**2) + real(r8), pointer :: fsr_nir_i_grc (:) => null() ! reflected diffuse nir solar radiation (W/m**2) real(r8), pointer :: nee_grc (:) => null() ! net CO2 flux (kg CO2/m**2/s) [+ to atm] real(r8), pointer :: nem_grc (:) => null() ! gridcell average net methane correction to CO2 flux (g C/m^2/s) real(r8), pointer :: ram1_grc (:) => null() ! aerodynamical resistance (s/m) @@ -127,6 +133,8 @@ subroutine InitAllocate(this, bounds) allocate(this%h2osoi_vol_grc (begg:endg,1:nlevgrnd)) ; this%h2osoi_vol_grc (:,:) =ival allocate(this%albd_grc (begg:endg,1:numrad)) ; this%albd_grc (:,:) =ival allocate(this%albi_grc (begg:endg,1:numrad)) ; this%albi_grc (:,:) =ival + allocate(this%apparent_albd_grc (begg:endg,1:numrad)) ; this%apparent_albd_grc (:,:) =ival + allocate(this%apparent_albi_grc (begg:endg,1:numrad)) ; this%apparent_albi_grc (:,:) =ival allocate(this%taux_grc (begg:endg)) ; this%taux_grc (:) =ival allocate(this%tauy_grc (begg:endg)) ; this%tauy_grc (:) =ival allocate(this%eflx_lwrad_out_grc (begg:endg)) ; this%eflx_lwrad_out_grc (:) =ival @@ -134,6 +142,10 @@ subroutine InitAllocate(this, bounds) allocate(this%eflx_lh_tot_grc (begg:endg)) ; this%eflx_lh_tot_grc (:) =ival allocate(this%qflx_evap_tot_grc (begg:endg)) ; this%qflx_evap_tot_grc (:) =ival allocate(this%fsa_grc (begg:endg)) ; this%fsa_grc (:) =ival + allocate(this%fsr_vis_d_grc (begg:endg)) ; this%fsr_vis_d_grc (:) =ival + allocate(this%fsr_vis_i_grc (begg:endg)) ; this%fsr_vis_i_grc (:) =ival + allocate(this%fsr_nir_d_grc (begg:endg)) ; this%fsr_nir_d_grc (:) =ival + allocate(this%fsr_nir_i_grc (begg:endg)) ; this%fsr_nir_i_grc (:) =ival allocate(this%nee_grc (begg:endg)) ; this%nee_grc (:) =ival allocate(this%nem_grc (begg:endg)) ; this%nem_grc (:) =ival allocate(this%ram1_grc (begg:endg)) ; this%ram1_grc (:) =ival @@ -185,7 +197,7 @@ end subroutine InitAllocate subroutine InitHistory(this, bounds) ! ! !USES: - use histFileMod, only : hist_addfld1d + use histFileMod, only : hist_addfld1d, hist_addfld2d ! ! !ARGUMENTS: class(lnd2atm_type) :: this @@ -231,6 +243,18 @@ subroutine InitHistory(this, bounds) ptr_lnd=this%flux_nh3_grc) end if + if (use_finetop_rad) then + this%apparent_albd_grc(begg:endg,:) = spval + call hist_addfld2d (fname='APPARENT_ALBD', units='proportion', type2d='numrad', & + avgflag='A', long_name='apparent surface albedo (direct)', & + ptr_gcell=this%apparent_albd_grc, default='inactive', c2l_scale_type='urbanf') + + this%apparent_albi_grc(begg:endg,:) = spval + call hist_addfld2d (fname='APPARENT_ALBI', units='proportion', type2d='numrad', & + avgflag='A', long_name='apparent surface albedo (indirect)', & + ptr_gcell=this%apparent_albi_grc, default='inactive', c2l_scale_type='urbanf') + end if + end subroutine InitHistory end module lnd2atmType diff --git a/components/elm/src/main/surfrdMod.F90 b/components/elm/src/main/surfrdMod.F90 index 48cd79c91f36..a48b2003fbda 100644 --- a/components/elm/src/main/surfrdMod.F90 +++ b/components/elm/src/main/surfrdMod.F90 @@ -36,6 +36,7 @@ module surfrdMod public :: surfrd_get_grid_conn ! Reads grid connectivity information from domain file public :: surfrd_topounit_data ! Read topounit physical properties public :: surfrd_get_topo_for_solar_rad ! Read topography dataset for TOP solar radiation parameterization + public :: surfrd_finetop_data ! Read topography dataset for fineTOP parameterization ! ! !PRIVATE MEMBER FUNCTIONS: private :: surfrd_special ! Read the special landunits @@ -1705,6 +1706,111 @@ subroutine surfrd_get_topo_for_solar_rad(domain,filename) end subroutine surfrd_get_topo_for_solar_rad +!----------------------------------------------------------------------- + subroutine surfrd_finetop_data(domain,filename) +! !DESCRIPTION: +! Read the topography parameters for fineTOP parameterization: +! Assume domain has already been initialized and read + +! !USES: + use domainMod , only : domain_type + use fileutils , only : getfil + use GridcellType, only : grc_pp + use elm_varpar , only : ndir_horizon_angle + +! !ARGUMENTS: + implicit none + type(domain_type),intent(in) :: domain ! domain to init + character(len=*) ,intent(in) :: filename ! grid filename +! +! !CALLED FROM: +! subroutine initialize +! +! !REVISION HISTORY: +! Created by Dalei Hao +! +! !LOCAL VARIABLES: +!EOP + type(file_desc_t) :: ncid ! netcdf file id + integer :: n ! indices + integer :: ni,nj,ns ! size of grid on file + integer :: dimid,varid ! netCDF id's + integer :: ier ! error status + real(r8) :: eps = 1.0e-12_r8 ! lat/lon error tolerance + integer :: beg,end ! local beg,end indices + logical :: isgrid2d ! true => file is 2d lat/lon + real(r8),pointer :: lonc(:),latc(:) ! local lat/lon + character(len=256) :: locfn ! local file name + logical :: readvar ! is variable on file + character(len=32) :: subname = 'surfrd_finetop_data' ! subroutine name +!----------------------------------------------------------------------- + + if (masterproc) then + if (filename == ' ') then + write(iulog,*) trim(subname),' ERROR: filename must be specified ' + call endrun() + else + write(iulog,*) 'Attempting to read topography parameters from fsurdat ',trim(filename) + endif + end if + + call getfil( filename, locfn, 0 ) + call ncd_pio_openfile (ncid, trim(locfn), 0) + call ncd_inqfdims(ncid, isgrid2d, ni, nj, ns) + + if (domain%ns /= ns) then + write(iulog,*) trim(subname),' ERROR: fsurdat file mismatch ns',& + domain%ns,ns + call endrun() + endif + + beg = domain%nbeg + end = domain%nend + + allocate(latc(beg:end),lonc(beg:end)) + + call ncd_io(ncid=ncid, varname='LONGXY', flag='read', data=lonc, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( trim(subname)//' ERROR: LONGXY NOT on fsurdat file' ) + + call ncd_io(ncid=ncid, varname='LATIXY', flag='read', data=latc, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( trim(subname)//' ERROR: LATIXY NOT on fsurdat file' ) + + do n = beg,end + if (abs(latc(n)-domain%latc(n)) > eps .or. & + abs(lonc(n)-domain%lonc(n)) > eps) then + write(iulog,*) trim(subname),' ERROR: fsurdat file mismatch lat,lon',latc(n),& + domain%latc(n),lonc(n),domain%lonc(n),eps + call endrun() + endif + enddo + + call check_dim(ncid, 'ndir_horizon_angle', ndir_horizon_angle) + + call ncd_io(ncid=ncid, varname='SLOPE_DEG', flag='read', data=grc_pp%slope_deg, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( trim(subname)//' ERROR: slope_deg NOT on fsurdat file' ) + call ncd_io(ncid=ncid, varname='ASPECT_DEG', flag='read', data=grc_pp%aspect_deg, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( trim(subname)//' ERROR: aspect_deg NOT on fsurdat file' ) + call ncd_io(ncid=ncid, varname='SKY_VIEW_FACTOR', flag='read', data=grc_pp%sky_view_factor, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( trim(subname)//' ERROR: sky_view_factor NOT on fsurdat file' ) + call ncd_io(ncid=ncid, varname='TERRAIN_CONFIG_FACTOR', flag='read', data=grc_pp%terrain_config_factor, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( trim(subname)//' ERROR: terrain_config_factor NOT on fsurdat file' ) + call ncd_io(ncid=ncid, varname='HORIZON_ANGLE_DEG', flag='read', data=grc_pp%horizon_angle_deg, & + dim1name=grlnd, readvar=readvar) + If (.not. readvar) call endrun( trim(subname)//' ERROR: horizon_angle_deg NOT on fsurdat file' ) + + deallocate(latc,lonc) + + call ncd_pio_closefile(ncid) + + end subroutine surfrd_finetop_data + + subroutine surfrd_fates_nocropmod( ncid, begg, endg ) !-------------------------------------------------------------------------- diff --git a/share/util/shr_orb_mod.F90 b/share/util/shr_orb_mod.F90 index 18a5a91d028f..272662700ba5 100644 --- a/share/util/shr_orb_mod.F90 +++ b/share/util/shr_orb_mod.F90 @@ -11,6 +11,7 @@ MODULE shr_orb_mod !---------------------------------------------------------------------------- ! PUBLIC: Interfaces and global data !---------------------------------------------------------------------------- + public :: shr_orb_azimuth public :: shr_orb_cosz public :: shr_orb_params public :: shr_orb_decl @@ -47,6 +48,42 @@ SUBROUTINE set_constant_zenith_angle_deg(angle_deg) END SUBROUTINE set_constant_zenith_angle_deg !======================================================================= + !======================================================================= + real(SHR_KIND_R8) pure function shr_orb_azimuth(jday,lat,lon,declin,z) + + !---------------------------------------------------------------------------- + ! + ! function returns the solar azimuth angle. + ! azimuth angle is defined with respect to north, positive to east + ! based on Sproul, Renewable Energy, 2007 + ! + !---------------------------------------------------------------------------- + real (SHR_KIND_R8),intent(in) :: jday ! Julian cal day (1.xx to 365.xx) + real (SHR_KIND_R8),intent(in) :: lat ! Centered latitude (radians) + real (SHR_KIND_R8),intent(in) :: lon ! Centered longitude (radians) + real (SHR_KIND_R8),intent(in) :: declin ! Solar declination (radians) + real (SHR_KIND_R8),intent(in) :: z ! Solar zenith angle (radians) + + real(SHR_KIND_R8) :: hour_angle + !---------------------------------------------------------------------------- + + hour_angle = 2.0_SHR_KIND_R8*pi*((jday-floor(jday)) - 0.5_SHR_KIND_R8) + lon + + ! constrain hour_angle to [-pi,pi] to determine east/west below + if(hour_angle > pi) hour_angle = hour_angle - 2.0_SHR_KIND_R8*pi + + shr_orb_azimuth = (sin(declin)*cos(lat) - cos(declin)*sin(lat)*cos(hour_angle))/ sin(z) + + shr_orb_azimuth = max(-1._SHR_KIND_R8, min(shr_orb_azimuth, 1._SHR_KIND_R8)) + + shr_orb_azimuth = acos(shr_orb_azimuth) + + ! azimuth is east for times between midnight and noon (h < 0) + ! azimuth is west for times between noon and midnight (h > 0) + if(hour_angle > 0.) shr_orb_azimuth = 2.0_SHR_KIND_R8*pi - shr_orb_azimuth + + end function shr_orb_azimuth + !======================================================================= real(SHR_KIND_R8) pure FUNCTION shr_orb_cosz(jday,lat,lon,declin,dt_avg,uniform_angle) From 71760ff464009d41b527e4c9c66d4369e4765bd9 Mon Sep 17 00:00:00 2001 From: daleihao Date: Fri, 31 Oct 2025 12:24:01 -0700 Subject: [PATCH 295/398] reformat and clean up the code fix a typo add error message fix a bug to avoid the initilization issue in the debug mode --- .../elm/src/biogeophys/SnowSnicarMod.F90 | 12 ++++-- .../elm/src/biogeophys/SurfaceAlbedoMod.F90 | 40 +++++++++---------- components/elm/src/main/atm2lndMod.F90 | 6 +-- components/elm/src/main/atm2lndType.F90 | 22 +++++----- components/elm/src/main/controlMod.F90 | 10 +++-- 5 files changed, 49 insertions(+), 41 deletions(-) diff --git a/components/elm/src/biogeophys/SnowSnicarMod.F90 b/components/elm/src/biogeophys/SnowSnicarMod.F90 index 61397261e496..157f540c8256 100644 --- a/components/elm/src/biogeophys/SnowSnicarMod.F90 +++ b/components/elm/src/biogeophys/SnowSnicarMod.F90 @@ -2249,7 +2249,6 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & ! for debugging only l_idx = col_pp%landunit(c_idx) - g_idx = col_pp%gridcell(c_idx) sfctype = lun_pp%itype(l_idx) lat_coord = grc_pp%latdeg(g_idx) lon_coord = grc_pp%londeg(g_idx) @@ -2271,8 +2270,15 @@ subroutine SNICAR_AD_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & if (use_finetop_rad) then slope_rad = grc_pp%slope_deg(g_idx) * deg2rad - h2osno_liq_lcl = h2osno_liq_lcl * cos(slope_rad) - h2osno_ice_lcl = h2osno_ice_lcl * cos(slope_rad) + + if ((flg_snw_ice == 1) .and. (snl(c_idx) > -1)) then + h2osno_liq_lcl(0) = h2osno_liq_lcl(0) * cos(slope_rad) + h2osno_ice_lcl(0) = h2osno_ice_lcl(0) * cos(slope_rad) + else + h2osno_liq_lcl(:) = h2osno_liq_lcl(:) * cos(slope_rad) + h2osno_ice_lcl(:) = h2osno_ice_lcl(:) * cos(slope_rad) + endif + h2osno_lcl = h2osno_lcl * cos(slope_rad) endif diff --git a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 index acc652a319be..f36f74411fb5 100644 --- a/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/components/elm/src/biogeophys/SurfaceAlbedoMod.F90 @@ -242,27 +242,27 @@ subroutine SurfaceAlbedo(bounds, & ! Cosine solar zenith angle for next time step deg2rad = SHR_CONST_PI/180._r8 - do g = bounds%begg,bounds%endg - coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1) + if (.not. use_finetop_rad) then + do g = bounds%begg,bounds%endg + coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1) + cosinc_gcell(g) = coszen_gcell(g) + end do + else + do g = bounds%begg,bounds%endg + coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1) + sza = acos(coszen_gcell(g)) ! solar zenith angle + saa = shr_orb_azimuth(nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1, sza) ! solar azimuth angle + + slope_rad = grc_pp%slope_deg(g) * deg2rad + aspect_rad = grc_pp%aspect_deg(g) * deg2rad + + cosinc_gcell(g) = cos(slope_rad) * coszen_gcell(g) + sin(slope_rad) * sin(sza) * cos(aspect_rad - saa) + cosinc_gcell(g) = max(-1._r8, min(cosinc_gcell(g), 1._r8)) + + if (cosinc_gcell(g) <= 0._r8) cosinc_gcell(g) = 0.1_r8 ! although direct solar radiation is zero, we need to calculate diffuse albedo in this case + end do + endif - if (use_finetop_rad) then - ! solar zenith angle - sza = acos(coszen_gcell(g)) - ! solar azimuth angle - saa = shr_orb_azimuth(nextsw_cday, grc_pp%lat(g), grc_pp%lon(g), declinp1, sza) - - slope_rad = grc_pp%slope_deg(g) * deg2rad - aspect_rad = grc_pp%aspect_deg(g) * deg2rad - - cosinc_gcell(g) = cos(slope_rad) * coszen_gcell(g) + sin(slope_rad) * sin(sza) * cos(aspect_rad - saa) - cosinc_gcell(g) = max(-1._r8, min(cosinc_gcell(g), 1._r8)) - !write(iulog,*) 'cosinc_gcell',cosinc_gcell(g) - !write(iulog,*) 'coszen_gcell',coszen_gcell(g) - if (cosinc_gcell(g) <= 0._r8) cosinc_gcell(g) = 0.1_r8 ! although direct solar radiation is zero, we need to calculate diffuse albedo in this case - else - cosinc_gcell(g) = coszen_gcell(g) - endif - end do do c = bounds%begc,bounds%endc g = col_pp%gridcell(c) coszen_col(c) = coszen_gcell(g) diff --git a/components/elm/src/main/atm2lndMod.F90 b/components/elm/src/main/atm2lndMod.F90 index 239972003af1..92b721ee9c70 100644 --- a/components/elm/src/main/atm2lndMod.F90 +++ b/components/elm/src/main/atm2lndMod.F90 @@ -540,9 +540,9 @@ subroutine topographic_effects_on_radiation(bounds, atm2lnd_vars, nextsw_cday, d f_short_dir(g) = 1._r8 f_short_dif(g) = 1._r8 f_short_refl(g,:) = 0._r8 - sza(g) = nan - saa(g) = nan - cosinc(g) = nan + sza(g) = spval + saa(g) = spval + cosinc(g) = spval ! scale shortwave radiation if (cossza > 0.0872_r8) then ! just modify when SZA > 85 degree 0.0872_r8 diff --git a/components/elm/src/main/atm2lndType.F90 b/components/elm/src/main/atm2lndType.F90 index 2a650e1f321f..d663fe085d75 100644 --- a/components/elm/src/main/atm2lndType.F90 +++ b/components/elm/src/main/atm2lndType.F90 @@ -331,14 +331,14 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_uovern (begg:endg)) ; this%forc_uovern (:) = ival if ( use_finetop_rad ) then - allocate(this%f_short_dir (begg:endg)) ; this%f_short_dir (:) = nan - allocate(this%f_short_dif (begg:endg)) ; this%f_short_dif (:) = nan - allocate(this%f_short_refl (begg:endg,numrad)) ; this%f_short_refl (:,:) = nan - allocate(this%f_long_dif (begg:endg)) ; this%f_long_dif (:) = nan - allocate(this%f_long_refl (begg:endg)) ; this%f_long_refl (:) = nan - allocate(this%sza (begg:endg)) ; this%sza (:) = nan - allocate(this%saa (begg:endg)) ; this%saa (:) = nan - allocate(this%cosinc (begg:endg)) ; this%cosinc (:) = nan + allocate(this%f_short_dir (begg:endg)) ; this%f_short_dir (:) = spval + allocate(this%f_short_dif (begg:endg)) ; this%f_short_dif (:) = spval + allocate(this%f_short_refl (begg:endg,numrad)) ; this%f_short_refl (:,:) = spval + allocate(this%f_long_dif (begg:endg)) ; this%f_long_dif (:) = spval + allocate(this%f_long_refl (begg:endg)) ; this%f_long_refl (:) = spval + allocate(this%sza (begg:endg)) ; this%sza (:) = spval + allocate(this%saa (begg:endg)) ; this%saa (:) = spval + allocate(this%cosinc (begg:endg)) ; this%cosinc (:) = spval allocate(this%forc_solad_pp_grc (begg:endg,numrad)) ; this%forc_solad_pp_grc (:,:) = ival allocate(this%forc_solai_pp_grc (begg:endg,numrad)) ; this%forc_solai_pp_grc (:,:) = ival allocate(this%forc_solar_pp_grc (begg:endg)) ; this%forc_solar_pp_grc (:) = ival @@ -578,11 +578,9 @@ subroutine InitHistory(this, bounds) call hist_addfld1d (fname='LWdown_PP', units='W/m^2', & avgflag='A', long_name='atmospheric longwave radiation (PP)', & ptr_gcell=this%forc_lwrad_not_downscaled_pp_grc, default='inactive') - endif - if ( use_finetop_rad ) then - this%forc_solad_pp_grc(begg:endg, :) = 0._r8 - this%forc_solai_pp_grc(begg:endg, :) = 0._r8 + this%forc_solad_pp_grc(begg:endg, :) = 0._r8 + this%forc_solai_pp_grc(begg:endg, :) = 0._r8 endif end subroutine InitHistory diff --git a/components/elm/src/main/controlMod.F90 b/components/elm/src/main/controlMod.F90 index 2c4f703f1dcb..55dd8d76c4f2 100644 --- a/components/elm/src/main/controlMod.F90 +++ b/components/elm/src/main/controlMod.F90 @@ -1123,13 +1123,17 @@ subroutine control_print () if (use_top_solar_rad) then write(iulog,*) ' use TOP solar radiation parameterization instead of PP' else - write(iulog,*) ' use_top_solar_rad is False, so do not run TOP solar radiation parameterization' + write(iulog,*) ' use_top_solar_rad is False, so do not run TOP solar radiation parameterization' end if - if (use_finetop_rad) then + if (use_finetop_rad .and. use_top_solar_rad) then + write(iulog,*) ' cannot use both TOP and fineTOP radiation parameterizations simultaneously' + call endrun(msg=' ERROR: use_finetop_rad and use_top_solar_rad cannot both be set to true.'//& + errMsg(__FILE__, __LINE__)) + else if (use_finetop_rad .and. (.not. use_top_solar_rad)) then write(iulog,*) ' use fineTOP radiation parameterization instead of PP' else - write(iulog,*) ' use_finetop_rad is False, so do not run fineTOP radiation parameterization' + write(iulog,*) ' use_finetop_rad is False, so do not run fineTOP radiation parameterization' end if if (use_cn) then From 95c0a37f249430081e4552c2faec448ac3732409 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 8 Jan 2026 15:53:11 -0700 Subject: [PATCH 296/398] EAMxx: allow nearest-point time interpolation in DataInterpolation --- ...mxx_mam_microphysics_process_interface.cpp | 6 +- .../spa/eamxx_spa_process_interface.cpp | 2 +- .../algorithm/eamxx_data_interpolation.cpp | 15 +- .../algorithm/eamxx_data_interpolation.hpp | 7 + .../tests/data_interpolation_tests.cpp | 309 ++++++++++++------ 5 files changed, 237 insertions(+), 102 deletions(-) diff --git a/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp b/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp index 01731647530a..815ebaba98b2 100644 --- a/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp +++ b/components/eamxx/src/physics/mam/eamxx_mam_microphysics_process_interface.cpp @@ -405,7 +405,7 @@ void MAMMicrophysics::set_oxid_reader() // Beg of any year, since we use yearly periodic timeline util::TimeStamp ref_ts_oxid (1,1,1,0,0,0); data_interp_oxid_ = std::make_shared(grid_,oxid_fields); - data_interp_oxid_->setup_time_database ({oxid_file_name},util::TimeLine::YearlyPeriodic, ref_ts_oxid); + data_interp_oxid_->setup_time_database ({oxid_file_name},util::TimeLine::YearlyPeriodic, DataInterpolation::Linear, ref_ts_oxid); data_interp_oxid_->create_horiz_remappers (oxid_map_file=="none" ? "" : oxid_map_file); data_interp_oxid_->set_logger(m_atm_logger); DataInterpolation::VertRemapData remap_data_oxid; @@ -441,7 +441,7 @@ void MAMMicrophysics::set_linoz_reader(){ } data_interp_linoz_ = std::make_shared(grid_,linoz_fields); - data_interp_linoz_->setup_time_database ({m_linoz_file_name},util::TimeLine::YearlyPeriodic, ref_ts_linoz); + data_interp_linoz_->setup_time_database ({m_linoz_file_name},util::TimeLine::YearlyPeriodic, DataInterpolation::Linear, ref_ts_linoz); data_interp_linoz_->create_horiz_remappers (linoz_map_file=="none" ? "" : linoz_map_file); data_interp_linoz_->set_logger(m_atm_logger); @@ -484,7 +484,7 @@ void MAMMicrophysics::set_elevated_emissions_reader() std::shared_ptr di_vertical = std::make_shared(grid_,vertical_fields); di_vertical->set_input_files_dimname(ShortFieldTagsNames::LEV,"altitude"); di_vertical->set_input_files_dimname(ShortFieldTagsNames::ILEV,"altitude_int"); - di_vertical->setup_time_database ({file_name},util::TimeLine::YearlyPeriodic, ref_ts_vertical); + di_vertical->setup_time_database ({file_name},util::TimeLine::YearlyPeriodic, DataInterpolation::Linear, ref_ts_vertical); di_vertical->create_horiz_remappers (extfrc_map_file=="none" ? "" : extfrc_map_file); di_vertical->set_logger(m_atm_logger); DataInterpolation::VertRemapData remap_data_vertical; diff --git a/components/eamxx/src/physics/spa/eamxx_spa_process_interface.cpp b/components/eamxx/src/physics/spa/eamxx_spa_process_interface.cpp index 810de43ed9aa..fc278aa516f9 100644 --- a/components/eamxx/src/physics/spa/eamxx_spa_process_interface.cpp +++ b/components/eamxx/src/physics/spa/eamxx_spa_process_interface.cpp @@ -86,7 +86,7 @@ void SPA::initialize_impl (const RunType /* run_type */) util::TimeStamp ref_ts (1,1,1,0,0,0); // Beg of any year, since we use yearly periodic timeline m_data_interpolation = std::make_shared(m_model_grid,spa_fields); - m_data_interpolation->setup_time_database ({spa_data_file},util::TimeLine::YearlyPeriodic, ref_ts); + m_data_interpolation->setup_time_database ({spa_data_file},util::TimeLine::YearlyPeriodic, DataInterpolation::Linear, ref_ts); if (m_iop_data_manager!=nullptr) { // IOP cases cannot have a remap file. We will create a IOPRemapper as the horiz remapper diff --git a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp index a953f5246322..8d4825811a13 100644 --- a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp +++ b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.cpp @@ -85,8 +85,16 @@ void DataInterpolation::run (const util::TimeStamp& ts) const auto& end = m_horiz_remapper_end->get_tgt_field(i); auto out = m_vert_remapper->get_src_field(i); - out.deep_copy(beg); - out.update(end,alpha,1-alpha); + if (m_time_interp_type==Linear) { + out.deep_copy(beg); + out.update(end,alpha,1-alpha); + } else { + if (alpha>0.5) { + out.deep_copy(end); + } else { + out.deep_copy(beg); + } + } } // For Dynamic3D/Dynamic3D profile we also need to compute the source pressure profile @@ -228,6 +236,7 @@ init_data_interval (const util::TimeStamp& t0) void DataInterpolation:: setup_time_database (const strvec_t& input_files, const util::TimeLine timeline, + const TimeInterpType interp_type, const util::TimeStamp& ref_ts) { // Log the final list of files, so the user know if something went wrong (e.g. a bad regex) @@ -327,6 +336,8 @@ setup_time_database (const strvec_t& input_files, EKAT_REQUIRE_MSG (m_time_database.size()>=2, "[DataInterpolation] Error! Input file(s) only contain 1 time slice overall.\n"); + m_time_interp_type = interp_type; + m_time_db_created = true; } diff --git a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp index ae517d75ab3e..97206b3bd865 100644 --- a/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp +++ b/components/eamxx/src/share/algorithm/eamxx_data_interpolation.hpp @@ -30,6 +30,11 @@ class DataInterpolation // to set up the src pressure profile (the user will take care of it) }; + enum TimeInterpType { + Linear, + Nearest + }; + struct VertRemapData { VertRemapData() = default; @@ -51,6 +56,7 @@ class DataInterpolation void setup_time_database (const strvec_t& input_files, const util::TimeLine timeline, + const TimeInterpType interp_type = Linear, const util::TimeStamp& ref_ts = util::TimeStamp()); // In case the input files store col/lev dims with exhotic names, the user can provide them here @@ -125,6 +131,7 @@ class DataInterpolation std::pair m_curr_interval_idx; TimeDatabase m_time_database; + TimeInterpType m_time_interp_type; ekat::Comm m_comm; diff --git a/components/eamxx/src/share/algorithm/tests/data_interpolation_tests.cpp b/components/eamxx/src/share/algorithm/tests/data_interpolation_tests.cpp index e16c507889d1..0ef006883ffb 100644 --- a/components/eamxx/src/share/algorithm/tests/data_interpolation_tests.cpp +++ b/components/eamxx/src/share/algorithm/tests/data_interpolation_tests.cpp @@ -52,6 +52,7 @@ void root_print (const ekat::Comm& comm, void run_tests (const std::shared_ptr& grid, const strvec_t& input_files, util::TimeStamp t_beg, const util::TimeLine timeline, + const DataInterpolation::TimeInterpType time_interp_type, const DataInterpolation::VRemapType vr_type = DataInterpolation::None) { auto t_end = t_beg + t_beg.days_in_curr_month()*spd; @@ -121,7 +122,7 @@ void run_tests (const std::shared_ptr& grid, int nfields = fields.size(); auto interp = create_interp(grid,fields); - interp->setup_time_database(input_files,util::TimeLine::YearlyPeriodic); + interp->setup_time_database(input_files,util::TimeLine::YearlyPeriodic,time_interp_type); interp->create_horiz_remappers (map_file); interp->create_vert_remapper (vremap_data); interp->init_data_interval(t0); @@ -149,7 +150,6 @@ void run_tests (const std::shared_ptr& grid, // to do a convex interpolation between f(t=t_beg) and f(t=t_end). util::TimeInterval time_from_beg(t_beg,time,timeline); double alpha = time_from_beg.length / t_beg.days_in_curr_month(); - double delta = delta_data[mm_beg]*(1-alpha) + delta_data[mm_end]*alpha; // Just in case our testing logic is buggy, the run call below should print // similar information, so we can more easily debug. @@ -160,11 +160,14 @@ void run_tests (const std::shared_ptr& grid, << " time : " << time.to_string() << "\n" << " t-beg: " << time_from_beg.length << "\n" << " days in mm_beg: " << t_beg.days_in_curr_month() << "\n" - << " alpha: " << alpha << "\n" - << " delta_beg: " << delta_data[mm_beg] << "\n" - << " delta_end: " << delta_data[mm_end] << "\n" - << " delta: " << delta << "\n"; + << " alpha: " << alpha << "\n"; + } + + if (time_interp_type==DataInterpolation::Nearest) { + alpha = alpha>0.5 ? 1 : 0; } + double delta = delta_data[mm_beg]*(1-alpha) + delta_data[mm_end]*alpha; + // Compute expected difference from base value interp->run(time); for (int i=0; i Date: Fri, 9 Jan 2026 09:24:21 -0700 Subject: [PATCH 297/398] EAMxx: purge old unused stuff from AtmosphereInput --- components/eamxx/src/share/io/scorpio_input.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/eamxx/src/share/io/scorpio_input.hpp b/components/eamxx/src/share/io/scorpio_input.hpp index 0790df65d55a..5f2b761a69ea 100644 --- a/components/eamxx/src/share/io/scorpio_input.hpp +++ b/components/eamxx/src/share/io/scorpio_input.hpp @@ -44,11 +44,6 @@ class AtmosphereInput using fm_type = FieldManager; using grid_type = AbstractGrid; - using KT = KokkosTypes; - template - using view_Nd_host = typename KT::template view_ND::HostMirror; - using view_1d_host = view_Nd_host<1>; - // --- Constructor(s) & Destructor --- // // NOTE: non-trivial constructors simply call the corresponding init method AtmosphereInput () = default; @@ -103,8 +98,6 @@ class AtmosphereInput protected: void set_grid (const std::shared_ptr& grid); - void set_views (const std::map& host_views_1d, - const std::map& layouts); void init_scorpio_structures (); void set_decompositions(); From feba5cdea907ce578ec7066360e2fcbf59fd97d3 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 9 Jan 2026 13:05:43 -0700 Subject: [PATCH 298/398] EAMxx: remove possibility to reset dim decomp in IO It was NEVER used, so keep impl simple and easy to maintain --- .../eamxx_scorpio_interface.cpp | 57 +++++-------------- .../eamxx_scorpio_interface.hpp | 11 +--- 2 files changed, 18 insertions(+), 50 deletions(-) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index 1a2b36aa0e71..d4e182ee3626 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -840,8 +840,7 @@ void set_var_decomp (PIOVar& var, void set_dim_decomp (const std::string& filename, const std::string& dimname, - const std::vector& my_offsets, - const bool allow_reset) + const std::vector& my_offsets) { auto& s = ScorpioSession::instance(); auto& f = impl::get_file(filename,"scorpio::set_decomp"); @@ -853,41 +852,17 @@ void set_dim_decomp (const std::string& filename, " - dimname : " + dimname + "\n"); if (dim.offsets!=nullptr) { - if (allow_reset) { - // We likely won't need the previously created decomps that included this dimension. - // So, as we remove decomps from vars that have this dim, keep track of their name, - // so that we can free them later *if no other users of them remain*. - std::set decomps_to_remove; - for (auto it : f.vars) { - auto v = it.second; - if (v->decomp!=nullptr and v->decomp->dim->name==dimname) { - decomps_to_remove.insert(v->decomp->name); - v->decomp = nullptr; - } - } - for (const auto& dn : decomps_to_remove) { - if (s.decomps.at(dn).use_count()==1) { - auto decomp = s.decomps.at(dn); - // There is no other customer of this decomposition, so we can safely free it - int err = PIOc_freedecomp(s.pio_sysid,decomp->ncid); - check_scorpio_noerr(err,filename,"decomp",dn,"set_dim_decomp","freedecomp"); - s.decomps.erase(dn); - } - } - } else { - // Check that the offsets are (globally) the same - int same = *dim.offsets==my_offsets; - const auto& comm = ScorpioSession::instance().comm; - comm.all_reduce(&same,1,MPI_MIN); - EKAT_REQUIRE_MSG(same==1, - "Error! Attempt to redefine a decomposition with a different dofs distribution.\n" - " - filename: " + filename + "\n" - " - dimname : " + dimname + "\n" - "If you are attempting to redefine the decomp, call this function with throw_if_changing_decomp=false.\n"); + // Not sure if we should error out. For now, if the offsets are the same (on ALL ranks), just return + int same = *dim.offsets==my_offsets; + const auto& comm = ScorpioSession::instance().comm; + comm.all_reduce(&same,1,MPI_MIN); + EKAT_REQUIRE_MSG(same==1, + "Error! Attempt to redefine a decomposition with a different dofs distribution.\n" + " - filename: " + filename + "\n" + " - dimname : " + dimname + "\n"); - // Same decomposition, so we can just return - return; - } + // Same decomposition, so we can just return + return; } // Check that offsets are less than the global dimension length @@ -913,17 +888,15 @@ void set_dim_decomp (const std::string& filename, void set_dim_decomp (const std::string& filename, const std::string& dimname, - const offset_t start, const offset_t count, - const bool allow_reset) + const offset_t start, const offset_t count) { std::vector offsets(count); std::iota(offsets.begin(),offsets.end(),start); - set_dim_decomp(filename,dimname,offsets,allow_reset); + set_dim_decomp(filename,dimname,offsets); } void set_dim_decomp (const std::string& filename, - const std::string& dimname, - const bool allow_reset) + const std::string& dimname) { const auto& comm = ScorpioSession::instance().comm; @@ -937,7 +910,7 @@ void set_dim_decomp (const std::string& filename, comm.scan(&offset,1,MPI_SUM); offset -= len; // scan is inclusive, but we need exclusive - set_dim_decomp (filename,dimname,offset,len,allow_reset); + set_dim_decomp (filename,dimname,offset,len); } // ================== Variable operations ================== // diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp index 7d680be5c8f5..a7613285c04e 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp @@ -131,22 +131,17 @@ std::string get_time_name (const std::string& filename); // - the third version is a shortcut of the second, where we compute start/count based // on a linear decomposition of the dimension along all ranks in the IO comm stored // in the ScorpioInstance. The return value is the local length of the dimension -// - if allow_reset=true, we simply reset the decomposition (if present). -// - if allow_reset=false, if a decomposition for this dim is already set, we error out void set_dim_decomp (const std::string& filename, const std::string& dimname, - const std::vector& my_offsets, - const bool allow_reset = false); + const std::vector& my_offsets); void set_dim_decomp (const std::string& filename, const std::string& dimname, - const offset_t start, const offset_t count, - const bool allow_reset = false); + const offset_t start, const offset_t count); void set_dim_decomp (const std::string& filename, - const std::string& dimname, - const bool allow_reset = false); + const std::string& dimname); // ================== Variable operations ================== // From 27bb22bc6a9986770c0032e122f027d24430d21f Mon Sep 17 00:00:00 2001 From: Peter Bogenschutz Date: Fri, 9 Jan 2026 14:47:25 -0800 Subject: [PATCH 299/398] remove first time step requirement, arrays should be initialized at all times to avoid possible carryover data if there is a major surface pressure adjustment --- components/eam/src/control/iop_data_mod.F90 | 37 ++++++++++----------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/components/eam/src/control/iop_data_mod.F90 b/components/eam/src/control/iop_data_mod.F90 index 4ae375e66979..e382e36536c7 100644 --- a/components/eam/src/control/iop_data_mod.F90 +++ b/components/eam/src/control/iop_data_mod.F90 @@ -645,7 +645,6 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) use error_messages, only : handle_ncerr use netcdf use shr_const_mod, only : SHR_CONST_PI - use time_manager, only : is_first_step !----------------------------------------------------------------------- implicit none #if ( defined RS6000 ) @@ -1037,7 +1036,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q=.true. endif - if ( is_first_step() ) cldobs = 0.0_r8 ! Initialize to zero + cldobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'cld', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, cldobs, status ) if ( status .ne. nf90_noerr ) then @@ -1046,7 +1045,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_cld = .true. endif - if ( is_first_step() ) clwpobs = 0.0_r8 ! Initialize to zero + clwpobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'clwp', .false., & dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, clwpobs, status ) if ( status .ne. nf90_noerr ) then @@ -1065,7 +1064,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if ( is_first_step() ) divq(:,:) = 0.0_r8 ! Initialize all to zero + divq(:,:) = 0.0_r8 ! Initialize all to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1084,7 +1083,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if (is_first_step() ) vertdivq(:,:) = 0.0_r8 ! Initialize all to zero + vertdivq(:,:) = 0.0_r8 ! Initialize all to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivq', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivq(:,1), status ) if ( status .ne. nf90_noerr ) then @@ -1135,7 +1134,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('NUMLIQ', inumliq, abrtf=.false.) if ( inumliq > 0 ) then have_srf = .false. - if ( is_first_step() ) numliqobs = 0.0_r8 ! Initialize to zero + numliqobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMLIQ', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numliqobs, status ) if ( status .ne. nf90_noerr ) then @@ -1148,7 +1147,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('CLDLIQ', icldliq) have_srf = .false. - if ( is_first_step() ) cldliqobs = 0.0_r8 ! Initialize to zero + cldliqobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDLIQ', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldliqobs, status ) if ( status .ne. nf90_noerr ) then @@ -1159,7 +1158,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call cnst_get_ind('CLDICE', icldice) - if ( is_first_step() ) cldiceobs = 0.0_r8 ! Initialize to zero + cldiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, cldiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1172,7 +1171,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) if ( inumice > 0 ) then have_srf = .false. - if ( is_first_step() ) numiceobs = 0.0_r8 ! Initialize to zero + numiceobs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMICE', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, numiceobs, status ) if ( status .ne. nf90_noerr ) then @@ -1192,7 +1191,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if ( is_first_step() ) divu = 0.0_r8 ! Initialize to zero + divu = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divu', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divu, status ) if ( status .ne. nf90_noerr ) then @@ -1211,7 +1210,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if ( is_first_step() ) divv = 0.0_r8 ! Initialize to zero + divv = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divv', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divv, status ) if ( status .ne. nf90_noerr ) then @@ -1230,7 +1229,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if ( is_first_step() ) divt = 0.0_r8 ! Initialize to zero + divt = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'divT', have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt, status ) if ( status .ne. nf90_noerr ) then @@ -1249,7 +1248,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if ( is_first_step() ) vertdivt = 0.0_r8 ! Initialize to zero + vertdivt = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivT', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, vertdivt, status ) if ( status .ne. nf90_noerr ) then @@ -1269,7 +1268,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_srf = .true. endif - if ( is_first_step() ) divt3d = 0.0_r8 ! Initialize to zero + divt3d = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divT3d', & have_srf, srf(1), fill_ends, dplevs, nlev,psobs, hyam, hybm, divt3d, status ) if ( status .ne. nf90_noerr ) then @@ -1309,7 +1308,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) endif ! large scale / geostropic horizontal wind (for nudging) - if ( is_first_step() ) uls = 0.0_r8 ! Initialize to zero + uls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'u_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, uls, status ) if ( status .ne. nf90_noerr ) then @@ -1343,7 +1342,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) call shr_sys_flush( iulog ) ! large scale / geostropic meridional wind (for nudging) - if ( is_first_step() ) vls = 0.0_r8 ! Initialize to zero + vls = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'v_ls', have_srf, srf(1), .true. , dplevs, nlev,psobs, hyam, hybm, vls, status ) if ( status .ne. nf90_noerr ) then @@ -1366,7 +1365,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_prec = .true. endif - if ( is_first_step() ) q1obs = 0.0_r8 ! Initialize to zero + q1obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q1', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q1obs, status ) if ( status .ne. nf90_noerr ) then @@ -1375,7 +1374,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_q1 = .true. endif - if ( is_first_step() ) q2obs = 0.0_r8 ! Initialize to zero + q2obs = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q2', & .false., dummy, fill_ends, dplevs, nlev,psobs, hyam, hybm, q2obs, status ) if ( status .ne. nf90_noerr ) then @@ -1449,7 +1448,7 @@ subroutine readiopdata(iop_update_phase1,hyam,hybm) have_tg = .true. endif - if ( is_first_step() ) wfld = 0.0_r8 ! Initialize to zero + wfld = 0.0_r8 ! Initialize to zero call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, & 'omega', .true., ptend, fill_ends, dplevs, nlev,psobs, hyam, hybm, wfld, status ) if ( status .ne. nf90_noerr ) then From 7fcc2add4a5350807f77bd4bdc88e77523cf4faf Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Tue, 21 Oct 2025 14:07:14 -0700 Subject: [PATCH 300/398] Add mpi_task to gpu affinity script Also, - remove --gpu-bind options - set max mpi+omp to 128 - fix spelling of --cpu-bind - clean-up omp env-vars from mpi-only runs --- cime_config/machines/config_batch.xml | 10 +--------- cime_config/machines/config_machines.xml | 1 + 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/cime_config/machines/config_batch.xml b/cime_config/machines/config_batch.xml index 97aafc482bc8..63a843cc0107 100644 --- a/cime_config/machines/config_batch.xml +++ b/cime_config/machines/config_batch.xml @@ -430,15 +430,7 @@ --constraint=gpu - - --gpus-per-node=4 - --gpu-bind=none - - - --gpus-per-task=1 - --gpu-bind=map_gpu:0,1,2,3 - - + --gpus-per-node=4 --gpu-bind=none diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 3955d541b7a8..7830be26fe84 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -367,6 +367,7 @@ -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} + /global/cfs/cdirs/e3sm/tools/set_affinity_npergpu.sh $SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} From 7c3088835b525789a9120d1fbbdfb4a2d8424ef4 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Tue, 21 Oct 2025 14:10:42 -0700 Subject: [PATCH 301/398] Add S/M/L pe-layouts for ne256-wcyclxx on pm-gpu --- cime_config/allactive/config_pesall.xml | 76 +++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index 7a6d23896c37..e36f595e9cff 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -2528,4 +2528,80 @@ + + + + pm-gpu ne256 for fully coupled cases with ATM on GPU, MPAS on CPU -- WCYCLXX2010 64 nodes, 64x1 + 64 + + 256 + -64 + -64 + -64 + -64 + -64 + + + 1 + 1 + 1 + 1 + + + 16 + + + 16 + + + + pm-gpu ne256 for fully coupled cases with ATM on GPU, MPAS on CPU -- WCYCLXX2010 128 nodes, 64x1 + 64 + + 512 + -128 + -128 + -128 + -128 + -128 + + + 1 + 1 + 1 + 1 + + + 16 + + + 16 + + + + pm-gpu ne256 for fully coupled cases with ATM on GPU, MPAS on CPU -- WCYCLXX2010 128 nodes, 64x1 + 64 + + 1024 + -256 + -256 + -256 + -256 + -256 + + + 1 + 1 + 1 + 1 + + + 16 + + + 16 + + + + From 30d2223f8b0079d382439cd5f9f95fec992eb1d8 Mon Sep 17 00:00:00 2001 From: noel Date: Thu, 11 Dec 2025 14:04:34 -0800 Subject: [PATCH 302/398] OK, maybe i needed to revert the cpu-bind flags to be original, so that a merge will then use the new syntax --- cime_config/machines/config_machines.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 7830be26fe84..5d0a9f7e4a4d 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -175,7 +175,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 256/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} + $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -365,7 +365,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} + $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} /global/cfs/cdirs/e3sm/tools/set_affinity_npergpu.sh $SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -530,7 +530,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 256/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} + $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -725,7 +725,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} + $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -889,7 +889,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 256/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} + $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -1083,7 +1083,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} + $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -3274,7 +3274,7 @@ -np {{ total_tasks }} --label -ppn {{ tasks_per_node }} - --cpu-bind core + --cpu-bindy core -d $SHELL{echo 32/ {{ tasks_per_node }} |bc} $ENV{GPU_TILE_COMPACT} From b5fc94183e4581a21e2d75fc58a2ad6394234daf Mon Sep 17 00:00:00 2001 From: noel Date: Thu, 11 Dec 2025 14:06:00 -0800 Subject: [PATCH 303/398] correct type in previous commit --- cime_config/machines/config_machines.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 5d0a9f7e4a4d..c5e95c58a4db 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3274,7 +3274,7 @@ -np {{ total_tasks }} --label -ppn {{ tasks_per_node }} - --cpu-bindy core + --cpu-bind core -d $SHELL{echo 32/ {{ tasks_per_node }} |bc} $ENV{GPU_TILE_COMPACT} From 1d96663fffdc10d22d6c8b38cd66b2aa814701fe Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Mon, 15 Dec 2025 12:09:07 -0800 Subject: [PATCH 304/398] Move affinity script to cime_config/machines/scripts --- cime_config/machines/config_machines.xml | 2 +- .../machines/scripts/pm-gpu_set_affinity_npergpu.sh | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index c5e95c58a4db..e9c9ce5956f8 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -367,7 +367,7 @@ -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} - /global/cfs/cdirs/e3sm/tools/set_affinity_npergpu.sh $SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} + $SRCROOT/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} diff --git a/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh b/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh new file mode 100755 index 000000000000..6bf19af40c56 --- /dev/null +++ b/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh @@ -0,0 +1,9 @@ +#!/bin/bash +#num_gpus=$(nvidia-smi -L | wc -l) +tasks_per_node=$1 +tasks_per_gpu=$(( ${tasks_per_node} / 4 )) +gpu=$(( (${SLURM_LOCALID} / ${tasks_per_gpu}) % 4 )) +export CUDA_VISIBLE_DEVICES=$gpu +#echo “RANK= ${SLURM_PROCID} LOCAL_RANK= ${SLURM_LOCALID} gpu= ${gpu}” +shift +"$@" From 4c26e9590f4f7a0f47a0bfd472232e01821fb3c0 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Tue, 16 Dec 2025 13:21:42 -0800 Subject: [PATCH 305/398] Bind MPI tasks to GPUs only when 64+ MPI processes per node --- cime_config/allactive/config_pesall.xml | 4 ++-- cime_config/machines/config_machines.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index e36f595e9cff..009cb46c16fd 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -2578,8 +2578,8 @@ 16 - - pm-gpu ne256 for fully coupled cases with ATM on GPU, MPAS on CPU -- WCYCLXX2010 128 nodes, 64x1 + + pm-gpu ne256 for fully coupled cases with ATM on GPU, MPAS on CPU -- WCYCLXX2010 256 nodes, 64x1 64 1024 diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index e9c9ce5956f8..b4ad0f229e83 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -367,7 +367,7 @@ -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} - $SRCROOT/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} + $SHELL{ppn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $ppn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $ppn; fi;} From 0820f7b1cb610cb9997357188faf00bab8761a43 Mon Sep 17 00:00:00 2001 From: noel Date: Fri, 19 Dec 2025 11:14:17 -0800 Subject: [PATCH 306/398] correct a formatting issue in a comment --- cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh b/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh index 6bf19af40c56..173e1071cd95 100755 --- a/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh +++ b/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh @@ -4,6 +4,6 @@ tasks_per_node=$1 tasks_per_gpu=$(( ${tasks_per_node} / 4 )) gpu=$(( (${SLURM_LOCALID} / ${tasks_per_gpu}) % 4 )) export CUDA_VISIBLE_DEVICES=$gpu -#echo “RANK= ${SLURM_PROCID} LOCAL_RANK= ${SLURM_LOCALID} gpu= ${gpu}” +#printf '?RANK= %s LOCAL_RANK= %s gpu= %s?\n' ${SLURM_PROCID} ${SLURM_LOCALID} ${gpu} shift "$@" From 62b3f254d81eff658ac468d00ee00e7fe4502ed9 Mon Sep 17 00:00:00 2001 From: noel Date: Mon, 22 Dec 2025 11:25:03 -0800 Subject: [PATCH 307/398] revert a change already merged in diff PR --- cime_config/machines/config_machines.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index b4ad0f229e83..50d67d185d49 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -457,6 +457,9 @@ 1 1 1 + 128M + spread + threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -464,11 +467,6 @@ $ENV{CRAY_NETCDF_HDF5PARALLEL_PREFIX} $ENV{CRAY_PARALLEL_NETCDF_PREFIX} - - 128M - spread - threads - 1 From 1ddc3976c1024fc97b9c3d36a0cdba153735701f Mon Sep 17 00:00:00 2001 From: noel Date: Mon, 22 Dec 2025 11:27:14 -0800 Subject: [PATCH 308/398] revert change already merged in a diff PR --- cime_config/machines/config_machines.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 50d67d185d49..474001c47715 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -353,8 +353,8 @@ nersc_slurm e3sm 128 - 128 - 128 + 256 + 256 4 64 64 From a5fdf9ed6e69f4548395be513cc868662b6e7cad Mon Sep 17 00:00:00 2001 From: noel Date: Mon, 22 Dec 2025 11:33:07 -0800 Subject: [PATCH 309/398] add same gpu bind treatment to other nersc machines similar to pm-gpu --- cime_config/machines/config_machines.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 474001c47715..e6622b84ac6b 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -367,7 +367,7 @@ -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} - $SHELL{ppn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $ppn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $ppn; fi;} + $SHELL{mpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $mpn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $mpn; fi;} @@ -725,7 +725,8 @@ -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} - + $SHELL{mpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $mpn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $mpn; fi;} + /opt/cray/pe/lmod/8.7.19/init/perl @@ -1083,7 +1084,8 @@ -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} - + $SHELL{mpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $mpn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $mpn; fi;} + /opt/cray/pe/lmod/8.7.19/init/perl From 41cfe754091484e2e4abf34262d7898117bcccd2 Mon Sep 17 00:00:00 2001 From: noel Date: Mon, 22 Dec 2025 13:18:38 -0800 Subject: [PATCH 310/398] minor enhancement to script to make it more general. but it may be fine to just hardcode a value of 4 here --- .../scripts/pm-gpu_set_affinity_npergpu.sh | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh b/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh index 173e1071cd95..4918d1685540 100755 --- a/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh +++ b/cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh @@ -1,9 +1,40 @@ #!/bin/bash -#num_gpus=$(nvidia-smi -L | wc -l) + +# Runtime launcher wrapper designed to enforce round-robin GPU affinity for high-density MPI jobs (e.g., MPN=64 on a 4-GPU node). +# It ensures optimal resource sharing and prevents device contention by partitioning MPI ranks into subgroups per device. + +# example with mpn=tasks_per_node=64 or 64 MPI's per node: +#+------------------+--------------------------+--------------+ +#| Local Rank Range | Logic: (Rank / 16) % 4 | Assigned GPU | +#+------------------+--------------------------+--------------+ +#| 00 - 15 | 0 / 16 ... 15 / 16 = 0 | dev0 | +#| 16 - 31 | 16 / 16 ... 31 / 16 = 1 | dev1 | +#| 32 - 47 | 32 / 16 ... 47 / 16 = 2 | dev2 | +#| 48 - 63 | 48 / 16 ... 63 / 16 = 3 | dev3 | +#+------------------+--------------------------+--------------+ + +# Get total MPI tasks per node from first argument tasks_per_node=$1 -tasks_per_gpu=$(( ${tasks_per_node} / 4 )) -gpu=$(( (${SLURM_LOCALID} / ${tasks_per_gpu}) % 4 )) + +# Dynamically detect the number of GPUs on this node +num_gpus=$(nvidia-smi -L | wc -l) + +# Calculate how many tasks share each GPU +# If 64 tasks and 4 GPUs, tasks_per_gpu = 16 +tasks_per_gpu=$(( ${tasks_per_node} / ${num_gpus} )) + +# Use 0 if SLURM_LOCALID is not set +local_id=${SLURM_LOCALID:-0} + +# Assign GPU based on Local Rank +# The modulo (%) handles edge cases if tasks_per_node isn't perfectly divisible +gpu=$(( (${local_id} / ${tasks_per_gpu}) % ${num_gpus} )) + export CUDA_VISIBLE_DEVICES=$gpu + #printf '?RANK= %s LOCAL_RANK= %s gpu= %s?\n' ${SLURM_PROCID} ${SLURM_LOCALID} ${gpu} +#echo "Rank ${SLURM_PROCID} (Local ${SLURM_LOCALID}) assigned to GPU ${gpu}" + +# Clean up arguments and launch the application shift -"$@" +exec "$@" From 3138334eac625c0e6cd49312e74246e23d1eb1fd Mon Sep 17 00:00:00 2001 From: noel Date: Mon, 22 Dec 2025 17:09:00 -0800 Subject: [PATCH 311/398] add other nersc machines with pm-gpu for these new pelayouts --- cime_config/allactive/config_pesall.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/allactive/config_pesall.xml b/cime_config/allactive/config_pesall.xml index 009cb46c16fd..b411f39410d7 100644 --- a/cime_config/allactive/config_pesall.xml +++ b/cime_config/allactive/config_pesall.xml @@ -2529,7 +2529,7 @@ - + pm-gpu ne256 for fully coupled cases with ATM on GPU, MPAS on CPU -- WCYCLXX2010 64 nodes, 64x1 64 From 6636a41363aceb9aa4d1b035e1ae2719e61d12f8 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sat, 10 Jan 2026 14:34:21 -0800 Subject: [PATCH 312/398] Add changes from PRs #7851,#7932 after the rebase of this PR #7818 --- cime_config/machines/config_machines.xml | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index e6622b84ac6b..2a6347be5287 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -175,7 +175,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 256/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} + $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -260,9 +260,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -273,6 +270,11 @@ $ENV{CRAY_LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH} CMA + + 128M + spread + threads + /global/cfs/cdirs/e3sm/3rdparty/protobuf/21.6/intel-2023.2.0/lib/pkgconfig:$ENV{PKG_CONFIG_PATH} $SHELL{if [ -z "$ADIOS2_ROOT" ]; then echo /global/cfs/cdirs/e3sm/3rdparty/adios2/2.10.2/cray-mpich-8.1.28/intel-2023.2.0; else echo "$ADIOS2_ROOT"; fi} @@ -353,8 +355,8 @@ nersc_slurm e3sm 128 - 256 - 256 + 128 + 128 4 64 64 @@ -365,7 +367,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} + $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} $SHELL{mpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $mpn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $mpn; fi;} @@ -457,9 +459,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -467,6 +466,11 @@ $ENV{CRAY_NETCDF_HDF5PARALLEL_PREFIX} $ENV{CRAY_PARALLEL_NETCDF_PREFIX} + + 128M + spread + threads + 1 @@ -528,7 +532,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 256/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} + $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -723,7 +727,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} + $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} $SHELL{mpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $mpn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $mpn; fi;} @@ -888,7 +892,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 256/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} + $SHELL{if [ 128 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} @@ -1082,7 +1086,7 @@ --label -n {{ total_tasks }} -N {{ num_nodes }} -c $SHELL{echo 128/`./xmlquery --value MAX_MPITASKS_PER_NODE`|bc} - $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu_bind=cores"; else echo "--cpu_bind=threads";fi;} + $SHELL{if [ 64 -ge `./xmlquery --value MAX_MPITASKS_PER_NODE` ]; then echo "--cpu-bind=cores"; else echo "--cpu-bind=threads";fi;} -m plane=$SHELL{echo `./xmlquery --value MAX_MPITASKS_PER_NODE`} $SHELL{mpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`; if [ 64 -le $mpn ]; then echo $CIMEROOT/../cime_config/machines/scripts/pm-gpu_set_affinity_npergpu.sh $mpn; fi;} From 59f90dd5ac90d9331f2ad7aa33d32d68b3e0e576 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sat, 10 Jan 2026 15:40:40 -0800 Subject: [PATCH 313/398] Keep MMF-compsets bound to the first 4 mpi tasks on-node --- cime_config/machines/config_batch.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cime_config/machines/config_batch.xml b/cime_config/machines/config_batch.xml index 63a843cc0107..97aafc482bc8 100644 --- a/cime_config/machines/config_batch.xml +++ b/cime_config/machines/config_batch.xml @@ -430,7 +430,15 @@ --constraint=gpu - + + --gpus-per-node=4 + --gpu-bind=none + + + --gpus-per-task=1 + --gpu-bind=map_gpu:0,1,2,3 + + --gpus-per-node=4 --gpu-bind=none From d4bd8611998919ec9f0343aaf49c354af741f7f1 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sun, 11 Jan 2026 00:41:11 +0000 Subject: [PATCH 314/398] Update cuda module on ALCF-Polaris after 2026-Jan-7 maint Update cuda module on ALCF-Polaris after 2026-Jan-7 maint: - cuda/12.6->12.9 - also update env-var NVIDIA_PATH->CUDA_HOME and link -lstdc++ --- cime_config/machines/cmake_macros/gnugpu_polaris.cmake | 2 +- cime_config/machines/config_machines.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/machines/cmake_macros/gnugpu_polaris.cmake b/cime_config/machines/cmake_macros/gnugpu_polaris.cmake index a300214c5260..01308c02ac13 100644 --- a/cime_config/machines/cmake_macros/gnugpu_polaris.cmake +++ b/cime_config/machines/cmake_macros/gnugpu_polaris.cmake @@ -15,4 +15,4 @@ set(MPIFC "ftn") set(SCC "cc") set(SCXX "CC") set(SFC "ftn") -string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{NVIDIA_PATH}/cuda/lib64/ ") +string(APPEND CMAKE_EXE_LINKER_FLAGS " -L$ENV{CUDA_HOME}/lib64/ -lstdc++ ") diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 3955d541b7a8..c3c887f1c90b 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3304,7 +3304,7 @@ netcdf-nvidia/4.9.3c-4.6.2f - cuda/12.6 + cuda/12.9 craype-accel-nvidia80 From 571a1dc43dd51b5cc55db93719fded2b2b48b26e Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sun, 11 Jan 2026 03:38:17 -0600 Subject: [PATCH 315/398] Update oneapi compiler modules on Chrysalis --- .../machines/cmake_macros/oneapi-ifx.cmake | 2 +- .../cmake_macros/oneapi-ifx_chrysalis.cmake | 3 +++ cime_config/machines/config_machines.xml | 16 +++++++++------- 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 cime_config/machines/cmake_macros/oneapi-ifx_chrysalis.cmake diff --git a/cime_config/machines/cmake_macros/oneapi-ifx.cmake b/cime_config/machines/cmake_macros/oneapi-ifx.cmake index 45ed57aa2daf..4cc9e1227051 100644 --- a/cime_config/machines/cmake_macros/oneapi-ifx.cmake +++ b/cime_config/machines/cmake_macros/oneapi-ifx.cmake @@ -13,7 +13,7 @@ string(APPEND CMAKE_CXX_FLAGS_DEBUG " -O0 -g") string(APPEND CMAKE_C_FLAGS " -fp-model precise -std=gnu99 -gline-tables-only -g") string(APPEND CMAKE_CXX_FLAGS " -fp-model precise -gline-tables-only -g") # -mllvm -disable-hir-temp-cleanup for oneapi v2025.2.0 https://github.com/argonne-lcf/AuroraBugTracking/issues/64 -string(APPEND CMAKE_Fortran_FLAGS " -traceback -convert big_endian -assume byterecl -assume realloc_lhs -fp-model precise -gline-tables-only -g -mllvm -disable-hir-temp-cleanup") +string(APPEND CMAKE_Fortran_FLAGS " -traceback -convert big_endian -assume byterecl -assume realloc_lhs -fp-model precise -mllvm -disable-hir-temp-cleanup") string(APPEND CPPDEFS " -DFORTRANUNDERSCORE -DNO_R16 -DCPRINTEL -DHAVE_SLASHPROC -DHIDE_MPI") string(APPEND CMAKE_Fortran_FORMAT_FIXED_FLAG " -fixed -132") string(APPEND CMAKE_Fortran_FORMAT_FREE_FLAG " -free") diff --git a/cime_config/machines/cmake_macros/oneapi-ifx_chrysalis.cmake b/cime_config/machines/cmake_macros/oneapi-ifx_chrysalis.cmake new file mode 100644 index 000000000000..d4125f5dd355 --- /dev/null +++ b/cime_config/machines/cmake_macros/oneapi-ifx_chrysalis.cmake @@ -0,0 +1,3 @@ + +string(APPEND CMAKE_EXE_LINKER_FLAGS " -L/gpfs/fs1/soft/chrysalis/spack-latest/opt/spack/linux-rhel8-x86_64/gcc-8.5.0/gcc-11.3.0-jkpmtgq/lib64 -lstdc++") + diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 3955d541b7a8..90d33d0b041a 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -2664,15 +2664,14 @@ parallel-netcdf/1.11.0-ifdodru - intel-oneapi-compilers/2022.2.0-dioefq5 - intel-oneapi-mkl/2022.2.0-w2y75l6 + intel-oneapi-compilers/2025.2.0-mdlxe55 - openmpi/4.1.3-ti25nay - hdf5/1.10.7-clocd2t - netcdf-c/4.7.4-nw7dztf - netcdf-fortran/4.5.3-qa6rhpj - parallel-netcdf/1.11.0-ejxy7kk + openmpi/4.1.8-nygtpa3 + hdf5/1.14.6-5cgownf + netcdf-c/4.9.3-mekqsor + netcdf-fortran/4.6.2-cjqpiwp + parallel-netcdf/1.14.1-f2fwvr2 $CIME_OUTPUT_ROOT/$CASE/run @@ -2719,6 +2718,9 @@ $SHELL{if [ -z "$SZ_ROOT" ]; then echo /lcrc/soft/climate/sz/2.1.12.5/gcc-11.2.0; else echo "$SZ_ROOT"; fi} $SHELL{if [ -z "$ZFP_ROOT" ]; then echo /lcrc/soft/climate/zfp/1.0.1/gcc-11.2.0; else echo "$ZFP_ROOT"; fi} + + $ENV{NETCDF_FORTRAN_PATH}/lib:$ENV{NETCDF_C_PATH}/lib:/gpfs/fs1/soft/chrysalis/spack-latest/opt/spack/linux-rhel8-x86_64/gcc-8.5.0/gcc-11.3.0-jkpmtgq/lib64:$ENV{LD_LIBRARY_PATH} + From f1c884cac34f76501cb31e3683f724b8636f7ab3 Mon Sep 17 00:00:00 2001 From: noel Date: Sun, 11 Jan 2026 11:09:01 -0800 Subject: [PATCH 316/398] move OMP section for pm-cpu missed in #7932 --- cime_config/machines/config_machines.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 3955d541b7a8..c2b5d3f661a4 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -260,9 +260,6 @@ 1 1 1 - 128M - spread - threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -273,6 +270,11 @@ $ENV{CRAY_LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH} CMA + + 128M + spread + threads + /global/cfs/cdirs/e3sm/3rdparty/protobuf/21.6/intel-2023.2.0/lib/pkgconfig:$ENV{PKG_CONFIG_PATH} $SHELL{if [ -z "$ADIOS2_ROOT" ]; then echo /global/cfs/cdirs/e3sm/3rdparty/adios2/2.10.2/cray-mpich-8.1.28/intel-2023.2.0; else echo "$ADIOS2_ROOT"; fi} From 6de1ee77898f0b4157cd1ba0acb03a92456fc390 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sun, 11 Jan 2026 11:46:22 -0800 Subject: [PATCH 317/398] Revert pm-cpu omp changes --- cime_config/machines/config_machines.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 2a6347be5287..da8ae77781ef 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -260,6 +260,9 @@ 1 1 1 + 128M + spread + threads FALSE /global/cfs/cdirs/e3sm/perl/lib/perl5-only-switch kdreg2 @@ -270,11 +273,6 @@ $ENV{CRAY_LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH} CMA - - 128M - spread - threads - /global/cfs/cdirs/e3sm/3rdparty/protobuf/21.6/intel-2023.2.0/lib/pkgconfig:$ENV{PKG_CONFIG_PATH} $SHELL{if [ -z "$ADIOS2_ROOT" ]; then echo /global/cfs/cdirs/e3sm/3rdparty/adios2/2.10.2/cray-mpich-8.1.28/intel-2023.2.0; else echo "$ADIOS2_ROOT"; fi} From 06d3ca48bd93ad51468a203cb2983d3ff6767662 Mon Sep 17 00:00:00 2001 From: Gregory Lemieux Date: Mon, 12 Jan 2026 12:12:38 -0800 Subject: [PATCH 318/398] updating finidat check to use trim for comparison --- components/elm/src/main/elm_driver.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 2d0e9a625b95..1e43b57c399f 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -1373,8 +1373,8 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) ! On the first step, send the solar zenith angles to FATES on non-continue restarts ! for the two-stream radiation scheme. if (use_fates .and. .not.doalb .and. get_nstep() == 1 .and. nsrest == nsrStartup) then - if ( (finidat == ' ') .or. & - (fates_radiation_model=='twostream') .and. .not.use_fates_sp ) then + if ( (trim(finidat) == '') .or. & + (fates_radiation_model=='twostream' .and. .not.use_fates_sp )) then call alm_fates%wrap_canopy_radiation(bounds_clump,surfalb_vars,nextsw_cday,declinp1) end if end if From 4b77dd670da315b47acf3763c296f45c26b12079 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 12 Jan 2026 13:26:14 -0700 Subject: [PATCH 319/398] Fix cld_fraction cmake [BFB] --- .../eamxx/tests/single-process/cld_fraction/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index c68b44febccc..85c11c530ecb 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -132,7 +132,7 @@ if (NOT EAMXX_ENABLE_GPU) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output_ml.yaml ${CMAKE_CURRENT_BINARY_DIR}/output_ml_${POSTFIX}.yaml) - CreateUnitTestFromExec(cld_frac_net_${POSTFIX} cld_frac_net_standalone + CreateUnitTestFromExec(cld_frac_net_${POSTFIX} cld_fraction_standalone EXE_ARGS "--args -ifile=input_ml_${POSTFIX}.yaml" LABELS cld_fraction FIXTURES_SETUP cld_frac_net_${POSTFIX}) From a8fa8f15efbaa9da33ad802e682443e37a6a127d Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 12 Jan 2026 14:03:41 -0700 Subject: [PATCH 320/398] Rework fix --- .../cld_fraction/CMakeLists.txt | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index 85c11c530ecb..cb30ed67b928 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -115,40 +115,40 @@ if (EAMXX_ENABLE_PYTHON) # So that we know, below, that we can run cpp-vs-py test for cld_frac_net output set (HAS_CLD_FRAC_NET_PY TRUE) endif() -endif() + if (NOT EAMXX_ENABLE_GPU) + ##################################### + # CldFracNet (CPP) # + ##################################### -if (NOT EAMXX_ENABLE_GPU) - ##################################### - # CldFracNet (CPP) # - ##################################### + # Create test that runs lapis-generated emulator + unset (PY_MODULE_NAME) + set (POSTFIX cpp) + set (EMULATOR lapis) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/input_ml_${POSTFIX}.yaml) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output_ml.yaml + ${CMAKE_CURRENT_BINARY_DIR}/output_ml_${POSTFIX}.yaml) - # Create test that runs lapis-generated emulator - unset (PY_MODULE_NAME) - set (POSTFIX cpp) - set (EMULATOR lapis) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input_ml.yaml - ${CMAKE_CURRENT_BINARY_DIR}/input_ml_${POSTFIX}.yaml) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/output_ml.yaml - ${CMAKE_CURRENT_BINARY_DIR}/output_ml_${POSTFIX}.yaml) - - CreateUnitTestFromExec(cld_frac_net_${POSTFIX} cld_fraction_standalone - EXE_ARGS "--args -ifile=input_ml_${POSTFIX}.yaml" - LABELS cld_fraction - FIXTURES_SETUP cld_frac_net_${POSTFIX}) - - if (HAS_CLD_FRAC_NET_PY) - # Compare output of py and cpp tests of cld_frac_net - set (SRC_FILE "cld_frac_net_standalone_output_cpp.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") - set (TGT_FILE "cld_frac_net_standalone_output_py.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") - set (TEST_NAME cld_frac_net_standalone_cpp_vs_py) - add_test (NAME ${TEST_NAME} - COMMAND ${SCREAM_BASE_DIR}/scripts/compare-nc-files - -s ${SRC_FILE} -t ${TGT_FILE} --tol 1e-6 - -c cldfrac_ice=cldfrac_ice cldfrac_tot=cldfrac_tot - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set_tests_properties(${TEST_NAME} PROPERTIES - LABELS "cldfrac;infrastructure" - FIXTURES_REQUIRED "cld_frac_net_py;cld_frac_net_cpp") + CreateUnitTestFromExec(cld_frac_net_${POSTFIX} cld_frac_net_standalone + EXE_ARGS "--args -ifile=input_ml_${POSTFIX}.yaml" + LABELS cld_fraction + FIXTURES_SETUP cld_frac_net_${POSTFIX}) + + if (HAS_CLD_FRAC_NET_PY) + # Compare output of py and cpp tests of cld_frac_net + set (SRC_FILE "cld_frac_net_standalone_output_cpp.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") + set (TGT_FILE "cld_frac_net_standalone_output_py.INSTANT.nsteps_x1.np1.${RUN_T0}.nc") + set (TEST_NAME cld_frac_net_standalone_cpp_vs_py) + add_test (NAME ${TEST_NAME} + COMMAND ${SCREAM_BASE_DIR}/scripts/compare-nc-files + -s ${SRC_FILE} -t ${TGT_FILE} --tol 1e-6 + -c cldfrac_ice=cldfrac_ice cldfrac_tot=cldfrac_tot + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(${TEST_NAME} PROPERTIES + LABELS "cldfrac;infrastructure" + FIXTURES_REQUIRED "cld_frac_net_py;cld_frac_net_cpp") + endif() endif() endif() + From d82676f4e28d578b635d924b484fa1742e79deed Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 12 Jan 2026 14:05:42 -0700 Subject: [PATCH 321/398] Merge more ifs --- .../eamxx/tests/single-process/cld_fraction/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt index cb30ed67b928..7038e19206de 100644 --- a/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt +++ b/components/eamxx/tests/single-process/cld_fraction/CMakeLists.txt @@ -114,9 +114,7 @@ if (EAMXX_ENABLE_PYTHON) # So that we know, below, that we can run cpp-vs-py test for cld_frac_net output set (HAS_CLD_FRAC_NET_PY TRUE) - endif() - if (NOT EAMXX_ENABLE_GPU) ##################################### # CldFracNet (CPP) # ##################################### From 928fd9e2a6158c8d52b86a48ec9b48286c5dbf31 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 9 Jan 2026 14:22:44 -0700 Subject: [PATCH 322/398] EAMxx: allow arbitrary decomp of 2+ dims in scorpio interface The dims must be the leading dims (i.e., slowest strides) and contiguous --- .../eamxx_scorpio_interface.cpp | 204 ++++++++++++------ .../eamxx_scorpio_interface.hpp | 6 + .../scorpio_interface/eamxx_scorpio_types.hpp | 42 ++-- .../tests/scorpio_interface_tests.cpp | 67 ++++++ 4 files changed, 242 insertions(+), 77 deletions(-) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index d4e182ee3626..5487d39169b9 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -30,20 +30,8 @@ struct ScorpioSession template using strmap_t = std::map; - strmap_t files; - strmap_t> decomps; - - // In the above map, we would like to label decomps as dtype_dim1$N1_dim2$N2... - // where N$i is the global length of dim$i. However, it *may* happen that we use - // two different decompositions for the same global layout, which would clash - // the names. For this reason, we append at the end an increasing counter, - // which disambiguate between globally-equivalent partitions. - // When adding a new decomp, we check this map to see if another decomp - // already exists with the same global layout. If so, we first check to see - // if that decomp is equivalent to the new one *on all ranks*. If yes, we - // recycle it, otherwise we create a new PIO decomp. - // strmap_t> decomp_global_layout_to_decomp_name; - // strmap_t decomp_global_layout_to_counter; + strmap_t files; + strmap_t> decomps; int pio_sysid = -1; int pio_type_default = -1; @@ -681,7 +669,12 @@ int get_dimlen_local (const std::string& filename, const std::string& dimname) " - dimname : " + dimname + "\n"); const auto& dim = pf.file->dims.at(dimname); - return dim->offsets==nullptr ? dim->length : dim->offsets->size(); + EKAT_REQUIRE_MSG (dim->decomp_rank<=1, + "Error! Could not inquire dimension local length. The dimension is decomposed together with other dims.\n" + " - filename: " + filename + "\n" + " - dimname : " + dimname + "\n"); + + return dim->decomp_rank==0 ? dim->length : pf.file->dim_decomps.at(dim->name)->offsets.size(); } bool has_time_dim (const std::string& filename) @@ -749,41 +742,54 @@ void reset_time_dim_len (const std::string& filename, const int new_length) void set_var_decomp (PIOVar& var, const std::string& filename) { - for (size_t i=1; ioffsets==nullptr, - "Error! We currently only allow decomposition on slowest-striding dimension.\n" - " Generalizing is not complicated, but it was not a priority.\n" - " - filename: " + filename + "\n" - " - varname : " + var.name + "\n" - " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" - " - bad dim : " + var.dims[i]->name + "\n"); - } - EKAT_REQUIRE_MSG (var.dims[0]->offsets!=nullptr, - "Error! Calling set_var_decomp, but the var first dimension does not appear to be decomposed.\n" - " - filename: " + filename + "\n" - " - varname : " + var.name + "\n" - " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n"); EKAT_REQUIRE_MSG (var.decomp==nullptr, "Error! You should have invalidated var.decomp before attempting to reset it.\n" " - filename : " + filename + "\n" " - varname : " + var.name + "\n" " - var decomp: " + var.decomp->name + "\n"); - // Create decomp name: dtype-dim1_dim2_..._dimk - std::shared_ptr decomp_dim; - std::string decomp_tag = var.dtype + "-"; - for (auto d : var.dims) { - decomp_tag += d->name + "<" + std::to_string(d->length) + ">_"; + // First, check if this var actually needs a decomp + int ndims = var.dims.size(); + + int decomp_rank = 0; + int num_decomp = 0; + int last_decomp = -1; + for (int idim=0; idimdecomp_rank>0) { + decomp_rank = d->decomp_rank; + ++num_decomp; + last_decomp = idim; + } } - decomp_tag.pop_back(); // remove trailing underscore + if (decomp_rank==0) { + // None of the var dims is decomposed + return; + } + if (num_decomp_dim2_..._dimk + auto get_dimtag = [](const auto dim) { + return dim->name + "<" + std::to_string(dim->length) + ">"; + }; + std::string decomp_tag = var.dtype + "-" + ekat::join(var.dims,get_dimtag,"_"); // Check if a decomp with this name already exists auto& s = ScorpioSession::instance(); - auto& decomp = s.decomps[decomp_tag]; #ifndef NDEBUG // Extra check: all ranks must agree on whether they have the decomposition! // If they don't agree, some rank will be stuck in a PIO call, waiting for others - int found = decomp==nullptr ? 0 : 1; + int found = s.decomps.count(decomp_tag); int min_found, max_found; const auto& comm = ScorpioSession::instance().comm; comm.all_reduce(&found,&min_found,1,MPI_MIN); @@ -793,31 +799,46 @@ void set_var_decomp (PIOVar& var, " - filename: " + filename + "\n" " - varname : " + var.name + "\n" " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" - " - decopm tag: " + decomp_tag + "\n"); + " - decomp tag: " + decomp_tag + "\n"); #endif - if (decomp==nullptr) { - // We haven't create this decomp yet. Go ahead and create one - decomp = std::make_shared(); - decomp->name = decomp_tag; - decomp->dim = var.dims[0]; + if (s.decomps.count(decomp_tag)==0) { + auto& f = s.files[filename]; - int ndims = var.dims.size(); + EKAT_REQUIRE_MSG (num_decomp>=decomp_rank, + "Error! We cannot decomposed this variable, as it contained multiple decomposed dims that were not decompsed together.\n" + " - filename: " + filename + "\n" + " - varname : " + var.name + "\n"); // Get ALL dims global lengths, and compute prod of *non-decomposed* dims - std::vector gdimlen = {decomp->dim->length}; - int non_decomp_dim_prod = 1; - for (int idim=1; idim gdimlen; + for (int idim=0; idimlength); - non_decomp_dim_prod *= d->length; } + // We haven't create this decomp yet. Go ahead and create one + auto& decomp = s.decomps[decomp_tag]; + decomp = std::make_shared(); + decomp->name = decomp_tag; + + // Retrieve the dim decomp + std::vector decomp_dim_names; + int non_decomp_dim_prod = 1; + for (auto d : var.dims) { + if (d->decomp_rank>0) { + decomp_dim_names.push_back(d->name); + } else { + non_decomp_dim_prod *= d->length; + } + } + decomp->dim_decomp = f.dim_decomps.at(ekat::join(decomp_dim_names,"_")); + // Create offsets list - const auto& dim_offsets = *decomp->dim->offsets; - int dim_loc_len = dim_offsets.size(); - decomp->offsets.resize (non_decomp_dim_prod*dim_loc_len); - for (int idof=0; idofdim_decomp->offsets; + int decomp_loc_len = dim_offsets.size(); + decomp->offsets.resize (non_decomp_dim_prod*decomp_loc_len); + for (int idof=0; idofoffsets.begin()+ idof*non_decomp_dim_prod; auto end = beg + non_decomp_dim_prod; @@ -835,14 +856,13 @@ void set_var_decomp (PIOVar& var, } // Set decomp data in the var - var.decomp = decomp; + var.decomp = s.decomps.at(decomp_tag); } void set_dim_decomp (const std::string& filename, const std::string& dimname, const std::vector& my_offsets) { - auto& s = ScorpioSession::instance(); auto& f = impl::get_file(filename,"scorpio::set_decomp"); auto& dim = impl::get_dim(filename,dimname,"scorpio::set_dim_decomp"); @@ -851,9 +871,10 @@ void set_dim_decomp (const std::string& filename, " - filename: " + filename + "\n" " - dimname : " + dimname + "\n"); - if (dim.offsets!=nullptr) { + auto& dim_decomp = f.dim_decomps[dimname]; + if (dim_decomp!=nullptr) { // Not sure if we should error out. For now, if the offsets are the same (on ALL ranks), just return - int same = *dim.offsets==my_offsets; + int same = dim_decomp->offsets==my_offsets; const auto& comm = ScorpioSession::instance().comm; comm.all_reduce(&same,1,MPI_MIN); EKAT_REQUIRE_MSG(same==1, @@ -875,7 +896,9 @@ void set_dim_decomp (const std::string& filename, " - offset : " + std::to_string(o) + "\n"); } - dim.offsets = std::make_shared>(my_offsets); + dim_decomp = std::make_shared(); + dim_decomp->offsets = my_offsets; + dim.decomp_rank = 1; // If vars were already defined, we need to process them, // and create the proper PIODecomp objects. @@ -913,6 +936,68 @@ void set_dim_decomp (const std::string& filename, set_dim_decomp (filename,dimname,offset,len); } +void set_dims_decomp (const std::string& filename, + const std::vector& dimnames, + const std::vector& my_offsets) +{ + auto& f = impl::get_file(filename,"scorpio::set_decomp"); + + std::vector dims; + int dims_prod = 1; + for (const auto& n : dimnames) { + dims.push_back(impl::get_dim(filename,n,"scorpio::set_dims_decomp")); + EKAT_REQUIRE_MSG (not dims.back().unlimited, + "Error! Cannot partition an unlimited dimension.\n" + " - filename: " + filename + "\n" + " - dimname : " + n + "\n"); + + dims_prod *= dims.back().length; + } + + auto& dim_decomp = f.dim_decomps[ekat::join(dimnames,"_")]; + if (dim_decomp!=nullptr) { + // Not sure if we should error out. For now, if the offsets are the same (on ALL ranks), just return + int same = dim_decomp->offsets==my_offsets; + const auto& comm = ScorpioSession::instance().comm; + comm.all_reduce(&same,1,MPI_MIN); + EKAT_REQUIRE_MSG(same==1, + "Error! Attempt to redefine a decomposition with a different dofs distribution.\n" + " - filename: " + filename + "\n" + " - dimnames: " + ekat::join(dimnames,",") + "\n"); + + // Same decomposition, so we can just return + return; + } + + // Check that offsets are less than the global dimension length + for (auto o : my_offsets) { + EKAT_REQUIRE_MSG (o>=0 && o(); + dim_decomp->offsets = my_offsets; + for (const auto& n : dimnames) { + f.dims[n]->decomp_rank = dimnames.size(); + dim_decomp->dims.push_back(f.dims[n]); + } + + // If vars were already defined, we need to process them, + // and create the proper PIODecomp objects. + for (auto it : f.vars) { + for (const auto& n : dimnames) { + if (ekat::contains(it.second->dim_names(),n)) { + set_var_decomp (*it.second,filename); + break; + } + } + } +} + // ================== Variable operations ================== // // Define var on output file (cannot call on Read/Append files) @@ -974,9 +1059,8 @@ void define_var (const std::string& filename, const std::string& varname, set_attribute(filename,varname,"units",units); } - if (var->dims.size()>0 and var->dims[0]->offsets!=nullptr) { - set_var_decomp (*var,filename); - } + // Set var decomp (will return quickly if none of the dims is decomposed) + set_var_decomp (*var,filename); } else { const auto& var = f.vars.at(varname); // The variable was already defined. Check that important metadata is the same diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp index a7613285c04e..c77b417eb552 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp @@ -143,6 +143,12 @@ void set_dim_decomp (const std::string& filename, void set_dim_decomp (const std::string& filename, const std::string& dimname); +// This version declares a decomposition of a group of dimensions. The offsets +// represent the offsets in the tensor-product of the dimensions. +void set_dims_decomp (const std::string& filename, + const std::vector& dimnames, + const std::vector& my_offsets); + // ================== Variable operations ================== // // Define var on output file (cannot call on Read/Append files) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_types.hpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_types.hpp index 2fd545c9e05a..65a5c71ef7d1 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_types.hpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_types.hpp @@ -63,26 +63,33 @@ struct PIOFileEntity : public PIOEntity { // A dimension struct PIODim : public PIOFileEntity { - int length = -1; - bool unlimited = false; - - // In case we decompose the dimension, this will store - // the owned offsets on this rank - // NOTE: use a pointer, so we can detect if a decomposition already - // existed or not when we set one. - std::shared_ptr> offsets; + int length = -1; + bool unlimited = false; + + // Track if/how this dim is decomposed + // - if 0, this dim is NOT decomposed. + // - if 1, this dim is decomposed by itself + // - if N, this dim is part of a joint decomp of N dimensions + int decomp_rank = 0; +}; + +// A decomposition of a set of 1+ dimensions. The offsets establish +// which of the (global) indices of the dims tensor product +// are owned on the current rank. +struct DimDecomp { + std::vector offsets; // Owned offsets + std::vector> dims; // Dimensions that participate in the decomp }; -// A decomposition // NOTE: the offsets of a PIODecomp are not the same as the offsets of -// stored in its dim. The latter are the offsets *along that dim*. -// A PIODecomp is associated with a Nd layout, which includes decomp_dim -// among its dimensions. PIODecomp::offsets are the offsets of the full -// array layout owned by this rank. Hence, there can be many PIODecomp +// stored in DimDecomp. The latter are the offsets *along those dims*. +// A PIOVarDecomp is associated with a Nd layout, which may include additional +// dimensions on top of the decomposed one. Hence, there can be many PIOVarDecomp // all storing the same dim struct PIODecomp : public PIOEntity { - std::vector offsets; // Owned offsets - std::shared_ptr dim; + std::vector offsets; // Owned var offsets + + std::shared_ptr dim_decomp; }; // A variable @@ -118,8 +125,9 @@ struct PIOVar : public PIOFileEntity { // A file, which is basically a container for dims and vars struct PIOFile : public PIOEntity { - std::map> dims; - std::map> vars; + std::map> dims; + std::map> vars; + std::map> dim_decomps; std::shared_ptr time_dim; FileMode mode; diff --git a/components/eamxx/src/share/scorpio_interface/tests/scorpio_interface_tests.cpp b/components/eamxx/src/share/scorpio_interface/tests/scorpio_interface_tests.cpp index dfba24867627..3c4213cdb1d5 100644 --- a/components/eamxx/src/share/scorpio_interface/tests/scorpio_interface_tests.cpp +++ b/components/eamxx/src/share/scorpio_interface/tests/scorpio_interface_tests.cpp @@ -209,4 +209,71 @@ TEST_CASE ("write_and_read") { finalize_subsystem (); } +TEST_CASE ("joint_decomp") { + ekat::Comm comm (MPI_COMM_WORLD); + + init_subsystem (comm); + + std::string filename = "scorpio_interface_write_joint_decomp_test_np" + std::to_string(comm.size()) + ".nc"; + + const int dim1 = 3; + const int dim2 = 10; + const int dim3 = comm.size(); + + // Offsets for dim3 decomp owned by this rank + std::vector my_offsets; + for (int i=0; i var1 (ldim); + for (int i=0; i var1 (dim1*dim2); + + std::vector tgt_var1 (dim1*dim2); + std::iota (tgt_var1.begin(),tgt_var1.end(),0); + + read_var (filename,"var1",var1.data()); + REQUIRE (tgt_var1==var1); + + // Cleanup + release_file (filename); + } + + finalize_subsystem (); +} + + } // namespace scream From a053f7d5ad836550df7f0892ab8668e34ce15f0f Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 12 Jan 2026 16:05:30 -0700 Subject: [PATCH 323/398] EAMxx: do not store mutex in grid base class Instead, use a static local mutex when needed in the methods --- .../eamxx/src/share/grid/abstract_grid.cpp | 20 ++++++++++++------- .../eamxx/src/share/grid/abstract_grid.hpp | 4 ---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/components/eamxx/src/share/grid/abstract_grid.cpp b/components/eamxx/src/share/grid/abstract_grid.cpp index 08554f67088b..c4e84de07c57 100644 --- a/components/eamxx/src/share/grid/abstract_grid.cpp +++ b/components/eamxx/src/share/grid/abstract_grid.cpp @@ -233,7 +233,8 @@ bool AbstractGrid::is_unique () const { }; - std::lock_guard lock(m_mutex); // Lock the mutex + static std::mutex m; + std::lock_guard lock(m); // Lock the mutex if (not m_is_unique_computed) { m_is_unique = compute_is_unique(); m_is_unique_computed = true; @@ -256,7 +257,7 @@ is_valid_layout (const FieldLayout& layout) const case LayoutType::Scalar1D: return layout.congruent(get_vertical_layout(midpoints)); case LayoutType::Vector1D: - return layout.congruent(get_vertical_layout(midpoints,layout.get_vector_dim())); + return layout.congruent(get_vertical_layout(midpoints,layout.get_vector_dim())); case LayoutType::Scalar2D: return layout.congruent(get_2d_scalar_layout()); case LayoutType::Vector2D: @@ -278,7 +279,8 @@ is_valid_layout (const FieldLayout& layout) const auto AbstractGrid:: get_global_min_dof_gid () const ->gid_type { - std::lock_guard lock(m_mutex); // Lock the mutex + static std::mutex m; + std::lock_guard lock(m); // Lock the mutex // Lazy calculation if (m_global_min_dof_gid==std::numeric_limits::max()) { m_global_min_dof_gid = field_min(m_dofs_gids,&get_comm()).as(); @@ -289,7 +291,8 @@ get_global_min_dof_gid () const ->gid_type auto AbstractGrid:: get_global_max_dof_gid () const ->gid_type { - std::lock_guard lock(m_mutex); // Lock the mutex + static std::mutex m; + std::lock_guard lock(m); // Lock the mutex // Lazy calculation if (m_global_max_dof_gid==-std::numeric_limits::max()) { m_global_max_dof_gid = field_max(m_dofs_gids,&get_comm()).as(); @@ -300,7 +303,8 @@ get_global_max_dof_gid () const ->gid_type auto AbstractGrid:: get_global_min_partitioned_dim_gid () const ->gid_type { - std::lock_guard lock(m_mutex); // Lock the mutex + static std::mutex m; + std::lock_guard lock(m); // Lock the mutex // Lazy calculation if (m_global_min_partitioned_dim_gid==std::numeric_limits::max()) { m_global_min_partitioned_dim_gid = field_min(m_partitioned_dim_gids,&get_comm()).as(); @@ -311,7 +315,8 @@ get_global_min_partitioned_dim_gid () const ->gid_type auto AbstractGrid:: get_global_max_partitioned_dim_gid () const ->gid_type { - std::lock_guard lock(m_mutex); // Lock the mutex + static std::mutex m; + std::lock_guard lock(m); // Lock the mutex // Lazy calculation if (m_global_max_partitioned_dim_gid==-std::numeric_limits::max()) { m_global_max_partitioned_dim_gid = field_max(m_partitioned_dim_gids,&get_comm()).as(); @@ -641,7 +646,8 @@ void AbstractGrid::create_dof_fields (const int scalar2d_layout_rank) auto AbstractGrid::get_gid2lid_map () const -> const std::map& { - std::lock_guard lock(m_mutex); // Lock the mutex + static std::mutex m; + std::lock_guard lock(m); // Lock the mutex int cur_sz = m_gid2lid.size(); if (cur_sz // Mutable, for lazy calculation mutable std::map m_gid2lid; - // For thread safety in modifying mutable items (just in case someone ever runs this code in - // threaded regions) - mutable std::mutex m_mutex; - // The MPI comm containing the ranks across which the global mesh is partitioned ekat::Comm m_comm; }; From ea276fa2c11d098ef0c87b300902c873d66bbce9 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 12 Jan 2026 16:08:57 -0700 Subject: [PATCH 324/398] EAMxx: allow to cleanup unused decomps in scorpio_interface Helps in unit tests where the same file is used multiple times with different grid decompositions --- .../eamxx_scorpio_interface.cpp | 20 +++++++++++++++++-- .../eamxx_scorpio_interface.hpp | 5 +++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index 5487d39169b9..ab2ffd55d7e2 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -200,7 +200,7 @@ size_t dtype_size (const std::string& dtype) { } int pio_iotype (IOType iotype) { - int iotype_int; + int iotype_int = {}; auto& s = ScorpioSession::instance(); switch(iotype){ case IOType::DefaultIOType: iotype_int = s.pio_type_default; break; @@ -998,6 +998,22 @@ void set_dims_decomp (const std::string& filename, } } +void clear_unused_decomps () +{ + auto& s = ScorpioSession::instance(); + + for (auto it=s.decomps.begin(); it!=s.decomps.end(); ) { + if (it->second.use_count()==1) { + int err = PIOc_freedecomp(s.pio_sysid,it->second->ncid); + check_scorpio_noerr(err,"clear_unused_decomps","freedecomp"); + + it = s.decomps.erase(it); + } else { + ++it; + } + } +} + // ================== Variable operations ================== // // Define var on output file (cannot call on Read/Append files) @@ -1475,7 +1491,7 @@ T get_attribute (const std::string& filename, err = PIOc_inq_atttype(pf.file->ncid,varid,attname.c_str(),&att_type); check_scorpio_noerr(err,filename,"attribute",attname,"get_attribute","inq_atttype"); - T val; + T val = T{}; if (att_type!=nctype(get_dtype())) { if (att_type==PIO_INT) { diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp index c77b417eb552..2d7b941f9b98 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.hpp @@ -149,6 +149,11 @@ void set_dims_decomp (const std::string& filename, const std::vector& dimnames, const std::vector& my_offsets); +// Clears all decompositions not currently in use +// This helps in some unit tests, where the same file is used +// in two different moments, with different grid decompositions +void clear_unused_decomps (); + // ================== Variable operations ================== // // Define var on output file (cannot call on Read/Append files) From 54afeb88f4c93b06de473e83fee0c0b90218339d Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 12 Jan 2026 16:11:28 -0700 Subject: [PATCH 325/398] EAMxx: allow to specify GID index base when creating point grid Helps in unit tests, when creating grids that need to work with NCO map files --- components/eamxx/src/share/grid/point_grid.cpp | 5 +++-- components/eamxx/src/share/grid/point_grid.hpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/eamxx/src/share/grid/point_grid.cpp b/components/eamxx/src/share/grid/point_grid.cpp index b950eec8780d..ece433d9666a 100644 --- a/components/eamxx/src/share/grid/point_grid.cpp +++ b/components/eamxx/src/share/grid/point_grid.cpp @@ -143,14 +143,15 @@ std::shared_ptr create_point_grid (const std::string& grid_name, const int num_global_cols, const int num_vertical_lev, - const ekat::Comm& comm) + const ekat::Comm& comm, + const int gid_base) { // Compute how many columns are owned by this rank const int num_procs = comm.size(); auto num_my_cols = num_global_cols / num_procs; int remainder = num_global_cols % num_procs; - int dof_offset = num_my_cols*comm.rank(); + int dof_offset = num_my_cols*comm.rank() + gid_base; if (comm.rank() < remainder) { ++num_my_cols; dof_offset += comm.rank(); diff --git a/components/eamxx/src/share/grid/point_grid.hpp b/components/eamxx/src/share/grid/point_grid.hpp index 4f9b18c0e1dc..a6546225a409 100644 --- a/components/eamxx/src/share/grid/point_grid.hpp +++ b/components/eamxx/src/share/grid/point_grid.hpp @@ -76,7 +76,8 @@ std::shared_ptr create_point_grid (const std::string& name, const int num_global_cols, const int num_vertical_lev, - const ekat::Comm& comm); + const ekat::Comm& comm, + const int gid_base = 0); } // namespace scream From 8881e225891f1d4b7fafb15a5620d705d288d46d Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Tue, 13 Jan 2026 01:21:01 -0600 Subject: [PATCH 326/398] Add missing atm_gustiness handling to moab import Add handling of atm_gustiness and implicit_stress to the moab import to match mct. The mct import was covering for it. --- components/elm/src/cpl/lnd_comp_mct.F90 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/elm/src/cpl/lnd_comp_mct.F90 b/components/elm/src/cpl/lnd_comp_mct.F90 index 6bfabe91f1ed..0a8069ec2b21 100644 --- a/components/elm/src/cpl/lnd_comp_mct.F90 +++ b/components/elm/src/cpl/lnd_comp_mct.F90 @@ -1210,6 +1210,7 @@ subroutine lnd_import_moab(EClock, bounds, atm2lnd_vars, glc2lnd_vars) use fileutils , only: getavu, relavu use spmdmod , only: masterproc, mpicom, iam, npes, MPI_REAL8, MPI_INTEGER, MPI_STATUS_SIZE use elm_nlUtilsMod , only : find_nlgroup_name + use FrictionVelocityMod, only: implicit_stress, atm_gustiness use seq_timemgr_mod, only : seq_timemgr_eclockgetdata use netcdf ! @@ -1430,9 +1431,21 @@ subroutine lnd_import_moab(EClock, bounds, atm2lnd_vars, glc2lnd_vars) top_as%ubot(topo) = x2l_lm(i,index_x2l_Sa_u) ! forc_uxy Atm state m/s top_as%vbot(topo) = x2l_lm(i,index_x2l_Sa_v) ! forc_vxy Atm state m/s top_as%zbot(topo) = x2l_lm(i,index_x2l_Sa_z) ! zgcmxy Atm state m + if (implicit_stress) then + top_as%wsresp(topo) = x2l_lm(i,index_x2l_Sa_wsresp) ! Atm state m/s/Pa + top_as%tau_est(topo) = x2l_lm(i,index_x2l_Sa_tau_est)! Atm state Pa + end if + if (atm_gustiness) then + top_as%ugust(topo) = x2l_lm(i,index_x2l_Sa_ugust) ! Atm state m/s + else + top_as%ugust(topo) = 0._r8 + end if ! assign the state forcing fields derived from other inputs ! Horizontal windspeed (m/s) top_as%windbot(topo) = sqrt(top_as%ubot(topo)**2 + top_as%vbot(topo)**2) + if (atm_gustiness) then + top_as%windbot(topo) = sqrt(top_as%windbot(topo)**2 + top_as%ugust(topo)**2) + end if ! Relative humidity (percent) if (top_as%tbot(topo) > SHR_CONST_TKFRZ) then e = esatw(tdc(top_as%tbot(topo))) From ad54060de7d3e42a5df195bba4d45d7c2f7bd2f8 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Tue, 13 Jan 2026 01:32:15 -0600 Subject: [PATCH 327/398] Move define and init of x2l_lm Move define and init of x2l_lm so that do_histinit will work. --- driver-moab/main/prep_lnd_mod.F90 | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/driver-moab/main/prep_lnd_mod.F90 b/driver-moab/main/prep_lnd_mod.F90 index b73080a10f3a..9ea92d4016a6 100644 --- a/driver-moab/main/prep_lnd_mod.F90 +++ b/driver-moab/main/prep_lnd_mod.F90 @@ -40,6 +40,7 @@ module prep_lnd_mod iMOAB_WriteMesh, iMOAB_GetMeshInfo, iMOAB_SetDoubleTagStorage, & iMOAB_SetMapGhostLayers, iMOAB_MigrateMapMesh use seq_comm_mct, only : num_moab_exports + use shr_moab_mod, only : mbGetnCells, mbGetCellTagVals #ifdef MOABCOMP use component_type_mod, only: compare_mct_av_moab_tag @@ -152,6 +153,7 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln character(CL) :: rof_gnam ! rof grid character(CL) :: glc_gnam ! glc grid type(mct_avect), pointer :: l2x_lx + type(mct_avect), pointer :: x2l_lx ! MOAB stuff integer :: ierr, idintx, rank character*32 :: appname @@ -168,6 +170,7 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln integer nvert(3), nvise(3), nbl(3), nsurf(3), nvisBC(3) ! for moab info integer mlsize ! moab land size integer nrflds ! number of rof fields projected on land + integer nflds ! number of x2l fields for MOAB allocation integer arrsize ! for setting the r2x fields on land to 0 integer ent_type ! for setting tags real (kind=R8) , allocatable :: tmparray (:) ! used to set the r2x fields to 0 @@ -208,8 +211,17 @@ subroutine prep_lnd_init(infodata, atm_c2_lnd, rof_c2_lnd, glc_c2_lnd, iac_c2_ln mpicom=mpicom_CPLID, iamroot=iamroot_CPLID) l2x_lx => component_get_c2x_cx(lnd(1)) + x2l_lx => component_get_x2c_cx(lnd(1)) lsize_l = mct_aVect_lsize(l2x_lx) + ! Allocate x2l_lm for MOAB history output (used by prep_lnd_get_x2l_lm) + if (mblxid .ge. 0) then + mlsize = mbGetnCells(mblxid) + nflds = mct_aVect_nRattr(x2l_lx) + allocate(x2l_lm(mlsize, nflds)) + x2l_lm = 0.0_r8 + endif + allocate(a2x_lx(num_inst_atm)) do eai = 1,num_inst_atm call mct_aVect_init(a2x_lx(eai), rList=seq_flds_a2x_fields, lsize=lsize_l) @@ -749,9 +761,6 @@ end subroutine prep_lnd_mrg ! this does almost nothing now, except documenting subroutine prep_lnd_mrg_moab (infodata) - use shr_moab_mod, only : mbGetnCells - use shr_moab_mod, only : mbGetCellTagVals - type(seq_infodata_type) , intent(in) :: infodata @@ -801,8 +810,6 @@ subroutine prep_lnd_mrg_moab (infodata) nflds = mct_aVect_nRattr(x2l_l) mbsize = mbGetnCells(mblxid) - allocate (x2l_lm(mbsize,nflds)) - allocate(mrgstr(nflds)) do i = 1,nflds field = mct_aVect_getRList2c(i, x2l_l) @@ -839,7 +846,7 @@ subroutine prep_lnd_mrg_moab (infodata) ! call mct_aVect_copy(aVin=r2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=r2x_SharedIndices) ! call mct_aVect_copy(aVin=g2x_l, aVout=x2l_l, vector=mct_usevector, sharedIndices=g2x_SharedIndices) - call mbGetCellTagVals(mblxid, trim(seq_flds_x2l_fields)//C_NULL_CHAR,x2l_lm,mbsize*nflds) + call mbGetCellTagVals(mblxid, trim(seq_flds_x2l_fields),x2l_lm,mbsize*nflds) if (first_time) then if (iamroot) then From 76a98625842a62360ced46eef41cd3d58be07e2d Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 12 Jan 2026 17:16:12 -0700 Subject: [PATCH 328/398] EAMxx: add grids interface to read geometry data from file --- .../eamxx/src/share/grid/CMakeLists.txt | 3 +- .../eamxx/src/share/grid/abstract_grid.cpp | 71 +++++++++++++++++++ .../eamxx/src/share/grid/abstract_grid.hpp | 9 +++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/components/eamxx/src/share/grid/CMakeLists.txt b/components/eamxx/src/share/grid/CMakeLists.txt index b89fccc6e5cd..c0a4eec39f33 100644 --- a/components/eamxx/src/share/grid/CMakeLists.txt +++ b/components/eamxx/src/share/grid/CMakeLists.txt @@ -8,7 +8,8 @@ add_library(eamxx_grid target_link_libraries (eamxx_grid PUBLIC eamxx_core eamxx_utils - eamxx_field) + eamxx_field + eamxx_scorpio_interface) if (NOT SCREAM_LIB_ONLY) add_subdirectory(tests) diff --git a/components/eamxx/src/share/grid/abstract_grid.cpp b/components/eamxx/src/share/grid/abstract_grid.cpp index c4e84de07c57..77b9162e972d 100644 --- a/components/eamxx/src/share/grid/abstract_grid.cpp +++ b/components/eamxx/src/share/grid/abstract_grid.cpp @@ -1,6 +1,7 @@ #include "share/grid/abstract_grid.hpp" #include "share/field/field_utils.hpp" +#include "share/scorpio_interface/eamxx_scorpio_interface.hpp" #include @@ -392,6 +393,76 @@ AbstractGrid::delete_geometry_data (const std::string& name) m_geo_fields.erase(name); } +void AbstractGrid:: +read_geometry_data(const std::string& filename, + const std::vector& names, + const std::map& dim_to_ncdim) +{ + read_geometry_data(filename,names,names,dim_to_ncdim); +} + +void AbstractGrid:: +read_geometry_data(const std::string& filename, + const std::vector& names, + const std::vector& nc_names, + const std::map& dim_to_ncdim) +{ + EKAT_REQUIRE_MSG (names.size()==nc_names.size(), + "[AbstractGrid] Error! Input names and nc_names sizes differ.\n" + " - grid name: " + this->name() + "\n" + " - geo data names: " + ekat::join(names,",") + "\n" + " - nc vars names: " + ekat::join(nc_names,",") + "\n"); + scorpio::register_file(filename,scorpio::Read); + + for (size_t i=0; iname() + "\n" + " - geo data name: " + names[i] + "\n"); + + auto f = m_geo_fields.at(names[i]); + const auto& fl = f.get_header().get_identifier().get_layout(); + + // If one of the field tags corresponds to the partitioned dim, init the decomp + if (fl.has_tag(get_partitioned_dim_tag())) { + auto t = get_partitioned_dim_tag(); + std::string dimname = has_special_tag_name(t) + ? get_special_tag_name(t) + : e2str(t); + auto gids_h = get_partitioned_dim_gids().get_view(); + auto min_gid = get_global_min_partitioned_dim_gid(); + std::vector offsets(m_num_local_dofs); + for (int idof=0; idof()); + break; + case DataType::FloatType: + scorpio::read_var(filename,nc_names[i],f.get_internal_view_data()); + break; + case DataType::IntType: + scorpio::read_var(filename,nc_names[i],f.get_internal_view_data()); + break; + default: + EKAT_ERROR_MSG ( + "Error! Unsupported/unrecognized data type while reading field from file.\n" + " - file name : " + filename + "\n" + " - field name: " + names[i] + "\n"); + } + + // Ensure data is up to date on device, since we read on host + f.sync_to_dev(); + } + + scorpio::release_file(filename); +} + void AbstractGrid::set_geometry_data (const Field& f) const { diff --git a/components/eamxx/src/share/grid/abstract_grid.hpp b/components/eamxx/src/share/grid/abstract_grid.hpp index 4d7271f8ac7a..ceca2bf87fa7 100644 --- a/components/eamxx/src/share/grid/abstract_grid.hpp +++ b/components/eamxx/src/share/grid/abstract_grid.hpp @@ -180,6 +180,15 @@ class AbstractGrid : public std::enable_shared_from_this void set_geometry_data(const Field &f) const; void delete_geometry_data(const std::string &name); + // Reads some geometry data from file + void read_geometry_data(const std::string& filename, + const std::vector& names, + const std::map& dim_to_ncdim = {}); + void read_geometry_data(const std::string& filename, + const std::vector& names, + const std::vector& nc_names, + const std::map& dim_to_ncdim = {}); + bool has_geometry_data(const std::string &name) const { From b30eee818655d8439f5b51696e1efc71425974f9 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 12 Jan 2026 17:17:45 -0700 Subject: [PATCH 329/398] EAMxx: add possibility to treat horizontal remap tgt grid as lat x lon grid --- .../src/share/io/eamxx_output_manager.cpp | 4 + .../eamxx/src/share/io/scorpio_output.cpp | 68 +++++--- .../eamxx/src/share/io/scorpio_output.hpp | 3 +- .../src/share/remap/coarsening_remapper.cpp | 147 ++++++++++++++++++ .../src/share/remap/coarsening_remapper.hpp | 2 + 5 files changed, 205 insertions(+), 19 deletions(-) diff --git a/components/eamxx/src/share/io/eamxx_output_manager.cpp b/components/eamxx/src/share/io/eamxx_output_manager.cpp index 7bee9e085c1a..c97fec6d5b1e 100644 --- a/components/eamxx/src/share/io/eamxx_output_manager.cpp +++ b/components/eamxx/src/share/io/eamxx_output_manager.cpp @@ -151,6 +151,10 @@ setup (const std::shared_ptr& field_mgr, // pio decomp for this var, since there are no dimensions. // Perhaps you can explore setting the var as a global att continue; + } else if (f.get_header().has_extra_data("save_as_geo_data") and + not f.get_header().get_extra_data("save_as_geo_data")) { + // This field is NOT to be saved as geo data + continue; } if (use_suffix) { fields.push_back(f.clone(f.name() + grid.second->m_disambiguation_suffix, grid.first)); diff --git a/components/eamxx/src/share/io/scorpio_output.cpp b/components/eamxx/src/share/io/scorpio_output.cpp index 69bb3d1fbfad..3a11c98afdcb 100644 --- a/components/eamxx/src/share/io/scorpio_output.cpp +++ b/components/eamxx/src/share/io/scorpio_output.cpp @@ -111,7 +111,7 @@ AtmosphereOutput::AtmosphereOutput(const ekat::Comm &comm, const ekat::Parameter // By default, IO is done directly on the field mgr grid auto fm_grid = field_mgr->get_grids_manager()->get_grid(grid_name); - + std::string output_data_layout = "default"; if (params.isParameter("field_names")) { // This simple parameter list option does *not* allow to remap fields @@ -304,6 +304,7 @@ void AtmosphereOutput::init() { auto fm_after_hr = m_field_mgrs[AfterHorizRemap]; m_io_grid = fm_after_hr->get_grid(); + m_latlon_output = m_io_grid->has_geometry_data("lat_idx"); EKAT_REQUIRE_MSG (m_io_grid->is_unique(), "Error! I/O only supports grids which are 'unique', meaning that the\n" @@ -343,6 +344,16 @@ void AtmosphereOutput::init() const auto& tags = layout.tags(); const auto& dims = layout.dims(); for (int j=0; jget_geometry_data("lat"); + auto lon = m_io_grid->get_geometry_data("lon"); + + m_dims_len.emplace("lat",lat.get_header().get_identifier().get_layout().size()); + m_dims_len.emplace("lon",lon.get_header().get_identifier().get_layout().size()); + + continue; + } // check tag against m_dims_len map. If not in there, then add it. std::string dimname = m_io_grid->has_special_tag_name(tags[j]) ? m_io_grid->get_special_tag_name(tags[j]) @@ -858,19 +869,32 @@ register_variables(const std::string& filename, void AtmosphereOutput::set_decompositions(const std::string& filename) { - if (m_decomp_dimname=="") - return; + if (m_latlon_output) { + // We need to find out which (lat,lon) offsets we own + auto lat_idx_h = m_io_grid->get_geometry_data("lat_idx").get_view(); + auto lon_idx_h = m_io_grid->get_geometry_data("lon_idx").get_view(); + int ncols = m_io_grid->get_num_local_dofs(); + int nlon = m_io_grid->get_geometry_data("lon").get_header().get_identifier().get_layout().size(); + std::vector offsets(ncols); + for (int i=0; iget_partitioned_dim_local_size(); - auto gids_f = m_io_grid->get_partitioned_dim_gids(); - auto gids_h = gids_f.get_view(); - auto min_gid = m_io_grid->get_global_min_partitioned_dim_gid(); - std::vector offsets(local_dim); - for (int idof=0; idofget_partitioned_dim_local_size(); + auto gids_f = m_io_grid->get_partitioned_dim_gids(); + auto gids_h = gids_f.get_view(); + auto min_gid = m_io_grid->get_global_min_partitioned_dim_gid(); + std::vector offsets(local_dim); + for (int idof=0; idof AtmosphereOutput:: get_var_dimnames (const FieldLayout& layout) const { + using namespace ShortFieldTagsNames; strvec_t dims; for (int i=0; ihas_special_tag_name(t) - ? m_io_grid->get_special_tag_name(t) - : layout.names()[i]; - if (tag_name=="dim" or tag_name=="bin") { - tag_name += std::to_string(layout.dim(i)); + if (t==COL and m_latlon_output) { + // Lat-Lon remapping uses a PointGrid target grid, so we replace the + // single column dimension with separate latitude and longitude dimensions. + dims.push_back("lat"); + dims.push_back("lon"); + } else { + auto tag_name = m_io_grid->has_special_tag_name(t) + ? m_io_grid->get_special_tag_name(t) + : layout.names()[i]; + if (tag_name=="dim" or tag_name=="bin") { + tag_name += std::to_string(layout.dim(i)); + } + dims.push_back(tag_name); // Add dimensions string to vector of dims. } - dims.push_back(tag_name); // Add dimensions string to vector of dims. } return dims; } diff --git a/components/eamxx/src/share/io/scorpio_output.hpp b/components/eamxx/src/share/io/scorpio_output.hpp index 243c032a45a6..f91eb8b046e7 100644 --- a/components/eamxx/src/share/io/scorpio_output.hpp +++ b/components/eamxx/src/share/io/scorpio_output.hpp @@ -229,7 +229,8 @@ class AtmosphereOutput DefaultMetadata m_default_metadata; bool m_add_time_dim; - bool m_track_avg_cnt = false; + bool m_track_avg_cnt = false; + bool m_latlon_output = false; std::string m_decomp_dimname = ""; std::shared_ptr m_atm_logger = diff --git a/components/eamxx/src/share/remap/coarsening_remapper.cpp b/components/eamxx/src/share/remap/coarsening_remapper.cpp index 1938d8de7008..9234d65c1e4d 100644 --- a/components/eamxx/src/share/remap/coarsening_remapper.cpp +++ b/components/eamxx/src/share/remap/coarsening_remapper.cpp @@ -1,5 +1,6 @@ #include "coarsening_remapper.hpp" +#include "share/scorpio_interface/eamxx_scorpio_interface.hpp" #include "share/grid/point_grid.hpp" #include "share/grid/grid_import_export.hpp" #include "share/field/field.hpp" @@ -11,6 +12,42 @@ namespace scream { +namespace { + +struct RealsClose { + // Find the unique lat/lon values + bool operator()(Real a, Real b) const { + // To avoid issues with rounding when lat/lon were stored in nc file, + // only compare up to 4 digits after decimal point + return std::round(a * 10000) < std::round(b * 10000); + } +}; + +// Helper fcn to gather the union of sets across MPI ranks +std::vector allgatherv_vec (const std::vector& my_vals, const ekat::Comm& comm) +{ + // Step 1: Gather sizes of each local set + int my_size = my_vals.size(); + std::vector count(comm.size()); + comm.all_gather(&my_size,count.data(),1); + + // Step 2: compute offsets + std::vector disp(comm.size(),0); + for (int i=1; i all_vals(disp.back()+count.back()); + MPI_Allgatherv (my_vals.data(),my_size,ekat::get_mpi_type(), + all_vals.data(),count.data(),disp.data(), + ekat::get_mpi_type(),comm.mpi_comm()); + + // Step 4: remove duplicates + std::set vals_set(all_vals.begin(),all_vals.end()); + return std::vector(vals_set.begin(),vals_set.end()); +} +} CoarseningRemapper:: CoarseningRemapper (const grid_ptr_type& src_grid, @@ -22,6 +59,12 @@ CoarseningRemapper (const grid_ptr_type& src_grid, { using namespace ShortFieldTagsNames; + // If this is a remap to lat-lon grid, replace the tgt PointGrid with a LatLonGrid + if (scorpio::has_dim(map_file,"dst_grid_rank") and + scorpio::get_dimlen(map_file,"dst_grid_rank")==2) { + setup_latlon_coarse_grid(map_file); + } + if (populate_tgt_grid_geo_data) { // Replicate the src grid geo data in the tgt grid. We use this remapper to do // the remapping (if needed), and clean it up afterwards. @@ -1118,6 +1161,110 @@ void CoarseningRemapper::setup_mpi_data_structures () } } +void CoarseningRemapper::setup_latlon_coarse_grid(const std::string& map_file) +{ + using namespace ShortFieldTagsNames; + + // Add lat/lon to the temp grid, and read from map file + auto nondim = ekat::units::Units::nondimensional(); + ekat::units::Units deg(nondim,"degrees"); + + auto pt_lat = m_coarse_grid->create_geometry_data("lat",m_coarse_grid->get_2d_scalar_layout(),deg); + auto pt_lon = m_coarse_grid->create_geometry_data("lon",m_coarse_grid->get_2d_scalar_layout(),deg); + // Read lat/lon from the map file. Be careful cause the vars/dims names are different from what eamxx uses + m_coarse_grid->read_geometry_data(map_file,{"lat","lon"},{"yc_b","xc_b"},{{"ncol","n_b"}}); + + // // We will NOT save the ncol version of lat/lon, but only the (lat) and (lon) 1d arrays + // pt_lat.get_header().set_extra_data("save_as_geo_data",false); + // pt_lon.get_header().set_extra_data("save_as_geo_data",false); + + RealsClose cmp; + std::set my_lats(cmp), my_lons(cmp); + + auto pt_lat_h = pt_lat.get_view(); + auto pt_lon_h = pt_lon.get_view(); + for (int i=0; iget_num_local_dofs(); ++i) { + my_lats.insert(pt_lat_h(i)); + my_lons.insert(pt_lon_h(i)); + } + + const auto& comm = m_coarse_grid->get_comm(); + auto lats = allgatherv_vec(std::vector(my_lats.begin(),my_lats.end()),comm); + auto lons = allgatherv_vec(std::vector(my_lons.begin(),my_lons.end()),comm); + int nlat = lats.size(); + int nlon = lons.size(); + + // Re-create lat/lon geometry data with only lat (or lon) dim + m_coarse_grid->delete_geometry_data("lat"); + m_coarse_grid->delete_geometry_data("lon"); + auto lat = m_coarse_grid->create_geometry_data("lat",FieldLayout({CMP},{nlat},{"lat"}),deg); + auto lon = m_coarse_grid->create_geometry_data("lon",FieldLayout({CMP},{nlon},{"lon"}),deg); + + auto lat_h = lat.get_view(); + auto lon_h = lon.get_view(); + std::copy_n(lats.begin(),nlat,lat_h.data()); + std::copy_n(lons.begin(),nlon,lon_h.data()); + lat.sync_to_dev(); + lon.sync_to_dev(); + + auto scalar2d = m_coarse_grid->get_2d_scalar_layout(); + auto lat_idx = m_coarse_grid->create_geometry_data("lat_idx",scalar2d,nondim,DataType::IntType); + auto lon_idx = m_coarse_grid->create_geometry_data("lon_idx",scalar2d,nondim,DataType::IntType); + lat_idx.get_header().set_extra_data("save_as_geo_data",false); + lon_idx.get_header().set_extra_data("save_as_geo_data",false); + + auto lat_idx_h = lat_idx.get_view(); + auto lon_idx_h = lon_idx.get_view(); + constexpr Real tol = 1e-3; + const auto lat_beg = lat_h.data(); + const auto lon_beg = lon_h.data(); + for (int i=0; iget_num_local_dofs(); ++i) { + auto lat_it = std::upper_bound(lat_beg,lat_beg+nlat,pt_lat_h(i)); + auto lon_it = std::upper_bound(lon_beg,lon_beg+nlon,pt_lon_h(i)); + if (lat_it == lat_beg) { + lat_idx_h(i) = 0; + } else if (lat_it == lat_beg+nlat) { + lat_idx_h(i) = std::distance(lat_beg,lat_it)-1; + } else { + auto prev = std::distance(lat_beg,lat_it)-1; + auto next = prev+1; + if (std::abs(pt_lat_h(i)- lat_h(prev)) Date: Mon, 12 Jan 2026 17:18:03 -0700 Subject: [PATCH 330/398] EAMxx: add unit test for lat-lon output --- .../eamxx/src/share/io/tests/CMakeLists.txt | 22 ++++ .../src/share/io/tests/check_latlon_output.py | 94 +++++++++++++++ .../eamxx/src/share/io/tests/io_latlon.cpp | 109 ++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100755 components/eamxx/src/share/io/tests/check_latlon_output.py create mode 100644 components/eamxx/src/share/io/tests/io_latlon.cpp diff --git a/components/eamxx/src/share/io/tests/CMakeLists.txt b/components/eamxx/src/share/io/tests/CMakeLists.txt index 059df09b0f61..f154a619d546 100644 --- a/components/eamxx/src/share/io/tests/CMakeLists.txt +++ b/components/eamxx/src/share/io/tests/CMakeLists.txt @@ -101,4 +101,26 @@ if (NOT SCREAM_ONLY_GENERATE_BASELINES) LIBS eamxx_io LABELS io MPI_RANKS 1 ${SCREAM_TEST_MAX_RANKS} ) + + ## Test latlon output + set(MAP_FILE map_ne30pg2_to_20x40_20260112.nc) + set(MAP_FILE_FULL ${SCREAM_INPUT_ROOT}/atm/scream/maps/${MAP_FILE}) + + GetInputFile ("scream/maps/${MAP_FILE}") + CreateUnitTest(io_latlon_write "io_latlon.cpp" + LIBS eamxx_io LABELS io + MPI_RANKS ${SCREAM_TEST_MAX_RANKS} + EXE_ARGS --args --map-file=${MAP_FILE_FULL} + FIXTURES_SETUP latlon_output + ) + + add_test ( + NAME io_latlon_check + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/check_latlon_output.py + --mask-cols 1 # Do not compare the 1x1 cols groups in the latlon grid corners + --map-file ${MAP_FILE_FULL} + --out-file ./io_latlon.INSTANT.nsteps_x1.np${SCREAM_TEST_MAX_RANKS}.2000.nc + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(io_latlon_check PROPERTIES FIXTURES_REQUIRED latlon_output) + endif() diff --git a/components/eamxx/src/share/io/tests/check_latlon_output.py b/components/eamxx/src/share/io/tests/check_latlon_output.py new file mode 100755 index 000000000000..ceb6615e36a4 --- /dev/null +++ b/components/eamxx/src/share/io/tests/check_latlon_output.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +""" +Checks that latlon output matches expected values +""" + +import argparse, sys, pathlib +from netCDF4 import Dataset +import numpy as np + +############################################################################### +def parse_command_line(args, description): +############################################################################### + parser = argparse.ArgumentParser( + usage="""\n{0} = [=] ... +OR +{0} --help +""".format(pathlib.Path(args[0]).name), + description=description, + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + + parser.add_argument("--map-file",required=True,type=str, + help="The path to the map file used in the io_latlon test", + ) + + parser.add_argument("--out-file",required=True,type=str, + help="The name of the output file generated by the io_latlon test", + ) + + parser.add_argument("-m","--mask-cols",default=0,type=int, + help="Number of columns to mask-out in each corner when comparing results" + ) + + return parser.parse_args(args[1:]) + +############################################################################### +def check_latlon_output(map_file,out_file,mask_cols): +############################################################################### + # Open the output file to read f_lat and f_lon + with Dataset(out_file, 'r') as out_ds: + f_lat = out_ds.variables['f_lat'][:] # Read f_lat variable + f_lon = out_ds.variables['f_lon'][:] # Read f_lon variable + + # Open the map file to read yc_b and xc_b + with Dataset(map_file, 'r') as map_ds: + yc_b = map_ds.variables['yc_b'][:] # Read yc_b variable + xc_b = map_ds.variables['xc_b'][:] # Read xc_b variable + + # Reshape yc_b and xc_b to match the layout of f_lat and f_lon + nlat = f_lat.shape[1] # Get the 2nd dim, as the 1st one is time + nlon = f_lat.shape[2] # Get the 2nd dim, as the 1st one is time + + yc_b = yc_b.reshape(nlat,nlon) + xc_b = xc_b.reshape(nlat,nlon) + + if (mask_cols>0): + # Compare entries "far" from corners + mask = np.ones(xc_b.shape, dtype=bool) + mask[:mask_cols,:mask_cols] = False + mask[:mask_cols,-mask_cols:] = False + mask[-mask_cols:,-mask_cols:] = False + mask[-mask_cols:,:mask_cols] = False + + lat_close = np.allclose(f_lat[0,:,:][mask], yc_b[mask], rtol=0.1) + lon_close = np.allclose(f_lon[0,:,:][mask], xc_b[mask], rtol=0.1) + else: + # Compare all entries (use first time slice to match yc_b/xc_b shape) + lat_close = np.allclose(f_lat[0,:,:], yc_b, rtol=0.1) + lon_close = np.allclose(f_lon[0,:,:], xc_b, rtol=0.1) + + + if not lat_close: + print("lat is NOT close") + print (f_lat[:]) + print (yc_b[:]) + + if not lon_close: + print("lon is NOT close") + print (f_lon[:]) + print (xc_b[:]) + + return lat_close and lon_close + +############################################################################### +def _main_func(description): +############################################################################### + success = check_latlon_output(**vars(parse_command_line(sys.argv, description))) + sys.exit(0 if success else 1) + +############################################################################### + +if (__name__ == "__main__"): + _main_func(__doc__) diff --git a/components/eamxx/src/share/io/tests/io_latlon.cpp b/components/eamxx/src/share/io/tests/io_latlon.cpp new file mode 100644 index 000000000000..f474db21d254 --- /dev/null +++ b/components/eamxx/src/share/io/tests/io_latlon.cpp @@ -0,0 +1,109 @@ +#include +#include + +#include "share/io/scorpio_input.hpp" +#include "share/io/eamxx_output_manager.hpp" +#include "share/grid/point_grid.hpp" + +#include + +namespace scream { + +// Create a point grid with ncols equal to the src or tgt grid of the map file +// Also read in lat/lon from map file +inline std::shared_ptr +create_grid(const ekat::Comm& comm, const std::string& map_file, const std::string& name, bool src) +{ + // Note: map files are 1-based, so create pt grid with 1-based gids + auto nondim = ekat::units::Units::nondimensional(); + ekat::units::Units deg(nondim,"degrees"); + std::string suffix = src ? "_a" : "_b"; + int ncols = scorpio::get_dimlen(map_file,"n"+suffix); + auto grid = create_point_grid(name,ncols,1,comm,1); + + auto lat = grid->create_geometry_data("lat",grid->get_2d_scalar_layout(),deg); + auto lon = grid->create_geometry_data("lon",grid->get_2d_scalar_layout(),deg); + auto io_grid = grid->clone(grid->name(),true); + io_grid->reset_field_tag_name(FieldTag::Column,"n"+suffix); + AtmosphereInput reader(map_file,io_grid,std::vector{lat.alias("yc"+suffix),lon.alias("xc"+suffix)}); + reader.read_variables(); + return grid; +} + +// Create a fm with a copy of lat/lon from the grid in it +std::shared_ptr create_fm(const std::shared_ptr& grid) +{ + using namespace ekat::units; + using namespace ShortFieldTagsNames; + using FID = FieldIdentifier; + + // Create a fm + auto fm = std::make_shared(grid,RepoState::Closed); + + Field f1(FID("f_lat", grid->get_2d_scalar_layout(),m,grid->name()),true); + Field f2(FID("f_lon", grid->get_2d_scalar_layout(),m,grid->name()),true); + f1.deep_copy(grid->get_geometry_data("lat")); + f2.deep_copy(grid->get_geometry_data("lon")); + + fm->add_field(f1); + fm->add_field(f2); + return fm; +} + +void print (const std::string& msg, const ekat::Comm& comm) { + if (comm.am_i_root()) { + printf("%s",msg.c_str()); + } +} + +TEST_CASE("io_latlon") +{ + using strvec_t = std::vector; + + // Setup the global structure + ekat::Comm comm(MPI_COMM_WORLD); // MPI communicator group used for I/O set as ekat object. + scorpio::init_subsystem(comm); + + print (" -> Test Setup ...\n",comm); + + auto& ts = ekat::TestSession::get(); + const std::string& map_file = ts.params.at("map-file"); + + // Construct a timestamp + util::TimeStamp t0 ({2000,1,1},{0,0,0}); + + auto src_grid = create_grid(comm,map_file,"ne4pg2",true); + auto tgt_grid = create_grid(comm,map_file,"latlon",false); + + // Later, we'll open the map file again to read lat/lon in the remapper, + // but we may have a different grid distribution, so we need to ensure that + // the var decomp will be set from scratch. + scorpio::clear_unused_decomps(); + + auto fm = create_fm(src_grid); + fm->init_fields_time_stamp(t0); + print (" -> Test Setup ... done\n",comm); + + // Setup remapped output streams and run them + print (" -> Write remapped output ... \n",comm); + OutputManager om; + + ekat::ParameterList params; + params.set("filename_prefix","io_latlon"); + params.set("averaging_type","instant"); + params.set("file_max_storage_type","one_year"); + auto& oc = params.sublist("output_control"); + oc.set("frequency",1); + oc.set("frequency_units","nsteps"); + params.set("field_names",{"f_lat","f_lon"}); + params.set("horiz_remap_file",map_file); + + om.initialize(comm,params,t0,false); + om.setup(fm,{src_grid->name()}); + om.finalize(); + print (" -> Write remapped putput ... done!\n",comm); + scorpio::finalize_subsystem(); + +} + +} // namespace scream From c2ad24a87834df01daee34947f7d67543e9d3402 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 13 Jan 2026 10:52:26 -0700 Subject: [PATCH 331/398] EAMxx: fix creation of decomp in scorpio interface Set in the session decomps map only if all goes well, to prevent errors in unit tests that check that our exceptions are correctly thrown. --- .../src/share/scorpio_interface/eamxx_scorpio_interface.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index ab2ffd55d7e2..3cab884d7658 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -818,8 +818,7 @@ void set_var_decomp (PIOVar& var, } // We haven't create this decomp yet. Go ahead and create one - auto& decomp = s.decomps[decomp_tag]; - decomp = std::make_shared(); + auto decomp = std::make_shared(); decomp->name = decomp_tag; // Retrieve the dim decomp @@ -853,6 +852,8 @@ void set_var_decomp (PIOVar& var, nullptr,nullptr); check_scorpio_noerr(err,filename,"decomp",decomp_tag,"set_var_decomp","InitDecomp"); + + s.decomps[decomp_tag] = decomp; } // Set decomp data in the var From acb300d6f2bb7d8dfe8433c92cc74f568b9ebe7c Mon Sep 17 00:00:00 2001 From: Ryan Knox Date: Wed, 14 Jan 2026 12:58:08 -0500 Subject: [PATCH 332/398] Update elm_driver.F90 --- components/elm/src/main/elm_driver.F90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/elm/src/main/elm_driver.F90 b/components/elm/src/main/elm_driver.F90 index 1e43b57c399f..5a3c439fe0bd 100644 --- a/components/elm/src/main/elm_driver.F90 +++ b/components/elm/src/main/elm_driver.F90 @@ -1373,8 +1373,7 @@ subroutine elm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate) ! On the first step, send the solar zenith angles to FATES on non-continue restarts ! for the two-stream radiation scheme. if (use_fates .and. .not.doalb .and. get_nstep() == 1 .and. nsrest == nsrStartup) then - if ( (trim(finidat) == '') .or. & - (fates_radiation_model=='twostream' .and. .not.use_fates_sp )) then + if ( trim(finidat) == '' .or. fates_radiation_model=='twostream') then call alm_fates%wrap_canopy_radiation(bounds_clump,surfalb_vars,nextsw_cday,declinp1) end if end if From bb44a886fd5835028c81cc34cb301760e51b18bd Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 14 Jan 2026 14:30:50 -0700 Subject: [PATCH 333/398] Move impls out of zm_functions.hpp, add common init --- .../eam/src/physics/cam/zm/zm_conv_types.F90 | 4 +- .../eamxx/scripts/gen-boiler/gen_boiler.py | 15 + .../eamxx/src/physics/zm/CMakeLists.txt | 9 +- .../src/physics/zm/eti/zm_common_init.cpp | 14 + .../src/physics/zm/eti/zm_input_state.cpp | 17 + .../src/physics/zm/eti/zm_output_tend.cpp | 17 + .../physics/zm/impl/zm_common_init_impl.hpp | 50 +++ .../physics/zm/impl/zm_input_state_impl.hpp | 148 +++++++++ .../physics/zm/impl/zm_output_tend_impl.hpp | 149 +++++++++ .../eamxx/src/physics/zm/zm_functions.hpp | 309 ++++-------------- 10 files changed, 481 insertions(+), 251 deletions(-) create mode 100644 components/eamxx/src/physics/zm/eti/zm_common_init.cpp create mode 100644 components/eamxx/src/physics/zm/eti/zm_input_state.cpp create mode 100644 components/eamxx/src/physics/zm/eti/zm_output_tend.cpp create mode 100644 components/eamxx/src/physics/zm/impl/zm_common_init_impl.hpp create mode 100644 components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp create mode 100644 components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp diff --git a/components/eam/src/physics/cam/zm/zm_conv_types.F90 b/components/eam/src/physics/cam/zm/zm_conv_types.F90 index f204719c41ba..4117fd581f9a 100644 --- a/components/eam/src/physics/cam/zm/zm_conv_types.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv_types.F90 @@ -18,7 +18,7 @@ module zm_conv_types public :: zm_param_set_for_testing ! set parameter values for testing public :: zm_param_mpi_broadcast ! broadcast parameter values to all MPI ranks public :: zm_param_print ! print parameter values for log file - + ! ZM derived types public :: zm_const_t ! derived type to hold ZM constants public :: zm_param_t ! derived type to hold ZM tunable parameters @@ -200,7 +200,7 @@ subroutine zm_param_set_for_testing(zm_param) zm_param%c0_lnd = 0.0020D0 zm_param%c0_ocn = 0.0020D0 zm_param%num_cin = 1 - zm_param%limcnv = 23 ! note - default for E3SMv3 => ne30pg2 w/ L80 + zm_param%limcnv = 23 ! note - default for E3SMv3 => ne30pg2 w/ L80 zm_param%mx_bot_lyr_adj = 1 zm_param%trig_dcape = .true. zm_param%trig_ull = .true. diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 3331f25afa9b..d01057eef0a9 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -291,6 +291,21 @@ "ncol", True ), + "zm" : ( + ( + "components/eam/src/physics/cam/zm/zm_conv_cape.F90", + "components/eam/src/physics/cam/zm/zm_conv.F90", + "components/eam/src/physics/cam/zm/zm_conv_mcsp.F90", + "components/eam/src/physics/cam/zm/zm_conv_types.F90", + "components/eam/src/physics/cam/zm/zm_conv_util.F90", + "components/eam/src/physics/cam/zm/zm_transport.F90" + ), + "components/eamxx/src/physics/zm", + "zm_common_init(); // Might need more specific init", + "zm_finalize_cxx();", + "ncol", + True + ), } # diff --git a/components/eamxx/src/physics/zm/CMakeLists.txt b/components/eamxx/src/physics/zm/CMakeLists.txt index a4d560261a00..d9d0721c4768 100644 --- a/components/eamxx/src/physics/zm/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/CMakeLists.txt @@ -32,7 +32,7 @@ set(ZM_F90_SRCS # ---------------------------------------------------------------------------- ) -set(ZM_CXX_SRCS +set(ZM_SRCS # ---------------------------------------------------------------------------- # C++/EAMxx atomsphere process for ZM eamxx_zm_process_interface.cpp @@ -42,10 +42,13 @@ set(ZM_CXX_SRCS # Add ETI source files if not on CUDA/HIP if (NOT EAMXX_ENABLE_GPU OR Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE OR Kokkos_ENABLE_HIP_RELOCATABLE_DEVICE_CODE) list(APPEND ZM_SRCS - ) + eti/zm_common_init.cpp + eti/zm_input_state.cpp + eti/zm_output_tend.cpp + ) # ZM ETI SRCS endif() -add_library(zm ${ZM_F90_SRCS} ${ZM_CXX_SRCS}) +add_library(zm ${ZM_F90_SRCS} ${ZM_SRCS}) set_target_properties(zm PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/modules diff --git a/components/eamxx/src/physics/zm/eti/zm_common_init.cpp b/components/eamxx/src/physics/zm/eti/zm_common_init.cpp new file mode 100644 index 000000000000..668ef1bc755b --- /dev/null +++ b/components/eamxx/src/physics/zm/eti/zm_common_init.cpp @@ -0,0 +1,14 @@ +#include "impl/zm_common_init_impl.hpp" + +namespace scream { +namespace zm { + +/* + * Explicit instantiation for doing zm_common_init on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace zm +} // namespace scream diff --git a/components/eamxx/src/physics/zm/eti/zm_input_state.cpp b/components/eamxx/src/physics/zm/eti/zm_input_state.cpp new file mode 100644 index 000000000000..d55e266bec20 --- /dev/null +++ b/components/eamxx/src/physics/zm/eti/zm_input_state.cpp @@ -0,0 +1,17 @@ +#include "impl/zm_input_state_impl.hpp" + +namespace scream { +namespace zm { + +/* + * Explicit instantiation for doing zm_input_state on Reals using the + * default device. + */ + +template void Functions::zm_input_state::transpose(int ncol, int nlev_mid); +template void Functions::zm_input_state::transpose(int ncol, int nlev_mid); + +template struct Functions; + +} // namespace zm +} // namespace scream diff --git a/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp b/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp new file mode 100644 index 000000000000..f35c1a04d34e --- /dev/null +++ b/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp @@ -0,0 +1,17 @@ +#include "impl/zm_output_tend_impl.hpp" + +namespace scream { +namespace zm { + +/* + * Explicit instantiation for doing zm_input_state on Reals using the + * default device. + */ + +template void Functions::zm_output_tend::transpose(int ncol, int nlev_mid); +template void Functions::zm_output_tend::transpose(int ncol, int nlev_mid); + +template struct Functions; + +} // namespace zm +} // namespace scream diff --git a/components/eamxx/src/physics/zm/impl/zm_common_init_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_common_init_impl.hpp new file mode 100644 index 000000000000..4247d574f068 --- /dev/null +++ b/components/eamxx/src/physics/zm/impl/zm_common_init_impl.hpp @@ -0,0 +1,50 @@ +#ifndef ZM_ZM_COMMON_INIT_IMPL_HPP +#define ZM_ZM_COMMON_INIT_IMPL_HPP + +#include "zm_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace zm { + +/* + * Implementation of zm zm_common_init. Clients should NOT + * #include this file, but include zm_functions.hpp instead. + */ + +template +void Functions::zm_common_init() +{ + s_common_init.tau = 3600.0; + s_common_init.alfa = 0.14; + s_common_init.ke = 2.5E-6; + s_common_init.dmpdz = -0.7e-3; + s_common_init.tpert_fix = true; + s_common_init.tpert_fac = 2.0; + s_common_init.tiedke_add = 0.8; + s_common_init.c0_lnd = 0.0020; + s_common_init.c0_ocn = 0.0020; + s_common_init.num_cin = 1; + s_common_init.limcnv = 23; // note - default for E3SMv3 => ne30pg2 w/ L80 + s_common_init.mx_bot_lyr_adj = 1; + s_common_init.trig_dcape = true; + s_common_init.trig_ull = true; + s_common_init.clos_dyn_adj = true; + s_common_init.no_deep_pbl = false; + // ZM micro parameters + s_common_init.zm_microp = true; + s_common_init.old_snow = false; + s_common_init.auto_fac = 7.0; + s_common_init.accr_fac = 1.5; + s_common_init.micro_dcs = 150.E-6; + // MCSP parameters + s_common_init.mcsp_enabled = true; + s_common_init.mcsp_t_coeff = 0.3; + s_common_init.mcsp_q_coeff = 0; + s_common_init.mcsp_u_coeff = 0; + s_common_init.mcsp_v_coeff = 0; +} + +} // namespace zm +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp new file mode 100644 index 000000000000..aa28d0d4f750 --- /dev/null +++ b/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp @@ -0,0 +1,148 @@ +#ifndef ZM_INPUT_STATE_IMPL_HPP +#define ZM_INPUT_STATE_IMPL_HPP + +#include "zm_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace zm { + +// ------------------------------------------------------------------------- +// transpose method for fortran bridging +template +template +void Functions::zm_input_state::transpose(int ncol, int nlev_mid) +{ + auto nlev_int = nlev_mid+1; + + // *********************************************************************** + // TEMPORARY + // *********************************************************************** + auto nlev_mid_packs = ekat::npack(nlev_mid); + auto nlev_int_packs = ekat::npack(nlev_int); + if (DirT == ekat::TransposeDirection::c2f) { + // create temporaries to avoid "Implicit capture" warning + const auto loc_f_z_mid = f_z_mid; + const auto loc_f_p_mid = f_p_mid; + const auto loc_f_p_del = f_p_del; + const auto loc_f_T_mid = f_T_mid; + const auto loc_f_qv = f_qv; + const auto loc_f_uwind = f_uwind; + const auto loc_f_vwind = f_vwind; + const auto loc_f_omega = f_omega; + const auto loc_f_cldfrac = f_cldfrac; + const auto loc_f_z_int = f_z_int; + const auto loc_f_p_int = f_p_int; + + //---------------------------------------------------------------------- + // mid-point level variables + Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { + const int icol = i/nlev_mid_packs; + const int klev = i%nlev_mid_packs; + loc_f_z_mid (icol,klev) = z_mid (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_p_mid (icol,klev) = p_mid (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_p_del (icol,klev) = p_del (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_T_mid (icol,klev) = T_mid (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_qv (icol,klev) = qv (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_uwind (icol,klev) = uwind (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_vwind (icol,klev) = vwind (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_omega (icol,klev) = omega (icol,klev/Spack::n)[klev%Spack::n]; + loc_f_cldfrac (icol,klev) = cldfrac (icol,klev/Spack::n)[klev%Spack::n]; + }); + + // interface level variables + Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { + const int icol = i/nlev_int_packs; + const int klev = i%nlev_int_packs; + f_z_int (icol,klev) = z_int (icol,klev/Spack::n)[klev%Spack::n]; + f_p_int (icol,klev) = p_int (icol,klev/Spack::n)[klev%Spack::n]; + }); + + //---------------------------------------------------------------------- + // copy to host mirrors + Kokkos::deep_copy(h_phis, phis ); + Kokkos::deep_copy(h_pblh, pblh ); + Kokkos::deep_copy(h_tpert, tpert ); + Kokkos::deep_copy(h_landfrac, landfrac ); + Kokkos::deep_copy(h_z_mid, f_z_mid ); + Kokkos::deep_copy(h_p_mid, f_p_mid ); + Kokkos::deep_copy(h_p_del, f_p_del ); + Kokkos::deep_copy(h_T_mid, f_T_mid ); + Kokkos::deep_copy(h_qv, f_qv ); + Kokkos::deep_copy(h_uwind, f_uwind ); + Kokkos::deep_copy(h_vwind, f_vwind ); + Kokkos::deep_copy(h_omega, f_omega ); + Kokkos::deep_copy(h_cldfrac, f_cldfrac ); + Kokkos::deep_copy(h_z_int, f_z_int ); + Kokkos::deep_copy(h_p_int, f_p_int ); + } + + // *********************************************************************** + // TEMPORARY + // *********************************************************************** + + // if (DirT == ekat::TransposeDirection::c2f) { + // ekat::device_to_host({h_phis.data()}, ncol, std::vector< view_1d>{phis}); + // ekat::device_to_host({h_pblh.data()}, ncol, std::vector< view_1d>{pblh}); + // ekat::device_to_host({h_tpert.data()}, ncol, std::vector>{tpert}); + // ekat::device_to_host({h_landfrac.data()}, ncol, std::vector< view_1d>{landfrac}); + // ekat::device_to_host({h_z_mid.data()}, ncol, nlev_mid, std::vector>{z_mid}); + // ekat::device_to_host({h_p_mid.data()}, ncol, nlev_mid, std::vector< view_2d>{p_mid}); + // ekat::device_to_host({h_p_del.data()}, ncol, nlev_mid, std::vector< view_2d>{p_del}); + // ekat::device_to_host({h_T_mid.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{T_mid}); + // ekat::device_to_host({h_qv.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{qv}); + // ekat::device_to_host({h_uwind.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{uwind}); + // ekat::device_to_host({h_vwind.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{vwind}); + // ekat::device_to_host({h_omega.data()}, ncol, nlev_mid, std::vector< view_2d>{omega}); + // ekat::device_to_host({h_cldfrac.data()}, ncol, nlev_mid, std::vector< view_2d>{cldfrac}); + // ekat::device_to_host({h_z_int.data()}, ncol, nlev_int, std::vector>{z_int}); + // ekat::device_to_host({h_p_int.data()}, ncol, nlev_int, std::vector< view_2d>{p_int}); + // } +} + +template +void Functions::zm_input_state::calculate_tpert(int ncol, int nlev, bool is_first_step) +{ + const Real cpair = PC::Cpair.value; + const Real latvap = PC::LatVap.value; + + // create temporaries to avoid "Implicit capture" warning + auto loc_tpert = tpert; + auto loc_pblh = pblh; + auto loc_z_int = z_int; + auto loc_p_mid = p_mid; + auto loc_qc = qc; + auto loc_thl_sec = thl_sec; + + Kokkos::parallel_for("zm_calculate_tpert",ncol, KOKKOS_LAMBDA (const int i) { + if (is_first_step) { + loc_tpert(i) = 0.0; + } else { + // identify interface index for top of PBL + int pblh_k_ind = -1; + for (int k=0; kloc_pblh(i) && z_int_tmp_kp1<=loc_pblh(i) ) { + pblh_k_ind = k; + } + } + if (pblh_k_ind==-1) { + // PBL top index not found, so just set the perturbation to zero + loc_tpert(i) = 0.0; + } else { + // calculate tpert as std deviation of temperature from SHOC's theta-l variance + auto exner_pbl = PF::exner_function( loc_p_mid(i,pblh_k_ind/Spack::n)[pblh_k_ind%Spack::n] ); + auto qc_pbl = loc_qc(i,pblh_k_ind/Spack::n)[pblh_k_ind%Spack::n]; + auto thl_sec_pbl = loc_thl_sec(i,pblh_k_ind/Spack::n)[pblh_k_ind%Spack::n]; + auto thl_std_pbl = sqrt( thl_sec_pbl ); // std deviation of thetal; + loc_tpert(i) = ( thl_std_pbl + (latvap/cpair)*qc_pbl ) / exner_pbl; + loc_tpert(i) = ekat::impl::min(2.0,loc_tpert(i)); // apply limiter + } + } + }); +} + +} // namespace zm +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp new file mode 100644 index 000000000000..1c8a4ca70d27 --- /dev/null +++ b/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp @@ -0,0 +1,149 @@ +#ifndef ZM_OUTPUT_TEND_IMPL_HPP +#define ZM_OUTPUT_TEND_IMPL_HPP + +#include "zm_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace zm { + +// ------------------------------------------------------------------------- +// transpose method for fortran bridging +template +template +void Functions::zm_output_tend::transpose(int ncol, int nlev_mid) +{ + auto nlev_int = nlev_mid+1; + + // *********************************************************************** + // TEMPORARY + // *********************************************************************** + auto nlev_mid_packs = ekat::npack(nlev_mid); + auto nlev_int_packs = ekat::npack(nlev_int); + if (DirT == ekat::TransposeDirection::f2c) { + // copy back to device + Kokkos::deep_copy(f_tend_t, h_tend_t); + Kokkos::deep_copy(f_tend_qv, h_tend_qv); + Kokkos::deep_copy(f_tend_u, h_tend_u); + Kokkos::deep_copy(f_tend_v, h_tend_v); + Kokkos::deep_copy(f_rain_prod,h_rain_prod); + Kokkos::deep_copy(f_snow_prod,h_snow_prod); + Kokkos::deep_copy(f_prec_flux,h_prec_flux); + Kokkos::deep_copy(f_snow_flux,h_snow_flux); + Kokkos::deep_copy(f_mass_flux,h_mass_flux); + Kokkos::deep_copy(prec, h_prec); + Kokkos::deep_copy(snow, h_snow); + Kokkos::deep_copy(cape, h_cape); + Kokkos::deep_copy(activity, h_activity); + + //---------------------------------------------------------------------- + // create temporaries to avoid "Implicit capture" warning + const auto loc_tend_t = tend_t; + const auto loc_tend_qv = tend_qv; + const auto loc_tend_u = tend_u; + const auto loc_tend_v = tend_v; + const auto loc_rain_prod = rain_prod; + const auto loc_snow_prod = snow_prod; + const auto loc_prec_flux = prec_flux; + const auto loc_snow_flux = snow_flux; + const auto loc_mass_flux = mass_flux; + + //---------------------------------------------------------------------- + // mid-point level variables + Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { + const int icol = i/nlev_mid_packs; + const int klev = i%nlev_mid_packs; + loc_tend_t (icol,klev/Spack::n)[klev%Spack::n] = f_tend_t (icol,klev); + loc_tend_qv (icol,klev/Spack::n)[klev%Spack::n] = f_tend_qv (icol,klev); + loc_tend_u (icol,klev/Spack::n)[klev%Spack::n] = f_tend_u (icol,klev); + loc_tend_v (icol,klev/Spack::n)[klev%Spack::n] = f_tend_v (icol,klev); + loc_rain_prod(icol,klev/Spack::n)[klev%Spack::n] = f_rain_prod(icol,klev); + loc_snow_prod(icol,klev/Spack::n)[klev%Spack::n] = f_snow_prod(icol,klev); + }); + + // interface level variables + Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { + const int icol = i/nlev_int_packs; + const int klev = i%nlev_int_packs; + loc_prec_flux(icol,klev/Spack::n)[klev%Spack::n] = f_prec_flux(icol,klev); + loc_snow_flux(icol,klev/Spack::n)[klev%Spack::n] = f_snow_flux(icol,klev); + loc_mass_flux(icol,klev/Spack::n)[klev%Spack::n] = f_mass_flux(icol,klev); + }); + } + // *********************************************************************** + // TEMPORARY + // *********************************************************************** + + // if (DirT == ekat::TransposeDirection::f2c) { + // ekat::host_to_device({h_prec.data()}, ncol, std::vector>{prec}); + // ekat::host_to_device({h_activity.data()}, ncol, std::vector> {activity}); + // ekat::host_to_device({h_prec.data()}, ncol, std::vector>{prec}); + // ekat::host_to_device({h_snow.data()}, ncol, std::vector>{snow}); + // ekat::host_to_device({h_cape.data()}, ncol, std::vector>{cape}); + // ekat::host_to_device({h_tend_t.data()}, ncol, nlev_mid, std::vector> {tend_t}, true); + // ekat::host_to_device({h_tend_qv.data()}, ncol, nlev_mid, std::vector> {tend_qv}, true); + // ekat::host_to_device({h_tend_u.data()}, ncol, nlev_mid, std::vector> {tend_u}, true); + // ekat::host_to_device({h_tend_v.data()}, ncol, nlev_mid, std::vector> {tend_v}, true); + // ekat::host_to_device({h_rain_prod.data()},ncol, nlev_mid, std::vector> {rain_prod}, true); + // ekat::host_to_device({h_snow_prod.data()},ncol, nlev_mid, std::vector> {snow_prod}, true); + // ekat::host_to_device({h_prec_flux.data()},ncol, nlev_int, std::vector> {prec_flux}, true); + // ekat::host_to_device({h_snow_flux.data()},ncol, nlev_int, std::vector> {snow_flux}, true); + // ekat::host_to_device({h_mass_flux.data()},ncol, nlev_int, std::vector> {mass_flux}, true); + // } +} + +template +void Functions::zm_output_tend::init(int ncol, int nlev_mid) +{ + auto nlev_int = nlev_mid+1; + auto nlev_mid_packs = ekat::npack(nlev_mid); + auto nlev_int_packs = ekat::npack(nlev_int); + Real init_fill_value = 0; + // create temporaries to avoid "Implicit capture" warning + auto loc_prec = prec; + auto loc_snow = snow; + auto loc_cape = cape; + auto loc_activity = activity; + auto loc_tend_t = tend_t; + auto loc_tend_qv = tend_qv; + auto loc_tend_u = tend_u; + auto loc_tend_v = tend_v; + auto loc_rain_prod = rain_prod; + auto loc_snow_prod = snow_prod; + auto loc_prec_flux = prec_flux; + auto loc_snow_flux = snow_flux; + auto loc_mass_flux = mass_flux; + + // 1D scalar variables + Kokkos::parallel_for("zm_output_init_s", KT::RangePolicy(0, ncol), KOKKOS_LAMBDA (const int i) { + loc_prec(i) = init_fill_value; + loc_snow(i) = init_fill_value; + loc_cape(i) = init_fill_value; + loc_activity(i) = -1; + }); + + // mid-point level variables + Kokkos::parallel_for("zm_output_init_m",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { + const int icol = i/nlev_mid_packs; + const int klev = i%nlev_mid_packs; + loc_tend_t (icol,klev) = init_fill_value; + loc_tend_qv (icol,klev) = init_fill_value; + loc_tend_u (icol,klev) = init_fill_value; + loc_tend_v (icol,klev) = init_fill_value; + loc_rain_prod(icol,klev) = init_fill_value; + loc_snow_prod(icol,klev) = init_fill_value; + }); + + // interface level variables + Kokkos::parallel_for("zm_output_init_i",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { + const int icol = i/nlev_int_packs; + const int klev = i%nlev_int_packs; + loc_prec_flux(icol,klev) = init_fill_value; + loc_snow_flux(icol,klev) = init_fill_value; + loc_mass_flux(icol,klev) = init_fill_value; + }); +} + +} // namespace zm +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 46ca36f4bbda..0e940e0f1349 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -51,6 +51,12 @@ struct Functions { // ----------------------------------------------------------------------------------------------- // Structs + // + // ---------- ZM constants --------- + // + struct ZMC { + }; + struct zm_runtime_opt { zm_runtime_opt() = default; bool apply_tendencies = false; @@ -134,130 +140,10 @@ struct Functions { // ------------------------------------------------------------------------- // transpose method for fortran bridging template - void transpose(int ncol, int nlev_mid) { - auto nlev_int = nlev_mid+1; - - // *********************************************************************** - // TEMPORARY - // *********************************************************************** - auto nlev_mid_packs = ekat::npack(nlev_mid); - auto nlev_int_packs = ekat::npack(nlev_int); - if (D == ekat::TransposeDirection::c2f) { - // create temporaries to avoid "Implicit capture" warning - const auto loc_f_z_mid = f_z_mid; - const auto loc_f_p_mid = f_p_mid; - const auto loc_f_p_del = f_p_del; - const auto loc_f_T_mid = f_T_mid; - const auto loc_f_qv = f_qv; - const auto loc_f_uwind = f_uwind; - const auto loc_f_vwind = f_vwind; - const auto loc_f_omega = f_omega; - const auto loc_f_cldfrac = f_cldfrac; - const auto loc_f_z_int = f_z_int; - const auto loc_f_p_int = f_p_int; - //---------------------------------------------------------------------- - // mid-point level variables - Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { - const int icol = i/nlev_mid_packs; - const int klev = i%nlev_mid_packs; - loc_f_z_mid (icol,klev) = z_mid (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_p_mid (icol,klev) = p_mid (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_p_del (icol,klev) = p_del (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_T_mid (icol,klev) = T_mid (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_qv (icol,klev) = qv (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_uwind (icol,klev) = uwind (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_vwind (icol,klev) = vwind (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_omega (icol,klev) = omega (icol,klev/Spack::n)[klev%Spack::n]; - loc_f_cldfrac (icol,klev) = cldfrac (icol,klev/Spack::n)[klev%Spack::n]; - }); - // interface level variables - Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { - const int icol = i/nlev_int_packs; - const int klev = i%nlev_int_packs; - f_z_int (icol,klev) = z_int (icol,klev/Spack::n)[klev%Spack::n]; - f_p_int (icol,klev) = p_int (icol,klev/Spack::n)[klev%Spack::n]; - }); - //---------------------------------------------------------------------- - // copy to host mirrors - Kokkos::deep_copy(h_phis, phis ); - Kokkos::deep_copy(h_pblh, pblh ); - Kokkos::deep_copy(h_tpert, tpert ); - Kokkos::deep_copy(h_landfrac, landfrac ); - Kokkos::deep_copy(h_z_mid, f_z_mid ); - Kokkos::deep_copy(h_p_mid, f_p_mid ); - Kokkos::deep_copy(h_p_del, f_p_del ); - Kokkos::deep_copy(h_T_mid, f_T_mid ); - Kokkos::deep_copy(h_qv, f_qv ); - Kokkos::deep_copy(h_uwind, f_uwind ); - Kokkos::deep_copy(h_vwind, f_vwind ); - Kokkos::deep_copy(h_omega, f_omega ); - Kokkos::deep_copy(h_cldfrac, f_cldfrac ); - Kokkos::deep_copy(h_z_int, f_z_int ); - Kokkos::deep_copy(h_p_int, f_p_int ); - } - // *********************************************************************** - // TEMPORARY - // *********************************************************************** - - // if (D == ekat::TransposeDirection::c2f) { - // ekat::device_to_host({h_phis.data()}, ncol, std::vector< view_1d>{phis}); - // ekat::device_to_host({h_pblh.data()}, ncol, std::vector< view_1d>{pblh}); - // ekat::device_to_host({h_tpert.data()}, ncol, std::vector>{tpert}); - // ekat::device_to_host({h_landfrac.data()}, ncol, std::vector< view_1d>{landfrac}); - // ekat::device_to_host({h_z_mid.data()}, ncol, nlev_mid, std::vector>{z_mid}); - // ekat::device_to_host({h_p_mid.data()}, ncol, nlev_mid, std::vector< view_2d>{p_mid}); - // ekat::device_to_host({h_p_del.data()}, ncol, nlev_mid, std::vector< view_2d>{p_del}); - // ekat::device_to_host({h_T_mid.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{T_mid}); - // ekat::device_to_host({h_qv.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{qv}); - // ekat::device_to_host({h_uwind.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{uwind}); - // ekat::device_to_host({h_vwind.data()}, ncol, nlev_mid, std::vector< view_2d< Spack >>{vwind}); - // ekat::device_to_host({h_omega.data()}, ncol, nlev_mid, std::vector< view_2d>{omega}); - // ekat::device_to_host({h_cldfrac.data()}, ncol, nlev_mid, std::vector< view_2d>{cldfrac}); - // ekat::device_to_host({h_z_int.data()}, ncol, nlev_int, std::vector>{z_int}); - // ekat::device_to_host({h_p_int.data()}, ncol, nlev_int, std::vector< view_2d>{p_int}); - // } - } + void transpose(int ncol, int nlev_mid); + // ------------------------------------------------------------------------- - void calculate_tpert(int ncol,int nlev,bool is_first_step) { - const Real cpair = PC::Cpair.value; - const Real latvap = PC::LatVap.value; - - // create temporaries to avoid "Implicit capture" warning - auto loc_tpert = tpert; - auto loc_pblh = pblh; - auto loc_z_int = z_int; - auto loc_p_mid = p_mid; - auto loc_qc = qc; - auto loc_thl_sec = thl_sec; - - Kokkos::parallel_for("zm_calculate_tpert",ncol, KOKKOS_LAMBDA (const int i) { - if (is_first_step) { - loc_tpert(i) = 0.0; - } else { - // identify interface index for top of PBL - int pblh_k_ind = -1; - for (int k=0; kloc_pblh(i) && z_int_tmp_kp1<=loc_pblh(i) ) { - pblh_k_ind = k; - } - } - if (pblh_k_ind==-1) { - // PBL top index not found, so just set the perturbation to zero - loc_tpert(i) = 0.0; - } else { - // calculate tpert as std deviation of temperature from SHOC's theta-l variance - auto exner_pbl = PF::exner_function( loc_p_mid(i,pblh_k_ind/Spack::n)[pblh_k_ind%Spack::n] ); - auto qc_pbl = loc_qc(i,pblh_k_ind/Spack::n)[pblh_k_ind%Spack::n]; - auto thl_sec_pbl = loc_thl_sec(i,pblh_k_ind/Spack::n)[pblh_k_ind%Spack::n]; - auto thl_std_pbl = sqrt( thl_sec_pbl ); // std deviation of thetal; - loc_tpert(i) = ( thl_std_pbl + (latvap/cpair)*qc_pbl ) / exner_pbl; - loc_tpert(i) = ekat::impl::min(2.0,loc_tpert(i)); // apply limiter - } - } - }); - } + void calculate_tpert(int ncol,int nlev,bool is_first_step); }; // ----------------------------------------------------------------------------------------------- @@ -320,131 +206,10 @@ struct Functions { // ------------------------------------------------------------------------- // transpose method for fortran bridging template - void transpose(int ncol, int nlev_mid) { - auto nlev_int = nlev_mid+1; - - // *********************************************************************** - // TEMPORARY - // *********************************************************************** - auto nlev_mid_packs = ekat::npack(nlev_mid); - auto nlev_int_packs = ekat::npack(nlev_int); - if (D == ekat::TransposeDirection::f2c) { - // copy back to device - Kokkos::deep_copy(f_tend_t, h_tend_t); - Kokkos::deep_copy(f_tend_qv, h_tend_qv); - Kokkos::deep_copy(f_tend_u, h_tend_u); - Kokkos::deep_copy(f_tend_v, h_tend_v); - Kokkos::deep_copy(f_rain_prod,h_rain_prod); - Kokkos::deep_copy(f_snow_prod,h_snow_prod); - Kokkos::deep_copy(f_prec_flux,h_prec_flux); - Kokkos::deep_copy(f_snow_flux,h_snow_flux); - Kokkos::deep_copy(f_mass_flux,h_mass_flux); - Kokkos::deep_copy(prec, h_prec); - Kokkos::deep_copy(snow, h_snow); - Kokkos::deep_copy(cape, h_cape); - Kokkos::deep_copy(activity, h_activity); - //---------------------------------------------------------------------- - // create temporaries to avoid "Implicit capture" warning - const auto loc_tend_t = tend_t; - const auto loc_tend_qv = tend_qv; - const auto loc_tend_u = tend_u; - const auto loc_tend_v = tend_v; - const auto loc_rain_prod = rain_prod; - const auto loc_snow_prod = snow_prod; - const auto loc_prec_flux = prec_flux; - const auto loc_snow_flux = snow_flux; - const auto loc_mass_flux = mass_flux; - //---------------------------------------------------------------------- - // mid-point level variables - Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { - const int icol = i/nlev_mid_packs; - const int klev = i%nlev_mid_packs; - loc_tend_t (icol,klev/Spack::n)[klev%Spack::n] = f_tend_t (icol,klev); - loc_tend_qv (icol,klev/Spack::n)[klev%Spack::n] = f_tend_qv (icol,klev); - loc_tend_u (icol,klev/Spack::n)[klev%Spack::n] = f_tend_u (icol,klev); - loc_tend_v (icol,klev/Spack::n)[klev%Spack::n] = f_tend_v (icol,klev); - loc_rain_prod(icol,klev/Spack::n)[klev%Spack::n] = f_rain_prod(icol,klev); - loc_snow_prod(icol,klev/Spack::n)[klev%Spack::n] = f_snow_prod(icol,klev); - }); - // interface level variables - Kokkos::parallel_for("zm_output_tx_mid",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { - const int icol = i/nlev_int_packs; - const int klev = i%nlev_int_packs; - loc_prec_flux(icol,klev/Spack::n)[klev%Spack::n] = f_prec_flux(icol,klev); - loc_snow_flux(icol,klev/Spack::n)[klev%Spack::n] = f_snow_flux(icol,klev); - loc_mass_flux(icol,klev/Spack::n)[klev%Spack::n] = f_mass_flux(icol,klev); - }); - } - // *********************************************************************** - // TEMPORARY - // *********************************************************************** - - // if (D == ekat::TransposeDirection::f2c) { - // ekat::host_to_device({h_prec.data()}, ncol, std::vector>{prec}); - // ekat::host_to_device({h_activity.data()}, ncol, std::vector> {activity}); - // ekat::host_to_device({h_prec.data()}, ncol, std::vector>{prec}); - // ekat::host_to_device({h_snow.data()}, ncol, std::vector>{snow}); - // ekat::host_to_device({h_cape.data()}, ncol, std::vector>{cape}); - // ekat::host_to_device({h_tend_t.data()}, ncol, nlev_mid, std::vector> {tend_t}, true); - // ekat::host_to_device({h_tend_qv.data()}, ncol, nlev_mid, std::vector> {tend_qv}, true); - // ekat::host_to_device({h_tend_u.data()}, ncol, nlev_mid, std::vector> {tend_u}, true); - // ekat::host_to_device({h_tend_v.data()}, ncol, nlev_mid, std::vector> {tend_v}, true); - // ekat::host_to_device({h_rain_prod.data()},ncol, nlev_mid, std::vector> {rain_prod}, true); - // ekat::host_to_device({h_snow_prod.data()},ncol, nlev_mid, std::vector> {snow_prod}, true); - // ekat::host_to_device({h_prec_flux.data()},ncol, nlev_int, std::vector> {prec_flux}, true); - // ekat::host_to_device({h_snow_flux.data()},ncol, nlev_int, std::vector> {snow_flux}, true); - // ekat::host_to_device({h_mass_flux.data()},ncol, nlev_int, std::vector> {mass_flux}, true); - // } - }; + void transpose(int ncol, int nlev_mid); // ------------------------------------------------------------------------- - void init(int ncol, int nlev_mid) { - auto nlev_int = nlev_mid+1; - auto nlev_mid_packs = ekat::npack(nlev_mid); - auto nlev_int_packs = ekat::npack(nlev_int); - Real init_fill_value = 0; - // create temporaries to avoid "Implicit capture" warning - auto loc_prec = prec; - auto loc_snow = snow; - auto loc_cape = cape; - auto loc_activity = activity; - auto loc_tend_t = tend_t; - auto loc_tend_qv = tend_qv; - auto loc_tend_u = tend_u; - auto loc_tend_v = tend_v; - auto loc_rain_prod = rain_prod; - auto loc_snow_prod = snow_prod; - auto loc_prec_flux = prec_flux; - auto loc_snow_flux = snow_flux; - auto loc_mass_flux = mass_flux; - // 1D scalar variables - Kokkos::parallel_for("zm_output_init_s", KT::RangePolicy(0, ncol), KOKKOS_LAMBDA (const int i) { - loc_prec(i) = init_fill_value; - loc_snow(i) = init_fill_value; - loc_cape(i) = init_fill_value; - loc_activity(i) = -1; - }); - // mid-point level variables - Kokkos::parallel_for("zm_output_init_m",KT::RangePolicy(0, ncol*nlev_mid_packs), KOKKOS_LAMBDA (const int i) { - const int icol = i/nlev_mid_packs; - const int klev = i%nlev_mid_packs; - loc_tend_t (icol,klev) = init_fill_value; - loc_tend_qv (icol,klev) = init_fill_value; - loc_tend_u (icol,klev) = init_fill_value; - loc_tend_v (icol,klev) = init_fill_value; - loc_rain_prod(icol,klev) = init_fill_value; - loc_snow_prod(icol,klev) = init_fill_value; - }); - // interface level variables - Kokkos::parallel_for("zm_output_init_i",KT::RangePolicy(0, ncol*nlev_int_packs), KOKKOS_LAMBDA (const int i) { - const int icol = i/nlev_int_packs; - const int klev = i%nlev_int_packs; - loc_prec_flux(icol,klev) = init_fill_value; - loc_snow_flux(icol,klev) = init_fill_value; - loc_mass_flux(icol,klev) = init_fill_value; - }); - }; - // ------------------------------------------------------------------------- + void init(int ncol, int nlev_mid); }; // ----------------------------------------------------------------------------------------------- @@ -453,14 +218,66 @@ struct Functions { zm_output_diag() = default; }; + // ----------------------------------------------------------------------------------------------- + + //---------------------------------------------------------------------------- + // Purpose: derived type to hold ZM tunable parameters + //---------------------------------------------------------------------------- + struct ZmCommonInit { + Real tau; // convective adjustment time scale + Real alfa; // max downdraft mass flux fraction + Real ke; // evaporation efficiency + Real dmpdz; // fractional mass entrainment rate [1/m] + bool tpert_fix; // flag to disable using applying tpert to PBL-rooted convection + Real tpert_fac; // tunable temperature perturbation factor + Real tiedke_add; // tunable temperature perturbation + Real c0_lnd; // autoconversion coefficient over land + Real c0_ocn; // autoconversion coefficient over ocean + int num_cin; // num of neg buoyancy regions allowed before the conv top and CAPE calc are completed + int limcnv; // upper pressure interface level to limit deep convection + int mx_bot_lyr_adj; // bot layer index adjustment for launch level search + bool trig_dcape; // true if to using DCAPE trigger - based on CAPE generation by the dycor + bool trig_ull; // true if to using the "unrestricted launch level" (ULL) mode + bool clos_dyn_adj; // flag for mass flux adjustment to CAPE closure + bool no_deep_pbl; // flag to eliminate deep convection within PBL + // ZM micro parameters + bool zm_microp; // switch for convective microphysics + bool old_snow; // switch to calculate snow prod in zm_conv_evap() (old treatment before zm_microp was implemented) + Real auto_fac; // ZM microphysics enhancement factor for droplet-rain autoconversion + Real accr_fac; // ZM microphysics enhancement factor for droplet-rain accretion + Real micro_dcs; // ZM microphysics size threshold for cloud ice to snow autoconversion [m] + // MCSP parameters + bool mcsp_enabled; // flag for mesoscale coherent structure parameterization (MSCP) + Real mcsp_t_coeff; // MCSP coefficient for temperature tendencies + Real mcsp_q_coeff; // MCSP coefficient for specific humidity tendencies + Real mcsp_u_coeff; // MCSP coefficient for zonal momentum tendencies + Real mcsp_v_coeff; // MCSP coefficient for meridional momentum tendencies + }; + // ----------------------------------------------------------------------------------------------- // Functions + // + // --------- Init/Finalize Functions --------- + // + static void zm_common_init(); + // static Int zm_main() + // + // --------- Members --------- + // + inline static ZmCommonInit s_common_init; + }; // struct Functions } // namespace zm } // namespace scream +#if defined(EAMXX_ENABLE_GPU) && !defined(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) \ + && !defined(KOKKOS_ENABLE_HIP_RELOCATABLE_DEVICE_CODE) +# include "impl/zm_input_state_impl.hpp" +# include "impl/zm_output_tend_impl.hpp" +# include "impl/zm_common_init.hpp" +#endif // GPU && !KOKKOS_ENABLE_*_RELOCATABLE_DEVICE_CODE #endif // ZM_FUNCTIONS_HPP From d2cc116ec7feb95249f0dd6a4b5f0dfe4f6116ec Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 14 Jan 2026 15:06:57 -0700 Subject: [PATCH 334/398] Get rid of unused deps in zm_transport --- .../eam/src/physics/cam/zm/zm_transport.F90 | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_transport.F90 b/components/eam/src/physics/cam/zm/zm_transport.F90 index 6a38a212a2a9..2ed0561ea4c4 100644 --- a/components/eam/src/physics/cam/zm/zm_transport.F90 +++ b/components/eam/src/physics/cam/zm/zm_transport.F90 @@ -1,6 +1,6 @@ module zm_transport !---------------------------------------------------------------------------- - ! + ! ! Transport routines for the Zhang-McFarlane deep convection scheme ! !---------------------------------------------------------------------------- @@ -8,9 +8,6 @@ module zm_transport use zm_eamxx_bridge_params, only: r8 #else use shr_kind_mod, only: r8=>shr_kind_r8 - use ppgrid - use cam_abortutils, only: endrun - use cam_logfile, only: iulog #endif implicit none @@ -24,24 +21,24 @@ module zm_transport private real(r8), parameter :: mbsth = 1.e-15_r8 ! threshold below which we treat the mass fluxes as zero (in mb/s) - + contains !=================================================================================================== ! We need to avoid building this for now when bridging from EAMxx -#ifndef SCREAM_CONFIG_IS_CMAKE - subroutine zm_transport_tracer( pcols, ncol, pver, & doconvtran, q, ncnst, & mu, md, du, eu, ed, dp, & jt, mx, ideep, il1g, il2g, & - fracis, dqdt, dpdry, dt ) - !---------------------------------------------------------------------------- + fracis, dqdt, dpdry, dt ) + !---------------------------------------------------------------------------- ! Purpose: Convective transport of tracer species !---------------------------------------------------------------------------- use zm_conv, only: zm_param +#ifndef SCREAM_CONFIG_IS_CMAKE use constituents, only: cnst_get_type_byind +#endif !---------------------------------------------------------------------------- ! Arguments integer, intent(in) :: pcols ! maximum number of columns @@ -67,7 +64,7 @@ subroutine zm_transport_tracer( pcols, ncol, pver, & real(r8), dimension(pcols,pver,ncnst), intent(out) :: dqdt ! output tendency array !---------------------------------------------------------------------------- ! Local variables - integer :: i,k ! loop indeces + integer :: i,k ! loop indices integer :: kbm ! Highest altitude index of cloud base integer :: kk ! Work index integer :: kkp1 ! Work index @@ -102,7 +99,7 @@ subroutine zm_transport_tracer( pcols, ncol, pver, & real(r8), parameter :: maxc_factor = 1.e-12_r8 real(r8), parameter :: flux_factor = 1.e-12_r8 !---------------------------------------------------------------------------- - + ! Find the highest level top and bottom levels of convection ktm = pver kbm = pver @@ -116,7 +113,11 @@ subroutine zm_transport_tracer( pcols, ncol, pver, & if (doconvtran(m)) then +#ifndef SCREAM_CONFIG_IS_CMAKE if (cnst_get_type_byind(m).eq.'dry') then +#else + if (.false.) then +#endif do k = 1,pver do i =il1g,il2g dptmp(i,k) = dpdry(i,k) @@ -308,15 +309,13 @@ subroutine zm_transport_tracer( pcols, ncol, pver, & end subroutine zm_transport_tracer -#endif /* SCREAM_CONFIG_IS_CMAKE */ - !=================================================================================================== subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & mu, md, du, eu, ed, dp, & jt, mx, ideep, il1g, il2g, & wind_tend, pguall, pgdall, icwu, icwd, dt, seten ) - !---------------------------------------------------------------------------- + !---------------------------------------------------------------------------- ! Purpose: Convective transport of momentum !---------------------------------------------------------------------------- use zm_conv, only: zm_param @@ -379,7 +378,7 @@ subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & real(r8), parameter :: momcu = 0.4_r8 ! pressure gradient term constant for updrafts real(r8), parameter :: momcd = 0.4_r8 ! pressure gradient term constant for downdrafts !---------------------------------------------------------------------------- - + ! Initialize variables pguall(1:ncol,1:pver, 1:nwind) = 0.0_r8 pgdall(1:ncol,1:pver, 1:nwind) = 0.0_r8 @@ -450,16 +449,16 @@ subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & end do end do - ! bottom boundary + ! bottom boundary k = pver km1 = max(1,k-1) do i=il1g,il2g mududp(i,k) = mu(i,k) * (wind_mid(i,k)-wind_mid(i,km1))/dp(i,km1) - mddudp(i,k) = md(i,k) * (wind_mid(i,k)-wind_mid(i,km1))/dp(i,km1) + mddudp(i,k) = md(i,k) * (wind_mid(i,k)-wind_mid(i,km1))/dp(i,km1) pgu(i,k) = -momcu * mududp(i,k) pgd(i,k) = -momcd * mddudp(i,k) end do - + !------------------------------------------------------------------------- ! Calculate in-cloud velocity @@ -475,7 +474,7 @@ subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & endif if (md(i,k) < -mbsth) then wind_int_d(i,k) = ( -ed(i,km1)*wind_mid(i,km1)*dp(i,km1) ) - pgd(i,km1)*dp(i,km1)/md(i,k) - endif + endif end do ! Updraft from bottom to top @@ -543,7 +542,7 @@ subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & end do end do - ! Calculate momentum flux in units of mb*m/s2 + ! Calculate momentum flux in units of mb*m/s2 do k = ktm,pver do i = il1g,il2g mflux(i,k,m) = -mu(i,k)*( wind_int_u(i,k) - wind_int(i,k) ) & @@ -551,7 +550,7 @@ subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & end do end do - ! Calculate winds at the end of the time step + ! Calculate winds at the end of the time step do k = ktm,pver do i = il1g,il2g km1 = max(1,k-1) @@ -569,7 +568,7 @@ subroutine zm_transport_momentum( pcols, ncol, pver, pverp, wind_in, nwind, & km1 = max(1,k-1) kp1 = min(pver,k+1) do i = il1g,il2g - ! calculate the KE fluxes at top and bot of layer + ! calculate the KE fluxes at top and bot of layer ! based on a discrete approximation to b&b eq(35) F_KE = u*F_u + v*F_v at interface utop = ( wind0(i,k ,1) + wind0(i,km1,1) )/2._r8 vtop = ( wind0(i,k ,2) + wind0(i,km1,2) )/2._r8 From c98c15bf29d5eaca91d7f19dc279d0dc7430c8a4 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 14 Jan 2026 15:15:52 -0700 Subject: [PATCH 335/398] Update bridge to new naming format --- .../src/physics/zm/tests/infra/CMakeLists.txt | 2 +- .../infra/{zm_iso_c.f90 => zm_c2f_bridge.f90} | 16 ++++++++++++++-- .../zm/tests/infra/zm_unit_tests_common.hpp | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) rename components/eamxx/src/physics/zm/tests/infra/{zm_iso_c.f90 => zm_c2f_bridge.f90} (86%) diff --git a/components/eamxx/src/physics/zm/tests/infra/CMakeLists.txt b/components/eamxx/src/physics/zm/tests/infra/CMakeLists.txt index b8f5d6556a47..ad1eb3609d6d 100644 --- a/components/eamxx/src/physics/zm/tests/infra/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/tests/infra/CMakeLists.txt @@ -1,5 +1,5 @@ set(INFRA_SRCS - zm_iso_c.f90 + zm_c2f_bridge.f90 zm_test_data.cpp ) diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_iso_c.f90 b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 similarity index 86% rename from components/eamxx/src/physics/zm/tests/infra/zm_iso_c.f90 rename to components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 index b0a61c1230f6..755085031c3f 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_iso_c.f90 +++ b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 @@ -1,4 +1,4 @@ -module zm_iso_c +module zm_c2f_bridge use iso_c_binding implicit none @@ -46,4 +46,16 @@ end subroutine zm_find_mse_max_c !=================================================================================================== -end module zm_iso_c + subroutine ientropy_bridge_f(rcall, s, p, qt, t, qst, tfg) bind(C) + use zm, only : ientropy + + integer(kind=c_int) , value, intent(in) :: rcall + real(kind=c_real) , value, intent(in) :: s, p, qt, tfg + real(kind=c_real) , intent(out) :: t, qst + + type(c_ptr) :: zm_const + + call zm_const_set_for_testing(zm_const) + call ientropy(rcall, s, p, qt, t, qst, tfg, zm_const) + end subroutine ientropy_bridge_f +end module zm_c2f_bridge diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp b/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp index 2487d2872fa4..75dbcf2bf6ed 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp @@ -67,6 +67,7 @@ struct UnitWrap { // Put struct decls here struct Test_zm_find_mse_max; + struct TestIentropy; }; // UnitWrap }; From 989a2d27d02c8976fd3afb3b7bc31a636c61a992 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 14 Jan 2026 16:29:15 -0700 Subject: [PATCH 336/398] EAMxx: move field_request.hpp into data_managers folder It doesn't belong with Field, as it pertains to how the FM needs to allocate fields/groups --- components/eamxx/src/control/atmosphere_driver.cpp | 4 ++-- components/eamxx/src/share/atm_process/atmosphere_process.hpp | 2 +- components/eamxx/src/share/data_managers/field_manager.hpp | 4 ++-- .../src/share/{field => data_managers}/field_request.hpp | 0 4 files changed, 5 insertions(+), 5 deletions(-) rename components/eamxx/src/share/{field => data_managers}/field_request.hpp (100%) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 2ec7cea3acab..69a62fea40c1 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -59,7 +59,7 @@ namespace control { * Note: at this stage, atm procs that act on non-ref grid(s) should be able to create their * remappers. The AD will *not* take care of remapping inputs/outputs of the process. * 4) Register all fields and all groups from all atm procs inside the field managers, and proceed - * to allocate fields. For more details, see the documentation in the share/field/field_request.hpp header. + * to allocate fields. For more details, see the documentation in the share/data_managers/field_request.hpp header. * 5) Set all the fields into the atm procs. Before this point, all the atm procs had were the * FieldIdentifiers for their input/output fields and FieldGroupInfo for their input/output * field groups. Now, we pass actual Field and FieldGroup objects to them, where both the @@ -84,7 +84,7 @@ namespace control { * - for field -> src/share/field/field.hpp * - for field manager -> src/share/data_managers/field_manager.hpp * - for field groups -> src/share/field/field_group.hpp - * - for field/group requests -> src/share/field/field_request.hpp + * - for field/group requests -> src/share/data_managers/field_request.hpp * - for grid -> src/share/grid/abstract_grid.hpp * - for grid manager -> src/share/data_managers/grids_manager.hpp * - for atm proc -> src/share/atm_process/atmosphere_process.hpp diff --git a/components/eamxx/src/share/atm_process/atmosphere_process.hpp b/components/eamxx/src/share/atm_process/atmosphere_process.hpp index ceeeddfef441..4a1565e86968 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process.hpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process.hpp @@ -7,9 +7,9 @@ #include "share/data_managers/SCDataManager.hpp" #include "share/data_managers/grids_manager.hpp" #include "share/data_managers/field_manager.hpp" +#include "share/data_managers/field_request.hpp" #include "share/property_checks/property_check.hpp" #include "share/field/field_identifier.hpp" -#include "share/field/field_request.hpp" #include "share/field/field.hpp" #include "share/field/field_group.hpp" diff --git a/components/eamxx/src/share/data_managers/field_manager.hpp b/components/eamxx/src/share/data_managers/field_manager.hpp index 7aedc12cffd0..58466734fbcd 100644 --- a/components/eamxx/src/share/data_managers/field_manager.hpp +++ b/components/eamxx/src/share/data_managers/field_manager.hpp @@ -1,11 +1,11 @@ #ifndef SCREAM_FIELD_MANAGER_HPP #define SCREAM_FIELD_MANAGER_HPP -#include "share/grid/abstract_grid.hpp" #include "share/data_managers/grids_manager.hpp" +#include "share/data_managers/field_request.hpp" +#include "share/grid/abstract_grid.hpp" #include "share/field/field.hpp" #include "share/field/field_group.hpp" -#include "share/field/field_request.hpp" #include "share/util/eamxx_utils.hpp" #include "share/core/eamxx_types.hpp" diff --git a/components/eamxx/src/share/field/field_request.hpp b/components/eamxx/src/share/data_managers/field_request.hpp similarity index 100% rename from components/eamxx/src/share/field/field_request.hpp rename to components/eamxx/src/share/data_managers/field_request.hpp From a9cf87aff378623684f8c9c1dcdeb7f9c523524d Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 15 Jan 2026 09:46:55 -0700 Subject: [PATCH 337/398] EAMxx: unify computed/required requests in atm process --- .../eamxx/src/control/atmosphere_driver.cpp | 42 ++++++---------- .../physics/nudging/tests/nudging_tests.cpp | 11 ++--- .../atm_process/atmosphere_diagnostic.cpp | 8 +-- .../share/atm_process/atmosphere_process.cpp | 32 ++++++------ .../share/atm_process/atmosphere_process.hpp | 44 ++++------------- .../atm_process/atmosphere_process_group.cpp | 49 ++++++------------- .../atm_process/atmosphere_process_group.hpp | 4 +- .../atm_process/tests/atm_diag_tests.cpp | 2 +- .../atm_process/tests/atm_proc_dag_tests.cpp | 16 +++--- .../atm_process/tests/atm_proc_tests.cpp | 2 +- .../src/share/data_managers/field_request.hpp | 15 ++++-- .../diagnostics/tests/atm_density_test.cpp | 2 +- .../tests/dry_static_energy_test.cpp | 2 +- .../share/diagnostics/tests/exner_test.cpp | 2 +- .../tests/field_at_pressure_level_tests.cpp | 2 +- .../tests/longwave_cloud_forcing_tests.cpp | 2 +- .../diagnostics/tests/number_paths_tests.cpp | 2 +- .../tests/potential_temperature_test.cpp | 2 +- .../tests/precip_surf_mass_flux_tests.cpp | 2 +- .../tests/relative_humidity_tests.cpp | 2 +- .../tests/sea_level_pressure_test.cpp | 2 +- .../tests/shortwave_cloud_forcing_tests.cpp | 2 +- .../surf_upward_latent_heat_flux_tests.cpp | 2 +- .../diagnostics/tests/vapor_flux_tests.cpp | 2 +- .../tests/vertical_layer_tests.cpp | 2 +- .../tests/virtual_temperature_test.cpp | 2 +- .../diagnostics/tests/water_path_tests.cpp | 2 +- .../eamxx/src/share/io/scorpio_output.cpp | 4 +- 28 files changed, 104 insertions(+), 157 deletions(-) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 69a62fea40c1..79bca84e688f 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -547,16 +547,10 @@ void AtmosphereDriver::create_fields() // Register required/computed fields. By now, the processes should have // fully built the ids of their required/computed fields and groups - for (const auto& req : m_atm_process_group->get_required_field_requests()) { + for (const auto& req : m_atm_process_group->get_field_requests()) { m_field_mgr->register_field(req); } - for (const auto& req : m_atm_process_group->get_computed_field_requests()) { - m_field_mgr->register_field(req); - } - for (const auto& greq : m_atm_process_group->get_required_group_requests()) { - m_field_mgr->register_group(greq); - } - for (const auto& greq : m_atm_process_group->get_computed_group_requests()) { + for (const auto& greq : m_atm_process_group->get_group_requests()) { m_field_mgr->register_group(greq); } @@ -566,26 +560,20 @@ void AtmosphereDriver::create_fields() // Set all the fields/groups in the processes. Input fields/groups will be handed // to the processes with const scalar type (const Real), to prevent them from // overwriting them (though, they can always cast away const...). - // IMPORTANT: set all computed fields/groups first, since the AtmProcGroup class - // needs to inspect those before deciding whether a required group is indeed - // required or not. E.g., in AtmProcGroup [A, B], if A computes group "blah" (or all - // the fields contained in group "blah"), then group "blah" is not a required - // group for the AtmProcGroup, even if it is a required group for B. - for (const auto& req : m_atm_process_group->get_computed_field_requests()) { - const auto& fid = req.fid; - m_atm_process_group->set_computed_field(m_field_mgr->get_field(fid)); - } - for (const auto& it : m_atm_process_group->get_computed_group_requests()) { - auto group = m_field_mgr->get_field_group(it.name, it.grid); - m_atm_process_group->set_computed_group(group); - } - for (const auto& it : m_atm_process_group->get_required_group_requests()) { - auto group = m_field_mgr->get_field_group(it.name, it.grid).get_const(); - m_atm_process_group->set_required_group(group); - } - for (const auto& req : m_atm_process_group->get_required_field_requests()) { + for (const auto& req : m_atm_process_group->get_field_requests()) { const auto& fid = req.fid; - m_atm_process_group->set_required_field(m_field_mgr->get_field(fid).get_const()); + const auto& f = m_field_mgr->get_field(fid); + if (req.usage & Computed) + m_atm_process_group->set_computed_field(f); + if (req.usage & Required) + m_atm_process_group->set_required_field(f.get_const()); + } + for (const auto& req : m_atm_process_group->get_group_requests()) { + auto group = m_field_mgr->get_field_group(req.name, req.grid); + if (req.usage & Computed) + m_atm_process_group->set_computed_group(group); + if (req.usage & Required) + m_atm_process_group->set_required_group(group.get_const()); } // Make atm procs create the proc-level tendency fields (if requested) diff --git a/components/eamxx/src/physics/nudging/tests/nudging_tests.cpp b/components/eamxx/src/physics/nudging/tests/nudging_tests.cpp index 602c13d21c6b..c533b560d76a 100644 --- a/components/eamxx/src/physics/nudging/tests/nudging_tests.cpp +++ b/components/eamxx/src/physics/nudging/tests/nudging_tests.cpp @@ -17,13 +17,12 @@ create_nudging (const ekat::Comm& comm, { auto nudging = std::make_shared(comm,params); nudging->set_grids(gm); - for (const auto& req : nudging->get_required_field_requests()) { + for (const auto& req : nudging->get_field_requests()) { auto f = fm->get_field(req.fid.name()); - nudging->set_required_field(f); - } - for (const auto& req : nudging->get_computed_field_requests()) { - auto f = fm->get_field(req.fid.name()); - nudging->set_computed_field(f); + if (req.usage & Required) + nudging->set_required_field(f.get_const()); + if (req.usage & Computed) + nudging->set_computed_field(f); } nudging->initialize(t0,RunType::Initial); diff --git a/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp b/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp index 823b8cce8c24..ec451561beea 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_diagnostic.cpp @@ -79,14 +79,14 @@ set_required_field_impl (const Field& f) { // While we fix all diags, this method will at least // throw an error if the pack size that the diag "requested" // is not compatible with the field alloc props. - for (const auto& it : get_required_field_requests()) { - if (it.fid.name()==f.name()) { + for (const auto& r : get_field_requests()) { + if (r.fid.name()==f.name()) { const auto& fap = f.get_header().get_alloc_properties(); - EKAT_REQUIRE_MSG (fap.get_largest_pack_size()>=it.pack_size, + EKAT_REQUIRE_MSG (fap.get_largest_pack_size()>=r.pack_size, "Error! Diagnostic input field cannot accommodate the needed pack size.\n" " - diag field: " + m_diagnostic_output.name() + "\n" " - input field: " + f.name() + "\n" - " - requested pack size: " + std::to_string(it.pack_size) + "\n" + " - requested pack size: " + std::to_string(r.pack_size) + "\n" " - field max pack size: " + std::to_string(fap.get_largest_pack_size()) + "\n"); break; } diff --git a/components/eamxx/src/share/atm_process/atmosphere_process.cpp b/components/eamxx/src/share/atm_process/atmosphere_process.cpp index 10c90d995bac..25b715e66aad 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process.cpp @@ -552,11 +552,11 @@ bool AtmosphereProcess::has_required_field (const FieldIdentifier& id) const { return has_required_field(id.name(),id.get_grid_name()); } -bool AtmosphereProcess::has_required_field (const std::string& name, const std::string& grid_name) const { - for (const auto& it : m_required_field_requests) { - if (it.fid.name()==name && it.fid.get_grid_name()==grid_name) { +bool AtmosphereProcess::has_required_field (const std::string& name, const std::string& grid_name) const +{ + for (const auto& r : m_field_requests) { + if (r.fid.name()==name and r.fid.get_grid_name()==grid_name and r.usage & Required) return true; - } } return false; } @@ -565,29 +565,29 @@ bool AtmosphereProcess::has_computed_field (const FieldIdentifier& id) const { return has_computed_field(id.name(),id.get_grid_name()); } -bool AtmosphereProcess::has_computed_field (const std::string& name, const std::string& grid_name) const { - for (const auto& it : m_computed_field_requests) { - if (it.fid.name()==name && it.fid.get_grid_name()==grid_name) { +bool AtmosphereProcess::has_computed_field (const std::string& name, const std::string& grid_name) const +{ + for (const auto& r : m_field_requests) { + if (r.fid.name()==name and r.fid.get_grid_name()==grid_name and r.usage & Computed) return true; - } } return false; } -bool AtmosphereProcess::has_required_group (const std::string& name, const std::string& grid) const { - for (const auto& it : m_required_group_requests) { - if (it.name==name && it.grid==grid) { +bool AtmosphereProcess::has_required_group (const std::string& name, const std::string& grid) const +{ + for (const auto& r : m_group_requests) { + if (r.name==name and r.grid==grid and r.usage & Required) return true; - } } return false; } -bool AtmosphereProcess::has_computed_group (const std::string& name, const std::string& grid) const { - for (const auto& it : m_computed_group_requests) { - if (it.name==name && it.grid==grid) { +bool AtmosphereProcess::has_computed_group (const std::string& name, const std::string& grid) const +{ + for (const auto& r : m_group_requests) { + if (r.name==name and r.grid==grid and r.usage & Computed) return true; - } } return false; } diff --git a/components/eamxx/src/share/atm_process/atmosphere_process.hpp b/components/eamxx/src/share/atm_process/atmosphere_process.hpp index 4a1565e86968..43736ebbf4af 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process.hpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process.hpp @@ -183,10 +183,8 @@ class AtmosphereProcess : public std::enable_shared_from_this // These methods allow the AD to figure out what each process needs, with very fine // grain detail. See field_request.hpp for more info on what FieldRequest and GroupRequest // are, and field_group.hpp for what groups of fields are. - const std::list& get_required_field_requests () const { return m_required_field_requests; } - const std::list& get_computed_field_requests () const { return m_computed_field_requests; } - const std::list& get_required_group_requests () const { return m_required_group_requests; } - const std::list& get_computed_group_requests () const { return m_computed_group_requests; } + const std::list& get_field_requests () const { return m_field_requests; } + const std::list& get_group_requests () const { return m_group_requests; } // These sets allow to get all the actual in/out fields stored by the atm proc // Note: if an atm proc requires a group, then all the fields in the group, as well as @@ -406,18 +404,8 @@ class AtmosphereProcess : public std::enable_shared_from_this static_assert(RT==Required || RT==Computed || RT==Updated, "Error! Invalid request type in call to add_field.\n"); - switch (RT) { - case Required: - m_required_field_requests.push_back(req); - break; - case Computed: - m_computed_field_requests.push_back(req); - break; - case Updated: - m_required_field_requests.push_back(req); - m_computed_field_requests.push_back(req); - break; - } + auto& r = m_field_requests.emplace_back(req); + r.usage = RT; } template @@ -426,20 +414,10 @@ class AtmosphereProcess : public std::enable_shared_from_this // Since we use C-style enum, let's avoid invalid integers casts static_assert(RT==Required || RT==Updated || RT==Computed, "Error! Invalid request type in call to add_group.\n"); - switch (RT) { - case Required: - m_required_group_requests.push_back(req); - break; - case Computed: - m_computed_group_requests.push_back(req); - break; - case Updated: - m_required_group_requests.push_back(req); - m_computed_group_requests.push_back(req); - break; - } - } + auto& r = m_group_requests.emplace_back(req); + r.usage = RT; + } // Override this method to initialize the derived virtual void initialize_impl(const RunType run_type) = 0; @@ -628,11 +606,9 @@ class AtmosphereProcess : public std::enable_shared_from_this // IOP object iop_data_ptr m_iop_data_manager; - // The list of in/out field/group requests. - std::list m_required_field_requests; - std::list m_computed_field_requests; - std::list m_required_group_requests; - std::list m_computed_group_requests; + // A map grid_name->requests for in/out field/group. + std::list m_field_requests; + std::list m_group_requests; void add_py_fields (const Field& f); void add_py_fields (const FieldGroup& g); diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp b/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp index 5589cbf784f7..2b220b86f1b0 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp @@ -154,22 +154,19 @@ void AtmosphereProcessGroup::set_grids (const std::shared_ptrset_grids(grids_manager); // Add inputs/outputs to the list of inputs of the group - for (const auto& req : atm_proc->get_required_field_requests()) { - process_required_field(req); - } - for (const auto& req : atm_proc->get_computed_field_requests()) { - add_field(req); - } - for (const auto& req : atm_proc->get_required_group_requests()) { - process_required_group(req); + for (const auto& ap_req : atm_proc->get_field_requests()) { + auto& req = m_field_requests.emplace_back(ap_req); + if (req.usage & Required) + process_required_field(req); } - for (const auto& req : atm_proc->get_computed_group_requests()) { - add_group(req); + for (const auto& ap_req : atm_proc->get_group_requests()) { + auto& req = m_group_requests.emplace_back(ap_req); + if (req.usage & Required) + process_required_group(req); } } @@ -351,10 +348,7 @@ void AtmosphereProcessGroup::pre_process_tracer_requests () { tracer_requests[req.fid.name()].push_back(req); } }; - for (auto& req : m_required_field_requests){ - gather_tracer_requests(req); - } - for (auto& req : m_computed_field_requests) { + for (auto& req : m_field_requests){ gather_tracer_requests(req); } @@ -404,12 +398,7 @@ void AtmosphereProcessGroup::pre_process_tracer_requests () { req.groups.push_back(advect_type); } }; - for (auto& req : m_required_field_requests){ - if (ekat::contains(req.groups, "tracers")) { - add_correct_tracer_group(req, tracer_advection_type.at(req.fid.name())); - } - } - for (auto& req : m_computed_field_requests) { + for (auto& req : m_field_requests){ if (ekat::contains(req.groups, "tracers")) { add_correct_tracer_group(req, tracer_advection_type.at(req.fid.name())); } @@ -670,7 +659,7 @@ void AtmosphereProcessGroup::set_computed_field_impl (const Field& f) { } void AtmosphereProcessGroup:: -process_required_group (const GroupRequest& req) { +process_required_group (GroupRequest& req) { if (m_group_schedule_type==ScheduleType::Sequential) { if (has_computed_group(req.name,req.grid)) { // Some previous atm proc computes this group, so it's not an 'input' @@ -682,18 +671,15 @@ process_required_group (const GroupRequest& req) { // NOTE; we don't have a way to check if all the fields in the group // are computed by previous processes, since we don't have // the list of all fields in this group. - add_group(req); - } else { - add_group(req); + req.usage = Computed; } } else { - // In parallel schedule, the inputs of all processes are inputs of the group - add_group(req); + EKAT_ERROR_MSG ("Error! Parallel schedule not supported.\n"); } } void AtmosphereProcessGroup:: -process_required_field (const FieldRequest& req) { +process_required_field (FieldRequest& req) { if (m_group_schedule_type==ScheduleType::Sequential) { if (has_computed_field(req.fid)) { // Some previous atm proc computes this field, so it's not an 'input' @@ -702,13 +688,10 @@ process_required_field (const FieldRequest& req) { // the required fields, we add to the computed fields. This way we // don't modify the inputs of the group, and still manage to communicate // to the AD the pack size and group affiliations that we need - add_field(req); - } else { - add_field(req); + req.usage = Computed; } } else { - // In parallel schedule, the inputs of all processes are inputs of the group - add_field(req); + EKAT_ERROR_MSG ("Error! Parallel schedule not supported.\n"); } } diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp b/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp index 2b27d5fa1dc1..3b861f6f786f 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp @@ -120,8 +120,8 @@ class AtmosphereProcessGroup : public AtmosphereProcess protected: // Adds fid to the list of required/computed fields of the group (as a whole). - void process_required_field (const FieldRequest& req); - void process_required_group (const GroupRequest& req); + void process_required_field (FieldRequest& req); + void process_required_group (GroupRequest& req); // The initialization, run, and finalization methods void initialize_impl(const RunType run_type); diff --git a/components/eamxx/src/share/atm_process/tests/atm_diag_tests.cpp b/components/eamxx/src/share/atm_process/tests/atm_diag_tests.cpp index 2122dcd484d9..93649970a5e8 100644 --- a/components/eamxx/src/share/atm_process/tests/atm_diag_tests.cpp +++ b/components/eamxx/src/share/atm_process/tests/atm_diag_tests.cpp @@ -82,7 +82,7 @@ TEST_CASE ("diagnostics") { diag_sum->set_grids(gm); std::map input_fields; - for (const auto& req : diag_sum->get_required_field_requests()) { + for (const auto& req : diag_sum->get_field_requests()) { Field f(req.fid); f.allocate_view(); f.get_header().get_tracking().update_time_stamp(t0); diff --git a/components/eamxx/src/share/atm_process/tests/atm_proc_dag_tests.cpp b/components/eamxx/src/share/atm_process/tests/atm_proc_dag_tests.cpp index 82697310f4ae..c4080cc178cd 100644 --- a/components/eamxx/src/share/atm_process/tests/atm_proc_dag_tests.cpp +++ b/components/eamxx/src/share/atm_process/tests/atm_proc_dag_tests.cpp @@ -200,11 +200,7 @@ TEST_CASE("atm_proc_dag", "") { -> std::map { std::map fields; - for (auto r : ap.get_required_field_requests()) { - fields[r.fid.name()] = Field(r.fid); - fields[r.fid.name()].allocate_view(); - } - for (auto r : ap.get_computed_field_requests()) { + for (auto r : ap.get_field_requests()) { fields[r.fid.name()] = Field(r.fid); fields[r.fid.name()].allocate_view(); } @@ -214,11 +210,11 @@ TEST_CASE("atm_proc_dag", "") { auto create_and_set_fields = [&] (AtmosphereProcess& ap) { auto fields = create_fields(ap); - for (auto r : ap.get_required_field_requests()) { - ap.set_required_field(fields.at(r.fid.name())); - } - for (auto r : ap.get_computed_field_requests()) { - ap.set_computed_field(fields.at(r.fid.name())); + for (auto r : ap.get_field_requests()) { + if (r.usage & Required) + ap.set_required_field(fields.at(r.fid.name()).get_const()); + if (r.usage & Computed) + ap.set_computed_field(fields.at(r.fid.name())); } }; diff --git a/components/eamxx/src/share/atm_process/tests/atm_proc_tests.cpp b/components/eamxx/src/share/atm_process/tests/atm_proc_tests.cpp index 88e2cc132622..0c055cfb7e3e 100644 --- a/components/eamxx/src/share/atm_process/tests/atm_proc_tests.cpp +++ b/components/eamxx/src/share/atm_process/tests/atm_proc_tests.cpp @@ -311,7 +311,7 @@ TEST_CASE ("subcycling") { ap_sub->set_grids(gm); // Create fields (should be just one) and set it in the atm procs - for(const auto& req : ap->get_required_field_requests()) { + for(const auto& req : ap->get_field_requests()) { Field f(req.fid); f.allocate_view(); f.deep_copy(0); diff --git a/components/eamxx/src/share/data_managers/field_request.hpp b/components/eamxx/src/share/data_managers/field_request.hpp index 2fe706a7a4a2..de14c0505af7 100644 --- a/components/eamxx/src/share/data_managers/field_request.hpp +++ b/components/eamxx/src/share/data_managers/field_request.hpp @@ -8,9 +8,10 @@ namespace scream { enum RequestType { - Required, - Computed, - Updated // For convenience, triggers Required+Computed + Invalid = 0, // To spot if a request was not set correctly + Required = 1, + Computed = 2, + Updated = 3, // For convenience, triggers Required+Computed }; // Whether a tracer should be advected by both Dynamics @@ -68,8 +69,10 @@ struct GroupRequest { // Main parts of a group request std::string name; // Group name std::string grid; // Grid name - int pack_size; // Request an allocation that can accomodate Pack + int pack_size = 1; // Request an allocation that can accomodate Pack MonolithicAlloc monolithic_alloc; // Whether the group should be allocated as a single n+1 dimensional field + + RequestType usage = RequestType::Invalid; // Whether we will need the group for read, write, or read/write }; // In order to use GroupRequest in std sorted containers (like std::set), @@ -179,12 +182,14 @@ struct FieldRequest { // Data FieldIdentifier fid; - int pack_size; + int pack_size = 1; std::list groups; SubviewInfo subview_info; std::string parent_name; bool incomplete = false; std::string calling_process = "UNKNOWN"; + + RequestType usage = RequestType::Invalid; // Whether we will need the group for read, write, or read/write }; // In order to use FieldRequest in std sorted containers (like std::set), diff --git a/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp b/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp index 94ffad17d925..e80a7ca112b2 100644 --- a/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/atm_density_test.cpp @@ -81,7 +81,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp b/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp index c2a525728707..f58cf5e0934e 100644 --- a/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/dry_static_energy_test.cpp @@ -83,7 +83,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/exner_test.cpp b/components/eamxx/src/share/diagnostics/tests/exner_test.cpp index 934bc7001862..d9daaee99516 100644 --- a/components/eamxx/src/share/diagnostics/tests/exner_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/exner_test.cpp @@ -78,7 +78,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/field_at_pressure_level_tests.cpp b/components/eamxx/src/share/diagnostics/tests/field_at_pressure_level_tests.cpp index 5d1d0ceee1a0..d42d51f39a9a 100644 --- a/components/eamxx/src/share/diagnostics/tests/field_at_pressure_level_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/field_at_pressure_level_tests.cpp @@ -225,7 +225,7 @@ get_test_diag(const ekat::Comm& comm, std::shared_ptr fm, st params.set("pressure_units",std::string("Pa")); auto diag = std::make_shared(comm,params); diag->set_grids(gm); - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { auto req_field = fm->get_field(req.fid); diag->set_required_field(req_field); } diff --git a/components/eamxx/src/share/diagnostics/tests/longwave_cloud_forcing_tests.cpp b/components/eamxx/src/share/diagnostics/tests/longwave_cloud_forcing_tests.cpp index 84a4a0efa02c..b5739489e1c8 100644 --- a/components/eamxx/src/share/diagnostics/tests/longwave_cloud_forcing_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/longwave_cloud_forcing_tests.cpp @@ -89,7 +89,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp b/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp index afa955e018c9..2a5bdb7b6090 100644 --- a/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/number_paths_tests.cpp @@ -94,7 +94,7 @@ void run(std::mt19937_64 &engine) { std::map input_fields; for(const auto &dd : diags) { const auto &diag = dd.second; - for(const auto &req : diag->get_required_field_requests()) { + for(const auto &req : diag->get_field_requests()) { if(input_fields.find(req.fid.name()) == input_fields.end()) { Field f(req.fid); f.allocate_view(); diff --git a/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp b/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp index 5f1134654f54..e232f27c8fec 100644 --- a/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/potential_temperature_test.cpp @@ -80,7 +80,7 @@ void run(std::mt19937_64& engine, int int_ptype) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp b/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp index e338508bdae3..c1e95aeb2e6c 100644 --- a/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/precip_surf_mass_flux_tests.cpp @@ -72,7 +72,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag_total->get_required_field_requests()) { + for (const auto& req : diag_total->get_field_requests()) { Field f(req.fid); f.get_header().get_alloc_properties().request_allocation(); f.allocate_view(); diff --git a/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp b/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp index 205ae61f01a3..02eef96a8f7e 100644 --- a/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/relative_humidity_tests.cpp @@ -96,7 +96,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp b/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp index 24ce74ce43b1..ef01e38e1c32 100644 --- a/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/sea_level_pressure_test.cpp @@ -75,7 +75,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/shortwave_cloud_forcing_tests.cpp b/components/eamxx/src/share/diagnostics/tests/shortwave_cloud_forcing_tests.cpp index cdea26718ec4..09ad45401800 100644 --- a/components/eamxx/src/share/diagnostics/tests/shortwave_cloud_forcing_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/shortwave_cloud_forcing_tests.cpp @@ -91,7 +91,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp b/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp index f0c022ec5d88..621d0cf88a16 100644 --- a/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/surf_upward_latent_heat_flux_tests.cpp @@ -61,7 +61,7 @@ void run(std::mt19937_64& engine, const ekat::Comm& comm, LoggerType& logger) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req: diag_latent_heat->get_required_field_requests()) { + for (const auto& req: diag_latent_heat->get_field_requests()) { Field f(req.fid); f.get_header().get_alloc_properties().request_allocation(); f.allocate_view(); diff --git a/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp b/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp index 9786e9bf7b79..6a2bfea51e7e 100644 --- a/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/vapor_flux_tests.cpp @@ -90,7 +90,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); f.allocate_view(); f.get_header().get_tracking().update_time_stamp(t0); diff --git a/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp b/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp index cc8ad2134d2b..363ca7ba055f 100644 --- a/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/vertical_layer_tests.cpp @@ -60,7 +60,7 @@ void run (const std::string& diag_name, const std::string& location) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/virtual_temperature_test.cpp b/components/eamxx/src/share/diagnostics/tests/virtual_temperature_test.cpp index fdb9d39f756a..c9e6f3ac9c73 100644 --- a/components/eamxx/src/share/diagnostics/tests/virtual_temperature_test.cpp +++ b/components/eamxx/src/share/diagnostics/tests/virtual_temperature_test.cpp @@ -78,7 +78,7 @@ void run(std::mt19937_64& engine) // Set the required fields for the diagnostic. std::map input_fields; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { Field f(req.fid); auto & f_ap = f.get_header().get_alloc_properties(); f_ap.request_allocation(packsize); diff --git a/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp b/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp index ba7e7b40e372..352633c591bf 100644 --- a/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp +++ b/components/eamxx/src/share/diagnostics/tests/water_path_tests.cpp @@ -121,7 +121,7 @@ void run(std::mt19937_64& engine) std::map input_fields; for (const auto& dd : diags) { const auto& diag = dd.second; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { if (input_fields.find(req.fid.name())==input_fields.end()) { Field f(req.fid); f.allocate_view(); diff --git a/components/eamxx/src/share/io/scorpio_output.cpp b/components/eamxx/src/share/io/scorpio_output.cpp index 69bb3d1fbfad..46699359fedc 100644 --- a/components/eamxx/src/share/io/scorpio_output.cpp +++ b/components/eamxx/src/share/io/scorpio_output.cpp @@ -1006,7 +1006,7 @@ process_requested_fields() // Helper lambda that initializes a diagnostic auto init_diag = [&](const std::shared_ptr& diag) { // Set inputs in the diag - for (const auto& freq : diag->get_required_field_requests()) { + for (const auto& freq : diag->get_field_requests()) { const auto& dep_name = freq.fid.name(); auto dep = fm_model->get_field(dep_name); @@ -1102,7 +1102,7 @@ process_requested_fields() } // Add its deps to the list of fields to process (if not already in fm_model) bool deps_met = true; - for (const auto& req : diag->get_required_field_requests()) { + for (const auto& req : diag->get_field_requests()) { if (not fm_model->has_field(req.fid.name())) { deps_met = false; add_these.insert(req.fid.name()); From 9b7c3595180fd8a3f259e53cff3ab2a525309846 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 11:22:11 -0700 Subject: [PATCH 338/398] Improvements to gen-boiler to handle scalar-only test data --- .../eamxx/scripts/gen-boiler/gen_boiler.py | 456 +++++++----------- .../eamxx/scripts/gen-boiler/run-gb-tests | 54 ++- .../eamxx/src/physics/zm/CMakeLists.txt | 1 + .../eamxx/src/physics/zm/eti/zm_ientropy.cpp | 14 + .../src/physics/zm/impl/zm_ientropy_impl.hpp | 34 ++ .../eamxx/src/physics/zm/tests/CMakeLists.txt | 1 + .../physics/zm/tests/infra/zm_test_data.cpp | 83 +++- .../physics/zm/tests/infra/zm_test_data.hpp | 16 +- .../eamxx/src/physics/zm/zm_functions.hpp | 14 + 9 files changed, 376 insertions(+), 297 deletions(-) create mode 100644 components/eamxx/src/physics/zm/eti/zm_ientropy.cpp create mode 100644 components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index d01057eef0a9..444c86c37b79 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -13,7 +13,7 @@ "cxx_bfb_unit_impl": lambda phys, sub, gen_code: f"""#include "catch2/catch.hpp" -#include "share/eamxx_types.hpp" +#include "share/core/eamxx_types.hpp" #include "physics/{phys}/{phys}_functions.hpp" #include "physics/{phys}/tests/infra/{phys}_test_data.hpp" @@ -1126,6 +1126,15 @@ def gen_struct_api(struct_name, arg_data): result.append("PTD_STD_DEF({}, {}, {});".\ format(struct_name, len(cons_args), ", ".join([name for name, _ in cons_args]))) + result.append("") + result.append("// TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices") + result.append("// template ") + result.append("// void transition()") + result.append("// {") + result.append("// PhysicsTestData::transition(PUT INT ARRAY SKIPS HERE);") + result.append("// shift_int_scalar(PUT INT SCALAR HERE);") + result.append("// }") + return result ############################################################################### @@ -1266,178 +1275,174 @@ def gen_glue_impl(phys, sub, arg_data, arg_names, col_dim, f2c=False, unpacked=F if not f2c: impl += init_code - if has_arrays(arg_data): - # - # Steps: - # 1) Set up typedefs - # 2) Sync to device - # 3) Unpack view array - # 4) Get nk_pack and policy - # 5) Get subviews - # 6) Call fn - # 7) Sync back to host - # - inputs, inouts, outputs = split_by_intent(arg_data) - reals, ints, bools = split_by_type(arg_data) - scalars, views = split_by_scalar_vs_view(arg_data) - all_inputs = inputs + inouts - all_outputs = inouts + outputs - - iscalars = list(sorted(set(all_inputs) & set(scalars))) - oscalars = list(sorted(set(all_outputs) & set(scalars))) - - oviews = list(sorted(set(all_outputs) & set(views))) - - vreals = list(sorted(set(reals) & set(views))) - vints = list(sorted(set(ints) & set(views))) - vbools = list(sorted(set(bools) & set(views))) - - sreals = list(sorted(set(reals) & set(scalars))) - sints = list(sorted(set(ints) & set(scalars))) - sbools = list(sorted(set(bools) & set(scalars))) - - ovreals = list(sorted(set(vreals) & set(all_outputs))) - ovints = list(sorted(set(vints) & set(all_outputs))) - ovbools = list(sorted(set(vbools) & set(all_outputs))) - - isreals = list(sorted(set(sreals) & set(all_inputs))) - isints = list(sorted(set(sints) & set(all_inputs))) - isbools = list(sorted(set(sbools) & set(all_inputs))) - - osreals = list(sorted(set(sreals) & set(all_outputs))) - osints = list(sorted(set(sints) & set(all_outputs))) - osbools = list(sorted(set(sbools) & set(all_outputs))) - - # - # 1) Set up typedefs (or just have these at the top of file so they can be shared?) - # - - # set up basics - - type_list = ["Real", "Int", "bool"] - impl += " // create device views and copy\n" - - # - # 2) Sync to device. Do ALL views, not just inputs - # - - for input_group, typename in zip([vreals, vints, vbools], type_list): - if input_group: - rank_map = get_rank_map(arg_data, input_group) + # + # Steps: + # 1) Set up typedefs + # 2) Sync to device + # 3) Unpack view array + # 4) Get nk_pack and policy + # 5) Get subviews + # 6) Call fn + # 7) Sync back to host + # + inputs, inouts, outputs = split_by_intent(arg_data) + reals, ints, bools = split_by_type(arg_data) + scalars, views = split_by_scalar_vs_view(arg_data) + all_inputs = inputs + inouts + all_outputs = inouts + outputs - for rank, arg_list in rank_map.items(): - impl += get_htd_dth_call(arg_data, rank, arg_list, typename, f2c=f2c) + iscalars = list(sorted(set(all_inputs) & set(scalars))) + oscalars = list(sorted(set(all_outputs) & set(scalars))) - # - # 3) Unpack view array - # + oviews = list(sorted(set(all_outputs) & set(views))) - for input_group, typename in zip([vreals, vints, vbools], type_list): - prefix_char = PREFIX_MAP[typename] - if input_group: - rank_map = get_rank_map(arg_data, input_group) + vreals = list(sorted(set(reals) & set(views))) + vints = list(sorted(set(ints) & set(views))) + vbools = list(sorted(set(bools) & set(views))) - for rank, arg_list in rank_map.items(): - view_type = get_view_type(typename, rank) - impl += f" {view_type}\n" - for idx, input_item in enumerate(arg_list): - impl += f" {input_item}_d(vec{rank}d{prefix_char}_in[{idx}]){';' if idx == len(arg_list) - 1 else ','}\n" - impl += "\n" - - - # - # 4) Get nk_pack and policy, unpack scalars, and launch kernel - # - if unpacked: - impl += f" const auto policy = ekat::TeamPolicyFactory::get_default_team_policy({obj}{col_dim}, {obj}nlev);\n\n" - else: - impl += f" const Int nk_pack = ekat::npack({obj}nlev);\n" - impl += f" const auto policy = ekat::TeamPolicyFactory::get_default_team_policy({obj}{col_dim}, nk_pack);\n\n" - - if scalars: - if not f2c: - impl += " // unpack data scalars because we do not want the lambda to capture d\n" - for input_group, typename in zip([isreals, isints, isbools], type_list): - if input_group: - for arg in input_group: - if arg not in oscalars and arg != col_dim: - impl += f" const {typename} {arg} = {obj}{arg};\n" - - # We use 0-rank views to handle output scalars - for output_group, typename in zip([osreals, osints, osbools], type_list): - if output_group: - view_type = get_view_type(typename, 0) - hview_type = view_type[0:-2] + "_h" - for arg in output_group: - impl += f' {hview_type} {arg}_h("{arg}_h");\n' - if arg in iscalars: - impl += f' {arg}_h() = {obj}{arg};\n' - impl += f' {view_type} {arg}_d = Kokkos::create_mirror_view_and_copy(DefaultDevice(), {arg}_h);\n' - - impl += "\n" - - impl += " Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) {\n" - impl += " const Int i = team.league_rank();\n\n" - - # - # 5) Get subviews - # - impl += " // Get single-column subviews of all inputs, shouldn't need any i-indexing\n" - impl += " // after this.\n" - - for view_arg in views: - dims = get_data_by_name(arg_data, view_arg, ARG_DIMS) - if col_dim in dims: - if len(dims) == 1: - pass - else: - impl += f" const auto {view_arg}_c = ekat::subview({view_arg}_d, i);\n" + sreals = list(sorted(set(reals) & set(scalars))) + sints = list(sorted(set(ints) & set(scalars))) + sbools = list(sorted(set(bools) & set(scalars))) + + ovreals = list(sorted(set(vreals) & set(all_outputs))) + ovints = list(sorted(set(vints) & set(all_outputs))) + ovbools = list(sorted(set(vbools) & set(all_outputs))) + + isreals = list(sorted(set(sreals) & set(all_inputs))) + isints = list(sorted(set(sints) & set(all_inputs))) + isbools = list(sorted(set(sbools) & set(all_inputs))) + + osreals = list(sorted(set(sreals) & set(all_outputs))) + osints = list(sorted(set(sints) & set(all_outputs))) + osbools = list(sorted(set(sbools) & set(all_outputs))) + + # + # 1) Set up typedefs (or just have these at the top of file so they can be shared?) + # + + # set up basics + + type_list = ["Real", "Int", "bool"] + impl += " // create device views and copy\n" + + # + # 2) Sync to device. Do ALL views, not just inputs + # + + for input_group, typename in zip([vreals, vints, vbools], type_list): + if input_group: + rank_map = get_rank_map(arg_data, input_group) + + for rank, arg_list in rank_map.items(): + impl += get_htd_dth_call(arg_data, rank, arg_list, typename, f2c=f2c) + + # + # 3) Unpack view array + # + + for input_group, typename in zip([vreals, vints, vbools], type_list): + prefix_char = PREFIX_MAP[typename] + if input_group: + rank_map = get_rank_map(arg_data, input_group) + + for rank, arg_list in rank_map.items(): + view_type = get_view_type(typename, rank) + impl += f" {view_type}\n" + for idx, input_item in enumerate(arg_list): + impl += f" {input_item}_d(vec{rank}d{prefix_char}_in[{idx}]){';' if idx == len(arg_list) - 1 else ','}\n" + impl += "\n" + + + # + # 4) Get nk_pack and policy, unpack scalars, and launch kernel + # + if unpacked: + impl += f" const auto policy = ekat::TeamPolicyFactory::get_default_team_policy({obj}{col_dim}, {obj}nlev);\n\n" + else: + impl += f" const Int nk_pack = ekat::npack({obj}nlev);\n" + impl += f" const auto policy = ekat::TeamPolicyFactory::get_default_team_policy({obj}{col_dim}, nk_pack);\n\n" + + if scalars: + if not f2c: + impl += " // unpack data scalars because we do not want the lambda to capture d\n" + for input_group, typename in zip([isreals, isints, isbools], type_list): + if input_group: + for arg in input_group: + if arg not in oscalars and arg != col_dim: + impl += f" const {typename} {arg} = {obj}{arg};\n" + + # We use 0-rank views to handle output scalars + for output_group, typename in zip([osreals, osints, osbools], type_list): + if output_group: + view_type = get_view_type(typename, 0) + hview_type = view_type[0:-2] + "_h" + for arg in output_group: + impl += f' {hview_type} {arg}_h("{arg}_h");\n' + if arg in iscalars: + impl += f' {arg}_h() = {obj}{arg};\n' + impl += f' {view_type} {arg}_d = Kokkos::create_mirror_view_and_copy(DefaultDevice(), {arg}_h);\n' impl += "\n" - # - # 6) Call fn - # - kernel_arg_names = ["team"] - for arg_name in arg_names: - if arg_name in views: - dims = get_data_by_name(arg_data, arg_name, ARG_DIMS) - if len(dims) == 1 and col_dim in dims: - kernel_arg_names.append(f"{arg_name}_d(i)") - else: - kernel_arg_names.append(f"{arg_name}_c") - elif arg_name in oscalars: - kernel_arg_names.append(f"{arg_name}_d()") + impl += " Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) {\n" + impl += " const Int i = team.league_rank();\n\n" + + # + # 5) Get subviews + # + impl += " // Get single-column subviews of all inputs, shouldn't need any i-indexing\n" + impl += " // after this.\n" + + for view_arg in views: + dims = get_data_by_name(arg_data, view_arg, ARG_DIMS) + if col_dim in dims: + if len(dims) == 1: + pass else: - if arg_name != col_dim: - kernel_arg_names.append(arg_name) + impl += f" const auto {view_arg}_c = ekat::subview({view_arg}_d, i);\n" - joinstr = ',\n ' - impl += f" SHF::{sub}(\n {joinstr.join(kernel_arg_names)});\n" - impl += " });\n\n" + impl += "\n" + + # + # 6) Call fn + # + kernel_arg_names = ["team"] + for arg_name in arg_names: + if arg_name in views: + dims = get_data_by_name(arg_data, arg_name, ARG_DIMS) + if len(dims) == 1 and col_dim in dims: + kernel_arg_names.append(f"{arg_name}_d(i)") + else: + kernel_arg_names.append(f"{arg_name}_c") + elif arg_name in oscalars: + kernel_arg_names.append(f"{arg_name}_d()") + else: + if arg_name != col_dim: + kernel_arg_names.append(arg_name) - # - # 7) Sync back to host - # - if oscalars: - impl += " // Get outputs back, start with scalars\n" - for arg in oscalars: - impl += f" Kokkos::deep_copy({arg}_h, {arg}_d);\n" - impl += f" {obj}{arg} = {arg}_h();\n" + joinstr = ',\n ' + impl += f" SHF::{sub}(\n {joinstr.join(kernel_arg_names)});\n" + impl += " });\n\n" - impl += "\n" + # + # 7) Sync back to host + # + if oscalars: + impl += " // Get outputs back, start with scalars\n" + for arg in oscalars: + impl += f" Kokkos::deep_copy({arg}_h, {arg}_d);\n" + impl += f" {obj}{arg} = {arg}_h();\n" - if oviews: - impl += " // Now get arrays\n" - for output_group, typename in zip([ovreals, ovints, ovbools], type_list): - if output_group: - rank_map = get_rank_map(arg_data, output_group) + impl += "\n" - for rank, arg_list in rank_map.items(): - impl += get_htd_dth_call(arg_data, rank, arg_list, typename, is_output=True, f2c=f2c) + if oviews: + impl += " // Now get arrays\n" + for output_group, typename in zip([ovreals, ovints, ovbools], type_list): + if output_group: + rank_map = get_rank_map(arg_data, output_group) - else: - expect(False, "Not yet supported") + for rank, arg_list in rank_map.items(): + impl += get_htd_dth_call(arg_data, rank, arg_list, typename, is_output=True, f2c=f2c) if not f2c: impl += final_code @@ -1621,14 +1626,14 @@ def gen_cxx_c2f_glue_impl(self, phys, sub, force_arg_data=None): transition_code_1 = "d.transition();" transition_code_2 = "d.transition();" data_struct = get_data_struct_name(sub) - init_code = get_physics_data(phys, INIT_CODE) + init_code = get_physics_data(phys, INIT_CODE).replace("(", "_f(") result = \ f"""void {sub}_f({data_struct}& d) {{ {transition_code_1} {init_code} - {sub}_c({arg_data_args}); + {sub}_f({arg_data_args}); {transition_code_2} }} @@ -1676,10 +1681,9 @@ def gen_cxx_c2f_data(self, phys, sub, force_arg_data=None): """ arg_data = force_arg_data if force_arg_data else self._get_arg_data(phys, sub) struct_members = "\n ".join(gen_struct_members(arg_data)) - any_arrays = has_arrays(arg_data) struct_name = get_data_struct_name(sub) - inheritance = " : public PhysicsTestData" if any_arrays else "" - api = "\n " + "\n ".join(gen_struct_api(struct_name, arg_data) if any_arrays else "") + inheritance = " : public PhysicsTestData" + api = "\n " + "\n ".join(gen_struct_api(struct_name, arg_data)) result = \ f"""struct {struct_name}{inheritance} {{ @@ -1777,7 +1781,6 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): """ arg_data = force_arg_data if force_arg_data else self._get_arg_data(phys, sub) data_struct = get_data_struct_name(sub) - has_array = has_arrays(arg_data) gen_random = \ """ @@ -1797,27 +1800,25 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): all_scalar_inputs = all_dims + [scalar_name for scalar_name, _ in input_scalars] scalar_comments = "// " + ", ".join(all_scalar_inputs) - if has_array: - all_data = dict(real_data) - for type_data in [int_data, bool_data]: - for k, v in type_data.items(): - if k in all_data: - all_data[k].extend(v) - else: - all_data[k] = v + all_data = dict(real_data) + for type_data in [int_data, bool_data]: + for k, v in type_data.items(): + if k in all_data: + all_data[k].extend(v) + else: + all_data[k] = v - for _, data in all_data.items(): - for datum in data: - check_arrays += f" REQUIRE(d_baseline.total(d_baseline.{data[0]}) == d_test.total(d_test.{datum}));\n" + for _, data in all_data.items(): + for datum in data: + check_arrays += f" REQUIRE(d_baseline.total(d_baseline.{data[0]}) == d_test.total(d_test.{datum}));\n" - check_arrays += f" for (Int k = 0; k < d_baseline.total(d_baseline.{data[0]}); ++k) {{\n" - for datum in data: - check_arrays += f" REQUIRE(d_baseline.{datum}[k] == d_test.{datum}[k]);\n" + check_arrays += f" for (Int k = 0; k < d_baseline.total(d_baseline.{data[0]}); ++k) {{\n" + for datum in data: + check_arrays += f" REQUIRE(d_baseline.{datum}[k] == d_test.{datum}[k]);\n" - check_arrays += " }\n" + check_arrays += " }\n" - if has_array: - result = \ + result = \ """ void run_bfb() {{ auto engine = Base::get_engine(); @@ -1873,97 +1874,6 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): gen_random=gen_random, check_scalars=check_scalars, check_arrays=check_arrays) - else: - inputs, inouts, outputs = split_by_intent(arg_data) - reals = split_by_type(arg_data)[0] - all_inputs = inputs + inouts - all_outputs = inouts + outputs - - ireals = list(sorted(set(all_inputs) & set(reals))) - oreals = list(sorted(set(all_outputs) & set(reals))) - ooreals = list(sorted(set(outputs) & set(reals))) - - spack_init = "" - if ireals: - spack_init = \ -"""// Init pack inputs - Spack {ireals}; - for (Int s = 0, vs = offset; s < Spack::n; ++s, ++vs) {{ - {ireal_assigns} - }} -""".format(ireals=", ".join(ireals), ireal_assigns="\n ".join(["{0}[s] = test_device(vs).{0};".format(ireal) for ireal in ireals])) - - spack_output_init = "" - if ooreals: - spack_output_init = \ -f"""// Init outputs - Spack {', '.join(['{}(0)'.format(ooreal) for ooreal in ooreals])}; -""" - - scalars = group_data(arg_data)[1] - func_call = f"Functions::{sub}({', '.join([(scalar if scalar in reals else 'test_device(0).{}'.format(scalar)) for scalar, _ in scalars])});" - - spack_output_to_dview = "" - if oreals: - spack_output_to_dview = \ -"""// Copy spacks back into test_device view - for (Int s = 0, vs = offset; s < Spack::n; ++s, ++vs) {{ - {} - }} -""".format("\n ".join(["test_device(vs).{0} = {0}[s];".format(oreal) for oreal in oreals])) - - result = \ -""" void run_bfb() - {{ - auto engine = Base::get_engine(); - - {data_struct} baseline_data[max_pack_size] = {{ - // TODO - }}; - - static constexpr Int num_runs = sizeof(baseline_data) / sizeof({data_struct});{gen_random} - - // Create copies of data for use by test and sync it to device. Needs to happen before read calls so that - // inout data is in original state - view_1d<{data_struct}> test_device("test_device", max_pack_size); - const auto test_host = Kokkos::create_mirror_view(test_device); - std::copy(&baseline_data[0], &baseline_data[0] + max_pack_size, test_host.data()); - Kokkos::deep_copy(test_device, test_host); - - // Get data from fortran - for (auto& d : baseline_data) {{ - {sub}(d); - }} - - // Get data from test. Run {sub} from a kernel and copy results back to host - Kokkos::parallel_for(num_test_itrs, KOKKOS_LAMBDA(const Int& i) {{ - const Int offset = i * Spack::n; - - {spack_init} - {spack_output_init} - - {func_call} - - {spack_output_to_dview} - }}); - - Kokkos::deep_copy(test_host, test_device); - - // Verify BFB results - if (SCREAM_BFB_TESTING) {{ - for (Int i = 0; i < num_runs; ++i) {{ - {data_struct}& d_baseline = baseline_data[i]; - {data_struct}& d_test = test_host[i]; -{check_scalars} }} - }} - }} // run_bfb""".format(data_struct=data_struct, - sub=sub, - gen_random=gen_random, - check_scalars=check_scalars, - spack_init=spack_init, - spack_output_init=spack_output_init, - func_call=func_call, - spack_output_to_dview=spack_output_to_dview) return result diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index e5ad4be439f1..c9fc8ea57eae 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -716,11 +716,45 @@ end module mymod {} PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); + +// TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices +// template +// void transition() +// { +// PhysicsTestData::transition(PUT INT ARRAY SKIPS HERE); +// shift_int_scalar(PUT INT SCALAR HERE); +// } """ actual = gen_struct_api("DataSubName", UT_ARG_DATA) line_by_line_compare(self, expected, "\n".join(actual)) + ########################################################################### + def test_gen_struct_api_scalars(self): + ########################################################################### + expected = \ +"""DataSubName(Real foo1_, Real foo2_, Real bar1_, Real bar2_, Real baz1_, Real baz2_, Int gag1_, Int gag2_, Int gal1_, Int gal2_, Int bal1_, Int bal2_, bool bit1_, bool bit2_, bool gut1_, bool gut2_, bool gat1_, bool gat2_) : + PhysicsTestData({ + }, + { + }), + foo1(foo1_), foo2(foo2_), bar1(bar1_), bar2(bar2_), baz1(baz1_), baz2(baz2_), gag1(gag1_), gag2(gag2_), gal1(gal1_), gal2(gal2_), bal1(bal1_), bal2(bal2_), bit1(bit1_), bit2(bit2_), gut1(gut1_), gut2(gut2_), gat1(gat1_), gat2(gat2_) +{} + +PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal1, gal2, bal1, bal2, bit1, bit2, gut1, gut2, gat1, gat2); + +// TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices +// template +// void transition() +// { +// PhysicsTestData::transition(PUT INT ARRAY SKIPS HERE); +// shift_int_scalar(PUT INT SCALAR HERE); +// } +""" + actual = gen_struct_api("DataSubName", UT_ARG_DATA_ALL_SCALAR) + + line_by_line_compare(self, expected, "\n".join(actual)) + ########################################################################### def test_f90_c2f_bind(self): ########################################################################### @@ -803,8 +837,8 @@ PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); """void fake_sub_f(FakeSubData& d) { d.transition(); - shoc_init(d.nlev, true); - fake_sub_c(d.foo1, d.foo2, d.bar1, d.bar2, d.bak1, d.bak2, d.tracerd1, d.tracerd2, d.gag, d.baz, d.bag, &d.bab1, &d.bab2, d.val, d.vals, d.shcol, d.nlev, d.nlevi, d.ntracers, d.ball1, d.ball2); + shoc_init_f(d.nlev, true); + fake_sub_f(d.foo1, d.foo2, d.bar1, d.bar2, d.bak1, d.bak2, d.tracerd1, d.tracerd2, d.gag, d.baz, d.bag, &d.bab1, &d.bab2, d.val, d.vals, d.shcol, d.nlev, d.nlevi, d.ntracers, d.ball1, d.ball2); d.transition(); } @@ -997,6 +1031,14 @@ PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); {} PTD_STD_DEF(FakeSubData, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); + + // TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices + // template + // void transition() + // { + // PhysicsTestData::transition(PUT INT ARRAY SKIPS HERE); + // shift_int_scalar(PUT INT SCALAR HERE); + // } }; """ @@ -1358,8 +1400,8 @@ WITH: void fake_sub_f(FakeSubData& d) { d.transition(); - shoc_init(d.nlev, true); - fake_sub_c(d.foo1, d.foo2, d.bar1, d.bar2, d.bak1, d.bak2, d.tracerd1, d.tracerd2, d.gag, d.baz, d.bag, &d.bab1, &d.bab2, d.val, d.vals, d.shcol, d.nlev, d.nlevi, d.ntracers, d.ball1, d.ball2); + shoc_init_f(d.nlev, true); + fake_sub_f(d.foo1, d.foo2, d.bar1, d.bar2, d.bak1, d.bak2, d.tracerd1, d.tracerd2, d.gag, d.baz, d.bag, &d.bab1, &d.bab2, d.val, d.vals, d.shcol, d.nlev, d.nlevi, d.ntracers, d.ball1, d.ball2); d.transition(); } @@ -1386,8 +1428,8 @@ void fake_sub_f(FakeSubData& d) void fake_sub_f(FakeSubData& d) { d.transition(); - shoc_init(d.nlev, true); - fake_sub_c(d.foo1, d.foo2, d.bar1, d.bar2, d.bak1, d.bak2, d.tracerd1, d.tracerd2, d.gag, d.baz, d.bag, &d.bab1, &d.bab2, d.val, d.vals, d.shcol, d.nlev, d.nlevi, d.ntracers, d.ball1, d.ball2); + shoc_init_f(d.nlev, true); + fake_sub_f(d.foo1, d.foo2, d.bar1, d.bar2, d.bak1, d.bak2, d.tracerd1, d.tracerd2, d.gag, d.baz, d.bag, &d.bab1, &d.bab2, d.val, d.vals, d.shcol, d.nlev, d.nlevi, d.ntracers, d.ball1, d.ball2); d.transition(); } diff --git a/components/eamxx/src/physics/zm/CMakeLists.txt b/components/eamxx/src/physics/zm/CMakeLists.txt index d9d0721c4768..9ac68063d002 100644 --- a/components/eamxx/src/physics/zm/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/CMakeLists.txt @@ -45,6 +45,7 @@ if (NOT EAMXX_ENABLE_GPU OR Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE OR Kokkos eti/zm_common_init.cpp eti/zm_input_state.cpp eti/zm_output_tend.cpp + eti/zm_ientropy.cpp ) # ZM ETI SRCS endif() diff --git a/components/eamxx/src/physics/zm/eti/zm_ientropy.cpp b/components/eamxx/src/physics/zm/eti/zm_ientropy.cpp new file mode 100644 index 000000000000..a23d124fabfa --- /dev/null +++ b/components/eamxx/src/physics/zm/eti/zm_ientropy.cpp @@ -0,0 +1,14 @@ +#include "impl/zm_ientropy_impl.hpp" + +namespace scream { +namespace zm { + +/* + * Explicit instantiation for doing ientropy on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace zm +} // namespace scream diff --git a/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp new file mode 100644 index 000000000000..b7eafcf6bcf0 --- /dev/null +++ b/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp @@ -0,0 +1,34 @@ +#ifndef ZM_IENTROPY_IMPL_HPP +#define ZM_IENTROPY_IMPL_HPP + +#include "zm_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace zm { + +/* + * Implementation of zm ientropy. Clients should NOT + * #include this file, but include zm_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::ientropy( + // Inputs + const MemberType& team, + const Int& rcall, + const Real& s, + const Real& p, + const Real& qt, + const Real& tfg, + // Outputs + Real& t, + Real& qst) +{ + // TODO +} + +} // namespace zm +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/zm/tests/CMakeLists.txt b/components/eamxx/src/physics/zm/tests/CMakeLists.txt index 5931865d1cc9..bf50afa51b24 100644 --- a/components/eamxx/src/physics/zm/tests/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/tests/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(infra) set(ZM_TESTS_SRCS zm_test_find_mse_max.cpp + zm_ientropy_tests.cpp ) # ZM_TESTS_SRCS # All tests should understand the same baseline args diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index df2740d10013..0487637e7089 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -16,23 +16,24 @@ namespace zm { extern "C" { - void zm_find_mse_max_c( Int pcols, - Int ncol, - Int pver, - Int num_msg, - Int *msemax_top_k, - bool pergro_active, - Real *temperature, - Real *zmid, - Real *sp_humidity, - Int *msemax_klev, - Real *mse_max_val ); - -} // extern "C" : end _c decls +void zm_find_mse_max_f( Int pcols, + Int ncol, + Int pver, + Int num_msg, + Int *msemax_top_k, + bool pergro_active, + Real *temperature, + Real *zmid, + Real *sp_humidity, + Int *msemax_klev, + Real *mse_max_val ); + +void ientropy_bridge_f(Int rcall, Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); +} // extern "C" : end _f decls void zm_find_mse_max(zm_data_find_mse_max& d){ d.transition(); - zm_find_mse_max_c( d.pcols, + zm_find_mse_max_f( d.pcols, d.ncol, d.pver, d.num_msg, @@ -46,7 +47,59 @@ void zm_find_mse_max(zm_data_find_mse_max& d){ d.transition(); } -// end _c impls +void ientropy_f(IentropyData& d) +{ + d.transition(); + zm_common_init(); + ientropy_c(d.rcall, d.s, d.p, d.qt, &d.t, &d.qst, d.tfg); + d.transition(); +} + +void ientropy(IentropyData& d) +{ + zm_common_init(); // Might need more specific init + + // create device views and copy + const auto policy = ekat::TeamPolicyFactory::get_default_team_policy(1, 1); + + // unpack data scalars because we do not want the lambda to capture d + const Real p = d.p; + const Real qt = d.qt; + const Real s = d.s; + const Real tfg = d.tfg; + const Int rcall = d.rcall; + view0dr_h qst_h("qst_h"); + view0dr_d qst_d = Kokkos::create_mirror_view_and_copy(DefaultDevice(), qst_h); + view0dr_h t_h("t_h"); + view0dr_d t_d = Kokkos::create_mirror_view_and_copy(DefaultDevice(), t_h); + + Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { + const Int i = team.league_rank(); + + // Get single-column subviews of all inputs, shouldn't need any i-indexing + // after this. + + SHF::ientropy( + team, + rcall, + s, + p, + qt, + tfg, + t_d(), + qst_d()); + }); + + // Get outputs back, start with scalars + Kokkos::deep_copy(qst_h, qst_d); + d.qst = qst_h(); + Kokkos::deep_copy(t_h, t_d); + d.t = t_h(); + + zm_finalize_cxx(); +} + +// end glue impls } // namespace zm } // namespace scream diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp index c05598717a64..5e098b8a9ac1 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp @@ -58,11 +58,21 @@ struct zm_data_find_mse_max : public PhysicsTestData { }; -// Glue functions to call fortran from from C++ with the Data struct +struct IentropyData { + // Inputs + Int rcall; + Real s, p, qt, tfg; + + // Outputs + Real t, qst; +}; + +// Glue functions for host test data. We can call either fortran or CXX with this data (_f -> fortran) void zm_find_mse_max(zm_data_find_mse_max& d); +void ientropy_f(IentropyData& d); +void ientropy(IentropyData& d); -extern "C" { // _f function decls -} +// End glue function decls } // namespace zm } // namespace scream diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 0e940e0f1349..02b89f13cf0d 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -269,6 +269,19 @@ struct Functions { // inline static ZmCommonInit s_common_init; + KOKKOS_FUNCTION + static void ientropy( + // Inputs + const MemberType& team, + const Int& rcall, + const Real& s, + const Real& p, + const Real& qt, + const Real& tfg, + // Outputs + Real& t, + Real& qst); + }; // struct Functions } // namespace zm @@ -279,5 +292,6 @@ struct Functions { # include "impl/zm_input_state_impl.hpp" # include "impl/zm_output_tend_impl.hpp" # include "impl/zm_common_init.hpp" +# include "impl/zm_ientropy_impl.hpp" #endif // GPU && !KOKKOS_ENABLE_*_RELOCATABLE_DEVICE_CODE #endif // ZM_FUNCTIONS_HPP From 6d93a2a6302bb093b57358d9908cbf95432b5862 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 11:41:22 -0700 Subject: [PATCH 339/398] Fix for output scalars, should not be in constructor arg list --- components/eamxx/scripts/gen-boiler/gen_boiler.py | 8 +++++--- components/eamxx/scripts/gen-boiler/run-gb-tests | 12 ++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 444c86c37b79..501422fd722c 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -1086,10 +1086,12 @@ def gen_struct_api(struct_name, arg_data): Given data, generate code for data struct api """ all_dims, scalars, real_data, int_data, bool_data = group_data(arg_data, filter_scalar_custom_types=True) + input_scalars = group_data(arg_data, filter_scalar_custom_types=True, filter_out_intent="out")[1] result = [] dim_args = [(item, "Int") for item in all_dims if item is not None] - cons_args = dim_args + scalars + cons_args = dim_args + input_scalars + all_scalars = dim_args + scalars result.append("{struct_name}({cons_args}) :".\ format(struct_name=struct_name, cons_args=", ".join(["{} {}_".format(argtype, name) for name, argtype in cons_args]))) @@ -1117,14 +1119,14 @@ def gen_struct_api(struct_name, arg_data): parent_call += "),\n" - parent_call += f" {', '.join(['{0}({0}_)'.format(name) for name, _ in cons_args])}" + parent_call += f" {', '.join(['{}({})'.format(name, name+'_' if name in [n for n,_ in cons_args] else '0') for name, _ in all_scalars])}" result.append(parent_call) result.append("{}") result.append("") result.append("PTD_STD_DEF({}, {}, {});".\ - format(struct_name, len(cons_args), ", ".join([name for name, _ in cons_args]))) + format(struct_name, len(all_scalars), ", ".join([name for name, _ in all_scalars]))) result.append("") result.append("// TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices") diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index c9fc8ea57eae..5872093bc2e1 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -687,7 +687,7 @@ end module mymod def test_gen_struct_api(self): ########################################################################### expected = \ -"""DataSubName(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, Int bab2_, bool val_) : +"""DataSubName(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, bool val_) : PhysicsTestData({ {shcol_}, {shcol_, nlev_}, @@ -712,7 +712,7 @@ end module mymod { {&vals} }), - shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(bab2_), val(val_) + shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(0), val(val_) {} PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); @@ -733,12 +733,12 @@ PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); def test_gen_struct_api_scalars(self): ########################################################################### expected = \ -"""DataSubName(Real foo1_, Real foo2_, Real bar1_, Real bar2_, Real baz1_, Real baz2_, Int gag1_, Int gag2_, Int gal1_, Int gal2_, Int bal1_, Int bal2_, bool bit1_, bool bit2_, bool gut1_, bool gut2_, bool gat1_, bool gat2_) : +"""DataSubName(Real foo1_, Real foo2_, Real bar1_, Real bar2_, Int gag1_, Int gag2_, Int gal1_, Int gal2_, bool bit1_, bool bit2_, bool gut1_, bool gut2_) : PhysicsTestData({ }, { }), - foo1(foo1_), foo2(foo2_), bar1(bar1_), bar2(bar2_), baz1(baz1_), baz2(baz2_), gag1(gag1_), gag2(gag2_), gal1(gal1_), gal2(gal2_), bal1(bal1_), bal2(bal2_), bit1(bit1_), bit2(bit2_), gut1(gut1_), gut2(gut2_), gat1(gat1_), gat2(gat2_) + foo1(foo1_), foo2(foo2_), bar1(bar1_), bar2(bar2_), baz1(0), baz2(0), gag1(gag1_), gag2(gag2_), gal1(gal1_), gal2(gal2_), bal1(0), bal2(0), bit1(bit1_), bit2(bit2_), gut1(gut1_), gut2(gut2_), gat1(0), gat2(0) {} PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal1, gal2, bal1, bal2, bit1, bit2, gut1, gut2, gat1, gat2); @@ -1002,7 +1002,7 @@ PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal Int bab2; Int *ball1, *ball2; - FakeSubData(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, Int bab2_, bool val_) : + FakeSubData(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, bool val_) : PhysicsTestData({ {shcol_}, {shcol_, nlev_}, @@ -1027,7 +1027,7 @@ PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal { {&vals} }), - shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(bab2_), val(val_) + shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(0), val(val_) {} PTD_STD_DEF(FakeSubData, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); From 8a64d5e2585eff71060729fe90d689b2f93aba48 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 11:47:17 -0700 Subject: [PATCH 340/398] Revert "Fix for output scalars, should not be in constructor arg list" This reverts commit 6d93a2a6302bb093b57358d9908cbf95432b5862. --- components/eamxx/scripts/gen-boiler/gen_boiler.py | 8 +++----- components/eamxx/scripts/gen-boiler/run-gb-tests | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 501422fd722c..444c86c37b79 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -1086,12 +1086,10 @@ def gen_struct_api(struct_name, arg_data): Given data, generate code for data struct api """ all_dims, scalars, real_data, int_data, bool_data = group_data(arg_data, filter_scalar_custom_types=True) - input_scalars = group_data(arg_data, filter_scalar_custom_types=True, filter_out_intent="out")[1] result = [] dim_args = [(item, "Int") for item in all_dims if item is not None] - cons_args = dim_args + input_scalars - all_scalars = dim_args + scalars + cons_args = dim_args + scalars result.append("{struct_name}({cons_args}) :".\ format(struct_name=struct_name, cons_args=", ".join(["{} {}_".format(argtype, name) for name, argtype in cons_args]))) @@ -1119,14 +1117,14 @@ def gen_struct_api(struct_name, arg_data): parent_call += "),\n" - parent_call += f" {', '.join(['{}({})'.format(name, name+'_' if name in [n for n,_ in cons_args] else '0') for name, _ in all_scalars])}" + parent_call += f" {', '.join(['{0}({0}_)'.format(name) for name, _ in cons_args])}" result.append(parent_call) result.append("{}") result.append("") result.append("PTD_STD_DEF({}, {}, {});".\ - format(struct_name, len(all_scalars), ", ".join([name for name, _ in all_scalars]))) + format(struct_name, len(cons_args), ", ".join([name for name, _ in cons_args]))) result.append("") result.append("// TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices") diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index 5872093bc2e1..c9fc8ea57eae 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -687,7 +687,7 @@ end module mymod def test_gen_struct_api(self): ########################################################################### expected = \ -"""DataSubName(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, bool val_) : +"""DataSubName(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, Int bab2_, bool val_) : PhysicsTestData({ {shcol_}, {shcol_, nlev_}, @@ -712,7 +712,7 @@ end module mymod { {&vals} }), - shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(0), val(val_) + shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(bab2_), val(val_) {} PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); @@ -733,12 +733,12 @@ PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); def test_gen_struct_api_scalars(self): ########################################################################### expected = \ -"""DataSubName(Real foo1_, Real foo2_, Real bar1_, Real bar2_, Int gag1_, Int gag2_, Int gal1_, Int gal2_, bool bit1_, bool bit2_, bool gut1_, bool gut2_) : +"""DataSubName(Real foo1_, Real foo2_, Real bar1_, Real bar2_, Real baz1_, Real baz2_, Int gag1_, Int gag2_, Int gal1_, Int gal2_, Int bal1_, Int bal2_, bool bit1_, bool bit2_, bool gut1_, bool gut2_, bool gat1_, bool gat2_) : PhysicsTestData({ }, { }), - foo1(foo1_), foo2(foo2_), bar1(bar1_), bar2(bar2_), baz1(0), baz2(0), gag1(gag1_), gag2(gag2_), gal1(gal1_), gal2(gal2_), bal1(0), bal2(0), bit1(bit1_), bit2(bit2_), gut1(gut1_), gut2(gut2_), gat1(0), gat2(0) + foo1(foo1_), foo2(foo2_), bar1(bar1_), bar2(bar2_), baz1(baz1_), baz2(baz2_), gag1(gag1_), gag2(gag2_), gal1(gal1_), gal2(gal2_), bal1(bal1_), bal2(bal2_), bit1(bit1_), bit2(bit2_), gut1(gut1_), gut2(gut2_), gat1(gat1_), gat2(gat2_) {} PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal1, gal2, bal1, bal2, bit1, bit2, gut1, gut2, gat1, gat2); @@ -1002,7 +1002,7 @@ PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal Int bab2; Int *ball1, *ball2; - FakeSubData(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, bool val_) : + FakeSubData(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, Int bab2_, bool val_) : PhysicsTestData({ {shcol_}, {shcol_, nlev_}, @@ -1027,7 +1027,7 @@ PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal { {&vals} }), - shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(0), val(val_) + shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(bab2_), val(val_) {} PTD_STD_DEF(FakeSubData, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); From eb8725ae214265d9dfd7b7ac96cc9d4bb9110012 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 12:00:14 -0700 Subject: [PATCH 341/398] Proper fix for output scalars --- components/eamxx/scripts/gen-boiler/gen_boiler.py | 8 +++++--- components/eamxx/scripts/gen-boiler/run-gb-tests | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 444c86c37b79..1f4f69464b48 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -1792,13 +1792,15 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): }""" _, scalars, real_data, int_data, bool_data = group_data(arg_data, filter_out_intent="in") + out_scalar_names = [scalar_name for scalar_name, _ in scalars] check_scalars, check_arrays, scalar_comments = "", "", "" for scalar in scalars: check_scalars += f" REQUIRE(d_baseline.{scalar[0]} == d_test.{scalar[0]});\n" - all_dims, input_scalars, _, _, _ = group_data(arg_data, filter_out_intent="out") - all_scalar_inputs = all_dims + [scalar_name for scalar_name, _ in input_scalars] - scalar_comments = "// " + ", ".join(all_scalar_inputs) + # Due to the mechanics of PTD, the constructor must take all scalars, not just input scalars + all_dims, all_scalars = group_data(arg_data)[0:2] + all_scalar_names = all_dims + [scalar_name for scalar_name, _ in all_scalars] + scalar_comments = "// " + ", ".join([('{} (output, set to zero)'.format(name) if name in out_scalar_names else name) for name in all_scalar_names]) all_data = dict(real_data) for type_data in [int_data, bool_data]: diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index c9fc8ea57eae..fdf0628a8a10 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -1275,7 +1275,7 @@ void Functions::fake_sub( // Set up inputs FakeSubData baseline_data[] = { // TODO - // shcol, nlev, nlevi, ntracers, gag, bab1, val + // shcol, nlev, nlevi, ntracers, gag, bab1 (output, set to zero), bab2 (output, set to zero), val FakeSubData(), }; From db6a532d636b2a251527e5f04ac4fa8d292cec56 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 14:22:00 -0700 Subject: [PATCH 342/398] Remove concept of treating dim scalars differently --- .../eamxx/scripts/gen-boiler/gen_boiler.py | 66 +++++++++++++------ .../eamxx/scripts/gen-boiler/run-gb-tests | 40 ++++++----- 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 1f4f69464b48..8c4ec18fbdfe 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -872,12 +872,10 @@ def gen_cxx_data_args(arg_data): """ Based on data, generate unpacking of Data struct args """ - all_dims = group_data(arg_data)[0] args_needs_ptr = [item[ARG_DIMS] is None and item[ARG_INTENT] != "in" for item in arg_data] arg_names = [item[ARG_NAME] for item in arg_data] - arg_dim_call = [item[ARG_NAME] in all_dims for item in arg_data] args = [f"{'&' if need_ptr else ''}d.{arg_name}" - for arg_name, need_ptr, dim_call in zip(arg_names, args_needs_ptr, arg_dim_call)] + for arg_name, need_ptr in zip(arg_names, args_needs_ptr)] return args ############################################################################### @@ -909,6 +907,31 @@ def has_arrays(arg_data): return False +############################################################################### +def get_scalar_members(arg_data): +############################################################################### + """ + Gen cxx code for data struct members in an order that matches gen_struct_members + """ + metadata = {} # intent -> type -> names + for name, argtype, intent, dims in arg_data: + if dims is None: + metadata.setdefault(intent, {}).setdefault(argtype, []).append(name) + + intent_order = ("in", "inout", "out") + type_order = ("integer", "real", "logical", "other") + + result = [] + for intent in intent_order: + if intent in metadata: + type_map = metadata[intent] + for curr_type in type_order: + for type_name, names in type_map.items(): + if (type_name == curr_type or (curr_type == "other" and type_name not in C_TYPE_MAP.keys())): + result.extend([(name, get_cxx_scalar_type(type_name)) for name in names]) + + return result + ############################################################################### def gen_struct_members(arg_data): ############################################################################### @@ -920,16 +943,22 @@ def gen_struct_members(arg_data): metadata.setdefault(intent, {}).setdefault((argtype, dims is not None), []).append(name) intent_order = ( ("in", "Inputs"), ("inout", "Inputs/Outputs"), ("out", "Outputs") ) + type_order = ("integer", "real", "logical", "other") + is_ptr_order = (False, True) + result = [] for intent, comment in intent_order: if intent in metadata: result.append(f"// {comment}") type_map = metadata[intent] - for type_info, names in type_map.items(): - type_name, is_ptr = type_info - decl_str = get_cxx_scalar_type(type_name) - decl_str += f" {', '.join(['{}{}'.format('*' if is_ptr else '', name) for name in names])};" - result.append(decl_str) + for curr_type in type_order: + for curr_is_ptr in is_ptr_order: + for type_info, names in type_map.items(): + type_name, is_ptr = type_info + if (type_name == curr_type or (curr_type == "other" and type_name not in C_TYPE_MAP.keys())) and is_ptr == curr_is_ptr: + decl_str = get_cxx_scalar_type(type_name) + decl_str += f" {', '.join(['{}{}'.format('*' if is_ptr else '', name) for name in names])};" + result.append(decl_str) result.append("") @@ -964,7 +993,7 @@ def extract_dim_scalars(dim): def group_data(arg_data, filter_out_intent=None, filter_scalar_custom_types=False): ############################################################################### """ - Given data, return ([all-dims], [scalars], {dims->[real_data]}, {dims->[int_data]}, {dims->[bool_data]}) + Given data, return ([scalars], {dims->[real_data]}, {dims->[int_data]}, {dims->[bool_data]}) """ scalars = [] @@ -986,9 +1015,8 @@ def group_data(arg_data, filter_out_intent=None, filter_scalar_custom_types=Fals if filter_out_intent is None or intent != filter_out_intent: if dims is None: if not (is_custom_type(argtype) and filter_scalar_custom_types): - if name not in all_dims: - scalars.append( (name, get_cxx_scalar_type(argtype))) - else: + scalars.append( (name, get_cxx_scalar_type(argtype))) + if name in all_dims: expect(argtype == "integer", f"Expected dimension {name} to be of type integer") expect(intent == "in", f"Expected dimension {name} to be intent in") @@ -1001,7 +1029,7 @@ def group_data(arg_data, filter_out_intent=None, filter_scalar_custom_types=Fals elif argtype == "logical": bool_data.setdefault(dims, []).append(name) - return all_dims, scalars, real_data, int_data, bool_data + return scalars, real_data, int_data, bool_data ############################################################################### def get_list_of_lists(items, indent): @@ -1085,11 +1113,11 @@ def gen_struct_api(struct_name, arg_data): """ Given data, generate code for data struct api """ - all_dims, scalars, real_data, int_data, bool_data = group_data(arg_data, filter_scalar_custom_types=True) + _, real_data, int_data, bool_data = group_data(arg_data, filter_scalar_custom_types=True) + cons_args = get_scalar_members(arg_data) + # Due to the mechanics of PTD, the constructor must take all scalars, not just input scalars result = [] - dim_args = [(item, "Int") for item in all_dims if item is not None] - cons_args = dim_args + scalars result.append("{struct_name}({cons_args}) :".\ format(struct_name=struct_name, cons_args=", ".join(["{} {}_".format(argtype, name) for name, argtype in cons_args]))) @@ -1791,15 +1819,15 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): d.randomize(engine); }""" - _, scalars, real_data, int_data, bool_data = group_data(arg_data, filter_out_intent="in") + scalars, real_data, int_data, bool_data = group_data(arg_data, filter_out_intent="in") out_scalar_names = [scalar_name for scalar_name, _ in scalars] check_scalars, check_arrays, scalar_comments = "", "", "" for scalar in scalars: check_scalars += f" REQUIRE(d_baseline.{scalar[0]} == d_test.{scalar[0]});\n" # Due to the mechanics of PTD, the constructor must take all scalars, not just input scalars - all_dims, all_scalars = group_data(arg_data)[0:2] - all_scalar_names = all_dims + [scalar_name for scalar_name, _ in all_scalars] + all_scalars = get_scalar_members(arg_data) + all_scalar_names = [scalar_name for scalar_name, _ in all_scalars] scalar_comments = "// " + ", ".join([('{} (output, set to zero)'.format(name) if name in out_scalar_names else name) for name in all_scalar_names]) all_data = dict(real_data) diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index fdf0628a8a10..15af507b3c60 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -292,16 +292,16 @@ class TestGenBoilerBasics(unittest.TestCase): # gen_struct_members self.assertEqual(gen_struct_members(UT_ARG_DATA), [ "// Inputs", - "Real *foo1, *foo2, *bar1, *bar2, *bak1, *bak2, *tracerd1, *tracerd2;", - "Real gag;", + "Int shcol, nlev, nlevi, ntracers;", "Int *bag;", + "Real gag;", + "Real *foo1, *foo2, *bar1, *bar2, *bak1, *bak2, *tracerd1, *tracerd2;", "bool val;", "bool *vals;", - "Int shcol, nlev, nlevi, ntracers;", "", "// Inputs/Outputs", - "Real *baz;", "Int bab1;", + "Real *baz;", "", "// Outputs", "Int bab2;", @@ -311,8 +311,7 @@ class TestGenBoilerBasics(unittest.TestCase): # group_data self.assertEqual(group_data(UT_ARG_DATA), ( - ['shcol', 'nlev', 'nlevi', 'ntracers'], - [('gag', 'Real'), ('bab1', 'Int'), ('bab2', 'Int'), ('val', 'bool')], + [('gag', 'Real'), ('bab1', 'Int'), ('bab2', 'Int'), ('val', 'bool'), ('shcol', 'Int'), ('nlev', 'Int'), ('nlevi', 'Int'), ('ntracers', 'Int')], { ('shcol',): ['foo1', 'foo2', 'baz'], ('shcol', 'nlev'): ['bar1', 'bar2'], @@ -326,7 +325,6 @@ class TestGenBoilerBasics(unittest.TestCase): }, {('shcol',): ['vals']})) self.assertEqual(group_data(UT_ARG_DATA_ALL_SCALAR), ( - [], [('foo1', 'Real'), ('foo2', 'Real'), ('bar1', 'Real'), ('bar2', 'Real'), ('baz1', 'Real'), ('baz2', 'Real'), ('gag1', 'Int'), ('gag2', 'Int'), ('gal1', 'Int'), ('gal2', 'Int'), ('bal1', 'Int'), ('bal2', 'Int'), ('bit1', 'bool'), ('bit2', 'bool'), ('gut1', 'bool'), ('gut2', 'bool'), ('gat1', 'bool'), ('gat2', 'bool')], {}, {}, @@ -687,7 +685,7 @@ end module mymod def test_gen_struct_api(self): ########################################################################### expected = \ -"""DataSubName(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, Int bab2_, bool val_) : +"""DataSubName(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, bool val_, Int bab1_, Int bab2_) : PhysicsTestData({ {shcol_}, {shcol_, nlev_}, @@ -712,10 +710,10 @@ end module mymod { {&vals} }), - shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(bab2_), val(val_) + shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), val(val_), bab1(bab1_), bab2(bab2_) {} -PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); +PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, val, bab1, bab2); // TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices // template @@ -733,15 +731,15 @@ PTD_STD_DEF(DataSubName, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); def test_gen_struct_api_scalars(self): ########################################################################### expected = \ -"""DataSubName(Real foo1_, Real foo2_, Real bar1_, Real bar2_, Real baz1_, Real baz2_, Int gag1_, Int gag2_, Int gal1_, Int gal2_, Int bal1_, Int bal2_, bool bit1_, bool bit2_, bool gut1_, bool gut2_, bool gat1_, bool gat2_) : +"""DataSubName(Int gag1_, Int gag2_, Real foo1_, Real foo2_, bool bit1_, bool bit2_, Int gal1_, Int gal2_, Real bar1_, Real bar2_, bool gut1_, bool gut2_, Int bal1_, Int bal2_, Real baz1_, Real baz2_, bool gat1_, bool gat2_) : PhysicsTestData({ }, { }), - foo1(foo1_), foo2(foo2_), bar1(bar1_), bar2(bar2_), baz1(baz1_), baz2(baz2_), gag1(gag1_), gag2(gag2_), gal1(gal1_), gal2(gal2_), bal1(bal1_), bal2(bal2_), bit1(bit1_), bit2(bit2_), gut1(gut1_), gut2(gut2_), gat1(gat1_), gat2(gat2_) + gag1(gag1_), gag2(gag2_), foo1(foo1_), foo2(foo2_), bit1(bit1_), bit2(bit2_), gal1(gal1_), gal2(gal2_), bar1(bar1_), bar2(bar2_), gut1(gut1_), gut2(gut2_), bal1(bal1_), bal2(bal2_), baz1(baz1_), baz2(baz2_), gat1(gat1_), gat2(gat2_) {} -PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal1, gal2, bal1, bal2, bit1, bit2, gut1, gut2, gat1, gat2); +PTD_STD_DEF(DataSubName, 18, gag1, gag2, foo1, foo2, bit1, bit2, gal1, gal2, bar1, bar2, gut1, gut2, bal1, bal2, baz1, baz2, gat1, gat2); // TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices // template @@ -987,22 +985,22 @@ PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal expected = \ """struct FakeSubData : public PhysicsTestData { // Inputs - Real *foo1, *foo2, *bar1, *bar2, *bak1, *bak2, *tracerd1, *tracerd2; - Real gag; + Int shcol, nlev, nlevi, ntracers; Int *bag; + Real gag; + Real *foo1, *foo2, *bar1, *bar2, *bak1, *bak2, *tracerd1, *tracerd2; bool val; bool *vals; - Int shcol, nlev, nlevi, ntracers; // Inputs/Outputs - Real *baz; Int bab1; + Real *baz; // Outputs Int bab2; Int *ball1, *ball2; - FakeSubData(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, Int bab1_, Int bab2_, bool val_) : + FakeSubData(Int shcol_, Int nlev_, Int nlevi_, Int ntracers_, Real gag_, bool val_, Int bab1_, Int bab2_) : PhysicsTestData({ {shcol_}, {shcol_, nlev_}, @@ -1027,10 +1025,10 @@ PTD_STD_DEF(DataSubName, 18, foo1, foo2, bar1, bar2, baz1, baz2, gag1, gag2, gal { {&vals} }), - shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), bab1(bab1_), bab2(bab2_), val(val_) + shcol(shcol_), nlev(nlev_), nlevi(nlevi_), ntracers(ntracers_), gag(gag_), val(val_), bab1(bab1_), bab2(bab2_) {} - PTD_STD_DEF(FakeSubData, 8, shcol, nlev, nlevi, ntracers, gag, bab1, bab2, val); + PTD_STD_DEF(FakeSubData, 8, shcol, nlev, nlevi, ntracers, gag, val, bab1, bab2); // TODO - You may need to transition int scalars or tell parent to skip transitioning int arrays that do not represent indices // template @@ -1275,7 +1273,7 @@ void Functions::fake_sub( // Set up inputs FakeSubData baseline_data[] = { // TODO - // shcol, nlev, nlevi, ntracers, gag, bab1 (output, set to zero), bab2 (output, set to zero), val + // shcol, nlev, nlevi, ntracers, gag, val, bab1 (output, set to zero), bab2 (output, set to zero) FakeSubData(), }; From 3ced1c9f94f44bdfa884f2213587be71e8a73c17 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 14:53:50 -0700 Subject: [PATCH 343/398] Stub for ientropy --- .../eam/src/physics/cam/zm/zm_conv_util.F90 | 8 +- .../physics/zm/tests/infra/zm_c2f_bridge.f90 | 9 +- .../physics/zm/tests/infra/zm_test_data.cpp | 67 ++++++++----- .../physics/zm/tests/infra/zm_test_data.hpp | 9 +- .../physics/zm/tests/zm_ientropy_tests.cpp | 94 +++++++++++++++++++ .../eamxx/src/physics/zm/zm_functions.hpp | 8 ++ 6 files changed, 165 insertions(+), 30 deletions(-) create mode 100644 components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp diff --git a/components/eam/src/physics/cam/zm/zm_conv_util.F90 b/components/eam/src/physics/cam/zm/zm_conv_util.F90 index ee0546ab7444..4c20b7f80643 100644 --- a/components/eam/src/physics/cam/zm/zm_conv_util.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv_util.F90 @@ -22,7 +22,7 @@ module zm_conv_util real(r8) function entropy(TK, p, qtot, zm_const) !---------------------------------------------------------------------------- ! Purpose: function to calculate entropy following: - ! + ! ! Raymond, D. J., and A. M. Blyth, 1992: Extension of the Stochastic Mixing ! Model to Cumulonimbus Clouds. J. Atmos. Sci., 49, 1968–1983 !---------------------------------------------------------------------------- @@ -63,7 +63,7 @@ subroutine ientropy(rcall, s, p, qt, T, qst, Tfg, zm_const) !---------------------------------------------------------------------------- ! Purpose: invert the entropy equation to return temperature and saturated ! vapor mixing ratio following Richard Brent's method:: - ! + ! ! Brent, R. P. Ch. 3-4 in Algorithms for Minimization Without Derivatives. ! Englewood Cliffs, NJ: Prentice-Hall, 1973. !---------------------------------------------------------------------------- @@ -101,7 +101,7 @@ subroutine ientropy(rcall, s, p, qt, T, qst, Tfg, zm_const) c = b fc = fb !---------------------------------------------------------------------------- - ! + ! converge: do i=0, LOOPMAX if ((fb > 0.0_r8 .and. fc > 0.0_r8) .or. & @@ -123,7 +123,7 @@ subroutine ientropy(rcall, s, p, qt, T, qst, Tfg, zm_const) tolerance = 2.0_r8*tol_eps*abs(b) + 0.5_r8*tol_coeff xm = 0.5_r8*(c-b) - + converged = (abs(xm) <= tolerance .or. fb == 0.0_r8) if (converged) exit converge diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 index 755085031c3f..d149eb7cf1a2 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 +++ b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 @@ -13,7 +13,7 @@ module zm_c2f_bridge contains !=================================================================================================== -subroutine zm_find_mse_max_c( pcols, ncol, pver, num_msg, msemax_top_k, pergro_active, temperature, zmid, sp_humidity, msemax_klev, mse_max_val ) bind(C) +subroutine zm_find_mse_max_f( pcols, ncol, pver, num_msg, msemax_top_k, pergro_active, temperature, zmid, sp_humidity, msemax_klev, mse_max_val ) bind(C) use zm_conv_cape, only: find_mse_max use zm_conv_types, only: zm_const_t, zm_param_t use zm_conv_types, only: zm_param_set_for_testing, zm_const_set_for_testing @@ -42,18 +42,19 @@ subroutine zm_find_mse_max_c( pcols, ncol, pver, num_msg, msemax_top_k, pergro_a pergro_active_f = pergro_active call find_mse_max( pcols, ncol, pver, num_msg, msemax_top_k, pergro_active_f, temperature, zmid, sp_humidity, zm_const, zm_param, msemax_klev, mse_max_val ) !----------------------------------------------------------------------------- -end subroutine zm_find_mse_max_c +end subroutine zm_find_mse_max_f !=================================================================================================== subroutine ientropy_bridge_f(rcall, s, p, qt, t, qst, tfg) bind(C) - use zm, only : ientropy + use zm_conv_util, only : ientropy + use zm_conv_types, only: zm_const_t, zm_const_set_for_testing integer(kind=c_int) , value, intent(in) :: rcall real(kind=c_real) , value, intent(in) :: s, p, qt, tfg real(kind=c_real) , intent(out) :: t, qst - type(c_ptr) :: zm_const + type(zm_const_t) :: zm_const call zm_const_set_for_testing(zm_const) call ientropy(rcall, s, p, qt, t, qst, tfg, zm_const) diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 0487637e7089..754cfb879011 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -1,4 +1,5 @@ #include "zm_test_data.hpp" +#include "zm_functions.hpp" #include @@ -14,23 +15,49 @@ using scream::Int; namespace scream { namespace zm { +using ZMF = Functions; +using ZMC = typename ZMF::ZMC; + +using ExeSpace = typename ZMF::KT::ExeSpace; +using MemberType = typename ZMF::KT::MemberType; + +using view0dr_d = ZMF::view_0d; +using view1di_d = ZMF::view_1d; +using view1dr_d = ZMF::view_1d; +using view2dr_d = ZMF::view_2d; +using view3dr_d = ZMF::view_3d; + +using WSM = typename ZMF::WorkspaceManager; + extern "C" { -void zm_find_mse_max_f( Int pcols, - Int ncol, - Int pver, - Int num_msg, - Int *msemax_top_k, - bool pergro_active, - Real *temperature, - Real *zmid, - Real *sp_humidity, - Int *msemax_klev, - Real *mse_max_val ); +void zm_find_mse_max_f(Int pcols, Int ncol, Int pver, Int num_msg, Int *msemax_top_k, bool pergro_active, Real *temperature, Real *zmid, Real *sp_humidity, Int *msemax_klev, Real *mse_max_val); void ientropy_bridge_f(Int rcall, Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); + } // extern "C" : end _f decls +// Inits and finalizes are not intended to be called outside this comp unit +namespace { + +void zm_common_init_f() +{ + // Anything to do here? +} + +// Wrapper around gw_init for cxx +void zm_common_init() +{ + ZMF::zm_common_init(); +} + +void zm_finalize_cxx() +{ + ZMF::zm_finalize(); +} + +} + void zm_find_mse_max(zm_data_find_mse_max& d){ d.transition(); zm_find_mse_max_f( d.pcols, @@ -50,14 +77,14 @@ void zm_find_mse_max(zm_data_find_mse_max& d){ void ientropy_f(IentropyData& d) { d.transition(); - zm_common_init(); - ientropy_c(d.rcall, d.s, d.p, d.qt, &d.t, &d.qst, d.tfg); + zm_common_init_f(); + ientropy_bridge_f(d.rcall, d.s, d.p, d.qt, &d.t, &d.qst, d.tfg); d.transition(); } void ientropy(IentropyData& d) { - zm_common_init(); // Might need more specific init + zm_common_init(); // create device views and copy const auto policy = ekat::TeamPolicyFactory::get_default_team_policy(1, 1); @@ -68,18 +95,16 @@ void ientropy(IentropyData& d) const Real s = d.s; const Real tfg = d.tfg; const Int rcall = d.rcall; - view0dr_h qst_h("qst_h"); - view0dr_d qst_d = Kokkos::create_mirror_view_and_copy(DefaultDevice(), qst_h); - view0dr_h t_h("t_h"); - view0dr_d t_d = Kokkos::create_mirror_view_and_copy(DefaultDevice(), t_h); + view0dr_d qst_d("qst_d"); + view0dr_d t_d("t_d"); + auto qst_h = Kokkos::create_mirror_view(qst_d); + auto t_h = Kokkos::create_mirror_view(t_d); Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { - const Int i = team.league_rank(); - // Get single-column subviews of all inputs, shouldn't need any i-indexing // after this. - SHF::ientropy( + ZMF::ientropy( team, rcall, s, diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp index 5e098b8a9ac1..727fc6d9df28 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp @@ -58,13 +58,20 @@ struct zm_data_find_mse_max : public PhysicsTestData { }; -struct IentropyData { +struct IentropyData : public PhysicsTestData { // Inputs Int rcall; Real s, p, qt, tfg; // Outputs Real t, qst; + + IentropyData(Int rcall_, Real s_, Real p_, Real qt_, Real tfg_, Real t_, Real qst_) : + PhysicsTestData({}, {}), + rcall(rcall_), s(s_), p(p_), qt(qt_), tfg(tfg_), t(t_), qst(qst_) + {} + + PTD_STD_DEF(IentropyData, 7, rcall, s, p, qt, tfg, t, qst); }; // Glue functions for host test data. We can call either fortran or CXX with this data (_f -> fortran) diff --git a/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp new file mode 100644 index 000000000000..9670f0f78061 --- /dev/null +++ b/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp @@ -0,0 +1,94 @@ +#include "catch2/catch.hpp" + +#include "share/core/eamxx_types.hpp" +#include "physics/zm/zm_functions.hpp" +#include "physics/zm/tests/infra/zm_test_data.hpp" + +#include "zm_unit_tests_common.hpp" + +#include +#include + +namespace scream { +namespace zm { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestIentropy : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up inputs + IentropyData baseline_data[] = { + // TODO + // rcall, s, p, qt, tfg, t (output, set to zero), qst (output, set to zero) + IentropyData(0 , 1, 2, 3 , 4 , 0 , 0), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(IentropyData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + IentropyData test_data[] = { + // TODO + IentropyData(baseline_data[0]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_ifile); + } + } + + // Get data from test + for (auto& d : test_data) { + if (this->m_baseline_action == GENERATE) { + ientropy_f(d); + } + else { + ientropy(d); + } + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + IentropyData& d_baseline = baseline_data[i]; + IentropyData& d_test = test_data[i]; + REQUIRE(d_baseline.t == d_test.t); + REQUIRE(d_baseline.qst == d_test.qst); + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_ofile); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace zm +} // namespace scream + +namespace { + +TEST_CASE("ientropy_bfb", "[zm]") +{ + using TestStruct = scream::zm::unit_test::UnitWrap::UnitTest::TestIentropy; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 02b89f13cf0d..05bfb2d8f28e 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -36,6 +36,7 @@ struct Functions { using KT = ekat::KokkosTypes; + template using view_0d = typename KT::template view; template using view_1d = typename KT::template view_1d; template using view_2d = typename KT::template view_2d; template using view_2dl = typename KT::template lview; @@ -48,6 +49,11 @@ struct Functions { template using view_2dh = typename view_2dl::HostMirror; template using view_1dh = typename view_1d::HostMirror; + using MemberType = typename KT::MemberType; + + using WorkspaceManager = typename ekat::WorkspaceManager; + using Workspace = typename WorkspaceManager::Workspace; + // ----------------------------------------------------------------------------------------------- // Structs @@ -262,6 +268,8 @@ struct Functions { // static void zm_common_init(); + static void zm_finalize() {} + // static Int zm_main() // From e13f1cb3a4203f3d18b6b3d38575e38036fa0cf4 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 15 Jan 2026 15:06:58 -0700 Subject: [PATCH 344/398] Stubs for entropy --- .../eamxx/src/physics/zm/CMakeLists.txt | 1 + .../eamxx/src/physics/zm/eti/zm_entropy.cpp | 14 +++ .../src/physics/zm/impl/zm_entropy_impl.hpp | 31 +++++++ .../eamxx/src/physics/zm/tests/CMakeLists.txt | 1 + .../physics/zm/tests/infra/zm_c2f_bridge.f90 | 34 +++++-- .../physics/zm/tests/infra/zm_test_data.cpp | 43 +++++++++ .../physics/zm/tests/infra/zm_test_data.hpp | 18 +++- .../zm/tests/infra/zm_unit_tests_common.hpp | 1 + .../src/physics/zm/tests/zm_entropy_tests.cpp | 92 +++++++++++++++++++ .../eamxx/src/physics/zm/zm_functions.hpp | 9 ++ 10 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 components/eamxx/src/physics/zm/eti/zm_entropy.cpp create mode 100644 components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp create mode 100644 components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp diff --git a/components/eamxx/src/physics/zm/CMakeLists.txt b/components/eamxx/src/physics/zm/CMakeLists.txt index 9ac68063d002..7eb98239b1c7 100644 --- a/components/eamxx/src/physics/zm/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/CMakeLists.txt @@ -46,6 +46,7 @@ if (NOT EAMXX_ENABLE_GPU OR Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE OR Kokkos eti/zm_input_state.cpp eti/zm_output_tend.cpp eti/zm_ientropy.cpp + eti/zm_entropy.cpp ) # ZM ETI SRCS endif() diff --git a/components/eamxx/src/physics/zm/eti/zm_entropy.cpp b/components/eamxx/src/physics/zm/eti/zm_entropy.cpp new file mode 100644 index 000000000000..0cd5423ca504 --- /dev/null +++ b/components/eamxx/src/physics/zm/eti/zm_entropy.cpp @@ -0,0 +1,14 @@ +#include "impl/zm_entropy_impl.hpp" + +namespace scream { +namespace zm { + +/* + * Explicit instantiation for doing entropy on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace zm +} // namespace scream diff --git a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp new file mode 100644 index 000000000000..e1b0de68556f --- /dev/null +++ b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp @@ -0,0 +1,31 @@ +#ifndef ZM_ENTROPY_IMPL_HPP +#define ZM_ENTROPY_IMPL_HPP + +#include "zm_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace zm { + +/* + * Implementation of zm entropy. Clients should NOT + * #include this file, but include zm_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +Real Functions::entropy( + // Inputs + const MemberType& team, + const Real& tk, + const Real& p, + const Real& qtot) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed + return 0; +} + +} // namespace zm +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/zm/tests/CMakeLists.txt b/components/eamxx/src/physics/zm/tests/CMakeLists.txt index bf50afa51b24..8a68ec7518d3 100644 --- a/components/eamxx/src/physics/zm/tests/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(infra) set(ZM_TESTS_SRCS zm_test_find_mse_max.cpp zm_ientropy_tests.cpp + zm_entropy_tests.cpp ) # ZM_TESTS_SRCS # All tests should understand the same baseline args diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 index d149eb7cf1a2..7ecc971db152 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 +++ b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 @@ -46,17 +46,31 @@ end subroutine zm_find_mse_max_f !=================================================================================================== - subroutine ientropy_bridge_f(rcall, s, p, qt, t, qst, tfg) bind(C) - use zm_conv_util, only : ientropy - use zm_conv_types, only: zm_const_t, zm_const_set_for_testing +subroutine ientropy_bridge_f(rcall, s, p, qt, t, qst, tfg) bind(C) + use zm_conv_util, only : ientropy + use zm_conv_types, only: zm_const_t, zm_const_set_for_testing - integer(kind=c_int) , value, intent(in) :: rcall - real(kind=c_real) , value, intent(in) :: s, p, qt, tfg - real(kind=c_real) , intent(out) :: t, qst + integer(kind=c_int) , value, intent(in) :: rcall + real(kind=c_real) , value, intent(in) :: s, p, qt, tfg + real(kind=c_real) , intent(out) :: t, qst - type(zm_const_t) :: zm_const + type(zm_const_t) :: zm_const + + call zm_const_set_for_testing(zm_const) + call ientropy(rcall, s, p, qt, t, qst, tfg, zm_const) +end subroutine ientropy_bridge_f + +subroutine entropy_bridge_f(tk, p, qtot, entropy_rv) bind(C) + use zm_conv_util, only : entropy + use zm_conv_types, only: zm_const_t, zm_const_set_for_testing + + real(kind=c_real) , value, intent(in) :: tk, p, qtot + real(kind=c_real) , intent(out) :: entropy_rv + + type(zm_const_t) :: zm_const + + call zm_const_set_for_testing(zm_const) + entropy_rv = entropy(tk, p, qtot, zm_const) +end subroutine entropy_bridge_f - call zm_const_set_for_testing(zm_const) - call ientropy(rcall, s, p, qt, t, qst, tfg, zm_const) - end subroutine ientropy_bridge_f end module zm_c2f_bridge diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 754cfb879011..2af74ff265d2 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -35,6 +35,7 @@ void zm_find_mse_max_f(Int pcols, Int ncol, Int pver, Int num_msg, Int *msemax_t void ientropy_bridge_f(Int rcall, Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); +void entropy_bridge_f(Real tk, Real p, Real qtot, zm_const_t zm_const, Real* entropy); } // extern "C" : end _f decls // Inits and finalizes are not intended to be called outside this comp unit @@ -124,6 +125,48 @@ void ientropy(IentropyData& d) zm_finalize_cxx(); } +void entropy_f(EntropyData& d) +{ + d.transition(); + zm_common_init_f(); // Might need more specific init + entropy_bridge_f(d.tk, d.p, d.qtot, &d.entropy); + d.transition(); +} + +void entropy(EntropyData& d) +{ + zm_common_init(); // Might need more specific init + + // create device views and copy + const auto policy = ekat::TeamPolicyFactory::get_default_team_policy(1, 1); + + // unpack data scalars because we do not want the lambda to capture d + const Real p = d.p; + const Real qtot = d.qtot; + const Real tk = d.tk; + view0dr_d entropy_d("entropy_d"); + auto entropy_h = Kokkos::create_mirror_view(entropy_d); + + Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { + const Int i = team.league_rank(); + + // Get single-column subviews of all inputs, shouldn't need any i-indexing + // after this. + + SHF::entropy( + team, + tk, + p, + qtot, + entropy_d()); + }); + + // Get outputs back, start with scalars + Kokkos::deep_copy(entropy_h, entropy_d); + d.entropy = entropy_h(); + + zm_finalize_cxx(); +} // end glue impls } // namespace zm diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp index 727fc6d9df28..540363c36b60 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp @@ -74,11 +74,27 @@ struct IentropyData : public PhysicsTestData { PTD_STD_DEF(IentropyData, 7, rcall, s, p, qt, tfg, t, qst); }; +struct EntropyData : public PhysicsTestData { + // Inputs + Real tk, p, qtot; + + // Outputs + Real entropy; + + EntropyData(Real tk_, Real p_, Real qtot_, Real entropy_) : + PhysicsTestData({}, {}), + tk(tk_), p(p_), qtot(qtot_), entropy(entropy_) + {} + + PTD_STD_DEF(EntropyData, 4, tk, p, qtot, entropy); +}; + // Glue functions for host test data. We can call either fortran or CXX with this data (_f -> fortran) void zm_find_mse_max(zm_data_find_mse_max& d); void ientropy_f(IentropyData& d); void ientropy(IentropyData& d); - +void entropy_f(EntropyData& d); +void entropy(EntropyData& d); // End glue function decls } // namespace zm diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp b/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp index 75dbcf2bf6ed..bbf1bf63eba9 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_unit_tests_common.hpp @@ -68,6 +68,7 @@ struct UnitWrap { struct Test_zm_find_mse_max; struct TestIentropy; + struct TestEntropy; }; // UnitWrap }; diff --git a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp new file mode 100644 index 000000000000..107e53067c3b --- /dev/null +++ b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp @@ -0,0 +1,92 @@ +#include "catch2/catch.hpp" + +#include "share/core/eamxx_types.hpp" +#include "physics/zm/zm_functions.hpp" +#include "physics/zm/tests/infra/zm_test_data.hpp" + +#include "zm_unit_tests_common.hpp" + +#include +#include + +namespace scream { +namespace zm { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestEntropy : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up inputs + EntropyData baseline_data[] = { + // tk, p, qtot, entropy (output, set to zero) + EntropyData(0, 0, 0, 0), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(EntropyData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + EntropyData test_data[] = { + // TODO + EntropyData(baseline_data[0]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_ifile); + } + } + + // Get data from test + for (auto& d : test_data) { + if (this->m_baseline_action == GENERATE) { + entropy_f(d); + } + else { + entropy(d); + } + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + EntropyData& d_baseline = baseline_data[i]; + EntropyData& d_test = test_data[i]; + REQUIRE(d_baseline.entropy == d_test.entropy); + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_ofile); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace zm +} // namespace scream + +namespace { + +TEST_CASE("entropy_bfb", "[zm]") +{ + using TestStruct = scream::zm::unit_test::UnitWrap::UnitTest::TestEntropy; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 05bfb2d8f28e..de74148ffc90 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -290,6 +290,14 @@ struct Functions { Real& t, Real& qst); + KOKKOS_FUNCTION + static Real entropy( + // Inputs + const MemberType& team, + const Real& tk, + const Real& p, + const Real& qtot); + }; // struct Functions } // namespace zm @@ -301,5 +309,6 @@ struct Functions { # include "impl/zm_output_tend_impl.hpp" # include "impl/zm_common_init.hpp" # include "impl/zm_ientropy_impl.hpp" +# include "impl/zm_entropy_impl.hpp" #endif // GPU && !KOKKOS_ENABLE_*_RELOCATABLE_DEVICE_CODE #endif // ZM_FUNCTIONS_HPP From 9de0f93656fa7c61215ae47a42e62298acfcce4e Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 15 Jan 2026 16:24:05 -0700 Subject: [PATCH 345/398] EAMxx: fix handling of required fields/groups in APG --- .../eamxx/src/control/atmosphere_driver.cpp | 8 +-- .../atm_process/atmosphere_process_group.cpp | 55 ++++--------------- .../atm_process/atmosphere_process_group.hpp | 4 -- 3 files changed, 14 insertions(+), 53 deletions(-) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 79bca84e688f..6e92b2751809 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -563,17 +563,17 @@ void AtmosphereDriver::create_fields() for (const auto& req : m_atm_process_group->get_field_requests()) { const auto& fid = req.fid; const auto& f = m_field_mgr->get_field(fid); - if (req.usage & Computed) - m_atm_process_group->set_computed_field(f); if (req.usage & Required) m_atm_process_group->set_required_field(f.get_const()); + if (req.usage & Computed) + m_atm_process_group->set_computed_field(f); } for (const auto& req : m_atm_process_group->get_group_requests()) { auto group = m_field_mgr->get_field_group(req.name, req.grid); - if (req.usage & Computed) - m_atm_process_group->set_computed_group(group); if (req.usage & Required) m_atm_process_group->set_required_group(group.get_const()); + if (req.usage & Computed) + m_atm_process_group->set_computed_group(group); } // Make atm procs create the proc-level tendency fields (if requested) diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp b/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp index 2b220b86f1b0..aff9a0ad8c61 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp @@ -159,14 +159,16 @@ void AtmosphereProcessGroup::set_grids (const std::shared_ptrget_field_requests()) { + bool already_computed = has_computed_field(ap_req.fid); auto& req = m_field_requests.emplace_back(ap_req); - if (req.usage & Required) - process_required_field(req); + if (req.usage & Required and already_computed) + req.usage = Computed; } for (const auto& ap_req : atm_proc->get_group_requests()) { + bool already_computed = has_computed_group(ap_req.name,ap_req.grid); auto& req = m_group_requests.emplace_back(ap_req); - if (req.usage & Required) - process_required_group(req); + if (req.usage & Required and already_computed) + req.usage = Computed; } } @@ -488,9 +490,9 @@ set_required_field (const Field& f) { // by a previous process. If so, then this FG is not a "required" FG // for this AtmosphereProcessGroup. // NOTE: the case where the FG itself is computed by a previous atm proc - // is already handled during `set_grids` (see process_required_group). + // is already handled during `set_grids` // NOTE: we still check also the groups computed by the previous procs, - // in case they contain some of the fields in this group. + // in case they contain this field bool computed = false; for (int iproc=0; iprochas_computed_field(fid)) { @@ -556,9 +558,9 @@ set_required_group (const FieldGroup& group) { // by a previous process. If so, then this group is not a "required" group // for this group. // NOTE: the case where the group itself is computed by a previous atm proc - // is already handled during `set_grids` (see process_required_group). + // is already handled during `set_grids` // NOTE: we still check also the groups computed by the previous procs, - // in case they contain some of the fields in this group. + // in case they contain all the fields in this group. std::set computed; for (const auto& it : group.m_individual_fields) { const auto& fn = it.first; @@ -658,43 +660,6 @@ void AtmosphereProcessGroup::set_computed_field_impl (const Field& f) { } } -void AtmosphereProcessGroup:: -process_required_group (GroupRequest& req) { - if (m_group_schedule_type==ScheduleType::Sequential) { - if (has_computed_group(req.name,req.grid)) { - // Some previous atm proc computes this group, so it's not an 'input' - // of the atm group as a whole. However, we might need a different - // pack size. So, instead of adding to the required groups, - // we add to the computed ones. This way we don't modify the inputs - // of the group, and still manage to communicate to the AD the pack size - // that we need. - // NOTE; we don't have a way to check if all the fields in the group - // are computed by previous processes, since we don't have - // the list of all fields in this group. - req.usage = Computed; - } - } else { - EKAT_ERROR_MSG ("Error! Parallel schedule not supported.\n"); - } -} - -void AtmosphereProcessGroup:: -process_required_field (FieldRequest& req) { - if (m_group_schedule_type==ScheduleType::Sequential) { - if (has_computed_field(req.fid)) { - // Some previous atm proc computes this field, so it's not an 'input' - // of the group as a whole. However, we might need a different pack size, - // or want to add it to a different group. So, instead of adding to - // the required fields, we add to the computed fields. This way we - // don't modify the inputs of the group, and still manage to communicate - // to the AD the pack size and group affiliations that we need - req.usage = Computed; - } - } else { - EKAT_ERROR_MSG ("Error! Parallel schedule not supported.\n"); - } -} - size_t AtmosphereProcessGroup::requested_buffer_size_in_bytes () const { size_t buf_size = 0; diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp b/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp index 3b861f6f786f..016f90d9a73c 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp @@ -119,10 +119,6 @@ class AtmosphereProcessGroup : public AtmosphereProcess protected: - // Adds fid to the list of required/computed fields of the group (as a whole). - void process_required_field (FieldRequest& req); - void process_required_group (GroupRequest& req); - // The initialization, run, and finalization methods void initialize_impl(const RunType run_type); void initialize_impl (); From dc76183921bf681fc642005e34887408cce248b2 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 15 Jan 2026 16:24:25 -0700 Subject: [PATCH 346/398] EAMxx: remove stranded undefined method in APG --- .../eamxx/src/share/atm_process/atmosphere_process_group.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp b/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp index 016f90d9a73c..07961f2a380f 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_group.hpp @@ -121,9 +121,8 @@ class AtmosphereProcessGroup : public AtmosphereProcess // The initialization, run, and finalization methods void initialize_impl(const RunType run_type); - void initialize_impl (); - void run_impl (const double dt); - void finalize_impl (/* what inputs? */); + void run_impl (const double dt); + void finalize_impl (/* what inputs? */); void run_sequential (const double dt); void run_parallel (const double dt); From e2014e11a01dfc2e4b269b38d040ba359c75802d Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 16 Jan 2026 10:54:54 -0700 Subject: [PATCH 347/398] EAMxx: declare some commonly used typedefs in the AD class --- .../eamxx/src/control/atmosphere_driver.cpp | 19 ++++++++----------- .../eamxx/src/control/atmosphere_driver.hpp | 6 +++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 2ec7cea3acab..52558b65430d 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -513,10 +513,9 @@ void AtmosphereDriver::setup_shoc_tms_links () void AtmosphereDriver::add_additional_column_data_to_property_checks () { // Get list of additional data fields from driver_options parameters. // If no fields given, return. - using vos_t = std::vector; - auto additional_data_fields = m_atm_params.sublist("driver_options").get("property_check_data_fields", + auto additional_data_fields = m_atm_params.sublist("driver_options").get("property_check_data_fields", {"NONE"}); - if (additional_data_fields == vos_t{"NONE"}) return; + if (additional_data_fields == strvec_t{"NONE"}) return; // Add requested fields to property checks const auto& grid_name = m_grids_manager->get_grid("physics")->name(); @@ -676,7 +675,7 @@ void AtmosphereDriver::create_fields() pl.set("units",fid.get_units().to_string()); pl.set("layout",fid.get_layout().names()); pl.set("standard_name",std_names.get_standardname(fid.name())); - std::vector providers,customers; + strvec_t providers,customers; const auto& track = it.second->get_header().get_tracking(); for (auto ap : track.get_providers()) { providers.push_back(ap.lock()->name()); @@ -735,8 +734,7 @@ void AtmosphereDriver::create_output_managers () { } // Create one output manager per output yaml file - using vos_t = std::vector; - const auto& output_yaml_files = io_params.get("output_yaml_files",vos_t{}); + const auto& output_yaml_files = io_params.get("output_yaml_files",strvec_t{}); for (const auto& fname : output_yaml_files) { ekat::ParameterList params; ekat::parse_yaml_file(fname,params); @@ -1059,12 +1057,12 @@ void AtmosphereDriver::set_initial_conditions () auto& ic_pl = m_atm_params.sublist("initial_conditions"); // Check which fields need to have an initial condition. - std::map> ic_fields_names; + strmap_t ic_fields_names; std::vector ic_fields_to_copy; // Check which fields should be loaded from the topography file - std::map> topography_file_fields_names; - std::map> topography_eamxx_fields_names; + strmap_t topography_file_fields_names; + strmap_t topography_eamxx_fields_names; // Helper lambda, to reduce code duplication auto process_ic_field = [&](const Field& f) { @@ -1377,8 +1375,7 @@ void AtmosphereDriver::set_initial_conditions () } // Compute IC perturbations of GLL fields (if requested) - using vos = std::vector; - const auto perturbed_fields = ic_pl.get("perturbed_fields", {}); + const auto perturbed_fields = ic_pl.get("perturbed_fields", {}); const auto num_perturb_fields = perturbed_fields.size(); if (num_perturb_fields > 0) { m_atm_logger->info(" [EAMxx] Adding random perturbation to ICs ..."); diff --git a/components/eamxx/src/control/atmosphere_driver.hpp b/components/eamxx/src/control/atmosphere_driver.hpp index 311a68319d76..411ee2be08da 100644 --- a/components/eamxx/src/control/atmosphere_driver.hpp +++ b/components/eamxx/src/control/atmosphere_driver.hpp @@ -191,6 +191,10 @@ class AtmosphereDriver const std::string& file_name); void register_groups (); + template + using strmap_t = std::map; + using strvec_t = std::vector; + field_mgr_ptr m_field_mgr; std::shared_ptr m_atm_process_group; @@ -255,7 +259,7 @@ class AtmosphereDriver // Current simulation casename std::string m_casename; // maps grid name to a vector of its initialized fields - std::map> m_fields_inited; + strmap_t m_fields_inited; }; } // namespace control From 9a53f504125a317473b40393704980562d6cba7e Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 16 Jan 2026 10:45:29 -0700 Subject: [PATCH 348/398] EAMxx: store providers/customers as strings in FieldTracking --- .../eamxx/src/control/atmosphere_driver.cpp | 13 +++------ .../share/atm_process/atmosphere_process.cpp | 4 +-- .../eamxx/src/share/field/field_tracking.cpp | 13 --------- .../eamxx/src/share/field/field_tracking.hpp | 27 +++++++------------ 4 files changed, 16 insertions(+), 41 deletions(-) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 52558b65430d..8c37b5e8eedb 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -675,16 +675,11 @@ void AtmosphereDriver::create_fields() pl.set("units",fid.get_units().to_string()); pl.set("layout",fid.get_layout().names()); pl.set("standard_name",std_names.get_standardname(fid.name())); - strvec_t providers,customers; const auto& track = it.second->get_header().get_tracking(); - for (auto ap : track.get_providers()) { - providers.push_back(ap.lock()->name()); - } - for (auto ap : track.get_customers()) { - customers.push_back(ap.lock()->name()); - } - pl.set("providers",providers); - pl.set("customers",customers); + const auto& p = track.get_providers(); + const auto& c = track.get_customers(); + pl.set("providers",strvec_t(p.begin(),p.end())); + pl.set("customers",strvec_t(c.begin(),c.end())); } ekat::write_yaml_file("eamxx_field_manager_content.yaml",pl_out); diff --git a/components/eamxx/src/share/atm_process/atmosphere_process.cpp b/components/eamxx/src/share/atm_process/atmosphere_process.cpp index 10c90d995bac..e2b2b54a4875 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process.cpp @@ -621,11 +621,11 @@ void AtmosphereProcess::update_time_stamps () { } void AtmosphereProcess::add_me_as_provider (const Field& f) { - f.get_header_ptr()->get_tracking().add_provider(weak_from_this()); + f.get_header_ptr()->get_tracking().add_provider(name()); } void AtmosphereProcess::add_me_as_customer (const Field& f) { - f.get_header_ptr()->get_tracking().add_customer(weak_from_this()); + f.get_header_ptr()->get_tracking().add_customer(name()); } void AtmosphereProcess:: diff --git a/components/eamxx/src/share/field/field_tracking.cpp b/components/eamxx/src/share/field/field_tracking.cpp index 55093451aeca..58ecb54d1432 100644 --- a/components/eamxx/src/share/field/field_tracking.cpp +++ b/components/eamxx/src/share/field/field_tracking.cpp @@ -2,19 +2,6 @@ namespace scream { -void FieldTracking::add_provider (const std::weak_ptr& provider) { - m_providers.insert(provider); -} - -void FieldTracking::add_customer (const std::weak_ptr& customer) { - m_customers.insert(customer); -} - -void FieldTracking:: -add_group (const std::string& group_name) { - m_groups.insert(group_name); -} - void FieldTracking::update_time_stamp (const TimeStamp& ts) { // We check that the given time stamp is not in the past. // This is to prevent users from tampering with time stamps (e.g., rewinding time). diff --git a/components/eamxx/src/share/field/field_tracking.hpp b/components/eamxx/src/share/field/field_tracking.hpp index 58e80525231c..e10c177c5113 100644 --- a/components/eamxx/src/share/field/field_tracking.hpp +++ b/components/eamxx/src/share/field/field_tracking.hpp @@ -15,17 +15,11 @@ namespace scream { -// Forward declarations -class AtmosphereProcess; -class FieldHeader; - class FieldTracking : public FamilyTracking { public: using TimeStamp = util::TimeStamp; using ci_string = ekat::CaseInsensitiveString; - using atm_proc_ptr_type = std::weak_ptr; - using atm_proc_set_type = ekat::WeakPtrSet; FieldTracking() = default; FieldTracking(const FieldTracking&) = default; @@ -41,8 +35,8 @@ class FieldTracking : public FamilyTracking { // - provider: can compute the field as an output // - customer: requires the field as an input - const atm_proc_set_type& get_providers () const { return m_providers; } - const atm_proc_set_type& get_customers () const { return m_customers; } + const std::set& get_providers () const { return m_providers; } + const std::set& get_customers () const { return m_customers; } // List of field groups that this field belongs to const std::set& get_groups_names () const { return m_groups; } @@ -50,11 +44,11 @@ class FieldTracking : public FamilyTracking { // ----- Setters ----- // // Add to the list of providers/customers - void add_provider (const std::weak_ptr& provider); - void add_customer (const std::weak_ptr& customer); + void add_provider (const std::string& provider) { m_providers.insert(provider); } + void add_customer (const std::string& customer) { m_customers.insert(customer); } // Add group name to the list of groups we belong to - void add_group (const std::string& group_name); + void add_group (const std::string& group) { m_groups.insert(group); } // Set the time stamp for this field. This can only be called once, due to TimeStamp implementation. // NOTE: if the field has 'children' (see FamilyTracking), their ts will be updated too. @@ -76,13 +70,12 @@ class FieldTracking : public FamilyTracking { // For accumulated vars, the time where the accumulation started TimeStamp m_accum_start; - ci_string m_accum_type; - // List of provider/customer processes. A provider is an atm process that computes/updates the field. - // A customer is an atm process that uses the field just as an input. - // NOTE: do NOT use shared_ptr, since you would create circular references. - atm_proc_set_type m_providers; - atm_proc_set_type m_customers; + // List of providers and customers of this field. + // - A provider is an entity that uses the field in writable mode + // - A customer is an entity that uses the field in read-only mode + std::set m_providers; + std::set m_customers; // Groups are used to bundle together fields, so that a process can request all of them // without knowing/listing all their names. For instance, the dynamics process needs to From cb7190073ea60ce4c6943cc92aeee10c5cf4f439 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 16 Jan 2026 09:44:14 -0700 Subject: [PATCH 349/398] EAMxx: fix check in APG set_grids --- .../eamxx/src/share/atm_process/atmosphere_process_group.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp b/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp index aff9a0ad8c61..4d1c7449cc92 100644 --- a/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp +++ b/components/eamxx/src/share/atm_process/atmosphere_process_group.cpp @@ -154,6 +154,7 @@ void AtmosphereProcessGroup::set_grids (const std::shared_ptrset_grids(grids_manager); @@ -161,13 +162,13 @@ void AtmosphereProcessGroup::set_grids (const std::shared_ptrget_field_requests()) { bool already_computed = has_computed_field(ap_req.fid); auto& req = m_field_requests.emplace_back(ap_req); - if (req.usage & Required and already_computed) + if (seq_splitting and req.usage & Required and already_computed) req.usage = Computed; } for (const auto& ap_req : atm_proc->get_group_requests()) { bool already_computed = has_computed_group(ap_req.name,ap_req.grid); auto& req = m_group_requests.emplace_back(ap_req); - if (req.usage & Required and already_computed) + if (seq_splitting and req.usage & Required and already_computed) req.usage = Computed; } } From cb875651d215323d4185b24f4868059637a97eba Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 16 Jan 2026 13:33:33 -0700 Subject: [PATCH 350/398] Handle different names for typedef wrapper --- .../eamxx/scripts/gen-boiler/gen_boiler.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 8c4ec18fbdfe..8a427d3507cb 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -245,7 +245,7 @@ # physics map. maps the name of a physics packages containing the original fortran subroutines to: # (path-to-origin, path-to-cxx-src, init-code) -ORIGIN_FILES, CXX_ROOT, INIT_CODE, FINALIZE_CODE, COLS_DIMNAME, UNPACKED = range(6) +ORIGIN_FILES, CXX_ROOT, INIT_CODE, FINALIZE_CODE, COLS_DIMNAME, UNPACKED, FTYPEDEF = range(7) PHYSICS = { "p3" : ( ("components/eam/src/physics/cam/micro_p3.F90",), @@ -253,7 +253,8 @@ "p3_init();", "", "its:ite", - False + False, + "P3F", ), "shoc" : ( ("components/eam/src/physics/cam/shoc.F90",), @@ -261,7 +262,8 @@ "shoc_init(d.nlev, true);", "", "shcol", - False + False, + "SHF", ), "dp" : ( ( @@ -274,7 +276,8 @@ "dp_init(d.plev, true);", "" "", - False + False, + "DPF", ), "gw" : ( ( @@ -289,7 +292,8 @@ "gw_common_init(); // Might need more specific init", "gw_finalize_cxx();", "ncol", - True + True, + "GWF", ), "zm" : ( ( @@ -304,7 +308,8 @@ "zm_common_init(); // Might need more specific init", "zm_finalize_cxx();", "ncol", - True + True, + "ZMF", ), } @@ -1449,7 +1454,8 @@ def gen_glue_impl(phys, sub, arg_data, arg_names, col_dim, f2c=False, unpacked=F kernel_arg_names.append(arg_name) joinstr = ',\n ' - impl += f" SHF::{sub}(\n {joinstr.join(kernel_arg_names)});\n" + ftypedef = get_physics_data(phys, FTYPEDEF) + impl += f" {ftypedef}::{sub}(\n {joinstr.join(kernel_arg_names)});\n" impl += " });\n\n" # From 08e3c9c03fc6cbb68bd173dacf4b2cd755a28542 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 16 Jan 2026 15:50:52 -0700 Subject: [PATCH 351/398] Add support for comment preservation --- .../eamxx/scripts/gen-boiler/gen_boiler.py | 105 +++++----- .../eamxx/scripts/gen-boiler/run-gb-tests | 184 +++++++++--------- 2 files changed, 158 insertions(+), 131 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index 8a427d3507cb..baa6b32dc30d 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -474,18 +474,28 @@ def remove_comments_and_ws(contents): Remove comments and whitespaces from fortran code """ new_lines = [] - comment_regex = re.compile(r"^([^!]*)") + new_comments = [] + prev_comment = "" for line in contents.splitlines(): - m = comment_regex.match(line) - if m is not None: - line = m.groups()[0].strip() + if "!" in line: + noncomment, comment = line.split("!", maxsplit=1) + noncomment = noncomment.strip() + comment = comment.strip() else: - line = line.strip() + noncomment = line.strip() + comment = "" - if line != "": - new_lines.append(line) + if noncomment != "": + new_lines.append(noncomment) + if comment != "": + new_comments.append(comment) + else: + new_comments.append(prev_comment) + prev_comment = "" + else: + prev_comment += comment - return "\n".join(new_lines) + return new_lines, new_comments ############################################################################### def normalize_f90(contents): @@ -495,21 +505,26 @@ def normalize_f90(contents): and lowercasing everything. """ # Must remove comments and whitespace for the alg below to work - contents = remove_comments_and_ws(contents) + lines, comments = remove_comments_and_ws(contents) + expect(len(lines) == len(comments), "Comment/line mismatch") new_lines = [] + new_comments = [] contination = False - for line in contents.splitlines(): + for line, comment in zip(lines, comments): line = line.lstrip("&") # always remove leading &, they are optional + line = line.lower() if line != "": if contination: new_lines[-1] += line.rstrip("&") + new_comments[-1] += comment else: new_lines.append(line.rstrip("&")) + new_comments.append(comment) contination = line.endswith("&") - return ("\n".join(new_lines)).lower() + return new_lines, new_comments ############################################################################### def split_top_commas(line): @@ -559,12 +574,12 @@ def get_arg_order(line): args_raw = line.rstrip(")").split("(", maxsplit=1)[-1] return [item.strip() for item in args_raw.split(",") if item.strip()] -ARG_NAME, ARG_TYPE, ARG_INTENT, ARG_DIMS = range(4) +ARG_NAME, ARG_TYPE, ARG_INTENT, ARG_DIMS, ARG_COMMENT = range(5) ############################################################################### -def parse_f90_args(line): +def parse_f90_args(line, comment=None): ############################################################################### """ - Given a line of fortran code declaring an argument[s], return [(argname, argtype, intent, dims)] + Given a line of fortran code declaring an argument[s], return [(argname, argtype, intent, dims, comment)] Anywhere you see "arg_data" in this program, it's referring to a list of data produced by this function. Anywhere you see "arg_datum", it's referring to a single item in this list. """ @@ -604,7 +619,7 @@ def parse_f90_args(line): all_dims.append(dims) names.append(name_dim.strip()) - return [(name, argtype, intent, dims) for name, dims in zip(names, all_dims)] + return [(name, argtype, intent, dims, None if not comment else comment) for name, dims in zip(names, all_dims)] ############################################################################### def parse_origin(contents, subs): @@ -616,14 +631,15 @@ def parse_origin(contents, subs): begin_func_regexes = [get_function_begin_regex(sub) for sub in subs] arg_decl_regex = re.compile(r"^.+intent\s*[(]\s*(in|out|inout)\s*[)]") - contents = normalize_f90(contents) + new_lines, new_comments = normalize_f90(contents) + expect(len(new_lines) == len(new_comments), "New Comment/line mismatch") db = {} active_sub = None result_name = None arg_order = [] arg_decls = [] - for line in contents.splitlines(): + for line, comment in zip(new_lines, new_comments): for sub, begin_sub_regex, begin_func_regex in zip(subs, begin_sub_regexes, begin_func_regexes): begin_sub_match = begin_sub_regex.match(line) begin_func_match = begin_func_regex.match(line) @@ -640,13 +656,13 @@ def parse_origin(contents, subs): if active_sub: decl_match = arg_decl_regex.match(line) if decl_match is not None: - arg_decls.extend(parse_f90_args(line)) + arg_decls.extend(parse_f90_args(line, comment)) elif result_name: result_decl_regex = re.compile(fr".+::\s*{result_name}([^\w]|$)") result_decl_match = result_decl_regex.match(line) if result_decl_match is not None: line = line.replace("::", " , intent(out) ::") - arg_decls.extend(parse_f90_args(line)) + arg_decls.extend(parse_f90_args(line, comment)) end_regex = get_subroutine_end_regex(active_sub) end_match = end_regex.match(line) @@ -682,7 +698,7 @@ def parse_origin(contents, subs): dim_scalars = extract_dim_scalars(arg_dim) for arg_dim in dim_scalars: if arg_dim not in arg_names: - global_ints_to_insert.append((arg_dim, "integer", "in", None)) + global_ints_to_insert.append((arg_dim, "integer", "in", None, None)) arg_names.add(arg_dim) db[active_sub] = global_ints_to_insert + ordered_decls @@ -778,22 +794,24 @@ def gen_arg_cxx_decls(arg_data, kokkos=False, unpacked=False, col_dim=None): types instead of C types. """ arg_names = [item[ARG_NAME] for item in arg_data] + arg_comments = [item[ARG_COMMENT] for item in arg_data] + arg_intents = [item[ARG_INTENT] for item in arg_data] if kokkos: arg_types = [get_kokkos_type(item, col_dim, unpacked=unpacked) for item in arg_data] else: arg_types = [get_cxx_type(item) for item in arg_data] - arg_sig_list = [(f"{arg_type} {arg_name}", arg_datum[ARG_INTENT]) - for arg_name, arg_type, arg_datum in zip(arg_names, arg_types, arg_data)] + arg_sig_list = [(f"{arg_type} {arg_name}", arg_intent, arg_comment) + for arg_name, arg_type, arg_intent, arg_comment in zip(arg_names, arg_types, arg_intents, arg_comments)] # For kokkos functions, we will almost always want the team and we don't want # the col_dim if kokkos: - arg_sig_list.insert(0, ("const MemberType& team", "in")) - for arg_sig, arg_intent in arg_sig_list: + arg_sig_list.insert(0, ("const MemberType& team", "in", None)) + for arg_sig, arg_intent, arg_comment in arg_sig_list: if arg_sig.split()[-1] == col_dim: expect(arg_intent == "in", f"col_dim {col_dim} wasn't an input, {arg_intent}?") - arg_sig_list.remove((arg_sig, arg_intent)) + arg_sig_list.remove((arg_sig, arg_intent, arg_comment)) break result = [] @@ -803,16 +821,19 @@ def gen_arg_cxx_decls(arg_data, kokkos=False, unpacked=False, col_dim=None): if kokkos: intent_map = {"in" : "Inputs", "inout" : "Inputs/Outputs", "out" : "Outputs"} curr = None - for arg_sig, arg_intent in arg_sig_list: + for arg_sig, arg_intent, arg_comment in arg_sig_list: if arg_intent != curr: fullname = intent_map[arg_intent] result.append(f"// {fullname}") curr = arg_intent - result.append(arg_sig) + if arg_comment: + result.append(f"{arg_sig} // {arg_comment}") + else: + result.append(arg_sig) else: - result = [arg_sig for arg_sig, _ in arg_sig_list] + result = [arg_sig for arg_sig, _, _ in arg_sig_list] return result @@ -823,7 +844,7 @@ def split_by_intent(arg_data): Take arg data and split into three lists of names based on intent: [inputs], [intouts], [outputs] """ inputs, inouts, outputs = [], [], [] - for name, _, intent, _ in arg_data: + for name, _, intent, _, _ in arg_data: if intent == "in": inputs.append(name) elif intent == "inout": @@ -842,7 +863,7 @@ def split_by_type(arg_data): Take arg data and split into three lists of names based on type: [reals], [ints], [logicals] """ reals, ints, logicals = [], [], [] - for name, argtype, _, _ in arg_data: + for name, argtype, _, _, _ in arg_data: if argtype == "real": reals.append(name) elif argtype == "integer": @@ -863,7 +884,7 @@ def split_by_scalar_vs_view(arg_data): Take arg data and split into two lists of names based on scalar/not-scalar: [scalars] [non-scalars] """ scalars, non_scalars = [], [] - for name, _, _, dims in arg_data: + for name, _, _, dims, _ in arg_data: if dims is not None: non_scalars.append(name) else: @@ -890,7 +911,7 @@ def gen_arg_f90_decls(arg_data): Generate f90 argument declarations, will attempt to group these together if possible. """ metadata = {} - for name, argtype, intent, dims in arg_data: + for name, argtype, intent, dims, _ in arg_data: metatuple = (argtype, intent, dims) metadata.setdefault(metatuple, []).append(name) @@ -906,7 +927,7 @@ def has_arrays(arg_data): """ Return if arg_data contains any array data """ - for _, _, _, dims in arg_data: + for _, _, _, dims, _ in arg_data: if dims is not None: return True @@ -919,7 +940,7 @@ def get_scalar_members(arg_data): Gen cxx code for data struct members in an order that matches gen_struct_members """ metadata = {} # intent -> type -> names - for name, argtype, intent, dims in arg_data: + for name, argtype, intent, dims, _ in arg_data: if dims is None: metadata.setdefault(intent, {}).setdefault(argtype, []).append(name) @@ -944,7 +965,7 @@ def gen_struct_members(arg_data): Gen cxx code for data struct members """ metadata = {} # intent -> (type, is_ptr) -> names - for name, argtype, intent, dims in arg_data: + for name, argtype, intent, dims, _ in arg_data: metadata.setdefault(intent, {}).setdefault((argtype, dims is not None), []).append(name) intent_order = ( ("in", "Inputs"), ("inout", "Inputs/Outputs"), ("out", "Outputs") ) @@ -1004,7 +1025,7 @@ def group_data(arg_data, filter_out_intent=None, filter_scalar_custom_types=Fals all_dims = [] - for name, argtype, _, dims in arg_data: + for name, argtype, _, dims, _ in arg_data: if dims is not None: for dim in dims: dscalars = extract_dim_scalars(dim) @@ -1016,7 +1037,7 @@ def group_data(arg_data, filter_out_intent=None, filter_scalar_custom_types=Fals int_data = {} bool_data = {} - for name, argtype, intent, dims in arg_data: + for name, argtype, intent, dims, _ in arg_data: if filter_out_intent is None or intent != filter_out_intent: if dims is None: if not (is_custom_type(argtype) and filter_scalar_custom_types): @@ -1216,9 +1237,9 @@ def check_existing_piece(lines, begin_regex, end_regex): ############################################################################### def get_data_by_name(arg_data, arg_name, data_idx): ############################################################################### - for name, a, b, c in arg_data: + for name, a, b, c, d in arg_data: if name == arg_name: - return [name, a, b, c][data_idx] + return [name, a, b, c, d][data_idx] expect(False, f"Name {arg_name} not found") @@ -1760,7 +1781,7 @@ def gen_cxx_func_decl(self, phys, sub, force_arg_data=None): arg_data = force_arg_data if force_arg_data else self._get_arg_data(phys, sub) arg_decls = gen_arg_cxx_decls(arg_data, kokkos=True, unpacked=self._unpacked, col_dim=self._col_dim) - arg_decls_str = ("\n ".join([item if item.startswith("//") else f"{item}," for item in arg_decls])).rstrip(",") + arg_decls_str = ("\n ".join([item if item.startswith("//") else (item.replace(" //", ", //") if "//" in item else f"{item},") for item in arg_decls])).rstrip(",") return f" KOKKOS_FUNCTION\n static void {sub}(\n {arg_decls_str});" @@ -2036,7 +2057,3 @@ def gen_boiler(self): print("ALL_SUCCESS" if all_success else "THERE WERE FAILURES") return all_success - -if __name__ == "__main__": - import doctest - doctest.run_docstring_examples(parse_f90_args, globals()) diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index 15af507b3c60..795490254d67 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -16,48 +16,48 @@ GEN_BOILER_DIR = Path(__file__).resolve().parent # A good set of arg data for unit testing UT_ARG_DATA = [ - ("foo1", "real", "in", ("shcol",)), - ("foo2", "real", "in", ("shcol",)), - ("bar1", "real", "in", ("shcol","nlev")), - ("bar2", "real", "in", ("shcol","nlev")), - ("bak1", "real", "in", ("shcol","-nlev:nlev")), - ("bak2", "real", "in", ("shcol","nlevi")), - ("tracerd1", "real", "in", ("shcol","nlev", "ntracers")), - ("tracerd2", "real", "in", ("shcol","nlev", "ntracers")), - ("gag", "real", "in", None), - ("baz", "real", "inout", ("shcol",)), - ("bag", "integer", "in", ("shcol","0:nlev")), - ("bab1", "integer", "inout", None), - ("bab2", "integer", "out", None), - ("val", "logical", "in", None), - ("vals", "logical", "in", ("shcol",)), - ("shcol", "integer", "in", None), - ("nlev", "integer", "in", None), - ("nlevi", "integer", "in", None), - ("ntracers", "integer", "in", None), - ("ball1", "integer", "out", ("shcol",)), - ("ball2", "integer", "out", ("shcol",)), + ("foo1", "real", "in", ("shcol",), None), + ("foo2", "real", "in", ("shcol",), None), + ("bar1", "real", "in", ("shcol","nlev"), None), + ("bar2", "real", "in", ("shcol","nlev"), None), + ("bak1", "real", "in", ("shcol","-nlev:nlev"), None), + ("bak2", "real", "in", ("shcol","nlevi"), None), + ("tracerd1", "real", "in", ("shcol","nlev", "ntracers"), None), + ("tracerd2", "real", "in", ("shcol","nlev", "ntracers"), None), + ("gag", "real", "in", None, None), + ("baz", "real", "inout", ("shcol",), None), + ("bag", "integer", "in", ("shcol","0:nlev"), None), + ("bab1", "integer", "inout", None, None), + ("bab2", "integer", "out", None, None), + ("val", "logical", "in", None, "Lone val comment"), + ("vals", "logical", "in", ("shcol",), None), + ("shcol", "integer", "in", None, None), + ("nlev", "integer", "in", None, None), + ("nlevi", "integer", "in", None, None), + ("ntracers", "integer", "in", None, None), + ("ball1", "integer", "out", ("shcol",), None), + ("ball2", "integer", "out", ("shcol",), None), ] UT_ARG_DATA_ALL_SCALAR = [ - ("foo1", "real", "in", None), - ("foo2", "real", "in", None), - ("bar1", "real", "inout", None), - ("bar2", "real", "inout", None), - ("baz1", "real", "out", None), - ("baz2", "real", "out", None), - ("gag1", "integer", "in", None), - ("gag2", "integer", "in", None), - ("gal1", "integer", "inout", None), - ("gal2", "integer", "inout", None), - ("bal1", "integer", "out", None), - ("bal2", "integer", "out", None), - ("bit1", "logical", "in", None), - ("bit2", "logical", "in", None), - ("gut1", "logical", "inout", None), - ("gut2", "logical", "inout", None), - ("gat1", "logical", "out", None), - ("gat2", "logical", "out", None), + ("foo1", "real", "in", None, None), + ("foo2", "real", "in", None, None), + ("bar1", "real", "inout", None, None), + ("bar2", "real", "inout", None, None), + ("baz1", "real", "out", None, None), + ("baz2", "real", "out", None, None), + ("gag1", "integer", "in", None, None), + ("gag2", "integer", "in", None, None), + ("gal1", "integer", "inout", None, None), + ("gal2", "integer", "inout", None, None), + ("bal1", "integer", "out", None, None), + ("bal2", "integer", "out", None, None), + ("bit1", "logical", "in", None, None), + ("bit2", "logical", "in", None, None), + ("gut1", "logical", "inout", None, None), + ("gut2", "logical", "inout", None, None), + ("gat1", "logical", "out", None, None), + ("gat2", "logical", "out", None, None), ] ############################################################################### @@ -241,9 +241,11 @@ class TestGenBoilerBasics(unittest.TestCase): 'const uview_1d&') # gen_arg_cxx_decls - self.assertEqual(gen_arg_cxx_decls([("foo", "real", "in", ("100",)), ("bar", "real", "in", None)]), + self.assertEqual(gen_arg_cxx_decls([("foo", "real", "in", ("100",), None), + ("bar", "real", "in", None, None)]), ['Real* foo', 'Real bar']) - self.assertEqual(gen_arg_cxx_decls([("foo", "real", "in", ("100",)), ("bar", "real", "out", None)], kokkos=True, col_dim="ignore"), + self.assertEqual(gen_arg_cxx_decls([("foo", "real", "in", ("100",), None), + ("bar", "real", "out", None, None)], kokkos=True, col_dim="ignore"), ['// Inputs', 'const MemberType& team', 'const uview_1d& foo', '// Outputs', 'Spack& bar']) # split_by_intent @@ -426,7 +428,7 @@ void Functions::linear_interp( // Outputs Int& bab2, // Inputs - const bool& val, + const bool& val, // Lone val comment const bool& vals, const Int& nlev, const Int& nlevi, @@ -479,7 +481,7 @@ c, d, e, f end subroutine foo end module mymod """ - actual = remove_comments_and_ws(test_str) + actual = "\n".join(remove_comments_and_ws(test_str)[0]) line_by_line_compare(self, expected_result, actual) expected_result2 = \ @@ -489,38 +491,45 @@ real, intent(in) :: a, b, c, d, e, f end subroutine foo end module mymod """ - actual2 = normalize_f90(test_str) + actual2 = "\n".join(normalize_f90(test_str)[0]) line_by_line_compare(self, expected_result2, actual2) ########################################################################### def test_parse_f90_args(self): ########################################################################### self.assertEqual(parse_f90_args('integer, intent(in) :: kts, kte, kbot'), - [('kts', 'integer', 'in', None), ('kte', 'integer', 'in', None), ('kbot', 'integer', 'in', None)]) + [('kts', 'integer', 'in', None, None), + ('kte', 'integer', 'in', None, None), + ('kbot', 'integer', 'in', None, None)]) self.assertEqual(parse_f90_args('real(rtype),intent(inout ), dimension(kts:kte) :: pres,dpres, dz '), - [('pres', 'real', 'inout', ('kts:kte',)), ('dpres', 'real', 'inout', ('kts:kte',)), ('dz', 'real', 'inout', ('kts:kte',))]) - self.assertEqual(parse_f90_args('logical (btype), intent( in) ::do_predict_nc'), - [('do_predict_nc', 'logical', 'in', None)]) + [('pres', 'real', 'inout', ('kts:kte',), None), + ('dpres', 'real', 'inout', ('kts:kte',), None), + ('dz', 'real', 'inout', ('kts:kte',), None)]) + self.assertEqual(parse_f90_args('logical (btype), intent( in) ::do_predict_nc', 'hi'), + [('do_predict_nc', 'logical', 'in', None, 'hi')]) self.assertEqual(parse_f90_args('real(rtype),intent(inout), dimension( kts:kte, its: ite) :: dz'), - [('dz', 'real', 'inout', ('kts:kte', 'its:ite'))]) + [('dz', 'real', 'inout', ('kts:kte', 'its:ite'), None)]) self.assertEqual(parse_f90_args('real(rtype),intent(inout), dimension(3) :: dz'), - [('dz', 'real', 'inout', ('3',))]) + [('dz', 'real', 'inout', ('3',), None)]) self.assertEqual(parse_f90_args('real(rtype),intent(inout), dimension(3,4) :: dz'), - [('dz', 'real', 'inout', ('3', '4'))]) + [('dz', 'real', 'inout', ('3', '4'), None)]) self.assertEqual(parse_f90_args('real(rtype), dimension(3,4),intent(inout) :: dz'), - [('dz', 'real', 'inout', ('3', '4'))]) + [('dz', 'real', 'inout', ('3', '4'), None)]) self.assertEqual(parse_f90_args('real(rtype), intent(in) :: x1(ncol,km1), y1(ncol , km1 )'), - [('x1', 'real', 'in', ('ncol', 'km1')), ('y1', 'real', 'in', ('ncol', 'km1'))]) + [('x1', 'real', 'in', ('ncol', 'km1'), None), + ('y1', 'real', 'in', ('ncol', 'km1'), None)]) self.assertEqual(parse_f90_args('real(rtype), intent(in) :: x1(ncol,km1,ntracers)'), - [('x1', 'real', 'in', ('ncol', 'km1', 'ntracers'))]) + [('x1', 'real', 'in', ('ncol', 'km1', 'ntracers'), None)]) self.assertEqual(parse_f90_args('type(element_t), intent(inout) :: elem(:)'), - [('elem', 'type::element_t', 'inout', (':',))]) + [('elem', 'type::element_t', 'inout', (':',), None)]) self.assertEqual(parse_f90_args('character*(max_path_len), intent(out), optional :: iopfile_out'), - [('iopfile_out', 'type::string', 'out', None)]) + [('iopfile_out', 'type::string', 'out', None, None)]) self.assertEqual(parse_f90_args('real(r8), intent(out) :: nm(ncol,pver), ni(ncol,0:pver)'), - [('nm', 'real', 'out', ('ncol', 'pver')), ('ni', 'real', 'out', ('ncol', '0:pver'))]) + [('nm', 'real', 'out', ('ncol', 'pver'), None), + ('ni', 'real', 'out', ('ncol', '0:pver'), None)]) self.assertEqual(parse_f90_args('real(r8), intent(out) :: nm(ncol,pver), ni(ncol,-pgwv:pgwv)'), - [('nm', 'real', 'out', ('ncol', 'pver')), ('ni', 'real', 'out', ('ncol', '-pgwv:pgwv'))]) + [('nm', 'real', 'out', ('ncol', 'pver'), None), + ('ni', 'real', 'out', ('ncol', '-pgwv:pgwv'), None)]) ########################################################################### def test_parse_origin(self): @@ -625,7 +634,7 @@ end module mymod integer(kind=c_int) , intent(in), dimension(shcol, 0:nlev) :: bag integer(kind=c_int) , intent(inout) :: bab1 integer(kind=c_int) , intent(out) :: bab2 - logical(kind=c_bool) , value, intent(in) :: val + logical(kind=c_bool) , value, intent(in) :: val ! Lone val comment logical(kind=c_bool) , intent(in), dimension(shcol) :: vals integer(kind=c_int) , value, intent(in) :: shcol, nlev, nlevi, ntracers integer(kind=c_int) , intent(out), dimension(shcol) :: ball1, ball2 @@ -634,49 +643,50 @@ end module mymod test1 = [item for item in sorted(parse_origin(teststr, ["p3_get_tables", "p3_init_b"]).items())] self.assertEqual(test1, [ ('p3_get_tables', [ - ('mu_r_user', 'real', 'out', ('150',)), - ('revap_user', 'real', 'out', ('300', '10')), - ('tracerd', 'real', 'out', ('300', '10', '42')), - ('vn_user', 'real', 'out', ('300', '10')), - ('vm_user', 'real', 'out', ('300', '10')) + ('mu_r_user', 'real', 'out', ('150',), None), + ('revap_user', 'real', 'out', ('300', '10'), None), + ('tracerd', 'real', 'out', ('300', '10', '42'), None), + ('vn_user', 'real', 'out', ('300', '10'), None), + ('vm_user', 'real', 'out', ('300', '10'), None) ]), ('p3_init_b', []) ]) + self.maxDiff = 9999 test2 = [item for item in parse_origin(teststr, ["impli_srf_stress_term"]).items()] self.assertEqual(test2, [ ('impli_srf_stress_term', [ - ('shcol', 'integer', 'in', None), - ('rho_zi_sfc', 'real', 'in', ('shcol',)), - ('uw_sfc', 'real', 'in', ('shcol',)), - ('vw_sfc', 'real', 'in', ('shcol',)), - ('u_wind_sfc', 'real', 'in', ('shcol',)), - ('v_wind_sfc', 'real', 'in', ('shcol',)), - ('ksrf', 'real', 'out', ('shcol',)) + ('shcol', 'integer', 'in', None, "intent-ins"), + ('rho_zi_sfc', 'real', 'in', ('shcol',), "air density at interfaces [kg/m3]"), + ('uw_sfc', 'real', 'in', ('shcol',), "vertical zonal momentum flux at surface [m3/s3]"), + ('vw_sfc', 'real', 'in', ('shcol',), "vertical meridional momentum flux at surface [m3/s3]"), + ('u_wind_sfc', 'real', 'in', ('shcol',), "zonal wind [m/s]"), + ('v_wind_sfc', 'real', 'in', ('shcol',), "meridional wind [m/s]"), + ('ksrf', 'real', 'out', ('shcol',), "function return value") ]), ]) test3 = [item for item in parse_origin(teststr, ["advance_iop_forcing"]).items()] self.assertEqual(test3, [ ('advance_iop_forcing', [ - ('plev', 'integer', 'in', None), - ('pcnst', 'integer', 'in', None), - ('scm_dt', 'real', 'in', None), - ('ps_in', 'real', 'in', None), - ('u_in', 'real', 'in', ('plev',)), - ('v_in', 'real', 'in', ('plev',)), - ('t_in', 'real', 'in', ('plev',)), - ('q_in', 'real', 'in', ('plev', 'pcnst')), - ('t_phys_frc', 'real', 'in', ('plev',)), - ('u_update', 'real', 'out', ('plev',)), - ('v_update', 'real', 'out', ('plev',)), - ('t_update', 'real', 'out', ('plev',)), - ('q_update', 'real', 'out', ('plev', 'pcnst')) + ('plev', 'integer', 'in', None, None), + ('pcnst', 'integer', 'in', None, None), + ('scm_dt', 'real', 'in', None, 'model time step [s]'), + ('ps_in', 'real', 'in', None, 'surface pressure [Pa]'), + ('u_in', 'real', 'in', ('plev',), 'zonal wind [m/s]'), + ('v_in', 'real', 'in', ('plev',), 'meridional wind [m/s]'), + ('t_in', 'real', 'in', ('plev',), 'temperature [K]'), + ('q_in', 'real', 'in', ('plev', 'pcnst'), 'q tracer array [units vary]'), + ('t_phys_frc', 'real', 'in', ('plev',), 'temperature forcing from physics [K/s]'), + ('u_update', 'real', 'out', ('plev',), 'updated zonal wind [m/s]'), + ('v_update', 'real', 'out', ('plev',), 'updated meridional wind [m/s]'), + ('t_update', 'real', 'out', ('plev',), 'updated temperature [K]'), + ('q_update', 'real', 'out', ('plev', 'pcnst'), 'updated q tracer array [units vary]') ]), ]) test4 = [item for item in parse_origin(teststr, ["iop_setinitial"]).items()] - self.assertEqual(test4, [('iop_setinitial', [('elem', 'type::element_t', 'inout', (':',))])]) + self.assertEqual(test4, [('iop_setinitial', [('elem', 'type::element_t', 'inout', (':',), None)])]) test5 = [item for item in parse_origin(teststr, ["fake_sub"]).items()] self.assertEqual(test5, [('fake_sub', UT_ARG_DATA)]) @@ -1189,7 +1199,7 @@ PTD_STD_DEF(DataSubName, 18, gag1, gag2, foo1, foo2, bit1, bit2, gal1, gal2, bar // Outputs Int& bab2, // Inputs - const bool& val, + const bool& val, // Lone val comment const bool& vals, const Int& nlev, const Int& nlevi, @@ -1237,7 +1247,7 @@ void Functions::fake_sub( // Outputs Int& bab2, // Inputs - const bool& val, + const bool& val, // Lone val comment const bool& vals, const Int& nlev, const Int& nlevi, From eb74489e4bb65ec216138517d6b7a37225af06cd Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 16 Jan 2026 15:55:15 -0800 Subject: [PATCH 352/398] update HOMME2SCRIP.py --- .../homme/test/tool/python/HOMME2SCRIP.py | 94 ++++++++++++------- 1 file changed, 58 insertions(+), 36 deletions(-) diff --git a/components/homme/test/tool/python/HOMME2SCRIP.py b/components/homme/test/tool/python/HOMME2SCRIP.py index 3c85a0091a7f..9aebe247df1f 100644 --- a/components/homme/test/tool/python/HOMME2SCRIP.py +++ b/components/homme/test/tool/python/HOMME2SCRIP.py @@ -7,14 +7,26 @@ Created May, 2025 by Walter Hannah (LLNL) ''' #--------------------------------------------------------------------------------------------------- -import datetime, os, numpy as np, xarray as xr +import datetime, os, numpy as np, xarray as xr, numba user, host = os.getenv('USER'), os.getenv('HOST') source_code_meta = 'HOMME2SCRIP.py' output_netcdf_type = 'NETCDF3_64BIT_DATA' +from time import perf_counter +enable_timers = True +# ------------------------------------------------------------------------------ +class tclr: END,GREEN,YELLOW,MAGENTA,CYAN='\033[0m','\033[32m','\033[33m','\033[35m','\033[36m' #--------------------------------------------------------------------------------------------------- class clr:END,RED,GREEN,MAGENTA,CYAN = '\033[0m','\033[31m','\033[32m','\033[35m','\033[36m' #--------------------------------------------------------------------------------------------------- verbose_indent = ' '*2 +# ------------------------------------------------------------------------------ +def print_timer(timer_start,description='',indent=None): + global verbose_indent + if indent is None: indent = verbose_indent + etime = perf_counter()-timer_start + time_str = f'{etime:10.1f} sec' + if etime>60: time_str += f' ({(etime/60):4.1f} min)' + print(f'\n{indent}{tclr.YELLOW}{description:40} elapsed time: {time_str}{tclr.END}') #--------------------------------------------------------------------------------------------------- usage = ''' python HOMME2SCRIP.py -i @@ -49,6 +61,7 @@ class clr:END,RED,GREEN,MAGENTA,CYAN = '\033[0m','\033[31m','\033[32m','\033[35m (opts, args) = parser.parse_args() #--------------------------------------------------------------------------------------------------- def main(): + if enable_timers: timer_start_all = perf_counter() #------------------------------------------------------------------------------- # check for valid input arguments if opts.src_file is None: raise ValueError(f'{clr.RED}src_file argument was not specified{clr.END}') @@ -63,7 +76,7 @@ def main(): #----------------------------------------------------------------------------- # open input file as dataset - ds = xr.open_dataset(opts.src_file) + ds = xr.open_dataset(opts.src_file,decode_timedelta=True) #----------------------------------------------------------------------------- # check for variables we need @@ -108,6 +121,8 @@ def main(): #----------------------------------------------------------------------------- # Create output dataset + if enable_timers: timer_start = perf_counter() + ds_out = ds.rename({'ncol' :'grid_size',\ 'area' :'grid_area',\ 'lev' :'grid_corners',\ @@ -125,51 +140,53 @@ def main(): ds_out['grid_corner_lat'] = ds_out['grid_corner_lat'].assign_attrs(units='degrees') ds_out['grid_corner_lon'] = ds_out['grid_corner_lon'].assign_attrs(units='degrees') + #----------------------------------------------------------------------------- + # transpose grid data for v in ds_out.variables: if 'grid_corners' in ds_out[v].dims: ds_out[v] = ds_out[v].transpose('grid_size','grid_corners',missing_dims='ignore') - ds_out.load() - #----------------------------------------------------------------------------- - def print_corners(lat,lon,num_corners): - for c in range(num_corners): - print(verbose_indent+(' '*6)+f'corner {c} lat/lon: {lat[c]:8.4f} {lon[c]:8.4f}') - return + if enable_timers: print_timer(timer_start,description='create output dataset') #----------------------------------------------------------------------------- - def swap_corners(ds,i): - # 1 2 3 4 -> 1 4 3 2 swap pos 1,3 - tmp_grid_corner_lon = ds.grid_corner_lon[i,:].copy(deep=True) - tmp_grid_corner_lat = ds.grid_corner_lat[i,:].copy(deep=True) - ds.grid_corner_lon[i,1] = tmp_grid_corner_lon[3] - ds.grid_corner_lon[i,3] = tmp_grid_corner_lon[1] - ds.grid_corner_lat[i,1] = tmp_grid_corner_lat[3] - ds.grid_corner_lat[i,3] = tmp_grid_corner_lat[1] - return - + @numba.njit() + def pole_corner_check(ncol,center_lat,center_lon,corner_lat,corner_lon): + num_modified = 0 + for i in range(ncol): + pole_dist = np.absolute( 90 - np.absolute( center_lat[i] ) ) + if ( pole_dist < 1e-9 ): + # 1 2 3 4 -> 1 4 3 2 swap pos 1,3 + tmp_corner_lon = corner_lon[i,:] + tmp_corner_lat = corner_lat[i,:] + corner_lon[i,1] = tmp_corner_lon[3] + corner_lon[i,3] = tmp_corner_lon[1] + corner_lat[i,1] = tmp_corner_lat[3] + corner_lat[i,3] = tmp_corner_lat[1] + num_modified += 1 + return num_modified #----------------------------------------------------------------------------- # Fix orientation at pole points print() print(verbose_indent+f'{clr.GREEN}Checking pole coordinates...{clr.END}') - for i in range(len(ds_out['grid_size'])): - abs_lat = np.absolute( ds_out.grid_center_lat[i].values ) - pole_dist = np.absolute( 90 - abs_lat ) - if ( pole_dist < 1e-9 ): - print() - print(verbose_indent+(' '*2)+f'{clr.GREEN}Pole point identified:{clr.END}') - print(verbose_indent+(' '*4)+f'i :{i:12}') - print(verbose_indent+(' '*4)+f'center lat/lon: {ds_out.grid_center_lat[i].values:8.4f} / {ds_out.grid_center_lon[i].values:8.4f}') - - print(verbose_indent+(' '*4)+f'Original corner indices:') - print_corners( ds_out.grid_corner_lat[i,:].values, ds_out.grid_corner_lon[i,:].values, num_corners ) - - print(verbose_indent+(' '*4)+f'Swapping corner indices 1 & 3...') - swap_corners(ds_out,i) - - print(verbose_indent+(' '*4)+f'Modified corner indices:') - print_corners( ds_out.grid_corner_lat[i,:].values, ds_out.grid_corner_lon[i,:].values, num_corners ) + if enable_timers: timer_start = perf_counter() + + tmp_ncol = len(ds_out['grid_size'].values) + tmp_center_lat = ds_out['grid_center_lat'].values + tmp_center_lon = ds_out['grid_center_lon'].values + tmp_corner_lat = ds_out['grid_corner_lat'].values + tmp_corner_lon = ds_out['grid_corner_lon'].values + + num_modified = pole_corner_check(tmp_ncol,tmp_center_lat,tmp_center_lon,tmp_corner_lat,tmp_corner_lon) + + if num_modified>0: + print(verbose_indent+(' '*2)+f'{clr.GREEN}{num_modified} pole point modified{clr.END}') + else: + print(verbose_indent+(' '*2)+f'No pole points modified') + + if enable_timers: print_timer(timer_start,description='pole check') + #----------------------------------------------------------------------------- # add imask and grid_dims to output datasest ds_out['grid_imask'] = xr.ones_like(ds_out['grid_size'],dtype=int) @@ -189,13 +206,18 @@ def swap_corners(ds,i): print() print(verbose_indent+f'{clr.GREEN}Writing output grid data...{clr.END}') + if enable_timers: timer_start = perf_counter() + ds_out.to_netcdf(path=opts.dst_file, mode='w', format=output_netcdf_type) + if enable_timers: print_timer(timer_start,description='write to file') + #----------------------------------------------------------------------------- # final print statements print() print(verbose_indent+f'{clr.GREEN}Successfully created file:{clr.END} {opts.dst_file}') - print() + + if enable_timers: print_timer(timer_start_all,description='total time') #--------------------------------------------------------------------------------------------------- if __name__ == '__main__': From 577844701399b2eee2d9f6dff3463dc04557a6f3 Mon Sep 17 00:00:00 2001 From: Mark Taylor Date: Fri, 16 Jan 2026 05:19:51 -0800 Subject: [PATCH 353/398] add HOMME2META.py (python version) HOMME2SCRIP.py: fix two bugs in variable metadata template.job: update namelist to demonstrate how to change output filename [BFB] Update components/homme/test/tool/template.job Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/python/HOMME2META.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/template.job Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/python/HOMME2META.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/python/HOMME2META.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/python/HOMME2SCRIP.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/python/HOMME2META.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update components/homme/test/tool/python/HOMME2META.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> typo in comments --- components/homme/test/tool/ncl/HOMME2META.ncl | 8 +- .../homme/test/tool/ncl/HOMME2SCRIP.ncl | 8 +- .../homme/test/tool/python/HOMME2META.py | 110 ++++++++++++++++++ .../homme/test/tool/python/HOMME2SCRIP.py | 8 +- components/homme/test/tool/template.job | 73 +++++++++--- 5 files changed, 178 insertions(+), 29 deletions(-) create mode 100644 components/homme/test/tool/python/HOMME2META.py diff --git a/components/homme/test/tool/ncl/HOMME2META.ncl b/components/homme/test/tool/ncl/HOMME2META.ncl index 9385b218f8fc..7915ff1464c0 100644 --- a/components/homme/test/tool/ncl/HOMME2META.ncl +++ b/components/homme/test/tool/ncl/HOMME2META.ncl @@ -14,17 +14,15 @@ if (.not. isvar("np")) then print("NPTS not specified on command line. Using default 4.") end if -template = name + "_tmp.nc" +template = name + "_tmp1.nc" output = name + "_latlon.nc" system("rm -f "+output) print("input: "+template+" output:"+output) fin = addfile(template,"r") ; -if (ne .gt. 512) then - setfileoption("nc","Format","NetCDF4") - ;setfileoption("nc","Format","NetCDF4Classic") -end if +setfileoption("nc","Format","NetCDF4") +;setfileoption("nc","Format","NetCDF4Classic") fout = addfile(output,"c") ; grid_size = dimsizes(fin->lat) diff --git a/components/homme/test/tool/ncl/HOMME2SCRIP.ncl b/components/homme/test/tool/ncl/HOMME2SCRIP.ncl index 7f03dafb5968..ecddd7855b72 100644 --- a/components/homme/test/tool/ncl/HOMME2SCRIP.ncl +++ b/components/homme/test/tool/ncl/HOMME2SCRIP.ncl @@ -13,16 +13,14 @@ if (.not. isvar("np")) then print("NPTS not specified on command line. Using default 4.") end if -template = name + "_tmp.nc" +template = name + "_tmp1.nc" output = name + "_scrip.nc" system("rm -f "+output) print("input: "+template+" output:"+output) fin = addfile(template,"r") ; -if (ne .gt. 512) then - setfileoption("nc","Format","NetCDF4") -end if +setfileoption("nc","Format","NetCDF4") fout = addfile(output,"c") ; grid_size = dimsizes(fin->lat) @@ -104,7 +102,7 @@ if (grid_corners .gt. 0) then end do end if -grid_imask = new ( (/grid_size/), "double") +grid_imask = new ( (/grid_size/), "integer") grid_imask = 1 grid_imask!0 = "grid_size" diff --git a/components/homme/test/tool/python/HOMME2META.py b/components/homme/test/tool/python/HOMME2META.py new file mode 100644 index 000000000000..ea006902a958 --- /dev/null +++ b/components/homme/test/tool/python/HOMME2META.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +import os +import xarray as xr +import datetime +user, host = os.getenv('USER'), os.getenv('HOST') +source_code_meta = 'HOMME2META.py' +output_netcdf_type = 'NETCDF3_64BIT_DATA' +#--------------------------------------------------------------------------------------------------- +class clr:END,RED,GREEN,MAGENTA,CYAN = '\033[0m','\033[31m','\033[32m','\033[35m','\033[36m' +#--------------------------------------------------------------------------------------------------- +verbose_indent = ' '*2 +#--------------------------------------------------------------------------------------------------- +usage = ''' +python HOMME2META.py --src_file --dst_file + +Purpose: + This script reads a HOMME grid template file and writes out a "latlon" format grid + description file of the np4/GLL grid. The output file contains a list of all the + unique GLL nodes (no duplicate degrees of freedom) and their subcell connectivity + (dividing each spectral element into a (np-1) x (np-1) subcells with GLL nodes as their corners) + + This "latlon" template file can be used by plotting programs to plot GLL vertex + data from the dycore (as opposed to the PG2 finite volume cell centered data from the physics) + It is also used by the MOAB disk averaging remapping algorithm. + +Environment + + This requires libraries such as xarray, which included in the E3SM unified environment: + https://e3sm.org/resources/tools/other-tools/e3sm-unified-environment/ + + Otherwise a simple conda environment can be created: + conda create --name example_env --channel conda-forge xarray numpy netcdf4 + +''' +from optparse import OptionParser +parser = OptionParser(usage=usage) +parser.add_option('--src_file', + dest='src_file', + default=None, + help='Input HOMME grid template file') +parser.add_option('--dst_file', + dest='dst_file', + default=None, + help='Output scrip grid file') +(opts, args) = parser.parse_args() + + +def main(): + #------------------------------------------------------------------------------- + # check for valid input arguments + if opts.src_file is None: raise ValueError(f'{clr.RED}src_file argument was not specified{clr.END}') + if opts.dst_file is None: raise ValueError(f'{clr.RED}dst_file argument was not specified{clr.END}') + + #----------------------------------------------------------------------------- + # print some informative stuff + print() + print(verbose_indent+f'{clr.GREEN}Input arguments:{clr.END}') + print(verbose_indent+f' {clr.CYAN}src_file{clr.END}: {opts.src_file}') + print(verbose_indent+f' {clr.CYAN}dst_file{clr.END}: {opts.dst_file}') + + #----------------------------------------------------------------------------- + # open input file as dataset + ds_in = xr.open_dataset(opts.src_file) + + + # Remove existing output if it exists + if os.path.exists(opts.dst_file): + os.remove(opts.dst_file) + + + # Compute grid size + lat = ds_in["lat"] + print(f"grid_size = {lat.size}") + + # Print lon/lat min/max + lon = ds_in["lon"] + print(f"lon min/max = {float(lon.min())} {float(lon.max())}") + print(f"lat min/max = {float(lat.min())} {float(lat.max())}") + + # Check for corners variable and slice first 4 rows + print("reading corners...") + corners_var = ds_in["corners"].values[0:4, :] # only first 4 rows + corners_int = corners_var.astype(int) + + # Prepare output dataset + print("opening dataset...") + ds_out = xr.Dataset() + + # Copy variables lat, lon, area + ds_out["area"] = ds_in["area"] + ds_out["lat"] = ds_in["lat"] # (("ncol"),ds_in["lat"]) + ds_out["lon"] = ds_in["lon"] # (("ncol"),ds_in["lon"].values) + # element_corners has 4 corners per cell; use "ncorners" and "ncells" as dimension names + ds_out["element_corners"] = (("ncorners","ncells"), corners_int) + + # Global attributes + ds_out.attrs = ds_in.attrs.copy() + ds_out.attrs['title'] = 'HOMME generated GLL grid data, latlon format' + ds_out.attrs['hostname'] = str(host) + ds_out.attrs['history'] = f'created by {user}, '+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ds_out.attrs['src_file'] = opts.src_file + ds_out.attrs['source_code'] = source_code_meta + + # Write to netCDF using the specified format + print("writing dataset...") + ds_out.to_netcdf(opts.dst_file, format=output_netcdf_type) + print(f"Wrote output file: {opts.dst_file} with format {output_netcdf_type}") + +if __name__ == "__main__": + main() diff --git a/components/homme/test/tool/python/HOMME2SCRIP.py b/components/homme/test/tool/python/HOMME2SCRIP.py index 9aebe247df1f..549232b5ca28 100644 --- a/components/homme/test/tool/python/HOMME2SCRIP.py +++ b/components/homme/test/tool/python/HOMME2SCRIP.py @@ -132,6 +132,7 @@ def main(): 'cv_lon':'grid_corner_lon',\ }).isel(grid_corners=slice(0,num_corners)) + ds_out['grid_area'] = ds_out['grid_area'].assign_attrs(units='radians^2') ds_out['grid_area'] = ds_out['grid_area'].assign_attrs(long_name='area weights') @@ -145,6 +146,10 @@ def main(): for v in ds_out.variables: if 'grid_corners' in ds_out[v].dims: ds_out[v] = ds_out[v].transpose('grid_size','grid_corners',missing_dims='ignore') + + # remove the grid_corners variable: + del ds_out['grid_corners'] + ds_out.load() if enable_timers: print_timer(timer_start,description='create output dataset') @@ -190,7 +195,8 @@ def pole_corner_check(ncol,center_lat,center_lon,corner_lat,corner_lon): #----------------------------------------------------------------------------- # add imask and grid_dims to output datasest ds_out['grid_imask'] = xr.ones_like(ds_out['grid_size'],dtype=int) - ds_out['grid_dims'] = xr.DataArray([len(ds_out['grid_imask'])],dims=['grid_rank']) + # HOMME grids are always 1D unstructured: + ds_out['grid_dims'] = xr.DataArray([1],dims=['grid_rank']) #----------------------------------------------------------------------------- # add global attributes diff --git a/components/homme/test/tool/template.job b/components/homme/test/tool/template.job index 0f8ca01512cc..d973caaa98e2 100755 --- a/components/homme/test/tool/template.job +++ b/components/homme/test/tool/template.job @@ -3,23 +3,54 @@ # script to show how to run various HOMME tools # # Generate NP4 scrip and subcell files +# +# For internal grids (NE>0) run 1 MPI task per core +# PM-CPU only 1 node needed up to NE512. 4 nodes needed for NE1024 +# +# RRM grids: non-memory scalable startup +# Need to use large -c values to get through GridVertex/GridEdge allocation, +# and large node counts to have sufficient memory for elem() allocation +# PM-CPU: 33M element RRM grid requires 128 nodes with -c 32 +# +# +# sbatch -q debug -N 4 -C cpu temp.job +# sbatch -q regular -t 10:00 -N 16 -C cpu temp.job # set TOOLDIR = `pwd` set WDIR = ~/scratch1/hommetool -set MACH = $TOOLDIR/../../cmake/machineFiles/darwin.cmake +set MACH = $TOOLDIR/../../cmake/machineFiles/pm-cpu.cmake set exe = $WDIR/src/tool/homme_tool -set NE=1024 +# internal cubed-sphere grids +set NE=30 +set mesh_file="none" # filepath and name to exodus .g file +set mesh_prefix="" # prefix to add to output filename + +# RRM grids +#set NE=0 +#set mesh_name = "2025-scream-conus-1024x2" +#set mesh_name = "2026-incite-conus-1024x3" +#set mesh_name = "2026-incite-conus-1024x4" +#set mesh_file = "/global/cfs/cdirs/e3sm/2026-INCITE-CONUS-RRM/files_grid/${mesh_name}.g" +#set mesh_name = "TEMPEST_NE30" +#set mesh_file = "/global/cfs/cdirs/e3sm/taylorm/mapping/grids/${mesh_name}.g" +#set mesh_prefix = ${mesh_name}- + + +# output filename will be ${mesh}-tmp1.nc: set NPTS=4 # be sure to rerun CMAKE if this is changed -set mesh = ne${NE}np${NPTS} +set mesh = ${mesh_prefix}ne${NE}np${NPTS} + cd $WDIR if (! -x $exe ) then - # configure set output = `$TOOLDIR/../../../../cime/CIME/Tools/get_case_env` - eval $output - cmake -C $MACH -DPREQX_NP=$NPTS -DPREQX_PLEV=26 $TOOLDIR/../.. - # compile the tool + #configure + #set output = `$TOOLDIR/../../../../cime/CIME/Tools/get_case_env` + #eval $output + cmake -C $MACH -DPREQX_NP=$NPTS -DPREQX_PLEV=26 \ + $TOOLDIR/../.. + make -j4 homme_tool if ( $status ) then echo Error compiling homme_tool. Ensure cmake configured properly. @@ -27,7 +58,9 @@ if (! -x $exe ) then endif endif if ( ${?SLURM_NNODES} ) then - set mpirun = "srun -K -c 1 -N $SLURM_NNODES" + #set mpirun = "srun -K -c 2 -N $SLURM_NNODES" + #set mpirun = "srun -K -c 8 -N $SLURM_NNODES" + set mpirun = "srun -K -c 32 -N $SLURM_NNODES" else set mpirun = "mpirun -np 4" endif @@ -38,7 +71,7 @@ rm -f input.nl cat > input.nl < 2M element meshes io_stride = 16 / EOF -$mpirun $exe < input.nl +time $mpirun $exe < input.nl -# make the 'latlon' file -ncks -O -v lat,lon,corners,area ${mesh}_tmp1.nc ${mesh}_tmp.nc + + +# make the 'latlon' file and the scrip file: ncl $TOOLDIR/ncl/HOMME2META.ncl name=\"$mesh\" ne=$NE np=$NPTS +ncl $TOOLDIR/ncl/HOMME2SCRIP.ncl name=\"$mesh\" ne=$NE np=$NPTS + +# python code to make latlon and scrip file: +# 10x slower than NCL code and requires numpy and xarray: +#python $TOOLDIR/python/HOMME2META.py --src_file ${mesh}_tmp1.nc --dst_file ${mesh}_latlon_python.nc +#python $TOOLDIR/python/HOMME2SCRIP.py --src_file ${mesh}_tmp1.nc --dst_file ${mesh}_scrip_python.nc -# make the 'scrip' file -ncks -O -v lat,lon,area,cv_lat,cv_lon ${mesh}_tmp1.nc ${mesh}_tmp.nc -ncl $TOOLDIR/ncl/HOMME2SCRIP.ncl name=\"$mesh\" ne=$NE np=$NPTS -rm -f {$mesh}_tmp.nc {$mesh}_tmp1.nc # make some plots (ncl defaults to ne4np4 grid #ncl $TOOLDIR/ncl/plotscrip.ncl From 57b80b539eedfda26c8bd881f5b9102e40fed2ec Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 16 Jan 2026 08:07:19 -0700 Subject: [PATCH 354/398] Fix typo in HOMME2META.py documentation --- components/homme/test/tool/python/HOMME2META.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/homme/test/tool/python/HOMME2META.py b/components/homme/test/tool/python/HOMME2META.py index ea006902a958..4839b3a36cd0 100644 --- a/components/homme/test/tool/python/HOMME2META.py +++ b/components/homme/test/tool/python/HOMME2META.py @@ -25,7 +25,7 @@ class clr:END,RED,GREEN,MAGENTA,CYAN = '\033[0m','\033[31m','\033[32m','\033[35m Environment - This requires libraries such as xarray, which included in the E3SM unified environment: + This requires libraries such as xarray, which is included in the E3SM unified environment: https://e3sm.org/resources/tools/other-tools/e3sm-unified-environment/ Otherwise a simple conda environment can be created: From e9cb07d6a3fc8ca2693a5b668258c1e03659a9f6 Mon Sep 17 00:00:00 2001 From: Walter Hannah Date: Fri, 16 Jan 2026 08:08:38 -0700 Subject: [PATCH 355/398] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/homme/test/tool/python/HOMME2META.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/homme/test/tool/python/HOMME2META.py b/components/homme/test/tool/python/HOMME2META.py index 4839b3a36cd0..6cd6d0e4d0ce 100644 --- a/components/homme/test/tool/python/HOMME2META.py +++ b/components/homme/test/tool/python/HOMME2META.py @@ -41,7 +41,7 @@ class clr:END,RED,GREEN,MAGENTA,CYAN = '\033[0m','\033[31m','\033[32m','\033[35m parser.add_option('--dst_file', dest='dst_file', default=None, - help='Output scrip grid file') + help='Output latlon grid file') (opts, args) = parser.parse_args() From cbcbc09555c1656bd61025683da230dc0e8d644d Mon Sep 17 00:00:00 2001 From: Mark Taylor Date: Sat, 17 Jan 2026 09:50:31 -0800 Subject: [PATCH 356/398] switch HOMME2SCRIP and META to python versions --- components/homme/test/tool/template.job | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/homme/test/tool/template.job b/components/homme/test/tool/template.job index d973caaa98e2..a177e640ff3f 100755 --- a/components/homme/test/tool/template.job +++ b/components/homme/test/tool/template.job @@ -97,13 +97,13 @@ time $mpirun $exe < input.nl # make the 'latlon' file and the scrip file: -ncl $TOOLDIR/ncl/HOMME2META.ncl name=\"$mesh\" ne=$NE np=$NPTS -ncl $TOOLDIR/ncl/HOMME2SCRIP.ncl name=\"$mesh\" ne=$NE np=$NPTS +#ncl $TOOLDIR/ncl/HOMME2META.ncl name=\"$mesh\" ne=$NE np=$NPTS +#ncl $TOOLDIR/ncl/HOMME2SCRIP.ncl name=\"$mesh\" ne=$NE np=$NPTS # python code to make latlon and scrip file: -# 10x slower than NCL code and requires numpy and xarray: -#python $TOOLDIR/python/HOMME2META.py --src_file ${mesh}_tmp1.nc --dst_file ${mesh}_latlon_python.nc -#python $TOOLDIR/python/HOMME2SCRIP.py --src_file ${mesh}_tmp1.nc --dst_file ${mesh}_scrip_python.nc +# needs numpy, xarray and numba: +python $TOOLDIR/python/HOMME2META.py --src_file ${mesh}_tmp1.nc --dst_file ${mesh}_latlon_python.nc +python $TOOLDIR/python/HOMME2SCRIP.py --src_file ${mesh}_tmp1.nc --dst_file ${mesh}_scrip_python.nc # make some plots (ncl defaults to ne4np4 grid From d8dbb777ae64894b78a342c2ecd5b1cf35538a8c Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Sat, 17 Jan 2026 20:28:04 -0600 Subject: [PATCH 357/398] Add mkl module --- cime_config/machines/config_machines.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 90d33d0b041a..a6ad54170552 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -2668,6 +2668,7 @@ openmpi/4.1.8-nygtpa3 + intel-oneapi-mkl/2025.2.0-bcimxay hdf5/1.14.6-5cgownf netcdf-c/4.9.3-mekqsor netcdf-fortran/4.6.2-cjqpiwp @@ -2718,9 +2719,6 @@ $SHELL{if [ -z "$SZ_ROOT" ]; then echo /lcrc/soft/climate/sz/2.1.12.5/gcc-11.2.0; else echo "$SZ_ROOT"; fi} $SHELL{if [ -z "$ZFP_ROOT" ]; then echo /lcrc/soft/climate/zfp/1.0.1/gcc-11.2.0; else echo "$ZFP_ROOT"; fi} - - $ENV{NETCDF_FORTRAN_PATH}/lib:$ENV{NETCDF_C_PATH}/lib:/gpfs/fs1/soft/chrysalis/spack-latest/opt/spack/linux-rhel8-x86_64/gcc-8.5.0/gcc-11.3.0-jkpmtgq/lib64:$ENV{LD_LIBRARY_PATH} - From e6c9dc4e5ac24e8059694b61a4e74a7acebce2d0 Mon Sep 17 00:00:00 2001 From: Mark Taylor Date: Mon, 19 Jan 2026 05:17:07 -0800 Subject: [PATCH 358/398] fix homme_tool netcdf/pnetcdf seleciton for reading files --- .../homme/src/interpolate_driver_mod.F90 | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/components/homme/src/interpolate_driver_mod.F90 b/components/homme/src/interpolate_driver_mod.F90 index fda01d71ed47..14f14cb39887 100644 --- a/components/homme/src/interpolate_driver_mod.F90 +++ b/components/homme/src/interpolate_driver_mod.F90 @@ -176,7 +176,7 @@ subroutine infile_initialize(elem, par, infilename, varnames, infile) type(io_desc_t), pointer :: iodesc character(len=80), allocatable :: varnames_list(:) - integer :: ndims, nvars, varcnt + integer :: ndims, nvars, varcnt, iotype integer :: ret, i, ncid, n integer :: varid, ncols, lev integer :: ne_file, np_file, nlev_file @@ -188,13 +188,9 @@ subroutine infile_initialize(elem, par, infilename, varnames, infile) if (par%masterproc) print *,'initializing input file: ',trim(infilename) -! call pio_setdebuglevel(1) - if(output_type.eq.'netcdf') then - ret = PIO_OpenFile(PIOFS, InFile%FileID, iotype_netcdf, infilename) - else - ret = PIO_OpenFile(PIOFS, InFile%FileID, iotype_pnetcdf, infilename) - end if - + ! call pio_setdebuglevel(1) + iotype = get_iotype() + ret = PIO_OpenFile(PIOFS, InFile%FileID, iotype, infilename) ret = PIO_inquire(InFile%FileID, nDimensions=ndims, nVariables=nvars, & nAttributes=infile%natts, unlimitedDimId=InFile%unlimid) @@ -1562,12 +1558,22 @@ end subroutine write_physgrid_smoothed_phis_file #ifndef HOMME_WITHOUT_PIOLIBRARY function get_iotype() result(iotype) - use pio, only: iotype_netcdf, iotype_pnetcdf + ! used when opening a file + ! need to pick between netcdf and pnetcdf options + ! netcdf4 can read all formats + ! pnetcdf cant read the newest netcdf4/hdf formats + + use pio, only: iotype_netcdf, iotype_pnetcdf, pio_iotype_netcdf4p,& + pio_iotype_netcdf4p_nczarr, pio_iotype_netcdf4c,pio_iotype_pnetcdf,pio_iotype_netcdf integer :: iotype if (output_type == 'netcdf') then + iotype = iotype_netcdf ! default + else if (output_type == 'netcdf4p') then iotype = iotype_netcdf + else if (output_type == 'netcdf64') then + iotype = iotype_pnetcdf else iotype = iotype_pnetcdf end if From 240d49d5648b13db3ff6bec350ec9c2c181a13c8 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 19 Jan 2026 11:10:55 -0700 Subject: [PATCH 359/398] EAMxx: remove commented code --- components/eamxx/src/share/remap/coarsening_remapper.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/eamxx/src/share/remap/coarsening_remapper.cpp b/components/eamxx/src/share/remap/coarsening_remapper.cpp index 9234d65c1e4d..27ffb5f830ba 100644 --- a/components/eamxx/src/share/remap/coarsening_remapper.cpp +++ b/components/eamxx/src/share/remap/coarsening_remapper.cpp @@ -1169,15 +1169,12 @@ void CoarseningRemapper::setup_latlon_coarse_grid(const std::string& map_file) auto nondim = ekat::units::Units::nondimensional(); ekat::units::Units deg(nondim,"degrees"); + // Declare lat/lon and read them from the map file. + // WARNING: the vars/dims names are different from what eamxx uses auto pt_lat = m_coarse_grid->create_geometry_data("lat",m_coarse_grid->get_2d_scalar_layout(),deg); auto pt_lon = m_coarse_grid->create_geometry_data("lon",m_coarse_grid->get_2d_scalar_layout(),deg); - // Read lat/lon from the map file. Be careful cause the vars/dims names are different from what eamxx uses m_coarse_grid->read_geometry_data(map_file,{"lat","lon"},{"yc_b","xc_b"},{{"ncol","n_b"}}); - // // We will NOT save the ncol version of lat/lon, but only the (lat) and (lon) 1d arrays - // pt_lat.get_header().set_extra_data("save_as_geo_data",false); - // pt_lon.get_header().set_extra_data("save_as_geo_data",false); - RealsClose cmp; std::set my_lats(cmp), my_lons(cmp); From 92c9a491826ee57552026fdeaccbc154a7925ce8 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Mon, 19 Jan 2026 11:50:46 -0700 Subject: [PATCH 360/398] EAMxx: add latlon output to eamxx-prod testmod --- .../testmods_dirs/eamxx/prod/shell_commands | 46 +++++++++++-------- ...mxx_output.decadal.1hourlyINST_latlon.yaml | 39 ++++++++++++++++ 2 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands index 44835fe52787..b511d3a18880 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands @@ -47,10 +47,12 @@ atm_grid=$(./xmlquery --value ATM_GRID) if [[ "${atm_grid}" = "ne30np4.pg2" ]]; then hmapfile="${input_data_dir}/atm/scream/maps/map_ne30pg2_to_ne4pg2_20231201.nc" armmapfile="${input_data_dir}/atm/scream/maps/map_ne30pg2_to_DecadalSites_c20240130.nc" + latlonmapfile="${input_data_dir}/atm/scream/maps/map_ne30pg2_to_20x40_20260112.nc" # Run with bugfixed SPA file $atmchange -b spa_data_file="${input_data_dir}/atm/scream/init/spa_v3.LR.F2010.2011-2025.c_20240405.nc" elif [[ "${atm_grid}" = "ne4np4.pg2" ]]; then hmapfile="${input_data_dir}/atm/scream/maps/map_ne4pg2_to_ne2pg2_c20240902.nc" + latlonmapfile="${input_data_dir}/atm/scream/maps/map_ne4pg2_to_10x20_20260112.nc" echo "Note: arm remap only works for ne30pg2 atm grids for now" armmapfile="not-supported-yet" # Keep default SPA file @@ -63,27 +65,33 @@ fi # set the output yaml files output_yaml_files=$(find ${cime_root}/../components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/ -maxdepth 1 -type f) +$atmchange -b output_yaml_files="" for file in ${output_yaml_files[@]}; do - # if the word "coarse" is in the file name, do nothing - if [[ "${file}" == *"_coarse.yaml" && "${hmapfile}" == "not-supported-yet" ]]; then - continue - elif [[ "${file}" == *"_arm.yaml" && "${armmapfile}" == "not-supported-yet" ]]; then - continue - else - # TODO: add remap file replacement for different grids - cp -v ${file} ./ - if [ "${file}" == "${output_yaml_files[0]}" ]; then - # First file, reset output list - $atmchange -b output_yaml_files="./$(basename ${file})" - else - # Append to output list - $atmchange -b output_yaml_files+="./$(basename ${file})" - fi - # Replace remap files - sed -i "s|horiz_remap_file:.*_to_ne30.*|horiz_remap_file: ${hmapfile}|" ./$(basename ${file}) - sed -i "s|horiz_remap_file:.*_to_DecadalSites.*|horiz_remap_file: ${armmapfile}|" ./$(basename ${file}) + # Grab the proper map file (if any) + mapfile="" + if [[ "${file}" == *"_coarse.yaml" ]]; then + mapfile=${hmapfile} + elif [[ "${file}" == *"_arm.yaml" ]]; then + mapfile=${armmapfile} + elif [[ "${file}" == *"_latlon.yaml" ]]; then + mapfile=${latlonmapfile} fi - # replace all filename prefixes so that st_archive works... + + # If remap is needed,but not supported for this res, skip this yaml + if [[ "${mapfile}" == "not-supported-yet" ]]; then + continue + fi + + # Copy yaml to case dir + cp -v ${file} ./ + + # Append to output list + $atmchange -b output_yaml_files+="./$(basename ${file})" + + # Replace horiz remap file + sed -i "s|horiz_remap_file:.*|horiz_remap_file: ${mapfile}|" ./$(basename ${file}) + + # Replace all filename prefixes so that st_archive works... sed -i "s|eamxx_output.decadal|${case_name}.scream|" ./$(basename ${file}) done diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml new file mode 100644 index 000000000000..9cfd6eb66faf --- /dev/null +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml @@ -0,0 +1,39 @@ +%YAML 1.1 +--- +filename_prefix: eamxx_output.decadal.1hourlyINST_latlon.h +iotype: pnetcdf +averaging_type: instant +max_snapshots_per_file: 1 # only one snapshot per file +horiz_remap_file: ${TESTMOD_WILL_EDIT_THIS_LINE_VIA_SED} +fields: + physics_pg2: + field_names: + # 3D + - T_mid + - RelativeHumidity + - qc + - qi + - qr + - qm + - ps + - cldfrac_tot_for_analysis + - cldfrac_liq + - cldfrac_ice_for_analysis + - omega + - tke + - eff_radius_qc + - eff_radius_qi + - nc + - ni + - nr + - bm + - p_mid + - z_mid + - U + - V + - landfrac +output_control: + frequency: 1 + frequency_units: nhours +restart: + force_new_file: true From 2f5684a05e24d0afdce1f4998f23888a1629820b Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 20 Jan 2026 08:56:21 -0700 Subject: [PATCH 361/398] EAMxx: append mach name to default work dir in test-all-scream Avoids overwriting results when 2+ machines are available on the same host (e.g., Perlmutter) --- components/eamxx/scripts/test_all_eamxx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/scripts/test_all_eamxx.py b/components/eamxx/scripts/test_all_eamxx.py index e3ccd5de914f..0870ef8ecea5 100644 --- a/components/eamxx/scripts/test_all_eamxx.py +++ b/components/eamxx/scripts/test_all_eamxx.py @@ -106,7 +106,7 @@ def __init__(self, cxx_compiler=None, f90_compiler=None, c_compiler=None, if self._work_dir is not None: self._work_dir = Path(self._work_dir).absolute() else: - self._work_dir = self._root_dir.absolute().joinpath("ctest-build") + self._work_dir = self._root_dir.absolute() / 'ctest-build' / self._machine.name self._work_dir.mkdir(parents=True, exist_ok=True) From e1c218a0d1335b81d277df6df91ba016beb9ad96 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 20 Jan 2026 10:19:08 -0700 Subject: [PATCH 362/398] EAMxx: adjust scripts-tests to test-all-scream mod --- components/eamxx/scripts/scripts-tests | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/eamxx/scripts/scripts-tests b/components/eamxx/scripts/scripts-tests index 63309d524f59..091907579a9c 100755 --- a/components/eamxx/scripts/scripts-tests +++ b/components/eamxx/scripts/scripts-tests @@ -33,7 +33,7 @@ CONFIG = { ############################################################################### def test_cmake_cache_contents(test_obj, build_name, cache_var, expected_value): ############################################################################### - cache_file = TEST_DIR.parent.joinpath("ctest-build", build_name, "CMakeCache.txt") + cache_file = TEST_DIR.parent / "ctest-build" / test_obj._machine.name / build_name / "CMakeCache.txt" test_obj.assertTrue(cache_file.is_file(), f"Missing cache file {cache_file}") # pylint: disable=no-member grep_output = run_cmd_assert_result(test_obj, f"grep ^{cache_var} CMakeCache.txt", from_dir=cache_file.parent) @@ -44,7 +44,7 @@ def test_cmake_cache_contents(test_obj, build_name, cache_var, expected_value): ############################################################################### def test_baseline_has_sha(test_obj, test_dir, build_name, expected_sha): ############################################################################### - baseline_sha_file = test_dir.parent/"ctest-build"/"baselines"/build_name/"baseline_git_sha" + baseline_sha_file = test_dir.parent/"ctest-build"/test_obj._machine.name/"baselines"/build_name/"baseline_git_sha" test_obj.assertTrue(baseline_sha_file.exists()) with baseline_sha_file.open("r", encoding="utf-8") as fd: baseline_sha = fd.read().strip() @@ -389,7 +389,7 @@ class TestTestAllScream(TestBaseOuter.TestBase): """ if self._full: - # Start a couple new tests, baselines will be generated in ctest-build/baselines + # Start a couple new tests, baselines will be generated in ctest-build/$machine/baselines env = "SCREAM_FAKE_ONLY=ON SCREAM_FAKE_GIT_HEAD=FAKE1" opts = "-b LOCAL -g -t dbg -t sp" cmd = self.get_cmd(f"{env} ./test-all-eamxx -m $machine {opts}", From 9d0549a1c1ad6ea98ef66d7a0192e0f57458cec4 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 20 Jan 2026 10:19:40 -0700 Subject: [PATCH 363/398] Workflows: adjust test-all-eamxx action paths for uploaded files --- .github/actions/test-all-eamxx/action.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/test-all-eamxx/action.yml b/.github/actions/test-all-eamxx/action.yml index 5c3a2a4a1da4..1d593c3ce279 100644 --- a/.github/actions/test-all-eamxx/action.yml +++ b/.github/actions/test-all-eamxx/action.yml @@ -135,8 +135,8 @@ runs: with: name: log-files-${{ inputs.build_type }}-${{ inputs.machine }} path: | - components/eamxx/ctest-build/*/Testing/Temporary/Last*.log - components/eamxx/ctest-build/*/ctest_resource_file.json - components/eamxx/ctest-build/*/CMakeCache.txt + components/eamxx/ctest-build/**/Testing/Temporary/Last*.log + components/eamxx/ctest-build/**/ctest_resource_file.json + components/eamxx/ctest-build/**/CMakeCache.txt env: NODE_EXTRA_CA_CERTS: ${{ env.NODE_EXTRA_CA_CERTS }} From 730cbba70980d8dde49a55ebd9045bccbfe3f521 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 20 Jan 2026 10:53:07 -0700 Subject: [PATCH 364/398] EAMxx: fix pylint errors in scripts-tests --- components/eamxx/scripts/scripts-tests | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/eamxx/scripts/scripts-tests b/components/eamxx/scripts/scripts-tests index 091907579a9c..711aedfebce2 100755 --- a/components/eamxx/scripts/scripts-tests +++ b/components/eamxx/scripts/scripts-tests @@ -33,7 +33,7 @@ CONFIG = { ############################################################################### def test_cmake_cache_contents(test_obj, build_name, cache_var, expected_value): ############################################################################### - cache_file = TEST_DIR.parent / "ctest-build" / test_obj._machine.name / build_name / "CMakeCache.txt" + cache_file = TEST_DIR.parent / "ctest-build" / test_obj.get_machine().name / build_name / "CMakeCache.txt" test_obj.assertTrue(cache_file.is_file(), f"Missing cache file {cache_file}") # pylint: disable=no-member grep_output = run_cmd_assert_result(test_obj, f"grep ^{cache_var} CMakeCache.txt", from_dir=cache_file.parent) @@ -44,7 +44,7 @@ def test_cmake_cache_contents(test_obj, build_name, cache_var, expected_value): ############################################################################### def test_baseline_has_sha(test_obj, test_dir, build_name, expected_sha): ############################################################################### - baseline_sha_file = test_dir.parent/"ctest-build"/test_obj._machine.name/"baselines"/build_name/"baseline_git_sha" + baseline_sha_file = test_dir.parent/"ctest-build"/test_obj.get_machine().name/"baselines"/build_name/"baseline_git_sha" test_obj.assertTrue(baseline_sha_file.exists()) with baseline_sha_file.open("r", encoding="utf-8") as fd: baseline_sha = fd.read().strip() @@ -125,6 +125,9 @@ class TestBaseOuter: # Hides the TestBase class from test scanner self._results = TEST_DIR.joinpath("results") self._results.mkdir(parents=True, exist_ok=True) # pylint: disable=no-member + def get_machine(self): + return self._machine + def get_cmd(self, cmd, machine): return cmd.replace("$machine", machine.name).replace("$results", str(self._results)) From 8f5d6e381662eb9935b1a49c153545546f42a01a Mon Sep 17 00:00:00 2001 From: Stephen Price Date: Tue, 20 Jan 2026 12:11:14 -0600 Subject: [PATCH 365/398] Update Greenland ice and liquid runoff mapping files For cases with high-resolution, dynamic Greenland ice sheet use 150e300 spreading functions for solid (ice) and liquid runoff. --- cime_config/config_grids.xml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cime_config/config_grids.xml b/cime_config/config_grids.xml index 36882ac9352a..d6910bba0a7b 100755 --- a/cime_config/config_grids.xml +++ b/cime_config/config_grids.xml @@ -6466,18 +6466,8 @@ cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_esmfaave.20240403.nc cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_esmfaave.20240403.nc cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_esmfaave.20240403.nc - - - /home/ac.sprice/temp/runoffSpreadingMaps/map_gis1to10kmR2_to_IcoswISC30E3r5_r50e100.cstmnn.20250326.nc - /home/ac.sprice/temp/runoffSpreadingMaps/map_gis1to10kmR2_to_IcoswISC30E3r5-nomask_r50e100.cstmnn.20250403.nc - - - + cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5_r150e300.cstmnn.20250326.nc + cpl/gridmaps/mpas.gis1to10km/map_gis1to10kmR2_to_IcoswISC30E3r5-nomask_r150e300.cstmnn.20250403.nc From 047a0c7ca9dba71a6f04dc701fa6d9b2102a1f26 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Tue, 20 Jan 2026 14:35:27 -0700 Subject: [PATCH 366/398] EAMxx: fix checks in the creation of PIO decompositions --- .../src/share/io/tests/check_latlon_output.py | 4 +- .../eamxx_scorpio_interface.cpp | 93 ++++++++++++------- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/components/eamxx/src/share/io/tests/check_latlon_output.py b/components/eamxx/src/share/io/tests/check_latlon_output.py index ceb6615e36a4..90190dee1d4c 100755 --- a/components/eamxx/src/share/io/tests/check_latlon_output.py +++ b/components/eamxx/src/share/io/tests/check_latlon_output.py @@ -48,8 +48,8 @@ def check_latlon_output(map_file,out_file,mask_cols): xc_b = map_ds.variables['xc_b'][:] # Read xc_b variable # Reshape yc_b and xc_b to match the layout of f_lat and f_lon - nlat = f_lat.shape[1] # Get the 2nd dim, as the 1st one is time - nlon = f_lat.shape[2] # Get the 2nd dim, as the 1st one is time + nlat = f_lat.shape[1] # nlat is the 2nd dim, as the 1st one is time + nlon = f_lat.shape[2] # nlon is the 3nd dim, as the 1st one is time yc_b = yc_b.reshape(nlat,nlon) xc_b = xc_b.reshape(nlat,nlon) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index 3cab884d7658..f671a35d6a80 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -748,24 +748,37 @@ void set_var_decomp (PIOVar& var, " - varname : " + var.name + "\n" " - var decomp: " + var.decomp->name + "\n"); - // First, check if this var actually needs a decomp + // First, check which dims are decomposed (if any). Check that different dims + // agree on what kind of decomp this should be. E.g., do NOT allow N dims that + // were not decomposed as part of a joint rank-N decomposition int ndims = var.dims.size(); - int decomp_rank = 0; - int num_decomp = 0; - int last_decomp = -1; + std::set decomp_ranks; + int last_decomp = 0; + std::vector decomposed_dims; for (int idim=0; idimdecomp_rank>0) { - decomp_rank = d->decomp_rank; - ++num_decomp; + decomposed_dims.push_back(d->name); + decomp_ranks.insert(d->decomp_rank); last_decomp = idim; } } - if (decomp_rank==0) { + + int num_decomp = decomposed_dims.size(); + if (num_decomp==0) { // None of the var dims is decomposed return; } + + EKAT_REQUIRE_MSG (decomp_ranks.size()==1, + "Error! We cannot decomposed this variable, as it contained multiple decomposed dims that were not decompsed together.\n" + " - filename: " + filename + "\n" + " - varname : " + var.name + "\n" + " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" + " - decomp dims: " + ekat::join(decomposed_dims,",") + "\n"); + + int decomp_rank = *decomp_ranks.begin(); if (num_decomp_dim2_..._dimk auto get_dimtag = [](const auto dim) { @@ -805,10 +828,14 @@ void set_var_decomp (PIOVar& var, if (s.decomps.count(decomp_tag)==0) { auto& f = s.files[filename]; - EKAT_REQUIRE_MSG (num_decomp>=decomp_rank, - "Error! We cannot decomposed this variable, as it contained multiple decomposed dims that were not decompsed together.\n" + // Final check: the decomposed dims must have been decomposed together (e.g., 2 dims that + // are part of rank-2 decompositions but NOT with each other are not ok) + EKAT_REQUIRE_MSG (f.dim_decomps.count(ekat::join(decomposed_dims,"_"))==1, + "Error! We cannot decomposed this variable, as the decomp dims were not decomposed jointly.\n" " - filename: " + filename + "\n" - " - varname : " + var.name + "\n"); + " - varname : " + var.name + "\n" + " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" + " - decomp dims: " + ekat::join(decomposed_dims,",") + "\n"); // Get ALL dims global lengths, and compute prod of *non-decomposed* dims std::vector gdimlen; @@ -817,21 +844,18 @@ void set_var_decomp (PIOVar& var, gdimlen.push_back(d->length); } - // We haven't create this decomp yet. Go ahead and create one - auto decomp = std::make_shared(); - decomp->name = decomp_tag; - - // Retrieve the dim decomp - std::vector decomp_dim_names; + // Retrieve the dimension(s) decomposition int non_decomp_dim_prod = 1; for (auto d : var.dims) { - if (d->decomp_rank>0) { - decomp_dim_names.push_back(d->name); - } else { + if (d->decomp_rank==0) { non_decomp_dim_prod *= d->length; } } - decomp->dim_decomp = f.dim_decomps.at(ekat::join(decomp_dim_names,"_")); + + // We haven't create this decomp yet. Go ahead and create one + auto decomp = std::make_shared(); + decomp->name = decomp_tag; + decomp->dim_decomp = f.dim_decomps.at(ekat::join(decomposed_dims,"_")); // Create offsets list const auto& dim_offsets = decomp->dim_decomp->offsets; @@ -943,18 +967,6 @@ void set_dims_decomp (const std::string& filename, { auto& f = impl::get_file(filename,"scorpio::set_decomp"); - std::vector dims; - int dims_prod = 1; - for (const auto& n : dimnames) { - dims.push_back(impl::get_dim(filename,n,"scorpio::set_dims_decomp")); - EKAT_REQUIRE_MSG (not dims.back().unlimited, - "Error! Cannot partition an unlimited dimension.\n" - " - filename: " + filename + "\n" - " - dimname : " + n + "\n"); - - dims_prod *= dims.back().length; - } - auto& dim_decomp = f.dim_decomps[ekat::join(dimnames,"_")]; if (dim_decomp!=nullptr) { // Not sure if we should error out. For now, if the offsets are the same (on ALL ranks), just return @@ -971,6 +983,21 @@ void set_dims_decomp (const std::string& filename, } // Check that offsets are less than the global dimension length + int dims_prod = 1; + for (const auto& n : dimnames) { + const auto& dim = impl::get_dim(filename,n,"scorpio::set_dims_decomp"); + EKAT_REQUIRE_MSG (not dim.unlimited, + "Error! Cannot partition an unlimited dimension.\n" + " - filename: " + filename + "\n" + " - dimname : " + n + "\n"); + EKAT_REQUIRE_MSG (not dim.decomp_rank>0, + "Error! At least one of the dimensions in this decomposition was already decomposed in a different way.\n" + " - filename: " + filename + "\n" + " - dimname : " + n + "\n"); + + dims_prod *= dim.length; + } + for (auto o : my_offsets) { EKAT_REQUIRE_MSG (o>=0 && o Date: Tue, 20 Jan 2026 16:32:01 -0700 Subject: [PATCH 367/398] EAMxx: fix some comments typos --- .../eamxx/src/share/io/tests/check_latlon_output.py | 2 +- .../share/scorpio_interface/eamxx_scorpio_interface.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/eamxx/src/share/io/tests/check_latlon_output.py b/components/eamxx/src/share/io/tests/check_latlon_output.py index 90190dee1d4c..6e4fc30448b2 100755 --- a/components/eamxx/src/share/io/tests/check_latlon_output.py +++ b/components/eamxx/src/share/io/tests/check_latlon_output.py @@ -49,7 +49,7 @@ def check_latlon_output(map_file,out_file,mask_cols): # Reshape yc_b and xc_b to match the layout of f_lat and f_lon nlat = f_lat.shape[1] # nlat is the 2nd dim, as the 1st one is time - nlon = f_lat.shape[2] # nlon is the 3nd dim, as the 1st one is time + nlon = f_lat.shape[2] # nlon is the 3rd dim, as the 1st one is time yc_b = yc_b.reshape(nlat,nlon) xc_b = xc_b.reshape(nlat,nlon) diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index f671a35d6a80..e573020452a4 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -772,7 +772,7 @@ void set_var_decomp (PIOVar& var, } EKAT_REQUIRE_MSG (decomp_ranks.size()==1, - "Error! We cannot decomposed this variable, as it contained multiple decomposed dims that were not decompsed together.\n" + "Error! We cannot decompose this variable, as it contained multiple decomposed dims that were not decomppsed together.\n" " - filename: " + filename + "\n" " - varname : " + var.name + "\n" " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" @@ -788,14 +788,14 @@ void set_var_decomp (PIOVar& var, } EKAT_REQUIRE_MSG (num_decomp==decomp_rank, - "Error! We cannot decomposed this variable, as it contained multiple decomposed dims that were not decompsed together.\n" + "Error! We cannot decompose this variable, as it contained multiple decomposed dims that were not decomppsed together.\n" " - filename: " + filename + "\n" " - varname : " + var.name + "\n" " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" " - decomp dims: " + ekat::join(decomposed_dims,",") + "\n"); EKAT_REQUIRE_MSG (last_decomp==(num_decomp-1), - "Error! We cannot decomposed this variable, as the decomp dims are not the slowest striding ones.\n" + "Error! We cannot decompose this variable, as the decomp dims are not the slowest striding ones.\n" " - filename: " + filename + "\n" " - varname : " + var.name + "\n" " - var dims: " + ekat::join(var.dims,get_entity_name,",") + "\n" @@ -990,7 +990,7 @@ void set_dims_decomp (const std::string& filename, "Error! Cannot partition an unlimited dimension.\n" " - filename: " + filename + "\n" " - dimname : " + n + "\n"); - EKAT_REQUIRE_MSG (not dim.decomp_rank>0, + EKAT_REQUIRE_MSG (dim.decomp_rank==0, "Error! At least one of the dimensions in this decomposition was already decomposed in a different way.\n" " - filename: " + filename + "\n" " - dimname : " + n + "\n"); From dc5a079fba5ec10286feb4dd6d6eea2ea3bcd095 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 21 Jan 2026 08:21:06 -0700 Subject: [PATCH 368/398] EAMxx: do not reset yaml file list in eamxx-prod testmod Other testmods existing BEFORE eamxx-prod may have already added yaml files --- .../cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands | 1 - 1 file changed, 1 deletion(-) diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands index b511d3a18880..76d93dee8746 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands @@ -65,7 +65,6 @@ fi # set the output yaml files output_yaml_files=$(find ${cime_root}/../components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/ -maxdepth 1 -type f) -$atmchange -b output_yaml_files="" for file in ${output_yaml_files[@]}; do # Grab the proper map file (if any) mapfile="" From 9f7f4439fb9e27c6b06c1c8f49020c185125270f Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 21 Jan 2026 12:02:47 -0700 Subject: [PATCH 369/398] EAMxx: remove manual inclusion of eamxx_config.h --- components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp | 2 -- .../eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp | 2 -- components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp | 2 -- components/eamxx/src/share/core/eamxx_types.hpp | 2 +- components/eamxx/src/share/remap/coarsening_remapper.hpp | 1 - components/eamxx/src/share/remap/refining_remapper_p2p.hpp | 1 - components/eamxx/src/share/remap/refining_remapper_rma.hpp | 1 - .../src/share/scorpio_interface/eamxx_scorpio_interface.cpp | 2 +- 8 files changed, 2 insertions(+), 11 deletions(-) diff --git a/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp b/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp index f33667b11e50..6233b6f22660 100644 --- a/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp +++ b/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp @@ -1,5 +1,3 @@ -#include "eamxx_config.h" - #include "share/atm_process/atmosphere_process.hpp" #include "control/atmosphere_driver.hpp" #include "control/surface_coupling_utils.hpp" diff --git a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp index ec1711db30ea..8dd9f1e7bc33 100644 --- a/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp +++ b/components/eamxx/src/physics/shoc/eamxx_shoc_process_interface.cpp @@ -3,8 +3,6 @@ #include "share/property_checks/field_lower_bound_check.hpp" #include "share/property_checks/field_within_interval_check.hpp" -#include "eamxx_config.h" // for SCREAM_CIME_BUILD - #include #include #include diff --git a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp index 6c854f5b1200..5ca2bf95fa3e 100644 --- a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp +++ b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp @@ -1,5 +1,3 @@ -#include "eamxx_config.h" // for SCREAM_CIME_BUILD - #include "share/property_checks/field_lower_bound_check.hpp" #include "share/property_checks/field_within_interval_check.hpp" diff --git a/components/eamxx/src/share/core/eamxx_types.hpp b/components/eamxx/src/share/core/eamxx_types.hpp index c082a7704add..b21d3cb64134 100644 --- a/components/eamxx/src/share/core/eamxx_types.hpp +++ b/components/eamxx/src/share/core/eamxx_types.hpp @@ -1,7 +1,7 @@ #ifndef SCREAM_TYPES_HPP #define SCREAM_TYPES_HPP -#include "eamxx_config.h" +#include "eamxx_config.hpp" #include diff --git a/components/eamxx/src/share/remap/coarsening_remapper.hpp b/components/eamxx/src/share/remap/coarsening_remapper.hpp index b6a723b4539d..b297297d5378 100644 --- a/components/eamxx/src/share/remap/coarsening_remapper.hpp +++ b/components/eamxx/src/share/remap/coarsening_remapper.hpp @@ -2,7 +2,6 @@ #define SCREAM_COARSENING_REMAPPER_HPP #include "share/remap/horiz_interp_remapper_base.hpp" -#include "eamxx_config.h" #include diff --git a/components/eamxx/src/share/remap/refining_remapper_p2p.hpp b/components/eamxx/src/share/remap/refining_remapper_p2p.hpp index d13d4f94aeb0..6dc227fe60f1 100644 --- a/components/eamxx/src/share/remap/refining_remapper_p2p.hpp +++ b/components/eamxx/src/share/remap/refining_remapper_p2p.hpp @@ -3,7 +3,6 @@ #include "share/remap/abstract_remapper.hpp" #include "share/remap/horiz_interp_remapper_base.hpp" -#include "eamxx_config.h" #include diff --git a/components/eamxx/src/share/remap/refining_remapper_rma.hpp b/components/eamxx/src/share/remap/refining_remapper_rma.hpp index 3fde0e388b0e..5c1544156997 100644 --- a/components/eamxx/src/share/remap/refining_remapper_rma.hpp +++ b/components/eamxx/src/share/remap/refining_remapper_rma.hpp @@ -4,7 +4,6 @@ #include "share/remap/abstract_remapper.hpp" #include "share/remap/horiz_interp_remapper_base.hpp" #include "share/util/eamxx_utils.hpp" -#include "eamxx_config.h" #include diff --git a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp index e573020452a4..ab59171b1071 100644 --- a/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp +++ b/components/eamxx/src/share/scorpio_interface/eamxx_scorpio_interface.cpp @@ -1,7 +1,7 @@ #include "eamxx_scorpio_interface.hpp" #include "eamxx_shr_interface_c2f.hpp" -#include "eamxx_config.h" +#include "share/core/eamxx_config.hpp" #include #include From 3efeb348fa83f718b10cd83843d7287b93be1442 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Wed, 21 Jan 2026 18:18:34 -0700 Subject: [PATCH 370/398] EAMxx: fix run_t0 num steps before initializing output mgrs The value of run_t0's num steps may be used to compute the timestamp of the next output during the OM init, so its value must already be correct --- .../eamxx/src/control/atmosphere_driver.cpp | 21 +++++++++++++------ .../mct_coupling/eamxx_cxx_f90_interface.cpp | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/components/eamxx/src/control/atmosphere_driver.cpp b/components/eamxx/src/control/atmosphere_driver.cpp index 827b71b3727f..b538dd2506ce 100644 --- a/components/eamxx/src/control/atmosphere_driver.cpp +++ b/components/eamxx/src/control/atmosphere_driver.cpp @@ -182,6 +182,20 @@ init_time_stamps (const util::TimeStamp& run_t0, const util::TimeStamp& case_t0, default: EKAT_ERROR_MSG ("Unsupported/unrecognized run_type: " + std::to_string(run_type) + "\n"); } + + // If it is a restarted run, make sure we have the correct num steps. + // If num_steps is left at default (0), it messes up output managers logic + if (m_run_type==RunType::Restart) { + // Figure out the name of the netcdf file containing the restart data + const auto& provenance = m_atm_params.sublist("provenance"); + const auto& casename = provenance.get("rest_caseid"); + auto filename = find_filename_in_rpointer (casename+".scream",true,m_atm_comm,m_run_t0); + + // Restart the num steps counter in the atm time stamp + int nsteps = scorpio::get_attribute(filename,"GLOBAL","nsteps"); + m_run_t0.set_num_steps(nsteps); + m_current_ts.set_num_steps(nsteps); + } } void AtmosphereDriver:: @@ -766,8 +780,8 @@ void AtmosphereDriver::initialize_output_managers () { output_grids.erase("physics_gll"); } - m_restart_output_manager->setup(m_field_mgr, output_grids); m_restart_output_manager->set_logger(m_atm_logger); + m_restart_output_manager->setup(m_field_mgr, output_grids); for (const auto& it : m_atm_process_group->get_restart_extra_data()) { m_restart_output_manager->add_global(it.first,it.second); } @@ -946,11 +960,6 @@ void AtmosphereDriver::restart_model () } } - // Restart the num steps counter in the atm time stamp - int nsteps = scorpio::get_attribute(filename,"GLOBAL","nsteps"); - m_current_ts.set_num_steps(nsteps); - m_run_t0.set_num_steps(nsteps); - for (auto& it : m_atm_process_group->get_restart_extra_data()) { const auto& name = it.first; auto& any = *it.second; diff --git a/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp b/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp index 6233b6f22660..22179d1d733c 100644 --- a/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp +++ b/components/eamxx/src/mct_coupling/eamxx_cxx_f90_interface.cpp @@ -174,9 +174,9 @@ void scream_create_atm_instance (const MPI_Fint f_comm, const int atm_id, ad.set_comm(atm_comm); ad.set_params(scream_params); + ad.set_provenance_data (caseid,rest_caseid,hostname,username,versionid); ad.init_scorpio(atm_id); ad.init_time_stamps(run_t0,case_t0,run_type); - ad.set_provenance_data (caseid,rest_caseid,hostname,username,versionid); ad.create_output_managers (); ad.create_atm_processes (); ad.create_grids (); From 60e13323c048a9624c65be8b728b43322a1ae9ef Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 22 Jan 2026 09:10:58 -0700 Subject: [PATCH 371/398] Add python to improv env The purge will result in a python too old to run CIME. [BFB] --- cime_config/machines/config_machines.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 93e220a71da7..48c956de6a44 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3029,6 +3029,7 @@ cmake/3.27.4 + python/3.11.6 gcc/12.3.0 From 4e355dbbc0ec204a695773829705a1f782be8d33 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 22 Jan 2026 14:08:39 -0700 Subject: [PATCH 372/398] Building --- .../src/physics/zm/impl/zm_entropy_impl.hpp | 36 ++++++++- .../physics/zm/tests/infra/zm_test_data.cpp | 15 +--- .../src/physics/zm/tests/zm_entropy_tests.cpp | 2 +- .../eamxx/src/physics/zm/zm_functions.hpp | 76 +++++++++++++++---- 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp index e1b0de68556f..cf6bf1259ee0 100644 --- a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp @@ -3,6 +3,8 @@ #include "zm_functions.hpp" // for ETI only but harmless for GPU +#include + namespace scream { namespace zm { @@ -20,9 +22,37 @@ Real Functions::entropy( const Real& p, const Real& qtot) { - // TODO - // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed - return 0; + //---------------------------------------------------------------------------- + // Purpose: function to calculate entropy following: + // + // Raymond, D. J., and A. M. Blyth, 1992: Extension of the Stochastic Mixing + // Model to Cumulonimbus Clouds. J. Atmos. Sci., 49, 1968–1983 + //---------------------------------------------------------------------------- + + //---------------------------------------------------------------------------- + // Local variables + Real qv; // water vapor mixing ratio + Real qst; // saturated vapor mixing ratio + Real e; // water vapor pressure + Real est; // saturated vapor pressure + Real L; // latent heat of vaporization + //---------------------------------------------------------------------------- + + // Calculate latent heat of vaporization - note T is converted to centigrade + L = PC::LatVap.value - (PC::CpLiq.value - ZMC::cpwv)*(tk - PC::Tmelt.value); + + // Use saturation mixing ratio to partition qtot into vapor part only + qsat_hPa(tk, p, est, qst); + qv = ekat::impl::min(qtot,qst); + e = qv*p / (PC::ep_2.value + qv); + + std::cout << "JGF tk=" << tk << ", p=" << p << ", qtot=" << qtot << ", L=" << L << ", est=" << est << ", qst=" << qst << ", qv=" << qv << ", e=" << e << std::endl; + + // calculate entropy per unit mass of dry air - Eq. 1 + return ( + (PC::Cpair.value + qtot*PC::CpLiq.value)*std::log(tk/PC::Tmelt.value) + - PC::Rair.value*std::log( (p-e)/ZMC::pref) + + L*qv/tk - qv*PC::RH2O.value*std::log(qv/qst)); } } // namespace zm diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 2af74ff265d2..693a486ae28c 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -35,7 +35,7 @@ void zm_find_mse_max_f(Int pcols, Int ncol, Int pver, Int num_msg, Int *msemax_t void ientropy_bridge_f(Int rcall, Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); -void entropy_bridge_f(Real tk, Real p, Real qtot, zm_const_t zm_const, Real* entropy); +void entropy_bridge_f(Real tk, Real p, Real qtot, Real* entropy); } // extern "C" : end _f decls // Inits and finalizes are not intended to be called outside this comp unit @@ -102,9 +102,6 @@ void ientropy(IentropyData& d) auto t_h = Kokkos::create_mirror_view(t_d); Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { - // Get single-column subviews of all inputs, shouldn't need any i-indexing - // after this. - ZMF::ientropy( team, rcall, @@ -148,17 +145,11 @@ void entropy(EntropyData& d) auto entropy_h = Kokkos::create_mirror_view(entropy_d); Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { - const Int i = team.league_rank(); - - // Get single-column subviews of all inputs, shouldn't need any i-indexing - // after this. - - SHF::entropy( + entropy_d() = ZMF::entropy( team, tk, p, - qtot, - entropy_d()); + qtot); }); // Get outputs back, start with scalars diff --git a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp index 107e53067c3b..09af5fffde58 100644 --- a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp +++ b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp @@ -23,7 +23,7 @@ struct UnitWrap::UnitTest::TestEntropy : public UnitWrap::UnitTest::Base { // Set up inputs EntropyData baseline_data[] = { // tk, p, qtot, entropy (output, set to zero) - EntropyData(0, 0, 0, 0), + EntropyData(270, 1000, .01, 0), }; static constexpr Int num_runs = sizeof(baseline_data) / sizeof(EntropyData); diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index de74148ffc90..6f400092a80f 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -61,6 +61,16 @@ struct Functions { // ---------- ZM constants --------- // struct ZMC { + // This value is slightly high, but it seems to be the value for the + // steam point of water originally (and most frequently) used in the + // Goff & Gratch scheme. + static inline constexpr Real tboil = 373.16; + + static inline constexpr Real omeps = 1 - PC::ep_2.value; + + static inline constexpr Real pref = 1000; + + static inline constexpr Real cpwv = 1.810e3; // specific heat of water vapor (J/K/kg) }; struct zm_runtime_opt { @@ -260,9 +270,6 @@ struct Functions { Real mcsp_v_coeff; // MCSP coefficient for meridional momentum tendencies }; - // ----------------------------------------------------------------------------------------------- - // Functions - // // --------- Init/Finalize Functions --------- // @@ -273,30 +280,69 @@ struct Functions { // static Int zm_main() // - // --------- Members --------- + // --------- Functions --------- // - inline static ZmCommonInit s_common_init; KOKKOS_FUNCTION static void ientropy( // Inputs const MemberType& team, - const Int& rcall, - const Real& s, - const Real& p, - const Real& qt, - const Real& tfg, + const Int& rcall, // call index + const Real& s, // entropy [J/kg] + const Real& p, // pressure [mb] + const Real& qt, // total water mixing ratio [kg/kg] + const Real& tfg, // input temperature for first guess [K] // Outputs - Real& t, - Real& qst); + Real& t, // temperature [k] + Real& qst); // saturation vapor mixing ratio [kg/kg] KOKKOS_FUNCTION static Real entropy( // Inputs const MemberType& team, - const Real& tk, - const Real& p, - const Real& qtot); + const Real& tk, // temperature [K] + const Real& p, // pressure [mb] + const Real& qtot); // total water mixing ratio [kg/kg] + + KOKKOS_INLINE_FUNCTION + static void qsat_hPa( + // Inputs + const Real& t, // Temperature [K] + const Real& p, // Pressure [hPa] + Real& es, // Saturation vapor pressure [hPa] + Real& qm) // Saturation mass mixing ratio [kg/kg] (vapor mass over dry mass) + { + // GoffGratch_svp_water + static constexpr Real magic1 = -7.90298; + static constexpr Real magic2 = 5.02808; + static constexpr Real magic3 = 1.3816e-7; + static constexpr Real magic4 = 11.344; + static constexpr Real magic5 = 8.1328e-3; + static constexpr Real magic6 = -3.49149; + static constexpr Real magic7 = 1013.246; + es = std::pow(10, magic1*(ZMC::tboil/t-1) + + magic2*std::log10(ZMC::tboil/t) - + magic3*(std::pow(10, magic4*(1 - t/ZMC::tboil)) - 1) + + magic5*(std::pow(10, magic6*(ZMC::tboil/t-1)) - 1) + + std::log10(magic7))*100; + std::cout << "From qsat_hPa, es = " << es << std::endl; + + if ( (p*100 - es) <= 0 ) { + qm = 1; + } + else { + qm = PC::ep_2.value*es / (p*100 - ZMC::omeps*es); + } + + es = es*0.01; + + es = std::min(es, p*100) + } + + // + // --------- Members --------- + // + inline static ZmCommonInit s_common_init; }; // struct Functions From 2dbda47bc21289cac31cd07fcb552841d22d32ca Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 22 Jan 2026 14:09:19 -0700 Subject: [PATCH 373/398] Remove prints --- components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp | 2 -- components/eamxx/src/physics/zm/zm_functions.hpp | 1 - 2 files changed, 3 deletions(-) diff --git a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp index cf6bf1259ee0..7914ee15ec24 100644 --- a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp @@ -46,8 +46,6 @@ Real Functions::entropy( qv = ekat::impl::min(qtot,qst); e = qv*p / (PC::ep_2.value + qv); - std::cout << "JGF tk=" << tk << ", p=" << p << ", qtot=" << qtot << ", L=" << L << ", est=" << est << ", qst=" << qst << ", qv=" << qv << ", e=" << e << std::endl; - // calculate entropy per unit mass of dry air - Eq. 1 return ( (PC::Cpair.value + qtot*PC::CpLiq.value)*std::log(tk/PC::Tmelt.value) diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 6f400092a80f..430d3aa011e1 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -325,7 +325,6 @@ struct Functions { magic3*(std::pow(10, magic4*(1 - t/ZMC::tboil)) - 1) + magic5*(std::pow(10, magic6*(ZMC::tboil/t-1)) - 1) + std::log10(magic7))*100; - std::cout << "From qsat_hPa, es = " << es << std::endl; if ( (p*100 - es) <= 0 ) { qm = 1; From ed3e2dd93283abef5f73d2f819ce6f618b6de11b Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 22 Jan 2026 15:03:57 -0700 Subject: [PATCH 374/398] Runs --- .../src/physics/zm/tests/infra/zm_c2f_bridge.f90 | 13 +++++++++++++ .../src/physics/zm/tests/infra/zm_test_data.cpp | 14 +++++++++++++- components/eamxx/src/physics/zm/zm_functions.hpp | 6 ++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 index 7ecc971db152..c8e4ba8d5fea 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 +++ b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 @@ -46,6 +46,19 @@ end subroutine zm_find_mse_max_f !=================================================================================================== +subroutine zm_common_init_bridge_f() bind(C) + use zm_eamxx_bridge_wv_saturation, only: wv_sat_init + + call wv_sat_init() +end subroutine zm_common_init_bridge_f + +subroutine zm_common_finalize_bridge_f() bind(C) + use zm_eamxx_bridge_wv_saturation, only: wv_sat_final + + call wv_sat_final() +end subroutine zm_common_finalize_bridge_f + + subroutine ientropy_bridge_f(rcall, s, p, qt, t, qst, tfg) bind(C) use zm_conv_util, only : ientropy use zm_conv_types, only: zm_const_t, zm_const_set_for_testing diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 693a486ae28c..9b2fad0cc94b 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -31,6 +31,10 @@ using WSM = typename ZMF::WorkspaceManager; extern "C" { +void zm_common_init_bridge_f(); + +void zm_common_finalize_bridge_f(); + void zm_find_mse_max_f(Int pcols, Int ncol, Int pver, Int num_msg, Int *msemax_top_k, bool pergro_active, Real *temperature, Real *zmid, Real *sp_humidity, Int *msemax_klev, Real *mse_max_val); void ientropy_bridge_f(Int rcall, Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); @@ -43,9 +47,15 @@ namespace { void zm_common_init_f() { - // Anything to do here? + zm_common_init_bridge_f(); +} + +void zm_common_finalize_f() +{ + zm_common_finalize_bridge_f(); } + // Wrapper around gw_init for cxx void zm_common_init() { @@ -80,6 +90,7 @@ void ientropy_f(IentropyData& d) d.transition(); zm_common_init_f(); ientropy_bridge_f(d.rcall, d.s, d.p, d.qt, &d.t, &d.qst, d.tfg); + zm_common_finalize_f(); d.transition(); } @@ -127,6 +138,7 @@ void entropy_f(EntropyData& d) d.transition(); zm_common_init_f(); // Might need more specific init entropy_bridge_f(d.tk, d.p, d.qtot, &d.entropy); + zm_common_finalize_f(); d.transition(); } diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 430d3aa011e1..dad97e1d2a2f 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -326,6 +326,7 @@ struct Functions { magic5*(std::pow(10, magic6*(ZMC::tboil/t-1)) - 1) + std::log10(magic7))*100; + // If pressure is less than SVP, set qs to maximum of 1. if ( (p*100 - es) <= 0 ) { qm = 1; } @@ -333,9 +334,10 @@ struct Functions { qm = PC::ep_2.value*es / (p*100 - ZMC::omeps*es); } - es = es*0.01; + // Ensures returned es is consistent with limiters on qs. + es = std::min(es, p*100); - es = std::min(es, p*100) + es = es*0.01; } // From 1649c08406947b38a34f366a591c549b5835ed79 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 23 Jan 2026 13:56:31 -0700 Subject: [PATCH 375/398] Port zm_ientropy impl --- .../eam/src/physics/cam/zm/zm_conv_util.F90 | 2 - .../src/physics/zm/impl/zm_entropy_impl.hpp | 3 - .../src/physics/zm/impl/zm_ientropy_impl.hpp | 95 ++++++++++++++++++- .../physics/zm/tests/infra/zm_c2f_bridge.f90 | 5 +- .../physics/zm/tests/infra/zm_test_data.cpp | 9 +- .../physics/zm/tests/infra/zm_test_data.hpp | 7 +- .../src/physics/zm/tests/zm_entropy_tests.cpp | 6 +- .../physics/zm/tests/zm_ientropy_tests.cpp | 6 +- .../eamxx/src/physics/zm/zm_functions.hpp | 11 ++- 9 files changed, 115 insertions(+), 29 deletions(-) diff --git a/components/eam/src/physics/cam/zm/zm_conv_util.F90 b/components/eam/src/physics/cam/zm/zm_conv_util.F90 index 4c20b7f80643..c47fe8044a88 100644 --- a/components/eam/src/physics/cam/zm/zm_conv_util.F90 +++ b/components/eam/src/physics/cam/zm/zm_conv_util.F90 @@ -81,8 +81,6 @@ subroutine ientropy(rcall, s, p, qt, T, qst, Tfg, zm_const) integer :: i ! loop iterator logical :: converged ! flag for convergence real(r8) :: est ! saturation vapor pressure - real(r8) :: this_lat ! local latitude - real(r8) :: this_lon ! local logitude real(r8) :: tolerance real(r8) :: a, b, c, d, ebr, fa, fb, fc, pbr, qbr, rbr, sbr, xm integer, parameter :: LOOPMAX = 100 ! Max number of iteration loops diff --git a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp index 7914ee15ec24..2b3637766dbc 100644 --- a/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_entropy_impl.hpp @@ -3,8 +3,6 @@ #include "zm_functions.hpp" // for ETI only but harmless for GPU -#include - namespace scream { namespace zm { @@ -17,7 +15,6 @@ template KOKKOS_FUNCTION Real Functions::entropy( // Inputs - const MemberType& team, const Real& tk, const Real& p, const Real& qtot) diff --git a/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp index b7eafcf6bcf0..46accd228a3d 100644 --- a/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp @@ -16,7 +16,6 @@ KOKKOS_FUNCTION void Functions::ientropy( // Inputs const MemberType& team, - const Int& rcall, const Real& s, const Real& p, const Real& qt, @@ -25,7 +24,99 @@ void Functions::ientropy( Real& t, Real& qst) { - // TODO + //---------------------------------------------------------------------------- + // Local variables + bool converged; // flag for convergence + Real a, b, c, d, ebr, fa, fb, fc, pbr, qbr, rbr, sbr, xm; + + //---------------------------------------------------------------------------- + // initialize variables + converged = false; + t = tfg; // first guess based on input temperature + a = tfg-10; // low bracket + b = tfg+10; // high bracket + + fa = entropy(a, p, qt) - s; + fb = entropy(b, p, qt) - s; + + c = b; + fc = fb; + + static constexpr Real half = 0.5; + + //---------------------------------------------------------------------------- + // + for (int i = 0; i <= ZMC::LOOPMAX; ++i) { + + if ((fb > 0 && fc > 0) || (fb < 0 && fc < 0)) { + c = a; + d = b-a; + fc = fa; + ebr = d; + } + + if (std::abs(fc) < std::abs(fb)) { + a = b; + b = c; + c = a; + fa = fb; + fb = fc; + fc = fa; + } + + Real tolerance = 2*ZMC::tol_eps*std::abs(b) + half*ZMC::tol_coeff; + xm = half*(c-b); + + converged = (std::abs(xm) <= tolerance || fb == 0); + if (converged) break; + + if (std::abs(ebr) >= tolerance && std::abs(fa) > std::abs(fb)) { + sbr=fb/fa; + if (a == c) { + pbr = 2*xm*sbr; + qbr = 1 - sbr; + } + else { + qbr = fa/fc; + rbr = fb/fc; + pbr = sbr*(2*xm*qbr*(qbr-rbr)-(b-a)*(rbr-1)); + qbr = (qbr-1)*(rbr-1)*(sbr-1); + } + + if (pbr > 0) qbr=-qbr; + + pbr=std::abs(pbr); + if (2*pbr < ekat::impl::min(3*xm*qbr-std::abs(tolerance*qbr), std::abs(ebr*qbr))) { + ebr = d; + d = pbr/qbr; + } + else { + d = xm; + ebr = d; + } + } + else { + d = xm; + ebr = d; + } + + a = b; + fa = fb; + if (std::abs(d) > tolerance) { + b += d; + } + else { + b += Kokkos::copysign(tolerance, xm); + } + + fb = entropy(b, p, qt) - s; + } + + t = b; + Real est; // saturation vapor pressure + qsat_hPa(t, p, est, qst); + + EKAT_KERNEL_REQUIRE_MSG(converged, "ZM_CONV: IENTROPY: Failed to converge"); } } // namespace zm diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 index c8e4ba8d5fea..97ae4bc89ce0 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 +++ b/components/eamxx/src/physics/zm/tests/infra/zm_c2f_bridge.f90 @@ -59,18 +59,17 @@ subroutine zm_common_finalize_bridge_f() bind(C) end subroutine zm_common_finalize_bridge_f -subroutine ientropy_bridge_f(rcall, s, p, qt, t, qst, tfg) bind(C) +subroutine ientropy_bridge_f(s, p, qt, t, qst, tfg) bind(C) use zm_conv_util, only : ientropy use zm_conv_types, only: zm_const_t, zm_const_set_for_testing - integer(kind=c_int) , value, intent(in) :: rcall real(kind=c_real) , value, intent(in) :: s, p, qt, tfg real(kind=c_real) , intent(out) :: t, qst type(zm_const_t) :: zm_const call zm_const_set_for_testing(zm_const) - call ientropy(rcall, s, p, qt, t, qst, tfg, zm_const) + call ientropy(1, s, p, qt, t, qst, tfg, zm_const) end subroutine ientropy_bridge_f subroutine entropy_bridge_f(tk, p, qtot, entropy_rv) bind(C) diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 9b2fad0cc94b..859855d0f108 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -37,7 +37,7 @@ void zm_common_finalize_bridge_f(); void zm_find_mse_max_f(Int pcols, Int ncol, Int pver, Int num_msg, Int *msemax_top_k, bool pergro_active, Real *temperature, Real *zmid, Real *sp_humidity, Int *msemax_klev, Real *mse_max_val); -void ientropy_bridge_f(Int rcall, Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); +void ientropy_bridge_f(Real s, Real p, Real qt, Real* t, Real* qst, Real tfg); void entropy_bridge_f(Real tk, Real p, Real qtot, Real* entropy); } // extern "C" : end _f decls @@ -89,7 +89,7 @@ void ientropy_f(IentropyData& d) { d.transition(); zm_common_init_f(); - ientropy_bridge_f(d.rcall, d.s, d.p, d.qt, &d.t, &d.qst, d.tfg); + ientropy_bridge_f(d.s, d.p, d.qt, &d.t, &d.qst, d.tfg); zm_common_finalize_f(); d.transition(); } @@ -106,7 +106,6 @@ void ientropy(IentropyData& d) const Real qt = d.qt; const Real s = d.s; const Real tfg = d.tfg; - const Int rcall = d.rcall; view0dr_d qst_d("qst_d"); view0dr_d t_d("t_d"); auto qst_h = Kokkos::create_mirror_view(qst_d); @@ -115,7 +114,6 @@ void ientropy(IentropyData& d) Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { ZMF::ientropy( team, - rcall, s, p, qt, @@ -156,9 +154,8 @@ void entropy(EntropyData& d) view0dr_d entropy_d("entropy_d"); auto entropy_h = Kokkos::create_mirror_view(entropy_d); - Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { + Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType&) { entropy_d() = ZMF::entropy( - team, tk, p, qtot); diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp index 540363c36b60..28b1bdbd1161 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.hpp @@ -60,18 +60,17 @@ struct zm_data_find_mse_max : public PhysicsTestData { struct IentropyData : public PhysicsTestData { // Inputs - Int rcall; Real s, p, qt, tfg; // Outputs Real t, qst; - IentropyData(Int rcall_, Real s_, Real p_, Real qt_, Real tfg_, Real t_, Real qst_) : + IentropyData(Real s_, Real p_, Real qt_, Real tfg_, Real t_, Real qst_) : PhysicsTestData({}, {}), - rcall(rcall_), s(s_), p(p_), qt(qt_), tfg(tfg_), t(t_), qst(qst_) + s(s_), p(p_), qt(qt_), tfg(tfg_), t(t_), qst(qst_) {} - PTD_STD_DEF(IentropyData, 7, rcall, s, p, qt, tfg, t, qst); + PTD_STD_DEF(IentropyData, 6, s, p, qt, tfg, t, qst); }; struct EntropyData : public PhysicsTestData { diff --git a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp index 09af5fffde58..627bc5b5d2f0 100644 --- a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp +++ b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp @@ -37,7 +37,6 @@ struct UnitWrap::UnitTest::TestEntropy : public UnitWrap::UnitTest::Base { // Create copies of data for use by test. Needs to happen before read calls so that // inout data is in original state EntropyData test_data[] = { - // TODO EntropyData(baseline_data[0]), }; @@ -58,12 +57,15 @@ struct UnitWrap::UnitTest::TestEntropy : public UnitWrap::UnitTest::Base { } } + const auto margin = std::numeric_limits::epsilon() * + (ekat::is_single_precision::value ? 1000 : 1); + // Verify BFB results, all data should be in C layout if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { for (Int i = 0; i < num_runs; ++i) { EntropyData& d_baseline = baseline_data[i]; EntropyData& d_test = test_data[i]; - REQUIRE(d_baseline.entropy == d_test.entropy); + REQUIRE(d_baseline.entropy == Approx(d_test.entropy).margin(margin)); } } else if (this->m_baseline_action == GENERATE) { diff --git a/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp index 9670f0f78061..7af698b5e4f4 100644 --- a/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp +++ b/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp @@ -22,9 +22,8 @@ struct UnitWrap::UnitTest::TestIentropy : public UnitWrap::UnitTest::Base // Set up inputs IentropyData baseline_data[] = { - // TODO - // rcall, s, p, qt, tfg, t (output, set to zero), qst (output, set to zero) - IentropyData(0 , 1, 2, 3 , 4 , 0 , 0), + // s, p, qt, tfg, t (output, set to zero), qst (output, set to zero) + IentropyData(3000, 1000, .01, 270, 0 , 0), }; static constexpr Int num_runs = sizeof(baseline_data) / sizeof(IentropyData); @@ -38,7 +37,6 @@ struct UnitWrap::UnitTest::TestIentropy : public UnitWrap::UnitTest::Base // Create copies of data for use by test. Needs to happen before read calls so that // inout data is in original state IentropyData test_data[] = { - // TODO IentropyData(baseline_data[0]), }; diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index dad97e1d2a2f..3005295b6fe1 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace scream { namespace zm { @@ -71,6 +72,12 @@ struct Functions { static inline constexpr Real pref = 1000; static inline constexpr Real cpwv = 1.810e3; // specific heat of water vapor (J/K/kg) + + static inline constexpr Int LOOPMAX = 100; // Max number of iteration loops for ientropy + + static inline constexpr Real tol_coeff = 0.001; // tolerance coeficient + + static inline constexpr Real tol_eps = 3.e-8; // small value for tolerance calculation }; struct zm_runtime_opt { @@ -287,7 +294,6 @@ struct Functions { static void ientropy( // Inputs const MemberType& team, - const Int& rcall, // call index const Real& s, // entropy [J/kg] const Real& p, // pressure [mb] const Real& qt, // total water mixing ratio [kg/kg] @@ -299,7 +305,6 @@ struct Functions { KOKKOS_FUNCTION static Real entropy( // Inputs - const MemberType& team, const Real& tk, // temperature [K] const Real& p, // pressure [mb] const Real& qtot); // total water mixing ratio [kg/kg] @@ -335,7 +340,7 @@ struct Functions { } // Ensures returned es is consistent with limiters on qs. - es = std::min(es, p*100); + es = ekat::impl::min(es, p*100); es = es*0.01; } From 8a939da421726f6f513e744358cd1a99ee514ef6 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 23 Jan 2026 15:04:08 -0700 Subject: [PATCH 376/398] Turn on ZM GPU tests --- components/eamxx/src/physics/zm/tests/CMakeLists.txt | 12 +++++------- components/eamxx/src/physics/zm/zm_functions.hpp | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/components/eamxx/src/physics/zm/tests/CMakeLists.txt b/components/eamxx/src/physics/zm/tests/CMakeLists.txt index 8a68ec7518d3..b063ec1281ba 100644 --- a/components/eamxx/src/physics/zm/tests/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/tests/CMakeLists.txt @@ -24,10 +24,8 @@ else() set(GZM_THREADS 1 ${SCREAM_TEST_MAX_THREADS} ${SCREAM_TEST_THREAD_INC}) endif() -if (NOT EAMXX_ENABLE_GPU) - CreateUnitTest(zm_tests "${ZM_TESTS_SRCS}" - LIBS zm zm_test_infra - EXE_ARGS "--args ${BASELINE_FILE_ARG}" - THREADS ${ZM_THREADS} - LABELS "zm;physics;baseline_gen;baseline_cmp") -endif() +CreateUnitTest(zm_tests "${ZM_TESTS_SRCS}" + LIBS zm zm_test_infra + EXE_ARGS "--args ${BASELINE_FILE_ARG}" + THREADS ${ZM_THREADS} + LABELS "zm;physics;baseline_gen;baseline_cmp") diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index 3005295b6fe1..c01c19e7b04d 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -359,7 +359,7 @@ struct Functions { && !defined(KOKKOS_ENABLE_HIP_RELOCATABLE_DEVICE_CODE) # include "impl/zm_input_state_impl.hpp" # include "impl/zm_output_tend_impl.hpp" -# include "impl/zm_common_init.hpp" +# include "impl/zm_common_init_impl.hpp" # include "impl/zm_ientropy_impl.hpp" # include "impl/zm_entropy_impl.hpp" #endif // GPU && !KOKKOS_ENABLE_*_RELOCATABLE_DEVICE_CODE From c5848c5ee0ca42f550c6797663e332af2ef43633 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Tue, 27 Jan 2026 16:44:53 -0700 Subject: [PATCH 377/398] Clean up naming convention. Merge ZmRuntimeOpt with ZmCommonInit. Rename ientropy --- .../eamxx/src/physics/zm/CMakeLists.txt | 2 +- .../physics/zm/eamxx_zm_process_interface.cpp | 24 ++--- .../physics/zm/eamxx_zm_process_interface.hpp | 12 +-- .../src/physics/zm/eti/zm_input_state.cpp | 6 +- ...{zm_ientropy.cpp => zm_invert_entropy.cpp} | 4 +- .../src/physics/zm/eti/zm_output_tend.cpp | 6 +- .../zm/fortran_bridge/zm_eamxx_bridge.cpp | 71 +++++++------- .../zm/fortran_bridge/zm_eamxx_bridge.hpp | 6 +- .../physics/zm/impl/zm_input_state_impl.hpp | 4 +- ...py_impl.hpp => zm_invert_entropy_impl.hpp} | 10 +- .../physics/zm/impl/zm_output_tend_impl.hpp | 4 +- .../physics/zm/tests/infra/zm_test_data.cpp | 2 +- .../eamxx/src/physics/zm/zm_functions.hpp | 93 +++++++++---------- 13 files changed, 121 insertions(+), 123 deletions(-) rename components/eamxx/src/physics/zm/eti/{zm_ientropy.cpp => zm_invert_entropy.cpp} (57%) rename components/eamxx/src/physics/zm/impl/{zm_ientropy_impl.hpp => zm_invert_entropy_impl.hpp} (90%) diff --git a/components/eamxx/src/physics/zm/CMakeLists.txt b/components/eamxx/src/physics/zm/CMakeLists.txt index 7eb98239b1c7..3ba2db2a2dd7 100644 --- a/components/eamxx/src/physics/zm/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/CMakeLists.txt @@ -45,7 +45,7 @@ if (NOT EAMXX_ENABLE_GPU OR Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE OR Kokkos eti/zm_common_init.cpp eti/zm_input_state.cpp eti/zm_output_tend.cpp - eti/zm_ientropy.cpp + eti/zm_invert_entropy.cpp eti/zm_entropy.cpp ) # ZM ETI SRCS endif() diff --git a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp index 6c854f5b1200..916b51afb997 100644 --- a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp +++ b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.cpp @@ -319,15 +319,15 @@ size_t ZMDeepConvection::requested_buffer_size_in_bytes() const const int nlev_int_packs = ekat::npack(m_nlev+1); size_t zm_buffer_size = 0; - zm_buffer_size+= ZMF::zm_input_state::num_1d_intgr * sizeof(Int) * m_ncol; - zm_buffer_size+= ZMF::zm_input_state::num_1d_scalr * sizeof(Scalar)* m_ncol; - zm_buffer_size+= ZMF::zm_input_state::num_2d_midlv * sizeof(Spack) * m_ncol * nlev_mid_packs; - zm_buffer_size+= ZMF::zm_input_state::num_2d_intfc * sizeof(Spack) * m_ncol * nlev_int_packs; + zm_buffer_size+= ZMF::ZmInputState::num_1d_intgr * sizeof(Int) * m_ncol; + zm_buffer_size+= ZMF::ZmInputState::num_1d_scalr * sizeof(Scalar)* m_ncol; + zm_buffer_size+= ZMF::ZmInputState::num_2d_midlv * sizeof(Spack) * m_ncol * nlev_mid_packs; + zm_buffer_size+= ZMF::ZmInputState::num_2d_intfc * sizeof(Spack) * m_ncol * nlev_int_packs; - zm_buffer_size+= ZMF::zm_output_tend::num_1d_intgr * sizeof(Int) * m_ncol; - zm_buffer_size+= ZMF::zm_output_tend::num_1d_scalr * sizeof(Scalar)* m_ncol; - zm_buffer_size+= ZMF::zm_output_tend::num_2d_midlv * sizeof(Spack) * m_ncol * nlev_mid_packs; - zm_buffer_size+= ZMF::zm_output_tend::num_2d_intfc * sizeof(Spack) * m_ncol * nlev_int_packs; + zm_buffer_size+= ZMF::ZmOutputTend::num_1d_intgr * sizeof(Int) * m_ncol; + zm_buffer_size+= ZMF::ZmOutputTend::num_1d_scalr * sizeof(Scalar)* m_ncol; + zm_buffer_size+= ZMF::ZmOutputTend::num_2d_midlv * sizeof(Spack) * m_ncol * nlev_mid_packs; + zm_buffer_size+= ZMF::ZmOutputTend::num_2d_intfc * sizeof(Spack) * m_ncol * nlev_int_packs; int num_f_mid = (9+6); int num_f_int = (2+3); @@ -347,10 +347,10 @@ void ZMDeepConvection::init_buffers(const ATMBufferManager &buffer_manager) const int nlev_mid_packs = ekat::npack(m_nlev); const int nlev_int_packs = ekat::npack(m_nlev+1); - constexpr auto num_1d_intgr = ZMF::zm_input_state::num_1d_intgr + ZMF::zm_output_tend::num_1d_intgr; - constexpr auto num_1d_scalr = ZMF::zm_input_state::num_1d_scalr + ZMF::zm_output_tend::num_1d_scalr; - constexpr auto num_2d_midlv = ZMF::zm_input_state::num_2d_midlv + ZMF::zm_output_tend::num_2d_midlv; - constexpr auto num_2d_intfc = ZMF::zm_input_state::num_2d_intfc + ZMF::zm_output_tend::num_2d_intfc; + constexpr auto num_1d_intgr = ZMF::ZmInputState::num_1d_intgr + ZMF::ZmOutputTend::num_1d_intgr; + constexpr auto num_1d_scalr = ZMF::ZmInputState::num_1d_scalr + ZMF::ZmOutputTend::num_1d_scalr; + constexpr auto num_2d_midlv = ZMF::ZmInputState::num_2d_midlv + ZMF::ZmOutputTend::num_2d_midlv; + constexpr auto num_2d_intfc = ZMF::ZmInputState::num_2d_intfc + ZMF::ZmOutputTend::num_2d_intfc; constexpr int num_f_mid = (9+6); constexpr int num_f_int = (2+3); diff --git a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.hpp b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.hpp index 8d400a52c913..97b1f75c64c3 100644 --- a/components/eamxx/src/physics/zm/eamxx_zm_process_interface.hpp +++ b/components/eamxx/src/physics/zm/eamxx_zm_process_interface.hpp @@ -19,7 +19,7 @@ class ZMDeepConvection : public AtmosphereProcess using ZMF = zm::Functions; using PF = scream::PhysicsFunctions; using PC = scream::physics::Constants; - + using Scalar = typename ZMF::Scalar; using Spack = typename ZMF::Spack; using SPackInt = typename ZMF::SPackInt; @@ -62,11 +62,11 @@ class ZMDeepConvection : public AtmosphereProcess int m_nlev; // Structures for arguments to ZM - ZMF::zm_runtime_opt zm_opts; - ZMF::zm_input_state zm_input; - ZMF::zm_output_tend zm_output; - ZMF::zm_output_diag zm_diag; - + ZMF::ZmRuntimeOpt zm_opts; + ZMF::ZmInputState zm_input; + ZMF::ZmOutputTend zm_output; + ZMF::ZmOutputDiag zm_diag; + }; // class ZMDeepConvection } // namespace scream diff --git a/components/eamxx/src/physics/zm/eti/zm_input_state.cpp b/components/eamxx/src/physics/zm/eti/zm_input_state.cpp index d55e266bec20..6430c2baf17e 100644 --- a/components/eamxx/src/physics/zm/eti/zm_input_state.cpp +++ b/components/eamxx/src/physics/zm/eti/zm_input_state.cpp @@ -4,12 +4,12 @@ namespace scream { namespace zm { /* - * Explicit instantiation for doing zm_input_state on Reals using the + * Explicit instantiation for ZmInputState struct on Reals using the * default device. */ -template void Functions::zm_input_state::transpose(int ncol, int nlev_mid); -template void Functions::zm_input_state::transpose(int ncol, int nlev_mid); +template void Functions::ZmInputState::transpose(int ncol, int nlev_mid); +template void Functions::ZmInputState::transpose(int ncol, int nlev_mid); template struct Functions; diff --git a/components/eamxx/src/physics/zm/eti/zm_ientropy.cpp b/components/eamxx/src/physics/zm/eti/zm_invert_entropy.cpp similarity index 57% rename from components/eamxx/src/physics/zm/eti/zm_ientropy.cpp rename to components/eamxx/src/physics/zm/eti/zm_invert_entropy.cpp index a23d124fabfa..8b5f6da9e4b6 100644 --- a/components/eamxx/src/physics/zm/eti/zm_ientropy.cpp +++ b/components/eamxx/src/physics/zm/eti/zm_invert_entropy.cpp @@ -1,10 +1,10 @@ -#include "impl/zm_ientropy_impl.hpp" +#include "impl/zm_invert_entropy_impl.hpp" namespace scream { namespace zm { /* - * Explicit instantiation for doing ientropy on Reals using the + * Explicit instantiation for doing invert_entropy on Reals using the * default device. */ diff --git a/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp b/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp index f35c1a04d34e..7941f4814ddf 100644 --- a/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp +++ b/components/eamxx/src/physics/zm/eti/zm_output_tend.cpp @@ -4,12 +4,12 @@ namespace scream { namespace zm { /* - * Explicit instantiation for doing zm_input_state on Reals using the + * Explicit instantiation for ZmOutputTent struct with Reals using the * default device. */ -template void Functions::zm_output_tend::transpose(int ncol, int nlev_mid); -template void Functions::zm_output_tend::transpose(int ncol, int nlev_mid); +template void Functions::ZmOutputTend::transpose(int ncol, int nlev_mid); +template void Functions::ZmOutputTend::transpose(int ncol, int nlev_mid); template struct Functions; diff --git a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.cpp b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.cpp index 9a3ed0543969..edcbbbe6b4a2 100644 --- a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.cpp +++ b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.cpp @@ -6,39 +6,40 @@ using scream::Int; // A C++ interface to ZM fortran calls and vice versa extern "C" { - void zm_eamxx_bridge_init_c( Int pver_in ); - void zm_eamxx_bridge_run_c( Int ncol, // 01 - Real dtime, // 02 - bool is_first_step, // 03 - const Real *state_phis, // 04 - Real *state_z_mid, // 05 - Real *state_z_int, // 06 - const Real *state_p_mid, // 07 - const Real *state_p_int, // 08 - const Real *state_p_del, // 09 - Real *state_t, // 10 - Real *state_qv, // 11 - Real *state_u, // 12 - Real *state_v, // 13 - Real *state_omega, // 14 - const Real *state_cldfrac, // 15 - const Real *state_pblh, // 16 - const Real *tpert, // 17 - const Real *landfrac, // 18 - Real *output_prec, // 19 - Real *output_snow, // 20 - Real *output_cape, // 21 - Int *output_activity, // 22 - Real *output_tend_t, // 23 - Real *output_tend_q, // 24 - Real *output_tend_u, // 25 - Real *output_tend_v, // 26 - Real *output_rain_prod, // 27 - Real *output_snow_prod, // 28 - Real *output_prec_flux, // 29 - Real *output_snow_flux, // 30 - Real *output_mass_flux // 31 +void zm_eamxx_bridge_init_c( Int pver_in ); + +void zm_eamxx_bridge_run_c( Int ncol, // 01 + Real dtime, // 02 + bool is_first_step, // 03 + const Real *state_phis, // 04 + Real *state_z_mid, // 05 + Real *state_z_int, // 06 + const Real *state_p_mid, // 07 + const Real *state_p_int, // 08 + const Real *state_p_del, // 09 + Real *state_t, // 10 + Real *state_qv, // 11 + Real *state_u, // 12 + Real *state_v, // 13 + Real *state_omega, // 14 + const Real *state_cldfrac, // 15 + const Real *state_pblh, // 16 + const Real *tpert, // 17 + const Real *landfrac, // 18 + Real *output_prec, // 19 + Real *output_snow, // 20 + Real *output_cape, // 21 + Int *output_activity, // 22 + Real *output_tend_t, // 23 + Real *output_tend_q, // 24 + Real *output_tend_u, // 25 + Real *output_tend_v, // 26 + Real *output_rain_prod, // 27 + Real *output_snow_prod, // 28 + Real *output_prec_flux, // 29 + Real *output_snow_flux, // 30 + Real *output_mass_flux // 31 ); } // extern "C" : end _c decls @@ -50,9 +51,9 @@ void zm_eamxx_bridge_init( Int pver ){ } void zm_eamxx_bridge_run( Int ncol, Int pver, - ZMF::zm_input_state& zm_input, - ZMF::zm_output_tend& zm_output, - ZMF::zm_runtime_opt& zm_opts + ZMF::ZmInputState& zm_input, + ZMF::ZmOutputTend& zm_output, + ZMF::ZmRuntimeOpt& zm_opts ){ //---------------------------------------------------------------------------- zm_input.transpose(ncol,pver); diff --git a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.hpp b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.hpp index 6282a39b9537..07f776cce8f8 100644 --- a/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.hpp +++ b/components/eamxx/src/physics/zm/fortran_bridge/zm_eamxx_bridge.hpp @@ -16,9 +16,9 @@ using ZMF = zm::Functions; // Glue functions to call fortran from from C++ with the Data struct void zm_eamxx_bridge_init( Int pver ); void zm_eamxx_bridge_run( Int ncol, Int pver, - ZMF::zm_input_state& zm_input, - ZMF::zm_output_tend& zm_output, - ZMF::zm_runtime_opt& zm_opts + ZMF::ZmInputState& zm_input, + ZMF::ZmOutputTend& zm_output, + ZMF::ZmRuntimeOpt& zm_opts ); extern "C" { // _f function decls diff --git a/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp index aa28d0d4f750..3cf45289f53e 100644 --- a/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_input_state_impl.hpp @@ -10,7 +10,7 @@ namespace zm { // transpose method for fortran bridging template template -void Functions::zm_input_state::transpose(int ncol, int nlev_mid) +void Functions::ZmInputState::transpose(int ncol, int nlev_mid) { auto nlev_int = nlev_mid+1; @@ -100,7 +100,7 @@ void Functions::zm_input_state::transpose(int ncol, int nlev_mid) } template -void Functions::zm_input_state::calculate_tpert(int ncol, int nlev, bool is_first_step) +void Functions::ZmInputState::calculate_tpert(int ncol, int nlev, bool is_first_step) { const Real cpair = PC::Cpair.value; const Real latvap = PC::LatVap.value; diff --git a/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp similarity index 90% rename from components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp rename to components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp index 46accd228a3d..34d60721fbee 100644 --- a/components/eamxx/src/physics/zm/impl/zm_ientropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp @@ -1,5 +1,5 @@ -#ifndef ZM_IENTROPY_IMPL_HPP -#define ZM_IENTROPY_IMPL_HPP +#ifndef ZM_INVERT_ENTROPY_IMPL_HPP +#define ZM_INVERT_ENTROPY_IMPL_HPP #include "zm_functions.hpp" // for ETI only but harmless for GPU @@ -7,13 +7,13 @@ namespace scream { namespace zm { /* - * Implementation of zm ientropy. Clients should NOT + * Implementation of zm invert_entropy. Clients should NOT * #include this file, but include zm_functions.hpp instead. */ template KOKKOS_FUNCTION -void Functions::ientropy( +void Functions::invert_entropy( // Inputs const MemberType& team, const Real& s, @@ -116,7 +116,7 @@ void Functions::ientropy( Real est; // saturation vapor pressure qsat_hPa(t, p, est, qst); - EKAT_KERNEL_REQUIRE_MSG(converged, "ZM_CONV: IENTROPY: Failed to converge"); + EKAT_KERNEL_REQUIRE_MSG(converged, "ZM_CONV: INVERT_ENTROPY: Failed to converge"); } } // namespace zm diff --git a/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp index 1c8a4ca70d27..4d6fdbe537d7 100644 --- a/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_output_tend_impl.hpp @@ -10,7 +10,7 @@ namespace zm { // transpose method for fortran bridging template template -void Functions::zm_output_tend::transpose(int ncol, int nlev_mid) +void Functions::ZmOutputTend::transpose(int ncol, int nlev_mid) { auto nlev_int = nlev_mid+1; @@ -92,7 +92,7 @@ void Functions::zm_output_tend::transpose(int ncol, int nlev_mid) } template -void Functions::zm_output_tend::init(int ncol, int nlev_mid) +void Functions::ZmOutputTend::init(int ncol, int nlev_mid) { auto nlev_int = nlev_mid+1; auto nlev_mid_packs = ekat::npack(nlev_mid); diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 859855d0f108..6f662cf15401 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -112,7 +112,7 @@ void ientropy(IentropyData& d) auto t_h = Kokkos::create_mirror_view(t_d); Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const MemberType& team) { - ZMF::ientropy( + ZMF::invert_entropy( team, s, p, diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index c01c19e7b04d..a21c04b836a1 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -73,26 +73,58 @@ struct Functions { static inline constexpr Real cpwv = 1.810e3; // specific heat of water vapor (J/K/kg) - static inline constexpr Int LOOPMAX = 100; // Max number of iteration loops for ientropy + static inline constexpr Int LOOPMAX = 100; // Max number of iteration loops for invert_entropy static inline constexpr Real tol_coeff = 0.001; // tolerance coeficient static inline constexpr Real tol_eps = 3.e-8; // small value for tolerance calculation }; - struct zm_runtime_opt { - zm_runtime_opt() = default; - bool apply_tendencies = false; + //---------------------------------------------------------------------------- + // Purpose: derived type to hold ZM tunable parameters + //---------------------------------------------------------------------------- + struct ZmRuntimeOpt { + ZmRuntimeOpt() = default; void load_runtime_options(ekat::ParameterList& params) { apply_tendencies = params.get("apply_tendencies", apply_tendencies); } + + Real tau; // convective adjustment time scale + Real alfa; // max downdraft mass flux fraction + Real ke; // evaporation efficiency + Real dmpdz; // fractional mass entrainment rate [1/m] + bool tpert_fix; // flag to disable using applying tpert to PBL-rooted convection + Real tpert_fac; // tunable temperature perturbation factor + Real tiedke_add; // tunable temperature perturbation + Real c0_lnd; // autoconversion coefficient over land + Real c0_ocn; // autoconversion coefficient over ocean + int num_cin; // num of neg buoyancy regions allowed before the conv top and CAPE calc are completed + int limcnv; // upper pressure interface level to limit deep convection + int mx_bot_lyr_adj; // bot layer index adjustment for launch level search + bool trig_dcape; // true if to using DCAPE trigger - based on CAPE generation by the dycor + bool trig_ull; // true if to using the "unrestricted launch level" (ULL) mode + bool clos_dyn_adj; // flag for mass flux adjustment to CAPE closure + bool no_deep_pbl; // flag to eliminate deep convection within PBL + bool apply_tendencies; + // ZM micro parameters + bool zm_microp; // switch for convective microphysics + bool old_snow; // switch to calculate snow prod in zm_conv_evap() (old treatment before zm_microp was implemented) + Real auto_fac; // ZM microphysics enhancement factor for droplet-rain autoconversion + Real accr_fac; // ZM microphysics enhancement factor for droplet-rain accretion + Real micro_dcs; // ZM microphysics size threshold for cloud ice to snow autoconversion [m] + // MCSP parameters + bool mcsp_enabled; // flag for mesoscale coherent structure parameterization (MSCP) + Real mcsp_t_coeff; // MCSP coefficient for temperature tendencies + Real mcsp_q_coeff; // MCSP coefficient for specific humidity tendencies + Real mcsp_u_coeff; // MCSP coefficient for zonal momentum tendencies + Real mcsp_v_coeff; // MCSP coefficient for meridional momentum tendencies }; // ----------------------------------------------------------------------------------------------- - struct zm_input_state { - zm_input_state() = default; + struct ZmInputState { + ZmInputState() = default; // ------------------------------------------------------------------------- Real dtime; // model phsyics time step [s] bool is_first_step; // flag for first call @@ -171,8 +203,8 @@ struct Functions { // ----------------------------------------------------------------------------------------------- - struct zm_output_tend { - zm_output_tend() = default; + struct ZmOutputTend { + ZmOutputTend() = default; // variable counters for device-side only static constexpr int num_1d_intgr = 1; // number of 1D integer views @@ -237,45 +269,10 @@ struct Functions { // ----------------------------------------------------------------------------------------------- - struct zm_output_diag { - zm_output_diag() = default; + struct ZmOutputDiag { + ZmOutputDiag() = default; }; - // ----------------------------------------------------------------------------------------------- - - //---------------------------------------------------------------------------- - // Purpose: derived type to hold ZM tunable parameters - //---------------------------------------------------------------------------- - struct ZmCommonInit { - Real tau; // convective adjustment time scale - Real alfa; // max downdraft mass flux fraction - Real ke; // evaporation efficiency - Real dmpdz; // fractional mass entrainment rate [1/m] - bool tpert_fix; // flag to disable using applying tpert to PBL-rooted convection - Real tpert_fac; // tunable temperature perturbation factor - Real tiedke_add; // tunable temperature perturbation - Real c0_lnd; // autoconversion coefficient over land - Real c0_ocn; // autoconversion coefficient over ocean - int num_cin; // num of neg buoyancy regions allowed before the conv top and CAPE calc are completed - int limcnv; // upper pressure interface level to limit deep convection - int mx_bot_lyr_adj; // bot layer index adjustment for launch level search - bool trig_dcape; // true if to using DCAPE trigger - based on CAPE generation by the dycor - bool trig_ull; // true if to using the "unrestricted launch level" (ULL) mode - bool clos_dyn_adj; // flag for mass flux adjustment to CAPE closure - bool no_deep_pbl; // flag to eliminate deep convection within PBL - // ZM micro parameters - bool zm_microp; // switch for convective microphysics - bool old_snow; // switch to calculate snow prod in zm_conv_evap() (old treatment before zm_microp was implemented) - Real auto_fac; // ZM microphysics enhancement factor for droplet-rain autoconversion - Real accr_fac; // ZM microphysics enhancement factor for droplet-rain accretion - Real micro_dcs; // ZM microphysics size threshold for cloud ice to snow autoconversion [m] - // MCSP parameters - bool mcsp_enabled; // flag for mesoscale coherent structure parameterization (MSCP) - Real mcsp_t_coeff; // MCSP coefficient for temperature tendencies - Real mcsp_q_coeff; // MCSP coefficient for specific humidity tendencies - Real mcsp_u_coeff; // MCSP coefficient for zonal momentum tendencies - Real mcsp_v_coeff; // MCSP coefficient for meridional momentum tendencies - }; // // --------- Init/Finalize Functions --------- @@ -291,7 +288,7 @@ struct Functions { // KOKKOS_FUNCTION - static void ientropy( + static void invert_entropy( // Inputs const MemberType& team, const Real& s, // entropy [J/kg] @@ -348,7 +345,7 @@ struct Functions { // // --------- Members --------- // - inline static ZmCommonInit s_common_init; + inline static ZmRuntimeOpt s_common_init; }; // struct Functions @@ -360,7 +357,7 @@ struct Functions { # include "impl/zm_input_state_impl.hpp" # include "impl/zm_output_tend_impl.hpp" # include "impl/zm_common_init_impl.hpp" -# include "impl/zm_ientropy_impl.hpp" +# include "impl/zm_invert_entropy_impl.hpp" # include "impl/zm_entropy_impl.hpp" #endif // GPU && !KOKKOS_ENABLE_*_RELOCATABLE_DEVICE_CODE #endif // ZM_FUNCTIONS_HPP From 1766af86e3fac0310eb4184bf3c9a0db48950ec0 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:55:48 -0700 Subject: [PATCH 378/398] Update components/eamxx/src/physics/zm/zm_functions.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/eamxx/src/physics/zm/zm_functions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/zm_functions.hpp b/components/eamxx/src/physics/zm/zm_functions.hpp index a21c04b836a1..a7d911ad53bc 100644 --- a/components/eamxx/src/physics/zm/zm_functions.hpp +++ b/components/eamxx/src/physics/zm/zm_functions.hpp @@ -75,7 +75,7 @@ struct Functions { static inline constexpr Int LOOPMAX = 100; // Max number of iteration loops for invert_entropy - static inline constexpr Real tol_coeff = 0.001; // tolerance coeficient + static inline constexpr Real tol_coeff = 0.001; // tolerance coefficient static inline constexpr Real tol_eps = 3.e-8; // small value for tolerance calculation }; From b277a68b5b72bf94ef63c6801fe947d20ec4f1ab Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:55:59 -0700 Subject: [PATCH 379/398] Update components/eamxx/src/physics/zm/tests/CMakeLists.txt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/eamxx/src/physics/zm/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/tests/CMakeLists.txt b/components/eamxx/src/physics/zm/tests/CMakeLists.txt index b063ec1281ba..7cfb49ea738a 100644 --- a/components/eamxx/src/physics/zm/tests/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/tests/CMakeLists.txt @@ -5,7 +5,7 @@ add_subdirectory(infra) set(ZM_TESTS_SRCS zm_test_find_mse_max.cpp zm_ientropy_tests.cpp - zm_entropy_tests.cpp + zm_entropy_tests.cpp ) # ZM_TESTS_SRCS # All tests should understand the same baseline args From bde0a1e0f57e1693feddc2ec36982435ca390327 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:56:10 -0700 Subject: [PATCH 380/398] Update components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp index 6f662cf15401..bdf31bc71eae 100644 --- a/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp +++ b/components/eamxx/src/physics/zm/tests/infra/zm_test_data.cpp @@ -56,7 +56,7 @@ void zm_common_finalize_f() } -// Wrapper around gw_init for cxx +// Wrapper around zm_common_init for cxx void zm_common_init() { ZMF::zm_common_init(); From b6c07401b23d57429b60915bbb892cb73208caec Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:56:24 -0700 Subject: [PATCH 381/398] Update components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp index 34d60721fbee..85ea0f530f4a 100644 --- a/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp @@ -27,7 +27,7 @@ void Functions::invert_entropy( //---------------------------------------------------------------------------- // Local variables bool converged; // flag for convergence - Real a, b, c, d, ebr, fa, fb, fc, pbr, qbr, rbr, sbr, xm; + Real a, b, c, d = 0, ebr, fa, fb, fc, pbr, qbr, rbr, sbr, xm; //---------------------------------------------------------------------------- // initialize variables From 958e6e6c841834e865d805165d244ec7f69e1c22 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:56:33 -0700 Subject: [PATCH 382/398] Update components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp index 7af698b5e4f4..7ba876ef8708 100644 --- a/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp +++ b/components/eamxx/src/physics/zm/tests/zm_ientropy_tests.cpp @@ -29,7 +29,7 @@ struct UnitWrap::UnitTest::TestIentropy : public UnitWrap::UnitTest::Base static constexpr Int num_runs = sizeof(baseline_data) / sizeof(IentropyData); // Generate random input data - // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + // Alternatively, you can use the baseline_data constructors/initializer lists to hardcode data for (auto& d : baseline_data) { d.randomize(engine); } From 2388a7ece8abbc99bc1cf7ec8431bad78684f128 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:57:25 -0700 Subject: [PATCH 383/398] Update components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp index 627bc5b5d2f0..6a66aa418862 100644 --- a/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp +++ b/components/eamxx/src/physics/zm/tests/zm_entropy_tests.cpp @@ -29,7 +29,7 @@ struct UnitWrap::UnitTest::TestEntropy : public UnitWrap::UnitTest::Base { static constexpr Int num_runs = sizeof(baseline_data) / sizeof(EntropyData); // Generate random input data - // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + // Alternatively, you can use the baseline_data constructors/initializer lists to hardcode data for (auto& d : baseline_data) { d.randomize(engine); } From 35b6df0c173b3ec69520d735dd11ea2e9176b783 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:58:32 -0700 Subject: [PATCH 384/398] Fix spelling mistka ein code generator --- components/eamxx/scripts/gen-boiler/gen_boiler.py | 2 +- components/eamxx/scripts/gen-boiler/run-gb-tests | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eamxx/scripts/gen-boiler/gen_boiler.py b/components/eamxx/scripts/gen-boiler/gen_boiler.py index baa6b32dc30d..5a6473a32855 100644 --- a/components/eamxx/scripts/gen-boiler/gen_boiler.py +++ b/components/eamxx/scripts/gen-boiler/gen_boiler.py @@ -1841,7 +1841,7 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): """ // Generate random input data - // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + // Alternatively, you can use the baseline_data constructors/initializer lists to hardcode data for (auto& d : baseline_data) { d.randomize(engine); }""" diff --git a/components/eamxx/scripts/gen-boiler/run-gb-tests b/components/eamxx/scripts/gen-boiler/run-gb-tests index 795490254d67..87f4aa6d4235 100755 --- a/components/eamxx/scripts/gen-boiler/run-gb-tests +++ b/components/eamxx/scripts/gen-boiler/run-gb-tests @@ -1290,7 +1290,7 @@ void Functions::fake_sub( static constexpr Int num_runs = sizeof(baseline_data) / sizeof(FakeSubData); // Generate random input data - // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + // Alternatively, you can use the baseline_data constructors/initializer lists to hardcode data for (auto& d : baseline_data) { d.randomize(engine); } From 6318629cff90eeba731cb194d0d8ab8bb8eb332b Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 28 Jan 2026 08:58:57 -0700 Subject: [PATCH 385/398] Fix uninit var --- components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp b/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp index 85ea0f530f4a..0fccfa7bd0a0 100644 --- a/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp +++ b/components/eamxx/src/physics/zm/impl/zm_invert_entropy_impl.hpp @@ -27,7 +27,7 @@ void Functions::invert_entropy( //---------------------------------------------------------------------------- // Local variables bool converged; // flag for convergence - Real a, b, c, d = 0, ebr, fa, fb, fc, pbr, qbr, rbr, sbr, xm; + Real a, b, c, d = 0, ebr = 0, fa, fb, fc, pbr, qbr, rbr, sbr, xm; //---------------------------------------------------------------------------- // initialize variables From 031b08d82457816f418cf565f8757bc3ed1e72c8 Mon Sep 17 00:00:00 2001 From: Aaron Donahue Date: Wed, 28 Jan 2026 15:29:18 -0800 Subject: [PATCH 386/398] Remove corrective_ml process from eamxx This commit removes a depracated capability in EAMxx, corrective_ml. --- .../eamxx/src/mct_coupling/CMakeLists.txt | 3 - components/eamxx/src/physics/CMakeLists.txt | 3 - .../src/physics/ml_correction/CMakeLists.txt | 29 --- .../eamxx_ml_correction_process_interface.cpp | 240 ------------------ .../eamxx_ml_correction_process_interface.hpp | 64 ----- .../physics/ml_correction/ml_correction.py | 215 ---------------- .../eamxx/src/physics/register_physics.hpp | 6 - 7 files changed, 560 deletions(-) delete mode 100644 components/eamxx/src/physics/ml_correction/CMakeLists.txt delete mode 100644 components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.cpp delete mode 100644 components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.hpp delete mode 100644 components/eamxx/src/physics/ml_correction/ml_correction.py diff --git a/components/eamxx/src/mct_coupling/CMakeLists.txt b/components/eamxx/src/mct_coupling/CMakeLists.txt index 143702e91162..92887dbd9346 100644 --- a/components/eamxx/src/mct_coupling/CMakeLists.txt +++ b/components/eamxx/src/mct_coupling/CMakeLists.txt @@ -48,9 +48,6 @@ if (TARGET zm) list(APPEND SCREAM_LIBS zm) endif() -if (SCREAM_ENABLE_ML_CORRECTION) - list (APPEND SCREAM_LIBS ml_correction) -endif () if (SCREAM_ENABLE_MAM) list (APPEND SCREAM_LIBS mam) endif() diff --git a/components/eamxx/src/physics/CMakeLists.txt b/components/eamxx/src/physics/CMakeLists.txt index 556dae0475c2..5b5c7a240e52 100644 --- a/components/eamxx/src/physics/CMakeLists.txt +++ b/components/eamxx/src/physics/CMakeLists.txt @@ -13,9 +13,6 @@ else() endif() add_subdirectory(shoc) add_subdirectory(cld_fraction) -if (SCREAM_ENABLE_ML_CORRECTION) - add_subdirectory(ml_correction) -endif() add_subdirectory(spa) add_subdirectory(nudging) if (SCREAM_ENABLE_MAM) diff --git a/components/eamxx/src/physics/ml_correction/CMakeLists.txt b/components/eamxx/src/physics/ml_correction/CMakeLists.txt deleted file mode 100644 index 6590c63b8c21..000000000000 --- a/components/eamxx/src/physics/ml_correction/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -set(MLCORRECTION_SRCS - eamxx_ml_correction_process_interface.cpp -) - -set(MLCORRECTION_HEADERS - eamxx_ml_correction_process_interface.hpp -) -include(ScreamUtils) - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0") - message(STATUS "Downloading Pybind11") - include(FetchContent) - - FetchContent_Declare(pybind11 GIT_REPOSITORY https://github.com/pybind/pybind11.git GIT_TAG v2.10.4) - FetchContent_MakeAvailable(pybind11) -else() - message(FATAL_ERROR "pybind11 is missing. Use CMake >= 3.11 or download it") -endif() -find_package(Python REQUIRED COMPONENTS Interpreter Development) - -add_library(ml_correction ${MLCORRECTION_SRCS}) -target_compile_definitions(ml_correction PUBLIC EAMXX_HAS_ML_CORRECTION) -target_compile_definitions(ml_correction PRIVATE -DML_CORRECTION_CUSTOM_PATH="${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(ml_correction SYSTEM PUBLIC ${PYTHON_INCLUDE_DIRS}) -target_link_libraries(ml_correction eamxx_physics_share scream_share pybind11::pybind11 Python::Python) - -if (TARGET eamxx_physics) - # Add this library to eamxx_physics - target_link_libraries(eamxx_physics INTERFACE ml_correction) -endif() diff --git a/components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.cpp b/components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.cpp deleted file mode 100644 index 73e4748f260a..000000000000 --- a/components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include "eamxx_ml_correction_process_interface.hpp" -#include "share/physics/physics_constants.hpp" -#include "share/property_checks/field_lower_bound_check.hpp" -#include "share/property_checks/field_within_interval_check.hpp" -#include "share/field/field_utils.hpp" - -#include -#include -#include -#include -#include - -namespace scream { -// ========================================================================================= -MLCorrection::MLCorrection(const ekat::Comm &comm, - const ekat::ParameterList ¶ms) - : AtmosphereProcess(comm, params) { - m_ML_model_path_tq = m_params.get("ml_model_path_tq"); - m_ML_model_path_uv = m_params.get("ml_model_path_uv"); - m_ML_model_path_sfc_fluxes = m_params.get("ml_model_path_sfc_fluxes"); - m_fields_ml_output_variables = m_params.get>("ml_output_fields"); - m_ML_correction_unit_test = m_params.get("ml_correction_unit_test"); -} - -// ========================================================================================= -void MLCorrection::set_grids( - const std::shared_ptr grids_manager) { - using namespace ekat::units; - using namespace ShortFieldTagsNames; - - // The units of mixing ratio Q are technically non-dimensional. - // Nevertheless, for output reasons, we like to see 'kg/kg'. - constexpr int ps = Pack::n; - m_grid = grids_manager->get_grid("physics"); - const auto &grid_name = m_grid->name(); - m_num_cols = m_grid->get_num_local_dofs(); // Number of columns on this rank - m_num_levs = - m_grid->get_num_vertical_levels(); // Number of levels per column - // Define the different field layouts that will be used for this process - - // Layout for 3D (2d horiz X 1d vertical) variable defined at mid-level and - // interfaces - FieldLayout scalar2d = m_grid->get_2d_scalar_layout(); - FieldLayout scalar3d_mid = m_grid->get_3d_scalar_layout(true); - FieldLayout scalar3d_int = m_grid->get_3d_scalar_layout(false); - FieldLayout vector3d_mid = m_grid->get_3d_vector_layout(true,2); - const auto m2 = pow(m,2); - if (not m_ML_correction_unit_test) { - const auto s2 = pow(s,2); - auto nondim = Units::nondimensional(); - add_field("phis", scalar2d, m2/s2, grid_name); - add_field("sfc_alb_dif_vis", scalar2d, nondim, grid_name); - add_field("SW_flux_dn", scalar3d_int, W/m2, grid_name, ps); - add_field("sfc_flux_sw_net", scalar2d, W/m2, grid_name); - add_field("sfc_flux_lw_dn", scalar2d, W/m2, grid_name); - m_lat = m_grid->get_geometry_data("lat"); - m_lon = m_grid->get_geometry_data("lon"); - } - - /* ----------------------- WARNING --------------------------------*/ - /* The following is a HACK to get things moving, we don't want to - * add all fields as "updated" long-term. A separate stream of work - * is adapting the infrastructure to allow for a generic "add_field" call - * to be used here which we can then setup using the m_fields_ml_output_variables variable - */ - add_field("T_mid", scalar3d_mid, K, grid_name, ps); - add_field("horiz_winds", vector3d_mid, m/s, grid_name, ps); - /* Note: we also need to update the precipitation after ML commits any column drying */ - add_field("pseudo_density", scalar3d_mid, Pa, grid_name, ps); - add_field("precip_liq_surf_mass", scalar2d, kg/m2, grid_name); - add_field("precip_ice_surf_mass", scalar2d, kg/m2, grid_name); - /* ----------------------- WARNING --------------------------------*/ - add_tracer("qv", m_grid, kg/kg, ps); - add_group("tracers", grid_name, 1, MonolithicAlloc::Required); -} - -// ========================================================================================= -void MLCorrection::initialize_impl(const RunType /* run_type */) { - fpe_mask = ekat::get_enabled_fpes(); - ekat::disable_all_fpes(); // required for importing numpy - if ( Py_IsInitialized() == 0 ) { - pybind11::initialize_interpreter(); - } - pybind11::module sys = pybind11::module::import("sys"); - sys.attr("path").attr("insert")(1, ML_CORRECTION_CUSTOM_PATH); - py_correction = pybind11::module::import("ml_correction"); - ML_model_tq = py_correction.attr("get_ML_model")(m_ML_model_path_tq); - ML_model_uv = py_correction.attr("get_ML_model")(m_ML_model_path_uv); - ML_model_sfc_fluxes = py_correction.attr("get_ML_model")(m_ML_model_path_sfc_fluxes); - ekat::enable_fpes(fpe_mask); - - // Enforce bounds on quantities adjusted by ML using Field Property Checks - using LowerBound = FieldLowerBoundCheck; - add_postcondition_check(get_field_out("precip_liq_surf_mass"),m_grid,0,true); - add_postcondition_check(get_field_out("precip_ice_surf_mass"),m_grid,0,true); - // Add sanity property check for other variables. - using Interval = FieldWithinIntervalCheck; - add_postcondition_check(get_field_out("qv"),m_grid,0,0.2,true); - add_postcondition_check(get_field_out("T_mid"),m_grid,100.0,500.0,false); - add_postcondition_check(get_field_out("horiz_winds"),m_grid,-400.0,400.0,false); -} - -// ========================================================================================= -void MLCorrection::run_impl(const double dt) { - // use model time to infer solar zenith angle for the ML prediction - auto current_ts = start_of_step_ts(); - std::string datetime_str = current_ts.get_date_string() + " " + current_ts.get_time_string(); - - const auto &phis = get_field_in("phis").get_view(); - const auto &sfc_alb_dif_vis = get_field_in("sfc_alb_dif_vis").get_view(); - - const auto &qv = get_field_out("qv").get_view(); - const auto &T_mid = get_field_out("T_mid").get_view(); - const auto &SW_flux_dn = get_field_out("SW_flux_dn").get_view(); - const auto &sfc_flux_sw_net = get_field_out("sfc_flux_sw_net").get_view(); - const auto &sfc_flux_lw_dn = get_field_out("sfc_flux_lw_dn").get_view(); - const auto &u = get_field_out("horiz_winds").get_component(0).get_view(); - const auto &v = get_field_out("horiz_winds").get_component(1).get_view(); - - // For precipitation adjustment we need to track the change in column integrated 'qv' - // So we clone the original qv before ML changes the state so we can back out a qv_tend - // to use with precip adjustment. - auto qv_src = get_field_in("qv"); - auto qv_in = qv_src.clone(); - - auto h_lat = m_lat.get_view(); - auto h_lon = m_lon.get_view(); - - const auto& tracers = get_group_out("tracers"); - const auto& tracers_info = tracers.m_info; - Int num_tracers = tracers_info->size(); - - ekat::disable_all_fpes(); // required for importing numpy - if ( Py_IsInitialized() == 0 ) { - pybind11::initialize_interpreter(); - } - // for qv, we need to stride across number of tracers - pybind11::object ob1 = py_correction.attr("update_fields")( - pybind11::array_t( - m_num_cols * m_num_levs, T_mid.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols * m_num_levs * num_tracers, qv.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols * m_num_levs, u.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols * m_num_levs, v.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols, h_lat.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols, h_lon.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols, phis.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols * (m_num_levs+1), SW_flux_dn.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols, sfc_alb_dif_vis.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols, sfc_flux_sw_net.data(), pybind11::str{}), - pybind11::array_t( - m_num_cols, sfc_flux_lw_dn.data(), pybind11::str{}), - m_num_cols, m_num_levs, num_tracers, dt, - ML_model_tq, ML_model_uv, ML_model_sfc_fluxes, datetime_str); - pybind11::gil_scoped_release no_gil; - ekat::enable_fpes(fpe_mask); - - // Now back out the qv change abd apply it to precipitation, only if Tq ML is turned on - if (m_ML_model_path_tq != "none") { - using PC = scream::physics::Constants; - using KT = KokkosTypes; - using MT = typename KT::MemberType; - using TPF = ekat::TeamPolicyFactory; - const auto &pseudo_density = get_field_in("pseudo_density").get_view(); - const auto &precip_liq_surf_mass = get_field_out("precip_liq_surf_mass").get_view(); - const auto &precip_ice_surf_mass = get_field_out("precip_ice_surf_mass").get_view(); - constexpr Real g = PC::gravit; - const auto num_levs = m_num_levs; - const auto policy = TPF::get_default_team_policy(m_num_cols, m_num_levs); - - const auto &qv_told = qv_in.get_view(); - const auto &qv_tnew = get_field_in("qv").get_view(); - Kokkos::parallel_for("Compute WVP diff", policy, - KOKKOS_LAMBDA(const MT& team) { - const int icol = team.league_rank(); - auto qold_icol = ekat::subview(qv_told,icol); - auto qnew_icol = ekat::subview(qv_tnew,icol); - auto rho_icol = ekat::subview(pseudo_density,icol); - Real net_column_moistening = 0; - // Compute WaterVaporPath Difference - // The water vapor path (WVP) is calculated as the integral of d_qv over the vertical column - // which is converted to the units of precipitation which are kg/m*m - // WVP = sum( d_qv * pseudo_density / gravity ), - // where d_qv = qv_new - qv_old - // units sanity check - // d_qv = kg/kg - // pseudo_density = Pa = kg/m/s2 - // gravity = m/s2 - // d_qv * pseduo_density / gravity = kg/kg * kg/m/s2 * s2/m = kg/m2 - // Compute WaterVaporPath Difference - Kokkos::parallel_reduce(Kokkos::TeamVectorRange(team, num_levs), - [&] (const int& ilev, Real& lsum) { - lsum += (qnew_icol(ilev)-qold_icol(ilev)) * rho_icol(ilev) / g; - },Kokkos::Sum(net_column_moistening)); - team.team_barrier(); - // Adjust Precipitation - // - Note, we subtract the water vapor path because positive precip represents - // a descrease in qv. - auto tot_precip = precip_liq_surf_mass(icol)+precip_ice_surf_mass(icol); - if (tot_precip>0) { - // adjust precip by weighted avg of both phases - Kokkos::single(Kokkos::PerTeam(team), [&] { - auto liq_frac = precip_liq_surf_mass(icol)/tot_precip; - auto ice_frac = precip_ice_surf_mass(icol)/tot_precip; - precip_liq_surf_mass(icol) -= liq_frac*net_column_moistening; - precip_ice_surf_mass(icol) -= ice_frac*net_column_moistening; - }); - } else { - // Apply all the adjustment to a single phase based on surface temperature - Kokkos::single(Kokkos::PerTeam(team), [&] { - auto T_icol = ekat::subview(T_mid,icol); - if (T_icol(num_levs-1)>273.15) { - precip_liq_surf_mass(icol) -= net_column_moistening; - } else { - precip_ice_surf_mass(icol) -= net_column_moistening; - } - }); - } - // Note, with the above formulation it is possible for the precipitation to go negative. - // We rely on the field property checker defined in the intialization function to repair - // any instances of negative precipitation. - }); - } -} - -// ========================================================================================= -void MLCorrection::finalize_impl() { - // Do nothing -} -// ========================================================================================= - -} // namespace scream diff --git a/components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.hpp b/components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.hpp deleted file mode 100644 index e90d0b496eef..000000000000 --- a/components/eamxx/src/physics/ml_correction/eamxx_ml_correction_process_interface.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef SCREAM_ML_CORRECTION_HPP -#define SCREAM_ML_CORRECTION_HPP - -#include "share/atm_process/atmosphere_process.hpp" - -#include -#include -#include -#include -#include - -namespace scream { - -/* - * The class responsible to handle the calculation of the subgrid cloud - * fractions - * - * The AD should store exactly ONE instance of this class stored - * in its list of subcomponents (the AD should make sure of this). - */ - -class MLCorrection : public AtmosphereProcess { - public: - using Pack = ekat::Pack; - // Constructors - MLCorrection(const ekat::Comm &comm, const ekat::ParameterList ¶ms); - - // The type of subcomponent - AtmosphereProcessType type() const { return AtmosphereProcessType::Physics; } - - // The name of the subcomponent - std::string name() const { return "MLCorrection"; } - - // Set the grid - void set_grids(const std::shared_ptr grids_manager); - - protected: - // The three main overrides for the subcomponent - void initialize_impl(const RunType run_type); - void run_impl(const double dt); - void finalize_impl(); - void apply_tendency(Field& base, const Field& next, const int dt); - - std::shared_ptr m_grid; - // Keep track of field dimensions and the iteration count - Int m_num_cols; - Int m_num_levs; - Field m_lat; - Field m_lon; - std::string m_ML_model_path_tq; - std::string m_ML_model_path_uv; - std::string m_ML_model_path_sfc_fluxes; - std::vector m_fields_ml_output_variables; - bool m_ML_correction_unit_test; - pybind11::module py_correction; - pybind11::object ML_model_tq; - pybind11::object ML_model_uv; - pybind11::object ML_model_sfc_fluxes; - int fpe_mask; -}; // class MLCorrection - -} // namespace scream - -#endif // SCREAM_ML_CORRECTION_HPP diff --git a/components/eamxx/src/physics/ml_correction/ml_correction.py b/components/eamxx/src/physics/ml_correction/ml_correction.py deleted file mode 100644 index acecdd95b467..000000000000 --- a/components/eamxx/src/physics/ml_correction/ml_correction.py +++ /dev/null @@ -1,215 +0,0 @@ -import numpy as np -import xarray as xr -import datetime -from vcm import cos_zenith_angle -from scream_run.steppers.machine_learning import ( - MachineLearningConfig, - open_model, - predict, -) - - -def get_ML_model(model_path): - if model_path == "NONE": - return None - config = MachineLearningConfig(models=[model_path]) - model = open_model(config) - return model - - -def ensure_correction_ordering(correction): - """Ensure that the ordering of the correction is always (ncol, z)""" - for key in correction: - if "z" in correction[key].dims: - correction[key] = correction[key].transpose("ncol", "z") - return correction - - -def get_ML_correction_dQ1_dQ2(model, T_mid, qv, cos_zenith, lat, phis, dt): - """Get ML correction for air temperature (dQ1) and specific humidity (dQ2) - - Args: - model: pre-trained ML model for dQ1 and dQ2 - T_mid: air temperature - qv: specific humidity - cos_zenith: cosine zenith angle - dt: time step (s) - """ - ds = xr.Dataset( - data_vars=dict( - T_mid=(["ncol", "z"], T_mid), - qv=(["ncol", "z"], qv), - cos_zenith_angle=(["ncol"], cos_zenith), - lat=(["ncol"], lat), - surface_geopotential=(["ncol"], phis), - ) - ) - return ensure_correction_ordering(predict(model, ds, dt)) - - -def get_ML_correction_dQu_dQv(model, T_mid, qv, cos_zenith, lat, phis, u, v, dt): - """Get ML correction for eastward wind (dQu or dQxwind) and northward wind (dQv or dQywind) - - Args: - model: pre-trained ML model for dQu and dQv - T_mid: air temperature - qv: specific humidity - cos_zenith: cosine zenith angle - lat: latitude - phis: surface geopotential - u: horizontal wind in x-direction - v: horizontal wind in y-direction - dt: time step (s) - """ - ds = xr.Dataset( - data_vars=dict( - T_mid=(["ncol", "z"], T_mid), - qv=(["ncol", "z"], qv), - U=(["ncol", "z"], u), - V=(["ncol", "z"], v), - lat=(["ncol"], lat), - surface_geopotential=(["ncol"], phis), - cos_zenith_angle=(["ncol"], cos_zenith), - ) - ) - output = ensure_correction_ordering(predict(model, ds, dt)) - # rename dQxwind and dQywind to dQu and dQv if needed - if "dQxwind" in output.keys(): - output["dQu"] = output.pop("dQxwind") - if "dQywind" in output.keys(): - output["dQv"] = output.pop("dQywind") - - return output - - -def get_ML_correction_sfc_fluxes( - model, - T_mid, - qv, - cos_zenith, - lat, - phis, - sfc_alb_dif_vis, - sw_flux_dn, - dt, -): - """Get ML correction for overriding surface fluxes (net shortwave and downward longwave) - ML model should have the following output variables: - net_shortwave_sfc_flux_via_transmissivity - override_for_time_adjusted_total_sky_downward_longwave_flux_at_surface - - Args: - model: pre-trained ML model for radiative fluxes - T_mid: air temperature - qv: specific humidity - cos_zenith: cosine zenith angle - lat: latitude - phis: surface geopotential - sfc_alb_dif_vis: surface albedo for diffuse shortwave radiation - sw_flux_dn: downward shortwave flux - dt: time step (s) - """ - SW_flux_dn_at_model_top = sw_flux_dn[:, 0] - ds = xr.Dataset( - data_vars=dict( - T_mid=(["ncol", "z"], T_mid), - qv=(["ncol", "z"], qv), - lat=(["ncol"], lat), - surface_geopotential=(["ncol"], phis), - cos_zenith_angle=(["ncol"], cos_zenith), - surface_diffused_shortwave_albedo=(["ncol"], sfc_alb_dif_vis), - total_sky_downward_shortwave_flux_at_top_of_atmosphere=( - ["ncol"], - SW_flux_dn_at_model_top, - ), - ) - ) - return predict(model, ds, dt) - - -def update_fields( - T_mid, - qv, - u, - v, - lat, - lon, - phis, - sw_flux_dn, - sfc_alb_dif_vis, - sfc_flux_sw_net, - sfc_flux_lw_dn, - Ncol, - Nlev, - num_tracers, - dt, - model_tq, - model_uv, - model_sfc_fluxes, - current_time, -): - """ - T_mid: temperature - qv: specific humidity - u: x-component of wind - v: y-component of wind - lat: latitude - lon: longitude - phis: surface geopotential - SW_flux_dn_at_model_top: downwelling shortwave flux at the top of the model - sfc_alb_dif_vis: surface diffuse shortwave albedo - sfc_flux_sw_net - sfc_flux_lw_dn - Ncol: number of columns - Nlev: number of levels - num_tracers: number of tracers - dt: time step (s) - model_tq: path to the ML model for temperature and specific humidity - model_uv: path to the ML model for u and v - current_time: current time in the format "YYYY-MM-DD HH:MM:SS" - """ - T_mid = np.reshape(T_mid, (-1, Nlev)) - u = np.reshape(u, (-1, Nlev)) - v = np.reshape(v, (-1, Nlev)) - # qv is a 3D array of shape (Ncol, num_tracers, Nlev) - # by default, qv is the frist tracer variable - qv = np.reshape(qv, (-1, num_tracers, Nlev)) - current_datetime = datetime.datetime.strptime(current_time, "%Y-%m-%d %H:%M:%S") - cos_zenith = cos_zenith_angle( - current_datetime, - lon, - lat, - ) - if model_tq is not None: - correction_tq = get_ML_correction_dQ1_dQ2( - model_tq, - T_mid, - qv[:, 0, :], - cos_zenith, - lat, - phis, - dt - ) - T_mid[:, :] += correction_tq["dQ1"].values * dt - qv[:, 0, :] += correction_tq["dQ2"].values * dt - if model_uv is not None: - correction_uv = get_ML_correction_dQu_dQv( - model_uv, T_mid, qv[:, 0, :], cos_zenith, lat, phis, u, v, dt - ) - u[:, :] += correction_uv["dQu"].values * dt - v[:, :] += correction_uv["dQv"].values * dt - if model_sfc_fluxes is not None: - sw_flux_dn = np.reshape(sw_flux_dn, (-1, Nlev+1)) - correction_sfc_fluxes = get_ML_correction_sfc_fluxes( - model_sfc_fluxes, - T_mid, - qv[:, 0, :], - cos_zenith, - lat, - phis, - sfc_alb_dif_vis, - sw_flux_dn, - dt, - ) - sfc_flux_sw_net[:] = correction_sfc_fluxes["net_shortwave_sfc_flux_via_transmissivity"].values - sfc_flux_lw_dn[:] = correction_sfc_fluxes["override_for_time_adjusted_total_sky_downward_longwave_flux_at_surface"].values diff --git a/components/eamxx/src/physics/register_physics.hpp b/components/eamxx/src/physics/register_physics.hpp index 4261930ad200..514bb3e2d9c5 100644 --- a/components/eamxx/src/physics/register_physics.hpp +++ b/components/eamxx/src/physics/register_physics.hpp @@ -41,9 +41,6 @@ #ifdef EAMXX_HAS_TMS #include "physics/tms/eamxx_tms_process_interface.hpp" #endif -#ifdef EAMXX_HAS_ML_CORRECTION -#include "physics/ml_correction/eamxx_ml_correction_process_interface.hpp" -#endif #ifdef EAMXX_HAS_IOP_FORCING #include "physics/iop_forcing/eamxx_iop_forcing_process_interface.hpp" #endif @@ -91,9 +88,6 @@ inline void register_physics () { #ifdef EAMXX_HAS_TMS proc_factory.register_product("tms",&create_atmosphere_process); #endif -#ifdef EAMXX_HAS_ML_CORRECTION - proc_factory.register_product("MLCorrection",&create_atmosphere_process); -#endif #ifdef EAMXX_HAS_IOP_FORCING proc_factory.register_product("iop_forcing",&create_atmosphere_process); #endif From f3ac4a6c43bd5a431cd50368193cd8acd6830b4d Mon Sep 17 00:00:00 2001 From: Aaron Donahue Date: Wed, 28 Jan 2026 15:45:15 -0800 Subject: [PATCH 387/398] missed a few files to delete --- .../cime_config/namelist_defaults_eamxx.xml | 9 -- .../eamxx/docs/developer/code_structure.md | 8 -- .../eamxx/tests/single-process/CMakeLists.txt | 3 - .../ml_correction/CMakeLists.txt | 31 ------- .../single-process/ml_correction/input.yaml | 30 ------- .../ml_correction_standalone.cpp | 86 ------------------- .../ml_correction/test_correction.py | 46 ---------- 7 files changed, 213 deletions(-) delete mode 100644 components/eamxx/tests/single-process/ml_correction/CMakeLists.txt delete mode 100644 components/eamxx/tests/single-process/ml_correction/input.yaml delete mode 100644 components/eamxx/tests/single-process/ml_correction/ml_correction_standalone.cpp delete mode 100644 components/eamxx/tests/single-process/ml_correction/test_correction.py diff --git a/components/eamxx/cime_config/namelist_defaults_eamxx.xml b/components/eamxx/cime_config/namelist_defaults_eamxx.xml index 1d432bfe4306..e3bd243a6634 100644 --- a/components/eamxx/cime_config/namelist_defaults_eamxx.xml +++ b/components/eamxx/cime_config/namelist_defaults_eamxx.xml @@ -451,15 +451,6 @@ be lost if SCREAM_HACK_XML is not enabled. - - - - - - - false - - diff --git a/components/eamxx/docs/developer/code_structure.md b/components/eamxx/docs/developer/code_structure.md index 0bda096bc2e9..0700d5a2dcfe 100644 --- a/components/eamxx/docs/developer/code_structure.md +++ b/components/eamxx/docs/developer/code_structure.md @@ -27,7 +27,6 @@ │ │ ├── cosp/ │ │ ├── iop_forcing/ │ │ ├── mam/ - │ │ ├── ml_correction/ │ │ ├── nudging/ │ │ ├── p3/ │ │ ├── rrtmgp/ @@ -105,13 +104,6 @@ in conjunction with the Doubly-Periodic (DP) configuration of SCREAM. - `mam`: Contains the high-performance **M**odal **A**erosol **M**odel, parameterized with **4** size modes known as **MAM4xx**. - - `ml_correction`: This is a product developed as a part of a Lawrence - Livermore National Laboratory LDRD project in which the goal was to - improve the results of low-resolution SCREAM runs by employing - machine-learning algorithms to analyze the output of nudged - high-resolution runs. - - This code is not actively supported but may be useful/or - interesting to some. - `nudging`: Contains machinery that can be applied to "nudge" quantities in EAMxx toward desired values, typically coming from previous model runs or reanalysis data. diff --git a/components/eamxx/tests/single-process/CMakeLists.txt b/components/eamxx/tests/single-process/CMakeLists.txt index f52727774d64..e12c428a2136 100644 --- a/components/eamxx/tests/single-process/CMakeLists.txt +++ b/components/eamxx/tests/single-process/CMakeLists.txt @@ -6,9 +6,6 @@ add_subdirectory(shoc) add_subdirectory(cld_fraction) add_subdirectory(spa) add_subdirectory(surface_coupling) -if (SCREAM_ENABLE_ML_CORRECTION ) - add_subdirectory(ml_correction) -endif() if (SCREAM_DOUBLE_PRECISION) add_subdirectory(rrtmgp) add_subdirectory(cosp) diff --git a/components/eamxx/tests/single-process/ml_correction/CMakeLists.txt b/components/eamxx/tests/single-process/ml_correction/CMakeLists.txt deleted file mode 100644 index a8b93cf440c7..000000000000 --- a/components/eamxx/tests/single-process/ml_correction/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -include(ScreamUtils) - -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0") - message(STATUS "Downloading Pybind11") - include(FetchContent) - - FetchContent_Declare(pybind11 - GIT_REPOSITORY https://github.com/pybind/pybind11.git GIT_TAG v2.10.4) - - FetchContent_MakeAvailable(pybind11) -else() - message(FATAL_ERROR "pybind11 is missing. Use CMake >= 3.11 or download it") -endif() - -find_package(Python REQUIRED COMPONENTS Interpreter Development) - -CreateUnitTest(ml_correction_standalone "ml_correction_standalone.cpp" - LIBS pybind11::pybind11 Python::Python ml_correction scream_control scream_share - LABELS ml_correction physics driver) - -target_compile_definitions(ml_correction_standalone PRIVATE -DCUSTOM_SYS_PATH="${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(ml_correction_standalone SYSTEM PRIVATE ${PYTHON_INCLUDE_DIRS}) - -# Set AD configurable options -set(NUM_STEPS 1) -set(ATM_TIME_STEP 1800) -set (RUN_T0 2021-10-12-45000) - -# Configure yaml input file to run directory -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/input.yaml - ${CMAKE_CURRENT_BINARY_DIR}/input.yaml) diff --git a/components/eamxx/tests/single-process/ml_correction/input.yaml b/components/eamxx/tests/single-process/ml_correction/input.yaml deleted file mode 100644 index 703b12a3fc08..000000000000 --- a/components/eamxx/tests/single-process/ml_correction/input.yaml +++ /dev/null @@ -1,30 +0,0 @@ -%YAML 1.1 ---- -driver_options: - atmosphere_dag_verbosity_level: 5 - -time_stepping: - time_step: ${ATM_TIME_STEP} - run_t0: ${RUN_T0} # YYYY-MM-DD-XXXXX - number_of_steps: ${NUM_STEPS} - -eamxx: - atm_procs_list: [MLCorrection] - ml_correction: - ml_model_path_tq: NONE - ml_model_path_uv: NONE - ml_model_path_sfc_fluxes: NONE - ml_output_fields: ["qv","T_mid"] - ml_correction_unit_test: True -grids_manager: - type: mesh_free - grids_names: [physics] - physics: - aliases: [point_grid] - type: point_grid - number_of_global_columns: 3 - number_of_vertical_levels: 128 - -initial_conditions: - qi: 0.0 -... diff --git a/components/eamxx/tests/single-process/ml_correction/ml_correction_standalone.cpp b/components/eamxx/tests/single-process/ml_correction/ml_correction_standalone.cpp deleted file mode 100644 index 2004d8cfea9d..000000000000 --- a/components/eamxx/tests/single-process/ml_correction/ml_correction_standalone.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include - -#include "control/atmosphere_driver.hpp" -#include "physics/register_physics.hpp" -#include "share/grid/mesh_free_grids_manager.hpp" - -#include -#include -#include - -#include -#include -#include - -#include - -namespace scream { -TEST_CASE("ml_correction-stand-alone", "") { - using namespace scream; - using namespace scream::control; - namespace py = pybind11; - - std::string fname = "input.yaml"; - ekat::ParameterList ad_params("Atmosphere Driver"); - parse_yaml_file(fname, ad_params); - - const auto& ts = ad_params.sublist("time_stepping"); - const auto dt = ts.get("time_step"); - const auto nsteps = ts.get("number_of_steps"); - const auto t0_str = ts.get("run_t0"); - const auto t0 = util::str_to_time_stamp(t0_str); - const auto ml = ad_params.sublist("eamxx").sublist("MLCorrection"); - const auto ML_model_tq_path = ml.get("ml_model_path_tq"); - const auto ML_model_uv_path = ml.get("ml_model_path_uv"); - - EKAT_ASSERT_MSG(dt > 0, "Error! Time step must be positive.\n"); - - ekat::Comm atm_comm(MPI_COMM_WORLD); - - register_physics(); - register_mesh_free_grids_manager(); - - AtmosphereDriver ad; - - ad.initialize(atm_comm, ad_params, t0); - - const auto& grid = ad.get_grids_manager()->get_grid("physics"); - const auto& field_mgr = *ad.get_field_mgr(); - - int num_cols = grid->get_num_local_dofs(); - int num_levs = grid->get_num_vertical_levels(); - - const auto &qv_field = field_mgr.get_field("qv"); - const auto &qv = qv_field.get_view(); - - for(int icol = 0; icol < num_cols; ++icol) { - for(int jlev = 0; jlev < num_levs; ++jlev) { - Real phase = icol * 3.14 / 2.0 / num_cols; - Real xval = jlev * 3.14 / 2.0 / num_levs; - qv(icol, jlev) = (1.0 + std::sin(xval - phase)) / 2.0; - } - } - qv_field.sync_to_dev(); - Real reference = 1e-4; - int fpe_mask = ekat::get_enabled_fpes(); - ekat::disable_all_fpes(); // required for importing numpy - if ( Py_IsInitialized() == 0 ) { - py::initialize_interpreter(); - } - py::module sys = pybind11::module::import("sys"); - sys.attr("path").attr("insert")(1, CUSTOM_SYS_PATH); - auto py_correction = py::module::import("test_correction"); - py::object ML_model_tq = py_correction.attr("get_ML_model")(ML_model_tq_path); - py::object ML_model_uv = py_correction.attr("get_ML_model")(ML_model_uv_path); - py::object ob1 = py_correction.attr("modify_view")( - py::array_t( - num_cols * num_levs, qv.data(), py::str{}), - num_cols, num_levs, ML_model_tq, ML_model_uv); - py::gil_scoped_release no_gil; - ekat::enable_fpes(fpe_mask); - REQUIRE(qv(1, 10) == reference); // This is the one that is modified - REQUIRE(qv(0, 10) != reference); // This one should be unchanged - ad.finalize(); -} - -} // namespace scream diff --git a/components/eamxx/tests/single-process/ml_correction/test_correction.py b/components/eamxx/tests/single-process/ml_correction/test_correction.py deleted file mode 100644 index 054cf5539686..000000000000 --- a/components/eamxx/tests/single-process/ml_correction/test_correction.py +++ /dev/null @@ -1,46 +0,0 @@ -import numpy as np -import h5py -import xarray as xr -import fv3fit -from scream_run.steppers.machine_learning import ( - MultiModelAdapter, - predict, -) - - -def get_ML_model(model_path): - if model_path == "NONE": - return None - config = MachineLearningConfig(models=[model_path]) - model = open_model(config) - return model - - -def sample_ML_prediction( - nz: int, input_data: np.ndarray, ML_model_tq: str, ML_model_uv: str -): - """ - This function is used to generate a sample ML prediction for the given input data. - We use a constant output predictor to generate the prediction. - """ - output_variables = ["qv"] - outputs = { - "qv": np.full(nz, 1e-4), - } - predictor = fv3fit.testing.ConstantOutputPredictor( - input_variables=["qv"], - output_variables=output_variables, - ) - predictor.set_outputs(**outputs) - model = MultiModelAdapter([predictor]) - if len(input_data.shape) < 2: - input_data = input_data[np.newaxis, :] - input_data = xr.Dataset({"qv": xr.DataArray(data=input_data, dims=["ncol", "z"])}) - output = predict(model, input_data, dt=1.0) - return output["qv"].values - - -def modify_view(data, Ncol, Nlev, model_tq, model_uv): - data = np.reshape(data, (-1, Nlev)) - prediction = sample_ML_prediction(Nlev, data[1, :], model_tq, model_uv) - data[1, :] = prediction From 6afc6703d7f55586e291acc5b1d94b0f3c863238 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Thu, 29 Jan 2026 10:57:52 -0700 Subject: [PATCH 388/398] Update ekat submodule --- externals/ekat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/ekat b/externals/ekat index 7733e184ec3b..cb8a12ea23ae 160000 --- a/externals/ekat +++ b/externals/ekat @@ -1 +1 @@ -Subproject commit 7733e184ec3b0266ec461c21677ac06c8c76219d +Subproject commit cb8a12ea23ae04cd048554902dec96d65527b75a From 8a049f40c3e55615a762290285089bc6b15e309c Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Fri, 30 Jan 2026 04:04:24 -0600 Subject: [PATCH 389/398] Update modules on Improv Update modules on Improv: * rm module purge * newer cmake/3.30.5 * newer pnetcdf/1.14.1 --- cime_config/machines/config_machines.xml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 3d0884c7872a..45dc66558ae4 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3027,9 +3027,7 @@ module module - - cmake/3.27.4 - python/3.11.6 + cmake/3.30.5-gcc-12.3.0 gcc/12.3.0 @@ -3042,9 +3040,9 @@ /lcrc/group/e3sm/soft/improv/netcdf-c/4.9.2b/gcc-12.3.0/openmpi-4.1.6 /lcrc/group/e3sm/soft/improv/netcdf-fortran/4.6.1b/gcc-12.3.0/openmpi-4.1.6 - /lcrc/group/e3sm/soft/improv/pnetcdf/1.12.3/gcc-12.3.0/openmpi-4.1.6 - /lcrc/group/e3sm/soft/improv/pnetcdf/1.12.3/gcc-12.3.0/openmpi-4.1.6/bin:/lcrc/group/e3sm/soft/improv/netcdf-fortran/4.6.1b/gcc-12.3.0/openmpi-4.1.6/bin:/lcrc/group/e3sm/soft/improv/netcdf-c/4.9.2b/gcc-12.3.0/openmpi-4.1.6/bin:/lcrc/group/e3sm/soft/improv/openmpi/4.1.6/gcc-12.3.0/bin:/lcrc/group/e3sm/soft/perl/improv/bin:$ENV{PATH} - $SHELL{lp=/lcrc/group/e3sm/soft/improv/netlib-lapack/3.12.0/gcc-12.3.0:/lcrc/group/e3sm/soft/improv/pnetcdf/1.12.3/gcc-12.3.0/openmpi-4.1.6/lib:/lcrc/group/e3sm/soft/improv/netcdf-fortran/4.6.1b/gcc-12.3.0/openmpi-4.1.6/lib:/lcrc/group/e3sm/soft/improv/netcdf-c/4.9.2b/gcc-12.3.0/openmpi-4.1.6/lib:/opt/pbs/lib:/lcrc/group/e3sm/soft/improv/openmpi/4.1.6/gcc-12.3.0/lib; if [ -z "$LD_LIBRARY_PATH" ]; then echo $lp; else echo "$lp:$LD_LIBRARY_PATH"; fi} + /lcrc/group/e3sm/soft/improv/pnetcdf/1.14.1/gcc-12.3.0/openmpi-4.1.6 + /lcrc/group/e3sm/soft/improv/pnetcdf/1.14.1/gcc-12.3.0/openmpi-4.1.6/bin:/lcrc/group/e3sm/soft/improv/netcdf-fortran/4.6.1b/gcc-12.3.0/openmpi-4.1.6/bin:/lcrc/group/e3sm/soft/improv/netcdf-c/4.9.2b/gcc-12.3.0/openmpi-4.1.6/bin:/lcrc/group/e3sm/soft/improv/openmpi/4.1.6/gcc-12.3.0/bin:/lcrc/group/e3sm/soft/perl/improv/bin:$ENV{PATH} + $SHELL{lp=/lcrc/group/e3sm/soft/improv/netlib-lapack/3.12.0/gcc-12.3.0:/lcrc/group/e3sm/soft/improv/pnetcdf/1.14.1/gcc-12.3.0/openmpi-4.1.6/lib:/lcrc/group/e3sm/soft/improv/netcdf-fortran/4.6.1b/gcc-12.3.0/openmpi-4.1.6/lib:/lcrc/group/e3sm/soft/improv/netcdf-c/4.9.2b/gcc-12.3.0/openmpi-4.1.6/lib:/opt/pbs/lib:/lcrc/group/e3sm/soft/improv/openmpi/4.1.6/gcc-12.3.0/lib; if [ -z "$LD_LIBRARY_PATH" ]; then echo $lp; else echo "$lp:$LD_LIBRARY_PATH"; fi} $SHELL{if [ -z "$MOAB_ROOT" ]; then echo /lcrc/soft/climate/moab/improv/gnu; else echo "$MOAB_ROOT"; fi} ^lockedfile,individual From f066288349c52b47a88d440b05ec19a672ec6406 Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 30 Jan 2026 10:09:24 -0700 Subject: [PATCH 390/398] EAMxx: fix bug in eamxx-prod testmod --- .../testdefs/testmods_dirs/eamxx/prod/shell_commands | 1 + .../prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands index 76d93dee8746..adcf5ae163ca 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands @@ -61,6 +61,7 @@ else echo "Note: horiz/arm remaps only work for ne30pg2 and ne4pg2 atm grids for now" hmapfile="not-supported-yet" armmapfile="not-supported-yet" + latlonmapfile="not-supported-yet" fi # set the output yaml files diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml index 9cfd6eb66faf..1944227f8fb3 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/yaml_outs/eamxx_output.decadal.1hourlyINST_latlon.yaml @@ -4,7 +4,7 @@ filename_prefix: eamxx_output.decadal.1hourlyINST_latlon.h iotype: pnetcdf averaging_type: instant max_snapshots_per_file: 1 # only one snapshot per file -horiz_remap_file: ${TESTMOD_WILL_EDIT_THIS_LINE_VIA_SED} +horiz_remap_file: non-existent.nc # shell_commands will sed this (if supported for current grid) fields: physics_pg2: field_names: From 29696fd5c382236dcba4d96fbf17052f4cd162fe Mon Sep 17 00:00:00 2001 From: Luca Bertagna Date: Fri, 30 Jan 2026 11:48:42 -0700 Subject: [PATCH 391/398] EAMxx: add support for horiz remap at ne256pg2 for eamxx-prod --- .../testdefs/testmods_dirs/eamxx/prod/shell_commands | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands index adcf5ae163ca..1f6d37e6b583 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/prod/shell_commands @@ -57,8 +57,17 @@ elif [[ "${atm_grid}" = "ne4np4.pg2" ]]; then armmapfile="not-supported-yet" # Keep default SPA file # ... (do nothing) +elif [[ "${atm_grid}" = "ne256np4.pg2" ]]; then + hmapfile="${input_data_dir}/atm/scream/maps/map_ne256pg2_to_ne30pg2_traave.20240206.nc" + latlonmapfile="${input_data_dir}/atm/scream/maps/map_ne4pg2_to_10x20_20260112.nc" + echo "Note: arm remap only works for ne30pg2 atm grids for now" + armmapfile="not-supported-yet" + echo "Note: latlon remap only works for ne4pg2 and ne30pg2 atm grids for now" + latlonmapfile="not-supported-yet" + # Keep default SPA file + # ... (do nothing) else - echo "Note: horiz/arm remaps only work for ne30pg2 and ne4pg2 atm grids for now" + echo "Note: horiz/arm/latlon remaps only work for ne30pg2 and ne4pg2 atm grids for now" hmapfile="not-supported-yet" armmapfile="not-supported-yet" latlonmapfile="not-supported-yet" From d770e315b73a813b342ac091889448b5d40bdc49 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Fri, 30 Jan 2026 18:57:39 -0800 Subject: [PATCH 392/398] Add P8,P1 pm-gpu testmods to shell_commands --- .../testdefs/testmods_dirs/eamxx/perturb/shell_commands | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands index b95f6722dc92..a6ac5b1596fb 100644 --- a/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands +++ b/components/eamxx/cime_config/testdefs/testmods_dirs/eamxx/perturb/shell_commands @@ -13,6 +13,13 @@ if [[ $machine == "frontier" ]]; then export http_proxy=http://proxy.ccs.ornl.gov:3128/ export https_proxy=http://proxy.ccs.ornl.gov:3128/ export no_proxy='localhost,127.0.0.0/8,*.ccs.ornl.gov' +elif [[ $machine == "pm-gpu" ]]; then + atm_grid=$(./xmlquery --value ATM_GRID) + if [[ "${atm_grid}" = "ne30np4.pg2" ]]; then + ./xmlchange NTASKS=8 # P8 testmod + elif [[ "${atm_grid}" = "ne4np4.pg2" ]]; then + ./xmlchange NTASKS=1 # P1 testmod + fi elif [[ $machine == "aurora" ]]; then ./xmlchange JOB_QUEUE=prod # need >1-hr wall-time fi From ad4910ef9c168e4d775605251acb9ff91567014e Mon Sep 17 00:00:00 2001 From: mahf708 Date: Fri, 30 Jan 2026 06:52:59 -0800 Subject: [PATCH 393/398] implement initial emulator infrastructure --- .gitignore | 3 + components/emulators/CMakeLists.txt | 21 ++ components/emulators/common/CMakeLists.txt | 4 + .../emulators/common/src/CMakeLists.txt | 11 + components/emulators/common/src/emulator.cpp | 39 ++++ components/emulators/common/src/emulator.hpp | 70 +++++++ .../common/src/emulator_registry.hpp | 157 ++++++++++++++ .../emulators/common/tests/CMakeLists.txt | 13 ++ .../emulators/common/tests/test_emulator.cpp | 198 ++++++++++++++++++ .../common/tests/test_emulator_registry.cpp | 169 +++++++++++++++ components/emulators/scripts/colors.sh | 27 +++ components/emulators/scripts/parse_args.sh | 46 ++++ components/emulators/test | 55 +++++ 13 files changed, 813 insertions(+) create mode 100644 components/emulators/CMakeLists.txt create mode 100644 components/emulators/common/CMakeLists.txt create mode 100644 components/emulators/common/src/CMakeLists.txt create mode 100644 components/emulators/common/src/emulator.cpp create mode 100644 components/emulators/common/src/emulator.hpp create mode 100644 components/emulators/common/src/emulator_registry.hpp create mode 100644 components/emulators/common/tests/CMakeLists.txt create mode 100644 components/emulators/common/tests/test_emulator.cpp create mode 100644 components/emulators/common/tests/test_emulator_registry.cpp create mode 100644 components/emulators/scripts/colors.sh create mode 100644 components/emulators/scripts/parse_args.sh create mode 100755 components/emulators/test diff --git a/.gitignore b/.gitignore index 1459fa93b894..dfdd6e51746b 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,6 @@ components/eamxx/docs/_presentations_html/ components/eamxx/src/python/build components/eamxx/src/python/build_src components/eamxx/src/python/dist + +# Emulator Components +components/emulators/build diff --git a/components/emulators/CMakeLists.txt b/components/emulators/CMakeLists.txt new file mode 100644 index 000000000000..5748f71e6799 --- /dev/null +++ b/components/emulators/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.16) +project(emulators LANGUAGES CXX) + +# Path to externals (relative to this file) +get_filename_component(E3SM_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) +set(EXTERNALS_ROOT "${E3SM_ROOT}/externals") + +# Catch2 from ekat +set(CATCH2_INCLUDE_DIR "${EXTERNALS_ROOT}/ekat/extern/Catch2/single_include") + +# Verify Catch2 exists +if(NOT EXISTS "${CATCH2_INCLUDE_DIR}/catch2/catch.hpp") + message(FATAL_ERROR "Catch2 not found at ${CATCH2_INCLUDE_DIR}. " + "Make sure externals/ekat is available.") +endif() + +# Enable testing at the top level +enable_testing() + +# Add subdirectories +add_subdirectory(common) diff --git a/components/emulators/common/CMakeLists.txt b/components/emulators/common/CMakeLists.txt new file mode 100644 index 000000000000..4161c64b6319 --- /dev/null +++ b/components/emulators/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Common utilities for emulator components + +add_subdirectory(src) +add_subdirectory(tests) diff --git a/components/emulators/common/src/CMakeLists.txt b/components/emulators/common/src/CMakeLists.txt new file mode 100644 index 000000000000..551ca20fbf7a --- /dev/null +++ b/components/emulators/common/src/CMakeLists.txt @@ -0,0 +1,11 @@ +# Common source library + +add_library(emulator_common + emulator.cpp +) + +target_compile_features(emulator_common PUBLIC cxx_std_17) + +target_include_directories(emulator_common PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/components/emulators/common/src/emulator.cpp b/components/emulators/common/src/emulator.cpp new file mode 100644 index 000000000000..9ffc8d8d5614 --- /dev/null +++ b/components/emulators/common/src/emulator.cpp @@ -0,0 +1,39 @@ +/** + * @file emulator.cpp + * @brief Implementation of the Emulator base class. + */ + +#include "emulator.hpp" +#include + +namespace emulator { + +Emulator::Emulator(EmulatorType type, int id, const std::string &name) + : m_type(type), m_id(id), m_name(name), m_initialized(false), + m_step_count(0) {} + +void Emulator::initialize() { + if (m_initialized) { + throw std::runtime_error("Emulator already initialized"); + } + init_impl(); + m_initialized = true; +} + +void Emulator::run(int dt) { + if (!m_initialized) { + throw std::runtime_error("Emulator::run() called before initialize()"); + } + run_impl(dt); + m_step_count++; +} + +void Emulator::finalize() { + if (!m_initialized) { + return; // Already finalized or never initialized + } + final_impl(); + m_initialized = false; +} + +} // namespace emulator diff --git a/components/emulators/common/src/emulator.hpp b/components/emulators/common/src/emulator.hpp new file mode 100644 index 000000000000..138d9612846f --- /dev/null +++ b/components/emulators/common/src/emulator.hpp @@ -0,0 +1,70 @@ +/** + * @file emulator.hpp + * @brief Abstract base class for all E3SM emulators. + */ + +#ifndef EMULATOR_HPP +#define EMULATOR_HPP + +#include + +namespace emulator { + +/** + * @brief Enumeration of emulator types in E3SM. + */ +enum class EmulatorType { + ATM_COMP = 0, ///< Atmosphere component emulator + OCN_COMP = 1, ///< Ocean component emulator + ICE_COMP = 2, ///< Sea ice component emulator + LND_COMP = 3 ///< Land component emulator +}; + +/** + * @brief Abstract base class for all E3SM emulators. + * + * Provides the common infrastructure for emulators. + * Derived classes implement the pure virtual methods for + * emulator-specific behavior. + */ +class Emulator { +public: + /** + * @brief Construct a new Emulator. + * + * @param type Emulator type + * @param id Emulator ID (-1 if unassigned) + * @param name Emulator name (empty if unassigned) + */ + explicit Emulator(EmulatorType type, int id = -1, + const std::string &name = ""); + virtual ~Emulator() = default; + + // Lifecycle methods + void initialize(); + void run(int dt); + void finalize(); + + // Accessors + EmulatorType type() const { return m_type; } + int id() const { return m_id; } + const std::string &name() const { return m_name; } + bool is_initialized() const { return m_initialized; } + int step_count() const { return m_step_count; } + +protected: + // Virtual methods for derived classes + virtual void init_impl() = 0; + virtual void run_impl(int dt) = 0; + virtual void final_impl() = 0; + + EmulatorType m_type; + int m_id; + std::string m_name; + bool m_initialized = false; + int m_step_count = 0; +}; + +} // namespace emulator + +#endif // EMULATOR_HPP diff --git a/components/emulators/common/src/emulator_registry.hpp b/components/emulators/common/src/emulator_registry.hpp new file mode 100644 index 000000000000..8175050ad4fe --- /dev/null +++ b/components/emulators/common/src/emulator_registry.hpp @@ -0,0 +1,157 @@ +/** + * @file emulator_registry.hpp + * @brief Singleton registry for managing emulator instances. + * + * Inspired by EAMxx's ScreamContext, this provides a type-safe registry + * for creating and retrieving emulator instances by name. + */ + +#ifndef EMULATOR_REGISTRY_HPP +#define EMULATOR_REGISTRY_HPP + +#include +#include +#include +#include +#include +#include + +namespace emulator { + +/** + * @brief Singleton registry for managing emulator instances. + * + * Provides type-safe storage and retrieval of emulator instances by name, + * allowing multiple instances of the same type with different names. + * + * ## Usage + * ```cpp + * // Create an emulator with a name + * auto& atm = EmulatorRegistry::instance().create("main_atm", + * args...); + * + * // Later, retrieve it by name + * auto& atm = EmulatorRegistry::instance().get_mut("main_atm"); + * + * // Check if it exists + * if (EmulatorRegistry::instance().has("main_atm")) { ... } + * + * // Clean up + * cleanup_emulator_registry(); + * ``` + */ +class EmulatorRegistry { +public: + /** + * @brief Get the singleton instance. + * @return Reference to the global EmulatorRegistry + */ + static EmulatorRegistry &instance() { + static EmulatorRegistry r; + return r; + } + + // Prevent copying and moving + EmulatorRegistry(const EmulatorRegistry &) = delete; + EmulatorRegistry &operator=(const EmulatorRegistry &) = delete; + EmulatorRegistry(EmulatorRegistry &&) = delete; + EmulatorRegistry &operator=(EmulatorRegistry &&) = delete; + + /** + * @brief Create and register a new emulator instance with a name. + * + * Creates an instance of type T with the given constructor arguments + * and stores it in the registry under the specified name. + * + * @tparam T Emulator type to create + * @tparam Args Constructor argument types + * @param name Unique name for this instance + * @param args Arguments to pass to T's constructor + * @return Reference to the newly created instance + * @throws std::runtime_error if an instance with the same name already exists + */ + template + T &create(const std::string &name, Args &&...args) { + if (m_objects.find(name) != m_objects.end()) { + throw std::runtime_error( + "Error! Object with name '" + name + + "' was already created in the emulator registry.\n"); + } + + auto ptr = std::make_shared(std::forward(args)...); + m_objects[name] = std::any(ptr); + + return *ptr; + } + + /** + * @brief Get a const reference to an existing emulator. + * + * @tparam T Emulator type to retrieve + * @param name Name of the instance + * @return Const reference to the emulator + * @throws std::runtime_error if no instance with the given name exists + * @throws std::bad_any_cast if the type doesn't match + */ + template const T &get(const std::string &name) const { + auto it = m_objects.find(name); + if (it == m_objects.end()) { + throw std::runtime_error("Error! Object with name '" + name + + "' not found in the emulator registry.\n"); + } + return *std::any_cast &>(it->second); + } + + /** + * @brief Get a mutable reference to an existing emulator. + * + * @tparam T Emulator type to retrieve + * @param name Name of the instance + * @return Reference to the emulator + * @throws std::runtime_error if no instance with the given name exists + * @throws std::bad_any_cast if the type doesn't match + */ + template T &get_mut(const std::string &name) { + auto it = m_objects.find(name); + if (it == m_objects.end()) { + throw std::runtime_error("Error! Object with name '" + name + + "' not found in the emulator registry.\n"); + } + return *std::any_cast &>(it->second); + } + + /** + * @brief Check if an instance with the given name exists. + * + * @param name Name of the instance to check + * @return true if an instance with the name exists in the registry + */ + bool has(const std::string &name) const { + return m_objects.find(name) != m_objects.end(); + } + + /** + * @brief Remove all objects from the registry. + * + * Should be called during shutdown to release resources. + */ + void clean_up() { m_objects.clear(); } + +private: + EmulatorRegistry() = default; + + std::unordered_map m_objects; ///< Name-indexed storage +}; + +/** + * @brief Convenience function to clean up the global emulator registry. + * + * Equivalent to EmulatorRegistry::instance().clean_up(). + */ +inline void cleanup_emulator_registry() { + EmulatorRegistry::instance().clean_up(); +} + +} // namespace emulator + +#endif // EMULATOR_REGISTRY_HPP diff --git a/components/emulators/common/tests/CMakeLists.txt b/components/emulators/common/tests/CMakeLists.txt new file mode 100644 index 000000000000..8685fe8b7a09 --- /dev/null +++ b/components/emulators/common/tests/CMakeLists.txt @@ -0,0 +1,13 @@ +# Common tests + +# Test for emulator_registry +add_executable(test_emulator_registry test_emulator_registry.cpp) +target_link_libraries(test_emulator_registry PRIVATE emulator_common) +target_include_directories(test_emulator_registry PRIVATE ${CATCH2_INCLUDE_DIR}) +add_test(NAME emulator_registry_tests COMMAND test_emulator_registry) + +# Test for emulator +add_executable(test_emulator test_emulator.cpp) +target_link_libraries(test_emulator PRIVATE emulator_common) +target_include_directories(test_emulator PRIVATE ${CATCH2_INCLUDE_DIR}) +add_test(NAME emulator_tests COMMAND test_emulator) diff --git a/components/emulators/common/tests/test_emulator.cpp b/components/emulators/common/tests/test_emulator.cpp new file mode 100644 index 000000000000..463adf4b9213 --- /dev/null +++ b/components/emulators/common/tests/test_emulator.cpp @@ -0,0 +1,198 @@ +// Catch2 v2 single header +#define CATCH_CONFIG_MAIN +#include + +#include "emulator.hpp" +#include "emulator_registry.hpp" + +namespace emulator { +namespace test { + +// Concrete implementation for testing +class TestEmulator : public Emulator { +public: + TestEmulator(int id = -1, const std::string &name = "") + : Emulator(EmulatorType::ATM_COMP, id, name) {} + + // Track calls for verification + bool init_called = false; + bool run_called = false; + bool final_called = false; + int last_dt = 0; + +protected: + void init_impl() override { init_called = true; } + void run_impl(int dt) override { + run_called = true; + last_dt = dt; + } + void final_impl() override { final_called = true; } +}; + +// Test emulators for different EmulatorTypes +class TestOcnEmulator : public Emulator { +public: + TestOcnEmulator(int id = -1, const std::string &name = "") + : Emulator(EmulatorType::OCN_COMP, id, name) {} + +protected: + void init_impl() override {} + void run_impl(int) override {} + void final_impl() override {} +}; + +class TestIceEmulator : public Emulator { +public: + TestIceEmulator(int id = -1, const std::string &name = "") + : Emulator(EmulatorType::ICE_COMP, id, name) {} + +protected: + void init_impl() override {} + void run_impl(int) override {} + void final_impl() override {} +}; + +class TestLndEmulator : public Emulator { +public: + TestLndEmulator(int id = -1, const std::string &name = "") + : Emulator(EmulatorType::LND_COMP, id, name) {} + +protected: + void init_impl() override {} + void run_impl(int) override {} + void final_impl() override {} +}; + +TEST_CASE("Emulator construction", "[emulator]") { + TestEmulator emu; + REQUIRE(emu.type() == EmulatorType::ATM_COMP); + REQUIRE(emu.id() == -1); + REQUIRE(emu.name().empty()); + REQUIRE_FALSE(emu.is_initialized()); + REQUIRE(emu.step_count() == 0); +} + +TEST_CASE("Emulator construction with args", "[emulator]") { + TestEmulator emu(42, "test_atm"); + REQUIRE(emu.id() == 42); + REQUIRE(emu.name() == "test_atm"); +} + +TEST_CASE("Emulator different types", "[emulator]") { + TestEmulator atm; + TestOcnEmulator ocn; + TestIceEmulator ice; + TestLndEmulator lnd; + + REQUIRE(atm.type() == EmulatorType::ATM_COMP); + REQUIRE(ocn.type() == EmulatorType::OCN_COMP); + REQUIRE(ice.type() == EmulatorType::ICE_COMP); + REQUIRE(lnd.type() == EmulatorType::LND_COMP); +} + +TEST_CASE("Emulator lifecycle", "[emulator]") { + TestEmulator emu(1, "test"); + + SECTION("initialize calls init_impl") { + REQUIRE_FALSE(emu.init_called); + emu.initialize(); + REQUIRE(emu.init_called); + REQUIRE(emu.is_initialized()); + } + + SECTION("run calls run_impl and increments step count") { + emu.initialize(); + REQUIRE(emu.step_count() == 0); + + emu.run(3600); + REQUIRE(emu.run_called); + REQUIRE(emu.last_dt == 3600); + REQUIRE(emu.step_count() == 1); + + emu.run(1800); + REQUIRE(emu.step_count() == 2); + } + + SECTION("finalize calls final_impl") { + emu.initialize(); + REQUIRE_FALSE(emu.final_called); + emu.finalize(); + REQUIRE(emu.final_called); + REQUIRE_FALSE(emu.is_initialized()); + } +} + +TEST_CASE("Emulator error handling", "[emulator]") { + TestEmulator emu(1, "test"); + + SECTION("run before initialize throws") { + REQUIRE_THROWS_AS(emu.run(100), std::runtime_error); + } + + SECTION("double initialize throws") { + emu.initialize(); + REQUIRE_THROWS_AS(emu.initialize(), std::runtime_error); + } + + SECTION("finalize without initialize is safe") { + REQUIRE_NOTHROW(emu.finalize()); + } + + SECTION("re-initialization after finalize works") { + emu.initialize(); + REQUIRE(emu.is_initialized()); + emu.run(100); + REQUIRE(emu.step_count() == 1); + + emu.finalize(); + REQUIRE_FALSE(emu.is_initialized()); + + // Re-initialize and verify it works + emu.initialize(); + REQUIRE(emu.is_initialized()); + emu.run(200); + REQUIRE(emu.step_count() == 2); // step count persists + } +} + +TEST_CASE("Emulator with EmulatorRegistry", "[emulator][integration]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + // Create emulator via registry with name + auto &emu = reg.create("test_emu", 99, "registry_test"); + + REQUIRE(reg.has("test_emu")); + REQUIRE(emu.type() == EmulatorType::ATM_COMP); + REQUIRE(emu.id() == 99); + + // Use emulator from registry + emu.initialize(); + emu.run(100); + + // Verify through registry access + const auto &ref = reg.get("test_emu"); + REQUIRE(ref.id() == 99); + REQUIRE(ref.step_count() == 1); + + // Test get_mut + auto &mut_ref = reg.get_mut("test_emu"); + mut_ref.run(200); + REQUIRE(ref.step_count() == 2); + + reg.clean_up(); +} + +TEST_CASE("EmulatorRegistry get_mut throws for unknown name", + "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + REQUIRE_THROWS_AS(reg.get_mut("nonexistent"), + std::runtime_error); + + reg.clean_up(); +} + +} // namespace test +} // namespace emulator diff --git a/components/emulators/common/tests/test_emulator_registry.cpp b/components/emulators/common/tests/test_emulator_registry.cpp new file mode 100644 index 000000000000..cbd76ca2098d --- /dev/null +++ b/components/emulators/common/tests/test_emulator_registry.cpp @@ -0,0 +1,169 @@ +// Catch2 v2 single header - define CATCH_CONFIG_MAIN in one translation unit +#define CATCH_CONFIG_MAIN +#include + +#include "emulator_registry.hpp" + +#include + +namespace emulator { +namespace test { + +// Simple test type for the registry +struct TestComponent { + int value; + std::string name; + + TestComponent() : value(0), name("default") {} + TestComponent(int v, const std::string &n) : value(v), name(n) {} +}; + +// Another test type to verify multiple types work +struct AnotherComponent { + double data; + explicit AnotherComponent(double d = 0.0) : data(d) {} +}; + +TEST_CASE("EmulatorRegistry instance access", "[emulator_registry]") { + auto ®1 = EmulatorRegistry::instance(); + auto ®2 = EmulatorRegistry::instance(); + REQUIRE(®1 == ®2); +} + +TEST_CASE("EmulatorRegistry create and retrieve", "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); // Start fresh + + SECTION("Create default-constructed object") { + auto &comp = reg.create("default_comp"); + REQUIRE(comp.value == 0); + REQUIRE(comp.name == "default"); + } + + SECTION("Create with arguments") { + auto &comp = reg.create("arg_comp", 42, "test"); + REQUIRE(comp.value == 42); + REQUIRE(comp.name == "test"); + } + + reg.clean_up(); +} + +TEST_CASE("EmulatorRegistry get methods", "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + reg.create("getter_comp", 100, "getter_test"); + + SECTION("get() returns const reference") { + const auto &comp = reg.get("getter_comp"); + REQUIRE(comp.value == 100); + REQUIRE(comp.name == "getter_test"); + } + + SECTION("get_mut() returns mutable reference") { + auto &comp = reg.get_mut("getter_comp"); + comp.value = 200; + comp.name = "modified"; + + const auto &check = reg.get("getter_comp"); + REQUIRE(check.value == 200); + REQUIRE(check.name == "modified"); + } + + reg.clean_up(); +} + +TEST_CASE("cleanup_emulator_registry free function", "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + reg.create("cleanup_comp", 999, "cleanup_test"); + REQUIRE(reg.has("cleanup_comp")); + + cleanup_emulator_registry(); // Test the convenience function + REQUIRE_FALSE(reg.has("cleanup_comp")); +} + +TEST_CASE("EmulatorRegistry has() method", "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + REQUIRE_FALSE(reg.has("my_comp")); + + reg.create("my_comp"); + REQUIRE(reg.has("my_comp")); + + reg.clean_up(); + REQUIRE_FALSE(reg.has("my_comp")); +} + +TEST_CASE("EmulatorRegistry multiple instances of same type", + "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + // Create multiple instances of the same type with different names + auto &comp1 = reg.create("comp1", 1, "first"); + auto &comp2 = reg.create("comp2", 2, "second"); + + REQUIRE(reg.has("comp1")); + REQUIRE(reg.has("comp2")); + + REQUIRE(comp1.value == 1); + REQUIRE(comp2.value == 2); + + // Retrieve by name + const auto &ref1 = reg.get("comp1"); + const auto &ref2 = reg.get("comp2"); + + REQUIRE(ref1.name == "first"); + REQUIRE(ref2.name == "second"); + + reg.clean_up(); +} + +TEST_CASE("EmulatorRegistry multiple types", "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + reg.create("test_comp", 1, "first"); + reg.create("another_comp", 3.14); + + REQUIRE(reg.has("test_comp")); + REQUIRE(reg.has("another_comp")); + + const auto &tc = reg.get("test_comp"); + const auto &ac = reg.get("another_comp"); + + REQUIRE(tc.value == 1); + REQUIRE(ac.data == 3.14); + + reg.clean_up(); +} + +TEST_CASE("EmulatorRegistry error handling", "[emulator_registry]") { + auto ® = EmulatorRegistry::instance(); + reg.clean_up(); + + SECTION("get() throws when object not found") { + REQUIRE_THROWS_AS(reg.get("nonexistent"), + std::runtime_error); + } + + SECTION("get_mut() throws when object not found") { + REQUIRE_THROWS_AS(reg.get_mut("nonexistent"), + std::runtime_error); + } + + SECTION("create() throws on duplicate name") { + reg.create("dup_comp"); + REQUIRE_THROWS_AS(reg.create("dup_comp"), + std::runtime_error); + } + + reg.clean_up(); +} + +} // namespace test +} // namespace emulator diff --git a/components/emulators/scripts/colors.sh b/components/emulators/scripts/colors.sh new file mode 100644 index 000000000000..f6281b758894 --- /dev/null +++ b/components/emulators/scripts/colors.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# +# Color definitions and print utilities for shell scripts +# + +# Colors +export RED='\033[0;31m' +export GREEN='\033[0;32m' +export YELLOW='\033[1;33m' +export BLUE='\033[0;34m' +export NC='\033[0m' # No Color + +print_status() { + echo -e "${GREEN}==>${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}WARNING:${NC} $1" +} + +print_error() { + echo -e "${RED}ERROR:${NC} $1" +} + +print_info() { + echo -e "${BLUE}INFO:${NC} $1" +} diff --git a/components/emulators/scripts/parse_args.sh b/components/emulators/scripts/parse_args.sh new file mode 100644 index 000000000000..b4bda9cbc0e1 --- /dev/null +++ b/components/emulators/scripts/parse_args.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# +# Reusable argument parsing for test scripts +# +# Usage: source this file, then call parse_test_args "$@" +# After calling, the following variables will be set: +# CLEAN_ONLY, BUILD_ONLY, VERBOSE +# + +# Default values +CLEAN_ONLY=false +BUILD_ONLY=false +VERBOSE=false + +parse_test_args() { + while [[ $# -gt 0 ]]; do + case $1 in + --clean-only) + CLEAN_ONLY=true + shift + ;; + --build-only) + BUILD_ONLY=true + shift + ;; + --verbose|-v) + VERBOSE=true + shift + ;; + --help|-h) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --clean-only Remove build directory and exit" + echo " --build-only Build without running tests" + echo " --verbose Show verbose test output" + echo " --help Show this help message" + exit 0 + ;; + *) + echo "ERROR: Unknown option: $1" >&2 + exit 1 + ;; + esac + done +} diff --git a/components/emulators/test b/components/emulators/test new file mode 100755 index 000000000000..def8818cb4ab --- /dev/null +++ b/components/emulators/test @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Test script for emulator_comps +# Builds and runs unit tests +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_DIR="${SCRIPT_DIR}/build" + +# Source utilities +source "${SCRIPT_DIR}/scripts/colors.sh" +source "${SCRIPT_DIR}/scripts/parse_args.sh" + +# Parse command line arguments +parse_test_args "$@" + +# Clean only mode +if [ "$CLEAN_ONLY" = true ]; then + print_status "Cleaning build directory..." + rm -rf "${BUILD_DIR}" + print_status "Done." + exit 0 +fi + +# Create build directory +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +# Configure (only if needed) +if [ ! -f "CMakeCache.txt" ]; then + print_status "Configuring CMake..." + cmake "${SCRIPT_DIR}" -DCMAKE_BUILD_TYPE=Release +fi + +# Build +print_status "Building..." +cmake --build . --parallel + +# Build only mode - exit before running tests +if [ "$BUILD_ONLY" = true ]; then + print_status "Build complete." + exit 0 +fi + +# Run tests +print_status "Running tests..." +if [ "$VERBOSE" = true ]; then + ctest --output-on-failure --verbose +else + ctest --output-on-failure +fi + +print_status "All tests passed!" From d6beab98c507c4d9c772f49af3396c22bad9f832 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 2 Feb 2026 10:47:15 -0700 Subject: [PATCH 394/398] Restore a couple needed team barriers This fixes a race condition in CaarFunctor. [BFB] --- components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp b/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp index fbb97a25b94e..e139dcea3fce 100644 --- a/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp +++ b/components/homme/src/theta-l_kokkos/cxx/CaarFunctorImpl.hpp @@ -547,6 +547,7 @@ struct CaarFunctorImpl { Kokkos::single(Kokkos::PerThread(kv.team),[&]() { pi_i(0)[0] = m_hvcoord.ps0*m_hvcoord.hybrid_ai0; }); + kv.team_barrier(); // necessary to avoid race in column_scan_mid_to_int ColumnOps::column_scan_mid_to_int(kv,dp,pi_i); @@ -555,6 +556,7 @@ struct CaarFunctorImpl { Kokkos::single(Kokkos::PerThread(kv.team),[&]() { omega_i(0)[0] = 0.0; }); + kv.team_barrier(); // necessary to avoid race in column_scan_mid_to_int ColumnOps::column_scan_mid_to_int(kv,div_vdp,omega_i); // Average omega_i to midpoints, and change sign, since later From 73372ced77e035389b4c48f5410c98b9436da8b9 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Mon, 2 Feb 2026 14:23:15 -0700 Subject: [PATCH 395/398] Fix thread spreading for zm test --- components/eamxx/src/physics/zm/tests/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/eamxx/src/physics/zm/tests/CMakeLists.txt b/components/eamxx/src/physics/zm/tests/CMakeLists.txt index 7cfb49ea738a..7364b6d5aa8c 100644 --- a/components/eamxx/src/physics/zm/tests/CMakeLists.txt +++ b/components/eamxx/src/physics/zm/tests/CMakeLists.txt @@ -17,11 +17,11 @@ if (SCREAM_ENABLE_BASELINE_TESTS) set(ZM_THREADS "${SCREAM_TEST_MAX_THREADS}") else() set(BASELINE_FILE_ARG "-c -b ${SCREAM_BASELINES_DIR}/data") - set(GZM_THREADS 1 ${SCREAM_TEST_MAX_THREADS} ${SCREAM_TEST_THREAD_INC}) + set(ZM_THREADS 1 ${SCREAM_TEST_MAX_THREADS} ${SCREAM_TEST_THREAD_INC}) endif() else() set(BASELINE_FILE_ARG "-n") # no baselines - set(GZM_THREADS 1 ${SCREAM_TEST_MAX_THREADS} ${SCREAM_TEST_THREAD_INC}) + set(ZM_THREADS 1 ${SCREAM_TEST_MAX_THREADS} ${SCREAM_TEST_THREAD_INC}) endif() CreateUnitTest(zm_tests "${ZM_TESTS_SRCS}" From 8c7c9d0d312562ce96f4009ef7c30b38568ab4b7 Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Wed, 4 Feb 2026 01:18:14 +0000 Subject: [PATCH 396/398] Update project on ALCF Polaris Update project on ALCF Polaris to E3SMinput --- cime_config/machines/config_machines.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/machines/config_machines.xml b/cime_config/machines/config_machines.xml index 3d0884c7872a..777c91d5a1ea 100644 --- a/cime_config/machines/config_machines.xml +++ b/cime_config/machines/config_machines.xml @@ -3254,8 +3254,8 @@ Linux gnugpu,gnu,nvidiagpu,nvidia mpich - E3SM_RRM - E3SM_RRM + E3SMinput + E3SMinput /grand/E3SMinput/polaris/ .* /eagle/$PROJECT/$USER/scratch From 17698774e9fae75b6516d3165bef27cf8998750f Mon Sep 17 00:00:00 2001 From: Azamat Mametjanov Date: Tue, 3 Feb 2026 20:35:26 -0600 Subject: [PATCH 397/398] Fix batching: jobmin->nodemin --- cime_config/machines/config_batch.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/machines/config_batch.xml b/cime_config/machines/config_batch.xml index 97aafc482bc8..1bc6a6aa9c1b 100644 --- a/cime_config/machines/config_batch.xml +++ b/cime_config/machines/config_batch.xml @@ -415,8 +415,8 @@ -l select={{ num_nodes }}:mpiprocs={{ tasks_per_node }} - debug - compute + debug + compute From d756cb6e85584bdc162b56e2aa556cb42824c9a3 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 26 Jan 2026 19:21:49 -0600 Subject: [PATCH 398/398] Add subglacial film at the freshwater freezing point to init mode --- .../src/mode_init/Registry_global_ocean.xml | 4 +++ .../mode_init/mpas_ocn_init_global_ocean.F | 28 ++++++++++++++++--- 2 files changed, 28 insertions(+), 4 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 3e3d6e9e4790..be0ef8924c34 100644 --- a/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml +++ b/components/mpas-ocean/src/mode_init/Registry_global_ocean.xml @@ -207,6 +207,10 @@ description="The constant temperature value to be used under land ice, typically something close to the freezing point." possible_values="Any real number." /> + 1.0e-5_RKIND)) cycle ! nothing to modify + n_subglacial = n_subglacial +1 + activeTracers(saltIndex, 1:maxLevelCell(iCell), iCell) = & + 0.0_RKIND + activeTracers(tempIndex, 1:maxLevelCell(iCell), iCell) = & + config_land_ice_cavity_freezing_temperature_coeff_0 + & + config_land_ice_cavity_freezing_temperature_coeff_p * landIcePressure(iCell) + + end do + call mpas_log_write('Number of subglacial cells with modified properties $i', intArgs=(/n_subglacial/)) + end if + if ( associated(activeTracersPistonVelocity) .and. associated(landIceMask) ) then do iCell = 1, nCells if(landIceMask(iCell) == 1) then