subroutine dyn_exchange_constituent_states(direction, exchange, conversion)
! Module(s) from CAM-SIMA.
use cam_abortutils, only: check_allocate, endrun
use cam_constituents, only: const_is_dry, const_is_water_species, num_advected
use cam_logfile, only: debugout_debug, debugout_info
use physics_types, only: phys_state
use vert_coord, only: pver
! Module(s) from CCPP.
use cam_ccpp_cap, only: cam_constituents_array
use ccpp_kinds, only: kind_phys
! Module(s) from CESM Share.
use shr_kind_mod, only: kind_r8 => shr_kind_r8
character(*), intent(in) :: direction
logical, intent(in) :: exchange
logical, intent(in) :: conversion
character(*), parameter :: subname = 'dyn_comp::dyn_exchange_constituent_states'
integer :: i, j
integer :: ierr
integer, allocatable :: is_water_species_index(:)
logical, allocatable :: is_conversion_needed(:)
logical, allocatable :: is_water_species(:)
real(kind_phys), pointer :: constituents(:, :, :) ! This points to CCPP memory.
real(kind_r8), allocatable :: sigma_all_q(:) ! Summation of all water species mixing ratios.
real(kind_dyn_mpas), pointer :: scalars(:, :, :) ! This points to MPAS memory.
call dyn_debug_print(debugout_debug, subname // ' entered')
select case (trim(adjustl(direction)))
case ('e', 'export')
if (exchange) then
call dyn_debug_print(debugout_info, 'Setting MPAS state "scalars" from physics state "constituents"')
end if
if (conversion) then
call dyn_debug_print(debugout_info, 'Converting MPAS state "scalars"')
end if
case ('i', 'import')
if (exchange) then
call dyn_debug_print(debugout_info, 'Setting physics state "constituents" from MPAS state "scalars"')
end if
if (conversion) then
call dyn_debug_print(debugout_info, 'Converting physics state "constituents"')
end if
case default
call endrun('Unsupported exchange direction "' // trim(adjustl(direction)) // '"', subname, __LINE__)
end select
nullify(constituents)
nullify(scalars)
allocate(is_conversion_needed(num_advected), stat=ierr)
call check_allocate(ierr, subname, &
'is_conversion_needed(num_advected)', &
'dyn_comp', __LINE__)
allocate(is_water_species(num_advected), stat=ierr)
call check_allocate(ierr, subname, &
'is_water_species(num_advected)', &
'dyn_comp', __LINE__)
do j = 1, num_advected
! All constituent mixing ratios in MPAS are dry.
! Therefore, conversion in between is needed for any constituent mixing ratios that are not dry in CAM-SIMA.
is_conversion_needed(j) = .not. const_is_dry(j)
is_water_species(j) = const_is_water_species(j)
end do
allocate(is_water_species_index(count(is_water_species)), stat=ierr)
call check_allocate(ierr, subname, &
'is_water_species_index(count(is_water_species))', &
'dyn_comp', __LINE__)
allocate(sigma_all_q(pver), stat=ierr)
call check_allocate(ierr, subname, &
'sigma_all_q(pver)', &
'dyn_comp', __LINE__)
constituents => cam_constituents_array()
if (.not. associated(constituents)) then
call endrun('Failed to find variable "constituents"', subname, __LINE__)
end if
call mpas_dynamical_core % get_variable_pointer(scalars, 'state', 'scalars', time_level=1)
if (trim(adjustl(direction)) == 'e' .or. trim(adjustl(direction)) == 'export') then
do i = 1, ncells_solve
if (conversion .and. any(is_conversion_needed)) then
! The summation term of equation 8 in doi:10.1029/2017MS001257.
! Using equation 7 here is not possible because it requires all constituent mixing ratio to be moist
! on the RHS of it. There is no such guarantee in CAM-SIMA.
sigma_all_q(:) = reverse(phys_state % pdel(i, :) / phys_state % pdeldry(i, :))
end if
! `j` is indexing into `scalars`, so it is regarded as MPAS scalar index.
do j = 1, num_advected
if (exchange) then
! Vertical index order is reversed between CAM-SIMA and MPAS.
scalars(j, :, i) = &
real(reverse(constituents(i, :, mpas_dynamical_core % map_constituent_index(j))), kind_dyn_mpas)
end if
if (conversion .and. is_conversion_needed(mpas_dynamical_core % map_constituent_index(j))) then
! Equation 8 in doi:10.1029/2017MS001257.
scalars(j, :, i) = &
real(real(scalars(j, :, i), kind_r8) * sigma_all_q(:), kind_dyn_mpas)
end if
end do
end do
else
is_water_species_index(:) = &
pack([(mpas_dynamical_core % map_mpas_scalar_index(i), i = 1, num_advected)], is_water_species)
do i = 1, ncells_solve
if (conversion .and. any(is_conversion_needed)) then
! The summation term of equation 8 in doi:10.1029/2017MS001257.
sigma_all_q(:) = reverse(1.0_kind_r8 + sum(real(scalars(is_water_species_index, :, i), kind_r8), 1))
end if
! `j` is indexing into `constituents`, so it is regarded as constituent index.
do j = 1, num_advected
if (exchange) then
! Vertical index order is reversed between CAM-SIMA and MPAS.
constituents(i, :, j) = &
reverse(real(scalars(mpas_dynamical_core % map_mpas_scalar_index(j), :, i), kind_r8))
end if
if (conversion .and. is_conversion_needed(j)) then
! Equation 8 in doi:10.1029/2017MS001257.
constituents(i, :, j) = &
constituents(i, :, j) / sigma_all_q(:)
end if
end do
end do
end if
deallocate(is_conversion_needed)
deallocate(is_water_species)
deallocate(is_water_species_index)
deallocate(sigma_all_q)
nullify(constituents)
nullify(scalars)
if (trim(adjustl(direction)) == 'e' .or. trim(adjustl(direction)) == 'export') then
! Because we are injecting data directly into MPAS memory, halo layers need to be updated manually.
call mpas_dynamical_core % exchange_halo('scalars')
end if
call dyn_debug_print(debugout_debug, subname // ' completed')
end subroutine dyn_exchange_constituent_states