FMS 2025.01.02-dev
Flexible Modeling System
Loading...
Searching...
No Matches
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!> @{
48MODULE diag_data_mod
49use 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
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=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(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
446CONTAINS
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
650END MODULE diag_data_mod
651!> @}
652! close documentation grouping
character(len=8) no_units
String indicating that the variable has no units.
subroutine fms_add_attribute(this, att_name, att_value)
Adds an attribute to the attribute type.
integer max_output_fields
Maximum number of output fields. Increase via diag_manager_nml.
real fill_value
Fill value used. Value will be NF90_FILL_REAL if using the netCDF module, otherwise will be 9....
integer, parameter direction_down
The axis points down if positive.
integer function get_base_year()
gets the module variable base_year
integer, parameter sub_regional
This is a file with a sub_region use the FmsNetcdfFile_t fileobj.
integer pack_size
1 for double and 2 for float
subroutine write_metadata(this, fileobj, var_name, cell_methods)
Writes out the attributes from an fmsDiagAttribute_type.
integer, parameter max_str_len
Max length for a string.
integer num_input_fields
Number of input fields in use.
logical use_cmor
Indicates if we should overwrite the MISSING_VALUE to use the CMOR missing value.
subroutine set_base_time(base_time_int)
Set the module variable base_time.
logical flush_nc_files
Control if diag_manager will force a flush of the netCDF file on each write. Note: changing this to ....
integer, parameter no_domain
Use the FmsNetcdfFile_t fileobj.
character(len=7) avg_name
Name of the average fields.
integer, parameter end_time
Use the end of the time average bounds.
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...
integer max_axis_attributes
Maximum number of user definable attributes per axis.
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".
integer function get_base_second()
gets the module variable base_second
logical use_modern_diag
Namelist flag to use the modernized diag_manager code.
integer max_axes
Maximum number of independent axes.
logical use_mpp_io
false is fms2_io (default); true is mpp_io
type(time_type), private base_time
The base_time read from diag_table.
integer, parameter is_x_axis
integer indicating that it is a x axis
integer, parameter diag_field_not_found
Return value for a diag_field that isn't found in the diag_table.
integer max_out_per_in_field
Maximum number of output_fields per input_field. Increase via diag_manager_nml.
integer max_input_fields
Maximum number of input fields. Increase via diag_manager_nml.
integer function get_base_month()
gets the module variable base_month
logical use_clock_average
.TRUE. if the averaging of variable is done based on the clock For example, if doing daily averages a...
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.
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...
integer num_output_fields
Number of output fields in use.
integer, parameter is_y_axis
integer indicating that it is a y axis
integer function get_var_type(var)
gets the type of a variable
type(time_type) diag_init_time
Time diag_manager_init called. If init_time not included in diag_manager_init call,...
integer, parameter time_min
The reduction method is min value.
integer, parameter ug_domain
Use the FmsNetcdfUnstructuredDomainFile_t fileobj.
integer, parameter time_diurnal
The reduction method is diurnal.
integer, parameter time_power
The reduction method is average with exponents.
integer max_files
Maximum number of output files allowed. Increase via diag_manager_nml.
integer num_files
Number of output files currenly in use by the diag_manager.
integer max_file_attributes
Maximum number of user definable global attributes per file.
integer function get_base_minute()
gets the module variable base_minute
real(r8_kind), parameter cmor_missing_value
CMOR standard missing value.
logical prepend_date
Should the history file have the start date prepended to the file name. .TRUE. is only supported if t...
character(len=2), dimension(:), allocatable fnum_for_domain
If this file number in the array is for the "unstructured" or "2d" domain.
integer, parameter begin_time
Use the begining of the time average bounds.
integer function get_base_day()
gets the module variable base_day
type(time_type) function get_base_time()
gets the module variable base_time
integer, parameter time_average
The reduction method is average of values.
integer, parameter direction_up
The axis points up if positive.
integer, parameter time_sum
The reduction method is sum of values.
integer, parameter time_rms
The reudction method is root mean square of values.
integer, parameter middle_time
Use the middle of the time average bounds.
logical module_is_initialized
Indicate if diag_manager has been initialized.
integer, parameter glo_reg_val
Value used in the region specification of the diag_table to indicate to use the full axis instead of ...
logical, private base_time_set
Flag indicating that the base_time is set This is to prevent users from calling set_base_time multipl...
integer, parameter time_none
There is no reduction method.
subroutine diag_data_init()
Initialize and write the version number of this file to the log file.
logical oor_warnings_fatal
Cause a fatal error if the output field has a value outside the given range for a variable.
integer, parameter time_max
The reduction method is max value.
integer function get_base_hour()
gets the module variable base_hour
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.
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.
integer, parameter two_d_domain
Use the FmsNetcdfDomainFile_t fileobj.
Define the region for field output.
Attribute type for diagnostic fields.
Type to hold the diagnostic axis description.
Diagnostic field type.
Contains the coordinates of the local domain to output.
Type to hold the attributes of the field/axis/file.
Type to hold the input field description.
Type to hold the output field description.
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.
Error handler.
Definition mpp.F90:382
integer function, public get_calendar_type()
Returns default calendar type for mapping from time to date.
character(len=9) function, public month_name(n)
Returns a character string containing the name of the month corresponding to month number n.
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...