Skip to content

Commit

Permalink
Merge branch 'main' of github.com:NOAA-GFDL/FMS into flexible_dm
Browse files Browse the repository at this point in the history
  • Loading branch information
uramirez8707 committed Oct 30, 2024
2 parents 631b008 + bd9cbeb commit 5fc7917
Show file tree
Hide file tree
Showing 26 changed files with 799 additions and 114 deletions.
5 changes: 5 additions & 0 deletions data_override/README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [Converting legacy data_table to data_table.yaml](README.MD#3-converting-legacy-data_table-to-data_tableyaml)
- [Examples](README.MD#4-examples)
- [External Weight File Structure](README.MD#5-external-weight-file-structure)
- [Ensemble and Nest Support](README.MD#6-ensemble-and-nest-support)

#### 1. YAML Data Table format:
Each entry in the data_table has the following key values:
Expand Down Expand Up @@ -200,3 +201,7 @@ variables:
- weight(:,:,2) -> (i,j+1)
- weight(:,:,3) -> (i+1,j)
- weight(:,:,4) -> (i+1,j+1)

#### 6. Ensemble and Nest Support

It may be desired to have each member of an ensemble use a different forcing file. In other to support this, FMS allows for each ensemble member to have its own data_table.yaml. For example, for a run with 2 ensemble members, fms will search for data_table_ens_01.yaml and data_table_ens_02.yaml. However, if both the data_table.yaml and the data_table_ens_* files are present, the code will crash as only 1 option is allowed. Similary, each nest can have its own data_table (data_table_nest_01.yaml), but in this case FMS will not crash if both data_table_nest_01.yaml and data_table.yaml are present. The main grid will use the data_table.yaml and the first nest will use the data_table_nest_01.yaml file.
15 changes: 12 additions & 3 deletions data_override/include/data_override.inc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
! modules. These modules are not intended to be used directly - they should be
! used through the data_override_mod API. See data_override.F90 for details.

use platform_mod, only: r4_kind, r8_kind, FMS_PATH_LEN
use platform_mod, only: r4_kind, r8_kind, FMS_PATH_LEN, FMS_FILE_LEN
use yaml_parser_mod
use constants_mod, only: DEG_TO_RAD
use mpp_mod, only : mpp_error, FATAL, WARNING, NOTE, stdout, stdlog, mpp_max
Expand All @@ -45,7 +45,7 @@ use mpp_domains_mod, only : domainUG, mpp_pass_SG_to_UG, mpp_get_UG_SG_domain, N
use time_manager_mod, only: time_type, OPERATOR(>), OPERATOR(<)
use fms2_io_mod, only : FmsNetcdfFile_t, open_file, close_file, &
read_data, fms2_io_init, variable_exists, &
get_mosaic_tile_file, file_exists
get_mosaic_tile_file, file_exists, get_instance_filename
use get_grid_version_mod, only: get_grid_version_1, get_grid_version_2
use fms_string_utils_mod, only: string

Expand Down Expand Up @@ -591,9 +591,18 @@ subroutine read_table_yaml(data_table)
integer :: nentries, mentries
integer :: i
character(len=50) :: buffer
character(len=FMS_FILE_LEN) :: filename !< Name of the expected data_table.yaml
integer :: file_id
file_id = open_and_parse_file("data_table.yaml")
! If doing and ensemble or nest run add the filename appendix (ens_XX or nest_XX) to the filename
call get_instance_filename("data_table.yaml", filename)
if (index(trim(filename), "ens_") .ne. 0) then
if (file_exists(filename) .and. file_exists("data_table.yaml")) &
call mpp_error(FATAL, "Both data_table.yaml and "//trim(filename)//" exists, pick one!")
endif
file_id = open_and_parse_file(trim(filename))
if (file_id==999) then
nentries = 0
else
Expand Down
4 changes: 4 additions & 0 deletions diag_manager/diag_yaml_format.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The purpose of this document is to explain the diag_table yaml format.
- [2.6 Sub_region Section](diag_yaml_format.md#26-sub_region-section)
- [3. More examples](diag_yaml_format.md#3-more-examples)
- [4. Schema](diag_yaml_format.md#4-schema)
- [5. Ensemble and Nest Support](diag_yaml_format.md#5-ensemble-and-nest-support)

### 1. Converting from legacy ascii diag_table format

Expand Down Expand Up @@ -349,3 +350,6 @@ diag_files:
A formal specification of the file format, in the form of a JSON schema, can be
found in the [gfdl_msd_schemas](https://github.com/NOAA-GFDL/gfdl_msd_schemas)
repository on Github.

### 5. Ensemble and Nest Support
When using nests, it may be desired for a nest to have a different file frequency or number of variables from the parent grid. This may allow users to save disk space and reduce simulations time. In order to supports, FMS allows each nest to have a different diag_table.yaml from the parent grid. For example, if running with 1 test FMS will use diag_table.yaml for the parent grid and diag_table.nest_01.yaml for the first nest Similary, each ensemble member can have its own diag_table (diag_table_ens_XX.yaml, where XX is the ensemble number). However, for the ensemble case if both the diag_table.yaml and the diag_table_ens_* files are present, the code will crash as only 1 option is allowed.
10 changes: 9 additions & 1 deletion diag_manager/fms_diag_yaml.F90
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module fms_diag_yaml_mod
use fms_mod, only: lowercase
use fms_diag_time_utils_mod, only: set_time_type
use time_manager_mod, only: time_type, date_to_string
use fms2_io_mod, only: file_exists, get_instance_filename

implicit none

Expand Down Expand Up @@ -384,10 +385,17 @@ subroutine diag_yaml_object_init(diag_subset_output)
!! outputing data at every frequency)
character(len=:), allocatable :: filename!< Diag file name (for error messages)
logical :: is_instantaneous !< .True. if the file is instantaneous (i.e no averaging)
character(len=FMS_FILE_LEN) :: yamlfilename !< Name of the expected diag_table.yaml

if (diag_yaml_module_initialized) return

diag_yaml_id = open_and_parse_file("diag_table.yaml")
! If doing and ensemble or nest run add the filename appendix (ens_XX or nest_XX) to the filename
call get_instance_filename("diag_table.yaml", yamlfilename)
if (index(trim(yamlfilename), "ens_") .ne. 0) then
if (file_exists(yamlfilename) .and. file_exists("diag_table.yaml")) &
call mpp_error(FATAL, "Both diag_table.yaml and "//trim(yamlfilename)//" exists, pick one!")
endif
diag_yaml_id = open_and_parse_file(trim(yamlfilename))

call diag_get_value_from_key(diag_yaml_id, 0, "title", diag_yaml%diag_title)
call get_value_from_key(diag_yaml_id, 0, "base_date", diag_yaml%diag_basedate)
Expand Down
15 changes: 12 additions & 3 deletions field_manager/field_manager.F90
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ module field_manager_mod
use fms_mod, only : lowercase, &
write_version_number, &
check_nml_error
use fms2_io_mod, only: file_exists
use fms2_io_mod, only: file_exists, get_instance_filename
use platform_mod, only: r4_kind, r8_kind, FMS_PATH_LEN, FMS_FILE_LEN
#ifdef use_yaml
use fm_yaml_mod
Expand Down Expand Up @@ -606,18 +606,27 @@ subroutine read_field_table_yaml(nfields, table_name)
logical :: fm_success !< logical for whether fm_change_list was a success
logical :: subparams !< logical whether subparams exist in this iteration

character(len=FMS_FILE_LEN) :: filename !< Name of the expected field_table.yaml

if (.not.PRESENT(table_name)) then
tbl_name = 'field_table.yaml'
else
tbl_name = trim(table_name)
endif
if (.not. file_exists(trim(tbl_name))) then

call get_instance_filename(tbl_name, filename)
if (index(trim(filename), "ens_") .ne. 0) then
if (file_exists(filename) .and. file_exists(tbl_name)) &
call mpp_error(FATAL, "Both "//trim(tbl_name)//" and "//trim(filename)//" exists, pick one!")
endif

if (.not. file_exists(trim(filename))) then
if(present(nfields)) nfields = 0
return
endif

! Construct my_table object
call build_fmTable(my_table, trim(tbl_name))
call build_fmTable(my_table, trim(filename))

do h=1,size(my_table%types)
do i=1,size(my_table%types(h)%models)
Expand Down
10 changes: 8 additions & 2 deletions fms2_io/fms_io_utils.F90
Original file line number Diff line number Diff line change
Expand Up @@ -824,8 +824,14 @@ subroutine get_instance_filename(name_in,name_out)
if ( i .ne. 0 ) then
name_out = name_in(1:i-1)//'.'//trim(filename_appendix)//name_in(i:length)
else
!< If .nc is not in the name, add the appendix at the end of the file
name_out = name_in(1:length) //'.'//trim(filename_appendix)
i = index(trim(name_in), ".yaml", back=.true.)
if (i .ne. 0) then
!< If .yaml is in the filename add the appendix before it
name_out = name_in(1:i-1)//'.'//trim(filename_appendix)//name_in(i:length)
else
!< If .nc and .yaml are not in the name, add the appendix at the end of the file
name_out = name_in(1:length) //'.'//trim(filename_appendix)
endif
end if
end if

Expand Down
161 changes: 117 additions & 44 deletions horiz_interp/horiz_interp_type.F90
Original file line number Diff line number Diff line change
Expand Up @@ -164,58 +164,131 @@ subroutine horiz_interp_type_eq(horiz_interp_out, horiz_interp_in)
call mpp_error(FATAL,'horiz_interp_type_eq: horiz_interp_type variable on right hand side is unassigned')
endif

horiz_interp_out%ilon = horiz_interp_in%ilon
horiz_interp_out%jlat = horiz_interp_in%jlat
horiz_interp_out%i_lon = horiz_interp_in%i_lon
horiz_interp_out%j_lat = horiz_interp_in%j_lat
horiz_interp_out%found_neighbors = horiz_interp_in%found_neighbors
horiz_interp_out%num_found = horiz_interp_in%num_found
horiz_interp_out%nlon_src = horiz_interp_in%nlon_src
horiz_interp_out%nlat_src = horiz_interp_in%nlat_src
horiz_interp_out%nlon_dst = horiz_interp_in%nlon_dst
horiz_interp_out%nlat_dst = horiz_interp_in%nlat_dst
if( allocated(horiz_interp_in%ilon )) &
horiz_interp_out%ilon = horiz_interp_in%ilon

if( allocated(horiz_interp_in%jlat )) &
horiz_interp_out%jlat = horiz_interp_in%jlat

if( allocated(horiz_interp_in%i_lon )) &
horiz_interp_out%i_lon = horiz_interp_in%i_lon

if( allocated(horiz_interp_in%j_lat )) &
horiz_interp_out%j_lat = horiz_interp_in%j_lat

if( allocated(horiz_interp_in%found_neighbors )) &
horiz_interp_out%found_neighbors = horiz_interp_in%found_neighbors

if( allocated(horiz_interp_in%num_found )) &
horiz_interp_out%num_found = horiz_interp_in%num_found

if( allocated(horiz_interp_in%i_src )) &
horiz_interp_out%i_src = horiz_interp_in%i_src

if( allocated(horiz_interp_in%j_src )) &
horiz_interp_out%j_src = horiz_interp_in%j_src

if( allocated(horiz_interp_in%i_dst )) &
horiz_interp_out%i_dst = horiz_interp_in%i_dst

if( allocated(horiz_interp_in%j_dst )) &
horiz_interp_out%j_dst = horiz_interp_in%j_dst

horiz_interp_out%nlon_src = horiz_interp_in%nlon_src
horiz_interp_out%nlat_src = horiz_interp_in%nlat_src
horiz_interp_out%nlon_dst = horiz_interp_in%nlon_dst
horiz_interp_out%nlat_dst = horiz_interp_in%nlat_dst
horiz_interp_out%interp_method = horiz_interp_in%interp_method
horiz_interp_out%I_am_initialized = .true.
horiz_interp_out%i_src = horiz_interp_in%i_src
horiz_interp_out%j_src = horiz_interp_in%j_src
horiz_interp_out%i_dst = horiz_interp_in%i_dst
horiz_interp_out%j_dst = horiz_interp_in%j_dst

if(horiz_interp_in%horizInterpReals8_type%is_allocated) then
horiz_interp_out%horizInterpReals8_type%faci = horiz_interp_in%horizInterpReals8_type%faci
horiz_interp_out%horizInterpReals8_type%facj = horiz_interp_in%horizInterpReals8_type%facj
horiz_interp_out%horizInterpReals8_type%area_src = horiz_interp_in%horizInterpReals8_type%area_src
horiz_interp_out%horizInterpReals8_type%area_dst = horiz_interp_in%horizInterpReals8_type%area_dst
horiz_interp_out%horizInterpReals8_type%wti = horiz_interp_in%horizInterpReals8_type%wti
horiz_interp_out%horizInterpReals8_type%wtj = horiz_interp_in%horizInterpReals8_type%wtj
horiz_interp_out%horizInterpReals8_type%src_dist = horiz_interp_in%horizInterpReals8_type%src_dist
horiz_interp_out%horizInterpReals8_type%rat_x = horiz_interp_in%horizInterpReals8_type%rat_x
horiz_interp_out%horizInterpReals8_type%rat_y = horiz_interp_in%horizInterpReals8_type%rat_y
horiz_interp_out%horizInterpReals8_type%lon_in = horiz_interp_in%horizInterpReals8_type%lon_in
horiz_interp_out%horizInterpReals8_type%lat_in = horiz_interp_in%horizInterpReals8_type%lat_in
horiz_interp_out%horizInterpReals8_type%area_frac_dst = horiz_interp_in%horizInterpReals8_type%area_frac_dst
horiz_interp_out%horizInterpReals8_type%max_src_dist = horiz_interp_in%horizInterpReals8_type%max_src_dist
horiz_interp_out%horizInterpReals8_type%is_allocated = .true.

if( allocated(horiz_interp_in%horizInterpReals8_type%faci)) &
horiz_interp_out%horizInterpReals8_type%faci = horiz_interp_in%horizInterpReals8_type%faci

if( allocated( horiz_interp_in%horizInterpReals8_type%facj)) &
horiz_interp_out%horizInterpReals8_type%facj = horiz_interp_in%horizInterpReals8_type%facj

if( allocated( horiz_interp_in%horizInterpReals8_type%area_src)) &
horiz_interp_out%horizInterpReals8_type%area_src = horiz_interp_in%horizInterpReals8_type%area_src

if( allocated( horiz_interp_in%horizInterpReals8_type%area_dst)) &
horiz_interp_out%horizInterpReals8_type%area_dst = horiz_interp_in%horizInterpReals8_type%area_dst

if( allocated( horiz_interp_in%horizInterpReals8_type%wti)) &
horiz_interp_out%horizInterpReals8_type%wti = horiz_interp_in%horizInterpReals8_type%wti

if( allocated( horiz_interp_in%horizInterpReals8_type%wtj)) &
horiz_interp_out%horizInterpReals8_type%wtj = horiz_interp_in%horizInterpReals8_type%wtj

if( allocated( horiz_interp_in%horizInterpReals8_type%src_dist)) &
horiz_interp_out%horizInterpReals8_type%src_dist = horiz_interp_in%horizInterpReals8_type%src_dist

if( allocated( horiz_interp_in%horizInterpReals8_type%rat_x)) &
horiz_interp_out%horizInterpReals8_type%rat_x = horiz_interp_in%horizInterpReals8_type%rat_x

if( allocated( horiz_interp_in%horizInterpReals8_type%rat_y)) &
horiz_interp_out%horizInterpReals8_type%rat_y = horiz_interp_in%horizInterpReals8_type%rat_y

if( allocated( horiz_interp_in%horizInterpReals8_type%lon_in)) &
horiz_interp_out%horizInterpReals8_type%lon_in = horiz_interp_in%horizInterpReals8_type%lon_in

if( allocated( horiz_interp_in%horizInterpReals8_type%lat_in)) &
horiz_interp_out%horizInterpReals8_type%lat_in = horiz_interp_in%horizInterpReals8_type%lat_in

if( allocated( horiz_interp_in%horizInterpReals8_type%area_frac_dst)) &
horiz_interp_out%horizInterpReals8_type%area_frac_dst = horiz_interp_in%horizInterpReals8_type%area_frac_dst

horiz_interp_out%horizInterpReals8_type%max_src_dist = horiz_interp_in%horizInterpReals8_type%max_src_dist

horiz_interp_out%horizInterpReals8_type%is_allocated = .true.
! this was left out previous to mixed mode
horiz_interp_out%horizInterpReals8_type%mask_in = horiz_interp_in%horizInterpReals8_type%mask_in
if( allocated(horiz_interp_in%horizInterpReals8_type%mask_in)) &
horiz_interp_out%horizInterpReals8_type%mask_in = horiz_interp_in%horizInterpReals8_type%mask_in

else if (horiz_interp_in%horizInterpReals4_type%is_allocated) then
horiz_interp_out%horizInterpReals4_type%faci = horiz_interp_in%horizInterpReals4_type%faci
horiz_interp_out%horizInterpReals4_type%facj = horiz_interp_in%horizInterpReals4_type%facj
horiz_interp_out%horizInterpReals4_type%area_src = horiz_interp_in%horizInterpReals4_type%area_src
horiz_interp_out%horizInterpReals4_type%area_dst = horiz_interp_in%horizInterpReals4_type%area_dst
horiz_interp_out%horizInterpReals4_type%wti = horiz_interp_in%horizInterpReals4_type%wti
horiz_interp_out%horizInterpReals4_type%wtj = horiz_interp_in%horizInterpReals4_type%wtj
horiz_interp_out%horizInterpReals4_type%src_dist = horiz_interp_in%horizInterpReals4_type%src_dist
horiz_interp_out%horizInterpReals4_type%rat_x = horiz_interp_in%horizInterpReals4_type%rat_x
horiz_interp_out%horizInterpReals4_type%rat_y = horiz_interp_in%horizInterpReals4_type%rat_y
horiz_interp_out%horizInterpReals4_type%lon_in = horiz_interp_in%horizInterpReals4_type%lon_in
horiz_interp_out%horizInterpReals4_type%lat_in = horiz_interp_in%horizInterpReals4_type%lat_in
horiz_interp_out%horizInterpReals4_type%area_frac_dst = horiz_interp_in%horizInterpReals4_type%area_frac_dst
horiz_interp_out%horizInterpReals4_type%max_src_dist = horiz_interp_in%horizInterpReals4_type%max_src_dist
horiz_interp_out%horizInterpReals4_type%is_allocated = .true.
if( allocated(horiz_interp_in%horizInterpReals4_type%faci)) &
horiz_interp_out%horizInterpReals4_type%faci = horiz_interp_in%horizInterpReals4_type%faci

if( allocated( horiz_interp_in%horizInterpReals4_type%facj)) &
horiz_interp_out%horizInterpReals4_type%facj = horiz_interp_in%horizInterpReals4_type%facj

if( allocated( horiz_interp_in%horizInterpReals4_type%area_src)) &
horiz_interp_out%horizInterpReals4_type%area_src = horiz_interp_in%horizInterpReals4_type%area_src

if( allocated( horiz_interp_in%horizInterpReals4_type%area_dst)) &
horiz_interp_out%horizInterpReals4_type%area_dst = horiz_interp_in%horizInterpReals4_type%area_dst

if( allocated( horiz_interp_in%horizInterpReals4_type%wti)) &
horiz_interp_out%horizInterpReals4_type%wti = horiz_interp_in%horizInterpReals4_type%wti

if( allocated( horiz_interp_in%horizInterpReals4_type%wtj)) &
horiz_interp_out%horizInterpReals4_type%wtj = horiz_interp_in%horizInterpReals4_type%wtj

if( allocated( horiz_interp_in%horizInterpReals4_type%src_dist)) &
horiz_interp_out%horizInterpReals4_type%src_dist = horiz_interp_in%horizInterpReals4_type%src_dist

if( allocated( horiz_interp_in%horizInterpReals4_type%rat_x)) &
horiz_interp_out%horizInterpReals4_type%rat_x = horiz_interp_in%horizInterpReals4_type%rat_x

if( allocated( horiz_interp_in%horizInterpReals4_type%rat_y)) &
horiz_interp_out%horizInterpReals4_type%rat_y = horiz_interp_in%horizInterpReals4_type%rat_y

if( allocated( horiz_interp_in%horizInterpReals4_type%lon_in)) &
horiz_interp_out%horizInterpReals4_type%lon_in = horiz_interp_in%horizInterpReals4_type%lon_in

if( allocated( horiz_interp_in%horizInterpReals4_type%lat_in)) &
horiz_interp_out%horizInterpReals4_type%lat_in = horiz_interp_in%horizInterpReals4_type%lat_in

if( allocated( horiz_interp_in%horizInterpReals4_type%area_frac_dst)) &
horiz_interp_out%horizInterpReals4_type%area_frac_dst = horiz_interp_in%horizInterpReals4_type%area_frac_dst

horiz_interp_out%horizInterpReals4_type%max_src_dist = horiz_interp_in%horizInterpReals4_type%max_src_dist

horiz_interp_out%horizInterpReals4_type%is_allocated = .true.
! this was left out previous to mixed mode
horiz_interp_out%horizInterpReals4_type%mask_in = horiz_interp_in%horizInterpReals4_type%mask_in
if( allocated(horiz_interp_in%horizInterpReals4_type%mask_in)) &
horiz_interp_out%horizInterpReals4_type%mask_in = horiz_interp_in%horizInterpReals4_type%mask_in

else
call mpp_error(FATAL, "horiz_interp_type_eq: cannot assign unallocated real values from horiz_interp_in")
Expand Down
1 change: 1 addition & 0 deletions libFMS.F90
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@ module fms
fms_string_utils_sort_this => fms_sort_this, &
fms_string_utils_find_my_string => fms_find_my_string, &
fms_string_utils_find_unique => fms_find_unique, &
fms_string_utils_f2c_string => fms_f2c_string, &
fms_string_utils_c2f_string => fms_c2f_string, &
fms_string_utils_cstring2cpointer => fms_cstring2cpointer, &
fms_string_utils_copy => string_copy
Expand Down
Loading

0 comments on commit 5fc7917

Please sign in to comment.