FV3 Bundle
diag_grid.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="seth.underwood@noaa.gov">
23  ! Seth Underwood
24  ! </CONTACT>
25  ! <HISTORY SRC="http://www.gfdl.noaa.gov/fms-cgi-bin/cvsweb.cgi/FMS/" />
26  ! <OVERVIEW>
27  ! <TT>diag_grid_mod</TT> is a set of procedures to work with the
28  ! model's global grid to allow regional output.
29  ! </OVERVIEW>
30  ! <DESCRIPTION>
31  ! <TT>diag_grid_mod</TT> contains useful utilities for dealing
32  ! with, mostly, regional output for grids other than the standard
33  ! lat/lon grid. This module contains three public procedures <TT>
34  ! diag_grid_init</TT>, which is shared globably in the <TT>
35  ! diag_manager_mod</TT>, <TT>diag_grid_end</TT> which will free
36  ! up memory used during the register field calls, and
37  ! <TT>get_local_indexes</TT>. The <TT>send_global_grid</TT>
38  ! procedure is called by the model that creates the global grid.
39  ! <TT>send_global_grid</TT> needs to be called before any fields
40  ! are registered that will output only regions. <TT>get_local_indexes</TT>
41  ! is to be called by the <TT>diag_manager_mod</TT> to discover the
42  ! global indexes defining a subregion on the tile.
43  !
44  ! <B>Change Log</B>
45  ! <DL>
46  ! <DT>September 2009</DT>
47  ! <DD>
48  ! <UL>
49  ! <LI>Single point region in Cubed Sphere</LI>
50  ! <LI>Single tile regions in the cubed sphere</LI>
51  ! </UL>
52  ! </DD>
53  ! </DL>
54  ! </DESCRIPTION>
55 
56  ! <INFO>
57  ! <FUTURE>
58  ! Multi-tile regional output in the cubed sphere.
59  ! </FUTURE>
60  ! <FUTURE>
61  ! Single grid in the tri-polar grid.
62  ! </FUTURE>
63  ! <FUTURE>
64  ! Multi-tile regional output in the tri-polar grid.
65  ! </FUTURE>
66  ! <FUTURE>
67  ! Regional output using array masking. This should allow
68  ! regional output to work on any current or future grid.
69  ! </FUTURE>
70  ! </INFO>
72  USE fms_mod, ONLY: write_version_number, error_mesg, warning, fatal,&
73  & mpp_pe
74  USE mpp_mod, ONLY: mpp_root_pe, mpp_npes, mpp_max, mpp_min
75  USE mpp_domains_mod, ONLY: domain2d, mpp_get_tile_id,&
76  & mpp_get_ntile_count, mpp_get_compute_domains
77 
78  IMPLICIT NONE
79 
80  ! Parameters
81  ! Include variable "version" to be written to log file.
82 #include<file_version.h>
83 
84  ! Derived data types
85  ! <PRIVATE>
86  ! <TYPE NAME="diag_global_grid_type">
87  ! <DESCRIPTION>
88  ! Contains the model's global grid data, and other grid information.
89  ! </DESCRIPTION>
90  ! <DATA NAME="glo_lat" TYPE="REAL, _ALLOCATABLE, DIMENSION(:,:)">
91  ! The latitude values on the global grid.
92  ! </DATA>
93  ! <DATA NAME="glo_lon" TYPE="REAL, _ALLOCATABLE, DIMENSION(:,:)">
94  ! The longitude values on the global grid.
95  ! </DATA>
96  ! <DATA NAME="aglo_lat" TYPE="REAL, _ALLOCATABLE, DIMENSION(:,:)">
97  ! The latitude values on the global a-grid. Here we expect isc-1:iec+1 and
98  ! jsc=1:jec+1 to be passed in.
99  ! </DATA>
100  ! <DATA NAME="aglo_lon" TYPE="REAL, _ALLOCATABLE, DIMENSION(:,:)">
101  ! The longitude values on the global a-grid. Here we expec isc-1:iec+j and
102  ! jsc-1:jec+1 to be passed in.
103  ! </DATA>
104  ! <DATA NAME="myXbegin" TYPE="INTEGER">
105  ! The starting index of the compute domain on the current PE.
106  ! </DATA>
107  ! <DATA NAME="myYbegin" TYPE="INTEGER">
108  ! The starting index of the compute domain on the cureent PE.
109  ! </DATA>
110  ! <DATA NAME="dimI" TYPE="INTEGER">
111  ! The dimension of the global grid in the 'i' / longitudal direction.
112  ! </DATA>
113  ! <DATA NAME="dimJ" TYPE="INTEGER">
114  ! The dimension of the global grid in the 'j' / latitudal direction.
115  ! </DATA>
116  ! <DATA NAME="adimI" TYPE="INTEGER">
117  ! The dimension of the global a-grid in the 'i' / longitudal direction. Again,
118  ! the expected dimension for diag_grid_mod is isc-1:iec+1.
119  ! </DATA>
120  ! <DATA NAME="adimJ" TYPE="INTEGER">
121  ! The dimension of the global a-grid in the 'j' / latitudal direction. Again,
122  ! the expected dimension for diag_grid_mod is jsc-1:jec+1.
123  ! </DATA>
124  ! <DATA NAME="tile_number" TYPE="INTEGER">
125  ! The tile the <TT>glo_lat</TT> and <TT>glo_lon</TT> define.
126  ! </DATA>
127  ! <DATA NAME="ntimes" TYPE="INTEGER">
128  ! The number of tiles.
129  ! </DATA>
130  ! <DATA NAME="peStart" TYPE="INTEGER">
131  ! The starting PE number for the current tile.
132  ! </DATA>
133  ! <DATA NAME="peEnd" TYPE="INTEGER">
134  ! The ending PE number for the current tile.
135  ! </DATA>
136  ! <DATA NAME="grid_type" TYPE="CHARACTER(len=128)">
137  ! The global grid type.
138  ! </DATA>
140  REAL, _allocatable, DIMENSION(:,:) :: glo_lat, glo_lon
141  REAL, _allocatable, DIMENSION(:,:) :: aglo_lat, aglo_lon
142  INTEGER :: myxbegin, myybegin
143  INTEGER :: dimi, dimj
144  INTEGER :: adimi, adimj
145  INTEGER :: tile_number
146  INTEGER :: ntiles
147  INTEGER :: pestart, peend
148  CHARACTER(len=128) :: grid_type
149  END TYPE diag_global_grid_type
150  ! </TYPE>
151  ! </PRIVATE>
152 
153  ! <PRIVATE>
154  ! <TYPE NAME="point">
155  ! <DESCRIPTION>
156  ! Private point type to hold the (x,y,z) location for a (lat,lon)
157  ! location.
158  ! </DESCRIPTION>
159  ! <DATA NAME="x" TYPE="REAL">
160  ! The x value of the (x,y,z) coordinates.
161  ! </DATA>
162  ! <DATA NAME="y" TYPE="REAL">
163  ! The y value of the (x,y,z) coordinates.
164  ! </DATA>
165  ! <DATA NAME="z" TYPE="REAL">
166  ! The z value of the (x,y,z) coordinates.
167  ! </DATA>
168  TYPE :: point
169  REAL :: x,y,z
170  END TYPE point
171  ! </TYPE>
172  ! </PRIVATE>
173 
174  ! <PRIVATE>
175  ! <DATA NAME="diag_global_grid" TYPE="TYPE(diag_global_grid_type)">
176  ! Variable to hold the global grid data
177  ! </DATA>
178  ! </PRIVATE>
180 
181  ! <PRIVATE>
182  ! <DATA NAME="diag_grid_initialized" TYPE="LOGICAL" DEFAULT=".FALSE.">
183  ! Indicates if the diag_grid_mod has been initialized.
184  ! </DATA>
185  ! </PRIVATE>
186  LOGICAL :: diag_grid_initialized = .false.
187 
188  PRIVATE
191 
192 CONTAINS
193 
194  ! <SUBROUTINE NAME="diag_grid_init">
195  ! <OVERVIEW>
196  ! Send the global grid to the <TT>diag_manager_mod</TT> for
197  ! regional output.
198  ! </OVERVIEW>
199  ! <TEMPLATE>
200  ! SUBROUTINE diag_grid_init(domain, glo_lat, glo_lon, aglo_lat, aglo_lon)
201  ! </TEMPLATE>
202  ! <DESCRIPTION>
203  ! In order for the diag_manager to do regional output for grids
204  ! other than the standard lat/lon grid, the <TT>
205  ! diag_manager_mod</TT> needs to know the the latitude and
206  ! longitude values for the entire global grid. This procedure
207  ! is the mechanism the models will use to share their grid with
208  ! the diagnostic manager.
209  !
210  ! This procedure needs to be called after the grid is created,
211  ! and before the first call to register the fields.
212  ! </DESCRIPTION>
213  ! <IN NAME="domain" TYPE="INTEGER">
214  ! The domain to which the grid data corresponds.
215  ! </IN>
216  ! <IN NAME="glo_lat" TYPE="REAL, DIMENSION(:,:)">
217  ! The latitude information for the grid tile.
218  ! </IN>
219  ! <IN NAME="glo_lon" TYPE="REAL, DIMENSION(:,:)">
220  ! The longitude information for the grid tile.
221  ! </IN>
222  ! <IN NAME="aglo_lat" TYPE="REAL, DIMENSION(:,:)">
223  ! The latitude information for the a-grid tile.
224  ! </IN>
225  ! <IN NAME="aglo_lon" TYPE="REAL, DIMENSION(:,:)">
226  ! The longitude information for the a-grid tile.
227  ! </IN>
228  SUBROUTINE diag_grid_init(domain, glo_lat, glo_lon, aglo_lat, aglo_lon)
229  TYPE(domain2d), INTENT(in) :: domain
230  REAL, INTENT(in), DIMENSION(:,:) :: glo_lat, glo_lon
231  REAL, INTENT(in), DIMENSION(:,:) :: aglo_lat, aglo_lon
232 
233  INTEGER, DIMENSION(1) :: tile
234  INTEGER :: ntiles
235  INTEGER :: stat
236  INTEGER :: i_dim, j_dim
237  INTEGER :: ai_dim, aj_dim
238  INTEGER, DIMENSION(2) :: latdim, londim
239  INTEGER, DIMENSION(2) :: alatdim, alondim
240  INTEGER :: mype, npes, npespertile
241  INTEGER, ALLOCATABLE, DIMENSION(:) :: xbegin, xend, ybegin, yend
242 
243  ! Write the file version to the logfile
244  CALL write_version_number("DIAG_GRID_MOD", version)
245 
246  ! Verify all allocatable / pointers for diag_global_grid hare not
247  ! allocated / associated.
248  IF ( ALLOCATED(xbegin) ) DEALLOCATE(xbegin)
249  IF ( ALLOCATED(ybegin) ) DEALLOCATE(ybegin)
250  IF ( ALLOCATED(xend) ) DEALLOCATE(xend)
251  IF ( ALLOCATED(yend) ) DEALLOCATE(yend)
252 
253  ! What is my PE
254  mype = mpp_pe() -mpp_root_pe() + 1
255 
256  ! Get the domain/pe layout, and allocate the [xy]begin|end arrays/pointers
257  npes = mpp_npes()
258  ALLOCATE(xbegin(npes), &
259  & ybegin(npes), &
260  & xend(npes), &
261  & yend(npes), stat=stat)
262  IF ( stat .NE. 0 ) THEN
263  CALL error_mesg('diag_grid_mod::diag_grid_init',&
264  &'Could not allocate memory for the compute grid indices&
265  &.', fatal)
266  END IF
267 
268  ! Get tile information
269  ntiles = mpp_get_ntile_count(domain)
270  tile = mpp_get_tile_id(domain)
271 
272  ! Number of PEs per tile
273  npespertile = npes / ntiles
274  diag_global_grid%peEnd = npespertile * tile(1)
275  diag_global_grid%peStart = diag_global_grid%peEnd - npespertile + 1
276 
277  ! Get the compute domains
278  CALL mpp_get_compute_domains(domain,&
279  & xbegin=xbegin, xend=xend,&
280  & ybegin=ybegin, yend=yend)
281 
282  ! Module initialized
283  diag_grid_initialized = .true.
284 
285  ! Get the size of the grids
286  latdim = shape(glo_lat)
287  londim = shape(glo_lon)
288  IF ( (latdim(1) == londim(1)) .AND.&
289  &(latdim(2) == londim(2)) ) THEN
290  i_dim = latdim(1)
291  j_dim = latdim(2)
292  ELSE
293  CALL error_mesg('diag_grid_mod::diag_grid_init',&
294  &'glo_lat and glo_lon must be the same shape.', fatal)
295  END IF
296 
297  ! Same thing for the a-grid
298  alatdim = shape(aglo_lat)
299  alondim = shape(aglo_lon)
300  IF ( (alatdim(1) == alondim(1)) .AND. &
301  &(alatdim(2) == alondim(2)) ) THEN
302  IF ( tile(1) == 4 .OR. tile(1) == 5 ) THEN
303  ! These tiles need to be transposed.
304  ai_dim = alatdim(2)
305  aj_dim = alatdim(1)
306  ELSE
307  ai_dim = alatdim(1)
308  aj_dim = alatdim(2)
309  END IF
310  ELSE
311  CALL error_mesg('diag_grid_mod::diag_grid_init',&
312  & "a-grid's glo_lat and glo_lon must be the same shape.", fatal)
313  END IF
314 
315  ! Allocate the grid arrays
316  IF ( _allocated(diag_global_grid%glo_lat) .OR.&
317  & _allocated(diag_global_grid%glo_lon) ) THEN
318  IF ( mpp_pe() == mpp_root_pe() ) &
319  & CALL error_mesg('diag_grid_mod::diag_grid_init',&
320  &'The global grid has already been initialized', warning)
321  ELSE
322  ALLOCATE(diag_global_grid%glo_lat(i_dim,j_dim),&
323  & diag_global_grid%glo_lon(i_dim,j_dim), stat=stat)
324  IF ( stat .NE. 0 ) THEN
325  CALL error_mesg('diag_grid_mod::diag_grid_init',&
326  &'Could not allocate memory for the global grid.', fatal)
327  END IF
328  END IF
329 
330  ! Same thing for the a-grid
331  IF ( _allocated(diag_global_grid%aglo_lat) .OR.&
332  & _allocated(diag_global_grid%aglo_lon) ) THEN
333  IF ( mpp_pe() == mpp_root_pe() ) &
334  & CALL error_mesg('diag_grid_mod::diag_grid_init',&
335  &'The global a-grid has already been initialized', warning)
336  ELSE
337  ALLOCATE(diag_global_grid%aglo_lat(0:ai_dim-1,0:aj_dim-1),&
338  & diag_global_grid%aglo_lon(0:ai_dim-1,0:aj_dim-1), stat=stat)
339  IF ( stat .NE. 0 ) THEN
340  CALL error_mesg('diag_global_mod::diag_grid_init',&
341  &'Could not allocate memory for the global a-grid', fatal)
342  END IF
343  END IF
344 
345  ! Set the values for diag_global_grid
346 
347  ! If we are on tile 4 or 5, we need to transpose the grid to get
348  ! this to work.
349  IF ( tile(1) == 4 .OR. tile(1) == 5 ) THEN
350  diag_global_grid%aglo_lat = transpose(aglo_lat)
351  diag_global_grid%aglo_lon = transpose(aglo_lon)
352  ELSE
353  diag_global_grid%aglo_lat = aglo_lat
354  diag_global_grid%aglo_lon = aglo_lon
355  END IF
356  diag_global_grid%glo_lat = glo_lat
357  diag_global_grid%glo_lon = glo_lon
358  diag_global_grid%dimI = i_dim
359  diag_global_grid%dimJ = j_dim
360  diag_global_grid%adimI = ai_dim
361  diag_global_grid%adimJ = aj_dim
362  !--- For the nested model, the nested region only has 1 tile ( ntiles = 1) but
363  !--- the tile_id is 7 for the nested region. In the routine get_local_indexes,
364  !--- local variables ijMin and ijMax have dimesnion (ntiles) and will access
365  !--- ijMin(diag_global_grid%tile_number,:). For the nested region, ntiles = 1 and
366  !--- diag_global_grid%tile_number = 7 will cause out of bounds. So need to
367  !--- set diag_global_grid%tile_number = 1 when ntiles = 1 for the nested model.
368  if(ntiles == 1) then
369  diag_global_grid%tile_number = 1
370  else
371  diag_global_grid%tile_number = tile(1)
372  endif
373  diag_global_grid%ntiles = ntiles
374  diag_global_grid%myXbegin = xbegin(mype)
375  diag_global_grid%myYbegin = ybegin(mype)
376 
377  ! Unallocate arrays used here
378  DEALLOCATE(xbegin)
379  DEALLOCATE(ybegin)
380  DEALLOCATE(xend)
381  DEALLOCATE(yend)
382  END SUBROUTINE diag_grid_init
383  ! </SUBROUTINE>
384 
385  ! <SUBROUTINE NAME="diag_grid_end">
386  ! <OVERVIEW>
387  ! Unallocate the diag_global_grid variable.
388  ! </OVERVIEW>
389  ! <TEMPLATE>
390  ! SUBROUTINE diag_grid_end()
391  ! </TEMPLATE>
392  ! <DESCRIPTION>
393  ! The <TT>diag_global_grid</TT> variable is only needed during
394  ! the register field calls, and then only if there are fields
395  ! requestion regional output. Once all the register fields
396  ! calls are complete (before the first <TT>send_data</TT> call
397  ! this procedure can be called to free up memory.
398  ! </DESCRIPTION>
399  SUBROUTINE diag_grid_end()
401  IF ( diag_grid_initialized ) THEN
402  ! De-allocate grid
403  IF ( _allocated(diag_global_grid%glo_lat) ) THEN
404  DEALLOCATE(diag_global_grid%glo_lat)
405  ELSE IF ( mpp_pe() == mpp_root_pe() ) THEN
406  CALL error_mesg('diag_grid_mod::diag_grid_end',&
407  &'diag_global_grid%glo_lat was not allocated.', warning)
408  END IF
409 
410  IF ( _allocated(diag_global_grid%glo_lon) ) THEN
411  DEALLOCATE(diag_global_grid%glo_lon)
412  ELSE IF ( mpp_pe() == mpp_root_pe() ) THEN
413  CALL error_mesg('diag_grid_mod::diag_grid_end',&
414  &'diag_global_grid%glo_lon was not allocated.', warning)
415  END IF
416  ! De-allocate a-grid
417  IF ( _allocated(diag_global_grid%aglo_lat) ) THEN
418  DEALLOCATE(diag_global_grid%aglo_lat)
419  ELSE IF ( mpp_pe() == mpp_root_pe() ) THEN
420  CALL error_mesg('diag_grid_mod::diag_grid_end',&
421  &'diag_global_grid%aglo_lat was not allocated.', warning)
422  END IF
423 
424  IF ( _allocated(diag_global_grid%aglo_lon) ) THEN
425  DEALLOCATE(diag_global_grid%aglo_lon)
426  ELSE IF ( mpp_pe() == mpp_root_pe() ) THEN
427  CALL error_mesg('diag_grid_mod::diag_grid_end',&
428  &'diag_global_grid%aglo_lon was not allocated.', warning)
429  END IF
430 
431  diag_grid_initialized = .false.
432  END IF
433  END SUBROUTINE diag_grid_end
434  ! </SUBROUTINE>
435 
436  ! <SUBROUTINE NAME="get_local_indexes">
437  ! <OVERVIEW>
438  ! Find the local start and local end indexes on the local PE
439  ! for regional output.
440  ! </OVERVIEW>
441  ! <TEMPLATE>
442  ! SUBROUTINE get_local_indexes(latStart, latEnd, lonStart,
443  ! lonEnd, istart, iend, jstart, jend)
444  ! </TEMPLATE>
445  ! <DESCRIPTION>
446  ! Given a defined region, find the local indexes on the local
447  ! PE surrounding the region.
448  ! </DESCRIPTION>
449  ! <IN NAME="latStart" TYPE="REAL">
450  ! The minimum latitude value defining the region. This value
451  ! must be less than latEnd, and be in the range [-90,90]
452  ! </IN>
453  ! <IN NAME="latEnd" TYPE="REAL">
454  ! The maximum latitude value defining the region. This value
455  ! must be greater than latStart, and be in the range [-90,90]
456  ! </IN>
457  ! <IN NAME="lonStart" TYPE="REAL">
458  ! The western most longitude value defining the region.
459  ! Possible ranges are either [-180,180] or [0,360].
460  ! </IN>
461  ! <IN NAME="lonEnd" TYPE="REAL">
462  ! The eastern most longitude value defining the region.
463  ! Possible ranges are either [-180,180] or [0,360].
464  ! </IN>
465  ! <OUT NAME="istart" TYPE="INTEGER">
466  ! The local start index on the local PE in the 'i' direction.
467  ! </OUT>
468  ! <OUT NAME="iend" TYPE="INTEGER">
469  ! The local end index on the local PE in the 'i' direction.
470  ! </OUT>
471  ! <OUT NAME="jstart" TYPE="INTEGER">
472  ! The local start index on the local PE in the 'j' direction.
473  ! </OUT>
474  ! <OUT NAME="jend" TYPE="INTEGER">
475  ! The local end index on the local PE in the 'j' direction.
476  ! </OUT>
477  SUBROUTINE get_local_indexes(latStart, latEnd, lonStart, lonEnd,&
478  & istart, iend, jstart, jend)
479  REAL, INTENT(in) :: latstart, lonstart !< lat/lon start angles
480  REAL, INTENT(in) :: latend, lonend !< lat/lon end angles
481  INTEGER, INTENT(out) :: istart, jstart !< i/j start indexes
482  INTEGER, INTENT(out) :: iend, jend !< i/j end indexes
483 
484  REAL, ALLOCATABLE, DIMENSION(:,:) :: delta_lat, delta_lon, grid_lon
485 
486  REAL, DIMENSION(4) :: dists_lon, dists_lat
487  REAL :: lonendadj, my_lonstart, my_lonend
488 
489  INTEGER, ALLOCATABLE, DIMENSION(:,:) :: ijmin, ijmax
490  INTEGER :: mytile, ntiles, i, j, k, dimi, dimj, istat
491  INTEGER :: count
492 
493  LOGICAL :: onmype
494 
495  !For cfsite potential fix.
496  INTEGER :: mini
497  INTEGER :: minj
498  REAL :: minimum_distance
499  REAL :: global_min_distance
500  INTEGER :: rank_buf
501 
502  IF ( .NOT. diag_grid_initialized )&
503  & CALL error_mesg('diag_grid_mod::get_local_indexes',&
504  &'Module not initialized, first initialze module with a call &
505  &to diag_grid_init', fatal)
506 
507  ! Make adjustment for negative longitude values
508  if ( lonstart < 0. ) then
509  my_lonstart = lonstart + 360.
510  else
511  my_lonstart = lonstart
512  end if
513  if ( lonend < 0. ) then
514  my_lonend = lonend + 360.
515  else
516  my_lonend = lonend
517  end if
518 
519  IF (latstart .EQ. latend .AND. my_lonstart .EQ. my_lonend) THEN
520 
521  !For a single point, use the a-grid longitude and latitude
522  !values.
523 
524  mytile = diag_global_grid%tile_number
525  ntiles = diag_global_grid%ntiles
526 
527  allocate(ijmin(ntiles,2))
528  ijmin = 0
529 
530  !Find the i,j indices of the a-grid point nearest to the
531  !my_lonStart,latStart point.
532  CALL find_nearest_agrid_index(latstart, &
533  my_lonstart, &
534  mini, &
535  minj, &
536  minimum_distance)
537 
538  !Find the minimum distance across all ranks.
539  global_min_distance = minimum_distance
540  CALL mpp_min(global_min_distance)
541 
542  !In the case of a tie (i.e. two ranks with exactly the same
543  !minimum distance), use the i,j values from the larger rank id.
544  IF (global_min_distance .EQ. minimum_distance) THEN
545  rank_buf = mpp_pe()
546  ELSE
547  rank_buf = -1
548  ENDIF
549  CALL mpp_max(rank_buf)
550 
551  !Sanity check.
552  IF (rank_buf .EQ. -1) THEN
553  CALL error_mesg("get_local_indexes", &
554  "No rank has minimum distance.", &
555  fatal)
556  ENDIF
557 
558  IF (rank_buf .EQ. mpp_pe()) THEN
559  ijmin(mytile,1) = mini + diag_global_grid%myXbegin - 1
560  ijmin(mytile,2) = minj + diag_global_grid%myYbegin - 1
561  ENDIF
562 
563  DO i = 1,ntiles
564  CALL mpp_max(ijmin(i,1))
565  CALL mpp_max(ijmin(i,2))
566  ENDDO
567 
568  istart = ijmin(mytile,1)
569  jstart = ijmin(mytile,2)
570  iend = istart
571  jend = jstart
572 
573  DEALLOCATE(ijmin)
574  ELSE
575 
576  mytile = diag_global_grid%tile_number
577  ntiles = diag_global_grid%ntiles
578 
579  ! Arrays to home min/max for each tile
580  ALLOCATE(ijmin(ntiles,2), stat=istat)
581  IF ( istat .NE. 0 )&
582  & CALL error_mesg('diag_grid_mod::get_local_indexes',&
583  &'Cannot allocate ijMin index array', fatal)
584  ALLOCATE(ijmax(ntiles,2), stat=istat)
585  IF ( istat .NE. 0 )&
586  & CALL error_mesg('diag_grid_mod::get_local_indexes',&
587  &'Cannot allocate ijMax index array', fatal)
588  ijmin = 0
589  ijmax = 0
590 
591  ! There will be four points to define a region, find all four.
592  ! Need to call the correct function depending on if the tile is a
593  ! pole tile or not.
594  dimi = diag_global_grid%dimI
595  dimj = diag_global_grid%dimJ
596 
597  ! Build the delta array
598  ALLOCATE(delta_lat(dimi,dimj), stat=istat)
599  IF ( istat .NE. 0 )&
600  & CALL error_mesg('diag_grid_mod::get_local_indexes',&
601  &'Cannot allocate latitude delta array', fatal)
602  ALLOCATE(delta_lon(dimi,dimj), stat=istat)
603  IF ( istat .NE. 0 )&
604  & CALL error_mesg('diag_grid_mod::get_local_indexes',&
605  &'Cannot allocate longitude delta array', fatal)
606  DO j=1, dimj
607  DO i=1, dimi
608  count = 0
609  dists_lon = 0.
610  dists_lat = 0.
611  IF ( i < dimi ) THEN
612  dists_lon(1) = abs(diag_global_grid%glo_lon(i+1,j) - diag_global_grid%glo_lon(i,j))
613  dists_lat(1) = abs(diag_global_grid%glo_lat(i+1,j) - diag_global_grid%glo_lat(i,j))
614  count = count+1
615  END IF
616  IF ( j < dimj ) THEN
617  dists_lon(2) = abs(diag_global_grid%glo_lon(i,j+1) - diag_global_grid%glo_lon(i,j))
618  dists_lat(2) = abs(diag_global_grid%glo_lat(i,j+1) - diag_global_grid%glo_lat(i,j))
619  count = count+1
620  END IF
621  IF ( i > 1 ) THEN
622  dists_lon(3) = abs(diag_global_grid%glo_lon(i,j) - diag_global_grid%glo_lon(i-1,j))
623  dists_lat(3) = abs(diag_global_grid%glo_lat(i,j) - diag_global_grid%glo_lat(i-1,j))
624  count = count+1
625  END IF
626  IF ( j > 1 ) THEN
627  dists_lon(4) = abs(diag_global_grid%glo_lon(i,j) - diag_global_grid%glo_lon(i,j-1))
628  dists_lat(4) = abs(diag_global_grid%glo_lat(i,j) - diag_global_grid%glo_lat(i,j-1))
629  count = count+1
630  END IF
631 
632  ! Fix wrap around problem
633  DO k=1, 4
634  IF ( dists_lon(k) > 180.0 ) THEN
635  dists_lon(k) = 360.0 - dists_lon(k)
636  END IF
637  END DO
638  delta_lon(i,j) = sum(dists_lon)/real(count)
639  delta_lat(i,j) = sum(dists_lat)/real(count)
640  END DO
641  END DO
642 
643  ijmin = huge(1)
644  ijmax = -huge(1)
645 
646  ! Adjusted longitude array
647  ALLOCATE(grid_lon(dimi,dimj), stat=istat)
648  IF ( istat .NE. 0 )&
649  & CALL error_mesg('diag_grid_mod::get_local_indexes',&
650  &'Cannot allocate temporary longitude array', fatal)
651  grid_lon = diag_global_grid%glo_lon
652 
653  ! Make adjustments where required
654  IF ( my_lonstart > my_lonend ) THEN
655  WHERE ( grid_lon < my_lonstart )
656  grid_lon = grid_lon + 360.0
657  END WHERE
658  lonendadj = my_lonend + 360.0
659  ELSE
660  lonendadj = my_lonend
661  END IF
662 
663  DO j=1, dimj-1
664  DO i=1, dimi-1
665  onmype = .false.
666  IF ( latstart-delta_lat(i,j) <= diag_global_grid%glo_lat(i,j) .AND.&
667  & diag_global_grid%glo_lat(i,j) < latend+delta_lat(i,j) ) THEN
668  ! Short-cut for the poles
669  IF ( (abs(latstart)-delta_lat(i,j) <= 90.0 .AND.&
670  & 90.0 <= abs(latend)+delta_lat(i,j)) .AND.&
671  & abs(diag_global_grid%glo_lat(i,j)) == 90.0 ) THEN
672  onmype = .true.
673  ELSE IF ( (my_lonstart-delta_lon(i,j) <= grid_lon(i,j) .AND.&
674  & grid_lon(i,j) < lonendadj+delta_lon(i,j)) ) THEN
675  onmype = .true.
676  ELSE
677  onmype = .false.
678  END IF
679  IF ( onmype ) THEN
680  ijmin(mytile,1) = min(ijmin(mytile,1),i + diag_global_grid%myXbegin - 1)
681  ijmax(mytile,1) = max(ijmax(mytile,1),i + diag_global_grid%myXbegin - 1)
682  ijmin(mytile,2) = min(ijmin(mytile,2),j + diag_global_grid%myYbegin - 1)
683  ijmax(mytile,2) = max(ijmax(mytile,2),j + diag_global_grid%myYbegin - 1)
684  END IF
685  END IF
686  END DO
687  END DO
688  DEALLOCATE(delta_lon)
689  DEALLOCATE(delta_lat)
690  DEALLOCATE(grid_lon)
691 
692  ! Global min/max reduce
693  DO i=1, ntiles
694  CALL mpp_min(ijmin(i,1))
695  CALL mpp_max(ijmax(i,1))
696  CALL mpp_min(ijmin(i,2))
697  CALL mpp_max(ijmax(i,2))
698  END DO
699 
700  IF ( ijmin(mytile,1) == huge(1) .OR. ijmax(mytile,1) == -huge(1) ) THEN
701  ijmin(mytile,1) = 0
702  ijmax(mytile,1) = 0
703  END IF
704  IF ( ijmin(mytile,2) == huge(1) .OR. ijmax(mytile,2) == -huge(1) ) THEN
705  ijmin(mytile,2) = 0
706  ijmax(mytile,2) = 0
707  END IF
708 
709  istart = ijmin(mytile,1)
710  jstart = ijmin(mytile,2)
711  iend = ijmax(mytile,1)
712  jend = ijmax(mytile,2)
713 
714  DEALLOCATE(ijmin)
715  DEALLOCATE(ijmax)
716  END IF
717 
718  END SUBROUTINE get_local_indexes
719  ! </SUBROUTINE>
720 
721  ! <SUBROUTINE NAME="get_local_indexes2">
722  ! <OVERVIEW>
723  ! Find the indices of the nearest grid point of the a-grid to the
724  ! specified (lon,lat) location on the local PE. if desired point not
725  ! within domain of local PE, return (0,0) as the indices.
726  ! </OVERVIEW>
727  ! <TEMPLATE>
728  ! SUBROUTINE get_local_indexes2 (lat, lon, iindex, jindex)
729  ! </TEMPLATE>
730  ! <DESCRIPTION>
731  ! Given a specified location, find the nearest a-grid indices on
732  ! the local PE.
733  ! </DESCRIPTION>
734  ! <IN NAME="lat" TYPE="REAL">
735  ! The requested latitude. This value must be in the range [-90,90]
736  ! </IN>
737  ! <IN NAME="lon" TYPE="REAL">
738  ! The requested longitude.
739  ! Possible ranges are either [-180,180] or [0,360].
740  ! </IN>
741  ! <OUT NAME="iindex" TYPE="INTEGER">
742  ! The local index on the local PE in the 'i' direction.
743  ! </OUT>
744  ! <OUT NAME="jindex" TYPE="INTEGER">
745  ! The local index on the local PE in the 'j' direction.
746  ! </OUT>
747  SUBROUTINE get_local_indexes2(lat, lon, iindex, jindex)
748  REAL, INTENT(in) :: lat, lon !< lat/lon location
749  INTEGER, INTENT(out) :: iindex, jindex !< i/j indexes
750 
751  INTEGER :: indexes(2)
752 
753  IF ( .NOT. diag_grid_initialized )&
754  & CALL error_mesg('diag_grid_mod::get_local_indexes2',&
755  &'Module not initialized, first initialze module with a call &
756  &to diag_grid_init', fatal)
757 
758  indexes = 0
759 
760  IF ( mod(diag_global_grid%tile_number,3) == 0 ) THEN
761  IF ( lat > 30.0 .AND. diag_global_grid%tile_number == 3 ) THEN
762  indexes(:) = find_pole_index_agrid(lat,lon)
763  ELSE IF ( lat < -30.0 .AND. diag_global_grid%tile_number == 6 ) THEN
764  indexes(:) = find_pole_index_agrid(lat,lon)
765  ENDIF
766  ELSE
767  indexes(:) = find_equator_index_agrid(lat,lon)
768  END IF
769 
770  iindex = indexes(1)
771  jindex = indexes(2)
772  IF (iindex == diag_global_grid%adimI -1 .OR.&
773  jindex == diag_global_grid%adimJ -1 ) THEN
774  iindex = 0
775  jindex = 0
776  ENDIF
777 
778  END SUBROUTINE get_local_indexes2
779  ! </SUBROUTINE>
780 
781  ! <PRIVATE>
782  ! <FUNCTION NAME="rad2deg">
783  ! <OVERVIEW>
784  ! Convert and angle in radian to degrees.
785  ! </OVERVIEW>
786  ! <TEMPLATE>
787  ! PURE ELEMENTAL REAL FUNCTION rad2deg(angle)
788  ! </TEMPLATE>
789  ! <DESCRIPTION>
790  ! Given a scalar, or an array of angles in radians this
791  ! function will return a scalar or array (of the same
792  ! dimension) of angles in degrees.
793  ! </DESCRIPTION>
794  ! <IN NAME="angle" TYPE="REAL">
795  ! Scalar or array of angles in radians.
796  ! </IN>
797  ! <OUT NAME="rad2deg" TYPE="REAL">
798  ! Scalar or array (depending on the size of angle) of angles in
799  ! degrees.
800  ! </OUT>
801  PURE ELEMENTAL REAL FUNCTION rad2deg(angle)
802  REAL, INTENT(in) :: angle
803 
804  rad2deg = rad_to_deg * angle
805  END FUNCTION rad2deg
806  ! </FUNCTION>
807  ! </PRIVATE>
808 
809  ! <PRIVATE>
810  ! <FUNCTION NAME="deg2rad">
811  ! <OVERVIEW>
812  ! Convert an angle in degrees to radians.
813  ! </OVERVIEW>
814  ! <TEMPLATE>
815  ! PURE ELEMENTAL REAL FUNCTION deg2rad(angle)
816  ! </TEMPLATE>
817  ! <DESCRIPTION>
818  ! Given a scalar, or an array of angles in degrees this
819  ! function will return a scalar or array (of the same
820  ! dimension) of angles in radians.
821  ! </DESCRIPTION>
822  ! <IN NAME="angle" TYPE="REAL">
823  ! Scalar or array of angles in degrees.
824  ! </IN>
825  PURE ELEMENTAL REAL FUNCTION deg2rad(angle)
826  REAL, INTENT(in) :: angle
827 
828  deg2rad = deg_to_rad * angle
829  END FUNCTION deg2rad
830  ! </FUNCTION>
831  ! </PRIVATE>
832 
833  ! <PRIVATE>
834  ! <FUNCTION NAME="find_pole_index_agrid">
835  ! <OVERVIEW>
836  ! Return the closest index (i,j) to the given (lat,lon) point.
837  ! </OVERVIEW>
838  ! <TEMPLATE>
839  ! PURE FUNCTION find_pole_index_agrid(lat, lon)
840  ! </TEMPLATE>
841  ! <DESCRIPTION>
842  ! This function searches a pole a-grid tile looking for the grid point
843  ! closest to the give (lat, lon) location, and returns the i
844  ! and j indexes of the point.
845  ! </DESCRIPTION>
846  ! <IN NAME="lat" TYPE="REAL">
847  ! Latitude location
848  ! </IN>
849  ! <IN NAME="lon" TYPE="REAL">
850  ! Longitude location
851  ! </IN>
852  ! <OUT NAME="find_pole_index" TYPE="INTEGER, DIMENSION(2)">
853  ! The (i, j) location of the closest grid to the given (lat,
854  ! lon) location.
855  ! </OUT>
856  PURE FUNCTION find_pole_index_agrid(lat, lon)
857  INTEGER, DIMENSION(2) :: find_pole_index_agrid
858  REAL, INTENT(in) :: lat, lon
859 
860  INTEGER :: indxi, indxj !< Indexes to be returned.
861  INTEGER :: dimi, dimj !< Size of the grid dimensions
862  INTEGER :: i,j !< Count indexes
863  INTEGER :: nearestcorner !< index of the nearest corner.
864  INTEGER, DIMENSION(4,2) :: ijarray !< indexes of the cornerPts and pntDistances arrays
865  REAL :: llat, llon
866  REAL :: maxctrdist !< maximum distance to center of grid
867  REAL, DIMENSION(4) :: pntdistances !< distance from origPt to corner
868  TYPE(point) :: origpt !< Original point
869  REAL, DIMENSION(4,2) :: cornerpts !< Corner points using (lat,lon)
870  TYPE(point), DIMENSION(9) :: points !< xyz of 8 nearest neighbors
871  REAL, DIMENSION(9) :: distsqrd !< distance between origPt and points(:)
872 
873  ! Set the inital fail values for indxI and indxJ
874  indxi = 0
875  indxj = 0
876 
877  dimi = diag_global_grid%adimI
878  dimj = diag_global_grid%adimJ
879 
880  ! Since the poles have an non-unique longitude value, make a small correction if looking for one of the poles.
881  IF ( lat == 90.0 ) THEN
882  llat = lat - .1
883  ELSE IF ( lat == -90.0 ) THEN
884  llat = lat + .1
885  ELSE
886  llat = lat
887  END IF
888  llon = lon
889 
890  origpt = latlon2xyz(llat,llon)
891 
892  iloop: DO i=0, dimi-2
893  jloop: DO j = 0, dimj-2
894  cornerpts = reshape( (/ diag_global_grid%aglo_lat(i, j), diag_global_grid%aglo_lon(i, j),&
895  & diag_global_grid%aglo_lat(i+1,j+1),diag_global_grid%aglo_lon(i+1,j+1),&
896  & diag_global_grid%aglo_lat(i+1,j), diag_global_grid%aglo_lon(i+1,j),&
897  & diag_global_grid%aglo_lat(i, j+1),diag_global_grid%aglo_lon(i, j+1) /),&
898  & (/ 4, 2 /), order=(/2,1/) )
899  ! Find the maximum half distance of the corner points
900  maxctrdist = max(gcirdistance(cornerpts(1,1),cornerpts(1,2), cornerpts(2,1),cornerpts(2,2)),&
901  & gcirdistance(cornerpts(3,1),cornerpts(3,2), cornerpts(4,1),cornerpts(4,2)))
902 
903  ! Find the distance of the four corner points to the point of interest.
904  pntdistances = gcirdistance(cornerpts(:,1),cornerpts(:,2), llat,llon)
905 
906  IF ( (minval(pntdistances) <= maxctrdist) .AND. (i*j.NE.0) ) THEN
907  ! Set up the i,j index array
908  ijarray = reshape( (/ i, j, i+1, j+1, i+1, j, i, j+1 /), (/ 4, 2 /), order=(/2,1/) )
909 
910  ! the nearest point index
911  nearestcorner = minloc(pntdistances,1)
912 
913  indxi = ijarray(nearestcorner,1)
914  indxj = ijarray(nearestcorner,2)
915 
916  EXIT iloop
917  END IF
918  END DO jloop
919  END DO iloop
920 
921 
922  ! Make sure we have indexes in the correct range
923  valid: IF ( (indxi <= 0 .OR. dimi-1 <= indxi) .OR. &
924  & (indxj <= 0 .OR. dimj-1 <= indxj) ) THEN
925  indxi = 0
926  indxj = 0
927  ELSE ! indxI and indxJ are valid.
928  ! Since we are looking for the closest grid point to the
929  ! (lat,lon) point, we need to check the surrounding
930  ! points. The indexes for the variable points are as follows
931  !
932  ! 1---4---7
933  ! | | |
934  ! 2---5---8
935  ! | | |
936  ! 3---6---9
937 
938  ! Set the 'default' values for points(:) x,y,z to some large
939  ! value.
940  DO i=1, 9
941  points(i)%x = 1.0e20
942  points(i)%y = 1.0e20
943  points(i)%z = 1.0e20
944  END DO
945 
946  ! All the points around the i,j indexes
947  points(1) = latlon2xyz(diag_global_grid%aglo_lat(indxi-1,indxj+1),&
948  & diag_global_grid%aglo_lon(indxi-1,indxj+1))
949  points(2) = latlon2xyz(diag_global_grid%aglo_lat(indxi-1,indxj),&
950  & diag_global_grid%aglo_lon(indxi-1,indxj))
951  points(3) = latlon2xyz(diag_global_grid%aglo_lat(indxi-1,indxj-1),&
952  & diag_global_grid%aglo_lon(indxi-1,indxj-1))
953  points(4) = latlon2xyz(diag_global_grid%aglo_lat(indxi, indxj+1),&
954  & diag_global_grid%aglo_lon(indxi, indxj+1))
955  points(5) = latlon2xyz(diag_global_grid%aglo_lat(indxi, indxj),&
956  & diag_global_grid%aglo_lon(indxi, indxj))
957  points(6) = latlon2xyz(diag_global_grid%aglo_lat(indxi, indxj-1),&
958  & diag_global_grid%aglo_lon(indxi, indxj-1))
959  points(7) = latlon2xyz(diag_global_grid%aglo_lat(indxi+1,indxj+1),&
960  & diag_global_grid%aglo_lon(indxi+1,indxj+1))
961  points(8) = latlon2xyz(diag_global_grid%aglo_lat(indxi+1,indxj),&
962  & diag_global_grid%aglo_lon(indxi+1,indxj))
963  points(9) = latlon2xyz(diag_global_grid%aglo_lat(indxi+1,indxj-1),&
964  & diag_global_grid%aglo_lon(indxi+1,indxj-1))
965 
966 
967  ! Calculate the distance squared between the points(:) and the origPt
968  distsqrd = distancesqrd(origpt, points)
969 
970  SELECT CASE (minloc(distsqrd,1))
971  CASE ( 1 )
972  indxi = indxi-1
973  indxj = indxj+1
974  CASE ( 2 )
975  indxi = indxi-1
976  indxj = indxj
977  CASE ( 3 )
978  indxi = indxi-1
979  indxj = indxj-1
980  CASE ( 4 )
981  indxi = indxi
982  indxj = indxj+1
983  CASE ( 5 )
984  indxi = indxi
985  indxj = indxj
986  CASE ( 6 )
987  indxi = indxi
988  indxj = indxj-1
989  CASE ( 7 )
990  indxi = indxi+1
991  indxj = indxj+1
992  CASE ( 8 )
993  indxi = indxi+1
994  indxj = indxj
995  CASE ( 9 )
996  indxi = indxi+1
997  indxj = indxj-1
998  CASE DEFAULT
999  indxi = 0
1000  indxj = 0
1001  END SELECT
1002  END IF valid
1003 
1004  ! Set the return value for the funtion
1005  find_pole_index_agrid = (/indxi, indxj/)
1006  END FUNCTION find_pole_index_agrid
1007  ! </FUNCTION>
1008  ! </PRIVATE>
1009 
1010  ! <PRIVATE>
1011  ! <FUNCTION NAME="find_equator_index_agrid">
1012  ! <OVERVIEW>
1013  ! Return the closest index (i,j) to the given (lat,lon) point.
1014  ! </OVERVIEW>
1015  ! <TEMPLATE>
1016  ! PURE FUNCTION find_equator_index_agrid(lat, lon)
1017  ! </TEMPLATE>
1018  ! <DESCRIPTION>
1019  ! This function searches a equator grid tile looking for the grid point
1020  ! closest to the give (lat, lon) location, and returns the i
1021  ! and j indexes of the point.
1022  ! </DESCRIPTION>
1023  ! <IN NAME="lat" TYPE="REAL">
1024  ! Latitude location
1025  ! </IN>
1026  ! <IN NAME="lon" TYPE="REAL">
1027  ! Longitude location
1028  ! </IN>
1029  ! <OUT NAME="find_equator_index" TYPE="INTEGER, DIMENSION(2)">
1030  ! The (i, j) location of the closest grid to the given (lat,
1031  ! lon) location.
1032  ! </OUT>
1033  PURE FUNCTION find_equator_index_agrid(lat, lon)
1034  INTEGER, DIMENSION(2) :: find_equator_index_agrid
1035  REAL, INTENT(in) :: lat, lon
1036 
1037  INTEGER :: indxi, indxj !< Indexes to be returned.
1038  INTEGER :: indxi_tmp !< Hold the indxI value if on tile 3 or 4
1039  INTEGER :: dimi, dimj !< Size of the grid dimensions
1040  INTEGER :: i,j !< Count indexes
1041  INTEGER :: jstart, jend, nextj !< j counting variables
1042  TYPE(point) :: origpt !< Original point
1043  TYPE(point), DIMENSION(4) :: points !< xyz of 8 nearest neighbors
1044  REAL, DIMENSION(4) :: distsqrd !< distance between origPt and points(:)
1045 
1046  ! Set the inital fail values for indxI and indxJ
1047  indxi = 0
1048  indxj = 0
1049 
1050  dimi = diag_global_grid%adimI
1051  dimj = diag_global_grid%adimJ
1052 
1053  ! check to see if the 'fix' for the latitude index is needed
1054  IF ( diag_global_grid%aglo_lat(1,1) > &
1055  &diag_global_grid%aglo_lat(1,2) ) THEN
1056  ! reverse the j search
1057  jstart = dimj-1
1058  jend = 1
1059  nextj = -1
1060  ELSE
1061  jstart = 0
1062  jend = dimj-2
1063  nextj = 1
1064  END IF
1065 
1066  ! find the I index
1067  iloop: DO i=0, dimi-2
1068  IF ( diag_global_grid%aglo_lon(i,0) >&
1069  & diag_global_grid%aglo_lon(i+1,0) ) THEN
1070  ! We are at the 0 longitudal line
1071  IF ( (diag_global_grid%aglo_lon(i,0) <= lon .AND. lon <= 360.) .OR.&
1072  & (0. <= lon .AND. lon < diag_global_grid%aglo_lon(i+1, 0)) ) THEN
1073  indxi = i
1074  EXIT iloop
1075  END IF
1076  ELSEIF ( diag_global_grid%aglo_lon(i,0) <= lon .AND.&
1077  & lon <= diag_global_grid%aglo_lon(i+1,0) ) THEN
1078  indxi = i
1079  EXIT iloop
1080  END IF
1081  END DO iloop
1082 
1083  ! Find the J index
1084  IF ( indxi > 0 ) THEN
1085  jloop: DO j=jstart, jend, nextj
1086  IF ( diag_global_grid%aglo_lat(indxi,j) <= lat .AND.&
1087  & lat <= diag_global_grid%aglo_lat(indxi,j+nextj) ) THEN
1088  indxj = j
1089  EXIT jloop
1090  END IF
1091  END DO jloop
1092  END IF
1093 
1094  ! Make sure we have indexes in the correct range
1095  valid: IF ( (indxi <= 0 .OR. dimi-1 < indxi) .OR. &
1096  & (indxj <= 0 .OR. dimj-1 < indxj) ) THEN
1097  indxi = 0
1098  indxj = 0
1099  ELSE ! indxI and indxJ are valid.
1100  ! Since we are looking for the closest grid point to the
1101  ! (lat,lon) point, we need to check the surrounding
1102  ! points. The indexes for the variable points are as follows
1103  !
1104  ! 1---3
1105  ! | |
1106  ! 2---4
1107 
1108  ! The original point
1109  origpt = latlon2xyz(lat,lon)
1110 
1111  ! Set the 'default' values for points(:) x,y,z to some large
1112  ! value.
1113  DO i=1, 4
1114  points(i)%x = 1.0e20
1115  points(i)%y = 1.0e20
1116  points(i)%z = 1.0e20
1117  END DO
1118 
1119  ! The original point
1120  origpt = latlon2xyz(lat,lon)
1121 
1122  points(1) = latlon2xyz(diag_global_grid%aglo_lat(indxi,indxj),&
1123  & diag_global_grid%aglo_lon(indxi,indxj))
1124  points(2) = latlon2xyz(diag_global_grid%aglo_lat(indxi,indxj+nextj),&
1125  & diag_global_grid%aglo_lon(indxi,indxj+nextj))
1126  points(3) = latlon2xyz(diag_global_grid%aglo_lat(indxi+1,indxj+nextj),&
1127  & diag_global_grid%aglo_lon(indxi+1,indxj+nextj))
1128  points(4) = latlon2xyz(diag_global_grid%aglo_lat(indxi+1,indxj),&
1129  & diag_global_grid%aglo_lon(indxi+1,indxj))
1130 
1131  ! Find the distance between the original point and the four
1132  ! grid points
1133  distsqrd = distancesqrd(origpt, points)
1134 
1135  SELECT CASE (minloc(distsqrd,1))
1136  CASE ( 1 )
1137  indxi = indxi;
1138  indxj = indxj;
1139  CASE ( 2 )
1140  indxi = indxi;
1141  indxj = indxj+nextj;
1142  CASE ( 3 )
1143  indxi = indxi+1;
1144  indxj = indxj+nextj;
1145  CASE ( 4 )
1146  indxi = indxi+1;
1147  indxj = indxj;
1148  CASE DEFAULT
1149  indxi = 0;
1150  indxj = 0;
1151  END SELECT
1152 
1153  ! If we are on tile 3 or 4, then the indxI and indxJ are
1154  ! reversed due to the transposed grids.
1155  IF ( diag_global_grid%tile_number == 4 .OR.&
1156  & diag_global_grid%tile_number == 5 ) THEN
1157  indxi_tmp = indxi
1158  indxi = indxj
1159  indxj = indxi_tmp
1160  END IF
1161  END IF valid
1162 
1163  ! Set the return value for the function
1164  find_equator_index_agrid = (/indxi, indxj/)
1165  END FUNCTION find_equator_index_agrid
1166  ! </FUNCTION>
1167  ! </PRIVATE>
1168 
1169  ! <PRIVATE>
1170  ! <FUNCTION NAME="latlon2xyz">
1171  ! <OVERVIEW>
1172  ! Return the (x,y,z) position of a given (lat,lon) point.
1173  ! </OVERVIEW>
1174  ! <TEMPLATE>
1175  ! PURE ELEMENTAL TYPE(point) FUNCTION latlon2xyz(lat, lon)
1176  ! </TEMPLATE>
1177  ! <DESCRIPTION>
1178  ! Given a specific (lat, lon) point on the Earth, return the
1179  ! corresponding (x,y,z) location. The return of latlon2xyz
1180  ! will be either a scalar or an array of the same size as lat
1181  ! and lon.
1182  ! </DESCRIPTION>
1183  ! <IN NAME="lat" TYPE="REAL">
1184  ! The latitude of the (x,y,z) location to find. <TT>lat</TT>
1185  ! can be either a scalar or array. <TT>lat</TT> must be of the
1186  ! same rank / size as <TT>lon</TT>. This function assumes
1187  ! <TT>lat</TT> is in the range [-90,90].
1188  ! </IN>
1189  ! <IN NAME="lon" TYPE="REAL">
1190  ! The longitude of the (x,y,z) location to find. <TT>lon</TT>
1191  ! can be either a scalar or array. <TT>lon</TT> must be of the
1192  ! same rank / size as <TT>lat</TT>. This function assumes
1193  ! <TT>lon</TT> is in the range [0,360].
1194  ! </IN>
1195  PURE ELEMENTAL TYPE(point) function latlon2xyz(lat, lon)
1196  REAL, INTENT(in) :: lat, lon
1197 
1198  ! lat/lon angles in radians
1199  REAL :: theta, phi
1200 
1201  ! Convert the lat lon values to radians The lat values passed in
1202  ! are in the range [-90,90], but we need to have a radian range
1203  ! [0,pi], where 0 is at the north pole. This is the reason for
1204  ! the subtraction from 90
1205  theta = deg2rad(90.-lat)
1206  phi = deg2rad(lon)
1207 
1208  ! Calculate the x,y,z point
1209  latlon2xyz%x = radius * sin(theta) * cos(phi)
1210  latlon2xyz%y = radius * sin(theta) * sin(phi)
1211  latlon2xyz%z = radius * cos(theta)
1212  END FUNCTION latlon2xyz
1213  ! </FUNCTION>
1214  ! </PRIVATE>
1215 
1216  ! <PRIVATE>
1217  ! <FUNCTION NAME="distanceSqrd">
1218  ! <OVERVIEW>
1219  ! Find the distance between two points in the Cartesian
1220  ! coordinate space.
1221  ! </OVERVIEW>
1222  ! <TEMPLATE>
1223  ! PURE ELEMENTAL REAL FUNCTION distanceSqrd(pt1, pt2)
1224  ! </TEMPLATE>
1225  ! <DESCRIPTION>
1226  ! <TT>distanceSqrd</TT> will find the distance squared between
1227  ! two points in the xyz coordinate space. <TT>pt1</TT> and <TT>
1228  ! pt2</TT> can either be both scalars, both arrays of the same
1229  ! size, or one a scalar and one an array. The return value
1230  ! will be a scalar or array of the same size as the input array.
1231  ! </DESCRIPTION>
1232  ! <IN NAME="pt1" TYPE="TYPE(POINT)" />
1233  ! <IN NAME="pt2" TYPE="TYPE(POINT)" />
1234  PURE ELEMENTAL REAL FUNCTION distancesqrd(pt1, pt2)
1235  TYPE(point), INTENT(in) :: pt1, pt2
1236 
1237  distancesqrd = (pt1%x-pt2%x)**2 +&
1238  & (pt1%y-pt2%y)**2 +&
1239  & (pt1%z-pt2%z)**2
1240  END FUNCTION distancesqrd
1241  ! </FUNCTION>
1242  ! </PRIVATE>
1243 
1244  ! <FUNCTION NAME="gCirDistance">
1245  ! <OVERVIEW>
1246  ! Find the distance, along the geodesic, between two points.
1247  ! </OVERVIEW>
1248  ! <TEMPLATE>
1249  ! PURE ELEMENTAL REAL FUNCTION gCirDistance(lat1, lon1, lat2, lon2)
1250  ! </TEMPLATE>
1251  ! <DESCRIPTION>
1252  ! <TT>aCirDistance</TT> will find the distance, along the geodesic, between two points defined by the (lat,lon) position of
1253  ! each point.
1254  ! </DESCRIPTION>
1255  ! <IN NAME="lat1" TYPE="REAL">Latitude of the first point</IN>
1256  ! <IN NAME="lon1" TYPE="REAL">Longitude of the first point</IN>
1257  ! <IN NAME="lat2" TYPE="REAL">Latitude of the second point</IN>
1258  ! <IN NAME="lon2" TYPE="REAL">Longitude of the second point</IN>
1259  PURE ELEMENTAL REAL FUNCTION gcirdistance(lat1, lon1, lat2, lon2)
1260  REAL, INTENT(in) :: lat1, lat2, lon1, lon2
1261 
1262  REAL :: theta1, theta2
1263  REAL :: deltalambda !< Difference in longitude angles, in radians.
1264  REAL :: deltatheta !< Difference in latitude angels, in radians.
1265 
1266  theta1 = deg2rad(lat1)
1267  theta2 = deg2rad(lat2)
1268  deltalambda = deg2rad(lon2-lon1)
1269  deltatheta = deg2rad(lat2-lat1)
1270 
1271  gcirdistance = radius * 2. * asin(sqrt((sin(deltatheta/2.))**2 + cos(theta1)*cos(theta2)*(sin(deltalambda/2.))**2))
1272  END FUNCTION gcirdistance
1273  ! </FUNCTION>
1274 
1275  !Find the i,j indices and distance of the a-grid point nearest to
1276  !the inputted lat,lon point.
1277  SUBROUTINE find_nearest_agrid_index(lat, &
1278  lon, &
1279  minI, &
1280  minJ, &
1281  minimum_distance)
1283  !Inputs/outputs
1284  REAL,INTENT(IN) :: lat
1285  REAL,INTENT(IN) :: lon
1286  INTEGER,INTENT(OUT) :: minI
1287  INTEGER,INTENT(OUT) :: minJ
1288  REAL,INTENT(OUT) :: minimum_distance
1289 
1290  !Local variables
1291  REAL :: llat
1292  REAL :: llon
1293  INTEGER :: j
1294  INTEGER :: i
1295  REAL :: dist
1296 
1297  !Since the poles have an non-unique longitude value, make a small
1298  !correction if looking for one of the poles.
1299  IF (lat .EQ. 90.0) THEN
1300  llat = lat - .1
1301  ELSEIF (lat .EQ. -90.0) THEN
1302  llat = lat + .1
1303  ELSE
1304  llat = lat
1305  END IF
1306  llon = lon
1307 
1308  !Loop through non-halo points. Calculate the distance
1309  !between each a-grid point and the point that we
1310  !are seeking. Store the minimum distance and its
1311  !corresponding i,j indices.
1312  mini = 0
1313  minj = 0
1314  minimum_distance = 2.0*radius*3.141592653
1315  DO j = 1,diag_global_grid%adimJ-2
1316  DO i = 1,diag_global_grid%adimI-2
1317  dist = gcirdistance(llat, &
1318  llon, &
1319  diag_global_grid%aglo_lat(i,j), &
1320  diag_global_grid%aglo_lon(i,j))
1321  IF (dist .LT. minimum_distance) THEN
1322 
1323  !These number shouldn't be hardcoded, but they have to
1324  !match the ones in diag_grid_init.
1325  if (diag_global_grid%tile_number .eq. 4 .or. &
1326  diag_global_grid%tile_number .eq. 5) then
1327 
1328  !Because of transpose in diag_grid_init.
1329  mini = j
1330  minj = i
1331 
1332  else
1333  mini = i
1334  minj = j
1335  endif
1336  minimum_distance = dist
1337  ENDIF
1338  ENDDO
1339  ENDDO
1340 
1341  !Check that valid i,j indices have been found.
1342  IF (mini .EQ. 0 .OR. minj .EQ. 0) THEN
1343  call error_mesg("find_nearest_agrid_index", &
1344  "A minimum distance was not found.", &
1345  fatal)
1346  ENDIF
1347 
1348  END SUBROUTINE find_nearest_agrid_index
1349 
1350 END MODULE diag_grid_mod
Definition: fms.F90:20
real, parameter, public radius
Radius of the Earth [m].
Definition: constants.F90:72
real, parameter, public rad_to_deg
Degrees per radian [deg/rad].
Definition: constants.F90:119
type(diag_global_grid_type) diag_global_grid
Definition: diag_grid.F90:179
pure integer function, dimension(2) find_equator_index_agrid(lat, lon)
Definition: diag_grid.F90:1034
subroutine, public diag_grid_init(domain, glo_lat, glo_lon, aglo_lat, aglo_lon)
Definition: diag_grid.F90:229
subroutine, public get_local_indexes(latStart, latEnd, lonStart, lonEnd, istart, iend, jstart, jend)
Definition: diag_grid.F90:479
pure elemental real function rad2deg(angle)
Definition: diag_grid.F90:802
Definition: mpp.F90:39
subroutine, public diag_grid_end()
Definition: diag_grid.F90:400
pure elemental type(point) function latlon2xyz(lat, lon)
Definition: diag_grid.F90:1196
logical diag_grid_initialized
Definition: diag_grid.F90:186
#define max(a, b)
Definition: mosaic_util.h:33
real, parameter, public deg_to_rad
Radians per degree [rad/deg].
Definition: constants.F90:120
subroutine find_nearest_agrid_index(lat, lon, minI, minJ, minimum_distance)
Definition: diag_grid.F90:1282
pure elemental real function distancesqrd(pt1, pt2)
Definition: diag_grid.F90:1235
#define min(a, b)
Definition: mosaic_util.h:32
pure elemental real function deg2rad(angle)
Definition: diag_grid.F90:826
subroutine, public error_mesg(routine, message, level)
Definition: fms.F90:529
pure elemental real function gcirdistance(lat1, lon1, lat2, lon2)
Definition: diag_grid.F90:1260
pure integer function, dimension(2) find_pole_index_agrid(lat, lon)
Definition: diag_grid.F90:857
subroutine, public get_local_indexes2(lat, lon, iindex, jindex)
Definition: diag_grid.F90:748