LCOV - code coverage report
Current view: | top level - utils - cam_map_utils.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 170 | 532 | 32.0 %
Date: | 2025-01-13 21:54:50 |  | Functions: | 11 | 21 | 52.4 %

              Line data    Source code
           1             : module cam_map_utils
           2             :   use pio,                 only: iMap=>PIO_OFFSET_KIND
           3             :   use cam_abortutils,      only: endrun
           4             :
           5             :   implicit none
           6             :   private
           7             :
           8             :   public iMap
           9             :
          10             :   integer, private, save      :: unique_map_index = 0
          11             :   integer, private, parameter :: max_srcs         = 2
          12             :   integer, private, parameter :: max_dests        = 2
          13             :
          14             :   !---------------------------------------------------------------------------
          15             :   !
          16             :   !  cam_filemap_t: Information for a CAM map (between data array and
          17             :   !                 NetCDF file)
          18             :   !
          19             :   !    The map targets one or two dimensions of the NetCDF file.
          20             :   !    The 2-D map is useful for blocks of data (2 dimensions of array which
          21             :   !      map to one or two dimensions in the NetCDF file). For a 1-1 mapping,
          22             :   !      the first dimension is of size 3 (instead of 4).
          23             :   !      map(1, i) = index value of first src (e.g., lon, ncol)
          24             :   !      map(2, i) = index value of second src (e.g., lat, chunk)
          25             :   !      map(3, i) = global offset of first dest (e.g., lon, ncol)
          26             :   !      map(4, i) = global offset of second dest (e.g., lat, NA)
          27             :   !    src is the array dimension position corresponding to the map dimension
          28             :   !      in normal (not permuted) arrays.
          29             :   !      A negative pos denotes counting backwards from the last array dimension
          30             :   !    dest entries are the NetCDF dimension positions (must be increasing)
          31             :   !    It is an error to have src(1) == src(2).
          32             :   !
          33             :   !---------------------------------------------------------------------------
          34             :   type, public :: cam_filemap_t
          35             :     private
          36             :     integer                    :: index              =  0
          37             :     integer(iMap),   pointer   :: map(:,:)           => NULL()
          38             :     integer                    :: src(max_srcs)      =  0
          39             :     integer                    :: dest(max_dests)    =  0
          40             :     integer(iMap)              :: limits(max_srcs,2) =  -1
          41             :     integer                    :: nmapped            = -1
          42             :     integer,         pointer   :: blcksz(:)          => NULL() !e.g.,ncol(lchnk)
          43             :   contains
          44             :     procedure          :: init          => cam_filemap_init
          45             :     procedure          :: get_index     => cam_filemap_getIndex
          46             :     procedure          :: new_index     => cam_filemap_newIndex
          47             :     procedure          :: clear         => cam_filemap_clear
          48             :     procedure          :: copy          => cam_filemap_copy
          49             :     procedure          :: copy_elem     => cam_filemap_copyElem
          50             :     procedure          :: num_elem      => cam_filemap_size
          51             :     procedure          :: is_mapped     => cam_filemap_isMapped
          52             :     procedure          :: num_mapped    => cam_filemap_numMapped
          53             :     procedure          :: map_val       => cam_filemap_mapVal
          54             :     procedure          :: coord_vals    => cam_filemap_coordVals
          55             :     procedure          :: coord_dests   => cam_filemap_coordDests
          56             :     procedure          :: get_filemap   => cam_filemap_get_filemap
          57             :     procedure          :: has_blocksize => cam_filemap_has_blocksize
          58             :     procedure          :: blocksize     => cam_filemap_get_blocksize
          59             :     procedure          :: array_bounds  => cam_filemap_get_array_bounds
          60             :     procedure          :: active_cols   => cam_filemap_get_active_cols
          61             :     procedure          :: columnize     => cam_filemap_columnize
          62             :     procedure          :: compact       => cam_filemap_compact
          63             : !!XXgoldyXX: Cleanup when working
          64             : !    procedure          :: init_latlon   => cam_filemap_init_latlon
          65             : !    procedure          :: init_unstruct => cam_filemap_init_unstruct
          66             : !    generic, public    :: init          => init_latlon, init_unstruct
          67             :   end type cam_filemap_t
          68             :
          69             :   !---------------------------------------------------------------------------
          70             :   !
          71             :   !  END: types BEGIN: private interfaces
          72             :   !
          73             :   !---------------------------------------------------------------------------
          74             :
          75             : contains
          76             :
          77             : !!#######################################################################
          78             : !!
          79             : !! index sorting routines:
          80             : !!  XXgoldyXX: Move to generic location?
          81             : !!
          82             : !!#######################################################################
          83             :
          84           0 :   subroutine index_sort_vector(data, indices, compressval, dups_ok_in)
          85             :     use spmd_utils,      only: mpi_integer, mpi_integer8, iam, mpicom, npes
          86             :     use shr_mpi_mod,     only: shr_mpi_chkerr
          87             :     use cam_abortutils,  only: endrun
          88             :     use m_MergeSorts,    only: IndexSet, IndexSort
          89             :
          90             :     ! Dummy arguments
          91             :     integer(iMap), pointer,  intent(in)    :: data(:)
          92             :     integer,       pointer,  intent(inout) :: indices(:)
          93             :     integer(iMap), optional, intent(in)    :: compressval
          94             :     logical,       optional, intent(in)    :: dups_ok_in
          95             :
          96             :     ! Local variables
          97             :     integer                                :: num_elem   ! # mapped elements
          98             :     integer                                :: num_active ! # mapped pes
          99             :     integer                                :: ierr
         100             :     integer                                :: i
         101             :     integer                                :: lb, ub
         102             :     integer                                :: mycnt, my_first_elem
         103             :     integer                                :: mpi_group_world
         104             :     integer                                :: mpi_sort_group
         105             :     integer                                :: mpi_sort_comm
         106             :     integer                                :: my_sort_rank
         107           0 :     integer,       allocatable             :: sort_pes(:)
         108           0 :     integer,       allocatable             :: displs(:)
         109           0 :     integer,       allocatable             :: recvcounts(:)
         110           0 :     integer(iMap), allocatable             :: elements(:)
         111           0 :     integer(iMap), allocatable             :: local_elem(:)
         112           0 :     integer,       allocatable             :: ind(:)
         113           0 :     integer,       allocatable             :: temp(:)
         114             :     logical                                :: dups_ok ! .true. iff duplicates OK
         115             :     character(len=*),           parameter  :: subname = 'INDEX_SORT_VECTOR'
         116             :
         117             :     ! Allow duplicate values?
         118           0 :     if (present(dups_ok_in)) then
         119           0 :       dups_ok = dups_ok_in
         120           0 :       if ((.not. dups_ok) .and. (.not. present(compressval))) then
         121           0 :         call endrun(trim(subname)//': dups_ok=.false. requires a compressval')
         122             :       end if
         123             :     else
         124             :       dups_ok = .true.
         125             :     end if
         126             :
         127             :     ! The patch mapped values are in the number space of the master grid.
         128             :     ! They need to be compressed to go from 1 to the number of elements in the
         129             :     ! patch.
         130             :     ! Figure out the mapped elements in my portion of the patch mask
         131           0 :     if (.not. associated(data)) then
         132           0 :       mycnt = 0
         133           0 :       allocate(local_elem(mycnt))
         134           0 :       allocate(ind(mycnt))
         135           0 :       num_elem = 0
         136           0 :       lb = 0
         137           0 :       ub = -1
         138           0 :     else if (present(compressval)) then
         139           0 :       mycnt = COUNT(data /= compressval)
         140           0 :       allocate(local_elem(mycnt))
         141           0 :       allocate(ind(mycnt))
         142           0 :       num_elem = 0
         143           0 :       lb = LBOUND(data, 1)
         144           0 :       ub = UBOUND(data, 1)
         145           0 :       do i = lb, ub
         146           0 :         if (data(i) /= compressval) then
         147           0 :           num_elem = num_elem + 1
         148           0 :           local_elem(num_elem) = data(i)
         149           0 :           ind(num_elem) = i
         150             :         end if
         151             :       end do
         152             :     else
         153           0 :       lb = LBOUND(data, 1)
         154           0 :       ub = UBOUND(data, 1)
         155           0 :       mycnt = size(data)
         156           0 :       allocate(local_elem(mycnt))
         157           0 :       local_elem(1:mycnt) = data(lb:ub)
         158           0 :       num_elem = mycnt
         159             :     end if
         160             :
         161             :     ! Find the tasks which have elements in this patch
         162             :     ! temp used for # elements per PE
         163           0 :     allocate(temp(0:npes-1))
         164             :     call MPI_allgather(mycnt, 1, MPI_integer, temp, 1, MPI_integer,           &
         165           0 :          mpicom, ierr)
         166           0 :     call shr_mpi_chkerr(ierr, subname//': MPI_allgather elements')
         167           0 :     num_active = COUNT(temp > 0)
         168           0 :     if (num_active > 1) then
         169           0 :       allocate(sort_pes(num_active))
         170           0 :       allocate(recvcounts(num_active))
         171           0 :       allocate(displs(num_active))
         172           0 :       num_elem = 0
         173           0 :       displs(1) = 0
         174             :       ! Find the number of mapped elements and number of pes in this patch
         175           0 :       my_sort_rank = -1
         176           0 :       do i = 0, npes - 1
         177           0 :         if (temp(i) > 0) then
         178           0 :           num_elem = num_elem + 1
         179           0 :           if (num_elem > num_active) then
         180           0 :             call endrun(subname//": overrun of sort_pes array")
         181             :           end if
         182           0 :           sort_pes(num_elem) = i
         183           0 :           if (iam == i) then
         184           0 :             my_sort_rank = num_elem - 1
         185           0 :             my_first_elem = displs(num_elem) + 1
         186             :           end if
         187           0 :           recvcounts(num_elem) = temp(i)
         188           0 :           if (num_elem < num_active) then
         189           0 :             displs(num_elem + 1) = displs(num_elem) + recvcounts(num_elem)
         190             :           end if
         191             :         end if
         192             :       end do
         193           0 :       if (num_elem < num_active) then
         194           0 :         call endrun(subname//": underrun of sort_pes array")
         195             :       end if
         196           0 :       if (my_sort_rank >= 0) then
         197           0 :         num_elem = SUM(temp) ! Total number of elements to sort
         198             :       else
         199           0 :         num_elem = 0
         200             :       end if
         201           0 :       deallocate(temp)  ! Cleanup
         202             :       ! Make a group with the active PEs
         203           0 :       call MPI_comm_group(mpicom, mpi_group_world, ierr)
         204           0 :       call shr_mpi_chkerr(ierr, subname//': MPI_comm_group mpi_group_world')
         205             :       call MPI_group_incl(mpi_group_world, num_active, sort_pes,              &
         206           0 :            mpi_sort_group, ierr)
         207           0 :       call shr_mpi_chkerr(ierr, subname//': MPI_group_incl sort_pes')
         208             :       ! Make a new communicator with the active PEs
         209           0 :       call MPI_comm_create(mpicom, mpi_sort_group, mpi_sort_comm, ierr)
         210           0 :       call shr_mpi_chkerr(ierr, subname//': MPI_comm_create mpi_sort_comm')
         211             :       ! Collect all the elements for sorting (only active tasks now)
         212           0 :       allocate(elements(num_elem))
         213           0 :       if (mycnt > 0) then
         214             :         call MPI_allgatherv(local_elem, mycnt, MPI_integer8,                  &
         215           0 :              elements, recvcounts, displs, MPI_integer8, mpi_sort_comm, ierr)
         216           0 :         call shr_mpi_chkerr(ierr, subname//': MPI_allgatherv')
         217             :         ! Clean up for active PEs only
         218           0 :         call MPI_comm_free(mpi_sort_comm, ierr)
         219             :       end if
         220             :       ! General clean up
         221           0 :       call MPI_group_free(mpi_sort_group, ierr)
         222           0 :       deallocate(recvcounts)
         223           0 :       deallocate(displs)
         224           0 :     else if (mycnt > 0) then
         225             :       ! We are the only PE with patch info
         226           0 :       num_elem = mycnt
         227           0 :       allocate(elements(size(local_elem)))
         228           0 :       elements = local_elem
         229             :       my_first_elem = 1
         230             :     end if
         231             :     ! At this point, num_elem should always be the local # of items to sort
         232           0 :     if (num_elem > 0) then
         233             :       ! Sanity check
         234           0 :       if (size(elements) < num_elem) then
         235           0 :         call endrun(trim(subname)//": size(elements) must be >= num_elem")
         236             :       end if
         237             :       !! Do the sort, recvcounts will be the temporary index array
         238           0 :       allocate(recvcounts(size(elements)))
         239           0 :       allocate(displs(size(recvcounts)))
         240           0 :       call IndexSet(num_elem, recvcounts)
         241           0 :       call IndexSort(num_elem, recvcounts, elements, descend=.false.)
         242             :       ! Compress recvcounts (repeat data values)
         243           0 :       displs = 0
         244           0 :       do i = 1, num_elem - 1
         245           0 :         if (elements(recvcounts(i)) == elements(recvcounts(i + 1))) then
         246           0 :           displs(i + 1) = displs(i) + 1
         247             :         else
         248           0 :           displs(i + 1) = displs(i)
         249             :         end if
         250             :       end do
         251             :       ! Unload recvcounts into indices. Assume indices is initialized w/ default
         252           0 :       do i = 1, num_elem
         253           0 :         if ( (recvcounts(i) >= my_first_elem) .and.                           &
         254           0 :              (recvcounts(i) < (my_first_elem + mycnt))) then
         255           0 :           if (.not. dups_ok) then
         256             :             ! Use our indirect access to set the correct indices location
         257             :             ! ind array already has lb offset included
         258             :             ! Eliminate duplicate values
         259           0 :             if ((i > 1) .and. (displs(i) > displs(MAX((i - 1),1)))) then
         260           0 :               indices(ind(recvcounts(i) - my_first_elem + 1)) = compressval
         261             :             else
         262           0 :               indices(ind(recvcounts(i) - my_first_elem + 1)) = i - displs(i)
         263             :             end if
         264           0 :           else if (allocated(ind)) then
         265           0 :             indices(ind(recvcounts(i) - my_first_elem + 1)) = i - displs(i)
         266             :           else
         267             :             ! recvcounts points directly at a local location
         268             :             ! NB: repeat data values all get same index
         269           0 :             indices(recvcounts(i) - my_first_elem + lb) = i - displs(i)
         270             :           end if
         271             :         end if
         272             :       end do
         273           0 :       deallocate(recvcounts)
         274           0 :       deallocate(displs)
         275             :     end if
         276             :
         277           0 :     if (allocated(ind)) then
         278           0 :       deallocate(ind)
         279             :     end if
         280           0 :     if (allocated(elements)) then
         281           0 :       deallocate(elements)
         282             :     end if
         283           0 :     deallocate(local_elem)
         284             :
         285           0 :   end subroutine index_sort_vector
         286             :
         287             : !!#######################################################################
         288             : !!
         289             : !! CAM grid mapping functions
         290             : !!
         291             : !!#######################################################################
         292             :
         293    10791936 :   integer function cam_filemap_getIndex(this)
         294             :     ! Dummy variable
         295             :     class(cam_filemap_t)                 :: this
         296             :
         297    10791936 :     cam_filemap_getIndex = this%index
         298             :
         299    10791936 :   end function cam_filemap_getIndex
         300             :
         301        7680 :   subroutine cam_filemap_newIndex(this)
         302             :     ! Dummy variable
         303             :     class(cam_filemap_t)                 :: this
         304             :
         305        7680 :     unique_map_index = unique_map_index + 1
         306        7680 :     this%index = unique_map_index
         307             :
         308        7680 :   end subroutine cam_filemap_newIndex
         309             :
         310        7680 :   subroutine cam_filemap_init(this, pemap, unstruct, src, dest)
         311             :     ! Dummy arguments
         312             :     class(cam_filemap_t)                 :: this
         313             :     integer(iMap),    pointer            :: pemap(:,:) ! Map elem for this PE
         314             :     logical,                  intent(in) :: unstruct
         315             :     integer,                  intent(in) :: src(:)
         316             :     integer, optional,        intent(in) :: dest(:)
         317             :
         318             :     ! Local variables
         319             :     integer                              :: i ! Loop index
         320             :     integer                              :: index
         321             :
         322             :     ! This shouldn't happen but maybe we will decide to reuse these
         323        7680 :     if (associated(this%map)) then
         324           0 :       deallocate(this%map)
         325           0 :       nullify(this%map)
         326             :     end if
         327             :
         328             :     ! Check in case these ever change (because algorithm then must be modified)
         329             :     if ((max_srcs /= 2) .or. (max_dests /= 2)) then
         330             :       call endrun('cam_filemap_init: max_src or max_dest modified')
         331             :     end if
         332             :
         333             :     ! Some items are simply copied
         334        7680 :     if (associated(pemap)) then
         335        7680 :       this%map => pemap
         336             :     else
         337           0 :       nullify(this%map)
         338             :     end if
         339       30720 :     this%src =  src
         340        7680 :     if (present(dest)) then
         341             :       ! Structred grids will likely always have dest = (1, 2) but maybe . . .
         342       30720 :       this%dest = dest
         343           0 :     else if (unstruct) then
         344             :       ! Unstructured grids are (so far) always spread along the first dimension
         345           0 :       this%dest(1) = 1
         346           0 :       this%dest(2) = 0
         347             :     else
         348           0 :       this%dest(1) = 1
         349           0 :       this%dest(2) = 2
         350             :     end if
         351             :     ! We may have holes in the 'block' decomposition which is specified by
         352             :     ! having src(2) < 0.
         353             :     ! NB: This is currently a special purpose hack in that it is purely
         354             :     !     convention that the last dimension specifies the block index and
         355             :     !     that those blocks may not be filled.
         356             :     !     The proper way to generalize this functionality is to allow
         357             :     !     src(1) to also be < 0 and to look for holes there as well
         358        7680 :     if (associated(this%map)) then
         359       23040 :       do i = 1, max_srcs
         360       23040 :         if (ANY(this%map(i,:) > 0)) then
         361             :           ! Min of all src(i) values
         362     1308864 :           this%limits(i, 1) = MINVAL(this%map(i,:), mask=(this%map(i,:)>0))
         363             :           ! Max of all src(i) values
         364     1293504 :           this%limits(i, 2) = MAXVAL(this%map(i,:), mask=(this%map(i,:)>0))
         365             :         else
         366           0 :           this%limits(i,1) = 0
         367           0 :           this%limits(i,2) = -1
         368             :         end if
         369             :       end do
         370             :
         371        7680 :       this%nmapped = 0
         372      646752 :       do index = 1, this%num_elem()
         373      646752 :         if ((this%dest(1) > 0) .and. (this%map(max_srcs+1, index) > 0)) then
         374      486008 :           if (this%dest(2) > 0) then
         375             :             ! Can't do this test unless we know the dim 2 is large enough
         376           0 :             if (this%map(max_srcs+2, index) > 0) then
         377           0 :               this%nmapped = this%nmapped + 1
         378             :             end if
         379             :           else
         380      486008 :             this%nmapped = this%nmapped + 1
         381             :           end if
         382             :         end if
         383             :       end do
         384             :     else
         385           0 :       this%limits(:,1) = 0
         386           0 :       this%limits(:,2) = -1
         387           0 :       this%nmapped = 0
         388             :     end if
         389        7680 :     if (src(max_srcs) < 0) then
         390             :       ! This shouldn't happen but maybe we will decide to reuse these
         391        7680 :       if (associated(this%blcksz)) then
         392           0 :         deallocate(this%blcksz)
         393           0 :         nullify(this%blcksz)
         394             :       end if
         395       23040 :       allocate(this%blcksz(this%limits(max_srcs,1):this%limits(max_srcs,2)))
         396       57072 :       this%blcksz = 0
         397      646752 :       do i = 1, this%num_elem()
         398      639072 :         index = this%map(max_srcs, i)
         399      646752 :         if (this%is_mapped(i)) then
         400      486008 :           this%blcksz(index) = this%blcksz(index) + 1
         401             :         end if
         402             :       end do
         403             :     end if
         404             :
         405        7680 :     call this%new_index()
         406             :
         407        7680 :   end subroutine cam_filemap_init
         408             :
         409           0 :   subroutine cam_filemap_clear(this)
         410             :     ! Dummy arguments
         411             :     class(cam_filemap_t)               :: this
         412             :
         413           0 :     if (associated(this%map)) then
         414           0 :       this%map = 0
         415             :     end if
         416           0 :     this%limits(:,1) = 0
         417           0 :     this%limits(:,2) = -1
         418           0 :     this%nmapped = 0
         419             :
         420             :     ! Update the index in case a decomp was made with the old values
         421           0 :     call this%new_index()
         422             :
         423           0 :   end subroutine cam_filemap_clear
         424             :
         425           0 :   subroutine cam_filemap_copy(this, map)
         426             :     ! Dummy arguments
         427             :     class(cam_filemap_t)               :: this
         428             :     type(cam_filemap_t),  intent(in)   :: map
         429             :
         430             :     ! This shouldn't happen but maybe we will decide to reuse these
         431           0 :     if (associated(this%map)) then
         432           0 :       deallocate(this%map)
         433           0 :       nullify(this%map)
         434             :     end if
         435             :
         436           0 :     if (associated(map%map)) then
         437           0 :       allocate(this%map(size(map%map, 1), size(map%map, 2)))
         438           0 :       if (map%num_elem() > 0) then
         439           0 :         this%map = map%map
         440             :       end if
         441             :     else
         442           0 :       nullify(this%map)
         443             :     end if
         444           0 :     this%src = map%src
         445           0 :     this%dest = map%dest
         446           0 :     this%limits = map%limits
         447           0 :     this%nmapped = map%nmapped
         448             :
         449             :     ! This shouldn't happen but maybe we will decide to reuse these
         450           0 :     if (associated(this%blcksz)) then
         451           0 :       deallocate(this%blcksz)
         452           0 :       nullify(this%blcksz)
         453             :     end if
         454           0 :     if (associated(map%blcksz)) then
         455           0 :       allocate(this%blcksz(size(map%blcksz)))
         456           0 :       this%blcksz = map%blcksz
         457             :     end if
         458             :
         459             :     ! Even a copy has to have a unique index
         460           0 :     call this%new_index()
         461             :
         462           0 :   end subroutine cam_filemap_copy
         463             :
         464           0 :   subroutine cam_filemap_copyElem(this, map, index)
         465             :     ! Dummy arguments
         466             :     class(cam_filemap_t)               :: this
         467             :     type(cam_filemap_t), intent(in)    :: map
         468             :     integer,             intent(in)    :: index
         469             :
         470           0 :     if (this%is_mapped(index)) then
         471           0 :       this%nmapped = this%nmapped - 1
         472             :     end if
         473           0 :     this%map(:, index) = map%map(:, index)
         474           0 :     if (this%is_mapped(index)) then
         475           0 :       this%nmapped = this%nmapped + 1
         476             :     end if
         477             :
         478           0 :   end subroutine cam_filemap_copyElem
         479             :
         480             :   !---------------------------------------------------------------------------
         481             :   !
         482             :   !  cam_filemap_size: Total number of elements in the map
         483             :   !
         484             :   !---------------------------------------------------------------------------
         485       33792 :   integer function cam_filemap_size(this)
         486             :     ! Dummy variable
         487             :     class(cam_filemap_t)                 :: this
         488             :
         489       33792 :     if (associated(this%map)) then
         490       33792 :       cam_filemap_size = size(this%map,2)
         491             :     else
         492             :       cam_filemap_size = 0
         493             :     end if
         494       33792 :   end function cam_filemap_size
         495             :
         496             :   !---------------------------------------------------------------------------
         497             :   !
         498             :   !  cam_filemap_isMapped: Return .true. iff the index value is mapped
         499             :   !
         500             :   !---------------------------------------------------------------------------
         501      639072 :   elemental logical function cam_filemap_isMapped(this, index)
         502             :     ! Dummy arguments
         503             :     class(cam_filemap_t),      intent(in)    :: this
         504             :     integer,                   intent(in)    :: index
         505             :
         506      639072 :     if (associated(this%map)) then
         507      639072 :       cam_filemap_isMapped = (this%map(3, index) > 0)
         508      639072 :       if ((size(this%map, 1) > 3) .and. cam_filemap_isMapped) then
         509           0 :         cam_filemap_isMapped = (this%map(4, index) > 0)
         510             :         ! No else needed
         511             :       end if
         512             :     else
         513             :       cam_filemap_isMapped = .false.
         514             :     end if
         515             :
         516      639072 :   end function cam_filemap_isMapped
         517             :
         518             :   !---------------------------------------------------------------------------
         519             :   !
         520             :   !  cam_filemap_numMapped: Number of elements in the map with non-zero entries
         521             :   !
         522             :   !---------------------------------------------------------------------------
         523       18432 :   integer function cam_filemap_numMapped(this)
         524             :     ! Dummy variable
         525             :     class(cam_filemap_t)                 :: this
         526             :
         527       18432 :     if (associated(this%map)) then
         528       18432 :       cam_filemap_numMapped = this%nmapped
         529             :     else
         530             :       cam_filemap_numMapped = 0
         531             :     end if
         532       18432 :   end function cam_filemap_numMapped
         533             :
         534             :   !---------------------------------------------------------------------------
         535             :   !
         536             :   !  cam_filemap_mapVal: Calculate an offset value from a map
         537             :   !
         538             :   !---------------------------------------------------------------------------
         539    17528400 :   integer(iMap) function cam_filemap_mapVal(this, index, dsize, dest_in)
         540             :     ! Dummy arguments
         541             :     class(cam_filemap_t)                     :: this
         542             :     integer,                   intent(in)    :: index
         543             :     integer(iMap),             intent(in)    :: dsize(:)
         544             :     integer,       optional,   intent(in)    :: dest_in(:)
         545             :
         546             :     ! Local variables
         547             :     integer                                  :: ndest
         548             :     integer                                  :: d(max_dests)
         549             :
         550    17528400 :     if (associated(this%map)) then
         551    17528400 :       if (present(dest_in)) then
         552     3510000 :         ndest = size(dest_in)
         553     3510000 :         d = 0
         554    10530000 :         d(:ndest) = dest_in(:ndest)
         555             :       else
         556    42055200 :         d = this%dest
         557             :       end if
         558    17528400 :       if (this%map(3, index) > 0) then
         559    16183860 :         cam_filemap_mapVal = ((this%map(3, index) - 1) * dsize(d(1))) + 1
         560    16183860 :         if (size(this%map, 1) > 3) then
         561           0 :           if (this%map(4, index) > 0) then
         562           0 :             cam_filemap_mapVal = ((this%map(4, index) - 1) * dsize(d(2))) +   &
         563           0 :                  cam_filemap_mapVal  ! No +1 because it is offset from map(3,:)
         564             :           else
         565             :             cam_filemap_mapVal = 0
         566             :           end if
         567             :         ! No else needed
         568             :         end if
         569             :       else
         570             :         cam_filemap_mapVal = 0
         571             :       end if
         572             :     else
         573             :       cam_filemap_mapVal = 0
         574             :     end if
         575    17528400 :   end function cam_filemap_mapVal
         576             :
         577             :   !---------------------------------------------------------------------------
         578             :   !
         579             :   !  cam_filemap_coordVals: Find coord indices matching map index
         580             :   !
         581             :   !---------------------------------------------------------------------------
         582           0 :   subroutine cam_filemap_coordVals(this, index, lonIndex, latIndex, isMapped)
         583             :     ! Dummy arguments
         584             :     class(cam_filemap_t)                     :: this
         585             :     integer,                   intent(in)    :: index
         586             :     integer,                   intent(out)   :: lonIndex
         587             :     integer,                   intent(out)   :: latIndex
         588             :     logical, optional,         intent(out)   :: isMapped
         589             :
         590           0 :     if (associated(this%map)) then
         591           0 :       if (size(this%map,1) > (max_srcs + 1)) then
         592           0 :         lonIndex = this%map(1, index)
         593           0 :         latIndex = this%map(2, index)
         594             :       else
         595           0 :         lonIndex = index
         596           0 :         latIndex = index
         597             :       end if
         598           0 :       if (present(isMapped)) then
         599           0 :         isMapped = this%is_mapped(index)
         600             :       end if
         601           0 :     else if (present(isMapped)) then
         602           0 :       lonIndex = 0
         603           0 :       latIndex = 0
         604           0 :       isMapped = .false.
         605             :     else
         606           0 :       call endrun("cam_filemap_coordVals: must have map or pass isMapped")
         607             :     end if
         608           0 :   end subroutine  cam_filemap_coordVals
         609             :
         610             :   !---------------------------------------------------------------------------
         611             :   !
         612             :   !  cam_filemap_coordDests: Find coord indices matching map index
         613             :   !
         614             :   !---------------------------------------------------------------------------
         615           0 :   subroutine cam_filemap_coordDests(this, index, lonIndex, latIndex, isMapped)
         616             :     ! Dummy arguments
         617             :     class(cam_filemap_t)                     :: this
         618             :     integer,                   intent(in)    :: index
         619             :     integer,                   intent(out)   :: lonIndex
         620             :     integer,                   intent(out)   :: latIndex
         621             :     logical, optional,         intent(out)   :: isMapped
         622             :
         623           0 :     if (associated(this%map)) then
         624           0 :       lonIndex = this%map(max_srcs + 1, index)
         625           0 :       if (size(this%map,1) > (max_srcs + 1)) then
         626           0 :         latIndex = this%map(max_srcs + 2, index)
         627             :       else
         628           0 :         latIndex = 0
         629             :       end if
         630           0 :       if (present(isMapped)) then
         631           0 :         isMapped = this%is_mapped(index)
         632             :       end if
         633           0 :     else if (present(isMapped)) then
         634           0 :       lonIndex = 0
         635           0 :       latIndex = 0
         636           0 :       isMapped = .false.
         637             :     else
         638           0 :       call endrun("cam_filemap_coordDests: must have map or pass isMapped")
         639             :     end if
         640           0 :   end subroutine  cam_filemap_coordDests
         641             :
         642             :   !---------------------------------------------------------------------------
         643             :   !
         644             :   !  cam_filemap_get_filemap: Create the mapping between an array and a file
         645             :   !             This is the workhorse function for creating a PIO decomp DOF
         646             :   !
         647             :   !---------------------------------------------------------------------------
         648       18432 :   subroutine cam_filemap_get_filemap(this, fieldlens, filelens, filemap,      &
         649       18432 :        src_in, dest_in, permutation_in)
         650             :     use shr_kind_mod, only: SHR_KIND_CL
         651             :
         652             :     ! Dummy arguments
         653             :     class(cam_filemap_t)                      :: this
         654             :     integer,                    intent(in)    :: fieldlens(:)
         655             :     integer,                    intent(in)    :: filelens(:)
         656             :     integer(iMap), pointer                    :: filemap(:)
         657             :     integer,          optional, intent(in)    :: src_in(:)
         658             :     integer,          optional, intent(in)    :: dest_in(:)
         659             :     integer,          optional, intent(in)    :: permutation_in(:)
         660             :
         661             :     ! Local variables
         662             :     integer                       :: srclens(7)          ! field dim lens
         663             :     integer                       :: srccnt              ! Rank of fieldlens
         664       18432 :     integer(iMap), allocatable    :: dsize(:)
         665             :     integer                       :: mapind(max_srcs)   ! Source index for map
         666       18432 :     integer,       allocatable    :: src_ind(:)     ! Map src to file dims
         667             :     integer                       :: fmind, j
         668             :     integer(iMap)                 :: mapSize, mapPos, pos, fileSize
         669             :     integer                       :: mapcnt         ! Dimension count
         670             :     integer                       :: tind, tlen     ! Temporarys
         671             :     integer                       :: i1, i2, i3, i4, i5, i6, i7
         672             :     integer                       :: i(7)
         673             :     character(len=SHR_KIND_CL)    :: errmsg
         674             :     character(len=32)             :: errfmt
         675             :     character(len=*), parameter   :: subname = 'cam_filemap_get_filemap: '
         676             :
         677             :     ! This shouldn't happen but, who knows what evil lurks in the hearts of SEs
         678       18432 :     if (associated(filemap)) then
         679           0 :       deallocate(filemap)
         680             :       nullify(filemap)
         681             :     end if
         682             :
         683             :     !
         684       50688 :     fileSize = product( int(filelens,kind=iMap) )
         685       18432 :     srccnt = size(fieldlens)
         686       85248 :     srclens(1:srccnt) = fieldlens(1:srccnt)
         687       18432 :     if (srccnt < 7) then
         688      117504 :       srclens(srccnt+1:7) = 1
         689             :     end if
         690             :
         691             :     ! Allocate output filemap (dof)
         692      103680 :     allocate(filemap(product(fieldlens)))
         693    17546832 :     filemap = 0
         694             :
         695             :     ! Find map source dimensions in input array
         696       18432 :     mapPos = 1                                ! To compare against map size
         697       18432 :     mapind = 0
         698       18432 :     if (present(src_in)) then
         699        1536 :       mapcnt = size(src_in)  ! Just used until end of loop below
         700        1536 :       if (mapcnt > max_srcs) then
         701           0 :         call endrun(subname//'src_in too large')
         702             :       end if
         703             :     end if
         704       55296 :     do j = 1, max_srcs
         705       36864 :       if (present(src_in)) then
         706        3072 :         if (mapcnt >= j) then
         707        3072 :           if (src_in(j) < 0) then
         708        1536 :             mapind(j) = srccnt + src_in(j) + 1
         709             :           else
         710        1536 :             mapind(j) = src_in(j)
         711             :           end if
         712             :         end if
         713             :       else
         714             :         ! A src == 0 means that map dimension is not used
         715       33792 :         if (this%src(j) /= 0) then
         716             :           ! src < 0 is count from last array dim
         717       33792 :           if (this%src(j) < 0) then
         718       16896 :             mapind(j) = srccnt + this%src(j) + 1
         719             :           else
         720       16896 :             mapind(j) = this%src(j)
         721             :           end if
         722             :         end if
         723             :       end if
         724       55296 :       if (mapind(j) > 0) then
         725       36864 :         mapPos = mapPos * srclens(mapind(j))  ! To compare against map size
         726             :       end if
         727             :     end do
         728       55296 :     mapcnt = COUNT(mapind /= 0)
         729             :
         730             :     ! Check that map matches dims
         731             :     ! Since patch maps are compressed, we can't do an equal compare but
         732             :     !   it is still an error if the map has more elements than the array
         733       18432 :     mapSize = this%num_elem()
         734       18432 :     if (mapPos < this%num_mapped()) then
         735           0 :        if (mapcnt > 1) then
         736           0 :           write(errfmt, '(a,i0,2a)') "(a,i0,a,", mapcnt, '(i0,", "),")")'
         737             :        else
         738           0 :           write(errfmt, '(a,i0,2a)') '(a,i0,a,i0,")")'
         739             :        end if
         740           0 :        write(errmsg, errfmt) 'Map size (',                 &
         741           0 :             this%num_mapped(), ') too large for array dims (',                &
         742           0 :             srclens(mapind(1:mapcnt))
         743           0 :       call endrun(subname//trim(errmsg))
         744             :     end if
         745             :
         746             :     ! dsize is a global offset for each dimension
         747       55296 :     allocate(dsize(size(filelens)))
         748       18432 :     dsize(1) = 1
         749       32256 :     do j = 1, size(filelens) - 1
         750       32256 :       dsize(j + 1) = dsize(j) * filelens(j)
         751             :     end do
         752             :
         753             :     ! src_ind maps each source dimension to the corresponding file dimension
         754       55296 :     allocate(src_ind(srccnt))
         755       18432 :     if (present(permutation_in)) then
         756           0 :       if (size(permutation_in) /= size(src_ind)) then
         757           0 :         call endrun(subname//'permutation_in must have same rank as fieldlens')
         758             :       end if
         759           0 :       src_ind = permutation_in
         760             :     else
         761       66816 :       src_ind = 0
         762             :       fmind = 1      ! Here fmind is first available permutation slot
         763       66816 :       do j = 1, srccnt
         764             :         ! We need to find the offset location for each non-mapped src dimension
         765      108288 :         if (ANY(mapind == j)) then
         766             :           continue
         767             :         else
         768             :           ! Find the next available output dimension
         769       11520 :           if (present(dest_in)) then
         770        4608 :             do while (ANY(dest_in == fmind))
         771        1536 :               fmind = fmind + 1
         772        3072 :               if (fmind > size(dsize)) then
         773           0 :                 call endrun(subname//'permutation calculation dest_in error')
         774             :               end if
         775             :             end do
         776             :           else
         777       39936 :             do while (ANY(this%dest == fmind))
         778        9984 :               fmind = fmind + 1
         779       19968 :               if (fmind > size(dsize)) then
         780           0 :                 call endrun(subname//'permutation calculation dest error')
         781             :               end if
         782             :             end do
         783             :           end if
         784       11520 :           if (fmind > size(dsize)) then
         785           0 :             call endrun(subname//'permutation calculation error')
         786             :           end if
         787       11520 :           src_ind(j) = fmind
         788       11520 :           fmind = fmind + 1
         789             :         end if
         790             :       end do
         791             :     end if
         792             :
         793             :     ! Step through the map and fill in local positions for each entry
         794       18432 :     fmind = 1
         795       36864 :     do i7 = 1, srclens(7)
         796       18432 :       i(7) = i7
         797       55296 :       do i6 = 1, srclens(6)
         798       18432 :         i(6) = i6
         799       55296 :         do i5 = 1, srclens(5)
         800       18432 :           i(5) = i5
         801       55296 :           do i4 = 1, srclens(4)
         802       18432 :             i(4) = i4
         803       99432 :             do i3 = 1, srclens(3)
         804       62568 :               i(3) = i3
         805     1360800 :               do i2 = 1, srclens(2)
         806     1279800 :                 i(2) = i2
         807    18870768 :                 do i1 = 1, srclens(1)
         808    17528400 :                   i(1) = i1
         809    17528400 :                   pos = 0  ! Offset from map pos so starts at zero
         810    17528400 :                   tind = 1 ! Offset into the map
         811    17528400 :                   tlen = 1
         812    69520320 :                   do j = 1, srccnt
         813   120918960 :                     if (ANY(mapind == j)) then
         814             :                       ! j is a distributed field dimension index
         815    35056800 :                       tind = tind + ((i(j) - 1) * tlen)
         816    35056800 :                       tlen = tlen * srclens(j)
         817             :                     else
         818             :                       ! j is a local field dimension index
         819    16935120 :                       pos = pos + ((i(j) - 1) * dsize(src_ind(j)))
         820             :                     end if
         821             :                   end do
         822    17528400 :                   if (tind > mapSize) then
         823             :                     write(errmsg, '(2(a,i0),a,12x,5(i0,", "),")")')           &
         824           0 :                          'internal error, tind (', tind, ') > mapSize (',     &
         825           0 :                          mapSize, '), srclens = (', srclens(1:5)
         826           0 :                     call endrun(subname//trim(errmsg))
         827             :                   end if
         828    31546800 :                   mapPos = this%map_val(tind, dsize, dest_in)
         829    17528400 :                   if ((mapPos > 0) .and. ((pos + mapPos) > fileSize)) then
         830           0 :                     call endrun(subname//'internal error, pos')
         831             :                   end if
         832    17528400 :                   if ((pos + mapPos) < 0) then
         833           0 :                     call endrun(subname//'internal error, mpos')
         834             :                   end if
         835    17528400 :                   if (mapPos > 0) then
         836    16183860 :                     filemap(fmind) = pos + mapPos
         837             :                   else
         838             :                     ! This element is not mapped
         839     1344540 :                     filemap(fmind) = 0
         840             :                   end if
         841    18808200 :                   fmind = fmind + 1
         842             :                 end do
         843             :               end do
         844             :             end do
         845             :           end do
         846             :         end do
         847             :       end do
         848             :     end do
         849       18432 :     if ((fmind - 1) /= size(filemap)) then
         850           0 :       call endrun(subname//'internal error, fmind')
         851             :     end if
         852       18432 :     deallocate(dsize)
         853       18432 :   end subroutine cam_filemap_get_filemap
         854             :
         855   231686064 :   integer function cam_filemap_get_blocksize(this, block_id)
         856             :
         857             :     ! Dummy arguments
         858             :     class(cam_filemap_t)                       :: this
         859             :     integer,                    intent(in)     :: block_id
         860             :
         861   231686064 :     if (.not. this%has_blocksize()) then
         862           0 :       call endrun('cam_filemap_get_blocksize: filemap has no blocks')
         863   231686064 :     else if ((block_id < LBOUND(this%blcksz, 1)) .or.                         &
         864             :          (block_id > UBOUND(this%blcksz, 1))) then
         865           0 :       call endrun('cam_filemap_get_blocksize: block_id out of range')
         866             :     else
         867   231686064 :       cam_filemap_get_blocksize = this%blcksz(block_id)
         868             :     end if
         869   231686064 :   end function cam_filemap_get_blocksize
         870             :
         871   231686064 :   logical function cam_filemap_has_blocksize(this, lbnd, ubnd)
         872             :
         873             :     ! Dummy arguments
         874             :     class(cam_filemap_t)                       :: this
         875             :     integer,             optional, intent(out) :: lbnd
         876             :     integer,             optional, intent(out) :: ubnd
         877             :
         878   231686064 :     cam_filemap_has_blocksize = associated(this%blcksz)
         879   231686064 :     if (present(lbnd)) then
         880           0 :       lbnd = LBOUND(this%blcksz, 1)
         881             :     end if
         882   231686064 :     if (present(ubnd)) then
         883           0 :       ubnd = UBOUND(this%blcksz, 1)
         884             :     end if
         885             :
         886   231686064 :   end function cam_filemap_has_blocksize
         887             :
         888             :   !---------------------------------------------------------------------------
         889             :   !
         890             :   !  cam_filemap_get_array_bounds: Sets grid bounds for the relevant array
         891             :   !            Only modifies the dimensions corresponding to the map's src
         892             :   !            dims should be sized (rank,2) with the second dimension used
         893             :   !            to store lower(1) and upper(2) bounds
         894             :   !
         895             :   !---------------------------------------------------------------------------
         896     1052928 :   subroutine cam_filemap_get_array_bounds(this, dims)
         897             :
         898             :     ! Dummy arguments
         899             :     class(cam_filemap_t)                       :: this
         900             :     integer,                    intent(inout)  :: dims(:,:)
         901             :
         902             :     ! Local variables
         903             :     integer                                    :: rank ! rank of target array
         904             :     integer                                    :: i    ! Loop variable
         905             :
         906     1052928 :     rank = size(dims,1)
         907     1052928 :     if (size(dims,2) < 2) then
         908           0 :       call endrun('cam_filemap_get_array_bounds: second dim of dims must be 2')
         909             :     end if
         910             :
         911     7370496 :     if (MAXVAL(this%limits(1:max_srcs, 1:2)) > HUGE(kind(dims))) then
         912           0 :       call endrun('cam_filemap_get_array_bounds: limits too large')
         913             :     end if
         914     3158784 :     do i = 1, max_srcs
         915     3158784 :       if (this%src(i) > 0) then
         916     1052928 :         if (this%src(i) > rank) then
         917           0 :           call endrun('cam_filemap_get_array_bounds: rank too small')
         918             :         else
         919             : !!XXgoldyXX: Maybe modify definition of this%limits?
         920             : !          dims(i, 1:2) = INT(this%limits(i, 1:2), kind=kind(dims))
         921     1052928 :           if (associated(this%map)) then
         922     3158784 :             if (size(this%map) > 0) then
         923    71519184 :               dims(i, 1) = MINVAL(this%map(i,:))
         924    71519184 :               dims(i, 2) = MAXVAL(this%map(i,:))
         925             :             else
         926           0 :               dims(i, 1) = 0
         927           0 :               dims(i, 2) = -1
         928             :             end if
         929             :           else
         930           0 :             dims(i, 1) = 0
         931           0 :             dims(i, 2) = -1
         932             :           end if
         933             :         end if
         934     1052928 :       else if (this%src(i) < 0) then
         935             : !!XXgoldyXX: Maybe modify definition of this%limits?
         936             : !        dims(rank + this%src(i) + 1, 1:2) = INT(this%limits(i, 1:2), kind=kind(dims))
         937     1052928 :         if (associated(this%map)) then
         938     3158784 :           if (size(this%map) > 0) then
         939    71519184 :             dims(rank + this%src(i) + 1, 1) = MINVAL(this%map(i,:))
         940    71519184 :             dims(rank + this%src(i) + 1, 2) = MAXVAL(this%map(i,:))
         941             :           else
         942           0 :             dims(rank + this%src(i) + 1, 1) = 0
         943           0 :             dims(rank + this%src(i) + 1, 2) = -1
         944             :           end if
         945             :         else
         946           0 :           dims(rank + this%src(i) + 1, 1) = 0
         947           0 :           dims(rank + this%src(i) + 1, 2) = -1
         948             :         end if
         949             :       else
         950             :         ! src(i)==0 means unused position
         951           0 :         dims(i,:) = 0
         952             :       end if
         953             :     end do
         954     1052928 :   end subroutine cam_filemap_get_array_bounds
         955             :
         956             :   !---------------------------------------------------------------------------
         957             :   !
         958             :   !  cam_filemap_get_active_cols: Find which columns are active in a dimension
         959             :   !        Because we normally decompose columns (blocks or chunks) in the
         960             :   !        last dimension, we default to that dimension
         961             :   !
         962             :   !---------------------------------------------------------------------------
         963           0 :   subroutine cam_filemap_get_active_cols(this, colnum, active, srcdim_in)
         964             :
         965             :     ! Dummy arguments
         966             :     class(cam_filemap_t)                       :: this
         967             :     integer,                    intent(in)     :: colnum
         968             :     logical,                    intent(out)    :: active(:)
         969             :     integer, optional,          intent(in)     :: srcdim_in
         970             :
         971             :     ! Local variables
         972             :     integer                                    :: srcdim
         973             :
         974           0 :     if (present(srcdim_in)) then
         975           0 :       srcdim = srcdim_in
         976             :     else
         977             :       srcdim = max_srcs
         978             :     end if
         979             :
         980             :     ! Sanity checks
         981           0 :     if ((srcdim < 1) .or. (srcdim > max_srcs)) then
         982           0 :       call endrun('cam_filemap_get_active_cols: srcdim out of range')
         983           0 :     else if (this%src(srcdim) >= 0) then
         984           0 :       call endrun('cam_filemap_get_active_cols: Invalid srcdim')
         985           0 :     else if (size(active) < size(this%map, (3 - srcdim))) then
         986           0 :       call endrun('cam_filemap_get_active_cols: active too small')
         987           0 :     else if (colnum < LBOUND(this%map, srcdim)) then
         988           0 :       call endrun('cam_filemap_get_active_cols: colnum too small')
         989           0 :     else if (colnum > UBOUND(this%map, srcdim)) then
         990           0 :       call endrun('cam_filemap_get_active_cols: colnum too large')
         991             :     ! else OK
         992             :     end if
         993             :
         994           0 :     active = .false.
         995             : !!XXgoldyXX: This is probably completely wrong. What we want is column info
         996           0 :     select case(srcdim)
         997             :       case (1)
         998           0 :         active(1:size(this%map, 2)) = (this%map(colnum,:) > 0)
         999             :       case (2)
        1000           0 :         active(1:size(this%map, 1)) = (this%map(:,colnum) > 0)
        1001             :       case default
        1002           0 :         call endrun('cam_filemap_get_active_cols: Invalid srcdim?!?')
        1003             :       end select
        1004           0 :   end subroutine cam_filemap_get_active_cols
        1005             :
        1006             :   !---------------------------------------------------------------------------
        1007             :   !
        1008             :   !  cam_filemap_columnize: Convert lon/lat map to ncol
        1009             :   !
        1010             :   !---------------------------------------------------------------------------
        1011           0 :   subroutine cam_filemap_columnize(this)
        1012             :     use spmd_utils,  only: mpi_sum, mpi_integer, mpicom
        1013             :     use shr_mpi_mod, only: shr_mpi_chkerr
        1014             :
        1015             :     ! Dummy argument
        1016             :     class(cam_filemap_t)                      :: this
        1017             :
        1018             :     ! Local variables
        1019             :     integer                                   :: i, j
        1020             :     integer                                   :: lmax(2)
        1021             :     integer                                   :: maxind(2)
        1022             :     integer                                   :: offset(2)
        1023             :     integer                                   :: ierr
        1024             :     integer(iMap), pointer                    :: newmap(:,:) => NULL()
        1025             :     character(len=*),              parameter  :: subname = 'CAM_FILEMAP_COLUMNIZE'
        1026             :     ! Create a new map with same size and ordering
        1027             :     ! We need the max lon/lat for calculating global offsets
        1028           0 :     lmax = 0
        1029           0 :     if (associated(this%map)) then
        1030           0 :       if (size(this%map, 1) == max_srcs) then
        1031           0 :         call endrun(trim(subname)//': must have at least 1 destination coord')
        1032           0 :       else if (size(this%map, 1) > (max_srcs + 2)) then
        1033           0 :         call endrun(trim(subname)//': has more than 2 destination coords')
        1034             :       end if
        1035           0 :       if (size(this%map, 2) > 0) then
        1036           0 :         lmax(1) = MAXVAL(this%map(max_srcs + 1, :))
        1037           0 :         if (size(this%map, 1) == (max_srcs + 2)) then
        1038           0 :           lmax(2) = MAXVAL(this%map(max_srcs + 2, :))
        1039             :         end if
        1040             :       end if
        1041             :     end if
        1042           0 :     call MPI_allreduce(lmax(1), maxind(1), 1, MPI_integer, mpi_sum, mpicom, ierr)
        1043           0 :     call shr_mpi_chkerr(ierr, subname//': MPI_allreduce maxlon')
        1044           0 :     call MPI_allreduce(lmax(2), maxind(2), 1, MPI_integer, mpi_sum, mpicom, ierr)
        1045           0 :     call shr_mpi_chkerr(ierr, subname//': MPI_allreduce maxlat')
        1046           0 :     if (associated(this%map)) then
        1047           0 :       if (size(this%map, 1) == (max_srcs + 2))then
        1048             :         ! Create the new map
        1049           0 :         allocate(newmap(max_srcs + 1, size(this%map, 2)))
        1050             :         ! Who's on first?
        1051           0 :         if (ANY(this%dest(1:2) <= 0)) then
        1052           0 :           call endrun(trim(subname)//': can only handle positive dest indices')
        1053           0 :         else if (this%dest(1) < this%dest(2)) then
        1054           0 :           offset(1) = 1
        1055           0 :           offset(2) = maxind(1)
        1056           0 :         else if (this%dest(1) > this%dest(2)) then
        1057           0 :           offset(1) = maxind(2)
        1058           0 :           offset(2) = 1
        1059             :         else
        1060           0 :           call endrun(trim(subname)//': dest indices cannot be equal')
        1061             :         end if
        1062           0 :         do i = 1, size(newmap, 2)
        1063           0 :           newmap(1:max_srcs, i) = this%map(1:max_srcs, i)
        1064           0 :           j = ((this%map(max_srcs+1, i) * offset(1)) +                        &
        1065           0 :                (this%map(max_srcs+2, i) * offset(2)))
        1066           0 :           newmap(max_srcs+1, i) = j
        1067             :         end do
        1068             :         ! Replace our map with the new one
        1069           0 :         deallocate(this%map)
        1070           0 :         this%map => newmap
        1071           0 :         nullify(newmap)
        1072             :         ! Fixup dest
        1073           0 :         this%dest(1) = 1
        1074           0 :         this%dest(2:) = 0
        1075             :         ! no else (do nothing if already ncol)
        1076             :       end if ! End if lon/lat map
        1077             :     end if
        1078             :
        1079           0 :   end subroutine cam_filemap_columnize
        1080             :
        1081             :   !---------------------------------------------------------------------------
        1082             :   !
        1083             :   !  cam_filemap_compact: Pack all active elements into a 1-based file order
        1084             :   !                       Also pack latitude and longitude maps
        1085             :   !
        1086             :   !---------------------------------------------------------------------------
        1087           0 :   subroutine cam_filemap_compact(this, lonmap, latmap,                        &
        1088             :        num_lons, num_lats, num_mapped, columnize, dups_ok_in)
        1089             :     use spmd_utils,  only: mpi_sum, mpi_integer, mpicom
        1090             :     use shr_mpi_mod, only: shr_mpi_chkerr
        1091             :
        1092             :     ! Dummy arguments
        1093             :     class(cam_filemap_t)                     :: this
        1094             :     integer(iMap),  pointer                  :: lonmap(:)
        1095             :     integer(iMap),  pointer                  :: latmap(:)
        1096             :     integer,        optional, intent(out)    :: num_lons
        1097             :     integer,        optional, intent(out)    :: num_lats
        1098             :     integer,        optional, intent(out)    :: num_mapped
        1099             :     logical,        optional, intent(in)     :: columnize  ! Convert to ncol
        1100             :     logical,        optional, intent(in)     :: dups_ok_in ! Dup coords OK
        1101             :
        1102             :     ! Local variables
        1103             :     integer                                  :: i
        1104             :     integer                                  :: ierr
        1105             :     integer(iMap), pointer                   :: data(:) => NULL()
        1106             :     integer,       pointer                   :: indices(:) => NULL()
        1107             :     integer                                  :: tmp_size
        1108             :     logical                                  :: dok
        1109             :     character(len=*),              parameter :: subname = 'CAM_FILEMAP_COMPACT'
        1110             :
        1111             :     !! Possibly convert lon/lat map to ncol
        1112           0 :     if (present(columnize)) then
        1113           0 :       if (columnize) then
        1114           0 :         call this%columnize()
        1115             :       end if
        1116             :     end if
        1117             :     !! Are duplicate coordinate indices (lat/lon) OK?
        1118           0 :     if (present(dups_ok_in)) then
        1119           0 :       dok = dups_ok_in
        1120             :     else
        1121           0 :       dok = .false.
        1122             :     end if
        1123             :     ! Get a global index sort of mapped elements.
        1124           0 :     do i = 1, max_dests
        1125           0 :       if (this%dest(i) > 0) then
        1126           0 :         if (associated(this%map)) then
        1127           0 :           if (size(this%map, 1) >= max_srcs + i) then
        1128           0 :             data => this%map(max_srcs + i, :)
        1129             :           else
        1130           0 :             nullify(data)
        1131             :           end if
        1132             :         else
        1133           0 :           nullify(data)
        1134             :         end if
        1135             :         ! Allocate indices if necessary
        1136           0 :         if (associated(indices)) then
        1137           0 :           deallocate(indices)
        1138             :           nullify(indices)
        1139             :         end if
        1140           0 :         if (associated(data)) then
        1141           0 :           allocate(indices(LBOUND(data, 1):UBOUND(data, 1)))
        1142           0 :           indices = 0
        1143             :         else
        1144           0 :           allocate(indices(0))
        1145             :         end if
        1146             :       end if
        1147           0 :       call index_sort_vector(data, indices, compressval=0_iMap)
        1148           0 :       if (associated(data) .and. associated(indices)) then
        1149           0 :         data = indices
        1150             :       end if
        1151             :     end do
        1152           0 :     if (associated(indices)) then
        1153           0 :       deallocate(indices)
        1154             :       nullify(indices)
        1155             :     end if
        1156             :     ! Get a global index sort of lat and lon maps
        1157             :     !! Compress latmap
        1158           0 :     if (associated(latmap)) then
        1159             :       ! Allocate indices
        1160           0 :       allocate(indices(LBOUND(latmap, 1):UBOUND(latmap, 1)))
        1161           0 :       indices = 0
        1162             :     end if
        1163           0 :     call index_sort_vector(latmap, indices, compressval=0_iMap, dups_ok_in=dok)
        1164           0 :     if (associated(latmap)) then
        1165           0 :       latmap = indices
        1166           0 :       deallocate(indices)
        1167             :       nullify(indices)
        1168             :     end if
        1169             :     !! Compress lonmap
        1170           0 :     if (associated(lonmap)) then
        1171           0 :       allocate(indices(LBOUND(lonmap, 1):UBOUND(lonmap, 1)))
        1172           0 :       indices = 0
        1173             :     end if
        1174           0 :     call index_sort_vector(lonmap, indices, compressval=0_iMap, dups_ok_in=dok)
        1175           0 :     if (associated(lonmap)) then
        1176           0 :       lonmap = indices
        1177           0 :       deallocate(indices)
        1178             :       nullify(indices)
        1179             :     end if
        1180             :
        1181           0 :     if (present(num_mapped)) then
        1182           0 :       if (this%num_elem() > 0) then
        1183             :         ! Total number of mapped elements
        1184           0 :         allocate(indices(this%num_elem()))
        1185           0 :         indices = [ (i, i = 1, size(indices)) ]
        1186           0 :         tmp_size = COUNT(this%is_mapped(indices))
        1187           0 :         deallocate(indices)
        1188             :         nullify(indices)
        1189             :       else
        1190           0 :         tmp_size = 0
        1191             :       end if
        1192             :       call MPI_allreduce(tmp_size, num_mapped, 1, MPI_integer,              &
        1193           0 :            mpi_sum, mpicom, ierr)
        1194           0 :       call shr_mpi_chkerr(ierr, subname//': MPI_allreduce num_mapped')
        1195           0 :       if (num_mapped <= 0) then
        1196           0 :         call endrun(trim(subname)//': num_mapped <= 0')
        1197             :       end if
        1198             :     end if
        1199           0 :     if (present(num_lons)) then
        1200           0 :       if (associated(lonmap)) then
        1201           0 :         tmp_size = COUNT(lonmap /= 0)
        1202             :       else
        1203           0 :         tmp_size = 0
        1204             :       end if
        1205             :       call MPI_allreduce(tmp_size, num_lons, 1, MPI_integer,                  &
        1206           0 :            mpi_sum, mpicom, ierr)
        1207           0 :       call shr_mpi_chkerr(ierr, subname//': MPI_allreduce num_lons')
        1208           0 :       if (num_lons <= 0) then
        1209           0 :         call endrun(trim(subname)//': numlons <= 0')
        1210             :       end if
        1211             :     end if
        1212           0 :     if (present(num_lats)) then
        1213           0 :       if (associated(latmap)) then
        1214           0 :         tmp_size = COUNT(latmap /= 0)
        1215             :       else
        1216           0 :         tmp_size = 0
        1217             :       end if
        1218             :       call MPI_allreduce(tmp_size, num_lats, 1, MPI_integer,                  &
        1219           0 :            mpi_sum, mpicom, ierr)
        1220           0 :       call shr_mpi_chkerr(ierr, subname//': MPI_allreduce num_lats')
        1221           0 :       if (num_lats <= 0) then
        1222           0 :         call endrun(trim(subname)//': numlats <= 0')
        1223             :       end if
        1224             :     end if
        1225             :
        1226           0 :   end subroutine cam_filemap_compact
        1227             :
        1228           0 : end module cam_map_utils

Generated by: LCOV version 1.14