!---------------------------------------------------------------------- ! 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