module metdata 10,20 !----------------------------------------------------------------------- ! ! BOP ! ! !MODULE: metdata ! ! !DESCRIPTION ! Handles reading and interpolating offline meteorological data which ! is used to drive the dynamics. ! ! !USES use shr_kind_mod, only: r8 => shr_kind_r8, r4 => shr_kind_r4 use time_manager, only: get_curr_date, get_step_size, get_calendar use spmd_utils, only: masterproc use ppgrid, only: pcols, pver, begchunk, endchunk use time_manager, only: get_curr_calday, get_curr_date, get_step_size use abortutils, only: endrun use dynamics_vars, only: T_FVDYCORE_GRID use phys_grid, only: scatter_field_to_chunk #if ( defined SPMD ) use mpishorthand, only: mpicom, mpir8, mpiint,mpichar use parutilitiesmodule, only: parcollective, BCSTOP, parscatter #endif use perf_mod use cam_logfile, only: iulog use pio, only: file_desc_t, pio_put_att, pio_global, pio_get_att, pio_inq_att, pio_inq_dimid, pio_inq_dimlen, & pio_closefile, pio_get_var, pio_inq_varid use cam_pio_utils, only: cam_pio_openfile implicit none private ! all unless made public save ! !PUBLIC MEMBERS public metdata_dyn_init ! subroutine to open files, allocate blocked arrays, etc public metdata_phys_init ! subroutine to allocate chunked arrays public advance_met ! subroutine to read more data and interpolate public get_met_fields ! interface to set meteorology fields public get_us_vs public offline_met_defaultopts public offline_met_setopts public met_winds_on_walls public write_met_restart public read_met_restart public met_rlx public fix_mass interface write_met_restart 1 Module procedure write_met_restart_bin Module procedure write_met_restart_pio end interface interface read_met_restart 1 Module procedure read_met_restart_bin Module procedure read_met_restart_pio end interface !------------------------------------------------------------------ ! Interface to access the meteorology fields. Possible invocations ! are as follows: ! call get_met_fields( physics_state, us, vs , tend, dt ) ! call get_met_fields( u, v ) ! call get_met_fields( srfflx_state ) !------------------------------------------------------------------ Interface get_met_fields ! overload accessors 4 Module Procedure get_dyn_flds Module Procedure get_uv_centered Module Procedure get_srf_flds Module Procedure get_ps End Interface real(r8), allocatable :: met_ps_next(:,:) ! PS interpolated to next timestep real(r8), allocatable :: met_ps_curr(:,:) ! PS interpolated to next timestep logical :: cell_wall_winds = .false. ! true => met data winds are cell centered logical :: remove_met_file = .false. ! delete metdata file when finished with it character(len=16) :: shflx_name = 'SHFLX' character(len=16) :: qflx_name = 'QFLX' real(r8) :: shflx_factor = 1._r8 real(r8) :: qflx_factor = 1._r8 ! !REVISION HISTORY: ! 31 Oct 2003 Francis Vitt Creation ! 05 Feb 2004 F Vitt Removed reading/inperpolating PS for current timestep ! -- only met_ps_next is needed ! 10 Nov 2004 F Vitt Implemented ability to read from series of files ! 16 Dec 2004 F Vitt Added offline_met_defaultopts and offline_met_setopts ! 14 Jul 2005 W Sawyer Removed pmgrid, spmd_dyn dependencies ! 12 Apr 2006 W Sawyer Removed unneeded ghosting of met_us, met_vs ! 08 Apr 2010 J Edwards Replaced serial netcdf calls with pio interface ! ! EOP !----------------------------------------------------------------------- ! $Id$ ! $Author$ !----------------------------------------------------------------------- type input2d real(r8), dimension(:,:), pointer :: data endtype input2d type input3d real(r8), dimension(:,:,:), pointer :: data endtype input3d real(r8), allocatable :: met_t(:,:,:) ! interpolated temperature real(r8), allocatable :: met_u(:,:,:) ! interpolated zonal wind real(r8), allocatable :: met_v(:,:,:) ! interpolated meridional wind real(r8), allocatable :: met_us(:,:,:) ! interpolated zonal wind -staggered real(r8), allocatable :: met_vs(:,:,:) ! interpolated meridional wind -staggered real(r8), allocatable :: met_q(:,:,:) ! interpolated water vapor real(r8), allocatable :: met_shflx(:,:)! interpolated surface pressure real(r8), allocatable :: met_qflx(:,:) ! interpolated water vapor flux real(r8), allocatable :: met_taux(:,:) ! interpolat real(r8), allocatable :: met_tauy(:,:) ! interpolated type(input3d) :: met_ti(2) type(input3d) :: met_ui(2) type(input3d) :: met_vi(2) type(input3d) :: met_usi(2) type(input3d) :: met_vsi(2) type(input3d) :: met_qi(2) type(input2d) :: met_psi_next(2) type(input2d) :: met_psi_curr(2) type(input2d) :: met_shflxi(2) type(input2d) :: met_qflxi(2) type(input2d) :: met_tauxi(2) type(input2d) :: met_tauyi(2) integer :: dateid ! var id of the date in the netCDF integer :: secid ! var id of the sec data 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) :: datatimemn = -1.e36_r8 ! time of prv. values read in for next timestep real(r8) :: datatimepn = -1.e36_r8 ! time of nxt. values read in for next timestep integer, parameter :: nm=1 ! array index for previous (minus) data integer, parameter :: np=2 ! array indes for next (plus) data real(r8) :: curr_mod_time ! model time - calendar day real(r8) :: next_mod_time ! model time - calendar day - next time step character(len=256) :: curr_filename, next_filename, metdata_file character(len=256) :: filenames_list = '' type(file_desc_t) :: curr_fileid, next_fileid ! the id of the NetCDF file real(r8), pointer, dimension(:) :: curr_data_times, next_data_times real(r8) :: alpha = 1.0_r8 ! don't read in water vapor ! real(r8), private :: alpha = 0.0 ! read in water vaper each time step real(r8), parameter :: D0_0 = 0.0_r8 real(r8), parameter :: D0_5 = 0.5_r8 real(r8), parameter :: D0_75 = 0.75_r8 real(r8), parameter :: D1_0 = 1.0_r8 real(r8), parameter :: days_per_month = 30.6_r8 real(r8), parameter :: days_per_non_leapyear = 365.0_r8 real(r8), parameter :: days_per_year = 365.25_r8 real(r8), parameter :: seconds_per_day = 86400.0_r8 real(r8), parameter :: fill_value = -9999.0_r8 logical :: online_test = .false. logical :: debug = .false. real(r8) :: met_rlx(pver) integer :: met_levels real(r8) :: rlx_top_km = 50._r8 real(r8) :: rlx_bot_km = 20._r8 real(r8) :: max_rlx = 1._r8 logical :: fix_mass = .true. contains !-------------------------------------------------------------------------- ! Get the default runtime options !-------------------------------------------------------------------------- subroutine offline_met_defaultopts( met_data_file_out, & 1 met_remove_file_out, & met_cell_wall_winds_out, & met_filenames_list_out, & met_rlx_top_km_out, & met_rlx_bot_km_out, & met_max_rlx_out, & met_fix_mass_out, & met_shflx_name_out, & met_shflx_factor_out, & met_qflx_name_out, & met_qflx_factor_out ) implicit none character(len=256), intent(out), optional :: met_data_file_out logical, intent(out), optional :: met_remove_file_out logical, intent(out), optional :: met_cell_wall_winds_out character(len=256), intent(out), optional :: met_filenames_list_out real(r8), intent(out), optional :: met_rlx_top_km_out real(r8), intent(out), optional :: met_rlx_bot_km_out real(r8), intent(out), optional :: met_max_rlx_out logical , intent(out), optional :: met_fix_mass_out character(len=16), intent(out), optional :: met_shflx_name_out real(r8), intent(out), optional :: met_shflx_factor_out character(len=16), intent(out), optional :: met_qflx_name_out real(r8), intent(out), optional :: met_qflx_factor_out if ( present( met_data_file_out ) ) then met_data_file_out = metdata_file endif if ( present( met_remove_file_out ) ) then met_remove_file_out = remove_met_file endif if ( present( met_cell_wall_winds_out ) ) then met_cell_wall_winds_out = cell_wall_winds endif if ( present( met_filenames_list_out ) ) then met_filenames_list_out = filenames_list endif if ( present( met_rlx_top_km_out ) ) then met_rlx_top_km_out = rlx_top_km endif if ( present( met_rlx_bot_km_out ) ) then met_rlx_bot_km_out = rlx_bot_km endif if ( present( met_max_rlx_out ) ) then met_max_rlx_out = max_rlx endif if ( present( met_fix_mass_out ) ) then met_fix_mass_out = fix_mass endif if ( present( met_shflx_name_out ) ) then met_shflx_name_out = shflx_name endif if ( present( met_shflx_factor_out ) ) then met_shflx_factor_out = shflx_factor endif if ( present( met_qflx_name_out ) ) then met_qflx_name_out = qflx_name endif if ( present( met_qflx_factor_out ) ) then met_qflx_factor_out = qflx_factor endif end subroutine offline_met_defaultopts !-------------------------------------------------------------------------- ! Set runtime options !-------------------------------------------------------------------------- subroutine offline_met_setopts( met_data_file_in, & 1 met_remove_file_in, & met_cell_wall_winds_in, & met_filenames_list_in, & met_rlx_top_km_in, & met_rlx_bot_km_in, & met_max_rlx_in, & met_fix_mass_in, & met_shflx_name_in, & met_shflx_factor_in, & met_qflx_name_in, & met_qflx_factor_in ) implicit none character(len=256), intent(in), optional :: met_data_file_in logical, intent(in), optional :: met_remove_file_in logical, intent(in), optional :: met_cell_wall_winds_in character(len=256), intent(in), optional :: met_filenames_list_in real(r8), intent(in), optional :: met_rlx_top_km_in real(r8), intent(in), optional :: met_rlx_bot_km_in real(r8), intent(in), optional :: met_max_rlx_in logical , intent(in), optional :: met_fix_mass_in character(len=16), intent(in), optional :: met_shflx_name_in real(r8), intent(in), optional :: met_shflx_factor_in character(len=16), intent(in), optional :: met_qflx_name_in real(r8), intent(in), optional :: met_qflx_factor_in if ( present( met_data_file_in ) ) then metdata_file = met_data_file_in endif if ( present( met_remove_file_in ) ) then remove_met_file = met_remove_file_in endif if ( present( met_cell_wall_winds_in ) ) then cell_wall_winds = met_cell_wall_winds_in endif if ( present( met_filenames_list_in ) ) then filenames_list = met_filenames_list_in endif if ( present( met_rlx_top_km_in ) ) then rlx_top_km = met_rlx_top_km_in endif if ( present( met_rlx_bot_km_in ) ) then rlx_bot_km = met_rlx_bot_km_in endif if ( present( met_max_rlx_in ) ) then max_rlx = met_max_rlx_in endif if ( present( met_fix_mass_in ) ) then fix_mass = met_fix_mass_in endif if ( present( met_shflx_name_in ) ) then shflx_name = met_shflx_name_in endif if ( present( met_shflx_factor_in ) ) then shflx_factor = met_shflx_factor_in endif if ( present( met_qflx_name_in ) ) then qflx_name = met_qflx_name_in endif if ( present( met_qflx_factor_in ) ) then qflx_factor = met_qflx_factor_in endif if (masterproc) then write(iulog,*)'Time-variant meteorological dataset (metdata_file) is: ', trim(metdata_file) write(iulog,*)'Meteorological data file will be removed (remove_met_file): ', remove_met_file write(iulog,*)'Meteorological winds are on cell walls (cell_wall_winds): ', cell_wall_winds write(iulog,*)'Meteorological file names list file: ', trim(filenames_list) write(iulog,*)'Meteorological relaxation top is (km): ', rlx_top_km write(iulog,*)'Meteorological relaxation bottom is (km): ', rlx_bot_km write(iulog,*)'Meteorological maximum relaxation is : ',max_rlx write(iulog,*)'Offline driver mass fixer is trurned on (fix_mass): ',fix_mass write(iulog,*)'Meteorological shflx field name : ', trim(shflx_name) write(iulog,*)'Meteorological shflx multiplication factor : ', shflx_factor write(iulog,*)'Meteorological qflx field name : ', trim(qflx_name) write(iulog,*)'Meteorological qflx multiplication factor : ', qflx_factor endif end subroutine offline_met_setopts !-------------------------------------------------------------------------- ! Opens file, allocates arrays !-------------------------------------------------------------------------- subroutine metdata_dyn_init(grid) 1,4 use infnan, only : nan use cam_control_mod, only : nsrest implicit none ! !INPUT PARAMETERS: type (T_FVDYCORE_GRID), intent(in) :: grid character(len=256) :: filen integer :: im, jm, km, jfirst, jlast, kfirst, klast integer :: ng_d, ng_s integer :: ierr im = grid%im km = grid%km jfirst = grid%jfirst jlast = grid%jlast kfirst = grid%kfirst klast = grid%klast ng_d = grid%ng_d ng_s = grid%ng_s if (nsrest/=1) then ! initial run or branch run curr_filename = metdata_file next_filename = '' else ! restart run ! curr_filename & next_filename already set by restart_dynamics endif call open_met_datafile( grid, curr_filename, curr_fileid, curr_data_times, check_dims=.true. ) if ( len_trim(next_filename) > 0 ) & call open_met_datafile( grid, next_filename, next_fileid, next_data_times ) ! ! allocate space for data arrays ... ! ! dynamics grid allocate( met_psi_next(nm)%data(im, jfirst:jlast) ) allocate( met_psi_next(np)%data(im, jfirst:jlast) ) allocate( met_psi_curr(nm)%data(im, jfirst:jlast) ) allocate( met_psi_curr(np)%data(im, jfirst:jlast) ) allocate( met_ps_next(im, jfirst:jlast) ) allocate( met_ps_curr(im, jfirst:jlast) ) allocate( met_us(im, jfirst-ng_d:jlast+ng_s, kfirst:klast) ) allocate( met_vs(im, jfirst-ng_s:jlast+ng_d, kfirst:klast) ) met_us = nan met_vs = nan if (cell_wall_winds) then allocate( met_usi(nm)%data(im, jfirst:jlast, kfirst:klast) ) allocate( met_usi(np)%data(im, jfirst:jlast, kfirst:klast) ) allocate( met_vsi(nm)%data(im, jfirst:jlast, kfirst:klast) ) allocate( met_vsi(np)%data(im, jfirst:jlast, kfirst:klast) ) endif if (.not. cell_wall_winds) then allocate( met_u(im, jfirst-ng_d:jlast+ng_d, kfirst:klast) ) allocate( met_ui(nm)%data(im, jfirst:jlast, kfirst:klast) ) allocate( met_ui(np)%data(im, jfirst:jlast, kfirst:klast) ) allocate( met_v(im, jfirst-ng_s:jlast+ng_d, kfirst:klast) ) allocate( met_vi(nm)%data(im, jfirst:jlast, kfirst:klast) ) allocate( met_vi(np)%data(im, jfirst:jlast, kfirst:klast) ) endif end subroutine metdata_dyn_init !================================================================================= subroutine metdata_phys_init 1,11 use cam_history, only : addfld,dyn_decomp,phys_decomp call addfld ('MET_RLX ',' ',pver, 'A','Meteorology relax function',dyn_decomp) call addfld ('MET_TAUX',' ',1, 'A','Meteorology taux',phys_decomp) call addfld ('MET_TAUY',' ',1, 'A','Meteorology tauy',phys_decomp) call addfld ('MET_SHFX',' ',1, 'A','Meteorology shflx',phys_decomp) call addfld ('MET_QFLX',' ',1, 'A','Meteorology qflx',phys_decomp) call addfld ('MET_PS',' ',1, 'A','Meteorology PS',dyn_decomp) call addfld ('MET_T',' ',pver, 'A','Meteorology T',phys_decomp) call addfld ('MET_U',' ',pver, 'A','Meteorology U',dyn_decomp) call addfld ('MET_V',' ',pver, 'A','Meteorology V',dyn_decomp) ! allocate chunked arrays allocate( met_ti(nm)%data(pcols,pver,begchunk:endchunk) ) allocate( met_ti(np)%data(pcols,pver,begchunk:endchunk) ) allocate( met_t(pcols,pver,begchunk:endchunk) ) allocate( met_qi(nm)%data(pcols,pver,begchunk:endchunk) ) allocate( met_qi(np)%data(pcols,pver,begchunk:endchunk) ) allocate( met_q(pcols,pver,begchunk:endchunk) ) allocate( met_shflxi(nm)%data(pcols,begchunk:endchunk) ) allocate( met_shflxi(np)%data(pcols,begchunk:endchunk) ) allocate( met_shflx(pcols,begchunk:endchunk) ) allocate( met_qflxi(nm)%data(pcols,begchunk:endchunk) ) allocate( met_qflxi(np)%data(pcols,begchunk:endchunk) ) allocate( met_qflx(pcols,begchunk:endchunk) ) allocate( met_tauxi(nm)%data(pcols,begchunk:endchunk) ) allocate( met_tauxi(np)%data(pcols,begchunk:endchunk) ) allocate( met_taux(pcols,begchunk:endchunk) ) allocate( met_tauyi(nm)%data(pcols,begchunk:endchunk) ) allocate( met_tauyi(np)%data(pcols,begchunk:endchunk) ) allocate( met_tauy(pcols,begchunk:endchunk) ) call set_met_rlx() end subroutine metdata_phys_init !----------------------------------------------------------------------- ! Reads more data if needed and interpolates data to current model time !----------------------------------------------------------------------- subroutine advance_met(grid) 1,7 use cam_history, only : outfld implicit none type (T_FVDYCORE_GRID), intent(in) :: grid real(r8) :: met_rlx_2d(grid%ifirstxy:grid%ilastxy,grid%km) integer :: i,j,k, idim call t_startf('MET__advance') ! ! call get_model_time() if ( ( curr_mod_time > datatimep ) .or. & ( next_mod_time > datatimepn ) ) then call check_files(grid) endif if ( curr_mod_time > datatimep ) then call read_next_metdata(grid) end if if ( next_mod_time > datatimepn ) then call read_next_ps(grid) end if ! need to inperpolate the data, regardless ! ! each mpi tasks needs to interpolate call interpolate_metdata(grid) call t_stopf('MET__advance') idim = grid%ilastxy - grid%ifirstxy + 1 do j = grid%jfirstxy, grid%jlastxy do k = 1, grid%km do i = grid%ifirstxy, grid%ilastxy met_rlx_2d(i,k) = met_rlx(k) enddo enddo call outfld('MET_RLX',met_rlx_2d, idim, j) enddo end subroutine advance_met !------------------------------------------------------------------- ! Method to get some the meteorology data. ! Sets the following srfflx_state member fields to the ! meteorology data : ! qflx ! shflx ! taux ! tauy !------------------------------------------------------------------- subroutine get_srf_flds( srfflx_state2d ) 1,8 use camsrfexch_types, only: srfflx_state use phys_grid, only: get_ncols_p use cam_history, only: outfld implicit none type(srfflx_state), intent(inout), dimension(begchunk:endchunk) :: srfflx_state2d integer :: c,ncol call t_startf('MET__GET_SRF_FLDS') do c=begchunk,endchunk ncol = get_ncols_p(c) srfflx_state2d(c)%wsx(:ncol) = met_taux(:ncol,c) srfflx_state2d(c)%wsy(:ncol) = met_tauy(:ncol,c) srfflx_state2d(c)%shf(:ncol) = met_shflx(:ncol,c)* shflx_factor srfflx_state2d(c)%cflx(:ncol,1) = met_qflx(:ncol,c) * qflx_factor end do ! Chunk loop if (debug) then write(iulog,*)'METDATA maxval(met_taux),minval(met_taux): ',maxval(met_taux),minval(met_taux) write(iulog,*)'METDATA maxval(met_tauy),minval(met_tauy): ',maxval(met_tauy),minval(met_tauy) write(iulog,*)'METDATA maxval(met_shflx),minval(met_shflx): ',maxval(met_shflx),minval(met_shflx) write(iulog,*)'METDATA maxval(met_qflx),minval(met_qflx): ',maxval(met_qflx),minval(met_qflx) endif if ( debug ) then do c = begchunk, endchunk call outfld('MET_TAUX',srfflx_state2d(c)%wsx , pcols ,c ) call outfld('MET_TAUY',srfflx_state2d(c)%wsy , pcols ,c ) call outfld('MET_SHFX',srfflx_state2d(c)%shf , pcols ,c ) call outfld('MET_QFLX',srfflx_state2d(c)%cflx(:,1) , pcols ,c ) enddo endif call t_stopf('MET__GET_SRF_FLDS') end subroutine get_srf_flds !------------------------------------------------------------------- ! allows access to physics state fields ! q : water vapor ! ps : surface pressure ! t : temperature !------------------------------------------------------------------- subroutine get_dyn_flds( state, tend, dt ) 1,7 use physics_types, only: physics_state, physics_tend, physics_dme_adjust use ppgrid, only: pcols, pver, begchunk, endchunk use phys_grid, only: get_ncols_p use cam_history, only: outfld implicit none type(physics_state), intent(inout), dimension(begchunk:endchunk) :: state type(physics_tend ), intent(inout), dimension(begchunk:endchunk) :: tend real(r8), intent(in ) :: dt ! model physics timestep integer :: lats(pcols) ! array of latitude indices integer :: lons(pcols) ! array of longitude indices integer :: c, ncol, i,j,k real(r8):: qini(pcols,pver) ! initial specific humidity real(r8) :: tmp(pcols,pver) call t_startf('MET__GET_DYN2') do c = begchunk, endchunk ncol = get_ncols_p(c) do k=1,pver do i=1,ncol state(c)%t(i,k) = (1._r8-met_rlx(k))*state(c)%t(i,k) + met_rlx(k)*met_t(i,k,c) qini(i,k) = state(c)%q(i,k,1) ! at this point tracer mixing ratios have already been ! converted from dry to moist !!$ if ( moist_q_mmr .and. (.not. online_test)) then state(c)%q(i,k,1) = alpha*state(c)%q(i,k,1) + & (1-alpha)*met_q(i,k,c) !!$ else !!$ ! dry-to-moist conversion !!$ state(c)%q(i,k,1) = alpha*state(c)%q(i,k,1) + & !!$ (1.-alpha)*met_q(i,c,k) & !!$ * state(c)%pdeldry(i,k)/state(c)%pdel(i,k) !!$ endif if ((state(c)%q(i,k,1) < D0_0).and. (alpha .ne. D1_0 )) state(c)%q(i,k,1) = D0_0 end do end do ! now adjust mass of each layer now that water vapor has changed if (( .not. online_test ) .and. (alpha .ne. D1_0 )) then call physics_dme_adjust(state(c), tend(c), qini, dt) endif end do if (debug) then write(iulog,*)'METDATA maxval(met_t),minval(met_t): ', maxval(met_t),minval(met_t) write(iulog,*)'METDATA maxval(met_ps_next),minval(met_ps_next): ', maxval(met_ps_next),minval(met_ps_next) endif do c = begchunk, endchunk call outfld('MET_T ',state(c)%t , pcols ,c ) enddo call t_stopf('MET__GET_DYN2') end subroutine get_dyn_flds !------------------------------------------------------------------------ ! get the meteorological winds on the grid cell centers (A-grid) !------------------------------------------------------------------------ subroutine get_uv_centered( grid, u, v ) 1,3 use cam_history, only: outfld implicit none type (T_FVDYCORE_GRID), intent(in) :: grid real(r8), intent(out) :: u(grid%im, grid%jfirst-grid%ng_d:grid%jlast+grid%ng_d, & grid%kfirst:grid%klast) ! u-wind on A-grid real(r8), intent(out) :: v(grid%im, grid%jfirst-grid%ng_s:grid%jlast+grid%ng_d, & grid%kfirst:grid%klast) ! v-wind on A-grid integer :: i,j,k integer :: jm, jfirst, jlast, jfirstxy, jlastxy, kfirst, klast, ng_d, ng_s, ifirstxy, ilastxy real(r8) :: u3s_tmp(grid%ifirstxy:grid%ilastxy,grid%km) real(r8) :: v3s_tmp(grid%ifirstxy:grid%ilastxy,grid%km) jm = grid%jm jfirstxy= grid%jfirstxy jlastxy = grid%jlastxy jfirst = grid%jfirst jlast = grid%jlast kfirst = grid%kfirst klast = grid%klast ifirstxy= grid%ifirstxy ilastxy = grid%ilastxy ng_d = grid%ng_d ng_s = grid%ng_s u(:,:,:) = D0_0 v(:,:,:) = D0_0 u( :, max(1,jfirst-ng_d):min(jm,jlast+ng_d), kfirst:klast ) = & met_u(:, max(1,jfirst-ng_d):min(jm,jlast+ng_d), kfirst:klast ) v( :, max(1,jfirst-ng_s):min(jm,jlast+ng_d), kfirst:klast ) = & met_v(:, max(1,jfirst-ng_s):min(jm,jlast+ng_d), kfirst:klast ) if (debug) write(iulog,*)'METDATA maxval(u),minval(u),maxval(v),minval(v) : ',& maxval(u(:, max(1,jfirst-ng_d):min(jm,jlast+ng_d), kfirst:klast )),& minval(u(:, max(1,jfirst-ng_d):min(jm,jlast+ng_d), kfirst:klast )),& maxval(v(:, max(1,jfirst-ng_s):min(jm,jlast+ng_d), kfirst:klast )),& minval(v(:, max(1,jfirst-ng_s):min(jm,jlast+ng_d), kfirst:klast )) if ( grid%twod_decomp .eq. 0 ) then do j = jfirst, jlast do k = kfirst, klast do i = 1, grid%im u3s_tmp(i,k) = u(i,j,k) v3s_tmp(i,k) = v(i,j,k) enddo enddo call outfld ('MET_U ', u3s_tmp, grid%im, j ) call outfld ('MET_V ', v3s_tmp, grid%im, j ) enddo endif end subroutine get_uv_centered !------------------------------------------------------------------------ ! get the meteorological surface pressure interp to dyn substep !------------------------------------------------------------------------ subroutine get_ps( grid, ps, nsubsteps, n ) 1,2 use cam_history, only: outfld implicit none type (T_FVDYCORE_GRID), intent(in) :: grid real(r8), intent(out) :: ps(grid%im, grid%jfirst:grid%jlast) integer, intent(in) :: nsubsteps integer, intent(in) :: n real(r8) :: num1, num2 integer :: j num1 = n num2 = nsubsteps ps(:,:) = met_ps_curr(:,:) + num1*(met_ps_next(:,:)-met_ps_curr(:,:))/num2 if ( grid%twod_decomp .eq. 0 ) then do j = grid%jfirst, grid%jlast call outfld('MET_PS',ps(:,j), grid%im ,j ) enddo endif end subroutine get_ps !------------------------------------------------------------------------ ! get the meteorological winds on the grid cell walls (vorticity winds) ! us : staggered zonal wind ! vs : staggered meridional wind !------------------------------------------------------------------------ subroutine get_us_vs( grid, us, vs ) 1 implicit none type (T_FVDYCORE_GRID), intent(in) :: grid real(r8), intent(inout) :: us(grid%im, grid%jfirst-grid%ng_d:grid%jlast+grid%ng_s, & grid%kfirst:grid%klast) ! u-wind on d-grid real(r8), intent(inout) :: vs(grid%im, grid%jfirst-grid%ng_s:grid%jlast+grid%ng_d, & grid%kfirst:grid%klast) ! v-wind on d-grid integer :: i,j,k integer :: jm, jfirst, jlast, kfirst, klast, ng_d, ng_s jm = grid%jm jfirst = grid%jfirst jlast = grid%jlast kfirst = grid%kfirst klast = grid%klast ng_d = grid%ng_d ng_s = grid%ng_s call t_startf('MET__get_us_vs') ! vertical relaxation (blending) occurs in dyn_run (dyn_comp.F90) us(:,:,:) = 1.e36_r8 vs(:,:,:) = 1.e36_r8 us( :, max(2,jfirst): min(jm,jlast), kfirst:klast) = & met_us( :, max(2,jfirst): min(jm,jlast), kfirst:klast) vs( :, max(1,jfirst): min(jm,jlast), kfirst:klast) = & met_vs( :, max(1,jfirst): min(jm,jlast), kfirst:klast) if (debug) write(iulog,*)grid%iam,': METDATA maxval(us),minval(us),maxval(vs),minval(vs) : ',& maxval(us( :, max(2,jfirst): min(jm,jlast), kfirst:klast)),& minval(us( :, max(2,jfirst): min(jm,jlast), kfirst:klast)),& maxval(vs( :, max(1,jfirst): min(jm,jlast), kfirst:klast)),& minval(vs( :, max(1,jfirst): min(jm,jlast), kfirst:klast)) !!$ if (debug) then !!$ u3s_tmp = 1.e36 !!$ do j = jfirst, jlast !!$ do k = kfirst, klast !!$ do i = 1, im !!$ if (j >= 2) u3s_tmp(i,k) = us(i,j,k) !!$ v3s_tmp(i,k) = vs(i,j,k) !!$ enddo !!$ enddo !!$ call outfld ('MET_US ', u3s_tmp, im, j ) !!$ call outfld ('MET_VS ', v3s_tmp, im, j ) !!$ enddo !!$ endif !!$ call t_stopf('MET__get_us_vs') end subroutine get_us_vs !------------------------------------------------------------------------- ! writes file names to restart file !------------------------------------------------------------------------- subroutine write_met_restart_pio(File) 1 type(file_desc_t), intent(inout) :: File integer :: ierr ierr = pio_put_att(File, PIO_GLOBAL, 'current_metdata_filename', curr_filename) ierr = pio_put_att(File, PIO_GLOBAL, 'next_metdata_filename', next_filename) end subroutine write_met_restart_pio subroutine read_met_restart_pio(File) 1 type(file_desc_t), intent(inout) :: File integer :: ierr, xtype, slen ierr = pio_inq_att(File, PIO_GLOBAL, 'current_metdata_filename',xtype, slen) ierr = pio_get_att(File, PIO_GLOBAL, 'current_metdata_filename', curr_filename) curr_filename(slen+1:256) = '' ierr = pio_inq_att(File, PIO_GLOBAL, 'next_metdata_filename',xtype, slen) ierr = pio_get_att(File, PIO_GLOBAL, 'next_metdata_filename', next_filename) next_filename(slen+1:256) = '' end subroutine read_met_restart_pio subroutine write_met_restart_bin( nrg ) 1,2 implicit none integer,intent(in) :: nrg ! Unit number integer :: ioerr ! error status if (masterproc) then write(nrg, iostat=ioerr) curr_filename if (ioerr /= 0 ) then write(iulog,*) 'WRITE ioerror ',ioerr,' on i/o unit = ',nrg call endrun ('WRITE_RESTART_DYNAMICS') end if write(nrg, iostat=ioerr) next_filename if (ioerr /= 0 ) then write(iulog,*) 'WRITE ioerror ',ioerr,' on i/o unit = ',nrg call endrun ('WRITE_RESTART_DYNAMICS') end if end if end subroutine write_met_restart_bin !------------------------------------------------------------------------- ! reads file names from restart file !------------------------------------------------------------------------- subroutine read_met_restart_bin( nrg ) 1,4 implicit none integer,intent(in) :: nrg ! Unit number integer :: ioerr ! error status if (masterproc) then read(nrg, iostat=ioerr) curr_filename if (ioerr /= 0 ) then write(iulog,*) 'READ ioerror ',ioerr,' on i/o unit = ',nrg call endrun ('READ_RESTART_DYNAMICS') end if read(nrg, iostat=ioerr) next_filename if (ioerr /= 0 ) then write(iulog,*) 'READ ioerror ',ioerr,' on i/o unit = ',nrg call endrun ('READ_RESTART_DYNAMICS') end if end if #if ( defined SPMD ) call mpibcast ( curr_filename ,len(curr_filename) ,mpichar,0,mpicom) call mpibcast ( next_filename ,len(next_filename) ,mpichar,0,mpicom) #endif end subroutine read_met_restart_bin !------------------------------------------------------------------------- ! returns true if the met winds are defined on cell walls !------------------------------------------------------------------------- function met_winds_on_walls() logical :: met_winds_on_walls met_winds_on_walls = cell_wall_winds end function met_winds_on_walls ! internal methods : !------------------------------------------------------------------------- ! transfers cell-centered winds to cell walls !------------------------------------------------------------------------- subroutine transfer_windsToWalls(grid) 1 implicit none type (T_FVDYCORE_GRID), intent(in) :: grid integer :: i,j,k integer :: im, jfirst, jlast, kfirst, klast im = grid%im jfirst = grid%jfirst jlast = grid%jlast kfirst = grid%kfirst klast = grid%klast call t_startf('MET__transfer_windsToWalls') !$omp parallel do private (i, j, k) do k = kfirst, klast do j = jfirst+1,jlast do i = 1,im met_us(i,j,k) = ( met_u(i,j,k) + met_u(i,j-1,k) )*D0_5 end do end do #if defined( SPMD ) if ( jfirst .gt. 1 ) then do i = 1, im ! met_u is alread ghosted at this point met_us(i,jfirst,k) = ( met_u(i,jfirst,k) + met_u(i,jfirst-1,k) )*D0_5 enddo endif #endif do j = jfirst,jlast met_vs(1,j,k) = ( met_v(1,j,k) + met_v(im,j,k) )*D0_5 do i = 2,im met_vs(i,j,k) = ( met_v(i,j,k) + met_v(i-1,j,k) )*D0_5 end do end do end do call t_stopf('MET__transfer_windsToWalls') end subroutine transfer_windsToWalls subroutine get_model_time() 5,9 implicit none integer yr, mon, day, ncsec ! components of a date call t_startf('MET__get_model_time') call get_curr_date(yr, mon, day, ncsec) curr_mod_time = get_time_float( yr, mon, day, ncsec ) next_mod_time = curr_mod_time + get_step_size()/seconds_per_day call t_stopf('MET__get_model_time') end subroutine get_model_time !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine check_files(grid) 2,15 use shr_sys_mod, only: shr_sys_system use ioFileMod, only: getfil implicit none type (T_FVDYCORE_GRID), intent(in) :: grid !----------------------------------------------------------------------- ! ... local variables !----------------------------------------------------------------------- character(len=256) :: ctmp character(len=256) :: loc_fname integer :: istat if (next_mod_time > curr_data_times(size(curr_data_times))) then if ( .not. associated(next_data_times) ) then ! open next file... next_filename = incr_filename( curr_filename ) call open_met_datafile( grid, next_filename, next_fileid, next_data_times ) endif endif if ( associated(next_data_times) ) then if (curr_mod_time >= next_data_times(1)) then ! close current file ... if (grid%iam == 0) then call pio_closefile( curr_fileid ) ! remove if requested if( remove_met_file ) then call getfil( 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 endif curr_filename = next_filename curr_fileid = next_fileid deallocate( curr_data_times ) allocate( curr_data_times( size( next_data_times ) ) ) curr_data_times(:) = next_data_times(:) next_filename = '' deallocate( next_data_times ) nullify( next_data_times ) endif endif end subroutine check_files !----------------------------------------------------------------------- !----------------------------------------------------------------------- function incr_filename( filename ) 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=256) :: incr_filename ! next filename in the sequence ! set new next_filename ... !----------------------------------------------------------------------- ! ... local variables !----------------------------------------------------------------------- integer :: pos, pos1, istat character(len=256) :: fn_new, line character(len=6) :: seconds character(len=5) :: num integer :: ios,unitnumber if ( len_trim(filenames_list) .eq. 0) then !----------------------------------------------------------------------- ! ... ccm type filename !----------------------------------------------------------------------- pos = len_trim( filename ) fn_new = filename(:pos) 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 write(iulog,*) 'incr_flnm: old filename = ',trim(filename) write(iulog,*) 'incr_flnm: open filenames_list : ',filenames_list unitnumber = shr_file_getUnit() open( unit=unitnumber, file=filenames_list, iostat=ios, status="OLD") if (ios /= 0) then call endrun('not able to open filenames_list file: '//filenames_list) 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: '//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: '//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: '//filenames_list) endif fn_new = trim(line) close(unit=unitnumber) call shr_file_freeUnit(unitnumber) endif incr_filename = trim(fn_new) write(iulog,*) 'incr_flnm: new filename = ',incr_filename end function incr_filename !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine find_times( itms, fids, datatm, datatp, time ) 5,5 implicit none 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 real(r8), intent(out):: datatm, datatp integer np1 ! current forward time index of dataset integer n,i ! integer :: curr_tsize, next_tsize, all_tsize real(r8), allocatable, dimension(:):: all_data_times curr_tsize = size(curr_data_times) next_tsize = 0 if ( associated(next_data_times)) next_tsize = size(next_data_times) all_tsize = curr_tsize + next_tsize allocate( all_data_times( all_tsize ) ) all_data_times(:curr_tsize) = curr_data_times(:) if (next_tsize > 0) all_data_times(curr_tsize+1:all_tsize) = next_data_times(:) ! find bracketing times do n=1, all_tsize-1 np1 = n + 1 datatm = all_data_times(n) datatp = all_data_times(np1) if ( (time .ge. datatm) .and. (time .le. datatp) ) then goto 20 endif enddo write(iulog,*)'FIND_TIMES: Failed to find dates bracketing desired time =', time write(iulog,*)' datatm = ',datatm write(iulog,*)' datatp = ',datatp write(iulog,*)' all_data_times = ',all_data_times call endrun 20 continue deallocate( all_data_times ) itms(1) = n itms(2) = np1 fids(:) = curr_fileid do i=1,2 if ( itms(i) > curr_tsize ) then itms(i) = itms(i) - curr_tsize fids(i) = next_fileid endif enddo end subroutine find_times !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine read_next_ps(grid) 1,4 use ncdio_atm, only: infld implicit none type (T_FVDYCORE_GRID), intent(in) :: grid integer :: recnos(2) type(file_desc_t) :: fids(2) character(len=8) :: varname integer :: ifirstxy, ilastxy, jfirstxy, jlastxy logical :: readvar if(online_test) then varname='arch_PS' else varname='PS' end if jfirstxy= grid%jfirstxy jlastxy = grid%jlastxy ifirstxy= grid%ifirstxy ilastxy = grid%ilastxy call find_times( recnos, fids, datatimemn, datatimepn, next_mod_time ) call infld(varname, fids(1), 'lon', 'lat', ifirstxy, ilastxy, jfirstxy, jlastxy, & met_psi_next(nm)%data, readvar, grid_map='DYN', timelevel=recnos(1)) call infld(varname, fids(2), 'lon', 'lat', ifirstxy, ilastxy, jfirstxy, jlastxy, & met_psi_next(np)%data, readvar, grid_map='DYN', timelevel=recnos(2)) if(masterproc) write(iulog,*)'READ_NEXT_PS: Read meteorological data ' end subroutine read_next_ps !------------------------------------------------------------------------ !------------------------------------------------------------------------ subroutine read_next_metdata(grid) 1,13 use ncdio_atm, only: infld implicit none type (T_FVDYCORE_GRID), intent(in) :: grid integer recnos(2), i ! type(file_desc_t) :: fids(2) character(len=8) :: Uname, Vname, Tname, Qname, psname integer :: im, jm, km logical :: readvar integer :: ifirstxy, ilastxy, jfirstxy, jlastxy call t_startf('MET__read_next_metdata') jfirstxy= grid%jfirstxy jlastxy = grid%jlastxy ifirstxy= grid%ifirstxy ilastxy = grid%ilastxy im = grid%im jm = grid%jm km = grid%km call find_times( recnos, fids, datatimem, datatimep, curr_mod_time ) ! ! Set up hyperslab corners ! if(online_test) then Tname='arch_T' Qname='arch_Q' PSname='arch_PS' if(cell_wall_winds) then Uname='arch_US' Vname='arch_VS' else Uname='arch_U' Vname='arch_V' end if else Tname='T' Qname='Q' PSname='PS' if(cell_wall_winds) then Uname='US' Vname='VS' else Uname='U' Vname='V' end if end if do i=1,2 call infld(Tname, fids(i), 'lon', 'lev', 'lat', 1, pcols, 1, pver, & begchunk, endchunk, met_ti(i)%data, readvar, grid_map='PHYS',timelevel=recnos(i)) if (cell_wall_winds) then call infld(Uname, fids(i), 'lon', 'lev', 'slat', ifirstxy, ilastxy, jfirstxy, jlastxy, & 1,km, met_usi(i)%data, readvar, grid_map='DYN',timelevel=recnos(i)) call infld(Vname, fids(i), 'slon', 'lev', 'lat', ifirstxy, ilastxy, jfirstxy, jlastxy, & 1,km,met_vsi(i)%data, readvar, grid_map='DYN',timelevel=recnos(i)) else call infld(Uname, fids(i), 'lon', 'lev', 'lat', ifirstxy, ilastxy, jfirstxy, jlastxy, & 1,km,met_ui(i)%data, readvar, grid_map='DYN',timelevel=recnos(i)) call infld(Vname, fids(i), 'lon', 'lev', 'lat', ifirstxy, ilastxy, jfirstxy, jlastxy, & 1,km,met_vi(i)%data, readvar, grid_map='DYN',timelevel=recnos(i)) endif call infld(Qname, fids(i), 'lon', 'lev', 'lat', 1, pcols, 1, pver, & begchunk, endchunk, met_qi(i)%data, readvar, grid_map='PHYS',timelevel=recnos(i)) call infld(shflx_name, fids(i), 'lon', 'lat', 1, pcols, begchunk, endchunk, & met_shflxi(i)%data, readvar, grid_map='PHYS',timelevel=recnos(i)) call infld(Qflx_name, fids(i), 'lon', 'lat', 1, pcols, begchunk, endchunk, & met_qflxi(i)%data, readvar, grid_map='PHYS',timelevel=recnos(i)) call infld('TAUX', fids(i), 'lon', 'lat', 1, pcols, begchunk, endchunk, & met_tauxi(i)%data, readvar, grid_map='PHYS',timelevel=recnos(i)) call infld('TAUY', fids(i), 'lon', 'lat', 1, pcols, begchunk, endchunk, & met_tauyi(i)%data, readvar, grid_map='PHYS',timelevel=recnos(i)) call infld(PSname, fids(i), 'lon', 'lat', ifirstxy, ilastxy, jfirstxy, jlastxy, & met_psi_curr(i)%data, readvar, grid_map='DYN',timelevel=recnos(i)) enddo if(masterproc) write(iulog,*)'READ_NEXT_METDATA: Read meteorological data ' call t_stopf('MET__read_next_metdata') end subroutine read_next_metdata !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ subroutine interpolate_metdata(grid) 1,6 #if defined( SPMD ) use mod_comm, only : mp_send4d_ns, mp_recv4d_ns #endif implicit none type (T_FVDYCORE_GRID), intent(in) :: grid real(r4) fact1, fact2 real(r4) nfact1, nfact2 real(r8) deltat,deltatn integer :: i,j,k integer :: im, jm, km, jfirst, jlast, kfirst, klast, ng_d, ng_s im = grid%im jm = grid%jm km = grid%km jfirst = grid%jfirst jlast = grid%jlast kfirst = grid%kfirst klast = grid%klast ng_d = grid%ng_d ng_s = grid%ng_s call t_startf('MET__interpolate_metdata') deltat = datatimep - datatimem deltatn = datatimepn - datatimemn fact1 = (datatimep - curr_mod_time)/deltat ! fact2 = (curr_mod_time - datatimem)/deltat fact2 = D1_0-fact1 nfact1 = (datatimepn - next_mod_time)/deltatn ! nfact2 = (next_mod_time - datatimemn)/deltatn nfact2 = D1_0-nfact1 met_t(:,:,:) = fact1*met_ti(nm)%data(:,:,:) + fact2*met_ti(np)%data(:,:,:) met_q(:,:,:) = fact1*met_qi(nm)%data(:,:,:) + fact2*met_qi(np)%data(:,:,:) if (.not. online_test) where (met_q .lt. D0_0) met_q = D0_0 met_ps_next(:,:) = nfact1*met_psi_next(nm)%data(:,:) + nfact2*met_psi_next(np)%data(:,:) met_ps_curr(:,:) = fact1*met_psi_curr(nm)%data(:,:) + fact2*met_psi_curr(np)%data(:,:) met_shflx(:,:) = fact1*met_shflxi(nm)%data(:,:) + fact2*met_shflxi(np)%data(:,:) met_qflx(:,:) = fact1*met_qflxi(nm)%data(:,:) + fact2*met_qflxi(np)%data(:,:) met_taux(:,:) = fact1*met_tauxi(nm)%data(:,:) + fact2*met_tauxi(np)%data(:,:) met_tauy(:,:) = fact1*met_tauyi(nm)%data(:,:) + fact2*met_tauyi(np)%data(:,:) if ( .not. cell_wall_winds ) then met_u(1:im,jfirst:jlast,kfirst:klast) = fact1*met_ui(nm)%data(1:im,jfirst:jlast,kfirst:klast) & + fact2*met_ui(np)%data(1:im,jfirst:jlast,kfirst:klast) met_v(1:im,jfirst:jlast,kfirst:klast) = fact1*met_vi(nm)%data(1:im,jfirst:jlast,kfirst:klast) & + fact2*met_vi(np)%data(1:im,jfirst:jlast,kfirst:klast) ! ghost u,v #if defined( SPMD ) call mp_send4d_ns( grid%commxy, im, jm, km, 1, jfirst, jlast, & kfirst, klast, ng_d, ng_d, met_u ) call mp_send4d_ns( grid%commxy, im, jm, km, 1, jfirst, jlast, & kfirst, klast, ng_d, ng_s, met_v ) call mp_recv4d_ns( grid%commxy, im, jm, km, 1, jfirst, jlast, & kfirst, klast, ng_d, ng_d, met_u ) call mp_recv4d_ns( grid%commxy, im, jm, km, 1, jfirst, jlast, & kfirst, klast, ng_d, ng_s, met_v ) #endif ! average to cell walls (vorticity winds) call transfer_windsToWalls(grid) else met_us(:,jfirst:jlast,kfirst:klast) = fact1*met_usi(nm)%data(:,jfirst:jlast,kfirst:klast) + & fact2*met_usi(np)%data(:,jfirst:jlast,kfirst:klast) met_vs(:,jfirst:jlast,kfirst:klast) = fact1*met_vsi(nm)%data(:,jfirst:jlast,kfirst:klast) + & fact2*met_vsi(np)%data(:,jfirst:jlast,kfirst:klast) endif ! ghost staggered u,v ! WS 2006.04.11: not necessary here since it will be done in cd_core ! write(iulog,*)'INTERPOLATE_METDATA: complete.' call t_stopf('MET__interpolate_metdata') end subroutine interpolate_metdata !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine get_dimension( fid, dname, dsize ) 11,2 implicit none type(file_desc_t), intent(in) :: fid character(*), intent(in) :: dname integer, intent(out) :: dsize integer :: dimid, ierr ierr = pio_inq_dimid( fid, dname, dimid ) ierr = pio_inq_dimlen( fid, dimid, dsize ) end subroutine get_dimension !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine open_met_datafile( grid, fname, fileid, times, check_dims ) 3,11 use ioFileMod, only: getfil implicit none type (T_FVDYCORE_GRID), intent(in) :: grid character(*), intent(in) :: fname type(file_desc_t), intent(inout) :: fileid real(r8), pointer :: times(:) logical, optional, intent(in) :: check_dims character(len=256) :: filen integer :: year, month, day, dsize, i, timesize integer :: dateid,secid integer, allocatable , dimension(:) :: dates, datesecs integer :: ierr integer :: im, jm, km im = grid%im jm = grid%jm km = grid%km ! ! open file and get fileid ! call getfil( fname, filen, 0 ) call cam_pio_openfile( fileid, filen, 0 ) if (grid%iam == 0) write(iulog,*)'open_met_datafile: ',trim(filen) call get_dimension( fileid, 'time', timesize ) if ( associated(times) ) deallocate(times) allocate( times(timesize) ) allocate( dates(timesize) ) allocate( datesecs(timesize) ) ierr = pio_inq_varid( fileid, 'date', dateid ) ierr = pio_inq_varid( fileid, 'datesec', secid ) ierr = pio_get_var( fileid, dateid, dates ) ierr = pio_get_var( fileid, secid, datesecs ) do i=1,timesize year = dates(i) / 10000 month = mod(dates(i),10000)/100 day = mod(dates(i),100) times(i) = get_time_float( year, month, day, datesecs(i) ) enddo deallocate( dates ) deallocate( datesecs ) ! ! check that the data dim sizes match models dimensions ! if (present(check_dims)) then if (check_dims) then call get_dimension( fileid, 'lon', dsize ) if (dsize /= im) then write(iulog,*)'open_met_datafile: lonsiz=',dsize,' must = ',im call endrun endif call get_dimension( fileid, 'lat', dsize ) if (dsize /= jm) then write(iulog,*)'open_met_datafile: latsiz=',dsize,' must = ',jm call endrun endif call get_dimension( fileid, 'lev', dsize ) #if ( defined WACCM_GHG || defined WACCM_MOZART ) met_levels = min( dsize, km ) #else if (dsize /= km) then write(iulog,*)'open_met_datafile: levsiz=',dsize,' must = ',km call endrun endif met_levels = km #endif endif endif end subroutine open_met_datafile !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ function get_time_float( year, month, day, sec ) 2,3 ! returns float representation of time -- number of days ! since 1 jan 0001 00:00:00.000 implicit none integer, intent(in) :: year, month, day integer, intent(in) :: sec real(r8) :: get_time_float ! ref date is 1 jan 0001 integer :: refyr, refmn, refdy real(r8) :: refsc, fltdy integer :: doy(12) ! jan feb mar apr may jun jul aug sep oct nov dec ! 31 28 31 30 31 30 31 31 31 31 30 31 data doy / 1, 32, 60, 91,121,152,182,213,244,274,305,335 / refyr = 1 refmn = 1 refdy = 1 refsc = D0_0 if ( get_calendar() == 'GREGORIAN' ) then fltdy = greg2jday(year, month, day) - greg2jday(refyr,refmn,refdy) else ! assume no_leap (all years are 365 days) fltdy = (year - refyr)*days_per_non_leapyear + & (doy(month)-doy(refmn)) + & (day-refdy) endif get_time_float = fltdy + ((sec-refsc)/seconds_per_day) endfunction get_time_float !----------------------------------------------------------------------- ! ... Return Julian day number given Gregorian date. ! ! Algorithm from Hatcher,D.A., Simple Formulae for Julian Day Numbers ! and Calendar Dates, Q.Jl.R.astr.Soc. (1984) v25, pp 53-55. !----------------------------------------------------------------------- function greg2jday( year, month, day ) 2 implicit none integer, intent(in) :: year, month, day integer :: greg2jday !----------------------------------------------------------------------- ! ... Local variables !----------------------------------------------------------------------- integer :: ap, mp integer :: y, d, n, g !----------------------------------------------------------------------- ! ... Modify year and month numbers !----------------------------------------------------------------------- ap = year - (12 - month)/10 mp = MOD( month-3,12 ) if( mp < 0 ) then mp = mp + 12 end if !----------------------------------------------------------------------- ! ... Julian day !----------------------------------------------------------------------- y = INT( days_per_year*( ap + 4712 ) ) d = INT( days_per_month*mp + D0_5 ) n = y + d + day + 59 g = INT( D0_75*INT( ap/100 + 49 ) ) - 38 greg2jday = n - g end function greg2jday !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine set_met_rlx( ) 1,4 use pmgrid use hycoef, only: hypm, ps0 integer :: k, k_cnt, k_top real(r8), parameter :: h0 = 7._r8 ! scale height (km) real(r8) :: p_top, p_bot 996 format( 'set_met_rlx: ',a15, I10 ) 997 format( 'set_met_rlx: ',a15, E10.2 ) 998 format( 'set_met_rlx: ',a15, PLEV(E10.2)) 999 format( 'set_met_rlx: ',a15, PLEV(F10.5)) met_rlx(:) = 999._r8 #if ( defined WACCM_GHG || defined WACCM_MOZART ) p_top = ps0 * exp( - rlx_top_km/h0 ) p_bot = ps0 * exp( - rlx_bot_km/h0 ) if (masterproc) then write(iulog,fmt=997) 'p_top = ',p_top write(iulog,fmt=997) 'p_bot = ',p_bot endif where( hypm < p_top ) met_rlx = 0._r8 endwhere where( hypm > p_bot ) met_rlx = max_rlx endwhere if ( any( met_rlx(:) /= max_rlx) ) then k_top = max(plev - met_levels, 1) do while ( met_rlx(k_top) /= 999._r8 ) k_top = k_top + 1 enddo met_rlx(1:k_top) = 0._r8 k_cnt = count( met_rlx == 999._r8 ) if (masterproc) then write(iulog,fmt=996) 'k_cnt = ',k_cnt write(iulog,fmt=996) 'k_top = ',k_top endif do k = k_top,k_top+k_cnt met_rlx(k) = max_rlx*real( k - k_top ) / real(k_cnt) enddo endif if (masterproc) then write(iulog,fmt=996) ' met_levels = ',met_levels write(iulog,fmt=996) 'non-zero terms:',count( met_rlx /= 0._r8 ) endif if ( met_levels < count( met_rlx /= 0._r8 ) ) then call endrun('set_met_rlx: met_rlx_top is too high for the meteorology data') endif if (masterproc) then write(iulog,fmt=998) 'press levels = ',hypm write(iulog,fmt=999) ' met_rlx = ',met_rlx endif #else met_rlx(:) = 1._r8 #endif if ( any( (met_rlx > 1._r8) .or. (met_rlx < 0._r8) ) ) then call endrun('Offline meteorology relaxation function not set correctly.') endif end subroutine set_met_rlx end module metdata