Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add regression test against original cloud chemistry module #9

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/chemistry/aerosol/cloud_aqueous_chemistry.F90
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
!----------------------------------------------------------------------------------
module cloud_aqueous_chemistry

#define USE_MAM
#undef USE_CARMA

use shr_kind_mod, only : r8 => shr_kind_r8
use cam_logfile, only : iulog
use physics_buffer,only: physics_buffer_desc, pbuf_get_index, pbuf_add_field, dtype_r8
Expand Down Expand Up @@ -38,7 +41,12 @@ subroutine sox_inti
use spmd_utils, only : masterproc
use phys_control, only : phys_getopts
use carma_flags_mod, only : carma_do_cloudborne
use clouds, only : sox_cldaero_init
#ifdef USE_MAM
use mam_clouds, only : sox_cldaero_init
#endif
#ifdef USE_CARMA
use carma_clouds, only : sox_cldaero_init
#endif

logical :: modal_aerosols

Expand Down Expand Up @@ -129,7 +137,7 @@ subroutine sox_inti
endif
return
end if

call sox_cldaero_init()

end subroutine sox_inti
Expand Down Expand Up @@ -186,7 +194,7 @@ subroutine setsox( state, &
#ifdef USE_MAM
use mam_clouds, only : sox_cldaero_update, sox_cldaero_create_obj, sox_cldaero_destroy_obj
#endif
#ifdef USE_CLOUDS
#ifdef USE_CARMA
use carma_clouds, only : sox_cldaero_update, sox_cldaero_create_obj, sox_cldaero_destroy_obj
#endif
use cloud_utilities, only : cldaero_conc_t
Expand Down
152 changes: 152 additions & 0 deletions src/chemistry/aerosol/cloud_aqueous_chemistry_snapshot.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
! Captures inputs and output to cloud aqueous chemistry routines
module cloud_aqueous_chemistry_snapshot

use shr_kind_mod, only : r8 => shr_kind_r8

implicit none
private

public :: cloud_snapshot_init, cloud_snapshot_capture_input, cloud_snapshot_capture_output

contains

!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
subroutine cloud_snapshot_init()

use cam_history, only : addfld, horiz_only

integer :: i_elem
character(len=10) :: index_string

call addfld( 'cloud_press_in', (/ 'lev' /), 'I', 'Pa', 'mid-point pressure' )
call addfld( 'cloud_pdel_in', (/ 'lev' /), 'I', 'Pa', 'pressure thickness of levels' )
call addfld( 'cloud_tfld_in', (/ 'lev' /), 'I', 'K', 'temperature' )
call addfld( 'cloud_mbar_in', (/ 'lev' /), 'I', 'AMU', 'mean wet atmopheric mass' )
call addfld( 'cloud_lwc_in', (/ 'lev' /), 'I', 'kg kg-1', 'cloud liquid water content' )
call addfld( 'cloud_cldfrc_in', (/ 'lev' /), 'I', 'unitless', 'cloud fraction' )
call addfld( 'cloud_cldnum_in', (/ 'lev' /), 'I', 'kg-1', 'droplet number concentration' )
call addfld( 'cloud_xhnm_in', (/ 'lev' /), 'I', 'cm-3', 'total atmospheric density' )
do i_elem = 1, 7
write(index_string, '(I10)') i_elem
call addfld( 'cloud_invariants_'//trim(adjustl(index_string))//'_in', (/ 'lev' /), 'I', 'unknown', 'invariant' )
end do
do i_elem = 1, 26
write(index_string, '(I10)') i_elem
call addfld( 'cloud_qcw_'//trim(adjustl(index_string))//'_in', (/ 'lev' /), 'I', 'vmr', 'cloud-borne aerosol' )
call addfld( 'cloud_qcw_'//trim(adjustl(index_string))//'_out', (/ 'lev' /), 'I', 'vmr', 'transported species' )
call addfld( 'cloud_qin_'//trim(adjustl(index_string))//'_in', (/ 'lev' /), 'I', 'vmr', 'transported species' )
call addfld( 'cloud_qin_'//trim(adjustl(index_string))//'_out', (/ 'lev' /), 'I', 'vmr', 'transported species' )
end do
call addfld( 'cloud_xphlwc_out', (/ 'lev' /), 'I', 'unitless', 'ph value multiplied by cloud liquid water content' )
do i_elem = 1, 4
write(index_string, '(I10)') i_elem
call addfld( 'cloud_aqso4_'//trim(adjustl(index_string))//'_out', horiz_only, 'I', 'unknown', 'aqueous phase chemistry' )
call addfld( 'cloud_aqh2so4_'//trim(adjustl(index_string))//'_out', horiz_only, 'I', 'unknown', 'aqueous phase chemistry' )
end do
call addfld( 'cloud_aqso4_h2o2_out', horiz_only, 'I', 'kg m-2', 'SO4 aqueous phase chemistry due to H2O2?' )
call addfld( 'cloud_aqso4_o3_out', horiz_only, 'I', 'kg m-2', 'SO4 aqueous phase chemistry due to O3?' )

end subroutine cloud_snapshot_init

!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
subroutine cloud_snapshot_capture_input(ncol, lchnk, loffset, dtime, press, &
pdel, tfld, mbar, lwc, cldfrc, cldnum, xhnm, invariants, qcw, qin)

use cam_history, only : outfld
use cam_logfile, only : iulog
use spmd_utils, only : is_main_process => masterproc

integer, intent(in) :: ncol ! num of columns in chunk
integer, intent(in) :: lchnk ! chunk id
integer, intent(in) :: loffset ! offset of chem tracers in the advected tracers array
real(r8), intent(in) :: dtime ! time step (sec)
real(r8), intent(in) :: press(:,:) ! midpoint pressure ( Pa )
real(r8), intent(in) :: pdel(:,:) ! pressure thickness of levels (Pa)
real(r8), intent(in) :: tfld(:,:) ! temperature
real(r8), intent(in) :: mbar(:,:) ! mean wet atmospheric mass ( amu )
real(r8), target, intent(in) :: lwc(:,:) ! cloud liquid water content (kg/kg)
real(r8), target, intent(in) :: cldfrc(:,:) ! cloud fraction
real(r8), intent(in) :: cldnum(:,:) ! droplet number concentration (#/kg)
real(r8), intent(in) :: xhnm(:,:) ! total atms density ( /cm**3)
real(r8), intent(in) :: invariants(:,:,:)
real(r8), target, intent(in) :: qcw(:,:,:) ! cloud-borne aerosol (vmr)
real(r8), intent(in) :: qin(:,:,:) ! transported species ( vmr )

integer :: i_elem
character(len=10) :: index_string

#if 0
if (is_main_process) then
write(iulog,*) "*****************************"
write(iulog,*) "Cloud Chemistry scalar inputs"
write(iulog,*) "*****************************"
write(iulog,*) "ncol: ", ncol
write(iulog,*) "lchnk: ", lchnk
write(iulog,*) "loffset: ", loffset
write(iulog,*) "dtime: ", dtime
write(iulog,*) "press dims: ", size(press, dim=1), size(press, dim=2)
write(iulog,*) "invariants dims: ", size(invariants, dim=1), size(invariants, dim=2), size(invariants, dim=3)
write(iulog,*) "qcw dims: ", size(qcw, dim=1), size(qcw, dim=2), size(qcw, dim=3)
write(iulog,*) "qin dims: ", size(qin, dim=1), size(qin, dim=2), size(qin, dim=3)
end if
#endif
call outfld( 'cloud_press_in', press(:ncol,:), ncol, lchnk )
call outfld( 'cloud_pdel_in', pdel(:ncol,:), ncol, lchnk )
call outfld( 'cloud_tfld_in', tfld(:ncol,:), ncol, lchnk )
call outfld( 'cloud_mbar_in', mbar(:ncol,:), ncol, lchnk )
call outfld( 'cloud_lwc_in', lwc(:ncol,:), ncol, lchnk )
call outfld( 'cloud_cldfrc_in', cldfrc(:ncol,:), ncol, lchnk )
call outfld( 'cloud_cldnum_in', cldnum(:ncol,:), ncol, lchnk )
call outfld( 'cloud_xhnm_in', xhnm(:ncol,:), ncol, lchnk )
do i_elem = 1, 7
write(index_string, '(I10)') i_elem
call outfld( 'cloud_invariants_'//trim(adjustl(index_string))//'_in', invariants(:ncol,:,i_elem), ncol, lchnk )
end do
do i_elem = 1, 26
write(index_string, '(I10)') i_elem
call outfld( 'cloud_qcw_'//trim(adjustl(index_string))//'_in', qcw(:ncol,:,i_elem), ncol, lchnk )
call outfld( 'cloud_qin_'//trim(adjustl(index_string))//'_in', qin(:ncol,:,i_elem), ncol, lchnk )
end do

end subroutine cloud_snapshot_capture_input

!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
subroutine cloud_snapshot_capture_output(ncol, lchnk, qcw, qin, xphlwc, &
aqso4, aqh2so4, aqso4_h2o2, aqso4_o3)

use cam_history, only : outfld

integer, intent(in) :: ncol ! num of columns in chunk
integer, intent(in) :: lchnk ! chunk id
real(r8), target, intent(in) :: qcw(:,:,:) ! cloud-borne aerosol (vmr)
real(r8), intent(in) :: qin(:,:,:) ! transported species ( vmr )
real(r8), intent(in) :: xphlwc(:,:) ! pH value multiplied by lwc

real(r8), intent(in) :: aqso4(:,:) ! aqueous phase chemistry
real(r8), intent(in) :: aqh2so4(:,:) ! aqueous phase chemistry
real(r8), intent(in) :: aqso4_h2o2(:) ! SO4 aqueous phase chemistry due to H2O2 (kg/m2)
real(r8), intent(in) :: aqso4_o3(:) ! SO4 aqueous phase chemistry due to O3 (kg/m2)

integer :: i_elem
character(len=10) :: index_string

call outfld( 'cloud_xphlwc_out', xphlwc(:ncol,:), ncol, lchnk )
call outfld( 'cloud_aqso4_h2o2_out', aqso4_h2o2(:ncol), ncol, lchnk )
call outfld( 'cloud_aqso4_o3_out', aqso4_o3(:ncol), ncol, lchnk )
do i_elem = 1, 4
write(index_string, '(I10)') i_elem
call outfld( 'cloud_aqso4_'//trim(adjustl(index_string))//'_out', aqso4(:ncol,i_elem), ncol, lchnk )
call outfld( 'cloud_aqh2so4_'//trim(adjustl(index_string))//'_out', aqh2so4(:ncol,i_elem), ncol, lchnk )
end do
do i_elem = 1, 26
write(index_string, '(I10)') i_elem
call outfld( 'cloud_qcw_'//trim(adjustl(index_string))//'_out', qcw(:ncol,:,i_elem), ncol, lchnk )
call outfld( 'cloud_qin_'//trim(adjustl(index_string))//'_out', qin(:ncol,:,i_elem), ncol, lchnk )
end do

end subroutine cloud_snapshot_capture_output

end module cloud_aqueous_chemistry_snapshot
53 changes: 51 additions & 2 deletions src/chemistry/modal_aero/aero_model.F90
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ subroutine aero_model_init( pbuf2d )
use modal_aero_gasaerexch, only: modal_aero_gasaerexch_init
use modal_aero_newnuc, only: modal_aero_newnuc_init
use modal_aero_rename, only: modal_aero_rename_init
use cloud_aqueous_chemistry_snapshot, only : cloud_snapshot_init

! args
type(physics_buffer_desc), pointer :: pbuf2d(:,:)
Expand Down Expand Up @@ -544,6 +545,8 @@ subroutine aero_model_init( pbuf2d )

call aero_wetdep_init()

call cloud_snapshot_init()

end subroutine aero_model_init

!=============================================================================
Expand Down Expand Up @@ -960,7 +963,8 @@ subroutine aero_model_gasaerexch( state, loffset, ncol, lchnk, troplev, delt, re
use modal_aero_gasaerexch, only : modal_aero_gasaerexch_sub
use modal_aero_newnuc, only : modal_aero_newnuc_sub
use modal_aero_data, only : cnst_name_cw, qqcw_get_field

use cloud_aqueous_chemistry_snapshot, only : cloud_snapshot_capture_input, &
cloud_snapshot_capture_output
!-----------------------------------------------------------------------
! ... dummy arguments
!-----------------------------------------------------------------------
Expand Down Expand Up @@ -1060,7 +1064,29 @@ subroutine aero_model_gasaerexch( state, loffset, ncol, lchnk, troplev, delt, re
dvmrcwdt(:ncol,:,:) = vmrcw(:ncol,:,:)

! aqueous chemistry ...

call cloud_snapshot_capture_input( &
! pbuf, &
ncol, &
lchnk, &
loffset, &
delt, &
pmid, &
pdel, &
tfld, &
mbar, &
cwat, &
cldfr, &
cldnum, &
airdens, &
invariants, &
vmrcw, &
vmr &
! xphlwc, &
! aqso4, &
! aqh2so4, &
! aqso4_h2o2, &
! aqso4_o3 &
)
if( has_sox ) then
call setsox( state, &
pbuf, &
Expand Down Expand Up @@ -1099,6 +1125,29 @@ subroutine aero_model_gasaerexch( state, loffset, ncol, lchnk, troplev, delt, re
call outfld( 'XPH_LWC', xphlwc(:ncol,:), ncol, lchnk )

endif
call cloud_snapshot_capture_output( &
! pbuf, &
ncol, &
lchnk, &
! loffset, &
! delt, &
! pmid, &
! pdel, &
! tfld, &
! mbar, &
! cwat, &
! cldfr, &
! cldnum, &
! airdens, &
! invariants, &
vmrcw, &
vmr, &
xphlwc, &
aqso4, &
aqh2so4, &
aqso4_h2o2, &
aqso4_o3 &
)

! Tendency due to aqueous chemistry
dvmrdt = (vmr - dvmrdt) / delt
Expand Down
4 changes: 2 additions & 2 deletions src/chemistry/modal_aero/mam_clouds.F90
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,16 @@ subroutine sox_cldaero_update( state, &
do n = 1, ntot_amode
m = lptr_so4_cw_amode(n)
l = m - loffset
aqso4(:,n)=0._r8
aqh2so4(:,n)=0._r8
if (l > 0) then
aqso4(:,n)=0._r8
do k=1,pver
do i=1,ncol
aqso4(i,n)=aqso4(i,n)+dqdt_aqso4(i,k,l)*adv_mass(l)/mbar(i,k) &
*pdel(i,k)/gravit ! kg/m2/s
enddo
enddo

aqh2so4(:,n)=0._r8
do k=1,pver
do i=1,ncol
aqh2so4(i,n)=aqh2so4(i,n)+dqdt_aqh2so4(i,k,l)*adv_mass(l)/mbar(i,k) &
Expand Down
21 changes: 21 additions & 0 deletions test/chemistry/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.6)

project(
cam_chemistry_tests
VERSION 0.1.0
LANGUAGES Fortran
)

option(CAMCHEM_ENABLE_MEMCHECK "Enable memory checking with valgrind" ON)
option(CAMCHEM_ENABLE_MPI "Build with MPI support" OFF)
option(CAMCHEM_ENABLE_OPENMP "Build with OpenMP support" OFF)

include(cmake/dependencies.cmake)

# Copy test data
add_custom_target(copy_test_data ALL ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/data ${CMAKE_BINARY_DIR}/test/chemistry/data)

enable_testing()

add_subdirectory(cloud_aqueous_chemistry)
31 changes: 31 additions & 0 deletions test/chemistry/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM fedora:41

RUN dnf -y update \
&& dnf -y install \
cmake \
gcc \
gcc-c++ \
gcc-fortran \
gdb \
git \
lapack-devel \
lcov \
m4 \
make \
netcdf-fortran-devel \
python3 \
python3-pip \
valgrind \
&& dnf clean all

COPY . /cam

RUN cd /cam/test/chemistry \
&& mkdir build \
&& cd build \
&& cmake \
-D CMAKE_BUILD_TYPE=DEBUG \
.. \
&& make

WORKDIR /cam/test/chemistry/build
22 changes: 22 additions & 0 deletions test/chemistry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Chemistry Tests
===============

Tests in this folder are used to support the porting of CAM-Chem functionality to CAM-SIMA.

To build and run the test suite, from this folder run:

```
mkdir build
cd build
cmake ..
make
make test
```

To run the tests in a Docker container, from the `CAM/test/chemistry` folder run:

```
docker build -t cam-test ../../ -f Dockerfile
docker run -it cam-test bash
make test
```
Loading
Loading