FV3 Bundle
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 
21 #include <fms_platform.h>
22  ! <CONTACT EMAIL="Matthew.Harrison@gfdl.noaa.gov">
23  ! Matt Harrison
24  ! </CONTACT>
25  ! <CONTACT EMAIL="Giang.Nong@noaa.gov">
26  ! Giang Nong
27  ! </CONTACT>
28  ! <CONTACT EMAIL="seth.underwood@noaa.gov">
29  ! Seth Underwood
30  ! </CONTACT>
31  ! <HISTORY SRC="http://www.gfdl.noaa.gov/fms-cgi-bin/cvsweb.cgi/FMS/" />
32  ! <OVERVIEW>
33  ! <TT>diag_manager_mod</TT> is a set of simple calls for parallel diagnostics
34  ! on distributed systems. It is geared toward the writing of data in netCDF
35  ! format.
36  ! </OVERVIEW>
37  ! <DESCRIPTION>
38  ! <TT>diag_manager_mod</TT> provides a convenient set of interfaces for
39  ! writing data to disk. It is built upon the parallel I/O interface of FMS
40  ! code <TT>/shared/mpp/mpp_io.F90</TT>.
41  !
42  ! A single group of calls to the <TT>diag_manager_mod</TT> interfaces
43  ! provides data to disk at any number of sampling and/or averaging intervals
44  ! specified at run-time. Run-time specification of diagnostics are input
45  ! through the diagnostics table.
46  !
47  ! <H4>Usage</H4>
48  ! Use of <TT>diag_manager</TT> includes the following steps:
49  ! <OL>
50  ! <LI> Create diag_table as described in the
51  ! <LINK SRC="diag_table.html">diag_table.F90</LINK>
52  ! documentation.</LI>
53  ! <LI> Call <LINK SRC="#diag_manager_init"><TT>diag_manager_init</TT></LINK> to initialize
54  ! diag_manager_mod.</LI>
55  ! <LI> Call <LINK SRC="#register_diag_field"><TT>register_diag_field</TT></LINK> to register the field to be
56  ! output.
57  ! <B>NOTE:</B> ALL fields in diag_table should be registered <I>BEFORE</I>
58  ! the first send_data call</LI>
59  ! <LI> Call <LINK SRC="#send_data"><TT>send_data</TT></LINK> to send data to output fields </LI>
60  ! <LI> Call <LINK SRC="#diag_manager_end"><TT>diag_manager_end</TT></LINK> to exit diag_manager </LI>
61  ! </OL>
62  !
63  ! <H4>Features</H4>
64  ! Features of <TT>diag_manager_mod</TT>:
65  ! <OL>
66  ! <LI> Ability to output from 0D arrays (scalars) to 3D arrays.</LI>
67  ! <LI> Ability to output time average of fields that have time dependent
68  ! mask.</LI>
69  ! <LI> Give optional warning if <TT>register_diag_field</TT> fails due to
70  ! misspelled module name or field name.</LI>
71  ! <LI> Check if a field is registered twice.</LI>
72  ! <LI> Check for duplicate lines in diag_table. </LI>
73  ! <LI> <LINK SRC="diag_table.html">diag_table</LINK> can contain fields
74  ! that are NOT written to any files. The file name in diag_table of
75  ! these fields is <TT>null</TT>.</LI>
76  ! <LI> By default, a field is output in its global grid. The user can now
77  ! output a field in a specified region. See
78  ! <LINK SRC="#send_data"><TT>send_data</TT></LINK> for more details.</LI>
79  ! <LI> To check if the diag table is set up correctly, user should set
80  ! <TT>debug_diag_manager=.true.</TT> in diag_manager namelist, then
81  ! the the content of diag_table is printed in stdout.</LI>
82  ! <LI> New optional format of file information in <LINK SRC="diag_table.html">diag_table</LINK>.It is possible to have just
83  ! one file name and reuse it many times. A time string will be appended to the base file name each time a new file is
84  ! opened. The time string can be any combination from year to second of current model time.
85  !
86  ! Here is an example file line: <BR />
87  ! <PRE>"file2_yr_dy%1yr%3dy",2,"hours",1,"hours","Time", 10, "days", "1 1 7 0 0 0", 6, "hours"</PRE>
88  ! <BR />
89  !
90  ! From left to right we have:
91  ! <UL>
92  ! <LI>file name</LI>
93  ! <LI>output frequency</LI>
94  ! <LI>output frequency unit</LI>
95  ! <LI>Format (should always be 1)</LI>
96  ! <LI>time axis unit</LI>
97  ! <LI>time axis name</LI>
98  ! <LI>frequency for creating new file</LI>
99  ! <LI>unit for creating new file</LI>
100  ! <LI>start time of the new file</LI>
101  ! <LI>file duration</LI>
102  ! <LI>file duration unit.</LI>
103  ! </UL>
104  ! The 'file duration', if absent, will be equal to frequency for creating a new file.
105  !
106  ! Thus, the above means: create a new file every 10 days, each file will last 6 hours from creation time, no files will
107  ! be created before time "1 1 7 0 0 0".
108  !
109  ! In this example the string
110  ! <TT>10, "days", "1 1 7 0 0 0", 6, "hours"</TT> is optional.
111  !
112  ! Keywords for the time string suffix is
113  ! <TT>%xyr,%xmo,%xdy,%xhr,%xmi,%xsc</TT> where <TT>x</TT> is a
114  ! mandatory 1 digit number specifying the width of field used in
115  ! writing the string</LI>
116  ! <LI> New time axis for time averaged fields. Users can use a namelist option to handle the time value written
117  ! to time axis for time averaged fields.
118  !
119  ! If <TT>mix_snapshot_average_fields=.true.</TT> then a time averaged file will have time values corresponding to
120  ! ending time_bound e.g. January monthly average is labeled Feb01. Users can have both snapshot and averaged fields in
121  ! one file.
122  !
123  ! If <TT>mix_snapshot_average_fields=.false.</TT> The time value written to time axis for time averaged fields is the
124  ! middle on the averaging time. For example, January monthly mean will be written at Jan 16 not Feb 01 as
125  ! before. However, to use this new feature users should <B>separate</B> snapshot fields and time averaged fields in
126  ! <B>different</B> files or a fatal error will occur.
127  !
128  ! The namelist <B>default</B> value is <TT>mix_snapshot_average_fields=.false.</TT></LI>
129  ! <LI> Time average, Root Mean Square, Max and Min, and diurnal. In addition to time average users can also get then Root Mean Square, Max or Min value
130  ! during the same interval of time as time average. For this purpose, in the diag table users must replace
131  ! <TT>.true.</TT> or <TT>.false.</TT> by "<TT>rms</TT>, <TT>max</TT>" or "<TT>min</TT>". <B><I>Note:</I></B> Currently, max
132  ! and min are not available for regional output.
133  !
134  ! A diurnal average or the average of an integer power can also be requested using <TT>diurnal##</TT> or <TT>pow##</TT> where
135  ! <TT>##</TT> are the number of diurnal sections or integer power to average.</LI>
136  ! <LI> <TT>standard_name</TT> is added as optional argument in <LINK SRC="#register_diag_field"><TT>register_diag_field</TT>
137  ! </LINK>.</LI>
138  ! <LI>When namelist variable <TT>debug_diag_manager = .true.</TT> array
139  ! bounds are checked in <LINK SRC="#send_data"><TT>send_data</TT></LINK>.</LI>
140  ! <LI>Coordinate attributes can be written in the output file if the
141  ! argument "<TT>aux</TT>" is given in <LINK SRC="diag_axis.html#diag_axis_init"><TT>diag_axis_init</TT></LINK>. The
142  ! corresponding fields (geolat/geolon) should also be written to the
143  ! same file.</LI>
144  ! </OL>
145  !
146  ! </DESCRIPTION>
147 
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 valid range. This range is defined in
176  ! the model, and passed to the <TT>diag_manager_mod</TT> via the OPTIONAL variable range in the <TT>register_diag_field</TT>
177  ! function.
178  ! </DATA>
179  ! <DATA NAME="oor_warnings_fatal" TYPE="LOGICAL" DEFAULT=".FALSE.">
180  ! If <TT>.TRUE.</TT> then <TT>diag_manager_mod</TT> will issue a <TT>FATAL</TT> error if any values for the output field are
181  ! outside the given range.
182  ! </DATA>
183  ! <DATA NAME="max_field_attributes" TYPE="INTEGER" DEFAULT="4">
184  ! Maximum number of user definable attributes per field.
185  ! </DATA>
186  ! <DATA NAME="max_file_attributes" TYPE="INTEGER" DEFAULT="2">
187  ! Maximum number of user definable global attributes per file.
188  ! </DATA>
189  ! <DATA NAME="prepend_date" TYPE="LOGICAL" DEFAULT=".TRUE.">
190  ! If <TT>.TRUE.</TT> then prepend the file start date to the output file. <TT>.TRUE.</TT> is only supported if the
191  ! diag_manager_init routine is called with the optional time_init parameter. Note: This was usually done by FRE after the
192  ! model run.
193  ! </DATA>
194  ! <DATA NAME="region_out_use_alt_value" TYPE="LOGICAL" DEFAULT=".TRUE.">
195  ! Will determine which value to use when checking a regional output if the region is the full axis or a sub-axis.
196  ! The values are defined as <TT>GLO_REG_VAL</TT> (-999) and <TT>GLO_REG_VAL_ALT</TT> (-1) in <TT>diag_data_mod</TT>.
197  ! </DATA>
198  ! </NAMELIST>
199 
200  USE time_manager_mod, ONLY: set_time, set_date, get_time, time_type, OPERATOR(>=), OPERATOR(>),&
201  & OPERATOR(<), OPERATOR(==), OPERATOR(/=), OPERATOR(/), OPERATOR(+), ASSIGNMENT(=), get_date, &
203  USE mpp_io_mod, ONLY: mpp_open, mpp_close, mpp_get_maxunits
204  USE mpp_mod, ONLY: mpp_get_current_pelist, mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
205 
206 #ifdef INTERNAL_FILE_NML
207  USE mpp_mod, ONLY: input_nml_file
208 #else
209  USE fms_mod, ONLY: open_namelist_file, close_file
210 #endif
211 
212  USE fms_mod, ONLY: error_mesg, fatal, warning, note, stdout, stdlog, write_version_number,&
213  & file_exist, fms_error_handler, check_nml_error, get_mosaic_tile_file, lowercase
238  USE constants_mod, ONLY: seconds_per_day
239 
240 #ifdef use_netCDF
241  USE netcdf, ONLY: nf90_int, nf90_float, nf90_char
242 #endif
243 
244 !----------
245 !ug support
248 !----------
249 
250  IMPLICIT NONE
251 
252  PRIVATE
259  ! Public interfaces from diag_grid_mod
260  PUBLIC :: diag_grid_init, diag_grid_end
263  ! Public interfaces from diag_data_mod
264  PUBLIC :: diag_field_not_found
265 
266  ! version number of this module
267  ! Include variable "version" to be written to log file.
268 #include<file_version.h>
269 
271 
272  ! <INTERFACE NAME="send_data">
273  ! <TEMPLATE>
274  ! send_data(diag_field_id, field, time, is_in, js_in, ks_in,
275  ! mask, rmask, ie_in, je_in, ke_in, weight)
276  ! </TEMPLATE>
277  ! <OVERVIEW>
278  ! Send data over to output fields.
279  ! </OVERVIEW>
280  ! <DESCRIPTION>
281  ! <TT>send_data</TT> is overloaded for fields having zero dimension
282  ! (scalars) to 3 dimension. <TT>diag_field_id</TT> corresponds to the id
283  ! returned from a previous call to <TT>register_diag_field</TT>. The field
284  ! array is restricted to the computational range of the array. Optional
285  ! argument <TT>is_in</TT> can be used to update sub-arrays of the entire
286  ! field. Additionally, an optional logical or real mask can be used to
287  ! apply missing values to the array.
288  !
289  ! If a field is declared to be <TT>mask_variant</TT> in
290  ! <TT>register_diag_field</TT> logical mask should be mandatory.
291  !
292  ! For the real mask, the mask is applied if the mask value is less than
293  ! 0.5.
294  !
295  ! By default, a field will be written out entirely in its global grid.
296  ! Users can also specify regions in which the field will be output. The
297  ! region is specified in diag-table just before the end of output_field
298  ! replacing "none".
299  !
300  ! For example, by default:
301  !
302  ! "ocean_mod","Vorticity","vorticity","file1","all",.false.,"none",2
303  !
304  ! for regional output:
305  !
306  ! "ocean_mod","Vorticity","vorticity_local","file2","all",.false.,"0.5 53.5 -89.5 -28.5 -1 -1",2
307  !
308  ! The format of a region is "<TT>xbegin xend ybegin yend zbegin zend</TT>".
309  ! If it is a 2D field use (-1 -1) for (zbegin zend) as in the example above.
310  ! For a 3D field use (-1 -1) for (zbegin zend) when you want to write the
311  ! entire vertical extent, otherwise specify real coordinates. The units
312  ! used for region are the actual units used in grid_spec.nc (for example
313  ! degrees for lat, lon). <B><I>NOTE:</I></B> A FATAL error will occur if
314  ! the region's boundaries are not found in grid_spec.nc.
315  !
316  ! Regional output on the cubed sphere grid is also supported. To use regional
317  ! output on the cubed sphere grid, first the grid information needs to be sent to
318  ! <TT>diag_manager_mod</TT> using the <LINK
319  ! SRC="diag_grid.html#diag_grid_init"><TT> diag_grid_init</TT></LINK>
320  ! subroutine.
321  !
322  ! <B><I>NOTE:</I></B> 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  ! Time averaging is supported in regional output.
329  !
330  ! Physical fields (written in "physics windows" of atmospheric code) are
331  ! fully supported for regional outputs.
332  !
333  ! <B><I>NOTE:</I></B> Most fields are defined in the data domain but use the
334  ! compute domain. In <TT>send_data</TT> the field can be passed in either
335  ! the data domain or in the compute domain. If the data domain is used, the
336  ! start and end indicies of the compute domain (isc, iec, . . .) should be
337  ! passed. If the compute domain is used no indices are needed. The indices
338  ! are for determining halo exclusively. If users want to output the field
339  ! partially they should use regional output as mentioned above.
340  !
341  ! Weight in Time averaging is now supported, each time level may have a
342  ! different weight. The default of weight is 1.
343  ! </DESCRIPTION>
344  ! <IN NAME="diag_field_id" TYPE="INTEGER"> </IN>
345  ! <IN NAME="field" TYPE="REAL, DIMENSION(:,:,:)"> </IN>
346  ! <IN NAME="time" TYPE="TYPE(time_type)"> </IN>
347  ! <IN NAME="is_in" TYPE="INTEGER, OPTIONAL"></IN>
348  ! <IN NAME="js_in" TYPE="INTEGER, OPTIONAL"></IN>
349  ! <IN NAME="ks_in" TYPE="INTEGER, OPTIONAL"></IN>
350  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:), OPTIONAL"></IN>
351  ! <IN NAME="rmask" TYPE="REAL, DIMENSION(:,:,:), OPTIONAL"></IN>
352  ! <IN NAME="ie_in" TYPE="INTEGER, OPTIONAL"></IN>
353  ! <IN NAME="je_in" TYPE="INTEGER, OPTIONAL"></IN>
354  ! <IN NAME="ke_in" TYPE="INTEGER, OPTIONAL"></IN>
355  ! <IN NAME="weight" TYPE="REAL, OPTIONAL"></IN>
356  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"></OUT>
357  INTERFACE send_data
358  MODULE PROCEDURE send_data_0d
359  MODULE PROCEDURE send_data_1d
360  MODULE PROCEDURE send_data_2d
361  MODULE PROCEDURE send_data_3d
362 #ifdef OVERLOAD_R8
363  MODULE PROCEDURE send_data_2d_r8
364  MODULE PROCEDURE send_data_3d_r8
365 #endif
366  END INTERFACE
367  ! </INTERFACE>
368 
369  ! <INTERFACE NAME="register_diag_field">
370  ! <OVERVIEW>
371  ! Register Diagnostic Field.
372  ! </OVERVIEW>
373  ! <TEMPLATE>
374  ! INTEGER FUNCTION register_diag_field (module_name, field_name, axes, init_time,
375  ! long_name, units, missing_value, range, mask_variant, standard_name,
376  ! verbose, area, volume, realm)
377  ! </TEMPLATE>
378  ! <DESCRIPTION>
379  ! Return field index for subsequent calls to
380  ! <LINK SRC="#send_data">send_data</LINK>.
381  !
382  ! <TT>axes</TT> are the axis ID returned from <TT>diag_axis_init</TT>,
383  ! <TT>axes</TT> are required for fields of 1-3 dimension and NOT required
384  ! for scalars.
385  !
386  ! For a static scalar (constant) <TT>init_time</TT> is not needed.
387  !
388  ! Optional <TT>mask_variant</TT> is for fields that have a time-dependent
389  ! mask. If <TT>mask_variant</TT> is true then <TT>mask</TT> must be
390  ! present in argument list of <TT>send_data</TT>.
391  !
392  ! The pair (<TT>module_name</TT>, <TT>fieldname</TT>) should be registered
393  ! only once or a FATAL error will occur.
394  ! </DESCRIPTION>
395  ! <IN NAME="module_name" TYPE="CHARACTER(len=*)" />
396  ! <IN NAME="field_name" TYPE="CHARACTER(len=*)" />
397  ! <IN NAME="axes" TYPE="INTEGER, DIMENSION(:)" />
398  ! <IN NAME="init_time" TYPE="TYPE(time_type)" />
399  ! <IN NAME="long_name" TYPE="CHARACTER(len=*)" />
400  ! <IN NAME="units" TYPE="CHARACTER(len=*)" />
401  ! <IN NAME="missing_value" TYPE="REAL" />
402  ! <IN NAME="range" TYPE="REAL, DIMENSION(2)" />
403  ! <IN NAME="mask_variant" TYPE="LOGICAL" />
404  ! <IN NAME="standard_name" TYPE="CHARACTER(len=*)" />
405  ! <IN NAME="area" TYPE="INTEGER, OPTIONAL" />
406  ! <IN NAME="volume" TYPE="INTEGER, OPTIONAL" />
407  ! <IN NAME="realm" TYPE="CHARACTER(len=*), OPTIONAL" />
409  MODULE PROCEDURE register_diag_field_scalar
410  MODULE PROCEDURE register_diag_field_array
411  END INTERFACE
412  ! </INTERFACE>
413 
414  ! <INTERFACE NAME="send_tile_averaged_data">
415  ! <OVERVIEW>
416  ! Send tile-averaged data over to output fields.
417  ! </OVERVIEW>
418  ! <TEMPLATE>
419  ! LOGICAL send_tile_averaged_data(diag_field_id, field, area, time, mask)
420  ! </TEMPLATE>
421  ! <DESCRIPTION>
422  ! <TT>send_tile_averaged_data</TT> is overloaded for 3D and 4D arrays.
423  ! <TT>diag_field_id</TT> corresponds to the ID returned by previous call
424  ! to <TT>register_diag_field</TT>. Logical masks can be used to mask out
425  ! undefined and/or unused values. Note that the dimension of output field
426  ! is smaller by one than the dimension of the data, since averaging over
427  ! tiles (3D dimension) is performed.
428  ! </DESCRIPTION>
429  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
430  ! <IN NAME="field" TYPE="REAL" DIM="(:,:,:)" />
431  ! <IN NAME="area" TYPE="REAL" DIM="(:,:,:)" />
432  ! <IN NAME="time" TYPE="TYPE(time_type)" DIM="(:,:,:)" />
433  ! <IN NAME="mask" TYPE="LOGICAL" DIM="(:,:,:)" />
435  MODULE PROCEDURE send_tile_averaged_data1d
436  MODULE PROCEDURE send_tile_averaged_data2d
437  MODULE PROCEDURE send_tile_averaged_data3d
438  END INTERFACE
439  ! </INTERFACE>
440 
441  ! <INTERFACE NAME="diag_field_add_attribute">
442  ! <OVERVIEW>
443  ! Add a attribute to the output field
444  ! </OVERVIEW>
445  ! <TEMPLATE>
446  ! SUBROUTINE diag_field_add_attribute(diag_field_id, att_name, att_value, pack)
447  ! </TEMPLATE>
448  ! <DESCRIPTION>
449  ! Add an arbitrary attribute and value to the output variable. Any number
450  ! of attributes can be added to a given field. All attribute addition must
451  ! be done before first <TT>send_data</TT> call.
452  !
453  ! If a real or integer attribute is already defined, a FATAL error will be called.
454  ! If a character attribute is already defined, then it will be prepended to the
455  ! existing attribute value.
456  ! </DESCRIPTION>
457  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
458  ! <IN NAME="att_name" TYPE="CHARACTER(len=*)" />
459  ! <IN NAME="att_value" TYPE="REAL|INTEGER|CHARACTER(len=*)" />
461  MODULE PROCEDURE diag_field_add_attribute_scalar_r
462  MODULE PROCEDURE diag_field_add_attribute_scalar_i
463  MODULE PROCEDURE diag_field_add_attribute_scalar_c
464  MODULE PROCEDURE diag_field_add_attribute_r1d
465  MODULE PROCEDURE diag_field_add_attribute_i1d
466  END INTERFACE diag_field_add_attribute
467  ! </INTERFACE>
468 
469 CONTAINS
470 
471  ! <FUNCTION NAME="register_diag_field_scalar" INTERFACE="register_diag_field">
472  ! <IN NAME="module_name" TYPE="CHARACTER(len=*)" />
473  ! <IN NAME="field_name" TYPE="CHARACTER(len=*)" />
474  ! <IN NAME="axes" TYPE="Not Applicable" />
475  ! <IN NAME="init_time" TYPE="TYPE(time_type), OPTIONAL" />
476  ! <IN NAME="long_name" TYPE="CHARACTER(len=*), OPTIONAL" />
477  ! <IN NAME="units" TYPE="CHARACTER(len=*), OPTIONAL" />
478  ! <IN NAME="missing_value" TYPE="REAL, OPTIONAL" />
479  ! <IN NAME="range" TYPE="REAL, DIMENSION(2), OPTIONAL" />
480  ! <IN NAME="mask_variant" TYPE="Not Applicable" />
481  ! <IN NAME="standard_name" TYPE="CHARACTER(len=*), OPTIONAL" />
482  ! <IN NAME="do_not_log" TYPE="LOGICAL, OPTIONAL" />
483  ! <IN NAME="area" TYPE="INTEGER, OPTIONAL" />
484  ! <IN NAME="volume" TYPE="INTEGER, OPTIONAL" />
485  ! <IN NAME="realm" TYPE="CHARACTER(len=*), OPTIONAL" />
486  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL" />
487  INTEGER FUNCTION register_diag_field_scalar(module_name, field_name, init_time, &
488  & long_name, units, missing_value, range, standard_name, do_not_log, err_msg,&
489  & area, volume, realm)
490  CHARACTER(len=*), INTENT(in) :: module_name, field_name
491  TYPE(time_type), OPTIONAL, INTENT(in) :: init_time
492  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
493  REAL, OPTIONAL, INTENT(in) :: missing_value
494  REAL, DIMENSION(2), OPTIONAL, INTENT(in) :: range
495  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log ! if TRUE, field information is not logged
496  CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg
497  INTEGER, OPTIONAL, INTENT(in) :: area, volume
498  CHARACTER(len=*), OPTIONAL, INTENT(in):: realm !< String to set as the value to the modeling_realm attribute
499 
500  IF ( PRESENT(err_msg) ) err_msg = ''
501 
502  IF ( PRESENT(init_time) ) THEN
503  register_diag_field_scalar = register_diag_field_array(module_name, field_name,&
504  & (/null_axis_id/), init_time,long_name, units, missing_value, range, &
505  & standard_name=standard_name, do_not_log=do_not_log, err_msg=err_msg,&
506  & area=area, volume=volume, realm=realm)
507  ELSE
508  register_diag_field_scalar = register_static_field(module_name, field_name,&
509  & (/null_axis_id/),long_name, units, missing_value, range,&
510  & standard_name=standard_name, do_not_log=do_not_log, realm=realm)
511  END IF
512  END FUNCTION register_diag_field_scalar
513  ! </FUNCTION>
514 
515  ! <FUNCTION NAME="register_diag_field_array" INTERFACE="register_diag_field">
516  ! <IN NAME="module_name" TYPE="CHARACTER(len=*)" />
517  ! <IN NAME="field_name" TYPE="CHARACTER(len=*)" />
518  ! <IN NAME="axes" TYPE="INTEGER, DIMENSION(:)" />
519  ! <IN NAME="init_time" TYPE="TYPE(time_type)" />
520  ! <IN NAME="long_name" TYPE="CHARACTER(len=*), OPTIONAL" />
521  ! <IN NAME="units" TYPE="CHARACTER(len=*), OPTIONAL" />
522  ! <IN NAME="missing_value" TYPE="REAL, OPTIONAL" />
523  ! <IN NAME="range" TYPE="REAL, DIMENSION(2), OPTIONAL" />
524  ! <IN NAME="mask_variant" TYPE="LOGICAL, OPTIONAL" />
525  ! <IN NAME="standard_name" TYPE="CHARACTER(len=*), OPTIONAL" />
526  ! <IN NAME="do_not_log" TYPE="LOGICAL, OPTIONAL" />
527  ! <IN NAME="interp_method" TYPE="CHARACTER(len=*), OPTIONAL">
528  ! The interp method to be used when regridding the field in post-processing.
529  ! Valid options are "conserve_order1", "conserve_order2", and "none".
530  ! </IN>
531  ! <IN NAME="tile_count" TYPE="INTEGER, OPTIONAL" />
532  ! <IN NAME="area" TYPE="INTEGER, OPTIONAL">diag_field_id containing the cell area field</IN>
533  ! <IN NAME="volume" TYPE="INTEGER, OPTIONAL">diag_field_id containing the cell volume field</IN>
534  ! <IN NAME="realm" TYPE="CHARACTER(len=*), OPTIONAL" />
535  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL" />
536  INTEGER FUNCTION register_diag_field_array(module_name, field_name, axes, init_time, &
537  & long_name, units, missing_value, range, mask_variant, standard_name, verbose,&
538  & do_not_log, err_msg, interp_method, tile_count, area, volume, realm)
539  CHARACTER(len=*), INTENT(in) :: module_name, field_name
540  INTEGER, INTENT(in) :: axes(:)
541  TYPE(time_type), INTENT(in) :: init_time
542  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
543  REAL, OPTIONAL, INTENT(in) :: missing_value, range(2)
544  LOGICAL, OPTIONAL, INTENT(in) :: mask_variant,verbose
545  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log ! if TRUE, field info is not logged
546  CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg
547  CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method
548  INTEGER, OPTIONAL, INTENT(in) :: tile_count
549  INTEGER, OPTIONAL, INTENT(in) :: area, volume
550  CHARACTER(len=*), OPTIONAL, INTENT(in):: realm !< String to set as the value to the modeling_realm attribute
551 
552  INTEGER :: field, j, ind, file_num, freq
553  INTEGER :: i, cm_ind, cm_file_num
554  INTEGER :: output_units
555  INTEGER :: stdout_unit
556  LOGICAL :: mask_variant1, verbose1
557  LOGICAL :: cm_found
558  CHARACTER(len=128) :: msg
559 
560  ! get stdout unit number
561  stdout_unit = stdout()
562 
563  IF ( PRESENT(mask_variant) ) THEN
564  mask_variant1 = mask_variant
565  ELSE
566  mask_variant1 = .false.
567  END IF
568 
569  IF ( PRESENT(verbose) ) THEN
570  verbose1 = verbose
571  ELSE
572  verbose1 = .false.
573  END IF
574 
575  IF ( PRESENT(err_msg) ) err_msg = ''
576 
577  ! Call register static, then set static back to false
578  register_diag_field_array = register_static_field(module_name, field_name, axes,&
579  & long_name, units, missing_value, range, mask_variant1, standard_name=standard_name,&
580  & dynamic=.true., do_not_log=do_not_log, interp_method=interp_method, tile_count=tile_count, realm=realm)
581 
582  IF ( .NOT.first_send_data_call ) THEN
583  ! <ERROR STATUS="WARNING">
584  ! module/output_field <module_name>/<field_name> registered AFTER first
585  ! send_data call, TOO LATE
586  ! </ERROR>
587  IF ( mpp_pe() == mpp_root_pe() ) &
588  & CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
589  &//trim(module_name)//'/'// trim(field_name)//&
590  &' registered AFTER first send_data call, TOO LATE', warning)
591  END IF
592 
593  IF ( register_diag_field_array < 0 ) THEN
594  ! <ERROR STATUS="WARNING">
595  ! module/output_field <modul_name>/<field_name> NOT found in diag_table
596  ! </ERROR>
597  IF ( debug_diag_manager .OR. verbose1 ) THEN
598  IF ( mpp_pe() == mpp_root_pe() ) &
599  & CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
600  &//trim(module_name)//'/'// trim(field_name)//' NOT found in diag_table',&
601  & warning)
602  END IF
603  ELSE
604  input_fields(register_diag_field_array)%static = .false.
606 
607 
608  ! Verify that area and volume do not point to the same variable
609  IF ( PRESENT(volume).AND.PRESENT(area) ) THEN
610  IF ( area.EQ.volume ) THEN
611  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
612  &//trim(module_name)//'/'// trim(field_name)//' AREA and VOLUME CANNOT be the same variable.&
613  & Contact the developers.',&
614  & fatal)
615  END IF
616  END IF
617 
618  ! Check for the existence of the area/volume field(s)
619  IF ( PRESENT(area) ) THEN
620  IF ( area < 0 ) THEN
621  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
622  &//trim(module_name)//'/'// trim(field_name)//' AREA measures field NOT found in diag_table.&
623  & Contact the model liaison.',&
624  & fatal)
625  END IF
626  END IF
627  IF ( PRESENT(volume) ) THEN
628  IF ( volume < 0 ) THEN
629  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
630  &//trim(module_name)//'/'// trim(field_name)//' VOLUME measures field NOT found in diag_table.&
631  & Contact the model liaison.',&
632  & fatal)
633  END IF
634  END IF
635 
636  IF ( PRESENT(standard_name) ) input_fields(field)%standard_name = standard_name
637 
638  DO j = 1, input_fields(field)%num_output_fields
639  ind = input_fields(field)%output_fields(j)
640  output_fields(ind)%static = .false.
641  ! Set up times in output_fields
642  output_fields(ind)%last_output = init_time
643  ! Get output frequency from for the appropriate output file
644  file_num = output_fields(ind)%output_file
645  IF ( file_num == max_files ) cycle
646  IF ( output_fields(ind)%local_output ) THEN
647  IF ( output_fields(ind)%need_compute) THEN
648  files(file_num)%local = .true.
649  END IF
650  END IF
651 
652  ! Need to sync start_time of file with init time of model
653  ! and close_time calculated with the duration of the file.
654  ! Also, increase next_open until it is greater than init_time.
655  CALL sync_file_times(file_num, init_time, err_msg=msg)
656  IF ( msg /= '' ) THEN
657  IF ( fms_error_handler('diag_manager_mod::register_diag_field', trim(msg), err_msg) ) RETURN
658  END IF
659 
660  freq = files(file_num)%output_freq
661  output_units = files(file_num)%output_units
662  output_fields(ind)%next_output = diag_time_inc(init_time, freq, output_units, err_msg=msg)
663  IF ( msg /= '' ) THEN
664  IF ( fms_error_handler('diag_manager_mod::register_diag_field',&
665  & ' file='//trim(files(file_num)%name)//': '//trim(msg),err_msg)) RETURN
666  END IF
667  output_fields(ind)%next_next_output = &
668  & diag_time_inc(output_fields(ind)%next_output, freq, output_units, err_msg=msg)
669  IF ( msg /= '' ) THEN
670  IF ( fms_error_handler('diag_manager_mod::register_diag_field',&
671  &' file='//trim(files(file_num)%name)//': '//trim(msg),err_msg) ) RETURN
672  END IF
673  IF ( debug_diag_manager .AND. mpp_pe() == mpp_root_pe() .AND. output_fields(ind)%local_output ) THEN
674  WRITE (msg,'(" lon(",F5.1,", ",F5.1,"), lat(",F5.1,", ",F5.1,"), dep(",F5.1,", ",F5.1,")")') &
675  & output_fields(ind)%output_grid%start(1),output_fields(ind)%output_grid%end(1),&
676  & output_fields(ind)%output_grid%start(2),output_fields(ind)%output_grid%end(2),&
677  & output_fields(ind)%output_grid%start(3),output_fields(ind)%output_grid%end(3)
678  WRITE(stdout_unit,* ) 'module/output_field '//trim(module_name)//'/'//trim(field_name)// &
679  & ' will be output in region:'//trim(msg)
680  END IF
681 
682  ! Set the cell_measures attribute in the out file
683  CALL init_field_cell_measures(output_fields(ind), area=area, volume=volume, err_msg=err_msg)
684  IF ( len_trim(err_msg).GT.0 ) THEN
685  CALL error_mesg ('diag_manager_mod::register_diag_field',&
686  & trim(err_msg)//' for module/field '//trim(module_name)//'/'//trim(field_name),&
687  & fatal)
688  END IF
689 
690  END DO
691  END IF
692  END FUNCTION register_diag_field_array
693  ! </FUNCTION>
694 
695  ! <FUNCTION NAME="register_static_field">
696  ! <OVERVIEW>
697  ! Register Static Field.
698  ! </OVERVIEW>
699  ! <TEMPLATE>
700  ! INTEGER FUNCTION register_static_field(module_name, field_name, axes,
701  ! long_name, units, missing_value, range, mask_variant, standard_name,
702  ! dynamic, do_not_log, interp_method, tile_count, area, volume, realm)
703  ! </TEMPLATE>
704  ! <DESCRIPTION>
705  ! Return field index for subsequent call to send_data.
706  ! </DESCRIPTION>
707  ! <IN NAME="module_name" TYPE="CHARACTER(len=*)" />
708  ! <IN NAME="field_name" TYPE="CHARACTER(len=*)" />
709  ! <IN NAME="axes" TYPE="INTEGER, DIMENSION(:)" />
710  ! <IN NAME="long_name" TYPE="CHARACTER(len=*), OPTIONAL" />
711  ! <IN NAME="units" TYPE="CHARACTER(len=*), OPTIONAL" />
712  ! <IN NAME="missing_value" TYPE="REAL, OPTIONAL" />
713  ! <IN NAME="range" TYPE="REAL, DIMENSION(2), OPTIONAL" />
714  ! <IN NAME="mask_variang" TYPE="LOGICAL, OPTIONAL" DEFAULT=".FALSE."/>
715  ! <IN NAME="standard_name" TYPE="CHARACTER(len=*), OPTIONAL" />
716  ! <IN NAME="dynamic" TYPE="LOGICAL, OPTIONAL" DEFAULT=".FALSE."/>
717  ! <IN NAME="do_not_log" TYPE="LOGICAL, OPTIONAL" DEFAULT=".TRUE."/>
718  ! <IN NAME="interp_method" TYPE="CHARACTER(len=*), OPTIOANL">
719  ! The interp method to be used when regridding the field in post-processing.
720  ! Valid options are "conserve_order1", "conserve_order2", and "none".
721  ! </IN>
722  ! <IN NAME="tile_count" TYPE="INTEGER, OPTIONAL" />
723  ! <IN NAME="area" TYPE="INTEGER, OPTIONAL">Field ID for the area field associated with this field</IN>
724  ! <IN NAME="volume" TYPE="INTEGER, OPTIONAL">Field ID for the volume field associated with this field</IN>
725  ! <IN NAME="realm" TYPE="CHARACTER(len=*), OPTIONAL" />
726  INTEGER FUNCTION register_static_field(module_name, field_name, axes, long_name, units,&
727  & missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method,&
728  & tile_count, area, volume, realm)
729  CHARACTER(len=*), INTENT(in) :: module_name, field_name
730  INTEGER, DIMENSION(:), INTENT(in) :: axes
731  CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
732  REAL, OPTIONAL, INTENT(in) :: missing_value
733  REAL, DIMENSION(2), OPTIONAL, INTENT(in) :: range
734  LOGICAL, OPTIONAL, INTENT(in) :: mask_variant
735  LOGICAL, OPTIONAL, INTENT(in) :: dynamic
736  LOGICAL, OPTIONAL, INTENT(in) :: do_not_log ! if TRUE, field information is not logged
737  CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method
738  INTEGER, OPTIONAL, INTENT(in) :: tile_count, area, volume
739  CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the value to the modeling_realm attribute
740 
741  REAL :: missing_value_use
742  INTEGER :: field, num_axes, j, out_num, k
743  INTEGER, DIMENSION(3) :: siz, local_siz, local_start, local_end ! indices of local domain of global axes
744  INTEGER :: tile, file_num
745  LOGICAL :: mask_variant1, dynamic1, allow_log
746  CHARACTER(len=128) :: msg
747  INTEGER :: domain_type
748 
749  ! Fatal error if the module has not been initialized.
750  IF ( .NOT.module_is_initialized ) THEN
751  ! <ERROR STATUS="FATAL">diag_manager has NOT been initialized</ERROR>
752  CALL error_mesg ('diag_manager_mod::register_static_field', 'diag_manager has NOT been initialized', fatal)
753  END IF
754 
755  ! Check if OPTIONAL parameters were passed in.
756  IF ( PRESENT(missing_value) ) THEN
757  IF ( use_cmor ) THEN
758  missing_value_use = cmor_missing_value
759  ELSE
760  missing_value_use = missing_value
761  END IF
762  END IF
763 
764  IF ( PRESENT(mask_variant) ) THEN
765  mask_variant1 = mask_variant
766  ELSE
767  mask_variant1 = .false.
768  END IF
769 
770  IF ( PRESENT(dynamic) ) THEN
771  dynamic1 = dynamic
772  ELSE
773  dynamic1 = .false.
774  END IF
775 
776  IF ( PRESENT(tile_count) ) THEN
777  tile = tile_count
778  ELSE
779  tile = 1
780  END IF
781 
782  IF ( PRESENT(do_not_log) ) THEN
783  allow_log = .NOT.do_not_log
784  ELSE
785  allow_log = .true.
786  END IF
787 
788  ! Namelist do_diag_field_log is by default false. Thus to log the
789  ! registration of the data field, but the OPTIONAL parameter
790  ! do_not_log == .FALSE. and the namelist variable
791  ! do_diag_field_log == .TRUE..
792  IF ( do_diag_field_log.AND.allow_log ) THEN
793  CALL log_diag_field_info (module_name, field_name, axes, &
794  & long_name, units, missing_value=missing_value, range=range, &
795  & dynamic=dynamic1)
796  END IF
797 
798  register_static_field = find_input_field(module_name, field_name, 1)
799  field = register_static_field
800  ! Negative index returned if this field was not found in the diag_table.
801  IF ( register_static_field < 0 ) RETURN
802 
803  ! Check that the axes are compatible with each other
804  domain_type = axis_compatible_check(axes,field_name)
805 
806  IF ( tile > 1 ) THEN
807  IF ( .NOT.input_fields(field)%register ) THEN
808  ! <ERROR STATUS="FATAL">
809  ! module/output_field <module_name>/<field_name> is not registered for tile_count = 1,
810  ! should not register for tile_count > 1
811  ! </ERROR>
812  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
813  & trim(field_name)//' is not registered for tile_count = 1, should not register for tile_count > 1',&
814  & fatal)
815  END IF
816 
817  CALL init_input_field(module_name, field_name, tile)
818  register_static_field = find_input_field(module_name, field_name, tile)
819  DO j = 1, input_fields(field)%num_output_fields
820  out_num = input_fields(field)%output_fields(j)
821  file_num = output_fields(out_num)%output_file
822  IF(input_fields(field)%local) THEN
823  CALL init_output_field(module_name, field_name,output_fields(out_num)%output_name,&
824  & files(file_num)%name,output_fields(out_num)%time_method, output_fields(out_num)%pack,&
825  & tile, input_fields(field)%local_coord)
826  ELSE
827  CALL init_output_field(module_name, field_name,output_fields(out_num)%output_name,&
828  & files(file_num)%name,output_fields(out_num)%time_method, output_fields(out_num)%pack, tile)
829  END IF
830  END DO
831  field = register_static_field
832  END IF
833 
834  ! Store information for this input field into input field table
835 
836  ! Set static to true, if called by register_diag_field this is
837  ! flipped back to false
838  input_fields(field)%static = .true.
839  ! check if the field is registered twice
840  IF ( input_fields(field)%register .AND. mpp_pe() == mpp_root_pe() ) THEN
841  ! <ERROR STATUS="FATAL">
842  ! module/output_field <module_name>/<field_name> ALREADY Registered, should
843  ! not register twice
844  ! </ERROR>
845  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
846  & trim(field_name)//' ALREADY registered, should not register twice', fatal)
847  END IF
848 
849  ! Verify that area and volume do not point to the same variable
850  IF ( PRESENT(volume).AND.PRESENT(area) ) THEN
851  IF ( area.EQ.volume ) THEN
852  CALL error_mesg ('diag_manager_mod::register_static_field', 'module/output_field '&
853  &//trim(module_name)//'/'// trim(field_name)//' AREA and VOLUME CANNOT be the same variable.&
854  & Contact the developers.',&
855  & fatal)
856  END IF
857  END IF
858 
859  ! Check for the existence of the area/volume field(s)
860  IF ( PRESENT(area) ) THEN
861  IF ( area < 0 ) THEN
862  CALL error_mesg ('diag_manager_mod::register_static_field', 'module/output_field '&
863  &//trim(module_name)//'/'// trim(field_name)//' AREA measures field NOT found in diag_table.&
864  & Contact the model liaison.n',&
865  & fatal)
866  END IF
867  END IF
868  IF ( PRESENT(volume) ) THEN
869  IF ( volume < 0 ) THEN
870  CALL error_mesg ('diag_manager_mod::register_static_field', 'module/output_field '&
871  &//trim(module_name)//'/'// trim(field_name)//' VOLUME measures field NOT found in diag_table&
872  & Contact the model liaison.',&
873  & fatal)
874  END IF
875  END IF
876 
877  ! Set flag that this field was registered
878  input_fields(field)%register = .true.
879  ! set flag for mask: does it change with time?
880  input_fields(field)%mask_variant = mask_variant1
881  ! Set flag for mask warning
882  input_fields(field)%issued_mask_ignore_warning = .false.
883 
884  ! Check for more OPTIONAL parameters.
885  IF ( PRESENT(long_name) ) THEN
886  input_fields(field)%long_name = trim(long_name)
887  ELSE
888  input_fields(field)%long_name = input_fields(field)%field_name
889  END IF
890 
891  IF ( PRESENT(standard_name) ) input_fields(field)%standard_name = standard_name
892 
893  IF ( PRESENT(units) ) THEN
894  input_fields(field)%units = trim(units)
895  ELSE
896  input_fields(field)%units = 'none'
897  END IF
898 
899  IF ( PRESENT(missing_value) ) THEN
900  input_fields(field)%missing_value = missing_value_use
901  input_fields(field)%missing_value_present = .true.
902  ELSE
903  input_fields(field)%missing_value_present = .false.
904  END IF
905 
906  IF ( PRESENT(range) ) THEN
907  input_fields(field)%range = range
908  ! don't use the range if it is not a valid range
909  input_fields(field)%range_present = range(2) .gt. range(1)
910  ELSE
911  input_fields(field)%range = (/ 1., 0. /)
912  input_fields(field)%range_present = .false.
913  END IF
914 
915  IF ( PRESENT(interp_method) ) THEN
916  IF ( trim(interp_method) .NE. 'conserve_order1' .AND.&
917  & trim(interp_method) .NE. 'conserve_order2' .AND.&
918  & trim(interp_method) .NE. 'none' ) THEN
919  ! <ERROR STATUS="FATAL">
920  ! when registering module/output_field <module_name>/<field_name> then optional
921  ! argument interp_method = <interp_method>, but it should be "conserve_order1",
922  ! "conserve_order2", or "none"
923  ! </ERROR>
924  CALL error_mesg ('diag_manager_mod::register_diag_field',&
925  & 'when registering module/output_field '//trim(module_name)//'/'//&
926  & trim(field_name)//', the optional argument interp_method = '//trim(interp_method)//&
927  & ', but it should be "conserve_order1", "conserve_order2", or "none"', fatal)
928  END IF
929  input_fields(field)%interp_method = trim(interp_method)
930  ELSE
931  input_fields(field)%interp_method = ''
932  END IF
933 
934  ! Store the axis info
935  num_axes = SIZE(axes(:)) ! num_axes should be <= 3.
936  input_fields(field)%axes(1:num_axes) = axes
937  input_fields(field)%num_axes = num_axes
938 
939  siz = 1
940  DO j = 1, num_axes
941  IF ( axes(j) .LE. 0 ) THEN
942  ! <ERROR STATUS="FATAL">
943  ! module/output_field <module_name>/<field_name> has non-positive axis_id
944  ! </ERROR>
945  CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
946  & trim(field_name)//' has non-positive axis_id', fatal)
947  END IF
948  siz(j) = get_axis_length(axes(j))
949  END DO
950 
951  ! Default length for axes is 1
952  DO j = 1, 3
953  input_fields(field)%size(j) = siz(j)
954  END DO
955 
956  local_siz = 1
957  local_start = 1
958  local_end= 1
959  ! Need to loop through all output_fields associated and allocate their buffers
960  DO j = 1, input_fields(field)%num_output_fields
961  out_num = input_fields(field)%output_fields(j)
962  ! Range is required when pack >= 4
963  IF ( output_fields(out_num)%pack>=4 .AND. .NOT.input_fields(field)%range_present ) THEN
964  IF(mpp_pe() .EQ. mpp_root_pe()) THEN
965  ! <ERROR STATUS="FATAL">
966  ! output_field <field_name> has pack >= 4, range is REQUIRED in register_diag_field
967  ! </ERROR>
968  CALL error_mesg ('diag_manager_mod::register_diag_field ', 'output_field '//trim(field_name)// &
969  ' has pack >=4, range is REQUIRED in register_diag_field', fatal)
970  END IF
971  END IF
972  ! reset the number of diurnal samples to 1 if the field is static (and, therefore,
973  ! doesn't vary diurnally)
974  IF ( .NOT.dynamic1 ) output_fields(out_num)%n_diurnal_samples = 1
975 
976  !Check that the domain associated with the inputted field matches
977  !the domain associated output files to which it will be written.
978  file_num = output_fields(out_num)%output_file
979  if (domain_type .eq. diag_axis_2ddomain) then
980  if (files(file_num)%use_domainUG) then
981  call error_mesg("diag_manager_mod::register_static_field", &
982  "Diagnostics living on a structured grid" &
983  //" and an unstructured grid cannot exist" &
984  //" in the same file (" &
985  //trim(files(file_num)%name)//")", &
986  fatal)
987  elseif (.not. files(file_num)%use_domain2D) then
988  files(file_num)%use_domain2D = .true.
989  endif
990  elseif (domain_type .eq. diag_axis_ugdomain) then
991  if (files(file_num)%use_domain2D) then
992  call error_mesg("diag_manager_mod::register_static_field", &
993  "Diagnostics living on a structured grid" &
994  //" and an unstructured grid cannot exist" &
995  //" in the same file (" &
996  //trim(files(file_num)%name)//")", &
997  fatal)
998  elseif (.not. files(file_num)%use_domainUG) then
999  files(file_num)%use_domainUG = .true.
1000  endif
1001  endif
1002 
1003 
1004  ! if local_output (size of output_fields does NOT equal size of input_fields)
1005  IF ( output_fields(out_num)%reduced_k_range ) THEN
1006  CALL get_subfield_vert_size(axes, out_num)
1007 
1008 !----------
1009 !ug support
1010  !Send_data requires that the reduced k dimension be the 3rd dimension
1011  !of the buffer, so set it to be the correct size. If the diagnostic
1012  !is unstructured, set the second dimension of the buffer to be 1.
1013  if (domain_type .eq. diag_axis_ugdomain) then
1014  local_start(2) = output_fields(out_num)%output_grid%l_start_indx(2)
1015  local_end(2) = output_fields(out_num)%output_grid%l_end_indx(2)
1016  local_siz(2) = local_end(2) - local_start(2) + 1
1017  allocate(output_fields(out_num)%buffer(siz(1),local_siz(2),siz(3), &
1018  output_fields(out_num)%n_diurnal_samples))
1019  output_fields(out_num)%region_elements = siz(1)*local_siz(2)*siz(3)
1020  output_fields(out_num)%reduced_k_unstruct = .true.
1021  else
1022  local_start(3) = output_fields(out_num)%output_grid%l_start_indx(3)
1023  local_end(3) = output_fields(out_num)%output_grid%l_end_indx(3)
1024  local_siz(3) = local_end(3) - local_start(3) + 1
1025  allocate(output_fields(out_num)%buffer(siz(1),siz(2),local_siz(3), &
1026  output_fields(out_num)%n_diurnal_samples))
1027  output_fields(out_num)%region_elements = siz(1)*siz(2)*local_siz(3)
1028  output_fields(out_num)%reduced_k_unstruct = .false.
1029  endif
1030  output_fields(out_num)%total_elements = siz(1)*siz(2)*siz(3)
1031 !----------
1032 
1033  IF ( output_fields(out_num)%time_max ) THEN
1034  output_fields(out_num)%buffer = max_value
1035  ELSE IF ( output_fields(out_num)%time_min ) THEN
1036  output_fields(out_num)%buffer = min_value
1037  ELSE
1038  output_fields(out_num)%buffer = empty
1039  END IF
1040  ELSE IF ( output_fields(out_num)%local_output ) THEN
1041  IF ( SIZE(axes(:)) .LE. 1 ) THEN
1042  ! <ERROR STATUS="FATAL">axes of <field_name> must >= 2 for local output</ERROR>
1043  CALL error_mesg ('diag_manager_mod::register_diag_field', 'axes of '//trim(field_name)//&
1044  & ' must >= 2 for local output', fatal)
1045  END IF
1046  CALL get_subfield_size(axes, out_num)
1047  IF ( output_fields(out_num)%need_compute ) THEN
1048  DO k = 1, num_axes
1049  local_start(k) = output_fields(out_num)%output_grid%l_start_indx(k)
1050  local_end(k) = output_fields(out_num)%output_grid%l_end_indx(k)
1051  local_siz(k) = local_end(k) - local_start(k) +1
1052  END DO
1053  ALLOCATE(output_fields(out_num)%buffer(local_siz(1), local_siz(2), local_siz(3),&
1054  & output_fields(out_num)%n_diurnal_samples))
1055  IF(output_fields(out_num)%time_max) THEN
1056  output_fields(out_num)%buffer = max_value
1057  ELSE IF(output_fields(out_num)%time_min) THEN
1058  output_fields(out_num)%buffer = min_value
1059  ELSE
1060  output_fields(out_num)%buffer = empty
1061  END IF
1062  output_fields(out_num)%region_elements = local_siz(1)*local_siz(2)*local_siz(3)
1063  output_fields(out_num)%total_elements = siz(1)*siz(2)*siz(3)
1064  files(output_fields(out_num)%output_file)%local = .true.
1065  END IF
1066  ELSE ! the field is output globally
1067  ! size of output_fields equal size of input_fields
1068  ALLOCATE(output_fields(out_num)%buffer(siz(1), siz(2), siz(3),&
1069  & output_fields(out_num)%n_diurnal_samples))
1070  IF(output_fields(out_num)%time_max) THEN
1071  output_fields(out_num)%buffer = max_value
1072  ELSE IF(output_fields(out_num)%time_min) THEN
1073  output_fields(out_num)%buffer = min_value
1074  ELSE
1075  output_fields(out_num)%buffer = empty
1076  END IF
1077  output_fields(out_num)%total_elements = siz(1)*siz(2)*siz(3)
1078  END IF
1079 
1080  ! Reset to false in register_field if this is not static
1081  output_fields(out_num)%static = .true.
1082  ! check if time average is true for static field
1083  IF ( .NOT.dynamic1 .AND. output_fields(out_num)%time_ops ) THEN
1084  WRITE (msg,'(a,"/",a)') trim(module_name), trim(field_name)
1085  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
1086  ! <ERROR STATUS="WARNING">
1087  ! module/field <module_name>/<field_name> is STATIC.
1088  ! Cannot perform time operations average, maximum or
1089  ! minimum on static fields. Setting the time operation to 'NONE'
1090  ! for this field.
1091  ! </ERROR>
1092  CALL error_mesg ('diag_manager_mod::register_static_field',&
1093  & 'module/field '//trim(msg)//' is STATIC. Cannot perform time operations&
1094  & average, maximum, or minimum on static fields. Setting the time operation&
1095  & to "NONE" for this field.', warning)
1096  END IF
1097  output_fields(out_num)%time_ops = .false.
1098  output_fields(out_num)%time_average = .false.
1099  output_fields(out_num)%time_method = 'point'
1100  END IF
1101 
1102  ! assume that the number of axes of output_fields = that of input_fields
1103  ! this should be changed later to take into account time-of-day axis
1104  output_fields(out_num)%num_axes = input_fields(field)%num_axes
1105  ! Axes are copied from input_fields if output globally or from subaxes if output locally
1106  IF ( .NOT.output_fields(out_num)%local_output ) THEN
1107  output_fields(out_num)%axes(1:input_fields(field)%num_axes) =&
1108  & input_fields(field)%axes(1:input_fields(field)%num_axes)
1109  ELSE
1110  output_fields(out_num)%axes(1:input_fields(field)%num_axes) =&
1111  & output_fields(out_num)%output_grid%subaxes(1:input_fields(field)%num_axes)
1112  END IF
1113 
1114  ! if necessary, initialize the diurnal time axis and append its index in the
1115  ! output field axes array
1116  IF ( output_fields(out_num)%n_diurnal_samples > 1 ) THEN
1117  output_fields(out_num)%axes(output_fields(out_num)%num_axes+1) =&
1118  & init_diurnal_axis(output_fields(out_num)%n_diurnal_samples)
1119  output_fields(out_num)%num_axes = output_fields(out_num)%num_axes+1
1120  END IF
1121 
1122  IF ( output_fields(out_num)%reduced_k_range ) THEN
1123 !----------
1124 !ug support
1125  if (domain_type .eq. diag_axis_ugdomain) then
1126  output_fields(out_num)%axes(2) = output_fields(out_num)%output_grid%subaxes(2)
1127  else
1128  output_fields(out_num)%axes(3) = output_fields(out_num)%output_grid%subaxes(3)
1129  endif
1130 !----------
1131  END IF
1132 
1133  ! Initialize a time variable used in an error check
1134  output_fields(out_num)%Time_of_prev_field_data = time_zero
1135 
1136  ! Set the cell_measures attribute in the out file
1137  CALL init_field_cell_measures(output_fields(out_num), area=area, volume=volume, err_msg=msg)
1138  IF ( len_trim(msg).GT.0 ) THEN
1139  CALL error_mesg ('diag_manager_mod::register_static_field',&
1140  & trim(msg)//' for module/field '//trim(module_name)//'/'//trim(field_name),&
1141  & fatal)
1142  END IF
1143 
1144  ! Add the modeling_realm attribute
1145  IF ( PRESENT(realm) ) THEN
1146  CALL prepend_attribute(output_fields(out_num), 'modeling_realm', lowercase(trim(realm)))
1147  END IF
1148  END DO
1149 
1150  IF ( input_fields(field)%mask_variant ) THEN
1151  DO j = 1, input_fields(field)%num_output_fields
1152  out_num = input_fields(field)%output_fields(j)
1153  IF(output_fields(out_num)%time_average) THEN
1154 !----------
1155 !ug support
1156  !Send_data requires that the reduced k dimension be the 3rd dimension
1157  !of the counter array, so set it to be the correct size. If the diagnostic
1158  !is unstructured, set the second dimension of the counter array to be 1.
1159  if (output_fields(out_num)%reduced_k_range .and. &
1160  domain_type .eq. diag_axis_ugdomain) then
1161  allocate(output_fields(out_num)%counter(siz(1),local_siz(2),siz(3), &
1162  output_fields(out_num)%n_diurnal_samples))
1163  else
1164  allocate(output_fields(out_num)%counter(siz(1),siz(2),siz(3), &
1165  output_fields(out_num)%n_diurnal_samples))
1166  endif
1167 !----------
1168  output_fields(out_num)%counter = 0.0
1169  END IF
1170  END DO
1171  END IF
1172  END FUNCTION register_static_field
1173  ! </FUNCTION>
1174 
1175  ! <FUNCTION NAME="get_diag_field_id">
1176  ! <OVERVIEW>
1177  ! Return the diagnostic field ID of a given variable.
1178  ! </OVERVIEW>
1179  ! <TEMPLATE>
1180  ! INTEGER FUNCTION get_diag_field_id(module_name, field_name)
1181  ! </TEMPLATE>
1182  ! <DESCRIPTION>
1183  ! get_diag_field_id will return the ID returned during the register_diag_field call. If
1184  ! the variable is not in the diag_table, then the value "DIAG_FIELD_NOT_FOUND" will be
1185  ! returned.
1186  ! </DESCRIPTION>
1187  ! <IN NAME="module_name" TYPE="CHARACTER(len=*)">Module name that registered the variable</IN>
1188  ! <IN NAME="field_name" TYPE="CHARACTER(len=*)">Variable name</IN>
1189  INTEGER FUNCTION get_diag_field_id(module_name, field_name)
1190  CHARACTER(len=*), INTENT(in) :: module_name, field_name
1191 
1192  ! find_input_field will return DIAG_FIELD_NOT_FOUND if the field is not
1193  ! included in the diag_table
1194  get_diag_field_id = find_input_field(module_name, field_name, tile_count=1)
1195  END FUNCTION get_diag_field_id
1196  ! </FUNCTION>
1197 
1198  ! <FUNCTION NAME="get_related_field">
1199  ! <OVERVIEW>
1200  ! Finds the corresponding related output field and file
1201  ! </OVERVIEW>
1202  ! <TEMPLATE>
1203  ! LOGICAL FUNCTION get_related_field(field, rel_field, out_field_id, out_file_id)
1204  ! </TEMPLATE>
1205  ! <DESCRIPTION>
1206  ! Finds the corresponding related output field and file for a given input field
1207  ! </DESCRIPTION>
1208  ! <IN NAME="field" TYPE="INTEGER">input field ID to find the corresponding</IN>
1209  ! <IN NAME="rel_field" TYPE="TYPE(output_field_type)">Output field that field must correspond to</IN>
1210  ! <OUT NAME="out_field_id" TYPE="INTEGER">output_field index of related output field</OUT>
1211  ! <OUT NAME="out_file_id" TYPE="INTEGER">file index of the out_field_id output field</OUT>
1212  LOGICAL FUNCTION get_related_field(field, rel_field, out_field_id, out_file_id)
1213  INTEGER, INTENT(in) :: field
1214  TYPE(output_field_type), INTENT(in) :: rel_field
1215  INTEGER, INTENT(out) :: out_field_id, out_file_id
1216 
1217  INTEGER :: i, cm_ind, cm_file_num
1218  INTEGER :: rel_file
1219 
1220  ! Output file index of field to compare to
1221  rel_file = rel_field%output_file
1222 
1223  ! Default return values
1224  out_field_id = -1
1225  out_file_id = -1
1226  get_related_field = .false.
1227 
1228  ! First check if any fields are in the same file as rel_field
1229  DO i = 1, input_fields(field)%num_output_fields
1230  cm_ind = input_fields(field)%output_fields(i)
1231  cm_file_num = output_fields(cm_ind)%output_file
1232 
1233  IF ( cm_file_num.EQ.rel_file.AND.&
1234  & (( (output_fields(cm_ind)%time_ops.EQV.rel_field%time_ops) .AND.&
1235  & (output_fields(cm_ind)%next_output.EQ.rel_field%next_output) .AND.&
1236  & (output_fields(cm_ind)%last_output.EQ.rel_field%last_output) ).OR.&
1237  & (output_fields(cm_ind)%static.OR.rel_field%static) ) ) THEN
1238  get_related_field = .true.
1239  out_field_id = cm_ind
1240  out_file_id = cm_file_num
1241  EXIT
1242  END IF
1243  END DO
1244 
1245  ! Now look for the field in a different file
1246  IF ( .NOT.get_related_field ) THEN
1247  DO i = 1, input_fields(field)%num_output_fields
1248  cm_ind = input_fields(field)%output_fields(i)
1249  cm_file_num = output_fields(cm_ind)%output_file
1250 
1251  ! If time_method, freq, output_units, next_output, and last_output the same, or
1252  ! the output_field is static then valid for cell_measures
1253 !!$ For now, only static fields can be in an external file
1254 !!$ IF ( ( (files(cm_file_num)%output_freq.EQ.files(rel_file)%output_freq) .AND.&
1255 !!$ & (files(cm_file_num)%output_units.EQ.files(rel_file)%output_units) .AND.&
1256 !!$ & (output_fields(cm_ind)%time_ops.EQV.rel_field%time_ops) .AND.&
1257 !!$ & (output_fields(cm_ind)%next_output.EQ.rel_field%next_output) .AND.&
1258 !!$ & (output_fields(cm_ind)%last_output.EQ.rel_field%last_output) ).OR.&
1259 !!$ & ( output_fields(cm_ind)%static.OR.rel_field%static ) ) THEN
1260  IF ( output_fields(cm_ind)%static.OR.rel_field%static ) THEN
1261  get_related_field = .true.
1262  out_field_id = cm_ind
1263  out_file_id = cm_file_num
1264  EXIT
1265  END IF
1266  END DO
1267  END IF
1268  END FUNCTION get_related_field
1269  ! </FUNCTION>
1270 
1271  ! <SUBROUTINE NAME="init_field_cell_measures">
1272  ! <OVERVIEW>
1273  ! If needed, add cell_measures and associated_file attribute to out field/file
1274  ! </OVERVIEW>
1275  ! <TEMPLATE>
1276  ! SUBROUTINE init_field_call_measure(ouput_field, area, volume, err_msg)
1277  ! </TEMPLATE>
1278  ! <DESCRIPTION>
1279  ! If needed, add cell_measures and associated_file attribute to out field/file
1280  ! </DESCRIPTION>
1281  ! <INOUT NAME="output_field" TYPE="TYPE(output_field_type)">Output field that needs the cell_measures</INOUT>
1282  ! <IN NAME="area" TYPE="INTEGER, OPTIONAL">Field ID for area</IN>
1283  ! <IN NAME="volume" TYPE="INTEGER, OPTIONAL">Field ID for volume</IN>
1284  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"> </OUT>
1285  SUBROUTINE init_field_cell_measures(output_field, area, volume, err_msg)
1286  TYPE(output_field_type), INTENT(inout) :: output_field
1287  INTEGER, INTENT(in), OPTIONAL :: area, volume
1288  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1289 
1290  INTEGER :: cm_ind, cm_file_num, file_num
1291 
1292  IF ( PRESENT(err_msg) ) THEN
1293  err_msg = ''
1294  END IF
1295 
1296  ! Verify that area/volume are defined (.gt.0
1297  IF ( PRESENT(area) ) THEN
1298  IF ( area.LE.0 ) THEN
1299  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measure',&
1300  & 'AREA field not in diag_table for field '//trim(input_fields(output_field%input_field)%module_name)//&
1301  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1302  END IF
1303  END IF
1304 
1305  IF ( PRESENT(volume) ) THEN
1306  IF ( volume.LE.0 ) THEN
1307  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measure',&
1308  & 'VOLUME field not in diag_table for field '//trim(input_fields(output_field%input_field)%module_name)//&
1309  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1310  END IF
1311  END IF
1312 
1313  ! Get the file number that the output_field will be written to
1314  file_num = output_field%output_file
1315 
1316  ! Take care of the cell_measures attribute
1317  IF ( PRESENT(area) ) THEN
1318  IF ( get_related_field(area, output_field, cm_ind, cm_file_num) ) THEN
1319  CALL prepend_attribute(output_field, 'cell_measures',&
1320  & 'area: '//trim(output_fields(cm_ind)%output_name))
1321  IF ( cm_file_num.NE.file_num ) THEN
1322  ! Not in the same file, set the global attribute associated_files
1323  CALL add_associated_files(file_num, cm_file_num, cm_ind)
1324  END IF
1325  ELSE
1326  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measures',&
1327  & 'AREA measures field "'//trim(input_fields(area)%module_name)//'/'//&
1328  & trim(input_fields(area)%field_name)//&
1329  & '" NOT in diag_table with correct output frequency for field '//&
1330  & trim(input_fields(output_field%input_field)%module_name)//&
1331  & '/'//trim(input_fields(output_field%input_field)%field_name), err_msg) ) RETURN
1332  END IF
1333  END IF
1334 
1335 
1336  IF ( PRESENT(volume) ) THEN
1337  IF ( get_related_field(volume, output_field, cm_ind, cm_file_num) ) THEN
1338  CALL prepend_attribute(output_field, 'cell_measures',&
1339  & 'volume: '//trim(output_fields(cm_ind)%output_name))
1340  IF ( cm_file_num.NE.file_num ) THEN
1341  ! Not in the same file, set the global attribute associated_files
1342  CALL add_associated_files(file_num, cm_file_num, cm_ind)
1343  END IF
1344  ELSE
1345  IF ( fms_error_handler('diag_manager_mod::init_field_cell_measures',&
1346  & 'VOLUME measures field "'//trim(input_fields(volume)%module_name)//'/'//&
1347  & trim(input_fields(volume)%field_name)//&
1348  & '" NOT in diag_table with correct output frequency for field '//&
1349  & 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  END SUBROUTINE init_field_cell_measures
1354  ! </SUBROUTINE>
1355 
1356  !> \brief Add to the associated files attribute
1357  !!
1358  !! \throw FATAL, "Length of asso_file_name is not long enough to hold the associated file name."
1359  !! The length of character array asso_file_name is not long enough to hold the full file name
1360  !! of the associated_file. Please contact the developer to increase the length of the variable.
1361  SUBROUTINE add_associated_files(file_num, cm_file_num, cm_ind)
1362  INTEGER, intent(in) :: file_num !< File number that needs the associated_files attribute
1363  INTEGER, intent(in) :: cm_file_num !< file number that contains the associated field
1364  INTEGER, intent(in) :: cm_ind !< index of the output_field in the associated file
1365 
1366  INTEGER :: year, month, day, hour, minute, second
1367  INTEGER :: n
1368  CHARACTER(len=25) :: date_prefix
1369  CHARACTER(len=256) :: asso_file_name
1370 
1371  ! Create the date_string
1372  IF ( prepend_date ) THEN
1373  CALL get_date(diag_init_time, year, month, day, hour, minute, second)
1374  WRITE (date_prefix, '(1I20.4, 2I2.2,".")') year, month, day
1375  date_prefix=adjustl(date_prefix)
1376  ELSE
1377  date_prefix=''
1378  END IF
1379 
1380  ! Get the base file name
1381  ! Verify asso_file_name is long enough to hold the file name,
1382  ! plus 17 for the additional '.ens_??.tile?.nc' (and a null character)
1383  IF ( len_trim(files(cm_file_num)%name)+17 > len(asso_file_name) ) THEN
1384  CALL error_mesg ('diag_manager_mod::add_associated_files',&
1385  & 'Length of asso_file_name is not long enough to hold the associated file name. '&
1386  & //'Contact the developer', fatal)
1387  ELSE
1388  asso_file_name = trim(files(cm_file_num)%name)
1389  END IF
1390 
1391  ! Add the ensemble number string into the file name
1392  ! As frepp does not have native support for multiple ensemble runs
1393  ! this will not be done. However, the code is left here for the time
1394  ! frepp does.
1395  !CALL get_instance_filename(TRIM(asso_file_name), asso_file_name)
1396 
1397  ! Append .nc suffix, if needed. Note that we no longer try to append cubic sphere tile
1398  ! number to the name of the associated file.
1399  n = max(len_trim(asso_file_name),3)
1400  if (asso_file_name(n-2:n).NE.'.nc') asso_file_name = trim(asso_file_name)//'.nc'
1401 
1402  ! Should look like :associated_files = " output_name: output_file_name " ;
1403  CALL prepend_attribute(files(file_num), 'associated_files',&
1404  & trim(output_fields(cm_ind)%output_name)//': '//&
1405  & trim(date_prefix)//trim(asso_file_name))
1406  END SUBROUTINE add_associated_files
1407 
1408  ! <FUNCTION NAME="send_data_0d" INTERFACE="send_data">
1409  ! <IN NAME="diag_field_id" TYPE="INTEGER"> </IN>
1410  ! <IN NAME="field" TYPE="REAL"> </IN>
1411  ! <IN NAME="time" TYPE="TYPE(time_type), OPTIONAL"> </IN>
1412  ! <IN NAME="is_in" TYPE="Not Applicable"></IN>
1413  ! <IN NAME="js_in" TYPE="Not Applicable"></IN>
1414  ! <IN NAME="ks_in" TYPE="Not Applicable"></IN>
1415  ! <IN NAME="mask" TYPE="Not Applicable"></IN>
1416  ! <IN NAME="rmask" TYPE="Not Applicable"></IN>
1417  ! <IN NAME="ie_in" TYPE="Not Applicable"></IN>
1418  ! <IN NAME="je_in" TYPE="Not Applicable"></IN>
1419  ! <IN NAME="ke_in" TYPE="Not Applicable"></IN>
1420  ! <IN NAME="weight" TYPE="Not Applicable"></IN>
1421  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"></OUT>
1422  LOGICAL FUNCTION send_data_0d(diag_field_id, field, time, err_msg)
1423  INTEGER, INTENT(in) :: diag_field_id
1424  REAL, INTENT(in) :: field
1425  TYPE(time_type), INTENT(in), OPTIONAL :: time
1426  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1427 
1428  REAL :: field_out(1, 1, 1)
1429 
1430  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1431  IF ( diag_field_id <= 0 ) THEN
1432  send_data_0d = .false.
1433  RETURN
1434  END IF
1435  ! First copy the data to a three d array with last element 1
1436  field_out(1, 1, 1) = field
1437  send_data_0d = send_data_3d(diag_field_id, field_out, time, err_msg=err_msg)
1438  END FUNCTION send_data_0d
1439  ! </FUNCTION>
1440 
1441  ! <FUNCTION NAME="send_data_1d" INTERFACE="send_data">
1442  ! <IN NAME="diag_field_id" TYPE="INTEGER"> </IN>
1443  ! <IN NAME="field" TYPE="REAL, DIMENSION(:)"> </IN>
1444  ! <IN NAME="time" TYPE="TYPE(time_type)"> </IN>
1445  ! <IN NAME="is_in" TYPE="INTEGER, OPTIONAL"></IN>
1446  ! <IN NAME="js_in" TYPE="Not Applicable"></IN>
1447  ! <IN NAME="ks_in" TYPE="Not Applicable"></IN>
1448  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:), OPTIONAL"></IN>
1449  ! <IN NAME="rmask" TYPE="REAL, DIMENSION(:), OPTIONAL"></IN>
1450  ! <IN NAME="ie_in" TYPE="INTEGER, OPTIONAL"></IN>
1451  ! <IN NAME="je_in" TYPE="Not Applicable"></IN>
1452  ! <IN NAME="ke_in" TYPE="Not Applicable"></IN>
1453  ! <IN NAME="weight" TYPE="REAL, OPTIONAL"></IN>
1454  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"></OUT>
1455  LOGICAL FUNCTION send_data_1d(diag_field_id, field, time, is_in, mask, rmask, ie_in, weight, err_msg)
1456  INTEGER, INTENT(in) :: diag_field_id
1457  REAL, DIMENSION(:), INTENT(in) :: field
1458  REAL, INTENT(in), OPTIONAL :: weight
1459  REAL, INTENT(in), DIMENSION(:), OPTIONAL :: rmask
1460  type(time_type), INTENT(in), OPTIONAL :: time
1461  INTEGER, INTENT(in), OPTIONAL :: is_in, ie_in
1462  LOGICAL, INTENT(in), DIMENSION(:), OPTIONAL :: mask
1463  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1464 
1465  REAL, DIMENSION(SIZE(field(:)), 1, 1) :: field_out
1466  LOGICAL, DIMENSION(SIZE(field(:)), 1, 1) :: mask_out
1467 
1468  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1469  IF ( diag_field_id <= 0 ) THEN
1470  send_data_1d = .false.
1471  RETURN
1472  END IF
1473 
1474  ! First copy the data to a three d array with last element 1
1475  field_out(:, 1, 1) = field
1476 
1477  ! Default values for mask
1478  IF ( PRESENT(mask) ) THEN
1479  mask_out(:, 1, 1) = mask
1480  ELSE
1481  mask_out = .true.
1482  END IF
1483 
1484  IF ( PRESENT(rmask) ) WHERE (rmask < 0.5) mask_out(:, 1, 1) = .false.
1485  IF ( PRESENT(mask) .OR. PRESENT(rmask) ) THEN
1486  IF ( PRESENT(is_in) .OR. PRESENT(ie_in) ) THEN
1487  send_data_1d = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=1, ks_in=1,&
1488  & mask=mask_out, ie_in=ie_in, je_in=1, ke_in=1, weight=weight, err_msg=err_msg)
1489  ELSE
1490  send_data_1d = send_data_3d(diag_field_id, field_out, time, mask=mask_out,&
1491  & weight=weight, err_msg=err_msg)
1492  END IF
1493  ELSE
1494  IF ( PRESENT(is_in) .OR. PRESENT(ie_in) ) THEN
1495  send_data_1d = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=1, ks_in=1,&
1496  & ie_in=ie_in, je_in=1, ke_in=1, weight=weight, err_msg=err_msg)
1497  ELSE
1498  send_data_1d = send_data_3d(diag_field_id, field_out, time, weight=weight, err_msg=err_msg)
1499  END IF
1500  END IF
1501  END FUNCTION send_data_1d
1502  ! </FUNCTION>
1503 
1504  ! <FUNCTION NAME="send_data_2d" INTERFACE="send_data">
1505  ! <IN NAME="diag_field_id" TYPE="INTEGER"> </IN>
1506  ! <IN NAME="field" TYPE="REAL, DIMENSION(:,:)"> </IN>
1507  ! <IN NAME="time" TYPE="TYPE(time_type)"> </IN>
1508  ! <IN NAME="is_in" TYPE="INTEGER, OPTIONAL"></IN>
1509  ! <IN NAME="js_in" TYPE="INTEGER, OPTIONAL"></IN>
1510  ! <IN NAME="ks_in" TYPE="Not Applicable"></IN>
1511  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:), OPTIONAL"></IN>
1512  ! <IN NAME="rmask" TYPE="REAL, DIMENSION(:,:), OPTIONAL"></IN>
1513  ! <IN NAME="ie_in" TYPE="INTEGER, OPTIONAL"></IN>
1514  ! <IN NAME="je_in" TYPE="INTEGER, OPTIONAL"></IN>
1515  ! <IN NAME="ke_in" TYPE="Not Applicable"></IN>
1516  ! <IN NAME="weight" TYPE="REAL, OPTIONAL"></IN>
1517  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"></OUT>
1518  LOGICAL FUNCTION send_data_2d(diag_field_id, field, time, is_in, js_in, &
1519  & mask, rmask, ie_in, je_in, weight, err_msg)
1520  INTEGER, INTENT(in) :: diag_field_id
1521  REAL, INTENT(in), DIMENSION(:,:) :: field
1522  REAL, INTENT(in), OPTIONAL :: weight
1523  type(time_type), INTENT(in), OPTIONAL :: time
1524  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ie_in, je_in
1525  LOGICAL, INTENT(in), DIMENSION(:,:), OPTIONAL :: mask
1526  REAL, INTENT(in), DIMENSION(:,:),OPTIONAL :: rmask
1527  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1528 
1529  REAL, DIMENSION(SIZE(field,1),SIZE(field,2),1) :: field_out
1530  LOGICAL, DIMENSION(SIZE(field,1),SIZE(field,2),1) :: mask_out
1531 
1532  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1533  IF ( diag_field_id <= 0 ) THEN
1534  send_data_2d = .false.
1535  RETURN
1536  END IF
1537 
1538  ! First copy the data to a three d array with last element 1
1539  field_out(:, :, 1) = field
1540 
1541  ! Default values for mask
1542  IF ( PRESENT(mask) ) THEN
1543  mask_out(:, :, 1) = mask
1544  ELSE
1545  mask_out = .true.
1546  END IF
1547 
1548  IF ( PRESENT(rmask) ) WHERE ( rmask < 0.5 ) mask_out(:, :, 1) = .false.
1549  IF ( PRESENT(mask) .OR. PRESENT(rmask) ) THEN
1550  send_data_2d = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=1, mask=mask_out,&
1551  & ie_in=ie_in, je_in=je_in, ke_in=1, weight=weight, err_msg=err_msg)
1552  ELSE
1553  send_data_2d = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=1,&
1554  & ie_in=ie_in, je_in=je_in, ke_in=1, weight=weight, err_msg=err_msg)
1555  END IF
1556  END FUNCTION send_data_2d
1557  ! </FUNCTION>
1558 
1559 #ifdef OVERLOAD_R8
1560  ! <FUNCTION NAME="send_data_2d_r8" INTERFACE="send_data">
1561  LOGICAL FUNCTION send_data_2d_r8(diag_field_id, field, time, is_in, js_in, &
1562  & mask, rmask, ie_in, je_in, weight, err_msg)
1563  INTEGER, INTENT(in) :: diag_field_id
1564  REAL(kind=8), INTENT(in), DIMENSION(:,:) :: field
1565  REAL, INTENT(in), OPTIONAL :: weight
1566  type(time_type), INTENT(in), OPTIONAL :: time
1567  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ie_in, je_in
1568  LOGICAL, INTENT(in), DIMENSION(:,:), OPTIONAL :: mask
1569  REAL, INTENT(in), DIMENSION(:,:),OPTIONAL :: rmask
1570  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1571 
1572  REAL, DIMENSION(SIZE(field,1),SIZE(field,2),1) :: field_out
1573  LOGICAL, DIMENSION(SIZE(field,1),SIZE(field,2),1) :: mask_out
1574 
1575  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1576  IF ( diag_field_id <= 0 ) THEN
1577  send_data_2d_r8 = .false.
1578  RETURN
1579  END IF
1580 
1581  ! First copy the data to a three d array with last element 1
1582  field_out(:, :, 1) = field
1583 
1584  ! Default values for mask
1585  IF ( PRESENT(mask) ) THEN
1586  mask_out(:, :, 1) = mask
1587  ELSE
1588  mask_out = .true.
1589  END IF
1590 
1591  IF ( PRESENT(rmask) ) WHERE ( rmask < 0.5 ) mask_out(:, :, 1) = .false.
1592  IF ( PRESENT(mask) .OR. PRESENT(rmask) ) THEN
1593  send_data_2d_r8 = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=1, mask=mask_out,&
1594  & ie_in=ie_in, je_in=je_in, ke_in=1, weight=weight, err_msg=err_msg)
1595  ELSE
1596  send_data_2d_r8 = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=1,&
1597  & ie_in=ie_in, je_in=je_in, ke_in=1, weight=weight, err_msg=err_msg)
1598  END IF
1599  END FUNCTION send_data_2d_r8
1600  ! </FUNCTION>
1601 
1602  ! <FUNCTION NAME="send_data_3d_r8" INTERFACE="send_data">
1603  LOGICAL FUNCTION send_data_3d_r8(diag_field_id, field, time, is_in, js_in, ks_in, &
1604  & mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
1605  INTEGER, INTENT(in) :: diag_field_id
1606  REAL(kind=8), INTENT(in), DIMENSION(:,:,:) :: field
1607  REAL, INTENT(in), OPTIONAL :: weight
1608  type(time_type), INTENT(in), OPTIONAL :: time
1609  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ks_in,ie_in,je_in, ke_in
1610  LOGICAL, INTENT(in), DIMENSION(:,:,:), OPTIONAL :: mask
1611  REAL, INTENT(in), DIMENSION(:,:,:),OPTIONAL :: rmask
1612  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1613 
1614  REAL, DIMENSION(SIZE(field,1),SIZE(field,2),size(field,3)) :: field_out
1615  LOGICAL, DIMENSION(SIZE(field,1),SIZE(field,2),size(field,3)) :: mask_out
1616 
1617  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1618  IF ( diag_field_id <= 0 ) THEN
1619  send_data_3d_r8 = .false.
1620  RETURN
1621  END IF
1622 
1623  ! First copy the data to a three d array with last element 1
1624  field_out = field
1625 
1626  ! Default values for mask
1627  IF ( PRESENT(mask) ) THEN
1628  mask_out = mask
1629  ELSE
1630  mask_out = .true.
1631  END IF
1632 
1633  IF ( PRESENT(rmask) ) WHERE ( rmask < 0.5 ) mask_out = .false.
1634  IF ( PRESENT(mask) .OR. PRESENT(rmask) ) THEN
1635  send_data_3d_r8 = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=ks_in, mask=mask_out,&
1636  & ie_in=ie_in, je_in=je_in, ke_in=ke_in, weight=weight, err_msg=err_msg)
1637  ELSE
1638  send_data_3d_r8 = send_data_3d(diag_field_id, field_out, time, is_in=is_in, js_in=js_in, ks_in=ks_in,&
1639  & ie_in=ie_in, je_in=je_in, ke_in=ke_in, weight=weight, err_msg=err_msg)
1640  END IF
1641  END FUNCTION send_data_3d_r8
1642  ! </FUNCTION>
1643 #endif
1644 
1645  ! <FUNCTION NAME="send_data_3d" INTERFACE="send_data">
1646  ! <IN NAME="diag_field_id" TYPE="INTEGER"> </IN>
1647  ! <IN NAME="field" TYPE="REAL, DIMENSION(:,:,:)"> </IN>
1648  ! <IN NAME="time" TYPE="TYPE(time_type)"> </IN>
1649  ! <IN NAME="is_in" TYPE="INTEGER, OPTIONAL"></IN>
1650  ! <IN NAME="js_in" TYPE="INTEGER, OPTIONAL"></IN>
1651  ! <IN NAME="ks_in" TYPE="INTEGER, OPTIONAL"></IN>
1652  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:), OPTIONAL"></IN>
1653  ! <IN NAME="rmask" TYPE="REAL, DIMENSION(:,:,:), OPTIONAL"></IN>
1654  ! <IN NAME="ie_in" TYPE="INTEGER, OPTIONAL"></IN>
1655  ! <IN NAME="je_in" TYPE="INTEGER, OPTIONAL"></IN>
1656  ! <IN NAME="ke_in" TYPE="INTEGER, OPTIONAL"></IN>
1657  ! <IN NAME="weight" TYPE="REAL, OPTIONAL"></IN>
1658  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"></OUT>
1659  LOGICAL FUNCTION send_data_3d(diag_field_id, field, time, is_in, js_in, ks_in, &
1660  & mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
1661  INTEGER, INTENT(in) :: diag_field_id
1662  REAL, DIMENSION(:,:,:), INTENT(in) :: field
1663  REAL, INTENT(in), OPTIONAL :: weight
1664  type(time_type), INTENT(in), OPTIONAL :: time
1665  INTEGER, INTENT(in), OPTIONAL :: is_in, js_in, ks_in,ie_in,je_in, ke_in
1666  LOGICAL, DIMENSION(:,:,:), INTENT(in), OPTIONAL :: mask
1667  REAL, DIMENSION(:,:,:), INTENT(in), OPTIONAL :: rmask
1668  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
1669 
1670  REAL :: weight1
1671  REAL :: missvalue
1672  INTEGER :: pow_value
1673  INTEGER :: ksr, ker
1674  INTEGER :: i, out_num, file_num, n1, n2, n3, number_of_outputs, ii,f1,f2,f3,f4
1675  INTEGER :: freq, units, is, js, ks, ie, je, ke, i1, j1,k1, j, k
1676  INTEGER, DIMENSION(3) :: l_start, l_end ! local start and end indices on 3 axes for regional output
1677  INTEGER :: hi, hj, twohi, twohj ! halo size in x and y direction
1678  INTEGER :: sample ! index along the diurnal time axis
1679  INTEGER :: day,second,tick ! components of the current date
1680  INTEGER :: status
1681  INTEGER :: numthreads
1682  INTEGER :: active_omp_level
1683 #if defined(_OPENMP)
1684  INTEGER :: omp_get_num_threads !< OMP function
1685  INTEGER :: omp_get_level !< OMP function
1686 #endif
1687  LOGICAL :: average, phys_window, need_compute
1688  LOGICAL :: reduced_k_range, local_output
1689  LOGICAL :: time_max, time_min, time_rms, time_sum
1690  LOGICAL :: missvalue_present
1691  LOGICAL, ALLOCATABLE, DIMENSION(:,:,:) :: oor_mask
1692  CHARACTER(len=256) :: err_msg_local
1693  CHARACTER(len=128) :: error_string, error_string1
1694 
1695  ! If diag_field_id is < 0 it means that this field is not registered, simply return
1696  IF ( diag_field_id <= 0 ) THEN
1697  send_data_3d = .false.
1698  RETURN
1699  ELSE
1700  send_data_3d = .true.
1701  END IF
1702 
1703  IF ( PRESENT(err_msg) ) err_msg = ''
1704  IF ( .NOT.module_is_initialized ) THEN
1705  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'diag_manager NOT initialized', err_msg) ) RETURN
1706  END IF
1707  err_msg_local = ''
1708  ! The following lines are commented out as they have not been included in the code prior to now,
1709  ! and there are a lot of send_data calls before register_diag_field calls. A method to do this safely
1710  ! needs to be developed.
1711  !
1712  ! Set first_send_data_call to .FALSE. on first non-static field.
1713 !!$ IF ( .NOT.input_fields(diag_field_id)%static .AND. first_send_data_call ) THEN
1714 !!$ first_send_data_call = .FALSE.
1715 !!$ END IF
1716 
1717  ! oor_mask is only used for checking out of range values.
1718  ALLOCATE(oor_mask(SIZE(field,1),SIZE(field,2),SIZE(field,3)), stat=status)
1719  IF ( status .NE. 0 ) THEN
1720  WRITE (err_msg_local, fmt='("Unable to allocate oor_mask(",I5,",",I5,",",I5,"). (STAT: ",I5,")")')&
1721  & SIZE(field,1), SIZE(field,2), SIZE(field,3), status
1722  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) RETURN
1723  END IF
1724 
1725  IF ( PRESENT(mask) ) THEN
1726  oor_mask = mask
1727  ELSE
1728  oor_mask = .true.
1729  END IF
1730  IF ( PRESENT(rmask) ) WHERE ( rmask < 0.5 ) oor_mask = .false.
1731 
1732  ! send_data works in either one or another of two modes.
1733  ! 1. Input field is a window (e.g. FMS physics)
1734  ! 2. Input field includes halo data
1735  ! It cannot handle a window of data that has halos.
1736  ! (A field with no windows or halos can be thought of as a special case of either mode.)
1737  ! The logic for indexing is quite different for these two modes, but is not clearly separated.
1738  ! If both the beggining and ending indices are present, then field is assumed to have halos.
1739  ! If only beggining indices are present, then field is assumed to be a window.
1740 
1741  ! There are a number of ways a user could mess up this logic, depending on the combination
1742  ! of presence/absence of is,ie,js,je. The checks below should catch improper combinations.
1743  IF ( PRESENT(ie_in) ) THEN
1744  IF ( .NOT.PRESENT(is_in) ) THEN
1745  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'ie_in present without is_in', err_msg) ) THEN
1746  DEALLOCATE(oor_mask)
1747  RETURN
1748  END IF
1749  END IF
1750  IF ( PRESENT(js_in) .AND. .NOT.PRESENT(je_in) ) THEN
1751  IF ( fms_error_handler('diag_manager_modsend_data_3d',&
1752  & 'is_in and ie_in present, but js_in present without je_in', err_msg) ) THEN
1753  DEALLOCATE(oor_mask)
1754  RETURN
1755  END IF
1756  END IF
1757  END IF
1758  IF ( PRESENT(je_in) ) THEN
1759  IF ( .NOT.PRESENT(js_in) ) THEN
1760  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'je_in present without js_in', err_msg) ) THEN
1761  DEALLOCATE(oor_mask)
1762  RETURN
1763  END IF
1764  END IF
1765  IF ( PRESENT(is_in) .AND. .NOT.PRESENT(ie_in) ) THEN
1766  IF ( fms_error_handler('diag_manager_mod::send_data_3d',&
1767  & 'js_in and je_in present, but is_in present without ie_in', err_msg)) THEN
1768  DEALLOCATE(oor_mask)
1769  RETURN
1770  END IF
1771  END IF
1772  END IF
1773 
1774  ! If is, js, or ks not present default them to 1
1775  is = 1
1776  js = 1
1777  ks = 1
1778  IF ( PRESENT(is_in) ) is = is_in
1779  IF ( PRESENT(js_in) ) js = js_in
1780  IF ( PRESENT(ks_in) ) ks = ks_in
1781  n1 = SIZE(field, 1)
1782  n2 = SIZE(field, 2)
1783  n3 = SIZE(field, 3)
1784  ie = is+n1-1
1785  je = js+n2-1
1786  ke = ks+n3-1
1787  IF ( PRESENT(ie_in) ) ie = ie_in
1788  IF ( PRESENT(je_in) ) je = je_in
1789  IF ( PRESENT(ke_in) ) ke = ke_in
1790  twohi = n1-(ie-is+1)
1791  IF ( mod(twohi,2) /= 0 ) THEN
1792  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'non-symmetric halos in first dimension', err_msg) ) THEN
1793  DEALLOCATE(oor_mask)
1794  RETURN
1795  END IF
1796  END IF
1797  twohj = n2-(je-js+1)
1798  IF ( mod(twohj,2) /= 0 ) THEN
1799  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'non-symmetric halos in second dimension', err_msg) ) THEN
1800  DEALLOCATE(oor_mask)
1801  RETURN
1802  END IF
1803  END IF
1804  hi = twohi/2
1805  hj = twohj/2
1806 
1807  ! The next line is necessary to ensure that is,ie,js,ie are relative to field(1:,1:)
1808  ! But this works only when there is no windowing.
1809  IF ( PRESENT(ie_in) .AND. PRESENT(je_in) ) THEN
1810  is=1+hi
1811  ie=n1-hi
1812  js=1+hj
1813  je=n2-hj
1814  END IF
1815 
1816  ! used for field, mask and rmask bounds
1817  f1=1+hi
1818  f2=n1-hi
1819  f3=1+hj
1820  f4=n2-hj
1821 
1822  ! weight is for time averaging where each time level may has a different weight
1823  IF ( PRESENT(weight) ) THEN
1824  weight1 = weight
1825  ELSE
1826  weight1 = 1.
1827  END IF
1828 
1829  ! Is there a missing_value?
1830  missvalue_present = input_fields(diag_field_id)%missing_value_present
1831  IF ( missvalue_present ) missvalue = input_fields(diag_field_id)%missing_value
1832 
1833  number_of_outputs = input_fields(diag_field_id)%num_output_fields
1834 !$OMP CRITICAL
1835  input_fields(diag_field_id)%numthreads = 1
1836  active_omp_level=0
1837 #if defined(_OPENMP)
1838  input_fields(diag_field_id)%numthreads = omp_get_num_threads()
1839  input_fields(diag_field_id)%active_omp_level = omp_get_level()
1840 #endif
1841  numthreads = input_fields(diag_field_id)%numthreads
1842  active_omp_level = input_fields(diag_field_id)%active_omp_level
1843 !$OMP END CRITICAL
1844 
1845  if(present(time)) input_fields(diag_field_id)%time = time
1846 
1847  ! Issue a warning if any value in field is outside the valid range
1848  IF ( input_fields(diag_field_id)%range_present ) THEN
1849  IF ( issue_oor_warnings .OR. oor_warnings_fatal ) THEN
1850  WRITE (error_string, '("[",ES14.5E3,",",ES14.5E3,"]")')&
1851  & input_fields(diag_field_id)%range(1:2)
1852  WRITE (error_string1, '("(Min: ",ES14.5E3,", Max: ",ES14.5E3, ")")')&
1853  & minval(field(f1:f2,f3:f4,ks:ke),mask=oor_mask(f1:f2,f3:f4,ks:ke)),&
1854  & maxval(field(f1:f2,f3:f4,ks:ke),mask=oor_mask(f1:f2,f3:f4,ks:ke))
1855  IF ( missvalue_present ) THEN
1856  IF ( any(oor_mask(f1:f2,f3:f4,ks:ke) .AND.&
1857  & ((field(f1:f2,f3:f4,ks:ke) < input_fields(diag_field_id)%range(1) .OR.&
1858  & field(f1:f2,f3:f4,ks:ke) > input_fields(diag_field_id)%range(2)).AND.&
1859  & field(f1:f2,f3:f4,ks:ke) .NE. missvalue)) ) THEN
1860  ! <ERROR STATUS="WARNING/FATAL">
1861  ! A value for <module_name> in field <field_name> (Min: <min_val>, Max: <max_val>)
1862  ! is outside the range [<lower_val>,<upper_val>] and not equal to the missing
1863  ! value.
1864  ! </ERROR>
1865  CALL error_mesg('diag_manager_mod::send_data_3d',&
1866  & 'A value for '//&
1867  &trim(input_fields(diag_field_id)%module_name)//' in field '//&
1868  &trim(input_fields(diag_field_id)%field_name)//' '&
1869  &//trim(error_string1)//&
1870  &' is outside the range '//trim(error_string)//',&
1871  & and not equal to the missing value.',&
1872  &oor_warning)
1873  END IF
1874  ELSE
1875  IF ( any(oor_mask(f1:f2,f3:f4,ks:ke) .AND.&
1876  & (field(f1:f2,f3:f4,ks:ke) < input_fields(diag_field_id)%range(1) .OR.&
1877  & field(f1:f2,f3:f4,ks:ke) > input_fields(diag_field_id)%range(2))) ) THEN
1878  ! <ERROR STATUS="WARNING/FATAL">
1879  ! A value for <module_name> in field <field_name> (Min: <min_val>, Max: <max_val>)
1880  ! is outside the range [<lower_val>,<upper_val>].
1881  ! </ERROR>
1882  CALL error_mesg('diag_manager_mod::send_data_3d',&
1883  & 'A value for '//&
1884  &trim(input_fields(diag_field_id)%module_name)//' in field '//&
1885  &trim(input_fields(diag_field_id)%field_name)//' '&
1886  &//trim(error_string1)//&
1887  &' is outside the range '//trim(error_string)//'.',&
1888  &oor_warning)
1889  END IF
1890  END IF
1891  END IF
1892  END IF
1893 
1894  ! Loop through each output field that depends on this input field
1895  num_out_fields: DO ii = 1, number_of_outputs
1896  ! Get index to an output field
1897  out_num = input_fields(diag_field_id)%output_fields(ii)
1898 
1899  ! is this field output on a local domain only?
1900  local_output = output_fields(out_num)%local_output
1901  ! if local_output, does the current PE take part in send_data?
1902  need_compute = output_fields(out_num)%need_compute
1903 
1904  reduced_k_range = output_fields(out_num)%reduced_k_range
1905 
1906  ! skip all PEs not participating in outputting this field
1907  IF ( local_output .AND. (.NOT.need_compute) ) cycle
1908 
1909  ! Get index to output file for this field
1910  file_num = output_fields(out_num)%output_file
1911  IF(file_num == max_files) cycle
1912  ! Output frequency and units for this file is
1913  freq = files(file_num)%output_freq
1914  units = files(file_num)%output_units
1915  ! Is this output field being time averaged?
1916  average = output_fields(out_num)%time_average
1917  ! Is this output field the rms?
1918  ! If so, then average is also .TRUE.
1919  time_rms = output_fields(out_num)%time_rms
1920  ! Power value for rms or pow(x) calculations
1921  pow_value = output_fields(out_num)%pow_value
1922  ! Looking for max and min value of this field over the sampling interval?
1923  time_max = output_fields(out_num)%time_max
1924  time_min = output_fields(out_num)%time_min
1925  ! Sum output over time interval
1926  time_sum = output_fields(out_num)%time_sum
1927  IF ( output_fields(out_num)%total_elements > SIZE(field(f1:f2,f3:f4,ks:ke)) ) THEN
1928  output_fields(out_num)%phys_window = .true.
1929  ELSE
1930  output_fields(out_num)%phys_window = .false.
1931  END IF
1932  phys_window = output_fields(out_num)%phys_window
1933  IF ( need_compute ) THEN
1934  l_start = output_fields(out_num)%output_grid%l_start_indx
1935  l_end = output_fields(out_num)%output_grid%l_end_indx
1936  END IF
1937 
1938  ! compute the diurnal index
1939  sample = 1
1940  IF ( PRESENT(time) ) THEN
1941  CALL get_time(time,second,day,tick) ! current date
1942  sample = floor((second+real(tick)/get_ticks_per_second())*output_fields(out_num)%n_diurnal_samples/seconds_per_day) + 1
1943  END IF
1944 
1945  ! Get the vertical layer start and end index.
1946  IF ( reduced_k_range ) THEN
1947 !----------
1948 !ug support
1949  if (output_fields(out_num)%reduced_k_unstruct) then
1950  js = output_fields(out_num)%output_grid%l_start_indx(2)
1951  je = output_fields(out_num)%output_grid%l_end_indx(2)
1952  endif
1953  l_start(3) = output_fields(out_num)%output_grid%l_start_indx(3)
1954  l_end(3) = output_fields(out_num)%output_grid%l_end_indx(3)
1955 !----------
1956  END IF
1957  ksr= l_start(3)
1958  ker= l_end(3)
1959 
1960  ! Initialize output time for fields output every time step
1961  IF ( freq == every_time .AND. .NOT.output_fields(out_num)%static ) THEN
1962  IF (output_fields(out_num)%next_output == output_fields(out_num)%last_output) THEN
1963  IF(PRESENT(time)) THEN
1964  output_fields(out_num)%next_output = time
1965  ELSE
1966  WRITE (error_string,'(a,"/",a)')&
1967  & trim(input_fields(diag_field_id)%module_name),&
1968  & trim(output_fields(out_num)%output_name)
1969  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
1970  & ', time must be present when output frequency = EVERY_TIME', err_msg)) THEN
1971  DEALLOCATE(oor_mask)
1972  RETURN
1973  END IF
1974  END IF
1975  END IF
1976  END IF
1977  IF ( .NOT.output_fields(out_num)%static .AND. .NOT.PRESENT(time) ) THEN
1978  WRITE (error_string,'(a,"/",a)')&
1979  & trim(input_fields(diag_field_id)%module_name), &
1980  & trim(output_fields(out_num)%output_name)
1981  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
1982  & ', time must be present for nonstatic field', err_msg)) THEN
1983  DEALLOCATE(oor_mask)
1984  RETURN
1985  END IF
1986  END IF
1987 
1988  ! Is it time to output for this field; CAREFUL ABOUT > vs >= HERE
1989  !--- The fields send out within openmp parallel region will be written out in
1990  !--- diag_send_complete.
1991  IF ( (numthreads == 1) .AND. (active_omp_level.LE.1) ) then
1992  IF ( .NOT.output_fields(out_num)%static .AND. freq /= end_of_run ) THEN
1993  IF ( time > output_fields(out_num)%next_output ) THEN
1994  ! A non-static field that has skipped a time level is an error
1995  IF ( time > output_fields(out_num)%next_next_output .AND. freq > 0 ) THEN
1996  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
1997  WRITE (error_string,'(a,"/",a)')&
1998  & trim(input_fields(diag_field_id)%module_name), &
1999  & trim(output_fields(out_num)%output_name)
2000  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2001  & ' is skipped one time level in output data', err_msg)) THEN
2002  DEALLOCATE(oor_mask)
2003  RETURN
2004  END IF
2005  END IF
2006  END IF
2007 
2008  status = writing_field(out_num, .false., error_string, time)
2009  IF(status == -1) THEN
2010  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
2011  IF(fms_error_handler('diag_manager_mod::send_data_3d','module/output_field '//trim(error_string)//&
2012  & ', write EMPTY buffer', err_msg)) THEN
2013  DEALLOCATE(oor_mask)
2014  RETURN
2015  END IF
2016  END IF
2017  END IF
2018  END IF !time > output_fields(out_num)%next_output
2019  END IF !.not.output_fields(out_num)%static .and. freq /= END_OF_RUN
2020  ! Finished output of previously buffered data, now deal with buffering new data
2021  END IF
2022 
2023  IF ( .NOT.output_fields(out_num)%static .AND. .NOT.need_compute .AND. debug_diag_manager ) THEN
2024  CALL check_bounds_are_exact_dynamic(out_num, diag_field_id, time, err_msg=err_msg_local)
2025  IF ( err_msg_local /= '' ) THEN
2026  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2027  DEALLOCATE(oor_mask)
2028  RETURN
2029  END IF
2030  END IF
2031  END IF
2032 
2033  ! Take care of submitted field data
2034  IF ( average ) THEN
2035  IF ( input_fields(diag_field_id)%mask_variant ) THEN
2036  IF ( need_compute ) THEN
2037  WRITE (error_string,'(a,"/",a)') &
2038  & trim(input_fields(diag_field_id)%module_name), &
2039  & trim(output_fields(out_num)%output_name)
2040  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2041  & ', regional output NOT supported with mask_variant', err_msg)) THEN
2042  DEALLOCATE(oor_mask)
2043  RETURN
2044  END IF
2045  END IF
2046 
2047  ! Should reduced_k_range data be supported with the mask_variant option ?????
2048  ! If not, error message should be produced and the reduced_k_range loop below eliminated
2049  IF ( PRESENT(mask) ) THEN
2050  IF ( missvalue_present ) THEN
2051  IF ( debug_diag_manager ) THEN
2052  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2053  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2054  IF ( err_msg_local /= '' ) THEN
2055  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2056  DEALLOCATE(oor_mask)
2057  RETURN
2058  END IF
2059  END IF
2060  END IF
2061  IF( numthreads>1 .AND. phys_window ) then
2062  IF ( reduced_k_range ) THEN
2063  DO k= ksr, ker
2064  k1= k - ksr + 1
2065  DO j=js, je
2066  DO i=is, ie
2067  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2068  IF ( pow_value /= 1 ) THEN
2069  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2070  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2071  & (field(i-is+1+hi, j-js+1+hj, k) * weight1)**(pow_value)
2072  ELSE
2073  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2074  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2075  & field(i-is+1+hi, j-js+1+hj, k) * weight1
2076  END IF
2077  output_fields(out_num)%counter(i-hi,j-hj,k1,sample) =&
2078  & output_fields(out_num)%counter(i-hi,j-hj,k1,sample) + weight1
2079  END IF
2080  END DO
2081  END DO
2082  END DO
2083  ELSE
2084  DO k=ks, ke
2085  DO j=js, je
2086  DO i=is, ie
2087  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2088  IF ( pow_value /= 1 ) THEN
2089  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2090  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2091  & (field(i-is+1+hi,j-js+1+hj,k)*weight1)**(pow_value)
2092  ELSE
2093  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2094  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2095  & field(i-is+1+hi,j-js+1+hj,k)*weight1
2096  END IF
2097  output_fields(out_num)%counter(i-hi,j-hj,k,sample) =&
2098  &output_fields(out_num)%counter(i-hi,j-hj,k,sample) + weight1
2099  END IF
2100  END DO
2101  END DO
2102  END DO
2103  END IF
2104  ELSE
2105 !$OMP CRITICAL
2106  IF ( reduced_k_range ) THEN
2107  DO k= ksr, ker
2108  k1= k - ksr + 1
2109  DO j=js, je
2110  DO i=is, ie
2111  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2112  IF ( pow_value /= 1 ) THEN
2113  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2114  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2115  & (field(i-is+1+hi, j-js+1+hj, k) * weight1)**(pow_value)
2116  ELSE
2117  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2118  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2119  & field(i-is+1+hi, j-js+1+hj, k) * weight1
2120  END IF
2121  output_fields(out_num)%counter(i-hi,j-hj,k1,sample) =&
2122  & output_fields(out_num)%counter(i-hi,j-hj,k1,sample) + weight1
2123  END IF
2124  END DO
2125  END DO
2126  END DO
2127  ELSE
2128  DO k=ks, ke
2129  DO j=js, je
2130  DO i=is, ie
2131  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2132  IF ( pow_value /= 1 ) THEN
2133  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2134  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2135  & (field(i-is+1+hi,j-js+1+hj,k)*weight1)**(pow_value)
2136  ELSE
2137  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2138  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2139  & field(i-is+1+hi,j-js+1+hj,k)*weight1
2140  END IF
2141  output_fields(out_num)%counter(i-hi,j-hj,k,sample) =&
2142  &output_fields(out_num)%counter(i-hi,j-hj,k,sample) + weight1
2143  END IF
2144  END DO
2145  END DO
2146  END DO
2147  END IF
2148 !$OMP END CRITICAL
2149  END IF
2150  ELSE
2151  WRITE (error_string,'(a,"/",a)')&
2152  & trim(input_fields(diag_field_id)%module_name), &
2153  & trim(output_fields(out_num)%output_name)
2154  IF ( fms_error_handler('diag_manager_mod::send_data_3d', 'module/output_field '//trim(error_string)//&
2155  & ', variable mask but no missing value defined', err_msg)) THEN
2156  DEALLOCATE(oor_mask)
2157  RETURN
2158  END IF
2159  END IF
2160  ELSE ! no mask present
2161  WRITE (error_string,'(a,"/",a)')&
2162  & trim(input_fields(diag_field_id)%module_name), &
2163  & trim(output_fields(out_num)%output_name)
2164  IF(fms_error_handler('diag_manager_mod::send_data_3d','module/output_field '//trim(error_string)//&
2165  & ', variable mask but no mask given', err_msg)) THEN
2166  DEALLOCATE(oor_mask)
2167  RETURN
2168  END IF
2169  END IF
2170  ELSE ! mask_variant=false
2171  IF ( PRESENT(mask) ) THEN
2172  IF ( missvalue_present ) THEN
2173  IF ( need_compute ) THEN
2174  IF (numthreads>1 .AND. phys_window) then
2175  DO k = l_start(3), l_end(3)
2176  k1 = k-l_start(3)+1
2177  DO j = js, je
2178  DO i = is, ie
2179  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
2180  i1 = i-l_start(1)-hi+1
2181  j1= j-l_start(2)-hj+1
2182  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2183  IF ( pow_value /= 1 ) THEN
2184  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2185  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2186  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2187  ELSE
2188  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2189  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2190  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2191  END IF
2192  ELSE
2193  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2194  END IF
2195  END IF
2196  END DO
2197  END DO
2198  END DO
2199  ELSE
2200 !$OMP CRITICAL
2201  DO k = l_start(3), l_end(3)
2202  k1 = k-l_start(3)+1
2203  DO j = js, je
2204  DO i = is, ie
2205  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
2206  i1 = i-l_start(1)-hi+1
2207  j1= j-l_start(2)-hj+1
2208  IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
2209  IF ( pow_value /= 1 ) THEN
2210  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2211  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2212  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2213  ELSE
2214  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2215  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2216  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2217  END IF
2218  ELSE
2219  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2220  END IF
2221  END IF
2222  END DO
2223  END DO
2224  END DO
2225 !$OMP END CRITICAL
2226  ENDIF
2227 !$OMP CRITICAL
2228  DO j = js, je
2229  DO i = is, ie
2230  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
2231  output_fields(out_num)%num_elements(sample) = &
2232  output_fields(out_num)%num_elements(sample) + l_end(3) - l_start(3) + 1
2233  END IF
2234  END DO
2235  END DO
2236 !$OMP END CRITICAL
2237  ELSE IF ( reduced_k_range ) THEN
2238  IF (numthreads>1 .AND. phys_window) then
2239  DO k=ksr, ker
2240  k1 = k - ksr + 1
2241  DO j=js, je
2242  DO i=is, ie
2243  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2244  IF ( pow_value /= 1 ) THEN
2245  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2246  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2247  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2248  ELSE
2249  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2250  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2251  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2252  END IF
2253  ELSE
2254  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
2255  END IF
2256  END DO
2257  END DO
2258  END DO
2259  ELSE
2260 !$OMP CRITICAL
2261  DO k=ksr, ker
2262  k1 = k - ksr + 1
2263  DO j=js, je
2264  DO i=is, ie
2265  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2266  IF ( pow_value /= 1 ) THEN
2267  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2268  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2269  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2270  ELSE
2271  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2272  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2273  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2274  END IF
2275  ELSE
2276  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
2277  END IF
2278  END DO
2279  END DO
2280  END DO
2281 !$OMP END CRITICAL
2282  END IF
2283  ELSE
2284  IF ( debug_diag_manager ) THEN
2285  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2286  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2287  IF ( err_msg_local /= '' ) THEN
2288  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2289  DEALLOCATE(oor_mask)
2290  RETURN
2291  END IF
2292  END IF
2293  END IF
2294  IF (numthreads>1 .AND. phys_window) then
2295  DO k=ks, ke
2296  DO j=js, je
2297  DO i=is, ie
2298  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2299  IF ( pow_value /= 1 ) THEN
2300  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2301  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2302  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2303  ELSE
2304  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2305  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2306  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2307  END IF
2308  ELSE
2309  output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
2310  END IF
2311  END DO
2312  END DO
2313  END DO
2314  ELSE
2315 !$OMP CRITICAL
2316  DO k=ks, ke
2317  DO j=js, je
2318  DO i=is, ie
2319  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2320  IF ( pow_value /= 1 ) THEN
2321  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2322  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2323  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2324  ELSE
2325  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2326  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2327  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2328  END IF
2329  ELSE
2330  output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
2331  END IF
2332  END DO
2333  END DO
2334  END DO
2335 !$OMP END CRITICAL
2336  END IF
2337  END IF
2338 !$OMP CRITICAL
2339  IF ( need_compute .AND. .NOT.phys_window ) THEN
2340  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))) ) &
2341  & output_fields(out_num)%count_0d(sample) =&
2342  & output_fields(out_num)%count_0d(sample) + weight1
2343  ELSE
2344  IF ( any(mask(f1:f2,f3:f4,ks:ke)) ) output_fields(out_num)%count_0d(sample) =&
2345  & output_fields(out_num)%count_0d(sample)+weight1
2346  END IF
2347 !$OMP END CRITICAL
2348 
2349  ELSE ! missing value NOT present
2350  IF ( (.NOT.all(mask(f1:f2,f3:f4,ks:ke)) .AND. mpp_pe() .EQ. mpp_root_pe()).AND.&
2351  & .NOT.input_fields(diag_field_id)%issued_mask_ignore_warning ) THEN
2352  ! <ERROR STATUS="WARNING">
2353  ! Mask will be ignored since missing values were not specified for field <field_name>
2354  ! in module <module_name>
2355  ! </ERROR>
2356  CALL error_mesg('diag_manager_mod::send_data_3d',&
2357  & 'Mask will be ignored since missing values were not specified for field '//&
2358  & trim(input_fields(diag_field_id)%field_name)//' in module '//&
2359  & trim(input_fields(diag_field_id)%module_name), warning)
2360  input_fields(diag_field_id)%issued_mask_ignore_warning = .true.
2361  END IF
2362  IF ( need_compute ) THEN
2363  IF (numthreads>1 .AND. phys_window) then
2364  DO j = js, je
2365  DO i = is, ie
2366  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
2367  i1 = i-l_start(1)-hi+1
2368  j1 = j-l_start(2)-hj+1
2369  IF ( pow_value /= 1 ) THEN
2370  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2371  & (field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2372  ELSE
2373  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2374  & field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2375  END IF
2376  END IF
2377  END DO
2378  END DO
2379  ELSE
2380 !$OMP CRITICAL
2381  DO j = js, je
2382  DO i = is, ie
2383  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
2384  i1 = i-l_start(1)-hi+1
2385  j1 = j-l_start(2)-hj+1
2386  IF ( pow_value /= 1 ) THEN
2387  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2388  & (field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2389  ELSE
2390  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample)+ &
2391  & field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2392  END IF
2393  END IF
2394  END DO
2395  END DO
2396 !$OMP END CRITICAL
2397  END IF
2398 !$OMP CRITICAL
2399  DO j = js, je
2400  DO i = is, ie
2401  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
2402  output_fields(out_num)%num_elements(sample)=&
2403  & output_fields(out_num)%num_elements(sample)+l_end(3)-l_start(3)+1
2404 
2405  END IF
2406  END DO
2407  END DO
2408 !$OMP END CRITICAL
2409  ELSE IF ( reduced_k_range ) THEN
2410  IF (numthreads>1 .AND. phys_window) then
2411  ksr= l_start(3)
2412  ker= l_end(3)
2413  IF ( pow_value /= 1 ) THEN
2414  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2415  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2416  & (field(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2417  ELSE
2418  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2419  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2420  & field(f1:f2,f3:f4,ksr:ker)*weight1
2421  END IF
2422  ELSE
2423 !$OMP CRITICAL
2424  ksr= l_start(3)
2425  ker= l_end(3)
2426  IF ( pow_value /= 1 ) THEN
2427  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2428  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2429  & (field(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2430  ELSE
2431  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2432  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
2433  & field(f1:f2,f3:f4,ksr:ker)*weight1
2434  END IF
2435 !$OMP END CRITICAL
2436  END IF
2437  ELSE
2438  IF ( debug_diag_manager ) THEN
2439  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2440  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2441  IF ( err_msg_local /= '') THEN
2442  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2443  DEALLOCATE(oor_mask)
2444  RETURN
2445  END IF
2446  END IF
2447  END IF
2448  IF (numthreads>1 .AND. phys_window) then
2449  IF ( pow_value /= 1 ) THEN
2450  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2451  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2452  & (field(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
2453  ELSE
2454  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2455  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2456  & field(f1:f2,f3:f4,ks:ke)*weight1
2457  END IF
2458  ELSE
2459 !$OMP CRITICAL
2460  IF ( pow_value /= 1 ) THEN
2461  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2462  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2463  & (field(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
2464  ELSE
2465  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2466  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2467  & field(f1:f2,f3:f4,ks:ke)*weight1
2468  END IF
2469 !$OMP END CRITICAL
2470  END IF
2471  END IF
2472 !$OMP CRITICAL
2473  IF ( .NOT.phys_window ) output_fields(out_num)%count_0d(sample) =&
2474  & output_fields(out_num)%count_0d(sample) + weight1
2475 !$OMP END CRITICAL
2476  END IF
2477  ELSE ! mask NOT present
2478  IF ( missvalue_present ) THEN
2479  IF ( need_compute ) THEN
2480  if( numthreads>1 .AND. phys_window ) then
2481  DO k = l_start(3), l_end(3)
2482  k1 = k - l_start(3) + 1
2483  DO j = js, je
2484  DO i = is, ie
2485  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
2486  i1 = i-l_start(1)-hi+1
2487  j1= j-l_start(2)-hj+1
2488  IF ( field(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2489  IF ( pow_value /= 1 ) THEN
2490  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2491  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2492  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2493  ELSE
2494  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2495  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2496  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2497  END IF
2498  ELSE
2499  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2500  END IF
2501  END IF
2502  END DO
2503  END DO
2504  END DO
2505  ELSE
2506 !$OMP CRITICAL
2507  DO k = l_start(3), l_end(3)
2508  k1 = k - l_start(3) + 1
2509  DO j = js, je
2510  DO i = is, ie
2511  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
2512  i1 = i-l_start(1)-hi+1
2513  j1= j-l_start(2)-hj+1
2514  IF ( field(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2515  IF ( pow_value /= 1 ) THEN
2516  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2517  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2518  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2519  ELSE
2520  output_fields(out_num)%buffer(i1,j1,k1,sample) =&
2521  & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
2522  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2523  END IF
2524  ELSE
2525  output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
2526  END IF
2527  END IF
2528  END DO
2529  END DO
2530  END DO
2531 !$OMP END CRITICAL
2532  END IF
2533 !$OMP CRITICAL
2534  DO j = js, je
2535  DO i = is, ie
2536  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
2537  output_fields(out_num)%num_elements(sample) =&
2538  & output_fields(out_num)%num_elements(sample) + l_end(3) - l_start(3) + 1
2539  END IF
2540  END DO
2541  END DO
2542  IF ( .NOT.phys_window ) THEN
2543  outer0: DO k = l_start(3), l_end(3)
2544  DO j=l_start(2)+hj, l_end(2)+hj
2545  DO i=l_start(1)+hi, l_end(1)+hi
2546  IF ( field(i,j,k) /= missvalue ) THEN
2547  output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) + weight1
2548  EXIT outer0
2549  END IF
2550  END DO
2551  END DO
2552  END DO outer0
2553  END IF
2554 !$OMP END CRITICAL
2555  ELSE IF ( reduced_k_range ) THEN
2556  if( numthreads>1 .AND. phys_window ) then
2557  ksr= l_start(3)
2558  ker= l_end(3)
2559  DO k = ksr, ker
2560  k1 = k - ksr + 1
2561  DO j=js, je
2562  DO i=is, ie
2563  IF ( field(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2564  IF ( pow_value /= 1 ) THEN
2565  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2566  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2567  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2568  ELSE
2569  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2570  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2571  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2572  END IF
2573  ELSE
2574  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) = missvalue
2575  END IF
2576  END DO
2577  END DO
2578  END DO
2579  else
2580 !$OMP CRITICAL
2581  ksr= l_start(3)
2582  ker= l_end(3)
2583  DO k = ksr, ker
2584  k1 = k - ksr + 1
2585  DO j=js, je
2586  DO i=is, ie
2587  IF ( field(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2588  IF ( pow_value /= 1 ) THEN
2589  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2590  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2591  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2592  ELSE
2593  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
2594  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
2595  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2596  END IF
2597  ELSE
2598  output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) = missvalue
2599  END IF
2600  END DO
2601  END DO
2602  END DO
2603 !$OMP END CRITICAL
2604  END IF
2605 !$OMP CRITICAL
2606  outer3: DO k = ksr, ker
2607  k1=k-ksr+1
2608  DO j=f3, f4
2609  DO i=f1, f2
2610  IF ( field(i,j,k) /= missvalue ) THEN
2611  output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) + weight1
2612  EXIT outer3
2613  END IF
2614  END DO
2615  END DO
2616  END DO outer3
2617 !$OMP END CRITICAL
2618  ELSE
2619  IF ( debug_diag_manager ) THEN
2620  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2621  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2622  IF ( err_msg_local /= '' ) THEN
2623  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2624  DEALLOCATE(oor_mask)
2625  RETURN
2626  END IF
2627  END IF
2628  END IF
2629  IF( numthreads > 1 .AND. phys_window ) then
2630  DO k=ks, ke
2631  DO j=js, je
2632  DO i=is, ie
2633  IF ( field(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2634  IF ( pow_value /= 1 ) THEN
2635  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2636  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2637  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2638  ELSE
2639  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2640  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2641  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2642  END IF
2643  ELSE
2644  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) = missvalue
2645  END IF
2646  END DO
2647  END DO
2648  END DO
2649  ELSE
2650 !$OMP CRITICAL
2651  DO k=ks, ke
2652  DO j=js, je
2653  DO i=is, ie
2654  IF ( field(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
2655  IF ( pow_value /= 1 ) THEN
2656  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2657  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2658  & (field(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
2659  ELSE
2660  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
2661  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
2662  & field(i-is+1+hi,j-js+1+hj,k) * weight1
2663  END IF
2664  ELSE
2665  output_fields(out_num)%buffer(i-hi,j-hj,k,sample) = missvalue
2666  END IF
2667  END DO
2668  END DO
2669  END DO
2670 !$OMP END CRITICAL
2671  END IF
2672 !$OMP CRITICAL
2673  outer1: DO k=ks, ke
2674  DO j=f3, f4
2675  DO i=f1, f2
2676  IF ( field(i,j,k) /= missvalue ) THEN
2677  output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) + weight1
2678  EXIT outer1
2679  END IF
2680  END DO
2681  END DO
2682  END DO outer1
2683 !$OMP END CRITICAL
2684  END IF
2685  ELSE ! no missing value defined, No mask
2686  IF ( need_compute ) THEN
2687  IF( numthreads > 1 .AND. phys_window ) then
2688  DO j = js, je
2689  DO i = is, ie
2690  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
2691  i1 = i-l_start(1)-hi+1
2692  j1= j-l_start(2)-hj+1
2693  IF ( pow_value /= 1 ) THEN
2694  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample) +&
2695  & (field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2696  ELSE
2697  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample) +&
2698  & field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2699  END IF
2700  END IF
2701  END DO
2702  END DO
2703  ELSE
2704 !$OMP CRITICAL
2705  DO j = js, je
2706  DO i = is, ie
2707  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
2708  i1 = i-l_start(1)-hi+1
2709  j1= j-l_start(2)-hj+1
2710  IF ( pow_value /= 1 ) THEN
2711  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample) +&
2712  & (field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
2713  ELSE
2714  output_fields(out_num)%buffer(i1,j1,:,sample)= output_fields(out_num)%buffer(i1,j1,:,sample) +&
2715  & field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
2716  END IF
2717  END IF
2718  END DO
2719  END DO
2720 !$OMP END CRITICAL
2721  END IF
2722 
2723 !$OMP CRITICAL
2724  DO j = js, je
2725  DO i = is, ie
2726  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
2727  output_fields(out_num)%num_elements(sample) =&
2728  & output_fields(out_num)%num_elements(sample)+l_end(3)-l_start(3)+1
2729  END IF
2730  END DO
2731  END DO
2732 !$OMP END CRITICAL
2733  ! Accumulate time average
2734  ELSE IF ( reduced_k_range ) THEN
2735  ksr= l_start(3)
2736  ker= l_end(3)
2737  IF( numthreads > 1 .AND. phys_window ) then
2738  IF ( pow_value /= 1 ) THEN
2739  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2740  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2741  & (field(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2742  ELSE
2743  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2744  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2745  & field(f1:f2,f3:f4,ksr:ker)*weight1
2746  END IF
2747  ELSE
2748 !$OMP CRITICAL
2749  IF ( pow_value /= 1 ) THEN
2750  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2751  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2752  & (field(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
2753  ELSE
2754  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
2755  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2756  & field(f1:f2,f3:f4,ksr:ker)*weight1
2757  END IF
2758 !$OMP END CRITICAL
2759  END IF
2760  ELSE
2761  IF ( debug_diag_manager ) THEN
2762  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2763  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2764  IF ( err_msg_local /= '' ) THEN
2765  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2766  DEALLOCATE(oor_mask)
2767  RETURN
2768  END IF
2769  END IF
2770  END IF
2771  IF( numthreads > 1 .AND. phys_window ) then
2772  IF ( pow_value /= 1 ) THEN
2773  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2774  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2775  & (field(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
2776  ELSE
2777  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2778  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2779  & field(f1:f2,f3:f4,ks:ke)*weight1
2780  END IF
2781  ELSE
2782 !$OMP CRITICAL
2783  IF ( pow_value /= 1 ) THEN
2784  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2785  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2786  & (field(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
2787  ELSE
2788  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
2789  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
2790  & field(f1:f2,f3:f4,ks:ke)*weight1
2791  END IF
2792 !$OMP END CRITICAL
2793  END IF
2794  END IF
2795 !$OMP CRITICAL
2796  IF ( .NOT.phys_window ) output_fields(out_num)%count_0d(sample) =&
2797  & output_fields(out_num)%count_0d(sample) + weight1
2798 !$OMP END CRITICAL
2799  END IF
2800  END IF ! if mask present
2801  END IF !if mask_variant
2802 !$OMP CRITICAL
2803  IF ( .NOT.need_compute .AND. .NOT.reduced_k_range )&
2804  & output_fields(out_num)%num_elements(sample) =&
2805  & output_fields(out_num)%num_elements(sample) + (ie-is+1)*(je-js+1)*(ke-ks+1)
2806  IF ( reduced_k_range ) &
2807  & output_fields(out_num)%num_elements(sample) = output_fields(out_num)%num_elements(sample) +&
2808  & (ie-is+1)*(je-js+1)*(ker-ksr+1)
2809 !$OMP END CRITICAL
2810  ! Add processing for Max and Min
2811  ELSE IF ( time_max ) THEN
2812  IF ( PRESENT(mask) ) THEN
2813  IF ( need_compute ) THEN
2814  DO k = l_start(3), l_end(3)
2815  k1 = k - l_start(3) + 1
2816  DO j = js, je
2817  DO i = is, ie
2818  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
2819  i1 = i-l_start(1)-hi+1
2820  j1= j-l_start(2)-hj+1
2821  IF ( mask(i-is+1+hi,j-js+1+hj,k) .AND.&
2822  & field(i-is+1+hi,j-js+1+hj,k)>output_fields(out_num)%buffer(i1,j1,k1,sample)) THEN
2823  output_fields(out_num)%buffer(i1,j1,k1,sample) = field(i-is+1+hi,j-js+1+hj,k)
2824  END IF
2825  END IF
2826  END DO
2827  END DO
2828  END DO
2829  ! Maximum time value with masking
2830  ELSE IF ( reduced_k_range ) THEN
2831  ksr = l_start(3)
2832  ker = l_end(3)
2833  WHERE ( mask(f1:f2,f3:f4,ksr:ker) .AND. &
2834  & field(f1:f2,f3:f4,ksr:ker) > output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample))&
2835  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field(f1:f2,f3:f4,ksr:ker)
2836  ELSE
2837  IF ( debug_diag_manager ) THEN
2838  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2839  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2840  IF ( err_msg_local /= '' ) THEN
2841  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2842  DEALLOCATE(oor_mask)
2843  RETURN
2844  END IF
2845  END IF
2846  END IF
2847  WHERE ( mask(f1:f2,f3:f4,ks:ke) .AND.&
2848  & field(f1:f2,f3:f4,ks:ke)>output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample))&
2849  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field(f1:f2,f3:f4,ks:ke)
2850  END IF
2851  ELSE
2852  IF ( need_compute ) THEN
2853  DO k = l_start(3), l_end(3)
2854  k1 = k - l_start(3) + 1
2855  DO j = js, je
2856  DO i = is, ie
2857  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
2858  i1 = i-l_start(1)-hi+1
2859  j1 = j-l_start(2)-hj+1
2860  IF ( field(i-is+1+hi,j-js+1+hj,k) > output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
2861  output_fields(out_num)%buffer(i1,j1,k1,sample) = field(i-is+1+hi,j-js+1+hj,k)
2862  END IF
2863  END IF
2864  END DO
2865  END DO
2866  END DO
2867  ! Maximum time value
2868  ELSE IF ( reduced_k_range ) THEN
2869  ksr = l_start(3)
2870  ker = l_end(3)
2871  WHERE ( field(f1:f2,f3:f4,ksr:ker) > output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) ) &
2872  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field(f1:f2,f3:f4,ksr:ker)
2873  ELSE
2874  IF ( debug_diag_manager ) THEN
2875  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2876  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2877  IF ( err_msg_local /= '' ) THEN
2878  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2879  DEALLOCATE(oor_mask)
2880  RETURN
2881  END IF
2882  END IF
2883  END IF
2884  WHERE ( field(f1:f2,f3:f4,ks:ke) > output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) ) &
2885  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field(f1:f2,f3:f4,ks:ke)
2886  END IF
2887  END IF
2888  output_fields(out_num)%count_0d(sample) = 1
2889  ELSE IF ( time_min ) THEN
2890  IF ( PRESENT(mask) ) THEN
2891  IF ( need_compute ) THEN
2892  DO k = l_start(3), l_end(3)
2893  k1 = k - l_start(3) + 1
2894  DO j = js, je
2895  DO i = is, ie
2896  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
2897  i1 = i-l_start(1)-hi+1
2898  j1 = j-l_start(2)-hj+1
2899  IF ( mask(i-is+1+hi,j-js+1+hj,k) .AND.&
2900  & field(i-is+1+hi,j-js+1+hj,k) < output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
2901  output_fields(out_num)%buffer(i1,j1,k1,sample) = field(i-is+1+hi,j-js+1+hj,k)
2902  END IF
2903  END IF
2904  END DO
2905  END DO
2906  END DO
2907  ! Minimum time value with masking
2908  ELSE IF ( reduced_k_range ) THEN
2909  ksr= l_start(3)
2910  ker= l_end(3)
2911  WHERE ( mask(f1:f2,f3:f4,ksr:ker) .AND.&
2912  & field(f1:f2,f3:f4,ksr:ker) < output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample)) &
2913  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field(f1:f2,f3:f4,ksr:ker)
2914  ELSE
2915  IF ( debug_diag_manager ) THEN
2916  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2917  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2918  IF ( err_msg_local /= '' ) THEN
2919  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2920  DEALLOCATE(oor_mask)
2921  RETURN
2922  END IF
2923  END IF
2924  END IF
2925  WHERE ( mask(f1:f2,f3:f4,ks:ke) .AND.&
2926  & field(f1:f2,f3:f4,ks:ke) < output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) ) &
2927  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field(f1:f2,f3:f4,ks:ke)
2928  END IF
2929  ELSE
2930  IF ( need_compute ) THEN
2931  DO k = l_start(3), l_end(3)
2932  k1 = k - l_start(3) + 1
2933  DO j = js, je
2934  DO i = is, ie
2935  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
2936  i1 = i-l_start(1)-hi+1
2937  j1= j-l_start(2)-hj+1
2938  IF ( field(i-is+1+hi,j-js+1+hj,k) < output_fields(out_num)%buffer(i1,j1,k1,sample) ) THEN
2939  output_fields(out_num)%buffer(i1,j1,k1,sample) = field(i-is+1+hi,j-js+1+hj,k)
2940  END IF
2941  END IF
2942  END DO
2943  END DO
2944  END DO
2945  ! Minimum time value
2946  ELSE IF ( reduced_k_range ) THEN
2947  ksr= l_start(3)
2948  ker= l_end(3)
2949  WHERE ( field(f1:f2,f3:f4,ksr:ker) < output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) ) &
2950  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field(f1:f2,f3:f4,ksr:ker)
2951  ELSE
2952  IF ( debug_diag_manager ) THEN
2953  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2954  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2955  IF ( err_msg_local /= '' ) THEN
2956  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2957  DEALLOCATE(oor_mask)
2958  RETURN
2959  END IF
2960  END IF
2961  END IF
2962  WHERE ( field(f1:f2,f3:f4,ks:ke) < output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) )&
2963  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field(f1:f2,f3:f4,ks:ke)
2964  END IF
2965  END IF
2966  output_fields(out_num)%count_0d(sample) = 1
2967  ELSE IF ( time_sum ) THEN
2968  IF ( PRESENT(mask) ) THEN
2969  IF ( need_compute ) THEN
2970  DO k = l_start(3), l_end(3)
2971  k1 = k - l_start(3) + 1
2972  DO j = js, je
2973  DO i = is, ie
2974  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
2975  i1 = i-l_start(1)-hi+1
2976  j1 = j-l_start(2)-hj+1
2977  IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
2978  output_fields(out_num)%buffer(i1,j1,k1,sample) = &
2979  output_fields(out_num)%buffer(i1,j1,k1,sample) + &
2980  field(i-is+1+hi,j-js+1+hj,k)
2981  END IF
2982  END IF
2983  END DO
2984  END DO
2985  END DO
2986  ! Minimum time value with masking
2987  ELSE IF ( reduced_k_range ) THEN
2988  ksr= l_start(3)
2989  ker= l_end(3)
2990  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = &
2991  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
2992  & field(f1:f2,f3:f4,ksr:ker)
2993  ELSE
2994  IF ( debug_diag_manager ) THEN
2995  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
2996  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
2997  IF ( err_msg_local /= '' ) THEN
2998  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
2999  DEALLOCATE(oor_mask)
3000  RETURN
3001  END IF
3002  END IF
3003  END IF
3004  WHERE ( mask(f1:f2,f3:f4,ks:ke) ) &
3005  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = &
3006  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) + &
3007  & field(f1:f2,f3:f4,ks:ke)
3008  END IF
3009  ELSE
3010  IF ( need_compute ) THEN
3011  DO k = l_start(3), l_end(3)
3012  k1 = k - l_start(3) + 1
3013  DO j = js, je
3014  DO i = is, ie
3015  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
3016  i1 = i-l_start(1)-hi+1
3017  j1= j-l_start(2)-hj+1
3018  output_fields(out_num)%buffer(i1,j1,k1,sample) = &
3019  & output_fields(out_num)%buffer(i1,j1,k1,sample) + &
3020  & field(i-is+1+hi,j-js+1+hj,k)
3021  END IF
3022  END DO
3023  END DO
3024  END DO
3025  ELSE IF ( reduced_k_range ) THEN
3026  ksr= l_start(3)
3027  ker= l_end(3)
3028  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = &
3029  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
3030  & field(f1:f2,f3:f4,ksr:ker)
3031  ELSE
3032  IF ( debug_diag_manager ) THEN
3033  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3034  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3035  IF ( err_msg_local /= '' ) THEN
3036  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3037  DEALLOCATE(oor_mask)
3038  RETURN
3039  END IF
3040  END IF
3041  END IF
3042  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = &
3043  & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) + &
3044  & field(f1:f2,f3:f4,ks:ke)
3045  END IF
3046  END IF
3047  output_fields(out_num)%count_0d(sample) = 1
3048  ELSE ! ( not average, not min, not max, not sum )
3049  output_fields(out_num)%count_0d(sample) = 1
3050  IF ( need_compute ) THEN
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. j <= l_end(2)+hj ) THEN
3054  i1 = i-l_start(1)-hi+1
3055  j1 = j-l_start(2)-hj+1
3056  output_fields(out_num)%buffer(i1,j1,:,sample) = field(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))
3057  END IF
3058  END DO
3059  END DO
3060  ! instantaneous output
3061  ELSE IF ( reduced_k_range ) THEN
3062  ksr = l_start(3)
3063  ker = l_end(3)
3064  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) = field(f1:f2,f3:f4,ksr:ker)
3065  ELSE
3066  IF ( debug_diag_manager ) THEN
3067  CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
3068  CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
3069  IF ( err_msg_local /= '' ) THEN
3070  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
3071  DEALLOCATE(oor_mask)
3072  RETURN
3073  END IF
3074  END IF
3075  END IF
3076  output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) = field(f1:f2,f3:f4,ks:ke)
3077  END IF
3078 
3079  IF ( PRESENT(mask) .AND. missvalue_present ) THEN
3080  IF ( need_compute ) THEN
3081  DO k = l_start(3), l_end(3)
3082  k1 = k - l_start(3) + 1
3083  DO j = js, je
3084  DO i = is, ie
3085  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
3086  i1 = i-l_start(1)-hi+1
3087  j1 = j-l_start(2)-hj+1
3088  IF ( .NOT.mask(i-is+1+hi,j-js+1+hj,k) )&
3089  & output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
3090  END IF
3091  END DO
3092  END DO
3093  END DO
3094  ELSE IF ( reduced_k_range ) THEN
3095  ksr= l_start(3)
3096  ker= l_end(3)
3097  DO k=ksr, ker
3098  k1= k - ksr + 1
3099  DO j=js, je
3100  DO i=is, ie
3101  IF ( .NOT.mask(i-is+1+hi,j-js+1+hj,k) ) &
3102  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
3103  END DO
3104  END DO
3105  END DO
3106  ELSE
3107  DO k=ks, ke
3108  DO j=js, je
3109  DO i=is, ie
3110  IF ( .NOT.mask(i-is+1+hi,j-js+1+hj,k) )&
3111  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
3112  END DO
3113  END DO
3114  END DO
3115  END IF
3116  END IF
3117  END IF !average
3118 
3119  IF ( output_fields(out_num)%static .AND. .NOT.need_compute .AND. debug_diag_manager ) THEN
3120  CALL check_bounds_are_exact_static(out_num, diag_field_id, err_msg=err_msg_local)
3121  IF ( err_msg_local /= '' ) THEN
3122  IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg)) THEN
3123  DEALLOCATE(oor_mask)
3124  RETURN
3125  END IF
3126  END IF
3127  END IF
3128 
3129  ! If rmask and missing value present, then insert missing value
3130  IF ( PRESENT(rmask) .AND. missvalue_present ) THEN
3131  IF ( need_compute ) THEN
3132  DO k = l_start(3), l_end(3)
3133  k1 = k - l_start(3) + 1
3134  DO j = js, je
3135  DO i = is, ie
3136  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
3137  i1 = i-l_start(1)-hi+1
3138  j1 = j-l_start(2)-hj+1
3139  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5 ) &
3140  & output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
3141  END IF
3142  END DO
3143  END DO
3144  END DO
3145  ELSE IF ( reduced_k_range ) THEN
3146  ksr= l_start(3)
3147  ker= l_end(3)
3148  DO k= ksr, ker
3149  k1 = k - ksr + 1
3150  DO j=js, je
3151  DO i=is, ie
3152  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5 ) &
3153  & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
3154  END DO
3155  END DO
3156  END DO
3157  ELSE
3158  DO k=ks, ke
3159  DO j=js, je
3160  DO i=is, ie
3161  IF ( rmask(i-is+1+hi,j-js+1+hj,k) < 0.5 ) &
3162  & output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
3163  END DO
3164  END DO
3165  END DO
3166  END IF
3167  END IF
3168 
3169  END DO num_out_fields
3170 
3171  DEALLOCATE(oor_mask)
3172  END FUNCTION send_data_3d
3173  ! </FUNCTION>
3174 
3175  ! <FUNCTION NAME="send_tile_averaged_data1d" INTERFACE="send_tile_averaged_data">
3176  ! <IN NAME="diag_field_id" TYPE="INTEGER"></IN>
3177  ! <IN NAME="field" TYPE="REAL, DIMENSION(:,:,:)"></IN>
3178  ! <IN NAME="area" TYPE="REAL, DIMENSION(:,:,:)"> </IN>
3179  ! <IN NAME="time" TYPE="TYPE(time_type)"> </IN>
3180  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:), OPTIONAL"></IN>
3181  LOGICAL FUNCTION send_tile_averaged_data1d ( id, field, area, time, mask )
3182  INTEGER, INTENT(in) :: id ! id od the diagnostic field
3183  REAL, INTENT(in) :: field(:,:) ! field to average and send
3184  REAL, INTENT(in) :: area (:,:) ! area of tiles (== averaging weights), arbitrary units
3185  TYPE(time_type), INTENT(in) :: time ! current time
3186  LOGICAL, INTENT(in),OPTIONAL :: mask (:,:) ! land mask
3187 
3188  REAL, DIMENSION(SIZE(field,1)) :: out(size(field,1))
3189 
3190  ! If id is < 0 it means that this field is not registered, simply return
3191  IF ( id <= 0 ) THEN
3192  send_tile_averaged_data1d = .false.
3193  RETURN
3194  END IF
3195 
3196  CALL average_tiles1d (id, field, area, mask, out)
3197  send_tile_averaged_data1d = send_data(id, out, time=time, mask=any(mask,dim=2))
3198  END FUNCTION send_tile_averaged_data1d
3199 
3200  ! <SUBROUTINE NAME="average_tiles1d">
3201  ! <OVERVIEW>
3202  ! </OVERVIEW>
3203  ! <TEMPLATE>
3204  ! SUBROUTINE average_tiles1d(diag_field_id, x, area, mask, out)
3205  ! </TEMPLATE>
3206  ! <DESCRIPTION>
3207  ! </DESCRIPTION>
3208  ! <IN NAME="diag_field_id" TYPE="INTEGER"></IN>
3209  ! <IN NAME="x" TYPE="REAL, DIMENSION(:,:)">(ug_index, tile) field to average</IN>
3210  ! <IN NAME="area" TYPE="REAL, DIMENSION(:,:,:)">(ug_index, tile) fractional area</IN>
3211  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:)">(ug_index, tile) land mask</IN>
3212  ! <OUT NAME="out" TYPE="REAL, DIMENSION(:,:)">(ug_index) result of averaging</OUT>
3213  SUBROUTINE average_tiles1d(diag_field_id, x, area, mask, out)
3214  INTEGER, INTENT(in) :: diag_field_id
3215  REAL, DIMENSION(:,:), INTENT(in) :: x
3216  REAL, DIMENSION(:,:), INTENT(in) :: area
3217  LOGICAL, DIMENSION(:,:), INTENT(in) :: mask
3218  REAL, DIMENSION(:), INTENT(out) :: out
3219 
3220  INTEGER :: it ! iterator over tile number
3221  REAL, DIMENSION(SIZE(x,1)) :: s ! area accumulator
3222  REAL :: local_missing_value
3223 
3224  ! # FATAL if diag_field_id is less than 0, indicates field was not in diag_table.
3225  ! The calling functions should not have passed in an invalid diag_field_id
3226  IF ( diag_field_id <= 0 ) THEN
3227  ! <ERROR STATUS="FATAL">
3228  ! diag_field_id less than 0. Contact developers.
3229  ! </ERROR>
3230  CALL error_mesg('diag_manager_mod::average_tiles1d',&
3231  & "diag_field_id less than 0. Contact developers.", fatal)
3232  END IF
3233 
3234  ! Initialize local_missing_value
3235  IF ( input_fields(diag_field_id)%missing_value_present ) THEN
3236  local_missing_value = input_fields(diag_field_id)%missing_value
3237  ELSE
3238  local_missing_value = 0.0
3239  END IF
3240 
3241  ! Initialize s and out to zero.
3242  s(:) = 0.0
3243  out(:) = 0.0
3244 
3245  DO it = 1, SIZE(area,dim=2)
3246  WHERE ( mask(:,it) )
3247  out(:) = out(:) + x(:,it)*area(:,it)
3248  s(:) = s(:) + area(:,it)
3249  END WHERE
3250  END DO
3251 
3252  WHERE ( s(:) > 0 )
3253  out(:) = out(:)/s(:)
3254  ELSEWHERE
3255  out(:) = local_missing_value
3256  END WHERE
3257  END SUBROUTINE average_tiles1d
3258 
3259 
3260  ! <FUNCTION NAME="send_tile_averaged_data2d" INTERFACE="send_tile_averaged_data">
3261  ! <IN NAME="diag_field_id" TYPE="INTEGER"></IN>
3262  ! <IN NAME="field" TYPE="REAL, DIMENSION(:,:,:)"></IN>
3263  ! <IN NAME="area" TYPE="REAL, DIMENSION(:,:,:)"> </IN>
3264  ! <IN NAME="time" TYPE="TYPE(time_type)"> </IN>
3265  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:), OPTIONAL"></IN>
3266  LOGICAL FUNCTION send_tile_averaged_data2d ( id, field, area, time, mask )
3267  INTEGER, INTENT(in) :: id ! id od the diagnostic field
3268  REAL, INTENT(in) :: field(:,:,:) ! field to average and send
3269  REAL, INTENT(in) :: area (:,:,:) ! area of tiles (== averaging weights), arbitrary units
3270  TYPE(time_type), INTENT(in) :: time ! current time
3271  LOGICAL, INTENT(in),OPTIONAL :: mask (:,:,:) ! land mask
3272 
3273  REAL, DIMENSION(SIZE(field,1),SIZE(field,2)) :: out(size(field,1), size(field,2))
3274 
3275  ! If id is < 0 it means that this field is not registered, simply return
3276  IF ( id <= 0 ) THEN
3277  send_tile_averaged_data2d = .false.
3278  RETURN
3279  END IF
3280 
3281  CALL average_tiles(id, field, area, mask, out)
3282  send_tile_averaged_data2d = send_data(id, out, time, mask=any(mask,dim=3))
3283  END FUNCTION send_tile_averaged_data2d
3284  ! </FUNCTION>
3285 
3286  ! <FUNCTION NAME="send_tile_averaged_data3d" INTERFACE="send_tile_averaged_data">
3287  ! <IN NAME="diag_field_id" TYPE="INTEGER"></IN>
3288  ! <IN NAME="field" TYPE="REAL, DIMENSION(:,:,:,:)"></IN>
3289  ! <IN NAME="area" TYPE="REAL, DIMENSION(:,:,:)"></IN>
3290  ! <IN NAME="time" TYPE="TYPE(time_type)"></IN>
3291  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:), OPTIONAL"> </IN>
3292  LOGICAL FUNCTION send_tile_averaged_data3d( id, field, area, time, mask )
3293  INTEGER, INTENT(in) :: id ! id of the diagnostic field
3294  REAL, DIMENSION(:,:,:,:), INTENT(in) :: field ! (lon, lat, tile, lev) field to average and send
3295  REAL, DIMENSION(:,:,:), INTENT(in) :: area (:,:,:) ! (lon, lat, tile) tile areas ( == averaging weights), arbitrary units
3296  TYPE(time_type), INTENT(in) :: time ! current time
3297  LOGICAL, DIMENSION(:,:,:), INTENT(in), OPTIONAL :: mask ! (lon, lat, tile) land mask
3298 
3299  REAL, DIMENSION(SIZE(field,1),SIZE(field,2),SIZE(field,4)) :: out
3300  LOGICAL, DIMENSION(SIZE(field,1),SIZE(field,2),SIZE(field,4)) :: mask3
3301  INTEGER :: it
3302 
3303  ! If id is < 0 it means that this field is not registered, simply return
3304  IF ( id <= 0 ) THEN
3305  send_tile_averaged_data3d = .false.
3306  RETURN
3307  END IF
3308 
3309  DO it=1, SIZE(field,4)
3310  CALL average_tiles(id, field(:,:,:,it), area, mask, out(:,:,it) )
3311  END DO
3312 
3313  mask3(:,:,1) = any(mask,dim=3)
3314  DO it = 2, SIZE(field,4)
3315  mask3(:,:,it) = mask3(:,:,1)
3316  END DO
3317 
3318  send_tile_averaged_data3d = send_data( id, out, time, mask=mask3 )
3319  END FUNCTION send_tile_averaged_data3d
3320  ! </FUNCTION>
3321 
3322  ! <SUBROUTINE NAME="average_tiles">
3323  ! <OVERVIEW>
3324  ! </OVERVIEW>
3325  ! <TEMPLATE>
3326  ! SUBROUTINE average_tiles(diag_field_id, x, area, mask, out)
3327  ! </TEMPLATE>
3328  ! <DESCRIPTION>
3329  ! </DESCRIPTION>
3330  ! <IN NAME="diag_field_id" TYPE="INTEGER"></IN>
3331  ! <IN NAME="x" TYPE="REAL, DIMENSION(:,:,:)">(lon, lat, tile) field to average</IN>
3332  ! <IN NAME="area" TYPE="REAL, DIMENSION(:,:,:)">(lon, lat, tile) fractional area</IN>
3333  ! <IN NAME="mask" TYPE="LOGICAL, DIMENSION(:,:,:)">(lon, lat, tile) land mask</IN>
3334  ! <OUT NAME="out" TYPE="REAL, DIMENSION(:,:)">(lon, lat) result of averaging</OUT>
3335  SUBROUTINE average_tiles(diag_field_id, x, area, mask, out)
3336  INTEGER, INTENT(in) :: diag_field_id
3337  REAL, DIMENSION(:,:,:), INTENT(in) :: x
3338  REAL, DIMENSION(:,:,:), INTENT(in) :: area
3339  LOGICAL, DIMENSION(:,:,:), INTENT(in) :: mask
3340  REAL, DIMENSION(:,:), INTENT(out) :: out
3341 
3342  INTEGER :: it ! iterator over tile number
3343  REAL, DIMENSION(SIZE(x,1),SIZE(x,2)) :: s ! area accumulator
3344  REAL :: local_missing_value
3345 
3346  ! # FATAL if diag_field_id is less than 0, indicates field was not in diag_table.
3347  ! The calling functions should not have passed in an invalid diag_field_id
3348  IF ( diag_field_id <= 0 ) THEN
3349  ! <ERROR STATUS="FATAL">
3350  ! diag_field_id less than 0. Contact developers.
3351  ! </ERROR>
3352  CALL error_mesg('diag_manager_mod::average_tiles',&
3353  & "diag_field_id less than 0. Contact developers.", fatal)
3354  END IF
3355 
3356  ! Initialize local_missing_value
3357  IF ( input_fields(diag_field_id)%missing_value_present ) THEN
3358  local_missing_value = input_fields(diag_field_id)%missing_value
3359  ELSE
3360  local_missing_value = 0.0
3361  END IF
3362 
3363  ! Initialize s and out to zero.
3364  s(:,:) = 0.0
3365  out(:,:) = 0.0
3366 
3367  DO it = 1, SIZE(area,3)
3368  WHERE ( mask(:,:,it) )
3369  out(:,:) = out(:,:) + x(:,:,it)*area(:,:,it)
3370  s(:,:) = s(:,:) + area(:,:,it)
3371  END WHERE
3372  END DO
3373 
3374  WHERE ( s(:,:) > 0 )
3375  out(:,:) = out(:,:)/s(:,:)
3376  ELSEWHERE
3377  out(:,:) = local_missing_value
3378  END WHERE
3379  END SUBROUTINE average_tiles
3380  ! </SUBROUTINE>
3381 
3382  INTEGER FUNCTION writing_field(out_num, at_diag_end, error_string, time)
3383  INTEGER, INTENT(in) :: out_num
3384  LOGICAL, INTENT(in) :: at_diag_end
3385  CHARACTER(len=*), INTENT(out) :: error_string
3386  TYPE(time_type), INTENT(in) :: time
3387 
3388  TYPE(time_type) :: middle_time
3389  LOGICAL :: time_max, time_min, reduced_k_range, missvalue_present
3390  LOGICAL :: average, time_rms, need_compute, phys_window
3391  INTEGER :: in_num, file_num, freq, units
3392  INTEGER :: b1,b2,b3,b4 ! size of buffer along x,y,z,and diurnal axes
3393  INTEGER :: i, j, k, m
3394  REAL :: missvalue, num
3395 
3396  writing_field = 0
3397 
3398  need_compute = output_fields(out_num)%need_compute
3399 
3400  in_num = output_fields(out_num)%input_field
3401  IF ( input_fields(in_num)%static ) RETURN
3402 
3403  missvalue = input_fields(in_num)%missing_value
3404  missvalue_present = input_fields(in_num)%missing_value_present
3405  reduced_k_range = output_fields(out_num)%reduced_k_range
3406  phys_window = output_fields(out_num)%phys_window
3407  ! Is this output field being time averaged?
3408  average = output_fields(out_num)%time_average
3409  ! Are we taking the rms of the field?
3410  ! If so, then average is also .TRUE.
3411  time_rms = output_fields(out_num)%time_rms
3412  ! Looking for max and min value of this field over the sampling interval?
3413  time_max = output_fields(out_num)%time_max
3414  time_min = output_fields(out_num)%time_min
3415  file_num = output_fields(out_num)%output_file
3416  freq = files(file_num)%output_freq
3417  units = files(file_num)%output_units
3418 
3419  ! If average get size: Average intervals are last_output, next_output
3420  IF ( average ) THEN
3421  b1=SIZE(output_fields(out_num)%buffer,1)
3422  b2=SIZE(output_fields(out_num)%buffer,2)
3423  b3=SIZE(output_fields(out_num)%buffer,3)
3424  b4=SIZE(output_fields(out_num)%buffer,4)
3425  IF ( input_fields(in_num)%mask_variant ) THEN
3426  DO m=1, b4
3427  DO k=1, b3
3428  DO j=1, b2
3429  DO i=1, b1
3430  IF ( output_fields(out_num)%counter(i,j,k,m) > 0. )THEN
3431  output_fields(out_num)%buffer(i,j,k,m) = &
3432  & output_fields(out_num)%buffer(i,j,k,m)/output_fields(out_num)%counter(i,j,k,m)
3433  IF ( time_rms ) output_fields(out_num)%buffer(i,j,k,m) = &
3434  sqrt(output_fields(out_num)%buffer(i,j,k,m))
3435  ELSE
3436  output_fields(out_num)%buffer(i,j,k,m) = missvalue
3437  END IF
3438  END DO
3439  END DO
3440  END DO
3441  END DO
3442  ELSE !not mask variant
3443  DO m = 1, b4
3444  IF ( phys_window ) THEN
3445  IF ( need_compute .OR. reduced_k_range ) THEN
3446  num = REAL(output_fields(out_num)%num_elements(m)/output_fields(out_num)%region_elements)
3447  ELSE
3448  num = REAL(output_fields(out_num)%num_elements(m)/output_fields(out_num)%total_elements)
3449  END IF
3450  ELSE
3451  num = output_fields(out_num)%count_0d(m)
3452  END IF
3453  IF ( num > 0. ) THEN
3454  IF ( missvalue_present ) THEN
3455  DO k=1, b3
3456  DO j=1, b2
3457  DO i=1, b1
3458  IF ( output_fields(out_num)%buffer(i,j,k,m) /= missvalue ) THEN
3459  output_fields(out_num)%buffer(i,j,k,m) = output_fields(out_num)%buffer(i,j,k,m)/num
3460  IF ( time_rms ) output_fields(out_num)%buffer(i,j,k,m) =&
3461  & sqrt(output_fields(out_num)%buffer(i,j,k,m))
3462  END IF
3463  END DO
3464  END DO
3465  END DO
3466  ELSE
3467  output_fields(out_num)%buffer(:,:,:,m) = output_fields(out_num)%buffer(:,:,:,m)/num
3468  IF ( time_rms ) output_fields(out_num)%buffer(:,:,:,m) =&
3469  & sqrt(output_fields(out_num)%buffer(:,:,:,m))
3470  END IF
3471  ELSE IF ( .NOT. at_diag_end ) THEN
3472  IF ( missvalue_present ) THEN
3473  IF(any(output_fields(out_num)%buffer /= missvalue)) THEN
3474  WRITE (error_string,'(a,"/",a)')&
3475  & trim(input_fields(in_num)%module_name), &
3476  & trim(output_fields(out_num)%output_name)
3477  writing_field = -1
3478  RETURN
3479  END IF
3480  END IF
3481  END IF
3482  END DO
3483  END IF ! mask_variant
3484  ELSE IF ( time_min .OR. time_max ) THEN
3485  IF ( missvalue_present ) THEN
3486  WHERE ( abs(output_fields(out_num)%buffer) == min_value )
3487  output_fields(out_num)%buffer = missvalue
3488  END WHERE
3489  END IF ! if missvalue is NOT present buffer retains max_value or min_value
3490  END IF !average
3491 
3492  ! Output field
3493  IF ( at_diag_end .AND. freq == end_of_run ) output_fields(out_num)%next_output = time
3494  IF ( (output_fields(out_num)%time_ops) .AND. (.NOT. mix_snapshot_average_fields) ) THEN
3495  middle_time = (output_fields(out_num)%last_output+output_fields(out_num)%next_output)/2
3496  CALL diag_data_out(file_num, out_num, output_fields(out_num)%buffer, middle_time)
3497  ELSE
3498  CALL diag_data_out(file_num, out_num, &
3499  & output_fields(out_num)%buffer, output_fields(out_num)%next_output)
3500  END IF
3501 
3502  IF ( at_diag_end ) RETURN
3503 
3504  ! Take care of cleaning up the time counters and the storeage size
3505  output_fields(out_num)%last_output = output_fields(out_num)%next_output
3506  IF ( freq == end_of_run ) THEN
3507  output_fields(out_num)%next_output = time
3508  ELSE
3509  IF ( freq == every_time ) THEN
3510  output_fields(out_num)%next_output = time
3511  ELSE
3512  output_fields(out_num)%next_output = output_fields(out_num)%next_next_output
3513  output_fields(out_num)%next_next_output = &
3514  & diag_time_inc(output_fields(out_num)%next_next_output, freq, units)
3515  END IF
3516  output_fields(out_num)%count_0d(:) = 0.0
3517  output_fields(out_num)%num_elements(:) = 0
3518  IF ( time_max ) THEN
3519  output_fields(out_num)%buffer = max_value
3520  ELSE IF ( time_min ) THEN
3521  output_fields(out_num)%buffer = min_value
3522  ELSE
3523  output_fields(out_num)%buffer = empty
3524  END IF
3525  IF ( input_fields(in_num)%mask_variant .AND. average ) output_fields(out_num)%counter = 0.0
3526  END IF
3527 
3528  END FUNCTION writing_field
3529 
3530  SUBROUTINE diag_manager_set_time_end(Time_end_in)
3531  type(time_type), INTENT(in) :: time_end_in
3532 
3533  time_end = time_end_in
3534 
3535  END SUBROUTINE diag_manager_set_time_end
3536 
3537  !-----------------------------------------------------------------------
3538  !>@brief The subroutine 'diag_send_complete_instant' allows the user to
3539  !! save diagnostic data on variable intervals (user defined in code logic)
3540  !! to the same file. The argument (time_type) will be written to the
3541  !! time axis correspondingly.
3542  !>@details The user is responsible for any averaging of accumulated data
3543  !! as this routine is not designed for instantaneous values. This routine
3544  !! works only for send_data calls within OpenMP regions as they are buffered
3545  !! until the complete signal is given.
3546  SUBROUTINE diag_send_complete_instant(time)
3547  type(time_type), INTENT(in) :: time
3548  !--- local variables
3549  integer :: file, j, freq, in_num, file_num, out_num
3550 
3551  DO file = 1, num_files
3552  freq = files(file)%output_freq
3553  IF (freq == 0) then
3554  DO j = 1, files(file)%num_fields
3555  out_num = files(file)%fields(j)
3556  in_num = output_fields(out_num)%input_field
3557  IF ( (input_fields(in_num)%numthreads == 1) .AND.&
3558  & (input_fields(in_num)%active_omp_level.LE.1) ) cycle
3559  file_num = output_fields(out_num)%output_file
3560  CALL diag_data_out(file_num, out_num, &
3561  & output_fields(out_num)%buffer, time)
3562  END DO
3563  END IF
3564  END DO
3565  END SUBROUTINE diag_send_complete_instant
3566 
3567  !-----------------------------------------------------------------------
3568  SUBROUTINE diag_send_complete(time_step, err_msg)
3569  type(time_type), INTENT(in) :: time_step
3570  character(len=*), INTENT(out), optional :: err_msg
3571 
3572  type(time_type) :: next_time, time
3573  integer :: file, j, out_num, in_num, freq, status
3574  logical :: local_output, need_compute
3575  CHARACTER(len=128) :: error_string
3576 
3577  IF ( time_end == time_zero ) THEN
3578  ! <ERROR STATUS="FATAL">
3579  ! diag_manager_set_time_end must be called before diag_send_complete
3580  ! </ERROR>
3581  CALL error_mesg('diag_manager_mod::diag_send_complete',&
3582  & "diag_manager_set_time_end must be called before diag_send_complete", fatal)
3583  END IF
3584 
3585  DO file = 1, num_files
3586  freq = files(file)%output_freq
3587  DO j = 1, files(file)%num_fields
3588  out_num = files(file)%fields(j) !this is position of output_field in array output_fields
3589  in_num = output_fields(out_num)%input_field
3590 
3591  IF ( (input_fields(in_num)%numthreads == 1) .AND. (input_fields(in_num)%active_omp_level.LE.1) ) cycle
3592  IF ( output_fields(out_num)%static .OR. freq == end_of_run ) cycle
3593  time = input_fields(in_num)%time
3594  IF ( time >= time_end ) cycle
3595 
3596  ! is this field output on a local domain only?
3597  local_output = output_fields(out_num)%local_output
3598  ! if local_output, does the current PE take part in send_data?
3599  need_compute = output_fields(out_num)%need_compute
3600  ! skip all PEs not participating in outputting this field
3601  IF ( local_output .AND. (.NOT.need_compute) ) cycle
3602  next_time = time + time_step
3603 
3604  IF ( next_time > output_fields(out_num)%next_output ) THEN
3605  ! A non-static field that has skipped a time level is an error
3606  IF ( next_time > output_fields(out_num)%next_next_output .AND. freq > 0 ) THEN
3607  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
3608  WRITE (error_string,'(a,"/",a)')&
3609  & trim(input_fields(in_num)%module_name), &
3610  & trim(output_fields(out_num)%output_name)
3611  IF ( fms_error_handler('diag_send_complete',&
3612  & 'module/output_field '//trim(error_string)//&
3613  & ' is skipped one time level in output data', err_msg)) RETURN
3614  END IF
3615  END IF
3616 
3617  status = writing_field(out_num, .false., error_string, next_time)
3618  IF ( status == -1 ) THEN
3619  IF ( mpp_pe() .EQ. mpp_root_pe() ) THEN
3620  IF(fms_error_handler('diag_manager_mod::diag_send_complete','module/output_field '//trim(error_string)//&
3621  & ', write EMPTY buffer', err_msg)) RETURN
3622  END IF
3623  END IF
3624  END IF !time > output_fields(out_num)%next_output
3625  END DO
3626  END DO
3627 
3628  END SUBROUTINE diag_send_complete
3629 
3630  ! <SUBROUTINE NAME="diag_manager_end">
3631  ! <OVERVIEW>
3632  ! Exit Diagnostics Manager.
3633  ! </OVERVIEW>
3634  ! <DESCRIPTION>
3635  ! Flushes diagnostic buffers where necessary. Close diagnostics files.
3636  !
3637  ! A warning will be issued here if a field in diag_table is not registered
3638  ! </DESCRIPTION>
3639  ! <TEMPLATE>
3640  ! SUBROUTINE diag_manager_end(time)
3641  ! </TEMPLATE>
3642  ! <IN NAME="TIME" TYPE="time_type"></IN>
3643  SUBROUTINE diag_manager_end(time)
3644  TYPE(time_type), INTENT(in) :: time
3645 
3646  INTEGER :: file
3647 
3648  IF ( do_diag_field_log ) THEN
3649  CALL mpp_close (diag_log_unit)
3650  END IF
3651  DO file = 1, num_files
3652  CALL closing_file(file, time)
3653  END DO
3654  END SUBROUTINE diag_manager_end
3655  ! </SUBROUTINE>
3656 
3657  ! <SUBROUTINE NAME="closing_file">
3658  ! <OVERVIEW>
3659  ! Replaces diag_manager_end; close just one file: files(file)
3660  ! </OVERVIEW>
3661  ! <TEMPLATE>
3662  ! SUBROUTINE closing_file(file, time)
3663  ! </TEMPLATE>
3664  ! <DESCRIPTION>
3665  ! </DESCRIPTION>
3666  ! <IN NAME="file" TYPE="INTEGER"></IN>
3667  ! <IN NAME="tile" TYPE="TYPE(time_type)"></IN>
3668  SUBROUTINE closing_file(file, time)
3669  INTEGER, INTENT(in) :: file
3670  TYPE(time_type), INTENT(in) :: time
3671 
3672  INTEGER :: j, i, input_num, freq, status
3673  INTEGER :: stdout_unit
3674  LOGICAL :: reduced_k_range, need_compute, local_output
3675  CHARACTER(len=128) :: message
3676 
3677  stdout_unit = stdout()
3678 
3679  ! Output all registered, non_static output_fields
3680  DO j = 1, files(file)%num_fields
3681  i = files(file)%fields(j) !this is position of output_field in array output_fields
3682 
3683  ! is this field output on a local domain only?
3684  local_output = output_fields(i)%local_output
3685  ! if local_output, does the current PE take part in send_data?
3686  need_compute = output_fields(i)%need_compute
3687 
3688  reduced_k_range = output_fields(i)%reduced_k_range
3689 
3690  ! skip all PEs not participating in outputting this field
3691  IF ( local_output .AND. (.NOT. need_compute) ) cycle
3692  ! skip fields that were not registered or non-static
3693  input_num = output_fields(i)%input_field
3694  IF ( input_fields(input_num)%static ) cycle
3695  IF ( .NOT.input_fields(input_num)%register ) cycle
3696  freq = files(file)%output_freq
3697  IF ( freq /= end_of_run .AND. files(file)%file_unit < 0 &
3698  & .AND. all(output_fields(i)%num_elements(:) == 0)&
3699  & .AND. all(output_fields(i)%count_0d(:) == 0) ) cycle
3700  ! Is it time to output for this field; CAREFUL ABOUT >= vs > HERE
3701  ! For end should be >= because no more data is coming
3702  IF ( time >= output_fields(i)%next_output .OR. freq == end_of_run ) THEN
3703  IF ( time >= output_fields(i)%next_next_output .AND. freq > 0 ) THEN
3704  WRITE (message,'(a,"/",a)') trim(input_fields(input_num)%module_name), &
3705  & trim(output_fields(i)%output_name)
3706  ! <ERROR STATUS="WARNING">
3707  ! <input_fields(input_num)%module_name>/<output_fields(i)%output_name> skip one time
3708  ! level, maybe send_data never called
3709  ! </ERROR>
3710  IF ( mpp_pe() .EQ. mpp_root_pe() ) &
3711  & CALL error_mesg('diag_manager_mod::closing_file', 'module/output_field ' //&
3712  & trim(message)//', skip one time level, maybe send_data never called', warning)
3713  ELSE
3714  status = writing_field(i, .true., message, time)
3715  END IF
3716  ELSEIF ( .NOT.output_fields(i)%written_once ) THEN
3717  ! <ERROR STATUS="NOTE">
3718  ! <output_fields(i)%output_name) NOT available, check if output interval > runlength.
3719  ! NetCDF fill_values are written
3720  ! </ERROR>
3721  CALL error_mesg('Potential error in diag_manager_end ',&
3722  & trim(output_fields(i)%output_name)//' NOT available,'//&
3723  & ' check if output interval > runlength. Netcdf fill_values are written', note)
3724  output_fields(i)%buffer = fill_value
3725  CALL diag_data_out(file, i, output_fields(i)%buffer, time, .true.)
3726  END IF
3727  END DO
3728  ! Now it's time to output static fields
3729  CALL write_static(file)
3730 
3731  !::sdu:: Write the manifest file here
3732  IF ( write_manifest_file ) THEN
3733  CALL write_diag_manifest(file)
3734  END IF
3735 
3736  ! Write out the number of bytes of data saved to this file
3737  IF ( write_bytes_in_file ) THEN
3738  CALL mpp_sum (files(file)%bytes_written)
3739  IF ( mpp_pe() == mpp_root_pe() )&
3740  & WRITE (stdout_unit,'(a,i12,a,a)') 'Diag_Manager: ',files(file)%bytes_written, &
3741  & ' bytes of data written to file ',trim(files(file)%name)
3742  END IF
3743  END SUBROUTINE closing_file
3744  ! </SUBROUTINE>
3745 
3746  ! <SUBROUTINE NAME="diag_manager_init">
3747  ! <OVERVIEW>
3748  ! Initialize Diagnostics Manager.
3749  ! </OVERVIEW>
3750  ! <TEMPLATE>
3751  ! SUBROUTINE diag_manager_init(diag_model_subset, err_msg)
3752  ! </TEMPLATE>
3753  ! <DESCRIPTION>
3754  ! Open and read diag_table. Select fields and files for diagnostic output.
3755  ! </DESCRIPTION>
3756  ! <IN NAME="diag_model_subset" TYPE="INTEGER, OPTIONAL"></IN>
3757  ! <IN NAME="time_init" TYPE="INTEGER, DIMENSION(6), OPTIONAL">Model time diag_manager initialized</IN>
3758  ! <OUT NAME="err_msg" TYPE="CHARACTER(len=*), OPTIONAL"></OUT>
3759  SUBROUTINE diag_manager_init(diag_model_subset, time_init, err_msg)
3760  INTEGER, OPTIONAL, INTENT(IN) :: diag_model_subset
3761  INTEGER, DIMENSION(6), OPTIONAL, INTENT(IN) :: time_init
3762  CHARACTER(len=*), INTENT(out), OPTIONAL :: err_msg
3763 
3764  CHARACTER(len=*), PARAMETER :: sep = '|'
3765 
3766  INTEGER, PARAMETER :: fltkind = float_kind
3767  INTEGER, PARAMETER :: dblkind = double_kind
3768  INTEGER :: diag_subset_output
3769  INTEGER :: mystat
3770  INTEGER, ALLOCATABLE, DIMENSION(:) :: pelist
3771  INTEGER :: stdlog_unit, stdout_unit
3772  integer :: j
3773 #ifndef INTERNAL_FILE_NML
3774  INTEGER :: nml_unit
3775 #endif
3776  CHARACTER(len=256) :: err_msg_local
3777 
3778  namelist /diag_manager_nml/ append_pelist_name, mix_snapshot_average_fields, max_output_fields, &
3783 
3784  ! If the module was already initialized do nothing
3785  IF ( module_is_initialized ) RETURN
3786 
3787  ! Clear the err_msg variable if contains any residual information
3788  IF ( PRESENT(err_msg) ) err_msg = ''
3789 
3790  ! Initialize diag_util_mod and diag_data_mod
3791  ! These init routine only write out the version number to the log file
3792  call diag_util_init()
3793  call diag_data_init()
3794 
3795  ! Determine pack_size from how many bytes a real value has (how compiled)
3796  pack_size = SIZE(transfer(0.0_dblkind, (/0.0, 0.0, 0.0, 0.0/)))
3797  IF ( pack_size.NE.1 .AND. pack_size.NE.2 ) THEN
3798  IF ( fms_error_handler('diag_manager_mod::diag_manager_init', 'unknown pack_size. Must be 1, or 2.', err_msg) ) RETURN
3799  END IF
3800 
3801  ! Get min and max values for real(kind=FLOAT_KIND)
3802  min_value = huge(0.0_fltkind)
3803  max_value = -min_value
3804 
3805  ! get stdlog and stdout unit number
3806  stdlog_unit = stdlog()
3807  stdout_unit = stdout()
3808 
3809  ! version number to logfile
3810  CALL write_version_number("DIAG_MANAGER_MOD", version)
3811 
3812  time_zero = set_time(0,0)
3813  !--- initialize time_end to time_zero
3815  diag_subset_output = diag_all
3816  IF ( PRESENT(diag_model_subset) ) THEN
3817  IF ( diag_model_subset >= diag_other .AND. diag_model_subset <= diag_all ) THEN
3818  diag_subset_output = diag_model_subset
3819  ELSE
3820  IF ( fms_error_handler('diag_manager_mod::diag_manager_init', 'invalid value of diag_model_subset',err_msg) ) RETURN
3821  END IF
3822  END IF
3823 
3824 #ifdef INTERNAL_FILE_NML
3825  READ (input_nml_file, nml=diag_manager_nml, iostat=mystat)
3826 #else
3827  IF ( file_exist('input.nml') ) THEN
3828  nml_unit = open_namelist_file()
3829  READ (nml_unit, diag_manager_nml, iostat=mystat)
3830  CALL close_file(nml_unit)
3831  ELSE
3832  ! Set mystat to an arbitrary positive number if input.nml does not exist.
3833  mystat = 100
3834  END IF
3835 #endif
3836  ! Check the status of reading the diag_manager_nml
3837 
3838  IF ( check_nml_error(iostat=mystat, nml_name='DIAG_MANAGER_NML') < 0 ) THEN
3839  IF ( mpp_pe() == mpp_root_pe() ) THEN
3840  CALL error_mesg('diag_manager_mod::diag_manager_init', 'DIAG_MANAGER_NML not found in input.nml. Using defaults.',&
3841  & warning)
3842  END IF
3843  END IF
3844 
3845  IF ( mpp_pe() == mpp_root_pe() ) THEN
3846  WRITE (stdlog_unit, diag_manager_nml)
3847  END IF
3848 
3849  ! Issue note about using the CMOR missing value.
3850  IF ( use_cmor ) THEN
3851  err_msg_local = ''
3852  WRITE (err_msg_local,'(ES8.1E2)') cmor_missing_value
3853  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Using CMOR missing value ('//trim(err_msg_local)//').', note)
3854  END IF
3855 
3856  ! Issue note if attempting to set diag_manager_nml::max_files larger than
3857  ! mpp_get_maxunits() -- Default is 1024 set in mpp_io.F90
3858  IF ( max_files .GT. mpp_get_maxunits() ) THEN
3859  err_msg_local = ''
3860  WRITE (err_msg_local,'(A,I6,A,I6,A,I6,A)') "DIAG_MANAGER_NML variable 'max_files' (",max_files,") is larger than '",&
3861  & mpp_get_maxunits(),"'. Forcing 'max_files' to be ",mpp_get_maxunits(),"."
3862  CALL error_mesg('diag_manager_mod::diag_managet_init', trim(err_msg_local), note)
3863  max_files = mpp_get_maxunits()
3864  END IF
3865 
3866  ! How to handle Out of Range Warnings.
3867  IF ( oor_warnings_fatal ) THEN
3868  oor_warning = fatal
3869  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Out &
3870  &of Range warnings are fatal.', note)
3871  ELSEIF ( .NOT.issue_oor_warnings ) THEN
3872  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Out &
3873  &of Range warnings will be ignored.', note)
3874  END IF
3875 
3876  IF ( mix_snapshot_average_fields ) THEN
3877  IF ( mpp_pe() == mpp_root_pe() ) THEN
3878  CALL error_mesg('diag_manager_mod::diag_manager_init', 'Setting diag_manager_nml variable '//&
3879  & 'mix_snapshot_average_fields = .TRUE. will cause ERRORS in the time coordinates '//&
3880  & 'of all time averaged fields. Strongly recommend setting mix_snapshot_average_fields '//&
3881  & '= .FALSE.', warning)
3882  END IF
3883  END IF
3884  ALLOCATE(output_fields(max_output_fields))
3885  ALLOCATE(input_fields(max_input_fields))
3886  DO j = 1, max_input_fields
3887  ALLOCATE(input_fields(j)%output_fields(max_out_per_in_field))
3888  END DO
3889  ALLOCATE(files(max_files))
3890  ALLOCATE(pelist(mpp_npes()))
3891  CALL mpp_get_current_pelist(pelist, pelist_name)
3892 
3893  ! set the diag_init_time if time_init present. Otherwise, set it to base_time
3894  IF ( PRESENT(time_init) ) THEN
3895  diag_init_time = set_date(time_init(1), time_init(2), time_init(3), time_init(4),&
3896  & time_init(5), time_init(6))
3897  ELSE
3899  IF ( prepend_date .EQV. .true. ) THEN
3900  CALL error_mesg('diag_manager_mod::diag_manager_init',&
3901  & 'prepend_date only supported when diag_manager_init is called with time_init present.', note)
3902  prepend_date = .false.
3903  END IF
3904  END IF
3905 
3906  CALL parse_diag_table(diag_subset=diag_subset_output, istat=mystat, err_msg=err_msg_local)
3907  IF ( mystat /= 0 ) THEN
3908  IF ( fms_error_handler('diag_manager_mod::diag_manager_init',&
3909  & 'Error parsing diag_table. '//trim(err_msg_local), err_msg) ) RETURN
3910  END IF
3911 
3912  !initialize files%bytes_written to zero
3913  files(:)%bytes_written = 0
3914 
3915  ! open diag field log file
3916  IF ( do_diag_field_log.AND.mpp_pe().EQ.mpp_root_pe() ) THEN
3917  CALL mpp_open(diag_log_unit, 'diag_field_log.out', nohdrs=.true.)
3918  WRITE (diag_log_unit,'(777a)') &
3919  & 'Module', sep, 'Field', sep, 'Long Name', sep,&
3920  & 'Units', sep, 'Number of Axis', sep, 'Time Axis', sep,&
3921  & 'Missing Value', sep, 'Min Value', sep, 'Max Value', sep,&
3922  & 'AXES LIST'
3923  END IF
3924 
3925  module_is_initialized = .true.
3926  ! create axis_id for scalars here
3927  null_axis_id = diag_axis_init('scalar_axis', (/0./), 'none', 'N', 'none')
3928  RETURN
3929  END SUBROUTINE diag_manager_init
3930  ! </SUBROUTINE>
3931 
3932 
3933  ! <FUNCTION NAME="get_base_time">
3934  ! <OVERVIEW>
3935  ! Return base time for diagnostics.
3936  ! </OVERVIEW>
3937  ! <TEMPLATE>
3938  ! TYPE(time_type) FUNCTION get_base_time()
3939  ! </TEMPLATE>
3940  ! <DESCRIPTION>
3941  ! Return base time for diagnostics (note: base time must be >= model time).
3942  ! </DESCRIPTION>
3943  TYPE(time_type) function get_base_time ()
3944  ! <ERROR STATUS="FATAL">
3945  ! MODULE has not been initialized
3946  ! </ERROR>
3947  IF ( .NOT.module_is_initialized ) CALL error_mesg('diag_manager_mod::get_base_time', &
3948  & 'module has not been initialized', fatal)
3950  END FUNCTION get_base_time
3951  ! </FUNCTION>
3952 
3953  ! <SUBROUTINE NAME="get_base_date">
3954  ! <OVERVIEW>
3955  ! Return base date for diagnostics.
3956  ! </OVERVIEW>
3957  ! <TEMPLATE>
3958  ! SUBROUTINE get_base_date(year, month, day, hour, minute, second)
3959  ! </TEMPLATE>
3960  ! <DESCRIPTION>
3961  ! Return date information for diagnostic reference time.
3962  ! </DESCRIPTION>
3963  ! <OUT NAME="year" TYPE="INTEGER"></OUT>
3964  ! <OUT NAME="month" TYPE="INTEGER"></OUT>
3965  ! <OUT NAME="day" TYPE="INTEGER"></OUT>
3966  ! <OUT NAME="hour" TYPE="INTEGER"></OUT>
3967  ! <OUT NAME="minute" TYPE="INTEGER"></OUT>
3968  ! <OUT NAME="second" TYPE="INTEGER"></OUT>
3969  SUBROUTINE get_base_date(year, month, day, hour, minute, second)
3970  INTEGER, INTENT(out) :: year, month, day, hour, minute, second
3971 
3972  ! <ERROR STATUS="FATAL">module has not been initialized</ERROR>
3973  IF (.NOT.module_is_initialized) CALL error_mesg ('diag_manager_mod::get_base_date', &
3974  & 'module has not been initialized', fatal)
3975  year = base_year
3976  month = base_month
3977  day = base_day
3978  hour = base_hour
3979  minute = base_minute
3980  second = base_second
3981  END SUBROUTINE get_base_date
3982  ! </SUBROUTINE>
3983 
3984  ! <FUNCTION NAME="need_data">
3985  ! <OVERVIEW>
3986  ! Determine whether data is needed for the current model time step.
3987  ! </OVERVIEW>
3988  ! <TEMPLATE>
3989  ! LOGICAL need_data(diag_field_id, next_model_time)
3990  ! </TEMPLATE>
3991  ! <DESCRIPTION>
3992  ! Determine whether data is needed for the current model time step.
3993  ! Since diagnostic data are buffered, the "next" model time is passed
3994  ! instead of the current model time. This call can be used to minimize
3995  ! overhead for complicated diagnostics.
3996  ! </DESCRIPTION>
3997  ! <IN NAME="next_model_time" TYPE="TYPE(time_type)">
3998  ! next_model_time = current model time + model time_step
3999  ! </IN>
4000  ! <IN NAME="diag_field_id" TYPE="INTEGER"></IN>
4001  LOGICAL FUNCTION need_data(diag_field_id, next_model_time)
4002  TYPE(time_type), INTENT(in) :: next_model_time
4003  INTEGER, INTENT(in) :: diag_field_id
4004 
4005  INTEGER :: i, out_num
4006 
4007  need_data = .false.
4008  IF ( diag_field_id < 0 ) RETURN ! this field is unused
4009  DO i = 1, input_fields(diag_field_id)%num_output_fields
4010  ! Get index to an output field
4011  out_num = input_fields(diag_field_id)%output_fields(i)
4012  IF ( .NOT.output_fields(out_num)%static ) THEN
4013  IF ( next_model_time > output_fields(out_num)%next_output ) need_data=.true.
4014  ! Is this output field being time averaged?
4015  ! assume average data based on every timestep
4016  ! needs to be changed when different forms of averaging are implemented
4017  IF ( output_fields(out_num)%time_average) need_data = .true.
4018  END IF
4019  END DO
4020  RETURN
4021  END FUNCTION need_data
4022  ! </FUNCTION>
4023 
4024  ! <FUNCTION NAME="init_diurnal_axis">
4025  ! <OVERVIEW>
4026  ! Finds or initializes a diurnal time axis and returns its' ID.
4027  ! </OVERVIEW>
4028  ! <TEMPLATE>
4029  ! INTEGER FUNCTION init_diurnal_axis(n_samples)
4030  ! </TEMPLATE>
4031  ! <DESCRIPTION>
4032  ! Given number of time intervals in the day, finds or initializes a diurnal time axis
4033  ! and returns its ID. It uses get_base_date, so should be in the file where it's accessible.
4034  ! The units are 'days since BASE_DATE', all diurnal axes belong to the set 'diurnal'
4035  ! </DESCRIPTION>
4036  ! <IN NAME="n_samples" TYPE="INTEGER">Number of intervals during the day</IN>
4037  INTEGER FUNCTION init_diurnal_axis(n_samples)
4038  INTEGER, INTENT(in) :: n_samples ! number of intervals during the day
4039 
4040  REAL :: data (n_samples) ! central points of time intervals
4041  REAL :: edges (n_samples+1) ! boundaries of time intervals
4042  INTEGER :: edges_id ! id of the corresponding edges
4043  INTEGER :: i
4044  INTEGER :: year, month, day, hour, minute, second ! components of the base date
4045  CHARACTER(32) :: name ! name of the axis
4046  CHARACTER(128) :: units ! units of time
4047 
4048  CALL get_base_date(year, month, day, hour, minute, second)
4049  WRITE (units,11) 'hours', year, month, day, hour, minute, second
4050 11 FORMAT(a,' since ',i4.4,'-',i2.2,'-',i2.2,' ',i2.2,':',i2.2,':',i2.2)
4051  ! compute central points and units
4052  edges(1) = 0.0
4053  DO i = 1, n_samples
4054  DATA (i) = 24.0*(REAL(i)-0.5)/n_samples
4055  edges(i+1) = 24.0* REAL(i)/n_samples
4056  END DO
4057 
4058  ! define edges
4059  name = ''
4060  WRITE (name,'(a,i2.2)') 'time_of_day_edges_', n_samples
4061  edges_id = get_axis_num(name, 'diurnal')
4062  IF ( edges_id <= 0 ) THEN
4063  edges_id = diag_axis_init(name,edges,units,'N','time of day edges', set_name='diurnal')
4064  END IF
4065 
4066  ! define axis itself
4067  name = ''
4068  WRITE (name,'(a,i2.2)') 'time_of_day_', n_samples
4069  init_diurnal_axis = get_axis_num(name, 'diurnal')
4070  IF ( init_diurnal_axis <= 0 ) THEN
4071  init_diurnal_axis = diag_axis_init(name, DATA, units, 'N', 'time of day', set_name='diurnal', edges=edges_id)
4072  END IF
4073  END FUNCTION init_diurnal_axis
4074  ! </FUNCTION>
4075 
4076  SUBROUTINE diag_field_attribute_init(diag_field_id, name, type, cval, ival, rval)
4077  INTEGER, INTENT(in) :: diag_field_id !< input field ID, obtained from diag_manager_mod::register_diag_field.
4078  CHARACTER(len=*), INTENT(in) :: name !< Name of the attribute
4079  INTEGER, INTENT(in) :: type !< NetCDF type (NF90_FLOAT, NF90_INT, NF90_CHAR)
4080  CHARACTER(len=*), INTENT(in), OPTIONAL :: cval !< Character string attribute value
4081  INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: ival !< Integer attribute value(s)
4082  REAL, DIMENSION(:), INTENT(in), OPTIONAL :: rval !< Real attribute value(s)
4083 
4084  INTEGER :: istat, length, i, j, this_attribute, out_field
4085  CHARACTER(len=1024) :: err_msg
4086 
4087  IF ( .NOT.first_send_data_call ) THEN
4088  ! Call error due to unable to add attribute after send_data called
4089  ! <ERROR STATUS="FATAL">
4090  ! Attempting to add attribute <name> to module/input_field <module_name>/<field_name>
4091  ! after first send_data call. Too late.
4092  ! </ERROR>
4093  CALL error_mesg('diag_manager_mod::diag_field_add_attribute', 'Attempting to add attribute "'&
4094  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4095  &//trim(input_fields(diag_field_id)%field_name)//'" after first send_data call. Too late.', fatal)
4096  END IF
4097 
4098  ! Simply return if diag_field_id <= 0 --- not in diag_table
4099  IF ( diag_field_id .LE. 0 ) THEN
4100  RETURN
4101  ELSE
4102  DO j=1,input_fields(diag_field_id)%num_output_fields
4103  out_field = input_fields(diag_field_id)%output_fields(j)
4104 
4105  ! Allocate memory for the attributes
4106  CALL attribute_init(output_fields(out_field))
4107 
4108  ! Check if attribute already exists
4109  this_attribute = 0
4110  DO i=1, output_fields(out_field)%num_attributes
4111  IF ( trim(output_fields(out_field)%attributes(i)%name) .EQ. trim(name) ) THEN
4112  this_attribute = i
4113  EXIT
4114  END IF
4115  END DO
4116 
4117  IF ( this_attribute.NE.0 .AND. (type.EQ.nf90_int .OR. type.EQ.nf90_float) ) THEN
4118  ! <ERROR STATUS="FATAL">
4119  ! Attribute <name> already defined for module/input_field <module_name>/<field_name>.
4120  ! Contact the developers
4121  ! </ERROR>
4122  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4123  & 'Attribute "'//trim(name)//'" already defined for module/input_field "'&
4124  &//trim(input_fields(diag_field_id)%module_name)//'/'&
4125  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4126  ELSE IF ( this_attribute.NE.0 .AND. type.EQ.nf90_char .AND. debug_diag_manager ) THEN
4127  ! <ERROR STATUS="NOTE">
4128  ! Attribute <name> already defined for module/input_field <module_name>/<field_name>.
4129  ! Prepending.
4130  ! </ERROR>
4131  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4132  & 'Attribute "'//trim(name)//'" already defined for module/input_field "'&
4133  &//trim(input_fields(diag_field_id)%module_name)//'/'&
4134  &//trim(input_fields(diag_field_id)%field_name)//'". Prepending.', note)
4135  ELSE IF ( this_attribute.EQ.0 ) THEN
4136  ! Defining a new attribute
4137  ! Increase the number of field attributes
4138  this_attribute = output_fields(out_field)%num_attributes + 1
4139  ! Checking to see if num_attributes == max_field_attributes, and return error message
4140  IF ( this_attribute .GT. max_field_attributes ) THEN
4141  ! <ERROR STATUS="FATAL">
4142  ! Number of attributes exceeds max_field_attributes for attribute <name> to module/input_field <module_name>/<field_name>.
4143  ! Increase diag_manager_nml:max_field_attributes.
4144  ! </ERROR>
4145  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4146  & 'Number of attributes exceeds max_field_attributes for attribute "'&
4147  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4148  &//trim(input_fields(diag_field_id)%field_name)//'". Increase diag_manager_nml:max_field_attributes.',&
4149  & fatal)
4150  ELSE
4151  output_fields(out_field)%num_attributes = this_attribute
4152  ! Set name and type
4153  output_fields(out_field)%attributes(this_attribute)%name = name
4154  output_fields(out_field)%attributes(this_attribute)%type = type
4155  ! Initialize catt to a blank string, as len_trim doesn't always work on an uninitialized string
4156  output_fields(out_field)%attributes(this_attribute)%catt = ''
4157  END IF
4158  END IF
4159 
4160  SELECT CASE (type)
4161  CASE (nf90_int)
4162  IF ( .NOT.PRESENT(ival) ) THEN
4163  ! <ERROR STATUS="FATAL">
4164  ! Number type claims INTEGER, but ival not present for attribute <name> to module/input_field <module_name>/<field_name>.
4165  ! Contact the developers.
4166  ! </ERROR>
4167  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4168  & 'Attribute type claims INTEGER, but ival not present for attribute "'&
4169  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4170  &//trim(input_fields(diag_field_id)%field_name)//'". Contact then developers.', fatal)
4171  END IF
4172  length = SIZE(ival)
4173  ! Allocate iatt(:) to size of ival
4174  ALLOCATE(output_fields(out_field)%attributes(this_attribute)%iatt(length), stat=istat)
4175  IF ( istat.NE.0 ) THEN
4176  ! <ERROR STATUS="FATAL">
4177  ! Unable to allocate iatt for attribute <name> to module/input_field <module_name>/<field_name>
4178  ! </ERROR>
4179  CALL error_mesg('diag_manager_mod::diag_field_add_attribute', 'Unable to allocate iatt for attribute "'&
4180  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4181  &//trim(input_fields(diag_field_id)%field_name)//'"', fatal)
4182  END IF
4183  ! Set remaining fields
4184  output_fields(out_field)%attributes(this_attribute)%len = length
4185  output_fields(out_field)%attributes(this_attribute)%iatt = ival
4186  CASE (nf90_float)
4187  IF ( .NOT.PRESENT(rval) ) THEN
4188  ! <ERROR STATUS="FATAL">
4189  ! Attribute type claims READ, but rval not present for attribute <name> to module/input_field <module_name>/<field_name>.
4190  ! Contact the developers.
4191  ! </ERROR>
4192  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4193  & 'Attribute type claims REAL, but rval not present for attribute "'&
4194  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4195  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4196  END IF
4197  length = SIZE(rval)
4198  ! Allocate iatt(:) to size of rval
4199  ALLOCATE(output_fields(out_field)%attributes(this_attribute)%fatt(length), stat=istat)
4200  IF ( istat.NE.0 ) THEN
4201  ! <ERROR STATUS="FATAL">
4202  ! Unable to allocate fatt for attribute <name> to module/input_field <module_name>/<field_name>
4203  ! </ERROR>
4204  CALL error_mesg('diag_manager_mod::diag_field_add_attribute', 'Unable to allocate fatt for attribute "'&
4205  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4206  &//trim(input_fields(diag_field_id)%field_name)//'"', fatal)
4207  END IF
4208  ! Set remaining fields
4209  output_fields(out_field)%attributes(this_attribute)%len = length
4210  output_fields(out_field)%attributes(this_attribute)%fatt = rval
4211  CASE (nf90_char)
4212  IF ( .NOT.PRESENT(cval) ) THEN
4213  ! <ERROR STATUS="FATAL">
4214  ! Attribute type claims CHARACTER, but cval not present for attribute <name> to module/input_field <module_name>/<field_name>.
4215  ! Contact the developers.
4216  ! </ERROR>
4217  CALL error_mesg('diag_manager_mod::diag_field_add_attribute',&
4218  & 'Attribute type claims CHARACTER, but cval not present for attribute "'&
4219  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4220  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4221  END IF
4222  CALL prepend_attribute(output_fields(out_field), trim(name), trim(cval))
4223  CASE default
4224  ! <ERROR STATUS="FATAL">
4225  ! Unknown attribute type for attribute <name> to module/input_field <module_name>/<field_name>.
4226  ! Contact the developers.
4227  ! </ERROR>
4228  CALL error_mesg('diag_manager_mod::diag_field_add_attribute', 'Unknown attribute type for attribute "'&
4229  &//trim(name)//'" to module/input_field "'//trim(input_fields(diag_field_id)%module_name)//'/'&
4230  &//trim(input_fields(diag_field_id)%field_name)//'". Contact the developers.', fatal)
4231  END SELECT
4232  END DO
4233  END IF
4234  END SUBROUTINE diag_field_attribute_init
4235 
4236  ! <SUBROUTINE NAME="diag_field_add_attribute_scalar_r" INTERFACE="diag_field_add_attribute">
4237  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
4238  ! <IN NAME="att_name" TYPE="CHARACTER(len=*)" />
4239  ! <IN NAME="att_value" TYPE="REAL" />
4240  SUBROUTINE diag_field_add_attribute_scalar_r(diag_field_id, att_name, att_value)
4241  INTEGER, INTENT(in) :: diag_field_id
4242  CHARACTER(len=*), INTENT(in) :: att_name
4243  REAL, INTENT(in) :: att_value
4244 
4245  CALL diag_field_add_attribute_r1d(diag_field_id, att_name, (/ att_value /))
4246  END SUBROUTINE diag_field_add_attribute_scalar_r
4247  ! </SUBROUTINE>
4248 
4249  ! <SUBROUTINE NAME="diag_field_add_attribute_scalar_i" INTERFACE="diag_field_add_attribute">
4250  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
4251  ! <IN NAME="att_name" TYPE="CHARACTER(len=*)" />
4252  ! <IN NAME="att_value" TYPE="INTEGER" />
4253  SUBROUTINE diag_field_add_attribute_scalar_i(diag_field_id, att_name, att_value)
4254  INTEGER, INTENT(in) :: diag_field_id
4255  CHARACTER(len=*), INTENT(in) :: att_name
4256  INTEGER, INTENT(in) :: att_value
4257 
4258  CALL diag_field_add_attribute_i1d(diag_field_id, att_name, (/ att_value /))
4259  END SUBROUTINE diag_field_add_attribute_scalar_i
4260  ! </SUBROUTINE>
4261 
4262  ! <SUBROUTINE NAME="diag_field_add_attribute_scalar_c" INTERFACE="diag_field_add_attribute">
4263  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
4264  ! <IN NAME="att_name" TYPE="CHARACTER(len=*)" />
4265  ! <IN NAME="att_value" TYPE="CHARACTER(len=*)" />
4266  SUBROUTINE diag_field_add_attribute_scalar_c(diag_field_id, att_name, att_value)
4267  INTEGER, INTENT(in) :: diag_field_id
4268  CHARACTER(len=*), INTENT(in) :: att_name
4269  CHARACTER(len=*), INTENT(in) :: att_value
4270 
4271  CALL diag_field_attribute_init(diag_field_id, att_name, nf90_char, cval=att_value)
4272  END SUBROUTINE diag_field_add_attribute_scalar_c
4273  ! </SUBROUTINE>
4274 
4275  ! <SUBROUTINE NAME="diag_field_add_attribute_r1d" INTERFACE="diag_field_add_attribute">
4276  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
4277  ! <IN NAME="att_name" TYPE="CHARACTER(len=*)" />
4278  ! <IN NAME="att_value" TYPE="REAL, DIMENSION(:)" />
4279  SUBROUTINE diag_field_add_attribute_r1d(diag_field_id, att_name, att_value)
4280  INTEGER, INTENT(in) :: diag_field_id
4281  CHARACTER(len=*), INTENT(in) :: att_name
4282  REAL, DIMENSION(:), INTENT(in) :: att_value
4283 
4284  INTEGER :: num_attributes, len
4285  CHARACTER(len=512) :: err_msg
4286 
4287  CALL diag_field_attribute_init(diag_field_id, att_name, nf90_float, rval=att_value)
4288  END SUBROUTINE diag_field_add_attribute_r1d
4289  ! </SUBROUTINE>
4290 
4291  ! <SUBROUTINE NAME="diag_field_add_attribute_i1d" INTERFACE="diag_field_add_attribute">
4292  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
4293  ! <IN NAME="att_name" TYPE="CHARACTER(len=*)" />
4294  ! <IN NAME="att_value" TYPE="INTEGER, DIMENSION(:)" />
4295  SUBROUTINE diag_field_add_attribute_i1d(diag_field_id, att_name, att_value)
4296  INTEGER, INTENT(in) :: diag_field_id
4297  CHARACTER(len=*), INTENT(in) :: att_name
4298  INTEGER, DIMENSION(:), INTENT(in) :: att_value
4299 
4300  CALL diag_field_attribute_init(diag_field_id, att_name, nf90_int, ival=att_value)
4301  END SUBROUTINE diag_field_add_attribute_i1d
4302  ! </SUBROUTINE>
4303 
4304  ! <SUBROUTINE NAME="diag_field_add_cell_measures">
4305  ! <OVERVIEW>
4306  ! Add the cell_measures attribute to a diag out field
4307  ! </OVERVIEW>
4308  ! <TEMPLATE>
4309  ! SUBROUTINE diag_field_add_cell_measures(diag_field_id, area, volume)
4310  ! </TEMPLATE>
4311  ! <DESCRIPTION>
4312  ! Add the cell_measures attribute to a give diag field. This is useful if the
4313  ! area/volume fields for the diagnostic field are defined in another module after
4314  ! the diag_field.
4315  ! </DESCRIPTION>
4316  ! <IN NAME="diag_field_id" TYPE="INTEGER" />
4317  ! <IN NAME="area" TYPE="INTEGER, OPTIONAL" />
4318  ! <IN NAME="volume" TYPE="INTEGER, OPTIONAL" />
4319  SUBROUTINE diag_field_add_cell_measures(diag_field_id, area, volume)
4320  INTEGER, INTENT(in) :: diag_field_id
4321  INTEGER, INTENT(in), OPTIONAL :: area, volume ! diag ids of area or volume
4322 
4323  integer :: j, ind
4324 
4325  IF ( diag_field_id.GT.0 ) THEN
4326  IF ( .NOT.PRESENT(area) .AND. .NOT.present(volume) ) THEN
4327  CALL error_mesg('diag_manager_mod::diag_field_add_cell_measures', &
4328  & 'either area or volume arguments must be present', fatal )
4329  END IF
4330 
4331  DO j=1, input_fields(diag_field_id)%num_output_fields
4332  ind = input_fields(diag_field_id)%output_fields(j)
4333  CALL init_field_cell_measures(output_fields(ind), area=area, volume=volume)
4334  END DO
4335  END IF
4336  END SUBROUTINE diag_field_add_cell_measures
4337  ! </SUBROUTINE>
4338 END MODULE diag_manager_mod
4339 
4340 ! <INFO>
4341 ! <COMPILER NAME="PORTABILITY">
4342 ! <TT>diag_manager_mod</TT> uses standard Fortran 90.
4343 ! </COMPILER>
4344 ! <COMPILER NAME="ACQUIRING SOURCE">
4345 ! Use the following commands to check out the source at GFDL.
4346 ! <PRE>
4347 ! setenv CVSROOT '/home/fms/cvs'
4348 ! cvs co diag_manager
4349 ! </PRE>
4350 ! </COMPILER>
4351 ! <COMPILER NAME="COMPILING AND LINKING SOURCE">
4352 ! Any module or program unit using <TT>diag_manager_mod</TT> must contain the line
4353 ! <PRE>
4354 ! use diag_manager_mod
4355 ! </PRE>
4356 ! If netCDF output is desired, the cpp flag <TT>-Duse_netCDF</TT>
4357 ! must be turned on.
4358 ! </COMPILER>
4359 ! <PRECOMP FLAG="-Duse_netCDF">
4360 ! Used to write out <LINK SRC="http://www.unidata.ucar.edu/software/netcdf">NetCDF</LINK> files.
4361 ! </PRECOMP>
4362 ! <PRECOMP FLAG="-Dtest_diag_manager">
4363 ! Used to build the unit test suite for the <TT>diag_manager_mod</TT>.
4364 ! </PRECOMP>
4365 ! <LOADER FLAG="-lnetcdf">
4366 ! Link in the NetCDF libraries.
4367 ! </LOADER>
4368 ! <TESTPROGRAM NAME="test">
4369 ! Unit test for the <TT>diag_manager_mod</TT>. Each test must be run separately, and ends with an intentional fatal error.
4370 ! Each test has its own <TT>diag_table</TT>, see the source of <TT>diag_manager.F90</TT> for the list of <TT>diag_tables</TT>
4371 ! for the unit tests.
4372 ! </TESTPROGRAM>
4373 ! <FUTURE>
4374 ! Regional output for the cubed-sphere grid.
4375 ! </FUTURE>
4376 ! </INFO>
4377 
4378 ! ********** Test Program **********
4379 #ifdef test_diag_manager
4380 ! This program runs only one of many possible tests with each execution.
4381 ! Each test ends with an intentional fatal error.
4382 ! diag_manager_mod is not a stateless module, and there are situations
4383 ! where a fatal error leaves the module in a state that does not allow
4384 ! it to function properly if used again. Therefore, the program must
4385 ! be terminated after each intentional fatal error.
4386 
4387 ! Each test is dependent on the diag_table, and different diag_tables
4388 ! exist for each test. Depending on the test, an intentional fatal error
4389 ! may be triggered upon the call to diag_manager_init, register_diag_field or send_data.
4390 ! Because of this, the calls to all of those routines differ depending on the test.
4391 
4392 ! The diag_table for each test is included below.
4393 
4394 !--------------------------------------------------------------------------------------------------
4395 ! diag_table for test 1
4396 
4397 ! test_diag_manager
4398 ! 1 3 1 0 0 0
4399 ! #output files
4400 ! "diag_test", 1, "days", 1, "days", "time",
4401 ! #output variables
4402 ! "test_diag_manager_mod", "dat1", "dat1", "diag_test", "all", .false., "none", 2,
4403 !--------------------------------------------------------------------------------------------------
4404 ! diag_table for test 2
4405 
4406 ! test_diag_manager
4407 ! 1 3 1 0 0 0
4408 ! #output files
4409 ! "diag_test", 1, "days", 1, "days", "time",
4410 ! #output variables
4411 ! "test_diag_manager_mod", "dat1", "dat1", "diag_test", "all", .false., "none", 2,
4412 !--------------------------------------------------------------------------------------------------
4413 ! diag_table for test 3
4414 
4415 ! test_diag_manager
4416 ! 1 3 1 0 0 0
4417 ! #output files
4418 ! "diag_test", 1, "days", 1, "days", "time",
4419 ! #output variables
4420 ! "test_diag_manager_mod", "dat1", "dat1", "diag_test", "all", .false., "none", 2,
4421 !--------------------------------------------------------------------------------------------------
4422 ! diag_table for test 4
4423 
4424 ! test_diag_manager
4425 ! 1 3 1 0 0 0
4426 ! #output files
4427 ! "diag_test", 1, "days", 1, "days", "time",
4428 ! "diag_test2", 1, "days", 1, "days", "time",
4429 ! #output variables
4430 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4431 ! "test_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4432 !--------------------------------------------------------------------------------------------------
4433 ! diag_table for test 5
4434 
4435 ! test_diag_manager
4436 ! 1 3 1 0 0 0
4437 ! #output files
4438 ! "diag_test", 1, "days", 1, "days", "time",
4439 ! "diag_test2", 1, "days", 1, "days", "time",
4440 ! #output variables
4441 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4442 ! "test_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4443 !--------------------------------------------------------------------------------------------------
4444 ! diag_table for test 6
4445 
4446 ! test_diag_manager
4447 ! 1 3 1 0 0 0
4448 ! #output files
4449 ! "diag_test", 1, "days", 1, "days", "time",
4450 ! "diag_test2", 1, "days", 1, "days", "time",
4451 ! #output variables
4452 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4453 ! "test_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4454 !--------------------------------------------------------------------------------------------------
4455 ! diag_table for test 7
4456 
4457 ! test_diag_manager
4458 ! 1 3 1 0 0 0
4459 ! #output files
4460 ! "diag_test", 1, "days", 1, "days", "time",
4461 ! #output variables
4462 ! "test_diag_manager_mod", "dat1", "dat1", "diag_test", "all", .false., "none", 2,
4463 !--------------------------------------------------------------------------------------------------
4464 ! diag_table for test 8
4465 
4466 ! test_diag_manager
4467 ! 1 3 1 0 0 0
4468 ! #output files
4469 ! "diag_test", 1, "days", 1, "days", "time",
4470 ! "diag_test2", 1, "days", 1, "days", "time",
4471 ! #output variables
4472 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4473 ! "test_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4474 !--------------------------------------------------------------------------------------------------
4475 ! diag_table for test 9
4476 
4477 ! test_diag_manager
4478 ! 1 3 1 0 0 0
4479 ! #output files
4480 ! "diag_test", 1, "days", 1, "days", "time",
4481 ! #output variables
4482 ! "test_diag_manager_mod", "bk", "bk", "diag_test", "all", .false., "none", 2,
4483 !--------------------------------------------------------------------------------------------------
4484 ! diag_table for test 10
4485 
4486 ! test_diag_manager
4487 ! 1 3 1 0 0 0
4488 ! #output files
4489 ! "diag_test", 1, "days", 1, "days", "time",
4490 ! #output variables
4491 ! "test_diag_manager_mod", "bk", "bk", "diag_test", "all", .false., "none", 2,
4492 !--------------------------------------------------------------------------------------------------
4493 ! diag_table for test 11
4494 
4495 ! test_diag_manager
4496 ! 1 3 1 0 0 0
4497 ! #output files
4498 ! "diag_test", 1, "days", 1, "days", "time",
4499 ! #output variables
4500 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4501 !--------------------------------------------------------------------------------------------------
4502 ! diag_table for test 12
4503 
4504 ! test_diag_manager
4505 ! 1 3 1 0 0 0
4506 ! #output files
4507 ! "diag_test", 1, "days", 1, "days", "time",
4508 ! #output variables
4509 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4510 ! # Test of the error check that duplicate field names do not appear in same file,
4511 ! "test_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4512 !--------------------------------------------------------------------------------------------------
4513 ! diag_table for test 13
4514 
4515 ! test_diag_manager
4516 ! 1 3 1 0 0 0
4517 ! #output files
4518 ! "diag_test", 1, "days", 1, "days", "time",
4519 ! "diag_test2", 1, "months", 1, "days", "time",
4520 ! #output variables
4521 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test", "all", .false., "none", 2,
4522 ! # Test of WARNING message that no data is written when run length is less than output interval
4523 ! "test_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4524 !--------------------------------------------------------------------------------------------------
4525 ! diag_table for test 14
4526 
4527 ! test_diag_manager
4528 ! 1990 1 29 0 0 0
4529 ! #output files
4530 ! "diag_test2", 1, "months", 1, "days", "time",
4531 ! #output variables
4532 ! # Test of check for invalid date. (Jan 29 1990 + one month = Feb 29 1990)
4533 ! "test_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4534 !--------------------------------------------------------------------------------------------------
4535 ! diag_table for test 16
4536 
4537 ! test_diag_manager
4538 ! 1 3 1 0 0 0
4539 ! #output files
4540 ! "diag_test2", 1, "months", 1, "days", "time",
4541 ! #output variables
4542 ! # Test for output file name to be modified with appended string
4543 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test2", "all", .false., "none", 2,
4544 !--------------------------------------------------------------------------------------------------
4545 ! diag_table for test 17
4546 
4547 ! test_diag_manager
4548 ! 1 3 1 0 0 0
4549 ! #output files
4550 ! "diag_test2", 1, "days", 1, "days", "time",
4551 ! #output variables
4552 ! "test_diag_manager_mod", "dat2", "dat2_rms", "diag_test2", "all", "rms", "none", 2,
4553 ! "test_diag_manager_mod", "dat2", "dat2", "diag_test2", "all", .true., "none", 2,
4554 !--------------------------------------------------------------------------------------------------
4555 !--------------------------------------------------------------------------------------------------
4556 !> diag_table for test 100 (unstructured grid)
4557 !!
4558 !!test_unstructured_grid_diag_manager
4559 !!1990 1 1 0 0 0
4560 !!#output files
4561 !!"unstructured_diag_test", 1, "days", 1, "days", "time",
4562 !!#output variables
4563 !!"UG_unit_test", "unstructured_real_scalar_field_data", "rsf_diag_1", "unstructured_diag_test", "all", .TRUE., "none", 1,
4564 !!"UG_unit_test", "unstructured_real_1D_field_data", "unstructured_real_1D_field_data", "unstructured_diag_test", "all", .TRUE., "none", 1,
4565 !!"UG_unit_test", "unstructured_real_2D_field_data", "unstructured_real_2D_field_data", "unstructured_diag_test", "all", .TRUE., "none", 1,
4566 !--------------------------------------------------------------------------------------------------
4567 PROGRAM test
4568  ! This program runs only one of many possible tests with each execution.
4569  ! Each test ends with an intentional fatal error.
4570  ! diag_manager_mod is not a stateless module, and there are situations
4571  ! where a fatal error leaves the module in a state that does not allow
4572  ! it to function properly if used again. Therefore, the program must
4573  ! be terminated after each intentional fatal error.
4574 
4575  ! Each test is dependent on the diag_table, and different diag_tables
4576  ! exist for each test. Depending on the test, an intentional fatal error
4577  ! may be triggered upon the call to diag_manager_init, register_diag_field or send_data.
4578  ! Because of this, the calls to all of those routines differ depending on the test.
4579 
4580  USE mpp_mod, ONLY: mpp_pe, mpp_root_pe, mpp_debug, mpp_set_stack_size
4581  USE mpp_io_mod, ONLY: mpp_io_init
4583  USE mpp_domains_mod, ONLY: mpp_define_io_domain, mpp_define_layout
4584  USE mpp_domains_mod, ONLY: mpp_domains_init, mpp_domains_set_stack_size
4585  USE fms_mod, ONLY: fms_init, fms_end, mpp_npes, file_exist, check_nml_error, open_file
4586  USE fms_mod, ONLY: error_mesg, fatal, warning, stdlog, stdout
4587 #ifdef INTERNAL_FILE_NML
4588  USE mpp_mod, ONLY: input_nml_file
4589 #else
4590  USE fms_mod, ONLY: open_namelist_file, close_file
4591 #endif
4592  USE fms_io_mod, ONLY: fms_io_init
4595 
4597  USE time_manager_mod, ONLY: noleap, julian, gregorian, thirty_day_months, OPERATOR(*), assignment(=)
4598  use time_manager_mod, ONLY: OPERATOR(+), OPERATOR(-), OPERATOR(/), days_in_month
4599 
4600  USE diag_manager_mod, ONLY: diag_manager_init, send_data, diag_axis_init, diag_manager_end
4602  USE diag_manager_mod, ONLY: diag_manager_set_time_end, diag_field_add_attribute, diag_axis_add_attribute
4604  USE diag_manager_mod, ONLY: get_diag_field_id, diag_field_not_found
4605  USE diag_axis_mod, ONLY: get_axis_num
4606 
4607  IMPLICIT NONE
4608 
4609  TYPE(domain2d) :: domain1
4610  TYPE(domain2d) :: domain2
4611 
4612  REAL, ALLOCATABLE, DIMENSION(:) :: lon_global1, lonb_global1
4613  REAL, ALLOCATABLE, DIMENSION(:) :: lat_global1, latb_global1
4614  REAL, ALLOCATABLE, DIMENSION(:) :: lon_global2, lonb_global2
4615  REAL, ALLOCATABLE, DIMENSION(:) :: lat_global2, latb_global2
4616  REAL, ALLOCATABLE, DIMENSION(:) :: pfull, bk, phalf
4617  REAL, ALLOCATABLE, DIMENSION(:) :: lon1, lat1, lonb1, latb1
4618  REAL, ALLOCATABLE, DIMENSION(:) :: lon2, lat2, lonb2, latb2
4619  REAL, ALLOCATABLE, DIMENSION(:,:,:) :: dat1, dat1h
4620  REAL, ALLOCATABLE, DIMENSION(:,:,:) :: dat2, dat2h
4621  REAL, ALLOCATABLE, DIMENSION(:,:) :: dat2_2d
4622  REAL :: solar_constant = 1600
4623  REAL :: surf_press = 1.e5
4624  REAL :: dp
4625  INTEGER :: id_phalf, id_pfull, id_bk
4626  INTEGER :: id_lon1, id_lonb1, id_latb1, id_lat1, id_dat1
4627  INTEGER :: id_lon2, id_lat2, id_dat2, id_dat2_2d, id_sol_con, id_dat2h, id_dat2h_2
4628  INTEGER :: id_dat2_got, id_none_got
4629  INTEGER :: i, j, k, is1, ie1, js1, je1, nml_unit, ierr, log_unit, out_unit, m
4630  INTEGER :: is_in, ie_in, js_in, je_in
4631  INTEGER :: is2, ie2, js2, je2, hi=1, hj=1
4632  INTEGER :: nlon1, nlat1, nlon2, nlat2
4633  INTEGER, DIMENSION(2) :: layout = (/0,0/)
4634  INTEGER :: test_number=1
4635  INTEGER :: nlon=18, nlat=18, nlev=2
4636  INTEGER :: io_layout(2) = (/0,0/)
4637  INTEGER :: nstep = 2
4638  TYPE(time_type) :: time, time_step, time_end, time_start, run_length
4639  LOGICAL :: used, test_successful
4640  CHARACTER(len=256) :: err_msg
4641  INTEGER :: omp_get_num_threads
4642 
4643  INTEGER :: nyc1, n, jsw, jew, isw, iew
4644  INTEGER :: numthreads=1, ny_per_thread, idthread
4645  INTEGER :: months=0, days=0, dt_step=0
4646 
4647  ! Variables needed for test 22
4648  INTEGER :: id_nv, id_nv_init
4649 
4650 !!!!!! Stuff for unstrctured grid
4651  integer(INT_KIND) :: nx = 8 !<Total number of grid points in the x-dimension (longitude?)
4652  integer(INT_KIND) :: ny = 8 !<Total number of grid points in the y-dimension (latitude?)
4653  integer(INT_KIND) :: nz = 2 !<Total number of grid points in the z-dimension (height)
4654  integer(INT_KIND) :: nt = 2 !<Total number of time grid points.
4655  integer(INT_KIND) :: io_tile_factor = 1 !< The IO tile factor
4656  integer(INT_KIND) :: halo = 2 !<Number of grid points in the halo???
4657  integer(INT_KIND) :: ntiles_x = 1 !<Number of tiles in the x-direction (A 2D grid of tiles is used in this test.)
4658  integer(INT_KIND) :: ntiles_y = 2 !<Number of tiles in the y-direction (A 2D grid of tiles is used in this test.)
4659  integer(INT_KIND) :: total_num_tiles !<The total number of tiles for the run (= ntiles_x*ntiles_y)
4660  integer(INT_KIND) :: stackmax = 1500000 !<Default size to which the mpp stack will be set.
4661  integer(INT_KIND) :: stackmaxd = 500000 !<Default size to which the mpp_domains stack will be set.
4662  logical(INT_KIND) :: debug = .false. !<Flag to print debugging information.
4663  character(len=64) :: test_file = "test_unstructured_grid" !<Base filename for the unit tests.
4664  character(len=64) :: iospec = '-F cachea' !<Something cray related ???
4665  integer(INT_KIND) :: pack_size = 1 !<(Number of bits in real(DOUBLE_KIND))/(Number of bits in real)
4666  integer(INT_KIND) :: npes !<Total number of ranks in the current pelist.
4667  integer(INT_KIND) :: io_status !<Namelist read error code.
4668  real(DOUBLE_KIND) :: doubledata = 0.0 !<Used to determine pack_size. This must be kind=DOUBLE_KIND.
4669  real :: realdata = 0.0 !<Used to determine pack_size. Do not specify a kind parameter.
4670  integer(INT_KIND) :: funit = 7 !<File unit.
4671  logical(INT_KIND) :: fopened !<Flag telling if a file is already open.
4672  type(time_type) :: diag_time !<
4673 
4674  integer(INT_KIND) :: output_unit=6
4675 !!!!!!
4676 
4677 
4678 
4679  namelist /test_diag_manager_nml/ layout, test_number, nlon, nlat, nlev, io_layout, numthreads, &
4680  dt_step, months, days
4681  namelist /utest_nml/nx,ny,nz,nt,ntiles_x,ntiles_y,io_tile_factor
4682  ! Initialize all id* vars to be -1
4683  id_nv = -1
4684  id_nv_init = -1
4685  id_phalf = -1
4686  id_pfull = -1
4687  id_bk = -1
4688  id_lon1 = -1
4689  id_lonb1 = -1
4690  id_latb1 = -1
4691  id_lat1 = -1
4692  id_dat1 = -1
4693  id_lon2 = -1
4694  id_lat2 = -1
4695  id_dat2 = -1
4696  id_dat2_2d = -1
4697  id_sol_con = -1
4698  id_dat2h = -1
4699  id_dat2h_2 = -1
4700  id_dat2_got = -1
4701  id_none_got = -1
4702 
4703  CALL fms_init
4704  log_unit = stdlog()
4705  out_unit = stdout()
4706  CALL constants_init
4707  CALL set_calendar_type(julian)
4708  npes = mpp_npes()
4709 #ifdef INTERNAL_FILE_NML
4710  READ (input_nml_file, nml=test_diag_manager_nml, iostat=ierr)
4711  READ (input_nml_file, nml=utest_nml, iostat=i)
4712 #else
4713  IF ( file_exist('input.nml') ) THEN
4714  nml_unit = open_namelist_file()
4715  READ(nml_unit, nml=test_diag_manager_nml, iostat=ierr)
4716  READ(nml_unit, nml=utest_nml, iostat=i)
4717  CALL close_file(nml_unit)
4718  ELSE
4719  ! Set ierr to an arbitrary positive number if input.nml does not exist.
4720  ierr = 100
4721  END IF
4722 #endif
4723  ! Check the status of reading the diag_manager_nml
4724  IF ( check_nml_error(iostat=ierr, nml_name='DIAG_MANAGER_NML') < 0 ) THEN
4725  IF ( mpp_pe() == mpp_root_pe() ) THEN
4726  CALL error_mesg('diag_manager_mod::diag_manager_init', 'TEST_DIAG_MANAGER_NML not found in input.nml. Using defaults.',&
4727  & warning)
4728  END IF
4729  END IF
4730  WRITE (log_unit,test_diag_manager_nml)
4731 
4732 !> If the test_number == 100, then call the unstrcutured grid unit test and skip everything else.
4733 if (test_number == 100) then
4734  !Initialize the mpp_domains module
4735  if (debug) then
4736  call mpp_domains_init(mpp_debug)
4737  else
4738  call mpp_domains_init()
4739  endif
4740 
4741  !Initialize the mpp_io module.
4742  if (debug) then
4743  call mpp_io_init(mpp_debug)
4744  else
4745  call mpp_io_init()
4746  endif
4747 
4748  !Initialize the fms_io module.
4749  call fms_io_init()
4750 
4751  !Set the mpp and mpp_domains stack sizes.
4752  call mpp_set_stack_size(stackmax)
4753  call mpp_domains_set_stack_size(stackmaxd)
4754 
4755  !Write out test configuration parameters.
4756  if (mpp_pe() .eq. mpp_root_pe()) then
4757  write(output_unit,*)
4758  write(output_unit,*) "Performing unstructured_io unit test with:"
4759  write(output_unit,*) "Total number of ranks: ", &
4760  npes
4761  write(output_unit,*) "Total number of grid points in the x-dimension: ", &
4762  nx
4763  write(output_unit,*) "Total number of grid points in the y-dimension: ", &
4764  ny
4765  write(output_unit,*) "Total number of grid points in the z-dimension: ", &
4766  nz
4767  write(output_unit,*) "Total number of grid points in the t-dimension: ", &
4768  nt
4769  write(output_unit,*) "Halo width (# of grid points): ", &
4770  halo
4771  write(output_unit,*) "Using Unstructured domaintypes and calls..."
4772  endif
4773 
4774  !Add a suffix to the test file.
4775  write(test_file,'(a,i3.3)') trim(test_file),npes
4776 
4777  !Initialize the diag manager module.
4778  call diag_manager_init()
4779 
4780  !Set the diag_time variable to be 01/01/1990 at 00:00:00 (midnight).
4781  call set_calendar_type(julian)
4782  time = set_date(1990,1,1,0,0,0)
4783  CALL unstruct_test (nx, ny, nz, npes, ntiles_x, 2, time,io_tile_factor)
4784 else
4785 !!!!!! ALL OTHER TESTS !!!!!!
4786  IF ( test_number == 12 ) THEN
4787  CALL diag_manager_init(err_msg=err_msg)
4788  IF ( err_msg /= '' ) THEN
4789  WRITE (out_unit,'(a)') 'test12 successful: err_msg='//trim(err_msg)
4790  CALL error_mesg('test_diag_manager','test12 successful.',fatal)
4791  ELSE
4792  WRITE (out_unit,'(a)') 'test12 fails'
4793  CALL error_mesg('test_diag_manager','test12 fails',fatal)
4794  END IF
4795  ELSE
4796  CALL diag_manager_init
4797  END IF
4798 
4799  IF ( layout(1)*layout(2) .NE. mpp_npes() ) THEN
4800  CALL mpp_define_layout((/1,nlon,1,nlat/), mpp_npes(), layout )
4801  END IF
4802 
4803  nlon1 = nlon
4804  nlat1 = nlat
4805  nlon2 = nlon * 2
4806  nlat2 = nlat * 2
4807 
4808  CALL mpp_define_domains((/1,nlon1,1,nlat1/), layout, domain1, name='test_diag_manager')
4809  CALL mpp_get_compute_domain(domain1, is1, ie1, js1, je1)
4810  ALLOCATE(lon_global1(nlon1), lonb_global1(nlon1+1))
4811  ALLOCATE(lat_global1(nlat1), latb_global1(nlat1+1))
4812  ALLOCATE(lon_global2(nlon2), lonb_global2(nlon2+1))
4813  ALLOCATE(lat_global2(nlat2), latb_global2(nlat2+1))
4814  ALLOCATE(pfull(nlev), bk(nlev), phalf(nlev+1))
4815 
4816  ALLOCATE(lon1(is1:ie1), lat1(js1:je1), lonb1(is1:ie1+1), latb1(js1:je1+1))
4817  CALL compute_grid(nlon1, nlat1, is1, ie1, js1, je1, lon_global1, lat_global1, lonb_global1, latb_global1, lon1, lat1, lonb1, latb1)
4818  CALL mpp_define_domains((/1,nlon2,1,nlat2/), layout, domain2, name='test_diag_manager')
4819  CALL mpp_get_compute_domain(domain2, is2, ie2, js2, je2)
4820  CALL mpp_define_io_domain(domain1, io_layout)
4821  CALL mpp_define_io_domain(domain2, io_layout)
4822 
4823  ALLOCATE(lon2(is2:ie2), lat2(js2:je2), lonb2(is2:ie2+1), latb2(js2:je2+1))
4824  CALL compute_grid(nlon2, nlat2, is2, ie2, js2, je2, lon_global2, lat_global2, lonb_global2, latb_global2, lon2, lat2, lonb2, latb2)
4825  dp = surf_press/nlev
4826  DO k=1, nlev+1
4827  phalf(k) = dp*(k-1)
4828  END DO
4829  DO k=1, nlev
4830  pfull(k) = .5*(phalf(k) + phalf(k+1))
4831  bk(k) = pfull(k)/surf_press
4832  END DO
4833 
4834  ALLOCATE(dat1(is1:ie1,js1:je1,nlev))
4835  ALLOCATE(dat1h(is1-hi:ie1+hi,js1-hj:je1+hj,nlev))
4836  dat1h = 0.
4837  DO j=js1, je1
4838  DO i=is1, ie1
4839  dat1(i,j,1) = sin(lon1(i))*cos(lat1(j))
4840  END DO
4841  END DO
4842  dat1h(is1:ie1,js1:je1,1) = dat1(:,:,1)
4843  dat1(:,:,2) = -dat1(:,:,1)
4844  dat1h(:,:,2) = -dat1h(:,:,1)
4845 
4846  ALLOCATE(dat2(is2:ie2,js2:je2,nlev))
4847  ALLOCATE(dat2_2d(is2:ie2,js2:je2))
4848  ALLOCATE(dat2h(is2-hi:ie2+hi,js2-hj:je2+hj,nlev))
4849  dat2h = 0.
4850  dat2 = 0.
4851  DO j=js2, je2
4852  DO i=is2, ie2
4853  dat2(i,j,1) = sin(lon2(i))*cos(lat2(j))
4854  END DO
4855  END DO
4856  dat2h(is2:ie2,js2:je2,1) = dat2(:,:,1)
4857  dat2(:,:,2) = -dat2(:,:,1)
4858  dat2h(:,:,2) = -dat2h(:,:,1)
4859  dat2_2d = dat2(:,:,1)
4860 
4861  id_lonb1 = diag_axis_init('lonb1', rad_to_deg*lonb_global1, 'degrees_E', 'x', long_name='longitude edges', domain2=domain1)
4862  id_latb1 = diag_axis_init('latb1', rad_to_deg*latb_global1, 'degrees_N', 'y', long_name='latitude edges', domain2=domain1)
4863 
4864  id_lon1 = diag_axis_init('lon1', rad_to_deg*lon_global1, 'degrees_E','x',long_name='longitude',domain2=domain1,edges=id_lonb1)
4865  id_lat1 = diag_axis_init('lat1', rad_to_deg*lat_global1, 'degrees_N','y',long_name='latitude', domain2=domain1,edges=id_latb1)
4866 
4867  id_phalf= diag_axis_init('phalf', phalf, 'Pa', 'z', long_name='half pressure level', direction=-1)
4868  id_pfull= diag_axis_init('pfull', pfull, 'Pa', 'z', long_name='full pressure level', direction=-1, edges=id_phalf)
4869 
4870  id_lon2 = diag_axis_init('lon2', rad_to_deg*lon_global2, 'degrees_E', 'x', long_name='longitude', domain2=domain2)
4871  id_lat2 = diag_axis_init('lat2', rad_to_deg*lat_global2, 'degrees_N', 'y', long_name='latitude', domain2=domain2)
4872 
4873  IF ( test_number == 22 ) THEN
4874  ! Can we get the 'nv' axis ID?
4875  id_nv = get_axis_num('nv', 'nv')
4876  IF ( id_nv .GT. 0 ) THEN
4877  write (out_unit,'(a)') 'test22.1 Passes: id_nv has a positive value'
4878  ELSE
4879  write (out_unit,'(a)') 'test22.1 Failed: id_nv does not have a positive value'
4880  END IF
4881 
4882  ! Can I call diag_axis_init on 'nv' again, and get the same ID back?
4883  id_nv_init = diag_axis_init( 'nv',(/1.,2./),'none','N','vertex number', set_name='nv')
4884  IF ( id_nv_init .EQ. id_nv ) THEN
4885  write (out_unit,'(a)') 'test22.2 Passes: Can call diag_axis_init on "nv" and get same ID'
4886  ELSE
4887  write (out_unit,'(a)') 'test22.2 Failed: Cannot call diag_axis_init on "nv" and get same ID'
4888  END IF
4889  END IF
4890 
4891  IF ( test_number == 21 ) THEN
4892  ! Testing addition of axis attributes
4893  CALL diag_axis_add_attribute(id_lon1, 'real_att', 2.3)
4894  CALL diag_axis_add_attribute(id_lat1, 'int_att', (/ 2, 3 /))
4895  CALL diag_axis_add_attribute(id_pfull, 'char_att', 'Some string')
4896  END IF
4897 
4898  IF ( test_number == 14 ) THEN
4899  time = set_date(1990,1,29,0,0,0)
4900  ELSE
4901  time = set_date(1990,1,1,0,0,0)
4902  END IF
4903 
4904  IF ( test_number == 16 ) THEN
4905  ! Test 16 tests the filename appendix
4906  CALL set_filename_appendix('g01')
4907  END IF
4908  id_dat1 = register_diag_field('test_diag_manager_mod', 'dat1', (/id_lon1,id_lat1,id_pfull/), time, 'sample data', 'K')
4909  IF ( test_number == 18 ) THEN
4910  CALL diag_field_add_attribute(id_dat1, 'real_att', 2.3)
4911  CALL diag_field_add_attribute(id_dat1, 'cell_methods', 'area: mean')
4912  CALL diag_field_add_attribute(id_dat1, 'cell_methods', 'lon: mean')
4913  END IF
4914  IF ( test_number == 18 .OR. test_number == 19 ) THEN
4915  id_dat2 = register_diag_field('test_diag_manager_mod', 'dat2', (/id_lon1,id_lat1,id_pfull/), time, 'sample data', 'K')
4916  CALL diag_field_add_attribute(id_dat2, 'interp_method', 'none')
4917  CALL diag_field_add_attribute(id_dat2, 'int_att', (/ 1, 2 /) )
4918  ELSE
4919  id_dat2 = register_diag_field('test_diag_manager_mod', 'dat2', (/id_lon2,id_lat2,id_pfull/), time, 'sample data', 'K')
4920  END IF
4921  id_sol_con = register_diag_field('test_diag_manager_mod', 'solar_constant', time, &
4922  'solar constant', 'watts/m2')
4923 
4924  IF ( test_number == 20 ) THEN
4925  id_dat2_got = get_diag_field_id('test_diag_manager_mod', 'dat2')
4926  IF ( id_dat2_got == id_dat2 ) THEN
4927  WRITE (out_unit,'(a)') .EQ.'test20.1 Passes, id_dat2id_dat2_got'
4928  ELSE
4929  WRITE (out_unit,'(a)') .NE.'test20.1 Failed, id_dat2id_dat2_got'
4930  END IF
4931 
4932  id_none_got = get_diag_field_id('no_mod', 'no_var')
4933  IF ( id_none_got == diag_field_not_found ) THEN
4934  write (out_unit,'(a)') .EQ.'test20.2 Passes, id_none_gotDIAG_FIELD_NOT_FOUND'
4935  ELSE
4936  write (out_unit,'(a)') .NE.'test20.2 Failed, id_none_gotDIAG_FIELD_NOT_FOUND'
4937  END IF
4938  END IF
4939 
4940  IF ( dt_step == 0 ) CALL error_mesg ('test_diag_manager',&
4941  & 'dt_step is not set', fatal)
4942 
4943  time_step = set_time(dt_step,0)
4944  time_start = time
4945  time_end = time
4946  DO m = 1,months
4947  time_end = time_end + set_time(0,days_in_month(time_end))
4948  END DO
4949  time_end = time_end + set_time(0, days)
4950  run_length = time_end - time_start
4951  nstep = run_length / time_step
4952 
4953  IF ( test_number == 18 ) THEN
4954  id_dat2h = register_diag_field('test_mod', 'dat2h', (/id_lon1,id_lat1,id_pfull/), time, 'sample data', 'K',&
4955  & volume=id_dat1, area=id_dat2, realm='myRealm', err_msg=err_msg)
4956  IF ( err_msg /= '' .OR. id_dat2h <= 0 ) THEN
4957  CALL error_mesg ('test_diag_manager',&
4958  & 'Unexpected error registering dat2h '//err_msg, fatal)
4959  END IF
4960  id_dat2h_2 = register_diag_field('test_mod', 'dat2h_2', (/id_lon1,id_lat1,id_pfull/), time, 'sample data', 'K',&
4961  & err_msg=err_msg)
4962  CALL diag_field_add_cell_measures(id_dat2h_2, area=id_dat2, volume=id_dat1)
4963  ELSE IF ( test_number == 19 ) THEN
4964  id_dat2h = register_diag_field('test_mod', 'dat2h', (/id_lon1,id_lat1,id_pfull/), time, 'sample data', 'K',&
4965  & volume=id_dat1, area=id_dat1, err_msg=err_msg)
4966  IF ( err_msg /= '' .OR. id_dat2h <= 0 ) THEN
4967  CALL error_mesg ('test_diag_manager',&
4968  & 'Expected error registering dat2h '//err_msg, fatal)
4969  END IF
4970  END IF
4971 
4972  IF ( test_number == 16 .OR. test_number == 17 .OR. test_number == 18 .OR. test_number == 21 .OR. test_number == 22 ) THEN
4973  is_in = 1
4974  js_in = 1
4975  ie_in = nlon
4976  je_in = nlat
4977 
4978  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat1, time, err_msg=err_msg)
4979  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat1, time, err_msg=err_msg)
4980  IF ( id_dat2h > 0 ) used = send_data(id_dat2h, dat2h, time, is_in=is_in, js_in=js_in, ie_in=ie_in, je_in=je_in, err_msg=err_msg)
4981  IF ( id_dat2h_2 > 0 ) used = send_data(id_dat2h_2, dat2h, time, is_in=is_in, js_in=js_in, ie_in=ie_in, je_in=je_in, err_msg=err_msg)
4982  time = time + set_time(0,1)
4983  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat1, time, err_msg=err_msg)
4984  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat1, time, err_msg=err_msg)
4985  IF ( id_dat2h > 0 ) used = send_data(id_dat2h, dat2h, time, is_in=is_in, js_in=js_in, ie_in=ie_in, je_in=je_in, err_msg=err_msg)
4986  IF ( id_dat2h_2 > 0 ) used = send_data(id_dat2h_2, dat2h, time, is_in=is_in, js_in=js_in, ie_in=ie_in, je_in=je_in, err_msg=err_msg)
4987  END IF
4988 
4989  !-- The following is used to test openMP
4990  IF ( test_number == 15 ) THEN
4991 !$ call omp_set_num_threads(numthreads)
4992  nyc1 = je1 - js1 + 1
4993  IF (mod(nyc1, numthreads ) /= 0) THEN
4994  CALL error_mesg ('test_diag_manager',&
4995  & 'The number of OpenMP threads must be an integral multiple &
4996  &of the number of rows in the compute domain', fatal)
4997  END IF
4998  ny_per_thread = nyc1/numthreads
4999 
5000  dat1 = 1
5001  CALL diag_manager_set_time_end(time_end)
5002  DO n = 1, nstep
5003 
5004  time = time + time_step
5005  !$OMP parallel do default(shared) private(isw, iew, jsw, jew )
5006 
5007  DO jsw = js1, je1, ny_per_thread
5008  jew = jsw + ny_per_thread -1
5009  isw = is1
5010  iew = ie1
5011  if(id_dat1>0) used = send_data(id_dat1, dat1(isw:iew, jsw:jew,:), time, &
5012  is_in=isw-is1+1, js_in=jsw-js1+1,err_msg=err_msg)
5013  if(id_sol_con>0) used = send_data(id_sol_con, solar_constant, time )
5014  END DO
5015  !$OMP END parallel do
5016  CALL diag_send_complete(time_step)
5017  END DO
5018  END IF
5019 
5020 
5021  IF ( test_number == 14 ) THEN
5022  id_dat2_2d = register_diag_field('test_mod', 'dat2', (/id_lon2,id_lat2/), time, 'sample data', 'K', err_msg=err_msg)
5023  IF ( err_msg /= '' ) THEN
5024  WRITE (out_unit,'(a)') 'test14 successful. err_msg='//trim(err_msg)
5025  ELSE
5026  WRITE (out_unit,'(a)') 'test14 fails.'
5027  END IF
5028  ELSE
5029  id_dat2_2d = register_diag_field('test_mod', 'dat2', (/id_lon2,id_lat2/), time, 'sample data', 'K')
5030  END IF
5031 
5032  id_bk = register_static_field('test_diag_manager_mod', 'bk', (/id_pfull/), 'half level sigma', 'none')
5033 
5034  IF ( test_number == 13 ) THEN
5035  IF ( id_dat2_2d > 0 ) used=send_data(id_dat2_2d, dat2(:,:,1), time, err_msg=err_msg)
5036  IF ( err_msg == '' ) THEN
5037  WRITE (out_unit,'(a)') 'test13: successful if a WARNING message appears that refers to output interval greater than runlength'
5038  ELSE
5039  WRITE (out_unit,'(a)') 'test13 fails: err_msg='//trim(err_msg)
5040  END IF
5041  END IF
5042 
5043  ! Note: test12 involves diag_manager_init, it does not require a call to send_data.
5044  ! See call to diag_manager_init above.
5045 
5046  IF ( test_number == 11 ) THEN
5047  is_in = 1+hi
5048  js_in = 1+hj
5049  ie_in = ie2-is2+1+hi
5050  je_in = je2-js2+1+hj
5051 
5052  IF ( id_dat2 > 0 ) used=send_data(id_dat2, dat2h, time, is_in=is_in, js_in=js_in, ie_in=ie_in, je_in=je_in, err_msg=err_msg)
5053  IF ( err_msg == '' ) THEN
5054  WRITE (out_unit,'(a)') 'test11.1 successful.'
5055  ELSE
5056  WRITE (out_unit,'(a)') 'test11.1 fails. err_msg='//trim(err_msg)
5057  END IF
5058 
5059  ! intentional_error: je_in is missing
5060  IF ( id_dat2 > 0 ) used=send_data(id_dat2, dat2h, time, is_in=is_in, js_in=js_in, ie_in=ie_in, err_msg=err_msg)
5061  IF ( err_msg == '' ) THEN
5062  WRITE (out_unit,'(a)') 'test11.2 fails.'
5063  ELSE
5064  WRITE (out_unit,'(a)') 'test11.2 successful. err_msg='//trim(err_msg)
5065  END IF
5066  END IF
5067 
5068  IF ( test_number == 10 ) THEN
5069  ! 1 window, no halos, static, 1 dimension, global data.
5070 
5071  IF ( id_bk > 0 ) used = send_data(id_bk, bk, err_msg=err_msg)
5072  IF ( err_msg == '' ) THEN
5073  WRITE (out_unit,'(a)') 'test10.1 successful.'
5074  ELSE
5075  WRITE (out_unit,'(a)') 'test10.1 fails: err_msg='//trim(err_msg)
5076  END IF
5077 
5078  ! intentional_error: data array too large.
5079  IF ( id_bk > 0 ) used = send_data(id_bk, phalf, err_msg=err_msg)
5080  IF ( err_msg == '' ) THEN
5081  WRITE(out_unit,'(a)') 'test10.2 fails.'
5082  ELSE
5083  WRITE (out_unit,'(a)') 'test10.2 successful: err_msg='//trim(err_msg)
5084  END IF
5085  END IF
5086 
5087  IF ( test_number == 9 ) THEN
5088  ! 1 window, no halos, static, 1 dimension, global data
5089  IF ( id_bk > 0 ) used = send_data(id_bk, bk, err_msg=err_msg)
5090  IF ( err_msg == '' ) THEN
5091  WRITE (out_unit,'(a)') 'test9.1 successful.'
5092  ELSE
5093  WRITE (out_unit,'(a)') 'test9.1 fails: err_msg='//trim(err_msg)
5094  END IF
5095 
5096  ! intentional_error: data array too small
5097  IF ( id_bk > 0 ) used = send_data(id_bk, bk(1:nlev-1), err_msg=err_msg) ! intentional_error
5098  IF ( err_msg == '' ) THEN
5099  WRITE (out_unit,'(a)') 'test9.2 fails.'
5100  ELSE
5101  WRITE (out_unit,'(a)') 'test9.2 successful: err_msg='//trim(err_msg)
5102  END IF
5103  END IF
5104 
5105  IF ( test_number == 8 ) THEN
5106  ! 1 window with halos
5107  is_in = 1+hi
5108  js_in = 1+hj
5109 
5110  ie_in = ie2-is2+1+hi
5111  je_in = je2-js2+1+hj
5112  IF ( id_dat2 > 0 ) used=send_data(id_dat2, dat2h, time, is_in=is_in, js_in=js_in,&
5113  & ks_in=1, ie_in=ie_in, je_in=je_in, ke_in=nlev, err_msg=err_msg)
5114  IF ( err_msg == '' ) THEN
5115  WRITE (out_unit,'(a)') 'test8.1 successful.'
5116  ELSE
5117  WRITE (out_unit,'(a)') 'test8.1 fails: err_msg='//trim(err_msg)
5118  END IF
5119 
5120  ! intentional_error: data array too small in both x and y directions
5121  ! Error check is done on second call to send_data. Change in value of Time triggers the check.
5122  time = time + set_time(0,1)
5123  ie_in = ie1-is1+1+hi
5124  je_in = je1-js1+1+hj
5125  IF ( id_dat2 > 0 ) used=send_data(id_dat2, dat1h, time, is_in=is_in, js_in=js_in,&
5126  & ks_in=1, ie_in=ie_in, je_in=je_in, ke_in=nlev, err_msg=err_msg)
5127  time = time + set_time(0,1)
5128  IF ( id_dat2 > 0 ) used=send_data(id_dat2, dat1h, time, is_in=is_in, js_in=js_in, &
5129  & ks_in=1, ie_in=ie_in, je_in=je_in, ke_in=nlev, err_msg=err_msg)
5130  IF ( err_msg == '' ) THEN
5131  WRITE (out_unit,'(a)') 'test8.2 fails.'
5132  ELSE
5133  WRITE (out_unit,'(a)') 'test8.2 successful: err_msg='//trim(err_msg)
5134  END IF
5135  END IF
5136 
5137  IF ( test_number == 7 ) THEN
5138  ! 1 window with halos
5139  is_in = 1+hi
5140  js_in = 1+hj
5141 
5142  ie_in = ie1-is1+1+hi
5143  je_in = je1-js1+1+hj
5144  IF ( id_dat1 > 0 ) used=send_data(id_dat1, dat1h, time, is_in=is_in, js_in=js_in,&
5145  & ks_in=1, ie_in=ie_in, je_in=je_in, ke_in=nlev, err_msg=err_msg)
5146  IF ( err_msg == '' ) THEN
5147  WRITE (out_unit,'(a)') 'test7.1 successful.'
5148  ELSE
5149  WRITE (out_unit,'(a)') 'test7.1 fails: err_msg='//trim(err_msg)
5150  END IF
5151 
5152  ! intentional_error: data array too large in both x and y directions
5153  ie_in = ie2-is2+1+hi
5154  je_in = je2-js2+1+hj
5155  IF ( id_dat1 > 0 ) used=send_data(id_dat1, dat2h, time, is_in=is_in, js_in=js_in,&
5156  & ks_in=1, ie_in=ie_in, je_in=je_in, ke_in=nlev, err_msg=err_msg)
5157  IF ( err_msg == '' ) THEN
5158  WRITE (out_unit,'(a)') 'test7.2 fails.'
5159  ELSE
5160  WRITE (out_unit,'(a)') 'test7.2 successful: err_msg='//trim(err_msg)
5161  END IF
5162  END IF
5163 
5164  IF ( test_number == 6 ) THEN
5165  ! multiple windows, no halos
5166  ! No error messages should appear at any point within either do loop for test6.1
5167  test_successful = .true.
5168  DO i=is2, ie2
5169  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(i:i,:,:), time, i-is2+1, 1, err_msg=err_msg)
5170  IF ( err_msg /= '' ) THEN
5171  WRITE (out_unit,'(a)') 'test6.1 fails: err_msg='//trim(err_msg)
5172  test_successful = .false.
5173  END IF
5174  END DO
5175  time = time + set_time(0,1)
5176  DO i=is2, ie2
5177  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(i:i,:,:), time, i-is2+1, 1, err_msg=err_msg)
5178  IF ( err_msg /= '' ) THEN
5179  WRITE (out_unit,'(a)') 'test6.1 fails: err_msg='//trim(err_msg)
5180  test_successful = .false.
5181  END IF
5182  END DO
5183  IF ( test_successful ) THEN
5184  WRITE (out_unit,'(a)') 'test6.1 successful.'
5185  ELSE
5186  WRITE (out_unit,'(a)') 'test6.1 fails.'
5187  END IF
5188 
5189  ! intentional_error: data array too small in y direction
5190  ! Error check is done on second call to send_data. Change in value of Time triggers the check.
5191  time = time + set_time(0,1)
5192  DO i=is2, ie2
5193  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(i:i,js2:je2-1,:), time, i-is2+1, 1)
5194  END DO
5195  time = time + set_time(0,1)
5196  DO i=is2, ie2
5197  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(i:i,js2:je2-1,:), time, i-is2+1, 1, err_msg=err_msg)
5198  IF ( err_msg /= '' ) EXIT ! exit immediately after error is detected. No need to continue.
5199  END DO
5200  IF ( err_msg == '' ) THEN
5201  WRITE (out_unit,'(a)') 'test6.2 fails.'
5202  ELSE
5203  WRITE (out_unit,'(a)') 'test6.2 successful: err_msg='//trim(err_msg)
5204  END IF
5205  END IF
5206 
5207  IF ( test_number == 5 ) THEN
5208  ! multiple windows, no halos
5209  ! No error messages should appear at any point within either do loop for test5.1
5210  test_successful = .true.
5211  DO j=js2, je2
5212  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(:,j:j,:), time, 1, j-js2+1, err_msg=err_msg)
5213  IF ( err_msg /= '' ) THEN
5214  WRITE (out_unit,'(a)') 'test5.1 fails: err_msg='//trim(err_msg)
5215  test_successful = .false.
5216  END IF
5217  END DO
5218  time = time + set_time(0,1)
5219  DO j=js2, je2
5220  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(:,j:j,:), time, 1, j-js2+1, err_msg=err_msg)
5221  IF ( err_msg /= '' ) THEN
5222  WRITE (out_unit,'(a)') 'test5.1 fails: err_msg='//trim(err_msg)
5223  test_successful = .false.
5224  END IF
5225  END DO
5226  IF ( test_successful ) THEN
5227  WRITE (out_unit,'(a)') 'test5.1 successful.'
5228  ELSE
5229  WRITE (out_unit,'(a)') 'test5.1 fails.'
5230  END IF
5231 
5232  ! intentional_error: data array too small in x direction.
5233  ! Error check is done on second call to send_data. Change in value of Time triggers the check.
5234  time = time + set_time(0,1)
5235  DO j=js2, je2
5236  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(is2:ie2-1,j:j,:), time, 1, j-js2+1)
5237  END DO
5238  time = time + set_time(0,1)
5239  DO j=js2, je2
5240  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2(is2:ie2-1,j:j,:), time, 1, j-js2+1, err_msg=err_msg)
5241  IF ( err_msg /= '' ) EXIT ! exit immediately after error is detected. No need to continue.
5242  END DO
5243  IF ( err_msg == '' ) THEN
5244  WRITE (out_unit,'(a)') 'test5.2 fails.'
5245  ELSE
5246  WRITE (out_unit,'(a)') 'test5.2 successful: err_msg='//trim(err_msg)
5247  END IF
5248  END IF
5249 
5250  IF ( test_number == 4 ) THEN
5251  ! 1 window, no halos
5252  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2, time, err_msg=err_msg)
5253  time = time + set_time(0,1)
5254  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat2, time, err_msg=err_msg)
5255  IF ( err_msg == '' ) THEN
5256  WRITE (out_unit,'(a)') 'test4.1 successful.'
5257  ELSE
5258  WRITE (out_unit,'(a)') 'test4.1 fails: err_msg='//trim(err_msg)
5259  END IF
5260 
5261  ! intentional_error: data array too small in both x and y directions
5262  ! Error check is done on second call to send_data. Change in value of Time triggers the check.
5263  time = time + set_time(0,1)
5264  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat1, time, err_msg=err_msg)
5265  time = time + set_time(0,1)
5266  IF ( id_dat2 > 0 ) used = send_data(id_dat2, dat1, time, err_msg=err_msg)
5267  IF ( err_msg == '' ) THEN
5268  WRITE (out_unit,'(a)') 'test4.2 fails.'
5269  ELSE
5270  WRITE (out_unit,'(a)') 'test4.2 successful: err_msg='//trim(err_msg)
5271  END IF
5272  END IF
5273 
5274  IF ( test_number == 3 ) THEN
5275  ! multiple windows, no halos
5276  ! No error messages should appear at any point within do loop for test3.1
5277  test_successful = .true.
5278  DO i=is1, ie1
5279  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat1(i:i,:,:), time, i-is1+1, 1, err_msg=err_msg)
5280  IF ( err_msg /= '' ) THEN
5281  WRITE (out_unit,'(a)') 'test3.1 fails: err_msg='//trim(err_msg)
5282  test_successful = .false.
5283  END IF
5284  END DO
5285  IF ( test_successful ) THEN
5286  WRITE (out_unit,'(a)') 'test3.1 successful.'
5287  ELSE
5288  WRITE (out_unit,'(a)') 'test3.1 fails.'
5289  END IF
5290 
5291  ! intentional_error: data array too large in y direction
5292  DO i=is1, ie1
5293  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat2(i:i,:,:), time, i-is1+1, 1, err_msg=err_msg)
5294  IF ( err_msg /= '' ) EXIT ! exit immediately after error is detected. No need to continue.
5295  END DO
5296  IF ( err_msg == '' ) THEN
5297  WRITE (out_unit,'(a)') 'test3.2 fails.'
5298  ELSE
5299  WRITE (out_unit,'(a)') 'test3.2 successful: err_msg='//trim(err_msg)
5300  END IF
5301  END IF
5302 
5303  IF ( test_number == 2 ) THEN
5304  ! multiple windows, no halos
5305  ! No error messages should appear at any point within do loop for test2.1
5306  test_successful = .true.
5307  DO j=js1, je1
5308  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat1(:,j:j,:), time, 1, j-js1+1, err_msg=err_msg)
5309  IF ( err_msg /= '' ) THEN
5310  WRITE (out_unit,'(a)') 'test2.1 fails: err_msg='//trim(err_msg)
5311  test_successful = .false.
5312  END IF
5313  END DO
5314  IF ( test_successful ) THEN
5315  WRITE (out_unit,'(a)') 'test2.1 successful.'
5316  ELSE
5317  WRITE (out_unit,'(a)') 'test2.1 fails.'
5318  END IF
5319 
5320  ! intentional_error: data array too large in x direction
5321  DO j=js1, je1
5322  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat2(:,j:j,:), time, 1, j-js1+1, err_msg=err_msg)
5323  IF ( err_msg /= '' ) EXIT ! exit immediately after error is detected. No need to continue.
5324  END DO
5325  IF ( err_msg == '' ) THEN
5326  WRITE (out_unit,'(a)') 'test2.2 fails.'
5327  ELSE
5328  WRITE (out_unit,'(a)') 'test2.2 successful: err_msg='//trim(err_msg)
5329  END IF
5330  END IF
5331 
5332  IF ( test_number == 1 ) THEN
5333  ! 1 window, no halos
5334  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat2, time, err_msg=err_msg)
5335  IF ( err_msg == '' ) THEN
5336  WRITE (out_unit,'(a)') 'test1.1 fails: Intentional error not detected'
5337  ELSE
5338  WRITE (out_unit,'(a)') 'test1.1 successful: '//trim(err_msg)
5339  END IF
5340 
5341  ! intentional_error: data array too large in both x and y directions
5342  IF ( id_dat1 > 0 ) used = send_data(id_dat1, dat1, time, err_msg=err_msg)
5343  IF ( err_msg == '' ) THEN
5344  WRITE (out_unit,'(a)') 'test1.2 successful'
5345  ELSE
5346  WRITE (out_unit,'(a)') 'test1.2 fails: '//trim(err_msg)
5347  END IF
5348  END IF
5349 endif !! This is the endif for the unstructured grid if
5350  CALL diag_manager_end(time)
5351  CALL fms_io_exit
5352  CALL fms_end
5353 
5354 CONTAINS
5355 
5356  SUBROUTINE compute_grid(nlon, nlat, is, ie, js, je, lon_global, lat_global, lonb_global, latb_global, lon, lat, lonb, latb)
5357  INTEGER, INTENT(in) :: nlon, nlat, is, ie, js, je
5358  REAL, INTENT(out), DIMENSION(:) :: lon_global, lat_global, lonb_global, latb_global, lon, lat, lonb, latb
5359 
5360  REAL :: dlon, dlat
5361  INTEGER :: i, j
5362 
5363  dlon = 2*pi/nlon
5364  dlat = pi/nlat
5365 
5366  DO i=1, nlon+1
5367  lonb_global(i) = dlon*(i-1)
5368  END DO
5369  DO j=1,nlat+1
5370  latb_global(j) = dlat*(j-1) - .5*pi
5371  END DO
5372  DO i=1,nlon
5373  lon_global(i) = .5*(lonb_global(i) + lonb_global(i+1))
5374  END DO
5375  DO j=1,nlat
5376  lat_global(j) = .5*(latb_global(j) + latb_global(j+1))
5377  END DO
5378  lon = lon_global(is:ie)
5379  lat = lat_global(js:je)
5380  lonb = lonb_global(is:ie+1)
5381  latb = latb_global(js:je+1)
5382  END SUBROUTINE compute_grid
5383 
5384  SUBROUTINE unstruct_test(nx, ny, nz, npes, num_domain_tiles_x, num_domain_tiles_y, diag_time,io_tile_factor)
5385  use, intrinsic :: iso_fortran_env, only: output_unit
5386  use mpp_parameter_mod, only: fatal
5387  use mpp_mod, only: mpp_error, &
5388  mpp_pe, &
5389  mpp_root_pe, &
5390  mpp_sync, &
5391  mpp_chksum
5392  use mpp_domains_mod, only: domain2d, &
5393  mpp_define_mosaic, &
5395  domainug, &
5396  mpp_define_unstruct_domain, &
5397 ! mpp_deallocate_domainUG, &
5398  mpp_get_ug_compute_domain, &
5399  mpp_get_ug_domain_grid_index, &
5400  mpp_get_ug_domain_ntiles
5403  send_data
5404  use time_manager_mod, only: time_type, &
5405  set_time, &
5406  operator(+), &
5407  assignment(=)
5408  implicit none
5409 
5410  !Inputs/Ouputs
5411  integer(INT_KIND),intent(in) :: nx !<The number of grid points in the x-direction.
5412  integer(INT_KIND),intent(in) :: ny !<The number of grid points in the y-direction.
5413  integer(INT_KIND),intent(in) :: nz !<The number of grid points in the z-direction.
5414  integer(INT_KIND),intent(in) :: npes !<The total number of ranks used in this test.
5415  integer(INT_KIND),intent(in) :: num_domain_tiles_x !<The total number of domain tiles in the x-dimension for the 2D structured domain in this test.
5416  integer(INT_KIND),intent(in) :: num_domain_tiles_y !<The total number of domain tiles in the y-dimension for the 2D structured domain in this test.
5417  type(time_type),intent(inout) :: diag_time !<Time for diag_manager.
5418  integer(INT_KIND),intent(in) :: io_tile_factor !<I/O tile factor. See below.
5419 
5420  !Local variables
5421  integer(INT_KIND) :: num_domain_tiles !<The total number of domain tiles for the 2D structured domain in this test.
5422  integer(INT_KIND) :: npes_per_domain_tile !<The number of ranks per domain tile for the 2D structured domain.
5423  integer(INT_KIND) :: my_domain_tile_id !<The 2D structured domain tile id for the current rank.
5424  logical(INT_KIND) :: is_domain_tile_root !<Flag telling if the current rank is the root rank of its associated 2D structured domain tile.
5425  integer(INT_KIND),dimension(2) :: layout_for_full_domain !<Rank layout (2D grid) for the full 2D structured domain. Example: 16 ranks -> (16,1) or (8,2) or (4,4) or (2,8) or (1,16)
5426  integer(INT_KIND),dimension(:),allocatable :: pe_start !<Array holding the smallest rank id assigned to each 2D structured domain tile.
5427  integer(INT_KIND),dimension(:),allocatable :: pe_end !<Array holding the largest rank id assigned to each 2D structured domain tile.
5428  integer(INT_KIND) :: x_grid_points_per_domain_tile !<The number of grid points in the x-dimension on each 2D structured domain tile.
5429  integer(INT_KIND) :: y_grid_points_per_domain_tile !<The number of grid points in the y-dimension on each 2D structured domain tile.
5430  integer(INT_KIND),dimension(:,:),allocatable :: global_indices !<Required to define the 2D structured domain.
5431  integer(INT_KIND),dimension(:,:),allocatable :: layout2D !<Required to define the 2D structured domain.
5432  type(domain2D) :: domain_2D !<A structured 2D domain.
5433  logical(INT_KIND),dimension(:,:,:),allocatable :: land_mask !<A toy mask.
5434  integer(INT_KIND),dimension(:),allocatable :: num_non_masked_grid_points_per_domain_tile !<Total number of non-masked grid points on each 2D structured domain tile.
5435  integer(INT_KIND) :: mask_counter !<Counting variable.
5436  integer(INT_KIND) :: num_non_masked_grid_points !<Total number of non-masked grid points for the 2D structured domain.
5437  integer(INT_KIND),dimension(:),allocatable :: num_land_tiles_per_non_masked_grid_point !<Number of land tiles per non-masked grid point for the 2D structured domain.
5438  integer(INT_KIND) :: num_ranks_using_unstructured_grid !<Number of ranks using the unstructured domain.
5439  integer(INT_KIND),dimension(:),allocatable :: unstructured_grid_point_index_map !<Array that maps indices between the 2D structured and unstructured domains.
5440  type(domainUG) :: domain_ug !<An unstructured mpp domain.
5441  integer(INT_KIND),dimension(:),allocatable :: unstructured_axis_data !<Data that is registered to the restart file for the unstructured axis.
5442  integer(INT_KIND) :: unstructured_axis_data_size !<Size of the unstructured axis data array.
5443  character(len=256) :: unstructured_axis_name !<Name for the unstructured axis.
5444  real,dimension(:),allocatable :: x_axis_data !<Data for the x-axis that is registered to the restart file.
5445  real,dimension(:),allocatable :: y_axis_data !<Data for the y-axis that is registered to the restart file.
5446  real,dimension(:),allocatable :: z_axis_data !<Data for the z-axis that is registered to the restart file.
5447  real :: unstructured_real_scalar_field_data_ref !<Reference test data for an unstructured real scalar field.
5448  real,dimension(:),allocatable :: unstructured_real_1D_field_data_ref !<Reference test data for an unstructured real 1D field.
5449  real,dimension(:,:),allocatable :: unstructured_real_2D_field_data_ref !<Reference test data for an unstructured real 2D field.
5450  real,dimension(:,:,:),allocatable :: unstructured_real_3D_field_data_ref !<Reference test data for an unstructured real 3D field.
5451  integer :: unstructured_int_scalar_field_data_ref !<Reference test data for an unstructured integer scalar field.
5452  integer,dimension(:),allocatable :: unstructured_int_1D_field_data_ref !<Reference test data for an unstructured integer 1D field.
5453  integer,dimension(:,:),allocatable :: unstructured_int_2D_field_data_ref !<Reference test data for an unstructured integer 2D field.
5454  character(len=256) :: unstructured_real_scalar_field_name !<Name for an unstructured real scalar field.
5455  real :: unstructured_real_scalar_field_data !<Data for an unstructured real scalar field.
5456  character(len=256) :: unstructured_real_1D_field_name !<Name for an unstructured real 1D field.
5457  real,dimension(:),allocatable :: unstructured_real_1D_field_data !<Data for an unstructured real 1D field.
5458  character(len=256) :: unstructured_real_2D_field_name !<Name for an unstructured real 2D field.
5459  real,dimension(:,:),allocatable :: unstructured_real_2D_field_data !<Data for an unstructured real 2D field.
5460  character(len=256) :: unstructured_real_3D_field_name !<Name for an unstructured real 3D field.
5461  real,dimension(:,:,:),allocatable :: unstructured_real_3D_field_data !<Data for an unstructured real 3D field.
5462  character(len=256) :: unstructured_int_scalar_field_name !<Name for an unstructured integer scalar field.
5463  integer :: unstructured_int_scalar_field_data !<Data for an unstructured integer scalar field.
5464  character(len=256) :: unstructured_int_1D_field_name !<Name for an unstructured integer 1D field.
5465  integer,dimension(:),allocatable :: unstructured_int_1D_field_data !<Data for an unstructured integer 1D field.
5466  character(len=256) :: unstructured_int_2D_field_name !<Name for an unstructured integer 2D field.
5467  character(len=100) :: unstructured_1d_alt !<Name of the unstrucutred 1D field if L>1
5468  integer,dimension(:,:),allocatable :: unstructured_int_2D_field_data !<Data for an unstructured integer 2D field.
5469  integer(INT_KIND),allocatable,dimension(:) :: unstructured_axis_diag_id !<Id returned for the unstructured axis by diag_axis_init.
5470  integer(INT_KIND) :: x_axis_diag_id !<Id returned for the x-axis by diag_axis_init.
5471  integer(INT_KIND) :: y_axis_diag_id !<Id returned for the y-axis by diag_axis_init.
5472  integer(INT_KIND) :: z_axis_diag_id !<Id returned for the z-axis by diag_axis_init.
5473  real,allocatable,dimension(:) :: lat, lon
5474  integer(INT_KIND) :: idlat
5475  integer(INT_KIND) :: idlon
5476  integer(INT_KIND) :: rsf_diag_id !<Id returned for a real scalar field associated with the unstructured grid by
5477  !!register_diag_field.
5478  integer(INT_KIND),allocatable,dimension(:) :: rsf_diag_1d_id !<Id returned for a real 1D array field associated with the unstructured grid by !!register_diag_field.
5479  integer(INT_KIND) :: rsf_diag_2d_id !<Id returned for a real 2D array field associated with the unstructured grid by !!register_diag_field.
5480  integer(INT_KIND) :: num_diag_time_steps !<Number of timesteps (to simulate the model running).
5481  type(time_type) :: diag_time_start !<Starting time for the test.
5482  type(time_type) :: diag_time_step !<Time step for the test.
5483  logical(INT_KIND) :: used !<Return value from send data.
5484 
5485  integer(INT_KIND) :: i !<Loop variable.
5486  integer(INT_KIND) :: j !<Loop variable.
5487  integer(INT_KIND) :: k,l=1 !<Loop variable.
5488  integer(INT_KIND) :: p !<Counting variable.
5489 
5490  !Needed to define the 2D structured domain but never used.
5491  integer(INT_KIND) :: ncontacts
5492  integer(INT_KIND),dimension(20) :: tile1
5493  integer(INT_KIND),dimension(20) :: tile2
5494  integer(INT_KIND),dimension(20) :: istart1
5495  integer(INT_KIND),dimension(20) :: iend1
5496  integer(INT_KIND),dimension(20) :: jstart1
5497  integer(INT_KIND),dimension(20) :: jend1
5498  integer(INT_KIND),dimension(20) :: istart2
5499  integer(INT_KIND),dimension(20) :: iend2
5500  integer(INT_KIND),dimension(20) :: jstart2
5501  integer(INT_KIND),dimension(20) :: jend2
5502 
5503  integer(INT_KIND),dimension(3) :: npes_io_group
5504 
5505  !Print out a message that the test is starting.
5506  if (mpp_pe() .eq. mpp_root_pe()) then
5507  write(output_unit,*)
5508  write(output_unit,*) "</----------------------------------------"
5509  write(output_unit,*) "Test create_unstructured_test_restart_file" &
5510  //" starting ..."
5511  write(output_unit,*)
5512  endif
5513 
5514  !Synchronize all ranks.
5515  call mpp_sync()
5516 
5517  !Make sure that valid inputs were passed in.
5518  if (nx .lt. 1 .or. ny .lt. 1) then
5519  call mpp_error(fatal, &
5520  "create_unstructured_test_restart_file:" &
5521  //" there must be at least on grid point in the" &
5522  //" x- and y- dimensions.")
5523  endif
5524  if (npes .gt. nx*ny) then
5525  call mpp_error(fatal, &
5526  "create_unstructured_test_restart_file:" &
5527  //" the total number of ranks cannot be greater" &
5528  //" than the total number of grid points in the" &
5529  //" x-y plane.")
5530  endif
5531  if (num_domain_tiles_x .lt. 1 .or. num_domain_tiles_y .lt. 1) then
5532  call mpp_error(fatal, &
5533  "create_unstructured_test_restart_file:" &
5534  //" there must be at least on domain tile in the" &
5535  //" x- and y- dimensions.")
5536  endif
5537  if (mod(nx,num_domain_tiles_x) .ne. 0) then
5538  call mpp_error(fatal, &
5539  "create_unstructured_test_restart_file:" &
5540  //" the total number of grid points in the" &
5541  //" x-dimension must be evenly divisible by the" &
5542  //" total number of domain tiles in the" &
5543  //" x-dimension.")
5544  endif
5545  if (mod(ny,num_domain_tiles_y) .ne. 0) then
5546  call mpp_error(fatal, &
5547  "create_unstructured_test_restart_file:" &
5548  //" the total number of grid points in the" &
5549  //" y-dimension must be evenly divisible by the" &
5550  //" total number of domain tiles in the" &
5551  //" y-dimension.")
5552  endif
5553  if (num_domain_tiles_x*num_domain_tiles_y .gt. npes) then
5554  call mpp_error(fatal, &
5555  "create_unstructured_test_restart_file:" &
5556  //" the total number of domain tiles cannot be" &
5557  //" greater than the total number of ranks.")
5558  endif
5559  if (mod(npes,num_domain_tiles_x) .ne. 0) then
5560  call mpp_error(fatal, &
5561  "create_unstructured_test_restart_file:" &
5562  //" the total number of ranks must be evenly" &
5563  //" divisible by the total number of domain" &
5564  //" tiles in the x-dimension.")
5565  endif
5566  if (mod(npes,num_domain_tiles_y) .ne. 0) then
5567  call mpp_error(fatal, &
5568  "create_unstructured_test_restart_file:" &
5569  //" the total number of ranks must be evenly" &
5570  //" divisible by the total number of domain" &
5571  //" tiles in the y-dimension.")
5572  endif
5573 
5574  !Set domain tile values for the 2D structured domain.
5575  num_domain_tiles = num_domain_tiles_x*num_domain_tiles_y
5576  npes_per_domain_tile = npes/num_domain_tiles
5577  my_domain_tile_id = (mpp_pe())/npes_per_domain_tile + 1
5578  if (mpp_pe() .eq. (my_domain_tile_id-1)*npes_per_domain_tile) then
5579  is_domain_tile_root = .true.
5580  else
5581  is_domain_tile_root = .false.
5582  endif
5583  layout_for_full_domain(1) = num_domain_tiles_x
5584  layout_for_full_domain(2) = npes/layout_for_full_domain(1)
5585 
5586  !For each 2D structured domain tile, store the beginning and ending
5587  !rank ids assigned to it. For example, if there are 8 ranks and 2
5588  !domain tiles, then tile 1 will be assigned ranks 0 - 3 and tile 2
5589  !will be assigned ranks 4 - 7.
5590  allocate(pe_start(num_domain_tiles))
5591  allocate(pe_end(num_domain_tiles))
5592  do i = 1,num_domain_tiles
5593  pe_start(i) = (i-1)*npes_per_domain_tile
5594  pe_end(i) = i*npes_per_domain_tile - 1
5595  enddo
5596 
5597  !Calculate parameters needed to construct the 2D structured domain.
5598  !All domain tiles are assumed to be the same size.
5599  x_grid_points_per_domain_tile = nx/num_domain_tiles_x
5600  y_grid_points_per_domain_tile = ny/num_domain_tiles_y
5601  allocate(global_indices(4,num_domain_tiles))
5602  do i = 1,num_domain_tiles
5603  global_indices(:,i) = (/1,x_grid_points_per_domain_tile, &
5604  1,y_grid_points_per_domain_tile/)
5605  enddo
5606  allocate(layout2d(2,num_domain_tiles))
5607  do i = 1,num_domain_tiles
5608  layout2d(1,i) = layout_for_full_domain(1)/num_domain_tiles_x
5609  layout2d(2,i) = layout_for_full_domain(2)/num_domain_tiles_y
5610  enddo
5611 
5612  !This test does not use the "contact" region between tiles, but
5613  !the 2D structured domain requires these inputs, so just set them
5614  !all equal to 1.
5615  ncontacts = 1
5616  tile1 = 1
5617  tile2 = 1
5618  istart1 = 1
5619  iend1 = 1
5620  jstart1 = 1
5621  jend1 = 1
5622  istart2 = 1
5623  iend2 = 1
5624  jstart2 = 1
5625  jend2 = 1
5626 !write (6,*)size(tile1)
5627  !Define the 2D structured domain.
5628  call mpp_define_mosaic(global_indices, &
5629  layout2d, &
5630  domain_2d, &
5631  num_domain_tiles, &
5632  0, &
5633  tile1, &
5634  tile2, &
5635  istart1, &
5636  iend1, &
5637  jstart1, &
5638  jend1, &
5639  istart2, &
5640  iend2, &
5641  jstart2, &
5642  jend2, &
5643  pe_start, &
5644  pe_end)
5645 
5646  !Define a toy mask to mimic what happens in the land model.
5647  allocate(land_mask(x_grid_points_per_domain_tile, &
5648  y_grid_points_per_domain_tile, &
5649  num_domain_tiles))
5650  allocate(num_non_masked_grid_points_per_domain_tile(num_domain_tiles))
5651  land_mask = .false.
5652  do k = 1,num_domain_tiles
5653  mask_counter = 0
5654  do j = 1,y_grid_points_per_domain_tile
5655  do i = 1,x_grid_points_per_domain_tile
5656  if (mod((k-1)*y_grid_points_per_domain_tile*x_grid_points_per_domain_tile + &
5657  (j-1)*x_grid_points_per_domain_tile + &
5658  (i-1),2) .eq. 0) then
5659  land_mask(i,j,k) = .true.
5660  mask_counter = mask_counter + 1
5661  endif
5662  enddo
5663  enddo
5664  num_non_masked_grid_points_per_domain_tile(k) = mask_counter
5665  enddo
5666 
5667  !Set the number of land tiles allowed per non-masked grid point.
5668  num_non_masked_grid_points = sum(num_non_masked_grid_points_per_domain_tile)
5669  allocate(num_land_tiles_per_non_masked_grid_point(num_non_masked_grid_points))
5670  num_land_tiles_per_non_masked_grid_point = 1
5671 
5672  !Set the number of ranks to use with the unstructured domain. There
5673  !must be at least one grid point per rank.
5674  num_ranks_using_unstructured_grid = npes
5675  if (num_ranks_using_unstructured_grid .gt. num_non_masked_grid_points) then
5676  call mpp_error(fatal, &
5677  "create_unstructured_test_restart_file:" &
5678  //" the number of ranks exceeds the number of" &
5679  //" non-masked grid points for the unstructured" &
5680  //" domain.")
5681  endif
5682 
5683  !Define an array used to map grid points from the "structured" 2D grid
5684  !to the "unstructured" 1D grid. The mapping goes as follows (fortran
5685  !ording so first index is fastest):
5686  !
5687  ! 2D "structured" grid (lon,lat,tile) => 1D "unstructured" grid (p)
5688  !
5689  !where masked points are skipped.
5690  allocate(unstructured_grid_point_index_map(num_non_masked_grid_points))
5691  p = 0
5692  do k = 1,num_domain_tiles
5693  do j = 1,y_grid_points_per_domain_tile
5694  do i = 1,x_grid_points_per_domain_tile
5695  if (land_mask(i,j,k)) then
5696  p = p + 1
5697  unstructured_grid_point_index_map(p) = (j-1)*x_grid_points_per_domain_tile + i
5698  endif
5699  enddo
5700  enddo
5701  enddo
5702  !> Set in namelist is "I/O tile factor". The number of ranks that
5703  !! participate in I/O for a tile is equal to:
5704  !!
5705  !! num_io_ranks_on_a_tile = num_ranks_on_the_tile / "I/O tile factor".
5706  !!
5707  !!so for:
5708  !!
5709  !! io_tile_factor = 1, all of the ranks on a tile participate in the I/O
5710  !! io_tile_factor = 2, 1/2 of the ranks on a tile participate in the I/O
5711  !! io_tile_factor = 3, 1/3 of the ranks on a tile participate in the I/O
5712  !! ...
5713  !! io_tile_factor = 0 is a special case where only one rank participates
5714  !! in the I/O for a tile.
5715  !! io_tile_factor = 1
5716 if (mpp_pe() == mpp_root_pe()) write(6,*) "IO_TILE_FACTOR is ",io_tile_factor
5717 allocate(unstructured_axis_diag_id(1))
5718 allocate(rsf_diag_1d_id(1))
5719 
5720  !Define the "unstructured" domain decomposition.
5721  call mpp_define_unstruct_domain(domain_ug, &
5722  domain_2d, &
5723  num_non_masked_grid_points_per_domain_tile, &
5724  num_land_tiles_per_non_masked_grid_point, &
5725  num_ranks_using_unstructured_grid, &
5726  io_tile_factor, &
5727  unstructured_grid_point_index_map)
5728 
5729 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
5730 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
5731 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
5732 !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !Don't need to modify above here! !!!!!!!!!!!!!!!!!!!!!!!!!!!!
5733 
5734  !Get the that will be registered for the unstructured axis. This should
5735  !be each rank's unstructured compute domain (I think, because a gather
5736  !is performed by the root of each I/O domain pelist.
5737  call mpp_get_ug_compute_domain(domain_ug,size=unstructured_axis_data_size)
5738  if(.not.allocated(unstructured_axis_data))allocate(unstructured_axis_data(unstructured_axis_data_size))
5739 !! THIS IS A PROBLEM !!
5740  call mpp_get_ug_domain_grid_index(domain_ug,unstructured_axis_data)
5741 !write(6,*)"ID:",mpp_pe()," DATA: ",unstructured_axis_data
5742  !Initialize the "unstructured" axis for the diagnostics.
5743  unstructured_axis_name = "ug_axis"
5744 
5745  unstructured_axis_diag_id(l) = diag_axis_init(trim(unstructured_axis_name), &
5746  real(unstructured_axis_data), &
5747  "none", &
5748  "U", &
5749  long_name="mapping indices", &
5750  domainu=domain_ug)
5751  call diag_axis_add_attribute(unstructured_axis_diag_id(l),'compress','grid_xt grid_yt')
5752 
5753 !write(6,*) "ID U",unstructured_axis_diag_id
5754  !Add the x-, y-, and z-axes to the restart file. Until a bug in
5755  !the code is resolved, I must register the unstructured axis first.
5756  !Also initialize the axes for the diagnostics.
5757  if (.not.allocated(x_axis_data)) allocate(x_axis_data(nx))
5758 ! if (.not.allocated(y_axis_data))allocate(y_axis_data(ny))
5759 !! ASSUMES 4 PEs!!!
5760 ! if (mpp_pe() > 4) call error_mesg("Diag_test_unstruct","Only 4 PEs please",fatal)
5761  do i=1,nx
5762  x_axis_data(i) = real(i)
5763  enddo
5764 ! if (mod(mpp_pe(),2).eq.0) then
5765 ! do j = 1,ny/4
5766 ! y_axis_data(j) = real(j)
5767 ! enddo
5768 !
5769 ! else
5770 ! do j = 1,ny/4
5771 ! y_axis_data(j) = real(j+ny/4)
5772 ! enddo
5773 ! endif
5774 
5775  x_axis_diag_id = diag_axis_init("grid_xt", &
5776  x_axis_data, &
5777  "degrees", &
5778  "X", &
5779  long_name="longitude")
5780 
5781  if (.not.allocated(y_axis_data))allocate(y_axis_data(ny/num_domain_tiles_y))
5782  do i = 1,ny/num_domain_tiles_y
5783  y_axis_data(i) = real(i)
5784  enddo
5785  y_axis_diag_id = diag_axis_init("grid_yt", &
5786  y_axis_data, &
5787  "degrees", &
5788  "Y", &
5789  long_name="latitude")
5790 
5791  if (.not.allocated(z_axis_data))allocate(z_axis_data(nz))
5792  do i = 1,nz
5793  z_axis_data(i) = real(i*5.0)
5794  enddo
5795  z_axis_diag_id = diag_axis_init("zfull", &
5796  z_axis_data, &
5797  "km", &
5798  "Z", &
5799  long_name="dont look down")
5800 !write (6,*) z_axis_diag_id
5801 
5802  !Define some reference test data.
5803 
5804  !real scalar field.
5805  unstructured_real_scalar_field_data_ref = 1234.5678*real(l)
5806 
5807  !real 1D field.
5808  if (.not.allocated(unstructured_real_1d_field_data_ref)) allocate(unstructured_real_1d_field_data_ref(unstructured_axis_data_size))
5809  do i = 1,unstructured_axis_data_size
5810  unstructured_real_1d_field_data_ref(i) = real(i) *real(i)+0.1*(mpp_pe()+1)
5811  enddo
5812 
5813  !real 2D field.
5814  if (.not.allocated(unstructured_real_2d_field_data_ref)) allocate(unstructured_real_2d_field_data_ref(unstructured_axis_data_size,nz))
5815  do j = 1,nz
5816  do i = 1,unstructured_axis_data_size
5817  unstructured_real_2d_field_data_ref(i,j) = real(j)+0.1*(mpp_pe()+1.0)
5818  !-1.0*real((j-1)* &
5819  !unstructured_axis_data_size+i) &
5820  !+ 1.1111111*real(l)
5821  enddo
5822  enddo
5823 
5824  !real 3D field.
5825 ! if(.not.allocated(unstructured_real_3D_field_data_ref) allocate(unstructured_real_3D_field_data_ref(unstructured_axis_data_size,nz,cc_axis_size))
5826 ! do k = 1,cc_axis_size
5827 ! do j = 1,nz
5828 ! do i = 1,unstructured_axis_data_size
5829 ! unstructured_real_3D_field_data_ref(i,j,k) = -1.0*real((k-1)*nz* &
5830 ! unstructured_axis_data_size+(j-1)* &
5831 ! unstructured_axis_data_size+i) &
5832 ! + 2.2222222
5833 ! enddo
5834 ! enddo
5835 ! enddo
5836 
5837  !integer scalar field.
5838  unstructured_int_scalar_field_data_ref = 7654321*l
5839 
5840  !integer 1D field.
5841  if (.not.allocated(unstructured_int_1d_field_data_ref)) allocate(unstructured_int_1d_field_data_ref(unstructured_axis_data_size))
5842  do i = 1,unstructured_axis_data_size
5843  unstructured_int_1d_field_data_ref(i) = i - 8*l
5844  enddo
5845 
5846  !integer 2D field.
5847  if (.not.allocated(unstructured_int_2d_field_data_ref)) allocate(unstructured_int_2d_field_data_ref(unstructured_axis_data_size,nz))
5848  do j = 1,nz
5849  do i = 1,unstructured_axis_data_size
5850  unstructured_int_2d_field_data_ref(i,j) = -1*((j-1)*unstructured_axis_data_size+i) + 2*l
5851  enddo
5852  enddo
5853 
5854  !> Latitude and Longitude
5855  allocate(lat(ny/num_domain_tiles_y),lon(nx))
5856  do i=1,nx
5857  lon(i) = real(i)*360.0/real(nx)
5858  enddo
5859  do j=1,ny/num_domain_tiles_y
5860  lat(j) = real(j)*180.8/real(ny)
5861  enddo
5862 
5863  !Add a real scalar field to the restart file. Initialize it as a
5864  !diagnostic.
5865  unstructured_real_scalar_field_name = "unstructured_real_scalar_field_1"
5866  unstructured_real_scalar_field_data = unstructured_real_scalar_field_data_ref
5867 
5868  idlon = register_diag_field("UG_unit_test", &
5869  "lon", &
5870  (/x_axis_diag_id/),&
5871  init_time=diag_time, &
5872  long_name="E-W longitude", &
5873  units="degrees")
5874 l=SIZE(unstructured_axis_diag_id)
5875 
5876  rsf_diag_id = register_diag_field("UG_unit_test", &
5877  "unstructured_real_scalar_field_data", &
5878  init_time=diag_time, &
5879  long_name="rsf_diag_1", &
5880  units="ergs")
5881  rsf_diag_1d_id(1) = register_diag_field("UG_unit_test", &
5882  "unstructured_real_1D_field_data", &
5883  (/unstructured_axis_diag_id(1)/),&
5884  init_time=diag_time, &
5885  long_name="ONE_D_ARRAY", &
5886  units="ergs")
5887 
5888  rsf_diag_2d_id = register_diag_field("UG_unit_test", &
5889  "unstructured_real_2D_field_data", &
5890  (/unstructured_axis_diag_id(1), z_axis_diag_id/),&
5891  init_time=diag_time, &
5892  long_name="TWO_D_ARRAY", &
5893  units="ergs")
5894 
5895  idlat = register_diag_field("UG_unit_test", &
5896  "lat", &
5897  (/y_axis_diag_id/),&
5898  init_time=diag_time, &
5899  long_name="S-N latitude", &
5900  units="degrees")
5901 
5902 
5903 IF (l .NE. 1) THEN
5904  do l=2,3
5905  write(unstructured_1d_alt,'(a,I0)') "unstructured_real_1D",l
5906  rsf_diag_1d_id(l) = register_diag_field("UG_unit_test", trim(unstructured_1d_alt),&
5907  (/unstructured_axis_diag_id(l)/),&
5908  init_time=diag_time, &
5909  long_name="OTHER"//trim(unstructured_1d_alt), &
5910  units="kg")
5911  enddo
5912 ENDIF !L.ne.1
5913  !Add a real 1D field to the restart file. This field is of the form:
5914  !field = field(unstructured).
5915  unstructured_real_1d_field_name = "unstructured_real_1D_field_1"
5916  if (.not.allocated(unstructured_real_1d_field_data)) allocate(unstructured_real_1d_field_data(unstructured_axis_data_size))
5917  unstructured_real_1d_field_data = unstructured_real_1d_field_data_ref
5918 
5919  !Add a real 2D field to the restart file. This field is of the form:
5920  !field = field(unstructured,z).
5921  unstructured_real_2d_field_name = "unstructured_real_2D_field_1"
5922  if (.not.allocated(unstructured_real_2d_field_data)) allocate(unstructured_real_2d_field_data(unstructured_axis_data_size,nz))
5923  unstructured_real_2d_field_data = unstructured_real_2d_field_data_ref
5924 ! allocate(unstructured_real_2D_field_data(unstructured_axis_data_size,nx))
5925 ! unstructured_real_2D_field_data = 1
5926 
5927  !Add a real 3D field to the restart file. This field is of the form:
5928  !field = field(unstructured,z,cc).
5929 ! unstructured_real_3D_field_name = "unstructured_real_3D_field_1"
5930 ! if (.not.allocated(unstructured_real_3D_field_data)) allocate(unstructured_real_3D_field_data(unstructured_axis_data_size,nz,cc_axis_size))
5931 ! unstructured_real_3D_field_data = unstructured_real_3D_field_data_ref
5932 
5933  !Add an integer scalar field to the restart file.
5934  unstructured_int_scalar_field_name = "unstructured_int_scalar_field_1"
5935  unstructured_int_scalar_field_data = unstructured_int_scalar_field_data_ref
5936 
5937  !Add an integer 1D field to the restart file. This field is of the
5938  !from: field = field(unstructured).
5939  unstructured_int_1d_field_name = "unstructured_int_1D_field_1"
5940  if (.not.allocated(unstructured_int_1d_field_data)) allocate(unstructured_int_1d_field_data(unstructured_axis_data_size))
5941  unstructured_int_1d_field_data = unstructured_int_1d_field_data_ref
5942 
5943  !Add an integer 2D field to the restart file. This field is of the
5944  !form: field = field(unstructured,z).
5945  unstructured_int_2d_field_name = "unstructured_int_2D_field_1"
5946  if (.not.allocated(unstructured_int_2d_field_data)) allocate(unstructured_int_2d_field_data(unstructured_axis_data_size,nz))
5947  unstructured_int_2d_field_data = unstructured_int_2d_field_data_ref
5948 
5949  !Simulate the model timesteps, so that diagnostics may be written
5950  !out.
5951  num_diag_time_steps = 4
5952  diag_time_step = set_time(12*3600)
5953  diag_time_start = diag_time
5954 ! used = send_data(idlat,lat,diag_time)
5955 ! used = send_data(idlon,lon,diag_time)
5956  do i = 1,num_diag_time_steps
5957 
5958  !Update the current time.
5959  diag_time = diag_time + diag_time_step
5960 
5961  !"Evolve" the test data.
5962  unstructured_real_scalar_field_data_ref = unstructured_real_scalar_field_data_ref + &
5963  real(1)
5964  unstructured_real_scalar_field_data = unstructured_real_scalar_field_data_ref
5965 
5966  !Update the data.
5967  if (rsf_diag_id .gt. 0) then
5968  used = send_data(rsf_diag_id, &
5969  unstructured_real_scalar_field_data, &
5970  diag_time)
5971  endif
5972  IF (SIZE(rsf_diag_1d_id) == 1) THEN
5973  used = send_data(rsf_diag_1d_id(1), &
5974  unstructured_real_1d_field_data, &
5975  diag_time)
5976  ELSE
5977  DO l=1,3
5978  used = send_data(rsf_diag_1d_id(l), &
5979  unstructured_real_1d_field_data, &
5980  diag_time)
5981  ENDDO
5982  ENDIF
5983  used = send_data(rsf_diag_2d_id, &
5984  unstructured_real_2d_field_data, &
5985  diag_time)
5986  used = send_data(idlat,lat,diag_time)
5987  used = send_data(idlon,lon,diag_time)
5988 
5989  enddo
5990  !Deallocate the unstructured domain.
5991  call mpp_sync()
5992 ! call mpp_deallocate_domainUG(domain_ug)
5993 
5994  !Deallocate the 2D structured domain.
5995  call mpp_deallocate_domain(domain_2d)
5996 
5997  !Deallocate local allocatables.
5998  deallocate(pe_start)
5999  deallocate(pe_end)
6000  deallocate(global_indices)
6001  deallocate(layout2d)
6002  deallocate(land_mask)
6003  deallocate(num_non_masked_grid_points_per_domain_tile)
6004  deallocate(num_land_tiles_per_non_masked_grid_point)
6005  deallocate(unstructured_grid_point_index_map)
6006  deallocate(x_axis_data)
6007  deallocate(y_axis_data)
6008  deallocate(z_axis_data)
6009  deallocate(unstructured_axis_data)
6010  deallocate(unstructured_real_1d_field_data_ref)
6011  deallocate(unstructured_real_2d_field_data_ref)
6012 ! deallocate(unstructured_real_3D_field_data_ref)
6013  deallocate(unstructured_int_1d_field_data_ref)
6014  deallocate(unstructured_int_2d_field_data_ref)
6015  deallocate(unstructured_real_1d_field_data)
6016  deallocate(unstructured_real_2d_field_data)
6017 ! deallocate(unstructured_real_3D_field_data)
6018  deallocate(unstructured_int_1d_field_data)
6019  deallocate(unstructured_int_2d_field_data)
6020 
6021 
6022 
6023  !Print out a message that the test is done.
6024  call mpp_sync()
6025  if (mpp_pe() .eq. mpp_root_pe()) then
6026  write(output_unit,*)
6027  write(output_unit,*) "Test create_unstructured_test_restart_file" &
6028  //" complete."
6029  write(output_unit,*) "----------------------------------------/>"
6030  write(output_unit,*)
6031  endif
6032 
6033 
6034  return
6035  END SUBROUTINE unstruct_test
6036 
6037 END PROGRAM test
6038 #endif
subroutine diag_field_add_attribute_scalar_c(diag_field_id, att_name, att_value)
Definition: fms.F90:20
integer(int_kind), parameter, public diag_axis_2ddomain
Definition: diag_axis.F90:67
subroutine, public get_subfield_vert_size(axes, outnum)
Definition: diag_util.F90:465
subroutine, public get_date(time, year, month, day, hour, minute, second, tick, err_msg)
real, parameter cmor_missing_value
CMOR standard missing value.
Definition: diag_data.F90:110
integer function, public get_ticks_per_second()
integer function, public get_tile_count(ids)
Definition: diag_axis.F90:799
logical write_manifest_file
Indicates if the manifest file should be written. If writing many regional files, then the terminatio...
Definition: diag_data.F90:735
integer, parameter every_time
Definition: diag_data.F90:103
character(len=256) global_descriptor
Definition: diag_data.F90:774
integer base_year
Definition: diag_data.F90:773
integer, parameter, public gregorian
integer num_output_fields
Definition: diag_data.F90:649
real, parameter, public rad_to_deg
Degrees per radian [deg/rad].
Definition: constants.F90:119
integer function, public find_input_field(module_name, field_name, tile_count)
Definition: diag_util.F90:1395
subroutine diag_field_add_attribute_scalar_r(diag_field_id, att_name, att_value)
integer, parameter, public noleap
integer, parameter diag_seconds
Definition: diag_data.F90:105
subroutine unstruct_test(nx, ny, nz, npes, num_domain_tiles_x, num_domain_tiles_y, diag_time, io_tile_factor)
subroutine diag_data_init()
Definition: diag_data.F90:816
integer max_field_attributes
Maximum number of user definable attributes per field. Liptak: Changed from 2 to 4 20170718...
Definition: diag_data.F90:731
integer base_month
Definition: diag_data.F90:773
integer(int_kind), parameter, public diag_axis_ugdomain
Definition: diag_axis.F90:68
integer num_files
Definition: diag_data.F90:647
subroutine diag_field_attribute_init(diag_field_id, name, type, cval, ival, rval)
integer max_axis_attributes
Maximum number of user definable attributes per axis.
Definition: diag_data.F90:733
logical function send_tile_averaged_data1d(id, field, area, time, mask)
subroutine, public diag_grid_init(domain, glo_lat, glo_lon, aglo_lat, aglo_lon)
Definition: diag_grid.F90:229
integer max_out_per_in_field
Maximum number of output_fields per input_field. Increase via diag_manager_nml.
Definition: diag_data.F90:714
subroutine, public diag_util_init()
Definition: diag_util.F90:152
real function, public get_date_dif(t2, t1, units)
Definition: diag_util.F90:2357
character(len=10), dimension(6) time_unit_list
Definition: diag_data.F90:798
type(time_type) base_time
Definition: diag_data.F90:772
character(len=32) pelist_name
Definition: diag_data.F90:800
subroutine, public update_bounds(out_num, lower_i, upper_i, lower_j, upper_j, lower_k, upper_k)
Definition: diag_util.F90:813
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)
integer function init_diurnal_axis(n_samples)
integer base_day
Definition: diag_data.F90:773
integer function, public get_diag_field_id(module_name, field_name)
integer, parameter end_of_run
Definition: diag_data.F90:104
subroutine diag_field_add_attribute_i1d(diag_field_id, att_name, att_value)
subroutine, public check_bounds_are_exact_dynamic(out_num, diag_field_id, Time, err_msg)
Definition: diag_util.F90:920
type(time_type) function, public get_base_time()
integer max_file_attributes
Maximum number of user definable global attributes per file.
Definition: diag_data.F90:732
logical function, public fms_error_handler(routine, message, err_msg)
Definition: fms.F90:573
logical function get_related_field(field, rel_field, out_field_id, out_file_id)
subroutine, public diag_manager_end(time)
integer, parameter diag_field_not_found
Definition: diag_data.F90:111
logical function send_data_1d(diag_field_id, field, time, is_in, mask, rmask, ie_in, weight, err_msg)
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:719
logical function send_data_0d(diag_field_id, field, time, err_msg)
subroutine closing_file(file, time)
subroutine, public write_static(file)
Definition: diag_util.F90:2555
subroutine, public diag_manager_set_time_end(Time_end_in)
integer function writing_field(out_num, at_diag_end, error_string, time)
type(output_field_type), dimension(:), allocatable output_fields
Definition: diag_data.F90:782
logical write_bytes_in_file
Definition: diag_data.F90:717
integer base_second
Definition: diag_data.F90:773
Definition: mpp.F90:39
subroutine, public diag_grid_end()
Definition: diag_grid.F90:400
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
integer, parameter diag_ocean
Definition: diag_data.F90:99
subroutine add_associated_files(file_num, cm_file_num, cm_ind)
Add to the associated files attribute.
subroutine, public init_output_field(module_name, field_name, output_name, output_file, time_method, pack, tile_count, local_coord)
Definition: diag_util.F90:1478
subroutine average_tiles1d(diag_field_id, x, area, mask, out)
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
subroutine, public check_out_of_bounds(out_num, diag_field_id, err_msg)
Definition: diag_util.F90:849
logical function send_data_2d(diag_field_id, field, time, is_in, js_in, mask, rmask, ie_in, je_in, weight, err_msg)
subroutine, public set_diag_global_att(component, gridType, tileName)
type(time_type) diag_init_time
Definition: diag_data.F90:771
subroutine, public set_calendar_type(type, err_msg)
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)
subroutine, public set_filename_appendix(string_in)
Definition: fms_io.F90:8366
subroutine, public get_diag_global_att(gAtt)
real, parameter, public pi
Ratio of circle circumference to diameter [N/A].
Definition: constants.F90:74
type(file_type), dimension(:), allocatable, save files
Definition: diag_data.F90:780
logical append_pelist_name
Definition: diag_data.F90:709
integer, parameter diag_hours
Definition: diag_data.F90:105
subroutine, public fms_init(localcomm)
Definition: fms.F90:353
integer max_num_axis_sets
Definition: diag_data.F90:725
logical oor_warnings_fatal
Definition: diag_data.F90:728
subroutine, public sync_file_times(file_id, init_time, err_msg)
Definition: diag_util.F90:1239
logical use_cmor
Definition: diag_data.F90:726
subroutine, public diag_manager_init(diag_model_subset, time_init, err_msg)
integer null_axis_id
Definition: diag_data.F90:650
subroutine, public fms_io_init()
Definition: fms_io.F90:638
integer max_axes
Maximum number of independent axes.
Definition: diag_data.F90:715
integer function, public days_in_month(Time, err_msg)
subroutine, public diag_send_complete_instant(time)
The subroutine &#39;diag_send_complete_instant&#39; allows the user to save diagnostic data on variable inter...
subroutine, public write_diag_manifest(file)
Public routine that will start the writing of the manifest file.
integer, parameter, public julian
type(input_field_type), dimension(:), allocatable input_fields
Definition: diag_data.F90:781
integer, parameter diag_minutes
Definition: diag_data.F90:105
integer, parameter, public thirty_day_months
integer function, public diag_axis_init(name, DATA, units, cart_name, long_name, direction, set_name, edges, Domain, Domain2, DomainU, aux, req, tile_count)
Definition: diag_axis.F90:157
logical function, public need_data(diag_field_id, next_model_time)
integer function, public get_axis_length(id)
Definition: diag_axis.F90:712
integer oor_warning
Definition: diag_data.F90:801
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 diag_field_add_attribute_scalar_i(diag_field_id, att_name, att_value)
logical module_is_initialized
Definition: diag_data.F90:796
logical function send_data_2d_r8(diag_field_id, field, time, is_in, js_in, mask, rmask, ie_in, je_in, weight, err_msg)
subroutine, public log_diag_field_info(module_name, field_name, axes, long_name, units, missing_value, range, dynamic)
Definition: diag_util.F90:716
integer max_files
Maximum number of output files allowed. Increase via diag_manager_nml.
Definition: diag_data.F90:711
subroutine diag_field_add_attribute_r1d(diag_field_id, att_name, att_value)
subroutine, public get_base_date(year, month, day, hour, minute, second)
integer max_output_fields
Maximum number of output fields. Increase via diag_manager_nml.
Definition: diag_data.F90:712
integer, parameter diag_years
Definition: diag_data.F90:106
integer pack_size
Definition: diag_data.F90:749
type(time_type) function, public diag_time_inc(time, output_freq, output_units, err_msg)
Definition: diag_util.F90:1285
type(time_type) time_end
type(domain2d) function, public get_domain2d(ids)
Definition: diag_axis.F90:860
subroutine, public check_bounds_are_exact_static(out_num, diag_field_id, err_msg)
Definition: diag_util.F90:993
logical function send_tile_averaged_data2d(id, field, area, time, mask)
subroutine, public fms_end()
Definition: fms.F90:476
subroutine, public fms_io_exit()
Definition: fms_io.F90:750
subroutine, public get_subfield_size(axes, outnum)
Definition: diag_util.F90:175
integer, parameter diag_other
Definition: diag_data.F90:98
type(time_type) function, public decrement_date(Time, years, months, days, hours, minutes, seconds, ticks, err_msg, allow_neg_inc)
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
logical first_send_data_call
Definition: diag_data.F90:795
#define max(a, b)
Definition: mosaic_util.h:33
integer base_hour
Definition: diag_data.F90:773
integer, parameter, public fatal
subroutine, public init_input_field(module_name, field_name, tile_count)
Definition: diag_util.F90:1426
logical do_diag_field_log
Definition: diag_data.F90:716
logical mix_snapshot_average_fields
Definition: diag_data.F90:710
logical prepend_date
Should the history file have the start date prepended to the file name.
Definition: diag_data.F90:734
integer(int_kind) function, public axis_compatible_check(id, varname)
Definition: diag_axis.F90:918
subroutine compute_grid(nlon, nlat, is, ie, js, je, lon_global, lat_global, lonb_global, latb_global, lon, lat, lonb, latb)
If the test_number == 100, then call the unstrcutured grid unit test and skip everything else...
integer diag_log_unit
Definition: diag_data.F90:797
integer max_input_fields
Maximum number of input fields. Increase via diag_manager_nml.
Definition: diag_data.F90:713
type(time_type) time_zero
Definition: diag_data.F90:794
subroutine, public diag_send_complete(time_step, err_msg)
subroutine, public get_instance_filename(name_in, name_out)
Definition: fms_io.F90:8379
subroutine init_field_cell_measures(output_field, area, volume, err_msg)
subroutine, public diag_field_add_cell_measures(diag_field_id, area, volume)
logical region_out_use_alt_value
Definition: diag_data.F90:729
integer, parameter diag_days
Definition: diag_data.F90:106
integer function, public get_axis_num(axis_name, set_name)
Definition: diag_axis.F90:1048
integer, parameter diag_all
Definition: diag_data.F90:100
subroutine, public parse_diag_table(diag_subset, istat, err_msg)
Definition: diag_table.F90:355
real, parameter, public seconds_per_day
Seconds in a day [s].
Definition: constants.F90:116
logical issue_oor_warnings
Definition: diag_data.F90:727
subroutine, public get_time(Time, seconds, days, ticks, err_msg)
subroutine, public error_mesg(routine, message, level)
Definition: fms.F90:529
logical debug_diag_manager
Definition: diag_data.F90:718
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)
logical function send_data_3d_r8(diag_field_id, field, time, is_in, js_in, ks_in, mask, rmask, ie_in, je_in, ke_in, weight, err_msg)
diag_manifest_mod writes out a manifest file for each diagnostic output file defined in the diag_tabl...
subroutine, public constants_init
dummy routine.
Definition: constants.F90:141
integer, parameter diag_months
Definition: diag_data.F90:106
integer base_minute
Definition: diag_data.F90:773
subroutine, public diag_data_out(file, field, dat, time, final_call_in, static_write_in)
Definition: diag_util.F90:2418
logical function send_tile_averaged_data3d(id, field, area, time, mask)
subroutine average_tiles(diag_field_id, x, area, mask, out)