[Dart-dev] [9464] DART/trunk/models/ROMS: Enforcing the DART style guide and adding support for doxygen documentation .
nancy at ucar.edu
nancy at ucar.edu
Thu Jan 7 16:08:09 MST 2016
Revision: 9464
Author: thoar
Date: 2016-01-07 16:08:09 -0700 (Thu, 07 Jan 2016)
Log Message:
-----------
Enforcing the DART style guide and adding support for doxygen documentation.
No (intentional) code changes. Formatting, comments, and documentation only.
Modified Paths:
--------------
DART/trunk/models/ROMS/dart_to_roms.f90
DART/trunk/models/ROMS/model_mod.f90
DART/trunk/models/ROMS/roms_to_dart.f90
-------------- next part --------------
Modified: DART/trunk/models/ROMS/dart_to_roms.f90
===================================================================
--- DART/trunk/models/ROMS/dart_to_roms.f90 2016-01-07 22:41:25 UTC (rev 9463)
+++ DART/trunk/models/ROMS/dart_to_roms.f90 2016-01-07 23:08:09 UTC (rev 9464)
@@ -4,30 +4,27 @@
!
! $Id$
+!-----------------------------------------------------------------------
+!> One of the interface executables between DART and ROMS.
+!>
+!> Reads a file containing a DART state vector and overwrite the
+!> corresponding values in a ROMS model analysis file.
+!> If the DART state vector has an 'advance_to_time' present, a
+!> file called model_in.DART is created with a time_manager_nml namelist
+!> appropriate to advance model to the requested time.
+!>
+!> The dart_to_roms_nml namelist setting for advance_time_present
+!> determines whether or not the input file has an 'advance_to_time'.
+!> Typically, only temporary files like 'assim_model_state_ic' have
+!> an 'advance_to_time'.
+!>
+!> author: PENG XIU 12/2013 @ University of Maine
+!> peng.xiu at maine.edu
+!>
+!> subsequently modified by TJH 1/2015
+
program dart_to_roms
-!----------------------------------------------------------------------
-! purpose: interface between DART and the ROMS model
-!
-! overwrite ROMS restart file
-! method: Read DART state vector and overwrite values in a model analysis file.
-! If the DART state vector has an 'advance_to_time' present, a
-! file called model_in.DART is created with a time_manager_nml namelist
-! appropriate to advance model to the requested time.
-!
-! The dart_to_roms_nml namelist setting for advance_time_present
-! determines whether or not the input file has an 'advance_to_time'.
-! Typically, only temporary files like 'assim_model_state_ic' have
-! an 'advance_to_time'.
-!
-!----------------------------------------------------------------
-!
-! author: PENG XIU 12/2013 @ University of Maine
-! peng.xiu at maine.edu
-!
-! subsequently modified by TJH 1/2015
-!----------------------------------------------------------------
-
use types_mod, only : r8
use utilities_mod, only : initialize_utilities, finalize_utilities, &
find_namelist_in_file, check_namelist_read, &
Modified: DART/trunk/models/ROMS/model_mod.f90
===================================================================
--- DART/trunk/models/ROMS/model_mod.f90 2016-01-07 22:41:25 UTC (rev 9463)
+++ DART/trunk/models/ROMS/model_mod.f90 2016-01-07 23:08:09 UTC (rev 9464)
@@ -4,19 +4,28 @@
!
! $Id$
!----------------------------------------------------------------
-!
-! author: PENG XIU 12/2013 @ University of Maine
-! peng.xiu at maine.edu
-!
-! based on subroutines from others work in the DART package
-! NOTE: For now, this code does not rotate ROMS vectors,
-! so, rotate them in the observation data if needed
+!>
+!> This is the interface between the ROMS ocean model and DART.
+!> There are 16 required public interfaces whose arguments CANNOT be changed.
+!> There are potentially many more public routines that are typically
+!> used by the converter programs. As the converter programs get phased out
+!> with the impending native netCDF read/write capability, these extra
+!> public interfaces may not need to be public.
+!>
+!> author: PENG XIU 12/2013 @ University of Maine
+!> peng.xiu at maine.edu
+!>
+!> based on subroutines from others work in the DART package
+!> NOTE: For now, this code does not rotate ROMS vectors,
+!> so, rotate them in the observation data if needed
+!>
+!> subsequently modified by the DART team.
+!>
+!> \todo
!----------------------------------------------------------------
module model_mod
-! This is the interface between the ROMS ocean model and DART.
-
! Modules that are absolutely required for use are listed
use types_mod, only : r4, r8, digits12, SECPERDAY, DEG2RAD, rad2deg, PI, &
MISSING_I, MISSING_R4, MISSING_R8, i4, i8
@@ -209,14 +218,20 @@
contains
-!------------------------------------------------------------------
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Called to do one time initialization of the model.
+!> In this case, it reads in the grid information, the namelist
+!> containing the variables of interest, where to get them, their size,
+!> their associated DART KIND, etc.
+!>
+!> In addition to harvesting the model metadata (grid,
+!> desired model advance step, etc.), it also fills a structure
+!> containing information about what variables are where in the DART
+!> framework.
subroutine static_init_model()
-! Called to do one time initialization of the model. In this case,
-! it reads in the grid information.
-
integer :: iunit, io,index1,indexN,ivar
integer :: ss, dd,i,TimeDimID
integer, dimension(NF90_MAX_VAR_DIMS) :: dimIDs
@@ -224,21 +239,15 @@
character(len=paramname_length) :: kind_string
integer :: ncid, VarID, numdims, varsize, dimlen
-
if ( module_initialized ) return
! The Plan:
!
-! read in the grid sizes from grid file
-!
-! allocate space, and read in actual grid values
-!
-! figure out model timestep
-!
-! Compute the model size.
-!
-! set the index numbers where the field types change
-!
+! * read in the grid sizes from grid file
+! * allocate space, and read in actual grid values
+! * figure out model timestep
+! * Compute the model size.
+! * set the index numbers where the field types change
! Print module information to log file and stdout.
call register_module(source, revision, revdate)
@@ -259,7 +268,7 @@
! Set the time step ... causes ROMS namelists to be read.
! Ensures model_timestep is multiple of 'ocean_dynamics_timestep'
-! FIXME 'ocean_dynamics_timestep' could/should be gotten from ROMS
+!> @todo FIXME 'ocean_dynamics_timestep' could/should be gotten from ROMS
model_timestep = set_model_time_step()
@@ -275,10 +284,10 @@
call nc_check( nf90_open(trim(model_restart_filename), NF90_NOWRITE, ncid), &
'static_init_model', 'open '//trim(model_restart_filename))
-call verify_state_variables( variables, ncid, model_restart_filename, &
+call verify_variables( variables, ncid, model_restart_filename, &
nfields, variable_table )
-TimeDimID = FindTimeDimension( ncid, model_restart_filename )
+TimeDimID = find_time_dimension( ncid, model_restart_filename )
if (TimeDimID < 0 ) then
write(*,*) 'CAUTION: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
@@ -427,31 +436,39 @@
end subroutine static_init_model
-!------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Set the desired minimum model advance time. This is generally NOT the
+!> dynamical timestep of the model, but rather the shortest forecast length
+!> you are willing to make. This impacts how frequently the observations
+!> may be assimilated.
+!>
function set_model_time_step()
-! the static_init_model ensures that the model namelists are read.
-
type(time_type) :: set_model_time_step
if ( .not. module_initialized ) call static_init_model
-! these are from the namelist
+! assimilation_period_seconds, assimilation_period_days are from the namelist
+!> @todo FIXME make sure set_model_time_step is an integer multiple of
+!> the dynamical timestep or whatever strategy ROMS employs.
+
set_model_time_step = set_time(assimilation_period_seconds, assimilation_period_days)
end function set_model_time_step
-!------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> return the name of the ROMS analysis filename that was set
+!> in the model_nml namelist
+!>
subroutine get_model_restart_filename( filename )
-! return the name of the analysis filename that was set
-! in the model_nml namelist
-
character(len=*), intent(OUT) :: filename
if ( .not. module_initialized ) call static_init_model
@@ -460,14 +477,19 @@
end subroutine get_model_restart_filename
-!------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Read the grid dimensions from the ROMS grid netcdf file.
+!> By reading the dimensions first, we can use them in variable
+!> declarations later - which is faster than using allocatable arrays.
+!>
+!> @todo FIXME Since every stagger dimension is specified, we should explicitly
+!> use them instead of trying to add or subtract 1 from some nominal value
+!>
+
subroutine get_grid_dimensions()
-! Read the grid dimensions from the ROMS netcdf file.
-! By reading the dimensions first, we can use them in variable
-! declarations later - which is faster than using allocatable arrays.
-
integer :: ncid
integer :: xi_rho
@@ -509,17 +531,23 @@
end subroutine get_grid_dimensions
-!------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Read the actual grid values from the ROMS netcdf file.
+!>
+!> @todo FIXME If the grid variables do not exist, they are calculated.
+!> It is not clear to me if this code block is correct in all circumstances,
+!> as I do not have access to a good test file. Minimally, instead of requiring
+!> setting a hardcoded logical, a simple test to see if the required variables
+!> exist and then taking appropriate action would be greatly preferred.
subroutine get_grid()
-! Read the actual grid values in from the ROMS netcdf file.
-!
-! The file name comes from module storage ... namelist.
-! This reads in the following arrays:
-
integer :: k,ncid, VarID,stat,i,j
+! The following 'automatic' arrays are more efficient than allocatable arrays.
+! This is, in part, why the grid dimensions were determined previously.
+
real(r8) :: dzt0(Nx,Ny)
real(r8) :: s_rho(Nz),Cs_r(Nz),SSH(Nx,Ny)
real(r8) :: x_rho(Nx,Ny), &
@@ -538,7 +566,7 @@
call error_handler(E_MSG,'get_grid:',string1,text2=string2,text3=string3)
endif
-! Read the netcdf file data
+! Open the netcdf file data
call nc_check(nf90_open(trim(grid_definition_filename), nf90_nowrite, ncid), &
'get_grid', 'open '//trim(grid_definition_filename))
@@ -557,10 +585,9 @@
! Read the variables
-!---------------------------------------
! If there are no lat and lon information in the file
-! TJH FIXME ... just test for the presence of the variables ... do not
-! depend on setting a logical
+!> @todo FIXME ... just test for the presence of the variables ...
+!> do not depend on setting a logical
if (nolatlon) then
@@ -607,8 +634,6 @@
VLON=TLON(:,1:Ny-1)
VLAT=TLAT(:,1:Ny-1)
- !---------------------------------------
-
else
call nc_check(nf90_inq_varid(ncid, 'lon_rho', VarID), &
@@ -693,7 +718,6 @@
! -0.00517297115481568, -0.00168895354075999/)
-
! Also get zeta values in order to calculate ZC
call nc_check(nf90_open(trim(model_restart_filename), nf90_nowrite, ncid), &
@@ -717,17 +741,27 @@
end subroutine get_grid
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Determines if the variables and DART KINDs specified by the 'variables'
+!> namelist variable are available in the ROMS analysis file and that the
+!> corresponding DART KIND is also supported.
+!>
+!>@param state_variables the list of variables and kinds from model_mod_nml
+!>@param ncid the netCDF handle to the ROMS analysis file
+!>@param filename the name of the ROMS analysis file (for error messages, mostly)
+!>@param ngood the number of variable/KIND pairs specified
+!>@param table a more convenient form for the variable/KIND pairs. Each row
+!> is a pair, column 1 is the variable, column 2 is the DART KIND
+subroutine verify_variables( state_variables, ncid, filename, ngood, table )
-subroutine verify_state_variables( state_variables, ncid, filename, ngood, table )
+character(len=*), intent(in) :: state_variables(:)
+integer, intent(in) :: ncid
+character(len=*), intent(in) :: filename
+integer, intent(out) :: ngood
+character(len=*), intent(inout) :: table(:,:)
-character(len=*), dimension(:), intent(in) :: state_variables
-integer, intent(in) :: ncid
-character(len=*), intent(in) :: filename
-integer, intent(out) :: ngood
-character(len=*), dimension(:,:), intent(inout) :: table
-
integer :: nrows, ncols, i, VarID
character(len=NF90_MAX_NAME) :: varname
character(len=NF90_MAX_NAME) :: dartstr
@@ -751,7 +785,7 @@
if ( table(i,1) == ' ' .or. table(i,2) == ' ' ) then
string1 = 'model_nml:model "variables" not fully specified'
- call error_handler(E_ERR,'verify_state_variables:',string1,source,revision,revdate)
+ call error_handler(E_ERR,'verify_variables:',string1,source,revision,revdate)
endif
! Make sure variable exists in model analysis variable list
@@ -759,17 +793,15 @@
write(string1,'(''variable '',a,'' in '',a)') trim(varname), trim(filename)
write(string2,'(''there is no '',a)') trim(string1)
call nc_check(NF90_inq_varid(ncid, trim(varname), VarID), &
- 'verify_state_variables', trim(string2))
+ 'verify_variables', trim(string2))
-
! Make sure DART kind is valid
if( get_raw_obs_kind_index(dartstr) < 0 ) then
write(string1,'(''there is no obs_kind <'',a,''> in obs_kind_mod.f90'')') trim(dartstr)
- call error_handler(E_ERR,'verify_state_variables:',string1,source,revision,revdate)
+ call error_handler(E_ERR,'verify_variables:',string1,source,revision,revdate)
endif
-
ngood = ngood + 1
enddo MyLoop
@@ -777,31 +809,43 @@
if (ngood == nrows) then
string1 = 'WARNING: There is a possibility you need to increase ''max_state_variables'''
write(string2,'(''WARNING: you have specified at least '',i4,'' perhaps more.'')')ngood
- call error_handler(E_MSG,'verify_state_variables:',string1,source,revision,revdate,text2=string2)
+ call error_handler(E_MSG,'verify_variables:',string1,source,revision,revdate,text2=string2)
endif
-end subroutine verify_state_variables
+end subroutine verify_variables
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> matches variable name in bounds table to assign
+!> the bounds if they exist. otherwise sets the bounds
+!> to missing_r8 which means they are unbounded.
+!> @todo FIXME the roms_state_bounds module variable that specifies the
+!> bounds is not actually set nor checked nor ... so all variables
+!> are unbounded.
+!>
+!> @param bounds_table table specifying the numeric bounds for each variable.
+!> as currently envisioned, a table specifying the variable
+!> name and its boundaries must be supplied ... ?namelist?
+!> @param ivar the handle to the variable in question
+!>
-
subroutine get_variable_bounds(bounds_table, ivar)
-! matches variable name in bounds table to assign
-! the bounds if they exist. otherwise sets the bounds
-! to missing_r8
-!
-character(len=*), intent(in) :: bounds_table(num_bounds_table_columns, max_state_variables)
-integer, intent(in) :: ivar
+character(len=*), intent(in) :: bounds_table(num_bounds_table_columns, max_state_variables)
+integer, intent(in) :: ivar
! local variables
-character(len=50) :: bounds_varname, bound
-character(len=10) :: clamp_or_fail
-real(r8) :: lower_bound, upper_bound
-integer :: n
+character(len=50) :: bounds_varname, bound
+character(len=10) :: clamp_or_fail
+real(r8) :: lower_bound, upper_bound
+integer :: n
+write(string1,*)'WARNING routine not tested.'
+write(string2,*)'"roms_state_bounds" from namelist is not set, not tested.'
+call error_handler(E_MSG,'get_variable_bounds:',string1, text2=string2)
+
n = 1
do while ( trim(bounds_table(1,n)) /= 'NULL' .and. trim(bounds_table(1,n)) /= '' )
@@ -867,25 +911,34 @@
end subroutine get_variable_bounds
-!-------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Reads the last timestep of the ROMS variables and packs them into a
+!> DART state vector. At present, only the last timestep is considered.
+!> @todo determining the timestep of the DESIRED time might be a nice extension.
+!>
+!> @param filename the ROMS file that contains the variables of interest.
+!> @param state_vector the DART state vector
+!> @param last_file_time the last time in the file.
+!>
+!> @todo FIXME last_file_time is provided as a convenience, not sure
+!> I am decoding the information correctly given the test file
+!> that I had. It would be nice to get an accurate time and ensure
+!> that the desired time is being read.
-
subroutine restart_file_to_sv(filename, state_vector, last_file_time)
-! Reads the current time and state variables
-! file and packs them into a dart state vector.
+character(len=*), intent(in) :: filename
+real(r8), intent(out) :: state_vector(:)
+type(time_type), intent(out) :: last_file_time
-character(len=*), intent(in) :: filename
-real(r8), intent(inout) :: state_vector(:)
-type(time_type), intent(out) :: last_file_time
-
! temp space to hold data while we are reading it
integer :: ndim1, ndim2, ndim3,ndim4
integer :: indx, iostatus, ivar
-real(r8), allocatable, dimension(:) :: data_1d_array
-real(r8), allocatable, dimension(:,:) :: data_2d_array
-real(r8), allocatable, dimension(:,:,:) :: data_3d_array
-real(r8), allocatable, dimension(:,:,:,:) :: data_4d_array
+real(r8), allocatable, dimension(:) :: data_1d_array
+real(r8), allocatable, dimension(:,:) :: data_2d_array
+real(r8), allocatable, dimension(:,:,:) :: data_3d_array
+real(r8), allocatable, dimension(:,:,:,:) :: data_4d_array
integer, dimension(NF90_MAX_VAR_DIMS) :: dimIDs, mystart, mycount
character(len=NF90_MAX_NAME) :: varname
@@ -922,7 +975,7 @@
! IF the netCDF variable has an 'ocean_time' dimension,
! we need to read the LAST timestep ...
-TimeDimID = FindTimeDimension(ncid, filename, last_file_time)
+TimeDimID = find_time_dimension(ncid, filename, last_file_time)
if (TimeDimID < 0) then
write(string1,*) trim(filename)//' has no "ocean_time" coordinate variable.'
@@ -1053,14 +1106,14 @@
end subroutine restart_file_to_sv
-!-----------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> parse the model_nml "analysis_time" string to extract a DART time.
+!> the expected format of the string is YYYY-MM-DD HH:MM:SS
+!> The time is expected to come from the Gregorian calendar.
-
function get_time_from_namelist()
-! parse a string to extract time.
-! the expected format of the string is YYYY?MM?DD?hh
-
type(time_type) :: get_time_from_namelist
integer :: iyear, imonth, iday, ihour, imin, isec
@@ -1082,18 +1135,20 @@
end function get_time_from_namelist
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Pack the values from a 1d array into the DART array
+!>
+!> @param data_1d_array the array containing the ROMS variable
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
-
subroutine prog_var_1d_to_vector(data_1d_array, x, ivar)
-! convert the values from a 1d array into a 1d array
-! starting at an offset.
+real(r8), intent(in) :: data_1d_array(:)
+real(r8), intent(inout) :: x(:)
+integer, intent(in) :: ivar
-real(r8), dimension(:), intent(in) :: data_1d_array
-real(r8), dimension(:), intent(inout) :: x
-integer, intent(in) :: ivar
-
integer :: idim1,ii
if ( .not. module_initialized ) call static_init_model
@@ -1116,17 +1171,21 @@
end subroutine prog_var_1d_to_vector
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Pack the values from a 2D array into the 1D DART array
+!>
+!> @param data_2d_array the array containing the ROMS variable
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
+!>
subroutine prog_var_2d_to_vector(data_2d_array, x, ivar)
-! convert the values from a 2d array into a 1d array
-! starting at an offset.
+real(r8), intent(in) :: data_2d_array(:,:)
+real(r8), intent(inout) :: x(:)
+integer, intent(in) :: ivar
-real(r8), dimension(:,:), intent(in) :: data_2d_array
-real(r8), dimension(:), intent(inout) :: x
-integer, intent(in) :: ivar
-
integer :: idim1,idim2,ii
if ( .not. module_initialized ) call static_init_model
@@ -1150,17 +1209,22 @@
end subroutine prog_var_2d_to_vector
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Pack the values from a 3D array into the 1D DART array
+!>
+!> @param data_3d_array the array containing the ROMS variable
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
+!>
+
subroutine prog_var_3d_to_vector(data_3d_array, x, ivar)
-! convert the values from a 2d array into a 1d array
-! starting at an offset.
+real(r8), intent(in) :: data_3d_array(:,:,:)
+real(r8), intent(inout) :: x(:)
+integer, intent(in) :: ivar
-real(r8), dimension(:,:,:), intent(in) :: data_3d_array
-real(r8), dimension(:), intent(inout) :: x
-integer, intent(in) :: ivar
-
integer :: idim1,idim2,idim3,ii
if ( .not. module_initialized ) call static_init_model
@@ -1187,18 +1251,21 @@
end subroutine prog_var_3d_to_vector
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Pack the values from a 4D array into the 1D DART array
+!>
+!> @param data_4d_array the array containing the ROMS variable
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
+!>
-
subroutine prog_var_4d_to_vector(data_4d_array, x, ivar)
-! convert the values from a 2d array into a 1d array
-! starting at an offset.
+real(r8), intent(in) :: data_4d_array(:,:,:,:)
+real(r8), intent(inout) :: x(:)
+integer, intent(in) :: ivar
-real(r8), dimension(:,:,:,:), intent(in) :: data_4d_array
-real(r8), dimension(:), intent(inout) :: x
-integer, intent(in) :: ivar
-
integer :: idim1,idim2,idim3,idim4,ii
if ( .not. module_initialized ) call static_init_model
@@ -1226,18 +1293,22 @@
end subroutine prog_var_4d_to_vector
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Extract the values from the 1D DART array into a 1D array
+!>
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
+!> @param data_1d_array the array containing the ROMS variable
+!>
subroutine vector_to_1d_prog_var(x, ivar, data_1d_array)
-! convert the values from a 1d array, starting at an offset,
-! into a 1d array.
+real(r8), intent(in) :: x(:)
+integer, intent(in) :: ivar
+real(r8), intent(out) :: data_1d_array(:)
-real(r8), dimension(:), intent(in) :: x
-integer, intent(in) :: ivar
-real(r8), dimension(:), intent(out) :: data_1d_array
-
integer :: idim1,ii
if ( .not. module_initialized ) call static_init_model
@@ -1260,17 +1331,21 @@
end subroutine vector_to_1d_prog_var
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Extract the values from the 1D DART array into a 2D array
+!>
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
+!> @param data_2d_array the array containing the ROMS variable
+!>
subroutine vector_to_2d_prog_var(x, ivar, data_2d_array)
-! convert the values from a 1d array, starting at an offset,
-! into a 2d array.
+real(r8), intent(in) :: x(:)
+integer, intent(in) :: ivar
+real(r8), intent(out) :: data_2d_array(:,:)
-real(r8), dimension(:), intent(in) :: x
-integer, intent(in) :: ivar
-real(r8), dimension(:,:), intent(out) :: data_2d_array
-
integer :: idim1,idim2,ii
if ( .not. module_initialized ) call static_init_model
@@ -1295,17 +1370,21 @@
end subroutine vector_to_2d_prog_var
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Extract the values from the 1D DART array into a 3D array
+!>
+!> @param x the array containing the DART state
+!> @param ivar handle to the DART structure relating what variable is where.
+!> @param data_3d_array the array containing the ROMS variable
+!>
subroutine vector_to_3d_prog_var(x, ivar, data_3d_array)
-! convert the values from a 1d array, starting at an offset,
-! into a 3d array.
+real(r8), intent(in) :: x(:)
+integer, intent(in) :: ivar
+real(r8), intent(out) :: data_3d_array(:,:,:)
-real(r8), dimension(:), intent(in) :: x
-integer, intent(in) :: ivar
-real(r8), dimension(:,:,:), intent(out) :: data_3d_array
-
integer :: idim1,idim2,idim3,ii
if ( .not. module_initialized ) call static_init_model
@@ -1332,13 +1411,18 @@
end subroutine vector_to_3d_prog_var
-!------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> given a DART KIND string,
+!> return the first and last index into the DART array of that KIND.
+!>
+!> @param string the variable name
+!> @param index1 first index into the DART state
+!> @param indexN last index into the DART state
+!>
subroutine get_index_range_string(string,index1,indexN)
-! Determine where a particular DART kind (string) exists in the
-! DART state vector.
-
character(len=*), intent(in) :: string
integer, intent(out) :: index1
integer, optional, intent(out) :: indexN
@@ -1359,16 +1443,22 @@
write(string1,*) 'Problem, cannot find indices for '//trim(string)
call error_handler(E_ERR,'get_index_range_string:',string1,source,revision,revdate)
endif
+
end subroutine get_index_range_string
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> given a DART KIND integer,
+!> return the first and last index into the DART array of that KIND.
+!>
+!> @param dartkind the integer describing the DART KIND
+!> @param index1 first index into the DART state
+!> @param indexN last index into the DART state
+!>
subroutine get_index_range_int(dartkind,index1,indexN)
-! Determine where a particular DART kind (integer) exists in the
-! DART state vector.
-
integer, intent(in) :: dartkind
integer, intent(out) :: index1
integer, optional, intent(out) :: indexN
@@ -1396,13 +1486,28 @@
end subroutine get_index_range_int
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Find the 'ocean_time' dimension in a ROMS netCDF file.
+!> If there is none - it is a fatal error.
+!> If the optional argument is present, the time of the last timestep
+!> is also returned.
+!>
+!> @param TimeDimID the netCDF dimension ID for 'ocean_time'
+!> @param ncid the netCDF handle to the ROMS netCDF file.
+!> @param filename the name of the ROMS netCDF file
+!> (used to generate useful error messages).
+!> @param last_time the time/date of the last timestep in the file.
+!>
+!> @todo FIXME Make sure the calculation is correct.
+!> The metadata claims to have a julian calendar, the 64bit real
+!> can support whole numbers that overflow a 32 bit integer. The
+!> only test file I have is for year 223 or something like that.
+!> DART normally uses a Gregorian calendar since our observations
+!> use that same calendar.
-function FindTimeDimension(ncid, filename, last_time) result(TimeDimId)
+function find_time_dimension(ncid, filename, last_time) result(TimeDimId)
-! Find the 'ocean_time' Dimension in a netCDF file.
-! If there is none - it is a fatal error.
-
integer :: TimeDimId
integer, intent(in) :: ncid
character(len=*), intent(in) :: filename
@@ -1420,7 +1525,7 @@
integer :: some_seconds, some_days
call nc_check(nf90_inq_dimid(ncid,'ocean_time',dimid=TimeDimId), &
- 'FindTimeDimension','cannot find "ocean_time" dimension in '//trim(filename))
+ 'find_time_dimension','cannot find "ocean_time" dimension in '//trim(filename))
! If you want the last time from the 'ocean_time' variable,
! you have to decode it a bit from the netCDF file metadata.
@@ -1428,15 +1533,15 @@
if (present(last_time)) then
call nc_check(nf90_inquire_dimension(ncid, TimeDimID, len=dimlen), &
- 'FindTimeDimension', 'inquire_dimension ocean_time'//trim(filename))
+ 'find_time_dimension', 'inquire_dimension ocean_time'//trim(filename))
call nc_check(nf90_inq_varid(ncid, 'ocean_time', VarID), &
- 'FindTimeDimension', 'inq_varid ocean_time from '//trim(filename))
+ 'find_time_dimension', 'inq_varid ocean_time from '//trim(filename))
allocate(ocean_time(dimlen))
call nc_check(nf90_get_var( ncid, VarID, ocean_time), &
- 'FindTimeDimension', 'get_var ocean_time from '//trim(filename))
+ 'find_time_dimension', 'get_var ocean_time from '//trim(filename))
! Make sure the calendar is expected form
! ocean-time:calendar = "julian" ;
@@ -1444,14 +1549,14 @@
! 1234567890123
call nc_check(nf90_get_att(ncid, VarID, 'units', unitstring), &
- 'FindTimeDimension', 'get_att ocean_time units '//trim(filename))
+ 'find_time_dimension', 'get_att ocean_time units '//trim(filename))
call nc_check(nf90_get_att(ncid, VarID, 'calendar', calendarstring), &
- 'FindTimeDimension', 'get_att ocean_time units '//trim(filename))
+ 'find_time_dimension', 'get_att ocean_time units '//trim(filename))
if (trim(calendarstring) /= 'julian') then
write(string1,*)'expecting ocean_time calendar of "julian"'
write(string2,*)'got '//trim(calendarstring)
- call error_handler(E_ERR,'FindTimeDimension:', string1, &
+ call error_handler(E_ERR,'find_time_dimension:', string1, &
source, revision, revdate, text2=string2, text3=string3)
endif
@@ -1461,7 +1566,7 @@
write(string1,*)'expecting ocean_time units of "seconds since ..."'
write(string2,*)'got '//trim(unitstring)
write(string3,*)'Cannot proceed. Stopping.'
- call error_handler(E_ERR,'FindTimeDimension:', string1, &
+ call error_handler(E_ERR,'find_time_dimension:', string1, &
source, revision, revdate, text2=string2, text3=string3)
endif
@@ -1470,7 +1575,7 @@
write(string1,*)'Unable to read ocean_time units. Error status was ',ios
write(string2,*)'expected "seconds since YYYY-MM-DD HH:MM:SS"'
write(string3,*)'was "'//trim(unitstring)//'"'
- call error_handler(E_ERR, 'FindTimeDimension:', string1, &
+ call error_handler(E_ERR, 'find_time_dimension:', string1, &
source, revision, revdate, text2=string2, text3=string3)
endif
@@ -1491,28 +1596,28 @@
! DART is interpreting this as the number of days of the 'origin'
call nc_check(nf90_inq_varid(ncid, 'dstart', VarID), &
- 'FindTimeDimension', 'inq_varid dstart from '//trim(filename))
+ 'find_time_dimension', 'inq_varid dstart from '//trim(filename))
call nc_check(nf90_get_var( ncid, VarID, dstart), &
- 'FindTimeDimension', 'get_var dstart from '//trim(filename))
+ 'find_time_dimension', 'get_var dstart from '//trim(filename))
call nc_check(nf90_get_att(ncid, VarID, 'units', unitstring), &
- 'FindTimeDimension', 'get_att dstart units '//trim(filename))
+ 'find_time_dimension', 'get_att dstart units '//trim(filename))
call nc_check(nf90_get_att(ncid, VarID, 'calendar', calendarstring), &
- 'FindTimeDimension', 'get_att dstart units '//trim(filename))
+ 'find_time_dimension', 'get_att dstart units '//trim(filename))
if (unitstring(1:10) /= 'days since') then
write(string1,*)'expecting dstart units of "days since ..."'
write(string2,*)'got '//trim(unitstring)
write(string3,*)'Cannot proceed. Stopping.'
- call error_handler(E_ERR,'FindTimeDimension:', string1, &
+ call error_handler(E_ERR,'find_time_dimension:', string1, &
source, revision, revdate, text2=string2, text3=string3)
endif
if (trim(calendarstring) /= 'julian') then
write(string1,*)'expecting dstart calendar of "julian"'
write(string2,*)'got '//trim(calendarstring)
- call error_handler(E_ERR,'FindTimeDimension:', string1, &
+ call error_handler(E_ERR,'find_time_dimension:', string1, &
source, revision, revdate, text2=string2, text3=string3)
endif
@@ -1521,7 +1626,7 @@
write(string1,*)'Unable to read dtime units. Error status was ',ios
write(string2,*)'expected "days since YYYY-MM-DD HH:MM:SS"'
write(string3,*)'was "'//trim(unitstring)//'"'
- call error_handler(E_ERR, 'FindTimeDimension:', string1, &
+ call error_handler(E_ERR, 'find_time_dimension:', string1, &
source, revision, revdate, text2=string2, text3=string3)
endif
@@ -1546,25 +1651,35 @@
deallocate(ocean_time)
endif
-end function FindTimeDimension
+end function find_time_dimension
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> Writes the (posterior) DART state into a ROMS netCDF analysis file.
+!> Just to be clear: only the ROMS variables that are part of the DART
+!> state are overwritten.
+!>
+!> @param state_vector the DART posterior state.
+!> @param filename the ROMS netCDF analysis file.
+!> @param statetime the DART time of the posterior.
+!>
+!> @todo FIXME ... use 'statetime' to find the proper time slot in the
+!> restart file. At present, we just stuff it into the last slot,
+!> regardless.
+!>
subroutine sv_to_restart_file(state_vector, filename, statetime)
-! Writes the current time and state variables from a dart state
-! vector (1d array) into a ROMS netcdf analysis file.
-
real(r8), intent(in) :: state_vector(:)
character(len=*), intent(in) :: filename
type(time_type), intent(in) :: statetime
! temp space to hold data while we are writing it
integer :: i, ivar
-real(r8), allocatable, dimension(:) :: data_1d_array
-real(r8), allocatable, dimension(:,:) :: data_2d_array
-real(r8), allocatable, dimension(:,:,:) :: data_3d_array
+real(r8), allocatable, dimension(:) :: data_1d_array
+real(r8), allocatable, dimension(:,:) :: data_2d_array
+real(r8), allocatable, dimension(:,:,:) :: data_3d_array
integer, dimension(NF90_MAX_VAR_DIMS) :: dimIDs, mystart, mycount
character(len=NF90_MAX_NAME) :: varname
@@ -1594,11 +1709,8 @@
! IF the netCDF variable has a TIME dimension, it must be the last dimension,
! and we need to read the LAST timestep and effectively squeeze out the
! singleton dimension when we stuff it into the DART state vector.
-! FIXME ... it is also a good idea to make sure that the state time
-! matches the time in the restart file
-!>@TODO use 'statetime' to find proper slot for the write.
-TimeDimID = FindTimeDimension( ncFileID, filename )
+TimeDimID = find_time_dimension( ncFileID, filename )
if ( TimeDimID > 0 ) then
call nc_check(nf90_inquire_dimension(ncFileID, TimeDimID, len=TimeDimLength), &
@@ -1724,21 +1836,36 @@
end subroutine sv_to_restart_file
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> for a given directive and range, do the data clamping for the given
+!> input array. only one of the optional array args should be specified - the
+!> one which matches the given dimsize. this still has replicated sections for
+!> each possible dimensionality (which so far is only 1 to 3 - add 4-7 only
+!> if needed) but at least it is isolated to this subroutine.
+!>
+!> @param out_of_range_fail switch to prescribe action. if TRUE and the data
+!> value is outside the expected range, issue a FATAL
+!> error. if FALSE, set the offending value to the
+!> appropriate max or min described by the 'range' variable.
+!> @param range the expected min and max describing the allowable range.
+!> @param dimsize the rank of the variable to be clamped.
+!> @param varname the name of the variable to be clamped.
+!> @param array_1d if dimsize == 1, this contains the data to be clamped.
+!> @param array_2d if dimsize == 1, this contains the data to be clamped.
+!> @param array_3d if dimsize == 3, this contains the data to be clamped.
+!>
-subroutine do_clamping(out_of_range_fail, range, dimsize, varname, array_1d, array_2d, array_3d)
- logical, intent(in) :: out_of_range_fail
- real(r8), intent(in) :: range(2)
- integer, intent(in) :: dimsize
- character(len=NF90_MAX_NAME), intent(in) :: varname
- real(r8),optional,intent(inout) :: array_1d(:), array_2d(:,:), array_3d(:,:,:)
+subroutine do_clamping(out_of_range_fail, range, dimsize, varname, &
+ array_1d, array_2d, array_3d)
+logical, intent(in) :: out_of_range_fail
+real(r8), intent(in) :: range(2)
+integer, intent(in) :: dimsize
+character(len=NF90_MAX_NAME), intent(in) :: varname
+real(r8), optional, intent(inout) :: array_1d(:)
+real(r8), optional, intent(inout) :: array_2d(:,:)
+real(r8), optional, intent(inout) :: array_3d(:,:,:)
-! for a given directive and range, do the data clamping for the given
-! input array. only one of the optional array args should be specified - the
-! one which matches the given dimsize. this still has replicated sections for
-! each possible dimensionality (which so far is only 1 to 3 - add 4-7 only
-! if needed) but at least it is isolated to this subroutine.
-
! these sections should all be identical except for the array_XX specified.
! if anyone can figure out a way to defeat fortran's strong typing for arrays
! so we don't have to replicate each of these sections, i'll buy you a cookie.
@@ -1888,13 +2015,22 @@
end subroutine do_clamping
-!------------------------------------------------------------------
+!-----------------------------------------------------------------------
+!>
+!> writes the time of the current state and (optionally) the time
+!> to be conveyed to ROMS to dictate the length of the forecast.
+!> This file is then used by scripts to modify the ROMS run.
+!> The format in the time information is totally at your discretion.
+!>
+!> @param time_filename name of the file (name is set by dart_to_roms_nml:time_filename)
+!> @param model_time the current time of the model state
+!> @param adv_to_time the time in the future of the next assimilation.
+!>
-
subroutine write_model_time(time_filename, model_time, adv_to_time)
- character(len=*), intent(in) :: time_filename
- type(time_type), intent(in) :: model_time
- type(time_type), intent(in), optional :: adv_to_time
+character(len=*), intent(in) :: time_filename
+type(time_type), intent(in) :: model_time
+type(time_type), intent(in), optional :: adv_to_time
integer :: iunit
@@ Diff output truncated at 40000 characters. @@
More information about the Dart-dev
mailing list