cable_output_config_mod Module

Reads and validates the output configuration file.

The configuration is a YAML file with two central ideas: streams, each linked to one output file and one write frequency, and output variables, each directed to one stream. Groups and modules are shorthand for sets of variables. This module turns the file into a flat list of stream settings and a flat list of variable uses (one per variable, aggregation and stream), with all groups and modules expanded and all {...} templates filled in.

Everything here is a function of its arguments. Problems are collected rather than stopping at the first, so that one run reports every mistake in the file.



Variables

Type Visibility Attributes Name Initial
character(len=32), private, parameter :: top_level_keys(4) = [character(len=32)::"streams", "variables", "groups", "modules"]

Keys that may appear in the file, in a stream, and in a variable, group or module entry. These are named constants rather than array constructors written in the calls, because gfortran can pass the wrong string length for such actual arguments.

character(len=32), private, parameter :: stream_keys(7) = [character(len=32)::"file_name", "frequency", "netcdf_name", "shuffle", "compression_level", "separate_file_per_variable", "metadata"]
character(len=32), private, parameter :: specification_keys(6) = [character(len=32)::"name", "stream", "aggregation", "reduction", "netcdf_name", "metadata"]
character(len=32), private, parameter :: stream_substitution_names(3) = [character(len=32)::"frequency", "start_date", "end_date"]

Substitutions available in the metadata of a stream.

character(len=16), private, parameter :: reserved_attributes(4) = [character(len=16)::"standard_name", "long_name", "units", "cell_methods"]

Attributes that are always written from the variable definition and so cannot be set in the file.


Functions

public function cable_output_config_load(file_name, definitions, start_date, end_date) result(config)

Read the configuration file file_name. Aborts, listing every problem, if it is invalid.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: file_name
type(cable_output_variable_definition_t), intent(in) :: definitions(:)
character(len=*), intent(in) :: start_date

First simulation date, YYYY-MM-DD.

character(len=*), intent(in) :: end_date

Last simulation date, YYYY-MM-DD.

Return Value type(cable_output_config_t)

public function cable_output_config_parse(text, definitions, start_date, end_date) result(config)

As cable_output_config_load, for a configuration held in a string.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: text
type(cable_output_variable_definition_t), intent(in) :: definitions(:)
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date

Return Value type(cable_output_config_t)

public function cable_output_config_build(root, definitions, start_date, end_date, problems) result(config)

Build the configuration from a parsed YAML document.

Read more…

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: root
type(cable_output_variable_definition_t), intent(in) :: definitions(:)
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date
character(len=:), intent(out), allocatable :: problems

Return Value type(cable_output_config_t)

public function cable_output_substitute(template, names, values, error) result(text)

Replace each {name} in template with the matching entry of values.

Read more…

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: template
character(len=*), intent(in) :: names(:)
character(len=*), intent(in) :: values(:)
character(len=:), intent(out), allocatable :: error

Return Value character(len=:), allocatable

private pure function find_name(names, name) result(name_index)

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: names(:)
character(len=*), intent(in) :: name

Return Value integer

private function require_scalar(node, key, context, problems) result(present_and_valid)

True if node has key holding a single value; otherwise records a problem.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: node
character(len=*), intent(in) :: key
character(len=*), intent(in) :: context
character(len=:), intent(inout), allocatable :: problems

Return Value logical

private pure function find_stream(streams, stream_id) result(stream_index)

Arguments

Type IntentOptional Attributes Name
type(cable_output_stream_config_t), intent(in) :: streams(:)
integer, intent(in) :: stream_id

Return Value integer

private pure function is_member(definition, section, name) result(member)

Whether definition is selected by the entry name of the given section.

Arguments

Type IntentOptional Attributes Name
type(cable_output_variable_definition_t), intent(in) :: definition
character(len=*), intent(in) :: section
character(len=*), intent(in) :: name

Return Value logical

private pure function any_definition_matches(definitions, section, name) result(found)

Arguments

Type IntentOptional Attributes Name
type(cable_output_variable_definition_t), intent(in) :: definitions(:)
character(len=*), intent(in) :: section
character(len=*), intent(in) :: name

Return Value logical

private pure function singular(section) result(word)

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: section

Return Value character(len=:), allocatable

private function stream_id_text(stream_id) result(text)

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: stream_id

Return Value character(len=:), allocatable

private function stream_label(stream) result(text)

Arguments

Type IntentOptional Attributes Name
type(cable_output_stream_config_t), intent(in) :: stream

Return Value character(len=:), allocatable


Subroutines

private subroutine read_streams(streams_node, start_date, end_date, streams, problems)

Read every stream. A subroutine because gfortran drops updates made to the deferred-length string problems inside a function called on the right of an assignment.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: streams_node
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date
type(cable_output_stream_config_t), intent(out), allocatable :: streams(:)
character(len=:), intent(inout), allocatable :: problems

private subroutine read_stream(stream_node, start_date, end_date, stream, problems)

A subroutine rather than a function so that problems, a deferred-length string, is reliably updated for the caller by gfortran.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: stream_node
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date
type(cable_output_stream_config_t), intent(inout) :: stream
character(len=:), intent(inout), allocatable :: problems

private subroutine check_streams_unique(streams, problems)

Stream numbers must be unique, and no two streams may write to the same file.

Arguments

Type IntentOptional Attributes Name
type(cable_output_stream_config_t), intent(in) :: streams(:)
character(len=:), intent(inout), allocatable :: problems

private subroutine add_specifications(root, section, streams, definitions, start_date, end_date, uses, use_count, problems)

Expand every entry of the variables, groups or modules section into variable uses.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: root
character(len=*), intent(in) :: section
type(cable_output_stream_config_t), intent(in) :: streams(:)
type(cable_output_variable_definition_t), intent(in) :: definitions(:)
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date
type(cable_output_variable_config_t), intent(inout), allocatable :: uses(:)
integer, intent(inout) :: use_count
character(len=:), intent(inout), allocatable :: problems

private subroutine add_specification(entry, section, entry_index, streams, definitions, start_date, end_date, uses, use_count, problems)

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: entry
character(len=*), intent(in) :: section
integer, intent(in) :: entry_index
type(cable_output_stream_config_t), intent(in) :: streams(:)
type(cable_output_variable_definition_t), intent(in) :: definitions(:)
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date
type(cable_output_variable_config_t), intent(inout), allocatable :: uses(:)
integer, intent(inout) :: use_count
character(len=:), intent(inout), allocatable :: problems

private subroutine add_use(entry, context, stream, definition, aggregation, reduction, netcdf_name_template, start_date, end_date, uses, use_count, problems)

Check one variable against one stream and append it to uses.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: entry
character(len=*), intent(in) :: context
type(cable_output_stream_config_t), intent(in) :: stream
type(cable_output_variable_definition_t), intent(in) :: definition
character(len=*), intent(in) :: aggregation
character(len=*), intent(in) :: reduction
character(len=*), intent(in) :: netcdf_name_template
character(len=*), intent(in) :: start_date
character(len=*), intent(in) :: end_date
type(cable_output_variable_config_t), intent(inout), allocatable :: uses(:)
integer, intent(inout) :: use_count
character(len=:), intent(inout), allocatable :: problems

private subroutine check_use_against_definition(label, definition, stream, reduction, problems)

Reductions and frequencies must make sense for the variable being written.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: label
type(cable_output_variable_definition_t), intent(in) :: definition
type(cable_output_stream_config_t), intent(in) :: stream
character(len=*), intent(in) :: reduction
character(len=:), intent(inout), allocatable :: problems

private subroutine check_rules(config, problems)

Rule 1: no two variables in a stream share a NetCDF name. Rule 2: no two variables in a stream are numerically identical.

Arguments

Type IntentOptional Attributes Name
type(cable_output_config_t), intent(in) :: config
character(len=:), intent(inout), allocatable :: problems

private subroutine read_metadata(node, context, names, values, attributes, problems)

The metadata mapping of node as attributes, with templates filled in.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: node
character(len=*), intent(in) :: context
character(len=*), intent(in) :: names(:)
character(len=*), intent(in) :: values(:)
type(cable_output_attribute_t), intent(out), allocatable :: attributes(:)
character(len=:), intent(inout), allocatable :: problems

private subroutine check_keys(node, allowed, context, problems)

Report every key of the mapping node that is not in allowed.

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: node
character(len=*), intent(in) :: allowed(:)
character(len=*), intent(in) :: context
character(len=:), intent(inout), allocatable :: problems

private subroutine read_integer(node, key, context, value, problems)

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: node
character(len=*), intent(in) :: key
character(len=*), intent(in) :: context
integer, intent(out) :: value
character(len=:), intent(inout), allocatable :: problems

private subroutine read_logical(node, key, context, value, problems)

Arguments

Type IntentOptional Attributes Name
type(cable_yaml_node_t), intent(in) :: node
character(len=*), intent(in) :: key
character(len=*), intent(in) :: context
logical, intent(out) :: value
character(len=:), intent(inout), allocatable :: problems