Although several implementations of background error formulation and associated covariance matrix might be available for a given model, it is unlikely an inheritance structure between them will bring much benefit. The interface is described without inheritance but like for any of the Fortran entities, the inheritance structure is not visible from the abstract (non-Fortran) layer and can be used if it proves useful.
The background error can be nonlinear. The linearize method is responsible for generating the covariance matrix object associated to the current error.
type :: bkg_error contains procedure :: create ! Constructor procedure :: delete ! Destructor procedure :: linearize ! Generate covariance matrix procedure :: print ! Prints human readable info end type bkg_error subroutine create(self, config, geom, bg) class(bkg_error), intent(inout) :: self type(config), intent(in) :: config type(geometry), intent(in) :: geom type(fields), intent(in) :: bg ! Background state end subroutine create subroutine delete(self) class(bkg_error), intent(inout) :: self end subroutine delete function linearize(self, config, fg) class(b_error_covariance), pointer :: linearize class(bkg_error), intent(in) :: self type(config), intent(in) :: config type(fields), intent(in) :: fg ! First-guess state end function linearize subroutine print(self) class(bkg_error), intent(in) :: self end subroutine print |
Once the Observation Errors have been defined, the Observation Error Covariance matrix is easier to define.
type :: b_error_covariance contains procedure :: create ! Constructor procedure :: delete ! Destructor procedure :: multiply ! Multiply by B procedure :: inv_mult ! Multiply by B^{-1} procedure :: randomize ! Returns random vector scaled by B procedure :: print ! Prints human readable info end type b_error_covariance subroutine create(self, geom, config) type(b_error_covariance), intent(inout) :: self type(geometry), intent(in) :: geom type(config), intent(in) :: config end subroutine create subroutine delete(self) type(b_error_covariance), intent(inout) :: self end subroutine delete subroutine multiply(self, dx, dz) type(b_error_covariance), intent(in) :: self type(fields), intent(in) :: dx ! input values type(fields), intent(inout) :: dz ! output values, dz = B * dx end subroutine multiply subroutine inv_mult(self, dx, dz) type(b_error_covariance), intent(in) :: self type(fields), intent(in) :: dx ! input values type(fields), intent(inout) :: dz ! output values, dz = B^{-1} * dx end subroutine inv_mult subroutine random(self, dx) type(b_error_covariance), intent(in) :: self type(fields), intent(inout) :: dx ! scaled random output values end subroutine random subroutine print(self) type(b_error_covariance), intent(in) :: self end subroutine print |
The same interface can also be used to represent any model space error covariance, in particular the model error covariance matrix.
The abstract base class at the Fortran level is not in principle needed by a system like JEDI which relies on its own mechanism for handling observation types. However, it is convenient for two reasons: it defines an interface that guaranties compatibility for higher level code and it avoids duplication of common code between types.
In principle, the same observation error covariance matrix can be used for several observation types. For example, a diagonal R can be written once and used several times. For that reason, the inheritance structure for R is distinct from that of the observation operators. Handling of observations errors is split in two classes, one for QC and other nonlinear functions, one for the observation error covariance matrix itself.
type, abstract :: obs_error contains procedure(obserr_create), deferred :: create ! Constructor procedure(obserr_delete), deferred :: delete ! Destructor procedure(obserr_qc), deferred :: quality_control ! Apply QC procedure(obserr_covar), deferred :: linearize ! Generate covariance matrix procedure(obserr_print), deferred :: print ! Prints human readable info end type obs_error abstract interface subroutine obserr_create(self, config, obsdb, yobs) class(obs_error), intent(inout) :: self type(config), intent(in) :: config type(obs_space), intent(in) :: obsdb type(obs_data), intent(in) :: yobs ! Observation values end subroutine obserr_create end interface abstract interface subroutine obserr_delete(self) class(obs_error), intent(inout) :: self end subroutine obserr_delete end interface abstract interface subroutine obserr_qc(self, ???, ???) ! What does QC need? class(obs_error), intent(in) :: self end subroutine obserr_qc end interface abstract interface function obserr_linearize(self, config) class(obs_error_covariance), pointer :: obserr_linearize class(obs_error), intent(in) :: self type(config), intent(in) :: config type(obs_data), intent(in) :: yobs ! Equivalent obs values at first guess end function obserr_linearize end interface abstract interface subroutine obserr_print(self) class(obs_error), intent(in) :: self end subroutine obserr_print end interface |
The interface to the quality control method still needs to be defined. What inputs are needed?
Once the Observation Errors have been defined, the Observation Error Covariance matrix is easier to define.
Note: the observation error covariance matrix interfaces exactly correspond to the background error covariance matrix interfaces where the geometry has been replaced by the obs_space and the fields by obs_vectors.
type :: obs_error_covariance contains procedure :: create ! Constructor procedure :: delete ! Destructor procedure :: multiply ! Multiply by R procedure :: inv_mult ! Multiply by R^{-1} procedure :: randomize ! Returns random vector scaled by R procedure :: print ! Prints human readable info end type obs_error_covariance subroutine create(self, obsdb, config) type(obs_error_covariance), intent(inout) :: self type(obs_space), intent(in) :: obsdb type(config), intent(in) :: config end subroutine create subroutine delete(self) type(obs_error_covariance), intent(inout) :: self end subroutine delete subroutine multiply(self, dy, dz) type(obs_error_covariance), intent(in) :: self type(obs_vector), intent(in) :: dy ! input values type(obs_vector), intent(inout) :: dz ! output values, dz = R * dy end subroutine multiply subroutine inv_mult(self, dy, dz) type(obs_error_covariance), intent(in) :: self type(obs_vector), intent(in) :: dy ! input values type(obs_vector), intent(inout) :: dz ! output values, dz = R^{-1} * dy end subroutine inv_mult subroutine random(self, dy) type(obs_error_covariance), intent(in) :: self type(obs_vector), intent(inout) :: dy ! scaled random output values end subroutine random subroutine print(self) type(obs_error_covariance), intent(in) :: self end subroutine print |