Skip to content

Commit f4b2a58

Browse files
authored
Merge pull request #783 from NCAR/get_state_variables
Generalized subroutine to read the state variables from the namelist (parse_variables)
2 parents aee5c05 + 9d0a17a commit f4b2a58

File tree

18 files changed

+576
-799
lines changed

18 files changed

+576
-799
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ test_beta_dist
208208
test_kde_dist
209209
test_window
210210
test_force_bounds
211+
test_parse_variables
211212

212213
# Directories to NOT IGNORE ... same as executable names
213214
# as far as I know, these must be listed after the executables

CHANGELOG.rst

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ individual files.
2222

2323
The changes are now listed with the most recent at the top.
2424

25+
**February 4 2025 :: Generic model_mod subroutine parse_variables. Tag v11.10.3**
26+
27+
- Creates two generalized subroutines that convert the table of state variables that is
28+
read in from the &model_nml to a state_var_type: parse_variables and parse_variables_clamp
29+
- Alternate versions for this subroutine were replaced with parse_variables in the
30+
models MOM6, wrf_hydro, aether_lat-lon, cam-fv, cam-se, POP, and cice
31+
- New dev test test_parse_variables added
32+
2533
**February 3 2025 :: Inflation documentation. Tag v11.10.2**
2634

2735
- Improved inflation documentation

assimilation_code/modules/io/state_structure_mod.f90

+62-5
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ module state_structure_mod
1818
!> The add_domain() call adds a 'domain' to the state. This may be a component in
1919
!> the case of XCESM or another coupled model.
2020
!>
21-
!> There are three ways to add a domain (these are overloaded as add_domain):
21+
!> There are four ways to add a domain (these are overloaded as add_domain):
2222
!> * add_domain_blank. This takes model size as an argument.
2323
!>
2424
!> * add_domain_from_file. This takes a netcdf file and a list of variables
2525
!>
26+
!> * add_domain_from_state_type. This takes a netcdf file and a state_var_type,
27+
!> which includes nvars, netcdf variable names, qtys (kinds),
28+
!> clamp_values (optional), and updates
29+
!>
2630
!> * add_domain_from_spec. This makes a skeleton structure for a domain. Dimensions
2731
!> for each variable must be added using add_dimension_to_variable(). This is intended
2832
!> to be used to create netcdf output for models like bgrid_solo that are spun up.
@@ -68,6 +72,8 @@ module state_structure_mod
6872

6973
use sort_mod, only : index_sort
7074

75+
use default_model_mod, only : state_var_type
76+
7177
use netcdf
7278

7379
implicit none
@@ -240,8 +246,8 @@ module state_structure_mod
240246
character(len=256) :: info_file = 'NULL'
241247

242248
! string identifying the manner in which the domain was created
243-
! 'blank', 'file', or 'spec'
244-
character(len=6) :: method = 'none'
249+
! 'blank', 'file', 'state_type', or 'spec'
250+
character(len=11) :: method = 'none'
245251

246252
end type domain_type
247253

@@ -281,6 +287,7 @@ module state_structure_mod
281287
module procedure add_domain_blank
282288
module procedure add_domain_from_file
283289
module procedure add_domain_from_spec
290+
module procedure add_domain_from_state_type
284291
end interface
285292

286293
interface get_index_start
@@ -313,8 +320,6 @@ module state_structure_mod
313320
!> into the state_strucutre.
314321
!>
315322
!> Returns a dom_id that can be used to harvest information of a particular domain
316-
!>
317-
!> Does this need to be a function or a subroutine?
318323

319324

320325
function add_domain_from_file(info_file, num_vars, var_names, kind_list, clamp_vals, update_list) result(dom_id)
@@ -365,6 +370,58 @@ function add_domain_from_file(info_file, num_vars, var_names, kind_list, clamp_v
365370
end function add_domain_from_file
366371

367372

373+
!-------------------------------------------------------------------------------
374+
!> Given an info_file, reads in a state_var_type including nvars, netcdf
375+
!> variable names, qtys (kinds), clamp values (optional), and updates into the
376+
!> state_structure
377+
!>
378+
!> Returns a dom_id that can be used to harvest information of a particular domain
379+
380+
381+
function add_domain_from_state_type(info_file, vars) result(dom_id)
382+
383+
character(len=*), intent(in) :: info_file
384+
type(state_var_type), intent(in) :: vars
385+
integer :: dom_id
386+
387+
integer :: ivar
388+
389+
! add to domains
390+
call assert_below_max_num_domains('add_domain_from_state_type')
391+
state%num_domains = state%num_domains + 1
392+
!>@todo dom_id should be a handle.
393+
dom_id = state%num_domains
394+
395+
! save information about the information file
396+
state%domain(dom_id)%info_file = info_file
397+
state%domain(dom_id)%method = 'state_type'
398+
399+
! set number of variables in this domain
400+
state%domain(dom_id)%num_variables = vars%nvars
401+
402+
! load up the variable names
403+
allocate(state%domain(dom_id)%variable(vars%nvars))
404+
405+
do ivar = 1, vars%nvars
406+
state%domain(dom_id)%variable(ivar)%varname = vars%netcdf_var_names(ivar)
407+
enddo
408+
409+
! load up variable id's and sizes
410+
call load_state_variable_info(state%domain(dom_id),dom_id)
411+
412+
! load up the domain unique dimension info
413+
call load_unique_dim_info(dom_id)
414+
415+
! load up any cf-conventions if they exist
416+
call load_common_cf_conventions(state%domain(dom_id))
417+
418+
call set_dart_kinds(dom_id, vars%nvars, vars%qtys)
419+
if (allocated(vars%clamp_values)) call set_clamping(dom_id, vars%nvars, vars%clamp_values)
420+
call set_update_list(dom_id, vars%nvars, vars%updates)
421+
422+
end function add_domain_from_state_type
423+
424+
368425
!-------------------------------------------------------------------------------
369426
!> Defines a skeleton structure for the state structure. Dimension can be
370427
!> added to variables with add_dimension_to_variable.

conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
author = 'Data Assimilation Research Section'
2222

2323
# The full version, including alpha/beta/rc tags
24-
release = '11.10.2'
24+
release = '11.10.3'
2525
root_doc = 'index'
2626

2727
# -- General configuration ---------------------------------------------------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
! DART software - Copyright UCAR. This open source software is provided
2+
! by UCAR, "as is", without charge, subject to all terms of use at
3+
! http://www.image.ucar.edu/DAReS/DART/DART_download
4+
5+
program test_parse_variables
6+
7+
use utilities_mod, only : find_namelist_in_file, check_namelist_read, &
8+
initialize_utilities, finalize_utilities
9+
use types_mod, only : vtablenamelength, MISSING_R8, r8
10+
use default_model_mod, only : parse_variables_clamp, parse_variables, &
11+
state_var_type, &
12+
MAX_STATE_VARIABLE_FIELDS_CLAMP, &
13+
MAX_STATE_VARIABLE_FIELDS
14+
use obs_kind_mod, only : QTY_SALINITY, QTY_POTENTIAL_TEMPERATURE, &
15+
QTY_U_CURRENT_COMPONENT
16+
17+
use test ! fortran-testanything
18+
19+
implicit none
20+
21+
integer :: iunit, io
22+
type(state_var_type) :: state_vars, state_vars_clamp
23+
24+
character(len=vtablenamelength) :: state_variables(MAX_STATE_VARIABLE_FIELDS) = ' '
25+
character(len=vtablenamelength) :: state_variables_clamp(MAX_STATE_VARIABLE_FIELDS_CLAMP) = ' '
26+
27+
namelist /model_nml/ &
28+
state_variables
29+
30+
namelist /model_nml_clamp/ &
31+
state_variables_clamp
32+
33+
call initialize_utilities('test_parse_variables')
34+
35+
call plan(28)
36+
37+
! Using namelist entry WITHOUT clamping values
38+
39+
call find_namelist_in_file('input.nml', 'model_nml', iunit)
40+
read(iunit, nml = model_nml, iostat = io)
41+
call check_namelist_read(iunit, io, 'model_nml')
42+
43+
state_vars = parse_variables(state_variables)
44+
45+
call ok(state_vars%nvars == 3)
46+
call ok(state_vars%netcdf_var_names(1) == 'SALT_CUR')
47+
call ok(state_vars%netcdf_var_names(2) == 'TEMP_CUR')
48+
call ok(state_vars%netcdf_var_names(3) == 'UVEL_CUR')
49+
call ok(state_vars%qtys(1) == QTY_SALINITY)
50+
call ok(state_vars%qtys(2) == QTY_POTENTIAL_TEMPERATURE)
51+
call ok(state_vars%qtys(3) == QTY_U_CURRENT_COMPONENT)
52+
call ok(allocated(state_vars_clamp%clamp_values) .eqv. .false.)
53+
call ok(state_vars%updates(1) .eqv. .true.)
54+
call ok(state_vars%updates(2) .eqv. .false.)
55+
call ok(state_vars%updates(3) .eqv. .true.)
56+
57+
! Using namelist entry WITH clamping values
58+
59+
call find_namelist_in_file('input.nml', 'model_nml_clamp', iunit)
60+
read(iunit, nml = model_nml_clamp, iostat = io)
61+
call check_namelist_read(iunit, io, 'model_nml_clamp')
62+
63+
state_vars_clamp = parse_variables_clamp(state_variables_clamp)
64+
65+
call ok(state_vars_clamp%nvars == 3)
66+
call ok(state_vars_clamp%netcdf_var_names(1) == 'SALT_CUR')
67+
call ok(state_vars_clamp%netcdf_var_names(2) == 'TEMP_CUR')
68+
call ok(state_vars_clamp%netcdf_var_names(3) == 'UVEL_CUR')
69+
call ok(state_vars_clamp%qtys(1) == QTY_SALINITY)
70+
call ok(state_vars_clamp%qtys(2) == QTY_POTENTIAL_TEMPERATURE)
71+
call ok(state_vars_clamp%qtys(3) == QTY_U_CURRENT_COMPONENT)
72+
call ok(allocated(state_vars_clamp%clamp_values) .eqv. .true.)
73+
call ok(state_vars_clamp%clamp_values(1,1) == 0.0_r8)
74+
call ok(state_vars_clamp%clamp_values(1,2) == 0.0_r8)
75+
call ok(state_vars_clamp%clamp_values(2,1) == 0.0_r8)
76+
call ok(state_vars_clamp%clamp_values(2,2) == 0.0_r8)
77+
call ok(state_vars_clamp%clamp_values(3,1) == 0.0_r8)
78+
call ok(state_vars_clamp%clamp_values(3,2) == 0.0_r8)
79+
call ok(state_vars_clamp%updates(1) .eqv. .true.)
80+
call ok(state_vars_clamp%updates(2) .eqv. .false.)
81+
call ok(state_vars_clamp%updates(3) .eqv. .true.)
82+
83+
call finalize_utilities()
84+
85+
end program test_parse_variables
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
&model_nml_clamp
2+
state_variables_clamp = 'SALT_CUR ', 'QTY_SALINITY', '0.0', '0.0', 'UPDATE',
3+
'TEMP_CUR ', 'QTY_POTENTIAL_TEMPERATURE', '0.0', '0.0', 'NO_COPY_BACK',
4+
'UVEL_CUR ', 'QTY_U_CURRENT_COMPONENT ', '0', '0.0', 'UPDATE',
5+
/
6+
7+
&model_nml
8+
state_variables = 'SALT_CUR ', 'QTY_SALINITY', 'UPDATE',
9+
'TEMP_CUR ', 'QTY_POTENTIAL_TEMPERATURE', 'NO_COPY_BACK',
10+
'UVEL_CUR ', 'QTY_U_CURRENT_COMPONENT ', 'update'
11+
/
12+
13+
&utilities_nml
14+
module_details = .false.
15+
write_nml = 'none'
16+
/
17+
18+
&preprocess_nml
19+
input_obs_kind_mod_file = '../../../assimilation_code/modules/observations/DEFAULT_obs_kind_mod.F90'
20+
quantity_files = '../../../assimilation_code/modules/observations/land_quantities_mod.f90',
21+
'../../../assimilation_code/modules/observations/default_quantities_mod.f90'
22+
'../../../assimilation_code/modules/observations/atmosphere_quantities_mod.f90'
23+
'../../../assimilation_code/modules/observations/ocean_quantities_mod.f90'
24+
output_obs_kind_mod_file = '../../../assimilation_code/modules/observations/obs_kind_mod.f90'
25+
input_obs_def_mod_file = '../../../observations/forward_operators/DEFAULT_obs_def_mod.F90'
26+
output_obs_def_mod_file = '../../../observations/forward_operators/obs_def_mod.f90'
27+
input_files = '../../../observations/forward_operators/obs_def_AIRS_mod.f90',
28+
'../../../observations/forward_operators/obs_def_AOD_mod.f90',
29+
'../../../observations/forward_operators/obs_def_AURA_mod.f90',
30+
'../../../observations/forward_operators/obs_def_COSMOS_mod.f90',
31+
'../../../observations/forward_operators/obs_def_CO_Nadir_mod.f90',
32+
'../../../observations/forward_operators/obs_def_GWD_mod.f90',
33+
'../../../observations/forward_operators/obs_def_QuikSCAT_mod.f90',
34+
'../../../observations/forward_operators/obs_def_SABER_mod.f90',
35+
'../../../observations/forward_operators/obs_def_altimeter_mod.f90',
36+
'../../../observations/forward_operators/obs_def_cloud_mod.f90',
37+
'../../../observations/forward_operators/obs_def_dew_point_mod.f90',
38+
'../../../observations/forward_operators/obs_def_dwl_mod.f90',
39+
'../../../observations/forward_operators/obs_def_eval_mod.f90',
40+
'../../../observations/forward_operators/obs_def_gps_mod.f90',
41+
'../../../observations/forward_operators/obs_def_gts_mod.f90',
42+
'../../../observations/forward_operators/obs_def_land_mod.f90',
43+
'../../../observations/forward_operators/obs_def_metar_mod.f90',
44+
'../../../observations/forward_operators/obs_def_ocean_mod.f90',
45+
'../../../observations/forward_operators/obs_def_pe2lyr_mod.f90',
46+
'../../../observations/forward_operators/obs_def_radar_mod.f90',
47+
'../../../observations/forward_operators/obs_def_reanalysis_bufr_mod.f90',
48+
'../../../observations/forward_operators/obs_def_rel_humidity_mod.f90',
49+
'../../../observations/forward_operators/obs_def_sqg_mod.f90',
50+
'../../../observations/forward_operators/obs_def_tower_mod.f90',
51+
'../../../observations/forward_operators/obs_def_tpw_mod.f90',
52+
'../../../observations/forward_operators/obs_def_upper_atm_mod.f90',
53+
'../../../observations/forward_operators/obs_def_vortex_mod.f90',
54+
'../../../observations/forward_operators/obs_def_wind_speed_mod.f90'
55+
/
56+
57+
&mpi_utilities_nml
58+
/
59+
60+
&obs_kind_nml
61+
/
62+
63+
&ensemble_manager_nml
64+
/
65+
66+
&state_vector_io_nml
67+
/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
3+
# DART software - Copyright UCAR. This open source software is provided
4+
# by UCAR, "as is", without charge, subject to all terms of use at
5+
# http://www.image.ucar.edu/DAReS/DART/DART_download
6+
7+
main() {
8+
9+
export DART=$(git rev-parse --show-toplevel)
10+
source "$DART"/build_templates/buildfunctions.sh
11+
12+
MODEL="none"
13+
EXTRA="$DART"/models/template/threed_model_mod.f90
14+
dev_test=1
15+
TEST="namelist"
16+
LOCATION="threed_sphere"
17+
18+
serial_programs=(
19+
test_parse_variables
20+
)
21+
22+
23+
# quickbuild arguments
24+
arguments "$@"
25+
26+
# clean the directory
27+
\rm -f -- *.o *.mod Makefile .cppdefs
28+
29+
# build any NetCDF files from .cdl files
30+
cdl_to_netcdf
31+
32+
# build and run preprocess before making any other DART executables
33+
buildpreprocess
34+
35+
# build
36+
buildit
37+
38+
# clean up
39+
\rm -f -- *.o *.mod
40+
41+
}
42+
43+
main "$@"

0 commit comments

Comments
 (0)