! SVN:$Id: ice_read_write.F90 861 2014-10-21 16:44:30Z tcraig $ !======================================================================= ! Routines for opening, reading and writing external files ! ! author: Tony Craig, NCAR ! ! 2004: Block structure added by William Lipscomb, LANL ! 2006: Converted to free source form (F90) by Elizabeth Hunke ! 2007: netcdf versions added by Alison McLaren & Ann Keen, Met Office module ice_read_write use ice_kinds_mod use ice_constants, only: c0, spval_dbl, & field_loc_noupdate, field_type_noupdate use ice_communicate, only: my_task, master_task use ice_broadcast, only: broadcast_scalar use ice_domain, only: distrb_info use ice_domain_size, only: max_blocks, nx_global, ny_global, ncat use ice_blocks, only: nx_block, ny_block, nghost use ice_exit, only: abort_ice #ifdef ncdf use netcdf #endif implicit none private public :: ice_open, & ice_open_ext, & ice_open_nc, & ice_read, & ice_read_ext, & ice_read_nc, & ice_read_global, & ice_read_global_nc, & ice_read_nc_uv, & ice_write, & ice_write_nc, & ice_write_ext, & ice_close_nc interface ice_write module procedure ice_write_xyt, & ice_write_xyzt end interface interface ice_read module procedure ice_read_xyt, & ice_read_xyzt end interface interface ice_read_nc module procedure ice_read_nc_xy, & ice_read_nc_xyz, & ice_read_nc_point, & ice_read_nc_z end interface interface ice_write_nc module procedure ice_write_nc_xy, & ice_write_nc_xyz end interface !======================================================================= contains !======================================================================= ! Opens an unformatted file for reading. ! nbits indicates whether the file is sequential or direct access. ! ! author: Tony Craig, NCAR subroutine ice_open(nu, filename, nbits) integer (kind=int_kind), intent(in) :: & nu , & ! unit number nbits ! no. of bits per variable (0 for sequential access) character (*) :: filename if (my_task == master_task) then if (nbits == 0) then ! sequential access open(nu,file=filename,form='unformatted') else ! direct access open(nu,file=filename,recl=nx_global*ny_global*nbits/8, & form='unformatted',access='direct') endif ! nbits = 0 endif ! my_task = master_task end subroutine ice_open !======================================================================= ! Opens an unformatted file for reading, incl ghost cells (direct access). ! nbits indicates whether the file is sequential or direct access. ! ! authors: Tony Craig, NCAR ! David Hebert, NRLSSC subroutine ice_open_ext(nu, filename, nbits) integer (kind=int_kind), intent(in) :: & nu , & ! unit number nbits ! no. of bits per variable (0 for sequential access) character (*) :: filename integer (kind=int_kind) :: & nx, ny ! grid dimensions including ghost cells if (my_task == master_task) then if (nbits == 0) then ! sequential access open(nu,file=filename,form='unformatted') else ! direct access nx = nx_global + 2*nghost ny = ny_global + 2*nghost open(nu,file=filename,recl=nx*ny*nbits/8, & form='unformatted',access='direct') endif ! nbits = 0 endif ! my_task = master_task end subroutine ice_open_ext !======================================================================= ! Read an unformatted file and scatter to processors. ! work is a real array, atype indicates the format of the data. ! If the optional variables field_loc and field_type are present, ! the ghost cells are filled using values from the global array. ! This prevents them from being filled with zeroes in land cells ! (subroutine ice_HaloUpdate need not be called). ! ! author: Tony Craig, NCAR subroutine ice_read_xyt(nu, nrec, work, atype, diag, & field_loc, field_type, & ignore_eof, hit_eof) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: scatter_global integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(out) :: & work ! output array (real, 8-byte) character (len=4), intent(in) :: & atype ! format for input array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) logical (kind=log_kind), optional, intent(in) :: ignore_eof logical (kind=log_kind), optional, intent(out) :: hit_eof ! local variables integer (kind=int_kind) :: i, j, ios real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array logical (kind=log_kind) :: ignore_eof_use real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 real (kind=real_kind), dimension(:,:), allocatable :: & work_gr integer(kind=int_kind), dimension(:,:), allocatable :: & work_gi4 integer(selected_int_kind(13)), dimension(:,:), allocatable :: & work_gi8 if (my_task == master_task) then allocate(work_g1(nx_global,ny_global)) else allocate(work_g1(1,1)) ! to save memory endif if (my_task == master_task) then !------------------------------------------------------------------- ! Read global array according to format atype !------------------------------------------------------------------- if (present(hit_eof)) hit_eof = .false. if (atype == 'ida4') then allocate(work_gi4(nx_global,ny_global)) read(nu,rec=nrec) work_gi4 work_g1 = real(work_gi4,kind=dbl_kind) deallocate(work_gi4) elseif (atype == 'ida8') then allocate(work_gi8(nx_global,ny_global)) read(nu,rec=nrec) work_gi8 work_g1 = real(work_gi8,kind=dbl_kind) deallocate(work_gi8) elseif (atype == 'rda4') then allocate(work_gr(nx_global,ny_global)) read(nu,rec=nrec) work_gr work_g1 = work_gr deallocate(work_gr) elseif (atype == 'rda8') then read(nu,rec=nrec) work_g1 elseif (atype == 'ruf8') then if (present(ignore_eof)) then ignore_eof_use = ignore_eof else ignore_eof_use = .false. endif if (ignore_eof_use) then ! Read line from file, checking for end-of-file read(nu, iostat=ios) ((work_g1(i,j),i=1,nx_global), & j=1,ny_global) if (present(hit_eof)) hit_eof = ios < 0 else read(nu) ((work_g1(i,j),i=1,nx_global),j=1,ny_global) endif else write(nu_diag,*) ' ERROR: reading unknown atype ',atype endif endif ! my_task = master_task if (present(hit_eof)) then call broadcast_scalar(hit_eof,master_task) if (hit_eof) then deallocate(work_g1) return endif endif !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum(work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' read_global ',nu, nrec, amin, amax, asum endif !------------------------------------------------------------------- ! Scatter data to individual processors. ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- if (present(field_loc)) then call scatter_global(work, work_g1, master_task, distrb_info, & field_loc, field_type) else call scatter_global(work, work_g1, master_task, distrb_info, & field_loc_noupdate, field_type_noupdate) endif deallocate(work_g1) end subroutine ice_read_xyt !======================================================================= ! Read an unformatted file and scatter to processors. ! work is a real array, atype indicates the format of the data. ! If the optional variables field_loc and field_type are present, ! the ghost cells are filled using values from the global array. ! This prevents them from being filled with zeroes in land cells ! (subroutine ice_HaloUpdate need not be called). ! ! author: Tony Craig, NCAR subroutine ice_read_xyzt(nu, nrec, work, atype, diag, & field_loc, field_type, & ignore_eof, hit_eof) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: scatter_global use ice_domain_size, only: nblyr integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_block,ny_block,nblyr+2,max_blocks), & intent(out) :: & work ! output array (real, 8-byte) character (len=4), intent(in) :: & atype ! format for input array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) logical (kind=log_kind), optional, intent(in) :: ignore_eof logical (kind=log_kind), optional, intent(out) :: hit_eof ! local variables integer (kind=int_kind) :: i, j, k, ios real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array logical (kind=log_kind) :: ignore_eof_use real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g4 integer(kind=int_kind), dimension(:,:,:), allocatable :: & work_gi5 integer(selected_int_kind(13)), dimension(:,:,:), allocatable :: & work_gi9 real (kind=real_kind), dimension(:,:,:), allocatable :: & work_gr3 if (my_task == master_task) then allocate(work_g4(nx_global,ny_global,nblyr+2)) else allocate(work_g4(1,1,nblyr+2)) ! to save memory endif if (my_task == master_task) then !------------------------------------------------------------------- ! Read global array according to format atype !------------------------------------------------------------------- if (present(hit_eof)) hit_eof = .false. if (atype == 'ida4') then allocate(work_gi5(nx_global,ny_global,nblyr+2)) read(nu,rec=nrec) work_gi5 work_g4 = real(work_gi5,kind=dbl_kind) deallocate(work_gi5) elseif (atype == 'ida8') then allocate(work_gi9(nx_global,ny_global,nblyr+2)) read(nu,rec=nrec) work_gi9 work_g4 = real(work_gi9,kind=dbl_kind) deallocate(work_gi9) elseif (atype == 'rda4') then allocate(work_gr3(nx_global,ny_global,nblyr+2)) read(nu,rec=nrec) work_gr3 work_g4 = work_gr3 deallocate(work_gr3) elseif (atype == 'rda8') then read(nu,rec=nrec) work_g4 elseif (atype == 'ruf8') then if (present(ignore_eof)) then ignore_eof_use = ignore_eof else ignore_eof_use = .false. endif if (ignore_eof_use) then ! Read line from file, checking for end-of-file read(nu, iostat=ios) (((work_g4(i,j,k),i=1,nx_global), & j=1,ny_global), & k=1,nblyr+2) if (present(hit_eof)) hit_eof = ios < 0 else read(nu) (((work_g4(i,j,k),i=1,nx_global),j=1,ny_global),& k=1,nblyr+2) endif else write(nu_diag,*) ' ERROR: reading unknown atype ',atype endif endif ! my_task = master_task if (present(hit_eof)) then call broadcast_scalar(hit_eof,master_task) if (hit_eof) then deallocate(work_g4) return endif endif !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then amin = minval(work_g4) amax = maxval(work_g4, mask = work_g4 /= spval_dbl) asum = sum (work_g4, mask = work_g4 /= spval_dbl) write(nu_diag,*) ' read_global ',nu, nrec, amin, amax, asum endif !------------------------------------------------------------------- ! Scatter data to individual processors. ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- do k = 1, nblyr+2 if (present(field_loc)) then call scatter_global(work(:,:,k,:), work_g4(:,:,k), master_task, distrb_info, & field_loc, field_type) else call scatter_global(work(:,:,k,:), work_g4(:,:,k), master_task, distrb_info, & field_loc_noupdate, field_type_noupdate) endif enddo !k deallocate(work_g4) end subroutine ice_read_xyzt !======================================================================= ! Read an unformatted file ! Just like ice_read except that it returns a global array. ! work_g is a real array, atype indicates the format of the data ! ! Adapted by William Lipscomb, LANL, from ice_read subroutine ice_read_global (nu, nrec, work_g, atype, diag, & ignore_eof, hit_eof) use ice_fileunits, only: nu_diag integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_global,ny_global), & intent(out) :: & work_g ! output array (real, 8-byte) character (len=4) :: & atype ! format for input array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind) :: & diag ! if true, write diagnostic output logical (kind=log_kind), optional, intent(in) :: ignore_eof logical (kind=log_kind), optional, intent(out) :: hit_eof ! local variables integer (kind=int_kind) :: i, j, ios real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array logical (kind=log_kind) :: ignore_eof_use real (kind=real_kind), dimension(:,:), allocatable :: & work_gr integer(kind=int_kind), dimension(:,:), allocatable :: & work_gi4 integer(selected_int_kind(13)), dimension(:,:), allocatable :: & work_gi8 work_g(:,:) = c0 if (my_task == master_task) then !------------------------------------------------------------------- ! Read global array according to format atype !------------------------------------------------------------------- if (present(hit_eof)) hit_eof = .false. if (atype == 'ida4') then allocate(work_gi4(nx_global,ny_global)) read(nu,rec=nrec) work_gi4 work_g = real(work_gi4,kind=dbl_kind) deallocate(work_gi4) elseif (atype == 'ida8') then allocate(work_gi8(nx_global,ny_global)) read(nu,rec=nrec) work_gi8 work_g = real(work_gi8,kind=dbl_kind) deallocate(work_gi8) elseif (atype == 'rda4') then allocate(work_gr(nx_global,ny_global)) read(nu,rec=nrec) work_gr work_g = work_gr deallocate(work_gr) elseif (atype == 'rda8') then read(nu,rec=nrec) work_g elseif (atype == 'ruf8') then if (present(ignore_eof)) then ignore_eof_use = ignore_eof else ignore_eof_use = .false. endif if (ignore_eof_use) then ! Read line from file, checking for end-of-file read(nu, iostat=ios) ((work_g(i,j),i=1,nx_global), & j=1,ny_global) if (present(hit_eof)) hit_eof = ios < 0 else read(nu) ((work_g(i,j),i=1,nx_global),j=1,ny_global) endif else write(nu_diag,*) ' ERROR: reading unknown atype ',atype endif endif ! my_task = master_task if (present(hit_eof)) then call broadcast_scalar(hit_eof,master_task) if (hit_eof) return endif !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task == master_task .and. diag) then amin = minval(work_g) amax = maxval(work_g, mask = work_g /= spval_dbl) asum = sum (work_g, mask = work_g /= spval_dbl) write(nu_diag,*) ' read_global ',nu, nrec, amin, amax,asum endif end subroutine ice_read_global !======================================================================= ! Read an unformatted file and scatter to processors, incl ghost cells. ! work is a real array, atype indicates the format of the data. ! (subroutine ice_HaloUpdate need not be called). subroutine ice_read_ext(nu, nrec, work, atype, diag, & field_loc, field_type, & ignore_eof, hit_eof) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: scatter_global_ext integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(out) :: & work ! output array (real, 8-byte) character (len=4), intent(in) :: & atype ! format for input array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) logical (kind=log_kind), optional, intent(in) :: ignore_eof logical (kind=log_kind), optional, intent(out) :: hit_eof ! local variables integer (kind=int_kind) :: i, j, ios, nx, ny real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array logical (kind=log_kind) :: ignore_eof_use real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 real (kind=real_kind), dimension(:,:), allocatable :: & work_gr integer(kind=int_kind), dimension(:,:), allocatable :: & work_gi4 integer(selected_int_kind(13)), dimension(:,:), allocatable :: & work_gi8 nx = nx_global + 2*nghost ny = ny_global + 2*nghost if (my_task == master_task) then allocate(work_g1(nx,ny)) else allocate(work_g1(1,1)) ! to save memory endif if (my_task == master_task) then !------------------------------------------------------------------- ! Read global array according to format atype !------------------------------------------------------------------- if (present(hit_eof)) hit_eof = .false. if (atype == 'ida4') then allocate(work_gi4(nx,ny)) read(nu,rec=nrec) work_gi4 work_g1 = real(work_gi4,kind=dbl_kind) deallocate(work_gi4) elseif (atype == 'ida8') then allocate(work_gi8(nx,ny)) read(nu,rec=nrec) work_gi8 work_g1 = real(work_gi8,kind=dbl_kind) deallocate(work_gi8) elseif (atype == 'rda4') then allocate(work_gr(nx,ny)) read(nu,rec=nrec) work_gr work_g1 = work_gr deallocate(work_gr) elseif (atype == 'rda8') then read(nu,rec=nrec) work_g1 elseif (atype == 'ruf8') then if (present(ignore_eof)) then ignore_eof_use = ignore_eof else ignore_eof_use = .false. endif if (ignore_eof_use) then ! Read line from file, checking for end-of-file read(nu, iostat=ios) ((work_g1(i,j),i=1,nx), & j=1,ny) if (present(hit_eof)) hit_eof = ios < 0 else read(nu) ((work_g1(i,j),i=1,nx),j=1,ny) endif else write(nu_diag,*) ' ERROR: reading unknown atype ',atype endif endif ! my_task = master_task if (present(hit_eof)) then call broadcast_scalar(hit_eof,master_task) if (hit_eof) then deallocate(work_g1) return endif endif !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum (work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' read_global ',nu, nrec, amin, amax, asum endif !------------------------------------------------------------------- ! Scatter data to individual processors. ! NOTE: Ghost cells are always updated !------------------------------------------------------------------- call scatter_global_ext(work, work_g1, master_task, distrb_info) deallocate(work_g1) end subroutine ice_read_ext !======================================================================= ! Writes an unformatted file ! work is a real array, atype indicates the format of the data subroutine ice_write_xyt(nu, nrec, work, atype, diag) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: gather_global integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(in) :: & work ! input array (real, 8-byte) character (len=4), intent(in) :: & atype ! format for output array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output ! local variables integer (kind=int_kind) :: i, j real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 real (kind=real_kind), dimension(:,:), allocatable :: & work_gr integer(kind=int_kind), dimension(:,:), allocatable :: & work_gi4 integer(selected_int_kind(13)), dimension(:,:), allocatable :: & work_gi8 !------------------------------------------------------------------- ! Gather data from individual processors !------------------------------------------------------------------- if (my_task == master_task) then allocate(work_g1(nx_global,ny_global)) else allocate(work_g1(1,1)) ! to save memory endif call gather_global(work_g1, work, master_task, distrb_info, spc_val=c0) if (my_task == master_task) then !------------------------------------------------------------------- ! Write global array according to format atype !------------------------------------------------------------------- if (atype == 'ida4') then allocate(work_gi4(nx_global,ny_global)) work_gi4 = nint(work_g1) write(nu,rec=nrec) work_gi4 deallocate(work_gi4) elseif (atype == 'ida8') then allocate(work_gi8(nx_global,ny_global)) work_gi8 = nint(work_g1) write(nu,rec=nrec) work_gi8 deallocate(work_gi8) elseif (atype == 'rda4') then allocate(work_gr(nx_global,ny_global)) work_gr = work_g1 write(nu,rec=nrec) work_gr deallocate(work_gr) elseif (atype == 'rda8') then write(nu,rec=nrec) work_g1 elseif (atype == 'ruf8') then write(nu) ((work_g1(i,j),i=1,nx_global),j=1,ny_global) else write(nu_diag,*) ' ERROR: writing unknown atype ',atype endif !------------------------------------------------------------------- ! diagnostics !------------------------------------------------------------------- if (diag) then amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum (work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' write_global ', nu, nrec, amin, amax, asum endif endif ! my_task = master_task deallocate(work_g1) end subroutine ice_write_xyt !======================================================================= ! Writes an unformatted file ! work is a real array, atype indicates the format of the data subroutine ice_write_xyzt(nu, nrec, work, atype, diag) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: gather_global use ice_domain_size, only: nblyr integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_block,ny_block,nblyr+2,max_blocks), & intent(in) :: & work ! input array (real, 8-byte) character (len=4), intent(in) :: & atype ! format for output array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output ! local variables integer (kind=int_kind) :: i, j, k real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g4 real (kind=real_kind), dimension(:,:,:), allocatable :: & work_gr3 integer(kind=int_kind), dimension(:,:,:), allocatable :: & work_gi5 integer(selected_int_kind(13)), dimension(:,:,:), allocatable :: & work_gi9 !------------------------------------------------------------------- ! Gather data from individual processors !------------------------------------------------------------------- if (my_task == master_task) then allocate(work_g4(nx_global,ny_global,nblyr+2)) else allocate(work_g4(1,1,nblyr+2)) ! to save memory endif do k = 1,nblyr+2 call gather_global(work_g4(:,:,k), work(:,:,k,:), master_task, & distrb_info, spc_val=c0) enddo !k if (my_task == master_task) then !------------------------------------------------------------------- ! Write global array according to format atype !------------------------------------------------------------------- if (atype == 'ida4') then allocate(work_gi5(nx_global,ny_global,nblyr+2)) work_gi5 = nint(work_g4) write(nu,rec=nrec) work_gi5 deallocate(work_gi5) elseif (atype == 'ida8') then allocate(work_gi9(nx_global,ny_global,nblyr+2)) work_gi9 = nint(work_g4) write(nu,rec=nrec) work_gi9 deallocate(work_gi9) elseif (atype == 'rda4') then allocate(work_gr3(nx_global,ny_global,nblyr+2)) work_gr3 = work_g4 write(nu,rec=nrec) work_gr3 deallocate(work_gr3) elseif (atype == 'rda8') then write(nu,rec=nrec) work_g4 elseif (atype == 'ruf8') then write(nu)(((work_g4(i,j,k),i=1,nx_global),j=1,ny_global), & k=1,nblyr+2) else write(nu_diag,*) ' ERROR: writing unknown atype ',atype endif !------------------------------------------------------------------- ! diagnostics !------------------------------------------------------------------- if (diag) then amin = minval(work_g4) amax = maxval(work_g4, mask = work_g4 /= spval_dbl) asum = sum (work_g4, mask = work_g4 /= spval_dbl) write(nu_diag,*) ' write_global ', nu, nrec, amin, amax, asum endif endif ! my_task = master_task deallocate(work_g4) end subroutine ice_write_xyzt !======================================================================= ! ! Writes an unformatted file, including ghost cells ! work is a real array, atype indicates the format of the data ! ! author: Tony Craig, NCAR subroutine ice_write_ext(nu, nrec, work, atype, diag) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: gather_global_ext integer (kind=int_kind), intent(in) :: & nu , & ! unit number nrec ! record number (0 for sequential access) real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(in) :: & work ! input array (real, 8-byte) character (len=4), intent(in) :: & atype ! format for output array ! (real/integer, 4-byte/8-byte) logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output ! local variables integer (kind=int_kind) :: i, j, nx, ny real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 real (kind=real_kind), dimension(:,:), allocatable :: & work_gr integer(kind=int_kind), dimension(:,:), allocatable :: & work_gi4 integer(selected_int_kind(13)), dimension(:,:), allocatable :: & work_gi8 !------------------------------------------------------------------- ! Gather data from individual processors !------------------------------------------------------------------- nx = nx_global + 2*nghost ny = ny_global + 2*nghost if (my_task == master_task) then allocate(work_g1(nx,ny)) else allocate(work_g1(1,1)) ! to save memory endif call gather_global_ext(work_g1, work, master_task, distrb_info, spc_val=c0) if (my_task == master_task) then !------------------------------------------------------------------- ! Write global array according to format atype !------------------------------------------------------------------- if (atype == 'ida4') then allocate(work_gi4(nx,ny)) work_gi4 = nint(work_g1) write(nu,rec=nrec) work_gi4 deallocate(work_gi4) elseif (atype == 'ida8') then allocate(work_gi8(nx,ny)) work_gi8 = nint(work_g1) write(nu,rec=nrec) work_gi8 deallocate(work_gi8) elseif (atype == 'rda4') then allocate(work_gr(nx,ny)) work_gr = work_g1 write(nu,rec=nrec) work_gr deallocate(work_gr) elseif (atype == 'rda8') then write(nu,rec=nrec) work_g1 elseif (atype == 'ruf8') then write(nu) ((work_g1(i,j),i=1,nx),j=1,ny) else write(nu_diag,*) ' ERROR: writing unknown atype ',atype endif !------------------------------------------------------------------- ! diagnostics !------------------------------------------------------------------- if (diag) then amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum (work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' write_global ', nu, nrec, amin, amax, asum endif endif ! my_task = master_task deallocate(work_g1) end subroutine ice_write_ext !======================================================================= ! Opens a netCDF file for reading ! Adapted by Alison McLaren, Met Office from ice_open subroutine ice_open_nc(filename, fid) character (char_len_long), intent(in) :: & filename ! netCDF filename integer (kind=int_kind), intent(out) :: & fid ! unit number ! local variables #ifdef ncdf integer (kind=int_kind) :: & status ! status variable from netCDF routine if (my_task == master_task) then status = nf90_open(filename, NF90_NOWRITE, fid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_open_nc: Cannot open '//trim(filename) ) endif endif ! my_task = master_task #else fid = -999 ! to satisfy intent(out) attribute #endif end subroutine ice_open_nc !======================================================================= ! Read a netCDF file and scatter to processors. ! If the optional variables field_loc and field_type are present, ! the ghost cells are filled using values from the global array. ! This prevents them from being filled with zeroes in land cells ! (subroutine ice_HaloUpdate need not be called). ! ! Adapted by Alison McLaren, Met Office from ice_read subroutine ice_read_nc_xy(fid, nrec, varname, work, diag, & field_loc, field_type, restart_ext) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: scatter_global, scatter_global_ext integer (kind=int_kind), intent(in) :: & fid , & ! file id nrec ! record number logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output character (len=*), intent(in) :: & varname ! field name in netcdf file real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(out) :: & work ! output array (real, 8-byte) logical (kind=log_kind), optional, intent(in) :: & restart_ext ! if true, read extended grid integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & varid , & ! variable id status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index dimlen ! size of dimension real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array character (char_len) :: & dimname ! dimension name real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 integer (kind=int_kind) :: nx, ny #ifdef ORCA_GRID real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g2 if (.not. present(restart_ext)) then if (my_task == master_task) then allocate(work_g2(nx_global+2,ny_global+1)) else allocate(work_g2(1,1)) ! to save memory endif endif #endif nx = nx_global ny = ny_global if (present(restart_ext)) then if (restart_ext) then nx = nx_global + 2*nghost ny = ny_global + 2*nghost endif endif if (my_task == master_task) then allocate(work_g1(nx,ny)) else allocate(work_g1(1,1)) ! to save memory endif if (my_task == master_task) then !------------------------------------------------------------- ! Find out ID of required variable !------------------------------------------------------------- status = nf90_inq_varid(fid, trim(varname), varid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_nc_xy: Cannot find variable '//trim(varname) ) endif !-------------------------------------------------------------- ! Read global array !-------------------------------------------------------------- #ifndef ORCA_GRID status = nf90_get_var( fid, varid, work_g1, & start=(/1,1,nrec/), & count=(/nx,ny,1/) ) #else if (.not. present(restart_ext)) then status = nf90_get_var( fid, varid, work_g2, & start=(/1,1,nrec/), & count=(/nx_global+2,ny_global+1,1/) ) work_g1 = work_g2(2:nx_global+1,1:ny_global) else status = nf90_get_var( fid, varid, work_g1, & start=(/1,1,nrec/), & count=(/nx,ny,1/) ) endif #endif endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then ! write(nu_diag,*) & ! 'ice_read_nc_xy, fid= ',fid, ', nrec = ',nrec, & ! ', varname = ',trim(varname) ! status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) ! write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar ! do id=1,ndim ! status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) ! write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen ! enddo amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum (work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' min, max, sum =', amin, amax, asum endif !------------------------------------------------------------------- ! Scatter data to individual processors. ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- if (present(restart_ext)) then if (restart_ext) then call scatter_global_ext(work, work_g1, master_task, distrb_info) endif else if (present(field_loc)) then call scatter_global(work, work_g1, master_task, distrb_info, & field_loc, field_type) else call scatter_global(work, work_g1, master_task, distrb_info, & field_loc_noupdate, field_type_noupdate) endif endif deallocate(work_g1) #ifdef ORCA_GRID if (.not. present(restart_ext)) deallocate(work_g2) #endif #else work = c0 ! to satisfy intent(out) attribute #endif end subroutine ice_read_nc_xy !======================================================================= ! Read a netCDF file and scatter to processors. ! If the optional variables field_loc and field_type are present, ! the ghost cells are filled using values from the global array. ! This prevents them from being filled with zeroes in land cells ! (subroutine ice_HaloUpdate need not be called). ! ! Adapted by David Bailey, NCAR from ice_read_nc_xy subroutine ice_read_nc_xyz(fid, nrec, varname, work, diag, & field_loc, field_type, restart_ext) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: scatter_global, scatter_global_ext integer (kind=int_kind), intent(in) :: & fid , & ! file id nrec ! record number character (len=*), intent(in) :: & varname ! field name in netcdf file logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output real (kind=dbl_kind), dimension(nx_block,ny_block,ncat,max_blocks), & intent(out) :: & work ! output array (real, 8-byte) logical (kind=log_kind), optional, intent(in) :: & restart_ext ! if true, read extended grid integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & varid , & ! variable id status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index n, & ! ncat index dimlen ! size of dimension real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array character (char_len) :: & dimname ! dimension name real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g1 integer (kind=int_kind) :: nx, ny #ifdef ORCA_GRID real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g2 if (.not. present(restart_ext)) then if (my_task == master_task) then allocate(work_g2(nx_global+2,ny_global+1,ncat)) else allocate(work_g2(1,1,ncat)) ! to save memory endif endif #endif nx = nx_global ny = ny_global if (present(restart_ext)) then if (restart_ext) then nx = nx_global + 2*nghost ny = ny_global + 2*nghost endif endif if (my_task == master_task) then allocate(work_g1(nx,ny,ncat)) else allocate(work_g1(1,1,ncat)) ! to save memory endif if (my_task == master_task) then !------------------------------------------------------------- ! Find out ID of required variable !------------------------------------------------------------- status = nf90_inq_varid(fid, trim(varname), varid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_nc_xyz: Cannot find variable '//trim(varname) ) endif !-------------------------------------------------------------- ! Read global array !-------------------------------------------------------------- #ifndef ORCA_GRID status = nf90_get_var( fid, varid, work_g1, & start=(/1,1,1,nrec/), & count=(/nx,ny,ncat,1/) ) #else if (.not. present(restart_ext)) then status = nf90_get_var( fid, varid, work_g2, & start=(/1,1,1,nrec/), & count=(/nx_global+2,ny_global+1,ncat,1/) ) work_g1 = work_g2(2:nx_global+1,1:ny_global,:) else status = nf90_get_var( fid, varid, work_g1, & start=(/1,1,1,nrec/), & count=(/nx,ny,ncat,1/) ) endif #endif endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then ! write(nu_diag,*) & ! 'ice_read_nc_xyz, fid= ',fid, ', nrec = ',nrec, & ! ', varname = ',trim(varname) ! status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) ! write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar ! do id=1,ndim ! status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) ! write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen ! enddo do n=1,ncat amin = minval(work_g1(:,:,n)) amax = maxval(work_g1(:,:,n), mask = work_g1(:,:,n) /= spval_dbl) asum = sum (work_g1(:,:,n), mask = work_g1(:,:,n) /= spval_dbl) write(nu_diag,*) ' min, max, sum =', amin, amax, asum enddo endif !------------------------------------------------------------------- ! Scatter data to individual processors. ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- if (present(restart_ext)) then if (restart_ext) then do n=1,ncat call scatter_global_ext(work(:,:,n,:), work_g1(:,:,n), & master_task, distrb_info) enddo endif else if (present(field_loc)) then do n=1,ncat call scatter_global(work(:,:,n,:), work_g1(:,:,n), master_task, & distrb_info, field_loc, field_type) enddo else do n=1,ncat call scatter_global(work(:,:,n,:), work_g1(:,:,n), master_task, & distrb_info, field_loc_noupdate, field_type_noupdate) enddo endif endif deallocate(work_g1) #ifdef ORCA_GRID if (.not. present(restart_ext)) deallocate(work_g2) #endif #else work = c0 ! to satisfy intent(out) attribute #endif end subroutine ice_read_nc_xyz !======================================================================= ! Read a netCDF file ! Adapted by Alison McLaren, Met Office from ice_read subroutine ice_read_nc_point(fid, nrec, varname, work, diag, & field_loc, field_type) use ice_fileunits, only: nu_diag integer (kind=int_kind), intent(in) :: & fid , & ! file id nrec ! record number logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output character (char_len), intent(in) :: & varname ! field name in netcdf file real (kind=dbl_kind), & intent(out) :: & work ! output variable (real, 8-byte) integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & varid, & ! netcdf id for field status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index dimlen ! size of dimension real (kind=dbl_kind), dimension(1) :: & workg ! temporary work variable character (char_len) :: & dimname ! dimension name if (my_task == master_task) then !------------------------------------------------------------- ! Find out ID of required variable !------------------------------------------------------------- status = nf90_inq_varid(fid, trim(varname), varid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_nc_point: Cannot find variable '//trim(varname) ) endif !-------------------------------------------------------------- ! Read point variable !-------------------------------------------------------------- status = nf90_get_var(fid, varid, workg, & start= (/ nrec /), & count=(/ 1 /) ) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_nc_point: Cannot get variable '//trim(varname) ) endif endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then write(nu_diag,*) & 'ice_read_nc_point, fid= ',fid, ', nrec = ',nrec, & ', varname = ',trim(varname) status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar do id=1,ndim status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen enddo endif work = workg(1) #else work = c0 ! to satisfy intent(out) attribute #endif end subroutine ice_read_nc_point !======================================================================= ! Adapted by Nicole Jeffery, LANL subroutine ice_read_nc_z(fid, nrec, varname, work, diag, & field_loc, field_type) use ice_domain_size, only: nilyr use ice_fileunits, only: nu_diag integer (kind=int_kind), intent(in) :: & fid , & ! file id nrec ! record number logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output character (char_len), intent(in) :: & varname ! field name in netcdf file real (kind=dbl_kind), dimension(nilyr), & intent(out) :: & work ! output array (real, 8-byte) integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) ! local variables real (kind=dbl_kind), dimension(:), allocatable :: & work_z #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & varid, & ! netcdf id for field status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index dimlen ! size of dimension character (char_len) :: & dimname ! dimension name allocate(work_z(nilyr)) if (my_task == master_task) then !------------------------------------------------------------- ! Find out ID of required variable !------------------------------------------------------------- status = nf90_inq_varid(fid, trim(varname), varid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_nc: Cannot find variable '//trim(varname) ) endif !-------------------------------------------------------------- ! Read global array !-------------------------------------------------------------- status = nf90_get_var( fid, varid, work_z, & start=(/1,nrec/), & count=(/nilyr,1/) ) endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then write(nu_diag,*) & 'ice_read_nc_z, fid= ',fid, ', nrec = ',nrec, & ', varname = ',trim(varname) status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar do id=1,ndim status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen enddo endif work(:) = work_z(:) deallocate(work_z) #else work = c0 ! to satisfy intent(out) attribute #endif end subroutine ice_read_nc_z !======================================================================= ! Write a netCDF file. ! ! Adapted by David Bailey, NCAR subroutine ice_write_nc_xy(fid, nrec, varid, work, diag, & restart_ext) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: gather_global, gather_global_ext integer (kind=int_kind), intent(in) :: & fid , & ! file id varid , & ! variable id nrec ! record number logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output logical (kind=log_kind), optional, intent(in) :: & restart_ext ! if true, write extended grid real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(in) :: & work ! output array (real, 8-byte) ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index dimlen ! size of dimension real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array character (char_len) :: & dimname ! dimension name real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 integer (kind=int_kind) :: nx, ny nx = nx_global ny = ny_global if (present(restart_ext)) then if (restart_ext) then nx = nx_global + 2*nghost ny = ny_global + 2*nghost endif endif if (my_task == master_task) then allocate(work_g1(nx,ny)) else allocate(work_g1(1,1)) ! to save memory endif if (present(restart_ext)) then if (restart_ext) then call gather_global_ext(work_g1, work, master_task, distrb_info, spc_val=c0) endif else call gather_global(work_g1, work, master_task, distrb_info, spc_val=c0) endif if (my_task == master_task) then !-------------------------------------------------------------- ! Write global array !-------------------------------------------------------------- status = nf90_put_var( fid, varid, work_g1, & start=(/1,1,nrec/), & count=(/nx,ny,1/) ) endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then ! write(nu_diag,*) & ! 'ice_write_nc_xy, fid= ',fid, ', nrec = ',nrec, & ! ', varid = ',varid ! status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) ! write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar ! do id=1,ndim ! status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) ! write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen ! enddo amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum (work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' min, max, sum =', amin, amax, asum endif deallocate(work_g1) #endif end subroutine ice_write_nc_xy !======================================================================= ! Write a netCDF file. ! ! Adapted by David Bailey, NCAR subroutine ice_write_nc_xyz(fid, nrec, varid, work, diag, & restart_ext) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: gather_global, gather_global_ext integer (kind=int_kind), intent(in) :: & fid , & ! file id varid , & ! variable id nrec ! record number logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output logical (kind=log_kind), optional, intent(in) :: & restart_ext ! if true, read extended grid real (kind=dbl_kind), dimension(nx_block,ny_block,ncat,max_blocks), & intent(in) :: & work ! output array (real, 8-byte) ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index n, & ! ncat index dimlen ! size of dimension real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array character (char_len) :: & dimname ! dimension name real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g1 integer (kind=int_kind) :: nx, ny nx = nx_global ny = ny_global if (present(restart_ext)) then if (restart_ext) then nx = nx_global + 2*nghost ny = ny_global + 2*nghost endif endif if (my_task == master_task) then allocate(work_g1(nx,ny,ncat)) else allocate(work_g1(1,1,ncat)) ! to save memory endif if (present(restart_ext)) then if (restart_ext) then do n=1,ncat call gather_global_ext(work_g1(:,:,n), work(:,:,n,:), & master_task, distrb_info, spc_val=c0) enddo endif else do n=1,ncat call gather_global(work_g1(:,:,n), work(:,:,n,:), & master_task, distrb_info, spc_val=c0) enddo endif if (my_task == master_task) then !-------------------------------------------------------------- ! Read global array !-------------------------------------------------------------- status = nf90_put_var( fid, varid, work_g1, & start=(/1,1,1,nrec/), & count=(/nx,ny,ncat,1/) ) endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then ! write(nu_diag,*) & ! 'ice_write_nc_xyz, fid= ',fid, ', nrec = ',nrec, & ! ', varid = ',varid ! status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) ! write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar ! do id=1,ndim ! status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) ! write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen ! enddo amin = 10000._dbl_kind amax = -10000._dbl_kind do n=1,ncat amin = minval(work_g1(:,:,n)) amax = maxval(work_g1(:,:,n), mask = work_g1(:,:,n) /= spval_dbl) asum = sum (work_g1(:,:,n), mask = work_g1(:,:,n) /= spval_dbl) write(nu_diag,*) ' min, max, sum =', amin, amax, asum enddo endif deallocate(work_g1) #endif end subroutine ice_write_nc_xyz !======================================================================= ! Read a netcdf file. ! Just like ice_read_nc except that it returns a global array. ! work_g is a real array ! ! Adapted by William Lipscomb, LANL, from ice_read ! Adapted by Ann Keen, Met Office, to read from a netcdf file subroutine ice_read_global_nc (fid, nrec, varname, work_g, diag) use ice_fileunits, only: nu_diag integer (kind=int_kind), intent(in) :: & fid , & ! file id nrec ! record number character (char_len), intent(in) :: & varname ! field name in netcdf file real (kind=dbl_kind), dimension(nx_global,ny_global), & intent(out) :: & work_g ! output array (real, 8-byte) logical (kind=log_kind) :: & diag ! if true, write diagnostic output ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & varid, & ! netcdf id for field status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index dimlen ! size of dimension real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array character (char_len) :: & dimname ! dimension name ! #ifdef ORCA_GRID real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g3 if (my_task == master_task) then allocate(work_g3(nx_global+2,ny_global+1)) else allocate(work_g3(1,1)) ! to save memory endif work_g3(:,:) = c0 #endif work_g(:,:) = c0 if (my_task == master_task) then !------------------------------------------------------------- ! Find out ID of required variable !------------------------------------------------------------- status = nf90_inq_varid(fid, trim(varname), varid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_global_nc: Cannot find variable '//trim(varname) ) endif !-------------------------------------------------------------- ! Read global array !-------------------------------------------------------------- #ifndef ORCA_GRID status = nf90_get_var( fid, varid, work_g, & start=(/1,1,nrec/), & count=(/nx_global,ny_global,1/) ) #else status = nf90_get_var( fid, varid, work_g3, & start=(/1,1,nrec/), & count=(/nx_global+2,ny_global+1,1/) ) work_g=work_g3(2:nx_global+1,1:ny_global) #endif endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task == master_task .and. diag) then ! write(nu_diag,*) & ! 'ice_read_global_nc, fid= ',fid, ', nrec = ',nrec, & ! ', varname = ',trim(varname) ! status = nf90_inquire(fid, nDimensions=ndim, nVariables=nvar) ! write(nu_diag,*) 'ndim= ',ndim,', nvar= ',nvar ! do id=1,ndim ! status = nf90_inquire_dimension(fid,id,name=dimname,len=dimlen) ! write(nu_diag,*) 'Dim name = ',trim(dimname),', size = ',dimlen ! enddo amin = minval(work_g) amax = maxval(work_g, mask = work_g /= spval_dbl) asum = sum (work_g, mask = work_g /= spval_dbl) write(nu_diag,*) 'min, max, sum = ', amin, amax, asum endif #ifdef ORCA_GRID deallocate(work_g3) #endif #else work_g = c0 ! to satisfy intent(out) attribute #endif end subroutine ice_read_global_nc !======================================================================= ! Closes a netCDF file ! author: Alison McLaren, Met Office subroutine ice_close_nc(fid) integer (kind=int_kind), intent(in) :: & fid ! unit number ! local variables #ifdef ncdf integer (kind=int_kind) :: & status ! status variable from netCDF routine if (my_task == master_task) then status = nf90_close(fid) endif #endif end subroutine ice_close_nc !======================================================================= ! Read a netCDF file and scatter to processors. ! If the optional variables field_loc and field_type are present, ! the ghost cells are filled using values from the global array. ! This prevents them from being filled with zeroes in land cells ! (subroutine ice_HaloUpdate need not be called). ! ! Adapted by Elizabeth Hunke for reading 3D ocean currents subroutine ice_read_nc_uv(fid, nrec, nzlev, varname, work, diag, & field_loc, field_type, restart_ext) use ice_fileunits, only: nu_diag use ice_gather_scatter, only: scatter_global, scatter_global_ext integer (kind=int_kind), intent(in) :: & fid , & ! file id nrec , & ! record number nzlev ! z level logical (kind=log_kind), intent(in) :: & diag ! if true, write diagnostic output character (len=*), intent(in) :: & varname ! field name in netcdf file real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), & intent(out) :: & work ! output array (real, 8-byte) logical (kind=log_kind), optional, intent(in) :: & restart_ext ! if true, read extended grid integer (kind=int_kind), optional, intent(in) :: & field_loc, & ! location of field on staggered grid field_type ! type of field (scalar, vector, angle) ! local variables #ifdef ncdf ! netCDF file diagnostics: integer (kind=int_kind) :: & varid , & ! variable id status, & ! status output from netcdf routines ndim, nvar, & ! sizes of netcdf file id, & ! dimension index dimlen ! size of dimension real (kind=dbl_kind) :: & amin, amax, asum ! min, max values and sum of input array character (char_len) :: & dimname ! dimension name real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 integer (kind=int_kind) :: nx, ny nx = nx_global ny = ny_global if (present(restart_ext)) then if (restart_ext) then nx = nx_global + 2*nghost ny = ny_global + 2*nghost endif endif if (my_task == master_task) then allocate(work_g1(nx,ny)) else allocate(work_g1(1,1)) ! to save memory endif if (my_task == master_task) then !------------------------------------------------------------- ! Find out ID of required variable !------------------------------------------------------------- status = nf90_inq_varid(fid, trim(varname), varid) if (status /= nf90_noerr) then call abort_ice ( & 'ice_read_nc_xy: Cannot find variable '//trim(varname) ) endif !-------------------------------------------------------------- ! Read global array !-------------------------------------------------------------- status = nf90_get_var( fid, varid, work_g1, & start=(/1,1,nzlev,nrec/), & count=(/nx,ny,1,1/) ) endif ! my_task = master_task !------------------------------------------------------------------- ! optional diagnostics !------------------------------------------------------------------- if (my_task==master_task .and. diag) then amin = minval(work_g1) amax = maxval(work_g1, mask = work_g1 /= spval_dbl) asum = sum (work_g1, mask = work_g1 /= spval_dbl) write(nu_diag,*) ' min, max, sum =', amin, amax, asum endif !------------------------------------------------------------------- ! Scatter data to individual processors. ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- if (present(restart_ext)) then if (restart_ext) then call scatter_global_ext(work, work_g1, master_task, distrb_info) endif else if (present(field_loc)) then call scatter_global(work, work_g1, master_task, distrb_info, & field_loc, field_type) else call scatter_global(work, work_g1, master_task, distrb_info, & field_loc_noupdate, field_type_noupdate) endif endif deallocate(work_g1) #else work = c0 ! to satisfy intent(out) attribute #endif end subroutine ice_read_nc_uv !======================================================================= end module ice_read_write !=======================================================================