Skip to content

Commit 83d58e1

Browse files
committed
Merge branch 'development' into hplin/hb_diff
2 parents 9472580 + 420b269 commit 83d58e1

File tree

56 files changed

+4092
-402
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+4092
-402
lines changed

.github/workflows/fortran_unit_tests.yml

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ jobs:
2323
CXX: g++-${{ matrix.version }}
2424
FC: gfortran-${{ matrix.version }}
2525
steps:
26+
- name: install dependencies
27+
run: |
28+
sudo apt install -y libnetcdff-dev libnetcdf-mpi-dev libopenmpi-dev openmpi-bin doxygen
29+
2630
- name: Checkout cam-sima
2731
uses: actions/checkout@v4
2832

@@ -34,16 +38,45 @@ jobs:
3438
cd build
3539
make install
3640
41+
- name: Build PIO
42+
run: |
43+
git clone --depth 1 --branch pio2_6_6 https://github.com/NCAR/ParallelIO.git
44+
cd ParallelIO
45+
FC=$(which mpif90) \
46+
CC=$(which mpicc) \
47+
cmake -S./ -B./build \
48+
-DCMAKE_INSTALL_PREFIX=./install \
49+
-DPIO_ENABLE_TIMING=OFF \
50+
-DWITH_PNETCDF=OFF \
51+
-DCMAKE_PREFIX_PATH="/usr/lib/x86_64-linux-gnu/cmake/netCDF" \
52+
-DNetCDF_Fortran_LIBRARY="/usr/lib/x86_64-linux-gnu/libnetcdff.a" \
53+
-DNetCDF_C_LIBRARY="/usr/lib/x86_64-linux-gnu/libnetcdf.so" \
54+
-DCMAKE_EXE_LINKER_FLAGS="-lmpi -Wl,--no-as-needed"
55+
cd build
56+
make
57+
make install
58+
59+
- name: Checkout atmospheric_physics
60+
run: |
61+
bin/git-fleximod update ncar-physics ccpp-framework share
62+
3763
- name: Build cam-sima
3864
run: |
65+
PIO_ROOT=$GITHUB_WORKSPACE/ParallelIO/install/ \
3966
cmake \
40-
-DCMAKE_PREFIX_PATH=$GITHUB_WORKSPACE/pFUnit/build/installed \
67+
-DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/pFUnit/build/installed;/usr/lib/x86_64-linux-gnu/cmake/netCDF;/usr/lib/x86_64-linux-gnu/" \
4168
-DCAM_SIMA_ENABLE_CODE_COVERAGE=ON \
69+
-DCAM_SIMA_ENABLE_IO_TESTS=ON \
70+
-DCAM_SIMA_ENABLE_TESTS=ON \
4271
-B./build \
4372
-S./test/unit/fortran
4473
cd build
4574
make
4675
76+
- name: Checkout datafiles for file IO reader tests
77+
run: |
78+
git clone https://github.com/earth-system-radiation/rrtmgp-data.git
79+
4780
- name: Run fortran unit tests
4881
run: |
4982
cd build && ctest -V --output-on-failure --output-junit test_results.xml

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
*.pyc
33
buildnmlc
44

5+
# Ignore compiled Fortran
6+
*.mod
7+
*.o
8+
59
# Ignore test output
610
test/include/*.mod
711
test/include/*.o
812
test/unit/python/tmp
913
test/system/*.log
1014
test/system/cime-tests.o*
1115
test_driver_*.sh
16+
build/
1217

1318
# Ignore editor temporaries and backups
1419
*.swp

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
[submodule "ncar-physics"]
2121
path = src/physics/ncar_ccpp
2222
url = https://github.com/ESCOMP/atmospheric_physics
23-
fxtag = 2b66267fe263d9268effeaa1d47e3c03e6121d74
23+
fxtag = e92f76351e7f7703fb6d91cb5e76dcbbc6dcb3f2
2424
fxrequired = AlwaysRequired
2525
fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics
2626
[submodule "rrtmgp-data"]

cime_config/atm_musica_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
MUSICA_REPO_URL = "https://github.com/NCAR/musica.git"
99
MUSICA_TAG = "25fff7ae42d146bf3f83ad5ac18b3caac8701ddd"
1010
CHEMISTRY_DATA_REPO_URL = "https://github.com/NCAR/cam-sima-chemistry-data.git"
11-
CHEMISTRY_DATA_TAG = "71ed143c54b0d5d6e3e70f3d05d413fddcf8d59e"
11+
CHEMISTRY_DATA_TAG = "1ea9d1b8b04980738894d30a864f9a000daf2e5c"

cime_config/buildlib

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,15 @@ def _build_cam():
193193
f'-I{os.path.join(musica_install_path, "include", "musica", "fortran")} '
194194
'"'
195195
)
196+
else:
197+
# If MUSICA scheme is not used, then copy over MUSICA
198+
# source code file into a build directory, as it is needed
199+
# by the temporary "musica_ccpp_dependencies.F90"
200+
# CAM-SIMA file:
201+
musica_species_src_path = os.path.join(atm_root, "src", "physics", "ncar_ccpp",
202+
"schemes", "musica", "util",
203+
"musica_ccpp_species.F90")
204+
_copy2_as_needed(musica_species_src_path, phys_dirs[0])
196205

197206
retcode, out, err = run_cmd(cmd)
198207
_LOGGER.info("Command %s:\n\nstdout:\n%s\n\nstderr:\n%s\n", cmd, out, err)
@@ -335,7 +344,7 @@ def _build_musica(clone_dest: str) -> str:
335344
cmake_build_type = "Debug"
336345
else:
337346
cmake_build_type = "Release"
338-
347+
339348
command = [
340349
"cmake",
341350
f"-D CMAKE_INSTALL_PREFIX={install_dir}",

cime_config/namelist_definition_cam.xml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -364,23 +364,6 @@
364364
</values>
365365
</entry>
366366

367-
<!-- Host model chemistry settings -->
368-
369-
<entry id="musica_config">
370-
<type>char*256</type>
371-
<category>chemistry</category>
372-
<group>chemistry_nl</group>
373-
<desc>
374-
Configuration option for the
375-
MUSICA chemistry package.
376-
377-
Default: none
378-
</desc>
379-
<values>
380-
<value>none</value>
381-
</values>
382-
</entry>
383-
384367
<!-- Tropopause -->
385368
<entry id="tropopause_climo_file">
386369
<type>char*256</type>

src/control/cam_comp.F90

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,18 @@ subroutine cam_timestep_init()
290290
!
291291
!-----------------------------------------------------------------------
292292

293-
use phys_comp, only: phys_timestep_init
294-
use physics_grid, only: lat_rad, lon_rad
295-
use orbital_data, only: orbital_data_advance
296-
use stepon, only: stepon_timestep_init
297-
use cam_ccpp_cap, only: cam_constituents_array
298-
use ccpp_kinds, only: kind_phys
299-
use musica_ccpp_dependencies, only: set_initial_musica_concentrations
293+
use phys_comp, only: phys_timestep_init
294+
use physics_grid, only: lat_rad, lon_rad
295+
use orbital_data, only: orbital_data_advance
296+
use stepon, only: stepon_timestep_init
297+
use cam_ccpp_cap, only: cam_constituents_array
298+
use cam_ccpp_cap, only: cam_model_const_properties
299+
use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t
300+
use ccpp_kinds, only: kind_phys
301+
use musica_ccpp_dependencies, only: set_initial_musica_concentrations
300302

301303
real(kind_phys), pointer :: constituents_array(:,:,:)
304+
type(ccpp_constituent_prop_ptr_t), pointer :: constituent_properties(:)
302305

303306
! Update current fractional calendar day. Needs to be updated at every timestep.
304307
calday = get_curr_calday()
@@ -331,7 +334,9 @@ subroutine cam_timestep_init()
331334
!----------------------------------------------------------
332335
if (is_first_timestep) then
333336
constituents_array => cam_constituents_array()
334-
call set_initial_musica_concentrations(constituents_array)
337+
constituent_properties => cam_model_const_properties()
338+
call set_initial_musica_concentrations(constituents_array, &
339+
constituent_properties)
335340
end if
336341

337342
!

src/control/runtime_opts.F90

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ subroutine read_namelist(nlfilename, single_column, scmlat, scmlon)
4545
use inic_analytic_utils, only: analytic_ic_readnl
4646

4747
use tropopause_climo_read, only: tropopause_climo_readnl
48-
use musica_sima_namelist, only: musica_ccpp_dependencies_readnl
4948

5049
! use tracers, only: tracers_readnl
5150
! use nudging, only: nudging_readnl
@@ -103,7 +102,6 @@ subroutine read_namelist(nlfilename, single_column, scmlat, scmlon)
103102
! call check_energy_readnl(nlfilename)
104103
call analytic_ic_readnl(nlfilename)
105104
call tropopause_climo_readnl(nlfilename)
106-
call musica_ccpp_dependencies_readnl(nlfilename)
107105
! call scam_readnl(nlfilename, single_column, scmlat, scmlon)
108106
! call nudging_readnl(nlfilename)
109107

src/data/registry.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,10 @@
534534
<dimensions>horizontal_dimension vertical_layer_dimension</dimensions>
535535
<ic_file_input_names>cp_or_cv_dycore</ic_file_input_names>
536536
</variable>
537+
537538
<!-- Constituent Variables -->
538539
<!-- These are only used to set possible IC file input names, as the constituents object handles allocation. -->
540+
<!-- Note: the first IC file input name should correspond to the short name of the constituent used in CAM, in order to facilitate reading constituent-dimensioned input fields. -->
539541
<variable local_name="q"
540542
standard_name="water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water"
541543
units="kg kg-1" type="real" constituent="true">

src/data/write_init_files.py

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -739,14 +739,21 @@ def get_dimension_info(hvar):
739739
- The local variable name of the vertical dimension (or None)
740740
- True if <hvar> has one dimension which is a horizontal dimension or
741741
if <hvar> has two dimensions (horizontal and vertical)
742+
- Flag if any dimensions are number_of_ccpp_constituents and needs
743+
reading separate variables by constituent and reassembled into
744+
host model indices.
742745
"""
743746
vdim_name = None
744747
legal_dims = False
745748
fail_reason = ""
749+
746750
dims = hvar.get_dimensions()
747751
levnm = hvar.has_vertical_dimension()
752+
has_constituent_dim = any('number_of_ccpp_constituents' in dim for dim in dims)
753+
748754
# <hvar> is only 'legal' for 2 or 3 dimensional fields (i.e., 1 or 2
749-
# dimensional variables). The second dimension must be vertical.
755+
# dimensional variables).
756+
# The second dimension must either be vertical or number of constituents.
750757
# XXgoldyXX: If we ever need to read scalars, it would have to be
751758
# done using global attributes, not 'infld'.
752759
ldims = len(dims)
@@ -758,7 +765,17 @@ def get_dimension_info(hvar):
758765
fail_reason += f"{suff}{lname} has no horizontal dimension"
759766
suff = "; "
760767
# end if
761-
if (ldims > 2) or ((ldims > 1) and (not levnm)):
768+
769+
if has_constituent_dim:
770+
# A special case where any dimensions include number_of_ccpp_constituents,
771+
# in this case the variable needs to be suffixed by an underscore plus the constituent name
772+
# and read and reassembled separately into host model constituent indices
773+
# based on constituent name.
774+
# This case will be handled separately.
775+
legal_dims = True
776+
elif (ldims > 2) or ((ldims > 1) and (not levnm)):
777+
# The regular case where the second dimension must be vertical,
778+
# and higher dimensions are unsupported.
762779
legal_dims = False
763780
unsupp = []
764781
for dim in dims:
@@ -785,6 +802,7 @@ def get_dimension_info(hvar):
785802
# end if
786803
suff = "; "
787804
# end if
805+
788806
if legal_dims and levnm:
789807
# <hvar> should be legal, find the correct local name for the
790808
# vertical dimension
@@ -808,7 +826,8 @@ def get_dimension_info(hvar):
808826
raise ValueError(f"Vertical dimension, '{levnm}', not found")
809827
# end if
810828
# end if
811-
return vdim_name, legal_dims, fail_reason
829+
830+
return vdim_name, legal_dims, fail_reason, has_constituent_dim
812831

813832
def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
814833
phys_check_fname_str, constituent_set,
@@ -850,7 +869,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
850869
call_string_key = f"case ('{var_stdname}')"
851870

852871
# Extract vertical level variable:
853-
levnm, call_read_field, reason = get_dimension_info(hvar)
872+
levnm, call_read_field, reason, has_constituent_read = get_dimension_info(hvar)
854873
if hvar.get_prop_value('protected'):
855874
call_read_field = False
856875
if reason:
@@ -860,14 +879,23 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
860879
# end if
861880
lvar = hvar.get_prop_value('local_name')
862881
reason += f"{suff}{lvar} is a protected variable"
882+
# end if
883+
863884
# Set "read_field" call string:
864885
if call_read_field:
865-
# Replace vertical dimension with local name
866-
call_str = "call read_field(file, " + \
867-
f"'{var_stdname}', input_var_names(:,name_idx), "
886+
if has_constituent_read:
887+
# Special case for constituent-dimension variables.
888+
call_str = f"call read_constituent_dimensioned_field(const_props, file, '{var_stdname}', input_var_names(:,name_idx), "
889+
else:
890+
# Replace vertical dimension with local name
891+
call_str = "call read_field(file, " + \
892+
f"'{var_stdname}', input_var_names(:,name_idx), "
893+
# end if
894+
868895
if levnm is not None:
869896
call_str += f"'{levnm}', "
870897
# end if
898+
871899
err_on_not_found_string = ""
872900
if var_stdname in vars_init_value:
873901
# if initial value is available, do not throw error when not found in initial condition file.
@@ -903,7 +931,8 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
903931
["shr_kind_mod", ["SHR_KIND_CS, SHR_KIND_CL, SHR_KIND_CX"]],
904932
["physics_data", ["read_field", "find_input_name_idx",
905933
"no_exist_idx", "init_mark_idx",
906-
"prot_no_init_idx", "const_idx"]],
934+
"prot_no_init_idx", "const_idx",
935+
"read_constituent_dimensioned_field"]],
907936
["cam_ccpp_cap", ["ccpp_physics_suite_variables",
908937
"cam_constituents_array",
909938
"cam_model_const_properties"]],
@@ -967,8 +996,13 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
967996
outfile.write("logical :: use_init_variables", 2)
968997
outfile.blank_line()
969998

999+
# Prepare constituent properties pointer for later usage:
1000+
outfile.comment("Get constituent properties pointer:", 2)
1001+
outfile.write("const_props => cam_model_const_properties()", 2)
1002+
outfile.blank_line()
1003+
9701004
# Initialize variables:
971-
outfile.comment("Initalize missing and non-initialized variables strings:",
1005+
outfile.comment("Initialize missing and non-initialized variables strings:",
9721006
2)
9731007
outfile.write("missing_required_vars = ' '", 2)
9741008
outfile.write("protected_non_init_vars = ' '", 2)
@@ -1103,7 +1137,6 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
11031137
# Read in constituent data
11041138
outfile.comment("Read in constituent variables if not using init variables", 2)
11051139
outfile.write("field_data_ptr => cam_constituents_array()", 2)
1106-
outfile.write("const_props => cam_model_const_properties()", 2)
11071140
outfile.blank_line()
11081141
outfile.comment("Iterate over all registered constituents", 2)
11091142
outfile.write("do constituent_idx = 1, size(const_props)", 2)
@@ -1138,7 +1171,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports,
11381171
outfile.write("call const_props(constituent_idx)%minimum(constituent_min_value, constituent_errflg, constituent_errmsg)", 5)
11391172
outfile.write("field_data_ptr(:,:,constituent_idx) = constituent_min_value", 5)
11401173
outfile.write("if (masterproc) then", 5)
1141-
outfile.write("write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to 0.'", 6)
1174+
outfile.write("write(iulog,*) 'Constituent ', trim(std_name), ' default value not configured. Setting to min value of ', constituent_min_value", 6)
11421175
outfile.write("end if", 5)
11431176
outfile.write("end if", 4)
11441177
outfile.write("end if", 3)
@@ -1191,7 +1224,12 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports,
11911224
call_string_key = f"case ('{var_stdname}')"
11921225

11931226
# Extract vertical level variable:
1194-
levnm, call_check_field, reason = get_dimension_info(hvar)
1227+
levnm, call_check_field, reason, has_constituent_read = get_dimension_info(hvar)
1228+
1229+
# If this is a constituent-indexed field, do not check it for now.
1230+
if has_constituent_read:
1231+
continue
1232+
# end if
11951233

11961234
# Set "check_field" call string:
11971235
if call_check_field:

0 commit comments

Comments
 (0)