module tracer_data 27,8 !----------------------------------------------------------------------- ! module used to read (and interpolate) offline tracer data (sources and ! mixing ratios) ! Created by: Francis Vitt -- 2 May 2006 ! Modified by : Jim Edwards -- 10 March 2009 !----------------------------------------------------------------------- use shr_kind_mod, only : r8 => shr_kind_r8,r4 => shr_kind_r4, shr_kind_cl, SHR_KIND_CS use time_manager, only : get_curr_date, get_step_size, get_calendar, get_curr_calday use spmd_utils, only : masterproc use ppgrid, only : pcols, pver, pverp, begchunk, endchunk use abortutils, only : endrun use cam_logfile, only : iulog use phys_buffer, only : pbuf, pbuf_get_fld_idx use time_manager, only : set_time_float_from_date, set_date_from_time_float use pio, only : file_desc_t, var_desc_t, & pio_seterrorhandling, pio_internal_error, pio_bcast_error, & pio_setdebuglevel, & pio_char, pio_noerr, & pio_inq_dimid, pio_inq_varid, & pio_def_dim, pio_def_var, & pio_put_att, pio_put_var, & pio_get_var, pio_get_att, pio_nowrite, pio_inq_dimlen, & pio_inq_vardimid, pio_inq_dimlen, pio_closefile implicit none private ! all unless made public save public :: trfld, input3d, input2d, trfile public :: trcdata_init public :: advance_trcdata public :: get_fld_data public :: get_fld_ndx public :: write_trc_restart public :: read_trc_restart public :: init_trc_restart ! !PUBLIC MEMBERS type input3d real(r8), dimension(:,:,:), pointer :: data endtype input3d type input2d real(r8), dimension(:,:), pointer :: data endtype input2d type trfld real(r8), dimension(:,:,:), pointer :: data type(input3d), dimension(4) :: input character(len=32) :: srcnam character(len=32) :: fldnam character(len=32) :: units type(var_desc_t) :: var_id integer :: chnk_offset integer :: coords(4) ! LATDIM | LONDIM | LEVDIM | TIMDIM integer :: order(4) ! LATDIM | LONDIM | LEVDIM | TIMDIM endtype trfld type trfile type(input2d), dimension(4) :: ps_in character(len=shr_kind_cl) :: pathname = ' ' character(len=shr_kind_cl) :: curr_filename = ' ' character(len=shr_kind_cl) :: next_filename = ' ' type(file_desc_t) :: curr_fileid type(file_desc_t) :: next_fileid type(var_desc_t), pointer :: currfnameid ! pio restart file var id type(var_desc_t), pointer :: nextfnameid ! pio restart file var id character(len=shr_kind_cl) :: filenames_list = '' real(r8) :: datatimem = -1.e36_r8 ! time of prv. values read in real(r8) :: datatimep = -1.e36_r8 ! time of nxt. values read in real(r8) :: datatimes(4) integer :: interp_recs real(r8), pointer, dimension(:) :: curr_data_times real(r8), pointer, dimension(:) :: next_data_times logical :: remove_trc_file = .false. ! delete file when finished with it real(r8) :: offset_time integer :: cyc_ndx_beg integer :: cyc_ndx_end integer :: cyc_yr = 0 real(r8) :: one_yr = 0 real(r8) :: curr_mod_time ! model time - calendar day real(r8) :: next_mod_time ! model time - calendar day - next time step integer :: nlon integer :: nlat integer :: nlev integer :: nilev integer :: ps_coords(3) ! LATDIM | LONDIM | TIMDIM integer :: ps_order(3) ! LATDIM | LONDIM | TIMDIM real(r8), pointer, dimension(:) :: lons real(r8), pointer, dimension(:) :: lats real(r8), pointer, dimension(:) :: levs real(r8), pointer, dimension(:) :: ilevs real(r8), pointer, dimension(:) :: hyam real(r8), pointer, dimension(:) :: hybm real(r8), pointer, dimension(:,:) :: ps real(r8) :: p0 type(var_desc_t) :: ps_id logical :: has_ps = .false. logical :: in_pbuf = .false. logical :: zonal_ave = .false. logical :: surf_data = .false. logical :: alt_data = .false. logical :: cyclical = .false. logical :: fill_in_months = .false. logical :: fixed = .false. logical :: initialized = .false. logical :: top_bndry = .false. endtype trfile integer, public, parameter :: MAXTRCRS = 100 integer, parameter :: LONDIM = 1 integer, parameter :: LATDIM = 2 integer, parameter :: LEVDIM = 3 integer, parameter :: TIMDIM = 4 integer, parameter :: PS_TIMDIM = 3 integer, parameter :: ZA_LATDIM = 1 integer, parameter :: ZA_LEVDIM = 2 integer, parameter :: ZA_TIMDIM = 3 integer, parameter :: nm=1 ! array index for previous (minus) data integer, parameter :: np=2 ! array indes for next (plus) data character(len=SHR_KIND_CS) :: calendar contains !-------------------------------------------------------------------------- !-------------------------------------------------------------------------- subroutine trcdata_init( specifier, filename, filelist, datapath, flds, file, & 5,36 rmv_file, data_ymd, data_tod, data_type ) use mo_constants, only : d2r use cam_control_mod, only : nsrest use commap, only : clat, clon use dyn_grid, only : get_dyn_grid_parm use string_utils, only : to_upper implicit none character(len=*), intent(in) :: specifier(:) character(len=*), intent(in) :: filename character(len=*), intent(in) :: filelist character(len=*), intent(in) :: datapath type(trfld), dimension(:), pointer :: flds type(trfile), intent(inout) :: file logical, intent(in) :: rmv_file integer, intent(in) :: data_ymd integer, intent(in) :: data_tod character(len=*), intent(in) :: data_type integer :: f, mxnflds, astat integer :: str_yr, str_mon, str_day integer :: lon_dimid, lat_dimid, lev_dimid, tim_dimid integer :: dimids(4), did type(var_desc_t) :: varid integer :: idx integer :: plon, plat, ierr real(r8) :: start_time, time1, time2 calendar = get_calendar() call specify_fields( specifier, flds ) file%datatimep=-1.e36_r8 file%datatimem=-1.e36_r8 mxnflds = 0 if (associated(flds)) mxnflds = size( flds ) if (mxnflds < 1) return file%remove_trc_file = rmv_file file%pathname = trim(datapath) file%filenames_list = trim(filelist) file%fill_in_months = .false. file%cyclical = .false. ! does not work when compiled with pathf90 ! select case ( to_upper(data_type) ) select case ( data_type ) case( 'FIXED' ) file%fixed = .true. case( 'INTERP_MISSING_MONTHS' ) file%fill_in_months = .true. case( 'CYCLICAL' ) file%cyclical = .true. file%cyc_yr = data_ymd/10000 case( 'SERIAL' ) case default write(iulog,*) 'trcdata_init: invalid data type: '//trim(data_type)//' file: '//trim(filename) write(iulog,*) 'trcdata_init: valid data types: SERIAL | CYCLICAL | FIXED | INTERP_MISSING_MONTHS ' call endrun('trcdata_init: invalid data type: '//trim(data_type)//' file: '//trim(filename)) endselect if (masterproc) then write(iulog,*) 'trcdata_init: data type: '//trim(data_type)//' file: '//trim(filename) endif if ( len_trim(file%curr_filename)<1 .or. file%fixed ) then ! initial run file%curr_filename = trim(filename) call get_model_time(file) if ( data_ymd > 0 .and. .not. file%cyclical ) then str_yr = data_ymd/10000 str_mon = (data_ymd - str_yr*10000)/100 str_day = data_ymd - str_yr*10000 - str_mon*100 call set_time_float_from_date( start_time, str_yr, str_mon, str_day, data_tod ) file%offset_time = start_time - file%curr_mod_time else file%offset_time = 0 endif endif call set_time_float_from_date( time2, 2, 1, 1, 0 ) call set_time_float_from_date( time1, 1, 1, 1, 0 ) file%one_yr = time2-time1 if ( file%cyclical ) then file%cyc_ndx_beg = -1 file%cyc_ndx_end = -1 if ( file%cyc_yr /= 0 ) then call set_time_float_from_date( time1, file%cyc_yr , 1, 1, 0 ) call set_time_float_from_date( time2, file%cyc_yr+1, 1, 1, 0 ) file%one_yr = time2-time1 endif call open_trc_datafile( file%curr_filename, file%pathname, file%curr_fileid, file%curr_data_times, & cyc_ndx_beg=file%cyc_ndx_beg, cyc_ndx_end=file%cyc_ndx_end, cyc_yr=file%cyc_yr ) else call open_trc_datafile( file%curr_filename, file%pathname, file%curr_fileid, file%curr_data_times ) file%curr_data_times = file%curr_data_times - file%offset_time endif call pio_seterrorhandling(File%curr_fileid, PIO_BCAST_ERROR) ierr = pio_inq_dimid( file%curr_fileid, 'lon', idx ) call pio_seterrorhandling(File%curr_fileid, PIO_INTERNAL_ERROR) file%zonal_ave = (ierr/=PIO_NOERR) plon = get_dyn_grid_parm('plon') plat = get_dyn_grid_parm('plat') if ( .not. file%zonal_ave ) then call get_dimension( file%curr_fileid, 'lon', file%nlon, dimid=lon_dimid, data=file%lons ) file%lons = file%lons * d2r endif ierr = pio_inq_dimid( file%curr_fileid, 'time', tim_dimid ) call get_dimension( file%curr_fileid, 'lat', file%nlat, dimid=lat_dimid, data=file%lats ) file%lats = file%lats * d2r allocate( file%ps(file%nlon,file%nlat), stat=astat ) if( astat /= 0 ) then write(iulog,*) 'trcdata_init: file%ps allocation error = ',astat call endrun('trcdata_init: failed to allocate x array') end if call pio_seterrorhandling(File%curr_fileid, PIO_BCAST_ERROR) ierr = pio_inq_varid( file%curr_fileid, 'PS', file%ps_id ) file%has_ps = (ierr==PIO_NOERR) ierr = pio_inq_dimid( file%curr_fileid, 'altitude', idx ) file%alt_data = (ierr==PIO_NOERR) if(file%alt_data) then file%surf_data=.false. else ierr = pio_inq_dimid( file%curr_fileid, 'lev', idx ) file%surf_data = (ierr/=PIO_NOERR) end if call pio_seterrorhandling(File%curr_fileid, PIO_INTERNAL_ERROR) if ( file%has_ps) then ierr = pio_inq_vardimid (file%curr_fileid, file%ps_id, dimids(1:3)) do did = 1,3 if ( dimids(did) == lon_dimid ) then file%ps_coords(LONDIM) = did file%ps_order(did) = LONDIM else if ( dimids(did) == lat_dimid ) then file%ps_coords(LATDIM) = did file%ps_order(did) = LATDIM else if ( dimids(did) == tim_dimid ) then file%ps_coords(PS_TIMDIM) = did file%ps_order(did) = PS_TIMDIM endif enddo endif if (masterproc) then write(iulog,*) 'trcdata_init: file%has_ps = ' , file%has_ps endif ! masterproc if (file%alt_data) then call get_dimension( file%curr_fileid, 'altitude_int', file%nilev, data=file%ilevs ) call get_dimension( file%curr_fileid, 'altitude', file%nlev, dimid=lev_dimid, data=file%levs ) else if (.not.file%surf_data) then call get_dimension( file%curr_fileid, 'lev', file%nlev, dimid=lev_dimid, data=file%levs ) file%levs = file%levs*100._r8 ! mbar->pascals else file%nlev = 1 lev_dimid = -1 endif endif if (file%has_ps) then allocate( file%hyam(file%nlev), file%hybm(file%nlev), stat=astat ) if( astat /= 0 ) then write(iulog,*) 'trcdata_init: file%hyam,file%hybm allocation error = ',astat call endrun('trcdata_init: failed to allocate file%hyam and file%hybm arrays') end if call pio_seterrorhandling(File%curr_fileid, PIO_BCAST_ERROR) ierr = pio_inq_varid( file%curr_fileid, 'P0', varid) call pio_seterrorhandling(File%curr_fileid, PIO_INTERNAL_ERROR) if ( ierr == PIO_NOERR ) then ierr = pio_get_var( file%curr_fileid, varid, file%p0 ) else file%p0 = 100000._r8 endif ierr = pio_inq_varid( file%curr_fileid, 'hyam', varid ) ierr = pio_get_var( file%curr_fileid, varid, file%hyam ) ierr = pio_inq_varid( file%curr_fileid, 'hybm', varid ) ierr = pio_get_var( file%curr_fileid, varid, file%hybm ) allocate( file %ps (pcols,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'trcdata_init: failed to allocate file%ps array; error = ',astat call endrun end if allocate( file%ps_in(1)%data(pcols,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'trcdata_init: failed to allocate file%ps_in(1)%data array; error = ',astat call endrun end if allocate( file%ps_in(2)%data(pcols,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'trcdata_init: failed to allocate file%ps_in(2)%data array; error = ',astat call endrun end if if( file%fill_in_months ) then allocate( file%ps_in(3)%data(pcols,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(*,*) 'trcdata_init: failed to allocate file%ps_in(3)%data array; error = ',astat call endrun end if allocate( file%ps_in(4)%data(pcols,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(*,*) 'trcdata_init: failed to allocate file%ps_in(4)%data array; error = ',astat call endrun end if end if endif flds_loop: do f = 1,mxnflds ! allocate memory only if not already in pbuf if ( .not. file%in_pbuf ) then if ( file%surf_data .or. file%top_bndry ) then allocate( flds(f) %data(pcols,1,begchunk:endchunk), stat=astat ) else allocate( flds(f) %data(pcols,pver,begchunk:endchunk), stat=astat ) endif if( astat/= 0 ) then write(iulog,*) 'trcdata_init: failed to allocate flds(f)%data array; error = ',astat call endrun end if flds(f)%chnk_offset = 0 else idx = pbuf_get_fld_idx(flds(f)%fldnam, failcode=-1 ) flds(f)%data => pbuf(idx)%fld_ptr(1,:,:,:,1) flds(f)%chnk_offset = -begchunk+1 endif allocate( flds(f)%input(1)%data(pcols,file%nlev,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'trcdata_init: failed to allocate flds(f)%input(1)%data array; error = ',astat call endrun end if allocate( flds(f)%input(2)%data(pcols,file%nlev,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'trcdata_init: failed to allocate flds(f)%input(2)%data array; error = ',astat call endrun end if if( file%fill_in_months ) then allocate( flds(f)%input(3)%data(pcols,file%nlev,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(*,*) 'trcdata_init: failed to allocate flds(f)%input(3)%data array; error = ',astat call endrun end if allocate( flds(f)%input(4)%data(pcols,file%nlev,begchunk:endchunk), stat=astat ) if( astat/= 0 ) then write(*,*) 'trcdata_init: failed to allocate flds(f)%input(4)%data array; error = ',astat call endrun end if endif ierr = pio_inq_varid( file%curr_fileid, flds(f)%srcnam, flds(f)%var_id ) if ( file%zonal_ave ) then ierr = pio_inq_vardimid (file%curr_fileid, flds(f)%var_id, dimids(1:3)) do did = 1,3 if ( dimids(did) == lat_dimid ) then flds(f)%coords(ZA_LATDIM) = did flds(f)%order(did) = ZA_LATDIM else if ( dimids(did) == lev_dimid ) then flds(f)%coords(ZA_LEVDIM) = did flds(f)%order(did) = ZA_LEVDIM else if ( dimids(did) == tim_dimid ) then flds(f)%coords(ZA_TIMDIM) = did flds(f)%order(did) = ZA_TIMDIM endif enddo else if ( file%surf_data ) then ierr = pio_inq_vardimid (file%curr_fileid, flds(f)%var_id, dimids(1:3)) do did = 1,3 if ( dimids(did) == lon_dimid ) then flds(f)%coords(LONDIM) = did flds(f)%order(did) = LONDIM else if ( dimids(did) == lat_dimid ) then flds(f)%coords(LATDIM) = did flds(f)%order(did) = LATDIM else if ( dimids(did) == tim_dimid ) then flds(f)%coords(PS_TIMDIM) = did flds(f)%order(did) = PS_TIMDIM endif enddo else ierr = pio_inq_vardimid (file%curr_fileid, flds(f)%var_id, dimids) do did = 1,4 if ( dimids(did) == lon_dimid ) then flds(f)%coords(LONDIM) = did flds(f)%order(did) = LONDIM else if ( dimids(did) == lat_dimid ) then flds(f)%coords(LATDIM) = did flds(f)%order(did) = LATDIM else if ( dimids(did) == lev_dimid ) then flds(f)%coords(LEVDIM) = did flds(f)%order(did) = LEVDIM else if ( dimids(did) == tim_dimid ) then flds(f)%coords(TIMDIM) = did flds(f)%order(did) = TIMDIM endif enddo endif flds(f)%units = '' ierr = pio_get_att( file%curr_fileid, flds(f)%var_id, 'units', flds(f)%units) enddo flds_loop endsubroutine trcdata_init !----------------------------------------------------------------------- ! Reads more data if needed and interpolates data to current model time !----------------------------------------------------------------------- subroutine advance_trcdata( flds, file, state ) 5,4 use physics_types,only : physics_state implicit none type(trfile), intent(inout) :: file type(trfld), intent(inout) :: flds(:) type(physics_state), intent(in):: state(begchunk:endchunk) real(r8) :: data_time if ( .not.( file%fixed .and. file%initialized ) ) then call get_model_time(file) data_time = file%datatimep if ( file%cyclical ) then ! wrap around if ( (file%datatimep<file%datatimem) .and. (file%curr_mod_time>file%datatimem) ) then data_time = data_time + file%one_yr endif endif if ( file%curr_mod_time > data_time ) then call read_next_trcdata( flds, file ) end if endif ! need to inperpolate the data, regardless ! ! each mpi task needs to interpolate call interpolate_trcdata( flds, file, state ) file%initialized = .true. end subroutine advance_trcdata !------------------------------------------------------------------- !------------------------------------------------------------------- subroutine get_fld_data( flds, field_name, data, ncol, lchnk ) implicit none type(trfld), intent(inout) :: flds(:) character(len=*), intent(in) :: field_name real(r8), intent(out) :: data(:,:) integer, intent(in) :: lchnk integer, intent(in) :: ncol integer :: f, nflds data(:,:) = 0._r8 nflds = size(flds) do f = 1, nflds if ( trim(flds(f)%fldnam) == trim(field_name) ) then data(:ncol,:) = flds(f)%data(:ncol,:,lchnk+flds(f)%chnk_offset ) endif enddo end subroutine get_fld_data !------------------------------------------------------------------- !------------------------------------------------------------------- subroutine get_fld_ndx( flds, field_name, idx ) implicit none type(trfld), intent(in) :: flds(:) character(len=*), intent(in) :: field_name integer, intent(out) :: idx integer :: f, nflds idx = -1 nflds = size(flds) do f = 1, nflds if ( trim(flds(f)%fldnam) == trim(field_name) ) then idx = f return endif enddo end subroutine get_fld_ndx !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine get_model_time(file) 5,9 implicit none type(trfile), intent(inout) :: file integer yr, mon, day, ncsec ! components of a date call get_curr_date(yr, mon, day, ncsec) if ( file%cyclical ) yr = file%cyc_yr call set_time_float_from_date( file%curr_mod_time, yr, mon, day, ncsec ) file%next_mod_time = file%curr_mod_time + get_step_size()/86400._r8 end subroutine get_model_time !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine check_files( file ) 2,15 use shr_sys_mod, only: shr_sys_system use ioFileMod, only: getfil implicit none type(trfile), intent(inout) :: file !----------------------------------------------------------------------- ! ... local variables !----------------------------------------------------------------------- character(len=shr_kind_cl) :: ctmp character(len=shr_kind_cl) :: loc_fname integer :: istat, astat if (file%next_mod_time > file%curr_data_times(size(file%curr_data_times))) then if ( .not. associated(file%next_data_times) ) then ! open next file if not already opened... file%next_filename = incr_filename( file%curr_filename, filenames_list=file%filenames_list, datapath=file%pathname ) call open_trc_datafile( file%next_filename, file%pathname, file%next_fileid, file%next_data_times ) file%next_data_times = file%next_data_times - file%offset_time endif endif if ( associated(file%next_data_times) ) then if (file%curr_mod_time >= file%next_data_times(1)) then ! close current file ... call pio_closefile( file%curr_fileid ) ! remove if requested if( file%remove_trc_file ) then call getfil( file%curr_filename, loc_fname, 0 ) write(iulog,*) 'check_files: removing file = ',trim(loc_fname) ctmp = 'rm -f ' // trim(loc_fname) write(iulog,*) 'check_files: fsystem issuing command - ' write(iulog,*) trim(ctmp) call shr_sys_system( ctmp, istat ) end if file%curr_filename = file%next_filename file%curr_fileid = file%next_fileid deallocate( file%curr_data_times, stat=astat ) if( astat/= 0 ) then write(iulog,*) 'check_files: failed to deallocate file%curr_data_times array; error = ',astat call endrun end if allocate( file%curr_data_times( size( file%next_data_times ) ), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'check_files: failed to allocate file%curr_data_times array; error = ',astat call endrun end if file%curr_data_times(:) = file%next_data_times(:) file%next_filename = '' deallocate( file%next_data_times, stat=astat ) if( astat/= 0 ) then write(iulog,*) 'check_files: failed to deallocate file%next_data_times array; error = ',astat call endrun end if nullify( file%next_data_times ) endif endif end subroutine check_files !----------------------------------------------------------------------- !----------------------------------------------------------------------- function incr_filename( filename, filenames_list, datapath ) 2,20 !----------------------------------------------------------------------- ! ... Increment or decrement a date string withing a filename ! the filename date section is assumed to be of the form ! yyyy-dd-mm !----------------------------------------------------------------------- use string_utils, only : incstr use shr_file_mod, only : shr_file_getunit, shr_file_freeunit implicit none character(len=*), intent(in) :: filename ! present dynamical dataset filename character(len=*), optional, intent(in) :: filenames_list character(len=*), optional, intent(in) :: datapath character(len=shr_kind_cl) :: incr_filename ! next filename in the sequence ! set new next_filename ... !----------------------------------------------------------------------- ! ... local variables !----------------------------------------------------------------------- integer :: pos, pos1, istat character(len=shr_kind_cl) :: fn_new, line, filepath character(len=6) :: seconds character(len=5) :: num integer :: ios,unitnumber if (( .not. present(filenames_list)) .or.(len_trim(filenames_list) == 0)) then !----------------------------------------------------------------------- ! ... ccm type filename !----------------------------------------------------------------------- pos = len_trim( filename ) fn_new = filename(:pos) if ( masterproc ) write(iulog,*) 'incr_flnm: old filename = ',trim(fn_new) if( fn_new(pos-2:) == '.nc' ) then pos = pos - 3 end if istat = incstr( fn_new(:pos), 1 ) if( istat /= 0 ) then write(iulog,*) 'incr_flnm: incstr returned ', istat write(iulog,*) ' while trying to decrement ',trim( fn_new ) call endrun end if else ! open filenames_list if ( masterproc ) write(iulog,*) 'incr_flnm: old filename = ',trim(filename) if ( masterproc ) write(iulog,*) 'incr_flnm: open filenames_list : ',trim(filenames_list) unitnumber = shr_file_getUnit() if ( present(datapath) ) then filepath = trim(datapath) //'/'// trim(filenames_list) else filepath = trim(datapath) endif open( unit=unitnumber, file=filepath, iostat=ios, status="OLD") if (ios /= 0) then call endrun('not able to open filenames_list file: '//trim(filepath)) endif ! read file names read( unit=unitnumber, fmt='(A)', iostat=ios ) line if (ios /= 0) then call endrun('not able to increment file name from filenames_list file: '//trim(filenames_list)) endif do while( trim(line) /= trim(filename) ) read( unit=unitnumber, fmt='(A)', iostat=ios ) line if (ios /= 0) then call endrun('not able to increment file name from filenames_list file: '//trim(filenames_list)) endif enddo read( unit=unitnumber, fmt='(A)', iostat=ios ) line if (ios /= 0) then call endrun('not able to increment file name from filenames_list file: '//trim(filenames_list)) endif fn_new = trim(line) close(unit=unitnumber) call shr_file_freeUnit(unitnumber) endif incr_filename = trim(fn_new) if ( masterproc ) write(iulog,*) 'incr_flnm: new filename = ',trim(incr_filename) end function incr_filename !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine find_times( itms, fids, time, file, datatimem, datatimep, times_found ) 5,5 implicit none type(trfile), intent(in) :: file real(r8), intent(out) :: datatimem, datatimep integer, intent(out) :: itms(2) ! record numbers that bracket time type(file_desc_t), intent(out) :: fids(2) ! ids of files that contains these recs real(r8), intent(in) :: time ! time of interest logical, intent(inout) :: times_found integer :: np1 ! current forward time index of dataset integer :: n,i ! integer :: curr_tsize, next_tsize, all_tsize integer :: astat integer :: cyc_tsize real(r8), allocatable, dimension(:):: all_data_times curr_tsize = size(file%curr_data_times) next_tsize = 0 if ( associated(file%next_data_times)) next_tsize = size(file%next_data_times) all_tsize = curr_tsize + next_tsize allocate( all_data_times( all_tsize ), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'find_times: failed to allocate all_data_times array; error = ',astat call endrun end if all_data_times(:curr_tsize) = file%curr_data_times(:) if (next_tsize > 0) all_data_times(curr_tsize+1:all_tsize) = file%next_data_times(:) if ( .not. file%cyclical ) then if ( all( all_data_times(:) > time ) ) then write(iulog,*) 'FIND_TIMES: ALL data times are after ', time write(iulog,*) 'FIND_TIMES: data times: ',all_data_times(:) write(iulog,*) 'FIND_TIMES: time: ',time call endrun('find_times: all(all_data_times(:) > time) '// trim(file%curr_filename) ) endif ! find bracketing times find_times_loop : do n=1, all_tsize-1 np1 = n + 1 datatimem = all_data_times(n) !+ file%offset_time datatimep = all_data_times(np1) !+ file%offset_time if ( (time .ge. datatimem) .and. (time .le. datatimep) ) then times_found = .true. exit find_times_loop endif enddo find_times_loop else cyc_tsize = file%cyc_ndx_end - file%cyc_ndx_beg + 1 if ( cyc_tsize > 1 ) then call findplb(all_data_times(file%cyc_ndx_beg:file%cyc_ndx_end),cyc_tsize, time, n ) if (n == cyc_tsize) then np1 = 1 else np1 = n+1 endif datatimem = all_data_times(n +file%cyc_ndx_beg-1) datatimep = all_data_times(np1+file%cyc_ndx_beg-1) times_found = .true. endif endif if ( .not. times_found ) then if (masterproc) then write(iulog,*)'FIND_TIMES: Failed to find dates bracketing desired time =', time write(iulog,*)' datatimem = ',file%datatimem write(iulog,*)' datatimep = ',file%datatimep write(iulog,*)' all_data_times = ',all_data_times !call endrun() return endif endif deallocate( all_data_times, stat=astat ) if( astat/= 0 ) then write(iulog,*) 'find_times: failed to deallocate all_data_times array; error = ',astat call endrun end if if ( .not. file%cyclical ) then itms(1) = n itms(2) = np1 else itms(1) = n +file%cyc_ndx_beg-1 itms(2) = np1 +file%cyc_ndx_beg-1 endif fids(:) = file%curr_fileid do i=1,2 if ( itms(i) > curr_tsize ) then itms(i) = itms(i) - curr_tsize fids(i) = file%next_fileid endif enddo end subroutine find_times !------------------------------------------------------------------------ !------------------------------------------------------------------------ subroutine read_next_trcdata( flds, file ) 1,23 implicit none type (trfile), intent(inout) :: file type (trfld),intent(inout) :: flds(:) integer :: recnos(4),i,f,nflds ! integer :: cnt4(4) ! array of counts for each dimension integer :: strt4(4) ! array of starting indices integer :: cnt3(3) ! array of counts for each dimension integer :: strt3(3) ! array of starting indices type(file_desc_t) :: fids(4) logical :: times_found integer :: cur_yr, cur_mon, cur_day, cur_sec, yr1, yr2, mon, date, sec real(r8) :: series1_time, series2_time type(file_desc_t) :: fid1, fid2 nflds = size(flds) times_found = .false. do while( .not. times_found ) call find_times( recnos, fids, file%curr_mod_time, file,file%datatimem, file%datatimep, times_found ) if ( .not. times_found ) then call check_files( file ) endif enddo file%interp_recs = 2 if ( file%fill_in_months ) then if( file%datatimep-file%datatimem > file%one_yr ) then call get_curr_date(cur_yr, cur_mon, cur_day, cur_sec) call set_date_from_time_float(file%datatimem, yr1, mon, date, sec ) call set_date_from_time_float(file%datatimep, yr2, mon, date, sec ) call set_time_float_from_date( series1_time, yr1, cur_mon, cur_day, cur_sec ) call set_time_float_from_date( series2_time, yr2, cur_mon, cur_day, cur_sec ) fid1 = fids(1) fid2 = fids(2) file%cyclical = .true. call set_cycle_indices( fid1, file%cyc_ndx_beg, file%cyc_ndx_end, yr1) call find_times( recnos(1:2), fids(1:2), series1_time, file, file%datatimes(1), file%datatimes(2), times_found ) if ( .not. times_found ) then call endrun('read_next_trcdata: time not found for series1_time') endif call set_cycle_indices( fid2, file%cyc_ndx_beg, file%cyc_ndx_end, yr2) if ( fid1%fh /= fid2%fh ) then file%cyc_ndx_beg = file%cyc_ndx_beg + size(file%curr_data_times) file%cyc_ndx_end = file%cyc_ndx_end + size(file%curr_data_times) endif call find_times( recnos(3:4), fids(3:4), series2_time, file, file%datatimes(3), file%datatimes(4), times_found ) if ( .not. times_found ) then call endrun('read_next_trcdata: time not found for series2_time') endif file%cyclical = .false. file%interp_recs = 4 call set_date_from_time_float( file%datatimes(1), yr1, mon, date, sec ) call set_time_float_from_date( file%datatimem, cur_yr, mon, date, sec ) if (file%datatimes(1) > file%datatimes(2) ) then ! wrap around if ( cur_mon == 1 ) then call set_time_float_from_date( file%datatimem, cur_yr-1, mon, date, sec ) endif endif call set_date_from_time_float( file%datatimes(2), yr1, mon, date, sec ) call set_time_float_from_date( file%datatimep, cur_yr, mon, date, sec ) if (file%datatimes(1) > file%datatimes(2) ) then ! wrap around if ( cur_mon == 12 ) then call set_time_float_from_date( file%datatimep, cur_yr+1, mon, date, sec ) endif endif endif endif ! ! Set up hyperslab corners ! strt4(:) = 1 strt3(:) = 1 do i=1,file%interp_recs do f = 1,nflds if ( file%zonal_ave ) then cnt3(flds(f)%coords(ZA_LATDIM)) = file%nlat cnt3(flds(f)%coords(ZA_LEVDIM)) = file%nlev cnt3(flds(f)%coords(ZA_TIMDIM)) = 1 strt3(flds(f)%coords(ZA_TIMDIM)) = recnos(i) call read_za_trc( fids(i), flds(f)%var_id, flds(f)%input(i)%data, strt3, cnt3, file, & (/ flds(f)%order(ZA_LATDIM),flds(f)%order(ZA_LEVDIM) /) ) else if ( file%surf_data ) then cnt3( flds(f)%coords(LONDIM)) = file%nlon cnt3( flds(f)%coords(LATDIM)) = file%nlat cnt3( flds(f)%coords(PS_TIMDIM)) = 1 strt3(flds(f)%coords(PS_TIMDIM)) = recnos(i) call read_2d_trc( fids(i), flds(f)%var_id, flds(f)%input(i)%data(:,1,:), strt3, cnt3, file, & (/ flds(f)%order(LONDIM),flds(f)%order(LATDIM) /) ) else cnt4(flds(f)%coords(LONDIM)) = file%nlon cnt4(flds(f)%coords(LATDIM)) = file%nlat cnt4(flds(f)%coords(LEVDIM)) = file%nlev cnt4(flds(f)%coords(TIMDIM)) = 1 strt4(flds(f)%coords(TIMDIM)) = recnos(i) call read_3d_trc( fids(i), flds(f)%var_id, flds(f)%input(i)%data, strt4, cnt4, file, & (/ flds(f)%order(LONDIM),flds(f)%order(LATDIM),flds(f)%order(LEVDIM) /)) endif enddo if ( file%has_ps ) then cnt3(file%ps_coords(LONDIM)) = file%nlon cnt3(file%ps_coords(LATDIM)) = file%nlat cnt3(file%ps_coords(PS_TIMDIM)) = 1 strt3(file%ps_coords(PS_TIMDIM)) = recnos(i) call read_2d_trc( fids(i), file%ps_id, file%ps_in(i)%data, strt3, cnt3, file, & (/ file%ps_order(LONDIM),file%ps_order(LATDIM) /) ) endif enddo end subroutine read_next_trcdata !------------------------------------------------------------------------ subroutine read_2d_trc( fid, vid, loc_arr, strt, cnt, file, order ) 2,17 use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish use phys_grid, only : pcols, begchunk, endchunk, get_ncols_p, get_rlat_all_p, get_rlon_all_p use mo_constants, only : pi use dycore, only: dycore_is use polar_avg, only: polar_average implicit none type(file_desc_t), intent(in) :: fid type(var_desc_t), intent(in) :: vid integer, intent(in) :: strt(:), cnt(:), order(2) real(r8),intent(out) :: loc_arr(:,:) type (trfile), intent(in) :: file real(r8) :: to_lats(pcols), to_lons(pcols), wrk(pcols) real(r8), allocatable, target :: wrk2d(:,:) real(r8), pointer :: wrk2d_in(:,:) integer :: tsize, c, i, j, ierr, ncols real(r8), parameter :: zero=0_r8, twopi=2_r8*pi type(interp_type) :: lon_wgts, lat_wgts nullify(wrk2d_in) allocate( wrk2d(cnt(1),cnt(2)), stat=ierr ) if( ierr /= 0 ) then write(iulog,*) 'read_2d_trc: wrk2d allocation error = ',ierr call endrun end if if(order(1)/=1 .or. order(2)/=2 .or. cnt(1)/=file%nlon .or. cnt(2)/=file%nlat) then allocate( wrk2d_in(file%nlon, file%nlat), stat=ierr ) if( ierr /= 0 ) then write(iulog,*) 'read_2d_trc: wrk2d_in allocation error = ',ierr call endrun end if end if ierr = pio_get_var( fid, vid, strt, cnt, wrk2d ) if(associated(wrk2d_in)) then wrk2d_in = reshape( wrk2d(:,:),(/file%nlon,file%nlat/), order=order ) deallocate(wrk2d) else wrk2d_in => wrk2d end if j=1 do c=begchunk,endchunk ncols = get_ncols_p(c) call get_rlat_all_p(c, pcols, to_lats) call get_rlon_all_p(c, pcols, to_lons) call lininterp_init(file%lons, file%nlon, to_lons, ncols, 2, lon_wgts, zero, twopi) call lininterp_init(file%lats, file%nlat, to_lats, ncols, 1, lat_wgts) call lininterp(wrk2d_in, file%nlon, file%nlat, loc_arr(1:ncols,c-begchunk+1), ncols, lon_wgts, lat_wgts) call lininterp_finish(lon_wgts) call lininterp_finish(lat_wgts) end do if(allocated(wrk2d)) then deallocate(wrk2d) else deallocate(wrk2d_in) end if if(dycore_is('LR')) call polar_average(loc_arr) end subroutine read_2d_trc !------------------------------------------------------------------------ subroutine read_za_trc( fid, vid, loc_arr, strt, cnt, file, order ) 1,12 use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish use phys_grid, only : pcols, begchunk, endchunk, get_ncols_p, get_rlat_all_p, get_rlon_all_p use mo_constants, only : pi use dycore, only : dycore_is use polar_avg, only : polar_average implicit none type(file_desc_t), intent(in) :: fid type(var_desc_t), intent(in) :: vid integer, intent(in) :: strt(:), cnt(:), order(2) real(r8),intent(out) :: loc_arr(:,:,:) type (trfile), intent(in) :: file type(interp_type) :: lat_wgts real(r8) :: to_lats(pcols), to_lons(pcols), wrk(pcols) real(r8), allocatable, target :: wrk2d(:,:) real(r8), pointer :: wrk2d_in(:,:) integer :: tsize, c, i, j, k, ierr, ncols nullify(wrk2d_in) allocate( wrk2d(cnt(1),cnt(2)), stat=ierr ) if( ierr /= 0 ) then write(iulog,*) 'read_2d_trc: wrk2d allocation error = ',ierr call endrun end if if(order(1)/=1 .or. order(2)/=2 .or. cnt(1)/=file%nlat .or. cnt(2)/=file%nlev) then allocate( wrk2d_in(file%nlat, file%nlev), stat=ierr ) if( ierr /= 0 ) then write(iulog,*) 'read_2d_trc: wrk2d_in allocation error = ',ierr call endrun end if end if ierr = pio_get_var( fid, vid, strt, cnt, wrk2d ) if(associated(wrk2d_in)) then wrk2d_in = reshape( wrk2d(:,:),(/file%nlon,file%nlat/), order=order ) deallocate(wrk2d) else wrk2d_in => wrk2d end if j=1 do c=begchunk,endchunk ncols = get_ncols_p(c) call get_rlat_all_p(c, pcols, to_lats) call lininterp_init(file%lats, file%nlat, to_lats, ncols, 1, lat_wgts) do k=1,file%nlev call lininterp(wrk2d_in(:,k), file%nlat, wrk(1:ncols), ncols, lat_wgts) loc_arr(1:ncols,k,c-begchunk+1) = wrk(1:ncols) end do call lininterp_finish(lat_wgts) end do end subroutine read_za_trc !------------------------------------------------------------------------ subroutine read_3d_trc( fid, vid, loc_arr, strt, cnt, file, order) 1,19 use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish use phys_grid, only : pcols, begchunk, endchunk, get_ncols_p, get_rlat_all_p, get_rlon_all_p use mo_constants, only : pi use dycore, only : dycore_is use polar_avg, only : polar_average use dycore, only : dycore_is implicit none type(file_desc_t), intent(in) :: fid type(var_desc_t), intent(in) :: vid integer, intent(in) :: strt(:), cnt(:), order(3) real(r8),intent(out) :: loc_arr(:,:,:) type (trfile), intent(in) :: file integer :: i,j,k, astat, c, ncols integer :: jlim(2), jl, ju, ierr integer :: gndx real(r8), allocatable, target :: wrk3d(:,:,:) real(r8), pointer :: wrk3d_in(:,:,:) real(r8) :: to_lons(pcols), to_lats(pcols) real(r8), parameter :: zero=0_r8, twopi=2_r8*pi type(interp_type) :: lon_wgts, lat_wgts loc_arr(:,:,:) = 0._r8 nullify(wrk3d_in) allocate(wrk3d(cnt(1),cnt(2),cnt(3)), stat=ierr) if( ierr /= 0 ) then write(iulog,*) 'read_3d_trc: wrk3d allocation error = ',ierr call endrun end if ierr = pio_get_var( fid, vid, strt, cnt, wrk3d ) if(order(1)/=1 .or. order(2)/=2 .or. order(3)/=3 .or. & cnt(1)/=file%nlon.or.cnt(2)/=file%nlat.or.cnt(3)/=file%nlev) then allocate(wrk3d_in(file%nlon,file%nlat,file%nlev),stat=ierr) if( ierr /= 0 ) then write(iulog,*) 'read_3d_trc: wrk3d allocation error = ',ierr call endrun end if wrk3d_in = reshape( wrk3d(:,:,:),(/file%nlon,file%nlat,file%nlev/), order=order ) deallocate(wrk3d) else wrk3d_in => wrk3d end if j=1 do c=begchunk,endchunk ncols = get_ncols_p(c) call get_rlat_all_p(c, pcols, to_lats) call get_rlon_all_p(c, pcols, to_lons) call lininterp_init(file%lons, file%nlon, to_lons(1:ncols), ncols, 2, lon_wgts, zero, twopi) call lininterp_init(file%lats, file%nlat, to_lats(1:ncols), ncols, 1, lat_wgts) call lininterp(wrk3d_in, file%nlon, file%nlat, file%nlev, loc_arr(:,:,c-begchunk+1), ncols, pcols, lon_wgts, lat_wgts) call lininterp_finish(lon_wgts) call lininterp_finish(lat_wgts) end do if(allocated(wrk3d)) then deallocate( wrk3d, stat=astat ) else deallocate( wrk3d_in, stat=astat ) end if if( astat/= 0 ) then write(iulog,*) 'read_3d_trc: failed to deallocate wrk3d array; error = ',astat call endrun endif if(dycore_is('LR')) call polar_average(file%nlev, loc_arr) end subroutine read_3d_trc !------------------------------------------------------------------------------ subroutine interpolate_trcdata( flds, file, state ) 1,6 use mo_util, only : rebin use physics_types,only : physics_state use physconst, only : cday implicit none type (trfld),intent(inout) :: flds(:) type (trfile), intent(inout) :: file type(physics_state), intent(in):: state(begchunk:endchunk) real(r8) :: fact1, fact2 real(r8) :: deltat integer :: f,nflds,c,ncol, i,k real(r8) :: ps(pcols) real(r8) :: datain(pcols,file%nlev) real(r8) :: pin(pcols,file%nlev) real(r8) :: model_z(pverp) real(r8), parameter :: m2km = 1.e-3_r8 nflds = size(flds) if ( file%interp_recs == 4 ) then deltat = file%datatimes(3) - file%datatimes(1) fact1 = (file%datatimes(3) - file%datatimem)/deltat fact2 = 1._r8-fact1 !$OMP PARALLEL DO PRIVATE (C, NCOL) do c = begchunk,endchunk ncol = state(c)%ncol if ( file%has_ps ) then file%ps_in(1)%data(:ncol,c) = fact1*file%ps_in(1)%data(:ncol,c) + fact2*file%ps_in(3)%data(:ncol,c) endif do f = 1,nflds flds(f)%input(1)%data(:ncol,:,c) = fact1*flds(f)%input(1)%data(:ncol,:,c) + fact2*flds(f)%input(3)%data(:ncol,:,c) enddo enddo deltat = file%datatimes(4) - file%datatimes(2) fact1 = (file%datatimes(4) - file%datatimep)/deltat fact2 = 1._r8-fact1 !$OMP PARALLEL DO PRIVATE (C, NCOL) do c = begchunk,endchunk ncol = state(c)%ncol if ( file%has_ps ) then file%ps_in(2)%data(:ncol,c) = fact1*file%ps_in(2)%data(:ncol,c) + fact2*file%ps_in(4)%data(:ncol,c) endif do f = 1,nflds flds(f)%input(2)%data(:ncol,:,c) = fact1*flds(f)%input(2)%data(:ncol,:,c) + fact2*flds(f)%input(4)%data(:ncol,:,c) enddo enddo endif file%interp_recs = 2 deltat = file%datatimep - file%datatimem if ( file%cyclical .and. (deltat < 0._r8) ) then deltat = deltat+file%one_yr if ( file%datatimep >= file%curr_mod_time ) then fact1 = (file%datatimep - file%curr_mod_time)/deltat else fact1 = (file%datatimep+file%one_yr - file%curr_mod_time)/deltat endif else fact1 = (file%datatimep - file%curr_mod_time)/deltat endif ! this assures that FIXED data are b4b on restarts if ( file%fixed ) then fact1 = dble(int(fact1*cday+.5_r8))/dble(cday) endif fact2 = 1._r8-fact1 !$OMP PARALLEL DO PRIVATE (C, NCOL, PS, I, K, PIN, F, DATAIN, MODEL_Z) do c = begchunk,endchunk ncol = state(c)%ncol if (file%surf_data) then do f = 1,nflds do i = 1,ncol flds(f)%data(i,1,c+flds(f)%chnk_offset) = & fact1*flds(f)%input(nm)%data(i,1,c) + fact2*flds(f)%input(np)%data(i,1,c) enddo enddo elseif (file%alt_data) then do f = 1,nflds datain(:ncol,:) = fact1*flds(f)%input(nm)%data(:ncol,:,c) + fact2*flds(f)%input(np)%data(:ncol,:,c) do i = 1,ncol model_z(1:pverp) = m2km * state(c)%zi(i,pverp:1:-1) call rebin( file%nlev, pver, file%ilevs, model_z, datain(i,:), flds(f)%data(i,:,c+flds(f)%chnk_offset) ) enddo enddo else if ( file%has_ps ) then ps(:ncol) = fact1*file%ps_in(nm)%data(:ncol,c) + fact2*file%ps_in(np)%data(:ncol,c) do i = 1,ncol do k = 1,file%nlev pin(i,k) = file%p0*file%hyam(k) + ps(i)*file%hybm(k) enddo enddo else do k = 1,file%nlev pin(:,k) = file%levs(k) enddo endif do f = 1,nflds datain(:ncol,:) = fact1*flds(f)%input(nm)%data(:ncol,:,c) + fact2*flds(f)%input(np)%data(:ncol,:,c) if ( file%top_bndry ) then call vert_interp_ub(ncol, file%nlev, file%levs, datain(:ncol,:), flds(f)%data(:ncol,:,c+flds(f)%chnk_offset) ) else call vert_interp(ncol, file%nlev, pin, state(c)%pmid, datain, flds(f)%data(:,:,c+flds(f)%chnk_offset) ) endif enddo endif enddo end subroutine interpolate_trcdata !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine get_dimension( fid, dname, dsize, dimid, data ) 11,2 implicit none type(file_desc_t), intent(in) :: fid character(*), intent(in) :: dname integer, intent(out) :: dsize integer, optional, intent(out) :: dimid real(r8), optional, pointer, dimension(:) :: data integer :: vid, ierr, id ierr = pio_inq_dimid( fid, dname, id ) ierr = pio_inq_dimlen( fid, id, dsize ) if ( present(dimid) ) then dimid = id endif if ( present(data) ) then if ( associated(data) ) then deallocate(data, stat=ierr) if( ierr /= 0 ) then write(iulog,*) 'get_dimension: data deallocation error = ',ierr call endrun('get_dimension: failed to deallocate data array') end if endif allocate( data(dsize), stat=ierr ) if( ierr /= 0 ) then write(iulog,*) 'get_dimension: data allocation error = ',ierr call endrun('get_dimension: failed to allocate data array') end if ierr = pio_inq_varid( fid, dname, vid ) ierr = pio_get_var( fid, vid, data ) endif end subroutine get_dimension !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine set_cycle_indices( fileid, cyc_ndx_beg, cyc_ndx_end, cyc_yr ) 2,4 implicit none type(file_desc_t), intent(in) :: fileid integer, intent(out) :: cyc_ndx_beg integer, intent(out) :: cyc_ndx_end integer, intent(in) :: cyc_yr integer, allocatable , dimension(:) :: dates, datesecs integer :: timesize, i, astat, year, ierr type(var_desc_T) :: dateid call get_dimension( fileid, 'time', timesize ) cyc_ndx_beg=-1 allocate( dates(timesize), stat=astat ) if( astat/= 0 ) then write(*,*) 'set_cycle_indices: failed to allocate dates array; error = ',astat call endrun end if ierr = pio_inq_varid( fileid, 'date', dateid ) ierr = pio_get_var( fileid, dateid, dates ) do i=1,timesize year = dates(i) / 10000 if ( year == cyc_yr ) then if (cyc_ndx_beg < 0) then cyc_ndx_beg = i endif cyc_ndx_end = i endif enddo deallocate( dates, stat=astat ) if( astat/= 0 ) then write(*,*) 'set_cycle_indices: failed to deallocate dates array; error = ',astat call endrun end if if (cyc_ndx_beg < 0) then write(*,*) 'set_cycle_indices: cycle year not found : ' , cyc_yr call endrun('set_cycle_indices: cycle year not found') endif end subroutine set_cycle_indices !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine open_trc_datafile( fname, path, piofile, times, cyc_ndx_beg, cyc_ndx_end, cyc_yr ) 3,13 use ioFileMod, only: getfil use cam_pio_utils, only: cam_pio_openfile implicit none character(*), intent(in) :: fname character(*), intent(in) :: path type(file_desc_t), intent(inout) :: piofile real(r8), pointer :: times(:) integer, optional, intent(out) :: cyc_ndx_beg integer, optional, intent(out) :: cyc_ndx_end integer, optional, intent(in) :: cyc_yr character(len=shr_kind_cl) :: filen, filepath integer :: year, month, day, dsize, i, timesize integer :: dateid,secid integer, allocatable , dimension(:) :: dates, datesecs integer :: astat, ierr filepath = trim(path) // '/' // trim(fname) ! ! open file and get fileid ! call getfil( filepath, filen, 0 ) call cam_pio_openfile( piofile, filen, PIO_NOWRITE) if(masterproc) write(iulog,*)'open_trc_datafile: ',trim(filen) call get_dimension(piofile, 'time', timesize) if ( associated(times) ) then deallocate(times, stat=ierr) if( ierr /= 0 ) then write(iulog,*) 'open_trc_datafile: data deallocation error = ',ierr call endrun('open_trc_datafile: failed to deallocate data array') end if endif allocate( times(timesize), stat=ierr ) if( ierr /= 0 ) then write(iulog,*) 'open_trc_datafile: data allocation error = ',ierr call endrun('open_trc_datafile: failed to allocate data array') end if allocate( dates(timesize), stat=astat ) if( astat/= 0 ) then if(masterproc) write(iulog,*) 'open_trc_datafile: failed to allocate dates array; error = ',astat call endrun end if allocate( datesecs(timesize), stat=astat ) if( astat/= 0 ) then if(masterproc) write(iulog,*) 'open_trc_datafile: failed to allocate datesec array; error = ',astat call endrun end if ierr = pio_inq_varid( piofile, 'date', dateid ) call pio_seterrorhandling( piofile, PIO_BCAST_ERROR) ierr = pio_inq_varid( piofile, 'datesec', secid ) call pio_seterrorhandling( piofile, PIO_INTERNAL_ERROR) if(ierr==PIO_NOERR) then ierr = pio_get_var( piofile, secid, datesecs ) else datesecs=0 end if ierr = pio_get_var( piofile, dateid, dates ) do i=1,timesize year = dates(i) / 10000 month = mod(dates(i),10000)/100 day = mod(dates(i),100) call set_time_float_from_date( times(i), year, month, day, datesecs(i) ) if ( present(cyc_yr) ) then if ( year == cyc_yr ) then if ( present(cyc_ndx_beg) .and. (cyc_ndx_beg < 0) ) then cyc_ndx_beg = i endif if ( present(cyc_ndx_end) ) then cyc_ndx_end = i endif endif endif enddo deallocate( dates, stat=astat ) if( astat/= 0 ) then if(masterproc) write(iulog,*) 'open_trc_datafile: failed to deallocate dates array; error = ',astat call endrun end if deallocate( datesecs, stat=astat ) if( astat/= 0 ) then if(masterproc) write(iulog,*) 'open_trc_datafile: failed to deallocate datesec array; error = ',astat call endrun end if if ( present(cyc_yr) .and. present(cyc_ndx_beg) ) then if (cyc_ndx_beg < 0) then write(iulog,*) 'open_trc_datafile: cycle year not found : ' , cyc_yr call endrun('open_trc_datafile: cycle year not found') endif endif end subroutine open_trc_datafile !-------------------------------------------------------------------------- !-------------------------------------------------------------------------- subroutine specify_fields( specifier, fields ) 1,2 implicit none character(len=*), intent(in) :: specifier(:) type(trfld), pointer, dimension(:) :: fields integer :: fld_cnt, astat integer :: i,j character(len=shr_kind_cl) :: str1, str2 character(len=32), allocatable, dimension(:) :: fld_name, src_name integer :: nflds nflds = size(specifier) allocate(fld_name(nflds), src_name(nflds), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'specify_fields: failed to allocate fld_name, src_name arrays; error = ',astat call endrun end if fld_cnt = 0 count_cnst: do i = 1, nflds if ( len_trim( specifier(i) ) == 0 ) then exit count_cnst endif j = scan( specifier(i),':') if (j > 0) then str1 = trim(adjustl( specifier(i)(:j-1) )) str2 = trim(adjustl( specifier(i)(j+1:) )) fld_name(i) = trim(adjustl( str1 )) src_name(i) = trim(adjustl( str2 )) else fld_name(i) = trim(adjustl( specifier(i) )) src_name(i) = trim(adjustl( specifier(i) )) endif fld_cnt = fld_cnt + 1 enddo count_cnst if( fld_cnt < 1 ) then return end if !----------------------------------------------------------------------- ! ... allocate field type array !----------------------------------------------------------------------- allocate( fields(fld_cnt), stat=astat ) if( astat/= 0 ) then write(iulog,*) 'specify_fields: failed to allocate fields array; error = ',astat call endrun end if do i = 1,fld_cnt fields(i)%fldnam = fld_name(i) fields(i)%srcnam = src_name(i) enddo deallocate(fld_name, src_name) end subroutine specify_fields !------------------------------------------------------------------------------ subroutine init_trc_restart( whence, piofile, tr_file ) 4 implicit none character(len=*), intent(in) :: whence type(file_desc_t), intent(inout) :: piofile type(trfile), intent(inout) :: tr_file character(len=32) :: name integer :: ioerr, mcdimid, maxlen ! Dimension should already be defined in restart file call pio_seterrorhandling(pioFile, PIO_BCAST_ERROR) ioerr = pio_inq_dimid(pioFile,'max_chars', mcdimid) call pio_seterrorhandling(pioFile, PIO_INTERNAL_ERROR) ! but define it if nessasary if(ioerr/= PIO_NOERR) then ioerr = pio_def_dim(pioFile, 'max_chars', SHR_KIND_CL, mcdimid) end if if(len_trim(tr_file%curr_filename)>1) then allocate(tr_file%currfnameid) name = trim(whence)//'_curr_fname' ioerr = pio_def_var(pioFile, name,pio_char, (/mcdimid/), tr_file%currfnameid) ioerr = pio_put_att(pioFile, tr_file%currfnameid, 'offset_time', tr_file%offset_time) maxlen = len_trim(tr_file%curr_filename) ioerr = pio_put_att(pioFile, tr_file%currfnameid, 'actual_len', maxlen) else nullify(tr_file%currfnameid) end if if(len_trim(tr_file%next_filename)>1) then allocate(tr_file%nextfnameid) name = trim(whence)//'_next_fname' ioerr = pio_def_var(pioFile, name,pio_char, (/mcdimid/), tr_file%nextfnameid) maxlen = len_trim(tr_file%next_filename) ioerr = pio_put_att(pioFile, tr_file%nextfnameid, 'actual_len', maxlen) else nullify(tr_file%nextfnameid) end if end subroutine init_trc_restart !------------------------------------------------------------------------- ! writes file names to restart file !------------------------------------------------------------------------- subroutine write_trc_restart( piofile, tr_file ) 4 implicit none type(file_desc_t), intent(inout) :: piofile type(trfile), intent(inout) :: tr_file integer :: ioerr, slen ! error status if(associated(tr_file%currfnameid)) then ioerr = pio_put_var(pioFile, tr_file%currfnameid, tr_file%curr_filename) deallocate(tr_file%currfnameid) nullify(tr_file%currfnameid) end if if(associated(tr_file%nextfnameid)) then ioerr = pio_put_var(pioFile, tr_file%nextfnameid, tr_file%next_filename) deallocate(tr_file%nextfnameid) nullify(tr_file%nextfnameid) end if end subroutine write_trc_restart !------------------------------------------------------------------------- ! reads file names from restart file !------------------------------------------------------------------------- subroutine read_trc_restart( whence, piofile, tr_file ) 4 implicit none character(len=*), intent(in) :: whence type(file_desc_t), intent(inout) :: piofile type(trfile), intent(inout) :: tr_file type(var_desc_t) :: vdesc character(len=64) :: name integer :: ioerr ! error status integer :: slen call PIO_SetErrorHandling(piofile, PIO_BCAST_ERROR) name = trim(whence)//'_curr_fname' ioerr = pio_inq_varid(piofile, name, vdesc) if(ioerr==PIO_NOERR) then tr_file%curr_filename=' ' ioerr = pio_get_att(piofile, vdesc, 'offset_time', tr_file%offset_time) ioerr = pio_get_att(piofile, vdesc, 'actual_len', slen) ioerr = pio_get_var(piofile, vdesc, tr_file%curr_filename) if(slen<SHR_KIND_CL) tr_file%curr_filename(slen+1:)=' ' end if name = trim(whence)//'_next_fname' ioerr = pio_inq_varid(piofile, name, vdesc) if(ioerr==PIO_NOERR) then tr_file%next_filename=' ' ioerr = pio_get_att(piofile, vdesc, 'actual_len', slen) ioerr = pio_get_var(piofile, vdesc, tr_file%next_filename) if(slen<SHR_KIND_CL) tr_file%next_filename(slen+1:)=' ' end if call PIO_SetErrorHandling(piofile, PIO_INTERNAL_ERROR) end subroutine read_trc_restart !------------------------------------------------------------------------------ subroutine vert_interp( ncol, levsiz, pin, pmid, datain, dataout) 1 !----------------------------------------------------------------------- ! ! Interpolate data from current time-interpolated values to model levels !-------------------------------------------------------------------------- implicit none ! Arguments ! integer, intent(in) :: ncol ! number of atmospheric columns integer, intent(in) :: levsiz real(r8), intent(in) :: pin(pcols,levsiz) real(r8), intent(in) :: pmid(pcols,pver) ! level pressures real(r8), intent(in) :: datain(pcols,levsiz) real(r8), intent(out) :: dataout(pcols,pver) ! ! local storage ! integer :: i ! longitude index integer :: k, kk, kkstart ! level indices integer :: kupper(pcols) ! Level indices for interpolation real(r8) :: dpu ! upper level pressure difference real(r8) :: dpl ! lower level pressure difference !-------------------------------------------------------------------------- ! ! Initialize index array ! do i=1,ncol kupper(i) = 1 end do do k=1,pver ! ! Top level we need to start looking is the top level for the previous k ! for all column points ! kkstart = levsiz do i=1,ncol kkstart = min0(kkstart,kupper(i)) end do ! ! Store level indices for interpolation ! do kk=kkstart,levsiz-1 do i=1,ncol if (pin(i,kk).lt.pmid(i,k) .and. pmid(i,k).le.pin(i,kk+1)) then kupper(i) = kk end if end do end do ! interpolate or extrapolate... do i=1,ncol if (pmid(i,k) .lt. pin(i,1)) then dataout(i,k) = datain(i,1)*pmid(i,k)/pin(i,1) else if (pmid(i,k) .gt. pin(i,levsiz)) then dataout(i,k) = datain(i,levsiz) else dpu = pmid(i,k) - pin(i,kupper(i)) dpl = pin(i,kupper(i)+1) - pmid(i,k) dataout(i,k) = (datain(i,kupper(i) )*dpl + & datain(i,kupper(i)+1)*dpu)/(dpl + dpu) end if end do end do end subroutine vert_interp !------------------------------------------------------------------------------ subroutine vert_interp_ub( ncol, nlevs, plevs, datain, dataout ) 1,1 use hycoef, only : hyai, ps0 !----------------------------------------------------------------------- ! ! Interpolate data from current time-interpolated values to top interface pressure ! -- from mo_tgcm_ubc.F90 !-------------------------------------------------------------------------- implicit none ! Arguments ! integer, intent(in) :: ncol integer, intent(in) :: nlevs real(r8), intent(in) :: plevs(nlevs) real(r8), intent(in) :: datain(ncol,nlevs) real(r8), intent(out) :: dataout(ncol) ! ! local variables ! integer :: i,ku,kl,kk real(r8) :: pinterp, delp pinterp = ps0 * hyai(1) if( pinterp <= plevs(1) ) then kl = 1 ku = 1 delp = 0._r8 else if( pinterp >= plevs(nlevs) ) then kl = nlevs ku = nlevs delp = 0._r8 else do kk = 2,nlevs if( pinterp <= plevs(kk) ) then ku = kk kl = kk - 1 delp = log( pinterp/plevs(kk) ) / log( plevs(kk-1)/plevs(kk) ) exit end if end do end if do i = 1,ncol dataout(i) = datain(i,kl) + delp * (datain(i,ku) - datain(i,kl)) end do end subroutine vert_interp_ub !------------------------------------------------------------------------------ end module tracer_data