58 USE constants_mod,
ONLY: deg_to_rad, rad_to_deg, radius
68 #include<file_version.h>
74 REAL,
allocatable,
DIMENSION(:,:) :: glo_lat
75 REAL,
allocatable,
DIMENSION(:,:) :: glo_lon
76 REAL,
allocatable,
DIMENSION(:,:) :: aglo_lat
79 REAL,
allocatable,
DIMENSION(:,:) :: aglo_lon
90 INTEGER :: tile_number
94 CHARACTER(len=128) :: grid_type
132 TYPE(
domain2d),
INTENT(in) :: domain
133 CLASS(*),
INTENT(in),
DIMENSION(:,:) :: glo_lat
134 CLASS(*),
INTENT(in),
DIMENSION(:,:) :: glo_lon
135 CLASS(*),
INTENT(in),
DIMENSION(:,:) :: aglo_lat
136 CLASS(*),
INTENT(in),
DIMENSION(:,:) :: aglo_lon
138 INTEGER,
DIMENSION(1) :: tile
141 INTEGER :: i_dim, j_dim
142 INTEGER :: ai_dim, aj_dim
143 INTEGER,
DIMENSION(2) :: latdim, londim
144 INTEGER,
DIMENSION(2) :: alatdim, alondim
145 INTEGER :: mype, npes, npespertile
146 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: xbegin, xend, ybegin, yend
153 IF (
ALLOCATED(xbegin) )
DEALLOCATE(xbegin)
154 IF (
ALLOCATED(ybegin) )
DEALLOCATE(ybegin)
155 IF (
ALLOCATED(xend) )
DEALLOCATE(xend)
156 IF (
ALLOCATED(yend) )
DEALLOCATE(yend)
159 mype =
mpp_pe() -mpp_root_pe() + 1
163 ALLOCATE(xbegin(npes), &
166 & yend(npes), stat=stat)
167 IF ( stat .NE. 0 )
THEN
168 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
169 &
'Could not allocate memory for the compute grid indices&
178 npespertile = npes / ntiles
184 & xbegin=xbegin, xend=xend,&
185 & ybegin=ybegin, yend=yend)
191 latdim = shape(glo_lat)
192 londim = shape(glo_lon)
193 IF ( (latdim(1) == londim(1)) .AND.&
194 &(latdim(2) == londim(2)) )
THEN
198 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
199 &
'glo_lat and glo_lon must be the same shape.', fatal)
203 alatdim = shape(aglo_lat)
204 alondim = shape(aglo_lon)
205 IF ( (alatdim(1) == alondim(1)) .AND. &
206 &(alatdim(2) == alondim(2)) )
THEN
207 IF ( tile(1) == 4 .OR. tile(1) == 5 )
THEN
216 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
217 &
"a-grid's glo_lat and glo_lon must be the same shape.", fatal)
223 IF (
mpp_pe() == mpp_root_pe() ) &
224 &
CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
225 &
'The global grid has already been initialized', warning)
229 IF ( stat .NE. 0 )
THEN
230 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
231 &
'Could not allocate memory for the global grid.', fatal)
238 IF (
mpp_pe() == mpp_root_pe() ) &
239 &
CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
240 &
'The global a-grid has already been initialized', warning)
244 IF ( stat .NE. 0 )
THEN
245 CALL error_mesg(
'diag_global_mod::diag_grid_init',&
246 &
'Could not allocate memory for the global a-grid', fatal)
254 IF ( tile(1) == 4 .OR. tile(1) == 5 )
THEN
255 SELECT TYPE (aglo_lat)
256 TYPE IS (real(kind=r4_kind))
258 TYPE IS (real(kind=r8_kind))
261 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
262 &
'The a-grid latitude data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
265 SELECT TYPE (aglo_lon)
266 TYPE IS (real(kind=r4_kind))
268 TYPE IS (real(kind=r8_kind))
271 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
272 &
'The a-grid longitude data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
275 SELECT TYPE (aglo_lat)
276 TYPE IS (real(kind=r4_kind))
278 TYPE IS (real(kind=r8_kind))
281 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
282 &
'The a-grid latitude data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
285 SELECT TYPE (aglo_lon)
286 TYPE IS (real(kind=r4_kind))
288 TYPE IS (real(kind=r8_kind))
291 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
292 &
'The a-grid longitude data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
296 SELECT TYPE (glo_lat)
297 TYPE IS (real(kind=r4_kind))
299 TYPE IS (real(kind=r8_kind))
302 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
303 &
'The grid latitude data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
306 SELECT TYPE (glo_lon)
307 TYPE IS (real(kind=r4_kind))
309 TYPE IS (real(kind=r8_kind))
312 CALL error_mesg(
'diag_grid_mod::diag_grid_init',&
313 &
'The grid longitude data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
355 ELSE IF (
mpp_pe() == mpp_root_pe() )
THEN
356 CALL error_mesg(
'diag_grid_mod::diag_grid_end',&
357 &
'diag_global_grid%glo_lat was not allocated.', warning)
362 ELSE IF (
mpp_pe() == mpp_root_pe() )
THEN
363 CALL error_mesg(
'diag_grid_mod::diag_grid_end',&
364 &
'diag_global_grid%glo_lon was not allocated.', warning)
369 ELSE IF (
mpp_pe() == mpp_root_pe() )
THEN
370 CALL error_mesg(
'diag_grid_mod::diag_grid_end',&
371 &
'diag_global_grid%aglo_lat was not allocated.', warning)
376 ELSE IF (
mpp_pe() == mpp_root_pe() )
THEN
377 CALL error_mesg(
'diag_grid_mod::diag_grid_end',&
378 &
'diag_global_grid%aglo_lon was not allocated.', warning)
391 & istart, iend, jstart, jend)
392 REAL,
INTENT(in) :: latstart
393 REAL,
INTENT(in) :: lonstart
394 REAL,
INTENT(in) :: latend
395 REAL,
INTENT(in) :: lonend
396 INTEGER,
INTENT(out) :: istart
397 INTEGER,
INTENT(out) :: jstart
398 INTEGER,
INTENT(out) :: iend
399 INTEGER,
INTENT(out) :: jend
401 REAL,
ALLOCATABLE,
DIMENSION(:,:) :: delta_lat, delta_lon, grid_lon
403 REAL,
DIMENSION(4) :: dists_lon, dists_lat
404 REAL :: lonendadj, my_lonstart, my_lonend
406 INTEGER,
ALLOCATABLE,
DIMENSION(:,:) :: ijmin, ijmax
407 INTEGER :: mytile, ntiles, i, j, k, dimi, dimj, istat
415 REAL :: minimum_distance
416 REAL :: global_min_distance
420 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes',&
421 &
'Module not initialized, first initialze module with a call &
422 &to diag_grid_init', fatal)
425 if ( lonstart < 0. )
then
426 my_lonstart = lonstart + 360.
428 my_lonstart = lonstart
430 if ( lonend < 0. )
then
431 my_lonend = lonend + 360.
436 IF (latstart .EQ. latend .AND. my_lonstart .EQ. my_lonend)
THEN
444 allocate(ijmin(ntiles,2))
456 global_min_distance = minimum_distance
457 CALL mpp_min(global_min_distance)
461 IF (global_min_distance .EQ. minimum_distance)
THEN
469 IF (rank_buf .EQ. -1)
THEN
471 "No rank has minimum distance.", &
475 IF (rank_buf .EQ.
mpp_pe())
THEN
485 istart = ijmin(mytile,1)
486 jstart = ijmin(mytile,2)
497 ALLOCATE(ijmin(ntiles,2), stat=istat)
499 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes',&
500 &
'Cannot allocate ijMin index array', fatal)
501 ALLOCATE(ijmax(ntiles,2), stat=istat)
503 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes',&
504 &
'Cannot allocate ijMax index array', fatal)
515 ALLOCATE(delta_lat(dimi,dimj), stat=istat)
517 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes',&
518 &
'Cannot allocate latitude delta array', fatal)
519 ALLOCATE(delta_lon(dimi,dimj), stat=istat)
521 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes',&
522 &
'Cannot allocate longitude delta array', fatal)
551 IF ( dists_lon(k) > 180.0 )
THEN
552 dists_lon(k) = 360.0 - dists_lon(k)
555 delta_lon(i,j) = sum(dists_lon)/real(count)
556 delta_lat(i,j) = sum(dists_lat)/real(count)
564 ALLOCATE(grid_lon(dimi,dimj), stat=istat)
566 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes',&
567 &
'Cannot allocate temporary longitude array', fatal)
571 IF ( my_lonstart > my_lonend )
THEN
572 WHERE ( grid_lon < my_lonstart )
573 grid_lon = grid_lon + 360.0
575 lonendadj = my_lonend + 360.0
577 lonendadj = my_lonend
586 IF ( (abs(latstart)-delta_lat(i,j) <= 90.0 .AND.&
587 & 90.0 <= abs(latend)+delta_lat(i,j)) .AND.&
590 ELSE IF ( (my_lonstart-delta_lon(i,j) <= grid_lon(i,j) .AND.&
591 & grid_lon(i,j) < lonendadj+delta_lon(i,j)) )
THEN
605 DEALLOCATE(delta_lon)
606 DEALLOCATE(delta_lat)
617 IF ( ijmin(mytile,1) == huge(1) .OR. ijmax(mytile,1) == -huge(1) )
THEN
621 IF ( ijmin(mytile,2) == huge(1) .OR. ijmax(mytile,2) == -huge(1) )
THEN
626 istart = ijmin(mytile,1)
627 jstart = ijmin(mytile,2)
628 iend = ijmax(mytile,1)
629 jend = ijmax(mytile,2)
641 REAL,
INTENT(in) :: lat
642 REAL,
INTENT(in) :: lon
643 INTEGER,
INTENT(out) :: iindex
644 INTEGER,
INTENT(out) :: jindex
646 INTEGER :: indexes(2)
649 &
CALL error_mesg(
'diag_grid_mod::get_local_indexes2',&
650 &
'Module not initialized, first initialze module with a call &
651 &to diag_grid_init', fatal)
684 REAL,
INTENT(in) :: angle
697 REAL,
INTENT(in) :: angle
712 REAL,
INTENT(in) :: lat
713 REAL,
INTENT(in) :: lon
721 INTEGER :: nearestcorner
722 INTEGER,
DIMENSION(4,2) :: ijarray
725 REAL,
DIMENSION(4) :: pntdistances
726 TYPE(
point) :: origpt
727 REAL,
DIMENSION(4,2) :: cornerpts
728 TYPE(
point),
DIMENSION(9) :: points
729 REAL,
DIMENSION(9) :: distsqrd
739 IF ( lat == 90.0 )
THEN
741 ELSE IF ( lat == -90.0 )
THEN
750 iloop:
DO i=0, dimi-2
751 jloop:
DO j = 0, dimj-2
756 & (/ 4, 2 /), order=(/2,1/) )
758 maxctrdist = max(
gcirdistance(cornerpts(1,1),cornerpts(1,2), cornerpts(2,1),cornerpts(2,2)),&
759 &
gcirdistance(cornerpts(3,1),cornerpts(3,2), cornerpts(4,1),cornerpts(4,2)))
762 pntdistances =
gcirdistance(cornerpts(:,1),cornerpts(:,2), llat,llon)
764 IF ( (minval(pntdistances) <= maxctrdist) .AND. (i*j.NE.0) )
THEN
766 ijarray = reshape( (/ i, j, i+1, j+1, i+1, j, i, j+1 /), (/ 4, 2 /), order=(/2,1/) )
769 nearestcorner = minloc(pntdistances,1)
771 indxi = ijarray(nearestcorner,1)
772 indxj = ijarray(nearestcorner,2)
781 valid:
IF ( (indxi <= 0 .OR. dimi-1 <= indxi) .OR. &
782 & (indxj <= 0 .OR. dimj-1 <= indxj) )
THEN
828 SELECT CASE (minloc(distsqrd,1))
876 REAL,
INTENT(in) :: lat
877 REAL,
INTENT(in) :: lon
879 INTEGER :: indxi, indxj
881 INTEGER :: dimi, dimj
883 INTEGER :: jstart, jend, nextj
884 TYPE(
point) :: origpt
885 TYPE(
point),
DIMENSION(4) :: points
886 REAL,
DIMENSION(4) :: distsqrd
909 iloop:
DO i=0, dimi-2
926 IF ( indxi > 0 )
THEN
927 jloop:
DO j=jstart, jend, nextj
937 valid:
IF ( (indxi <= 0 .OR. dimi-1 < indxi) .OR. &
938 & (indxj <= 0 .OR. dimj-1 < indxj) )
THEN
977 SELECT CASE (minloc(distsqrd,1))
1019 REAL,
INTENT(in) :: lat
1023 REAL,
INTENT(in) :: lon
1040 latlon2xyz%x = radius * sin(theta) * cos(phi)
1041 latlon2xyz%y = radius * sin(theta) * sin(phi)
1055 TYPE(
point),
INTENT(in) :: pt1, pt2
1058 & (pt1%y-pt2%y)**2 +&
1068 REAL,
INTENT(in) :: lat1, lat2, lon1, lon2
1070 REAL :: theta1, theta2
1076 deltalambda =
deg2rad(lon2-lon1)
1077 deltatheta =
deg2rad(lat2-lat1)
1079 gcirdistance = radius * 2. * asin(sqrt((sin(deltatheta/2.))**2 + cos(theta1)*cos(theta2)*(sin(deltalambda/2.))**2))
1091 REAL,
INTENT(IN) :: lat
1092 REAL,
INTENT(IN) :: lon
1093 INTEGER,
INTENT(OUT) :: minI
1094 INTEGER,
INTENT(OUT) :: minJ
1095 REAL,
INTENT(OUT) :: minimum_distance
1106 IF (lat .EQ. 90.0)
THEN
1108 ELSEIF (lat .EQ. -90.0)
THEN
1121 minimum_distance = 2.0*radius*3.141592653
1128 IF (dist .LT. minimum_distance)
THEN
1143 minimum_distance = dist
1149 IF (mini .EQ. 0 .OR. minj .EQ. 0)
THEN
1150 call error_mesg(
"find_nearest_agrid_index", &
1151 "A minimum distance was not found.", &
1157 END MODULE diag_grid_mod
pure elemental real function distancesqrd(pt1, pt2)
Find the distance between two points in the Cartesian coordinate space.
pure integer function, dimension(2) find_equator_index_agrid(lat, lon)
Return the closest index (i,j) to the given (lat,lon) point.
subroutine, public diag_grid_init(domain, glo_lat, glo_lon, aglo_lat, aglo_lon)
Send the global grid to the diag_manager_mod for regional output.
pure elemental type(point) function latlon2xyz(lat, lon)
Return the (x,y,z) position of a given (lat,lon) point.
pure elemental real function gcirdistance(lat1, lon1, lat2, lon2)
Find the distance, along the geodesic, between two points.
type(diag_global_grid_type) diag_global_grid
Variable to hold the global grid data.
logical diag_grid_initialized
Indicates if the diag_grid_mod has been initialized.
subroutine, public diag_grid_end()
Unallocate the diag_global_grid variable.
pure elemental real function deg2rad(angle)
Convert an angle in degrees to radians.
subroutine, public get_local_indexes2(lat, lon, iindex, jindex)
Find the indices of the nearest grid point of the a-grid to the specified (lon,lat) location on the l...
subroutine, public get_local_indexes(latStart, latEnd, lonStart, lonEnd, istart, iend, jstart, jend)
Find the local start and local end indexes on the local PE for regional output.
pure integer function, dimension(2) find_pole_index_agrid(lat, lon)
Return the closest index (i,j) to the given (lat,lon) point.
subroutine find_nearest_agrid_index(lat, lon, minI, minJ, minimum_distance)
Find the i,j indices and distance of the a-grid point nearest to the inputted lat,...
pure elemental real function rad2deg(angle)
Private type to hold the model's global grid data, and other grid information for use in this module.
Private type to hold the corresponding (x,y,z) location for a (lat,lon) location.
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
subroutine, public error_mesg(routine, message, level)
Print notes, warnings and error messages; terminates program for warning and error messages....
integer function, dimension(size(domain%tile_id(:))) mpp_get_tile_id(domain)
Returns the tile_id on current pe.
integer function mpp_get_ntile_count(domain)
Returns number of tiles in mosaic.
Retrieve the entire array of compute domain extents associated with a decomposition.
The domain2D type contains all the necessary information to define the global, compute and data domai...
integer function mpp_npes()
Returns processor count for current pelist.
integer function mpp_pe()
Returns processor ID.
Reduction operations. Find the max of scalar a from the PEs in pelist result is also automatically br...
Reduction operations. Find the min of scalar a from the PEs in pelist result is also automatically br...