-
Notifications
You must be signed in to change notification settings - Fork 141
/
Copy pathdiag_manager.F90
4624 lines (4305 loc) · 228 KB
/
diag_manager.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS is distributed in the hope that it will be useful, but WITHOUT
!* ANY WARRANTY; 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 not, see <http://www.gnu.org/licenses/>.
!***********************************************************************
!> @defgroup diag_manager_mod diag_manager_mod
!> @ingroup diag_manager
!! @brief diag_manager_mod is a set of simple calls for parallel diagnostics
!! on distributed systems. It is geared toward the writing of data in netCDF
!! format. See @ref diag_manager for diag table information.
!! @author Matt Harrison, Giang Nong, Seth Underwood
!!
!! <TT>diag_manager_mod</TT> provides a convenient set of interfaces for
!! writing data to disk. It is built upon the parallel I/O interface of FMS
!! code <TT>/shared/mpp/mpp_io.F90</TT>.
!!
!! A single group of calls to the <TT>diag_manager_mod</TT> interfaces
!! provides data to disk at any number of sampling and/or averaging intervals
!! specified at run-time. Run-time specification of diagnostics are input
!! through the diagnostics table.
!!
!! <H4>Usage</H4>
!! Use of <TT>diag_manager</TT> includes the following steps:
!! <OL>
!! <LI> Create diag_table as described in the @ref diag_table_mod
!! documentation.</LI>
!! <LI> Call @ref diag_manager_init to initialize
!! diag_manager_mod.</LI>
!! <LI> Call @ref register_diag_field to register the field to be
!! output.
!! <B>NOTE:</B> ALL fields in diag_table should be registered <I>BEFORE</I>
!! the first send_data call</LI>
!! <LI> Call @ref send_data to send data to output fields </LI>
!! <LI> Call @ref diag_manager_end to exit diag_manager </LI>
!! </OL>
!!
!! <H4>Features</H4>
!! Features of <TT>diag_manager_mod</TT>:
!! <OL>
!! <LI> Ability to output from 0D arrays (scalars) to 3D arrays.</LI>
!! <LI> Ability to output time average of fields that have time dependent
!! mask.</LI>
!! <LI> Give optional warning if <TT>register_diag_field</TT> fails due to
!! misspelled module name or field name.</LI>
!! <LI> Check if a field is registered twice.</LI>
!! <LI> Check for duplicate lines in diag_table. </LI>
!! <LI> @ref diag_table_mod can contain fields
!! that are NOT written to any files. The file name in diag_table of
!! these fields is <TT>null</TT>.</LI>
!! <LI> By default, a field is output in its global grid. The user can now
!! output a field in a specified region. See
!! @ref send_data for more details.</LI>
!! <LI> To check if the diag table is set up correctly, user should set
!! <TT>debug_diag_manager=.true.</TT> in diag_manager namelist, then
!! the the content of diag_table is printed in stdout.</LI>
!! <LI> New optional format of file information in @ref diag_table_mod.
!! It is possible to have just
!! 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 opened. The time string can be
!! any combination from year to second of current model time.
!!
!! Here is an example file line: <BR />
!! <PRE>"file2_yr_dy%1yr%3dy",2,"hours",1,"hours","Time", 10, "days", "1 1 7 0 0 0", 6, "hours"</PRE>
!! <BR />
!!
!! From left to right we have:
!! <UL>
!! <LI>file name</LI>
!! <LI>output frequency</LI>
!! <LI>output frequency unit</LI>
!! <LI>Format (should always be 1)</LI>
!! <LI>time axis unit</LI>
!! <LI>time axis name</LI>
!! <LI>frequency for creating new file</LI>
!! <LI>unit for creating new file</LI>
!! <LI>start time of the new file</LI>
!! <LI>file duration</LI>
!! <LI>file duration unit.</LI>
!! </UL>
!! The 'file duration', if absent, will be equal to frequency for creating a new file.
!!
!! Thus, the above means: create a new file every 10 days, each file will last 6 hours
!! from creation time, no files will
!! be created before time "1 1 7 0 0 0".
!!
!! In this example the string
!! <TT>10, "days", "1 1 7 0 0 0", 6, "hours"</TT> is optional.
!!
!! Keywords for the time string suffix is
!! <TT>%xyr,%xmo,%xdy,%xhr,%xmi,%xsc</TT> where <TT>x</TT> is a
!! mandatory 1 digit number specifying the width of field used in
!! writing the string</LI>
!! <LI> New time axis for time averaged fields. Users can use a namelist option to handle the time value written
!! to time axis for time averaged fields.
!!
!! If <TT>mix_snapshot_average_fields=.true.</TT> then a time averaged file will have
!! time values corresponding to
!! ending time_bound e.g. January monthly average is labeled Feb01. Users can have
!! both snapshot and averaged fields in
!! one file.
!!
!! If <TT>mix_snapshot_average_fields=.false.</TT> The time value written to time
!! axis for time averaged fields is the
!! middle on the averaging time. For example, January monthly mean will be written at Jan 16 not Feb 01 as
!! before. However, to use this new feature users should <B>separate</B> snapshot
!! fields and time averaged fields in
!! <B>different</B> files or a fatal error will occur.
!!
!! The namelist <B>default</B> value is <TT>mix_snapshot_average_fields=.false.</TT></LI>
!! <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
!! during the same interval of time as time average. For this purpose, in the diag table users must replace
!! <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
!! and min are not available for regional output.
!!
!! A diurnal average or the average of an integer power can also be requested using
!! <TT>diurnal##</TT> or <TT>pow##</TT> where
!! <TT>##</TT> are the number of diurnal sections or integer power to average.</LI>
!! <LI> <TT>standard_name</TT> is added as optional argument in @ref register_diag_field. </LI>
!! <LI>When namelist variable <TT>debug_diag_manager = .true.</TT> array
!! bounds are checked in @ref send_data.</LI>
!! <LI>Coordinate attributes can be written in the output file if the
!! argument "aux" is given in @ref diag_axis_mod#diag_axis_init . The
!! corresponding fields (geolat/geolon) should also be written to the
!! same file.</LI>
!! </OL>
!> @file
!> @ingroup diag_manager_mod
!> @brief File for @ref diag_manager_mod
MODULE diag_manager_mod
use platform_mod
! <NAMELIST NAME="diag_manager_nml">
! <DATA NAME="append_pelist_name" TYPE="LOGICAL" DEFAULT=".FALSE.">
! </DATA>
! <DATA NAME="mix_snapshot_average_fields" TYPE="LOGICAL" DEFAULT=".FALSE.">
! Set to .TRUE. to allow both time average and instantaneous fields in the same output file.
! </DATA>
! <DATA NAME="max_files" TYPE="INTEGER" DEFULT="31">
! </DATA>
! <DATA NAME="max_output_fields" TYPE="INTEGER" DEFAULT="300">
! </DATA>
! <DATA NAME="max_input_fields" TYPE="INTEGER" DEFAULT="300">
! </DATA>
! <DATA NAME="max_axes" TYPE="INTEGER" DEFAULT="60">
! </DATA>
! <DATA NAME="do_diag_field_log" TYPE="LOGICAL" DEFAULT=".FALSE.">
! </DATA>
! <DATA NAME="write_bytes_in_files" TYPE="LOGICAL" DEFAULT=".FALSE.">
! </DATA>
! <DATA NAME="debug_diag_manager" TYPE="LOGICAL" DEFAULT=".FALSE.">
! </DATA>
! <DATA NAME="max_num_axis_sets" TYPE="INTEGER" DEFAULT="25">
! </DATA>
! <DATA NAME="use_cmor" TYPE="LOGICAL" DEFAULT=".FALSE.">
! Let the <TT>diag_manager</TT> know if the missing value (if supplied) should be overridden to be the
! CMOR standard value of -1.0e20.
! </DATA>
! <DATA NAME="issue_oor_warnings" TYPE="LOGICAL" DEFAULT=".TRUE.">
! If <TT>.TRUE.</TT>, then the <TT>diag_manager</TT> will check for values outside the
! valid range. This range is defined in
! the model, and passed to the <TT>diag_manager_mod</TT> via the OPTIONAL variable range
! in the <TT>register_diag_field</TT>
! function.
! </DATA>
! <DATA NAME="oor_warnings_fatal" TYPE="LOGICAL" DEFAULT=".FALSE.">
! 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
! outside the given range.
! </DATA>
! <DATA NAME="max_field_attributes" TYPE="INTEGER" DEFAULT="4">
! Maximum number of user definable attributes per field.
! </DATA>
! <DATA NAME="max_file_attributes" TYPE="INTEGER" DEFAULT="2">
! Maximum number of user definable global attributes per file.
! </DATA>
! <DATA NAME="prepend_date" TYPE="LOGICAL" DEFAULT=".TRUE.">
! If <TT>.TRUE.</TT> then prepend the file start date to the output file. <TT>.TRUE.</TT>
! is only supported if the
! diag_manager_init routine is called with the optional time_init parameter. Note:
! This was usually done by FRE after the
! model run.
! </DATA>
! <DATA NAME="region_out_use_alt_value" TYPE="LOGICAL" DEFAULT=".TRUE.">
! Will determine which value to use when checking a regional output if the region is the full axis or a sub-axis.
! 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>.
! </DATA>
! <DATA NAME="use_mpp_io" TYPE="LOGICAL" DEFAULT=".false.">
! Set to true, diag_manager uses mpp_io. Default is fms2_io.
! </DATA>
! </NAMELIST>
USE time_manager_mod, ONLY: set_time, set_date, get_time, time_type, OPERATOR(>=), OPERATOR(>),&
& OPERATOR(<), OPERATOR(==), OPERATOR(/=), OPERATOR(/), OPERATOR(+), ASSIGNMENT(=), get_date, &
& get_ticks_per_second
USE mpp_mod, ONLY: mpp_get_current_pelist, mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
USE mpp_mod, ONLY: input_nml_file, mpp_error
USE fms_mod, ONLY: error_mesg, FATAL, WARNING, NOTE, stdout, stdlog, write_version_number,&
& fms_error_handler, check_nml_error, lowercase
USE diag_axis_mod, ONLY: diag_axis_init, get_axis_length, get_axis_num, get_domain2d, get_tile_count,&
& diag_axis_add_attribute, axis_compatible_check, CENTER, NORTH, EAST, get_diag_axis_name
USE diag_util_mod, ONLY: get_subfield_size, log_diag_field_info, update_bounds,&
& check_out_of_bounds, check_bounds_are_exact_dynamic, check_bounds_are_exact_static,&
& diag_time_inc, find_input_field, init_input_field, init_output_field,&
& diag_data_out, write_static, get_date_dif, get_subfield_vert_size, sync_file_times,&
& prepend_attribute, attribute_init, diag_util_init, field_log_separator, &
& get_file_start_time
USE diag_data_mod, ONLY: max_files, CMOR_MISSING_VALUE, DIAG_OTHER, DIAG_OCEAN, DIAG_ALL, EVERY_TIME,&
& END_OF_RUN, DIAG_SECONDS, DIAG_MINUTES, DIAG_HOURS, DIAG_DAYS, DIAG_MONTHS, DIAG_YEARS, num_files,&
& max_input_fields, max_output_fields, num_output_fields, EMPTY, FILL_VALUE, null_axis_id,&
& MAX_VALUE, MIN_VALUE, get_base_time, get_base_year, get_base_month, get_base_day,&
& get_base_hour, get_base_minute, get_base_second, global_descriptor, coord_type, files, input_fields,&
& output_fields, Time_zero, append_pelist_name, mix_snapshot_average_fields,&
& first_send_data_call, do_diag_field_log, write_bytes_in_file, debug_diag_manager,&
& diag_log_unit, time_unit_list, pelist_name, max_axes, module_is_initialized, max_num_axis_sets,&
& use_cmor, issue_oor_warnings, oor_warnings_fatal, oor_warning, pack_size,&
& max_out_per_in_field, flush_nc_files, region_out_use_alt_value, max_field_attributes, output_field_type,&
& max_file_attributes, max_axis_attributes, prepend_date, DIAG_FIELD_NOT_FOUND, diag_init_time, diag_data_init,&
& use_mpp_io, use_refactored_send, &
& use_modern_diag, use_clock_average, diag_null, pack_size_str
USE diag_data_mod, ONLY: fileobj, fileobjU, fnum_for_domain, fileobjND
USE diag_table_mod, ONLY: parse_diag_table
USE diag_output_mod, ONLY: get_diag_global_att, set_diag_global_att
USE diag_grid_mod, ONLY: diag_grid_init, diag_grid_end
use fms_diag_object_mod, only:fms_diag_object
USE constants_mod, ONLY: SECONDS_PER_DAY
USE fms_diag_outfield_mod, ONLY: fmsDiagOutfieldIndex_type, fmsDiagOutfield_type
USE fms_diag_fieldbuff_update_mod, ONLY: fieldbuff_update, fieldbuff_copy_missvals, &
& fieldbuff_copy_fieldvals
USE netcdf, ONLY: NF90_INT, NF90_FLOAT, NF90_CHAR
!----------
!ug support
use diag_axis_mod, only: DIAG_AXIS_2DDOMAIN
use diag_axis_mod, only: DIAG_AXIS_UGDOMAIN
!----------
IMPLICIT NONE
PRIVATE
PUBLIC :: diag_manager_init, send_data, send_tile_averaged_data, diag_manager_end,&
& register_diag_field, register_static_field, diag_axis_init, get_base_time, get_base_date,&
& need_data, DIAG_ALL, DIAG_OCEAN, DIAG_OTHER, get_date_dif, DIAG_SECONDS,&
& DIAG_MINUTES, DIAG_HOURS, DIAG_DAYS, DIAG_MONTHS, DIAG_YEARS, get_diag_global_att,&
& set_diag_global_att, diag_field_add_attribute, diag_field_add_cell_measures,&
& get_diag_field_id, diag_axis_add_attribute, CMOR_MISSING_VALUE, null_axis_id
PUBLIC :: CENTER, NORTH, EAST !< Used for diag_axis_init
! Public interfaces from diag_grid_mod
PUBLIC :: diag_grid_init, diag_grid_end
PUBLIC :: diag_manager_set_time_end, diag_send_complete
PUBLIC :: diag_send_complete_instant
! Public interfaces from diag_data_mod
PUBLIC :: DIAG_FIELD_NOT_FOUND
! version number of this module
! Include variable "version" to be written to log file.
#include<file_version.h>
type(time_type) :: Time_end
!> @brief Send data over to output fields.
!!
!> <TT>send_data</TT> is overloaded for fields having zero dimension
!! (scalars) to 3 dimension. <TT>diag_field_id</TT> corresponds to the id
!! returned from a previous call to <TT>register_diag_field</TT>. The field
!! array is restricted to the computational range of the array. Optional
!! argument <TT>is_in</TT> can be used to update sub-arrays of the entire
!! field. Additionally, an optional logical or real mask can be used to
!! apply missing values to the array.
!!
!! If a field is declared to be <TT>mask_variant</TT> in
!! <TT>register_diag_field</TT> logical mask should be mandatory.
!!
!! For the real mask, the mask is applied if the mask value is less than
!! 0.5.
!!
!! By default, a field will be written out entirely in its global grid.
!! Users can also specify regions in which the field will be output. The
!! region is specified in diag-table just before the end of output_field
!! replacing "none".
!!
!! For example, by default:
!!
!! "ocean_mod","Vorticity","vorticity","file1","all",.false.,"none",2
!!
!! for regional output:
!!
!! "ocean_mod","Vorticity","vorticity_local","file2","all",.false.,"0.5 53.5 -89.5 -28.5 -1 -1",2
!!
!! The format of a region is "<TT>xbegin xend ybegin yend zbegin zend</TT>".
!! If it is a 2D field use (-1 -1) for (zbegin zend) as in the example above.
!! For a 3D field use (-1 -1) for (zbegin zend) when you want to write the
!! entire vertical extent, otherwise specify real coordinates. The units
!! used for region are the actual units used in grid_spec.nc (for example
!! degrees for lat, lon). <B><I>NOTE:</I></B> A FATAL error will occur if
!! the region's boundaries are not found in grid_spec.nc.
!!
!! Regional output on the cubed sphere grid is also supported. To use regional
!! output on the cubed sphere grid, first the grid information needs to be sent to
!! <TT>diag_manager_mod</TT> using the @ref diag_grid#diag_grid_init subroutine.
!!
!! @note When using regional output the files containing regional
!! outputs should be different from files containing global (default) output.
!! It is a FATAL error to have one file containing both regional and global
!! results. For maximum flexibility and independence from PE counts one file
!! should contain just one region.
!!
!!
!! Time averaging is supported in regional output.
!!
!! Physical fields (written in "physics windows" of atmospheric code) are
!! fully supported for regional outputs.
!!
!! <B><I>NOTE:</I></B> Most fields are defined in the data domain but use the
!! compute domain. In <TT>send_data</TT> the field can be passed in either
!! the data domain or in the compute domain. If the data domain is used, the
!! start and end indicies of the compute domain (isc, iec, . . .) should be
!! passed. If the compute domain is used no indices are needed. The indices
!! are for determining halo exclusively. If users want to output the field
!! partially they should use regional output as mentioned above.
!!
!! Weight in Time averaging is now supported, each time level may have a
!! different weight. The default of weight is 1.
!> @ingroup diag_manager_mod
INTERFACE send_data
MODULE PROCEDURE send_data_0d
MODULE PROCEDURE send_data_1d
MODULE PROCEDURE send_data_2d
MODULE PROCEDURE send_data_3d
MODULE PROCEDURE send_data_4d
END INTERFACE
!> @brief Register a diagnostic field for a given module
!> @ingroup diag_manager_mod
INTERFACE register_diag_field
MODULE PROCEDURE register_diag_field_scalar
MODULE PROCEDURE register_diag_field_array
END INTERFACE
!> @brief Send tile-averaged data over to output fields.
!> @ingroup diag_manager_mod
INTERFACE send_tile_averaged_data
MODULE PROCEDURE send_tile_averaged_data1d
MODULE PROCEDURE send_tile_averaged_data2d
MODULE PROCEDURE send_tile_averaged_data3d
END INTERFACE
!> @brief Add a attribute to the output field
!> @ingroup diag_manager_mod
INTERFACE diag_field_add_attribute
MODULE PROCEDURE diag_field_add_attribute_scalar_r
MODULE PROCEDURE diag_field_add_attribute_scalar_i
MODULE PROCEDURE diag_field_add_attribute_scalar_c
MODULE PROCEDURE diag_field_add_attribute_r1d
MODULE PROCEDURE diag_field_add_attribute_i1d
END INTERFACE diag_field_add_attribute
!> @addtogroup diag_manager_mod
!> @{
CONTAINS
!> @brief Registers a scalar field
!! @return field index for subsequent call to send_data.
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)
CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from
CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from
CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file
CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute
CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute
LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged
CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call
INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
! Fatal error if range is present and its extent is not 2.
IF ( PRESENT(range) ) THEN
IF ( SIZE(range) .NE. 2 ) THEN
! <ERROR STATUS="FATAL">extent of range should be 2</ERROR>
CALL error_mesg ('diag_manager_mod::register_diag_field', 'extent of range should be 2', FATAL)
END IF
END IF
if (use_modern_diag) then
if( do_diag_field_log) then
if ( PRESENT(do_not_log) ) THEN
if(.not. do_not_log) call log_diag_field_info(module_name, field_name, (/NULL_AXIS_ID/), long_name,&
& units, missing_value, range, dynamic=.true.)
else
call log_diag_field_info(module_name, field_name, (/NULL_AXIS_ID/), long_name, units,&
& missing_value, range, dynamic=.true.)
endif
endif
register_diag_field_scalar = fms_diag_object%fms_register_diag_field_scalar( &
& module_name, field_name, init_time, long_name=long_name, units=units, &
& missing_value=missing_value, var_range=range, standard_name=standard_name, &
& do_not_log=do_not_log, err_msg=err_msg, area=area, volume=volume, realm=realm)
else
register_diag_field_scalar = register_diag_field_scalar_old(module_name, field_name, init_time, &
& long_name=long_name, units=units, missing_value=missing_value, range=range, standard_name=standard_name, &
& do_not_log=do_not_log, err_msg=err_msg, area=area, volume=volume, realm=realm)
endif
end function register_diag_field_scalar
!> @brief Registers an array field
!> @return field index for subsequent call to send_data.
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)
CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from
CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
INTEGER, INTENT(in) :: axes(:) !< Ids corresponding to the variable axis
TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from
CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute
CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute
CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute
LOGICAL, OPTIONAL, INTENT(in) :: mask_variant !< Mask variant
CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file
LOGICAL, OPTIONAL, INTENT(in) :: verbose !< Print more information
LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged
CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call
CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
!! regridding the field in post-processing.
!! Valid options are "conserve_order1",
!! "conserve_order2", and "none".
INTEGER, OPTIONAL, INTENT(in) :: tile_count !< The current tile number
INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
if (use_modern_diag) then
if( do_diag_field_log) then
if ( PRESENT(do_not_log) ) THEN
if(.not. do_not_log) call log_diag_field_info(module_name, field_name, axes, long_name,&
& units, missing_value, range, dynamic=.true.)
else
call log_diag_field_info(module_name, field_name, axes, long_name, units,&
& missing_value, range, dynamic=.true.)
endif
endif
register_diag_field_array = fms_diag_object%fms_register_diag_field_array( &
& module_name, field_name, axes, init_time, long_name=long_name, &
& units=units, missing_value=missing_value, var_range=range, mask_variant=mask_variant, &
& standard_name=standard_name, verbose=verbose, do_not_log=do_not_log, err_msg=err_msg, &
& interp_method=interp_method, tile_count=tile_count, area=area, volume=volume, realm=realm)
else
register_diag_field_array = register_diag_field_array_old(module_name, field_name, axes, init_time, &
& long_name=long_name, units=units, missing_value=missing_value, range=range, mask_variant=mask_variant, &
& standard_name=standard_name, verbose=verbose, do_not_log=do_not_log, err_msg=err_msg, &
& interp_method=interp_method, tile_count=tile_count, area=area, volume=volume, realm=realm)
endif
end function register_diag_field_array
!> @brief Return field index for subsequent call to send_data.
!! @return field index for subsequent call to send_data.
INTEGER FUNCTION 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)
CHARACTER(len=*), INTENT(in) :: module_name !< Name of the module, the field is on
CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
INTEGER, DIMENSION(:), INTENT(in) :: axes !< Axes_id of the field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Longname to be added as a attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to be added as a attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard name to be added as a attribute
CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to be added as a attribute
CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range !< Range to be added as a attribute
LOGICAL, OPTIONAL, INTENT(in) :: mask_variant !< Flag indicating if the field is has
!! a mask variant
LOGICAL, OPTIONAL, INTENT(in) :: DYNAMIC !< Flag indicating if the field is dynamic
LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field information is not logged
CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
!! regridding the field in post-processing
!! Valid options are "conserve_order1",
!! "conserve_order2", and "none".
INTEGER, OPTIONAL, INTENT(in) :: tile_count !! Number of tiles
INTEGER, OPTIONAL, INTENT(in) :: area !< Field ID for the area field associated
!! with this field
INTEGER, OPTIONAL, INTENT(in) :: volume !< Field ID for the volume field associated
!! with this field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the value to the
!! modeling_realm attribute
! Fatal error if the module has not been initialized.
IF ( .NOT.module_is_initialized ) THEN
! <ERROR STATUS="FATAL">diag_manager has NOT been initialized</ERROR>
CALL error_mesg ('diag_manager_mod::register_static_field', 'diag_manager has NOT been initialized', FATAL)
END IF
if (use_modern_diag) then
if( do_diag_field_log) then
if ( PRESENT(do_not_log) ) THEN
if(.not. do_not_log) call log_diag_field_info(module_name, field_name, axes, long_name,&
& units, missing_value, range, dynamic=.false.)
else
call log_diag_field_info(module_name, field_name, axes, long_name, units,&
& missing_value, range, dynamic=.false.)
endif
endif
register_static_field = fms_diag_object%fms_register_static_field(module_name, field_name, axes, &
& long_name=long_name, units=units, missing_value=missing_value, range=range, mask_variant=mask_variant, &
& standard_name=standard_name, dynamic=DYNAMIC, do_not_log=do_not_log, interp_method=interp_method,&
& tile_count=tile_count, area=area, volume=volume, realm=realm)
else
register_static_field = register_static_field_old(module_name, field_name, axes, &
& long_name=long_name, units=units, missing_value=missing_value, range=range, mask_variant=mask_variant, &
& standard_name=standard_name, dynamic=DYNAMIC, do_not_log=do_not_log, interp_method=interp_method,&
& tile_count=tile_count, area=area, volume=volume, realm=realm)
endif
END FUNCTION register_static_field
!> @brief Registers a scalar field
!! @return field index for subsequent call to send_data.
INTEGER FUNCTION register_diag_field_scalar_old(module_name, field_name, init_time, &
& long_name, units, missing_value, range, standard_name, do_not_log, err_msg,&
& area, volume, realm)
CHARACTER(len=*), INTENT(in) :: module_name !< Module where the field comes from
CHARACTER(len=*), INTENT(in) :: field_name !< Name of the field
TYPE(time_type), OPTIONAL, INTENT(in) :: init_time !< Time to start writing data from
CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name !< Long_name to add as a variable attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: units !< Units to add as a variable_attribute
CHARACTER(len=*), OPTIONAL, INTENT(in) :: standard_name !< Standard_name to name the variable in the file
CLASS(*), OPTIONAL, INTENT(in) :: missing_value !< Missing value to add as a variable attribute
CLASS(*), OPTIONAL, INTENT(in) :: range(:) !< Range to add a variable attribute
LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< If TRUE, field information is not logged
CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg !< Error_msg from call
INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
IF ( PRESENT(err_msg) ) err_msg = ''
IF ( PRESENT(init_time) ) THEN
register_diag_field_scalar_old = register_diag_field_array(module_name, field_name,&
& (/null_axis_id/), init_time,long_name, units, missing_value, range, &
& standard_name=standard_name, do_not_log=do_not_log, err_msg=err_msg,&
& area=area, volume=volume, realm=realm)
ELSE
register_diag_field_scalar_old = register_static_field(module_name, field_name,&
& (/null_axis_id/),long_name, units, missing_value, range,&
& standard_name=standard_name, do_not_log=do_not_log, realm=realm)
END IF
END FUNCTION register_diag_field_scalar_old
!> @brief Registers an array field
!> @return field index for subsequent call to send_data.
INTEGER FUNCTION register_diag_field_array_old(module_name, field_name, axes, init_time, &
& long_name, units, missing_value, range, mask_variant, standard_name, verbose,&
& do_not_log, err_msg, interp_method, tile_count, area, volume, realm)
CHARACTER(len=*), INTENT(in) :: module_name, field_name
INTEGER, INTENT(in) :: axes(:)
TYPE(time_type), INTENT(in) :: init_time
CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
CLASS(*), OPTIONAL, INTENT(in) :: missing_value
CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range
LOGICAL, OPTIONAL, INTENT(in) :: mask_variant,verbose
LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field info is not logged
CHARACTER(len=*), OPTIONAL, INTENT(out):: err_msg
CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
!! regridding the field in post-processing.
!! Valid options are "conserve_order1",
!! "conserve_order2", and "none".
INTEGER, OPTIONAL, INTENT(in) :: tile_count !< The current tile number
INTEGER, OPTIONAL, INTENT(in) :: area !< Id of the area field
INTEGER, OPTIONAL, INTENT(in) :: volume !< Id of the volume field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the modeling_realm attribute
INTEGER :: field, j, ind, file_num, freq
INTEGER :: output_units
INTEGER :: stdout_unit
LOGICAL :: mask_variant1, verbose1
CHARACTER(len=128) :: msg
TYPE(time_type) :: diag_file_init_time !< The intial time of the diag_file
! get stdout unit number
stdout_unit = stdout()
IF ( PRESENT(mask_variant) ) THEN
mask_variant1 = mask_variant
ELSE
mask_variant1 = .FALSE.
END IF
IF ( PRESENT(verbose) ) THEN
verbose1 = verbose
ELSE
verbose1 = .FALSE.
END IF
IF ( PRESENT(err_msg) ) err_msg = ''
! Fatal error if range is present and its extent is not 2.
IF ( PRESENT(range) ) THEN
IF ( SIZE(range) .NE. 2 ) THEN
! <ERROR STATUS="FATAL">extent of range should be 2</ERROR>
CALL error_mesg ('diag_manager_mod::register_diag_field', 'extent of range should be 2', FATAL)
END IF
END IF
! Call register static, then set static back to false
register_diag_field_array_old = register_static_field(module_name, field_name, axes,&
& long_name, units, missing_value, range, mask_variant1, standard_name=standard_name,&
& DYNAMIC=.TRUE., do_not_log=do_not_log, interp_method=interp_method, tile_count=tile_count, realm=realm)
IF ( .NOT.first_send_data_call ) THEN
! <ERROR STATUS="WARNING">
! module/output_field <module_name>/<field_name> registered AFTER first
! send_data call, TOO LATE
! </ERROR>
IF ( mpp_pe() == mpp_root_pe() ) &
& CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//&
&' registered AFTER first send_data call, TOO LATE', WARNING)
END IF
IF ( register_diag_field_array_old < 0 ) THEN
! <ERROR STATUS="WARNING">
! module/output_field <modul_name>/<field_name> NOT found in diag_table
! </ERROR>
IF ( debug_diag_manager .OR. verbose1 ) THEN
IF ( mpp_pe() == mpp_root_pe() ) &
& CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' NOT found in diag_table',&
& WARNING)
END IF
ELSE
input_fields(register_diag_field_array_old)%static = .FALSE.
field = register_diag_field_array_old
! Verify that area and volume do not point to the same variable
IF ( PRESENT(volume).AND.PRESENT(area) ) THEN
IF ( area.EQ.volume ) THEN
IF (PRESENT(err_msg)) THEN
err_msg = 'diag_manager_mod::register_diag_field: module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' AREA and VOLUME CANNOT be the same variable.&
& Contact the developers.'
register_diag_field_array_old = -1
RETURN
ELSE
CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' AREA and VOLUME CANNOT be the same variable.&
& Contact the developers.',&
& FATAL)
ENDIF
END IF
END IF
! Check for the existence of the area/volume field(s)
IF ( PRESENT(area) ) THEN
IF ( area < 0 ) THEN
IF (PRESENT(err_msg)) THEN
err_msg = 'diag_manager_mod::register_diag_field: module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' AREA measures field NOT found in diag_table.&
& Contact the model liaison.'
register_diag_field_array_old = -1
RETURN
ELSE
CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' AREA measures field NOT found in diag_table.&
& Contact the model liaison.',&
& FATAL)
ENDIF
END IF
END IF
IF ( PRESENT(volume) ) THEN
IF ( volume < 0 ) THEN
IF (PRESENT(err_msg)) THEN
err_msg = 'diag_manager_mod::register_diag_field: module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' VOLUME measures field NOT found in diag_table.&
& Contact the model liaison.'
register_diag_field_array_old = -1
RETURN
ELSE
CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' VOLUME measures field NOT found in diag_table.&
& Contact the model liaison.',&
& FATAL)
ENDIF
END IF
END IF
IF ( PRESENT(standard_name) ) input_fields(field)%standard_name = standard_name
DO j = 1, input_fields(field)%num_output_fields
ind = input_fields(field)%output_fields(j)
output_fields(ind)%static = .FALSE.
! Set up times in output_fields
! Get output frequency from for the appropriate output file
file_num = output_fields(ind)%output_file
IF ( file_num == max_files ) CYCLE
IF ( output_fields(ind)%local_output ) THEN
IF ( output_fields(ind)%need_compute) THEN
files(file_num)%local = .TRUE.
END IF
END IF
! Need to sync start_time of file with init time of model
! and close_time calculated with the duration of the file.
! Also, increase next_open until it is greater than init_time.
CALL sync_file_times(file_num, init_time, err_msg=msg)
IF ( msg /= '' ) THEN
IF ( fms_error_handler('diag_manager_mod::register_diag_field', TRIM(msg), err_msg) ) RETURN
END IF
freq = files(file_num)%output_freq
diag_file_init_time = get_file_start_time(file_num)
output_units = files(file_num)%output_units
output_fields(ind)%last_output = diag_file_init_time
output_fields(ind)%next_output = diag_time_inc(diag_file_init_time, freq, output_units, err_msg=msg)
IF ( msg /= '' ) THEN
IF ( fms_error_handler('diag_manager_mod::register_diag_field',&
& ' file='//TRIM(files(file_num)%name)//': '//TRIM(msg),err_msg)) RETURN
END IF
output_fields(ind)%next_next_output = &
& diag_time_inc(output_fields(ind)%next_output, freq, output_units, err_msg=msg)
IF ( msg /= '' ) THEN
IF ( fms_error_handler('diag_manager_mod::register_diag_field',&
&' file='//TRIM(files(file_num)%name)//': '//TRIM(msg),err_msg) ) RETURN
END IF
IF ( debug_diag_manager .AND. mpp_pe() == mpp_root_pe() .AND. output_fields(ind)%local_output ) THEN
WRITE (msg,'(" lon(",F5.1,", ",F5.1,"), lat(",F5.1,", ",F5.1,"), dep(",F5.1,", ",F5.1,")")') &
& output_fields(ind)%output_grid%start(1),output_fields(ind)%output_grid%end(1),&
& output_fields(ind)%output_grid%start(2),output_fields(ind)%output_grid%end(2),&
& output_fields(ind)%output_grid%start(3),output_fields(ind)%output_grid%end(3)
WRITE(stdout_unit,* ) 'module/output_field '//TRIM(module_name)//'/'//TRIM(field_name)// &
& ' will be output in region:'//TRIM(msg)
END IF
! Set the cell_measures attribute in the out file
CALL init_field_cell_measures(output_fields(ind), area=area, volume=volume, err_msg=err_msg)
IF ( LEN_TRIM(err_msg).GT.0 ) THEN
CALL error_mesg ('diag_manager_mod::register_diag_field',&
& TRIM(err_msg)//' for module/field '//TRIM(module_name)//'/'//TRIM(field_name),&
& FATAL)
END IF
END DO
END IF
END FUNCTION register_diag_field_array_old
!> @brief Return field index for subsequent call to send_data.
!! @return field index for subsequent call to send_data.
INTEGER FUNCTION register_static_field_old(module_name, field_name, axes, long_name, units,&
& missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method,&
& tile_count, area, volume, realm)
CHARACTER(len=*), INTENT(in) :: module_name, field_name
INTEGER, DIMENSION(:), INTENT(in) :: axes
CHARACTER(len=*), OPTIONAL, INTENT(in) :: long_name, units, standard_name
CLASS(*), OPTIONAL, INTENT(in) :: missing_value
CLASS(*), DIMENSION(:), OPTIONAL, INTENT(in) :: range
LOGICAL, OPTIONAL, INTENT(in) :: mask_variant
LOGICAL, OPTIONAL, INTENT(in) :: DYNAMIC
LOGICAL, OPTIONAL, INTENT(in) :: do_not_log !< if TRUE, field information is not logged
CHARACTER(len=*), OPTIONAL, INTENT(in) :: interp_method !< The interp method to be used when
!! regridding the field in post-processing.
!! Valid options are "conserve_order1",
!! "conserve_order2", and "none".
INTEGER, OPTIONAL, INTENT(in) :: tile_count
INTEGER, OPTIONAL, INTENT(in) :: area !< Field ID for the area field associated with this field
INTEGER, OPTIONAL, INTENT(in) :: volume !< Field ID for the volume field associated with this field
CHARACTER(len=*), OPTIONAL, INTENT(in) :: realm !< String to set as the value to the modeling_realm attribute
REAL :: missing_value_use !< Local copy of missing_value
REAL, DIMENSION(2) :: range_use !< Local copy of range
INTEGER :: field, num_axes, j, out_num, k
INTEGER, DIMENSION(3) :: siz, local_siz, local_start, local_end ! indices of local domain of global axes
INTEGER :: tile, file_num
LOGICAL :: mask_variant1, dynamic1, allow_log
CHARACTER(len=128) :: msg
INTEGER :: domain_type, i
character(len=256) :: axis_name
! Fatal error if the module has not been initialized.
IF ( .NOT.module_is_initialized ) THEN
! <ERROR STATUS="FATAL">diag_manager has NOT been initialized</ERROR>
CALL error_mesg ('diag_manager_mod::register_static_field_old', 'diag_manager has NOT been initialized', FATAL)
END IF
! Check if OPTIONAL parameters were passed in.
IF ( PRESENT(missing_value) ) THEN
IF ( use_cmor ) THEN
missing_value_use = CMOR_MISSING_VALUE
ELSE
SELECT TYPE (missing_value)
TYPE IS (real(kind=r4_kind))
missing_value_use = missing_value
TYPE IS (real(kind=r8_kind))
missing_value_use = real(missing_value)
CLASS DEFAULT
CALL error_mesg ('diag_manager_mod::register_static_field',&
& 'The missing_value is not one of the supported types of real(kind=4) or real(kind=8)', FATAL)
END SELECT
END IF
END IF
IF ( PRESENT(mask_variant) ) THEN
mask_variant1 = mask_variant
ELSE
mask_variant1 = .FALSE.
END IF
IF ( PRESENT(DYNAMIC) ) THEN
dynamic1 = DYNAMIC
ELSE
dynamic1 = .FALSE.
END IF
IF ( PRESENT(tile_count) ) THEN
tile = tile_count
ELSE
tile = 1
END IF
IF ( PRESENT(do_not_log) ) THEN
allow_log = .NOT.do_not_log
ELSE
allow_log = .TRUE.
END IF
! Fatal error if range is present and its extent is not 2.
IF ( PRESENT(range) ) THEN
IF ( SIZE(range) .NE. 2 ) THEN
! <ERROR STATUS="FATAL">extent of range should be 2</ERROR>
CALL error_mesg ('diag_manager_mod::register_static_field', 'extent of range should be 2', FATAL)
END IF
END IF
! only writes log if do_diag_field_log is true in the namelist (default false)
! if do_diag_field_log is true and do_not_log arg is present as well, it will only print if do_not_log = false
IF ( do_diag_field_log.AND.allow_log ) THEN
CALL log_diag_field_info (module_name, field_name, axes, &
& long_name, units, missing_value=missing_value, range=range, &
& DYNAMIC=dynamic1)
END IF
register_static_field_old = find_input_field(module_name, field_name, 1)
field = register_static_field_old
! Negative index returned if this field was not found in the diag_table.
IF ( register_static_field_old < 0 ) RETURN
! Check that the axes are compatible with each other
domain_type = axis_compatible_check(axes,field_name)
IF ( tile > 1 ) THEN
IF ( .NOT.input_fields(field)%register ) THEN
! <ERROR STATUS="FATAL">
! module/output_field <module_name>/<field_name> is not registered for tile_count = 1,
! should not register for tile_count > 1
! </ERROR>
CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
& TRIM(field_name)//' is not registered for tile_count = 1, should not register for tile_count > 1',&
& FATAL)
END IF
CALL init_input_field(module_name, field_name, tile)
register_static_field_old = find_input_field(module_name, field_name, tile)
DO j = 1, input_fields(field)%num_output_fields
out_num = input_fields(field)%output_fields(j)
file_num = output_fields(out_num)%output_file
IF(input_fields(field)%local) THEN
CALL init_output_field(module_name, field_name,output_fields(out_num)%output_name,&
& files(file_num)%name,output_fields(out_num)%time_method, output_fields(out_num)%pack,&
& tile, input_fields(field)%local_coord)
ELSE
CALL init_output_field(module_name, field_name,output_fields(out_num)%output_name,&
& files(file_num)%name,output_fields(out_num)%time_method, output_fields(out_num)%pack, tile)
END IF
END DO
field = register_static_field_old
END IF
! Store information for this input field into input field table
! Set static to true, if called by register_diag_field this is
! flipped back to false
input_fields(field)%static = .TRUE.
! check if the field is registered twice
IF ( input_fields(field)%register .AND. mpp_pe() == mpp_root_pe() ) THEN
! <ERROR STATUS="FATAL">
! module/output_field <module_name>/<field_name> ALREADY Registered, should
! not register twice
! </ERROR>
CALL error_mesg ('diag_manager_mod::register_diag_field', 'module/output_field '//trim(module_name)//'/'//&
& TRIM(field_name)//' ALREADY registered, should not register twice', FATAL)
END IF
! Verify that area and volume do not point to the same variable
IF ( PRESENT(volume).AND.PRESENT(area) ) THEN
IF ( area.EQ.volume ) THEN
CALL error_mesg ('diag_manager_mod::register_static_field_old', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' AREA and VOLUME CANNOT be the same variable.&
& Contact the developers.',&
& FATAL)
END IF
END IF
! Check for the existence of the area/volume field(s)
IF ( PRESENT(area) ) THEN
IF ( area < 0 ) THEN
CALL error_mesg ('diag_manager_mod::register_static_field_old', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' AREA measures field NOT found in diag_table.&
& Contact the model liaison.n',&
& FATAL)
END IF
END IF
IF ( PRESENT(volume) ) THEN
IF ( volume < 0 ) THEN
CALL error_mesg ('diag_manager_mod::register_static_field_old', 'module/output_field '&
&//TRIM(module_name)//'/'// TRIM(field_name)//' VOLUME measures field NOT found in diag_table&
& Contact the model liaison.',&
& FATAL)
END IF
END IF
! Set flag that this field was registered
input_fields(field)%register = .TRUE.
! set flag for mask: does it change with time?
input_fields(field)%mask_variant = mask_variant1
! Set flag for mask warning
input_fields(field)%issued_mask_ignore_warning = .FALSE.
! Check for more OPTIONAL parameters.
IF ( PRESENT(long_name) ) THEN
input_fields(field)%long_name = TRIM(long_name)
ELSE
input_fields(field)%long_name = input_fields(field)%field_name
END IF
IF ( PRESENT(standard_name) ) input_fields(field)%standard_name = standard_name
IF ( PRESENT(units) ) THEN
input_fields(field)%units = TRIM(units)
ELSE
input_fields(field)%units = 'none'
END IF
IF ( PRESENT(missing_value) ) THEN
input_fields(field)%missing_value = missing_value_use
input_fields(field)%missing_value_present = .TRUE.
ELSE
input_fields(field)%missing_value_present = .FALSE.
END IF
IF ( PRESENT(range) ) THEN
SELECT TYPE (range)
TYPE IS (real(kind=r4_kind))
range_use = range
TYPE IS (real(kind=r8_kind))
range_use = real(range)
CLASS DEFAULT
CALL error_mesg ('diag_manager_mod::register_static_field',&
& 'The range is not one of the supported types of real(kind=4) or real(kind=8)', FATAL)
END SELECT
input_fields(field)%range = range_use
! don't use the range if it is not a valid range
input_fields(field)%range_present = range_use(2) .gt. range_use(1)
ELSE
input_fields(field)%range = (/ 1., 0. /)
input_fields(field)%range_present = .FALSE.
END IF
IF ( PRESENT(interp_method) ) THEN
IF ( TRIM(interp_method) .NE. 'conserve_order1' .AND.&
& TRIM(interp_method) .NE. 'conserve_order2' .AND.&
& TRIM(interp_method) .NE. 'none' ) THEN
! <ERROR STATUS="FATAL">
! when registering module/output_field <module_name>/<field_name> then optional
! argument interp_method = <interp_method>, but it should be "conserve_order1",
! "conserve_order2", or "none"
! </ERROR>
CALL error_mesg ('diag_manager_mod::register_diag_field',&
& 'when registering module/output_field '//TRIM(module_name)//'/'//&
& TRIM(field_name)//', the optional argument interp_method = '//TRIM(interp_method)//&
& ', but it should be "conserve_order1", "conserve_order2", or "none"', FATAL)
END IF