FMS  2024.01.00
Flexible Modeling System
diag_data.F90
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !> @defgroup diag_data_mod diag_data_mod
20 !> @ingroup diag_manager
21 !! @brief Type descriptions and global variables for the diag_manager modules.
22 !! @author Seth Underwood <seth.underwood@noaa.gov>
23 !!
24 !! Notation:
25 !! <DL>
26 !! <DT>input field</DT>
27 !! <DD>The data structure describing the field as
28 !! registered by the model code.</DD>
29 !!
30 !! <DT>output field</DT>
31 !! <DD>The data structure describing the actual
32 !! diagnostic output with requested frequency and
33 !! other options.</DD>
34 !! </DL>
35 !!
36 !! Input fields, output fields, and output files are gathered in arrays called
37 !! "input_fields", "output_fields", and "files", respectively. Indices in these
38 !! arrays are used as pointers to create associations between various data
39 !! structures.
40 !!
41 !! Each input field associated with one or several output fields via array of
42 !! indices output_fields; each output field points to the single "parent" input
43 !! field with the input_field index, and to the output file with the output_file
44 !! index.
45 
46 !> @addtogroup diag_data_mod
47 !> @{
48 MODULE diag_data_mod
49 use platform_mod
50 
51  USE time_manager_mod, ONLY: get_calendar_type, no_calendar, set_date, set_time, month_name, time_type
52  USE constants_mod, ONLY: seconds_per_hour, seconds_per_minute
53  USE mpp_domains_mod, ONLY: domain1d, domain2d, domainug
54  USE fms_mod, ONLY: write_version_number
55  USE fms_diag_bbox_mod, ONLY: fmsdiagibounds_type
56  use mpp_mod, ONLY: mpp_error, fatal, warning, mpp_pe, mpp_root_pe, stdlog
57 
58  ! NF90_FILL_REAL has value of 9.9692099683868690e+36.
59  USE netcdf, ONLY: nf_fill_real => nf90_fill_real
60  use fms2_io_mod
61 
62  IMPLICIT NONE
63 
64  PUBLIC
65 
66  ! Specify storage limits for fixed size tables used for pointers, etc.
67  integer, parameter :: diag_null = -999 !< Integer represening NULL in the diag_object
68  character(len=1), parameter :: diag_null_string = " "
69  integer, parameter :: diag_not_found = -1
70  integer, parameter :: diag_not_registered = 0
71  integer, parameter :: diag_registered_id = 10
72  !> Supported averaging intervals
73  integer, parameter :: monthly = 30
74  integer, parameter :: daily = 24
75  integer, parameter :: diurnal = 2
76  integer, parameter :: yearly = 12
77  integer, parameter :: no_diag_averaging = 0
78  integer, parameter :: instantaneous = 0
79  integer, parameter :: three_hourly = 3
80  integer, parameter :: six_hourly = 6
81  !integer, parameter :: seasonally = 180
82  !> Supported type/kind of the variable
83  !integer, parameter :: r16=16
84  integer, parameter :: r8 = 8
85  integer, parameter :: r4 = 4
86  integer, parameter :: i8 = -8
87  integer, parameter :: i4 = -4
88  integer, parameter :: string = 19 !< s is the 19th letter of the alphabet
89  integer, parameter :: null_type_int = -999
90  INTEGER, PARAMETER :: max_fields_per_file = 300 !< Maximum number of fields per file.
91  INTEGER, PARAMETER :: diag_other = 0
92  INTEGER, PARAMETER :: diag_ocean = 1
93  INTEGER, PARAMETER :: diag_all = 2
94  INTEGER, PARAMETER :: very_large_file_freq = 100000
95  INTEGER, PARAMETER :: very_large_axis_length = 10000
96  INTEGER, PARAMETER :: every_time = 0
97  INTEGER, PARAMETER :: end_of_run = -1
98  INTEGER, PARAMETER :: diag_seconds = 1, diag_minutes = 2, diag_hours = 3
99  INTEGER, PARAMETER :: diag_days = 4, diag_months = 5, diag_years = 6
100  INTEGER, PARAMETER :: max_subaxes = 10
101  INTEGER, PARAMETER :: no_domain = 1 !< Use the FmsNetcdfFile_t fileobj
102  INTEGER, PARAMETER :: two_d_domain = 2 !< Use the FmsNetcdfDomainFile_t fileobj
103  INTEGER, PARAMETER :: ug_domain = 3 !< Use the FmsNetcdfUnstructuredDomainFile_t fileobj
104  INTEGER, PARAMETER :: sub_regional = 4 !< This is a file with a sub_region use the FmsNetcdfFile_t fileobj
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
182  TYPE file_type
183  CHARACTER(len=128) :: 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(I4_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  LOGICAL :: use_mpp_io = .false. !< false is fms2_io (default); true is mpp_io
390  LOGICAL :: use_refactored_send = .false. !< Namelist flag to use refactored send_data math funcitons.
391  LOGICAL :: use_modern_diag = .false. !< Namelist flag to use the modernized diag_manager code
392  LOGICAL :: use_clock_average = .false. !< .TRUE. if the averaging of variable is done based on the clock
393  !! For example, if doing daily averages and your start the simulation in
394  !! day1_hour3, it will do the average between day1_hour3 to day2_hour 0
395  !! the default behavior will do the average between day1 hour3 to day2 hour3
396  ! <!-- netCDF variable -->
397 
398  REAL :: fill_value = nf_fill_real !< Fill value used. Value will be <TT>NF90_FILL_REAL</TT> if using the
399  !! netCDF module, otherwise will be 9.9692099683868690e+36.
400  ! from file /usr/local/include/netcdf.inc
401 
402  !! @note `pack_size` and `pack_size_str` are set in diag_manager_init depending on how FMS was compiled
403  !! if FMS was compiled with default reals as 64bit, it will be set to 1 and "double",
404  !! if FMS was compiled with default reals as 32bit, it will set to 2 and "float"
405  !! The time variables will written in the precision defined by `pack_size_str`
406  !! This is to reproduce previous diag manager behavior.
407  !TODO This may not be mixed precision friendly
408  INTEGER :: pack_size = 1 !< 1 for double and 2 for float
409  CHARACTER(len=6) :: pack_size_str="double" !< Pack size as a string to be used in fms2_io register call
410  !! set to "double" or "float"
411 
412  ! <!-- REAL public variables -->
413  REAL(r8_kind) :: empty = 0.0
414  REAL(r8_kind) :: max_value, min_value
415 
416  ! <!-- Global data for all files -->
417  TYPE(time_type) :: diag_init_time !< Time diag_manager_init called. If init_time not included in
418  !! diag_manager_init call, then same as base_time
419  TYPE(time_type), private :: base_time !< The base_time read from diag_table
420  logical, private :: base_time_set !< Flag indicating that the base_time is set
421  !! This is to prevent users from calling set_base_time multiple times
422  INTEGER, private :: base_year, base_month, base_day, base_hour, base_minute, base_second
423  CHARACTER(len = 256):: global_descriptor
424 
425  ! <!-- ALLOCATABLE variables -->
426  TYPE(file_type), SAVE, ALLOCATABLE :: files(:)
427  TYPE(input_field_type), ALLOCATABLE :: input_fields(:)
428  TYPE(output_field_type), ALLOCATABLE :: output_fields(:)
429  ! used if use_mpp_io = .false.
430  type(fmsnetcdfunstructureddomainfile_t),allocatable, target :: fileobju(:)
431  type(fmsnetcdfdomainfile_t),allocatable, target :: fileobj(:)
432  type(fmsnetcdffile_t),allocatable, target :: fileobjnd(:)
433  character(len=2),allocatable :: fnum_for_domain(:) !< If this file number in the array is for the "unstructured"
434  !! or "2d" domain
435 
436  ! <!-- Even More Variables -->
437  TYPE(time_type) :: time_zero
438  LOGICAL :: first_send_data_call = .true.
439  LOGICAL :: module_is_initialized = .false. !< Indicate if diag_manager has been initialized
440  INTEGER :: diag_log_unit
441  CHARACTER(len=10), DIMENSION(6) :: time_unit_list = (/'seconds ', 'minutes ',&
442  & 'hours ', 'days ', 'months ', 'years '/)
443  character(len=32) :: pelist_name
444  INTEGER :: oor_warning = warning
445 
446 CONTAINS
447 
448  !> @brief Initialize and write the version number of this file to the log file.
449  SUBROUTINE diag_data_init()
450  IF (module_is_initialized) THEN
451  RETURN
452  END IF
453 
454  ! Write version number out to log file
455  call write_version_number("DIAG_DATA_MOD", version)
456  module_is_initialized = .true.
457  base_time_set = .false.
458 
459  END SUBROUTINE diag_data_init
460 
461  !> @brief Set the module variable base_time
462  subroutine set_base_time(base_time_int)
463  integer :: base_time_int(6) !< base_time as an array [year month day hour min sec]
464 
465  CHARACTER(len=9) :: amonth !< Month name
466  INTEGER :: stdlog_unit !< Fortran file unit number for the stdlog file.
467 
468  if (.not. module_is_initialized) call mpp_error(fatal, "set_base_time: diag_data is not initialized")
469  if (base_time_set) call mpp_error(fatal, "set_base_time: the base_time is already set!")
470 
471  base_year = base_time_int(1)
472  base_month = base_time_int(2)
473  base_day = base_time_int(3)
474  base_hour = base_time_int(4)
475  base_minute = base_time_int(5)
476  base_second = base_time_int(6)
477 
478  ! Set up the time type for base time
479  IF ( get_calendar_type() /= no_calendar ) THEN
480  IF ( base_year==0 .OR. base_month==0 .OR. base_day==0 ) THEN
481  call mpp_error(fatal, 'diag_data_mod::set_base_time'//&
482  & 'The base_year/month/day can not equal zero')
483  END IF
484  base_time = set_date(base_year, base_month, base_day, base_hour, base_minute, base_second)
485  amonth = month_name(base_month)
486  ELSE
487  ! No calendar - ignore year and month
488  base_time = set_time(nint(base_hour*seconds_per_hour)+nint(base_minute*seconds_per_minute)+base_second, &
489  & base_day)
490  base_year = 0
491  base_month = 0
492  amonth = 'day'
493  END IF
494 
495  ! get the stdlog unit number
496  stdlog_unit = stdlog()
497 
498  IF ( mpp_pe() == mpp_root_pe() ) THEN
499  WRITE (stdlog_unit,'("base date used = ",I4,1X,A,2I3,2(":",I2.2)," gmt")') base_year, trim(amonth), base_day, &
500  & base_hour, base_minute, base_second
501  END IF
502 
503  base_time_set = .true.
504 
505  end subroutine set_base_time
506 
507  !> @brief gets the module variable base_time
508  !> @return the base_time
509  function get_base_time() &
510  result(res)
511  TYPE(time_type) :: res
512  res = base_time
513  end function get_base_time
514 
515  !> @brief gets the module variable base_year
516  !> @return the base_year
517  function get_base_year() &
518  result(res)
519  integer :: res
520  res = base_year
521  end function get_base_year
522 
523  !> @brief gets the module variable base_month
524  !> @return the base_month
525  function get_base_month() &
526  result(res)
527  integer :: res
528  res = base_month
529  end function get_base_month
530 
531  !> @brief gets the module variable base_day
532  !> @return the base_day
533  function get_base_day() &
534  result(res)
535  integer :: res
536  res = base_day
537  end function get_base_day
538 
539  !> @brief gets the module variable base_hour
540  !> @return the base_hour
541  function get_base_hour() &
542  result(res)
543  integer :: res
544  res = base_hour
545  end function get_base_hour
546 
547  !> @brief gets the module variable base_minute
548  !> @return the base_minute
549  function get_base_minute() &
550  result(res)
551  integer :: res
552  res = base_minute
553  end function get_base_minute
554 
555  !> @brief gets the module variable base_second
556  !> @return the base_second
557  function get_base_second() &
558  result(res)
559  integer :: res
560  res = base_second
561  end function get_base_second
562 
563  !> @brief Adds an attribute to the attribute type
564  subroutine fms_add_attribute(this, att_name, att_value)
565  class(fmsdiagattribute_type), intent(inout) :: this !< Diag attribute type
566  character(len=*), intent(in) :: att_name !< Name of the attribute
567  class(*), intent(in) :: att_value(:) !< The attribute value to add
568 
569  integer :: natt !< the size of att_value
570 
571  natt = size(att_value)
572  this%att_name = att_name
573  select type (att_value)
574  type is (integer(kind=i4_kind))
575  allocate(integer(kind=i4_kind) :: this%att_value(natt))
576  this%att_value = att_value
577  type is (integer(kind=i8_kind))
578  allocate(integer(kind=i8_kind) :: this%att_value(natt))
579  this%att_value = att_value
580  type is (real(kind=r4_kind))
581  allocate(real(kind=r4_kind) :: this%att_value(natt))
582  this%att_value = att_value
583  type is (real(kind=r8_kind))
584  allocate(real(kind=r8_kind) :: this%att_value(natt))
585  this%att_value = att_value
586  type is (character(len=*))
587  allocate(character(len=len(att_value)) :: this%att_value(natt))
588  select type(aval => this%att_value)
589  type is (character(len=*))
590  aval = att_value
591  end select
592  end select
593  end subroutine fms_add_attribute
594 
595  !> @brief gets the type of a variable
596  !> @return the type of the variable (r4,r8,i4,i8,string)
597  function get_var_type(var) &
598  result(var_type)
599  class(*), intent(in) :: var !< Variable to get the type for
600  integer :: var_type !< The variable's type
601 
602  select type(var)
603  type is (real(r4_kind))
604  var_type = r4
605  type is (real(r8_kind))
606  var_type = r8
607  type is (integer(i4_kind))
608  var_type = i4
609  type is (integer(i8_kind))
610  var_type = i8
611  type is (character(len=*))
612  var_type = string
613  class default
614  call mpp_error(fatal, "get_var_type:: The variable does not have a supported type. "&
615  &"The supported types are r4, r8, i4, i8 and string.")
616  end select
617  end function get_var_type
618 
619  !> @brief Writes out the attributes from an fmsDiagAttribute_type
620  subroutine write_metadata(this, fileobj, var_name, cell_methods)
621  class(fmsdiagattribute_type), intent(inout) :: this !< Diag attribute type
622  class(fmsnetcdffile_t), INTENT(INOUT) :: fileobj !< Fms2_io fileobj to write to
623  character(len=*), intent(in) :: var_name !< The name of the variable to write to
624  character(len=*), optional, intent(inout) :: cell_methods !< The cell methods attribute
625 
626  select type (att_value =>this%att_value)
627  type is (character(len=*))
628  !< If the attribute is cell methods append to the current cell_methods attribute value
629  !! This will be writen once all of the cell_methods attributes are gathered ...
630  if (present(cell_methods)) then
631  if (trim(this%att_name) .eq. "cell_methods") then
632  cell_methods = trim(cell_methods)//" "//trim(att_value(1))
633  return
634  endif
635  endif
636 
637  call register_variable_attribute(fileobj, var_name, this%att_name, trim(att_value(1)), &
638  str_len=len_trim(att_value(1)))
639  type is (real(kind=r8_kind))
640  call register_variable_attribute(fileobj, var_name, this%att_name, real(att_value, kind=r8_kind))
641  type is (real(kind=r4_kind))
642  call register_variable_attribute(fileobj, var_name, this%att_name, real(att_value, kind=r4_kind))
643  type is (integer(kind=i4_kind))
644  call register_variable_attribute(fileobj, var_name, this%att_name, int(att_value, kind=i4_kind))
645  type is (integer(kind=i8_kind))
646  call register_variable_attribute(fileobj, var_name, this%att_name, int(att_value, kind=i8_kind))
647  end select
648 
649  end subroutine write_metadata
650 END MODULE diag_data_mod
651 !> @}
652 ! 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:398
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:104
integer pack_size
1 for double and 2 for float
Definition: diag_data.F90:408
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:551
integer function get_base_year()
gets the module variable base_year
Definition: diag_data.F90:519
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:543
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:599
integer, parameter no_domain
Use the FmsNetcdfFile_t fileobj.
Definition: diag_data.F90:101
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:73
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:409
logical use_modern_diag
Namelist flag to use the modernized diag_manager code.
Definition: diag_data.F90:391
type(time_type) function get_base_time()
gets the module variable base_time
Definition: diag_data.F90:511
integer max_axes
Maximum number of independent axes.
Definition: diag_data.F90:361
logical use_mpp_io
false is fms2_io (default); true is mpp_io
Definition: diag_data.F90:389
type(time_type), private base_time
The base_time read from diag_table.
Definition: diag_data.F90:419
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:392
integer, parameter string
s is the 19th letter of the alphabet
Definition: diag_data.F90:88
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
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:535
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:417
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:103
subroutine set_base_time(base_time_int)
Set the module variable base_time.
Definition: diag_data.F90:463
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:621
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:433
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:450
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:527
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:565
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:439
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:420
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:559
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:90
logical use_refactored_send
Namelist flag to use refactored send_data math funcitons.
Definition: diag_data.F90:390
integer, parameter r8
Supported type/kind of the variable.
Definition: diag_data.F90:84
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:102
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 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:758
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:59
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:378
Error handler.
Definition: mpp.F90:382
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...