FV3 Bundle
column_diagnostics.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 
20 
22 
23 
24 
25 use mpp_io_mod, only: mpp_io_init, mpp_open, mpp_ascii, &
26  mpp_overwr, mpp_sequential, &
27  mpp_multi, mpp_close
28 use fms_mod, only: fms_init, mpp_pe, mpp_root_pe, &
29  file_exist, check_nml_error, &
30  error_mesg, fatal, note, warning, &
31  close_file, open_namelist_file, &
32  stdlog, write_version_number
36 use mpp_mod, only: input_nml_file
37 
38 !-------------------------------------------------------------------
39 
40 implicit none
41 private
42 
43 !---------------------------------------------------------------------
44 ! module to locate and mark desired diagnostic columns
45 !
46 !
47 !--------------------------------------------------------------------
48 
49 
50 
51 
52 !---------------------------------------------------------------------
53 !----------- ****** VERSION NUMBER ******* ---------------------------
54 
55 
56 ! Include variable "version" to be written to log file.
57 #include<file_version.h>
58 
59 
60 
61 !---------------------------------------------------------------------
62 !------- interfaces --------
63 
68 
69 
70 !private
71 
72 
73 !--------------------------------------------------------------------
74 !---- namelist -----
75 
76 real :: crit_xdistance = 4.0
77  ! model grid points must be within crit_xdistance in
78  ! longitude of the requested diagnostics point
79  ! coordinates in order to be flagged as the desired
80  ! point
81  ! [ degrees ]
82 real :: crit_ydistance = 4.0
83  ! model grid points must be within crit_ydistance in
84  ! latitude of the requested diagnostics point
85  ! coordinates in order to be flagged as the desired
86  ! point
87  ! [ degrees ]
88 
89 namelist / column_diagnostics_nml / &
92 
93 !--------------------------------------------------------------------
94 !-------- public data -----
95 
96 
97 !--------------------------------------------------------------------
98 !------ private data ------
99 
100 
101 logical :: module_is_initialized = .false.
102 
103 !-------------------------------------------------------------------
104 !-------------------------------------------------------------------
105 
106 
107 
108  contains
109 
110 
111 
112 !####################################################################
113 
114 subroutine column_diagnostics_init
116 !--------------------------------------------------------------------
117 ! column_diagnostics_init is the constructor for
118 ! column_diagnostics_mod.
119 !--------------------------------------------------------------------
120 
121 !--------------------------------------------------------------------
122 ! local variables:
123 !
124  integer :: unit, ierr, io
125 
126 !--------------------------------------------------------------------
127 ! local variables:
128 !
129 ! unit unit number for nml file
130 ! ierr error return flag
131 ! io error return code
132 !
133 !---------------------------------------------------------------------
134 
135 !--------------------------------------------------------------------
136 ! if routine has already been executed, return.
137 !--------------------------------------------------------------------
138  if (module_is_initialized) return
139 
140 !---------------------------------------------------------------------
141 ! verify that all modules used by this module have been initialized.
142 !----------------------------------------------------------------------
143  call mpp_io_init
144  call fms_init
145  call time_manager_init
146  call constants_init
147 
148 !---------------------------------------------------------------------
149 ! read namelist.
150 !---------------------------------------------------------------------
151 #ifdef INTERNAL_FILE_NML
152  read (input_nml_file, column_diagnostics_nml, iostat=io)
153  ierr = check_nml_error(io, 'column_diagnostics_nml')
154 #else
155  if (file_exist('input.nml')) then
156  unit = open_namelist_file( )
157  ierr=1; do while (ierr /= 0)
158  read (unit, nml=column_diagnostics_nml, iostat=io, end=10)
159  ierr = check_nml_error(io, 'column_diagnostics_nml')
160  enddo
161 10 call close_file (unit)
162  endif
163 #endif
164 !---------------------------------------------------------------------
165 ! write version number and namelist to logfile.
166 !---------------------------------------------------------------------
167  call write_version_number("COLUMN_DIAGNOSTICS_MOD", version)
168  if (mpp_pe() == mpp_root_pe()) then
169  unit = stdlog()
170  write (unit, nml=column_diagnostics_nml)
171  endif
172 !--------------------------------------------------------------------
173  module_is_initialized = .true.
174 
175 
176 end subroutine column_diagnostics_init
177 
178 
179 
180 !####################################################################
181 
182 
184  (module, num_diag_pts_latlon, num_diag_pts_ij, &
185  global_i , global_j , global_lat_latlon, &
186  global_lon_latlon, lonb_in, latb_in, &
187  do_column_diagnostics, &
188  diag_lon, diag_lat, diag_i, diag_j, diag_units)
190 !---------------------------------------------------------------------
191 ! initialize_diagnostic_columns returns the (i, j, lat, lon) coord-
192 ! inates of any diagnostic columns that are located on the current
193 ! processor.
194 !----------------------------------------------------------------------
195 
196 !---------------------------------------------------------------------
197 character(len=*), intent(in) :: module
198 integer, intent(in) :: num_diag_pts_latlon, &
199  num_diag_pts_ij
200 integer, dimension(:), intent(in) :: global_i, global_j
201 real , dimension(:), intent(in) :: global_lat_latlon, &
202  global_lon_latlon
203 real, dimension(:,:), intent(in) :: lonb_in, latb_in
204 logical, dimension(:,:), intent(out) :: do_column_diagnostics
205 integer, dimension(:), intent(inout) :: diag_i, diag_j
206 real , dimension(:), intent(out) :: diag_lat, diag_lon
207 integer, dimension(:), intent(out) :: diag_units
208 !---------------------------------------------------------------------
209 
210 !---------------------------------------------------------------------
211 ! intent(in) variables:
212 !
213 ! module module calling this subroutine
214 ! num_diag_pts_latlon number of diagnostic columns specified
215 ! by lat-lon coordinates
216 ! num_diag_pts_ij number of diagnostic columns specified
217 ! by global (i,j) coordinates
218 ! global_i specified global i coordinates
219 ! global_j specified global j coordinates
220 ! global_lat_latlon specified global lat coordinates
221 ! global_lon_latlon specified global lon coordinates
222 !
223 ! intent(out) variables:
224 !
225 ! do_column_diagnostics is a diagnostic column in this jrow ?
226 ! diag_i processor i indices of diagnstic columns
227 ! diag_j processor j indices of diagnstic columns
228 ! diag_lat latitudes of diagnostic columns
229 ! [ degrees ]
230 ! diag_lon longitudes of diagnostic columns
231 ! [ degrees ]
232 ! diag_units unit number for each diagnostic column
233 !
234 !---------------------------------------------------------------------
235 
236 !--------------------------------------------------------------------
237 ! local variables:
238 
239  real, dimension(size(diag_i,1)) :: global_lat, global_lon
240  real, dimension(size(latb_in,1)-1, size(latb_in,2)-1) :: &
241  distance, distance_x, distance_y, &
242  distance_x2, distance2
243  real, dimension(size(latb_in,1), size(latb_in,2)) :: latb_deg
244  real, dimension(size(lonb_in,1), size(lonb_in,2)) :: lonb_deg
245  real :: dellat, dellon
246  real :: latb_max, latb_min, lonb_max, lonb_min
247 
248  integer :: num_diag_pts
249  integer :: i, j, nn
250  real :: ref_lat
251  real :: current_distance
252  character(len=8) :: char
253  character(len=32) :: filename
254  logical :: allow_ij_input
255  logical :: open_file
256 
257 !--------------------------------------------------------------------
258 ! local variables:
259 !
260 ! global_lat latitudes for all diagnostic columns [ degrees ]
261 ! global_lon longitudes for all diagnostic columns
262 ! [ degrees ]
263 ! num_diag_pts total number of diagnostic columns
264 ! i, j, nn do loop indices
265 ! char character string for diaganostic column index
266 ! filename filename for output file for diagnostic column
267 !
268 !---------------------------------------------------------------------
269 
271 
272 !--------------------------------------------------------------------
273 ! save the input lat and lon fields. define the delta of latitude
274 ! and longitude.
275 !--------------------------------------------------------------------
276  latb_deg = latb_in*radian
277  lonb_deg = lonb_in*radian
278  dellat = latb_in(1,2) - latb_in(1,1)
279  dellon = lonb_in(2,1) - lonb_in(1,1)
280  latb_max = maxval(latb_deg(:,:))
281  latb_min = minval(latb_deg(:,:))
282  lonb_max = maxval(lonb_deg(:,:))
283  lonb_min = minval(lonb_deg(:,:))
284  if (lonb_min < 10.0 .or. lonb_max > 350.) then
285  lonb_min = 0.
286  lonb_max = 360.0
287  endif
288 
289  allow_ij_input = .true.
290  ref_lat = latb_in(1,1)
291  do i =2,size(latb_in,1)
292  if (latb_in(i,1) /= ref_lat) then
293  allow_ij_input = .false.
294  exit
295  endif
296  end do
297 
298  if ( .not. allow_ij_input .and. num_diag_pts_ij /= 0) then
299  call error_mesg ('column_diagnostics_mod', &
300  'cannot specify column diagnostics column with (i,j) &
301  &coordinates when using cubed sphere -- must specify &
302  & lat/lon coordinates', fatal)
303  endif
304 
305 !----------------------------------------------------------------------
306 ! initialize column_diagnostics flag and diag unit numbers. define
307 ! total number of diagnostic columns.
308 !----------------------------------------------------------------------
309  do_column_diagnostics = .false.
310  diag_units(:) = -1
311  diag_i(:) = -99
312  diag_j(:) = -99
313  diag_lat(:) = -999.
314  diag_lon(:) = -999.
315  num_diag_pts = size(diag_i(:))
316 
317 !--------------------------------------------------------------------
318 ! define an array of lat-lon values for all diagnostic columns.
319 !--------------------------------------------------------------------
320  do nn = 1, num_diag_pts_latlon
321  global_lat(nn) = global_lat_latlon(nn)
322  global_lon(nn) = global_lon_latlon(nn)
323  end do
324 
325  do nn = 1, num_diag_pts_ij
326  global_lat(nn+num_diag_pts_latlon) = &
327  ((-0.5*acos(-1.0) + 0.5*dellat) + &
328  (global_j(nn)-1) *dellat)*radian
329  global_lon(nn+num_diag_pts_latlon) = (0.5*dellon + &
330  (global_i(nn)-1)*dellon)*radian
331  end do
332 
333 !----------------------------------------------------------------------
334 ! loop over all diagnostic points to check for their presence on
335 ! this processor.
336 !----------------------------------------------------------------------
337  do nn=1,num_diag_pts
338  open_file = .false.
339 
340 !----------------------------------------------------------------------
341 ! verify that the values of lat and lon are valid.
342 !----------------------------------------------------------------------
343  if (global_lon(nn) >= 0. .and. global_lon(nn) <= 360.0) then
344  else
345  call error_mesg ('column_diagnostics_mod', &
346  ' invalid longitude', fatal)
347  endif
348  if (global_lat(nn) >= -90.0 .and. global_lat(nn) <= 90.0) then
349  else
350  call error_mesg ('column_diagnostics_mod', &
351  ' invalid latitude', fatal)
352  endif
353 
354 !--------------------------------------------------------------------
355 ! if the desired diagnostics column is within the current
356 ! processor's domain, define the total and coordinate distances from
357 ! each of the processor's grid points to the diagnostics point.
358 !--------------------------------------------------------------------
359 
360  if (global_lat(nn) .ge. latb_min .and. &
361  global_lat(nn) .le. latb_max) then
362  if (global_lon(nn) .ge. lonb_min .and.&
363  global_lon(nn) .le. lonb_max) then
364  do j=1,size(latb_deg,2) - 1
365  do i=1,size(lonb_deg,1) - 1
366  distance_y(i,j) = abs(global_lat(nn) - latb_deg(i,j))
367  distance_x(i,j) = abs(global_lon(nn) - lonb_deg(i,j))
368  distance_x2(i,j) = abs((global_lon(nn)-360.) - &
369  lonb_deg(i,j))
370  distance(i,j) = (global_lat(nn) - latb_deg(i,j))**2 + &
371  (global_lon(nn) - lonb_deg(i,j))**2
372  distance2(i,j) = (global_lat(nn) - latb_deg(i,j))**2 + &
373  ((global_lon(nn)-360.) - &
374  lonb_deg(i,j))**2
375  end do
376  end do
377 
378 !--------------------------------------------------------------------
379 ! find the grid point on the processor that is within the specified
380 ! critical distance and also closest to the requested diagnostics
381 ! column. save the (i,j) coordinates and (lon,lat) of this model
382 ! grid point. set a flag indicating that a disgnostics file should
383 ! be opened on this processor for this diagnostic point.
384 !--------------------------------------------------------------------
385  current_distance = distance(1,1)
386  do j=1,size(latb_deg,2) - 1
387  do i=1,size(lonb_deg,1) - 1
388  if (distance_x(i,j) <= crit_xdistance .and. &
389  distance_y(i,j) <= crit_ydistance ) then
390  if (distance(i,j) < current_distance) then
391  current_distance = distance(i,j)
392  do_column_diagnostics(i,j) = .true.
393  diag_j(nn) = j
394  diag_i(nn) = i
395  diag_lon(nn) = lonb_deg(i,j)
396  diag_lat(nn) = latb_deg(i,j)
397  open_file = .true.
398  endif
399  endif
400 
401 !---------------------------------------------------------------------
402 ! check needed because of the 0.0 / 360.0 longitude periodicity.
403 !---------------------------------------------------------------------
404  if (distance_x2(i,j) <= crit_xdistance .and. &
405  distance_y(i,j) <= crit_ydistance ) then
406  if (distance2(i,j) < current_distance) then
407  current_distance = distance2(i,j)
408  do_column_diagnostics(i,j) = .true.
409  diag_j(nn) = j
410  diag_i(nn) = i
411  diag_lon(nn) = lonb_deg(i,j)
412  diag_lat(nn) = latb_deg(i,j)
413  open_file = .true.
414  endif
415  endif
416  end do
417  end do
418 
419 !--------------------------------------------------------------------
420 ! if the point has been found on this processor, open a diagnostics
421 ! file.
422 !--------------------------------------------------------------------
423  if (open_file) then
424  write (char, '(i2)') nn
425  filename = trim(module) // '_point' // &
426  trim(adjustl(char)) // '.out'
427  call mpp_open (diag_units(nn), filename, &
428  form=mpp_ascii, &
429  action=mpp_overwr, &
430  access=mpp_sequential, &
431  threading=mpp_multi, nohdrs=.true.)
432  endif ! (open_file)
433  endif
434  endif
435  end do
436 
437 !---------------------------------------------------------------------
438 
439 
440 end subroutine initialize_diagnostic_columns
441 
442 
443 
444 
445 !####################################################################
446 
447 subroutine column_diagnostics_header &
448  (module, diag_unit, time, nn, diag_lon, &
449  diag_lat, diag_i, diag_j)
451 !--------------------------------------------------------------------
452 ! column_diagnostics_header writes out information concerning
453 ! time and location of following data into the column_diagnostics
454 ! output file.
455 !--------------------------------------------------------------------
456 
457 !--------------------------------------------------------------------
458 character(len=*), intent(in) :: module
459 type(time_type), intent(in) :: time
460 integer, intent(in) :: diag_unit
461 integer, intent(in) :: nn
462 real, dimension(:), intent(in) :: diag_lon, diag_lat
463 integer, dimension(:), intent(in) :: diag_i, diag_j
464 
465 !--------------------------------------------------------------------
466 ! intent(in) variables
467 !
468 ! module module name calling this subroutine
469 ! Time current model time [ time_type ]
470 ! diag_unit unit number for column_diagnostics output
471 ! nn index of diagnostic column currently active
472 ! diag_lon longitude of current diagnostic column [ degrees ]
473 ! diag_lat latitude of current diagnostic column [ degrees ]
474 ! diag_i i coordinate of current diagnostic column
475 ! diag_j j coordinate of current diagnostic column
476 !
477 !---------------------------------------------------------------------
478 
479 !--------------------------------------------------------------------
480 ! local variables:
481 
482  integer :: year, month, day, hour, minute, second
483  character(len=8) :: mon
484  character(len=64) :: header
485 
486 !--------------------------------------------------------------------
487 ! local variables:
488 !
489 ! year, month, day, hour, minute, seconds
490 ! integers defining the current time
491 ! mon character string for the current month
492 ! header title for the output
493 !
494 !--------------------------------------------------------------------
495 
497 
498 !--------------------------------------------------------------------
499 ! convert the time type to a date and time for printing. convert
500 ! month to a character string.
501 !--------------------------------------------------------------------
502  call get_date (time, year, month, day, hour, minute, second)
503  mon = month_name(month)
504 
505 !---------------------------------------------------------------------
506 ! write timestamp and column location information to the diagnostic
507 ! columns output unit.
508 !---------------------------------------------------------------------
509  write (diag_unit,'(a)') ' '
510  write (diag_unit,'(a)') ' '
511  write (diag_unit,'(a)') &
512  '======================================================'
513  write (diag_unit,'(a)') ' '
514  header = ' PRINTING ' // module // ' DIAGNOSTICS'
515  write (diag_unit,'(a)') header
516  write (diag_unit,'(a)') ' '
517  write (diag_unit,'(a, i6,2x, a,i4,i4,i4,i4)') ' time stamp:', &
518  year, trim(mon), day, &
519  hour, minute, second
520  write (diag_unit,'(a, i4)') &
521  ' DIAGNOSTIC POINT COORDINATES, point #', nn
522  write (diag_unit,'(a)') ' '
523  write (diag_unit,'(a,f8.3,a,f8.3)') ' longitude = ', &
524  diag_lon(nn), ' latitude = ', diag_lat(nn)
525  write (diag_unit,'(a, i6, a,i6,a,i6)') &
526  ' on processor # ', mpp_pe(), &
527  ' : processor i =', diag_i(nn), &
528  ' , processor j =', diag_j(nn)
529  write (diag_unit,'(a)') ' '
530 
531 !---------------------------------------------------------------------
532 
533 
534 
535 end subroutine column_diagnostics_header
536 
537 
538 
539 !######################################################################
540 
541 subroutine close_column_diagnostics_units (diag_units)
543 !---------------------------------------------------------------------
544 ! close_column_diagnostics_units closes any open column_diagnostics
545 ! files associated with the calling module.
546 !----------------------------------------------------------------------
547 
548 !----------------------------------------------------------------------
549 integer, dimension(:), intent(in) :: diag_units
550 !----------------------------------------------------------------------
551 
552 !--------------------------------------------------------------------
553 ! intent(in) variable:
554 !
555 ! diag_units array of column diagnostic unit numbers
556 !
557 !--------------------------------------------------------------------
558 
559 !--------------------------------------------------------------------
560 ! local variable
561 
562  integer :: nn ! do loop index
563 
564 !--------------------------------------------------------------------
565 ! close the unit associated with each diagnostic column.
566 !--------------------------------------------------------------------
567  do nn=1, size(diag_units(:))
568  if (diag_units(nn) /= -1) then
569  call mpp_close (diag_units(nn))
570  endif
571  end do
572 
573 !---------------------------------------------------------------------
574 
575 
576 end subroutine close_column_diagnostics_units
577 
578 
579 !#####################################################################
580 
581 
582 
583 
584  end module column_diagnostics_mod
Definition: fms.F90:20
subroutine, public get_date(time, year, month, day, hour, minute, second, tick, err_msg)
subroutine, public column_diagnostics_header(module, diag_unit, Time, nn, diag_lon, diag_lat, diag_i, diag_j)
subroutine, public initialize_diagnostic_columns(module, num_diag_pts_latlon, num_diag_pts_ij, global_i, global_j, global_lat_latlon, global_lon_latlon, lonb_in, latb_in, do_column_diagnostics, diag_lon, diag_lat, diag_i, diag_j, diag_units)
character(len=9) function, public month_name(n)
Definition: mpp.F90:39
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
real, parameter, public pi
Ratio of circle circumference to diameter [N/A].
Definition: constants.F90:74
real, parameter, public radian
Equal to RAD_TO_DEG for backward compatability. [rad/deg].
Definition: constants.F90:121
subroutine, public fms_init(localcomm)
Definition: fms.F90:353
subroutine, public column_diagnostics_init
subroutine, public time_manager_init()
subroutine, public close_column_diagnostics_units(diag_units)
subroutine, public error_mesg(routine, message, level)
Definition: fms.F90:529
subroutine, public constants_init
dummy routine.
Definition: constants.F90:141