- ! Make an interface check_bounds_are_exact for the subroutines check_bounds_are_exact_static
- ! and
- ! check_bounds_are_exact_dynamic.
- !
- ! INTERFACE check_bounds_are_exact
- ! MODULE PROCEDURE check_bounds_are_exact_static
- ! MODULE PROCEDURE check_bounds_are_exact_dynamic
- ! END INTERFACE check_bounds_are_exact
- !
- !
-
USE diag_data_mod, ONLY: output_fields, input_fields, files, do_diag_field_log, diag_log_unit,&
& VERY_LARGE_AXIS_LENGTH, time_zero, VERY_LARGE_FILE_FREQ, END_OF_RUN, EVERY_TIME,&
& DIAG_SECONDS, DIAG_MINUTES, DIAG_HOURS, DIAG_DAYS, DIAG_MONTHS, DIAG_YEARS, get_base_time,&
diff --git a/diag_manager/fms_diag_axis_object.F90 b/diag_manager/fms_diag_axis_object.F90
index e13ae7551a..527a14abbf 100644
--- a/diag_manager/fms_diag_axis_object.F90
+++ b/diag_manager/fms_diag_axis_object.F90
@@ -18,8 +18,11 @@
!> @defgroup fms_diag_axis_object_mod fms_diag_axis_object_mod
!> @ingroup diag_manager
-!! @brief fms_diag_axis_object_mod stores the diag axis object, a diag domain
-!! object, and a subaxis object.
+!! @brief Modern object-oriented implementation of diagnostic axis management for the FMS diagnostic manager.
+!!
+!! This module provides type-based classes for managing diagnostic axes in FMS.
+!! It serves as the modern, object-oriented replacement for @ref diag_axis_mod, utilizing Fortran 2003+ class structures
+!! and polymorphism.
!> @file
!> @brief File for @ref diag_axis_object_mod
@@ -56,10 +59,16 @@ module fms_diag_axis_object_mod
!> @}
- !> @brief Type to hold the domain info for an axis
- !! This type was created to avoid having to send in "Domain", "Domain2", "DomainUG" as arguments into subroutines
- !! and instead only 1 class(diagDomain_t) argument can be send
- !> @ingroup diag_axis_object_mod
+ !> @brief Base type for domain information associated with an axis.
+ !!
+ !! This type was created to avoid requiring separate "Domain", "Domain2", and "DomainUG" arguments
+ !! in subroutines. Instead, a single polymorphic class(diagDomain_t) argument can be used, which is
+ !! polymorphically extended to handle different domain types.
+ !!
+ !! This base provides a unified interface for domain operations regardless of whether
+ !! the axis uses 1D domain decomposition, 2D domain decomposition, or an unstructured grid domain.
+ !!
+ !! @ingroup diag_axis_object_mod
type diagDomain_t
contains
procedure :: set => set_axis_domain
@@ -67,25 +76,51 @@ module fms_diag_axis_object_mod
procedure :: get_ntiles
end type diagDomain_t
- !> @brief Type to hold the 1d domain
+ !> @brief Type to hold 1D domain decomposition information for an axis.
+ !!
+ !! This type extends the diagDomain_t base type and is used when an axis is
+ !! associated with a 1D domain (typically a vertical or time axis).
+ !! The 1D domain provides information about how the axis is partitioned across
+ !! MPI processes along a single dimension.
type, extends(diagDomain_t) :: diagDomain1d_t
- type(domain1d) :: Domain !< 1d Domain of the axis
+ type(domain1d) :: Domain !< 1D domain object describing axis decomposition
end type
- !> @brief Type to hold the 2d domain
+ !> @brief Type to hold 2D domain decomposition information for an axis.
+ !!
+ !! This type extends the diagDomain_t base type and is used when an axis is
+ !! part of a 2D domain (typically for horizontal "X" or "Y" axes in atmospheric models).
+ !! The 2D domain provides information about how the axis is partitioned across
+ !! MPI processes in both the X and Y dimensions.
type, extends(diagDomain_t) :: diagDomain2d_t
- type(domain2d) :: Domain2 !< 2d Domain of an "X" or "Y" axis
+ type(domain2d) :: Domain2 !< 2D domain object describing X-Y decomposition of an axis
end type
- !> @brief Type to hold the unstructured domain
+ !> @brief Type to hold unstructured grid domain information for an axis.
+ !!
+ !! This type extends the diagDomain_t base type and is used when an axis is
+ !! associated with an unstructured (irregular) grid domain. Unstructured grids are commonly
+ !! used in models with non-uniform spatial decomposition, such as icosahedral grids.
+ !! The unstructured domain provides information about cell connectivity and partitioning.
type, extends(diagDomain_t) :: diagDomainUg_t
- type(domainUG) :: DomainUG !< Domain of "U" axis
+ type(domainUG) :: DomainUG !< Unstructured domain object for irregular mesh decomposition
end type
- !> @brief Type to hold the diagnostic axis description.
- !> @ingroup diag_axis_object_mod
+ !> @brief Base type for diagnostic axis objects.
+ !!
+ !! This is the base type for all diagnostic axis implementations. It provides
+ !! a unified interface for axis operations and is polymorphically extended by more specific
+ !! axis types:
+ !! - @ref fmsDiagFullAxis_type - A complete axis with coordinates
+ !! - @ref fmsDiagSubAxis_type - A subset of a full axis for regional output
+ !! - @ref fmsDiagDiurnalAxis_type - A subset of a full axis for diurnal averaging
+ !!
+ !! The base type defines a common interface for querying axis properties and writing
+ !! axis data to output files via the FMS2_IO library.
+ !!
+ !! @ingroup diag_axis_object_mod
TYPE :: fmsDiagAxis_type
- INTEGER , private :: axis_id !< ID of the axis
+ INTEGER , private :: axis_id !< Unique identifier for this axis
contains
procedure :: get_parent_axis_id
@@ -100,24 +135,37 @@ module fms_diag_axis_object_mod
procedure :: get_edges_id
END TYPE fmsDiagAxis_type
- !> @brief Type to hold the diag_axis (either subaxis or a full axis)
- !> @ingroup diag_axis_object_mod
+ !> @brief Container type to hold a polymorphic diagnostic axis object.
+ !!
+ !! This container type allows storage of any type derived from fmsDiagAxis_type
+ !! (e.g., fmsDiagFullAxis_type, fmsDiagSubAxis_type, or fmsDiagDiurnalAxis_type)
+ !! in an array. This polymorphic storage approach enables dynamic type checking
+ !! and method dispatch at runtime.
+ !!
+ !! @ingroup diag_axis_object_mod
type :: fmsDiagAxisContainer_type
- class(fmsDiagAxis_type), allocatable :: axis
+ class(fmsDiagAxis_type), allocatable :: axis !< Polymorphic axis object (Full, Sub, or Diurnal)
end type
- !> @brief Type to hold the subaxis
- !> @ingroup diag_axis_object_mod
+ !> @brief Type representing a subregion or subset of a parent diagnostic axis.
+ !!
+ !! A subaxis is created when a user requests output for a limited region of a full axis.
+ !! This can occur for regional output (e.g., a subregion of the full domain) or for
+ !! dimension compression (e.g., selected depth levels in a vertical axis).
+ !!
+ !! Each subaxis maintains references to its parent axis and stores the index ranges
+ !! that define the subregion on the current PE, as well as globally.
+ !! Subaxes may also store Z-axis bounds for identifying equivalent subaxes across files.
+ !!
+ !! @ingroup diag_axis_object_mod
TYPE, extends(fmsDiagAxis_type) :: fmsDiagSubAxis_type
- CHARACTER(len=:), ALLOCATABLE , private :: subaxis_name !< Name of the subaxis
- INTEGER , private :: starting_index !< Starting index of the subaxis relative to the
- !! parent axis
- INTEGER , private :: ending_index !< Ending index of the subaxis relative to the
- !! parent axis
- INTEGER , private :: parent_axis_id !< Id of the parent_axis
- INTEGER , private :: compute_idx(2) !< Starting and ending index of the compute domain
- INTEGER, allocatable, private :: global_idx(:) !< Starting and ending index of the global domain
- real(kind=r4_kind), allocatable, private :: zbounds(:) !< Bounds of the Z axis
+ CHARACTER(len=:), ALLOCATABLE , private :: subaxis_name !< Name of the subaxis (typically parent_name_subNN)
+ INTEGER , private :: starting_index !< First index of subregion relative to parent axis
+ INTEGER , private :: ending_index !< Last index of subregion relative to parent axis
+ INTEGER , private :: parent_axis_id !< Axis ID of the parent full axis
+ INTEGER , private :: compute_idx(2) !< [start, end] indices of compute domain on this PE
+ INTEGER, allocatable, private :: global_idx(:) !< [start, end] indices in global domain
+ real(kind=r4_kind), allocatable, private :: zbounds(:) !< Bounds [min, max] if this is a Z-axis subregion
contains
procedure :: fill_subaxis
procedure :: axis_length
@@ -127,54 +175,71 @@ module fms_diag_axis_object_mod
procedure :: is_same_zbounds
END TYPE fmsDiagSubAxis_type
- !> @brief Type to hold the diurnal axis
- !> @ingroup diag_axis_object_mod
+ !> @brief Type for diurnal (daily cycle) sampling axes.
+ !!
+ !! This specialized axis type represents time-of-day sampling for diurnal averaging.
+ !! Diurnal axes divide a 24-hour period into regular intervals for accumulating
+ !! time-averaged or instantaneous samples at each time-of-day bin. This is commonly
+ !! used in climate modeling to analyze the diurnal cycle of variables.
+ !!
+ !! Each diurnal axis has an associated edges axis that defines the bin boundaries,
+ !! and stores the actual diurnal coordinate data for output to NetCDF files.
+ !!
+ !! @ingroup diag_axis_object_mod
TYPE, extends(fmsDiagAxis_type) :: fmsDiagDiurnalAxis_type
- INTEGER , private :: ndiurnal_samples !< The number of diurnal samples
- CHARACTER(len=:), ALLOCATABLE, private :: axis_name !< The diurnal axis name
- CHARACTER(len=:), ALLOCATABLE, private :: long_name !< The longname of the diurnal axis
- CHARACTER(len=:), ALLOCATABLE, private :: units !< The units
- INTEGER , private :: edges_id !< The id of the diurnal edges
- CHARACTER(len=:), ALLOCATABLE, private :: edges_name !< The name of the edges axis
- CLASS(*), ALLOCATABLE, private :: diurnal_data(:) !< The diurnal data
+ INTEGER , private :: ndiurnal_samples !< Number of time-of-day samples in 24-hour period
+ CHARACTER(len=:), ALLOCATABLE, private :: axis_name !< Name of the diurnal axis (e.g., time_of_day_06)
+ CHARACTER(len=:), ALLOCATABLE, private :: long_name !< Long name for the diurnal axis
+ CHARACTER(len=:), ALLOCATABLE, private :: units !< Units string (hours since reference time)
+ INTEGER , private :: edges_id !< Axis ID of the diurnal edges axis
+ CHARACTER(len=:), ALLOCATABLE, private :: edges_name !< Name of the edges axis (e.g., time_of_day_edges_06)
+ CLASS(*), ALLOCATABLE, private :: diurnal_data(:) !< Coordinate values: times within 24-hour day
contains
procedure :: get_diurnal_axis_samples
procedure :: write_diurnal_metadata
END TYPE fmsDiagDiurnalAxis_type
- !> @brief Type to hold the diagnostic axis description.
- !> @ingroup diag_axis_object_mod
+ !> @brief Type representing a complete diagnostic axis with coordinates and metadata.
+ !!
+ !! This is the primary type for storing axis information. It contains the coordinate
+ !! values, metadata (name, units, long name), domain information, and optional attributes.
+ !! A full axis can have subaxes defined from it for regional output or selective output.
+ !!
+ !! The axis stores data in either single or double precision floating point format,
+ !! as determined by the input coordinate array. Domain information is stored polymorphically
+ !! to support 1D, 2D, and unstructured grid domains.
+ !!
+ !! @ingroup diag_axis_object_mod
TYPE, extends(fmsDiagAxis_type) :: fmsDiagFullAxis_type
- CHARACTER(len=:), ALLOCATABLE, private :: axis_name !< Name of the axis
- CHARACTER(len=:), ALLOCATABLE, private :: units !< Units of the axis
- CHARACTER(len=:), ALLOCATABLE, private :: long_name !< Long_name attribute of the axis
- CHARACTER(len=1) , private :: cart_name !< Cartesian name "X", "Y", "Z", "T", "U", "N"
- CLASS(*), ALLOCATABLE, private :: axis_data(:) !< Data of the axis
- CHARACTER(len=:), ALLOCATABLE, private :: type_of_data !< The type of the axis_data ("float" or "double")
- !< TO DO this can be a dlinked to avoid having limits
- integer, ALLOCATABLE, private :: subaxis(:) !< Array of subaxis
- integer , private :: nsubaxis !< Number of subaxis
- class(diagDomain_t),ALLOCATABLE, private :: axis_domain !< Domain
- INTEGER , private :: type_of_domain !< The type of domain ("NO_DOMAIN", "TWO_D_DOMAIN",
- !! or "UG_DOMAIN")
- INTEGER , private :: length !< Global axis length
- INTEGER , private :: direction !< Direction of the axis 0, 1, -1
- INTEGER, ALLOCATABLE, private :: edges_id !< Axis ID for the edges axis
- !! This axis will be written to the file
- CHARACTER(len=:), ALLOCATABLE, private :: edges_name !< Name for the previously defined "edges axis"
- !! This will be written as an attribute
- CHARACTER(len=:), ALLOCATABLE, private :: aux !< Auxiliary name, can only be