FMS  2026.03
Flexible Modeling System
diag_data.F90
1 !***********************************************************************
2 !* Apache License 2.0
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* Licensed under the Apache License, Version 2.0 (the "License");
7 !* you may not use this file except in compliance with the License.
8 !* You may obtain a copy of the License at
9 !*
10 !* http://www.apache.org/licenses/LICENSE-2.0
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 !* PARTICULAR PURPOSE. See the License for the specific language
16 !* governing permissions and limitations under the License.
17 !***********************************************************************
18 !> @defgroup diag_data_mod diag_data_mod
19 !> @ingroup diag_manager
20 !! @brief Type descriptions and global variables for the diag_manager modules.
21 !! @author Seth Underwood <seth.underwood@noaa.gov>
22 !!
23 !! Notation:
24 !! <DL>
25 !! <DT>input field</DT>
26 !! <DD>The data structure describing the field as
27 !! registered by the model code.</DD>
28 !!
29 !! <DT>output field</DT>
30 !! <DD>The data structure describing the actual
31 !! diagnostic output with requested frequency and
32 !! other options.</DD>
33 !! </DL>
34 !!
35 !! Input fields, output fields, and output files are gathered in arrays called
36 !! "input_fields", "output_fields", and "files", respectively. Indices in these
37 !! arrays are used as pointers to create associations between various data
38 !! structures.
39 !!
40 !! Each input field associated with one or several output fields via array of
41 !! indices output_fields; each output field points to the single "parent" input
42 !! field with the input_field index, and to the output file with the output_file
43 !! index.
44 
45 !> @addtogroup diag_data_mod
46 !> @{
47 MODULE diag_data_mod
48 use platform_mod
49 
50  USE time_manager_mod, ONLY: get_calendar_type, no_calendar, set_date, set_time, month_name, time_type
51  USE constants_mod, ONLY: seconds_per_hour, seconds_per_minute
52  USE mpp_domains_mod, ONLY: domain1d, domain2d, domainug
53  USE fms_mod, ONLY: write_version_number
54  USE fms_diag_bbox_mod, ONLY: fmsdiagibounds_type
55  use mpp_mod, ONLY: mpp_error, fatal, warning, mpp_pe, mpp_root_pe, stdlog
56 
57  ! NF90_FILL_REAL has value of 9.9692099683868690e+36.
58  USE netcdf, ONLY: nf_fill_real => nf90_fill_real
59  use fms2_io_mod
60 
61  IMPLICIT NONE
62 
63  PUBLIC
64 
65  ! Specify storage limits for fixed size tables used for pointers, etc.
66  integer, parameter :: diag_null = -999 !< Integer represening NULL in the diag_object
67  character(len=1), parameter :: diag_null_string = " "
68  integer, parameter :: diag_not_found = -1
69  integer, parameter :: diag_not_registered = 0
70  integer, parameter :: diag_registered_id = 10
71  !> Supported averaging intervals
72  integer, parameter :: monthly = 30
73  integer, parameter :: daily = 24
74  integer, parameter :: diurnal = 2
75  integer, parameter :: yearly = 12
76  integer, parameter :: no_diag_averaging = 0
77  integer, parameter :: instantaneous = 0
78  integer, parameter :: three_hourly = 3
79  integer, parameter :: six_hourly = 6
80  !integer, parameter :: seasonally = 180
81  !> Supported type/kind of the variable
82  !integer, parameter :: r16=16
83  integer, parameter :: r8 = 8
84  integer, parameter :: r4 = 4
85  integer, parameter :: i8 = -8
86  integer, parameter :: i4 = -4
87  integer, parameter :: string = 19 !< s is the 19th letter of the alphabet
88  integer, parameter :: null_type_int = -999
89  INTEGER, PARAMETER :: max_fields_per_file = 300 !< Maximum number of fields per file.
90  INTEGER, PARAMETER :: diag_other = 0
91  INTEGER, PARAMETER :: diag_ocean = 1
92  INTEGER, PARAMETER :: diag_all = 2
93  INTEGER, PARAMETER :: very_large_file_freq = 100000
94  INTEGER, PARAMETER :: very_large_axis_length = 10000
95  INTEGER, PARAMETER :: every_time = 0
96  INTEGER, PARAMETER :: end_of_run = -1
97  INTEGER, PARAMETER :: diag_seconds = 1, diag_minutes = 2, diag_hours = 3
98  INTEGER, PARAMETER :: diag_days = 4, diag_months = 5, diag_years = 6
99  INTEGER, PARAMETER :: max_subaxes = 10
100  INTEGER, PARAMETER :: no_domain = 1 !< Use the FmsNetcdfFile_t fileobj
101  INTEGER, PARAMETER :: two_d_domain = 2 !< Use the FmsNetcdfDomainFile_t fileobj
102  INTEGER, PARAMETER :: ug_domain = 3 !< Use the FmsNetcdfUnstructuredDomainFile_t fileobj
103  INTEGER, PARAMETER :: sub_regional = 4 !< This is a file with a sub_region use the FmsNetcdfFile_t fileobj
104  integer, parameter :: max_dimensions = 5 !< Max number of dimensions allowed (including unlimited dimension)
105  INTEGER, PARAMETER :: direction_up = 1 !< The axis points up if positive
106  INTEGER, PARAMETER :: direction_down = -1 !< The axis points down if positive
107  INTEGER, PARAMETER :: glo_reg_val = -999 !< Value used in the region specification of the diag_table
108  !! to indicate to use the full axis instead of a sub-axis
109  INTEGER, PARAMETER :: glo_reg_val_alt = -1 !< Alternate value used in the region specification of the
110  !! diag_table to indicate to use the full axis instead of a sub-axis
111  REAL(r8_kind), PARAMETER :: cmor_missing_value = 1.0e20 !< CMOR standard missing value
112  INTEGER, PARAMETER :: diag_field_not_found = -1 !< Return value for a diag_field that isn't found in the diag_table
113  INTEGER, PARAMETER :: latlon_gridtype = 1
114  INTEGER, PARAMETER :: index_gridtype = 2
115  INTEGER, PARAMETER :: null_gridtype = diag_null
116  INTEGER, PARAMETER :: time_none = 0 !< There is no reduction method
117  INTEGER, PARAMETER :: time_min = 1 !< The reduction method is min value
118  INTEGER, PARAMETER :: time_max = 2 !< The reduction method is max value
119  INTEGER, PARAMETER :: time_sum = 3 !< The reduction method is sum of values
120  INTEGER, PARAMETER :: time_average= 4 !< The reduction method is average of values
121  INTEGER, PARAMETER :: time_rms = 5 !< The reudction method is root mean square of values
122  INTEGER, PARAMETER :: time_diurnal = 6 !< The reduction method is diurnal
123  INTEGER, PARAMETER :: time_power = 7 !< The reduction method is average with exponents
124  CHARACTER(len=7) :: avg_name = 'average' !< Name of the average fields
125  CHARACTER(len=8) :: no_units = "NO UNITS"!< String indicating that the variable has no units
126  INTEGER, PARAMETER :: begin_time = 1 !< Use the begining of the time average bounds
127  INTEGER, PARAMETER :: middle_time = 2 !< Use the middle of the time average bounds
128  INTEGER, PARAMETER :: end_time = 3 !< Use the end of the time average bounds
129  INTEGER, PARAMETER :: max_str_len = 255 !< Max length for a string
130  INTEGER, PARAMETER :: is_x_axis = 1 !< integer indicating that it is a x axis
131  INTEGER, PARAMETER :: is_y_axis = 2 !< integer indicating that it is a y axis
132  !> @}
133 
134  !> @brief Contains the coordinates of the local domain to output.
135  !> @ingroup diag_data_mod
137  REAL, DIMENSION(3) :: start !< start coordinates (lat,lon,depth) of local domain to output
138  REAL, DIMENSION(3) :: end !< end coordinates (lat,lon,depth) of local domain to output
139  INTEGER, DIMENSION(3) :: l_start_indx !< start indices at each LOCAL PE
140  INTEGER, DIMENSION(3) :: l_end_indx !< end indices at each LOCAL PE
141  INTEGER, DIMENSION(3) :: subaxes !< id returned from diag_subaxes_init of 3 subaxes
142  END TYPE diag_grid
143 
144  !> @brief Diagnostic field type
145  !> @ingroup diag_data_mod
147  TYPE(domain2d) :: Domain
148  TYPE(domainUG) :: DomainU
149  REAL :: miss, miss_pack
150  LOGICAL :: miss_present, miss_pack_present
151  INTEGER :: tile_count
152  character(len=128) :: fieldname !< Fieldname
153  END TYPE diag_fieldtype
154 
155  !> @brief Attribute type for diagnostic fields
156  !> @ingroup diag_data_mod
157  TYPE :: diag_atttype
158  INTEGER :: type !< Data type of attribute values (NF_INT, NF_FLOAT, NF_CHAR)
159  INTEGER :: len !< Number of values in attribute, or if a character string then
160  !! length of the string.
161  CHARACTER(len=128) :: name !< Name of the attribute
162  CHARACTER(len=1280) :: catt !< Character string to hold character value of attribute
163  REAL, allocatable, DIMENSION(:) :: fatt !< REAL array to hold value of REAL attributes
164  INTEGER, allocatable, DIMENSION(:) :: iatt !< INTEGER array to hold value of INTEGER attributes
165  END TYPE diag_atttype
166 
167  !!TODO: coord_type deserves a better name, like coord_interval_type or coord_bbox_type.
168  !! additionally, consider using a 2D array.
169  !> @brief Define the region for field output
170  !> @ingroup diag_data_mod
172  REAL :: xbegin
173  REAL :: xend
174  REAL :: ybegin
175  REAL :: yend
176  REAL :: zbegin
177  REAL :: zend
178  END TYPE coord_type
179 
180  !> @brief Type to define the diagnostic files that will be written as defined by the diagnostic table.
181  !> @ingroup diag_data_mod
183  CHARACTER(len=FMS_FILE_LEN) :: name !< Name of the output file.
184  CHARACTER(len=128) :: long_name
185  INTEGER, DIMENSION(max_fields_per_file) :: fields
186  INTEGER :: num_fields
187  INTEGER :: output_freq
188  INTEGER :: output_units
189  INTEGER :: format
190  INTEGER :: time_units
191  INTEGER :: file_unit
192  INTEGER :: bytes_written
193  INTEGER :: time_axis_id, time_bounds_id
194  INTEGER :: new_file_freq !< frequency to create new file
195  INTEGER :: new_file_freq_units !< time units of new_file_freq (days, hours, years, ...)
196  INTEGER :: duration
197  INTEGER :: duration_units
198  INTEGER :: tile_count
199  LOGICAL :: local !< .TRUE. if fields are output in a region instead of global.
200  TYPE(time_type) :: last_flush
201  TYPE(time_type) :: next_open !< Time to open a new file.
202  TYPE(time_type) :: start_time !< Time file opened.
203  TYPE(time_type) :: close_time !< Time file closed. File does not allow data after close time
204  TYPE(diag_fieldtype):: f_avg_start, f_avg_end, f_avg_nitems, f_bounds
205  TYPE(diag_atttype), allocatable, dimension(:) :: attributes !< Array to hold user definable attributes
206  INTEGER :: num_attributes !< Number of defined attibutes
207 !----------
208 !ug support
209  logical(L4_KIND) :: use_domainug = .false.
210  logical(I4_KIND) :: use_domain2d = .false.
211 !----------
212 !Check if time axis was already registered
213  logical, allocatable :: is_time_axis_registered
214 !Support for fms2_io time
215  real :: rtime_current
216  integer :: time_index
217  CHARACTER(len=10) :: filename_time_bounds
218  END TYPE file_type
219 
220  !> @brief Type to hold the input field description
221  !> @ingroup diag_data_mod
223  CHARACTER(len=128) :: module_name, field_name, long_name, units
224  CHARACTER(len=256) :: standard_name
225  CHARACTER(len=64) :: interp_method
226  INTEGER, DIMENSION(3) :: axes
227  INTEGER :: num_axes
228  LOGICAL :: missing_value_present, range_present
229  REAL :: missing_value
230  REAL, DIMENSION(2) :: range
231  INTEGER, allocatable, dimension(:) :: output_fields
232  INTEGER :: num_output_fields
233  INTEGER, DIMENSION(3) :: size
234  LOGICAL :: static, register, mask_variant, local
235  INTEGER :: numthreads
236  INTEGER :: active_omp_level !< The current level of OpenMP nesting
237  INTEGER :: tile_count
238  TYPE(coord_type) :: local_coord
239  TYPE(time_type) :: time
240  LOGICAL :: issued_mask_ignore_warning !< Indicates if the mask_ignore_warning
241  !! has been issued for this input
242  !! field. Once .TRUE. the warning message
243  !! is suppressed on all subsequent
244  !! send_data calls.
245  END TYPE input_field_type
246 
247  !> @brief Type to hold the output field description.
248  !> @ingroup diag_data_mod
250  INTEGER :: input_field !< index of the corresponding input field in the table
251  INTEGER :: output_file !< index of the output file in the table
252  CHARACTER(len=128) :: output_name
253  LOGICAL :: time_average !< true if the output field is averaged over time interval
254  LOGICAL :: time_rms !< true if the output field is the rms. If true, then time_average is also
255  LOGICAL :: static
256  LOGICAL :: time_max !< true if the output field is maximum over time interval
257  LOGICAL :: time_min !< true if the output field is minimum over time interval
258  LOGICAL :: time_sum !< true if the output field is summed over time interval
259  LOGICAL :: time_ops !< true if any of time_min, time_max, time_rms or time_average is true
260  INTEGER :: pack
261  INTEGER :: pow_value !< Power value to use for mean_pow(n) calculations
262  CHARACTER(len=50) :: time_method !< time method field from the input file
263  ! coordinates of the buffer and counter are (x, y, z, time-of-day)
264  REAL, allocatable, DIMENSION(:,:,:,:) :: buffer !< coordinates of the buffer and counter are (x,
265  !! y, z, time-of-day)
266  REAL, allocatable, DIMENSION(:,:,:,:) :: counter !< coordinates of the buffer and counter are (x,y,z,time-of-day)
267  ! the following two counters are used in time-averaging for some
268  ! combination of the field options. Their size is the length of the
269  ! diurnal axis; the counters must be tracked separately for each of
270  ! the diurnal interval, because the number of time slices accumulated
271  ! in each can be different, depending on time step and the number of
272  ! diurnal samples.
273  REAL, allocatable, DIMENSION(:) :: count_0d !< the following two counters are used in time-averaging for some
274  !! combination of the field options. Their size is the length of the
275  !! diurnal axis; the counters must be tracked separately for each of
276  !! the diurnal interval, because the number of time slices accumulated
277  !! in each can be different, depending on time step and the number of
278  !! diurnal samples.
279  INTEGER, allocatable, dimension(:) :: num_elements !< the following two counters are used in time-averaging
280  !! for some combination of the field options. Their size is the length of the
281  !! diurnal axis; the counters must be tracked separately for each of
282  !! the diurnal interval, because the number of time slices accumulated
283  !! in each can be different, depending on time step and the number of
284  !! diurnal samples.
285 
286  TYPE(time_type) :: last_output, next_output, next_next_output
287  TYPE(diag_fieldtype) :: f_type
288  INTEGER, DIMENSION(4) :: axes
289  INTEGER :: num_axes, total_elements, region_elements
290  INTEGER :: n_diurnal_samples !< number of diurnal sample intervals, 1 or more
291  TYPE(diag_grid) :: output_grid
292  LOGICAL :: local_output, need_compute, phys_window, written_once
293  LOGICAL :: reduced_k_range
294  TYPE(fmsdiagibounds_type) :: buff_bounds
295  TYPE(time_type) :: time_of_prev_field_data
296  TYPE(diag_atttype), allocatable, dimension(:) :: attributes
297  INTEGER :: num_attributes
298 !----------
299 !ug support
300  logical :: reduced_k_unstruct = .false.
301 !----------
302  END TYPE output_field_type
303 
304  !> @brief Type to hold the diagnostic axis description.
305  !> @ingroup diag_data_mod
307  CHARACTER(len=128) :: name
308  CHARACTER(len=256) :: units, long_name
309  CHARACTER(len=1) :: cart_name
310  REAL, DIMENSION(:), POINTER :: diag_type_data
311  INTEGER, DIMENSION(MAX_SUBAXES) :: start
312  INTEGER, DIMENSION(MAX_SUBAXES) :: end
313  CHARACTER(len=128), DIMENSION(MAX_SUBAXES) :: subaxis_name
314  INTEGER :: length, direction, edges, set, shift
315  TYPE(domain1d) :: Domain
316  TYPE(domain2d) :: Domain2
317  TYPE(domain2d), dimension(MAX_SUBAXES) :: subaxis_domain2
318  type(domainUG) :: DomainUG
319  CHARACTER(len=128) :: aux, req
320  INTEGER :: tile_count
321  TYPE(diag_atttype), allocatable, dimension(:) :: attributes !< Array to hold user definable attributes
322  INTEGER :: num_attributes !< Number of defined attibutes
323  INTEGER :: domain_position !< The position in the doman (NORTH or EAST or CENTER)
324  END TYPE diag_axis_type
325 
326  !> @ingroup diag_data_mod
328  CHARACTER(len=128) :: grid_type='regular'
329  CHARACTER(len=128) :: tile_name='N/A'
330  END TYPE diag_global_att_type
331 
332  !> @brief Type to hold the attributes of the field/axis/file
333  !> @ingroup diag_data_mod
335  class(*), allocatable :: att_value(:) !< Value of the attribute
336  character(len=:), allocatable :: att_name !< Name of the attribute
337  contains
338  procedure :: add => fms_add_attribute
339  procedure :: write_metadata
340  end type fmsdiagattribute_type
341 ! Include variable "version" to be written to log file.
342 #include<file_version.h>
343 
344  !> @addtogroup diag_data_mod
345  !> @{
346 
347  ! <!-- Other public variables -->
348  INTEGER :: num_files = 0 !< Number of output files currenly in use by the diag_manager.
349  INTEGER :: num_input_fields = 0 !< Number of input fields in use.
350  INTEGER :: num_output_fields = 0 !< Number of output fields in use.
351  INTEGER :: null_axis_id
352 
353  ! <!-- Namelist variables -->
354  LOGICAL :: append_pelist_name = .false.
355  LOGICAL :: mix_snapshot_average_fields =.false.
356  INTEGER :: max_files = 31 !< Maximum number of output files allowed. Increase via diag_manager_nml.
357  INTEGER :: max_output_fields = 300 !< Maximum number of output fields. Increase via diag_manager_nml.
358  INTEGER :: max_input_fields = 600 !< Maximum number of input fields. Increase via diag_manager_nml.
359  INTEGER :: max_out_per_in_field = 150 !< Maximum number of output_fields per input_field. Increase
360  !! via diag_manager_nml.
361  INTEGER :: max_axes = 60 !< Maximum number of independent axes.
362  LOGICAL :: do_diag_field_log = .false.
363  LOGICAL :: write_bytes_in_file = .false.
364  LOGICAL :: debug_diag_manager = .false.
365  LOGICAL :: flush_nc_files = .false. !< Control if diag_manager will force a
366  !! flush of the netCDF file on each write.
367  !! Note: changing this to .TRUE. can greatly
368  !! reduce the performance of the model, as the
369  !! model must wait until the flush to disk has
370  !! completed.
371  INTEGER :: max_num_axis_sets = 25
372  LOGICAL :: use_cmor = .false. !< Indicates if we should overwrite the MISSING_VALUE to use the CMOR missing value.
373  LOGICAL :: issue_oor_warnings = .true. !< Issue warnings if the output field has values outside the given
374  !! range for a variable.
375  LOGICAL :: oor_warnings_fatal = .false. !< Cause a fatal error if the output field has a value outside the
376  !! given range for a variable.
377  LOGICAL :: region_out_use_alt_value = .true. !< Will determine which value to use when checking a regional
378  !! output if the region is the full axis or a sub-axis.
379  !! The values are defined as <TT>GLO_REG_VAL</TT>
380  !! (-999) and <TT>GLO_REG_VAL_ALT</TT> (-1) in <TT>diag_data_mod</TT>.
381 
382  INTEGER :: max_field_attributes = 4 !< Maximum number of user definable attributes per field. Liptak:
383  !! Changed from 2 to 4 20170718
384  INTEGER :: max_file_attributes = 2 !< Maximum number of user definable global attributes per file.
385  INTEGER :: max_axis_attributes = 4 !< Maximum number of user definable attributes per axis.
386  LOGICAL :: prepend_date = .true. !< Should the history file have the start date prepended to the file name.
387  !! <TT>.TRUE.</TT> is only supported if the diag_manager_init
388  !! routine is called with the optional time_init parameter.
389  CHARACTER(len=16) :: wildcard_filename_prefix = '_' !< String inserted immediately before the first
390  !! substituted time field when using a wildcard (%)
391  !! file name.
392  CHARACTER(len=16) :: wildcard_filename_separator = '_' !< String inserted between each subsequent
393  !! substituted time field when using a wildcard (%)
394  !! file name.
395  LOGICAL :: use_refactored_send = .false. !< Namelist flag to use refactored send_data math funcitons.
396  LOGICAL :: use_modern_diag = .false. !< Namelist flag to use the modernized diag_manager code
397  LOGICAL :: use_clock_average = .false. !< .TRUE. if the averaging of variable is done based on the clock
398  !! For example, if doing daily averages and your start the simulation in
399  !! day1_hour3, it will do the average between day1_hour3 to day2_hour 0
400  !! the default behavior will do the average between day1 hour3 to day2 hour3
401  ! <!-- netCDF variable -->
402 
403  REAL :: fill_value = nf_fill_real !< Fill value used. Value will be <TT>NF90_FILL_REAL</TT> if using the
404  !! netCDF module, otherwise will be 9.9692099683868690e+36.
405  ! from file /usr/local/include/netcdf.inc
406 
407  !! @note `pack_size` and `pack_size_str` are set in diag_manager_init depending on how FMS was compiled
408  !! if FMS was compiled with default reals as 64bit, it will be set to 1 and "double",
409  !! if FMS was compiled with default reals as 32bit, it will set to 2 and "float"
410  !! The time variables will written in the precision defined by `pack_size_str`
411  !! This is to reproduce previous diag manager behavior.
412  !TODO This may not be mixed precision friendly
413  INTEGER :: pack_size = 1 !< 1 for double and 2 for float
414  CHARACTER(len=6) :: pack_size_str="double" !< Pack size as a string to be used in fms2_io register call
415  !! set to "double" or "float"
416 
417  ! <!-- REAL public variables -->
418  REAL(r8_kind) :: empty = 0.0
419  REAL(r8_kind) :: max_value, min_value
420 
421  ! <!-- Global data for all files -->
422  TYPE(time_type) :: diag_init_time !< Time diag_manager_init called. If init_time not included in
423  !! diag_manager_init call, then same as base_time
424  TYPE(time_type), private :: base_time !< The base_time read from diag_table
425  logical, private :: base_time_set !< Flag indicating that the base_time is set
426  !! This is to prevent users from calling set_base_time multiple times
427  INTEGER, private :: base_year, base_month, base_day, base_hour, base_minute, base_second
428  CHARACTER(len = 256):: global_descriptor
429 
430  ! <!-- ALLOCATABLE variables -->
431  TYPE(file_type), SAVE, ALLOCATABLE :: files(:)
432  TYPE(input_field_type), ALLOCATABLE :: input_fields(:)
433  TYPE(output_field_type), ALLOCATABLE :: output_fields(:)
434  type(fmsnetcdfunstructureddomainfile_t),allocatable, target :: fileobju(:)
435  type(fmsnetcdfdomainfile_t),allocatable, target :: fileobj(:)
436  type(fmsnetcdffile_t),allocatable, target :: fileobjnd(:)
437  character(len=2),allocatable :: fnum_for_domain(:) !< If this file number in the array is for the "unstructured"
438  !! or "2d" domain
439 
440  ! <!-- Even More Variables -->
441  TYPE(time_type) :: time_zero
442  LOGICAL :: first_send_data_call = .true.
443  LOGICAL :: module_is_initialized = .false. !< Indicate if diag_manager has been initialized
444  INTEGER :: diag_log_unit
445  CHARACTER(len=10), DIMENSION(6) :: time_unit_list = (/'seconds ', 'minutes ',&
446  & 'hours ', 'days ', 'months ', 'years '/)
447  character(len=32) :: pelist_name
448  INTEGER :: oor_warning = warning
449 
450 CONTAINS
451 
452  !> @brief Initialize and write the version number of this file to the log file.
453  SUBROUTINE diag_data_init()
454  IF (module_is_initialized) THEN
455  RETURN
456  END IF
457 
458  ! Write version number out to log file
459  call write_version_number("DIAG_DATA_MOD", version)
460  module_is_initialized = .true.
461  base_time_set = .false.
462 
463  END SUBROUTINE diag_data_init
464 
465  !> @brief Set the module variable base_time
466  subroutine set_base_time(base_time_int)
467  integer :: base_time_int(6) !< base_time as an array [year month day hour min sec]
468 
469  CHARACTER(len=9) :: amonth !< Month name
470  INTEGER :: stdlog_unit !< Fortran file unit number for the stdlog file.
471 
472  if (.not. module_is_initialized) call mpp_error(fatal, "set_base_time: diag_data is not initialized")
473  if (base_time_set) call mpp_error(fatal, "set_base_time: the base_time is already set!")
474 
475  base_year = base_time_int(1)
476  base_month = base_time_int(2)
477  base_day = base_time_int(3)
478  base_hour = base_time_int(4)
479  base_minute = base_time_int(5)
480  base_second = base_time_int(6)
481 
482  ! Set up the time type for base time
483  IF ( get_calendar_type() /= no_calendar ) THEN
484  IF ( base_year==0 .OR. base_month==0 .OR. base_day==0 ) THEN
485  call mpp_error(fatal, 'diag_data_mod::set_base_time'//&
486  & 'The base_year/month/day can not equal zero')
487  END IF
488  base_time = set_date(base_year, base_month, base_day, base_hour, base_minute, base_second)
489  amonth = month_name(base_month)
490  ELSE
491  ! No calendar - ignore year and month
492  base_time = set_time(nint(base_hour*seconds_per_hour)+nint(base_minute*seconds_per_minute)+base_second, &
493  & base_day)
494  base_year = 0
495  base_month = 0
496  amonth = 'day'
497  END IF
498 
499  ! get the stdlog unit number
500  stdlog_unit = stdlog()
501 
502  IF ( mpp_pe() == mpp_root_pe() ) THEN
503  WRITE (stdlog_unit,'("base date used = ",I4,1X,A,2I3,2(":",I2.2)," gmt")') base_year, trim(amonth), base_day, &
504  & base_hour, base_minute, base_second
505  END IF
506 
507  base_time_set = .true.
508 
509  end subroutine set_base_time
510 
511  !> @brief gets the module variable base_time
512  !> @return the base_time
513  function get_base_time() &
514  result(res)
515  TYPE(time_type) :: res
516  res = base_time
517  end function get_base_time
518 
519  !> @brief gets the module variable base_year
520  !> @return the base_year
521  function get_base_year() &
522  result(res)
523  integer :: res
524  res = base_year
525  end function get_base_year
526 
527  !> @brief gets the module variable base_month
528  !> @return the base_month
529  function get_base_month() &
530  result(res)
531  integer :: res
532  res = base_month
533  end function get_base_month
534 
535  !> @brief gets the module variable base_day
536  !> @return the base_day
537  function get_base_day() &
538  result(res)
539  integer :: res
540  res = base_day
541  end function get_base_day
542 
543  !> @brief gets the module variable base_hour
544  !> @return the base_hour
545  function get_base_hour() &
546  result(res)
547  integer :: res
548  res = base_hour
549  end function get_base_hour
550 
551  !> @brief gets the module variable base_minute
552  !> @return the base_minute
553  function get_base_minute() &
554  result(res)
555  integer :: res
556  res = base_minute
557  end function get_base_minute
558 
559  !> @brief gets the module variable base_second
560  !> @return the base_second
561  function get_base_second() &
562  result(res)
563  integer :: res
564  res = base_second
565  end function get_base_second
566 
567  !> @brief Adds an attribute to the attribute type
568  subroutine fms_add_attribute(this, att_name, att_value)
569  class(fmsdiagattribute_type), intent(inout) :: this !< Diag attribute type
570  character(len=*), intent(in) :: att_name !< Name of the attribute
571  class(*), intent(in) :: att_value(:) !< The attribute value to add
572 
573  integer :: natt !< the size of att_value
574 
575 #ifndef __NVCOMPILER
576  natt = size(att_value)
577  this%att_name = att_name
578  select type (att_value)
579  type is (integer(kind=i4_kind))
580  allocate(integer(kind=i4_kind) :: this%att_value(natt))
581  this%att_value = att_value
582  type is (integer(kind=i8_kind))
583  allocate(integer(kind=i8_kind) :: this%att_value(natt))
584  this%att_value = att_value
585  type is (real(kind=r4_kind))
586  allocate(real(kind=r4_kind) :: this%att_value(natt))
587  this%att_value = att_value
588  type is (real(kind=r8_kind))
589  allocate(real(kind=r8_kind) :: this%att_value(natt))
590  this%att_value = att_value
591  type is (character(len=*))
592  allocate(character(len=len(att_value)) :: this%att_value(natt))
593  select type(aval => this%att_value)
594  type is (character(len=*))
595  aval = att_value
596  end select
597  end select
598 #endif
599  end subroutine fms_add_attribute
600 
601  !> @brief gets the type of a variable
602  !> @return the type of the variable (r4,r8,i4,i8,string)
603  function get_var_type(var) &
604  result(var_type)
605  class(*), intent(in) :: var !< Variable to get the type for
606  integer :: var_type !< The variable's type
607 
608  select type(var)
609  type is (real(r4_kind))
610  var_type = r4
611  type is (real(r8_kind))
612  var_type = r8
613  type is (integer(i4_kind))
614  var_type = i4
615  type is (integer(i8_kind))
616  var_type = i8
617  type is (character(len=*))
618  var_type = string
619  class default
620  call mpp_error(fatal, "get_var_type:: The variable does not have a supported type. &
621  &The supported types are r4, r8, i4, i8 and string.")
622  end select
623  end function get_var_type
624 
625  !> @brief Writes out the attributes from an fmsDiagAttribute_type
626  subroutine write_metadata(this, fileobj, var_name, cell_methods)
627  class(fmsdiagattribute_type), intent(inout) :: this !< Diag attribute type
628  class(fmsnetcdffile_t), INTENT(INOUT) :: fileobj !< Fms2_io fileobj to write to
629  character(len=*), intent(in) :: var_name !< The name of the variable to write to
630  character(len=*), optional, intent(inout) :: cell_methods !< The cell methods attribute
631 
632  select type (att_value =>this%att_value)
633  type is (character(len=*))
634  !< If the attribute is cell methods append to the current cell_methods attribute value
635  !! This will be writen once all of the cell_methods attributes are gathered ...
636  if (present(cell_methods)) then
637  if (trim(this%att_name) .eq. "cell_methods") then
638  cell_methods = trim(cell_methods)//" "//trim(att_value(1))
639  return
640  endif
641  endif
642 
643  call register_variable_attribute(fileobj, var_name, this%att_name, trim(att_value(1)), &
644  str_len=len_trim(att_value(1)))
645  type is (real(kind=r8_kind))
646  call register_variable_attribute(fileobj, var_name, this%att_name, real(att_value, kind=r8_kind))
647  type is (real(kind=r4_kind))
648  call register_variable_attribute(fileobj, var_name, this%att_name, real(att_value, kind=r4_kind))
649  type is (integer(kind=i4_kind))
650  call register_variable_attribute(fileobj, var_name, this%att_name, int(att_value, kind=i4_kind))
651  type is (integer(kind=i8_kind))
652  call register_variable_attribute(fileobj, var_name, this%att_name, int(att_value, kind=i8_kind))
653  end select
654 
655  end subroutine write_metadata
656 END MODULE diag_data_mod
657 !> @}
658 ! close documentation grouping
character(len=8) no_units
String indicating that the variable has no units.
Definition: diag_data.F90:125
integer max_output_fields
Maximum number of output fields. Increase via diag_manager_nml.
Definition: diag_data.F90:357
real fill_value
Fill value used. Value will be NF90_FILL_REAL if using the netCDF module, otherwise will be 9....
Definition: diag_data.F90:403
integer, parameter direction_down
The axis points down if positive.
Definition: diag_data.F90:106
integer, parameter sub_regional
This is a file with a sub_region use the FmsNetcdfFile_t fileobj.
Definition: diag_data.F90:103
integer pack_size
1 for double and 2 for float
Definition: diag_data.F90:413
integer, parameter max_str_len
Max length for a string.
Definition: diag_data.F90:129
integer function get_base_minute()
gets the module variable base_minute
Definition: diag_data.F90:555
integer function get_base_year()
gets the module variable base_year
Definition: diag_data.F90:523
integer num_input_fields
Number of input fields in use.
Definition: diag_data.F90:349
integer function get_base_hour()
gets the module variable base_hour
Definition: diag_data.F90:547
logical use_cmor
Indicates if we should overwrite the MISSING_VALUE to use the CMOR missing value.
Definition: diag_data.F90:372
logical flush_nc_files
Control if diag_manager will force a flush of the netCDF file on each write. Note: changing this to ....
Definition: diag_data.F90:365
integer function get_var_type(var)
gets the type of a variable
Definition: diag_data.F90:605
integer, parameter no_domain
Use the FmsNetcdfFile_t fileobj.
Definition: diag_data.F90:100
character(len=7) avg_name
Name of the average fields.
Definition: diag_data.F90:124
integer, parameter end_time
Use the end of the time average bounds.
Definition: diag_data.F90:128
integer, parameter glo_reg_val_alt
Alternate value used in the region specification of the diag_table to indicate to use the full axis i...
Definition: diag_data.F90:109
integer max_axis_attributes
Maximum number of user definable attributes per axis.
Definition: diag_data.F90:385
integer, parameter monthly
Supported averaging intervals.
Definition: diag_data.F90:72
character(len=6) pack_size_str
Pack size as a string to be used in fms2_io register call set to "double" or "float".
Definition: diag_data.F90:414
logical use_modern_diag
Namelist flag to use the modernized diag_manager code.
Definition: diag_data.F90:396
type(time_type) function get_base_time()
gets the module variable base_time
Definition: diag_data.F90:515
integer max_axes
Maximum number of independent axes.
Definition: diag_data.F90:361
type(time_type), private base_time
The base_time read from diag_table.
Definition: diag_data.F90:424
integer, parameter is_x_axis
integer indicating that it is a x axis
Definition: diag_data.F90:130
integer, parameter diag_field_not_found
Return value for a diag_field that isn't found in the diag_table.
Definition: diag_data.F90:112
integer max_out_per_in_field
Maximum number of output_fields per input_field. Increase via diag_manager_nml.
Definition: diag_data.F90:359
integer max_input_fields
Maximum number of input fields. Increase via diag_manager_nml.
Definition: diag_data.F90:358
logical use_clock_average
.TRUE. if the averaging of variable is done based on the clock For example, if doing daily averages a...
Definition: diag_data.F90:397
integer, parameter string
s is the 19th letter of the alphabet
Definition: diag_data.F90:87
logical issue_oor_warnings
Issue warnings if the output field has values outside the given range for a variable.
Definition: diag_data.F90:373
logical region_out_use_alt_value
Will determine which value to use when checking a regional output if the region is the full axis or a...
Definition: diag_data.F90:377
integer num_output_fields
Number of output fields in use.
Definition: diag_data.F90:350
character(len=16) wildcard_filename_separator
String inserted between each subsequent substituted time field when using a wildcard (%) file name.
Definition: diag_data.F90:392
integer, parameter is_y_axis
integer indicating that it is a y axis
Definition: diag_data.F90:131
integer function get_base_day()
gets the module variable base_day
Definition: diag_data.F90:539
type(time_type) diag_init_time
Time diag_manager_init called. If init_time not included in diag_manager_init call,...
Definition: diag_data.F90:422
integer, parameter time_min
The reduction method is min value.
Definition: diag_data.F90:117
integer, parameter ug_domain
Use the FmsNetcdfUnstructuredDomainFile_t fileobj.
Definition: diag_data.F90:102
subroutine set_base_time(base_time_int)
Set the module variable base_time.
Definition: diag_data.F90:467
integer, parameter time_diurnal
The reduction method is diurnal.
Definition: diag_data.F90:122
integer, parameter time_power
The reduction method is average with exponents.
Definition: diag_data.F90:123
integer max_files
Maximum number of output files allowed. Increase via diag_manager_nml.
Definition: diag_data.F90:356
integer num_files
Number of output files currenly in use by the diag_manager.
Definition: diag_data.F90:348
integer max_file_attributes
Maximum number of user definable global attributes per file.
Definition: diag_data.F90:384
real(r8_kind), parameter cmor_missing_value
CMOR standard missing value.
Definition: diag_data.F90:111
subroutine write_metadata(this, fileobj, var_name, cell_methods)
Writes out the attributes from an fmsDiagAttribute_type.
Definition: diag_data.F90:627
logical prepend_date
Should the history file have the start date prepended to the file name. .TRUE. is only supported if t...
Definition: diag_data.F90:386
character(len=2), dimension(:), allocatable fnum_for_domain
If this file number in the array is for the "unstructured" or "2d" domain.
Definition: diag_data.F90:437
integer, parameter max_dimensions
Max number of dimensions allowed (including unlimited dimension)
Definition: diag_data.F90:104
integer, parameter begin_time
Use the begining of the time average bounds.
Definition: diag_data.F90:126
subroutine diag_data_init()
Initialize and write the version number of this file to the log file.
Definition: diag_data.F90:454
integer, parameter time_average
The reduction method is average of values.
Definition: diag_data.F90:120
integer, parameter direction_up
The axis points up if positive.
Definition: diag_data.F90:105
integer function get_base_month()
gets the module variable base_month
Definition: diag_data.F90:531
integer, parameter time_sum
The reduction method is sum of values.
Definition: diag_data.F90:119
subroutine fms_add_attribute(this, att_name, att_value)
Adds an attribute to the attribute type.
Definition: diag_data.F90:569
character(len=16) wildcard_filename_prefix
String inserted immediately before the first substituted time field when using a wildcard (%) file na...
Definition: diag_data.F90:389
integer, parameter time_rms
The reudction method is root mean square of values.
Definition: diag_data.F90:121
integer, parameter middle_time
Use the middle of the time average bounds.
Definition: diag_data.F90:127
logical module_is_initialized
Indicate if diag_manager has been initialized.
Definition: diag_data.F90:443
integer, parameter glo_reg_val
Value used in the region specification of the diag_table to indicate to use the full axis instead of ...
Definition: diag_data.F90:107
logical, private base_time_set
Flag indicating that the base_time is set This is to prevent users from calling set_base_time multipl...
Definition: diag_data.F90:425
integer, parameter time_none
There is no reduction method.
Definition: diag_data.F90:116
logical oor_warnings_fatal
Cause a fatal error if the output field has a value outside the given range for a variable.
Definition: diag_data.F90:375
integer function get_base_second()
gets the module variable base_second
Definition: diag_data.F90:563
integer, parameter time_max
The reduction method is max value.
Definition: diag_data.F90:118
integer, parameter max_fields_per_file
Maximum number of fields per file.
Definition: diag_data.F90:89
logical use_refactored_send
Namelist flag to use refactored send_data math funcitons.
Definition: diag_data.F90:395
integer, parameter r8
Supported type/kind of the variable.
Definition: diag_data.F90:83
integer max_field_attributes
Maximum number of user definable attributes per field. Liptak: Changed from 2 to 4 20170718.
Definition: diag_data.F90:382
integer, parameter two_d_domain
Use the FmsNetcdfDomainFile_t fileobj.
Definition: diag_data.F90:101
Define the region for field output.
Definition: diag_data.F90:171
Attribute type for diagnostic fields.
Definition: diag_data.F90:157
Type to hold the diagnostic axis description.
Definition: diag_data.F90:306
Diagnostic field type.
Definition: diag_data.F90:146
Contains the coordinates of the local domain to output.
Definition: diag_data.F90:136
Type to define the diagnostic files that will be written as defined by the diagnostic table.
Definition: diag_data.F90:182
Type to hold the attributes of the field/axis/file.
Definition: diag_data.F90:334
Type to hold the input field description.
Definition: diag_data.F90:222
Type to hold the output field description.
Definition: diag_data.F90:249
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
Definition: fms.F90:701
One dimensional domain used to manage shared data access between pes.
The domain2D type contains all the necessary information to define the global, compute and data domai...
Domain information for managing data on unstructured grids.
integer function stdlog()
This function returns the current standard fortran unit numbers for log messages. Log messages,...
Definition: mpp_util.inc:58
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:406
Error handler.
Definition: mpp.F90:385
character(len=9) function, public month_name(n)
Returns a character string containing the name of the month corresponding to month number n.
integer function, public get_calendar_type()
Returns default calendar type for mapping from time to date.
Given an input date in year, month, days, etc., creates a time_type that represents this time interva...
Given some number of seconds and days, returns the corresponding time_type.
Type to represent amounts of time. Implemented as seconds and days to allow for larger intervals.
Data structure holding a 3D bounding box. It is commonlyused to represent the interval bounds or limi...