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

Instantaneous CAM-SIMA history infrastructure #274

Merged
merged 97 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
8c066f0
Work on adding history
Jul 30, 2022
44f1660
Correct CIME paths for new CIME
Aug 2, 2022
ff48e4f
Start stripping out old stuff
Aug 2, 2022
56006e0
history test script and history unit test passing
Aug 7, 2022
ab8eb89
Added history external
Aug 7, 2022
478905b
Checkin to work on other branch
Feb 10, 2023
70dd483
Partial implementation of filename spec in new initialization scheme.
Mar 22, 2023
7f3bb0b
Improvements to reading configuration and associated tests
Mar 28, 2023
bbd2c4b
Resurrect Fortran history tests. Add ability to use real endrun for d…
Mar 31, 2023
ebb15c3
Merge remote-tracking branch 'ESCOMP/development' into history_court
Jun 26, 2023
e4fa834
Updating Externals_CAM.cfg to point to tj2016 atmospheric physics fork.
mwaxmonsky Mar 1, 2024
81224d5
Resolving merge conflicts with Externals_CAM.cfg
mwaxmonsky Mar 15, 2024
19e1586
Merging in updates from ccpp-framework and atmospheric_physcis. Upda…
mwaxmonsky Mar 15, 2024
680d5a8
Updates based on bug fixes and feedback.
mwaxmonsky Apr 3, 2024
fc35548
Updating to latest atmos_phys changes.
mwaxmonsky Apr 15, 2024
0eb4e8f
Merge branch 'development' into tj2016
mwaxmonsky Apr 25, 2024
b6e7ab4
merge forward; some namelist mods
May 6, 2024
dcb4a5c
Merge branch 'development' into tj2016
mwaxmonsky May 10, 2024
0b309d1
instantaneous file output working
May 28, 2024
05ddd39
move registry hist routines to new module; update precision logic
May 31, 2024
23bc2bb
merge to head of cam_development
May 31, 2024
1212435
add constituents handling for add and out fields
May 31, 2024
bc7eba2
code cleanup; better error handling; use new buffer interfaces
Jun 4, 2024
7baf682
code cleanup; fix for indexing on multiple files
Jun 5, 2024
c1acda8
fix and add hist_config tests
Jun 6, 2024
510ade6
add test for ic_names dictionary
Jun 6, 2024
0635898
more thoroughly separate physics history write from generate_registry
Jun 7, 2024
f76b038
Standard names update.
mwaxmonsky Jun 7, 2024
0f53092
Update to latest atmos_phys
mwaxmonsky Jun 7, 2024
7591a27
Update to match generated code from capgen.
mwaxmonsky Jun 7, 2024
52d9b06
create register history tests; update existing tests
Jun 8, 2024
abf329a
enable avg flags in registry; clear buffers
Jun 10, 2024
61963c8
remove fortran tests until we design a new framework
Jun 11, 2024
dc7fe59
merge to head of development
Jun 11, 2024
ae52006
fix mpi broadcast nl counts
Jun 12, 2024
222227a
Updating to latest atmos_phys.
mwaxmonsky Jun 14, 2024
138f410
Updating to latest atmos_phys.
mwaxmonsky Jun 17, 2024
c561a98
Updating to latest atmos_phys.
mwaxmonsky Jun 25, 2024
7eddc01
fix dimensions for parallel; move history to timestep_final
Jun 25, 2024
f1c8c30
merge to head of development
Jun 25, 2024
279a2ca
Fixing merge conflict with branch development
mwaxmonsky Jun 27, 2024
70c235c
Removing standard names csv file as no longer needed.
mwaxmonsky Jun 27, 2024
8a64782
Moving input names to standard names xml generator to tools directory.
mwaxmonsky Jun 27, 2024
dfd52b1
Updating to latest development ccpp-framework.
mwaxmonsky Jun 27, 2024
f63ebf2
Removing commented code and updating standard name.
mwaxmonsky Jun 27, 2024
4fd48f7
conditionally write instantaneous file
Jun 30, 2024
330509e
grid support clean-up
Jul 1, 2024
8319b96
remove pointers for iodesc to be passed to initdecomp
Jul 1, 2024
3ac1b72
Fixing pylint errors.
mwaxmonsky Jul 1, 2024
04fd2ba
fix for intel compiler; add "allocatable" for nl arrays
Jul 5, 2024
2c8c7c5
Merge remote-tracking branch 'ESCOMP/development' into HEAD
Jul 5, 2024
a1a5202
specify character len
Jul 5, 2024
8191b82
fix broadcasts for arrays of character arrays
Jul 5, 2024
1885961
fix frequency calculations; couple fixes for output
Jul 6, 2024
f7e9d1f
allow instantaneous and accumulated fields on same volume
Jul 8, 2024
6024452
Removing anomalous backslash in regex string by using raw string.
mwaxmonsky Jul 8, 2024
498dbbb
code cleanup
Jul 8, 2024
5a7c176
Adding missing docstrings.
mwaxmonsky Jul 9, 2024
2e4b42e
python clean-up
Jul 9, 2024
228fc52
python cleanup for test_hist_config
Jul 9, 2024
14dcf39
remove unnecessary python version check
Jul 9, 2024
d394b92
handle volume configured with no fields
Jul 9, 2024
d87e41f
fix hist_config test
Jul 9, 2024
1a58f15
fix write_nstep0 logic
Jul 9, 2024
67b0b21
add missing mpi_broadcast
Jul 10, 2024
0fe3378
Merge branch 'development' into tj2016
mwaxmonsky Jul 11, 2024
7e8562b
Addressing review comments.
mwaxmonsky Jul 12, 2024
dbdbbad
Addressing review comments and adding error checking to PIO calls.
mwaxmonsky Jul 15, 2024
0f673e2
Addressing review comments. Updating tphys variable name to better c…
mwaxmonsky Jul 15, 2024
277fbdf
Merge remote-tracking branch 'mwax/tj2016' into history_court
Jul 15, 2024
9bd89cb
use diagnostic schemes instead of python-generated history
Jul 22, 2024
512becc
bring to head of development
Jul 24, 2024
8ac3838
fix unit tests
Jul 24, 2024
48f0807
fix to enable no history configurations in nl
Aug 7, 2024
9525b75
remove pio dependency from modular history to enable unit testing
Aug 9, 2024
cf6aa62
merge to head of development
Aug 23, 2024
8322b49
address one wave of review comments
peverwhee Aug 29, 2024
ac7c8a2
Merge branch 'history_court' of https://github.com/peverwhee/CAM-SIMA…
peverwhee Aug 29, 2024
1f023c1
fix python unit tests
peverwhee Aug 29, 2024
0784bcf
fix another unit test
peverwhee Aug 29, 2024
68b73b5
address next chunk of reviewer comments; through cam_history_support
peverwhee Sep 5, 2024
39a66ed
next round of review comments; through cam_history.F90
peverwhee Sep 9, 2024
7db18c3
more cleanup of cam_hist_file
peverwhee Sep 12, 2024
a0533cc
put safe_endrun back
peverwhee Sep 13, 2024
e7a7fa1
append %f to user-specified filename template
peverwhee Sep 13, 2024
813f377
more python review comments; fix unit tests
peverwhee Sep 13, 2024
87a61f3
update regular expressions
peverwhee Sep 14, 2024
923089f
Merge remote-tracking branch 'ESCOMP/development' into history_court
Sep 16, 2024
ea14039
merge to head of cam development; update vertically integrated standa…
Sep 16, 2024
9120544
update standard names
Sep 16, 2024
3ea79b3
address review comments
Sep 25, 2024
b437934
fix unit tests
Sep 25, 2024
dd882d1
update atmospheric_physics hash; small clean-up to python
Oct 17, 2024
175b30b
merge to head of development
Oct 17, 2024
2f32b91
bring in formal history_output tag
Oct 22, 2024
cdf9222
fix num_samples bug
Oct 24, 2024
69ac862
merge to head of development
Oct 24, 2024
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
95 changes: 51 additions & 44 deletions cime_config/hist_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
_OUT_PRECS = ['REAL32', 'REAL64']
_TRUE_VALUES = {"true", "t", ".true."}
_FALSE_VALUES = {"false", "f", ".false."}
_NETCDF_ID_RE = re.compile(r"^[a-z]\w{0,62}$", re.IGNORECASE)
# NetCDF variable name requirements:
# https://docs.unidata.ucar.edu/netcdf-c/current/programming_notes.html#object_name
_NETCDF_ID_RE = re.compile(r"^[a-z][\w._@+]{0,256}$", re.IGNORECASE)

##############################################################################
###
Expand Down Expand Up @@ -125,22 +127,20 @@ def _list_of_idents(entry, sep=','):
(['foo', 'BA2r3'], None)
>>> _list_of_idents("foo, 3bar")
(None, 'Found invalid identifiers:\\n 3bar')
>>> _list_of_idents("foo.3bar")
(None, 'Found invalid identifiers:\\n foo.3bar')
>>> _list_of_idents("foo3bariendnaadfasdfbasdlkfap983rasdfvalsda938qjnasdasd98adfasxd")
(None, 'Found invalid identifiers:\\n foo3bariendnaadfasdfbasdlkfap983rasdfvalsda938qjnasdasd98adfasxd')
>>> _list_of_idents("foo.3bar, foo3bariendnaadfasdfbasdlkfap983rasdfvalsda938qjnasdasd98adfasxd")
(None, 'Found invalid identifiers:\\n foo.3bar\\n foo3bariendnaadfasdfbasdlkfap983rasdfvalsda938qjnasdasd98adfasxd')
>>> _list_of_idents("foo.3bar; foo", sep=';')
(None, 'Found invalid identifiers:\\n foo.3bar')
>>> _list_of_idents("foo,3bar", sep=';')
(None, 'Found invalid identifiers:\\n foo,3bar')
>>> _list_of_idents("foo#3bar, foo3baifijeowfjeiofjewiofjeiwofjewiofejifwjoefdfewfefdfdkjokmcdioanicdiaoilfejieojwiefjidojfioejsiofdjkljnxpoiadjfioenskcodiafkamd199fd9a0fdjkldajfdfjiodanckdalirhgieoskjcdskdfieowfidjfslk129dkjfaiocsriendnaadfasdfbasdlkfap983rasdfvalsda938qjnasdasd98adfasxd")
(None, 'Found invalid identifiers:\\n foo#3bar\\n foo3baifijeowfjeiofjewiofjeiwofjewiofejifwjoefdfewfefdfdkjokmcdioanicdiaoilfejieojwiefjidojfioejsiofdjkljnxpoiadjfioenskcodiafkamd199fd9a0fdjkldajfdfjiodanckdalirhgieoskjcdskdfieowfidjfslk129dkjfaiocsriendnaadfasdfbasdlkfap983rasdfvalsda938qjnasdasd98adfasxd')
>>> _list_of_idents("foo,3bar; foo", sep=';')
(None, 'Found invalid identifiers:\\n foo,3bar')
>>> _list_of_idents(" ")
(None, 'No identifiers found')
"""
if entry.strip():
potential_list = [x.strip() for x in entry.split(sep)]
bad_list = [sample for sample in potential_list if _NETCDF_ID_RE.match(sample) is None]
if len(bad_list) > 0:
return (None, f"Found invalid identifiers:\n " + '\n '.join(bad_list))
return (None, "Found invalid identifiers:\n " + "\n ".join(bad_list))
# end if
return (potential_list, None)
# end if
Expand All @@ -161,52 +161,50 @@ def _is_mult_period(entry):
>>> _is_mult_period("3 * nmonths")
((3, 'nmonths'), None)
>>> _is_mult_period("2*fortnights")
(None, 'period must be one of nsteps, nstep, nseconds, nsecond, nminutes, nminute, nhours, nhour, ndays, nday, nmonths, nmonth, nyears, nyear, steps, seconds, minutes, hours, days, months, years')
(None, 'period ("fortnights") must be one of nsteps, nstep, nseconds, nsecond, nminutes, nminute, nhours, nhour, ndays, nday, nmonths, nmonth, nyears, nyear, steps, seconds, minutes, hours, days, months, years')
>>> _is_mult_period("7*nhours of day")
(None, 'period must be one of nsteps, nstep, nseconds, nsecond, nminutes, nminute, nhours, nhour, ndays, nday, nmonths, nmonth, nyears, nyear, steps, seconds, minutes, hours, days, months, years')
(None, 'period ("nhours of day") must be one of nsteps, nstep, nseconds, nsecond, nminutes, nminute, nhours, nhour, ndays, nday, nmonths, nmonth, nyears, nyear, steps, seconds, minutes, hours, days, months, years')
>>> _is_mult_period(" ")
(None, 'a frequency ([<mult>*]period) is required')
(None, 'frequency ([<mult>*]period) is required, found " "')
>>> _is_mult_period("1*nyear")
((1, 'nyear'), None)
>>> _is_mult_period("-6*nhours")
(None, "multiplier '-6' in '-6*nhours' must be a positive integer")
(None, 'multiplier ("-6") must be a positive integer')
>>> _is_mult_period("7h*nhours")
(None, "multiplier '7h' in '7h*nhours' must be a positive integer")
(None, '"7h" in "7h*nhours" is not a valid integer')
>>> _is_mult_period("5*nhours*ndays")
(None, "multiplier '5*nhours' in '5*nhours*ndays' must be a positive integer")
(None, 'frequency must be of the form ([<mult>*]period), found "5*nhours*ndays". Do you have too many multipliers or periods?')
"""
if not entry.strip():
errmsg = "a frequency ([<mult>*]period) is required"
return (None, errmsg)
if not entry or not entry.strip():
return (None, f"frequency ([<mult>*]period) is required, found \"{entry}\"")
# end if
_OPTIONAL_MULTIPLIER_TOKEN = r"((?P<multiplier>.*)\*)"
_REQUIRED_PERIOD_TOKEN = "(?P<period>.*)"
_MULT_PERIOD_REGEX = f"^{_OPTIONAL_MULTIPLIER_TOKEN}?\s*{_REQUIRED_PERIOD_TOKEN}$"
match = re.match(_MULT_PERIOD_REGEX, entry.strip())
group_dict = match.groupdict()
if len(group_dict) == 0 or 'period' not in group_dict:
errmsg = f"Bad formatting of frequency, '{entry}' must be in the form of '[<integer>*]<time period>'"
return (None, errmsg)
# end if
# Check multiplier
tokens = [x.strip() for x in str(entry.strip()).split('*')]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think entry is already a string, so no need to convert it here. Also I don't think there is any need to strip twice:

Suggested change
tokens = [x.strip() for x in str(entry.strip()).split('*')]
tokens = [x.strip() for x in entry.split('*')]

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleaned up! thanks!

num_tokens = len(tokens)

multiplier = 1
if 'multiplier' in group_dict:
potential_multiplier = group_dict['multiplier']
if potential_multiplier:
multiplier, errmsg = _is_integer(potential_multiplier)
if errmsg or (multiplier <= 0):
errmsg = f"multiplier '{potential_multiplier}' in '{entry}' must be a positive integer"
return (None, errmsg)
# end if
# end if
period = ""
if num_tokens == 1:
period = tokens[0].lower()
elif num_tokens == 2:
multiplier = tokens[0]
period = tokens[1].lower()
else:
return (None, f"frequency must be of the form ([<mult>*]period), found \"{entry}\". Do you have too many multipliers or periods?")
# end if
# Check for valid period
period = group_dict['period'].strip().lower()

if period not in _TIME_PERIODS:
errmsg = f'period must be one of {", ".join(_TIME_PERIODS)}'
return (None, errmsg)
time_periods = ", ".join(_TIME_PERIODS)
return (None, f"period (\"{period}\") must be one of {time_periods}")
# end if
return ((multiplier, period), None)
(candidate_multiplier, errmsg) = _is_integer(multiplier)
if errmsg:
return (None, f"\"{multiplier}\" in \"{entry}\" is not a valid integer")
# end if
if candidate_multiplier <= 0:
return (None, f"multiplier (\"{candidate_multiplier}\") must be a positive integer")
# end if

return ((candidate_multiplier, period), None)

##############################################################################
def _is_prec_str(entry):
Expand Down Expand Up @@ -308,6 +306,8 @@ def _parse_hist_config_line(line, no_command_ok=False):
(None, None, "Invalid history config line, 'use_topo_file = .false.'")
>>> _parse_hist_config_line("use_topo_file = .false.", no_command_ok=True)
('use_topo_file', None, None)
>>> _parse_hist_config_line(" ")
(None, None, None)
"""
# Find the possible history configuration command for <line>.
if _blank_config_line(line):
Expand Down Expand Up @@ -679,7 +679,7 @@ def remove_fields(self, fields, pobj, logger):
all_removed = False
missing_fields = fields_to_delete.difference(fields_deleted)
ctx = context_string(pobj)
missing_fields_string = ", ".join(list(missing_fields))
missing_fields_string = ", ".join(missing_fields)
errmsg = f"Cannot remove field(s), '{missing_fields_string}', not found on hist volume, {self.volume}{ctx}"
logger.warning(errmsg)
# end if
Expand Down Expand Up @@ -772,6 +772,13 @@ def output_frequency(self):
return self.__output_freq

def __out_frequency_is_valid(this, ofreq):
"""
Determine if a user-supplied output frequency is valid.
Checks:
- frequency is tuple (multiplier, period)
- multiplier is a positive integer
- period is in list of valid time periods
"""
return isinstance(ofreq, tuple) and \
(len(ofreq) == 2) and \
(ofreq[0] > 0) and \
Expand Down
5 changes: 3 additions & 2 deletions src/dynamics/utils/hycoef.F90
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ subroutine hycoef_init(file, psdry)
if (dry_coord) then
call add_vert_coord('ilev', pverp, &
'hybrid level at interfaces (1000*(A+B))', 'hPa', ailev, &
positive='down')
positive='down', &
standard_name='atmosphere_hybrid_sigma_pressure_coordinate_at_interfaces')
call add_hist_coord('hyai', pverp, &
'hybrid A coefficient at layer interfaces', '1', hyai, dimname='ilev')
call add_hist_coord('hybi', pverp, &
Expand All @@ -309,7 +310,7 @@ subroutine hycoef_init(file, psdry)
call add_vert_coord('ilev', pverp, &
'hybrid level at interfaces (1000*(A+B))', 'hPa', ailev, &
positive='down', &
standard_name='atmosphere_hybrid_sigma_pressure_coordinate', &
standard_name='atmosphere_hybrid_sigma_pressure_coordinate_at_interfaces', &
formula_terms=formula_terms)
end if

Expand Down
18 changes: 14 additions & 4 deletions src/history/cam_hist_file.F90
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ module cam_hist_file
integer, private :: output_freq_mult = UNSET_I
character(len=8), private :: output_freq_type = UNSET_C
integer, private :: num_samples = 0
real(kind=r8), private :: beg_time = UNSET_R8
real(kind=r8), private :: end_time = UNSET_R8
real(r8), private :: beg_time = UNSET_R8
real(r8), private :: end_time = UNSET_R8
character(len=:), allocatable, private :: filename_spec
character(len=max_fldlen), allocatable, private :: field_names(:)
character(len=3), allocatable, private :: accumulate_types(:)
Expand Down Expand Up @@ -914,7 +914,7 @@ subroutine config_define_file(this, restart, logname, host, model_doi_url)
use cam_history_support, only: max_chars
use time_manager, only: get_ref_date, timemgr_get_calendar_cf
use time_manager, only: get_step_size
use string_utils, only: date2yyyymmdd, sec2hms
use string_utils, only: date2yyyymmdd, sec2hms, stringify
use cam_control_mod, only: caseid
use cam_initfiles, only: ncdata, bnd_topo
use cam_abortutils, only: check_allocate, endrun
Expand Down Expand Up @@ -967,6 +967,7 @@ subroutine config_define_file(this, restart, logname, host, model_doi_url)
! A structure to hold the horizontal dimension and coordinate info
type(cam_grid_header_info_t), allocatable :: header_info(:)
integer, allocatable :: mdimids(:)
integer, parameter :: max_netcdf_len = 256
character(len=*), parameter :: subname = 'config_define_file: '

is_initfile = (this%hfile_type == hfile_type_init_value)
Expand Down Expand Up @@ -1218,6 +1219,15 @@ subroutine config_define_file(this, restart, logname, host, model_doi_url)
mdims = this%field_list(field_index)%dimensions()
mdimsize = size(mdims)
fname_tmp = strip_suffix(this%field_list(field_index)%diag_name())
! Ensure that fname_tmp is not longer than the maximum length for a
! netcdf file
if (len_trim(fname_tmp) > max_netcdf_len) then
! Endrun if the name is too long
write(errmsg, *) 'config_define_file: variable name ', trim(fname_tmp), &
' too long for NetCDF file (len=', stringify((/len(trim(fname_tmp))/)), ' > ', &
stringify((/max_netcdf_len/)), ')'
call endrun(errmsg, file=__FILE__, line=__LINE__)
end if
!
! Create variables and atributes for fields written out as columns
!
Expand Down Expand Up @@ -1659,7 +1669,7 @@ subroutine read_namelist_entry(unitn, hfile_config, hist_inst_fields, &
character(len=max_fldlen), allocatable, intent(inout) :: hist_max_fields(:)
character(len=max_fldlen), allocatable, intent(inout) :: hist_var_fields(:)
! Local variables (namelist)
character(len=vlen) :: hist_volume ! h# ir i, not config number
character(len=vlen) :: hist_volume
character(len=vlen) :: hist_precision
nusbaume marked this conversation as resolved.
Show resolved Hide resolved
integer :: hist_max_frames
character(len=flen) :: hist_output_frequency
Expand Down
5 changes: 4 additions & 1 deletion src/utils/cam_abortutils.F90
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ subroutine cam_register_open_file(file, file_name)
! Local variables
type(open_file_pointer), pointer :: of_ptr
type(open_file_pointer), pointer :: of_new
integer :: ierr
character(len=*), parameter :: subname = 'cam_register_open_file'

nullify(of_new)
Expand All @@ -80,7 +81,9 @@ subroutine cam_register_open_file(file, file_name)
! If we get here, go ahead and register the file
if (associated(open_files_pool)) then
of_new => open_files_pool
allocate(of_new%file_desc)
allocate(of_new%file_desc, stat=ierr)
call check_allocate(ierr, subname, 'of_file%file_desc', file=__FILE__, &
line=__LINE__)
of_new%file_desc = file
of_new%file_name = file_name
allocate(open_files_pool%next)
Expand Down
13 changes: 13 additions & 0 deletions src/utils/cam_filenames.F90
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ character(len=cl) function interpret_filename_spec(filename_spec, unit, accum_ty
else
call get_curr_date(year, month, day, ncsec)
end if
else
if (present(yr_spec)) then
year = yr_spec
end if
if (present(mon_spec)) then
month = mon_spec
end if
if (present(day_spec)) then
day = day_spec
end if
if (present(sec_spec)) then
ncsec = sec_spec
end if
end if ! No else, do not use these quantities below.
!
! Go through each character in the filename specifier and interpret
Expand Down
2 changes: 2 additions & 0 deletions test/run_unit_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ run_doctest cime_config/create_readnl_files.py
run_doctest src/data/generate_registry_data.py
# ParamGen atm_in namelist writer doctests:
run_doctest cime_config/atm_in_paramgen.py
# CAM history config doctests:
run_doctest cime_config/hist_config.py
# CAM config unit tests:
run_unittest test/unit/test_cam_config.py
# CAM autogen unit tests:
Expand Down
5 changes: 2 additions & 3 deletions test/unit/test_hist_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _test_config(self, config, vol, prec, maxf, outfreq, ftype, write_nstep0, fi
self.assertEqual(config.output_frequency, outfreq,
msg="Bad output frequency")
self.assertEqual(config.file_type, ftype, msg="Bad file type")
self.assertEqual(config.write_nstep0, write_nstep0, msg="Bad write_nste0 flag")
self.assertEqual(config.write_nstep0, write_nstep0, msg="Bad write_nstep0 flag")
self.assertEqual(config.filename_spec, filename_spec, msg="Bad filename spec")
self.assertEqual(config.restart_fname_spec, restart_fname_spec, msg="Bad restart filename spec")

Expand Down Expand Up @@ -188,7 +188,6 @@ def test_bad_user_nl_cam(self):
# Read in file:
file_lines = old_file.readlines()
# Edit to add bad lines
print(file_lines[14])
file_lines[8] = ""
file_lines[9] = "hist_remove_fields;h0:\n"
file_lines[10] = "hist_output_frequency;h0: 1+nmonths\n"
Expand All @@ -211,7 +210,7 @@ def test_bad_user_nl_cam(self):

exception_split = str(err.exception).split('\n')
errmsg_expected = ["No identifiers found, at",
"period must be one of nsteps, nstep, nseconds, nsecond, nminutes, nminute, nhours, nhour, ndays, nday, nmonths, nmonth, nyears, nyear, steps, seconds, minutes, hours, days, months, years, at",
"period (\"1+nmonths\") must be one of nsteps, nstep, nseconds, nsecond, nminutes, nminute, nhours, nhour, ndays, nday, nmonths, nmonth, nyears, nyear, steps, seconds, minutes, hours, days, months, years, at",
"precision must be one of REAL32, REAL64, at",
"Found invalid identifiers",
"T&U&V, at",
Expand Down
Loading