FMS  2024.01.00
Flexible Modeling System
diag_manager.F90
Go to the documentation of this file.
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_manager_mod diag_manager_mod
20 !> @ingroup diag_manager
21 !! @brief diag_manager_mod is a set of simple calls for parallel diagnostics
22 !! on distributed systems. It is geared toward the writing of data in netCDF
23 !! format. See @ref diag_manager for diag table information.
24 !! @author Matt Harrison, Giang Nong, Seth Underwood
25 !!
26 !! <TT>diag_manager_mod</TT> provides a convenient set of interfaces for
27 !! writing data to disk. It is built upon the parallel I/O interface of FMS
28 !! code <TT>/shared/mpp/mpp_io.F90</TT>.
29 !!
30 !! A single group of calls to the <TT>diag_manager_mod</TT> interfaces
31 !! provides data to disk at any number of sampling and/or averaging intervals
32 !! specified at run-time. Run-time specification of diagnostics are input
33 !! through the diagnostics table.
34 !!
35 !! <H4>Usage</H4>
36 !! Use of <TT>diag_manager</TT> includes the following steps:
37 !! <OL>
38 !! <LI> Create diag_table as described in the @ref diag_table_mod
39 !! documentation.</LI>
40 !! <LI> Call @ref diag_manager_init to initialize
41 !! diag_manager_mod.</LI>
42 !! <LI> Call @ref register_diag_field to register the field to be
43 !! output.
44 !! <B>NOTE:</B> ALL fields in diag_table should be registered <I>BEFORE</I>
45 !! the first send_data call</LI>
46 !! <LI> Call @ref send_data to send data to output fields </LI>
47 !! <LI> Call @ref diag_manager_end to exit diag_manager </LI>
48 !! </OL>
49 !!
50 !! <H4>Features</H4>
51 !! Features of <TT>diag_manager_mod</TT>:
52 !! <OL>
53 !! <LI> Ability to output from 0D arrays (scalars) to 3D arrays.</LI>
54 !! <LI> Ability to output time average of fields that have time dependent
55 !! mask.</LI>
56 !! <LI> Give optional warning if <TT>register_diag_field</TT> fails due to
57 !! misspelled module name or field name.</LI>
58 !! <LI> Check if a field is registered twice.</LI>
59 !! <LI> Check for duplicate lines in diag_table. </LI>
60 !! <LI> @ref diag_table_mod can contain fields
61 !! that are NOT written to any files. The file name in diag_table of
62 !! these fields is <TT>null</TT>.</LI>
63 !! <LI> By default, a field is output in its global grid. The user can now
64 !! output a field in a specified region. See
65 !! @ref send_data for more details.</LI>
66 !! <LI> To check if the diag table is set up correctly, user should set
67 !! <TT>debug_diag_manager=.true.</TT> in diag_manager namelist, then
68 !! the the content of diag_table is printed in stdout.</LI>
69 !! <LI> New optional format of file information in @ref diag_table_mod.
70 !! It is possible to have just
71 !! one file name and reuse it many times. A time string will be appended to
72 !! the base file name each time a new file is opened. The time string can be
73 !! any combination from year to second of current model time.
74 !!
75 !! Here is an example file line: <BR />
76 !! <PRE>"file2_yr_dy%1yr%3dy",2,"hours",1,"hours","Time", 10, "days", "1 1 7 0 0 0", 6, "hours"</PRE>
77 !! <BR />
78 !!
79 !! From left to right we have:
80 !! <UL>
81 !! <LI>file name</LI>
82 !! <LI>output frequency</LI>
83 !! <LI>output frequency unit</LI>
84 !! <LI>Format (should always be 1)</LI>
85 !! <LI>time axis unit</LI>
86 !! <LI>time axis name</LI>
87 !! <LI>frequency for creating new file</LI>
88 !! <LI>unit for creating new file</LI>
89 !! <LI>start time of the new file</LI>
90 !! <LI>file duration</LI>
91 !! <LI>file duration unit.</LI>
92 !! </UL>
93 !! The 'file duration', if absent, will be equal to frequency for creating a new file.
94 !!
95 !! Thus, the above means: create a new file every 10 days, each file will last 6 hours
96 !! from creation time, no files will
97 !! be created before time "1 1 7 0 0 0".
98 !!
99 !! In this example the string
100 !! <TT>10, "days", "1 1 7 0 0 0", 6, "hours"</TT> is optional.
101 !!
102 !! Keywords for the time string suffix is
103 !! <TT>%xyr,%xmo,%xdy,%xhr,%xmi,%xsc</TT> where <TT>x</TT> is a
104 !! mandatory 1 digit number specifying the width of field used in
105 !! writing the string</LI>
106 !! <LI> New time axis for time averaged fields. Users can use a namelist option to handle the time value written
107 !! to time axis for time averaged fields.
108 !!
109 !! If <TT>mix_snapshot_average_fields=.true.</TT> then a time averaged file will have
110 !! time values corresponding to
111 !! ending time_bound e.g. January monthly average is labeled Feb01. Users can have
112 !! both snapshot and averaged fields in
113 !! one file.
114 !!
115 !! If <TT>mix_snapshot_average_fields=.false.</TT> The time value written to time
116 !! axis for time averaged fields is the
117 !! middle on the averaging time. For example, January monthly mean will be written at Jan 16 not Feb 01 as
118 !! before. However, to use this new feature users should <B>separate</B> snapshot
119 !! fields and time averaged fields in
120 !! <B>different</B> files or a fatal error will occur.
121 !!
122 !! The namelist <B>default</B> value is <TT>mix_snapshot_average_fields=.false.</TT></LI>
123 !! <LI> Time average, Root Mean Square, Max and Min, and diurnal. In addition to time average
124 !! users can also get then Root Mean Square, Max or Min value
125 !! during the same interval of time as time average. For this purpose, in the diag table users must replace
126 !! <TT>.true.</TT> or <TT>.false.</TT> by <TT>rms</TT>, <TT>max</TT> or <TT>min</TT>.
127 !! <B><I>Note:</I></B> Currently, max
128 !! and min are not available for regional output.
129 !!
130 !! A diurnal average or the average of an integer power can also be requested using
131 !! <TT>diurnal##</TT> or <TT>pow##</TT> where
132 !! <TT>##</TT> are the number of diurnal sections or integer power to average.</LI>
133 !! <LI> <TT>standard_name</TT> is added as optional argument in @ref register_diag_field. </LI>
134 !! <LI>When namelist variable <TT>debug_diag_manager = .true.</TT> array
135 !! bounds are checked in @ref send_data.</LI>
136 !! <LI>Coordinate attributes can be written in the output file if the
137 !! argument "aux" is given in @ref diag_axis_mod#diag_axis_init . The
138 !! corresponding fields (geolat/geolon) should also be written to the
139 !! same file.</LI>
140 !! </OL>
141 
142 !> @file
143 !> @ingroup diag_manager_mod
144 !> @brief File for @ref diag_manager_mod
145 
146 MODULE diag_manager_mod
147 use platform_mod
148  ! <NAMELIST NAME="diag_manager_nml">
149  ! <DATA NAME="append_pelist_name" TYPE="LOGICAL" DEFAULT=".FALSE.">
150  ! </DATA>
151  ! <DATA NAME="mix_snapshot_average_fields" TYPE="LOGICAL" DEFAULT=".FALSE.">
152  ! Set to .TRUE. to allow both time average and instantaneous fields in the same output file.
153  ! </DATA>
154  ! <DATA NAME="max_files" TYPE="INTEGER" DEFULT="31">
155  ! </DATA>
156  ! <DATA NAME="max_output_fields" TYPE="INTEGER" DEFAULT="300">
157  ! </DATA>
158  ! <DATA NAME="max_input_fields" TYPE="INTEGER" DEFAULT="300">
159  ! </DATA>
160  ! <DATA NAME="max_axes" TYPE="INTEGER" DEFAULT="60">
161  ! </DATA>
162  ! <DATA NAME="do_diag_field_log" TYPE="LOGICAL" DEFAULT=".FALSE.">
163  ! </DATA>
164  ! <DATA NAME="write_bytes_in_files" TYPE="LOGICAL" DEFAULT=".FALSE.">
165  ! </DATA>
166  ! <DATA NAME="debug_diag_manager" TYPE="LOGICAL" DEFAULT=".FALSE.">
167  ! </DATA>
168  ! <DATA NAME="max_num_axis_sets" TYPE="INTEGER" DEFAULT="25">
169  ! </DATA>
170  ! <DATA NAME="use_cmor" TYPE="LOGICAL" DEFAULT=".FALSE.">
171  ! Let the <TT>diag_manager</TT> know if the missing value (if supplied) should be overridden to be the
172  ! CMOR standard value of -1.0e20.
173  ! </DATA>
174  ! <DATA NAME="issue_oor_warnings" TYPE="LOGICAL" DEFAULT=".TRUE.">
175  ! If <TT>.TRUE.</TT>, then the <TT>diag_manager</TT> will check for values outside the
176  ! valid range. This range is defined in
177  ! the model, and passed to the <TT>diag_manager_mod</TT> via the OPTIONAL variable range
178  ! in the <TT>register_diag_field</TT>
179  ! function.
180  ! </DATA>
181  ! <DATA NAME="oor_warnings_fatal" TYPE="LOGICAL" DEFAULT=".FALSE.">
182  ! If <TT>.TRUE.</TT> then <TT>diag_manager_mod</TT> will issue a <TT>FATAL</TT> error
183  ! if any values for the output field are
184  ! outside the given range.
185  ! </DATA>
186  ! <DATA NAME="max_field_attributes" TYPE="INTEGER" DEFAULT="4">
187  ! Maximum number of user definable attributes per field.
188  ! </DATA>
189  ! <DATA NAME="max_file_attributes" TYPE="INTEGER" DEFAULT="2">
190  ! Maximum number of user definable global attributes per file.
191  ! </DATA>
192  ! <DATA NAME="prepend_date" TYPE="LOGICAL" DEFAULT=".TRUE.">
193  ! If <TT>.TRUE.</TT> then prepend the file start date to the output file. <TT>.TRUE.</TT>
194  ! is only supported if the
195  ! diag_manager_init routine is called with the optional time_init parameter. Note:
196  ! This was usually done by FRE after the
197  ! model run.
198  ! </DATA>
199  ! <DATA NAME="region_out_use_alt_value" TYPE="LOGICAL" DEFAULT=".TRUE.">
200  ! Will determine which value to use when checking a regional output if the region is the full axis or a sub-axis.
201  ! The values are defined as <TT>GLO_REG_VAL</TT> (-999) and <TT>GLO_REG_VAL_ALT</TT>
202  ! (-1) in <TT>diag_data_mod</TT>.
203  ! </DATA>
204  ! <DATA NAME="use_mpp_io" TYPE="LOGICAL" DEFAULT=".false.">
205  ! Set to true, diag_manager uses mpp_io. Default is fms2_io.
206  ! </DATA>
207  ! </NAMELIST>
208 
209  USE time_manager_mod, ONLY: set_time, set_date, get_time, time_type, OPERATOR(>=), OPERATOR(>),&
210  & OPERATOR(<), OPERATOR(==), OPERATOR(/=), OPERATOR(/), OPERATOR(+), ASSIGNMENT(=), get_date, &
212  USE mpp_mod, ONLY: mpp_get_current_pelist, mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
213 
214  USE mpp_mod, ONLY: input_nml_file, mpp_error
215 
216  USE fms_mod, ONLY: error_mesg, fatal, warning, note, stdout, stdlog, write_version_number,&
217  & fms_error_handler, check_nml_error, lowercase
220  USE diag_util_mod, ONLY: get_subfield_size, log_diag_field_info, update_bounds,&
226  USE diag_data_mod, ONLY: max_files, cmor_missing_value, diag_other, diag_ocean, diag_all, every_time,&
227  & end_of_run, diag_seconds, diag_minutes, diag_hours, diag_days, diag_months, diag_years, num_files,&
229  & max_value, min_value, get_base_time, get_base_year, get_base_month, get_base_day,&
230  & get_base_hour, get_base_minute, get_base_second, global_descriptor, coord_type, files, input_fields,&
231  & output_fields, time_zero, append_pelist_name, mix_snapshot_average_fields,&
232  & first_send_data_call, do_diag_field_log, write_bytes_in_file, debug_diag_manager,&
233  & diag_log_unit, time_unit_list, pelist_name, max_axes, module_is_initialized, max_num_axis_sets,&
239  USE diag_data_mod, ONLY: fileobj, fileobju, fnum_for_domain, fileobjnd
240  USE diag_table_mod, ONLY: parse_diag_table
241  USE diag_output_mod, ONLY: get_diag_global_att, set_diag_global_att
242  USE diag_grid_mod, ONLY: diag_grid_init, diag_grid_end
243  use fms_diag_object_mod, only:fms_diag_object
244 
245  USE constants_mod, ONLY: seconds_per_day
246  USE fms_diag_outfield_mod, ONLY: fmsdiagoutfieldindex_type, fmsdiagoutfield_type
247  USE fms_diag_fieldbuff_update_mod, ONLY: fieldbuff_update, fieldbuff_copy_missvals, &
249 
250  USE netcdf, ONLY: nf90_int, nf90_float, nf90_char
251 
252 !----------
253 !ug support
254  use diag_axis_mod, only: diag_axis_2ddomain
255  use diag_axis_mod, only: diag_axis_ugdomain
256 !----------
257 
258  IMPLICIT NONE
259 
260  PRIVATE
262  & register_diag_field, register_static_field, diag_axis_init, get_base_time, get_base_date,&
263  & need_data, diag_all, diag_ocean, diag_other, get_date_dif, diag_seconds,&
264  & diag_minutes, diag_hours, diag_days, diag_months, diag_years, get_diag_global_att,&
266  & get_diag_field_id, diag_axis_add_attribute, cmor_missing_value, null_axis_id
267  PUBLIC :: center, north, east !< Used for diag_axis_init
268  ! Public interfaces from diag_grid_mod
269  PUBLIC :: diag_grid_init, diag_grid_end
270  PUBLIC :: diag_manager_set_time_end, diag_send_complete
272  ! Public interfaces from diag_data_mod
273  PUBLIC :: diag_field_not_found
274 
275  ! version number of this module
276  ! Include variable "version" to be written to log file.
277 #include<file_version.h>
278 
279  type(time_type) :: Time_end
280 
281  !> @brief Send data over to output fields.
282  !!
283  !> <TT>send_data</TT> is overloaded for fields having zero dimension
284  !! (scalars) to 3 dimension. <TT>diag_field_id</TT> corresponds to the id
285  !! returned from a previous call to <TT>register_diag_field</TT>. The field
286  !! array is restricted to the computational range of the array. Optional
287  !! argument <TT>is_in</TT> can be used to update sub-arrays of the entire
288  !! field. Additionally, an optional logical or real mask can be used to
289  !! apply missing values to the array.
290  !!
291  !! If a field is declared to be <TT>mask_variant</TT> in
292  !! <TT>register_diag_field</TT> logical mask should be mandatory.
293  !!
294  !! For the real mask, the mask is applied if the mask value is less than
295  !! 0.5.
296  !!
297  !! By default, a field will be written out entirely in its global grid.
298  !! Users can also specify regions in which the field will be output. The
299  !! region is specified in diag-table just before the end of output_field
300  !! replacing "none".
301  !!
302  !! For example, by default:
303  !!
304  !! "ocean_mod","Vorticity","vorticity","file1","all",.false.,"none",2
305  !!
306  !! for regional output:
307  !!
308  !! "ocean_mod","Vorticity","vorticity_local","file2","all",.false.,"0.5 53.5 -89.5 -28.5 -1 -1",2
309  !!
310  !! The format of a region is "<TT>xbegin xend ybegin yend zbegin zend</TT>".
311  !! If it is a 2D field use (-1 -1) for (zbegin zend) as in the example above.
312  !! For a 3D field use (-1 -1) for (zbegin zend) when you want to write the
313  !! entire vertical extent, otherwise specify real coordinates. The units
314  !! used for region are the actual units used in grid_spec.nc (for example
315  !! degrees for lat, lon). <B><I>NOTE:</I></B> A FATAL error will occur if
316  !! the region's boundaries are not found in grid_spec.nc.
317  !!
318  !! Regional output on the cubed sphere grid is also supported. To use regional
319  !! output on the cubed sphere grid, first the grid information needs to be sent to
320  !! <TT>diag_manager_mod</TT> using the @ref diag_grid#diag_grid_init subroutine.
321  !!
322  !! @note When using regional output the files containing regional
323  !! outputs should be different from files containing global (default) output.
324  !! It is a FATAL error to have one file containing both regional and global
325  !! results. For maximum flexibility and independence from PE counts one file
326  !! should contain just one region.
327  !!
328  !!
329  !! Time averaging is supported in regional output.
330  !!
331  !! Physical fields (written in "physics windows" of atmospheric code) are
332  !! fully supported for regional outputs.
333  !!
334  !! <B><I>NOTE:</I></B> Most fields are defined in the data domain but use the
335  !! compute domain. In <TT>send_data</TT> the field can be passed in either
336  !! the data domain or in the compute domain. If the data domain is used, the
337  !! start and end indicies of the compute domain (isc, iec, . . .) should be
338  !! passed. If the compute domain is used no indices are needed. The indices
339  !! are for determining halo exclusively. If users want to output the field
340  !! partially they should use regional output as mentioned above.
341  !!
342  !! Weight in Time averaging is now supported, each time level may have a
343  !! different weight. The default of weight is 1.
344  !> @ingroup diag_manager_mod
345  INTERFACE send_data
346  MODULE PROCEDURE send_data_0d
347  MODULE PROCEDURE send_data_1d
348  MODULE PROCEDURE send_data_2d
349  MODULE PROCEDURE send_data_3d
350  MODULE PROCEDURE send_data_4d
351  END INTERFACE
352 
353  !> @brief Register a diagnostic field for a given module
354  !> @ingroup diag_manager_mod
356  MODULE PROCEDURE register_diag_field_scalar
357  MODULE PROCEDURE register_diag_field_array
358  END INTERFACE
359 
360  !> @brief Send tile-averaged data over to output fields.
361  !> @ingroup diag_manager_mod
363  MODULE PROCEDURE send_tile_averaged_data1d
364  MODULE PROCEDURE send_tile_averaged_data2d
365  MODULE PROCEDURE send_tile_averaged_data3d
366  END INTERFACE
367 
368  !> @brief Add a attribute to the output field
369  !> @ingroup diag_manager_mod
371  MODULE PROCEDURE diag_field_add_attribute_scalar_r
372  MODULE PROCEDURE diag_field_add_attribute_scalar_i
373  MODULE PROCEDURE diag_field_add_attribute_scalar_c
374  MODULE PROCEDURE diag_field_add_attribute_r1d
375  MODULE PROCEDURE diag_field_add_attribute_i1d
376  END INTERFACE diag_field_add_attribute
377 
378 !> @addtogroup diag_manager_mod
379 !> @{
380 CONTAINS
381 
382  !> @brief Registers a scalar field
383  !! @return field index for subsequent call to send_data.
384  INTEGER FUNCTION register_diag_field_scalar(module_name, field_name, init_time, &
385  & long_name, units, missing_value, range, standard_name, do_not_log, err_msg,&
386  & area, volume, realm, multiple_send_data)
387  CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from
388  CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
389  TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from
390  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute
391  CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute
392  CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file
393  CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute
394  CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute
395  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged
396  CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call
397  INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
398  INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
399  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
400  LOGICAL, OPTIONAL, INTENT(in) :: multiple_send_data !< .True. if send data is called, multiple times
401  !! for the same time
402 
403  ! Fatal error if range is present and its extent is not 2.
404  IF ( PRESENT(range) ) THEN
405  IF ( SIZE(range) .NE. 2 ) THEN
406  ! <ERROR STATUS="FATAL">extent of range should be 2</ERROR>
407  CALL error_mesg ('diag_manager_mod::register_diag_field', 'extent of range should be 2', fatal)
408  END IF
409  END IF
410  if (use_modern_diag) then
411  if( do_diag_field_log) then
412  if ( PRESENT(do_not_log) ) THEN
413  if(.not. do_not_log) call log_diag_field_info(module_name, field_name, (/null_axis_id/), long_name,&
414  & units, missing_value, range, dynamic=.true.)
415  else
416  call log_diag_field_info(module_name, field_name, (/null_axis_id/), long_name, units,&
417  & missing_value, range, dynamic=.true.)
418  endif
419  endif
420  register_diag_field_scalar = fms_diag_object%fms_register_diag_field_scalar( &
421  & module_name, field_name, init_time, long_name=long_name, units=units, &
422  & missing_value=missing_value, var_range=range, standard_name=standard_name, &
423  & do_not_log=do_not_log, err_msg=err_msg, area=area, volume=volume, realm=realm, &
424  multiple_send_data=multiple_send_data)
425  else
426  register_diag_field_scalar = register_diag_field_scalar_old(module_name, field_name, init_time, &
427  & long_name=long_name, units=units, missing_value=missing_value, range=range, standard_name=standard_name, &
428  & do_not_log=do_not_log, err_msg=err_msg, area=area, volume=volume, realm=realm)
429  endif
430  end function register_diag_field_scalar
431 
432  !> @brief Registers an array field
433  !> @return field index for subsequent call to send_data.
434  INTEGER FUNCTION register_diag_field_array(module_name, field_name, axes, init_time, &
435  & long_name, units, missing_value, range, mask_variant, standard_name, verbose,&
436  & do_not_log, err_msg, interp_method, tile_count, area, volume, realm, multiple_send_data)
437  CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from
438  CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
439  INTEGER, INTENT(in) :: axes(:) !< Ids corresponding to the variable axis
440  TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from
441  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute
442  CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute
443  CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute
444  CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute
445  LOGICAL, OPTIONAL, INTENT(in) :: mask_variant !< .True. if the mask changes over time
446  CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file
447  LOGICAL, OPTIONAL, INTENT(in) :: verbose !< Print more information
448  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged
449  CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call
450  CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
451  !! regridding the field in post-processing.
452  !! Valid options are "conserve_order1",
453  !! "conserve_order2", and "none".
454  INTEGER, OPTIONAL, INTENT(in) :: tile_count !< The current tile number
455  INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
456  INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
457  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
458  LOGICAL, OPTIONAL, INTENT(in) :: multiple_send_data !< .True. if send data is called, multiple times
459  !! for the same time
460 
461  if (use_modern_diag) then
462  if( do_diag_field_log) then
463  if ( PRESENT(do_not_log) ) THEN
464  if(.not. do_not_log) call log_diag_field_info(module_name, field_name, axes, long_name,&
465  & units, missing_value, range, dynamic=.true.)
466  else
467  call log_diag_field_info(module_name, field_name, axes, long_name, units,&
468  & missing_value, range, dynamic=.true.)
469  endif
470  endif
471  register_diag_field_array = fms_diag_object%fms_register_diag_field_array( &
472  & module_name, field_name, axes, init_time, long_name=long_name, &
473  & units=units, missing_value=missing_value, var_range=range, mask_variant=mask_variant, &
474  & standard_name=standard_name, verbose=verbose, do_not_log=do_not_log, err_msg=err_msg, &
475  & interp_method=interp_method, tile_count=tile_count, area=area, volume=volume, realm=realm, &
476  multiple_send_data=multiple_send_data)
477  else
478  register_diag_field_array = register_diag_field_array_old(module_name, field_name, axes, init_time, &
479  & long_name=long_name, units=units, missing_value=missing_value, range=range, mask_variant=mask_variant, &
480  & standard_name=standard_name, verbose=verbose, do_not_log=do_not_log, err_msg=err_msg, &
481  & interp_method=interp_method, tile_count=tile_count, area=area, volume=volume, realm=realm)
482  endif
483 end function register_diag_field_array
484 
485  !> @brief Return field index for subsequent call to send_data.
486  !! @return field index for subsequent call to send_data.
487  INTEGER FUNCTION register_static_field(module_name, field_name, axes, long_name, units,&
488  & missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method,&
489  & tile_count, area, volume, realm)
490  CHARACTER(len=*), INTENT(in) :: module_name !< Name of the module, the field is on
491  CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
492  INTEGER, DIMENSION(:), INTENT(in) :: axes !< Axes_id of the field
493  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Longname to be added as a attribute
494  CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to be added as a attribute
495  CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard name to be added as a attribute
496  CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to be added as a attribute
497  CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range !< Range to be added as a attribute
498  LOGICAL, OPTIONAL, INTENT(in) :: mask_variant !< .True. if the mask changes over time
499  LOGICAL, OPTIONAL, INTENT(in) :: dynamic !< Flag indicating if the field is dynamic
500  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field information is not logged
501  CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
502  !! regridding the field in post-processing
503  !! Valid options are "conserve_order1",
504  !! "conserve_order2", and "none".
505  INTEGER, OPTIONAL, INTENT(in) :: tile_count !! Number of tiles
506  INTEGER, OPTIONAL, INTENT(in) :: area !< Field ID for the area field associated
507  !! with this field
508  INTEGER, OPTIONAL, INTENT(in) :: volume !< Field ID for the volume field associated
509  !! with this field
510  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the value to the
511  !! modeling_realm attribute
512 
513  ! Fatal error if the module has not been initialized.
514  IF ( .NOT.module_is_initialized ) THEN
515  ! <ERROR STATUS="FATAL">diag_manager has NOT been initialized</ERROR>
516  CALL error_mesg ('diag_manager_mod::register_static_field', 'diag_manager has NOT been initialized', fatal)
517  END IF
518 
519  if (use_modern_diag) then
520  if( do_diag_field_log) then
521  if ( PRESENT(do_not_log) ) THEN
522  if(.not. do_not_log) call log_diag_field_info(module_name, field_name, axes, long_name,&
523  & units, missing_value, range, dynamic=.false.)
524  else
525  call log_diag_field_info(module_name, field_name, axes, long_name, units,&
526  & missing_value, range, dynamic=.false.)
527  endif
528  endif
529  register_static_field = fms_diag_object%fms_register_static_field(module_name, field_name, axes, &
530  & long_name=long_name, units=units, missing_value=missing_value, range=range, mask_variant=mask_variant, &
531  & standard_name=standard_name, dynamic=dynamic, do_not_log=do_not_log, interp_method=interp_method,&
532  & tile_count=tile_count, area=area, volume=volume, realm=realm)
533  else
534  register_static_field = register_static_field_old(module_name, field_name, axes, &
535  & long_name=long_name, units=units, missing_value=missing_value, range=range, mask_variant=mask_variant, &
536  & standard_name=standard_name, dynamic=dynamic, do_not_log=do_not_log, interp_method=interp_method,&
537  & tile_count=tile_count, area=area, volume=volume, realm=realm)
538  endif
539 END FUNCTION register_static_field
540 
541  !> @brief Registers a scalar field
542  !! @return field index for subsequent call to send_data.
543  INTEGER FUNCTION register_diag_field_scalar_old(module_name, field_name, init_time, &
544  & long_name, units, missing_value, range, standard_name, do_not_log, err_msg,&
545  & area, volume, realm)
546  CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from
547  CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
548  TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from
549  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute
550  CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute
551  CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file
552  CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute
553  CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute
554  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged
555  CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call
556  INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
557  INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
558  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
559 
560  IF ( PRESENT(err_msg) ) err_msg = ''
561 
562  IF ( PRESENT(init_time) ) THEN
564  & (/null_axis_id/), init_time,long_name, units, missing_value, range, &
565  & standard_name=standard_name, do_not_log=do_not_log, err_msg=err_msg,&
566  & area=area, volume=volume, realm=realm)
567  ELSE
568  register_diag_field_scalar_old = register_static_field(module_name, field_name,&
569  & (/null_axis_id/),long_name, units, missing_value, range,&
570  & standard_name=standard_name, do_not_log=do_not_log, realm=realm)
571  END IF
572  END FUNCTION register_diag_field_scalar_old
573 
574  !> @brief Registers an array field
575  !> @return field index for subsequent call to send_data.
576  INTEGER FUNCTION register_diag_field_array_old(module_name, field_name, axes, init_time, &
577  & long_name, units, missing_value, range, mask_variant, standard_name, verbose,&
578  & do_not_log, err_msg, interp_method, tile_count, area, volume, realm)
579  CHARACTER(len=*), INTENT(in) :: module_name, field_name
580  INTEGER, INTENT(in) :: axes(:)
581  TYPE(time_type), INTENT(in) :: init_time
582  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
583  CLASS(*), OPTIONAL, INTENT(in) :: missing_value
584  CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range
585  LOGICAL, OPTIONAL, INTENT(in) :: mask_variant,verbose
586  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field info is not logged
587  CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg
588  CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
589  !! regridding the field in post-processing.
590  !! Valid options are "conserve_order1",
591  !! "conserve_order2", and "none".
592  INTEGER, OPTIONAL, INTENT(in) :: tile_count !< The current tile number
593  INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
594  INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
595  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
596 
597  INTEGER :: field, j, ind, file_num, freq
598  INTEGER :: output_units
599  INTEGER :: stdout_unit
600  LOGICAL :: mask_variant1, verbose1
601  CHARACTER(len=128) :: msg
602  TYPE(time_type) :: diag_file_init_time !< The intial time of the diag_file
603 
604  ! get stdout unit number
605  stdout_unit = stdout()
606 
607  IF ( PRESENT(mask_variant) ) THEN
608  mask_variant1 = mask_variant
609  ELSE
610  mask_variant1 = .false.
611  END IF
612 
613  IF ( PRESENT(verbose) ) THEN
614  verbose1 = verbose
615  ELSE
616  verbose1 = .false.
617  END IF
618 
619  IF ( PRESENT(err_msg) ) err_msg = ''
620 
621  ! Fatal error if range is present and its extent is not 2.
622  IF ( PRESENT(range) ) THEN
623  IF ( SIZE(range) .NE. 2 ) THEN
624  ! <ERROR STATUS="FATAL">extent of range should be 2</ERROR>
625  CALL error_mesg ('diag_manager_mod::register_diag_field', 'extent of range should be 2', fatal)
626  END IF
627  END IF
628 
629  ! Call register static, then set static back to false
630  register_diag_field_array_old = register_static_field(module_name, field_name, axes,&
631  & long_name, units, missing_value, range, mask_variant1, standard_name=standard_name,&
632  & dynamic=.true., do_not_log=do_not_log, interp_method=interp_method, tile_count=tile_count, realm=realm)
633 
634  IF ( .NOT.first_send_data_call ) THEN
635  ! <ERROR STATUS="WARNING">
636  ! module/output_field <module_name>/<field_name> registered AFTER first
637  ! send_data call, TOO LATE
638  ! </ERROR>
639  IF ( mpp_pe() == mpp_root_pe() ) &
640  & CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
641  &//trim(module_name)//'/'// trim(field_name)//&
642  &' registered AFTER first send_data call, TOO LATE', warning)
643  END IF
644 
645  IF ( register_diag_field_array_old < 0 ) THEN
646  ! <ERROR STATUS="WARNING">
647  ! module/output_field <modul_name>/<field_name> NOT found in diag_table
648  ! </ERROR>
649  IF ( debug_diag_manager .OR. verbose1 ) THEN
650  IF ( mpp_pe() == mpp_root_pe() ) &
651  & CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
652  &//trim(module_name)//'/'// trim(field_name)//' NOT found in diag_table',&
653  & warning)
654  END IF
655  ELSE
656  input_fields(register_diag_field_array_old)%static = .false.
658 
659 
660  ! Verify that area and volume do not point to the same variable
661  IF ( PRESENT(volume).AND.PRESENT(area) ) THEN
662  IF ( area.EQ.volume ) THEN
663  IF (PRESENT(err_msg)) THEN
664  err_msg = 'diag_manager_mod::register_diag_field: module/output_field '&
665  &//trim(module_name)//'/'// trim(field_name)//' AREA and VOLUME CANNOT be the same variable.&
666  & Contact the developers.'
668  RETURN
669  ELSE
670  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
671  &//trim(module_name)//'/'// trim(field_name)//' AREA and VOLUME CANNOT be the same variable.&
672  & Contact the developers.',&
673  & fatal)
674  ENDIF
675  END IF
676  END IF
677 
678  ! Check for the existence of the area/volume field(s)
679  IF ( PRESENT(area) ) THEN
680  IF ( area < 0 ) THEN
681  IF (PRESENT(err_msg)) THEN
682  err_msg = 'diag_manager_mod::register_diag_field: module/output_field '&
683  &//trim(module_name)//'/'// trim(field_name)//' AREA measures field NOT found in diag_table.&
684  & Contact the model liaison.'
686  RETURN
687  ELSE
688  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
689  &//trim(module_name)//'/'// trim(field_name)//' AREA measures field NOT found in diag_table.&
690  & Contact the model liaison.',&
691  & fatal)
692  ENDIF
693  END IF
694  END IF
695  IF ( PRESENT(volume) ) THEN
696  IF ( volume < 0 ) THEN
697  IF (PRESENT(err_msg)) THEN
698  err_msg = 'diag_manager_mod::register_diag_field: module/output_field '&
699  &//trim(module_name)//'/'// trim(field_name)//' VOLUME measures field NOT found in diag_table.&
700  & Contact the model liaison.'
702  RETURN
703  ELSE
704  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
705  &//trim(module_name)//'/'// trim(field_name)//' VOLUME measures field NOT found in diag_table.&
706  & Contact the model liaison.',&
707  & fatal)
708  ENDIF
709  END IF
710  END IF
711 
712  IF ( PRESENT(standard_name) ) input_fields(field)%standard_name = standard_name
713 
714  DO j = 1, input_fields(field)%num_output_fields
715  ind = input_fields(field)%output_fields(j)
716  output_fields(ind)%static = .false.
717  ! Set up times in output_fields
718  ! Get output frequency from for the appropriate output file
719  file_num = output_fields(ind)%output_file
720  IF ( file_num == max_files ) cycle
721  IF ( output_fields(ind)%local_output ) THEN
722  IF ( output_fields(ind)%need_compute) THEN
723  files(file_num)%local = .true.
724  END IF
725  END IF
726 
727  ! Need to sync start_time of file with init time of model
728  ! and close_time calculated with the duration of the file.
729  ! Also, increase next_open until it is greater than init_time.
730  CALL sync_file_times(file_num, init_time, err_msg=msg)
731  IF ( msg /= '' ) THEN
732  IF ( fms_error_handler('diag_manager_mod::register_diag_field', trim(msg), err_msg) ) RETURN
733  END IF
734 
735  freq = files(file_num)%output_freq
736  diag_file_init_time = get_file_start_time(file_num)
737  output_units = files(file_num)%output_units
738  output_fields(ind)%last_output = diag_file_init_time
739  output_fields(ind)%next_output = diag_time_inc(diag_file_init_time, freq, output_units, err_msg=msg)
740  IF ( msg /= '' ) THEN
741  IF ( fms_error_handler('diag_manager_mod::register_diag_field',&
742  & ' file='//trim(files(file_num)%name)//': '//trim(msg),err_msg)) RETURN
743  END IF
744  output_fields(ind)%next_next_output = &
745  & diag_time_inc(output_fields(ind)%next_output, freq, output_units, err_msg=msg)
746  IF ( msg /= '' ) THEN
747  IF ( fms_error_handler('diag_manager_mod::register_diag_field',&
748  &' file='//trim(files(file_num)%name)//': '//trim(msg),err_msg) ) RETURN
749  END IF
750  IF ( debug_diag_manager .AND. mpp_pe() == mpp_root_pe() .AND. output_fields(ind)%local_output ) THEN
751  WRITE (msg,'(" lon(",F5.1,", ",F5.1,"), lat(",F5.1,", ",F5.1,"), dep(",F5.1,", ",F5.1,")")') &
752  & output_fields(ind)%output_grid%start(1),output_fields(ind)%output_grid%end(1),&
753  & output_fields(ind)%output_grid%start(2),output_fields(ind)%output_grid%end(2),&
754  & output_fields(ind)%output_grid%start(3),output_fields(ind)%output_grid%end(3)
755  WRITE(stdout_unit,* ) 'module/output_field '//trim(module_name)//'/'//trim(field_name)// &
756  & ' will be output in region:'//trim(msg)
757  END IF
758 
759  ! Set the cell_measures attribute in the out file
760  CALL init_field_cell_measures(output_fields(ind), area=area, volume=volume, err_msg=err_msg)
761  IF ( len_trim(err_msg).GT.0 ) THEN
762  CALL error_mesg ('diag_manager_mod::register_diag_field',&
763  & trim(err_msg)//' for module/field '//trim(module_name)//'/'//trim(field_name),&
764  & fatal)
765  END IF
766 
767  END DO
768  END IF
769 
770  END FUNCTION register_diag_field_array_old
771  !> @brief Return field index for subsequent call to send_data.
772  !! @return field index for subsequent call to send_data.
773  INTEGER FUNCTION register_static_field_old(module_name, field_name, axes, long_name, units,&
774  & missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method,&
775  & tile_count, area, volume, realm)
776  CHARACTER(len=*), INTENT(in) :: module_name, field_name
777  INTEGER, DIMENSION(:), INTENT(in) :: axes
778  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
779  CLASS(*), OPTIONAL, INTENT(in) :: missing_value
780  CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range
781  LOGICAL, OPTIONAL, INTENT(in) :: mask_variant
782  LOGICAL, OPTIONAL, INTENT(in) :: dynamic
783  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field information is not logged
784  CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
785  !! regridding the field in post-processing.
786  !! Valid options are "conserve_order1",
787  !! "conserve_order2", and "none".
788  INTEGER, OPTIONAL, INTENT(in) :: tile_count
789  INTEGER, OPTIONAL, INTENT(in) :: area !< Field ID for the area field associated with this field
790  INTEGER, OPTIONAL, INTENT(in) :: volume !< Field ID for the volume field associated with this field
791  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the value to the modeling_realm attribute
792 
793  REAL :: missing_value_use !< Local copy of missing_value
794  REAL, DIMENSION(2) :: range_use !< Local copy of range
795  INTEGER :: field, num_axes, j, out_num, k
796  INTEGER, DIMENSION(3) :: siz, local_siz, local_start, local_end ! indices of local domain of global axes
797  INTEGER :: tile, file_num
798  LOGICAL :: mask_variant1, dynamic1, allow_log
799  CHARACTER(len=128) :: msg
800  INTEGER :: domain_type, i
801  character(len=256) :: axis_name
802 
803  ! Fatal error if the module has not been initialized.
804  IF ( .NOT.module_is_initialized ) THEN
805  ! <ERROR STATUS="FATAL">diag_manager has NOT been initialized</ERROR>
806  CALL error_mesg ('diag_manager_mod::register_static_field_old', 'diag_manager has NOT been initialized', fatal)
807  END IF
808 
809  ! Check if OPTIONAL parameters were passed in.
810  IF ( PRESENT(missing_value) ) THEN
811  IF ( use_cmor ) THEN
812  missing_value_use = cmor_missing_value
813  ELSE
814  SELECT TYPE (missing_value)
815  TYPE IS (real(kind=r4_kind))
816  missing_value_use = missing_value
817  TYPE IS (real(kind=r8_kind))
818  missing_value_use = real(missing_value)
819  CLASS DEFAULT
820  CALL error_mesg ('diag_manager_mod::register_static_field',&
821  & 'The missing_value is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
822  END SELECT
823  END IF
824  END IF
825 
826  IF ( PRESENT(mask_variant) ) THEN
827  mask_variant1 = mask_variant
828  ELSE
829  mask_variant1 = .false.
830  END IF
831 
832  IF ( PRESENT(dynamic) ) THEN
833  dynamic1 = dynamic
834  ELSE
835  dynamic1 = .false.
836  END IF
837 
838  IF ( PRESENT(tile_count) ) THEN
839  tile = tile_count
840  ELSE
841  tile = 1
842  END IF
843 
844  IF ( PRESENT(do_not_log) ) THEN
845  allow_log = .NOT.do_not_log
846  ELSE
847  allow_log = .true.
848  END IF
849 
850  ! Fatal error if range is present and its extent is not 2.
851  IF ( PRESENT(range) ) THEN
852  IF ( SIZE(range) .NE. 2 ) THEN
853  ! <ERROR STATUS="FATAL">extent of range should be 2</ERROR>
854  CALL error_mesg ('diag_manager_mod::register_static_field', 'extent of range should be 2', fatal)
855  END IF
856  END IF
857 
858  ! only writes log if do_diag_field_log is true in the namelist (default false)
859  ! if do_diag_field_log is true and do_not_log arg is present as well, it will only print if do_not_log = false
860  IF ( do_diag_field_log.AND.allow_log ) THEN
861  CALL log_diag_field_info (module_name, field_name, axes, &
862  & long_name, units, missing_value=missing_value, range=range, &
863  & dynamic=dynamic1)
864  END IF
865 
866  register_static_field_old = find_input_field(module_name, field_name, 1)
868  ! Negative index returned if this field was not found in the diag_table.
869  IF ( register_static_field_old < 0 ) RETURN
870 
871  ! Check that the axes are compatible with each other
872  domain_type = axis_compatible_check(axes,field_name)
873 
874  IF ( tile > 1 ) THEN
875  IF ( .NOT.input_fields(field)%register ) THEN
876  ! <ERROR STATUS="FATAL">
877  ! module/output_field <module_name>/<field_name> is not registered for tile_count = 1,
878  ! should not register for tile_count > 1
879  ! </ERROR>
880  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
881  & trim(field_name)//' is not registered for tile_count = 1, should not register for tile_count > 1',&
882  & fatal)
883  END IF
884 
885  CALL init_input_field(module_name, field_name, tile)
886  register_static_field_old = find_input_field(module_name, field_name, tile)
887  DO j = 1, input_fields(field)%num_output_fields
888  out_num = input_fields(field)%output_fields(j)
889  file_num = output_fields(out_num)%output_file
890  IF(input_fields(field)%local) THEN
891  CALL init_output_field(module_name, field_name,output_fields(out_num)%output_name,&
892  & files(file_num)%name,output_fields(out_num)%time_method, output_fields(out_num)%pack,&
893  & tile, input_fields(field)%local_coord)
894  ELSE
895  CALL init_output_field(module_name, field_name,output_fields(out_num)%output_name,&
896  & files(file_num)%name,output_fields(out_num)%time_method, output_fields(out_num)%pack, tile)
897  END IF
898  END DO
900  END IF
901 
902  ! Store information for this input field into input field table
903 
904  ! Set static to true, if called by register_diag_field this is
905  ! flipped back to false
906  input_fields(field)%static = .true.
907  ! check if the field is registered twice
908  IF ( input_fields(field)%register .AND. mpp_pe() == mpp_root_pe() ) THEN
909  ! <ERROR STATUS="FATAL">
910  ! module/output_field <module_name>/<field_name> ALREADY Registered, should
911  ! not register twice
912  ! </ERROR>
913  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
914  & trim(field_name)//' ALREADY registered, should not register twice', fatal)
915  END IF
916 
917  ! Verify that area and volume do not point to the same variable
918  IF ( PRESENT(volume).AND.PRESENT(area) ) THEN
919  IF ( area.EQ.volume ) THEN
920  CALL error_mesg ('diag_manager_mod::register_static_field_old', 'module/output_field '&
921  &//trim(module_name)//'/'// trim(field_name)//' AREA and VOLUME CANNOT be the same variable.&
922  & Contact the developers.',&
923  & fatal)
924  END IF
925  END IF
926 
927  ! Check for the existence of the area/volume field(s)
928  IF ( PRESENT(area) ) THEN
929  IF ( area < 0 ) THEN
930  CALL error_mesg ('diag_manager_mod::register_static_field_old', 'module/output_field '&
931  &//trim(module_name)//'/'// trim(field_name)//' AREA measures field NOT found in diag_table.&
932  & Contact the model liaison.n',&
933  & fatal)
934  END IF
935  END IF
936  IF ( PRESENT(volume) ) THEN
937  IF ( volume < 0 ) THEN
938  CALL error_mesg ('diag_manager_mod::register_static_field_old', 'module/output_field '&
939  &//trim(module_name)//'/'// trim(field_name)//' VOLUME measures field NOT found in diag_table&
940  & Contact the model liaison.',&
941  & fatal)
942  END IF
943  END IF
944 
945  ! Set flag that this field was registered
946  input_fields(field)%register = .true.
947  ! set flag for mask: does it change with time?
948  input_fields(field)%mask_variant = mask_variant1
949  ! Set flag for mask warning
950  input_fields(field)%issued_mask_ignore_warning = .false.
951 
952  ! Check for more OPTIONAL parameters.
953  IF ( PRESENT(long_name) ) THEN
954  input_fields(field)%long_name = trim(long_name)
955  ELSE
956  input_fields(field)%long_name = input_fields(field)%field_name
957  END IF
958 
959  IF ( PRESENT(standard_name) ) input_fields(field)%standard_name = standard_name
960 
961  IF ( PRESENT(units) ) THEN
962  input_fields(field)%units = trim(units)
963  ELSE
964  input_fields(field)%units = 'none'
965  END IF
966 
967  IF ( PRESENT(missing_value) ) THEN
968  input_fields(field)%missing_value = missing_value_use
969  input_fields(field)%missing_value_present = .true.
970  ELSE
971  input_fields(field)%missing_value_present = .false.
972  END IF
973 
974  IF ( PRESENT(range) ) THEN
975  SELECT TYPE (range)
976  TYPE IS (real(kind=r4_kind))
977  range_use = range
978  TYPE IS (real(kind=r8_kind))
979  range_use = real(range)
980  CLASS DEFAULT
981  CALL error_mesg ('diag_manager_mod::register_static_field',&
982  & 'The range is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
983  END SELECT
984  input_fields(field)%range = range_use
985  ! don't use the range if it is not a valid range
986  input_fields(field)%range_present = range_use(2) .gt. range_use(1)
987  ELSE
988  input_fields(field)%range = (/ 1., 0. /)
989  input_fields(field)%range_present = .false.
990  END IF
991 
992  IF ( PRESENT(interp_method) ) THEN
993  IF ( trim(interp_method) .NE. 'conserve_order1' .AND.&
994  & trim(interp_method) .NE. 'conserve_order2' .AND.&
995  & trim(interp_method) .NE. 'none' ) THEN
996  ! <ERROR STATUS="FATAL">
997  ! when registering module/output_field <module_name>/<field_name> then optional
998  ! argument interp_method = <interp_method>, but it should be "conserve_order1",
999  ! "conserve_order2", or "none"
1000  ! </ERROR>
1001  CALL error_mesg ('diag_manager_mod::register_diag_field',&
1002  & 'when registering module/output_field '//trim(module_name)//'/'//&
1003  & trim(field_name)//', the optional argument interp_method = '//trim(interp_method)//&
1004  & ', but it should be "conserve_order1", "conserve_order2", or "none"', fatal)
1005  END IF
1006  input_fields(field)%interp_method = trim(interp_method)
1007  ELSE
1008  input_fields(field)%interp_method = ''
1009  END IF
1010 
1011  ! Store the axis info
1012  num_axes = SIZE(axes(:)) ! num_axes should be <= 3.
1013  input_fields(field)%axes(1:num_axes) = axes
1014  input_fields(field)%num_axes = num_axes
1015 
1016  siz = 1
1017  DO j = 1, num_axes
1018  IF ( axes(j) .LE. 0 ) THEN
1019  ! <ERROR STATUS="FATAL">
1020  ! module/output_field <module_name>/<field_name> has non-positive axis_id
1021  ! </ERROR>
1022  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
1023  & trim(field_name)//' has non-positive axis_id', fatal)
1024  END IF
1025  siz(j) = get_axis_length(axes(j))
1026  END DO
1027 
1028  ! Default length for axes is 1
1029  DO j = 1, 3
1030  input_fields(field)%size(j) = siz(j)
1031  END DO
1032 
1033  local_siz = 1
1034  local_start = 1
1035  local_end= 1
1036  ! Need to loop through all output_fields associated and allocate their buffers
1037  DO j = 1, input_fields(field)%num_output_fields
1038  out_num = input_fields(field)%output_fields(j)
1039  ! Range is required when pack >= 4
1040  IF ( output_fields(out_num)%pack>=4 .AND. .NOT.input_fields(field)%range_present ) THEN
1041  IF(mpp_pe() .EQ. mpp_root_pe()) THEN
1042  ! <ERROR STATUS="FATAL">
1043  ! output_field <field_name> has pack >= 4, range is REQUIRED in register_diag_field
1044  ! </ERROR>
1045  CALL error_mesg ('diag_manager_mod::register_diag_field ', 'output_field '//trim(field_name)// &
1046  ' has pack >=4, range is REQUIRED in register_diag_field', fatal)
1047  END IF
1048  END IF
1049  ! reset the number of diurnal samples to 1 if the field is static (and, therefore,
1050  ! doesn't vary diurnally)
1051  IF ( .NOT.dynamic1 ) output_fields(out_num)%n_diurnal_samples = 1
1052 
1053  !Check that the domain associated with the inputted field matches
1054  !the domain associated output files to which it will be written.
1055  file_num = output_fields(out_num)%output_file
1056  if (domain_type .eq. diag_axis_2ddomain) then
1057  if (files(file_num)%use_domainUG) then
1058  call error_mesg("diag_manager_mod::register_static_field_old", &
1059  "Diagnostics living on a structured grid" &
1060  //" and an unstructured grid cannot exist" &
1061  //" in the same file (" &
1062  //trim(files(file_num)%name)//")", &
1063  fatal)
1064  elseif (.not. files(file_num)%use_domain2D) then
1065  files(file_num)%use_domain2D = .true.
1066  endif
1067  elseif (domain_type .eq. diag_axis_ugdomain) then
1068  if (files(file_num)%use_domain2D) then
1069  call error_mesg("diag_manager_mod::register_static_field_old", &
1070  "Diagnostics living on a structured grid" &
1071  //" and an unstructured grid cannot exist" &
1072  //" in the same file (" &
1073  //trim(files(file_num)%name)//")", &
1074  fatal)
1075  elseif (.not. files(file_num)%use_domainUG) then
1076  files(file_num)%use_domainUG = .true.
1077  endif
1078  endif
1079 
1080 
1081  ! if local_output (size of output_fields does NOT equal size of input_fields)
1082  IF ( output_fields(out_num)%reduced_k_range ) THEN
1083  CALL get_subfield_vert_size(axes, out_num)
1084 
1085 !----------
1086 !ug support
1087  !Send_data requires that the reduced k dimension be the 3rd dimension
1088  !of the buffer, so set it to be the correct size. If the diagnostic
1089  !is unstructured, set the second dimension of the buffer to be 1.
1090  if (domain_type .eq. diag_axis_ugdomain) then
1091  local_start(2) = output_fields(out_num)%output_grid%l_start_indx(2)
1092  local_end(2) = output_fields(out_num)%output_grid%l_end_indx(2)
1093  local_siz(2) = local_end(2) - local_start(2) + 1
1094  allocate(output_fields(out_num)%buffer(siz(1),local_siz(2),siz(3), &
1095  output_fields(out_num)%n_diurnal_samples))
1096  output_fields(out_num)%region_elements = siz(1)*local_siz(2)*siz(3)
1097  output_fields(out_num)%reduced_k_unstruct = .true.
1098  else
1099  local_start(3) = output_fields(out_num)%output_grid%l_start_indx(3)
1100  local_end(3) = output_fields(out_num)%output_grid%l_end_indx(3)
1101  local_siz(3) = local_end(3) - local_start(3) + 1
1102  allocate(output_fields(out_num)%buffer(siz(1),siz(2),local_siz(3), &
1103  output_fields(out_num)%n_diurnal_samples))
1104  output_fields(out_num)%region_elements = siz(1)*siz(2)*local_siz(3)
1105  output_fields(out_num)%reduced_k_unstruct = .false.
1106  endif
1107  output_fields(out_num)%total_elements = siz(1)*siz(2)*siz(3)
1108 !----------
1109 
1110  IF ( output_fields(out_num)%time_max ) THEN
1111  output_fields(out_num)%buffer = max_value
1112  ELSE IF ( output_fields(out_num)%time_min ) THEN
1113  output_fields(out_num)%buffer = min_value
1114  ELSE
1115  output_fields(out_num)%buffer = empty
1116  END IF
1117  ELSE IF ( output_fields(out_num)%local_output ) THEN
1118  IF ( SIZE(axes(:)) .LE. 1 ) THEN
1119  ! <ERROR STATUS="FATAL">axes of <field_name> must >= 2 for local output</ERROR>
1120  CALL error_mesg ('diag_manager_mod::register_diag_field', 'axes of '//trim(field_name)//&
1121  & ' must >= 2 for local output', fatal)
1122  END IF
1123  CALL get_subfield_size(axes, out_num)
1124  IF ( output_fields(out_num)%need_compute ) THEN
1125  DO k = 1, num_axes
1126  local_start(k) = output_fields(out_num)%output_grid%l_start_indx(k)
1127  local_end(k) = output_fields(out_num)%output_grid%l_end_indx(k)
1128  local_siz(k) = local_end(k) - local_start(k) +1
1129  END DO
1130  ALLOCATE(output_fields(out_num)%buffer(local_siz(1), local_siz(2), local_siz(3),&
1131  & output_fields(out_num)%n_diurnal_samples))
1132  IF(output_fields(out_num)%time_max) THEN
1133  output_fields(out_num)%buffer = max_value
1134  ELSE IF(output_fields(out_num)%time_min) THEN
1135  output_fields(out_num)%buffer = min_value
1136  ELSE
1137  output_fields(out_num)%buffer = empty
1138  END IF
1139  output_fields(out_num)%region_elements = local_siz(1)*local_siz(2)*local_siz(3)
1140  output_fields(out_num)%total_elements = siz(1)*siz(2)*siz(3)
1141  files(output_fields(out_num)%output_file)%local = .true.
1142  END IF
1143  ELSE ! the field is output globally
1144  ! size of output_fields equal size of input_fields
1145  ALLOCATE(output_fields(out_num)%buffer(siz(1), siz(2), siz(3),&
1146  & output_fields(out_num)%n_diurnal_samples))
1147  IF(output_fields(out_num)%time_max) THEN
1148  output_fields(out_num)%buffer = max_value
1149  ELSE IF(output_fields(out_num)%time_min) THEN
1150  output_fields(out_num)%buffer = min_value
1151  ELSE
1152  output_fields(out_num)%buffer = empty
1153  END IF
1154  output_fields(out_num)%total_elements = siz(1)*siz(2)*siz(3)
1155  END IF
1156 
1157  ! Reset to false in register_field if this is not static
1158  output_fields(out_num)%static = .true.
1159  ! check if time average is true for static field
1160  IF ( .NOT.dynamic1 .AND. output_fields(out_num)%time_ops ) THEN
1161  WRITE (msg,'(a,"/",a)') trim(module_name), trim(field_name)
1162  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
1163  ! <ERROR STATUS="WARNING">
1164  ! module/field <module_name>/<field_name> is STATIC.
1165  ! Cannot perform time operations average, maximum or
1166  ! minimum on static fields. Setting the time operation to 'NONE'
1167  ! for this field.
1168  ! </ERROR>
1169  CALL error_mesg ('diag_manager_mod::register_static_field_old',&
1170  & 'module/field '//trim(msg)//' is STATIC. Cannot perform time operations&
1171  & average, maximum, or minimum on static fields. Setting the time operation&
1172  & to "NONE" for this field.', warning)
1173  END IF
1174  output_fields(out_num)%time_ops = .false.
1175  output_fields(out_num)%time_average = .false.
1176  output_fields(out_num)%time_method = 'point'
1177  END IF
1178 
1179  ! assume that the number of axes of output_fields = that of input_fields
1180  ! this should be changed later to take into account time-of-day axis
1181  output_fields(out_num)%num_axes = input_fields(field)%num_axes
1182  ! Axes are copied from input_fields if output globally or from subaxes if output locally
1183  IF ( .NOT.output_fields(out_num)%local_output ) THEN
1184  output_fields(out_num)%axes(1:input_fields(field)%num_axes) =&
1185  & input_fields(field)%axes(1:input_fields(field)%num_axes)
1186  ELSE
1187  output_fields(out_num)%axes(1:input_fields(field)%num_axes) =&
1188  & output_fields(out_num)%output_grid%subaxes(1:input_fields(field)%num_axes)
1189  END IF
1190 
1191  ! if necessary, initialize the diurnal time axis and append its index in the
1192  ! output field axes array
1193  IF ( output_fields(out_num)%n_diurnal_samples > 1 ) THEN
1194  output_fields(out_num)%axes(output_fields(out_num)%num_axes+1) =&
1195  & init_diurnal_axis(output_fields(out_num)%n_diurnal_samples)
1196  output_fields(out_num)%num_axes = output_fields(out_num)%num_axes+1
1197  END IF
1198 
1199  IF ( output_fields(out_num)%reduced_k_range ) THEN
1200 !----------
1201 !ug support
1202  if (domain_type .eq. diag_axis_ugdomain) then
1203  output_fields(out_num)%axes(2) = output_fields(out_num)%output_grid%subaxes(2)
1204  else
1205  output_fields(out_num)%axes(3) = output_fields(out_num)%output_grid%subaxes(3)
1206  endif
1207 !----------
1208  END IF
1209 
1210  ! Initialize a time variable used in an error check
1211  output_fields(out_num)%Time_of_prev_field_data = time_zero
1212 
1213  ! Set the cell_measures attribute in the out file
1214  CALL init_field_cell_measures(output_fields(out_num), area=area, volume=volume, err_msg=msg)
1215  IF ( len_trim(msg).GT.0 ) THEN
1216  CALL error_mesg ('diag_manager_mod::register_static_field_old',&
1217  & trim(msg)//' for module/field '//trim(module_name)//'/'//trim(field_name),&
1218  & fatal)
1219  END IF
1220 
1221  ! Add the modeling_realm attribute
1222  IF ( PRESENT(realm) ) THEN
1223  CALL prepend_attribute(output_fields(out_num), 'modeling_realm', lowercase(trim(realm)))
1224  END IF
1225  END DO
1226 
1227  IF ( input_fields(field)%mask_variant ) THEN
1228  DO j = 1, input_fields(field)%num_output_fields
1229  out_num = input_fields(field)%output_fields(j)
1230  IF(output_fields(out_num)%time_average) THEN
1231 !----------
1232 !ug support
1233  !Send_data requires that the reduced k dimension be the 3rd dimension
1234  !of the counter array, so set it to be the correct size. If the diagnostic
1235  !is unstructured, set the second dimension of the counter array to be 1.
1236  if (output_fields(out_num)%reduced_k_range .and. &
1237  domain_type .eq. diag_axis_ugdomain) then
1238  allocate(output_fields(out_num)%counter(siz(1),local_siz(2),siz(3), &
1239  output_fields(out_num)%n_diurnal_samples))
1240  else
1241  allocate(output_fields(out_num)%counter(siz(1),siz(2),siz(3), &
1242  output_fields(out_num)%n_diurnal_samples))
1243  endif
1244 !----------
1245  output_fields(out_num)%counter = 0.0
1246  END IF
1247  END DO
1248  END IF
1249  END FUNCTION register_static_field_old
1250 
1251  !> @brief Return the diagnostic field ID of a given variable.
1252  !! @return get_diag_field_id will return the ID returned during the register_diag_field call.
1253  !! If the variable is not in the diag_table, then the value "DIAG_FIELD_NOT_FOUND" will be
1254  !! returned.
1255  INTEGER FUNCTION get_diag_field_id(module_name, field_name)
1256  CHARACTER(len=*), INTENT(in) :: module_name !< Module name that registered the variable
1257  CHARACTER(len=*), INTENT(in) :: field_name !< Variable name
1258 
1259  integer :: i !< For do loops
1260 
1261  get_diag_field_id = diag_field_not_found
1262  if (use_modern_diag) then
1263  get_diag_field_id = fms_diag_object%fms_get_diag_field_id_from_name(module_name, field_name)
1264  else
1265  ! find_input_field will return DIAG_FIELD_NOT_FOUND if the field is not
1266  ! included in the diag_table
1267  get_diag_field_id = find_input_field(module_name, field_name, tile_count=1)
1268  endif
1269  END FUNCTION get_diag_field_id
1270 
1271  !> @brief Finds the corresponding related output field and file for a given input field
1272  !! @return Logical get_related_field
1273  LOGICAL FUNCTION get_related_field(field, rel_field, out_field_id, out_file_id)
1274  INTEGER, INTENT(in) :: field !< input field ID to find the corresponding
1275  TYPE(output_field_type), INTENT(in) :: rel_field !< Output field that field must correspond to
1276  INTEGER, INTENT(out) :: out_field_id !< output_field index of related output field
1277  INTEGER, INTENT(out) :: out_file_id !< file index of the out_field_id output field
1278 
1279  INTEGER :: i, cm_ind, cm_file_num
1280  INTEGER :: rel_file
1281 
1282  ! Output file index of field to compare to
1283  rel_file = rel_field%output_file
1284 
1285  ! Default return values
1286  out_field_id = -1
1287  out_file_id = -1
1288  get_related_field = .false.
1289 
1290  ! First check if any fields are in the same file as rel_field
1291  DO i = 1, input_fields(field)%num_output_fields
1292  cm_ind = input_fields(field)%output_fields(i)
1293  cm_file_num = output_fields(cm_ind)%output_file
1294 
1295  IF ( cm_file_num.EQ.rel_file.AND.&
1296  & (( (output_fields(cm_ind)%time_ops.EQV.rel_field%time_ops) .AND.&
1297  & (output_fields(cm_ind)%next_output.EQ.rel_field%next_output) .AND.&
1298  & (output_fields(cm_ind)%last_output.EQ.rel_field%last_output) ).OR.&
1299  & (output_fields(cm_ind)%static.OR.rel_field%static) ) ) THEN
1300  get_related_field = .true.
1301  out_field_id = cm_ind
1302  out_file_id = cm_file_num
1303  EXIT
1304  END IF
1305  END DO
1306 
1307  ! Now look for the field in a different file
1308  IF ( .NOT.get_related_field ) THEN
1309  DO i = 1, input_fields(field)%num_output_fields
1310  cm_ind = input_fields(field)%output_fields(i)
1311  cm_file_num = output_fields(cm_ind)%output_file
1312 
1313  ! If time_method, freq, output_units, next_output, and last_output the same, or
1314  ! the output_field is static then valid for cell_measures
1315 !!$ For now, only static fields can be in an external file
1316 !!$ IF ( ( (files(cm_file_num)%output_freq.EQ.files(rel_file)%output_freq) .AND.&
1317 !!$ & (files(cm_file_num)%output_units.EQ.files(rel_file)%output_units) .AND.&
1318 !!$ & (output_fields(cm_ind)%time_ops.EQV.rel_field%time_ops) .AND.&
1319 !!$ & (output_fields(cm_ind)%next_output.EQ.rel_field%next_output) .AND.&
1320 !!$ & (output_fields(cm_ind)%last_output.EQ.rel_field%last_output) ).OR.&
1321 !!$ & ( output_fields(cm_ind)%static.OR.rel_field%static ) ) THEN
1322  IF ( output_fields(cm_ind)%static.OR.rel_field%static ) THEN
1323  get_related_field = .true.
1324  out_field_id = cm_ind
1325  out_file_id = cm_file_num
1326  EXIT
1327  END IF
1328  END DO
1329  END IF
1330  END FUNCTION get_related_field
1331 
1332  !> @brief If needed, add cell_measures and associated_file attribute to out field/file
1333  SUBROUTINE init_field_cell_measures(output_field, area, volume, err_msg)
1334  TYPE(output_field_type), INTENT(inout) :: output_field !< Output field that needs the cell_measures
1335  INTEGER, INTENT(in), OPTIONAL :: area !< Field ID for area
1336  INTEGER, INTENT(in), OPTIONAL :: volume !< Field ID for volume
1337  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1338 
1339  INTEGER :: cm_ind, cm_file_num, file_num
1340 
1341  IF ( PRESENT(err_msg) ) THEN
1342  err_msg = ''
1343  END IF
1344 
1345  ! Verify that area/volume are defined (.gt.0
1346  IF ( PRESENT(area) ) THEN
1347  IF ( area.LE.0 ) THEN
1348  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measure',&
1349  & 'AREA field not in diag_table for field '//trim(input_fields(output_field%input_field)%module_name)//&
1350  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1351  END IF
1352  END IF
1353 
1354  IF ( PRESENT(volume) ) THEN
1355  IF ( volume.LE.0 ) THEN
1356  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measure',&
1357  &'VOLUME field not in diag_table for field '//trim(input_fields(output_field%input_field)%module_name)//&
1358  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1359  END IF
1360  END IF
1361 
1362  ! Get the file number that the output_field will be written to
1363  file_num = output_field%output_file
1364 
1365  ! Take care of the cell_measures attribute
1366  IF ( PRESENT(area) ) THEN
1367  IF ( get_related_field(area, output_field, cm_ind, cm_file_num) ) THEN
1368  CALL prepend_attribute(output_field, 'cell_measures',&
1369  & 'area: '//trim(output_fields(cm_ind)%output_name))
1370  IF ( cm_file_num.NE.file_num ) THEN
1371  ! Not in the same file, set the global attribute associated_files
1372  CALL add_associated_files(file_num, cm_file_num, cm_ind)
1373  END IF
1374  ELSE
1375  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measures',&
1376  & 'AREA measures field "'//trim(input_fields(area)%module_name)//'/'//&
1377  & trim(input_fields(area)%field_name)//&
1378  & '" NOT in diag_table with correct output frequency for field '//&
1379  & trim(input_fields(output_field%input_field)%module_name)//&
1380  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1381  END IF
1382  END IF
1383 
1384 
1385  IF ( PRESENT(volume) ) THEN
1386  IF ( get_related_field(volume, output_field, cm_ind, cm_file_num) ) THEN
1387  CALL prepend_attribute(output_field, 'cell_measures',&
1388  & 'volume: '//trim(output_fields(cm_ind)%output_name))
1389  IF ( cm_file_num.NE.file_num ) THEN
1390  ! Not in the same file, set the global attribute associated_files
1391  CALL add_associated_files(file_num, cm_file_num, cm_ind)
1392  END IF
1393  ELSE
1394  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measures',&
1395  & 'VOLUME measures field "'//trim(input_fields(volume)%module_name)//'/'//&
1396  & trim(input_fields(volume)%field_name)//&
1397  & '" NOT in diag_table with correct output frequency for field '//&
1398  & trim(input_fields(output_field%input_field)%module_name)//&
1399  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1400  END IF
1401  END IF
1402  END SUBROUTINE init_field_cell_measures
1403 
1404  !> @brief Add to the associated files attribute
1405  !!
1406  !! @throw FATAL, "Length of asso_file_name is not long enough to hold the associated file name."
1407  !! The length of character array asso_file_name is not long enough to hold the full file name
1408  !! of the associated_file. Please contact the developer to increase the length of the variable.
1409  SUBROUTINE add_associated_files(file_num, cm_file_num, cm_ind)
1410  INTEGER, intent(in) :: file_num !< File number that needs the associated_files attribute
1411  INTEGER, intent(in) :: cm_file_num !< file number that contains the associated field
1412  INTEGER, intent(in) :: cm_ind !< index of the output_field in the associated file
1413 
1414  INTEGER :: year, month, day, hour, minute, second
1415  INTEGER :: n
1416  CHARACTER(len=25) :: date_prefix
1417  CHARACTER(len=256) :: asso_file_name
1418 
1419  ! Create the date_string
1420  IF ( prepend_date ) THEN
1421  CALL get_date(diag_init_time, year, month, day, hour, minute, second)
1422  WRITE (date_prefix, '(1I20.4, 2I2.2,".")') year, month, day
1423  date_prefix=adjustl(date_prefix)
1424  ELSE
1425  date_prefix=''
1426  END IF
1427 
1428  ! Get the base file name
1429  ! Verify asso_file_name is long enough to hold the file name,
1430  ! plus 17 for the additional '.ens_??.tile?.nc' (and a null character)
1431  IF ( len_trim(files(cm_file_num)%name)+17 > len(asso_file_name) ) THEN
1432  CALL error_mesg ('diag_manager_mod::add_associated_files',&
1433  & 'Length of asso_file_name is not long enough to hold the associated file name. '&
1434  & //'Contact the developer', fatal)
1435  ELSE
1436  asso_file_name = trim(files(cm_file_num)%name)
1437  END IF
1438 
1439  ! Add the ensemble number string into the file name
1440  ! As frepp does not have native support for multiple ensemble runs
1441  ! this will not be done. However, the code is left here for the time
1442  ! frepp does.
1443  !CALL get_instance_filename(TRIM(asso_file_name), asso_file_name)
1444 
1445  ! Append .nc suffix, if needed. Note that we no longer try to append cubic sphere tile
1446  ! number to the name of the associated file.
1447  n = max(len_trim(asso_file_name),3)
1448  if (asso_file_name(n-2:n).NE.'.nc') asso_file_name = trim(asso_file_name)//'.nc'
1449 
1450  ! Should look like :associated_files = " output_name: output_file_name " ;
1451  CALL prepend_attribute(files(file_num), 'associated_files',&
1452  & trim(output_fields(cm_ind)%output_name)//': '//&
1453  & trim(date_prefix)//trim(asso_file_name))
1454  END SUBROUTINE add_associated_files
1455 
1456  !> @return true if send is successful
1457  LOGICAL FUNCTION send_data_0d(diag_field_id, field, time, err_msg)
1458  INTEGER, INTENT(in) :: diag_field_id
1459  CLASS(*), INTENT(in) :: field
1460  TYPE(time_type), INTENT(in), OPTIONAL :: time
1461  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1462 
1463  CLASS(*), allocatable :: field_out(:, :, :) !< Local copy of field
1464 
1465  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1466  IF ( diag_field_id <= 0 ) THEN
1467  send_data_0d = .false.
1468  RETURN
1469  END IF
1470 
1471  ! First copy the data to a three d array with last element 1
1472  SELECT TYPE (field)
1473  TYPE IS (real(kind=r4_kind))
1474  allocate(real(r4_kind) :: field_out(1,1,1))
1475  select type(field_out)
1476  type is (real(r4_kind))
1477  field_out(1, 1, 1) = field
1478  class default
1479  call error_mesg('diag_manager_mod::send_data_0d', &
1480  & 'Error allocating field out as real(r4_kind)', fatal)
1481  end select
1482  TYPE IS (real(kind=r8_kind))
1483  allocate(real(r8_kind) :: field_out(1,1,1))
1484  select type(field_out)
1485  type is (real(r8_kind))
1486  field_out(1, 1, 1) = field
1487  class default
1488  call error_mesg('diag_manager_mod::send_data_0d', &
1489  & 'Error allocating field out as real(r8_kind)', fatal)
1490  end select
1491  CLASS DEFAULT
1492  CALL error_mesg ('diag_manager_mod::send_data_0d',&
1493  & 'The field is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1494  END SELECT
1495 
1496  send_data_0d = diag_send_data(diag_field_id, field_out, time, err_msg=err_msg)
1497  END FUNCTION send_data_0d
1498 
1499  !> @return true if send is successful
1500  LOGICAL FUNCTION send_data_1d(diag_field_id, field, time, is_in, mask, rmask, ie_in, weight, err_msg)
1501  INTEGER, INTENT(in) :: diag_field_id
1502  CLASS(*), DIMENSION(:), INTENT(in) :: field
1503  CLASS(*), INTENT(in), OPTIONAL :: weight
1504  CLASS(*), INTENT(in), DIMENSION(:), OPTIONAL :: rmask
1505  TYPE (time_type), INTENT(in), OPTIONAL :: time
1506  INTEGER, INTENT(in), OPTIONAL :: is_in, ie_in
1507  LOGICAL, INTENT(in), DIMENSION(:), OPTIONAL :: mask
1508  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1509 
1510  CLASS(*), ALLOCATABLE :: field_out(:,:,:) !< Local copy of field
1511  LOGICAL, DIMENSION(SIZE(field(:)), 1, 1) :: mask_out !< Local copy of mask
1512 
1513  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1514  IF ( diag_field_id <= 0 ) THEN
1515  send_data_1d = .false.
1516  RETURN
1517  END IF
1518 
1519  ! First copy the data to a three d array with last element 1
1520  ! type checking done in diag_send_data
1521  SELECT TYPE (field)
1522  TYPE IS (real(kind=r4_kind))
1523  allocate(real(r4_kind) :: field_out(SIZE(field),1,1))
1524  select type(field_out)
1525  type is (real(r4_kind))
1526  field_out(:, 1, 1) = field
1527  class default
1528  call error_mesg('diag_manager_mod::send_data_1d', &
1529  & 'Error allocating field out as real(r4_kind)', fatal)
1530  end select
1531  TYPE IS (real(kind=r8_kind))
1532  allocate(real(r8_kind) :: field_out(SIZE(field),1,1))
1533  select type(field_out)
1534  type is (real(r8_kind))
1535  field_out(:, 1, 1) = field
1536  class default
1537  call error_mesg('diag_manager_mod::send_data_1d', &
1538  & 'Error allocating field out as real(r8_kind)', fatal)
1539  end select
1540  CLASS DEFAULT
1541  CALL error_mesg ('diag_manager_mod::send_data_1d',&
1542  & 'The field is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1543  END SELECT
1544 
1545  ! Default values for mask
1546  IF ( PRESENT(mask) ) THEN
1547  mask_out(:, 1, 1) = mask
1548  ELSE
1549  mask_out = .true.
1550  END IF
1551 
1552  IF ( PRESENT(rmask) ) THEN
1553  SELECT TYPE (rmask)
1554  TYPE IS (real(kind=r4_kind))
1555  WHERE (rmask < 0.5_r4_kind) mask_out(:, 1, 1) = .false.
1556  TYPE IS (real(kind=r8_kind))
1557  WHERE (rmask < 0.5_r8_kind) mask_out(:, 1, 1) = .false.
1558  CLASS DEFAULT
1559  CALL error_mesg ('diag_manager_mod::send_data_1d',&
1560  & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1561  END SELECT
1562  END IF
1563 
1564  IF ( PRESENT(mask) .OR. PRESENT(rmask) ) THEN
1565  IF ( PRESENT(is_in) .OR. PRESENT(ie_in) ) THEN
1566  send_data_1d = diag_send_data(diag_field_id, field_out, time, is_in=is_in, js_in=1, ks_in=1,&
1567  & mask=mask_out, ie_in=ie_in, je_in=1, ke_in=1, weight=weight, err_msg=err_msg)
1568  ELSE
1569  send_data_1d = diag_send_data(diag_field_id, field_out, time, mask=mask_out,&
1570  & weight=weight, err_msg=err_msg)
1571  END IF
1572  ELSE
1573  IF ( PRESENT(is_in) .OR. PRESENT(ie_in) ) THEN
1574  send_data_1d = diag_send_data(diag_field_id, field_out, time, is_in=is_in, js_in=1, ks_in=1,&
1575  & ie_in=ie_in, je_in=1, ke_in=1, weight=weight, err_msg=err_msg)
1576  ELSE
1577  send_data_1d = diag_send_data(diag_field_id, field_out, time, weight=weight, err_msg=err_msg)
1578  END IF
1579  END IF
1580  END FUNCTION send_data_1d
1581 
1582  !> @return true if send is successful
1583  LOGICAL FUNCTION send_data_2d(diag_field_id, field, time, is_in, js_in, &
1584  & mask, rmask, ie_in, je_in, weight, err_msg)
1585  INTEGER, INTENT(in) :: diag_field_id
1586  CLASS(*), INTENT(in), DIMENSION(:,:) :: field
1587  CLASS(*), INTENT(in), OPTIONAL :: weight
1588  TYPE (time_type), INTENT(in), OPTIONAL :: time
1589  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ie_in, je_in
1590  LOGICAL, INTENT(in), DIMENSION(:,:), OPTIONAL :: mask
1591  CLASS(*), INTENT(in), DIMENSION(:,:),OPTIONAL :: rmask
1592  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1593 
1594  CLASS(*), ALLOCATABLE :: field_out(:,:,:) !< Local copy of field
1595  LOGICAL, DIMENSION(SIZE(field,1),SIZE(field,2),1) :: mask_out !< Local copy of mask
1596 
1597  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1598  IF ( diag_field_id <= 0 ) THEN
1599  send_data_2d = .false.
1600  RETURN
1601  END IF
1602 
1603  ! First copy the data to a three d array with last element 1
1604  SELECT TYPE (field)
1605  TYPE IS (real(kind=r4_kind))
1606  allocate(real(r4_kind) :: field_out(SIZE(field,1),SIZE(field,2),1))
1607  select type(field_out)
1608  type is (real(r4_kind))
1609  field_out(:, :, 1) = field
1610  class default
1611  call error_mesg('diag_manager_mod::send_data_2d', &
1612  & 'Error allocating field out as real(r4_kind)', fatal)
1613  end select
1614  TYPE IS (real(kind=r8_kind))
1615  allocate(real(r8_kind) :: field_out(SIZE(field,1),SIZE(field,2),1))
1616  select type(field_out)
1617  type is (real(r8_kind))
1618  field_out(:, :, 1) = field
1619  class default
1620  call error_mesg('diag_manager_mod::send_data_2d', &
1621  & 'Error allocating field out as real(r8_kind)', fatal)
1622  end select
1623  CLASS DEFAULT
1624  CALL error_mesg ('diag_manager_mod::send_data_2d',&
1625  & 'The field is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1626  END SELECT
1627 
1628  ! Default values for mask
1629  IF ( PRESENT(mask) ) THEN
1630  mask_out(:, :, 1) = mask
1631  ELSE
1632  mask_out = .true.
1633  END IF
1634 
1635  IF ( PRESENT(rmask) ) THEN
1636  SELECT TYPE (rmask)
1637  TYPE IS (real(kind=r4_kind))
1638  WHERE ( rmask < 0.5_r4_kind ) mask_out(:, :, 1) = .false.
1639  TYPE IS (real(kind=r8_kind))
1640  WHERE ( rmask < 0.5_r8_kind ) mask_out(:, :, 1) = .false.
1641  CLASS DEFAULT
1642  CALL error_mesg ('diag_manager_mod::send_data_2d',&
1643  & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1644  END SELECT
1645  END IF
1646 
1647  IF ( PRESENT(mask) .OR. PRESENT(rmask) ) THEN
1648  send_data_2d = diag_send_data(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=1,&
1649  & mask=mask_out, ie_in=ie_in, je_in=je_in, ke_in=1, weight=weight, err_msg=err_msg)
1650  ELSE
1651  send_data_2d = diag_send_data(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=1,&
1652  & ie_in=ie_in, je_in=je_in, ke_in=1, weight=weight, err_msg=err_msg)
1653  END IF
1654  END FUNCTION send_data_2d
1655 
1656  !> @return true if send is successful
1657  LOGICAL FUNCTION send_data_3d(diag_field_id, field, time, is_in, js_in, ks_in, &
1658  & mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
1659  INTEGER, INTENT(in) :: diag_field_id
1660  CLASS(*), DIMENSION(:,:,:), INTENT(in) :: field
1661  CLASS(*), INTENT(in), OPTIONAL :: weight
1662  TYPE (time_type), INTENT(in), OPTIONAL :: time
1663  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ks_in,ie_in,je_in, ke_in
1664  LOGICAL, DIMENSION(:,:,:), INTENT(in), OPTIONAL :: mask
1665  CLASS(*), DIMENSION(:,:,:), INTENT(in), OPTIONAL :: rmask
1666  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1667 
1668  if (present(mask) .and. present(rmask)) then
1669  send_data_3d = diag_send_data(diag_field_id, field, time=time, is_in=is_in, js_in=js_in, ks_in=ks_in, &
1670  mask=mask, rmask=rmask, ie_in=ie_in, je_in=je_in, ke_in=ke_in, weight=weight, &
1671  err_msg=err_msg)
1672  elseif (present(rmask)) then
1673  send_data_3d = diag_send_data(diag_field_id, field, time=time, is_in=is_in, js_in=js_in, ks_in=ks_in, &
1674  rmask=rmask, ie_in=ie_in, je_in=je_in, ke_in=ke_in, weight=weight, err_msg=err_msg)
1675  elseif (present(mask)) then
1676  send_data_3d = diag_send_data(diag_field_id, field, time=time, is_in=is_in, js_in=js_in, ks_in=ks_in, &
1677  mask=mask, ie_in=ie_in, je_in=je_in, ke_in=ke_in, weight=weight, err_msg=err_msg)
1678  else
1679  send_data_3d = diag_send_data(diag_field_id, field, time=time, is_in=is_in, js_in=js_in, ks_in=ks_in, &
1680  ie_in=ie_in, je_in=je_in, ke_in=ke_in, weight=weight, err_msg=err_msg)
1681  endif
1682  END FUNCTION send_data_3d
1683 
1684  !> @return true if send is successful
1685 !TODO documentation, seperate the old and new
1686  LOGICAL FUNCTION diag_send_data(diag_field_id, field, time, is_in, js_in, ks_in, &
1687  & mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
1688  INTEGER, INTENT(in) :: diag_field_id
1689  CLASS(*), DIMENSION(:,:,:), INTENT(in),TARGET,CONTIGUOUS :: field
1690  CLASS(*), INTENT(in), OPTIONAL :: weight
1691  TYPE (time_type), INTENT(in), OPTIONAL :: time
1692  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ks_in,ie_in,je_in, ke_in
1693  LOGICAL, DIMENSION(:,:,:), INTENT(in), OPTIONAL, contiguous, target :: mask
1694  CLASS(*), DIMENSION(:,:,:), INTENT(in), OPTIONAL, contiguous, target :: rmask
1695  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1696 
1697  REAL :: weight1
1698  REAL :: missvalue
1699  INTEGER :: pow_value
1700  INTEGER :: ksr, ker
1701  INTEGER :: i, out_num, file_num, n1, n2, n3, number_of_outputs, ii,f1,f2,f3,f4
1702  INTEGER :: freq, units, is, js, ks, ie, je, ke, i1, j1,k1, j, k
1703  INTEGER, DIMENSION(3) :: l_start !< local start indices on 3 axes for regional output
1704  INTEGER, DIMENSION(3) :: l_end !< local end indices on 3 axes for regional output
1705  INTEGER :: hi !< halo size in x direction
1706  INTEGER :: hj !< halo size in y direction
1707  INTEGER :: twohi !< halo size in x direction
1708  INTEGER :: twohj !< halo size in y direction
1709  INTEGER :: sample !< index along the diurnal time axis
1710  INTEGER :: day !< components of the current date
1711  INTEGER :: second !< components of the current date
1712  INTEGER :: tick !< components of the current date
1713  INTEGER :: status
1714  INTEGER :: numthreads
1715  INTEGER :: active_omp_level
1716 #if defined(_OPENMP)
1717  INTEGER :: omp_get_num_threads !< OMP function
1718  INTEGER :: omp_get_level !< OMP function
1719 #endif
1720  LOGICAL :: average, phys_window, need_compute
1721  LOGICAL :: reduced_k_range, local_output
1722  LOGICAL :: time_max, time_min, time_rms, time_sum
1723  LOGICAL :: missvalue_present
1724  LOGICAL, ALLOCATABLE, DIMENSION(:,:,:) :: oor_mask
1725  CHARACTER(len=256) :: err_msg_local
1726  CHARACTER(len=128) :: error_string, error_string1
1727 
1728  REAL, ALLOCATABLE, DIMENSION(:,:,:) :: field_out !< Local copy of field
1729  class(*), allocatable, dimension(:,:,:,:) :: field_remap !< 4d remapped array
1730  logical, allocatable, dimension(:,:,:,:) :: mask_remap !< 4d remapped array
1731  class(*), allocatable, dimension(:,:,:,:) :: rmask_remap !< 4d remapped array
1732  REAL(kind=r4_kind), POINTER, DIMENSION(:,:,:) :: rmask_ptr_r4 !< A pointer to r4 type of rmask
1733  REAL(kind=r8_kind), POINTER, DIMENSION(:,:,:) :: rmask_ptr_r8 !<A pointer to r8 type of rmask
1734 
1735  TYPE(fmsdiagoutfieldindex_type), ALLOCATABLE:: ofield_index_cfg !<Instance used in calling math functions.
1736  TYPE(fmsdiagoutfield_type), ALLOCATABLE:: ofield_cfg !<Instance used in calling math functions.
1737  LOGICAL :: mf_result !<Logical result returned from some math (buffer udate) functions.
1738 
1739  REAL :: rmask_threshold !< Holds the values 0.5_r4_kind or 0.5_r8_kind, or related threhold values
1740  !! needed to be passed to the math/buffer update functions.
1741  character(len=:), allocatable :: field_name !< Name of the field
1742 
1743  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1744  IF ( diag_field_id <= 0 ) THEN
1745  diag_send_data = .false.
1746  RETURN
1747  ELSE
1748  diag_send_data = .true.
1749  END IF
1750 
1751  IF ( PRESENT(err_msg) ) err_msg = ''
1752  IF ( .NOT.module_is_initialized ) THEN
1753  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'diag_manager NOT initialized', err_msg) ) RETURN
1754  END IF
1755  err_msg_local = ''
1756  ! The following lines are commented out as they have not been included in the code prior to now,
1757  ! and there are a lot of send_data calls before register_diag_field calls. A method to do this safely
1758  ! needs to be developed.
1759  !
1760  ! Set first_send_data_call to .FALSE. on first non-static field.
1761 !!$ IF ( .NOT.input_fields(diag_field_id)%static .AND. first_send_data_call ) THEN
1762 !!$ first_send_data_call = .FALSE.
1763 !!$ END IF
1764 
1765  ! First copy the data to a three d array
1766  ALLOCATE(field_out(SIZE(field,1),SIZE(field,2),SIZE(field,3)), stat=status)
1767  IF ( status .NE. 0 ) THEN
1768  WRITE (err_msg_local, fmt='("Unable to allocate field_out(",I5,",",I5,",",I5,"). (STAT: ",I5,")")')&
1769  & SIZE(field,1), SIZE(field,2), SIZE(field,3), status
1770  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) RETURN
1771  END IF
1772  SELECT TYPE (field)
1773  TYPE IS (real(kind=r4_kind))
1774  field_out = field
1775  TYPE IS (real(kind=r8_kind))
1776  field_out = real(field)
1777  CLASS DEFAULT
1778  CALL error_mesg ('diag_manager_mod::send_data_3d',&
1779  & 'The field is not one of the supported types (real(kind=4) or real(kind=8)). '//&
1780  & 'If using an integer, please set use_modern_diag=.t. in the diag_manager_nml.', fatal)
1781  END SELECT
1782  ! Split old and modern2023 here
1783  modern_if: iF (use_modern_diag) then
1784  field_name = fms_diag_object%fms_get_field_name_from_id(diag_field_id)
1785  call copy_3d_to_4d(field, field_remap, trim(field_name)//"'s data")
1786  if (present(rmask)) call copy_3d_to_4d(rmask, rmask_remap, trim(field_name)//"'s mask")
1787  if (present(mask)) then
1788  allocate(mask_remap(1:size(mask,1), 1:size(mask,2), 1:size(mask,3), 1))
1789  mask_remap(:,:,:,1) = mask
1790  endif
1791  diag_send_data = fms_diag_object%fms_diag_accept_data(diag_field_id, field_remap, mask_remap, rmask_remap, &
1792  time, is_in, js_in, ks_in, ie_in, je_in, ke_in, weight, &
1793  err_msg)
1794  deallocate (field_remap)
1795  if (allocated(mask_remap)) deallocate(mask_remap)
1796  if (allocated(rmask_remap)) deallocate(rmask_remap)
1797  elSE ! modern_if
1798  ! oor_mask is only used for checking out of range values.
1799  ALLOCATE(oor_mask(SIZE(field,1),SIZE(field,2),SIZE(field,3)), stat=status)
1800  IF ( status .NE. 0 ) THEN
1801  WRITE (err_msg_local, fmt='("Unable to allocate oor_mask(",I5,",",I5,",",I5,"). (STAT: ",I5,")")')&
1802  & SIZE(field,1), SIZE(field,2), SIZE(field,3), status
1803  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) RETURN
1804  END IF
1805 
1806  IF ( PRESENT(mask) ) THEN
1807  oor_mask = mask
1808  ELSE
1809  oor_mask = .true.
1810  END IF
1811 
1812  rmask_ptr_r4 => null()
1813  rmask_ptr_r8 => null()
1814  IF ( PRESENT(rmask) ) THEN
1815  SELECT TYPE (rmask)
1816  TYPE IS (real(kind=r4_kind))
1817  WHERE ( rmask < 0.5_r4_kind ) oor_mask = .false.
1818  rmask_threshold = 0.5_r4_kind
1819  rmask_ptr_r4 => rmask
1820  TYPE IS (real(kind=r8_kind))
1821  WHERE ( rmask < 0.5_r8_kind ) oor_mask = .false.
1822  rmask_threshold = 0.5_r8_kind
1823  rmask_ptr_r8 => rmask
1824  CLASS DEFAULT
1825  CALL error_mesg ('diag_manager_mod::send_data_3d',&
1826  & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1827  END SELECT
1828  END IF
1829 
1830  ! send_data works in either one or another of two modes.
1831  ! 1. Input field is a window (e.g. FMS physics)
1832  ! 2. Input field includes halo data
1833  ! It cannot handle a window of data that has halos.
1834  ! (A field with no windows or halos can be thought of as a special case of either mode.)
1835  ! The logic for indexing is quite different for these two modes, but is not clearly separated.
1836  ! If both the beggining and ending indices are present, then field is assumed to have halos.
1837  ! If only beggining indices are present, then field is assumed to be a window.
1838 
1839  ! There are a number of ways a user could mess up this logic, depending on the combination
1840  ! of presence/absence of is,ie,js,je. The checks below should catch improper combinations.
1841  IF ( PRESENT(ie_in) ) THEN
1842  IF ( .NOT.PRESENT(is_in) ) THEN
1843  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'ie_in present without is_in', err_msg) ) THEN
1844  DEALLOCATE(field_out)
1845  DEALLOCATE(oor_mask)
1846  RETURN
1847  END IF
1848  END IF
1849  IF ( PRESENT(js_in) .AND. .NOT.PRESENT(je_in) ) THEN
1850  IF ( fms_error_handler('diag_manager_modsend_data_3d',&
1851  & 'is_in and ie_in present, but js_in present without je_in', err_msg) ) THEN
1852  DEALLOCATE(field_out)
1853  DEALLOCATE(oor_mask)
1854  RETURN
1855  END IF
1856  END IF
1857  END IF
1858  IF ( PRESENT(je_in) ) THEN
1859  IF ( .NOT.PRESENT(js_in) ) THEN
1860  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'je_in present without js_in', err_msg) ) THEN
1861  DEALLOCATE(field_out)
1862  DEALLOCATE(oor_mask)
1863  RETURN
1864  END IF
1865  END IF
1866  IF ( PRESENT(is_in) .AND. .NOT.PRESENT(ie_in) ) THEN
1867  IF ( fms_error_handler('diag_manager_mod::send_data_3d',&
1868  & 'js_in and je_in present, but is_in present without ie_in', err_msg)) THEN
1869  DEALLOCATE(field_out)
1870  DEALLOCATE(oor_mask)
1871  RETURN
1872  END IF
1873  END IF
1874  END IF
1875 
1876  ! If is, js, or ks not present default them to 1
1877  is = 1
1878  js = 1
1879  ks = 1
1880  IF ( PRESENT(is_in) ) is = is_in
1881  IF ( PRESENT(js_in) ) js = js_in
1882  IF ( PRESENT(ks_in) ) ks = ks_in
1883  n1 = SIZE(field, 1)
1884  n2 = SIZE(field, 2)
1885  n3 = SIZE(field, 3)
1886  ie = is+n1-1
1887  je = js+n2-1
1888  ke = ks+n3-1
1889  IF ( PRESENT(ie_in) ) ie = ie_in
1890  IF ( PRESENT(je_in) ) je = je_in
1891  IF ( PRESENT(ke_in) ) ke = ke_in
1892  twohi = n1-(ie-is+1)
1893  IF ( mod(twohi,2) /= 0 ) THEN
1894  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'non-symmetric halos in first dimension', &
1895  & err_msg) ) THEN
1896  DEALLOCATE(field_out)
1897  DEALLOCATE(oor_mask)
1898  RETURN
1899  END IF
1900  END IF
1901  twohj = n2-(je-js+1)
1902  IF ( mod(twohj,2) /= 0 ) THEN
1903  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'non-symmetric halos in second dimension', &
1904  & err_msg) ) THEN
1905  DEALLOCATE(field_out)
1906  DEALLOCATE(oor_mask)
1907  RETURN
1908  END IF
1909  END IF
1910  hi = twohi/2
1911  hj = twohj/2
1912 
1913  ! The next line is necessary to ensure that is,ie,js,ie are relative to field(1:,1:)
1914  ! But this works only when there is no windowing.
1915  IF ( PRESENT(ie_in) .AND. PRESENT(je_in) ) THEN
1916  is=1+hi
1917  ie=n1-hi
1918  js=1+hj
1919  je=n2-hj
1920  END IF
1921 
1922  ! used for field, mask and rmask bounds
1923  f1=1+hi
1924  f2=n1-hi
1925  f3=1+hj
1926  f4=n2-hj
1927 
1928  ! weight is for time averaging where each time level may has a different weight
1929  IF ( PRESENT(weight) ) THEN
1930  SELECT TYPE (weight)
1931  TYPE IS (real(kind=r4_kind))
1932  weight1 = weight
1933  TYPE IS (real(kind=r8_kind))
1934  weight1 = real(weight)
1935  CLASS DEFAULT
1936  CALL error_mesg ('diag_manager_mod::send_data_3d',&
1937  & 'The weight is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
1938  END SELECT
1939  ELSE
1940  weight1 = 1.
1941  END IF
1942 
1943  ! Is there a missing_value?
1944  missvalue_present = input_fields(diag_field_id)%missing_value_present
1945  IF ( missvalue_present ) missvalue = input_fields(diag_field_id)%missing_value
1946 
1947  number_of_outputs = input_fields(diag_field_id)%num_output_fields
1948 !$OMP CRITICAL
1949  input_fields(diag_field_id)%numthreads = 1
1950  active_omp_level=0
1951 #if defined(_OPENMP)
1952  input_fields(diag_field_id)%numthreads = omp_get_num_threads()
1953  input_fields(diag_field_id)%active_omp_level = omp_get_level()
1954 #endif
1955  numthreads = input_fields(diag_field_id)%numthreads
1956  active_omp_level = input_fields(diag_field_id)%active_omp_level
1957 !$OMP END CRITICAL
1958 
1959  if(present(time)) input_fields(diag_field_id)%time = time
1960 
1961  ! Issue a warning if any value in field is outside the valid range
1962  IF ( input_fields(diag_field_id)%range_present ) THEN
1963  IF ( issue_oor_warnings .OR. oor_warnings_fatal ) THEN
1964  WRITE (error_string, '("[",ES14.5E3,",",ES14.5E3,"]")')&
1965  & input_fields(diag_field_id)%range(1:2)
1966  WRITE (error_string1, '("(Min: ",ES14.5E3,", Max: ",ES14.5E3, ")")')&
1967  & minval(field_out(f1:f2,f3:f4,ks:ke),mask=oor_mask(f1:f2,f3:f4,ks:ke)),&
1968  & maxval(field_out(f1:f2,f3:f4,ks:ke),mask=oor_mask(f1:f2,f3:f4,ks:ke))
1969  IF ( missvalue_present ) THEN
1970  IF ( any(oor_mask(f1:f2,f3:f4,ks:ke) .AND.&
1971  & ((field_out(f1:f2,f3:f4,ks:ke) < input_fields(diag_field_id)%range(1) .OR.&
1972  & field_out(f1:f2,f3:f4,ks:ke) > input_fields(diag_field_id)%range(2)).AND.&
1973  & field_out(f1:f2,f3:f4,ks:ke) .NE. missvalue)) ) THEN
1974  ! <ERROR STATUS="WARNING/FATAL">
1975  ! A value for <module_name> in field <field_name> (Min: <min_val>, Max: <max_val>)
1976  ! is outside the range [<lower_val>,<upper_val>] and not equal to the missing
1977  ! value.
1978  ! </ERROR>
1979  CALL error_mesg('diag_manager_mod::send_data_3d',&
1980  & 'A value for '//&
1981  &trim(input_fields(diag_field_id)%module_name)//' in field '//&
1982  &trim(input_fields(diag_field_id)%field_name)//' '&
1983  &//trim(error_string1)//&
1984  &' is outside the range '//trim(error_string)//',&
1985  & and not equal to the missing value.',&
1986  &oor_warning)
1987  END IF
1988  ELSE
1989  IF ( any(oor_mask(f1:f2,f3:f4,ks:ke) .AND.&
1990  & (field_out(f1:f2,f3:f4,ks:ke) < input_fields(diag_field_id)%range(1) .OR.&
1991  & field_out(f1:f2,f3:f4,ks:ke) > input_fields(diag_field_id)%range(2))) ) THEN
1992  ! <ERROR STATUS="WARNING/FATAL">
1993  ! A value for <module_name> in field <field_name> (Min: <min_val>, Max: <max_val>)
1994  ! is outside the range [<lower_val>,<upper_val>].
1995  ! </ERROR>
1996  CALL error_mesg('diag_manager_mod::send_data_3d',&
1997  & 'A value for '//&
1998  &trim(input_fields(diag_field_id)%module_name)//' in field '//&
1999  &trim(input_fields(diag_field_id)%field_name)//' '&
2000  &//trim(error_string1)//&
2001  &' is outside the range '//trim(error_string)//'.',&
2002  &oor_warning)
2003  END IF
2004  END IF
2005  END IF
2006  END IF
2007 
2008  ! Loop through each output field that depends on this input field
2009  num_out_fields: DO ii = 1, number_of_outputs
2010  ! Get index to an output field
2011  out_num = input_fields(diag_field_id)%output_fields(ii)
2012 
2013  ! is this field output on a local domain only?
2014  local_output = output_fields(out_num)%local_output
2015  ! if local_output, does the current PE take part in send_data?
2016  need_compute = output_fields(out_num)%need_compute
2017 
2018  reduced_k_range = output_fields(out_num)%reduced_k_range
2019 
2020  ! skip all PEs not participating in outputting this field
2021  IF ( local_output .AND. (.NOT.need_compute) ) cycle
2022 
2023  ! Get index to output file for this field
2024  file_num = output_fields(out_num)%output_file
2025  IF(file_num == max_files) cycle
2026  ! Output frequency and units for this file is
2027  freq = files(file_num)%output_freq
2028  units = files(file_num)%output_units
2029  ! Is this output field being time averaged?
2030  average = output_fields(out_num)%time_average
2031  ! Is this output field the rms?
2032  ! If so, then average is also .TRUE.
2033  time_rms = output_fields(out_num)%time_rms
2034  ! Power value for rms or pow(x) calculations
2035  pow_value = output_fields(out_num)%pow_value
2036  ! Looking for max and min value of this field over the sampling interval?
2037  time_max = output_fields(out_num)%time_max
2038  time_min = output_fields(out_num)%time_min
2039  ! Sum output over time interval
2040  time_sum = output_fields(out_num)%time_sum
2041  IF ( output_fields(out_num)%total_elements > SIZE(field_out(f1:f2,f3:f4,ks:ke)) ) THEN
2042  output_fields(out_num)%phys_window = .true.
2043  ELSE
2044  output_fields(out_num)%phys_window = .false.
2045  END IF
2046  phys_window = output_fields(out_num)%phys_window
2047  IF ( need_compute ) THEN
2048  l_start = output_fields(out_num)%output_grid%l_start_indx
2049  l_end = output_fields(out_num)%output_grid%l_end_indx
2050  END IF
2051 
2052  ! compute the diurnal index
2053  sample = 1
2054  IF ( PRESENT(time) ) THEN
2055  CALL get_time(time,second,day,tick) ! current date
2056  sample = floor( (second+real(tick)/get_ticks_per_second()) &
2057  & * output_fields(out_num)%n_diurnal_samples/seconds_per_day) + 1
2058  END IF
2059 
2060  ! Get the vertical layer start and end index.
2061  IF ( reduced_k_range ) THEN
2062 !----------
2063 !ug support
2064  if (output_fields(out_num)%reduced_k_unstruct) then
2065  js = output_fields(out_num)%output_grid%l_start_indx(2)
2066  je = output_fields(out_num)%output_grid%l_end_indx(2)
2067  endif
2068  l_start(3) = output_fields(out_num)%output_grid%l_start_indx(3)
2069  l_end(3) = output_fields(out_num)%output_grid%l_end_indx(3)
2070 !----------
2071  END IF
2072  ksr= l_start(3)
2073  ker= l_end(3)
2074 
2075  ! Initialize output time for fields output every time step
2076  IF ( freq == every_time .AND. .NOT.output_fields(out_num)%static ) THEN
2077  IF (output_fields(out_num)%next_output == output_fields(out_num)%last_output) THEN
2078  IF(PRESENT(time)) THEN
2079  output_fields(out_num)%next_output = time
2080  ELSE
2081  WRITE (error_string,'(a,"/",a)')&
2082  & trim(input_fields(diag_field_id)%module_name),&
2083  & trim(output_fields(out_num)%output_name)
2084  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2085  & ', time must be present when output frequency = EVERY_TIME', err_msg)) THEN
2086  DEALLOCATE(field_out)
2087  DEALLOCATE(oor_mask)
2088  RETURN
2089  END IF
2090  END IF
2091  END IF
2092  END IF
2093  IF ( .NOT.output_fields(out_num)%static .AND. .NOT.PRESENT(time) ) THEN
2094  WRITE (error_string,'(a,"/",a)')&
2095  & trim(input_fields(diag_field_id)%module_name), &
2096  & trim(output_fields(out_num)%output_name)
2097  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2098  & ', time must be present for nonstatic field', err_msg)) THEN
2099  DEALLOCATE(field_out)
2100  DEALLOCATE(oor_mask)
2101  RETURN
2102  END IF
2103  END IF
2104 
2105  ! Is it time to output for this field; CAREFUL ABOUT > vs >= HERE
2106  !--- The fields send out within openmp parallel region will be written out in
2107  !--- diag_send_complete.
2108  IF ( (numthreads == 1) .AND. (active_omp_level.LE.1) ) then
2109  IF ( .NOT.output_fields(out_num)%static .AND. freq /= end_of_run ) THEN
2110  IF ( time > output_fields(out_num)%next_output ) THEN
2111  ! A non-static field that has skipped a time level is an error
2112  IF ( time > output_fields(out_num)%next_next_output .AND. freq > 0 ) THEN
2113  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
2114  WRITE (error_string,'(a,"/",a)')&
2115  & trim(input_fields(diag_field_id)%module_name), &
2116  & trim(output_fields(out_num)%output_name)
2117  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//&
2118  & trim(error_string)//' is skipped one time level in output data', err_msg)) THEN
2119  DEALLOCATE(field_out)
2120  DEALLOCATE(oor_mask)
2121  RETURN
2122  END IF
2123  END IF
2124  END IF
2125 
2126  status = writing_field(out_num, .false., error_string, time)
2127  IF(status == -1) THEN
2128  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
2129  IF(fms_error_handler('diag_manager_mod::send_data_3d','module/output_field '//trim(error_string)&
2130  & //', write EMPTY buffer', err_msg)) THEN
2131  DEALLOCATE(field_out)
2132  DEALLOCATE(oor_mask)
2133  RETURN
2134  END IF
2135  END IF
2136  END IF
2137  END IF !time > output_fields(out_num)%next_output
2138  END IF !.not.output_fields(out_num)%static .and. freq /= END_OF_RUN
2139  ! Finished output of previously buffered data, now deal with buffering new data
2140  END IF
2141 
2142  if (present(time)) then
2143  !! If the last_output is greater than the time passed in, it is not time to start averaging the data
2144  if (output_fields(out_num)%last_output > time) cycle
2145  endif
2146 
2147  IF ( .NOT.output_fields(out_num)%static .AND. .NOT.need_compute .AND. debug_diag_manager ) THEN
2148  CALL check_bounds_are_exact_dynamic(out_num, diag_field_id, time, err_msg=err_msg_local)
2149  IF ( err_msg_local /= '' ) THEN
2150  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2151  DEALLOCATE(field_out)
2152  DEALLOCATE(oor_mask)
2153  RETURN
2154  END IF
2155  END IF
2156  END IF
2157 
2158  IF (use_refactored_send) THEN
2159  ALLOCATE( ofield_index_cfg )
2160  CALL ofield_index_cfg%initialize( is, js, ks, ie, je, ke, &
2161  & hi, hj, f1, f2, f3, f4)
2162 
2163  ALLOCATE( ofield_cfg )
2164  CALL ofield_cfg%initialize( input_fields(diag_field_id), output_fields(out_num), PRESENT(mask), freq)
2165 
2166  IF ( average ) THEN
2167  !!TODO (Future work): the copy that is filed_out should not be necessary
2168  mf_result = fieldbuff_update(ofield_cfg, ofield_index_cfg, field_out, sample, &
2169  & output_fields(out_num)%buffer, output_fields(out_num)%counter ,output_fields(out_num)%buff_bounds,&
2170  & output_fields(out_num)%count_0d(sample), output_fields(out_num)%num_elements(sample), &
2171  & mask, weight1 ,missvalue, &
2172  & input_fields(diag_field_id)%numthreads, input_fields(diag_field_id)%active_omp_level,&
2173  & input_fields(diag_field_id)%issued_mask_ignore_warning, &
2174  & l_start, l_end, err_msg, err_msg_local )
2175  IF (mf_result .eqv. .false.) THEN
2176  DEALLOCATE(ofield_index_cfg)
2177  DEALLOCATE(ofield_cfg)
2178  DEALLOCATE(field_out)
2179  DEALLOCATE(oor_mask)
2180  RETURN
2181  END IF
2182  ELSE !!NOT AVERAGE
2183  mf_result = fieldbuff_copy_fieldvals(ofield_cfg, ofield_index_cfg, field_out, sample, &
2184  & output_fields(out_num)%buffer, output_fields(out_num)%buff_bounds , &
2185  & output_fields(out_num)%count_0d(sample), &
2186  & mask, missvalue, l_start, l_end, err_msg, err_msg_local)
2187  IF (mf_result .eqv. .false.) THEN
2188  DEALLOCATE(ofield_index_cfg)
2189  DEALLOCATE(ofield_cfg)
2190  DEALLOCATE(field_out)
2191  DEALLOCATE(oor_mask)
2192  RETURN
2193  END IF
2194  END IF
2195 
2196  IF ( output_fields(out_num)%static .AND. .NOT.need_compute .AND. debug_diag_manager ) THEN
2197  CALL check_bounds_are_exact_static(out_num, diag_field_id, err_msg=err_msg_local)
2198  IF ( err_msg_local /= '' ) THEN
2199  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg)) THEN
2200  DEALLOCATE(field_out)
2201  DEALLOCATE(oor_mask)
2202  RETURN
2203  END IF
2204  END IF
2205  END IF
2206 
2207  !!TODO: (Discusssion) One of the calls below will not compile depending
2208  !! on the value of REAL. This is to the mixed use of REAL, R4, R8 and CLASS(*)
2209  !! in send_data_3d. A copy of rmask can be made to avoid but it would be wasteful.
2210  !! The option used for now is that the original code to copy missing values is
2211  !! is used at the end of this procedure.
2212  !IF ( PRESENT(rmask) .AND. missvalue_present ) THEN
2213  ! SELECT TYPE (rmask)
2214  ! TYPE IS (real(kind=r4_kind))
2215  ! call fieldbuff_copy_missvals(ofield_cfg, ofield_index_cfg, &
2216  ! & output_fields(out_num)%buffer, sample, &
2217  ! & l_start, l_end, rmask_ptr_r4, rmask_threshold, missvalue)
2218  ! TYPE IS (real(kind=r8_kind))
2219  ! call fieldbuff_copy_missvals(ofield_cfg, ofield_index_cfg, &
2220  ! & output_fields(out_num)%buffer, sample, &
2221  ! & l_start, l_end, rmask_ptr_r8, rmask_threshold, missvalue)
2222  ! CLASS DEFAULT
2223  ! CALL error_mesg ('diag_manager_mod::send_data_3d',&
2224  ! & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', FATAL)
2225  ! END SELECT
2226  !END IF
2227 
2228  IF(ALLOCATED(ofield_index_cfg)) THEN
2229  DEALLOCATE(ofield_index_cfg)
2230  ENDIF
2231  IF(ALLOCATED(ofield_cfg)) THEN
2232  DEALLOCATE(ofield_cfg)
2233  ENDIF
2234 
2235  ELSE !! END USE_REFACTORED_SEND; Don''t use CYCLE option.
2236 
2237  ! Take care of submitted field data
2238  IF ( average ) THEN
2239  IF ( input_fields(diag_field_id)%mask_variant ) THEN
2240  IF ( need_compute ) THEN
2241  WRITE (error_string,'(a,"/",a)') &
2242  & trim(input_fields(diag_field_id)%module_name), &
2243  & trim(output_fields(out_num)%output_name)
2244  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2245  & ', regional output NOT supported with mask_variant', err_msg)) THEN
2246  DEALLOCATE(field_out)
2247  DEALLOCATE(oor_mask)
2248  RETURN
2249  END IF
2250  END IF
2251 
2252  ! Should reduced_k_range data be supported with the mask_variant option ?????
2253  ! If not, error message should be produced and the reduced_k_range loop below eliminated
2254  IF ( PRESENT(mask) ) THEN
2255  IF ( missvalue_present ) THEN
2256  IF ( debug_diag_manager ) THEN
2257  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2258  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2259  IF ( err_msg_local /= '' ) THEN
2260  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2261  DEALLOCATE(field_out)
2262  DEALLOCATE(oor_mask)
2263  RETURN
2264  END IF
2265  END IF
2266  END IF
2267  IF( numthreads>1 .AND. phys_window ) then
2268  IF ( reduced_k_range ) THEN
2269  DO k= ksr, ker
2270  k1= k - ksr + 1
2271  DO j=js, je
2272  DO i=is, ie
2273  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2274  IF ( pow_value /= 1 ) THEN
2275  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2276  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2277  & (field_out(i-is+1+hi, j-js+1+hj, k) * weight1)**(pow_value)
2278  ELSE
2279  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2280  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2281  & field_out(i-is+1+hi, j-js+1+hj, k) * weight1
2282  END IF
2283  output_fields(out_num)%counter(i-hi,j-hj,k1,sample) =&
2284  & output_fields(out_num)%counter(i-hi,j-hj,k1,sample) + weight1
2285  END IF
2286  END DO
2287  END DO
2288  END DO
2289  ELSE
2290  DO k=ks, ke
2291  DO j=js, je
2292  DO i=is, ie
2293  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2294  IF ( pow_value /= 1 ) THEN
2295  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2296  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2297  & (field_out(i-is+1+hi,j-js+1+hj,k)*weight1)**(pow_value)
2298  ELSE
2299  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2300  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2301  & field_out(i-is+1+hi,j-js+1+hj,k)*weight1
2302  END IF
2303  output_fields(out_num)%counter(i-hi,j-hj,k,sample) =&
2304  &output_fields(out_num)%counter(i-hi,j-hj,k,sample) + weight1
2305  END IF
2306  END DO
2307  END DO
2308  END DO
2309  END IF
2310  ELSE
2311 !$OMP CRITICAL
2312  IF ( reduced_k_range ) THEN
2313  DO k= ksr, ker
2314  k1= k - ksr + 1
2315  DO j=js, je
2316  DO i=is, ie
2317  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2318  IF ( pow_value /= 1 ) THEN
2319  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2320  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2321  & (field_out(i-is+1+hi, j-js+1+hj, k) * weight1)**(pow_value)
2322  ELSE
2323  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2324  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2325  & field_out(i-is+1+hi, j-js+1+hj, k) * weight1
2326  END IF
2327  output_fields(out_num)%counter(i-hi,j-hj,k1,sample) =&
2328  & output_fields(out_num)%counter(i-hi,j-hj,k1,sample) + weight1
2329  END IF
2330  END DO
2331  END DO
2332  END DO
2333  ELSE
2334  DO k=ks, ke
2335  DO j=js, je
2336  DO i=is, ie
2337  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2338  IF ( pow_value /= 1 ) THEN
2339  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2340  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2341  & (field_out(i-is+1+hi,j-js+1+hj,k)*weight1)**(pow_value)
2342  ELSE
2343  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2344  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2345  & field_out(i-is+1+hi,j-js+1+hj,k)*weight1
2346  END IF
2347  output_fields(out_num)%counter(i-hi,j-hj,k,sample) =&
2348  &output_fields(out_num)%counter(i-hi,j-hj,k,sample) + weight1
2349  END IF
2350  END DO
2351  END DO
2352  END DO
2353  END IF
2354 !$OMP END CRITICAL
2355  END IF
2356  ELSE
2357  WRITE (error_string,'(a,"/",a)')&
2358  & trim(input_fields(diag_field_id)%module_name), &
2359  & trim(output_fields(out_num)%output_name)
2360  IF(fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2361  & ', variable mask but no missing value defined', err_msg)) THEN
2362  DEALLOCATE(field_out)
2363  DEALLOCATE(oor_mask)
2364  RETURN
2365  END IF
2366  END IF
2367  ELSE ! no mask present
2368  WRITE (error_string,'(a,"/",a)')&
2369  & trim(input_fields(diag_field_id)%module_name), &
2370  & trim(output_fields(out_num)%output_name)
2371  IF(fms_error_handler('diag_manager_mod::send_data_3d','module/output_field '//trim(error_string)//&
2372  & ', variable mask but no mask given', err_msg)) THEN
2373  DEALLOCATE(field_out)
2374  DEALLOCATE(oor_mask)
2375  RETURN
2376  END IF
2377  END IF
2378  ELSE ! mask_variant=false
2379  IF ( PRESENT(mask) ) THEN
2380  IF ( missvalue_present ) THEN
2381  IF ( need_compute ) THEN
2382  IF (numthreads>1 .AND. phys_window) then
2383  DO k = l_start(3), l_end(3)
2384  k1 = k-l_start(3)+1
2385  DO j = js, je
2386  DO i = is, ie
2387  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2388  & j <= l_end(2)+hj ) THEN
2389  i1 = i-l_start(1)-hi+1
2390  j1= j-l_start(2)-hj+1
2391  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2392  IF ( pow_value /= 1 ) THEN
2393  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2394  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2395  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2396  ELSE
2397  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2398  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2399  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2400  END IF
2401  ELSE
2402  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2403  END IF
2404  END IF
2405  END DO
2406  END DO
2407  END DO
2408  ELSE
2409 !$OMP CRITICAL
2410  DO k = l_start(3), l_end(3)
2411  k1 = k-l_start(3)+1
2412  DO j = js, je
2413  DO i = is, ie
2414  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2415  & j <= l_end(2)+hj ) THEN
2416  i1 = i-l_start(1)-hi+1
2417  j1= j-l_start(2)-hj+1
2418  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2419  IF ( pow_value /= 1 ) THEN
2420  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2421  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2422  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2423  ELSE
2424  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2425  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2426  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2427  END IF
2428  ELSE
2429  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2430  END IF
2431  END IF
2432  END DO
2433  END DO
2434  END DO
2435 !$OMP END CRITICAL
2436  ENDIF
2437 !$OMP CRITICAL
2438  DO j = js, je
2439  DO i = is, ie
2440  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2441  & j <= l_end(2)+hj ) THEN
2442  output_fields(out_num)%num_elements(sample) = &
2443  output_fields(out_num)%num_elements(sample) + l_end(3) - l_start(3) + 1
2444  END IF
2445  END DO
2446  END DO
2447 !$OMP END CRITICAL
2448  ELSE IF ( reduced_k_range ) THEN
2449  IF (numthreads>1 .AND. phys_window) then
2450  DO k=ksr, ker
2451  k1 = k - ksr + 1
2452  DO j=js, je
2453  DO i=is, ie
2454  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2455  IF ( pow_value /= 1 ) THEN
2456  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2457  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2458  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2459  ELSE
2460  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2461  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2462  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2463  END IF
2464  ELSE
2465  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
2466  END IF
2467  END DO
2468  END DO
2469  END DO
2470  ELSE
2471 !$OMP CRITICAL
2472  DO k=ksr, ker
2473  k1 = k - ksr + 1
2474  DO j=js, je
2475  DO i=is, ie
2476  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2477  IF ( pow_value /= 1 ) THEN
2478  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2479  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2480  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2481  ELSE
2482  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2483  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2484  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2485  END IF
2486  ELSE
2487  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
2488  END IF
2489  END DO
2490  END DO
2491  END DO
2492 !$OMP END CRITICAL
2493  END IF
2494  ELSE
2495  IF ( debug_diag_manager ) THEN
2496  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2497  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2498  IF ( err_msg_local /= '' ) THEN
2499  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2500  DEALLOCATE(field_out)
2501  DEALLOCATE(oor_mask)
2502  RETURN
2503  END IF
2504  END IF
2505  END IF
2506  IF (numthreads>1 .AND. phys_window) then
2507  DO k=ks, ke
2508  DO j=js, je
2509  DO i=is, ie
2510  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2511  IF ( pow_value /= 1 ) THEN
2512  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2513  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2514  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2515  ELSE
2516  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2517  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2518  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2519  END IF
2520  ELSE
2521  output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
2522  END IF
2523  END DO
2524  END DO
2525  END DO
2526  ELSE
2527 !$OMP CRITICAL
2528  DO k=ks, ke
2529  DO j=js, je
2530  DO i=is, ie
2531  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2532  IF ( pow_value /= 1 ) THEN
2533  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2534  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2535  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2536  ELSE
2537  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2538  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2539  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2540  END IF
2541  ELSE
2542  output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
2543  END IF
2544  END DO
2545  END DO
2546  END DO
2547 !$OMP END CRITICAL
2548  END IF
2549  END IF
2550 !$OMP CRITICAL
2551  IF ( need_compute .AND. .NOT.phys_window ) THEN
2552  IF ( any(mask(l_start(1)+hi:l_end(1)+hi,l_start(2)+hj:l_end(2)+hj,l_start(3):l_end(3))) ) &
2553  & output_fields(out_num)%count_0d(sample) =&
2554  & output_fields(out_num)%count_0d(sample) + weight1
2555  ELSE
2556  IF ( any(mask(f1:f2,f3:f4,ks:ke)) ) output_fields(out_num)%count_0d(sample) =&
2557  & output_fields(out_num)%count_0d(sample)+weight1
2558  END IF
2559 !$OMP END CRITICAL
2560 
2561  ELSE ! missing value NOT present
2562  IF ( (.NOT.all(mask(f1:f2,f3:f4,ks:ke)) .AND. mpp_pe() .EQ. mpp_root_pe()).AND.&
2563  & .NOT.input_fields(diag_field_id)%issued_mask_ignore_warning ) THEN
2564  ! <ERROR STATUS="WARNING">
2565  ! Mask will be ignored since missing values were not specified for field <field_name>
2566  ! in module <module_name>
2567  ! </ERROR>
2568  CALL error_mesg('diag_manager_mod::send_data_3d',&
2569  & 'Mask will be ignored since missing values were not specified for field '//&
2570  & trim(input_fields(diag_field_id)%field_name)//' in module '//&
2571  & trim(input_fields(diag_field_id)%module_name), warning)
2572  input_fields(diag_field_id)%issued_mask_ignore_warning = .true.
2573  END IF
2574  IF ( need_compute ) THEN
2575  IF (numthreads>1 .AND. phys_window) then
2576  DO j = js, je
2577  DO i = is, ie
2578  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2579  & j <= l_end(2)+hj ) THEN
2580  i1 = i-l_start(1)-hi+1
2581  j1 = j-l_start(2)-hj+1
2582  IF ( pow_value /= 1 ) THEN
2583  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2584  & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2585  & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2586  ELSE
2587  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2588  & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2589  & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2590  END IF
2591  END IF
2592  END DO
2593  END DO
2594  ELSE
2595 !$OMP CRITICAL
2596  DO j = js, je
2597  DO i = is, ie
2598  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2599  & j <= l_end(2)+hj ) THEN
2600  i1 = i-l_start(1)-hi+1
2601  j1 = j-l_start(2)-hj+1
2602  IF ( pow_value /= 1 ) THEN
2603  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2604  & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2605  & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2606  ELSE
2607  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2608  & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2609  & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2610  END IF
2611  END IF
2612  END DO
2613  END DO
2614 !$OMP END CRITICAL
2615  END IF
2616 !$OMP CRITICAL
2617  DO j = js, je
2618  DO i = is, ie
2619  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2620  & j <= l_end(2)+hj ) THEN
2621  output_fields(out_num)%num_elements(sample)=&
2622  & output_fields(out_num)%num_elements(sample)+l_end(3)-l_start(3)+1
2623 
2624  END IF
2625  END DO
2626  END DO
2627 !$OMP END CRITICAL
2628  ELSE IF ( reduced_k_range ) THEN
2629  IF (numthreads>1 .AND. phys_window) then
2630  ksr= l_start(3)
2631  ker= l_end(3)
2632  IF ( pow_value /= 1 ) THEN
2633  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2634  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2635  & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2636  ELSE
2637  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2638  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2639  & field_out(f1:f2,f3:f4,ksr:ker)*weight1
2640  END IF
2641  ELSE
2642 !$OMP CRITICAL
2643  ksr= l_start(3)
2644  ker= l_end(3)
2645  IF ( pow_value /= 1 ) THEN
2646  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2647  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2648  & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2649  ELSE
2650  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2651  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2652  & field_out(f1:f2,f3:f4,ksr:ker)*weight1
2653  END IF
2654 !$OMP END CRITICAL
2655  END IF
2656  ELSE
2657  IF ( debug_diag_manager ) THEN
2658  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2659  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2660  IF ( err_msg_local /= '') THEN
2661  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2662  DEALLOCATE(field_out)
2663  DEALLOCATE(oor_mask)
2664  RETURN
2665  END IF
2666  END IF
2667  END IF
2668  IF (numthreads>1 .AND. phys_window) then
2669  IF ( pow_value /= 1 ) THEN
2670  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2671  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2672  & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
2673  ELSE
2674  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2675  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2676  & field_out(f1:f2,f3:f4,ks:ke)*weight1
2677  END IF
2678  ELSE
2679 !$OMP CRITICAL
2680  IF ( pow_value /= 1 ) THEN
2681  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2682  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2683  & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
2684  ELSE
2685  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2686  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2687  & field_out(f1:f2,f3:f4,ks:ke)*weight1
2688  END IF
2689 !$OMP END CRITICAL
2690  END IF
2691  END IF
2692 !$OMP CRITICAL
2693  IF ( .NOT.phys_window ) output_fields(out_num)%count_0d(sample) =&
2694  & output_fields(out_num)%count_0d(sample) + weight1
2695 !$OMP END CRITICAL
2696  END IF
2697  ELSE ! mask NOT present
2698  IF ( missvalue_present ) THEN
2699  IF ( need_compute ) THEN
2700  if( numthreads>1 .AND. phys_window ) then
2701  DO k = l_start(3), l_end(3)
2702  k1 = k - l_start(3) + 1
2703  DO j = js, je
2704  DO i = is, ie
2705  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2706  & j <= l_end(2)+hj) THEN
2707  i1 = i-l_start(1)-hi+1
2708  j1= j-l_start(2)-hj+1
2709  IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2710  IF ( pow_value /= 1 ) THEN
2711  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2712  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2713  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2714  ELSE
2715  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2716  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2717  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2718  END IF
2719  ELSE
2720  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2721  END IF
2722  END IF
2723  END DO
2724  END DO
2725  END DO
2726  ELSE
2727 !$OMP CRITICAL
2728  DO k = l_start(3), l_end(3)
2729  k1 = k - l_start(3) + 1
2730  DO j = js, je
2731  DO i = is, ie
2732  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2733  & j <= l_end(2)+hj) THEN
2734  i1 = i-l_start(1)-hi+1
2735  j1= j-l_start(2)-hj+1
2736  IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2737  IF ( pow_value /= 1 ) THEN
2738  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2739  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2740  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2741  ELSE
2742  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2743  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2744  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2745  END IF
2746  ELSE
2747  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2748  END IF
2749  END IF
2750  END DO
2751  END DO
2752  END DO
2753 !$OMP END CRITICAL
2754  END IF
2755 !$OMP CRITICAL
2756  DO j = js, je
2757  DO i = is, ie
2758  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2759  & j <= l_end(2)+hj) THEN
2760  output_fields(out_num)%num_elements(sample) =&
2761  & output_fields(out_num)%num_elements(sample) + l_end(3) - l_start(3) + 1
2762  END IF
2763  END DO
2764  END DO
2765  IF ( .NOT.phys_window ) THEN
2766  outer0: DO k = l_start(3), l_end(3)
2767  DO j=l_start(2)+hj, l_end(2)+hj
2768  DO i=l_start(1)+hi, l_end(1)+hi
2769  IF ( field_out(i,j,k) /= missvalue ) THEN
2770  output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample)&
2771  & + weight1
2772  EXIT outer0
2773  END IF
2774  END DO
2775  END DO
2776  END DO outer0
2777  END IF
2778 !$OMP END CRITICAL
2779  ELSE IF ( reduced_k_range ) THEN
2780  if( numthreads>1 .AND. phys_window ) then
2781  ksr= l_start(3)
2782  ker= l_end(3)
2783  DO k = ksr, ker
2784  k1 = k - ksr + 1
2785  DO j=js, je
2786  DO i=is, ie
2787  IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2788  IF ( pow_value /= 1 ) THEN
2789  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2790  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2791  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2792  ELSE
2793  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2794  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2795  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2796  END IF
2797  ELSE
2798  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) = missvalue
2799  END IF
2800  END DO
2801  END DO
2802  END DO
2803  else
2804 !$OMP CRITICAL
2805  ksr= l_start(3)
2806  ker= l_end(3)
2807  DO k = ksr, ker
2808  k1 = k - ksr + 1
2809  DO j=js, je
2810  DO i=is, ie
2811  IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2812  IF ( pow_value /= 1 ) THEN
2813  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2814  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2815  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2816  ELSE
2817  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2818  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2819  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2820  END IF
2821  ELSE
2822  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) = missvalue
2823  END IF
2824  END DO
2825  END DO
2826  END DO
2827 !$OMP END CRITICAL
2828  END IF
2829 !$OMP CRITICAL
2830  outer3: DO k = ksr, ker
2831  k1=k-ksr+1
2832  DO j=f3, f4
2833  DO i=f1, f2
2834  IF ( field_out(i,j,k) /= missvalue ) THEN
2835  output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) &
2836  & + weight1
2837  EXIT outer3
2838  END IF
2839  END DO
2840  END DO
2841  END DO outer3
2842 !$OMP END CRITICAL
2843  ELSE
2844  IF ( debug_diag_manager ) THEN
2845  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2846  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2847  IF ( err_msg_local /= '' ) THEN
2848  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2849  DEALLOCATE(field_out)
2850  DEALLOCATE(oor_mask)
2851  RETURN
2852  END IF
2853  END IF
2854  END IF
2855  IF( numthreads > 1 .AND. phys_window ) then
2856  DO k=ks, ke
2857  DO j=js, je
2858  DO i=is, ie
2859  IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2860  IF ( pow_value /= 1 ) THEN
2861  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2862  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2863  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2864  ELSE
2865  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2866  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2867  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2868  END IF
2869  ELSE
2870  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) = missvalue
2871  END IF
2872  END DO
2873  END DO
2874  END DO
2875  ELSE
2876 !$OMP CRITICAL
2877  DO k=ks, ke
2878  DO j=js, je
2879  DO i=is, ie
2880  IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2881  IF ( pow_value /= 1 ) THEN
2882  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2883  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2884  & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2885  ELSE
2886  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2887  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2888  & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
2889  END IF
2890  ELSE
2891  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) = missvalue
2892  END IF
2893  END DO
2894  END DO
2895  END DO
2896 !$OMP END CRITICAL
2897  END IF
2898 !$OMP CRITICAL
2899  outer1: DO k=ks, ke
2900  DO j=f3, f4
2901  DO i=f1, f2
2902  IF ( field_out(i,j,k) /= missvalue ) THEN
2903  output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) &
2904  & + weight1
2905  EXIT outer1
2906  END IF
2907  END DO
2908  END DO
2909  END DO outer1
2910 !$OMP END CRITICAL
2911  END IF
2912  ELSE ! no missing value defined, No mask
2913  IF ( need_compute ) THEN
2914  IF( numthreads > 1 .AND. phys_window ) then
2915  DO j = js, je
2916  DO i = is, ie
2917  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2918  & j <= l_end(2)+hj ) THEN
2919  i1 = i-l_start(1)-hi+1
2920  j1= j-l_start(2)-hj+1
2921  IF ( pow_value /= 1 ) THEN
2922  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2923  & output_fields(out_num)%buffer(i1,j1,:,sample) +&
2924  & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2925  ELSE
2926  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2927  & output_fields(out_num)%buffer(i1,j1,:,sample) +&
2928  & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2929  END IF
2930  END IF
2931  END DO
2932  END DO
2933  ELSE
2934 !$OMP CRITICAL
2935  DO j = js, je
2936  DO i = is, ie
2937  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2938  & j <= l_end(2)+hj ) THEN
2939  i1 = i-l_start(1)-hi+1
2940  j1= j-l_start(2)-hj+1
2941  IF ( pow_value /= 1 ) THEN
2942  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2943  & output_fields(out_num)%buffer(i1,j1,:,sample) +&
2944  & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2945  ELSE
2946  output_fields(out_num)%buffer(i1,j1,:,sample)= &
2947  & output_fields(out_num)%buffer(i1,j1,:,sample) +&
2948  & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2949  END IF
2950  END IF
2951  END DO
2952  END DO
2953 !$OMP END CRITICAL
2954  END IF
2955 
2956 !$OMP CRITICAL
2957  DO j = js, je
2958  DO i = is, ie
2959  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
2960  & j <= l_end(2)+hj ) THEN
2961  output_fields(out_num)%num_elements(sample) =&
2962  & output_fields(out_num)%num_elements(sample)+l_end(3)-l_start(3)+1
2963  END IF
2964  END DO
2965  END DO
2966 !$OMP END CRITICAL
2967  ! Accumulate time average
2968  ELSE IF ( reduced_k_range ) THEN
2969  ksr= l_start(3)
2970  ker= l_end(3)
2971  IF( numthreads > 1 .AND. phys_window ) then
2972  IF ( pow_value /= 1 ) THEN
2973  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2974  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2975  & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2976  ELSE
2977  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2978  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2979  & field_out(f1:f2,f3:f4,ksr:ker)*weight1
2980  END IF
2981  ELSE
2982 !$OMP CRITICAL
2983  IF ( pow_value /= 1 ) THEN
2984  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2985  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2986  & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2987  ELSE
2988  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2989  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2990  & field_out(f1:f2,f3:f4,ksr:ker)*weight1
2991  END IF
2992 !$OMP END CRITICAL
2993  END IF
2994  ELSE
2995  IF ( debug_diag_manager ) THEN
2996  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2997  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2998  IF ( err_msg_local /= '' ) THEN
2999  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3000  DEALLOCATE(field_out)
3001  DEALLOCATE(oor_mask)
3002  RETURN
3003  END IF
3004  END IF
3005  END IF
3006  IF( numthreads > 1 .AND. phys_window ) then
3007  IF ( pow_value /= 1 ) THEN
3008  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
3009  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
3010  & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
3011  ELSE
3012  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
3013  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
3014  & field_out(f1:f2,f3:f4,ks:ke)*weight1
3015  END IF
3016  ELSE
3017 !$OMP CRITICAL
3018  IF ( pow_value /= 1 ) THEN
3019  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
3020  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
3021  & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
3022  ELSE
3023  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
3024  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
3025  & field_out(f1:f2,f3:f4,ks:ke)*weight1
3026  END IF
3027 !$OMP END CRITICAL
3028  END IF
3029  END IF
3030 !$OMP CRITICAL
3031  IF ( .NOT.phys_window ) output_fields(out_num)%count_0d(sample) =&
3032  & output_fields(out_num)%count_0d(sample) + weight1
3033 !$OMP END CRITICAL
3034  END IF
3035  END IF ! if mask present
3036  END IF !if mask_variant
3037 !$OMP CRITICAL
3038  IF ( .NOT.need_compute .AND. .NOT.reduced_k_range )&
3039  & output_fields(out_num)%num_elements(sample) =&
3040  & output_fields(out_num)%num_elements(sample) + (ie-is+1)*(je-js+1)*(ke-ks+1)
3041  IF ( reduced_k_range ) &
3042  & output_fields(out_num)%num_elements(sample) = output_fields(out_num)%num_elements(sample) +&
3043  & (ie-is+1)*(je-js+1)*(ker-ksr+1)
3044 !$OMP END CRITICAL
3045  ! Add processing for Max and Min
3046  ELSE IF ( time_max ) THEN
3047  IF ( PRESENT(mask) ) THEN
3048  IF ( need_compute ) THEN
3049  DO k = l_start(3), l_end(3)
3050  k1 = k - l_start(3) + 1
3051  DO j = js, je
3052  DO i = is, ie
3053  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
3054  & j <= l_end(2)+hj ) THEN
3055  i1 = i-l_start(1)-hi+1
3056  j1= j-l_start(2)-hj+1
3057  IF ( mask(i-is+1+hi,j-js+1+hj,k) .AND. field_out(i-is+1+hi,j-js+1+hj,k)>&
3058  & output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
3059  output_fields(out_num)%buffer(i1,j1,k1,sample) = field_out(i-is+1+hi,j-js+1+hj,k)
3060  END IF
3061  END IF
3062  END DO
3063  END DO
3064  END DO
3065  ! Maximum time value with masking
3066  ELSE IF ( reduced_k_range ) THEN
3067  ksr = l_start(3)
3068  ker = l_end(3)
3069  WHERE ( mask(f1:f2,f3:f4,ksr:ker) .AND. field_out(f1:f2,f3:f4,ksr:ker) >&
3070  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) )&
3071  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field_out(f1:f2,f3:f4,ksr:ker)
3072  ELSE
3073  IF ( debug_diag_manager ) THEN
3074  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3075  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3076  IF ( err_msg_local /= '' ) THEN
3077  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3078  DEALLOCATE(field_out)
3079  DEALLOCATE(oor_mask)
3080  RETURN
3081  END IF
3082  END IF
3083  END IF
3084  WHERE ( mask(f1:f2,f3:f4,ks:ke) .AND. field_out(f1:f2,f3:f4,ks:ke)>&
3085  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) )&
3086  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field_out(f1:f2,f3:f4,ks:ke)
3087  END IF
3088  ELSE
3089  IF ( need_compute ) THEN
3090  DO k = l_start(3), l_end(3)
3091  k1 = k - l_start(3) + 1
3092  DO j = js, je
3093  DO i = is, ie
3094  IF(l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
3095  & j <= l_end(2)+hj ) THEN
3096  i1 = i-l_start(1)-hi+1
3097  j1 = j-l_start(2)-hj+1
3098  IF ( field_out(i-is+1+hi,j-js+1+hj,k)>output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
3099  output_fields(out_num)%buffer(i1,j1,k1,sample) = field_out(i-is+1+hi,j-js+1+hj,k)
3100  END IF
3101  END IF
3102  END DO
3103  END DO
3104  END DO
3105  ! Maximum time value
3106  ELSE IF ( reduced_k_range ) THEN
3107  ksr = l_start(3)
3108  ker = l_end(3)
3109  WHERE ( field_out(f1:f2,f3:f4,ksr:ker) >&
3110  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) ) &
3111  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field_out(f1:f2,f3:f4,ksr:ker)
3112  ELSE
3113  IF ( debug_diag_manager ) THEN
3114  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3115  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3116  IF ( err_msg_local /= '' ) THEN
3117  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3118  DEALLOCATE(field_out)
3119  DEALLOCATE(oor_mask)
3120  RETURN
3121  END IF
3122  END IF
3123  END IF
3124  WHERE ( field_out(f1:f2,f3:f4,ks:ke) >&
3125  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) ) &
3126  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field_out(f1:f2,f3:f4,ks:ke)
3127  END IF
3128  END IF
3129  output_fields(out_num)%count_0d(sample) = 1
3130  ELSE IF ( time_min ) THEN
3131  IF ( PRESENT(mask) ) THEN
3132  IF ( need_compute ) THEN
3133  DO k = l_start(3), l_end(3)
3134  k1 = k - l_start(3) + 1
3135  DO j = js, je
3136  DO i = is, ie
3137  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
3138  & j <= l_end(2)+hj ) THEN
3139  i1 = i-l_start(1)-hi+1
3140  j1 = j-l_start(2)-hj+1
3141  IF ( mask(i-is+1+hi,j-js+1+hj,k) .AND. field_out(i-is+1+hi,j-js+1+hj,k) <&
3142  & output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
3143  output_fields(out_num)%buffer(i1,j1,k1,sample) = field_out(i-is+1+hi,j-js+1+hj,k)
3144  END IF
3145  END IF
3146  END DO
3147  END DO
3148  END DO
3149  ! Minimum time value with masking
3150  ELSE IF ( reduced_k_range ) THEN
3151  ksr= l_start(3)
3152  ker= l_end(3)
3153  WHERE ( mask(f1:f2,f3:f4,ksr:ker) .AND. field_out(f1:f2,f3:f4,ksr:ker) <&
3154  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) ) &
3155  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field_out(f1:f2,f3:f4,ksr:ker)
3156  ELSE
3157  IF ( debug_diag_manager ) THEN
3158  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3159  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3160  IF ( err_msg_local /= '' ) THEN
3161  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3162  DEALLOCATE(field_out)
3163  DEALLOCATE(oor_mask)
3164  RETURN
3165  END IF
3166  END IF
3167  END IF
3168  WHERE ( mask(f1:f2,f3:f4,ks:ke) .AND. field_out(f1:f2,f3:f4,ks:ke) <&
3169  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) ) &
3170  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field_out(f1:f2,f3:f4,ks:ke)
3171  END IF
3172  ELSE
3173  IF ( need_compute ) THEN
3174  DO k = l_start(3), l_end(3)
3175  k1 = k - l_start(3) + 1
3176  DO j = js, je
3177  DO i = is, ie
3178  IF ( l_start(1)+hi <=i.AND.i<=l_end(1)+hi.AND.l_start(2)+hj<=j.AND.j<=l_end(2)+hj) THEN
3179  i1 = i-l_start(1)-hi+1
3180  j1= j-l_start(2)-hj+1
3181  IF ( field_out(i-is+1+hi,j-js+1+hj,k) <&
3182  & output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
3183  output_fields(out_num)%buffer(i1,j1,k1,sample) = field_out(i-is+1+hi,j-js+1+hj,k)
3184  END IF
3185  END IF
3186  END DO
3187  END DO
3188  END DO
3189  ! Minimum time value
3190  ELSE IF ( reduced_k_range ) THEN
3191  ksr= l_start(3)
3192  ker= l_end(3)
3193  WHERE ( field_out(f1:f2,f3:f4,ksr:ker) <&
3194  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) ) &
3195  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field_out(f1:f2,f3:f4,ksr:ker)
3196  ELSE
3197  IF ( debug_diag_manager ) THEN
3198  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3199  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3200  IF ( err_msg_local /= '' ) THEN
3201  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3202  DEALLOCATE(field_out)
3203  DEALLOCATE(oor_mask)
3204  RETURN
3205  END IF
3206  END IF
3207  END IF
3208  WHERE ( field_out(f1:f2,f3:f4,ks:ke) <&
3209  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) )&
3210  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field_out(f1:f2,f3:f4,ks:ke)
3211  END IF
3212  END IF
3213  output_fields(out_num)%count_0d(sample) = 1
3214  ELSE IF ( time_sum ) THEN
3215  IF ( PRESENT(mask) ) THEN
3216  IF ( need_compute ) THEN
3217  DO k = l_start(3), l_end(3)
3218  k1 = k - l_start(3) + 1
3219  DO j = js, je
3220  DO i = is, ie
3221  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
3222  & j <= l_end(2)+hj ) THEN
3223  i1 = i-l_start(1)-hi+1
3224  j1 = j-l_start(2)-hj+1
3225  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
3226  output_fields(out_num)%buffer(i1,j1,k1,sample) = &
3227  output_fields(out_num)%buffer(i1,j1,k1,sample) + &
3228  field_out(i-is+1+hi,j-js+1+hj,k)
3229  END IF
3230  END IF
3231  END DO
3232  END DO
3233  END DO
3234  ! Minimum time value with masking
3235  ELSE IF ( reduced_k_range ) THEN
3236  ksr= l_start(3)
3237  ker= l_end(3)
3238  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = &
3239  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
3240  & field_out(f1:f2,f3:f4,ksr:ker)
3241  ELSE
3242  IF ( debug_diag_manager ) THEN
3243  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3244  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3245  IF ( err_msg_local /= '' ) THEN
3246  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3247  DEALLOCATE(field_out)
3248  DEALLOCATE(oor_mask)
3249  RETURN
3250  END IF
3251  END IF
3252  END IF
3253  WHERE ( mask(f1:f2,f3:f4,ks:ke) ) &
3254  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = &
3255  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) + &
3256  & field_out(f1:f2,f3:f4,ks:ke)
3257  END IF
3258  ELSE
3259  IF ( need_compute ) THEN
3260  DO k = l_start(3), l_end(3)
3261  k1 = k - l_start(3) + 1
3262  DO j = js, je
3263  DO i = is, ie
3264  IF ( l_start(1)+hi <=i.AND.i<=l_end(1)+hi.AND.l_start(2)+hj<=j.AND.j<=l_end(2)+hj) THEN
3265  i1 = i-l_start(1)-hi+1
3266  j1= j-l_start(2)-hj+1
3267  output_fields(out_num)%buffer(i1,j1,k1,sample) = &
3268  & output_fields(out_num)%buffer(i1,j1,k1,sample) + &
3269  & field_out(i-is+1+hi,j-js+1+hj,k)
3270  END IF
3271  END DO
3272  END DO
3273  END DO
3274  ELSE IF ( reduced_k_range ) THEN
3275  ksr= l_start(3)
3276  ker= l_end(3)
3277  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = &
3278  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
3279  & field_out(f1:f2,f3:f4,ksr:ker)
3280  ELSE
3281  IF ( debug_diag_manager ) THEN
3282  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3283  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3284  IF ( err_msg_local /= '' ) THEN
3285  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3286  DEALLOCATE(field_out)
3287  DEALLOCATE(oor_mask)
3288  RETURN
3289  END IF
3290  END IF
3291  END IF
3292  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = &
3293  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) + &
3294  & field_out(f1:f2,f3:f4,ks:ke)
3295  END IF
3296  END IF
3297  output_fields(out_num)%count_0d(sample) = 1
3298  ELSE ! ( not average, not min, not max, not sum )
3299  output_fields(out_num)%count_0d(sample) = 1
3300  IF ( need_compute ) THEN
3301  DO j = js, je
3302  DO i = is, ie
3303  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. j <= l_end(2)+hj) THEN
3304  i1 = i-l_start(1)-hi+1
3305  j1 = j-l_start(2)-hj+1
3306  output_fields(out_num)%buffer(i1,j1,:,sample) =&
3307  & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))
3308  END IF
3309  END DO
3310  END DO
3311  ! instantaneous output
3312  ELSE IF ( reduced_k_range ) THEN
3313  ksr = l_start(3)
3314  ker = l_end(3)
3315  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field_out(f1:f2,f3:f4,ksr:ker)
3316  ELSE
3317  IF ( debug_diag_manager ) THEN
3318  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3319  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3320  IF ( err_msg_local /= '' ) THEN
3321  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3322  DEALLOCATE(field_out)
3323  DEALLOCATE(oor_mask)
3324  RETURN
3325  END IF
3326  END IF
3327  END IF
3328  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field_out(f1:f2,f3:f4,ks:ke)
3329  END IF
3330 
3331  IF ( PRESENT(mask) .AND. missvalue_present ) THEN
3332  IF ( need_compute ) THEN
3333  DO k = l_start(3), l_end(3)
3334  k1 = k - l_start(3) + 1
3335  DO j = js, je
3336  DO i = is, ie
3337  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
3338  & j <= l_end(2)+hj ) THEN
3339  i1 = i-l_start(1)-hi+1
3340  j1 = j-l_start(2)-hj+1
3341  IF ( .NOT.mask(i-is+1+hi,j-js+1+hj,k) )&
3342  & output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
3343  END IF
3344  END DO
3345  END DO
3346  END DO
3347  ELSE IF ( reduced_k_range ) THEN
3348  ksr= l_start(3)
3349  ker= l_end(3)
3350  DO k=ksr, ker
3351  k1= k - ksr + 1
3352  DO j=js, je
3353  DO i=is, ie
3354  IF ( .NOT.mask(i-is+1+hi,j-js+1+hj,k) ) &
3355  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
3356  END DO
3357  END DO
3358  END DO
3359  ELSE
3360  DO k=ks, ke
3361  DO j=js, je
3362  DO i=is, ie
3363  IF ( .NOT.mask(i-is+1+hi,j-js+1+hj,k) )&
3364  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
3365  END DO
3366  END DO
3367  END DO
3368  END IF
3369  END IF
3370  END IF !average
3371 
3372  IF ( output_fields(out_num)%static .AND. .NOT.need_compute .AND. debug_diag_manager ) THEN
3373  CALL check_bounds_are_exact_static(out_num, diag_field_id, err_msg=err_msg_local)
3374  IF ( err_msg_local /= '' ) THEN
3375  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg)) THEN
3376  DEALLOCATE(field_out)
3377  DEALLOCATE(oor_mask)
3378  RETURN
3379  END IF
3380  END IF
3381  END IF
3382 
3383  END IF !! END OF IS_USE_REFACTORED SEND
3384 
3385  ! If rmask and missing value present, then insert missing value
3386  IF ( PRESENT(rmask) .AND. missvalue_present ) THEN
3387  IF ( need_compute ) THEN
3388  SELECT TYPE (rmask)
3389  TYPE IS (real(kind=r4_kind))
3390  DO k = l_start(3), l_end(3)
3391  k1 = k - l_start(3) + 1
3392  DO j = js, je
3393  DO i = is, ie
3394  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND.&
3395  & j <= l_end(2)+hj ) THEN
3396  i1 = i-l_start(1)-hi+1
3397  j1 = j-l_start(2)-hj+1
3398  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5_r4_kind ) &
3399  & output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
3400  END IF
3401  END DO
3402  END DO
3403  END DO
3404  TYPE IS (real(kind=r8_kind))
3405  DO k = l_start(3), l_end(3)
3406  k1 = k - l_start(3) + 1
3407  DO j = js, je
3408  DO i = is, ie
3409  IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND.&
3410  & j <= l_end(2)+hj ) THEN
3411  i1 = i-l_start(1)-hi+1
3412  j1 = j-l_start(2)-hj+1
3413  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5_r8_kind ) &
3414  & output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
3415  END IF
3416  END DO
3417  END DO
3418  END DO
3419  CLASS DEFAULT
3420  CALL error_mesg ('diag_manager_mod::send_data_3d',&
3421  & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
3422  END SELECT
3423  ELSE IF ( reduced_k_range ) THEN
3424  ksr= l_start(3)
3425  ker= l_end(3)
3426  SELECT TYPE (rmask)
3427  TYPE IS (real(kind=r4_kind))
3428  DO k= ksr, ker
3429  k1 = k - ksr + 1
3430  DO j=js, je
3431  DO i=is, ie
3432  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5_r4_kind ) &
3433  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
3434  END DO
3435  END DO
3436  END DO
3437  TYPE IS (real(kind=r8_kind))
3438  DO k= ksr, ker
3439  k1 = k - ksr + 1
3440  DO j=js, je
3441  DO i=is, ie
3442  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5_r8_kind ) &
3443  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
3444  END DO
3445  END DO
3446  END DO
3447  CLASS DEFAULT
3448  CALL error_mesg ('diag_manager_mod::send_data_3d',&
3449  & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
3450  END SELECT
3451  ELSE
3452  SELECT TYPE (rmask)
3453  TYPE IS (real(kind=r4_kind))
3454  DO k=ks, ke
3455  DO j=js, je
3456  DO i=is, ie
3457  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5_r4_kind ) &
3458  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
3459  END DO
3460  END DO
3461  END DO
3462  TYPE IS (real(kind=r8_kind))
3463  DO k=ks, ke
3464  DO j=js, je
3465  DO i=is, ie
3466  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5_r8_kind ) &
3467  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
3468  END DO
3469  END DO
3470  END DO
3471  CLASS DEFAULT
3472  CALL error_mesg ('diag_manager_mod::send_data_3d',&
3473  & 'The rmask is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
3474  END SELECT
3475  END IF
3476  END IF
3477 
3478  END DO num_out_fields
3479 
3480  DEALLOCATE(field_out)
3481  DEALLOCATE(oor_mask)
3482  endIF modern_if
3483  END FUNCTION diag_send_data
3484 
3485  !> @brief Updates the output buffer for a field based on the data for current time step
3486  !! @return true if send is successful
3487  LOGICAL FUNCTION send_data_4d(diag_field_id, field, time, is_in, js_in, ks_in, &
3488  & mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
3489  INTEGER, INTENT(in) :: diag_field_id !< The field id returned from the register call
3490  CLASS(*), INTENT(in) :: field(:,:,:,:) !< The field data for the current time step
3491  CLASS(*), INTENT(in), OPTIONAL :: weight !< The weight to multiply the data by when averaging
3492  TYPE (time_type), INTENT(in), OPTIONAL :: time !< The current model time
3493  INTEGER, INTENT(in), OPTIONAL :: is_in !< Starting i index of the data
3494  INTEGER, INTENT(in), OPTIONAL :: js_in !< Starting j index of the data
3495  INTEGER, INTENT(in), OPTIONAL :: ks_in !< Starting k index of the data
3496  INTEGER, INTENT(in), OPTIONAL :: ie_in !< Ending i index of the data
3497  INTEGER, INTENT(in), OPTIONAL :: je_in !< Ending j index of the data
3498  INTEGER, INTENT(in), OPTIONAL :: ke_in !< Ending k index of the data
3499  LOGICAL, INTENT(in), OPTIONAL :: mask(:,:,:,:) !< Logical mask indicating the points to not average
3500  CLASS(*), INTENT(in), OPTIONAL :: rmask(:,:,:,:) !< Real mask indicating the points to not averafe
3501  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg !< If some errors occurs, send_data will return the
3502  !! error message instead of crashing
3503 
3504  class(*), allocatable :: rmask_local(:,:,:,:) !< Real version of the mask variable
3505  logical, allocatable :: mask_local(:,:,:,:) !< Local version of the mask variable
3506 
3507  ! If diag_field_id is < 0 it means that this field is not registered, simply return
3508  IF ( diag_field_id <= 0 ) THEN
3509  send_data_4d = .false.
3510  RETURN
3511  ENDIF
3512 
3513  if (.not. use_modern_diag) &
3514  call mpp_error(fatal, "Send_data_4d is only supported when diag_manager_nml::use_modern_diag=.true.")
3515 
3516  !< The error checking is done in accept_data
3517  if (present(mask)) mask_local = mask
3518  if (present(rmask)) rmask_local = rmask
3519 
3520  send_data_4d = fms_diag_object%fms_diag_accept_data(diag_field_id, field, mask_local, rmask_local, &
3521  time, is_in, js_in, ks_in, ie_in, je_in, ke_in, weight, &
3522  err_msg)
3523 
3524  if (present(err_msg)) then
3525  if (err_msg .ne. "") then
3526  call mpp_error(note, trim(err_msg))
3527  send_data_4d = .false.
3528  return
3529  endif
3530  endif
3531 
3532  if (allocated(rmask_local)) deallocate(rmask_local)
3533  if (allocated(mask_local)) deallocate(mask_local)
3534  end function send_data_4d
3535 
3536  !> @return true if send is successful
3537  LOGICAL FUNCTION send_tile_averaged_data1d ( id, field, area, time, mask )
3538  INTEGER, INTENT(in) :: id !< id od the diagnostic field
3539  REAL, INTENT(in) :: field(:,:) !< field to average and send
3540  REAL, INTENT(in) :: area (:,:) !< area of tiles (== averaging weights), arbitrary units
3541  TYPE(time_type), INTENT(in) :: time !< current time
3542  LOGICAL, INTENT(in),OPTIONAL :: mask (:,:) !< land mask
3543 
3544  REAL, DIMENSION(SIZE(field,1)) :: out(size(field,1))
3545 
3546  ! If id is < 0 it means that this field is not registered, simply return
3547  IF ( id <= 0 ) THEN
3548  send_tile_averaged_data1d = .false.
3549  RETURN
3550  END IF
3551 
3552  CALL average_tiles1d (id, field, area, mask, out)
3553  send_tile_averaged_data1d = send_data(id, out, time=time, mask=any(mask,dim=2))
3554  END FUNCTION send_tile_averaged_data1d
3555 
3556  !> @brief Calculates average for a field with the given area and land mask
3557  SUBROUTINE average_tiles1d(diag_field_id, x, area, mask, out)
3558  INTEGER, INTENT(in) :: diag_field_id
3559  REAL, DIMENSION(:,:), INTENT(in) :: x !< (ug_index, tile) field to average
3560  REAL, DIMENSION(:,:), INTENT(in) :: area !< (ug_index, tile) fractional area
3561  LOGICAL, DIMENSION(:,:), INTENT(in) :: mask !< (ug_index, tile) land mask
3562  REAL, DIMENSION(:), INTENT(out) :: out !< (ug_index) result of averaging
3563 
3564  INTEGER :: it !< iterator over tile number
3565  REAL, DIMENSION(SIZE(x,1)) :: s !< area accumulator
3566  REAL :: local_missing_value
3567 
3568  ! # FATAL if diag_field_id is less than 0, indicates field was not in diag_table.
3569  ! The calling functions should not have passed in an invalid diag_field_id
3570  IF ( diag_field_id <= 0 ) THEN
3571  ! <ERROR STATUS="FATAL">
3572  ! diag_field_id less than 0. Contact developers.
3573  ! </ERROR>
3574  CALL error_mesg('diag_manager_mod::average_tiles1d',&
3575  & "diag_field_id less than 0. Contact developers.", fatal)
3576  END IF
3577 
3578  ! Initialize local_missing_value
3579  IF ( input_fields(diag_field_id)%missing_value_present ) THEN
3580  local_missing_value = input_fields(diag_field_id)%missing_value
3581  ELSE
3582  local_missing_value = 0.0
3583  END IF
3584 
3585  ! Initialize s and out to zero.
3586  s(:) = 0.0
3587  out(:) = 0.0
3588 
3589  DO it = 1, SIZE(area,dim=2)
3590  WHERE ( mask(:,it) )
3591  out(:) = out(:) + x(:,it)*area(:,it)
3592  s(:) = s(:) + area(:,it)
3593  END WHERE
3594  END DO
3595 
3596  WHERE ( s(:) > 0 )
3597  out(:) = out(:)/s(:)
3598  ELSEWHERE
3599  out(:) = local_missing_value
3600  END WHERE
3601  END SUBROUTINE average_tiles1d
3602 
3603  !> @return true if send is successful
3604  LOGICAL FUNCTION send_tile_averaged_data2d ( id, field, area, time, mask )
3605  INTEGER, INTENT(in) :: id !< id od the diagnostic field
3606  REAL, INTENT(in) :: field(:,:,:) !< field to average and send
3607  REAL, INTENT(in) :: area (:,:,:) !< area of tiles (== averaging weights), arbitrary units
3608  TYPE(time_type), INTENT(in) :: time !< current time
3609  LOGICAL, INTENT(in),OPTIONAL :: mask (:,:,:) !< land mask
3610 
3611  REAL, DIMENSION(SIZE(field,1),SIZE(field,2)) :: out(size(field,1), size(field,2))
3612 
3613  ! If id is < 0 it means that this field is not registered, simply return
3614  IF ( id <= 0 ) THEN
3615  send_tile_averaged_data2d = .false.
3616  RETURN
3617  END IF
3618 
3619  CALL average_tiles(id, field, area, mask, out)
3620  send_tile_averaged_data2d = send_data(id, out, time, mask=any(mask,dim=3))
3621  END FUNCTION send_tile_averaged_data2d
3622 
3623  !> @return true if send is successful
3624  LOGICAL FUNCTION send_tile_averaged_data3d( id, field, area, time, mask )
3625  INTEGER, INTENT(in) :: id !< id of the diagnostic field
3626  REAL, DIMENSION(:,:,:,:), INTENT(in) :: field !< (lon, lat, tile, lev) field to average and send
3627  REAL, DIMENSION(:,:,:), INTENT(in) :: area (:,:,:) !< (lon, lat, tile) tile areas ( == averaging
3628  !! weights), arbitrary units
3629  TYPE(time_type), INTENT(in) :: time !< current time
3630  LOGICAL, DIMENSION(:,:,:), INTENT(in), OPTIONAL :: mask !< (lon, lat, tile) land mask
3631 
3632  REAL, DIMENSION(SIZE(field,1),SIZE(field,2),SIZE(field,4)) :: out
3633  LOGICAL, DIMENSION(SIZE(field,1),SIZE(field,2),SIZE(field,4)) :: mask3
3634  INTEGER :: it
3635 
3636  ! If id is < 0 it means that this field is not registered, simply return
3637  IF ( id <= 0 ) THEN
3638  send_tile_averaged_data3d = .false.
3639  RETURN
3640  END IF
3641 
3642  DO it=1, SIZE(field,4)
3643  CALL average_tiles(id, field(:,:,:,it), area, mask, out(:,:,it) )
3644  END DO
3645 
3646  mask3(:,:,1) = any(mask,dim=3)
3647  DO it = 2, SIZE(field,4)
3648  mask3(:,:,it) = mask3(:,:,1)
3649  END DO
3650 
3651  send_tile_averaged_data3d = send_data( id, out, time, mask=mask3 )
3652  END FUNCTION send_tile_averaged_data3d
3653 
3654  !> @brief Calculates tile average of a field
3655  SUBROUTINE average_tiles(diag_field_id, x, area, mask, out)
3656  INTEGER, INTENT(in) :: diag_field_id
3657  REAL, DIMENSION(:,:,:), INTENT(in) :: x !< (lon, lat, tile) field to average
3658  REAL, DIMENSION(:,:,:), INTENT(in) :: area !< (lon, lat, tile) fractional area
3659  LOGICAL, DIMENSION(:,:,:), INTENT(in) :: mask !< (lon, lat, tile) land mask
3660  REAL, DIMENSION(:,:), INTENT(out) :: out !< (lon, lat) result of averaging
3661 
3662  INTEGER :: it !< iterator over tile number
3663  REAL, DIMENSION(SIZE(x,1),SIZE(x,2)) :: s !< area accumulator
3664  REAL :: local_missing_value
3665 
3666  ! # FATAL if diag_field_id is less than 0, indicates field was not in diag_table.
3667  ! The calling functions should not have passed in an invalid diag_field_id
3668  IF ( diag_field_id <= 0 ) THEN
3669  ! <ERROR STATUS="FATAL">
3670  ! diag_field_id less than 0. Contact developers.
3671  ! </ERROR>
3672  CALL error_mesg('diag_manager_mod::average_tiles',&
3673  & "diag_field_id less than 0. Contact developers.", fatal)
3674  END IF
3675 
3676  ! Initialize local_missing_value
3677  IF ( input_fields(diag_field_id)%missing_value_present ) THEN
3678  local_missing_value = input_fields(diag_field_id)%missing_value
3679  ELSE
3680  local_missing_value = 0.0
3681  END IF
3682 
3683  ! Initialize s and out to zero.
3684  s(:,:) = 0.0
3685  out(:,:) = 0.0
3686 
3687  DO it = 1, SIZE(area,3)
3688  WHERE ( mask(:,:,it) )
3689  out(:,:) = out(:,:) + x(:,:,it)*area(:,:,it)
3690  s(:,:) = s(:,:) + area(:,:,it)
3691  END WHERE
3692  END DO
3693 
3694  WHERE ( s(:,:) > 0 )
3695  out(:,:) = out(:,:)/s(:,:)
3696  ELSEWHERE
3697  out(:,:) = local_missing_value
3698  END WHERE
3699  END SUBROUTINE average_tiles
3700 
3701  !> @return Integer writing_field
3702  INTEGER FUNCTION writing_field(out_num, at_diag_end, error_string, time)
3703  INTEGER, INTENT(in) :: out_num
3704  LOGICAL, INTENT(in) :: at_diag_end
3705  CHARACTER(len=*), INTENT(out) :: error_string
3706  TYPE(time_type), INTENT(in) :: time
3707 
3708  TYPE(time_type) :: middle_time
3709  TYPE(time_type) :: filename_time
3710  LOGICAL :: time_max, time_min, reduced_k_range, missvalue_present
3711  LOGICAL :: average, time_rms, need_compute, phys_window
3712  INTEGER :: in_num, file_num, freq, units
3713  INTEGER :: b1,b2,b3,b4 !< size of buffer along x,y,z,and diurnal axes
3714  INTEGER :: i, j, k, m
3715  REAL :: missvalue, num
3716  writing_field = 0
3717 
3718  need_compute = output_fields(out_num)%need_compute
3719 
3720  in_num = output_fields(out_num)%input_field
3721  IF ( input_fields(in_num)%static ) RETURN
3722 
3723  missvalue = input_fields(in_num)%missing_value
3724  missvalue_present = input_fields(in_num)%missing_value_present
3725  reduced_k_range = output_fields(out_num)%reduced_k_range
3726  phys_window = output_fields(out_num)%phys_window
3727  ! Is this output field being time averaged?
3728  average = output_fields(out_num)%time_average
3729  ! Are we taking the rms of the field?
3730  ! If so, then average is also .TRUE.
3731  time_rms = output_fields(out_num)%time_rms
3732  ! Looking for max and min value of this field over the sampling interval?
3733  time_max = output_fields(out_num)%time_max
3734  time_min = output_fields(out_num)%time_min
3735  file_num = output_fields(out_num)%output_file
3736  freq = files(file_num)%output_freq
3737  units = files(file_num)%output_units
3738 
3739  ! If average get size: Average intervals are last_output, next_output
3740  IF ( average ) THEN
3741  b1=SIZE(output_fields(out_num)%buffer,1)
3742  b2=SIZE(output_fields(out_num)%buffer,2)
3743  b3=SIZE(output_fields(out_num)%buffer,3)
3744  b4=SIZE(output_fields(out_num)%buffer,4)
3745  IF ( input_fields(in_num)%mask_variant ) THEN
3746  DO m=1, b4
3747  DO k=1, b3
3748  DO j=1, b2
3749  DO i=1, b1
3750  IF ( output_fields(out_num)%counter(i,j,k,m) > 0. )THEN
3751  output_fields(out_num)%buffer(i,j,k,m) = &
3752  & output_fields(out_num)%buffer(i,j,k,m)/output_fields(out_num)%counter(i,j,k,m)
3753  IF ( time_rms ) output_fields(out_num)%buffer(i,j,k,m) = &
3754  sqrt(output_fields(out_num)%buffer(i,j,k,m))
3755  ELSE
3756  output_fields(out_num)%buffer(i,j,k,m) = missvalue
3757  END IF
3758  END DO
3759  END DO
3760  END DO
3761  END DO
3762  ELSE !not mask variant
3763  DO m = 1, b4
3764  IF ( phys_window ) THEN
3765  IF ( need_compute .OR. reduced_k_range ) THEN
3766  num = real(output_fields(out_num)%num_elements(m)/output_fields(out_num)%region_elements)
3767  ELSE
3768  num = real(output_fields(out_num)%num_elements(m)/output_fields(out_num)%total_elements)
3769  END IF
3770  ELSE
3771  num = output_fields(out_num)%count_0d(m)
3772  END IF
3773  IF ( num > 0. ) THEN
3774  IF ( missvalue_present ) THEN
3775  DO k=1, b3
3776  DO j=1, b2
3777  DO i=1, b1
3778  IF ( output_fields(out_num)%buffer(i,j,k,m) /= missvalue ) THEN
3779  output_fields(out_num)%buffer(i,j,k,m) = output_fields(out_num)%buffer(i,j,k,m)/num
3780  IF ( time_rms ) output_fields(out_num)%buffer(i,j,k,m) =&
3781  & sqrt(output_fields(out_num)%buffer(i,j,k,m))
3782  END IF
3783  END DO
3784  END DO
3785  END DO
3786  ELSE
3787  output_fields(out_num)%buffer(:,:,:,m) = output_fields(out_num)%buffer(:,:,:,m)/num
3788  IF ( time_rms ) output_fields(out_num)%buffer(:,:,:,m) =&
3789  & sqrt(output_fields(out_num)%buffer(:,:,:,m))
3790  END IF
3791  ELSE IF ( .NOT. at_diag_end ) THEN
3792  IF ( missvalue_present ) THEN
3793  IF(any(output_fields(out_num)%buffer /= missvalue)) THEN
3794  WRITE (error_string,'(a,"/",a)')&
3795  & trim(input_fields(in_num)%module_name), &
3796  & trim(output_fields(out_num)%output_name)
3797  writing_field = -1
3798  RETURN
3799  END IF
3800  END IF
3801  END IF
3802  END DO
3803  END IF ! mask_variant
3804  ELSE IF ( time_min .OR. time_max ) THEN
3805  IF ( missvalue_present ) THEN
3806  WHERE ( abs(output_fields(out_num)%buffer) == min_value )
3807  output_fields(out_num)%buffer = missvalue
3808  END WHERE
3809  END IF ! if missvalue is NOT present buffer retains max_value or min_value
3810  END IF !average
3811 
3812  ! Output field
3813  IF ( at_diag_end .AND. freq == end_of_run ) output_fields(out_num)%next_output = time
3814 ! if (time .eq. output_fields(out_num)%next_output) then
3815  IF ( (output_fields(out_num)%time_ops) .AND. (.NOT. mix_snapshot_average_fields) ) THEN
3816  middle_time = (output_fields(out_num)%last_output+output_fields(out_num)%next_output)/2
3817  if (trim(files(file_num)%filename_time_bounds) == "begin") then
3818  filename_time = output_fields(out_num)%last_output
3819  elseif (trim(files(file_num)%filename_time_bounds) == "middle") then
3820  filename_time = middle_time
3821  elseif (trim(files(file_num)%filename_time_bounds) == "end") then
3822  filename_time = output_fields(out_num)%next_output
3823  endif
3824 
3825  CALL diag_data_out(file_num, out_num, output_fields(out_num)%buffer, middle_time, &
3826  & filename_time=filename_time)
3827  ELSE
3828  CALL diag_data_out(file_num, out_num, &
3829  & output_fields(out_num)%buffer, output_fields(out_num)%next_output)
3830  END IF
3831 !output_fields(out_num)%last_output = output_fields(out_num)%next_output
3832 ! endif
3833  IF ( at_diag_end ) RETURN
3834 
3835  ! Take care of cleaning up the time counters and the storeage size
3836  output_fields(out_num)%last_output = output_fields(out_num)%next_output
3837  IF ( freq == end_of_run ) THEN
3838  output_fields(out_num)%next_output = time
3839  ELSE
3840  IF ( freq == every_time ) THEN
3841  output_fields(out_num)%next_output = time
3842  ELSE
3843  output_fields(out_num)%next_output = output_fields(out_num)%next_next_output
3844  output_fields(out_num)%next_next_output = &
3845  & diag_time_inc(output_fields(out_num)%next_next_output, freq, units)
3846  END IF
3847  output_fields(out_num)%count_0d(:) = 0.0
3848  output_fields(out_num)%num_elements(:) = 0
3849  IF ( time_max ) THEN
3850  output_fields(out_num)%buffer = max_value
3851  ELSE IF ( time_min ) THEN
3852  output_fields(out_num)%buffer = min_value
3853  ELSE
3854  output_fields(out_num)%buffer = empty
3855  END IF
3856  IF ( input_fields(in_num)%mask_variant .AND. average ) output_fields(out_num)%counter = 0.0
3857  END IF
3858  END FUNCTION writing_field
3859 
3860  SUBROUTINE diag_manager_set_time_end(Time_end_in)
3861  TYPE (time_type), INTENT(in) :: time_end_in
3862 
3863  time_end = time_end_in
3864 
3865  END SUBROUTINE diag_manager_set_time_end
3866 
3867  !-----------------------------------------------------------------------
3868  !> @brief The subroutine 'diag_send_complete_instant' allows the user to
3869  !! save diagnostic data on variable intervals (user defined in code logic)
3870  !! to the same file. The argument (time_type) will be written to the
3871  !! time axis correspondingly.
3872  !!
3873  !> The user is responsible for any averaging of accumulated data
3874  !! as this routine is not designed for instantaneous values. This routine
3875  !! works only for send_data calls within OpenMP regions as they are buffered
3876  !! until the complete signal is given.
3878  TYPE (time_type), INTENT(in) :: time
3879  !--- local variables
3880  integer :: file, j, freq, in_num, file_num, out_num
3881 
3882  DO file = 1, num_files
3883  freq = files(file)%output_freq
3884  IF (freq == 0) then
3885  DO j = 1, files(file)%num_fields
3886  out_num = files(file)%fields(j)
3887  in_num = output_fields(out_num)%input_field
3888  IF ( (input_fields(in_num)%numthreads == 1) .AND.&
3889  & (input_fields(in_num)%active_omp_level.LE.1) ) cycle
3890  file_num = output_fields(out_num)%output_file
3891  CALL diag_data_out(file_num, out_num, &
3892  & output_fields(out_num)%buffer, time)
3893  END DO
3894  END IF
3895  END DO
3896  END SUBROUTINE diag_send_complete_instant
3897 
3898  !-----------------------------------------------------------------------
3899  !> @brief Saves diagnostic data for the given time value.
3900  SUBROUTINE diag_send_complete(time_step, err_msg)
3901  TYPE (time_type), INTENT(in) :: time_step
3902  character(len=*), INTENT(out), optional :: err_msg
3903 
3904  type(time_type) :: next_time, time
3905  integer :: file, j, out_num, in_num, freq, status
3906  logical :: local_output, need_compute
3907  CHARACTER(len=128) :: error_string
3908 
3909  IF ( time_end == time_zero ) THEN
3910  ! <ERROR STATUS="FATAL">
3911  ! diag_manager_set_time_end must be called before diag_send_complete
3912  ! </ERROR>
3913  CALL error_mesg('diag_manager_mod::diag_send_complete',&
3914  & "diag_manager_set_time_end must be called before diag_send_complete", fatal)
3915  END IF
3916 
3917  if (use_modern_diag) then
3918  call fms_diag_object%fms_diag_send_complete(time_step)
3919  return
3920  endif
3921 
3922  DO file = 1, num_files
3923  freq = files(file)%output_freq
3924  DO j = 1, files(file)%num_fields
3925  out_num = files(file)%fields(j) !this is position of output_field in array output_fields
3926  in_num = output_fields(out_num)%input_field
3927 
3928  IF ( (input_fields(in_num)%numthreads == 1) .AND. (input_fields(in_num)%active_omp_level.LE.1) ) cycle
3929  IF ( output_fields(out_num)%static .OR. freq == end_of_run ) cycle
3930  time = input_fields(in_num)%time
3931  IF ( time >= time_end ) cycle
3932 
3933  ! is this field output on a local domain only?
3934  local_output = output_fields(out_num)%local_output
3935  ! if local_output, does the current PE take part in send_data?
3936  need_compute = output_fields(out_num)%need_compute
3937  ! skip all PEs not participating in outputting this field
3938  IF ( local_output .AND. (.NOT.need_compute) ) cycle
3939  next_time = time + time_step
3940 
3941  IF ( next_time > output_fields(out_num)%next_output ) THEN
3942  ! A non-static field that has skipped a time level is an error
3943  IF ( next_time > output_fields(out_num)%next_next_output .AND. freq > 0 ) THEN
3944  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
3945  WRITE (error_string,'(a,"/",a)')&
3946  & trim(input_fields(in_num)%module_name), &
3947  & trim(output_fields(out_num)%output_name)
3948  IF ( fms_error_handler('diag_send_complete',&
3949  & 'module/output_field '//trim(error_string)//&
3950  & ' is skipped one time level in output data', err_msg)) RETURN
3951  END IF
3952  END IF
3953 
3954  status = writing_field(out_num, .false., error_string, next_time)
3955  IF ( status == -1 ) THEN
3956  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
3957  IF(fms_error_handler('diag_manager_mod::diag_send_complete','module/output_field '//&
3958  & trim(error_string)//', write EMPTY buffer', err_msg)) RETURN
3959  END IF
3960  END IF
3961  END IF !time > output_fields(out_num)%next_output
3962  END DO
3963  END DO
3964 
3965  END SUBROUTINE diag_send_complete
3966 
3967  !> @brief Flushes diagnostic buffers where necessary. Close diagnostics files.
3968  !! A warning will be issued here if a field in diag_table is not registered
3969  SUBROUTINE diag_manager_end(time)
3970  TYPE(time_type), INTENT(in) :: time
3971 
3972  INTEGER :: file
3973 
3974  IF ( do_diag_field_log ) THEN
3975  close (diag_log_unit)
3976  END IF
3977  DO file = 1, num_files
3978  CALL closing_file(file, time)
3979  END DO
3980  if (allocated(fileobju)) deallocate(fileobju)
3981  if (allocated(fileobj)) deallocate(fileobj)
3982  if (allocated(fileobjnd)) deallocate(fileobjnd)
3983  if (allocated(fnum_for_domain)) deallocate(fnum_for_domain)
3984 
3985  if (use_modern_diag) then
3986  call fms_diag_object%diag_end(time)
3987  endif
3988  END SUBROUTINE diag_manager_end
3989 
3990  !> @brief Replaces diag_manager_end; close just one file: files(file)
3991  SUBROUTINE closing_file(file, time)
3992  INTEGER, INTENT(in) :: file
3993  TYPE(time_type), INTENT(in) :: time
3994 
3995  INTEGER :: j, i, input_num, freq, status
3996  INTEGER :: stdout_unit
3997  LOGICAL :: reduced_k_range, need_compute, local_output
3998  CHARACTER(len=128) :: message
3999 
4000  stdout_unit = stdout()
4001 
4002  ! Output all registered, non_static output_fields
4003  DO j = 1, files(file)%num_fields
4004  i = files(file)%fields(j) !this is position of output_field in array output_fields
4005 
4006  ! is this field output on a local domain only?
4007  local_output = output_fields(i)%local_output
4008  ! if local_output, does the current PE take part in send_data?
4009  need_compute = output_fields(i)%need_compute
4010 
4011  reduced_k_range = output_fields(i)%reduced_k_range
4012 
4013  ! skip all PEs not participating in outputting this field
4014  IF ( local_output .AND. (.NOT. need_compute) ) cycle
4015  ! skip fields that were not registered or non-static
4016  input_num = output_fields(i)%input_field
4017  IF ( input_fields(input_num)%static ) cycle
4018  IF ( .NOT.input_fields(input_num)%register ) cycle
4019  freq = files(file)%output_freq
4020  IF ( freq /= end_of_run .AND. files(file)%file_unit < 0 &
4021  & .AND. all(output_fields(i)%num_elements(:) == 0)&
4022  & .AND. all(output_fields(i)%count_0d(:) == 0) ) cycle
4023  ! Is it time to output for this field; CAREFUL ABOUT >= vs > HERE
4024  ! For end should be >= because no more data is coming
4025  IF ( time >= output_fields(i)%next_output .OR. freq == end_of_run ) THEN
4026  IF ( time >= output_fields(i)%next_next_output .AND. freq > 0 ) THEN
4027  WRITE (message,'(a,"/",a)') trim(input_fields(input_num)%module_name), &
4028  & trim(output_fields(i)%output_name)
4029  ! <ERROR STATUS="WARNING">
4030  ! <input_fields(input_num)%module_name>/<output_fields(i)%output_name> skip one time
4031  ! level, maybe send_data never called
4032  ! </ERROR>
4033  IF ( mpp_pe() .EQ. mpp_root_pe() ) &
4034  & CALL error_mesg('diag_manager_mod::closing_file', 'module/output_field ' //&
4035  & trim(message)//', skip one time level, maybe send_data never called', warning)
4036  status = writing_field(i, .true.,message,time)
4037  ELSE
4038  status = writing_field(i, .true., message, time)
4039  END IF
4040  ELSEIF ( .NOT.output_fields(i)%written_once ) THEN
4041  ! <ERROR STATUS="NOTE">
4042  ! <output_fields(i)%output_name) NOT available, check if output interval > runlength.
4043  ! NetCDF fill_values are written
4044  ! </ERROR>
4045  CALL error_mesg('Potential error in diag_manager_end ',&
4046  & trim(output_fields(i)%output_name)//' NOT available,'//&
4047  & ' check if output interval > runlength. Netcdf fill_values are written', note)
4048  output_fields(i)%buffer = fill_value
4049  CALL diag_data_out(file, i, output_fields(i)%buffer, time, .true.)
4050  END IF
4051  END DO
4052  ! Now it's time to output static fields
4053  CALL write_static(file)
4054 
4055  ! Write out the number of bytes of data saved to this file
4056  IF ( write_bytes_in_file ) THEN
4057  CALL mpp_sum (files(file)%bytes_written)
4058  IF ( mpp_pe() == mpp_root_pe() )&
4059  & WRITE (stdout_unit,'(a,i12,a,a)') 'Diag_Manager: ',files(file)%bytes_written, &
4060  & ' bytes of data written to file ',trim(files(file)%name)
4061  END IF
4062  END SUBROUTINE closing_file
4063 
4064  !> @brief Initialize Diagnostics Manager.
4065  !! @details Open and read diag_table. Select fields and files for diagnostic output.
4066  SUBROUTINE diag_manager_init(diag_model_subset, time_init, err_msg)
4067  INTEGER, OPTIONAL, INTENT(IN) :: diag_model_subset
4068  INTEGER, DIMENSION(6), OPTIONAL, INTENT(IN) :: time_init !< Model time diag_manager initialized
4069  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
4070 
4071  CHARACTER(len=*), PARAMETER :: sep = '|'
4072 
4073  INTEGER, PARAMETER :: fltkind = r4_kind
4074  INTEGER, PARAMETER :: dblkind = r8_kind
4075  INTEGER :: diag_subset_output
4076  INTEGER :: mystat
4077  INTEGER, ALLOCATABLE, DIMENSION(:) :: pelist
4078  INTEGER :: stdlog_unit, stdout_unit
4079  integer :: j
4080  CHARACTER(len=256) :: err_msg_local
4081 
4082  namelist /diag_manager_nml/ append_pelist_name, mix_snapshot_average_fields, max_output_fields, &
4083  & max_input_fields, max_axes, do_diag_field_log, write_bytes_in_file, debug_diag_manager,&
4084  & max_num_axis_sets, max_files, use_cmor, issue_oor_warnings,&
4085  & oor_warnings_fatal, max_out_per_in_field, flush_nc_files, region_out_use_alt_value, max_field_attributes,&
4086  & max_file_attributes, max_axis_attributes, prepend_date, use_modern_diag, use_clock_average, &
4087  & field_log_separator, use_refactored_send
4088 
4089  ! If the module was already initialized do nothing
4090  IF ( module_is_initialized ) RETURN
4091 
4092  ! Clear the err_msg variable if contains any residual information
4093  IF ( PRESENT(err_msg) ) err_msg = ''
4094 
4095  ! Initialize diag_util_mod and diag_data_mod
4096  ! These init routine only write out the version number to the log file
4097  call diag_util_init()
4098  call diag_data_init()
4099 
4100  ! Determine pack_size from how many bytes a real value has (how compiled)
4101  pack_size = SIZE(transfer(0.0_dblkind, (/0.0, 0.0, 0.0, 0.0/)))
4102  IF (pack_size .EQ. 1) then
4103  pack_size_str = "double"
4104  else if (pack_size .EQ. 2) then
4105  pack_size_str = "float"
4106  else
4107  IF ( fms_error_handler('diag_manager_mod::diag_manager_init', 'unknown pack_size. Must be 1, or 2.', &
4108  & err_msg) ) RETURN
4109  END IF
4110 
4111  ! Get min and max values for real(kind=R4_KIND)
4112  min_value = huge(0.0_fltkind)
4113  max_value = -min_value
4114 
4115  ! get stdlog and stdout unit number
4116  stdlog_unit = stdlog()
4117  stdout_unit = stdout()
4118 
4119  ! version number to logfile
4120  CALL write_version_number("DIAG_MANAGER_MOD", version)
4121 
4122  time_zero = set_time(0,0)
4123  !--- initialize time_end to time_zero
4124  time_end = time_zero
4125  diag_subset_output = diag_all
4126  IF ( PRESENT(diag_model_subset) ) THEN
4127  IF ( diag_model_subset >= diag_other .AND. diag_model_subset <= diag_all ) THEN
4128  diag_subset_output = diag_model_subset
4129  ELSE
4130  IF ( fms_error_handler('diag_manager_mod::diag_manager_init', 'invalid value of diag_model_subset', &
4131  & err_msg) ) RETURN
4132  END IF
4133  END IF
4134 
4135  READ (input_nml_file, nml=diag_manager_nml, iostat=mystat)
4136  ! Check the status of reading the diag_manager_nml
4137 
4138  IF ( check_nml_error(iostat=mystat, nml_name='DIAG_MANAGER_NML') < 0 ) THEN
4139  IF ( mpp_pe() == mpp_root_pe() ) THEN
4140  CALL error_mesg('diag_manager_mod::diag_manager_init', &
4141  & 'DIAG_MANAGER_NML not found in input nml file. Using defaults.', warning)
4142  END IF
4143  END IF
4144 
4145  IF (.not. use_modern_diag .and. use_clock_average) &
4146  call mpp_error(fatal, "diag_manager_mod: You cannot set use_modern_diag=.false. and &
4147  & use_clock_average=.true. in diag_manager_nml")
4148 
4149  IF ( mpp_pe() == mpp_root_pe() ) THEN
4150  WRITE (stdlog_unit, diag_manager_nml)
4151  END IF
4152 
4153  ! Issue note about using the CMOR missing value.
4154  IF ( use_cmor ) THEN
4155  err_msg_local = ''
4156  WRITE (err_msg_local,'(ES8.1E2)') cmor_missing_value
4157  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Using CMOR missing value ('//trim(err_msg_local)// &
4158  & ').', note)
4159  END IF
4160 
4161  ! How to handle Out of Range Warnings.
4162  IF ( oor_warnings_fatal ) THEN
4163  oor_warning = fatal
4164  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Out &
4165  &of Range warnings are fatal.', note)
4166  ELSEIF ( .NOT.issue_oor_warnings ) THEN
4167  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Out &
4168  &of Range warnings will be ignored.', note)
4169  END IF
4170 
4171  IF ( mix_snapshot_average_fields ) THEN
4172  IF ( mpp_pe() == mpp_root_pe() ) THEN
4173  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Setting diag_manager_nml variable '//&
4174  & 'mix_snapshot_average_fields = .TRUE. will cause ERRORS in the time coordinates '//&
4175  & 'of all time averaged fields. Strongly recommend setting mix_snapshot_average_fields '//&
4176  & '= .FALSE.', warning)
4177  END IF
4178  END IF
4179  ALLOCATE(output_fields(max_output_fields))
4180  ALLOCATE(input_fields(max_input_fields))
4181  DO j = 1, max_input_fields
4182  ALLOCATE(input_fields(j)%output_fields(max_out_per_in_field))
4183  END DO
4184 !> Allocate files
4185  ALLOCATE(files(max_files))
4186  ALLOCATE(fileobju(max_files))
4187  ALLOCATE(fileobj(max_files))
4188  ALLOCATE(fileobjnd(max_files))
4189  ALLOCATE(fnum_for_domain(max_files))
4190  !> Initialize fnum_for_domain with "dn" which stands for done
4191  fnum_for_domain(:) = "dn"
4192  ALLOCATE(pelist(mpp_npes()))
4193  CALL mpp_get_current_pelist(pelist, pelist_name)
4194 
4195  ! set the diag_init_time if time_init present. Otherwise, set it to base_time
4196  IF ( PRESENT(time_init) ) THEN
4197  diag_init_time = set_date(time_init(1), time_init(2), time_init(3), time_init(4),&
4198  & time_init(5), time_init(6))
4199  ELSE
4200  diag_init_time = get_base_time()
4201  IF ( prepend_date .EQV. .true. ) THEN
4202  CALL error_mesg('diag_manager_mod::diag_manager_init',&
4203  & 'prepend_date only supported when diag_manager_init is called with time_init present.', note)
4204  prepend_date = .false.
4205  END IF
4206  END IF
4207 
4208  if (use_modern_diag) then
4209  CALL fms_diag_object%init(diag_subset_output)
4210  endif
4211  if (.not. use_modern_diag) then
4212  CALL parse_diag_table(diag_subset=diag_subset_output, istat=mystat, err_msg=err_msg_local)
4213  IF ( mystat /= 0 ) THEN
4214  IF ( fms_error_handler('diag_manager_mod::diag_manager_init',&
4215  & 'Error parsing diag_table. '//trim(err_msg_local), err_msg) ) RETURN
4216  END IF
4217  endif
4218  !initialize files%bytes_written to zero
4219  files(:)%bytes_written = 0
4220 
4221  ! open diag field log file
4222  IF ( do_diag_field_log.AND.mpp_pe().EQ.mpp_root_pe() ) THEN
4223  open(newunit=diag_log_unit, file='diag_field_log.out', action='WRITE')
4224  WRITE (diag_log_unit,'(777a)') &
4225  & 'Module', field_log_separator, 'Field', field_log_separator, &
4226  & 'Long Name', field_log_separator, 'Units', field_log_separator, &
4227  & 'Number of Axis', field_log_separator, 'Time Axis', field_log_separator, &
4228  & 'Missing Value', field_log_separator, 'Min Value', field_log_separator, &
4229  & 'Max Value', field_log_separator, 'AXES LIST'
4230  END IF
4231 
4232  module_is_initialized = .true.
4233  ! create axis_id for scalars here
4234  if(.not. use_modern_diag) null_axis_id = diag_axis_init('scalar_axis', (/0./), 'none', 'N', 'none')
4235  RETURN
4236  END SUBROUTINE diag_manager_init
4237 
4238  !> @brief Return base date for diagnostics.
4239  !! @details Return date information for diagnostic reference time.
4240  SUBROUTINE get_base_date(year, month, day, hour, minute, second)
4241  INTEGER, INTENT(out) :: year, month, day, hour, minute, second
4242 
4243  ! <ERROR STATUS="FATAL">module has not been initialized</ERROR>
4244  IF (.NOT.module_is_initialized) CALL error_mesg ('diag_manager_mod::get_base_date', &
4245  & 'module has not been initialized', fatal)
4246  year = get_base_year()
4247  month = get_base_month()
4248  day = get_base_day()
4249  hour = get_base_hour()
4250  minute = get_base_minute()
4251  second = get_base_second()
4252  END SUBROUTINE get_base_date
4253 
4254  !> @brief Determine whether data is needed for the current model time step.
4255  !! @return Logical need_data
4256  !! @details Determine whether data is needed for the current model time step.
4257  !! Since diagnostic data are buffered, the "next" model time is passed
4258  !! instead of the current model time. This call can be used to minimize
4259  !! overhead for complicated diagnostics.
4260  LOGICAL FUNCTION need_data(diag_field_id, next_model_time)
4261  TYPE(time_type), INTENT(in) :: next_model_time !< next_model_time = current model time + model time_step
4262  INTEGER, INTENT(in) :: diag_field_id
4263 
4264  INTEGER :: i, out_num
4265 
4266  need_data = .false.
4267  IF ( diag_field_id < 0 ) RETURN ! this field is unused
4268  DO i = 1, input_fields(diag_field_id)%num_output_fields
4269  ! Get index to an output field
4270  out_num = input_fields(diag_field_id)%output_fields(i)
4271  IF ( .NOT.output_fields(out_num)%static ) THEN
4272  IF ( next_model_time > output_fields(out_num)%next_output ) need_data=.true.
4273  ! Is this output field being time averaged?
4274  ! assume average data based on every timestep
4275  ! needs to be changed when different forms of averaging are implemented
4276  IF ( output_fields(out_num)%time_average) need_data = .true.
4277  END IF
4278  END DO
4279  RETURN
4280  END FUNCTION need_data
4281 
4282  !> @brief Finds or initializes a diurnal time axis and returns its' ID.
4283  !! @return Integer init_diurnal_axis
4284  !! @details Given number of time intervals in the day, finds or initializes a diurnal time axis
4285  !! and returns its ID. It uses get_base_date, so should be in the file where it's accessible.
4286  !! The units are 'days since BASE_DATE', all diurnal axes belong to the set 'diurnal'
4287  INTEGER FUNCTION init_diurnal_axis(n_samples)
4288  INTEGER, INTENT(in) :: n_samples !< number of intervals during the day
4289 
4290  REAL :: center_data (n_samples) !< central points of time intervals
4291  REAL :: edges (n_samples+1) !< boundaries of time intervals
4292  INTEGER :: edges_id !< id of the corresponding edges
4293  INTEGER :: i
4294  INTEGER :: year !< components of the base date
4295  INTEGER :: month !< components of the base date
4296  INTEGER :: day !< components of the base date
4297  INTEGER :: hour !< components of the base date
4298  INTEGER :: minute !< components of the base date
4299  INTEGER :: second !< components of the base date
4300  CHARACTER(32) :: name !< name of the axis
4301  CHARACTER(128) :: units !< units of time
4302 
4303  CALL get_base_date(year, month, day, hour, minute, second)
4304  WRITE (units,11) 'hours', year, month, day, hour, minute, second
4305 11 FORMAT(a,' since ',i4.4,'-',i2.2,'-',i2.2,' ',i2.2,':',i2.2,':',i2.2)
4306  ! compute central points and units
4307  edges(1) = 0.0
4308  DO i = 1, n_samples
4309  center_data(i) = 24.0*(real(i)-0.5)/n_samples
4310  edges(i+1) = 24.0* real(i)/n_samples
4311  END DO
4312 
4313  ! define edges
4314  name = ''
4315  WRITE (name,'(a,i2.2)') 'time_of_day_edges_', n_samples
4316  edges_id = get_axis_num(name, 'diurnal')
4317  IF ( edges_id <= 0 ) THEN
4318  edges_id = diag_axis_init(name,edges,units,'N','time of day edges', set_name='diurnal')
4319  END IF
4320 
4321  ! define axis itself
4322  name = ''
4323  WRITE (name,'(a,i2.2)') 'time_of_day_', n_samples
4324  init_diurnal_axis = get_axis_num(name, 'diurnal')
4325  IF ( init_diurnal_axis <= 0 ) THEN
4326  init_diurnal_axis = diag_axis_init(name, center_data, units, 'N', 'time of day', &
4327  set_name='diurnal', edges=edges_id)
4328  END IF
4329  END FUNCTION init_diurnal_axis
4330 
4331  SUBROUTINE diag_field_attribute_init(diag_field_id, name, type, cval, ival, rval)
4332  INTEGER, INTENT(in) :: diag_field_id !< input field ID, obtained from diag_manager_mod::register_diag_field.
4333  CHARACTER(len=*), INTENT(in) :: name !< Name of the attribute
4334  INTEGER, INTENT(in) :: type !< NetCDF type (NF90_FLOAT, NF90_INT, NF90_CHAR)
4335  CHARACTER(len=*), INTENT(in), OPTIONAL :: cval !< Character string attribute value
4336  INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: ival !< Integer attribute value(s)
4337  REAL, DIMENSION(:), INTENT(in), OPTIONAL :: rval !< Real attribute value(s)
4338 
4339  INTEGER :: istat, length, i, j, this_attribute, out_field
4340 
4341  IF ( .NOT.first_send_data_call ) THEN
4342  ! Call error due to unable to add attribute after send_data called
4343  ! <ERROR STATUS="FATAL">
4344  ! Attempting to add attribute <name> to module/input_field <module_name>/<field_name>
4345  ! after first send_data call. Too late.
4346  ! </ERROR>
4347  CALL error_mesg('diag_manager_mod::diag_field_add_attribute', 'Attempting to add attribute "'&
4348  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4349  &//trim(input_fields(diag_field_id)%field_name)//'" after first send_data call. Too late.', fatal)
4350  END IF
4351 
4352  ! Simply return if diag_field_id <= 0 --- not in diag_table
4353  IF ( diag_field_id .LE. 0 ) THEN
4354  RETURN
4355  ELSE
4356  DO j=1,input_fields(diag_field_id)%num_output_fields
4357  out_field = input_fields(diag_field_id)%output_fields(j)
4358 
4359  ! Allocate memory for the attributes
4360  CALL attribute_init(output_fields(out_field))
4361 
4362  ! Check if attribute already exists
4363  this_attribute = 0
4364  DO i=1, output_fields(out_field)%num_attributes
4365  IF ( trim(output_fields(out_field)%attributes(i)%name) .EQ. trim(name) ) THEN
4366  this_attribute = i
4367  EXIT
4368  END IF
4369  END DO
4370 
4371  IF ( this_attribute.NE.0 .AND. (type.EQ.nf90_int .OR. type.EQ.nf90_float) ) THEN
4372  ! <ERROR STATUS="FATAL">
4373  ! Attribute <name> already defined for module/input_field <module_name>/<field_name>.
4374  ! Contact the developers
4375  ! </ERROR>
4376  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4377  & 'Attribute "'//trim(name)//'" already defined for module/input_field "'&
4378  &//trim(input_fields(diag_field_id)%module_name)//'/'&
4379  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4380  ELSE IF ( this_attribute.NE.0 .AND. type.EQ.nf90_char .AND. debug_diag_manager ) THEN
4381  ! <ERROR STATUS="NOTE">
4382  ! Attribute <name> already defined for module/input_field <module_name>/<field_name>.
4383  ! Prepending.
4384  ! </ERROR>
4385  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4386  & 'Attribute "'//trim(name)//'" already defined for module/input_field "'&
4387  &//trim(input_fields(diag_field_id)%module_name)//'/'&
4388  &//trim(input_fields(diag_field_id)%field_name)//'". Prepending.', note)
4389  ELSE IF ( this_attribute.EQ.0 ) THEN
4390  ! Defining a new attribute
4391  ! Increase the number of field attributes
4392  this_attribute = output_fields(out_field)%num_attributes + 1
4393  ! Checking to see if num_attributes == max_field_attributes, and return error message
4394  IF ( this_attribute .GT. max_field_attributes ) THEN
4395  ! <ERROR STATUS="FATAL">
4396  ! Number of attributes exceeds max_field_attributes for attribute <name>
4397  ! to module/input_field <module_name>/<field_name>.
4398  ! Increase diag_manager_nml:max_field_attributes.
4399  ! </ERROR>
4400  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4401  & 'Number of attributes exceeds max_field_attributes for attribute "'&
4402  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4403  &//trim(input_fields(diag_field_id)%field_name)&
4404  &//'". Increase diag_manager_nml:max_field_attributes.', fatal)
4405  ELSE
4406  output_fields(out_field)%num_attributes = this_attribute
4407  ! Set name and type
4408  output_fields(out_field)%attributes(this_attribute)%name = name
4409  output_fields(out_field)%attributes(this_attribute)%type = type
4410  ! Initialize catt to a blank string, as len_trim doesn't always work on an uninitialized string
4411  output_fields(out_field)%attributes(this_attribute)%catt = ''
4412  END IF
4413  END IF
4414 
4415  SELECT CASE (type)
4416  CASE (nf90_int)
4417  IF ( .NOT.PRESENT(ival) ) THEN
4418  ! <ERROR STATUS="FATAL">
4419  ! Number type claims INTEGER, but ival not present for attribute <name> to
4420  ! module/input_field <module_name>/<field_name>.
4421  ! Contact the developers.
4422  ! </ERROR>
4423  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4424  & 'Attribute type claims INTEGER, but ival not present for attribute "'&
4425  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4426  &//trim(input_fields(diag_field_id)%field_name)//'". Contact then developers.', fatal)
4427  END IF
4428  length = SIZE(ival)
4429  ! Allocate iatt(:) to size of ival
4430  ALLOCATE(output_fields(out_field)%attributes(this_attribute)%iatt(length), stat=istat)
4431  IF ( istat.NE.0 ) THEN
4432  ! <ERROR STATUS="FATAL">
4433  ! Unable to allocate iatt for attribute <name> to module/input_field <module_name>/<field_name>
4434  ! </ERROR>
4435  CALL error_mesg('diag_manager_mod::diag_field_add_attribute','Unable to allocate iatt for attribute "'&
4436  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4437  &//trim(input_fields(diag_field_id)%field_name)//'"', fatal)
4438  END IF
4439  ! Set remaining fields
4440  output_fields(out_field)%attributes(this_attribute)%len = length
4441  output_fields(out_field)%attributes(this_attribute)%iatt = ival
4442  CASE (nf90_float)
4443  IF ( .NOT.PRESENT(rval) ) THEN
4444  ! <ERROR STATUS="FATAL">
4445  ! Attribute type claims READ, but rval not present for attribute <name> to
4446  ! module/input_field <module_name>/<field_name>.
4447  ! Contact the developers.
4448  ! </ERROR>
4449  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4450  & 'Attribute type claims REAL, but rval not present for attribute "'&
4451  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4452  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4453  END IF
4454  length = SIZE(rval)
4455  ! Allocate iatt(:) to size of rval
4456  ALLOCATE(output_fields(out_field)%attributes(this_attribute)%fatt(length), stat=istat)
4457  IF ( istat.NE.0 ) THEN
4458  ! <ERROR STATUS="FATAL">
4459  ! Unable to allocate fatt for attribute <name> to module/input_field <module_name>/<field_name>
4460  ! </ERROR>
4461  CALL error_mesg('diag_manager_mod::diag_field_add_attribute','Unable to allocate fatt for attribute "'&
4462  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4463  &//trim(input_fields(diag_field_id)%field_name)//'"', fatal)
4464  END IF
4465  ! Set remaining fields
4466  output_fields(out_field)%attributes(this_attribute)%len = length
4467  output_fields(out_field)%attributes(this_attribute)%fatt = rval
4468  CASE (nf90_char)
4469  IF ( .NOT.PRESENT(cval) ) THEN
4470  ! <ERROR STATUS="FATAL">
4471  ! Attribute type claims CHARACTER, but cval not present for attribute <name>
4472  ! to module/input_field <module_name>/<field_name>.
4473  ! Contact the developers.
4474  ! </ERROR>
4475  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4476  & 'Attribute type claims CHARACTER, but cval not present for attribute "'&
4477  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4478  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4479  END IF
4480  CALL prepend_attribute(output_fields(out_field), trim(name), trim(cval))
4481  CASE default
4482  ! <ERROR STATUS="FATAL">
4483  ! Unknown attribute type for attribute <name> to module/input_field <module_name>/<field_name>.
4484  ! Contact the developers.
4485  ! </ERROR>
4486  CALL error_mesg('diag_manager_mod::diag_field_add_attribute', 'Unknown attribute type for attribute "'&
4487  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4488  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4489  END SELECT
4490  END DO
4491  END IF
4492  END SUBROUTINE diag_field_attribute_init
4493 
4494  !> @brief Add a scalar real attribute to the diag field corresponding to a given id
4495  SUBROUTINE diag_field_add_attribute_scalar_r(diag_field_id, att_name, att_value)
4496  INTEGER, INTENT(in) :: diag_field_id !< ID number for field to add attribute to
4497  CHARACTER(len=*), INTENT(in) :: att_name !< new attribute name
4498  REAL, INTENT(in) :: att_value !< new attribute value
4499 
4500  if (use_modern_diag) then
4501  call fms_diag_object%fms_diag_field_add_attribute(diag_field_id, att_name, (/att_value /))
4502  else
4503  CALL diag_field_add_attribute_r1d(diag_field_id, att_name, (/ att_value /))
4504  endif
4505  END SUBROUTINE diag_field_add_attribute_scalar_r
4506 
4507  !> @brief Add a scalar integer attribute to the diag field corresponding to a given id
4508  SUBROUTINE diag_field_add_attribute_scalar_i(diag_field_id, att_name, att_value)
4509  INTEGER, INTENT(in) :: diag_field_id !< ID number for field to add attribute to
4510  CHARACTER(len=*), INTENT(in) :: att_name !< new attribute name
4511  INTEGER, INTENT(in) :: att_value !< new attribute value
4512 
4513  if (use_modern_diag) then
4514  call fms_diag_object%fms_diag_field_add_attribute(diag_field_id, att_name, (/att_value /))
4515  else
4516  CALL diag_field_add_attribute_i1d(diag_field_id, att_name, (/ att_value /))
4517  endif
4518  END SUBROUTINE diag_field_add_attribute_scalar_i
4519 
4520  !> @brief Add a scalar character attribute to the diag field corresponding to a given id
4521  SUBROUTINE diag_field_add_attribute_scalar_c(diag_field_id, att_name, att_value)
4522  INTEGER, INTENT(in) :: diag_field_id !< ID number for field to add attribute to
4523  CHARACTER(len=*), INTENT(in) :: att_name !< new attribute name
4524  CHARACTER(len=*), INTENT(in) :: att_value !< new attribute value
4525 
4526  if (use_modern_diag) then
4527  call fms_diag_object%fms_diag_field_add_attribute(diag_field_id, att_name, (/att_value /))
4528  else
4529  CALL diag_field_attribute_init(diag_field_id, att_name, nf90_char, cval=att_value)
4530  endif
4531  END SUBROUTINE diag_field_add_attribute_scalar_c
4532 
4533  !> @brief Add a real 1D array attribute to the diag field corresponding to a given id
4534  SUBROUTINE diag_field_add_attribute_r1d(diag_field_id, att_name, att_value)
4535  INTEGER, INTENT(in) :: diag_field_id !< ID number for field to add attribute to
4536  CHARACTER(len=*), INTENT(in) :: att_name !< new attribute name
4537  REAL, DIMENSION(:), INTENT(in) :: att_value !< new attribute value
4538 
4539  if (use_modern_diag) then
4540  call fms_diag_object%fms_diag_field_add_attribute(diag_field_id, att_name, att_value)
4541  else
4542  CALL diag_field_attribute_init(diag_field_id, att_name, nf90_float, rval=att_value)
4543  endif
4544  END SUBROUTINE diag_field_add_attribute_r1d
4545 
4546  !> @brief Add an integer 1D array attribute to the diag field corresponding to a given id
4547  SUBROUTINE diag_field_add_attribute_i1d(diag_field_id, att_name, att_value)
4548  INTEGER, INTENT(in) :: diag_field_id !< ID number for field to add attribute to
4549  CHARACTER(len=*), INTENT(in) :: att_name !< new attribute name
4550  INTEGER, DIMENSION(:), INTENT(in) :: att_value !< new attribute value
4551 
4552  if (use_modern_diag) then
4553  call fms_diag_object%fms_diag_field_add_attribute(diag_field_id, att_name, att_value)
4554  else
4555  CALL diag_field_attribute_init(diag_field_id, att_name, nf90_int, ival=att_value)
4556  endif
4557  END SUBROUTINE diag_field_add_attribute_i1d
4558 
4559  !> @brief Add the cell_measures attribute to a diag out field
4560  !!
4561  !> Add the cell_measures attribute to a give diag field. This is useful if the
4562  !! area/volume fields for the diagnostic field are defined in another module after
4563  !! the diag_field.
4564  SUBROUTINE diag_field_add_cell_measures(diag_field_id, area, volume)
4565  INTEGER, INTENT(in) :: diag_field_id
4566  INTEGER, INTENT(in), OPTIONAL :: area !< diag ids of area
4567  INTEGER, INTENT(in), OPTIONAL :: volume !< diag ids of volume
4568 
4569  integer :: j, ind
4570 
4571  IF ( diag_field_id.GT.0 ) THEN
4572  IF ( .NOT.PRESENT(area) .AND. .NOT.present(volume) ) THEN
4573  CALL error_mesg('diag_manager_mod::diag_field_add_cell_measures', &
4574  & 'either area or volume arguments must be present', fatal )
4575  END IF
4576 
4577  if (use_modern_diag) then
4578  call fms_diag_object%fms_diag_field_add_cell_measures(diag_field_id, area, volume)
4579  return
4580  ENDIF
4581 
4582  DO j=1, input_fields(diag_field_id)%num_output_fields
4583  ind = input_fields(diag_field_id)%output_fields(j)
4584  CALL init_field_cell_measures(output_fields(ind), area=area, volume=volume)
4585  END DO
4586  END IF
4587  END SUBROUTINE diag_field_add_cell_measures
4588 
4589  !> @brief Copies a 3d buffer to a 4d buffer
4590  subroutine copy_3d_to_4d(data_in, data_out, field_name)
4591  class(*), intent(in) :: data_in(:,:,:) !< Data to copy
4592  character(len=*), intent(in) :: field_name !< Name of the field copying (for error messages)
4593  class(*), allocatable, intent(out) :: data_out(:,:,:,:) !< 4D version of the data
4594 
4595  !TODO this should be extended to integers
4596  select type(data_in)
4597  type is (real(kind=r8_kind))
4598  allocate(real(kind=r8_kind) :: data_out(1:size(data_in,1), 1:size(data_in,2), 1:size(data_in,3), 1))
4599  select type (data_out)
4600  type is (real(kind=r8_kind))
4601  data_out(:,:,:,1) = data_in
4602  class default
4603  call mpp_error(fatal, "The copy of "//trim(field_name)//&
4604  " was not allocated to the correct type (r8_kind). This shouldn't have happened")
4605  end select
4606  type is (real(kind=r4_kind))
4607  allocate(real(kind=r4_kind) :: data_out(1:size(data_in,1), 1:size(data_in,2), 1:size(data_in,3), 1))
4608  select type (data_out)
4609  type is (real(kind=r4_kind))
4610  data_out(:,:,:,1) = data_in
4611  class default
4612  call mpp_error(fatal, "The copy of "//trim(field_name)//&
4613  " was not allocated to the correct type (r4_kind). This shouldn't have happened")
4614  end select
4615  class default
4616  call mpp_error(fatal, "The data for "//trim(field_name)//&
4617  &" is not a valid type. Currently only r4 and r8 are supported")
4618  end select
4619  end subroutine copy_3d_to_4d
4620 
4621 END MODULE diag_manager_mod
4622 !> @}
4623 ! close documentation grouping
integer(i4_kind) function, public axis_compatible_check(id, varname)
Checks if the axes are compatible.
Definition: diag_axis.F90:745
integer function, public get_axis_length(id)
Return the length of the axis.
Definition: diag_axis.F90:612
integer function, public get_axis_num(axis_name, set_name)
Returns index into axis table corresponding to a given axis name.
Definition: diag_axis.F90:847
type(domain2d) function, public get_domain2d(ids)
Return the 2D domain for the axis IDs given.
Definition: diag_axis.F90:699
integer function, public get_tile_count(ids)
Return the tile count for the axis.
Definition: diag_axis.F90:659
subroutine, public get_diag_axis_name(id, axis_name)
Return the short name of the axis.
Definition: diag_axis.F90:589
integer(i4_kind), parameter, public diag_axis_2ddomain
For unstructured grid support.
Definition: diag_axis.F90:63
integer function, public diag_axis_init(name, array_data, units, cart_name, long_name, direction, set_name, edges, Domain, Domain2, DomainU, aux, req, tile_count, domain_position)
Initialize the axis, and return the axis ID.
Definition: diag_axis.F90:111
integer(i4_kind), parameter, public diag_axis_ugdomain
For unstructured grid support.
Definition: diag_axis.F90:64
Add an arbitrary attribute and value to the diagnostic axis.
Definition: diag_axis.F90:89
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 pack_size
1 for double and 2 for float
Definition: diag_data.F90:408
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 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 max_axis_attributes
Maximum number of user definable attributes per axis.
Definition: diag_data.F90:385
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
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
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 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 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
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
subroutine diag_data_init()
Initialize and write the version number of this file to the log file.
Definition: diag_data.F90:450
integer function get_base_month()
gets the module variable base_month
Definition: diag_data.F90:527
logical module_is_initialized
Indicate if diag_manager has been initialized.
Definition: diag_data.F90:439
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
logical use_refactored_send
Namelist flag to use refactored send_data math funcitons.
Definition: diag_data.F90:390
integer max_field_attributes
Maximum number of user definable attributes per field. Liptak: Changed from 2 to 4 20170718.
Definition: diag_data.F90:382
Define the region for field output.
Definition: diag_data.F90:171
Type to hold the output field description.
Definition: diag_data.F90:249
subroutine, public diag_grid_init(domain, glo_lat, glo_lon, aglo_lat, aglo_lon)
Send the global grid to the diag_manager_mod for regional output.
Definition: diag_grid.F90:132
subroutine, public diag_grid_end()
Unallocate the diag_global_grid variable.
Definition: diag_grid.F90:350
logical function, public need_data(diag_field_id, next_model_time)
Determine whether data is needed for the current model time step.
logical function get_related_field(field, rel_field, out_field_id, out_file_id)
Finds the corresponding related output field and file for a given input field.
logical function send_data_2d(diag_field_id, field, time, is_in, js_in, mask, rmask, ie_in, je_in, weight, err_msg)
integer function register_diag_field_scalar(module_name, field_name, init_time, long_name, units, missing_value, range, standard_name, do_not_log, err_msg, area, volume, realm, multiple_send_data)
Registers a scalar field.
subroutine diag_field_add_attribute_r1d(diag_field_id, att_name, att_value)
Add a real 1D array attribute to the diag field corresponding to a given id.
integer function, public register_static_field(module_name, field_name, axes, long_name, units, missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method, tile_count, area, volume, realm)
Return field index for subsequent call to send_data.
subroutine copy_3d_to_4d(data_in, data_out, field_name)
Copies a 3d buffer to a 4d buffer.
logical function send_data_4d(diag_field_id, field, time, is_in, js_in, ks_in, mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
Updates the output buffer for a field based on the data for current time step.
subroutine diag_field_attribute_init(diag_field_id, name, type, cval, ival, rval)
logical function send_tile_averaged_data3d(id, field, area, time, mask)
integer function register_diag_field_array(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, area, volume, realm, multiple_send_data)
Registers an array field.
integer function register_diag_field_scalar_old(module_name, field_name, init_time, long_name, units, missing_value, range, standard_name, do_not_log, err_msg, area, volume, realm)
Registers a scalar field.
subroutine diag_field_add_attribute_i1d(diag_field_id, att_name, att_value)
Add an integer 1D array attribute to the diag field corresponding to a given id.
integer function register_static_field_old(module_name, field_name, axes, long_name, units, missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method, tile_count, area, volume, realm)
Return field index for subsequent call to send_data.
subroutine closing_file(file, time)
Replaces diag_manager_end; close just one file: files(file)
subroutine, public diag_field_add_cell_measures(diag_field_id, area, volume)
Add the cell_measures attribute to a diag out field.
subroutine init_field_cell_measures(output_field, area, volume, err_msg)
If needed, add cell_measures and associated_file attribute to out field/file.
integer function register_diag_field_array_old(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, area, volume, realm)
Registers an array field.
subroutine, public diag_send_complete_instant(time)
The subroutine 'diag_send_complete_instant' allows the user to save diagnostic data on variable inter...
subroutine diag_field_add_attribute_scalar_i(diag_field_id, att_name, att_value)
Add a scalar integer attribute to the diag field corresponding to a given id.
subroutine average_tiles(diag_field_id, x, area, mask, out)
Calculates tile average of a field.
logical function send_data_0d(diag_field_id, field, time, err_msg)
subroutine add_associated_files(file_num, cm_file_num, cm_ind)
Add to the associated files attribute.
integer function writing_field(out_num, at_diag_end, error_string, time)
subroutine, public diag_manager_init(diag_model_subset, time_init, err_msg)
Initialize Diagnostics Manager.
integer function, public get_diag_field_id(module_name, field_name)
Return the diagnostic field ID of a given variable.
subroutine, public get_base_date(year, month, day, hour, minute, second)
Return base date for diagnostics.
subroutine diag_field_add_attribute_scalar_r(diag_field_id, att_name, att_value)
Add a scalar real attribute to the diag field corresponding to a given id.
logical function send_data_3d(diag_field_id, field, time, is_in, js_in, ks_in, mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
subroutine average_tiles1d(diag_field_id, x, area, mask, out)
Calculates average for a field with the given area and land mask.
logical function diag_send_data(diag_field_id, field, time, is_in, js_in, ks_in, mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
logical function send_tile_averaged_data1d(id, field, area, time, mask)
logical function send_data_1d(diag_field_id, field, time, is_in, mask, rmask, ie_in, weight, err_msg)
subroutine, public diag_manager_end(time)
Flushes diagnostic buffers where necessary. Close diagnostics files. A warning will be issued here if...
logical function send_tile_averaged_data2d(id, field, area, time, mask)
integer function init_diurnal_axis(n_samples)
Finds or initializes a diurnal time axis and returns its' ID.
subroutine diag_field_add_attribute_scalar_c(diag_field_id, att_name, att_value)
Add a scalar character attribute to the diag field corresponding to a given id.
subroutine, public diag_send_complete(time_step, err_msg)
Saves diagnostic data for the given time value.
Add a attribute to the output field.
Register a diagnostic field for a given module.
Send data over to output fields.
Send tile-averaged data over to output fields.
subroutine, public get_diag_global_att(gAtt)
Return the global attribute type.
subroutine, public set_diag_global_att(component, gridType, tileName)
Set the global attribute type.
subroutine, public parse_diag_table(diag_subset, istat, err_msg)
Parse the diag_table in preparation for diagnostic output.
Definition: diag_table.F90:318
subroutine, public get_subfield_size(axes, outnum)
Get the size, start, and end indices for output fields.
Definition: diag_util.F90:135
subroutine, public init_input_field(module_name, field_name, tile_count)
Initialize the input field.
Definition: diag_util.F90:1311
subroutine, public check_bounds_are_exact_static(out_num, diag_field_id, err_msg)
Check if the array indices for output_fields(out_num) are equal to the output_fields(out_num)buffer u...
Definition: diag_util.F90:1018
integer function, public find_input_field(module_name, field_name, tile_count)
Return the field number for the given module name, field name, and tile number.
Definition: diag_util.F90:1292
subroutine, public write_static(file)
Output all static fields in this file.
Definition: diag_util.F90:2207
subroutine, public diag_data_out(file, field, dat, time, final_call_in, static_write_in, filename_time)
Write data out to file, and if necessary flush the buffers.
Definition: diag_util.F90:2057
subroutine, public init_output_field(module_name, field_name, output_name, output_file, time_method, pack, tile_count, local_coord)
Initialize the output field.
Definition: diag_util.F90:1344
type(time_type) function, public get_file_start_time(file_num)
Get the a diag_file's start_time as it is defined in the diag_table.
Definition: diag_util.F90:2503
subroutine, public sync_file_times(file_id, init_time, err_msg)
Synchronize the file's start and close times with the model start and end times.
Definition: diag_util.F90:1245
character(len=1), public field_log_separator
separator used for csv-style log of registered fields set by nml in diag_manager init
Definition: diag_util.F90:117
subroutine, public check_out_of_bounds(out_num, diag_field_id, err_msg)
Checks if the array indices for output_fields(out_num) are outside the output_fields(out_num)buffer u...
Definition: diag_util.F90:843
subroutine, public get_subfield_vert_size(axes, outnum)
Get size, start and end indices for output fields.
Definition: diag_util.F90:417
subroutine, public log_diag_field_info(module_name, field_name, axes, long_name, units, missing_value, range, dynamic)
Writes brief diagnostic field info to the log file.
Definition: diag_util.F90:637
subroutine, public update_bounds(out_num, lower_i, upper_i, lower_j, upper_j, lower_k, upper_k)
Update the output_fields x, y, and z min and max boundaries (array indices) with the six specified bo...
Definition: diag_util.F90:748
subroutine, public diag_util_init()
Write the version number of this file to the log file.
Definition: diag_util.F90:125
subroutine, public check_bounds_are_exact_dynamic(out_num, diag_field_id, Time, err_msg)
This is an adaptor to the check_bounds_are_exact_dynamic_modern function to maintain an interface ser...
Definition: diag_util.F90:991
Allocates the atttype in out_file.
Definition: diag_util.F90:98
Prepend a value to a string attribute in the output field or output file.
Definition: diag_util.F90:91
Interface fieldbuff_copy_fieldvals updates elements of the field output buffer with copies of corresp...
Interface fieldbuff_copy_missvals updates elements of the field output buffer with the missvalue inpu...
Interface fieldbuff_update updates elements of field output buffer based on input field data and math...
Class fmsDiagOutfield_type (along with class ms_diag_outfield_index_type ) contain information used i...
Class fms_diag_outfield_index_type which (along with class fmsDiagOutfield_type) encapsulate related ...
integer function, public check_nml_error(IOSTAT, NML_NAME)
Checks the iostat argument that is returned after reading a namelist and determines if the error code...
Definition: fms.F90:580
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
logical function, public fms_error_handler(routine, message, err_msg)
Facilitates the control of fatal error conditions.
Definition: fms.F90:525
subroutine, public error_mesg(routine, message, level)
Print notes, warnings and error messages; terminates program for warning and error messages....
Definition: fms.F90:498
integer function stdout()
This function returns the current standard fortran unit numbers for output.
Definition: mpp_util.inc:43
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_npes()
Returns processor count for current pelist.
Definition: mpp_util.inc:392
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:378
Error handler.
Definition: mpp.F90:382
Reduction operation.
Definition: mpp.F90:597
integer function, public get_ticks_per_second()
Returns the number of ticks per second.
subroutine, public get_time(Time, seconds, days, ticks, err_msg)
Returns days and seconds ( < 86400 ) corresponding to a time. err_msg should be checked for any error...
subroutine, public get_date(time, year, month, day, hour, minute, second, tick, err_msg)
Gets the date for different calendar types. Given a time_interval, returns the corresponding date und...
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.