Oasis3-MCT
mod_oasis_map.F90
Go to the documentation of this file.
1 
2 !> OASIS map (interpolation) data and methods
3 
4 
6 
11  USE mod_oasis_sys
12  USE mod_oasis_part
13  USE mod_oasis_var
14  USE mod_oasis_mpi
16  USE mod_oasis_io
17  USE mod_oasis_timer
18  USE mct_mod
19  USE grids ! scrip
20  USE netcdf
21 
22  IMPLICIT NONE
23 
24  private
25 
26  public oasis_map_genmap
29 
30  !--- Type of data
31 
32  public prism_mapper_type
33 
34  !> Mapper data for interpolating data between grids
36  !--- fixed at initialization ---
37  type(mct_smatp),pointer :: smatp(:) !< stores mapping data such as weights
38  integer(kind=ip_i4_p) :: nwgts !< number of weights in weights file
39  character(len=ic_long):: file !< file to read/write
40  character(len=ic_med) :: loc !< location setting, src or dst model
41  character(len=ic_med) :: opt !< optimization setting, bfb, sum, or opt
42  character(len=ic_med) :: optval !< mct map setting, src or dst, derived from opt
43  logical :: init !< flag indicating initialization complete
44  integer(kind=ip_i4_p) :: spart !< src partition
45  integer(kind=ip_i4_p) :: dpart !< dst partition
46  character(len=ic_med) :: srcgrid !< source grid name
47  character(len=ic_med) :: dstgrid !< target grid name
48  logical :: avred !< flag indicating AV_ms, AV_md data has been read
49  type(mct_avect) :: av_ms !< stores data for CONSERV for src such as mask and area
50  type(mct_avect) :: av_md !< stores data for CONSERV for dst such as mask and area
51  end type prism_mapper_type
52 
53  integer(kind=ip_i4_p) ,public :: prism_mmapper !< max mappers
54  integer(kind=ip_i4_p) ,public :: prism_nmapper = 0 !< mapper counter
55  type(prism_mapper_type) ,public, pointer :: prism_mapper(:) !< list of defined mappers
56 
57  !--- local kinds ---
58 
59  integer,private,parameter :: r8 = ip_double_p
60  integer,private,parameter :: in = ip_i4_p
61 
62  !--- variable assocaited with local data buffers and reallocation
63 
64  real(R8),private,allocatable :: snew(:,:),sold(:,:) ! reals
65  integer,private,allocatable :: rnew(:),rold(:) ! ints
66  integer,private,allocatable :: cnew(:),cold(:) ! ints
67 
68  logical, parameter :: local_timers_on = .false.
69 
70 !------------------------------------------------------------
71 CONTAINS
72 !------------------------------------------------------------
73 
74 !------------------------------------------------------------
75 
76 !> Routine to generate mapping weights data via a direct SCRIP call
77 
78 !> This routine reads in grid data from files and passes that data
79 !> to SCRIP. Mapping weights are generated and written to a file.
80 !> This entire operation is done on a single task.
81 
82  SUBROUTINE oasis_map_genmap(mapid,namid)
83 
84  IMPLICIT NONE
85 
86  integer(ip_i4_p), intent(in) :: mapid !< map id
87  integer(ip_i4_p), intent(in) :: namid !< namcouple id
88  !----------------------------------------------------------
89 
90  integer(ip_i4_p) :: src_size,src_rank, ncrn_src
91  integer(ip_i4_p) ,allocatable :: src_dims(:),src_mask(:)
92  real(ip_double_p),allocatable :: src_lon(:),src_lat(:)
93  real(ip_double_p),allocatable :: src_corner_lon(:,:),src_corner_lat(:,:)
94  integer(ip_i4_p) :: dst_size,dst_rank, ncrn_dst
95  integer(ip_i4_p) ,allocatable :: dst_dims(:),dst_mask(:)
96  real(ip_double_p),allocatable :: dst_lon(:),dst_lat(:)
97  real(ip_double_p),allocatable :: dst_corner_lon(:,:),dst_corner_lat(:,:)
98  integer(ip_i4_p) ,allocatable :: ifld2(:,:)
99  real(ip_double_p),allocatable :: fld2(:,:),fld3(:,:,:)
100  integer(ip_i4_p) :: i,j,k,icnt,nx,ny,nc
101  logical :: lextrapdone
102  logical :: do_corners
103  character(len=ic_med) :: filename
104  character(len=ic_med) :: fldname
105  character(len=*),parameter :: subname = '(oasis_map_genmap)'
106 
107  call oasis_debug_enter(subname)
108 
109  lextrapdone = .false.
110  nx = -1 ! must be read
111  ny = -1 ! must be read
112  nc = 1 ! might not be read, set to something reasonable
113 
114  !--- checks first ---
115 
116  if (trim(namscrtyp(namid)) /= 'SCALAR') then
117  write(nulprt,*) subname,estr,'only scrip type SCALAR mapping supported'
118  call oasis_abort(file=__file__,line=__line__)
119  endif
120 
121  do_corners = .false.
122  if (trim(namscrmet(namid)) == 'CONSERV') then
123  do_corners = .true.
124  endif
125 
126  !--- src data ---
127 
128  filename = 'grids.nc'
129  if (do_corners) then
130  fldname = trim(namsrcgrd(namid))//'.clo'
131  call oasis_io_read_field_fromroot(filename,fldname,nx=nx,ny=ny,nz=nc)
132  else
133  fldname = trim(namsrcgrd(namid))//'.lon'
134  call oasis_io_read_field_fromroot(filename,fldname,nx=nx,ny=ny)
135  endif
136  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',&
137  trim(fldname),nx,ny,nc,do_corners
138  src_rank = 2
139  src_size = nx*ny
140  allocate(src_dims(src_rank))
141  src_dims(1) = nx
142  src_dims(2) = ny
143  ncrn_src = nc
144  allocate(src_mask(src_size))
145  allocate(src_lon(src_size))
146  allocate(src_lat(src_size))
147  allocate(src_corner_lon(ncrn_src,src_size))
148  allocate(src_corner_lat(ncrn_src,src_size))
149 
150  allocate(ifld2(nx,ny))
151  filename = 'masks.nc'
152  fldname = trim(namsrcgrd(namid))//'.msk'
153  call oasis_io_read_field_fromroot(filename,fldname,ifld2=ifld2)
154  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
155  src_mask(icnt) = ifld2(i,j)
156  enddo; enddo
157  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
158  minval(src_mask),maxval(src_mask)
159  deallocate(ifld2)
160 
161  allocate(fld2(nx,ny))
162  filename = 'grids.nc'
163  fldname = trim(namsrcgrd(namid))//'.lon'
164  call oasis_io_read_field_fromroot(filename,fldname,fld2=fld2)
165  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
166  src_lon(icnt) = fld2(i,j)
167  enddo; enddo
168  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
169  minval(src_lon),maxval(src_lon)
170  fldname = trim(namsrcgrd(namid))//'.lat'
171  call oasis_io_read_field_fromroot(filename,fldname,fld2=fld2)
172  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
173  src_lat(icnt) = fld2(i,j)
174  enddo; enddo
175  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
176  minval(src_lat),maxval(src_lat)
177  deallocate(fld2)
178 
179  if (do_corners) then
180  allocate(fld3(nx,ny,nc))
181  filename = 'grids.nc'
182  fldname = trim(namsrcgrd(namid))//'.clo'
183  call oasis_io_read_field_fromroot(filename,fldname,fld3=fld3)
184  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
185  do k = 1,nc
186  src_corner_lon(k,icnt) = fld3(i,j,k)
187  enddo
188  enddo; enddo
189  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
190  minval(src_corner_lon),maxval(src_corner_lon)
191  fldname = trim(namsrcgrd(namid))//'.cla'
192  call oasis_io_read_field_fromroot(filename,fldname,fld3=fld3)
193  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
194  do k = 1,nc
195  src_corner_lat(k,icnt) = fld3(i,j,k)
196  enddo
197  enddo; enddo
198  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
199  minval(src_corner_lat),maxval(src_corner_lat)
200  deallocate(fld3)
201  else
202  src_corner_lon = -9999.
203  src_corner_lat = -9999.
204  endif
205 
206  !--- dst data ---
207 
208  filename = 'grids.nc'
209  if (do_corners) then
210  fldname = trim(namdstgrd(namid))//'.clo'
211  call oasis_io_read_field_fromroot(filename,fldname,nx=nx,ny=ny,nz=nc)
212  else
213  fldname = trim(namdstgrd(namid))//'.lon'
214  call oasis_io_read_field_fromroot(filename,fldname,nx=nx,ny=ny)
215  endif
216  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname),nx,ny,nc
217  dst_rank = 2
218  dst_size = nx*ny
219  allocate(dst_dims(dst_rank))
220  dst_dims(1) = nx
221  dst_dims(2) = ny
222  ncrn_dst = nc
223  allocate(dst_mask(dst_size))
224  allocate(dst_lon(dst_size))
225  allocate(dst_lat(dst_size))
226  allocate(dst_corner_lon(ncrn_dst,dst_size))
227  allocate(dst_corner_lat(ncrn_dst,dst_size))
228 
229  allocate(ifld2(nx,ny))
230  filename = 'masks.nc'
231  fldname = trim(namdstgrd(namid))//'.msk'
232  call oasis_io_read_field_fromroot(filename,fldname,ifld2=ifld2)
233  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
234  dst_mask(icnt) = ifld2(i,j)
235  enddo; enddo
236  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
237  minval(dst_mask),maxval(dst_mask)
238  deallocate(ifld2)
239 
240  allocate(fld2(nx,ny))
241  filename = 'grids.nc'
242  fldname = trim(namdstgrd(namid))//'.lon'
243  call oasis_io_read_field_fromroot(filename,fldname,fld2=fld2)
244  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
245  dst_lon(icnt) = fld2(i,j)
246  enddo; enddo
247  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
248  minval(dst_lon),maxval(dst_lon)
249  fldname = trim(namdstgrd(namid))//'.lat'
250  call oasis_io_read_field_fromroot(filename,fldname,fld2=fld2)
251  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
252  dst_lat(icnt) = fld2(i,j)
253  enddo; enddo
254  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
255  minval(dst_lat),maxval(dst_lat)
256  deallocate(fld2)
257 
258  if (do_corners) then
259  allocate(fld3(nx,ny,nc))
260  filename = 'grids.nc'
261  fldname = trim(namdstgrd(namid))//'.clo'
262  call oasis_io_read_field_fromroot(filename,fldname,fld3=fld3)
263  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
264  do k = 1,nc
265  dst_corner_lon(k,icnt) = fld3(i,j,k)
266  enddo
267  enddo; enddo
268  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
269  minval(dst_corner_lon),maxval(dst_corner_lon)
270  fldname = trim(namdstgrd(namid))//'.cla'
271  call oasis_io_read_field_fromroot(filename,fldname,fld3=fld3)
272  icnt = 0; do j = 1,ny; do i = 1,nx; icnt = icnt + 1
273  do k = 1,nc
274  dst_corner_lat(k,icnt) = fld3(i,j,k)
275  enddo
276  enddo; enddo
277  if (oasis_debug >= 15) write(nulprt,*) subname,' read ',trim(filename),' ',trim(fldname), &
278  minval(dst_corner_lat),maxval(dst_corner_lat)
279  deallocate(fld3)
280  else
281  dst_corner_lon = -9999.
282  dst_corner_lat = -9999.
283  endif
284 
285  IF (oasis_debug >= 15) THEN
286  WRITE(nulprt,*) subname,' call grid_init '
287  CALL oasis_flush(nulprt)
288  ENDIF
289 
290  !--- 0/1 mask convention opposite in scrip vs oasis
291  src_mask = 1 - src_mask
292  dst_mask = 1 - dst_mask
293  call grid_init(namscrmet(namid),namscrres(namid),namscrbin(namid), &
294  src_size, dst_size, src_dims, dst_dims, &
295  src_rank, dst_rank, ncrn_src, ncrn_dst, &
296  src_mask, dst_mask, namsrcgrd(namid), namdstgrd(namid), &
297  src_lat, src_lon, dst_lat, dst_lon, &
298  src_corner_lat, src_corner_lon, &
299  dst_corner_lat, dst_corner_lon, &
300  ilogunit=nulprt,ilogprt=oasis_debug)
301  if (oasis_debug >= 15) then
302  WRITE(nulprt,*) subname,' done grid_init '
303  CALL oasis_flush(nulprt)
304  ENDIF
305 
306  IF (oasis_debug >= 15) THEN
307  WRITE(nulprt,*) subname,' call scrip '
308  CALL oasis_flush(nulprt)
309  ENDIF
310  if (local_timers_on) call oasis_timer_start('cpl_genmap_scrip')
311  call scrip(prism_mapper(mapid)%file,prism_mapper(mapid)%file,namscrmet(namid), &
312  namscrnor(namid),lextrapdone,namscrvam(namid),namscrnbr(namid),namscrord(namid), &
313  mpi_comm_map, mpi_size_map, mpi_rank_map, mpi_root_map)
314  if (local_timers_on) call oasis_timer_stop('cpl_genmap_scrip')
315  IF (oasis_debug >= 15) THEN
316  WRITE(nulprt,*) subname,' done scrip '
317  CALL oasis_flush(nulprt)
318  ENDIF
319 
320  deallocate(src_dims, dst_dims)
321  deallocate(src_mask)
322  deallocate(src_lon)
323  deallocate(src_lat)
324  deallocate(src_corner_lon)
325  deallocate(src_corner_lat)
326  deallocate(dst_mask)
327  deallocate(dst_lon)
328  deallocate(dst_lat)
329  deallocate(dst_corner_lon)
330  deallocate(dst_corner_lat)
331 
332 
333  call oasis_debug_exit(subname)
334 
335  END SUBROUTINE oasis_map_genmap
336 
337 !------------------------------------------------------------
338 !BOP ===========================================================================
339 !> Read in mapping matrix data from a SCRIP netCDF weights file
340 !
341 ! !IROUTINE: oasis_map_sMatReaddnc_orig - Do a distributed read of a NetCDF SCRIP file and
342 ! return weights in a distributed SparseMatrix
343 !
344 ! !DESCRIPTION:
345 !> Read in mapping matrix data from a SCRIP netCDF data file using
346 !> a low memory method and then scatter to all pes. Based on
347 !> the sMatReaddnc method from CESM1.0.3.
348 !>
349 ! !REMARKS:
350 !> This routine leverages gsmaps to determine scatter pattern.
351 !>
352 !> The scatter is implemented as a broadcast of all weights then a local
353 !> computation on each pe to determine with weights to keep based
354 !> on gsmap information.
355 !>
356 !> The algorithm to determine whether a weight belongs on a pe involves
357 !> creating a couple local arrays (lsstart and lscount) which are
358 !> the local values of start and length from the gsmap. These are
359 !> sorted via a bubble sort and then searched via a binary search
360 !> to check whether a global index is on the local pe.
361 !>
362 !> The local buffer sizes are estimated up front based on ngridcell/npes
363 !> plus 20% (search for 1.2 below). If the local buffer size fills up, then
364 !> the buffer is reallocated 50% larger (search for 1.5 below) and the fill
365 !> continues. The idea is to trade off memory reallocation and copy
366 !> with memory usage. 1.2 and 1.5 are arbitary, other values may
367 !> result in better performance.
368 !>
369 !> Once all the matrix weights have been read, the sMat is initialized,
370 !> the values from the buffers are copied in, and everything is deallocated.
371 !
372 ! !INTERFACE: -----------------------------------------------------------------
373 
374 subroutine oasis_map_smatreaddnc_orig(sMat,SgsMap,DgsMap,newdom, &
375  fileName,mytask,mpicom,nwgts, &
376  areasrc,areadst,ni_i,nj_i,ni_o,nj_o )
378 ! !USES:
379 
380  !--- local kinds ---
381  integer,parameter :: R8 = ip_double_p
382  integer,parameter :: IN = ip_i4_p
383 
384 ! !INPUT/OUTPUT PARAMETERS:
385 
386  type(mct_smat) ,intent(out),pointer :: sMat(:) !< mapping data
387  type(mct_gsmap) ,intent(in) ,target :: SgsMap !< src gsmap
388  type(mct_gsmap) ,intent(in) ,target :: DgsMap !< dst gsmap
389  character(*) ,intent(in) :: newdom !< type of sMat (src or dst)
390  !< src = rearrange and map (bfb), dst = map and rearrange (partial sums)
391  character(*) ,intent(in) :: filename!< netCDF file to read
392  integer(IN) ,intent(in) :: mytask !< processor id
393  integer(IN) ,intent(in) :: mpicom !< mpi communicator
394  integer(IN) ,intent(out) :: nwgts !< number of weights
395  type(mct_avect) ,intent(out), optional :: areasrc !< area of src grid from mapping file
396  type(mct_avect) ,intent(out), optional :: areadst !< area of dst grid from mapping file
397  integer(IN) ,intent(out), optional :: ni_i !< number of lons on input grid
398  integer(IN) ,intent(out), optional :: nj_i !< number of lats on input grid
399  integer(IN) ,intent(out), optional :: ni_o !< number of lons on output grid
400  integer(IN) ,intent(out), optional :: nj_o !< number of lats on output grid
401 
402 ! !EOP
403 
404  !--- local ---
405  integer :: n,m ! generic loop indicies
406  integer :: na ! size of source domain
407  integer :: nb ! size of destination domain
408  integer :: ns ! number of non-zero elements in matrix
409  integer :: ni,nj ! number of row and col in the matrix
410  integer :: igrow ! aVect index for matrix row
411  integer :: igcol ! aVect index for matrix column
412  integer :: iwgt ! aVect index for matrix element
413  integer :: iarea ! aVect index for area
414  integer :: rsize ! size of read buffer
415  integer :: cnt ! local num of wgts
416  integer :: cntold ! local num of wgts, previous read
417  integer :: start(1)! netcdf read
418  integer :: count(1)! netcdf read
419  integer :: start2(2)! netcdf read
420  integer :: count2(2)! netcdf read
421  integer :: bsize ! buffer size
422  integer :: nread ! number of reads
423  logical :: mywt ! does this weight belong on my pe
424  integer :: dims(2)
425  logical :: abort_weight ! flag if bad weight found
426 
427  !--- buffers for i/o ---
428  real(R8) ,allocatable :: rtemp(:) ! real temporary
429  real(R8) ,allocatable :: Sbuf(:,:) ! real weights
430  real(R8) ,allocatable :: remaps(:,:) ! real weights with num_wgts dim
431  integer,allocatable :: Rbuf(:) ! ints rows
432  integer,allocatable :: Cbuf(:) ! ints cols
433 
434  !--- variables associated with local computation of global indices
435  integer :: lsize ! size of local seg map
436  integer :: commsize ! size of local communicator
437  integer,allocatable :: lsstart(:) ! local seg map info
438  integer,allocatable :: lscount(:) ! local seg map info
439  type(mct_gsmap),pointer :: mygsmap ! pointer to one of the gsmaps
440  integer :: l1,l2 ! generice indices for sort
441  logical :: found ! for sort
442 
443  !--- variable assocaited with local data buffers and reallocation
444  real(R8) ,allocatable :: Snew(:,:),Sold(:,:) ! reals
445  integer,allocatable :: Rnew(:),Rold(:) ! ints
446  integer,allocatable :: Cnew(:),Cold(:) ! ints
447 
448  character,allocatable :: str(:) ! variable length char string
449  character(len=ic_long):: attstr ! netCDF attribute name string
450  integer :: status ! netCDF routine return code
451  integer :: fid ! netCDF file ID
452  integer :: vid ! netCDF variable ID
453  integer :: did ! netCDF dimension ID
454  !--- arbitrary size of read buffer, this is the chunk size weights reading
455  integer,parameter :: rbuf_size = 100000
456 
457  !--- global source and destination areas ---
458  type(mct_avect) :: areasrc0 ! area of src grid from mapping file
459  type(mct_avect) :: areadst0 ! area of src grid from mapping file
460 
461  character(*),parameter :: areaAV_field = 'aream'
462 
463  !--- formats ---
464  character(*),parameter :: subName = '(oasis_map_sMatReaddnc_orig)'
465 
466 !-------------------------------------------------------------------------------
467 !
468 !-------------------------------------------------------------------------------
469 
470  call oasis_debug_enter(subname)
471  call oasis_mpi_commsize(mpicom,commsize)
472  nwgts = -1
473  if (local_timers_on) call oasis_timer_start('map_read_orig_read')
474 
475  if (mytask == 0) then
476  if (oasis_debug >= 2) write(nulprt,*) subname," reading mapping matrix data decomposed..."
477 
478  !----------------------------------------------------------------------------
479  !> * Open and read the file SCRIP weights size on the root task
480  !----------------------------------------------------------------------------
481 
482  if (oasis_debug >=2 ) write(nulprt,*) subname," * file name : ",trim(filename)
483  status = nf90_open(trim(filename),nf90_nowrite,fid)
484  if (status /= nf90_noerr) then
485  write(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
486  WRITE(nulprt,*) subname,estr,'mapping file not found = ',trim(filename)
487  call oasis_abort(file=__file__,line=__line__)
488  endif
489 
490  !--- get matrix dimensions ----------
491 ! status = nf90_inq_dimid (fid, 'n_s', did) ! size of sparse matrix
492  status = nf90_inq_dimid(fid, 'num_links', did) ! size of sparse matrix
493  status = nf90_inquire_dimension(fid, did , len = ns)
494 ! status = nf90_inq_dimid (fid, 'n_a', did) ! size of input vector
495  status = nf90_inq_dimid(fid, 'src_grid_size', did) ! size of input vector
496  status = nf90_inquire_dimension(fid, did , len = na)
497 ! status = nf90_inq_dimid (fid, 'n_b', did) ! size of output vector
498  status = nf90_inq_dimid(fid, 'dst_grid_size', did) ! size of output vector
499  status = nf90_inquire_dimension(fid, did , len = nb)
500  status = nf90_inq_dimid(fid, 'num_wgts', did) ! size of output vector
501  status = nf90_inquire_dimension(fid, did , len = nwgts)
502 
503  if (present(ni_i) .and. present(nj_i) .and. present(ni_o) .and. present(nj_o)) then
504 ! status = nf90_inq_dimid (fid, 'ni_a', did) ! number of lons in input grid
505 ! status = nf90_inquire_dimension(fid, did , len = ni_i)
506 ! status = nf90_inq_dimid (fid, 'nj_a', did) ! number of lats in input grid
507 ! status = nf90_inquire_dimension(fid, did , len = nj_i)
508 ! status = nf90_inq_dimid (fid, 'ni_b', did) ! number of lons in output grid
509 ! status = nf90_inquire_dimension(fid, did , len = ni_o)
510 ! status = nf90_inq_dimid (fid, 'nj_b', did) ! number of lats in output grid
511 ! status = nf90_inquire_dimension(fid, did , len = nj_o)
512  status = nf90_inq_varid(fid, 'src_grid_dims', vid)
513  status = nf90_get_var(fid, vid, dims)
514  ni_i = dims(1)
515  nj_i = dims(2)
516  status = nf90_inq_varid(fid, 'dst_grid_dims', vid)
517  status = nf90_get_var(fid, vid, dims)
518  ni_o = dims(1)
519  nj_o = dims(2)
520  end if
521 
522  if (oasis_debug >= 2) write(nulprt,*) subname," * matrix dims src x dst : ",na,' x',nb
523  if (oasis_debug >= 2) write(nulprt,*) subname," * number of non-zero elements: ",ns
524 
525  endif
526 
527  !----------------------------------------------------------------------------
528  !> * Read and load area_a on root task
529  !----------------------------------------------------------------------------
530 
531  if (present(areasrc)) then
532  if (mytask == 0) then
533  call mct_avect_init(areasrc0,' ',areaav_field,na)
534 ! status = nf90_inq_varid (fid,'area_a',vid)
535  status = nf90_inq_varid(fid,'src_grid_area',vid)
536  IF (status /= nf90_noerr) THEN
537  WRITE(nulprt,*) subname,' nf90_strerrr = ',trim(nf90_strerror(status))
538  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
539  CALL oasis_flush(nulprt)
540  ENDIF
541  status = nf90_get_var(fid, vid, areasrc0%rAttr)
542  IF (status /= nf90_noerr) THEN
543  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
544  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
545  CALL oasis_flush(nulprt)
546  ENDIF
547  endif
548  call mct_avect_scatter(areasrc0, areasrc, sgsmap, 0, mpicom, status)
549  if (status /= 0) call mct_die(subname,"Error on scatter of areasrc0")
550  if (mytask == 0) then
551 ! if (present(dbug)) then
552 ! if (dbug > 2) then
553 ! write(nulprt,*) subName,'Size of src ',mct_aVect_lSize(areasrc0)
554 ! write(nulprt,*) subName,'min/max src ',minval(areasrc0%rAttr(1,:)),maxval(areasrc0%rAttr(1,:))
555 ! endif
556 ! end if
557  call mct_avect_clean(areasrc0)
558  end if
559  end if
560 
561  !----------------------------------------------------------------------------
562  !> * Read and load area_b on root task
563  !----------------------------------------------------------------------------
564 
565  if (present(areadst)) then
566  if (mytask == 0) then
567  call mct_avect_init(areadst0,' ',areaav_field,nb)
568 ! status = nf90_inq_varid (fid,'area_b',vid)
569  status = nf90_inq_varid(fid,'dst_grid_area',vid)
570  IF (status /= nf90_noerr) THEN
571  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
572  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
573  CALL oasis_flush(nulprt)
574  ENDIF
575  status = nf90_get_var(fid, vid, areadst0%rAttr)
576  IF (status /= nf90_noerr) THEN
577  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
578  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
579  CALL oasis_flush(nulprt)
580  ENDIF
581  endif
582  call mct_avect_scatter(areadst0, areadst, dgsmap, 0, mpicom, status)
583  if (status /= 0) call mct_die(subname,"Error on scatter of areadst0")
584  if (mytask == 0) then
585 ! if (present(dbug)) then
586 ! if (dbug > 2) then
587 ! write(nulprt,*) subName,'Size of dst ',mct_aVect_lSize(areadst0)
588 ! write(nulprt,*) subName,'min/max dst ',minval(areadst0%rAttr(1,:)),maxval(areadst0%rAttr(1,:))
589 ! endif
590 ! end if
591  call mct_avect_clean(areadst0)
592  endif
593  endif
594 
595  !----------------------------------------------------------------------------
596  !> * Broadcast ni and nj if requested
597  !----------------------------------------------------------------------------
598 
599  if (present(ni_i) .and. present(nj_i) .and. present(ni_o) .and. present(nj_o)) then
600  call oasis_mpi_bcast(ni_i,mpicom,subname//" MPI in ni_i bcast")
601  call oasis_mpi_bcast(nj_i,mpicom,subname//" MPI in nj_i bcast")
602  call oasis_mpi_bcast(ni_o,mpicom,subname//" MPI in ni_o bcast")
603  call oasis_mpi_bcast(nj_o,mpicom,subname//" MPI in nj_o bcast")
604  end if
605 
606  !----------------------------------------------------------------------------
607  !> * Broadcast array sizes and allocate arrays for local storage
608  !----------------------------------------------------------------------------
609 
610  call oasis_mpi_bcast(ns,mpicom,subname//" MPI in ns bcast")
611  call oasis_mpi_bcast(na,mpicom,subname//" MPI in na bcast")
612  call oasis_mpi_bcast(nb,mpicom,subname//" MPI in nb bcast")
613  call oasis_mpi_bcast(nwgts,mpicom,subname//" MPI in nwgts bcast")
614  if (local_timers_on) call oasis_timer_stop('map_read_orig_read')
615 
616  if (local_timers_on) call oasis_timer_start('map_read_orig_sort')
617  !--- setup local seg map, sorted
618  if (newdom == 'src') then
619  mygsmap => dgsmap
620  elseif (newdom == 'dst') then
621  mygsmap => sgsmap
622  else
623  write(nulprt,*) subname,estr,'invalid newdom value, expect src or dst = ',newdom
624  call oasis_abort(file=__file__,line=__line__)
625  endif
626  lsize = 0
627  do n = 1,size(mygsmap%start)
628  if (mygsmap%pe_loc(n) == mytask) then
629  lsize=lsize+1
630  endif
631  enddo
632  allocate(lsstart(lsize),lscount(lsize),stat=status)
633  if (status /= 0) call mct_perr_die(subname,':: allocate Lsstart',status)
634 
635  !----------------------------------------------------------------------------
636  !> * Initialize lsstart and lscount, the sorted list of local indices
637  !----------------------------------------------------------------------------
638 
639  lsize = 0
640  do n = 1,size(mygsmap%start)
641  if (mygsmap%pe_loc(n) == mytask) then ! on my pe
642  lsize=lsize+1
643  found = .false.
644  l1 = 1
645  do while (.not.found .and. l1 < lsize) ! bubble sort copy
646  if (mygsmap%start(n) < lsstart(l1)) then
647  do l2 = lsize, l1+1, -1
648  lsstart(l2) = lsstart(l2-1)
649  lscount(l2) = lscount(l2-1)
650  enddo
651  found = .true.
652  else
653  l1 = l1 + 1
654  endif
655  enddo
656  lsstart(l1) = mygsmap%start(n)
657  lscount(l1) = mygsmap%length(n)
658  endif
659  enddo
660  do n = 1,lsize-1
661  if (lsstart(n) > lsstart(n+1)) then
662  write(nulprt,*) subname,estr,'lsstart not properly sorted'
663  call oasis_abort(file=__file__,line=__line__)
664  endif
665  enddo
666  if (local_timers_on) call oasis_timer_stop('map_read_orig_sort')
667 
668  !----------------------------------------------------------------------------
669  !> * Compute the number of chunks to read, read size is rbuf_size
670  !----------------------------------------------------------------------------
671 
672  if (local_timers_on) call oasis_timer_start('map_read_orig_dist')
673  rsize = min(rbuf_size,ns) ! size of i/o chunks
674  bsize = ((ns/commsize) + 1 ) * 1.2 ! local temporary buffer size
675  if (ns == 0) then
676  nread = 0
677  else
678  nread = (ns-1)/rsize + 1 ! num of reads to do
679  endif
680 
681  !----------------------------------------------------------------------------
682  !> * Allocate arrays for local weights plus row and column indices
683  !----------------------------------------------------------------------------
684 
685  if (mytask == 0) then
686  allocate(remaps(nwgts,rsize),stat=status)
687  if (status /= 0) call mct_perr_die(subname,':: allocate remaps',status)
688  endif
689  allocate(smat(nwgts),stat=status)
690  if (status /= 0) call mct_perr_die(subname,':: allocate Smat',status)
691  allocate(sbuf(nwgts,rsize),rbuf(rsize),cbuf(rsize),stat=status)
692  if (status /= 0) call mct_perr_die(subname,':: allocate Sbuf',status)
693  allocate(snew(nwgts,bsize),cnew(bsize),rnew(bsize),stat=status)
694  if (status /= 0) call mct_perr_die(subname,':: allocate Snew1',status)
695 
696  !----------------------------------------------------------------------------
697  !> * Loop over the chunks of weights data
698  !----------------------------------------------------------------------------
699 
700  cnt = 0
701  do n = 1,nread
702  start(1) = (n-1)*rsize + 1
703  count(1) = min(rsize,ns-start(1)+1)
704  start2(1) = 1
705  count2(1) = nwgts
706  start2(2) = start(1)
707  count2(2) = count(1)
708 
709  !----------------------------------------------------------------------------
710  !> * Read chunk of data on root pe
711  !----------------------------------------------------------------------------
712 
713  if (mytask== 0) then
714 ! status = nf90_inq_varid (fid,'S' ,vid)
715  status = nf90_inq_varid(fid,'remap_matrix' ,vid)
716 ! status = nf90_get_var(fid,vid,start,count,Sbuf)
717  status = nf90_get_var(fid,vid,remaps,start2,count2)
718  sbuf(:,:) = remaps(:,:)
719  IF (status /= nf90_noerr) THEN
720  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
721  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
722  CALL oasis_flush(nulprt)
723  ENDIF
724 
725 ! status = nf90_inq_varid (fid,'row',vid)
726  status = nf90_inq_varid(fid,'dst_address',vid)
727  status = nf90_get_var(fid,vid,rbuf,start,count)
728  IF (status /= nf90_noerr) THEN
729  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
730  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
731  CALL oasis_flush(nulprt)
732  ENDIF
733 
734 ! status = nf90_inq_varid (fid,'col',vid)
735  status = nf90_inq_varid(fid,'src_address',vid)
736  status = nf90_get_var(fid,vid,cbuf,start,count)
737  IF (status /= nf90_noerr) THEN
738  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
739  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
740  CALL oasis_flush(nulprt)
741  ENDIF
742  endif
743 
744  !----------------------------------------------------------------------------
745  !> * Broadcast S, row, col to all tasks
746  !----------------------------------------------------------------------------
747 
748  call oasis_mpi_bcast(sbuf,mpicom,subname//" MPI in Sbuf bcast")
749  call oasis_mpi_bcast(rbuf,mpicom,subname//" MPI in Rbuf bcast")
750  call oasis_mpi_bcast(cbuf,mpicom,subname//" MPI in Cbuf bcast")
751 
752  !----------------------------------------------------------------------------
753  !> * Each task keeps only the data required
754  !----------------------------------------------------------------------------
755 
756  if (namwgtopt == "abort_on_bad_index") then
757  abort_weight = .false.
758  do m = 1,count(1)
759  !--- check for bad weights
760  if ((rbuf(m) <= 0 .or. rbuf(m) > nb .or. &
761  cbuf(m) <= 0 .or. cbuf(m) > na) &
762 ! tcx weight = 0
763  .and. (minval(sbuf(:,m)) /= 0._r8 .or. maxval(sbuf(:,m)) /= 0._r8) &
764  ) then
765  abort_weight = .true.
766  WRITE(nulprt,'(3A,I12,A,I12,A,I12,A,G13.7,A,G13.7,A)') &
767  subname,wstr,'BAD weight found in '//trim(filename), &
768  m,'=id',cbuf(m),'=src',rbuf(m),'=dst',minval(sbuf(:,m)),'=minS',maxval(sbuf(:,m)),'=maxS'
769  endif
770  enddo
771  if (abort_weight) then
772  WRITE(nulprt,*) subname,wstr,'BAD weight found, aborting'
773  call oasis_abort(file=__file__,line=__line__)
774  endif
775  endif
776 
777  do m = 1,count(1)
778  !--- check for bad weights
779  if ((namwgtopt(1:16) == "ignore_bad_index") .and. &
780  (rbuf(m) <= 0 .or. rbuf(m) > nb .or. &
781  cbuf(m) <= 0 .or. cbuf(m) > na)) then
782  mywt = .false.
783 ! tcx weight = 0
784  if (minval(sbuf(:,m)) /= 0._r8 .or. maxval(sbuf(:,m)) /= 0._r8) then
785  if (oasis_debug >= 2 .and. namwgtopt /= "ignore_bad_index_silently") then
786  WRITE(nulprt,'(3A,I12,A,I12,A,I12,A,G13.7,A,G13.7,A)') &
787  subname,wstr,'BAD weight found in '//trim(filename), &
788  m,'=id',cbuf(m),'=src',rbuf(m),'=dst',minval(sbuf(:,m)),'=minS',maxval(sbuf(:,m)),'=maxS'
789  endif
790  endif
791  elseif (newdom == 'src') then
792  mywt = check_myindex(rbuf(m),lsstart,lscount)
793  elseif (newdom == 'dst') then
794  mywt = check_myindex(cbuf(m),lsstart,lscount)
795  endif
796 
797  if (mywt) then
798  cntold = cnt
799  cnt = cnt + 1
800 
801  !----------------------------------------------------------------------------
802  !> * Reallocate local weights arrays if they need to be bigger
803  !----------------------------------------------------------------------------
804  if (cnt > bsize) then
805  !--- allocate old arrays and copy new into old
806  allocate(sold(1:nwgts,cntold),rold(cntold),cold(cntold),stat=status)
807  if (status /= 0) call mct_perr_die(subname,':: allocate old',status)
808  sold(1:nwgts,1:cntold) = snew(1:nwgts,1:cntold)
809  rold(1:cntold) = rnew(1:cntold)
810  cold(1:cntold) = cnew(1:cntold)
811 
812  !--- reallocate new to bigger size, increase buffer by 50% (arbitrary)
813  deallocate(snew,rnew,cnew,stat=status)
814  if (status /= 0) call mct_perr_die(subname,':: allocate new',status)
815  bsize = 1.5 * bsize
816  if (oasis_debug > 15) write(nulprt,*) subname,' reallocate bsize to ',bsize
817  allocate(snew(nwgts,bsize),rnew(bsize),cnew(bsize),stat=status)
818  if (status /= 0) call mct_perr_die(subname,':: allocate old',status)
819 
820  !--- copy data back into new
821  snew(1:nwgts,1:cntold) = sold(1:nwgts,1:cntold)
822  rnew(1:cntold) = rold(1:cntold)
823  cnew(1:cntold) = cold(1:cntold)
824  deallocate(sold,rold,cold,stat=status)
825  if (status /= 0) call mct_perr_die(subname,':: deallocate old',status)
826  endif
827 
828  snew(1:nwgts,cnt) = sbuf(1:nwgts,m)
829  rnew(cnt) = rbuf(m)
830  cnew(cnt) = cbuf(m)
831  endif
832  enddo ! count
833  enddo ! nread
834 
835  !----------------------------------------------------------------------------
836  !> * Clean up arrays
837  !----------------------------------------------------------------------------
838 
839  if (mytask == 0) then
840  deallocate(remaps, stat=status)
841  if (status /= 0) call mct_perr_die(subname,':: deallocate remaps',status)
842  endif
843  deallocate(sbuf,rbuf,cbuf, stat=status)
844  if (status /= 0) call mct_perr_die(subname,':: deallocate Sbuf',status)
845  if (local_timers_on) call oasis_timer_stop('map_read_orig_dist')
846 
847  !----------------------------------------------------------------------------
848  !> * Initialize the mct sMat data type
849  !----------------------------------------------------------------------------
850 
851  if (local_timers_on) call oasis_timer_start('map_read_orig_smati')
852  ! mct_sMat_init must be given the number of rows and columns that
853  ! would be in the full matrix. Nrows= size of output vector=nb.
854  ! Ncols = size of input vector = na.
855  do n = 1,nwgts
856  call mct_smat_init(smat(n), nb, na, cnt)
857  enddo
858 
859  igrow = mct_smat_indexia(smat(1),'grow')
860  igcol = mct_smat_indexia(smat(1),'gcol')
861  iwgt = mct_smat_indexra(smat(1),'weight')
862 
863  if (cnt /= 0) then
864  do n = 1,nwgts
865  smat(n)%data%rAttr(iwgt ,1:cnt) = snew(n,1:cnt)
866  smat(n)%data%iAttr(igrow,1:cnt) = rnew(1:cnt)
867  smat(n)%data%iAttr(igcol,1:cnt) = cnew(1:cnt)
868  enddo
869  endif
870  if (local_timers_on) call oasis_timer_stop('map_read_orig_smati')
871 
872  !----------------------------------------------------------------------------
873  !> * More clean up
874  !----------------------------------------------------------------------------
875 
876  if (local_timers_on) call oasis_timer_start('map_read_orig_clean')
877  deallocate(snew,rnew,cnew, stat=status)
878  deallocate(lsstart,lscount,stat=status)
879  if (status /= 0) call mct_perr_die(subname,':: deallocate new',status)
880 
881  if (mytask == 0) then
882  status = nf90_close(fid)
883  IF (oasis_debug >= 2) THEN
884  WRITE(nulprt,*) subname," ... done reading file"
885  CALL oasis_flush(nulprt)
886  ENDIF
887  endif
888  if (local_timers_on) call oasis_timer_stop('map_read_orig_clean')
889 
890  call oasis_debug_exit(subname)
891 
892 end subroutine oasis_map_smatreaddnc_orig
893 
894 !===============================================================================
895 !BOP ===========================================================================
896 !> Read in mapping matrix data from a SCRIP netCDF file using smart scatter (ceg)
897 !
898 ! !IROUTINE: oasis_map_sMatReaddnc_ceg - Do a distributed read of a NetCDF SCRIP file and
899 ! return weights in a distributed SparseMatrix
900 !
901 ! !DESCRIPTION:
902 !> Read in mapping matrix data from a SCRIP netCDF data file using
903 !> a low memory method and then scatter to all pes using a smart method
904 !> where only select data is sent to tasks. Based on the sMatReaddnc method
905 !> from CESM1.0.3
906 ! !REMARKS:
907 !> This routine leverages gsmaps to determine scatter pattern
908 !>
909 !> The scatter is implemented via the root task reading the data and
910 !> then determining which task gets which weights from the gsmap.
911 !> The root the sends specific data to each task.
912 !>
913 !> The algorithm to determine which task a weigth belongs to involves
914 !> checking the task ownership for a given global index.
915 !>
916 !> The local buffer sizes are estimated up front based on ngridcell/npes
917 !> plus 20% (see 1.2 below). If the local buffer size fills up, then
918 !> the buffer is reallocated 50% larger (see 1.5 below) and the fill
919 !> continues. The idea is to trade off memory reallocation and copy
920 !> with memory usage. 1.2 and 1.5 are arbitary, other values may
921 !> result in better performance.
922 !>
923 !> Once all the matrix weights have been read, the sMat is initialized,
924 !> the values from the buffers are copied in, and everything is deallocated.
925 !
926 ! !INTERFACE: -----------------------------------------------------------------
927 
928 subroutine oasis_map_smatreaddnc_ceg(sMat,SgsMap,DgsMap,newdom, &
929  fileName,mytask,mpicom,nwgts, &
930  areasrc,areadst,ni_i,nj_i,ni_o,nj_o )
932 ! !USES:
933 
934 ! !INPUT/OUTPUT PARAMETERS:
935 
936  type(mct_smat) ,intent(out),pointer :: sMat(:) !< mapping data
937  type(mct_gsmap) ,intent(in) ,target :: SgsMap !< src gsmap
938  type(mct_gsmap) ,intent(in) ,target :: DgsMap !< dst gsmap
939  character(*) ,intent(in) :: newdom !< type of sMat (src or dst)
940  !< src = rearrange and map (bfb), dst = map and rearrange (partial sums)
941  character(*) ,intent(in) :: filename!< netCDF file to read
942  integer(IN) ,intent(in) :: mytask !< processor id
943  integer(IN) ,intent(in) :: mpicom !< mpi communicator
944  integer(IN) ,intent(out) :: nwgts !< number of weights
945  type(mct_avect) ,intent(out), optional :: areasrc !< area of src grid from mapping file
946  type(mct_avect) ,intent(out), optional :: areadst !< area of dst grid from mapping file
947  integer(IN) ,intent(out), optional :: ni_i !< number of lons on input grid
948  integer(IN) ,intent(out), optional :: nj_i !< number of lats on input grid
949  integer(IN) ,intent(out), optional :: ni_o !< number of lons on output grid
950  integer(IN) ,intent(out), optional :: nj_o !< number of lats on output grid
951 
952 ! !EOP
953 
954  !--- local ---
955  integer :: n,m ! generic loop indicies
956  integer :: na ! size of source domain
957  integer :: nb ! size of destination domain
958  integer :: ns ! number of non-zero elements in matrix
959  integer :: ni,nj ! number of row and col in the matrix
960  integer :: igrow ! aVect index for matrix row
961  integer :: igcol ! aVect index for matrix column
962  integer :: iwgt ! aVect index for matrix element
963  integer :: iarea ! aVect index for area
964  integer :: rsize ! size of read buffer
965  integer :: cnt ! local num of wgts
966  integer :: start(1)! netcdf read
967  integer :: count(1)! netcdf read
968  integer :: start2(2)! netcdf read
969  integer :: count2(2)! netcdf read
970  integer :: bsize ! buffer size
971  integer :: nread ! number of reads
972  logical :: mywt ! does this weight belong on my pe
973  integer :: dims(2)
974  logical :: abort_weight ! flag if bad weight found
975 
976  !--- buffers for i/o ---
977  real(R8) ,allocatable :: rtemp(:) ! real temporary
978  real(R8) ,allocatable :: Sbuf(:,:) ! real weights
979  real(R8) ,allocatable :: remaps(:,:) ! real weights with num_wgts dim
980  integer,allocatable :: Rbuf(:) ! ints rows
981  integer,allocatable :: Cbuf(:) ! ints cols
982  real(R8),allocatable :: SReadData(:,:) !
983  integer,allocatable :: RReadData(:) !
984  integer,allocatable :: CReadData(:) !
985  integer,allocatable :: pesave(:) !
986  real(R8),allocatable :: SDistData(:,:) !
987  integer,allocatable :: RDistData(:) !
988  integer,allocatable :: CDistData(:) !
989 
990  !--- variables associated with local computation of global indices
991  integer :: commsize ! size of local communicator
992  type(mct_gsmap),pointer :: mygsmap ! pointer to one of the gsmaps
993  integer :: l1,l2,lsize ! generice indices for sort
994  integer,allocatable :: lsstart(:) ! local seg map info
995  integer,allocatable :: lscount(:) ! local seg map info
996  integer,allocatable :: lspeloc(:) ! local seg map info
997  integer,allocatable :: sortkey(:) ! local sort key info
998  logical :: found ! for sort
999  integer :: pe ! Process ID of owning process
1000  integer :: reclen ! Length of Rbuf/Cbuf to be received
1001  integer :: ierr ! MPI error check
1002  integer,allocatable :: cntrs(:) ! Counters of number of elements stored for each processor
1003  integer :: mpistatus(mpi_status_size) ! MPI_Status object
1004 
1005  character,allocatable :: str(:) ! variable length char string
1006  character(len=ic_long):: attstr ! netCDF attribute name string
1007  integer :: status ! netCDF routine return code
1008  integer :: fid ! netCDF file ID
1009  integer :: vid ! netCDF variable ID
1010  integer :: did ! netCDF dimension ID
1011  !--- arbitrary size of read buffer, this is the chunk size weights reading
1012  integer,parameter :: rbuf_size = 100000
1013  integer :: dimbuffer(8)
1014 
1015  !--- global source and destination areas ---
1016  type(mct_avect) :: areasrc0 ! area of src grid from mapping file
1017  type(mct_avect) :: areadst0 ! area of src grid from mapping file
1018 
1019  character(*),parameter :: areaAV_field = 'aream'
1020 
1021  !--- formats ---
1022  character(*),parameter :: subName = '(oasis_map_sMatReaddnc_ceg)'
1023  character*80 :: fname
1024 
1025 !-------------------------------------------------------------------------------
1026 !
1027 !-------------------------------------------------------------------------------
1028 
1029  call oasis_debug_enter(subname)
1030  call oasis_mpi_commsize(mpicom,commsize)
1031  nwgts = -1
1032  if (local_timers_on) call oasis_timer_start('map_read_ceg_read')
1033 
1034  if (mytask == 0) then
1035  if (oasis_debug >= 2) write(nulprt,*) subname," reading mapping matrix data decomposed..."
1036 
1037  !----------------------------------------------------------------------------
1038  !> * Open and read the file SCRIP weights size on the root task
1039  !----------------------------------------------------------------------------
1040 
1041  if (oasis_debug >=2 ) write(nulprt,*) subname," * file name : ",trim(filename)
1042  status = nf90_open(trim(filename),nf90_nowrite,fid)
1043  if (status /= nf90_noerr) then
1044  write(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1045  WRITE(nulprt,*) subname,estr,'mapping file not found = ',trim(filename)
1046  call oasis_abort(file=__file__,line=__line__)
1047  endif
1048 
1049  !--- get matrix dimensions ----------
1050 ! status = nf90_inq_dimid (fid, 'n_s', did) ! size of sparse matrix
1051  status = nf90_inq_dimid(fid, 'num_links', did) ! size of sparse matrix
1052  status = nf90_inquire_dimension(fid, did , len = ns)
1053 ! status = nf90_inq_dimid (fid, 'n_a', did) ! size of input vector
1054  status = nf90_inq_dimid(fid, 'src_grid_size', did) ! size of input vector
1055  status = nf90_inquire_dimension(fid, did , len = na)
1056 ! status = nf90_inq_dimid (fid, 'n_b', did) ! size of output vector
1057  status = nf90_inq_dimid(fid, 'dst_grid_size', did) ! size of output vector
1058  status = nf90_inquire_dimension(fid, did , len = nb)
1059  status = nf90_inq_dimid(fid, 'num_wgts', did) ! size of output vector
1060  status = nf90_inquire_dimension(fid, did , len = nwgts)
1061 
1062  if (present(ni_i) .and. present(nj_i) .and. present(ni_o) .and. present(nj_o)) then
1063 ! status = nf90_inq_dimid (fid, 'ni_a', did) ! number of lons in input grid
1064 ! status = nf90_inquire_dimension(fid, did , len = ni_i)
1065 ! status = nf90_inq_dimid (fid, 'nj_a', did) ! number of lats in input grid
1066 ! status = nf90_inquire_dimension(fid, did , len = nj_i)
1067 ! status = nf90_inq_dimid (fid, 'ni_b', did) ! number of lons in output grid
1068 ! status = nf90_inquire_dimension(fid, did , len = ni_o)
1069 ! status = nf90_inq_dimid (fid, 'nj_b', did) ! number of lats in output grid
1070 ! status = nf90_inquire_dimension(fid, did , len = nj_o)
1071  status = nf90_inq_varid(fid, 'src_grid_dims', vid)
1072  status = nf90_get_var(fid, vid, dims)
1073  ni_i = dims(1)
1074  nj_i = dims(2)
1075  status = nf90_inq_varid(fid, 'dst_grid_dims', vid)
1076  status = nf90_get_var(fid, vid, dims)
1077  ni_o = dims(1)
1078  nj_o = dims(2)
1079  end if
1080 
1081  if (oasis_debug >= 2) write(nulprt,*) subname," * matrix dims src x dst : ",na,' x',nb
1082  if (oasis_debug >= 2) write(nulprt,*) subname," * number of non-zero elements: ",ns
1083 
1084  endif
1085 
1086  !----------------------------------------------------------------------------
1087  !> * Read and load area_a on root task
1088  !----------------------------------------------------------------------------
1089 
1090  if (present(areasrc)) then
1091  if (mytask == 0) then
1092  call mct_avect_init(areasrc0,' ',areaav_field,na)
1093 ! status = nf90_inq_varid (fid,'area_a',vid)
1094  status = nf90_inq_varid(fid,'src_grid_area',vid)
1095  IF (status /= nf90_noerr) THEN
1096  WRITE(nulprt,*) subname,' nf90_strerrr = ',trim(nf90_strerror(status))
1097  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1098  CALL oasis_flush(nulprt)
1099  ENDIF
1100  status = nf90_get_var(fid, vid, areasrc0%rAttr)
1101  IF (status /= nf90_noerr) THEN
1102  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1103  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1104  CALL oasis_flush(nulprt)
1105  ENDIF
1106  endif
1107  call mct_avect_scatter(areasrc0, areasrc, sgsmap, 0, mpicom, status)
1108  if (status /= 0) call mct_die(subname,"Error on scatter of areasrc0")
1109  if (mytask == 0) then
1110 ! if (present(dbug)) then
1111 ! if (dbug > 2) then
1112 ! write(nulprt,*) subName,'min/max src ',minval(areasrc0%rAttr(1,:)),maxval(areasrc0%rAttr(1,:))
1113 ! endif
1114 ! end if
1115  call mct_avect_clean(areasrc0)
1116  end if
1117  end if
1118 
1119  !----------------------------------------------------------------------------
1120  !> * Read and load area_b on root task
1121  !----------------------------------------------------------------------------
1122 
1123  if (present(areadst)) then
1124  if (mytask == 0) then
1125  call mct_avect_init(areadst0,' ',areaav_field,nb)
1126 ! status = nf90_inq_varid (fid,'area_b',vid)
1127  status = nf90_inq_varid(fid,'dst_grid_area',vid)
1128  IF (status /= nf90_noerr) THEN
1129  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1130  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1131  CALL oasis_flush(nulprt)
1132  ENDIF
1133  status = nf90_get_var(fid, vid, areadst0%rAttr)
1134  IF (status /= nf90_noerr) THEN
1135  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1136  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1137  CALL oasis_flush(nulprt)
1138  ENDIF
1139  endif
1140  call mct_avect_scatter(areadst0, areadst, dgsmap, 0, mpicom, status)
1141  if (status /= 0) call mct_die(subname,"Error on scatter of areadst0")
1142  if (mytask == 0) then
1143 ! if (present(dbug)) then
1144 ! if (dbug > 2) then
1145 ! write(nulprt,*) subName,'min/max dst ',minval(areadst0%rAttr(1,:)),maxval(areadst0%rAttr(1,:))
1146 ! endif
1147 ! end if
1148  call mct_avect_clean(areadst0)
1149  endif
1150  endif
1151 
1152  !----------------------------------------------------------------------------
1153  !> * Broadcast ni and nj if requested
1154  !> * Broadcast array sizes and allocate arrays for local storage
1155  ! Replace 8 MPI_Bcasts with just one
1156  !----------------------------------------------------------------------------
1157 
1158  if (mpi_rank_local.eq.0) then
1159  dimbuffer(1) = ns
1160  dimbuffer(2) = na
1161  dimbuffer(3) = nb
1162  dimbuffer(4) = nwgts
1163  if (present(ni_i) .and. present(nj_i) .and. present(ni_o) .and. present(nj_o)) then
1164  dimbuffer(5) = ni_i
1165  dimbuffer(6) = nj_i
1166  dimbuffer(7) = ni_o
1167  dimbuffer(8) = nj_o
1168  end if
1169  endif
1170  call oasis_mpi_bcast(dimbuffer,mpicom,subname//" MPI of dimbuffer")
1171  if (mpi_rank_local.ne.0) then
1172  ns = dimbuffer(1)
1173  na = dimbuffer(2)
1174  nb = dimbuffer(3)
1175  nwgts = dimbuffer(4)
1176  if (present(ni_i) .and. present(nj_i) .and. present(ni_o) .and. present(nj_o)) then
1177  ni_i = dimbuffer(5)
1178  nj_i = dimbuffer(6)
1179  ni_o = dimbuffer(7)
1180  nj_o = dimbuffer(8)
1181  end if
1182  endif
1183 
1184 ! call oasis_mpi_bcast(ni_i,mpicom,subName//" MPI in ni_i bcast")
1185 ! call oasis_mpi_bcast(nj_i,mpicom,subName//" MPI in nj_i bcast")
1186 ! call oasis_mpi_bcast(ni_o,mpicom,subName//" MPI in ni_o bcast")
1187 ! call oasis_mpi_bcast(nj_o,mpicom,subName//" MPI in nj_o bcast")
1188 
1189  !--- setup local seg map, sorted
1190  if (newdom == 'src') then
1191  mygsmap => dgsmap
1192  elseif (newdom == 'dst') then
1193  mygsmap => sgsmap
1194  else
1195  write(nulprt,*) subname,estr,'invalid newdom value, expect src or dst = ',newdom
1196  call oasis_abort(file=__file__,line=__line__)
1197  endif
1198 
1199  !----------------------------------------------------------------------------
1200  !> * Compute the number of chunks to read, read size is rbuf_size
1201  !----------------------------------------------------------------------------
1202 
1203  rsize = min(rbuf_size,ns) ! size of i/o chunks
1204  bsize = ((ns/commsize) + 1 ) * 1.2 ! local temporary buffer size
1205  if (ns == 0) then
1206  nread = 0
1207  else
1208  nread = (ns-1)/rsize + 1 ! num of reads to do
1209  endif
1210 
1211  !----------------------------------------------------------------------------
1212  !> * Allocate arrays for local weights plus row and column indices
1213  !----------------------------------------------------------------------------
1214 
1215  allocate(smat(nwgts),stat=status)
1216  if (status /= 0) call mct_perr_die(subname,':: allocate Smat',status)
1217  allocate(sbuf(nwgts,rsize),rbuf(rsize),cbuf(rsize),stat=status)
1218  if (status /= 0) call mct_perr_die(subname,':: allocate Sbuf',status)
1219  allocate(snew(nwgts,bsize),cnew(bsize),rnew(bsize),stat=status)
1220  if (status /= 0) call mct_perr_die(subname,':: allocate Snew1',status)
1221 ! write(nulprt,*) subname,mpi_rank_local,rsize,rsize*nwgts
1222 
1223  cnt = 1
1224  if (local_timers_on) call oasis_timer_stop('map_read_ceg_read')
1225 
1226  !----------------------------------------------------------------------------
1227  !> * On the root task
1228  !----------------------------------------------------------------------------
1229 
1230  if (mytask == 0) then
1231 
1232  !----------------------------------------------------------------------------
1233  !> * Initialize lsstart, lscount, and lspeloc, the sorted list of local indices
1234  !> * Sort via bubble sort or merge sort depending on size of array
1235  !----------------------------------------------------------------------------
1236 
1237  if (local_timers_on) call oasis_timer_start('map_read_ceg_sort')
1238  lsize = size(mygsmap%start)
1239  allocate(lsstart(lsize),lscount(lsize),lspeloc(lsize),stat=status)
1240  if (status /= 0) call mct_perr_die(subname,':: allocate Lsstart',status)
1241 
1242  if (lsize > 10) then
1243  ! merge sort
1244  allocate(sortkey(lsize),stat=status)
1245  if (status /= 0) call mct_perr_die(subname,':: allocate sortkey',status)
1246  do n = 1,lsize
1247  lsstart(n) = mygsmap%start(n)
1248  lscount(n) = mygsmap%length(n)
1249  lspeloc(n) = mygsmap%pe_loc(n)
1250  sortkey(n) = n
1251  enddo
1252  call oasis_sys_sorti(lsize,lsstart,sortkey)
1253  call oasis_sys_sortikey(lsize,lscount,sortkey)
1254  call oasis_sys_sortikey(lsize,lspeloc,sortkey)
1255  deallocate(sortkey)
1256  else
1257  ! bubble sort
1258  do n = 1,lsize
1259  found = .false.
1260  l1 = 1
1261  do while (.not.found .and. l1 < n)
1262  if (mygsmap%start(n) < lsstart(l1)) then
1263  do l2 = n, l1+1, -1
1264  lsstart(l2) = lsstart(l2-1)
1265  lscount(l2) = lscount(l2-1)
1266  lspeloc(l2) = lspeloc(l2-1)
1267  enddo
1268  found = .true.
1269  else
1270  l1 = l1 + 1
1271  endif
1272  enddo
1273  lsstart(l1) = mygsmap%start(n)
1274  lscount(l1) = mygsmap%length(n)
1275  lspeloc(l1) = mygsmap%pe_loc(n)
1276  enddo
1277  endif
1278 
1279  do n = 1,size(mygsmap%start)-1
1280  if (lsstart(n) > lsstart(n+1)) then
1281  write(nulprt,*) subname,estr,'lsstart not properly sorted'
1282  call oasis_abort(file=__file__,line=__line__)
1283  endif
1284  enddo
1285  if (local_timers_on) call oasis_timer_stop('map_read_ceg_sort')
1286  if (local_timers_on) call oasis_timer_start('map_read_ceg_dist')
1287 
1288  !----------------------------------------------------------------------------
1289  !> * Allocate arrays for reading data on the root
1290  !----------------------------------------------------------------------------
1291 
1292  allocate(remaps(nwgts,rsize),stat=status)
1293  if (status /= 0) call mct_perr_die(subname,':: allocate remaps',status)
1294  allocate(sreaddata(nwgts,rsize),rreaddata(rsize),creaddata(rsize),stat=status)
1295  if (status /= 0) call mct_perr_die(subname,':: allocate SReadData',status)
1296  allocate(pesave(rsize),stat=status)
1297  if (status /= 0) call mct_perr_die(subname,':: allocate pesave',status)
1298  allocate(sdistdata(nwgts,rsize),rdistdata(rsize),cdistdata(rsize), stat=status)
1299  if (status /= 0) call mct_perr_die(subname,':: allocate SDistData',status)
1300  allocate(cntrs(0:mpi_size_local), stat=status) ! Purposefully allocating one extra
1301  if (status /= 0) call mct_perr_die(subname,':: allocate cntrs',status)
1302 
1303  !----------------------------------------------------------------------------
1304  !> * Loop over the chunks of weights data
1305  !----------------------------------------------------------------------------
1306 
1307  do n = 1,nread
1308  start(1) = (n-1)*rsize + 1
1309  count(1) = min(rsize,ns-start(1)+1)
1310  start2(1) = 1
1311  count2(1) = nwgts
1312  start2(2) = start(1)
1313  count2(2) = count(1)
1314 
1315  !----------------------------------------------------------------------------
1316  !> * Read chunk of data
1317  !----------------------------------------------------------------------------
1318 
1319 ! status = nf90_inq_varid (fid,'S' ,vid)
1320  status = nf90_inq_varid(fid,'remap_matrix' ,vid)
1321 ! status = nf90_get_var(fid,vid,start,count,Sbuf)
1322  status = nf90_get_var(fid,vid,remaps,start2,count2)
1323  sreaddata(:,:) = remaps(:,:)
1324  IF (status /= nf90_noerr) THEN
1325  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1326  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1327  CALL oasis_flush(nulprt)
1328  ENDIF
1329 ! status = nf90_inq_varid (fid,'row',vid)
1330  status = nf90_inq_varid(fid,'dst_address',vid)
1331  status = nf90_get_var(fid,vid,rreaddata,start,count)
1332  IF (status /= nf90_noerr) THEN
1333  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1334  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1335  CALL oasis_flush(nulprt)
1336  ENDIF
1337 
1338 ! status = nf90_inq_varid (fid,'col',vid)
1339  status = nf90_inq_varid(fid,'src_address',vid)
1340  status = nf90_get_var(fid,vid,creaddata,start,count)
1341  IF (status /= nf90_noerr) THEN
1342  WRITE(nulprt,*) subname,' nf90_strerror = ',trim(nf90_strerror(status))
1343  WRITE(nulprt,*) subname,'model :',compid,' proc :',mpi_rank_local
1344  CALL oasis_flush(nulprt)
1345  ENDIF
1346 
1347  ! Two stage process
1348  ! 1. Count how many to send to each process
1349  ! 2. Build the sending array up in process receiving order
1350 
1351  ! Initialize cntrs array for number of accumulations per process
1352  cntrs =0
1353  pesave = -99
1354 
1355  !----------------------------------------------------------------------------
1356  !> * Determine which process owns each weight and count them
1357  !> * Determine offsets in the array
1358  !----------------------------------------------------------------------------
1359 
1360  if (namwgtopt == "abort_on_bad_index") then
1361  abort_weight = .false.
1362  do m = 1,count(1)
1363  !--- check for bad weights
1364  if ((rreaddata(m) <= 0 .or. rreaddata(m) > nb .or. &
1365  creaddata(m) <= 0 .or. creaddata(m) > na) &
1366 ! tcx weight = 0
1367  .and. (minval(sreaddata(:,m)) /= 0._r8 .or. maxval(sreaddata(:,m)) /= 0._r8) &
1368  ) then
1369  abort_weight = .true.
1370  WRITE(nulprt,'(3A,I12,A,I12,A,I12,A,G13.7,A,G13.7,A)') &
1371  subname,wstr,'BAD weight found in '//trim(filename), &
1372  m,'=id',creaddata(m),'=src',rreaddata(m),'=dst',minval(sreaddata(:,m)),'=minS',maxval(sreaddata(:,m)),'=maxS'
1373  endif
1374  enddo
1375  if (abort_weight) then
1376  WRITE(nulprt,*) subname,wstr,'BAD weight found, aborting'
1377  call oasis_abort(file=__file__,line=__line__)
1378  endif
1379  endif
1380 
1381  do m = 1,count(1)
1382  !--- check for bad weights
1383  if ((namwgtopt(1:16) == "ignore_bad_index") .and. &
1384  (rreaddata(m) <= 0 .or. rreaddata(m) > nb .or. &
1385  creaddata(m) <= 0 .or. creaddata(m) > na)) then
1386  pe = -11
1387 ! tcx weight = 0
1388  if (minval(sreaddata(:,m)) /= 0._r8 .or. maxval(sreaddata(:,m)) /= 0._r8) then
1389  if (oasis_debug >= 2 .and. namwgtopt /= "ignore_bad_index_silently") then
1390  WRITE(nulprt,'(3A,I12,A,I12,A,I12,A,G13.7,A,G13.7,A)') &
1391  subname,wstr,'BAD weight found in '//trim(filename), &
1392  m,'=id',creaddata(m),'=src',rreaddata(m),'=dst',minval(sreaddata(:,m)),'=minS',maxval(sreaddata(:,m)),'=maxS'
1393  endif
1394  endif
1395  else if (newdom == 'src') then
1396  pe = get_cegindex(rreaddata(m),lsstart,lscount,lspeloc)
1397  else if (newdom == 'dst') then
1398  pe = get_cegindex(creaddata(m),lsstart,lscount,lspeloc)
1399  endif
1400  pesave(m) = pe
1401 
1402  ! Copy data, incrementing index array, pe = 1 to mpi_size_local
1403  if (pe == -11) then
1404  ! skip it, understood, get_cegindex will error with -99
1405  elseif (pe+1 < 1 .or. pe+1 > mpi_size_local) then
1406  ! skip this case too
1407  ! write(nulprt,*) subname,wstr,'get_cegindex search error', m,count(1),CReadData(m),RReadData(m),SReadData(:,m)
1408  else
1409  cntrs(pe+1) = cntrs(pe+1) + 1 ! Note incrementing 1->noprocs rather than 0->noprocs-1
1410  endif
1411 
1412  end do
1413 
1414  cntrs(0) = 1
1415  do pe = 1, mpi_size_local
1416  cntrs(pe) = cntrs(pe-1) + cntrs(pe)
1417  end do
1418 
1419  !----------------------------------------------------------------------------
1420  !> * Determine which process owns each weight and fill arrays
1421  !----------------------------------------------------------------------------
1422 
1423  do m = 1,count(1)
1424 
1425  pe = pesave(m)
1426 
1427  ! Copy data, incrementing index array, pe = 1 to mpi_size_local
1428  if (pe+1 < 1 .or. pe+1 > mpi_size_local) then
1429  ! skip it
1430  ! write(nulprt,*) subname,'get_cegindex search error2', m,count(1),CReadData(m),RReadData(m),SReadData(:,m)
1431  else
1432  ! Copy data, incrementing index array
1433  sdistdata(:,cntrs(pe)) = sreaddata(:,m)
1434  rdistdata(cntrs(pe)) = rreaddata(m)
1435  cdistdata(cntrs(pe)) = creaddata(m)
1436 
1437  cntrs(pe) = cntrs(pe) + 1
1438  endif
1439 
1440  enddo ! count
1441 
1442  !----------------------------------------------------------------------------
1443  !> * Send select data from root to other processes
1444  ! Copy root process data into local array
1445  ! Send data from root to other processes
1446  !----------------------------------------------------------------------------
1447 
1448  if (cntrs(0).gt.1) then ! Need to do it differently if it is for me!
1449  reclen = cntrs(0)-1
1450  ! Reallocate local weights arrays if they need to be bigger
1451  call augment_arrays(cnt, reclen, bsize, nwgts)
1452 
1453  !--- now p0 copies straight into the ?new arrays
1454  snew(1:nwgts,cnt:cnt+reclen-1) = sdistdata(1:nwgts,1:reclen)
1455  rnew(cnt:cnt+reclen-1) = rdistdata(1:reclen)
1456  cnew(cnt:cnt+reclen-1) = cdistdata(1:reclen)
1457  cnt = cnt + reclen
1458 
1459  endif
1460 
1461  do pe = 1, mpi_size_local
1462  if (cntrs(pe).gt.cntrs(pe-1)) then
1463  ! Send data out
1464  m = cntrs(pe)-cntrs(pe-1)
1465 ! write(nulprt,*) subname, 'Sending [to, datalen] ', pe, m, cntrs(pe-1), cntrs(pe)
1466  call mpi_send(m, 1, mpi_integer, pe, 4000, mpicom, ierr)
1467  call mpi_send(sdistdata(1,cntrs(pe-1)), nwgts*m, mpi_real8, pe, 1000, mpicom, ierr)
1468  call mpi_send(rdistdata(cntrs(pe-1)), m, mpi_integer, pe, 2000, mpicom, ierr)
1469  call mpi_send(cdistdata(cntrs(pe-1)), m, mpi_integer, pe, 3000, mpicom, ierr)
1470  endif
1471  enddo
1472 
1473  enddo ! nread
1474 
1475  !----------------------------------------------------------------------------
1476  !> * Deallocate memory on root process
1477  !----------------------------------------------------------------------------
1478 
1479  m = -1
1480  do pe = 1, mpi_size_local-1
1481  !write(nulprt,*) subname, 'Final sending [to, datalen] ', m, cntrs(m)
1482  call mpi_send(m, 1, mpi_integer, pe, 4000, mpicom, ierr)
1483  end do
1484 
1485  ! Free memory used during the distribution
1486  deallocate(lsstart,lscount,lspeloc, stat=status)
1487  if (status /= 0) call mct_perr_die(subname,':: deallocate lsstart',status)
1488  deallocate(pesave, stat=status)
1489  if (status /= 0) call mct_perr_die(subname,':: deallocate pesave',status)
1490  deallocate(sreaddata,rreaddata,creaddata, stat=status)
1491  if (status /= 0) call mct_perr_die(subname,':: deallocate SReadData',status)
1492  deallocate(sdistdata,rdistdata,cdistdata, stat=status)
1493  if (status /= 0) call mct_perr_die(subname,':: deallocate SDistData',status)
1494  deallocate(cntrs, stat=status)
1495  if (status /= 0) call mct_perr_die(subname,':: deallocate cntrs',status)
1496  deallocate(remaps, stat=status)
1497  if (status /= 0) call mct_perr_die(subname,':: deallocate remaps',status)
1498 
1499  if (local_timers_on) call oasis_timer_stop('map_read_ceg_dist')
1500 
1501  !----------------------------------------------------------------------------
1502  !> * On non-root processes
1503  !----------------------------------------------------------------------------
1504 
1505  else ! mytask == 0
1506 
1507  if (local_timers_on) call oasis_timer_start('map_read_ceg_dist')
1508  !----------------------------------------------------------------------------
1509  !> * Receive data from root
1510  !----------------------------------------------------------------------------
1511 
1512  call oasis_mpi_recv(reclen, 0, 4000, mpicom, subname//" MPI in reclen recv")
1513  ! Check we haven't now had the last data
1514  do while (reclen.ne.-1)
1515 
1516  !--- recv S, row, col on all other pes
1517  !write(nulprt,*) subname, 'Receiving [global-id, datalen] ', mpi_rank_global, reclen
1518  call mpi_recv(sbuf, reclen*nwgts, mpi_real8, 0, 1000, mpicom, mpi_status_ignore, ierr)
1519  call mpi_recv(rbuf, reclen, mpi_integer, 0, 2000, mpicom, mpi_status_ignore, ierr)
1520  call mpi_recv(cbuf, reclen, mpi_integer, 0, mpi_any_tag, mpicom, mpistatus, ierr)
1521 
1522  !----------------------------------------------------------------------------
1523  !> * Reallocate local weights arrays if they need to be bigger
1524  !----------------------------------------------------------------------------
1525 
1526  call augment_arrays(cnt, reclen, bsize, nwgts)
1527 
1528  !--- now each pe keeps what it has been sent
1529  snew(1:nwgts,cnt:cnt+reclen-1) = sbuf(1:nwgts,1:reclen)
1530  rnew(cnt:cnt+reclen-1) = rbuf(1:reclen)
1531  cnew(cnt:cnt+reclen-1) = cbuf(1:reclen)
1532  cnt = cnt + reclen
1533 
1534  call oasis_mpi_recv(reclen, 0, 4000, mpicom, subname//" MPI in reclen recv")
1535  end do
1536  if (local_timers_on) call oasis_timer_stop('map_read_ceg_dist')
1537 
1538  endif ! mytask == 0
1539 
1540  if (local_timers_on) call oasis_timer_start('map_read_ceg_smati')
1541  ! Fix cnt to be the length of the array
1542  cnt = cnt-1
1543 
1544  !----------------------------------------------------------------------------
1545  !> * Clean up arrays
1546  !----------------------------------------------------------------------------
1547 
1548  deallocate(sbuf,rbuf,cbuf, stat=status)
1549  if (status /= 0) call mct_perr_die(subname,':: deallocate Sbuf',status)
1550 
1551  !----------------------------------------------------------------------------
1552  !> * Initialize the mct sMat data type
1553  !----------------------------------------------------------------------------
1554 
1555  ! mct_sMat_init must be given the number of rows and columns that
1556  ! would be in the full matrix. Nrows= size of output vector=nb.
1557  ! Ncols = size of input vector = na.
1558  do n = 1,nwgts
1559  call mct_smat_init(smat(n), nb, na, cnt)
1560  enddo
1561 
1562  igrow = mct_smat_indexia(smat(1),'grow')
1563  igcol = mct_smat_indexia(smat(1),'gcol')
1564  iwgt = mct_smat_indexra(smat(1),'weight')
1565 
1566  if (cnt /= 0) then
1567  do n = 1,nwgts
1568  smat(n)%data%rAttr(iwgt ,1:cnt) = snew(n,1:cnt)
1569  smat(n)%data%iAttr(igrow,1:cnt) = rnew(1:cnt)
1570  smat(n)%data%iAttr(igcol,1:cnt) = cnew(1:cnt)
1571  enddo
1572  endif
1573  if (local_timers_on) call oasis_timer_stop('map_read_ceg_smati')
1574 
1575  !----------------------------------------------------------------------------
1576  !> * More clean up
1577  !----------------------------------------------------------------------------
1578 
1579  if (local_timers_on) call oasis_timer_start('map_read_ceg_clean')
1580  deallocate(snew,rnew,cnew, stat=status)
1581  if (status /= 0) call mct_perr_die(subname,':: deallocate new',status)
1582 
1583  if (mytask == 0) then
1584  status = nf90_close(fid)
1585  IF (oasis_debug >= 2) THEN
1586  WRITE(nulprt,*) subname," ... done reading file"
1587  CALL oasis_flush(nulprt)
1588  ENDIF
1589  endif
1590 
1591  if (local_timers_on) call oasis_timer_stop('map_read_ceg_clean')
1592  call oasis_debug_exit(subname)
1593 
1594 end subroutine oasis_map_smatreaddnc_ceg
1595 
1596 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1597 !!!!!!!!!!!!!!!!!!!!!!!!! Extend array and store data !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1598 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1599 
1600 !> Function that increases temporary work array size of Snew, Rnew, Cnew
1601 
1602 subroutine augment_arrays(cnt, reclen, bsize, nwgts)
1604 ! !USES:
1605 
1606  integer, intent(inout) :: cnt !< elements in current array
1607  integer, intent(in) :: reclen !< elements of new data
1608  integer, intent(inout) :: bsize !< max size of current array
1609  integer, intent(in) :: nwgts !< number of weights in S
1610 
1611  integer :: status ! netCDF routine return code
1612  !--- formats ---
1613  character(*),parameter :: subName = '(ceg_coupler_augment_arrays)'
1614 
1615 
1616  !--- ?new arrays need to be bigger?
1617  if (cnt+reclen > bsize) then
1618 
1619 ! write(nulprt,*) subname,mpi_rank_global, 'EXTEND'
1620 
1621  !--- allocate old arrays and copy new into old
1622  allocate(sold(1:nwgts,cnt),rold(cnt),cold(cnt),stat=status)
1623  if (status /= 0) call mct_perr_die(subname,':: allocate old',status)
1624  sold(1:nwgts,1:cnt-1) = snew(1:nwgts,1:cnt-1)
1625  rold(1:cnt-1) = rnew(1:cnt-1)
1626  cold(1:cnt-1) = cnew(1:cnt-1)
1627 
1628  !--- reallocate new to bigger size, increase buffer by 50% (arbitrary)
1629  deallocate(snew,rnew,cnew,stat=status)
1630  if (status /= 0) call mct_perr_die(subname,':: allocate new',status)
1631  bsize = 1.5 * (cnt+reclen)
1632  if (oasis_debug > 15) write(nulprt,*) subname,' reallocate bsize to ',bsize
1633  allocate(snew(nwgts,bsize),rnew(bsize),cnew(bsize),stat=status)
1634  if (status /= 0) call mct_perr_die(subname,':: allocate old',status)
1635 
1636  !--- copy data back into new
1637  snew(1:nwgts,1:cnt-1) = sold(1:nwgts,1:cnt-1)
1638  rnew(1:cnt-1) = rold(1:cnt-1)
1639  cnew(1:cnt-1) = cold(1:cnt-1)
1640  deallocate(sold,rold,cold,stat=status)
1641  if (status /= 0) call mct_perr_die(subname,':: deallocate old',status)
1642  endif
1643 
1644 end subroutine augment_arrays
1645 
1646 !------------------------------------------------------------
1647 ! !BOP ===========================================================================
1648 !
1649 !> Function that checks whether an index is part of a start and count list
1650 !
1651 !> Does a binary search on a sorted start and count list to determine
1652 !> whether index is a value in the list. The list values consist of
1653 !> the values start(i):start(i)+count(i)-1 for all i.
1654 !
1655 ! !DESCRIPTION:
1656 ! Do a binary search to see if a value is contained in a list of
1657 ! values. return true or false. starti must be monotonically
1658 ! increasing, function does NOT check this.
1659 !
1660 ! !INTERFACE: -----------------------------------------------------------------
1661 
1662 logical function check_myindex(index,starti,counti)
1664 ! !USES:
1665 
1666  !--- local kinds ---
1667  integer,parameter :: R8 = ip_double_p
1668  integer,parameter :: IN = ip_i4_p
1669 
1670 ! !INPUT/OUTPUT PARAMETERS:
1671 
1672  integer(IN) :: index !< index to search
1673  integer(IN) :: starti(:) !< start list
1674  integer(IN) :: counti(:) !< count list
1675 
1676 ! !EOP
1677 
1678  !--- local ---
1679  integer(IN) :: nl,nc,nr,ncprev
1680  integer(IN) :: lsize
1681  logical :: stopnow
1682 
1683  !--- formats ---
1684  character(*),parameter :: subName = '(check_myindex) '
1685 
1686 !-------------------------------------------------------------------------------
1687 !
1688 !-------------------------------------------------------------------------------
1689 
1690 ! call oasis_debug_enter(subname)
1691  check_myindex = .false.
1692 
1693  lsize = size(starti)
1694  if (lsize < 1) then
1695 ! call oasis_debug_exit(subname)
1696  return
1697  endif
1698 
1699  nl = 0
1700  nr = lsize + 1
1701  nc = (nl+nr)/2
1702  stopnow = .false.
1703  do while (.not.stopnow)
1704  if (index < starti(nc)) then
1705  nr = nc
1706  elseif (index > (starti(nc) + counti(nc) - 1)) then
1707  nl = nc
1708  else
1709  check_myindex = .true.
1710 ! call oasis_debug_exit(subname)
1711  return
1712  endif
1713  ncprev = nc
1714  nc = (nl + nr)/2
1715  if (nc == ncprev .or. nc < 1 .or. nc > lsize) stopnow = .true.
1716  enddo
1717 
1718  check_myindex = .false.
1719 
1720 ! call oasis_debug_exit(subname)
1721 
1722 end function check_myindex
1723 
1724 !------------------------------------------------------------
1725 ! !BOP ===========================================================================
1726 !
1727 !> Function that carrys out a binary search for index in list
1728 !
1729 ! !DESCRIPTION:
1730 ! Do a binary search to see if a value is contained in a list of
1731 ! values. return value of processor that owns it
1732 ! starti must be monotonically
1733 ! increasing, function does NOT check this.
1734 !
1735 ! !INTERFACE: -----------------------------------------------------------------
1736 
1737 integer function get_cegindex(index,starti,counti,peloci)
1739 ! !USES:
1740 
1741 
1742  !--- local kinds ---
1743  integer,parameter :: R8 = ip_double_p
1744  integer,parameter :: IN = ip_i4_p
1745 
1746 ! !INPUT/OUTPUT PARAMETERS:
1747 
1748  integer(IN) :: index !< index to search
1749  integer(IN) :: starti(:) !< start list
1750  integer(IN) :: counti(:) !< count list
1751  integer(IN) :: peloci(:) !< pe list
1752 
1753 ! !EOP
1754 
1755 
1756  !--- local ---
1757  integer(IN) :: nl,nc,nr,ncprev
1758  integer(IN) :: lsize
1759  logical :: stopnow
1760 
1761  !--- formats ---
1762  character(*),parameter :: subName = '(get_cegindex) '
1763 
1764 !-------------------------------------------------------------------------------
1765 !
1766 !-------------------------------------------------------------------------------
1767 ! call oasis_debug_enter(subname)
1768 
1769  get_cegindex = -99
1770  lsize = size(starti)
1771  if (lsize < 1) then
1772 ! call oasis_debug_exit(subname)
1773  return
1774  endif
1775 
1776  nl = 0
1777  nr = lsize + 1
1778  nc = (nl+nr)/2
1779  stopnow = .false.
1780  do while (.not.stopnow)
1781  if (index < starti(nc)) then
1782  nr = nc
1783  elseif (index > (starti(nc) + counti(nc) - 1)) then
1784  nl = nc
1785  else
1786  get_cegindex = peloci(nc)
1787 ! call oasis_debug_exit(subname)
1788  return
1789  endif
1790  ncprev = nc
1791  nc = (nl + nr)/2
1792  if (nc == ncprev .or. nc < 1 .or. nc > lsize) stopnow = .true.
1793  enddo
1794 
1795 
1796 ! call oasis_debug_exit(subname)
1797 
1798 
1799 end function get_cegindex
1800 
1801 !===============================================================================
1802 END MODULE mod_oasis_map
1803 
1804 
System type methods.
Provides a common location for several OASIS variables.
Provides reusable IO routines for OASIS.
Definition: mod_oasis_io.F90:4
integer, dimension(:), allocatable, private rnew
subroutine, public oasis_map_smatreaddnc_ceg(sMat, SgsMap, DgsMap, newdom, fileName, mytask, mpicom, nwgts, areasrc, areadst, ni_i, nj_i, ni_o, nj_o)
Read in mapping matrix data from a SCRIP netCDF file using smart scatter (ceg)
logical function check_myindex(index, starti, counti)
Function that checks whether an index is part of a start and count list.
integer(kind=ip_intwp_p) nulprt
subroutine augment_arrays(cnt, reclen, bsize, nwgts)
Function that increases temporary work array size of Snew, Rnew, Cnew.
subroutine, public oasis_abort(id_compid, cd_routine, cd_message, file, line, rcode)
OASIS abort method, publically available to users.
subroutine, public oasis_map_smatreaddnc_orig(sMat, SgsMap, DgsMap, newdom, fileName, mytask, mpicom, nwgts, areasrc, areadst, ni_i, nj_i, ni_o, nj_o)
Read in mapping matrix data from a SCRIP netCDF weights file.
integer, parameter ip_i4_p
real(r8), dimension(:,:), allocatable, private snew
Defines kinds for OASIS.
integer, parameter ip_double_p
Character string manipulation methods.
Provides a generic and simpler interface into MPI calls for OASIS.
integer, dimension(:), allocatable, private rold
subroutine, public oasis_debug_enter(string)
Used when a subroutine is entered, write info to log file at some debug level.
integer, dimension(:), allocatable, private cold
character(len=ic_lvar), dimension(:), pointer, public namsrcgrd
src grid name
OASIS partition data and methods.
subroutine, public oasis_io_read_field_fromroot(filename, fldname, ifld2, fld2, fld3, nx, ny, nz)
Read a field on the root task from a file into an array.
character(len=ic_med), dimension(:), pointer, public namscrtyp
scrip mapping type (SCALAR, VECTOR)
character(len=ic_med), dimension(:), pointer, public namscrmet
scrip method (CONSERV, DISTWGT, BILINEAR, BICUBIC, GAUSWGT)
subroutine, public oasis_map_genmap(mapid, namid)
Routine to generate mapping weights data via a direct SCRIP call.
integer(kind=ip_i4_p), public prism_mmapper
max mappers
Defines parameters for OASIS.
OASIS variable data and methods.
integer(kind=ip_i4_p) oasis_debug
character(len= *), parameter, public estr
type(prism_mapper_type), dimension(:), pointer, public prism_mapper
list of defined mappers
integer, dimension(:), allocatable, private cnew
integer function get_cegindex(index, starti, counti, peloci)
Function that carrys out a binary search for index in list.
integer(kind=ip_i4_p), public prism_nmapper
mapper counter
integer, parameter, private in
real(r8), dimension(:,:), allocatable, private sold
integer, parameter, private r8
Performance timer methods.
Reads the namcouple file for use in OASIS.
Mapper data for interpolating data between grids.
logical, parameter local_timers_on
OASIS map (interpolation) data and methods.