Skip to content

Commit

Permalink
Merge pull request #376 from Benjamin-Gunn/new-model-automation
Browse files Browse the repository at this point in the history
New model automation
  • Loading branch information
hkershaw-brown authored Aug 19, 2022
2 parents ef5d959 + 6b93c14 commit 477409d
Show file tree
Hide file tree
Showing 13 changed files with 988 additions and 229 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ individual files.

The changes are now listed with the most recent at the top.

**August 19 2022 :: Automated setup of new model interfaces. Tag: v10.3.0**

- Automated initial setup of new model interfaces to aid users developing
model_mod code and documentation.

*contributed by Benjamin Gunn*

**August 18 2022 :: Bug-fixes for obs_utilities build and mpas_atm. Tag: v10.2.1**

- obs_utilities_mod no longer included by default for model/work builds because
Expand Down
36 changes: 35 additions & 1 deletion assimilation_code/location/threed/location_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module location_mod
set_location_missing, is_location_in_region, get_maxdist, &
write_location, read_location, interactive_location, query_location, &
LocationDims, LocationName, LocationLName, LocationStorageOrder, LocationUnits, &
get_close_type, get_close_init, get_close, get_close_destroy, &
get_close_type, get_close_init, get_close_obs, get_close_state, get_close_destroy, &
operator(==), operator(/=), get_dist, has_vertical_choice, vertical_localization_on, &
set_vertical, is_vertical, get_vertical_localization_coord, &
set_vertical_localization_coord, convert_vertical_obs, convert_vertical_state
Expand Down Expand Up @@ -450,6 +450,40 @@ end subroutine get_close_destroy

!----------------------------------------------------------------------------

subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, &
num_close, close_ind, dist, ens_handle)

type(get_close_type), intent(in) :: gc
type(location_type), intent(in) :: base_loc, locs(:)
integer, intent(in) :: base_type, loc_qtys(:)
integer(i8), intent(in) :: loc_indx(:)
integer, intent(out) :: num_close, close_ind(:)
real(r8), optional, intent(out) :: dist(:)
type(ensemble_type), optional, intent(in) :: ens_handle

call get_close(gc, base_loc, base_type, locs, loc_qtys, &
num_close, close_ind, dist, ens_handle)

end subroutine get_close_state

!----------------------------------------------------------------------------
subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, &
num_close, close_ind, dist, ens_handle)

type(get_close_type), intent(in) :: gc
type(location_type), intent(in) :: base_loc, locs(:)
integer, intent(in) :: base_type, loc_qtys(:), loc_types(:)
integer, intent(out) :: num_close, close_ind(:)
real(r8), optional, intent(out) :: dist(:)
type(ensemble_type), optional, intent(in) :: ens_handle

call get_close(gc, base_loc, base_type, locs, loc_qtys, &
num_close, close_ind, dist, ens_handle)

end subroutine get_close_obs


!----------------------------------------------------------------------------
subroutine get_close(gc, base_loc, base_type, locs, loc_qtys, &
num_close, close_ind, dist, ensemble_handle)

Expand Down
182 changes: 114 additions & 68 deletions assimilation_code/location/twod/location_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,28 @@ module location_mod
! The internal representation of the location is currently implemented
! as (x, y) from 0.0 to 1.0 in both dimensions.

use types_mod, only : r8, MISSING_R8
use types_mod, only : r8, MISSING_R8, i8
use utilities_mod, only : error_handler, E_ERR, ascii_file_format
use random_seq_mod, only : random_seq_type, init_random_seq, random_uniform
use default_location_mod, only : has_vertical_choice, vertical_localization_on, &
get_vertical_localization_coord, &
set_vertical_localization_coord
use ensemble_manager_mod, only : ensemble_type

implicit none
private

public :: location_type, get_location, set_location, &
set_location_missing, is_location_in_region, get_maxdist, &
write_location, read_location, interactive_location, query_location, &
LocationDims, LocationName, LocationLName, get_close_obs, &
get_close_maxdist_init, get_close_obs_init, get_close_type, &
operator(==), operator(/=), get_dist, get_close_obs_destroy, &
vert_is_height, vert_is_pressure, vert_is_undef, vert_is_level, &
vert_is_surface, has_vertical_localization, &
set_vert, get_vert, set_which_vert
LocationDims, LocationName, LocationLName, LocationStorageOrder, LocationUnits, &
get_close_obs, get_close_maxdist_init, get_close_init, get_close_type, &
operator(==), operator(/=), get_dist, get_close_destroy, &
is_vertical, set_vertical, vertical_localization_on, &
set_vert, get_vert, set_which_vert, has_vertical_choice, &
get_close_state, &
convert_vertical_obs, convert_vertical_state, get_vertical_localization_coord, &
set_vertical_localization_coord

character(len=*), parameter :: source = 'twod/location_mod.f90'

Expand All @@ -46,6 +52,8 @@ module location_mod
integer, parameter :: LocationDims = 2
character(len = 129), parameter :: LocationName = "loc2D"
character(len = 129), parameter :: LocationLName = "twod cyclic locations: x, y"
character(len = 129), parameter :: LocationStorageOrder = "x, y"
character(len = 129), parameter :: LocationUnits = " "

character(len = 129) :: errstring

Expand Down Expand Up @@ -412,27 +420,36 @@ subroutine interactive_location(location, set_to_default)
end subroutine interactive_location

!----------------------------------------------------------------------------
! Initializes get_close accelerator - unused in this location module

subroutine get_close_obs_init(gc, num, obs)

! Initializes part of get_close accelerator that depends on the particular obs
subroutine get_close_init(gc, num, maxdist, locs, maxdist_list)

type(get_close_type), intent(inout) :: gc
integer, intent(in) :: num
type(location_type), intent(in) :: obs(num)
real(r8), intent(in) :: maxdist
type(location_type), intent(in) :: locs(:)
real(r8), intent(in), optional :: maxdist_list(:)

! Set the maximum localization distance
gc%maxdist = maxdist

! Set the value of num_obs in the structure
! Save the value of num_locs
gc%num = num

end subroutine get_close_obs_init
if (present(maxdist_list)) then
write(errstring,*)'twod locations does not support different cutoff distances by type'
call error_handler(E_ERR, 'get_close_init', errstring, source)
endif

end subroutine get_close_init

!----------------------------------------------------------------------------

subroutine get_close_obs_destroy(gc)
subroutine get_close_destroy(gc)

type(get_close_type), intent(inout) :: gc

end subroutine get_close_obs_destroy
end subroutine get_close_destroy

!----------------------------------------------------------------------------

Expand All @@ -448,8 +465,7 @@ subroutine get_close_maxdist_init(gc, maxdist, maxdist_list)
end subroutine get_close_maxdist_init

!----------------------------------------------------------------------------

subroutine get_close_obs(gc, base_obs_loc, base_obs_type, obs, obs_kind, &
subroutine get_close(gc, base_obs_loc, base_obs_type, obs, obs_kind, &
num_close, close_ind, dist)

! Default version with no smarts; no need to be smart in 1D
Expand Down Expand Up @@ -485,8 +501,43 @@ subroutine get_close_obs(gc, base_obs_loc, base_obs_type, obs, obs_kind, &
endif
end do

end subroutine get_close

!---------------------------------------------------------------------------
subroutine get_close_obs(gc, base_loc, base_type, locs, loc_qtys, loc_types, &
num_close, close_ind, dist, ens_handle)


type(get_close_type), intent(in) :: gc
type(location_type), intent(in) :: base_loc, locs(:)
integer, intent(in) :: base_type, loc_qtys(:), loc_types(:)
integer, intent(out) :: num_close, close_ind(:)
real(r8), optional, intent(out) :: dist(:)
type(ensemble_type), optional, intent(in) :: ens_handle

call get_close(gc, base_loc, base_type, locs, loc_qtys, &
num_close, close_ind, dist)

end subroutine get_close_obs

!---------------------------------------------------------------------------
subroutine get_close_state(gc, base_loc, base_type, locs, loc_qtys, loc_indx, &
num_close, close_ind, dist, ens_handle)


type(get_close_type), intent(in) :: gc
type(location_type), intent(in) :: base_loc, locs(:)
integer, intent(in) :: base_type, loc_qtys(:)
integer(i8), intent(in) :: loc_indx(:)
integer, intent(out) :: num_close, close_ind(:)
real(r8), optional, intent(out) :: dist(:)
type(ensemble_type), optional, intent(in) :: ens_handle

call get_close(gc, base_loc, base_type, locs, loc_qtys, &
num_close, close_ind, dist)

end subroutine get_close_state

!---------------------------------------------------------------------------

function get_maxdist(gc, obs_type)
Expand Down Expand Up @@ -528,70 +579,32 @@ end function is_location_in_region
! common code that sometimes needs vertical info.
!----------------------------------------------------------------------------

function vert_is_undef(loc)

! Stub, always returns false.

logical :: vert_is_undef
type(location_type), intent(in) :: loc

vert_is_undef = .false.

end function vert_is_undef

!----------------------------------------------------------------------------

function vert_is_surface(loc)

! Stub, always returns false.

logical :: vert_is_surface
type(location_type), intent(in) :: loc

vert_is_surface = .false.

end function vert_is_surface

! stubs - here only because they have a location type as one of the arguments
!----------------------------------------------------------------------------

function vert_is_pressure(loc)

! Stub, always returns false.
function is_vertical(loc, which_vert)

logical :: vert_is_pressure
logical :: is_vertical
type(location_type), intent(in) :: loc
character(len=*), intent(in) :: which_vert

vert_is_pressure = .false.

end function vert_is_pressure
is_vertical = .false.

!----------------------------------------------------------------------------

function vert_is_height(loc)

! Stub, always returns false.
end function is_vertical

logical :: vert_is_height
type(location_type), intent(in) :: loc

vert_is_height = .false.

end function vert_is_height

!----------------------------------------------------------------------------
!--------------------------------------------------------------------

function vert_is_level(loc)

! Stub, always returns false.
subroutine set_vertical(loc, vloc, which_vert)

logical :: vert_is_level
type(location_type), intent(in) :: loc
type(location_type), intent(inout) :: loc
real(r8), optional, intent(in) :: vloc
integer, optional, intent(in) :: which_vert

vert_is_level = .false.

end function vert_is_level
end subroutine set_vertical

!---------------------------------------------------------------------------
!--------------------------------------------------------------------

function has_vertical_localization()

Expand Down Expand Up @@ -637,6 +650,39 @@ subroutine set_which_vert(loc, which_vert)

end subroutine set_which_vert

!--------------------------------------------------------------------

subroutine convert_vertical_obs(ens_handle, num, locs, loc_qtys, loc_types, &
which_vert, status)

type(ensemble_type), intent(in) :: ens_handle
integer, intent(in) :: num
type(location_type), intent(inout) :: locs(:)
integer, intent(in) :: loc_qtys(:), loc_types(:)
integer, intent(in) :: which_vert
integer, intent(out) :: status(:)

status(:) = 0

end subroutine convert_vertical_obs

!--------------------------------------------------------------------

subroutine convert_vertical_state(ens_handle, num, locs, loc_qtys, loc_indx, &
which_vert, istatus)

type(ensemble_type), intent(in) :: ens_handle
integer, intent(in) :: num
type(location_type), intent(inout) :: locs(:)
integer, intent(in) :: loc_qtys(:)
integer(i8), intent(in) :: loc_indx(:)
integer, intent(in) :: which_vert
integer, intent(out) :: istatus

istatus = 0

end subroutine convert_vertical_state

!----------------------------------------------------------------------------
! end of location/twod/location_mod.f90
!----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
author = 'Data Assimilation Research Section'

# The full version, including alpha/beta/rc tags
release = '10.2.1'
release = '10.3.0'
master_doc = 'README'

# -- General configuration ---------------------------------------------------
Expand Down
47 changes: 40 additions & 7 deletions guide/advice-for-new-collaborators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ DART is often used for the following types of projects:

- Learning about Data Assimilation (DA)
- Using DART with an existing model and supported observations
- **Adding a DART interface to a new model**
- `Adding a DART interface to a new model`_
- Using new observations with DART in an existing model
- Using both a new model and new observations with DART
- Using DART to teach DA
Expand Down Expand Up @@ -312,10 +312,43 @@ of the state variables then doing it on demand is more efficient.
The options here are namelist selectable at runtime and the impact
on total runtime can be easily measured and compared.

Reuse code when possible
------------------------
Adding a DART interface to a new model
--------------------------------------

The ``models/template`` directory has files that can be used to start
porting code to support a new model, but we also recommend looking at
the existing supported models and reusing code from them if possible.
Models with similar grid types or vertical coordiates are good candidates.
DART provides a script ``new_model.sh`` which will create the necessary files
for a new model interface.
Enter ``./new_model.sh``, then the desired model name and location module separated
by spaces. This will create the necessary files to get started.

For example to create a model interface for a model called BOUMME which uses
the 3D sphere location module:

.. code-block:: text
cd models
./new_model.sh BOUMME threed_sphere
This will create an BOUMME model directory with the following files:

.. code-block:: text
BOUMME/
├── model_mod.f90
├── readme.rst
└── work
├── input.nml
└── quickbuild.sh
- ``model_mod.f90`` is where to add the :doc:`required model_mod routines<required-model-mod-routines>`.
- ``readme.rst`` is a stub to add documenation for your model interface.
- ``quickbuild.sh`` is used to compile DART for your model.


Templates are chosen based on location module input. The currently supported
location templates are for 3D and 1D modules, with the possibility for more
in the future. At the moment, ``threed_sphere``, ``threed_cartesian``, and
``oned`` will produce model_mod.f90 code that compile will sucessfully with ``./quickbuild.sh``.

We recommend looking at the existing supported models and reusing code from them if
possible. Models with similar grid types or vertical coordinates are good
candidates.
Loading

0 comments on commit 477409d

Please sign in to comment.