Skip to content

Commit 057dd78

Browse files
committed
Merge branch 'init_atmosphere/snow_albd_interp' into develop (PR #750)
This merge allows the init_atmosphere model to safely interpolate maximum snow albedo in parallel with any mesh partition file (not just CVT partition files). However, because other fields have not yet been updated to run in parallel, the multiprocessor check in init_atm_cases is still present. * init_atmosphere/snow_albd_interp: Change scalefactor from c_float to RKIND Parallel interpolation of maximum snow albedo Enable the geotile manager to supersample tiles Initialize, finalize and push all modis snoalb onto the stack Update geotile manager to work with negative grid spacing Remove previous interpolation of snow albedo
2 parents c8ca8fa + 9f4dfbf commit 057dd78

File tree

2 files changed

+156
-92
lines changed

2 files changed

+156
-92
lines changed

src/core_init_atmosphere/mpas_geotile_manager.F

+25-9
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@ function mpas_geotile_mgr_init(mgr, path) result(ierr)
274274
! Calculate the total number of pixels in x dir
275275
! NOTE: This calculation assumes that a dataset is a global dataset and may
276276
! not work correctly for non-global datasets
277-
mgr % pixel_nx = nint(360.0_RKIND / dx)
278-
mgr % pixel_ny = nint(180.0_RKIND / dy)
277+
mgr % pixel_nx = nint(360.0_RKIND / abs(dx))
278+
mgr % pixel_ny = nint(180.0_RKIND / abs(dy))
279279

280280
! Calculate the number of tiles in the x, y directions
281281
! NOTE: This calculation assumes that a dataset is a global dataset and may
@@ -682,16 +682,22 @@ end function mpas_geotile_mgr_gen_tile_name
682682
!
683683
! public subroutine mpas_geotile_mgr_tile_to_latlon => tile_to_latlon
684684
!
685-
!> \brief Translate a tile indices to latitude and longitude,
685+
!> \brief Find the latitude, longitude location of a tile's pixels
686686
!> \author Miles A. Curry
687687
!> \date 02/20/2020
688688
!> \details
689-
!> Given a tile, translate the relative tile coordinates, i, j, of that
690-
!> tile to a latitude and longitude coordinate. Upon success, lat, lon
691-
!> will be in the range of -1/2 * pi to 1/2 * pi and 0 to 2.0 * pi, respectively.
689+
!> Given a tile, translate the pixel coordinates, i, j to a corresponding latitude
690+
!> and longitude coordinate.
691+
!>
692+
!> If supersample_fac is present each pixel will be subdivided into supersample_fac ^ 2
693+
!> sub-pixels. If supersample_fac is greater than 1, then the calling code will need
694+
!> to pass in supersampled i and j coordinates.
695+
!>
696+
!> Upon success, lat, lon will be in the range of -1/2 * pi to 1/2 * pi and 0 to
697+
!> 2.0 * pi, respectively.
692698
!
693699
!-----------------------------------------------------------------------
694-
subroutine mpas_geotile_mgr_tile_to_latlon(mgr, tile, j, i, lat, lon)
700+
subroutine mpas_geotile_mgr_tile_to_latlon(mgr, tile, j, i, lat, lon, supersample_fac)
695701
696702
implicit none
697703
@@ -701,24 +707,34 @@ subroutine mpas_geotile_mgr_tile_to_latlon(mgr, tile, j, i, lat, lon)
701707
integer, value :: i
702708
real (kind=RKIND), intent(out) :: lat
703709
real (kind=RKIND), intent(out) :: lon
710+
integer, optional, intent(in) :: supersample_fac
704711
705712
integer, pointer :: tile_bdr
706713
real (kind=RKIND), pointer :: known_lon
707714
real (kind=RKIND), pointer :: known_lat
708715
real (kind=RKIND), pointer :: dx
709716
real (kind=RKIND), pointer :: dy
717+
integer :: supersample_lcl
710718
integer :: ierr
711719
712720
ierr = 0
713721
722+
if (present(supersample_fac)) then
723+
supersample_lcl = supersample_fac
724+
else
725+
supersample_lcl = 1
726+
end if
727+
714728
call mpas_pool_get_config(mgr % pool, 'tile_bdr', tile_bdr)
715729
call mpas_pool_get_config(mgr % pool, 'known_lat', known_lat)
716730
call mpas_pool_get_config(mgr % pool, 'known_lon', known_lon)
717731
call mpas_pool_get_config(mgr % pool, 'dx', dx)
718732
call mpas_pool_get_config(mgr % pool, 'dy', dy)
719733
720-
lat = real((j - (tile_bdr + 1) + tile % y - 1), kind=RKIND) * dy + known_lat
721-
lon = real((i - (tile_bdr + 1) + tile % x - 1), kind=RKIND) * dx + known_lon
734+
lat = known_lat + real(j - (supersample_lcl * tile_bdr + 1) + (supersample_lcl * (tile % y - 1)), kind=RKIND) * dy &
735+
/ supersample_lcl
736+
lon = known_lon + real(i - (supersample_lcl * tile_bdr + 1) + (supersample_lcl * (tile % x - 1)), kind=RKIND) * dx &
737+
/ supersample_lcl
722738
723739
call deg2Rad(lat)
724740
call deg2Rad(lon)

src/core_init_atmosphere/mpas_init_atm_static.F

+131-83
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ subroutine init_atm_static(mesh, dims, configs)
8888
integer,dimension(:,:),allocatable:: ncat
8989

9090
real(kind=RKIND), pointer :: scalefactor_ptr
91-
real(kind=c_float):: scalefactor
91+
real(kind=RKIND) :: scalefactor
9292
real(kind=c_float),dimension(:,:,:),pointer,contiguous :: rarray
9393
type(c_ptr) :: rarray_ptr
9494

@@ -129,10 +129,12 @@ subroutine init_atm_static(mesh, dims, configs)
129129
integer (kind=I8KIND), dimension(:), pointer :: ter_integer
130130
real (kind=RKIND), dimension(:), pointer :: soiltemp
131131
real (kind=RKIND), dimension(:), pointer :: snoalb
132+
integer (kind=I8KIND), dimension(:), pointer :: snoalb_integer
132133
real (kind=RKIND), dimension(:), pointer :: shdmin, shdmax
133134
real (kind=RKIND), dimension(:,:), pointer :: greenfrac
134135
real (kind=RKIND), dimension(:,:), pointer :: albedo12m
135136
real (kind=RKIND) :: msgval, fillval
137+
real (kind=RKIND), pointer :: missing_value
136138
integer, pointer :: category_min, category_max
137139
integer, dimension(:), pointer :: lu_index
138140
integer, dimension(:), pointer :: soilcat_top
@@ -150,6 +152,7 @@ subroutine init_atm_static(mesh, dims, configs)
150152
type (mpas_geotile_type), pointer :: tile
151153

152154
real (kind=RKIND) :: tval
155+
integer (kind=I8KIND) :: i8val
153156
integer, pointer :: tile_bdr
154157
integer, pointer :: tile_nx, tile_ny
155158

@@ -829,107 +832,152 @@ subroutine init_atm_static(mesh, dims, configs)
829832
!
830833
if (trim(config_maxsnowalbedo_data) == 'MODIS') then
831834
835+
geog_sub_path = 'maxsnowalb_modis/'
836+
832837
call mpas_log_write('Using MODIS 0.05-deg data for maximum snow albedo')
833838
if (supersample_fac > 1) then
834839
call mpas_log_write(' Dataset will be supersampled by a factor of $i', intArgs=(/supersample_fac/))
835840
end if
836841
837-
nx = 1206
838-
ny = 1206
839-
nz = 1
840-
isigned = 1
841-
endian = 0
842-
wordsize = 2
843-
scalefactor = 0.01
844-
msgval = real(-999.0,kind=R4KIND)*real(0.01,kind=R4KIND)
845-
fillval = 0.0
846-
allocate(rarray(nx,ny,nz))
847-
allocate(nhs(nCells))
848-
nhs(:) = 0
849-
snoalb(:) = 0.0
842+
ierr = mgr % init(trim(config_geog_data_path)//trim(geog_sub_path))
843+
if (ierr /= 0) then
844+
call mpas_log_write('Error occurred when initializing the interpolation of snow albedo (snoalb)', &
845+
messageType=MPAS_LOG_CRIT)
846+
endif
850847
851-
rarray_ptr = c_loc(rarray)
852-
853-
start_lat = 90.0 - 0.05 * 0.5 / supersample_fac
854-
start_lon = -180.0 + 0.05 * 0.5 / supersample_fac
855-
geog_sub_path = 'maxsnowalb_modis/'
848+
call mpas_pool_get_config(mgr % pool, 'tile_bdr', tile_bdr)
849+
call mpas_pool_get_config(mgr % pool, 'tile_x', tile_nx)
850+
call mpas_pool_get_config(mgr % pool, 'tile_y', tile_ny)
851+
call mpas_pool_get_config(mgr % pool, 'missing_value', missing_value)
852+
call mpas_pool_get_config(mgr % pool, 'scale_factor', scalefactor_ptr)
853+
scalefactor = scalefactor_ptr
856854
857-
do jTileStart = 1,02401,ny-6
858-
jTileEnd = jTileStart + ny - 1 - 6
855+
allocate(nhs(nCells))
856+
allocate(snoalb_integer(nCells))
857+
snoalb_integer(:) = 0
858+
snoalb(:) = 0.0
859+
nhs(:) = 0
860+
fillval = 0.0
859861
860-
do iTileStart=1,06001,nx-6
861-
iTileEnd = iTileStart + nx - 1 - 6
862-
write(fname,'(a,i5.5,a1,i5.5,a1,i5.5,a1,i5.5)') trim(geog_data_path)//trim(geog_sub_path), &
863-
iTileStart,'-',iTileEnd,'.',jTileStart,'-',jTileEnd
864-
call mpas_log_write(trim(fname))
865-
call mpas_f_to_c_string(fname, c_fname)
862+
do iCell = 1, nCells
863+
if (nhs(iCell) == 0) then
864+
tile => null()
865+
ierr = mgr % get_tile(latCell(iCell), lonCell(iCell), tile)
866+
if (ierr /= 0 .or. .not. associated(tile)) then
867+
call mpas_log_write('Could not get tile that contained cell $i', intArgs=(/iCell/), messageType=MPAS_LOG_CRIT)
868+
end if
866869
867-
call read_geogrid(c_fname,rarray_ptr,nx,ny,nz,isigned,endian, &
868-
wordsize,istatus)
869-
call init_atm_check_read_error(istatus, fname)
870-
rarray(:,:,:) = rarray(:,:,:) * scalefactor
870+
ierr = mgr % push_tile(tile)
871+
if (ierr /= 0) then
872+
call mpas_log_write("Error pushing this tile onto the stack: "//trim(tile%fname), messageType=MPAS_LOG_CRIT)
873+
end if
874+
end if
871875
872-
iPoint = 1
873-
do j=supersample_fac * 3 + 1, supersample_fac * (ny-3)
874-
do i=supersample_fac * 3 + 1, supersample_fac * (nx-3)
875-
ii = (i - 1) / supersample_fac + 1
876-
jj = (j - 1) / supersample_fac + 1
876+
do while (.not. mgr % is_stack_empty())
877+
tile => mgr % pop_tile()
877878
878-
lat_pt = start_lat - (supersample_fac*(jTileStart-1) + j - (supersample_fac*3+1)) * 0.05 / supersample_fac
879-
lon_pt = start_lon + (supersample_fac*(iTileStart-1) + i - (supersample_fac*3+1)) * 0.05 / supersample_fac
880-
lat_pt = lat_pt * PI / 180.0
881-
lon_pt = lon_pt * PI / 180.0
879+
if (tile % is_processed) then
880+
cycle
881+
end if
882882
883-
iPoint = nearest_cell(lat_pt,lon_pt,iPoint,nCells,maxEdges, &
884-
nEdgesOnCell,cellsOnCell, &
885-
latCell,lonCell)
886-
if (rarray(ii,jj,1) /= msgval) then
883+
call mpas_log_write('Processing tile: '//trim(tile % fname))
884+
885+
all_pixels_mapped_to_halo_cells = .true.
886+
887+
do j = supersample_fac * tile_bdr + 1, supersample_fac * (tile_ny + tile_bdr), 1
888+
do i = supersample_fac * tile_bdr + 1, supersample_fac * (tile_nx + tile_bdr), 1
889+
890+
ii = (i - 1) / supersample_fac + 1
891+
jj = (j - 1) / supersample_fac + 1
892+
893+
i8val = int(tile % tile(ii, jj, 1), kind=I8KIND)
894+
895+
call mgr % tile_to_latlon(tile, j, i, lat_pt, lon_pt, supersample_fac)
896+
call mpas_latlon_to_xyz(xPixel, yPixel, zPixel, sphere_radius, lat_pt, lon_pt)
897+
call mpas_kd_search(tree, (/xPixel, yPixel, zPixel/), res)
898+
899+
if (bdyMaskCell(res % id) < nBdyLayers) then
900+
!
901+
! This field only matters for land cells, and for all but the outermost boundary cells,
902+
! we can safely assume that the nearest model grid cell contains the pixel (else, a different
903+
! cell would be nearest).
904+
!
905+
! Since values in i8val are not yet scaled, we can compare them to missing_value, which
906+
! also is not scaled, without scaling either value
907+
if (landmask(res % id) == 1 .and. i8val /= int(missing_value, kind=I8KIND)) then
908+
snoalb_integer(res % id) = snoalb_integer(res % id) + i8val
909+
nhs(res % id) = nhs(res % id) + 1
910+
end if
911+
912+
!
913+
! When a pixel maps to a non-land cell or is a missing value, the values are not accumulated
914+
! above; however, these pixels may still reside in an owned cell, in which case we will still need
915+
! to push the tile's neighbors onto the stack for processing.
916+
!
917+
if (res % id <= nCellsSolve) then
918+
all_pixels_mapped_to_halo_cells = .false.
919+
end if
920+
! For outermost cells, additional work is needed to verify that the pixel
921+
! actually lies within the nearest cell
922+
else
923+
if (mpas_in_cell(xPixel, yPixel, zPixel, xCell(res % id), yCell(res % id), zCell(res % id), &
924+
nEdgesOnCell(res % id), verticesOnCell(:,res % id), xVertex, yVertex, zVertex)) then
925+
926+
! Since values in i8val are not yet scaled, we can compare them to missing_value, which
927+
! also is not scaled, without scaling either value
928+
if (landmask(res % id) == 1 .and. i8val /= int(missing_value, kind=I8KIND)) then
929+
snoalb_integer(res % id) = snoalb_integer(res % id) + i8val
930+
nhs(res % id) = nhs(res % id) + 1
931+
end if
932+
933+
!
934+
! When a pixel maps to a non-land cell or is a missing value, the values are not accumulated
935+
! above; however, these pixels may still reside in an owned cell, in which case we will still need
936+
! to push the tile's neighbors onto the stack for processing.
937+
!
938+
if (res % id <= nCellsSolve) then
939+
all_pixels_mapped_to_halo_cells = .false.
940+
end if
941+
end if
942+
end if
943+
end do
944+
end do
887945
888-
!
889-
! This field only matters for land cells, and for all but the outermost boundary cells,
890-
! we can safely assume that the nearest model grid cell contains the pixel (else, a different
891-
! cell would be nearest)
892-
!
893-
if (landmask(iPoint) == 1 .and. bdyMaskCell(iPoint) < nBdyLayers) then
894-
snoalb(iPoint) = snoalb(iPoint) + rarray(ii,jj,1)
895-
nhs(iPoint) = nhs(iPoint) + 1
946+
tile % is_processed = .true.
896947
897-
! For outermost land cells, additional work is needed to verify that the pixel
898-
! actually lies within the nearest cell
899-
else if (landmask(iPoint) == 1) then
900-
zPixel = sphere_radius * sin(lat_pt) ! Model cell coordinates assume a "full" sphere radius
901-
xPixel = sphere_radius * cos(lon_pt) * cos(lat_pt) ! at this point, so we need to ues the same radius
902-
yPixel = sphere_radius * sin(lon_pt) * cos(lat_pt) ! for source pixel coordinates
903-
904-
if (mpas_in_cell(xPixel, yPixel, zPixel, xCell(iPoint), yCell(iPoint), zCell(iPoint), &
905-
nEdgesOnCell(iPoint), verticesOnCell(:,iPoint), xVertex, yVertex, zVertex)) then
906-
snoalb(iPoint) = snoalb(iPoint) + rarray(ii,jj,1)
907-
nhs(iPoint) = nhs(iPoint) + 1
908-
end if
948+
if (.not. all_pixels_mapped_to_halo_cells) then
949+
ierr = mgr % push_neighbors(tile)
950+
if (ierr /= 0) then
951+
call mpas_log_write("Error pushing the tile neighbors of: "//trim(tile%fname), messageType=MPAS_LOG_CRIT)
909952
end if
910-
end if
911-
end do
912-
end do
913-
914-
end do
953+
end if
954+
end do
915955
end do
916956
917-
do iCell = 1,nCells
918-
!
919-
! Mismatches in land mask can lead to MPAS land points with no maximum snow albedo.
920-
! Ideally, we would perform a search for nearby valid albedos, but for now using
921-
! the fill value will at least allow the model to run. In general, the number of cells
922-
! to be treated in this way tends to be a very small fraction of the total number of cells.
923-
!
924-
if (nhs(iCell) == 0) then
925-
snoalb(iCell) = fillval
926-
else
927-
snoalb(iCell) = snoalb(iCell) / real(nhs(iCell))
928-
end if
929-
snoalb(iCell) = 0.01_RKIND * snoalb(iCell) ! Convert from percent to fraction
957+
do iCell = 1, nCells
958+
!
959+
! Mismatches in land mask can lead to MPAS land points with no maximum snow albedo.
960+
! Ideally, we would perform a search for nearby valid albedos, but for now using
961+
! the fill value will at least allow the model to run. In general, the number of cells
962+
! to be treated in this way tends to be a very small fraction of the total number of cells.
963+
!
964+
if (nhs(iCell) == 0) then
965+
snoalb(iCell) = fillval
966+
else
967+
snoalb(iCell) = real(snoalb_integer(iCell), kind=R8KIND) / real(nhs(iCell), kind=R8KIND)
968+
snoalb(iCell) = snoalb(iCell) * scalefactor
969+
snoalb(iCell) = 0.01_RKIND * snoalb(iCell) ! Convert from percent to fraction
970+
endif
930971
end do
931-
deallocate(rarray)
972+
932973
deallocate(nhs)
974+
deallocate(snoalb_integer)
975+
976+
ierr = mgr % finalize()
977+
if (ierr /= 0) then
978+
call mpas_log_write('Error occurred when finalizing the interpolation of snow albedo (snoalb)', &
979+
messageType=MPAS_LOG_CRIT)
980+
endif
933981
934982
else if (trim(config_maxsnowalbedo_data) == 'NCEP') then
935983

0 commit comments

Comments
 (0)