!----------------------------------------------------------------------
! NEMO system team, System and Interface for oceanic RElocable Nesting
!----------------------------------------------------------------------
!
! MODULE: iom_mpp
!
! DESCRIPTION:
!> @brief massively parallel processing Input/Output manager :
!> Library to read/write mpp files
!>
!> @details
!>
!> to open mpp files (only file to be used (see mpp_get_use)
!> will be open):
!> CALL iom_mpp_open(td_mpp)
!> - td_mpp is a mpp structure
!>
!> to creates mpp files:
!> CALL iom_mpp_create(td_mpp)
!> - td_mpp is a mpp structure
!>
!> to write in mpp files :
!> CALL iom_mpp_write_file(td_mpp)
!> - td_mpp is a mpp structure
!>
!> to close mpp files:
!> CALL iom_mpp_close(td_mpp)
!>
!> to read one variable in an mpp files:
!> - tl_var=iom_mpp_read_var( td_mpp, id_varid, [td_dom,] [ld_border] )
!> - tl_var=iom_mpp_read_var( td_mpp, [cd_name,] [td_dom,] [ld_border,] [cd_stdname] )
!> - td_mpp is a mpp structure
!> - id_varid is a variable id
!> - td_dom is a domain structure (optional, can't be used with ld_border)
!> - ld_border is true if we want to read border of global domain only
!> (optional, can't be used with td_dom)
!> - cd_name is variable name (optional, cd_name and/or cd_stdname should be specify.)
!> - cd_stdname is variable standard name (optional, cd_name and/or cd_stdname should be specify.)
!>
!>
!> @author
!> J.Paul
! REVISION HISTORY:
!> @date Nov, 2013 - Initial Version
!
!> @note Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
!> @todo
!> - add read var with start and count as in iom
!> - add iom_mpp_fill_var_value : cf iom_fill_var_value
!> - not so easy to use that it should be, have to work on it
!> - improve mpp init
!> - improve mpp_get_use
!> - imporve dom_init
!----------------------------------------------------------------------
MODULE iom_mpp
USE netcdf ! nf90 library
USE kind ! F90 kind parameter
USE fct ! basic useful function
USE logger ! log file manager
USE dim ! dimension manager
USE att ! attribute manager
USE var ! variable manager
USE file ! file manager
USE iom ! I/O manager
USE mpp ! mpp manager
USE dom ! domain manager
IMPLICIT NONE
PRIVATE
! NOTE_avoid_public_variables_if_possible
! function and subroutine
PUBLIC :: iom_mpp_open !< open files composing mpp structure to be used
PUBLIC :: iom_mpp_create !< creates files composing mpp structure to be used
PUBLIC :: iom_mpp_close !< close file composing mpp structure
PUBLIC :: iom_mpp_read_var !< read one variable in an mpp structure
PUBLIC :: iom_mpp_fill_var !< fill variable value in mpp structure
PUBLIC :: iom_mpp_write_file !< write mpp structure in files
PRIVATE :: iom_mpp__read_var_id !< read one variable in an mpp structure, given variable id
PRIVATE :: iom_mpp__read_var_name !< read one variable in an mpp structure, given variable name
PRIVATE :: iom_mpp__read_var_value !< read variable value in an mpp structure
PRIVATE :: iom_mpp__no_pole_no_overlap !< do not overlap north fold boundary or east-west boundary
PRIVATE :: iom_mpp__no_pole_cyclic !< do not overlap north fold boundary. However uses cyclic east-west boundary
PRIVATE :: iom_mpp__no_pole_overlap !< do not overlap north fold boundary. However overlaps east-west boundary
! PRIVATE :: iom_mpp__pole_no_overlap !< overlaps north fold boundary. However do not overlap east-west boundary
! PRIVATE :: iom_mpp__pole_cyclic !< overlaps north fold boundary and uses cyclic east-west boundary
! PRIVATE :: iom_mpp__pole_overlap !< overlaps north fold boundary and east-west boundary
INTERFACE iom_mpp_read_var !< read one variable in an mpp structure
MODULE PROCEDURE iom_mpp__read_var_id !< given variable id
MODULE PROCEDURE iom_mpp__read_var_name !< given variable name
END INTERFACE iom_mpp_read_var
INTERFACE iom_mpp_fill_var !< fill variable value in an mpp structure
MODULE PROCEDURE iom_mpp__fill_var_id !< given variable id
MODULE PROCEDURE iom_mpp__fill_var_name !< given variable name
MODULE PROCEDURE iom_mpp__fill_var_all !< fill all variable
END INTERFACE iom_mpp_fill_var
CONTAINS
!-------------------------------------------------------------------
!> @brief This subroutine open files composing mpp structure to be used
!> If try to open a file in write mode that did not exist, create it.
!>
!> If file already exist, get information about:
!> - the number of variables
!> - the number of dimensions
!> - the number of global attributes
!> - the ID of the unlimited dimension
!> - the file format
!> and finally read dimensions.
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_mpp : mpp structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp_open(td_mpp)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
! local variable
CHARACTER(LEN=lc) :: cl_name
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP OPEN: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
IF( ANY(td_mpp%t_proc(:)%l_use) )THEN
! add suffix to mpp name
td_mpp%c_name=file_add_suffix( TRIM(td_mpp%c_name), &
& TRIM(td_mpp%c_type) )
td_mpp%t_proc(:)%c_type=TRIM(td_mpp%c_type)
IF( td_mpp%i_nproc > 1 )THEN
DO ji=1,td_mpp%i_nproc
IF( td_mpp%t_proc(ji)%l_use )THEN
cl_name=TRIM( file_rename(td_mpp%c_name, ji) )
td_mpp%t_proc(ji)%c_name=TRIM(cl_name)
CALL iom_open(td_mpp%t_proc(ji))
ENDIF
ENDDO
ELSE ! td_mpp%i_nproc == 1
cl_name=TRIM( file_rename(td_mpp%c_name) )
td_mpp%t_proc(1)%c_name=TRIM(cl_name)
CALL iom_open(td_mpp%t_proc(1))
ENDIF
ELSE
IF( ANY(td_mpp%t_proc(:)%l_ctr) )THEN
CALL logger_warn("IOM MPP OPEN: open file on border")
DO ji=1,td_mpp%i_nproc
IF( td_mpp%t_proc(ji)%l_ctr )THEN
CALL iom_open(td_mpp%t_proc(ji))
ENDIF
ENDDO
ELSE
CALL logger_error( " IOM MPP OPEN: no processor to be used.")
CALL logger_debug( " use mpp_get_use before running iom_mpp_open")
ENDIF
ENDIF
ENDIF
END SUBROUTINE iom_mpp_open
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine create files, composing mpp structure to be used,
!> in write mode
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_mpp : mpp structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp_create(td_mpp)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP CREATE: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
! forced to open in write mode
td_mpp%t_proc(:)%l_wrt=.TRUE.
td_mpp%t_proc(:)%l_use=.TRUE.
CALL iom_mpp_open(td_mpp)
ENDIF
END SUBROUTINE iom_mpp_create
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine close files composing mpp structure.
!>
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp_close(td_mpp)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP CLOSE: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
DO ji=1,td_mpp%i_nproc
IF( td_mpp%t_proc(ji)%i_id /= 0 )THEN
CALL iom_close(td_mpp%t_proc(ji))
ENDIF
ENDDO
ENDIF
END SUBROUTINE iom_mpp_close
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read variable value in opened mpp files,
!> given variable id.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!>
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[in] id_varid : variable id
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!> @return variable structure
!-------------------------------------------------------------------
!> @code
TYPE(TVAR) FUNCTION iom_mpp__read_var_id(td_mpp, id_varid,&
& td_dom, ld_border)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(IN) :: td_mpp
INTEGER(i4), INTENT(IN) :: id_varid
TYPE(TDOM) , INTENT(IN), OPTIONAL :: td_dom
LOGICAL, INTENT(IN), OPTIONAL :: ld_border
! local variable
INTEGER(i4), DIMENSION(1) :: il_ind
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP READ VAR: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
IF( ANY(td_mpp%t_proc(:)%i_id /= 0) )THEN
! look for variable id
il_ind(:)=MINLOC( td_mpp%t_proc(1)%t_var(:)%i_id, &
& mask=(td_mpp%t_proc(1)%t_var(:)%i_id==id_varid))
IF( il_ind(1) /= 0 )THEN
iom_mpp__read_var_id=td_mpp%t_proc(1)%t_var(il_ind(1))
!!! read variable value
CALL iom_mpp__read_var_value(td_mpp, iom_mpp__read_var_id, &
& td_dom, ld_border)
ELSE
CALL logger_error( &
& " IOM MPP READ VAR: there is no variable with id "//&
& TRIM(fct_str(id_varid))//" in processor/file "//&
& TRIM(td_mpp%t_proc(1)%c_name))
ENDIF
ELSE
CALL logger_error(" IOM MPP READ VAR: can't read variable, mpp "//&
& TRIM(td_mpp%c_name)//" not opened")
ENDIF
ENDIF
END FUNCTION iom_mpp__read_var_id
!> @endcode
!-------------------------------------------------------------------
!> @brief This function read variable value in opened mpp files,
!> given variable name or standard name.
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @details
!> look first for variable name. If it doesn't
!> exist in file, look for variable standard name.
!> If variable name is not present, check variable standard name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[in] cd_name : variable name
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!> @return variable structure
!-------------------------------------------------------------------
!> @code
TYPE(TVAR) FUNCTION iom_mpp__read_var_name(td_mpp, cd_name, &
& td_dom, ld_border )
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(IN) :: td_mpp
CHARACTER(LEN=*), INTENT(IN) :: cd_name
TYPE(TDOM) , INTENT(IN), OPTIONAL :: td_dom
LOGICAL, INTENT(IN), OPTIONAL :: ld_border
! local variable
INTEGER(i4) :: il_varid
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP READ VAR: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
il_varid=var_get_id( td_mpp%t_proc(1)%t_var(:), cd_name)
IF( il_varid /= 0 )THEN
iom_mpp__read_var_name=td_mpp%t_proc(1)%t_var(il_varid)
!!! read variable value
CALL iom_mpp__read_var_value( td_mpp, &
& iom_mpp__read_var_name, &
& td_dom, ld_border)
ELSE
CALL logger_error( &
& " IOM MPP READ VAR: there is no variable with "//&
& "name or standard name"//TRIM(cd_name)//&
& " in processor/file "//TRIM(td_mpp%t_proc(1)%c_name))
ENDIF
ENDIF
END FUNCTION iom_mpp__read_var_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine fill all variable value in opened mpp files,
!> given variable id.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!>
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_mpp : mpp structure
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__fill_var_all(td_mpp, td_dom, ld_border)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
TYPE(TDOM) , INTENT(IN), OPTIONAL :: td_dom
LOGICAL, INTENT(IN), OPTIONAL :: ld_border
! local variable
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP FILL VAR : domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
DO ji=1,td_mpp%t_proc(1)%i_nvar
CALL iom_mpp_fill_var(td_mpp, ji, td_dom, ld_border )
ENDDO
ENDIF
END SUBROUTINE iom_mpp__fill_var_all
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine fill variable value in opened mpp files,
!> given variable id.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!>
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_mpp : mpp structure
!> @param[in] id_varid : variable id
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__fill_var_id(td_mpp, id_varid, td_dom, ld_border)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
INTEGER(i4), INTENT(IN) :: id_varid
TYPE(TDOM) , INTENT(IN), OPTIONAL :: td_dom
LOGICAL, INTENT(IN), OPTIONAL :: ld_border
! local variable
INTEGER(i4), DIMENSION(1) :: il_ind
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP FILL VAR: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
IF( ANY(td_mpp%t_proc(:)%i_id /= 0) )THEN
! look for variable id
il_ind(:)=MINLOC( td_mpp%t_proc(1)%t_var(:)%i_id, &
& mask=(td_mpp%t_proc(1)%t_var(:)%i_id==id_varid))
IF( il_ind(1) /= 0 )THEN
!!! read variable value
CALL iom_mpp__read_var_value( td_mpp, &
& td_mpp%t_proc(1)%t_var(il_ind(1)), &
& td_dom, ld_border)
ELSE
CALL logger_error( &
& " IOM MPP FILL VAR : there is no variable with id "//&
& TRIM(fct_str(id_varid))//" in processor/file "//&
& TRIM(td_mpp%t_proc(1)%c_name))
ENDIF
ELSE
CALL logger_error(" IOM MPP FILL VAR : can't read variable, mpp "//&
& TRIM(td_mpp%c_name)//" not opened")
ENDIF
ENDIF
END SUBROUTINE iom_mpp__fill_var_id
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine fill variable value in opened mpp files,
!> given variable name or standard name.
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @details
!> look first for variable name. If it doesn't
!> exist in file, look for variable standard name.
!> If variable name is not present, check variable standard name.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[inout] td_mpp : mpp structure
!> @param[in] cd_name : variable name or standard name
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__fill_var_name(td_mpp, cd_name, td_dom, ld_border )
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
CHARACTER(LEN=*), INTENT(IN ) :: cd_name
TYPE(TDOM) , INTENT(IN ), OPTIONAL :: td_dom
LOGICAL, INTENT(IN ), OPTIONAL :: ld_border
! local variable
INTEGER(i4) :: il_ind
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " IOM MPP FILL VAR : domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
il_ind=var_get_id( td_mpp%t_proc(1)%t_var(:), cd_name, cd_name)
IF( il_ind /= 0 )THEN
!!! read variable value
CALL iom_mpp__read_var_value(td_mpp, &
& td_mpp%t_proc(1)%t_var(il_ind), &
& td_dom, ld_border)
ELSE
CALL logger_error( &
& " IOM MPP FILL VAR : there is no variable with "//&
& "name or standard name "//TRIM(cd_name)//&
& " in processor/file "//TRIM(td_mpp%t_proc(1)%c_name))
ENDIF
ENDIF
END SUBROUTINE iom_mpp__fill_var_name
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!> @return variable structure completed
!
!> @todo
!> - modif en fonction dimension de la variable lu pour cas dom
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__read_var_value(td_mpp, td_var, &
& td_dom, ld_border )
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(IN) :: td_mpp
TYPE(TVAR), INTENT(INOUT) :: td_var
TYPE(TDOM), INTENT(IN), OPTIONAL :: td_dom
LOGICAL, INTENT(IN), OPTIONAL :: ld_border
! local variable
INTEGER(i4) :: il_status
INTEGER(i4), DIMENSION(4) :: il_ind
INTEGER(i4) :: il_i1p
INTEGER(i4) :: il_i2p
INTEGER(i4) :: il_j1p
INTEGER(i4) :: il_j2p
LOGICAL :: ll_border
TYPE(TVAR) :: tl_var
TYPE(TMPP) :: tl_mpp
TYPE(TDOM) :: tl_dom
! loop indices
INTEGER(i4) :: jk
!----------------------------------------------------------------
ll_border=.FALSE.
IF( PRESENT(ld_border) ) ll_border=ld_border
! check td_dom and ld_border optionals parameters...
IF( ll_border .AND. PRESENT(td_dom) )THEN
CALL logger_error( "IOM MPP READ VAR VALUE: &
& domain and border can't be both specify")
ENDIF
IF( ll_border )THEN
! copy mpp structure
tl_mpp=td_mpp
! forced to keep same id
tl_mpp%t_proc(:)%i_id=td_mpp%t_proc(:)%i_id
IF( ALL(td_mpp%t_proc(:)%l_ctr) )THEN
CALL logger_warn( "IOM MPP READ VAR VALUE: &
& contour not define. look for it")
! get contour
CALL mpp_get_contour( tl_mpp )
ENDIF
! Allocate space to hold variable value in structure
IF( ASSOCIATED(td_var%d_value) )THEN
DEALLOCATE(td_var%d_value)
ENDIF
DO jk=1,ip_maxdim
IF( .NOT. td_var%t_dim(jk)%l_use ) tl_mpp%t_dim(jk)%i_len = 1
ENDDO
! use mpp global dimension
td_var%t_dim(:)%i_len=tl_mpp%t_dim(:)%i_len
ALLOCATE(td_var%d_value( td_var%t_dim(1)%i_len, &
& td_var%t_dim(2)%i_len, &
& td_var%t_dim(3)%i_len, &
& td_var%t_dim(4)%i_len),&
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " IOM MPP READ VAR VALUE: not enough space to put variable "//&
& TRIM(td_var%c_name)//&
& " in variable structure")
ENDIF
! read border processor
DO jk=1,tl_mpp%i_nproc
IF( tl_mpp%t_proc(jk)%l_ctr )THEN
CALL logger_debug(" IOM MPP READ VAR VALUE: name "//TRIM(td_var%c_name) )
CALL logger_debug(" IOM MPP READ VAR VALUE: ndim "//TRIM(fct_str(td_var%i_ndim)) )
tl_var=iom_read_var( tl_mpp%t_proc(jk), td_var%c_name )
! get processor indices
il_ind(:)=mpp_get_proc_index( tl_mpp, jk )
il_i1p = il_ind(1)
il_i2p = il_ind(2)
il_j1p = il_ind(3)
il_j2p = il_ind(4)
IF( .NOT. td_var%t_dim(1)%l_use )THEN
il_i1p=1
il_i2p=1
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
il_j1p=1
il_j2p=1
ENDIF
! replace value in mpp domain
td_var%d_value(il_i1p:il_i2p,il_j1p:il_j2p,:,:) = &
& tl_var%d_value(:,:,:,:)
! clean variable
CALL var_clean(tl_var)
ENDIF
ENDDO
ENDIF
IF( PRESENT(td_dom) )THEN
! copy mpp structure
tl_mpp=td_mpp
! forced to keep same id
tl_mpp%t_proc(:)%i_id=td_mpp%t_proc(:)%i_id
IF( ALL(.NOT. td_mpp%t_proc(:)%l_use) )THEN
CALL logger_warn( "IOM MPP READ VAR VALUE: &
& processor to be used not defined. look for it")
! get processor to be used
CALL mpp_get_use( tl_mpp, td_dom )
ENDIF
! Allocate space to hold variable value in structure
IF( ASSOCIATED(td_var%d_value) )THEN
DEALLOCATE(td_var%d_value)
ENDIF
tl_dom=td_dom
DO jk=1,ip_maxdim
IF( .NOT. td_var%t_dim(jk)%l_use ) tl_dom%t_dim(jk)%i_len = 1
ENDDO
! use domain dimension
td_var%t_dim(1:2)%i_len=tl_dom%t_dim(1:2)%i_len
ALLOCATE(td_var%d_value( tl_dom%t_dim(1)%i_len, &
& tl_dom%t_dim(2)%i_len, &
& td_var%t_dim(3)%i_len, &
& td_var%t_dim(4)%i_len),&
& stat=il_status)
IF(il_status /= 0 )THEN
CALL logger_error( &
& " IOM MPP READ VAR VALUE: not enough space to put variable "//&
& TRIM(td_var%c_name)//&
& " in variable structure")
ENDIF
CALL logger_debug("IOM MPP READ VAR VALUE: shape ("//&
& TRIM(fct_str(SIZE(td_var%d_value(:,:,:,:),DIM=1)))//","//&
& TRIM(fct_str(SIZE(td_var%d_value(:,:,:,:),DIM=2)))//","//&
& TRIM(fct_str(SIZE(td_var%d_value(:,:,:,:),DIM=3)))//","//&
& TRIM(fct_str(SIZE(td_var%d_value(:,:,:,:),DIM=4)))//")" )
! FillValue by default
td_var%d_value(:,:,:,:)=td_var%d_fill
IF( tl_dom%i_jmin < tl_dom%i_jmax )THEN
! no north pole
IF( tl_dom%i_imin == 1 .AND. &
& tl_dom%i_imax == tl_dom%t_dim0(1)%i_len )THEN
! east west cyclic
CALL iom_mpp__no_pole_cyclic(tl_mpp, td_var, tl_dom)
ELSEIF( tl_dom%i_imin < tl_dom%i_imax )THEN
! no east west overlap
CALL iom_mpp__no_pole_no_overlap(tl_mpp, td_var, tl_dom)
! no more EW overlap in variable
td_var%i_ew=-1
ELSEIF( tl_dom%i_imin > tl_dom%i_imax )THEN
! east west overlap
CALL iom_mpp__no_pole_overlap(tl_mpp, td_var, tl_dom)
! no more EW overlap in variable
td_var%i_ew=-1
ELSE
CALL logger_error(" IOM MPP READ VAR VALUE: invalid domain definition.")
ENDIF
ELSE ! tl_dom%i_jmin >= tl_dom%i_jmax
! north pole
CALL logger_error("IOM MPP READ VAR VALUE: siren is not able to do so now "//&
& "maybe in the next release")
! IF( tl_dom%i_imin < tl_dom%i_imax )THEN
! ! no east west overlap
! CALL iom_mpp__pole_no_overlap(tl_mpp, td_var, tl_dom)
! ELSEIF(tl_dom%i_imin == tl_dom%i_imax)THEN
! ! east west cyclic
! CALL iom_mpp__pole_cyclic(tl_mpp, td_var, tl_dom)
! ELSE ! tl_dom%i_imin > tl_dom%i_imax
! ! east west overlap
! CALL iom_mpp__pole_overlap(tl_mpp, td_var, tl_dom)
! ENDIF
ENDIF
ENDIF
! force to change _FillValue to avoid mistake
! with dummy zero _FillValue
IF( td_var%d_fill == 0._dp )THEN
CALL var_chg_FillValue(td_var)
ENDIF
END SUBROUTINE iom_mpp__read_var_value
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure. The output domain do not overlap
!> north fold boundary or east-west boundary.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @return variable structure completed
!
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__no_pole_no_overlap(td_mpp, td_var, td_dom )
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(IN) :: td_mpp
TYPE(TVAR), INTENT(INOUT) :: td_var
TYPE(TDOM), INTENT(IN), OPTIONAL :: td_dom
! local variable
INTEGER(i4), DIMENSION(4) :: il_ind
INTEGER(i4) :: il_i1p
INTEGER(i4) :: il_j1p
INTEGER(i4) :: il_i2p
INTEGER(i4) :: il_j2p
INTEGER(i4) :: il_i1
INTEGER(i4) :: il_j1
INTEGER(i4) :: il_i2
INTEGER(i4) :: il_j2
INTEGER(i4), DIMENSION(4) :: il_start
INTEGER(i4), DIMENSION(4) :: il_count
TYPE(TVAR) :: tl_var
TYPE(TDOM) :: tl_dom
! loop indices
INTEGER(i4) :: jk
!----------------------------------------------------------------
! change dimension length if not use
tl_dom=td_dom
IF( .NOT. td_var%t_dim(1)%l_use )THEN
tl_dom%i_imin=1 ; tl_dom%i_imax=1
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
tl_dom%i_jmin=1 ; tl_dom%i_jmax=1
ENDIF
! IF( .NOT. td_var%t_dim(3)%l_use )THEN
! tl_dom%i_kmin=1 ; tl_dom%i_kmax=1
! ENDIF
! IF( .NOT. td_var%t_dim(4)%l_use )THEN
! tl_dom%i_lmin=1 ; tl_dom%i_lmax=1
! ENDIF
! read processor
DO jk=1,td_mpp%i_nproc
IF( td_mpp%t_proc(jk)%l_use )THEN
! get processor indices
il_ind(:)=mpp_get_proc_index( td_mpp, jk )
il_i1p = il_ind(1)
il_i2p = il_ind(2)
il_j1p = il_ind(3)
il_j2p = il_ind(4)
IF( .NOT. td_var%t_dim(1)%l_use )THEN
il_i1p=tl_dom%i_imin ; il_i2p=tl_dom%i_imax
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
il_j1p=tl_dom%i_jmin ; il_j2p=tl_dom%i_jmax
ENDIF
il_i1=MAX(il_i1p, tl_dom%i_imin)
il_i2=MIN(il_i2p, tl_dom%i_imax)
il_j1=MAX(il_j1p, tl_dom%i_jmin)
il_j2=MIN(il_j2p, tl_dom%i_jmax)
IF( (il_i1<=il_i2).AND.(il_j1<=il_j2) )THEN
il_start(:)=(/ il_i1-il_i1p+1, &
& il_j1-il_j1p+1, &
& 1,1 /)
! & tl_dom%i_kmin, &
! & tl_dom%i_lmin /)
il_count(:)=(/ il_i2-il_i1+1, &
& il_j2-il_j1+1, &
& td_var%t_dim(3)%i_len, &
& td_var%t_dim(4)%i_len /)
! & tl_dom%t_dim(3)%i_len, &
! & tl_dom%t_dim(4)%i_len /)
tl_var=iom_read_var( td_mpp%t_proc(jk), td_var%c_name,&
& il_start(:), il_count(:) )
! replace value in output variable structure
td_var%d_value( il_i1 - tl_dom%i_imin + 1 : &
& il_i2 - tl_dom%i_imin + 1, &
& il_j1 - tl_dom%i_jmin + 1 : &
& il_j2 - tl_dom%i_jmin + 1, &
& :,:) = tl_var%d_value(:,:,:,:)
ENDIF
ENDIF
ENDDO
END SUBROUTINE iom_mpp__no_pole_no_overlap
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure. The output domain do not overlap north fold boundary.
!> However it uses cyclic east-west boundary.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @return variable structure completed
!
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__no_pole_cyclic(td_mpp, td_var, td_dom )
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(IN ) :: td_mpp
TYPE(TVAR), INTENT(INOUT) :: td_var
TYPE(TDOM), INTENT(IN ), OPTIONAL :: td_dom
! local variable
INTEGER(i4), DIMENSION(4) :: il_ind
INTEGER(i4) :: il_i1p
INTEGER(i4) :: il_j1p
INTEGER(i4) :: il_i2p
INTEGER(i4) :: il_j2p
INTEGER(i4) :: il_i1
INTEGER(i4) :: il_j1
INTEGER(i4) :: il_i2
INTEGER(i4) :: il_j2
INTEGER(i4), DIMENSION(4) :: il_start
INTEGER(i4), DIMENSION(4) :: il_count
TYPE(TVAR) :: tl_var
TYPE(TDOM) :: tl_dom
! loop indices
INTEGER(i4) :: jk
!----------------------------------------------------------------
! change dimension length if not use
tl_dom=td_dom
IF( .NOT. td_var%t_dim(1)%l_use )THEN
tl_dom%i_imin=1 ; tl_dom%i_imax=1
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
tl_dom%i_jmin=1 ; tl_dom%i_jmax=1
ENDIF
! IF( .NOT. td_var%t_dim(3)%l_use )THEN
! tl_dom%i_kmin=1 ; tl_dom%i_kmax=1
! ENDIF
! IF( .NOT. td_var%t_dim(4)%l_use )THEN
! tl_dom%i_lmin=1 ; tl_dom%i_lmax=1
! ENDIF
! read processor
DO jk=1,td_mpp%i_nproc
IF( td_mpp%t_proc(jk)%l_use )THEN
! get processor indices
il_ind(:)=mpp_get_proc_index( td_mpp, jk )
il_i1p = il_ind(1)
il_i2p = il_ind(2)
il_j1p = il_ind(3)
il_j2p = il_ind(4)
IF( .NOT. td_var%t_dim(1)%l_use )THEN
il_i1p=tl_dom%i_imin ; il_i2p=tl_dom%i_imax
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
il_j1p=tl_dom%i_jmin ; il_j2p=tl_dom%i_jmax
ENDIF
il_i1=il_i1p
il_j1=MAX(il_j1p, td_dom%i_jmin)
il_i2=il_i2p
il_j2=MIN(il_j2p, td_dom%i_jmax)
IF( (il_i1<=il_i2).AND.(il_j1<=il_j2) )THEN
il_start(:)=(/ il_i1, &
& il_j1-il_j1p+1, &
& 1,1 /)
! & tl_dom%i_kmin, &
! & tl_dom%i_lmin /)
il_count(:)=(/ il_i2-il_i1+1, &
& il_j2-il_j1+1, &
& td_var%t_dim(3)%i_len, &
& td_var%t_dim(4)%i_len /)
! & tl_dom%t_dim(3)%i_len, &
! & tl_dom%t_dim(4)%i_len /)
tl_var=iom_read_var( td_mpp%t_proc(jk), td_var%c_name,&
& il_start(:), il_count(:) )
! replace value in output variable structure
td_var%d_value( il_i1 : il_i2, &
& il_j1 - td_dom%i_jmin + 1 : &
& il_j2 - td_dom%i_jmin + 1, &
& :,:) = tl_var%d_value(:,:,:,:)
ENDIF
ENDIF
ENDDO
END SUBROUTINE iom_mpp__no_pole_cyclic
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure. The output domain do not overlap north fold boundary.
!> However it overlaps east-west boundary.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @return variable structure completed
!
!> @todo
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp__no_pole_overlap(td_mpp, td_var, td_dom )
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(IN) :: td_mpp
TYPE(TVAR), INTENT(INOUT) :: td_var
TYPE(TDOM), INTENT(IN), OPTIONAL :: td_dom
! local variable
INTEGER(i4), DIMENSION(4) :: il_ind
INTEGER(i4) :: il_i1p
INTEGER(i4) :: il_j1p
INTEGER(i4) :: il_i2p
INTEGER(i4) :: il_j2p
INTEGER(i4) :: il_i1
INTEGER(i4) :: il_j1
INTEGER(i4) :: il_i2
INTEGER(i4) :: il_j2
INTEGER(i4) :: il_ioffset
INTEGER(i4), DIMENSION(4) :: il_start
INTEGER(i4), DIMENSION(4) :: il_count
TYPE(TVAR) :: tl_var
TYPE(TDOM) :: tl_dom
! loop indices
INTEGER(i4) :: jk
!----------------------------------------------------------------
il_ioffset = (td_mpp%t_dim(1)%i_len-2) - td_dom%i_imin + 1
! change dimension length if not use
tl_dom=td_dom
IF( .NOT. td_var%t_dim(1)%l_use )THEN
tl_dom%i_imin=1 ; tl_dom%i_imax=1
il_ioffset=0
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
tl_dom%i_jmin=1 ; tl_dom%i_jmax=1
ENDIF
! IF( .NOT. td_var%t_dim(3)%l_use )THEN
! tl_dom%i_kmin=1 ; tl_dom%i_kmax=1
! ENDIF
! IF( .NOT. td_var%t_dim(4)%l_use )THEN
! tl_dom%i_lmin=1 ; tl_dom%i_lmax=1
! ENDIF
! read processor
DO jk=1,td_mpp%i_nproc
IF( td_mpp%t_proc(jk)%l_use )THEN
! get processor indices
il_ind(:)=mpp_get_proc_index( td_mpp, jk )
il_i1p = il_ind(1)
il_i2p = il_ind(2)
il_j1p = il_ind(3)
il_j2p = il_ind(4)
IF( .NOT. td_var%t_dim(1)%l_use )THEN
il_i1p=tl_dom%i_imin ; il_i2p=tl_dom%i_imax
ENDIF
IF( .NOT. td_var%t_dim(2)%l_use )THEN
il_j1p=tl_dom%i_jmin ; il_j2p=tl_dom%i_jmax
ENDIF
!!!!!! get first part of domain
il_i1=MAX(il_i1p, td_dom%i_imin)
il_j1=MAX(il_j1p, td_dom%i_jmin)
il_i2=MIN(il_i2p, td_mpp%t_dim(1)%i_len-td_var%i_ew) ! east-west overlap
il_j2=MIN(il_j2p, td_dom%i_jmax)
IF( (il_i1<=il_i2).AND.(il_j1<=il_j2) )THEN
il_start(:)=(/ il_i1-il_i1p+1, &
& il_j1-il_j1p+1, &
& 1,1 /)
! & tl_dom%i_kmin, &
! & tl_dom%i_lmin /)
il_count(:)=(/ il_i2-il_i1+1, &
& il_j2-il_j1+1, &
& td_var%t_dim(3)%i_len, &
& td_var%t_dim(4)%i_len /)
! & tl_dom%t_dim(3)%i_len, &
! & tl_dom%t_dim(4)%i_len /)
tl_var=iom_read_var( td_mpp%t_proc(jk), td_var%c_name,&
& il_start(:), il_count(:) )
! replace value in output variable structure
td_var%d_value( il_i1 - td_dom%i_imin + 1 : &
& il_i2 - td_dom%i_imin + 1, &
& il_j1 - td_dom%i_jmin + 1 : &
& il_j2 - td_dom%i_jmin + 1, &
& :,:) = tl_var%d_value(:,:,:,:)
ENDIF
!!!!! get second part of domain
il_i1=MAX(il_i1p, 1)
il_j1=MAX(il_j1p, td_dom%i_jmin)
il_i2=MIN(il_i2p, td_dom%i_imax)
il_j2=MIN(il_j2p, td_dom%i_jmax)
IF( (il_i1<=il_i2).AND.(il_j1<=il_j2) )THEN
il_start(:)=(/ il_i1, &
& il_j1-il_j1p+1, &
& 1,1 /)
! & tl_dom%i_kmin, &
! & tl_dom%i_lmin /)
il_count(:)=(/ il_i2-il_i1+1, &
& il_j2-il_j1+1, &
& td_var%t_dim(3)%i_len, &
& td_var%t_dim(4)%i_len /)
! & tl_dom%t_dim(3)%i_len, &
! & tl_dom%t_dim(4)%i_len /)
tl_var=iom_read_var( td_mpp%t_proc(jk), td_var%c_name,&
& il_start(:), il_count(:) )
! replace value in output variable structure
td_var%d_value( il_ioffset + il_i1 : &
& il_ioffset + il_i2, &
& il_j1 - td_dom%i_jmin + 1 : &
& il_j2 - td_dom%i_jmin + 1, &
& :,:) = tl_var%d_value(:,:,:,:)
ENDIF
ENDIF
ENDDO
END SUBROUTINE iom_mpp__no_pole_overlap
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure. The output domain overlaps
!> north fold boundary. However it do not overlap east-west boundary.
!>
!> @details
!> If domain is given, read only domain.
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @return variable structure completed
!
!> @todo
!-------------------------------------------------------------------
!> @code
! SUBROUTINE iom_mpp__pole_no_overlap(td_mpp, td_var, td_dom )
! IMPLICIT NONE
! ! Argument
! TYPE(TMPP), INTENT(IN) :: td_mpp
! TYPE(TVAR), INTENT(INOUT) :: td_var
! TYPE(TDOM), INTENT(IN), OPTIONAL :: td_dom
!
! ! local variable
!
! ! loop indices
! !----------------------------------------------------------------
!
! END SUBROUTINE iom_mpp__pole_no_overlap
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure. The output domain overlaps north fold boundary.
!> and uses cyclic east-west boundary.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!> @return variable structure completed
!
!> @todo
!-------------------------------------------------------------------
!> @code
! SUBROUTINE iom_mpp__pole_cyclic(td_mpp, td_var, td_dom )
! IMPLICIT NONE
! ! Argument
! TYPE(TMPP), INTENT(IN) :: td_mpp
! TYPE(TVAR), INTENT(INOUT) :: td_var
! TYPE(TDOM), INTENT(IN), OPTIONAL :: td_dom
!
! ! local variable
!
! ! loop indices
! !----------------------------------------------------------------
!
! END SUBROUTINE iom_mpp__pole_cyclic
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine read variable value
!> in an mpp structure. The output domain overlaps north fold boundary.
!> and east-west boundary.
!>
!> @details
!> If domain is given, read only domain.
!> If border is .TRUE., read only border processor
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_mpp : mpp structure
!> @param[inout] td_var : variable structure
!> @param[in] td_dom : domain structure
!> @param[in] ld_border : read only border
!> @return variable structure completed
!
!> @todo
!-------------------------------------------------------------------
!> @code
! SUBROUTINE iom_mpp__pole_overlap(td_mpp, td_var, td_dom )
! IMPLICIT NONE
! ! Argument
! TYPE(TMPP), INTENT(IN) :: td_mpp
! TYPE(TVAR), INTENT(INOUT) :: td_var
! TYPE(TDOM), INTENT(IN), OPTIONAL :: td_dom
!
! ! local variable
!
! ! loop indices
! !----------------------------------------------------------------
!
! END SUBROUTINE iom_mpp__pole_overlap
!> @endcode
!-------------------------------------------------------------------
!> @brief This subroutine write mpp structure in opened files.
!
!> @details
!
!> @author J.Paul
!> - Nov, 2013- Initial Version
!
!> @param[in] td_file : file structure
!-------------------------------------------------------------------
!> @code
SUBROUTINE iom_mpp_write_file(td_mpp)
IMPLICIT NONE
! Argument
TYPE(TMPP), INTENT(INOUT) :: td_mpp
! loop indices
INTEGER(i4) :: ji
!----------------------------------------------------------------
! check if mpp exist
IF( .NOT. ASSOCIATED(td_mpp%t_proc) )THEN
CALL logger_error( " MPP WRITE: domain decomposition not define "//&
& " in mpp strcuture "//TRIM(td_mpp%c_name))
ELSE
DO ji=1, td_mpp%i_nproc
IF( td_mpp%t_proc(ji)%i_id /= 0 )THEN
CALL iom_write_file(td_mpp%t_proc(ji))
ELSE
CALL logger_debug( " MPP WRITE: no id associated to file "//&
& TRIM(td_mpp%t_proc(ji)%c_name) )
ENDIF
ENDDO
ENDIF
END SUBROUTINE iom_mpp_write_file
!> @endcode
END MODULE iom_mpp