Skip to content

Commit

Permalink
merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
boulderdaze committed Feb 20, 2025
2 parents 7e02d90 + 8b4d541 commit 2269446
Show file tree
Hide file tree
Showing 183 changed files with 857 additions and 408 deletions.
73 changes: 73 additions & 0 deletions .github/workflows/fortran_unit_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Fortran Unit Tests

on:
push:
branches:
- development
- main
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true

jobs:
gcc-toolchain:
runs-on: ubuntu-latest
strategy:
matrix:
version: [12, 13, 14]
env:
CC: gcc-${{ matrix.version }}
CXX: g++-${{ matrix.version }}
FC: gfortran-${{ matrix.version }}
steps:
- name: Checkout cam-sima
uses: actions/checkout@v4

- name: Build pFUnit
run: |
git clone --depth 1 --branch v4.10.0 https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git
cd pFUnit
cmake -B./build -S.
cd build
make install
- name: Build cam-sima
run: |
cmake \
-DCMAKE_PREFIX_PATH=/home/runner/work/CAM-SIMA/CAM-SIMA/pFUnit/build/installed \
-DCAM_SIMA_ENABLE_CODE_COVERAGE=ON \
-B./build \
-S./test/unit/fortran
cd build
make
- name: Run fortran unit tests
run: |
cd build && ctest -V --output-on-failure --output-junit test_results.xml
- name: Upload unit test results
uses: actions/upload-artifact@v4
with:
name: unit-test-results-${{ env.FC }}
path: build/test_results.xml

- name: Setup GCov
run: |
python3 -m venv venv
source venv/bin/activate
pip3 install gcovr
- name: Run Gcov
run: |
source venv/bin/activate
cd build
gcovr --gcov-executable gcov-${{ matrix.version }} -r .. --filter '\.\./src' --html cam_sima_code_coverage.html --txt
- name: Upload code coverage results
uses: actions/upload-artifact@v4
with:
name: code-coverage-results-${{ env.FC }}
path: build/cam_sima_code_coverage.html
7 changes: 4 additions & 3 deletions .github/workflows/python_unit_tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Python Unit Tests

on:
workflow_dispatch:
pull_request:
types: [opened, synchronize, reopened]
push:
Expand All @@ -16,12 +17,12 @@ jobs:
#a PR is either opened or synced (i.e. additional commits are pushed
#to branch involved in PR).
python_unit_tests:
if: github.event_name == 'pull_request' || github.repository == 'ESCOMP/CAM-SIMA'
if: github.event_name == 'pull_request' || github.repository == 'ESCOMP/CAM-SIMA' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
strategy:
matrix:
#All of these python versions will be used to run tests:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
fail-fast: false
steps:
# Acquire github action routines:
Expand Down Expand Up @@ -56,4 +57,4 @@ jobs:
pytest src/data --doctest-modules
# Run all python unit tests:
pytest test/unit
pytest test/unit/python
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildnmlc
# Ignore test output
test/include/*.mod
test/include/*.o
test/unit/tmp
test/unit/python/tmp
test/system/*.log
test/system/cime-tests.o*
test_driver_*.sh
Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
[submodule "ncar-physics"]
path = src/physics/ncar_ccpp
url = https://github.com/ESCOMP/atmospheric_physics
fxtag = 60b71f3fd9f10b362caf64afffce12de10854d4d
fxtag = 252b500a93c89f36ece7d8ba08fd8eb025279eaa
fxrequired = AlwaysRequired
fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics
[submodule "ccs_config"]
Expand Down
11 changes: 8 additions & 3 deletions cime_config/atm_in_paramgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1495,11 +1495,16 @@ def write(self, output_path):
# Write all variables within that group (sorted alphabetically):
for var in sorted(self._data[nml_group], key=var_sort_key):
#Extract variable value(s):
val = self._data[nml_group][var]["values"].strip()
val = self._data[nml_group][var]["values"]

#If no value is set then move to the next variable:
#Raise error if no value found:
if val is None:
continue
emsg = f"Namelist entry '{var}' is missing a "
emsg += "valid/default 'value' element."
raise AtmInParamGenError(emsg)
else:
#If value found then strip white space:
val = val.strip()
#End if

#Extract variable type:
Expand Down
3 changes: 2 additions & 1 deletion cime_config/buildlib
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def _build_cam():
os.path.join(atm_root, "src", "history", "buffers", "src"),
os.path.join(atm_root, "src", "history", "buffers", "src", "hash"),
os.path.join(atm_root, "src", "history", "buffers", "src", "util"),
os.path.join(atm_root, "src", "utils")]
os.path.join(atm_root, "src", "utils"),
os.path.join(atm_root, "src", "core_utils")]
for path in phys_dirs:
if path not in paths:
paths.append(path)
Expand Down
2 changes: 1 addition & 1 deletion cime_config/cam_autogen.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def _find_scheme_source(source_dirs, metadata_file_name):
doctests:
1. Check that the function can correctly find source and namelist files:
>>> _find_scheme_source([os.path.join(_CAM_ROOT_DIR, "test", "unit", "sample_files", \
>>> _find_scheme_source([os.path.join(_CAM_ROOT_DIR, "test", "unit", "python", "sample_files", \
"autogen_files")], "two_scheme_banana") # doctest: +ELLIPSIS
('...two_scheme_banana.F90', '...two_scheme_banana_namelist.xml')
Expand Down
9 changes: 9 additions & 0 deletions cime_config/testdefs/testlist_cam.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@
<option name="comment">Test for Moist Held-Suarez (TJ2016) physics (physics_after_coupler group)</option>
</options>
</test>
<test compset="FPHYStest" grid="ne3pg3_ne3pg3_mg37" name="SMS_Ln2" testmods="cam/outfrq_zm_derecho">
<machines>
<machine name="derecho" compiler="gnu" category="aux_sima"/>
</machines>
<options>
<option name="wallclock">00:10:00</option>
<option name="comment">Test for Zhang McFarlane physics</option>
</options>
</test>

<!-- Derecho dycore tests -->
<test compset="FKESSLER" grid="mpasa480_mpasa480" name="SMS_Ln9" testmods="cam/outfrq_kessler_mpas_derecho">
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
./xmlchange CAM_CONFIG_OPTS="--dyn none --physics-suites kessler"
./xmlchange CAM_CONFIG_OPTS="--dyn none --physics-suites kessler_test"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./xmlchange CAM_CONFIG_OPTS="--dyn none --physics-suites zhang_mcfarlane"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ncdata='/glade/campaign/cesm/community/amwg/sima_baselines/cam_sima_test_snapshots/cam_ne3pg3_ZM_snapshot_derecho_gnu_before_c20250116.nc'
ncdata_check='/glade/campaign/cesm/community/amwg/sima_baselines/cam_sima_test_snapshots/cam_ne3pg3_ZM_snapshot_derecho_gnu_after_c20250116.nc'
debug_output=0
pver=32
zmconv_momcd=.7D0
zmconv_momcu=.7D0
zmconv_num_cin=1
hist_add_inst_fields;h1: ZMDT, ZMDQ, CAPE, FREQZM, CMFMC_DP, ZMMU, ZMMD, DLFZM, PCONVT, PCONVB, ZMFLXPRC, ZMFLXSNW
hist_add_inst_fields;h1: ZMNTPRPD, ZMNTSNPD, ZMEIHEAT, PRECCDZM, PRECZ
hist_add_inst_fields;h1: ZMUPGU, ZMUPGD, ZMVPGU, ZMVPGD, ZMICUU, ZMICUD, ZMICVU, ZMICVD
hist_add_inst_fields;h1: EVAPTZM, FZSNTZM, EVSNTZM, EVAPQZM
hist_add_inst_fields;h1: ZMMTU, ZMMTV, ZMMTT
hist_add_inst_fields;h1: ZMDLIQ, ZMDICE
hist_output_frequency;h1: 1*nstep
hist_precision;h1: REAL64
hist_max_frames;h1: 1
9 changes: 9 additions & 0 deletions src/core_utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set(CORE_UTILS_SRC string_core_utils.F90)

# core_utils is not integrated into the CMake build of any top level
# project yet and this CMake is for testing purposes only.
# Making a change to this project's CMake will not impact the build of
# a parent project at this time.
add_library(core_utils ${CORE_UTILS_SRC})
target_include_directories(core_utils PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

162 changes: 162 additions & 0 deletions src/core_utils/string_core_utils.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
module string_core_utils

implicit none
private

public :: core_to_str ! Convert integer to left justified string
public :: core_int_date_to_yyyymmdd ! Convert encoded date integer to "yyyy-mm-dd" format
public :: core_int_seconds_to_hhmmss ! Convert integer seconds past midnight to "hh:mm:ss" format
public :: core_stringify ! Convert one or more values of any intrinsic data types to a character string for pretty printing

CONTAINS

character(len=10) pure function core_to_str(n)
! return default integer as a left justified string

integer, intent(in) :: n

write(core_to_str,'(i0)') n

end function core_to_str

character(len=10) pure function core_int_date_to_yyyymmdd (date)
! Undefined behavior if date <= 0

! Input arguments
integer, intent(in) :: date

! Local variables
integer :: year ! year of yyyy-mm-dd
integer :: month ! month of yyyy-mm-dd
integer :: day ! day of yyyy-mm-dd

year = date / 10000
month = (date - year*10000) / 100
day = date - year*10000 - month*100

write(core_int_date_to_yyyymmdd, '(i4.4,A,i2.2,A,i2.2)') &
year,'-',month,'-',day

end function core_int_date_to_yyyymmdd

character(len=8) pure function core_int_seconds_to_hhmmss (seconds)
! Undefined behavior if seconds outside [0, 86400]

! Input arguments
integer, intent(in) :: seconds

! Local variables
integer :: hours ! hours of hh:mm:ss
integer :: minutes ! minutes of hh:mm:ss
integer :: secs ! seconds of hh:mm:ss

hours = seconds / 3600
minutes = (seconds - hours*3600) / 60
secs = (seconds - hours*3600 - minutes*60)

write(core_int_seconds_to_hhmmss,'(i2.2,A,i2.2,A,i2.2)') &
hours,':',minutes,':',secs

end function core_int_seconds_to_hhmmss

!> Convert one or more values of any intrinsic data types to a character string for pretty printing.
!> If `value` contains more than one element, the elements will be stringified, delimited by `separator`, then concatenated.
!> If `value` contains exactly one element, the element will be stringified without using `separator`.
!> If `value` contains zero element or is of unsupported data types, an empty character string is produced.
!> If `separator` is not supplied, it defaults to `, ` (i.e., a comma and a space).
!> (KCW, 2024-02-04)
pure function core_stringify(value, separator)
use, intrinsic :: iso_fortran_env, only: int32, int64, real32, real64

class(*), intent(in) :: value(:)
character(*), optional, intent(in) :: separator
character(:), allocatable :: core_stringify

integer, parameter :: sizelimit = 1024

character(:), allocatable :: buffer, delimiter, format
integer :: i, n, offset

if (present(separator)) then
delimiter = separator
else
delimiter = ', '
end if

n = min(size(value), sizelimit)

if (n == 0) then
core_stringify = ''
return
end if

select type (value)
type is (character(*))
allocate(character(len(value) * n + len(delimiter) * (n - 1)) :: buffer)

buffer(:) = ''
offset = 0

do i = 1, n
if (len(delimiter) > 0 .and. i > 1) then
buffer(offset + 1:offset + len(delimiter)) = delimiter
offset = offset + len(delimiter)
end if

if (len_trim(adjustl(value(i))) > 0) then
buffer(offset + 1:offset + len_trim(adjustl(value(i)))) = trim(adjustl(value(i)))
offset = offset + len_trim(adjustl(value(i)))
end if
end do
type is (integer(int32))
allocate(character(11 * n + len(delimiter) * (n - 1)) :: buffer)
allocate(character(17 + len(delimiter) + floor(log10(real(n))) + 1) :: format)

write(format, '(a, i0, 3a)') '(ss, ', n, '(i0, :, "', delimiter, '"))'
write(buffer, format) value
type is (integer(int64))
allocate(character(20 * n + len(delimiter) * (n - 1)) :: buffer)
allocate(character(17 + len(delimiter) + floor(log10(real(n))) + 1) :: format)

write(format, '(a, i0, 3a)') '(ss, ', n, '(i0, :, "', delimiter, '"))'
write(buffer, format) value
type is (logical)
allocate(character(1 * n + len(delimiter) * (n - 1)) :: buffer)
allocate(character(13 + len(delimiter) + floor(log10(real(n))) + 1) :: format)

write(format, '(a, i0, 3a)') '(', n, '(l1, :, "', delimiter, '"))'
write(buffer, format) value
type is (real(real32))
allocate(character(13 * n + len(delimiter) * (n - 1)) :: buffer)

if (maxval(abs(value)) < 1.0e5_real32) then
allocate(character(20 + len(delimiter) + floor(log10(real(n))) + 1) :: format)
write(format, '(a, i0, 3a)') '(ss, ', n, '(f13.6, :, "', delimiter, '"))'
else
allocate(character(23 + len(delimiter) + floor(log10(real(n))) + 1) :: format)
write(format, '(a, i0, 3a)') '(ss, ', n, '(es13.6e2, :, "', delimiter, '"))'
end if

write(buffer, format) value
type is (real(real64))
allocate(character(13 * n + len(delimiter) * (n - 1)) :: buffer)

if (maxval(abs(value)) < 1.0e5_real64) then
allocate(character(20 + len(delimiter) + floor(log10(real(n))) + 1) :: format)
write(format, '(a, i0, 3a)') '(ss, ', n, '(f13.6, :, "', delimiter, '"))'
else
allocate(character(23 + len(delimiter) + floor(log10(real(n))) + 1) :: format)
write(format, '(a, i0, 3a)') '(ss, ', n, '(es13.6e2, :, "', delimiter, '"))'
end if

write(buffer, format) value
class default
core_stringify = ''
return
end select

core_stringify = trim(buffer)

end function core_stringify

end module string_core_utils
2 changes: 1 addition & 1 deletion src/data/physconst.meta
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
dimensions = ()
protected = True
[ cpliq ]
standard_name = specific_heat_of_liquid_water_at_20c
standard_name = specific_heat_of_liquid_water_at_constant_pressure
long_name = Specific heat of fresh H2O
units = J kg-1 K-1
type = real | kind = kind_phys
Expand Down
4 changes: 2 additions & 2 deletions src/data/ref_pres.meta
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
dimensions = ()
protected = True
[ trop_cloud_top_lev ]
standard_name = index_of_pressure_at_troposhere_cloud_top
standard_name = vertical_layer_index_of_troposphere_cloud_top
units = index
type = integer
dimensions = ()
Expand Down Expand Up @@ -65,7 +65,7 @@
dimensions = ()
protected = True
[ nbot_molec ]
standard_name = index_of_pressure_at_bottom_of_molecular_diffusion
standard_name = vertical_layer_index_at_bottom_of_molecular_diffusion
units = index
type = integer
dimensions = ()
Expand Down
Loading

0 comments on commit 2269446

Please sign in to comment.