module dynVarTimeUninterpMod #include "shr_assert.h" !--------------------------------------------------------------------------- ! !DESCRIPTION: ! Contains a derived type and associated methods that extend the base class, ! dyn_var_type. The type defined here is for variables that should NOT be interpolated ! in time. For variables of this type, the data will snap to their new value at the ! beginning of each year, and then stay fixed throughout the year. Before the start of ! the time series, the data are fixed at their value from the first year in the file; ! after the end of the time series, the data are fixed at their value from the last year ! in the file. ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use dynVarMod , only : dyn_var_type implicit none private save ! !PUBLIC TYPES: public :: dyn_var_time_uninterp_type type, extends(dyn_var_type) :: dyn_var_time_uninterp_type private ! Note that data are stored as 1-d, then converted to the appropriate dimensionality ! as needed real(r8), allocatable :: data_at_tlower(:) ! data at time time_index_lower integer :: time_index_lower ! current time_index_lower corresponding to the data contains generic :: get_current_data => & ! Get the current value of the data get_current_data_1d, get_current_data_2d procedure :: get_current_data_1d ! Get the current value of the data, for a 1-d variable procedure :: get_current_data_2d ! Get the current value of the data, for a 2-d variable procedure :: read_data_if_needed ! Read the next time slice of data, if necessary end type dyn_var_time_uninterp_type interface dyn_var_time_uninterp_type module procedure constructor ! initialize a new dyn_var_time_uninterp_type object end interface dyn_var_time_uninterp_type contains ! ====================================================================== ! Constructors ! ====================================================================== !----------------------------------------------------------------------- type(dyn_var_time_uninterp_type) function constructor( & dyn_file, varname, dim1name, conversion_factor, & do_check_sums_equal_1, data_shape, allow_nodata) ! ! !DESCRIPTION: ! Creates an object of type dyn_var_time_uninterp_type. This also reads the first ! set of data. ! ! Assumes that dyn_file has already been initialized. ! ! !USES: use dynFileMod , only : dyn_file_type use dynTimeInfoMod , only : time_info_type ! ! !ARGUMENTS: type(dyn_file_type), target, intent(in) :: dyn_file ! file containing this variable character(len=*), intent(in) :: varname ! variable name on file character(len=*), intent(in) :: dim1name ! dim1name on file real(r8), intent(in) :: conversion_factor ! data are DIVIDED by conversion_factor immediately after reading them logical, optional, intent(in) :: allow_nodata ! Flag to allow there to be no data if the field doesn't exist on the dataset ! Only relevant for 2-d variables: should we check to make sure that all sums equal 1? logical, intent(in) :: do_check_sums_equal_1 ! Shape of data; max number of dimensions is given by dyn_var_max_dims in dynVarMod. ! First dimension is the spatial dimension. integer, intent(in) :: data_shape(:) logical :: lallow_nodata ! Local version of allow_nodata which is by default FALSE !----------------------------------------------------------------------- lallow_nodata = .false. if ( present(allow_nodata) )then lallow_nodata = allow_nodata end if ! Set metadata common to all dyn_var_type objects call constructor%set_metadata( & dyn_file=dyn_file, & varname=varname, & dim1name=dim1name, & conversion_factor=conversion_factor, & do_check_sums_equal_1=do_check_sums_equal_1, & data_shape=data_shape, allow_nodata=lallow_nodata) ! Allocate space for data allocate(constructor%data_at_tlower(product(data_shape))) ! Read first set of data constructor%time_index_lower = dyn_file%time_info%get_time_index_lower() call constructor%read_variable(constructor%time_index_lower, constructor%data_at_tlower) end function constructor ! ====================================================================== ! Public methods ! ====================================================================== ! The following specific procedures are NOT actually public, but they can be accessed ! via the generic type-bound procedure, get_current_data ! DIMS 1,2 !----------------------------------------------------------------------- subroutine get_current_data_{DIMS}d(this, cur_data) ! ! !DESCRIPTION: ! Get the current value of the data, in cur_data. cur_data should have the same ! dimensionality as the underlying data, as given by the data_shape argument that was ! passed to the constructor. ! ! If necessary, new data are read from the file. ! ! Should be called once per time step, AFTER calling set_current_year on the ! underlying dyn_file variable ! ! !ARGUMENTS: class(dyn_var_time_uninterp_type) , intent(inout) :: this ! this object real(r8) , intent(out) :: cur_data{DIMSTR} ! current value of data ! ! !LOCAL VARIABLES: integer :: ndims ! ndims of data in 'this' character(len=*), parameter :: subname = 'get_current_data_{DIMS}d' !----------------------------------------------------------------------- ! Do some error checking ndims = size(this%get_data_shape()) SHR_ASSERT({DIMS} == ndims, subname//' ERROR: # dims of output argument must match ndims') SHR_ASSERT_ALL((shape(cur_data) == this%get_data_shape()), subname//' ERROR: shape of cur_data must match shape of data') ! Get current data call this%read_data_if_needed() cur_data = reshape(this%data_at_tlower, shape(cur_data)) end subroutine get_current_data_{DIMS}d ! ====================================================================== ! Private methods ! ====================================================================== !----------------------------------------------------------------------- subroutine read_data_if_needed(this) ! ! !DESCRIPTION: ! Determine if new data need to be read from the file; if so, read them. ! ! We need to read new data if the current time on dyn_file disagrees with the time ! for which we currently have stored data. ! ! !USES: use dynFileMod , only : dyn_file_type use dynTimeInfoMod , only : time_info_type ! ! !ARGUMENTS: class(dyn_var_time_uninterp_type), intent(inout) :: this ! this object ! ! !LOCAL VARIABLES: type(dyn_file_type), pointer :: dyn_file ! the dyn_file of this object integer :: time_index_lower_cur ! current value of time_index_lower on dyn_file character(len=*), parameter :: subname = 'read_data_if_needed' !----------------------------------------------------------------------- dyn_file => this%get_dyn_file() time_index_lower_cur = dyn_file%time_info%get_time_index_lower() if (time_index_lower_cur /= this%time_index_lower) then call this%read_variable(time_index_lower_cur, this%data_at_tlower) this%time_index_lower = time_index_lower_cur end if end subroutine read_data_if_needed end module dynVarTimeUninterpMod