!WRF:PACKAGE:RSL
!
MODULE module_dm
USE module_machine
USE module_wrf_error
USE module_driver_constants
! USE module_comm_dm
IMPLICIT NONE
#if ( NMM_CORE == 1 ) || defined( WRF_CHEM )
INTEGER, PARAMETER :: max_halo_width = 6
#else
INTEGER, PARAMETER :: max_halo_width = 6 ! 5
#endif
INTEGER :: ips_save, ipe_save, jps_save, jpe_save, itrace
INTEGER ntasks, ntasks_y, ntasks_x, mytask, mytask_x, mytask_y
INTEGER local_communicator, local_communicator_periodic, local_iocommunicator
INTEGER local_communicator_x, local_communicator_y ! subcommunicators for rows and cols of mesh
LOGICAL :: dm_debug_flag = .FALSE.
INTERFACE wrf_dm_maxval
#if ( defined(PROMOTE_FLOAT) || ( RWORDSIZE == DWORDSIZE ) )
MODULE PROCEDURE wrf_dm_maxval_real , wrf_dm_maxval_integer
#else
MODULE PROCEDURE wrf_dm_maxval_real , wrf_dm_maxval_integer, wrf_dm_maxval_doubleprecision
#endif
END INTERFACE
INTERFACE wrf_dm_minval ! gopal's doing
#if ( defined(PROMOTE_FLOAT) || ( RWORDSIZE == DWORDSIZE ) )
MODULE PROCEDURE wrf_dm_minval_real , wrf_dm_minval_integer
#else
MODULE PROCEDURE wrf_dm_minval_real , wrf_dm_minval_integer, wrf_dm_minval_doubleprecision
#endif
END INTERFACE
CONTAINS
SUBROUTINE MPASPECT( P, MINM, MINN, PROCMIN_M, PROCMIN_N )
IMPLICIT NONE
INTEGER P, M, N, MINI, MINM, MINN, PROCMIN_M, PROCMIN_N
MINI = 2*P
MINM = 1
MINN = P
DO M = 1, P
IF ( MOD( P, M ) .EQ. 0 ) THEN
N = P / M
IF ( ABS(M-N) .LT. MINI &
.AND. M .GE. PROCMIN_M &
.AND. N .GE. PROCMIN_N &
) THEN
MINI = ABS(M-N)
MINM = M
MINN = N
ENDIF
ENDIF
ENDDO
IF ( MINM .LT. PROCMIN_M .OR. MINN .LT. PROCMIN_N ) THEN
WRITE( wrf_err_message , * )'MPASPECT: UNABLE TO GENERATE PROCESSOR MESH. STOPPING.'
CALL wrf_message ( TRIM ( wrf_err_message ) )
WRITE(0,*)' PROCMIN_M ', PROCMIN_M
WRITE( wrf_err_message , * )' PROCMIN_M ', PROCMIN_M
CALL wrf_message ( TRIM ( wrf_err_message ) )
WRITE( wrf_err_message , * )' PROCMIN_N ', PROCMIN_N
CALL wrf_message ( TRIM ( wrf_err_message ) )
WRITE( wrf_err_message , * )' P ', P
CALL wrf_message ( TRIM ( wrf_err_message ) )
WRITE( wrf_err_message , * )' MINM ', MINM
CALL wrf_message ( TRIM ( wrf_err_message ) )
WRITE( wrf_err_message , * )' MINN ', MINN
CALL wrf_message ( TRIM ( wrf_err_message ) )
CALL wrf_error_fatal ( 'module_dm: mpaspect' )
ENDIF
RETURN
END SUBROUTINE MPASPECT
SUBROUTINE compute_mesh( ntasks , ntasks_x, ntasks_y )
IMPLICIT NONE
INTEGER, INTENT(IN) :: ntasks
INTEGER, INTENT(OUT) :: ntasks_x, ntasks_y
CALL nl_get_nproc_x ( 1, ntasks_x )
CALL nl_get_nproc_y ( 1, ntasks_y )
! check if user has specified in the namelist
IF ( ntasks_x .GT. 0 .OR. ntasks_y .GT. 0 ) THEN
! if only ntasks_x is specified then make it 1-d decomp in i
IF ( ntasks_x .GT. 0 .AND. ntasks_y .EQ. -1 ) THEN
ntasks_y = ntasks / ntasks_x
! if only ntasks_y is specified then make it 1-d decomp in j
ELSE IF ( ntasks_x .EQ. -1 .AND. ntasks_y .GT. 0 ) THEN
ntasks_x = ntasks / ntasks_y
ENDIF
! make sure user knows what they're doing
IF ( ntasks_x * ntasks_y .NE. ntasks ) THEN
WRITE( wrf_err_message , * )'WRF_DM_INITIALIZE (RSL_LITE): nproc_x * nproc_y in namelist ne ',ntasks
CALL wrf_error_fatal ( wrf_err_message )
ENDIF
ELSE
! When neither is specified, work out mesh with MPASPECT
! Pass nproc_ln and nproc_nt so that number of procs in
! i-dim (nproc_ln) is equal or lesser.
CALL mpaspect ( ntasks, ntasks_x, ntasks_y, 1, 1 )
ENDIF
END SUBROUTINE compute_mesh
SUBROUTINE wrf_dm_initialize
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER :: local_comm, local_comm2, new_local_comm, group, newgroup, p, p1, ierr
INTEGER, ALLOCATABLE, DIMENSION(:) :: ranks
INTEGER comdup
INTEGER, DIMENSION(2) :: dims, coords
LOGICAL, DIMENSION(2) :: isperiodic
LOGICAL :: reorder_mesh
CALL wrf_get_dm_communicator ( local_comm )
CALL mpi_comm_size( local_comm, ntasks, ierr )
CALL nl_get_reorder_mesh( 1, reorder_mesh )
CALL compute_mesh( ntasks, ntasks_x, ntasks_y )
WRITE( wrf_err_message , * )'Ntasks in X ',ntasks_x,', ntasks in Y ',ntasks_y
CALL wrf_message( wrf_err_message )
CALL mpi_comm_rank( local_comm, mytask, ierr )
! extra code to reorder the communicator 20051212jm
IF ( reorder_mesh ) THEN
ALLOCATE (ranks(ntasks))
CALL mpi_comm_dup ( local_comm , local_comm2, ierr )
CALL mpi_comm_group ( local_comm2, group, ierr )
DO p1=1,ntasks
p = p1 - 1
ranks(p1) = mod( p , ntasks_x ) * ntasks_y + p / ntasks_x
ENDDO
CALL mpi_group_incl( group, ntasks, ranks, newgroup, ierr )
DEALLOCATE (ranks)
CALL mpi_comm_create( local_comm2, newgroup, new_local_comm , ierr )
ELSE
new_local_comm = local_comm
ENDIF
! end extra code to reorder the communicator 20051212jm
dims(1) = ntasks_y ! rows
dims(2) = ntasks_x ! columns
isperiodic(1) = .false.
isperiodic(2) = .false.
CALL mpi_cart_create( new_local_comm, 2, dims, isperiodic, .false., local_communicator, ierr )
dims(1) = ntasks_y ! rows
dims(2) = ntasks_x ! columns
isperiodic(1) = .true.
isperiodic(2) = .true.
CALL mpi_cart_create( new_local_comm, 2, dims, isperiodic, .false., local_communicator_periodic, ierr )
! debug
CALL mpi_comm_rank( local_communicator_periodic, mytask, ierr )
CALL mpi_cart_coords( local_communicator_periodic, mytask, 2, coords, ierr )
! write(0,*)'periodic coords ',mytask, coords
CALL mpi_comm_rank( local_communicator, mytask, ierr )
CALL mpi_cart_coords( local_communicator, mytask, 2, coords, ierr )
! write(0,*)'non periodic coords ',mytask, coords
mytask_x = coords(2) ! col task (x)
mytask_y = coords(1) ! row task (y)
CALL nl_set_nproc_x ( 1, ntasks_x )
CALL nl_set_nproc_y ( 1, ntasks_y )
! 20061228 set up subcommunicators for processors in X, Y coords of mesh
! note that local_comm_x has all the processors in a row (X=0:nproc_x-1);
! in other words, local_comm_x has all the processes with the same rank in Y
CALL MPI_Comm_dup( new_local_comm, comdup, ierr )
IF ( ierr .NE. 0 ) CALL wrf_error_fatal('MPI_Comm_dup fails in 20061228 mod')
CALL MPI_Comm_split(comdup,mytask_y,mytask,local_communicator_x,ierr)
IF ( ierr .NE. 0 ) CALL wrf_error_fatal('MPI_Comm_split fails for x in 20061228 mod')
CALL MPI_Comm_split(comdup,mytask_x,mytask,local_communicator_y,ierr)
IF ( ierr .NE. 0 ) CALL wrf_error_fatal('MPI_Comm_split fails for y in 20061228 mod')
! end 20061228
CALL wrf_set_dm_communicator ( local_communicator )
#else
ntasks = 1
ntasks_x = 1
ntasks_y = 1
mytask = 0
mytask_x = 0
mytask_y = 0
#endif
RETURN
END SUBROUTINE wrf_dm_initialize
SUBROUTINE get_dm_max_halo_width( id, width )
IMPLICIT NONE
INTEGER, INTENT(IN) :: id
INTEGER, INTENT(OUT) :: width
IF ( id .EQ. 1 ) THEN ! this is coarse domain
width = max_halo_width
ELSE
width = max_halo_width + 3
ENDIF
RETURN
END SUBROUTINE get_dm_max_halo_width
SUBROUTINE patch_domain_rsl_lite( id , parent, parent_id, &
sd1 , ed1 , sp1 , ep1 , sm1 , em1 , &
sd2 , ed2 , sp2 , ep2 , sm2 , em2 , &
sd3 , ed3 , sp3 , ep3 , sm3 , em3 , &
sp1x , ep1x , sm1x , em1x , &
sp2x , ep2x , sm2x , em2x , &
sp3x , ep3x , sm3x , em3x , &
sp1y , ep1y , sm1y , em1y , &
sp2y , ep2y , sm2y , em2y , &
sp3y , ep3y , sm3y , em3y , &
bdx , bdy )
USE module_domain, ONLY : domain, head_grid, find_grid_by_id
IMPLICIT NONE
INTEGER, INTENT(IN) :: sd1 , ed1 , sd2 , ed2 , sd3 , ed3 , bdx , bdy
INTEGER, INTENT(OUT) :: sp1 , ep1 , sp2 , ep2 , sp3 , ep3 , &
sm1 , em1 , sm2 , em2 , sm3 , em3
INTEGER, INTENT(OUT) :: sp1x , ep1x , sp2x , ep2x , sp3x , ep3x , &
sm1x , em1x , sm2x , em2x , sm3x , em3x
INTEGER, INTENT(OUT) :: sp1y , ep1y , sp2y , ep2y , sp3y , ep3y , &
sm1y , em1y , sm2y , em2y , sm3y , em3y
INTEGER, INTENT(IN) :: id, parent_id
TYPE(domain),POINTER :: parent
! Local variables
INTEGER :: ids, ide, jds, jde, kds, kde
INTEGER :: ims, ime, jms, jme, kms, kme
INTEGER :: ips, ipe, jps, jpe, kps, kpe
INTEGER :: imsx, imex, jmsx, jmex, kmsx, kmex
INTEGER :: ipsx, ipex, jpsx, jpex, kpsx, kpex
INTEGER :: imsy, imey, jmsy, jmey, kmsy, kmey
INTEGER :: ipsy, ipey, jpsy, jpey, kpsy, kpey
INTEGER :: c_sd1 , c_ed1 , c_sd2 , c_ed2 , c_sd3 , c_ed3
INTEGER :: c_sp1 , c_ep1 , c_sp2 , c_ep2 , c_sp3 , c_ep3 , &
c_sm1 , c_em1 , c_sm2 , c_em2 , c_sm3 , c_em3
INTEGER :: c_sp1x , c_ep1x , c_sp2x , c_ep2x , c_sp3x , c_ep3x , &
c_sm1x , c_em1x , c_sm2x , c_em2x , c_sm3x , c_em3x
INTEGER :: c_sp1y , c_ep1y , c_sp2y , c_ep2y , c_sp3y , c_ep3y , &
c_sm1y , c_em1y , c_sm2y , c_em2y , c_sm3y , c_em3y
INTEGER :: c_ids, c_ide, c_jds, c_jde, c_kds, c_kde
INTEGER :: c_ims, c_ime, c_jms, c_jme, c_kms, c_kme
INTEGER :: c_ips, c_ipe, c_jps, c_jpe, c_kps, c_kpe
INTEGER :: idim , jdim , kdim , rem , a, b
INTEGER :: i, j, ni, nj, Px, Py, P
INTEGER :: parent_grid_ratio, i_parent_start, j_parent_start
INTEGER :: shw
INTEGER :: idim_cd, jdim_cd, ierr
INTEGER :: max_dom
TYPE(domain), POINTER :: intermediate_grid
TYPE(domain), POINTER :: nest_grid
CHARACTER*256 :: mess
INTEGER parent_max_halo_width
INTEGER thisdomain_max_halo_width
SELECT CASE ( model_data_order )
! need to finish other cases
CASE ( DATA_ORDER_ZXY )
ids = sd2 ; ide = ed2
jds = sd3 ; jde = ed3
kds = sd1 ; kde = ed1
CASE ( DATA_ORDER_XYZ )
ids = sd1 ; ide = ed1
jds = sd2 ; jde = ed2
kds = sd3 ; kde = ed3
CASE ( DATA_ORDER_XZY )
ids = sd1 ; ide = ed1
jds = sd3 ; jde = ed3
kds = sd2 ; kde = ed2
CASE ( DATA_ORDER_YXZ)
ids = sd2 ; ide = ed2
jds = sd1 ; jde = ed1
kds = sd3 ; kde = ed3
END SELECT
CALL nl_get_max_dom( 1 , max_dom )
CALL get_dm_max_halo_width( id , thisdomain_max_halo_width )
IF ( id .GT. 1 ) THEN
CALL get_dm_max_halo_width( parent%id , parent_max_halo_width )
ENDIF
CALL compute_memory_dims_rsl_lite ( id, thisdomain_max_halo_width, 0 , bdx, bdy, &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
imsx, imex, jmsx, jmex, kmsx, kmex, &
imsy, imey, jmsy, jmey, kmsy, kmey, &
ips, ipe, jps, jpe, kps, kpe, &
ipsx, ipex, jpsx, jpex, kpsx, kpex, &
ipsy, ipey, jpsy, jpey, kpsy, kpey )
! ensure that the every parent domain point has a full set of nested points under it
! even at the borders. Do this by making sure the number of nest points is a multiple of
! the nesting ratio. Note that this is important mostly to the intermediate domain, which
! is the subject of the scatter gather comms with the parent
IF ( id .GT. 1 ) THEN
CALL nl_get_parent_grid_ratio( id, parent_grid_ratio )
if ( mod(ime,parent_grid_ratio) .NE. 0 ) ime = ime + parent_grid_ratio - mod(ime,parent_grid_ratio)
if ( mod(jme,parent_grid_ratio) .NE. 0 ) jme = jme + parent_grid_ratio - mod(jme,parent_grid_ratio)
ENDIF
SELECT CASE ( model_data_order )
CASE ( DATA_ORDER_ZXY )
sp2 = ips ; ep2 = ipe ; sm2 = ims ; em2 = ime
sp3 = jps ; ep3 = jpe ; sm3 = jms ; em3 = jme
sp1 = kps ; ep1 = kpe ; sm1 = kms ; em1 = kme
sp2x = ipsx ; ep2x = ipex ; sm2x = imsx ; em2x = imex
sp3x = jpsx ; ep3x = jpex ; sm3x = jmsx ; em3x = jmex
sp1x = kpsx ; ep1x = kpex ; sm1x = kmsx ; em1x = kmex
sp2y = ipsy ; ep2y = ipey ; sm2y = imsy ; em2y = imey
sp3y = jpsy ; ep3y = jpey ; sm3y = jmsy ; em3y = jmey
sp1y = kpsy ; ep1y = kpey ; sm1y = kmsy ; em1y = kmey
CASE ( DATA_ORDER_ZYX )
sp3 = ips ; ep3 = ipe ; sm3 = ims ; em3 = ime
sp2 = jps ; ep2 = jpe ; sm2 = jms ; em2 = jme
sp1 = kps ; ep1 = kpe ; sm1 = kms ; em1 = kme
sp3x = ipsx ; ep3x = ipex ; sm3x = imsx ; em3x = imex
sp2x = jpsx ; ep2x = jpex ; sm2x = jmsx ; em2x = jmex
sp1x = kpsx ; ep1x = kpex ; sm1x = kmsx ; em1x = kmex
sp3y = ipsy ; ep3y = ipey ; sm3y = imsy ; em3y = imey
sp2y = jpsy ; ep2y = jpey ; sm2y = jmsy ; em2y = jmey
sp1y = kpsy ; ep1y = kpey ; sm1y = kmsy ; em1y = kmey
CASE ( DATA_ORDER_XYZ )
sp1 = ips ; ep1 = ipe ; sm1 = ims ; em1 = ime
sp2 = jps ; ep2 = jpe ; sm2 = jms ; em2 = jme
sp3 = kps ; ep3 = kpe ; sm3 = kms ; em3 = kme
sp1x = ipsx ; ep1x = ipex ; sm1x = imsx ; em1x = imex
sp2x = jpsx ; ep2x = jpex ; sm2x = jmsx ; em2x = jmex
sp3x = kpsx ; ep3x = kpex ; sm3x = kmsx ; em3x = kmex
sp1y = ipsy ; ep1y = ipey ; sm1y = imsy ; em1y = imey
sp2y = jpsy ; ep2y = jpey ; sm2y = jmsy ; em2y = jmey
sp3y = kpsy ; ep3y = kpey ; sm3y = kmsy ; em3y = kmey
CASE ( DATA_ORDER_YXZ)
sp2 = ips ; ep2 = ipe ; sm2 = ims ; em2 = ime
sp1 = jps ; ep1 = jpe ; sm1 = jms ; em1 = jme
sp3 = kps ; ep3 = kpe ; sm3 = kms ; em3 = kme
sp2x = ipsx ; ep2x = ipex ; sm2x = imsx ; em2x = imex
sp1x = jpsx ; ep1x = jpex ; sm1x = jmsx ; em1x = jmex
sp3x = kpsx ; ep3x = kpex ; sm3x = kmsx ; em3x = kmex
sp2y = ipsy ; ep2y = ipey ; sm2y = imsy ; em2y = imey
sp1y = jpsy ; ep1y = jpey ; sm1y = jmsy ; em1y = jmey
sp3y = kpsy ; ep3y = kpey ; sm3y = kmsy ; em3y = kmey
CASE ( DATA_ORDER_XZY )
sp1 = ips ; ep1 = ipe ; sm1 = ims ; em1 = ime
sp3 = jps ; ep3 = jpe ; sm3 = jms ; em3 = jme
sp2 = kps ; ep2 = kpe ; sm2 = kms ; em2 = kme
sp1x = ipsx ; ep1x = ipex ; sm1x = imsx ; em1x = imex
sp3x = jpsx ; ep3x = jpex ; sm3x = jmsx ; em3x = jmex
sp2x = kpsx ; ep2x = kpex ; sm2x = kmsx ; em2x = kmex
sp1y = ipsy ; ep1y = ipey ; sm1y = imsy ; em1y = imey
sp3y = jpsy ; ep3y = jpey ; sm3y = jmsy ; em3y = jmey
sp2y = kpsy ; ep2y = kpey ; sm2y = kmsy ; em2y = kmey
CASE ( DATA_ORDER_YZX )
sp3 = ips ; ep3 = ipe ; sm3 = ims ; em3 = ime
sp1 = jps ; ep1 = jpe ; sm1 = jms ; em1 = jme
sp2 = kps ; ep2 = kpe ; sm2 = kms ; em2 = kme
sp3x = ipsx ; ep3x = ipex ; sm3x = imsx ; em3x = imex
sp1x = jpsx ; ep1x = jpex ; sm1x = jmsx ; em1x = jmex
sp2x = kpsx ; ep2x = kpex ; sm2x = kmsx ; em2x = kmex
sp3y = ipsy ; ep3y = ipey ; sm3y = imsy ; em3y = imey
sp1y = jpsy ; ep1y = jpey ; sm1y = jmsy ; em1y = jmey
sp2y = kpsy ; ep2y = kpey ; sm2y = kmsy ; em2y = kmey
END SELECT
IF ( id.EQ.1 ) THEN
WRITE(wrf_err_message,*)'*************************************'
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'Parent domain'
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ids,ide,jds,jde ',ids,ide,jds,jde
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ims,ime,jms,jme ',ims,ime,jms,jme
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ips,ipe,jps,jpe ',ips,ipe,jps,jpe
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'*************************************'
CALL wrf_message( TRIM(wrf_err_message) )
ENDIF
IF ( id .GT. 1 ) THEN
CALL nl_get_shw( id, shw )
CALL nl_get_i_parent_start( id , i_parent_start )
CALL nl_get_j_parent_start( id , j_parent_start )
CALL nl_get_parent_grid_ratio( id, parent_grid_ratio )
SELECT CASE ( model_data_order )
CASE ( DATA_ORDER_ZXY )
idim = ed2-sd2+1
jdim = ed3-sd3+1
kdim = ed1-sd1+1
c_kds = sd1 ; c_kde = ed1
CASE ( DATA_ORDER_ZYX )
idim = ed3-sd3+1
jdim = ed2-sd2+1
kdim = ed1-sd1+1
c_kds = sd1 ; c_kde = ed1
CASE ( DATA_ORDER_XYZ )
idim = ed1-sd1+1
jdim = ed2-sd2+1
kdim = ed3-sd3+1
c_kds = sd3 ; c_kde = ed3
CASE ( DATA_ORDER_YXZ)
idim = ed2-sd2+1
jdim = ed1-sd1+1
kdim = ed3-sd3+1
c_kds = sd3 ; c_kde = ed3
CASE ( DATA_ORDER_XZY )
idim = ed1-sd1+1
jdim = ed3-sd3+1
kdim = ed2-sd2+1
c_kds = sd2 ; c_kde = ed2
CASE ( DATA_ORDER_YZX )
idim = ed3-sd3+1
jdim = ed1-sd1+1
kdim = ed2-sd2+1
c_kds = sd2 ; c_kde = ed2
END SELECT
idim_cd = idim / parent_grid_ratio + 1 + 2*shw + 1
jdim_cd = jdim / parent_grid_ratio + 1 + 2*shw + 1
c_ids = i_parent_start-shw ; c_ide = c_ids + idim_cd - 1
c_jds = j_parent_start-shw ; c_jde = c_jds + jdim_cd - 1
! we want the intermediate domain to be decomposed the
! the same as the underlying nest. So try this:
c_ips = -1
nj = ( c_jds - j_parent_start ) * parent_grid_ratio + 1 + 1 ;
ierr = 0
DO i = c_ids, c_ide
ni = ( i - i_parent_start ) * parent_grid_ratio + 1 + 1 ;
CALL task_for_point ( ni, nj, ids, ide, jds, jde, ntasks_x, ntasks_y, Px, Py, &
1, 1, ierr )
IF ( Px .EQ. mytask_x ) THEN
c_ipe = i
IF ( c_ips .EQ. -1 ) c_ips = i
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
IF (c_ips .EQ. -1 ) THEN
c_ipe = -1
c_ips = 0
ENDIF
c_jps = -1
ni = ( c_ids - i_parent_start ) * parent_grid_ratio + 1 + 1 ;
ierr = 0
DO j = c_jds, c_jde
nj = ( j - j_parent_start ) * parent_grid_ratio + 1 + 1 ;
CALL task_for_point ( ni, nj, ids, ide, jds, jde, ntasks_x, ntasks_y, Px, Py, &
1, 1, ierr )
IF ( Py .EQ. mytask_y ) THEN
c_jpe = j
IF ( c_jps .EQ. -1 ) c_jps = j
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
IF (c_jps .EQ. -1 ) THEN
c_jpe = -1
c_jps = 0
ENDIF
IF ( c_ips <= c_ipe ) THEN
! extend the patch dimensions out shw along edges of domain
IF ( mytask_x .EQ. 0 ) THEN
c_ips = c_ips - shw
ENDIF
IF ( mytask_x .EQ. ntasks_x-1 ) THEN
c_ipe = c_ipe + shw
ENDIF
c_ims = max( c_ips - max(shw,thisdomain_max_halo_width), c_ids - bdx ) - 1
c_ime = min( c_ipe + max(shw,thisdomain_max_halo_width), c_ide + bdx ) + 1
ELSE
c_ims = 0
c_ime = 0
ENDIF
! handle j dims
IF ( c_jps <= c_jpe ) THEN
! extend the patch dimensions out shw along edges of domain
IF ( mytask_y .EQ. 0 ) THEN
c_jps = c_jps - shw
ENDIF
IF ( mytask_y .EQ. ntasks_y-1 ) THEN
c_jpe = c_jpe + shw
ENDIF
c_jms = max( c_jps - max(shw,thisdomain_max_halo_width), c_jds - bdx ) - 1
c_jme = min( c_jpe + max(shw,thisdomain_max_halo_width), c_jde + bdx ) + 1
! handle k dims
ELSE
c_jms = 0
c_jme = 0
ENDIF
c_kps = 1
c_kpe = c_kde
c_kms = 1
c_kme = c_kde
WRITE(wrf_err_message,*)'*************************************'
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'Nesting domain'
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ids,ide,jds,jde ',ids,ide,jds,jde
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ims,ime,jms,jme ',ims,ime,jms,jme
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ips,ipe,jps,jpe ',ips,ipe,jps,jpe
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'INTERMEDIATE domain'
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ids,ide,jds,jde ',c_ids,c_ide,c_jds,c_jde
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ims,ime,jms,jme ',c_ims,c_ime,c_jms,c_jme
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'ips,ipe,jps,jpe ',c_ips,c_ipe,c_jps,c_jpe
CALL wrf_message( TRIM(wrf_err_message) )
WRITE(wrf_err_message,*)'*************************************'
CALL wrf_message( TRIM(wrf_err_message) )
SELECT CASE ( model_data_order )
CASE ( DATA_ORDER_ZXY )
c_sd2 = c_ids ; c_ed2 = c_ide ; c_sp2 = c_ips ; c_ep2 = c_ipe ; c_sm2 = c_ims ; c_em2 = c_ime
c_sd3 = c_jds ; c_ed3 = c_jde ; c_sp3 = c_jps ; c_ep3 = c_jpe ; c_sm3 = c_jms ; c_em3 = c_jme
c_sd1 = c_kds ; c_ed1 = c_kde ; c_sp1 = c_kps ; c_ep1 = c_kpe ; c_sm1 = c_kms ; c_em1 = c_kme
CASE ( DATA_ORDER_ZYX )
c_sd3 = c_ids ; c_ed3 = c_ide ; c_sp3 = c_ips ; c_ep3 = c_ipe ; c_sm3 = c_ims ; c_em3 = c_ime
c_sd2 = c_jds ; c_ed2 = c_jde ; c_sp2 = c_jps ; c_ep2 = c_jpe ; c_sm2 = c_jms ; c_em2 = c_jme
c_sd1 = c_kds ; c_ed1 = c_kde ; c_sp1 = c_kps ; c_ep1 = c_kpe ; c_sm1 = c_kms ; c_em1 = c_kme
CASE ( DATA_ORDER_XYZ )
c_sd1 = c_ids ; c_ed1 = c_ide ; c_sp1 = c_ips ; c_ep1 = c_ipe ; c_sm1 = c_ims ; c_em1 = c_ime
c_sd2 = c_jds ; c_ed2 = c_jde ; c_sp2 = c_jps ; c_ep2 = c_jpe ; c_sm2 = c_jms ; c_em2 = c_jme
c_sd3 = c_kds ; c_ed3 = c_kde ; c_sp3 = c_kps ; c_ep3 = c_kpe ; c_sm3 = c_kms ; c_em3 = c_kme
CASE ( DATA_ORDER_YXZ)
c_sd2 = c_ids ; c_ed2 = c_ide ; c_sp2 = c_ips ; c_ep2 = c_ipe ; c_sm2 = c_ims ; c_em2 = c_ime
c_sd1 = c_jds ; c_ed1 = c_jde ; c_sp1 = c_jps ; c_ep1 = c_jpe ; c_sm1 = c_jms ; c_em1 = c_jme
c_sd3 = c_kds ; c_ed3 = c_kde ; c_sp3 = c_kps ; c_ep3 = c_kpe ; c_sm3 = c_kms ; c_em3 = c_kme
CASE ( DATA_ORDER_XZY )
c_sd1 = c_ids ; c_ed1 = c_ide ; c_sp1 = c_ips ; c_ep1 = c_ipe ; c_sm1 = c_ims ; c_em1 = c_ime
c_sd3 = c_jds ; c_ed3 = c_jde ; c_sp3 = c_jps ; c_ep3 = c_jpe ; c_sm3 = c_jms ; c_em3 = c_jme
c_sd2 = c_kds ; c_ed2 = c_kde ; c_sp2 = c_kps ; c_ep2 = c_kpe ; c_sm2 = c_kms ; c_em2 = c_kme
CASE ( DATA_ORDER_YZX )
c_sd3 = c_ids ; c_ed3 = c_ide ; c_sp3 = c_ips ; c_ep3 = c_ipe ; c_sm3 = c_ims ; c_em3 = c_ime
c_sd1 = c_jds ; c_ed1 = c_jde ; c_sp1 = c_jps ; c_ep1 = c_jpe ; c_sm1 = c_jms ; c_em1 = c_jme
c_sd2 = c_kds ; c_ed2 = c_kde ; c_sp2 = c_kps ; c_ep2 = c_kpe ; c_sm2 = c_kms ; c_em2 = c_kme
END SELECT
ALLOCATE ( intermediate_grid )
ALLOCATE ( intermediate_grid%parents( max_parents ) )
ALLOCATE ( intermediate_grid%nests( max_nests ) )
intermediate_grid%allocated=.false.
NULLIFY( intermediate_grid%sibling )
DO i = 1, max_nests
NULLIFY( intermediate_grid%nests(i)%ptr )
ENDDO
NULLIFY (intermediate_grid%next)
NULLIFY (intermediate_grid%same_level)
NULLIFY (intermediate_grid%i_start)
NULLIFY (intermediate_grid%j_start)
NULLIFY (intermediate_grid%i_end)
NULLIFY (intermediate_grid%j_end)
intermediate_grid%id = id ! these must be the same. Other parts of code depend on it (see gen_comms.c)
intermediate_grid%num_nests = 0
intermediate_grid%num_siblings = 0
intermediate_grid%num_parents = 1
intermediate_grid%max_tiles = 0
intermediate_grid%num_tiles_spec = 0
CALL find_grid_by_id ( id, head_grid, nest_grid )
nest_grid%intermediate_grid => intermediate_grid ! nest grid now has a pointer to this baby
intermediate_grid%parents(1)%ptr => nest_grid ! the intermediate grid considers nest its parent
intermediate_grid%num_parents = 1
intermediate_grid%is_intermediate = .TRUE.
SELECT CASE ( model_data_order )
CASE ( DATA_ORDER_ZXY )
intermediate_grid%nids = nest_grid%sd32 ; intermediate_grid%njds = nest_grid%sd33
intermediate_grid%nide = nest_grid%ed32 ; intermediate_grid%njde = nest_grid%sd33
CASE ( DATA_ORDER_ZYX )
intermediate_grid%nids = nest_grid%sd33 ; intermediate_grid%njds = nest_grid%sd32
intermediate_grid%nide = nest_grid%ed33 ; intermediate_grid%njde = nest_grid%sd32
CASE ( DATA_ORDER_XYZ )
intermediate_grid%nids = nest_grid%sd31 ; intermediate_grid%njds = nest_grid%sd32
intermediate_grid%nide = nest_grid%ed31 ; intermediate_grid%njde = nest_grid%sd32
CASE ( DATA_ORDER_YXZ)
intermediate_grid%nids = nest_grid%sd32 ; intermediate_grid%njds = nest_grid%sd31
intermediate_grid%nide = nest_grid%ed32 ; intermediate_grid%njde = nest_grid%sd31
CASE ( DATA_ORDER_XZY )
intermediate_grid%nids = nest_grid%sd31 ; intermediate_grid%njds = nest_grid%sd33
intermediate_grid%nide = nest_grid%ed31 ; intermediate_grid%njde = nest_grid%sd33
CASE ( DATA_ORDER_YZX )
intermediate_grid%nids = nest_grid%sd33 ; intermediate_grid%njds = nest_grid%sd31
intermediate_grid%nide = nest_grid%ed33 ; intermediate_grid%njde = nest_grid%sd31
END SELECT
intermediate_grid%nids = ids
intermediate_grid%nide = ide
intermediate_grid%njds = jds
intermediate_grid%njde = jde
c_sm1x = 1 ; c_em1x = 1 ; c_sm2x = 1 ; c_em2x = 1 ; c_sm3x = 1 ; c_em3x = 1
c_sm1y = 1 ; c_em1y = 1 ; c_sm2y = 1 ; c_em2y = 1 ; c_sm3y = 1 ; c_em3y = 1
intermediate_grid%sm31x = c_sm1x
intermediate_grid%em31x = c_em1x
intermediate_grid%sm32x = c_sm2x
intermediate_grid%em32x = c_em2x
intermediate_grid%sm33x = c_sm3x
intermediate_grid%em33x = c_em3x
intermediate_grid%sm31y = c_sm1y
intermediate_grid%em31y = c_em1y
intermediate_grid%sm32y = c_sm2y
intermediate_grid%em32y = c_em2y
intermediate_grid%sm33y = c_sm3y
intermediate_grid%em33y = c_em3y
#if defined(SGIALTIX) && (! defined(MOVE_NESTS) )
! allocate space for the intermediate domain
CALL alloc_space_field ( intermediate_grid, intermediate_grid%id , 1, 2 , .TRUE., & ! use same id as nest
c_sd1, c_ed1, c_sd2, c_ed2, c_sd3, c_ed3, &
c_sm1, c_em1, c_sm2, c_em2, c_sm3, c_em3, &
c_sm1x, c_em1x, c_sm2x, c_em2x, c_sm3x, c_em3x, &
c_sm1y, c_em1y, c_sm2y, c_em2y, c_sm3y, c_em3y, &
c_sm1x, c_em1x, c_sm2x, c_em2x, c_sm3x, c_em3x, & ! x-xpose
c_sm1y, c_em1y, c_sm2y, c_em2y, c_sm3y, c_em3y ) ! y-xpose
#endif
intermediate_grid%sd31 = c_sd1
intermediate_grid%ed31 = c_ed1
intermediate_grid%sp31 = c_sp1
intermediate_grid%ep31 = c_ep1
intermediate_grid%sm31 = c_sm1
intermediate_grid%em31 = c_em1
intermediate_grid%sd32 = c_sd2
intermediate_grid%ed32 = c_ed2
intermediate_grid%sp32 = c_sp2
intermediate_grid%ep32 = c_ep2
intermediate_grid%sm32 = c_sm2
intermediate_grid%em32 = c_em2
intermediate_grid%sd33 = c_sd3
intermediate_grid%ed33 = c_ed3
intermediate_grid%sp33 = c_sp3
intermediate_grid%ep33 = c_ep3
intermediate_grid%sm33 = c_sm3
intermediate_grid%em33 = c_em3
CALL med_add_config_info_to_grid ( intermediate_grid )
intermediate_grid%dx = parent%dx
intermediate_grid%dy = parent%dy
intermediate_grid%dt = parent%dt
ENDIF
RETURN
END SUBROUTINE patch_domain_rsl_lite
SUBROUTINE compute_memory_dims_rsl_lite ( &
id , maxhalowidth , &
shw , bdx, bdy , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
imsx, imex, jmsx, jmex, kmsx, kmex, &
imsy, imey, jmsy, jmey, kmsy, kmey, &
ips, ipe, jps, jpe, kps, kpe, &
ipsx, ipex, jpsx, jpex, kpsx, kpex, &
ipsy, ipey, jpsy, jpey, kpsy, kpey )
IMPLICIT NONE
INTEGER, INTENT(IN) :: id , maxhalowidth
INTEGER, INTENT(IN) :: shw, bdx, bdy
INTEGER, INTENT(IN) :: ids, ide, jds, jde, kds, kde
INTEGER, INTENT(OUT) :: ims, ime, jms, jme, kms, kme
INTEGER, INTENT(OUT) :: imsx, imex, jmsx, jmex, kmsx, kmex
INTEGER, INTENT(OUT) :: imsy, imey, jmsy, jmey, kmsy, kmey
INTEGER, INTENT(OUT) :: ips, ipe, jps, jpe, kps, kpe
INTEGER, INTENT(OUT) :: ipsx, ipex, jpsx, jpex, kpsx, kpex
INTEGER, INTENT(OUT) :: ipsy, ipey, jpsy, jpey, kpsy, kpey
INTEGER Px, Py, P, i, j, k, ierr
#if ( ! NMM_CORE == 1 )
! xy decomposition
ips = -1
j = jds
ierr = 0
DO i = ids, ide
CALL task_for_point ( i, j, ids, ide, jds, jde, ntasks_x, ntasks_y, Px, Py, &
1, 1, ierr )
IF ( Px .EQ. mytask_x ) THEN
ipe = i
IF ( ips .EQ. -1 ) ips = i
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
! handle setting the memory dimensions where there are no X elements assigned to this proc
IF (ips .EQ. -1 ) THEN
ipe = -1
ips = 0
ENDIF
jps = -1
i = ids
ierr = 0
DO j = jds, jde
CALL task_for_point ( i, j, ids, ide, jds, jde, ntasks_x, ntasks_y, Px, Py, &
1, 1, ierr )
IF ( Py .EQ. mytask_y ) THEN
jpe = j
IF ( jps .EQ. -1 ) jps = j
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
! handle setting the memory dimensions where there are no Y elements assigned to this proc
IF (jps .EQ. -1 ) THEN
jpe = -1
jps = 0
ENDIF
!begin: wig; 12-Mar-2008
! This appears redundant with the conditionals above, but we get cases with only
! one of the directions being set to "missing" when turning off extra processors.
! This may break the handling of setting only one of nproc_x or nproc_y via the namelist.
IF (ipe .EQ. -1 .or. jpe .EQ. -1) THEN
ipe = -1
ips = 0
jpe = -1
jps = 0
ENDIF
!end: wig; 12-Mar-2008
!
! description of transpose decomposition strategy for RSL LITE. 20061231jm
!
! Here is the tranpose scheme that is implemented for RSL_LITE. Upper-case
! XY corresponds to the dimension of the processor mesh, lower-case xyz
! corresponds to grid dimension.
!
! xy zy zx
!
! XxYy <--> XzYy <--> XzYx <- note x decomposed over Y procs
! ^ ^
! | |
! +------------------+ <- this edge is costly; see below
!
! The aim is to avoid all-to-all communication over whole
! communicator. Instead, when possible, use a transpose scheme that requires
! all-to-all within dimensional communicators; that is, communicators
! defined for the processes in a rank or column of the processor mesh. Note,
! however, it is not possible to create a ring of transposes between
! xy-yz-xz decompositions without at least one of the edges in the ring
! being fully all-to-all (in other words, one of the tranpose edges must
! rotate and not just transpose a plane of the model grid within the
! processor mesh). The issue is then, where should we put this costly edge
! in the tranpose scheme we chose? To avoid being completely arbitrary,
! we chose a scheme most natural for models that use parallel spectral
! transforms, where the costly edge is the one that goes from the xz to
! the xy decomposition. (May be implemented as just a two step transpose
! back through yz).
!
! Additional notational convention, below. The 'x' or 'y' appended to the
! dimension start or end variable refers to which grid dimension is all
! on-processor in the given decomposition. That is ipsx and ipex are the
! start and end for the i-dimension in the zy decomposition where x is
! on-processor. ('z' is assumed for xy decomposition and not appended to
! the ips, ipe, etc. variable names).
!
! XzYy decomposition
kpsx = -1
j = jds ;
ierr = 0
DO k = kds, kde
CALL task_for_point ( k, j, kds, kde, jds, jde, ntasks_x, ntasks_y, Px, Py, &
1, 1, ierr )
IF ( Px .EQ. mytask_x ) THEN
kpex = k
IF ( kpsx .EQ. -1 ) kpsx = k
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
! handle case where no levels are assigned to this process
! no iterations. Do same for I and J. Need to handle memory alloc below.
IF (kpsx .EQ. -1 ) THEN
kpex = -1
kpsx = 0
ENDIF
jpsx = -1
k = kds ;
ierr = 0
DO j = jds, jde
CALL task_for_point ( k, j, kds, kde, jds, jde, ntasks_x, ntasks_y, Px, Py, &
1, 1, ierr )
IF ( Py .EQ. mytask_y ) THEN
jpex = j
IF ( jpsx .EQ. -1 ) jpsx = j
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
IF (jpsx .EQ. -1 ) THEN
jpex = -1
jpsx = 0
ENDIF
!begin: wig; 12-Mar-2008
! This appears redundant with the conditionals above, but we get cases with only
! one of the directions being set to "missing" when turning off extra processors.
! This may break the handling of setting only one of nproc_x or nproc_y via the namelist.
IF (ipex .EQ. -1 .or. jpex .EQ. -1) THEN
ipex = -1
ipsx = 0
jpex = -1
jpsx = 0
ENDIF
!end: wig; 12-Mar-2008
! XzYx decomposition (note, x grid dim is decomposed over Y processor dim)
kpsy = kpsx ! same as above
kpey = kpex ! same as above
ipsy = -1
k = kds ;
ierr = 0
DO i = ids, ide
CALL task_for_point ( i, k, ids, ide, kds, kde, ntasks_y, ntasks_x, Py, Px, &
1, 1, ierr ) ! x and y for proc mesh reversed
IF ( Py .EQ. mytask_y ) THEN
ipey = i
IF ( ipsy .EQ. -1 ) ipsy = i
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
IF (ipsy .EQ. -1 ) THEN
ipey = -1
ipsy = 0
ENDIF
#else
! In case of NMM CORE, the domain only ever runs from ids..ide-1 and jds..jde-1 so
! adjust decomposition to reflect. 20051020 JM
ips = -1
j = jds
ierr = 0
DO i = ids, ide-1
CALL task_for_point ( i, j, ids, ide-1, jds, jde-1, ntasks_x, ntasks_y, Px, Py, &
1, 1 , ierr )
IF ( Px .EQ. mytask_x ) THEN
ipe = i
IF ( Px .EQ. ntasks_x-1 ) ipe = ipe + 1
IF ( ips .EQ. -1 ) ips = i
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
jps = -1
i = ids ;
ierr = 0
DO j = jds, jde-1
CALL task_for_point ( i, j, ids, ide-1, jds, jde-1, ntasks_x, ntasks_y, Px, Py, &
1 , 1 , ierr )
IF ( Py .EQ. mytask_y ) THEN
jpe = j
IF ( Py .EQ. ntasks_y-1 ) jpe = jpe + 1
IF ( jps .EQ. -1 ) jps = j
ENDIF
ENDDO
IF ( ierr .NE. 0 ) THEN
CALL tfp_message(__FILE__,__LINE__)
ENDIF
#endif
! extend the patch dimensions out shw along edges of domain
IF ( ips < ipe .and. jps < jpe ) THEN !wig; 11-Mar-2008
IF ( mytask_x .EQ. 0 ) THEN
ips = ips - shw
ipsy = ipsy - shw
ENDIF
IF ( mytask_x .EQ. ntasks_x-1 ) THEN
ipe = ipe + shw
ipey = ipey + shw
ENDIF
IF ( mytask_y .EQ. 0 ) THEN
jps = jps - shw
jpsx = jpsx - shw
ENDIF
IF ( mytask_y .EQ. ntasks_y-1 ) THEN
jpe = jpe + shw
jpex = jpex + shw
ENDIF
ENDIF !wig; 11-Mar-2008
kps = 1
kpe = kde-kds+1
kms = 1
kme = kpe
kmsx = kpsx
kmex = kpex
kmsy = kpsy
kmey = kpey
! handle setting the memory dimensions where there are no levels assigned to this proc
IF ( kpsx .EQ. 0 .AND. kpex .EQ. -1 ) THEN
kmsx = 0
kmex = 0
ENDIF
IF ( kpsy .EQ. 0 .AND. kpey .EQ. -1 ) THEN
kmsy = 0
kmey = 0
ENDIF
IF ( (jps .EQ. 0 .AND. jpe .EQ. -1) .OR. (ips .EQ. 0 .AND. ipe .EQ. -1) ) THEN
ims = 0
ime = 0
ELSE
ims = max( ips - max(shw,maxhalowidth), ids - bdx ) - 1
ime = min( ipe + max(shw,maxhalowidth), ide + bdx ) + 1
ENDIF
imsx = ids
imex = ide
ipsx = imsx
ipex = imex
! handle setting the memory dimensions where there are no Y elements assigned to this proc
IF ( ipsy .EQ. 0 .AND. ipey .EQ. -1 ) THEN
imsy = 0
imey = 0
ELSE
imsy = ipsy
imey = ipey
ENDIF
IF ( (jps .EQ. 0 .AND. jpe .EQ. -1) .OR. (ips .EQ. 0 .AND. ipe .EQ. -1) ) THEN
jms = 0
jme = 0
ELSE
jms = max( jps - max(shw,maxhalowidth), jds - bdy ) - 1
jme = min( jpe + max(shw,maxhalowidth), jde + bdy ) + 1
ENDIF
jmsx = jpsx
jmex = jpex
jmsy = jds
jmey = jde
! handle setting the memory dimensions where there are no X elements assigned to this proc
IF ( jpsx .EQ. 0 .AND. jpex .EQ. -1 ) THEN
jmsx = 0
jmex = 0
ELSE
jpsy = jmsy
jpey = jmey
ENDIF
END SUBROUTINE compute_memory_dims_rsl_lite
! internal, used below for switching the argument to MPI calls
! if reals are being autopromoted to doubles in the build of WRF
INTEGER function getrealmpitype()
#ifndef STUBMPI
IMPLICIT NONE
INCLUDE 'mpif.h'
INTEGER rtypesize, dtypesize, ierr
CALL mpi_type_size ( MPI_REAL, rtypesize, ierr )
CALL mpi_type_size ( MPI_DOUBLE_PRECISION, dtypesize, ierr )
IF ( RWORDSIZE .EQ. rtypesize ) THEN
getrealmpitype = MPI_REAL
ELSE IF ( RWORDSIZE .EQ. dtypesize ) THEN
getrealmpitype = MPI_DOUBLE_PRECISION
ELSE
CALL wrf_error_fatal ( 'RWORDSIZE or DWORDSIZE does not match any MPI type' )
ENDIF
#else
! required dummy initialization for function that is never called
getrealmpitype = 1
#endif
RETURN
END FUNCTION getrealmpitype
REAL FUNCTION wrf_dm_max_real ( inval )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
REAL inval, retval
INTEGER ierr
CALL mpi_allreduce ( inval, retval , 1, getrealmpitype(), MPI_MAX, local_communicator, ierr )
wrf_dm_max_real = retval
#else
REAL inval
wrf_dm_max_real = inval
#endif
END FUNCTION wrf_dm_max_real
REAL FUNCTION wrf_dm_min_real ( inval )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
REAL inval, retval
INTEGER ierr
CALL mpi_allreduce ( inval, retval , 1, getrealmpitype(), MPI_MIN, local_communicator, ierr )
wrf_dm_min_real = retval
#else
REAL inval
wrf_dm_min_real = inval
#endif
END FUNCTION wrf_dm_min_real
SUBROUTINE wrf_dm_min_reals ( inval, retval, n )
IMPLICIT NONE
INTEGER n
REAL inval(*)
REAL retval(*)
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER ierr
CALL mpi_allreduce ( inval, retval , n, getrealmpitype(), MPI_MIN, local_communicator, ierr )
#else
retval(1:n) = inval(1:n)
#endif
END SUBROUTINE wrf_dm_min_reals
REAL FUNCTION wrf_dm_sum_real ( inval )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
REAL inval, retval
INTEGER ierr
CALL mpi_allreduce ( inval, retval , 1, getrealmpitype(), MPI_SUM, local_communicator, ierr )
wrf_dm_sum_real = retval
#else
REAL inval
wrf_dm_sum_real = inval
#endif
END FUNCTION wrf_dm_sum_real
SUBROUTINE wrf_dm_sum_reals (inval, retval)
IMPLICIT NONE
REAL, INTENT(IN) :: inval(:)
REAL, INTENT(OUT) :: retval(:)
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER ierr
CALL mpi_allreduce ( inval, retval, SIZE(inval), getrealmpitype(), MPI_SUM, local_communicator, ierr )
#else
retval = inval
#endif
END SUBROUTINE wrf_dm_sum_reals
INTEGER FUNCTION wrf_dm_sum_integer ( inval )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER inval, retval
INTEGER ierr
CALL mpi_allreduce ( inval, retval , 1, MPI_INTEGER, MPI_SUM, local_communicator, ierr )
wrf_dm_sum_integer = retval
#else
INTEGER inval
wrf_dm_sum_integer = inval
#endif
END FUNCTION wrf_dm_sum_integer
INTEGER FUNCTION wrf_dm_bxor_integer ( inval )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER inval, retval
INTEGER ierr
CALL mpi_allreduce ( inval, retval , 1, MPI_INTEGER, MPI_BXOR, local_communicator, ierr )
wrf_dm_bxor_integer = retval
#else
INTEGER inval
wrf_dm_bxor_integer = inval
#endif
END FUNCTION wrf_dm_bxor_integer
SUBROUTINE wrf_dm_maxval_real ( val, idex, jdex )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
REAL val, val_all( ntasks )
INTEGER idex, jdex, ierr
INTEGER dex(2)
INTEGER dex_all (2,ntasks)
INTEGER i
dex(1) = idex ; dex(2) = jdex
CALL mpi_allgather ( dex, 2, MPI_INTEGER, dex_all , 2, MPI_INTEGER, local_communicator, ierr )
CALL mpi_allgather ( val, 1, getrealmpitype(), val_all , 1, getrealmpitype(), local_communicator, ierr )
val = val_all(1)
idex = dex_all(1,1) ; jdex = dex_all(2,1)
DO i = 2, ntasks
IF ( val_all(i) .GT. val ) THEN
val = val_all(i)
idex = dex_all(1,i)
jdex = dex_all(2,i)
ENDIF
ENDDO
#else
REAL val
INTEGER idex, jdex, ierr
#endif
END SUBROUTINE wrf_dm_maxval_real
#ifndef PROMOTE_FLOAT
SUBROUTINE wrf_dm_maxval_doubleprecision ( val, idex, jdex )
IMPLICIT NONE
# ifndef STUBMPI
INCLUDE 'mpif.h'
DOUBLE PRECISION val, val_all( ntasks )
INTEGER idex, jdex, ierr
INTEGER dex(2)
INTEGER dex_all (2,ntasks)
INTEGER i
dex(1) = idex ; dex(2) = jdex
CALL mpi_allgather ( dex, 2, MPI_INTEGER, dex_all , 2, MPI_INTEGER, local_communicator, ierr )
CALL mpi_allgather ( val, 1, MPI_DOUBLE_PRECISION, val_all , 1, MPI_DOUBLE_PRECISION, local_communicator, ierr )
val = val_all(1)
idex = dex_all(1,1) ; jdex = dex_all(2,1)
DO i = 2, ntasks
IF ( val_all(i) .GT. val ) THEN
val = val_all(i)
idex = dex_all(1,i)
jdex = dex_all(2,i)
ENDIF
ENDDO
# else
DOUBLE PRECISION val
INTEGER idex, jdex, ierr
# endif
END SUBROUTINE wrf_dm_maxval_doubleprecision
#endif
SUBROUTINE wrf_dm_maxval_integer ( val, idex, jdex )
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER val, val_all( ntasks )
INTEGER idex, jdex, ierr
INTEGER dex(2)
INTEGER dex_all (2,ntasks)
INTEGER i
dex(1) = idex ; dex(2) = jdex
CALL mpi_allgather ( dex, 2, MPI_INTEGER, dex_all , 2, MPI_INTEGER, local_communicator, ierr )
CALL mpi_allgather ( val, 1, MPI_INTEGER, val_all , 1, MPI_INTEGER, local_communicator, ierr )
val = val_all(1)
idex = dex_all(1,1) ; jdex = dex_all(2,1)
DO i = 2, ntasks
IF ( val_all(i) .GT. val ) THEN
val = val_all(i)
idex = dex_all(1,i)
jdex = dex_all(2,i)
ENDIF
ENDDO
#else
INTEGER val
INTEGER idex, jdex
#endif
END SUBROUTINE wrf_dm_maxval_integer
! For HWRF some additional computation is required. This is gopal's doing
SUBROUTINE wrf_dm_minval_real ( val, idex, jdex )
IMPLICIT NONE
REAL val, val_all( ntasks )
INTEGER idex, jdex, ierr
INTEGER dex(2)
INTEGER dex_all (2,ntasks)
!
! Collective operation. Each processor calls passing a local value and its index; on return
! all processors are passed back the maximum of all values passed and its index.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
dex(1) = idex ; dex(2) = jdex
CALL mpi_allgather ( dex, 2, MPI_INTEGER, dex_all , 2, MPI_INTEGER, comm, ierr )
CALL mpi_allgather ( val, 1, MPI_REAL, val_all , 1, MPI_REAL, comm, ierr )
val = val_all(1)
idex = dex_all(1,1) ; jdex = dex_all(2,1)
DO i = 2, ntasks
IF ( val_all(i) .LT. val ) THEN
val = val_all(i)
idex = dex_all(1,i)
jdex = dex_all(2,i)
ENDIF
ENDDO
#endif
END SUBROUTINE wrf_dm_minval_real
#ifndef PROMOTE_FLOAT
SUBROUTINE wrf_dm_minval_doubleprecision ( val, idex, jdex )
IMPLICIT NONE
DOUBLE PRECISION val, val_all( ntasks )
INTEGER idex, jdex, ierr
INTEGER dex(2)
INTEGER dex_all (2,ntasks)
!
! Collective operation. Each processor calls passing a local value and its index; on return
! all processors are passed back the maximum of all values passed and its index.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
dex(1) = idex ; dex(2) = jdex
CALL mpi_allgather ( dex, 2, MPI_INTEGER, dex_all , 2, MPI_INTEGER, comm, ierr )
CALL mpi_allgather ( val, 1, MPI_DOUBLE_PRECISION, val_all , 1, MPI_DOUBLE_PRECISION, comm, ierr )
val = val_all(1)
idex = dex_all(1,1) ; jdex = dex_all(2,1)
DO i = 2, ntasks
IF ( val_all(i) .LT. val ) THEN
val = val_all(i)
idex = dex_all(1,i)
jdex = dex_all(2,i)
ENDIF
ENDDO
#endif
END SUBROUTINE wrf_dm_minval_doubleprecision
#endif
SUBROUTINE wrf_dm_minval_integer ( val, idex, jdex )
IMPLICIT NONE
INTEGER val, val_all( ntasks )
INTEGER idex, jdex, ierr
INTEGER dex(2)
INTEGER dex_all (2,ntasks)
!
! Collective operation. Each processor calls passing a local value and its index; on return
! all processors are passed back the maximum of all values passed and its index.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
dex(1) = idex ; dex(2) = jdex
CALL mpi_allgather ( dex, 2, MPI_INTEGER, dex_all , 2, MPI_INTEGER, comm, ierr )
CALL mpi_allgather ( val, 1, MPI_INTEGER, val_all , 1, MPI_INTEGER, comm, ierr )
val = val_all(1)
idex = dex_all(1,1) ; jdex = dex_all(2,1)
DO i = 2, ntasks
IF ( val_all(i) .LT. val ) THEN
val = val_all(i)
idex = dex_all(1,i)
jdex = dex_all(2,i)
ENDIF
ENDDO
#endif
END SUBROUTINE wrf_dm_minval_integer ! End of gopal's doing
SUBROUTINE split_communicator
#ifndef STUBMPI
IMPLICIT NONE
INCLUDE 'mpif.h'
LOGICAL mpi_inited
INTEGER mpi_comm_here, mpi_comm_local, comdup, mytask, ntasks, ierr, io_status
# if defined(_OPENMP) && defined(MPI2_THREAD_SUPPORT)
INTEGER thread_support_provided, thread_support_requested
#endif
INTEGER i, j
INTEGER, ALLOCATABLE :: icolor(:)
INTEGER tasks_per_split
NAMELIST /namelist_split/ tasks_per_split
CALL MPI_INITIALIZED( mpi_inited, ierr )
IF ( .NOT. mpi_inited ) THEN
# if defined(_OPENMP) && defined(MPI2_THREAD_SUPPORT)
thread_support_requested = MPI_THREAD_FUNNELED
CALL mpi_init_thread ( thread_support_requested, thread_support_provided, ierr )
IF ( thread_support_provided .lt. thread_support_requested ) THEN
CALL WRF_ERROR_FATAL( "failed to initialize MPI thread support")
ENDIF
# else
CALL mpi_init ( ierr )
# endif
mpi_comm_here = MPI_COMM_WORLD
#ifdef HWRF
CALL atm_cmp_start( mpi_comm_here ) ! atmospheric side of HWRF coupler will split MPI_COMM_WORLD and return communicator as argument
#endif
CALL wrf_set_dm_communicator( mpi_comm_here )
ENDIF
CALL wrf_get_dm_communicator( mpi_comm_here )
CALL wrf_termio_dup( mpi_comm_here )
CALL MPI_Comm_rank ( mpi_comm_here, mytask, ierr ) ;
CALL mpi_comm_size ( mpi_comm_here, ntasks, ierr ) ;
IF ( mytask .EQ. 0 ) THEN
OPEN ( unit=27, file="namelist.input", form="formatted", status="old" )
tasks_per_split = ntasks
READ ( 27 , NML = namelist_split, IOSTAT=io_status )
CLOSE ( 27 )
ENDIF
CALL mpi_bcast( io_status, 1 , MPI_INTEGER , 0 , mpi_comm_here, ierr )
IF ( io_status .NE. 0 ) THEN
RETURN ! just ignore and return
ENDIF
CALL mpi_bcast( tasks_per_split, 1 , MPI_INTEGER , 0 , mpi_comm_here, ierr )
IF ( tasks_per_split .GT. ntasks .OR. tasks_per_split .LE. 0 ) RETURN
IF ( mod( ntasks, tasks_per_split ) .NE. 0 ) THEN
CALL wrf_message( 'WARNING: tasks_per_split does not evenly divide ntasks. Some tasks will be wasted.' )
ENDIF
ALLOCATE( icolor(ntasks) )
j = 0
DO WHILE ( j .LT. ntasks / tasks_per_split )
DO i = 1, tasks_per_split
icolor( i + j * tasks_per_split ) = j
ENDDO
j = j + 1
ENDDO
CALL MPI_Comm_dup(mpi_comm_here,comdup,ierr)
CALL MPI_Comm_split(comdup,icolor(mytask+1),mytask,mpi_comm_local,ierr)
CALL wrf_set_dm_communicator( mpi_comm_local )
DEALLOCATE( icolor )
#endif
END SUBROUTINE split_communicator
SUBROUTINE init_module_dm
#ifndef STUBMPI
IMPLICIT NONE
INTEGER mpi_comm_local, mpi_comm_here, ierr, mytask, nproc
INCLUDE 'mpif.h'
LOGICAL mpi_inited
CALL mpi_initialized( mpi_inited, ierr )
IF ( .NOT. mpi_inited ) THEN
! If MPI has not been initialized then initialize it and
! make comm_world the communicator
! Otherwise, something else (e.g. split_communicator) has already
! initialized MPI, so just grab the communicator that
! should already be stored and use that.
CALL mpi_init ( ierr )
mpi_comm_here = MPI_COMM_WORLD
CALL wrf_set_dm_communicator ( mpi_comm_here )
ENDIF
CALL wrf_get_dm_communicator( mpi_comm_local )
CALL wrf_termio_dup( mpi_comm_local )
#endif
END SUBROUTINE init_module_dm
! stub
SUBROUTINE wrf_dm_move_nest ( parent, nest, dx, dy )
USE module_domain, ONLY : domain
IMPLICIT NONE
TYPE (domain), INTENT(INOUT) :: parent, nest
INTEGER, INTENT(IN) :: dx,dy
RETURN
END SUBROUTINE wrf_dm_move_nest
!------------------------------------------------------------------------------
SUBROUTINE get_full_obs_vector( nsta, nerrf, niobf, &
mp_local_uobmask, &
mp_local_vobmask, &
mp_local_cobmask, errf )
!------------------------------------------------------------------------------
! PURPOSE: Do MPI allgatherv operation across processors to get the
! errors at each observation point on all processors.
!
!------------------------------------------------------------------------------
INTEGER, INTENT(IN) :: nsta ! Observation index.
INTEGER, INTENT(IN) :: nerrf ! Number of error fields.
INTEGER, INTENT(IN) :: niobf ! Number of observations.
LOGICAL, INTENT(IN) :: MP_LOCAL_UOBMASK(NIOBF)
LOGICAL, INTENT(IN) :: MP_LOCAL_VOBMASK(NIOBF)
LOGICAL, INTENT(IN) :: MP_LOCAL_COBMASK(NIOBF)
REAL, INTENT(INOUT) :: errf(nerrf, niobf)
#ifndef STUBMPI
INCLUDE 'mpif.h'
! Local declarations
integer i, n, nlocal_dot, nlocal_crs
REAL UVT_BUFFER(NIOBF) ! Buffer for holding U, V, or T
REAL QRK_BUFFER(NIOBF) ! Buffer for holding Q or RKO
REAL SFP_BUFFER(NIOBF) ! Buffer for holding Surface pressure
REAL PBL_BUFFER(NIOBF) ! Buffer for holding (real) KPBL index
INTEGER N_BUFFER(NIOBF)
REAL FULL_BUFFER(NIOBF)
INTEGER IFULL_BUFFER(NIOBF)
INTEGER IDISPLACEMENT(1024) ! HARD CODED MAX NUMBER OF PROCESSORS
INTEGER ICOUNT(1024) ! HARD CODED MAX NUMBER OF PROCESSORS
INTEGER :: MPI_COMM_COMP ! MPI group communicator
INTEGER :: NPROCS ! Number of processors
INTEGER :: IERR ! Error code from MPI routines
! Get communicator for MPI operations.
CALL WRF_GET_DM_COMMUNICATOR(MPI_COMM_COMP)
! Get rank of monitor processor and broadcast to others.
CALL MPI_COMM_SIZE( MPI_COMM_COMP, NPROCS, IERR )
! DO THE U FIELD
NLOCAL_DOT = 0
DO N = 1, NSTA
IF ( MP_LOCAL_UOBMASK(N) ) THEN ! USE U-POINT MASK
NLOCAL_DOT = NLOCAL_DOT + 1
UVT_BUFFER(NLOCAL_DOT) = ERRF(1,N) ! U WIND COMPONENT
SFP_BUFFER(NLOCAL_DOT) = ERRF(7,N) ! SURFACE PRESSURE
QRK_BUFFER(NLOCAL_DOT) = ERRF(9,N) ! RKO
N_BUFFER(NLOCAL_DOT) = N
ENDIF
ENDDO
CALL MPI_ALLGATHER(NLOCAL_DOT,1,MPI_INTEGER, &
ICOUNT,1,MPI_INTEGER, &
MPI_COMM_COMP,IERR)
I = 1
IDISPLACEMENT(1) = 0
DO I = 2, NPROCS
IDISPLACEMENT(I) = IDISPLACEMENT(I-1) + ICOUNT(I-1)
ENDDO
CALL MPI_ALLGATHERV( N_BUFFER, NLOCAL_DOT, MPI_INTEGER, &
IFULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_INTEGER, MPI_COMM_COMP, IERR)
! U
CALL MPI_ALLGATHERV( UVT_BUFFER, NLOCAL_DOT, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(1,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! SURF PRESS AT U-POINTS
CALL MPI_ALLGATHERV( SFP_BUFFER, NLOCAL_DOT, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(7,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! RKO
CALL MPI_ALLGATHERV( QRK_BUFFER, NLOCAL_DOT, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(9,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! DO THE V FIELD
NLOCAL_DOT = 0
DO N = 1, NSTA
IF ( MP_LOCAL_VOBMASK(N) ) THEN ! USE V-POINT MASK
NLOCAL_DOT = NLOCAL_DOT + 1
UVT_BUFFER(NLOCAL_DOT) = ERRF(2,N) ! V WIND COMPONENT
SFP_BUFFER(NLOCAL_DOT) = ERRF(8,N) ! SURFACE PRESSURE
N_BUFFER(NLOCAL_DOT) = N
ENDIF
ENDDO
CALL MPI_ALLGATHER(NLOCAL_DOT,1,MPI_INTEGER, &
ICOUNT,1,MPI_INTEGER, &
MPI_COMM_COMP,IERR)
I = 1
IDISPLACEMENT(1) = 0
DO I = 2, NPROCS
IDISPLACEMENT(I) = IDISPLACEMENT(I-1) + ICOUNT(I-1)
ENDDO
CALL MPI_ALLGATHERV( N_BUFFER, NLOCAL_DOT, MPI_INTEGER, &
IFULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_INTEGER, MPI_COMM_COMP, IERR)
! V
CALL MPI_ALLGATHERV( UVT_BUFFER, NLOCAL_DOT, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(2,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! SURF PRESS AT V-POINTS
CALL MPI_ALLGATHERV( SFP_BUFFER, NLOCAL_DOT, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(8,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! DO THE CROSS FIELDS, T AND Q
NLOCAL_CRS = 0
DO N = 1, NSTA
IF ( MP_LOCAL_COBMASK(N) ) THEN ! USE MASS-POINT MASK
NLOCAL_CRS = NLOCAL_CRS + 1
UVT_BUFFER(NLOCAL_CRS) = ERRF(3,N) ! TEMPERATURE
QRK_BUFFER(NLOCAL_CRS) = ERRF(4,N) ! MOISTURE
PBL_BUFFER(NLOCAL_CRS) = ERRF(5,N) ! KPBL
SFP_BUFFER(NLOCAL_CRS) = ERRF(6,N) ! SURFACE PRESSURE
N_BUFFER(NLOCAL_CRS) = N
ENDIF
ENDDO
CALL MPI_ALLGATHER(NLOCAL_CRS,1,MPI_INTEGER, &
ICOUNT,1,MPI_INTEGER, &
MPI_COMM_COMP,IERR)
IDISPLACEMENT(1) = 0
DO I = 2, NPROCS
IDISPLACEMENT(I) = IDISPLACEMENT(I-1) + ICOUNT(I-1)
ENDDO
CALL MPI_ALLGATHERV( N_BUFFER, NLOCAL_CRS, MPI_INTEGER, &
IFULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_INTEGER, MPI_COMM_COMP, IERR)
! T
CALL MPI_ALLGATHERV( UVT_BUFFER, NLOCAL_CRS, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(3,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! Q
CALL MPI_ALLGATHERV( QRK_BUFFER, NLOCAL_CRS, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(4,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! KPBL
CALL MPI_ALLGATHERV( PBL_BUFFER, NLOCAL_CRS, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(5,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
! SURF PRESS AT MASS POINTS
CALL MPI_ALLGATHERV( SFP_BUFFER, NLOCAL_CRS, MPI_REAL, &
FULL_BUFFER, ICOUNT, IDISPLACEMENT, &
MPI_REAL, MPI_COMM_COMP, IERR)
DO N = 1, NSTA
ERRF(6,IFULL_BUFFER(N)) = FULL_BUFFER(N)
ENDDO
#endif
END SUBROUTINE get_full_obs_vector
SUBROUTINE wrf_dm_maxtile_real ( val , tile)
IMPLICIT NONE
REAL val, val_all( ntasks )
INTEGER tile
INTEGER ierr
!
! Collective operation. Each processor calls passing a local value and its index; on return
! all processors are passed back the maximum of all values passed and its tile number.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
CALL mpi_allgather ( val, 1, getrealmpitype(), val_all , 1, getrealmpitype(), comm, ierr )
val = val_all(1)
tile = 1
DO i = 2, ntasks
IF ( val_all(i) .GT. val ) THEN
tile = i
val = val_all(i)
ENDIF
ENDDO
#endif
END SUBROUTINE wrf_dm_maxtile_real
SUBROUTINE wrf_dm_mintile_real ( val , tile)
IMPLICIT NONE
REAL val, val_all( ntasks )
INTEGER tile
INTEGER ierr
!
! Collective operation. Each processor calls passing a local value and its index; on return
! all processors are passed back the minimum of all values passed and its tile number.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
CALL mpi_allgather ( val, 1, getrealmpitype(), val_all , 1, getrealmpitype(), comm, ierr )
val = val_all(1)
tile = 1
DO i = 2, ntasks
IF ( val_all(i) .LT. val ) THEN
tile = i
val = val_all(i)
ENDIF
ENDDO
#endif
END SUBROUTINE wrf_dm_mintile_real
SUBROUTINE wrf_dm_mintile_double ( val , tile)
IMPLICIT NONE
DOUBLE PRECISION val, val_all( ntasks )
INTEGER tile
INTEGER ierr
!
! Collective operation. Each processor calls passing a local value and its index; on return
! all processors are passed back the minimum of all values passed and its tile number.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
CALL mpi_allgather ( val, 1, MPI_DOUBLE_PRECISION, val_all , 1, MPI_DOUBLE_PRECISION, comm, ierr )
val = val_all(1)
tile = 1
DO i = 2, ntasks
IF ( val_all(i) .LT. val ) THEN
tile = i
val = val_all(i)
ENDIF
ENDDO
#endif
END SUBROUTINE wrf_dm_mintile_double
SUBROUTINE wrf_dm_tile_val_int ( val , tile)
IMPLICIT NONE
INTEGER val, val_all( ntasks )
INTEGER tile
INTEGER ierr
!
! Collective operation. Get value from input tile.
!
!
INTEGER i, comm
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL wrf_get_dm_communicator ( comm )
CALL mpi_allgather ( val, 1, MPI_INTEGER, val_all , 1, MPI_INTEGER, comm, ierr )
val = val_all(tile)
#endif
END SUBROUTINE wrf_dm_tile_val_int
SUBROUTINE wrf_get_hostname ( str )
CHARACTER*(*) str
CHARACTER tmp(512)
INTEGER i , n, cs
CALL rsl_lite_get_hostname( tmp, 512, n, cs )
DO i = 1, n
str(i:i) = tmp(i)
ENDDO
RETURN
END SUBROUTINE wrf_get_hostname
SUBROUTINE wrf_get_hostid ( hostid )
INTEGER hostid
CHARACTER tmp(512)
INTEGER i, sz, n, cs
CALL rsl_lite_get_hostname( tmp, 512, n, cs )
hostid = cs
RETURN
END SUBROUTINE wrf_get_hostid
END MODULE module_dm
!=========================================================================
! wrf_dm_patch_domain has to be outside the module because it is called
! by a routine in module_domain but depends on module domain
SUBROUTINE wrf_dm_patch_domain ( id , domdesc , parent_id , parent_domdesc , &
sd1 , ed1 , sp1 , ep1 , sm1 , em1 , &
sd2 , ed2 , sp2 , ep2 , sm2 , em2 , &
sd3 , ed3 , sp3 , ep3 , sm3 , em3 , &
sp1x , ep1x , sm1x , em1x , &
sp2x , ep2x , sm2x , em2x , &
sp3x , ep3x , sm3x , em3x , &
sp1y , ep1y , sm1y , em1y , &
sp2y , ep2y , sm2y , em2y , &
sp3y , ep3y , sm3y , em3y , &
bdx , bdy )
USE module_domain, ONLY : domain, head_grid, find_grid_by_id
USE module_dm, ONLY : patch_domain_rsl_lite
IMPLICIT NONE
INTEGER, INTENT(IN) :: sd1 , ed1 , sd2 , ed2 , sd3 , ed3 , bdx , bdy
INTEGER, INTENT(OUT) :: sp1 , ep1 , sp2 , ep2 , sp3 , ep3 , &
sm1 , em1 , sm2 , em2 , sm3 , em3
INTEGER :: sp1x , ep1x , sp2x , ep2x , sp3x , ep3x , &
sm1x , em1x , sm2x , em2x , sm3x , em3x
INTEGER :: sp1y , ep1y , sp2y , ep2y , sp3y , ep3y , &
sm1y , em1y , sm2y , em2y , sm3y , em3y
INTEGER, INTENT(INOUT):: id , domdesc , parent_id , parent_domdesc
TYPE(domain), POINTER :: parent
TYPE(domain), POINTER :: grid_ptr
! this is necessary because we cannot pass parent directly into
! wrf_dm_patch_domain because creating the correct interface definitions
! would generate a circular USE reference between module_domain and module_dm
! see comment this date in module_domain for more information. JM 20020416
NULLIFY( parent )
grid_ptr => head_grid
CALL find_grid_by_id( parent_id , grid_ptr , parent )
CALL patch_domain_rsl_lite ( id , parent, parent_id , &
sd1 , ed1 , sp1 , ep1 , sm1 , em1 , &
sd2 , ed2 , sp2 , ep2 , sm2 , em2 , &
sd3 , ed3 , sp3 , ep3 , sm3 , em3 , &
sp1x , ep1x , sm1x , em1x , &
sp2x , ep2x , sm2x , em2x , &
sp3x , ep3x , sm3x , em3x , &
sp1y , ep1y , sm1y , em1y , &
sp2y , ep2y , sm2y , em2y , &
sp3y , ep3y , sm3y , em3y , &
bdx , bdy )
RETURN
END SUBROUTINE wrf_dm_patch_domain
SUBROUTINE wrf_termio_dup( comm )
IMPLICIT NONE
INTEGER, INTENT(IN) :: comm
INTEGER mytask, ntasks
#ifndef STUBMPI
INTEGER ierr
INCLUDE 'mpif.h'
CALL mpi_comm_size(comm, ntasks, ierr )
CALL mpi_comm_rank(comm, mytask, ierr )
write(0,*)'starting wrf task ',mytask,' of ',ntasks
CALL rsl_error_dup1( mytask )
#else
mytask = 0
ntasks = 1
#endif
END SUBROUTINE wrf_termio_dup
SUBROUTINE wrf_get_myproc( myproc )
USE module_dm , ONLY : mytask
IMPLICIT NONE
INTEGER myproc
myproc = mytask
RETURN
END SUBROUTINE wrf_get_myproc
SUBROUTINE wrf_get_nproc( nproc )
USE module_dm , ONLY : ntasks
IMPLICIT NONE
INTEGER nproc
nproc = ntasks
RETURN
END SUBROUTINE wrf_get_nproc
SUBROUTINE wrf_get_nprocx( nprocx )
USE module_dm , ONLY : ntasks_x
IMPLICIT NONE
INTEGER nprocx
nprocx = ntasks_x
RETURN
END SUBROUTINE wrf_get_nprocx
SUBROUTINE wrf_get_nprocy( nprocy )
USE module_dm , ONLY : ntasks_y
IMPLICIT NONE
INTEGER nprocy
nprocy = ntasks_y
RETURN
END SUBROUTINE wrf_get_nprocy
SUBROUTINE wrf_dm_bcast_bytes ( buf , size )
USE module_dm , ONLY : local_communicator
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
#endif
INTEGER size
#ifndef NEC
INTEGER*1 BUF(size)
#else
CHARACTER*1 BUF(size)
#endif
#ifndef STUBMPI
CALL BYTE_BCAST ( buf , size, local_communicator )
#endif
RETURN
END SUBROUTINE wrf_dm_bcast_bytes
SUBROUTINE wrf_dm_bcast_string( BUF, N1 )
IMPLICIT NONE
INTEGER n1
!
! Collective operation. Given a string and a size in characters on task zero, broadcast and return that buffer on all tasks.
!
!
CHARACTER*(*) buf
#ifndef STUBMPI
INTEGER ibuf(256),i,n
CHARACTER*256 tstr
n = n1
! Root task is required to have the correct value of N1, other tasks
! might not have the correct value.
CALL wrf_dm_bcast_integer( n , 1 )
IF (n .GT. 256) n = 256
IF (n .GT. 0 ) then
DO i = 1, n
ibuf(I) = ichar(buf(I:I))
ENDDO
CALL wrf_dm_bcast_integer( ibuf, n )
buf = ''
DO i = 1, n
buf(i:i) = char(ibuf(i))
ENDDO
ENDIF
#endif
RETURN
END SUBROUTINE wrf_dm_bcast_string
SUBROUTINE wrf_dm_bcast_integer( BUF, N1 )
IMPLICIT NONE
INTEGER n1
INTEGER buf(*)
CALL wrf_dm_bcast_bytes ( BUF , N1 * IWORDSIZE )
RETURN
END SUBROUTINE wrf_dm_bcast_integer
SUBROUTINE wrf_dm_bcast_double( BUF, N1 )
IMPLICIT NONE
INTEGER n1
! this next declaration is REAL, not DOUBLE PRECISION because it will be autopromoted
! to double precision by the compiler when WRF is compiled for 8 byte reals. Only reason
! for having this separate routine is so we pass the correct MPI type to mpi_scatterv
! since we were not indexing the globbuf and Field arrays it does not matter
REAL buf(*)
CALL wrf_dm_bcast_bytes ( BUF , N1 * DWORDSIZE )
RETURN
END SUBROUTINE wrf_dm_bcast_double
SUBROUTINE wrf_dm_bcast_real( BUF, N1 )
IMPLICIT NONE
INTEGER n1
REAL buf(*)
CALL wrf_dm_bcast_bytes ( BUF , N1 * RWORDSIZE )
RETURN
END SUBROUTINE wrf_dm_bcast_real
SUBROUTINE wrf_dm_bcast_logical( BUF, N1 )
IMPLICIT NONE
INTEGER n1
LOGICAL buf(*)
CALL wrf_dm_bcast_bytes ( BUF , N1 * LWORDSIZE )
RETURN
END SUBROUTINE wrf_dm_bcast_logical
SUBROUTINE write_68( grid, v , s , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
its, ite, jts, jte, kts, kte )
USE module_domain, ONLY : domain
IMPLICIT NONE
TYPE(domain) , INTENT (INOUT) :: grid
CHARACTER *(*) s
INTEGER ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
its, ite, jts, jte, kts, kte
REAL, DIMENSION( ims:ime , kms:kme, jms:jme ) :: v
INTEGER i,j,k,ierr
logical, external :: wrf_dm_on_monitor
real globbuf( ids:ide, kds:kde, jds:jde )
character*3 ord, stag
if ( kds == kde ) then
ord = 'xy'
stag = 'xy'
CALL wrf_patch_to_global_real ( v, globbuf, grid%domdesc, stag, ord, &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
its, ite, jts, jte, kts, kte )
else
stag = 'xyz'
ord = 'xzy'
CALL wrf_patch_to_global_real ( v, globbuf, grid%domdesc, stag, ord, &
ids, ide, kds, kde, jds, jde, &
ims, ime, kms, kme, jms, jme, &
its, ite, kts, kte, jts, jte )
endif
if ( wrf_dm_on_monitor() ) THEN
WRITE(68,*) ide-ids+1, jde-jds+1 , s
DO j = jds, jde
DO i = ids, ide
WRITE(68,*) globbuf(i,1,j)
ENDDO
ENDDO
endif
RETURN
END
SUBROUTINE wrf_abort
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER ierr
CALL mpi_abort(MPI_COMM_WORLD,1,ierr)
#else
STOP
#endif
END SUBROUTINE wrf_abort
SUBROUTINE wrf_dm_shutdown
IMPLICIT NONE
#ifndef STUBMPI
INTEGER ierr
CALL MPI_FINALIZE( ierr )
#endif
RETURN
END SUBROUTINE wrf_dm_shutdown
LOGICAL FUNCTION wrf_dm_on_monitor()
IMPLICIT NONE
#ifndef STUBMPI
INCLUDE 'mpif.h'
INTEGER tsk, ierr, mpi_comm_local
CALL wrf_get_dm_communicator( mpi_comm_local )
CALL mpi_comm_rank ( mpi_comm_local, tsk , ierr )
wrf_dm_on_monitor = tsk .EQ. 0
#else
wrf_dm_on_monitor = .TRUE.
#endif
RETURN
END FUNCTION wrf_dm_on_monitor
SUBROUTINE rsl_comm_iter_init(shw,ps,pe)
INTEGER shw, ps, pe
INTEGER iter, plus_send_start, plus_recv_start, &
minus_send_start, minus_recv_start
COMMON /rcii/ iter, plus_send_start, plus_recv_start, &
minus_send_start, minus_recv_start
iter = 0
minus_send_start = ps
minus_recv_start = ps-1
plus_send_start = pe
plus_recv_start = pe+1
END SUBROUTINE rsl_comm_iter_init
LOGICAL FUNCTION rsl_comm_iter ( id , is_intermediate, &
shw , xy , ds, de_in, ps, pe, nds,nde, &
sendbeg_m, sendw_m, sendbeg_p, sendw_p, &
recvbeg_m, recvw_m, recvbeg_p, recvw_p )
USE module_dm, ONLY : ntasks_x, ntasks_y, mytask_x, mytask_y
IMPLICIT NONE
INTEGER, INTENT(IN) :: id,shw,xy,ds,de_in,ps,pe,nds,nde
LOGICAL, INTENT(IN) :: is_intermediate ! treated differently, coarse but with same decomp as nest
INTEGER, INTENT(OUT) :: sendbeg_m, sendw_m, sendbeg_p, sendw_p
INTEGER, INTENT(OUT) :: recvbeg_m, recvw_m, recvbeg_p, recvw_p
INTEGER k, kn, ni, nj, de, Px, Py, nt, me, lb, ub, ierr
LOGICAL went
INTEGER iter, plus_send_start, plus_recv_start, &
minus_send_start, minus_recv_start
INTEGER parent_grid_ratio, parent_start
COMMON /rcii/ iter, plus_send_start, plus_recv_start, &
minus_send_start, minus_recv_start
#if (NMM_CORE == 1 )
! In case of NMM CORE, the domain only ever runs from ids..ide-1 and jds..jde-1 so
! adjust decomposition to reflect. 20081206 JM
de = de_in - 1
#else
de = de_in
#endif
IF ( xy .EQ. 1 ) THEN ! X/I axis
nt = ntasks_x
me = mytask_x
IF ( is_intermediate ) THEN
CALL nl_get_i_parent_start(id,parent_start)
CALL nl_get_parent_grid_ratio(id,parent_grid_ratio)
ENDIF
ELSE
nt = ntasks_y
me = mytask_y
IF ( is_intermediate ) THEN
CALL nl_get_j_parent_start(id,parent_start)
CALL nl_get_parent_grid_ratio(id,parent_grid_ratio)
ENDIF
ENDIF
iter = iter + 1
#if (DA_CORE == 0)
went = .FALSE.
! send to minus
sendw_m = 0
sendbeg_m = 1
IF ( me .GT. 0 ) THEN
lb = minus_send_start
sendbeg_m = lb-ps+1
DO k = lb,ps+shw-1
went = .TRUE.
IF ( is_intermediate ) THEN
kn = ( k - parent_start ) * parent_grid_ratio + 1 + 1 ;
CALL task_for_point (kn,1,nds,nde,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ELSE
CALL task_for_point (k,1,ds,de,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ENDIF
IF ( Px .NE. me+(iter-1) ) THEN
exit
ENDIF
minus_send_start = minus_send_start+1
sendw_m = sendw_m + 1
ENDDO
ENDIF
! recv from minus
recvw_m = 0
recvbeg_m = 1
IF ( me .GT. 0 ) THEN
ub = minus_recv_start
recvbeg_m = ps - ub
DO k = minus_recv_start,ps-shw,-1
went = .TRUE.
IF ( is_intermediate ) THEN
kn = ( k - parent_start ) * parent_grid_ratio + 1 + 1 ;
CALL task_for_point (kn,1,nds,nde,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ELSE
CALL task_for_point (k,1,ds,de,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ENDIF
IF ( Px .NE. me-iter ) THEN
exit
ENDIF
minus_recv_start = minus_recv_start-1
recvw_m = recvw_m + 1
ENDDO
ENDIF
! send to plus
sendw_p = 0
sendbeg_p = 1
IF ( me .LT. nt-1 ) THEN
ub = plus_send_start
sendbeg_p = pe - ub + 1
DO k = ub,pe-shw+1,-1
went = .TRUE.
IF ( is_intermediate ) THEN
kn = ( k - parent_start ) * parent_grid_ratio + 1 + 1 ;
CALL task_for_point (kn,1,nds,nde,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ELSE
CALL task_for_point (k,1,ds,de,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ENDIF
IF ( Px .NE. me-(iter-1) ) THEN
exit
ENDIF
plus_send_start = plus_send_start - 1
sendw_p = sendw_p + 1
ENDDO
ENDIF
! recv from plus
recvw_p = 0
recvbeg_p = 1
IF ( me .LT. nt-1 ) THEN
lb = plus_recv_start
recvbeg_p = lb - pe
DO k = lb,pe+shw
went = .TRUE.
IF ( is_intermediate ) THEN
kn = ( k - parent_start ) * parent_grid_ratio + 1 + 1 ;
CALL task_for_point (kn,1,nds,nde,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ELSE
CALL task_for_point (k,1,ds,de,1,1,nt,1,Px,Py,1,1,ierr) ! assume same alg. for x and y and just use x
ENDIF
IF ( Px .NE. me+iter ) THEN
exit
ENDIF
plus_recv_start = plus_recv_start + 1
recvw_p = recvw_p + 1
ENDDO
ENDIF
#else
if ( iter .eq. 1 ) then
went = .true.
else
went = .false.
endif
sendw_m = 0 ; sendw_p = 0 ; recvw_m = 0 ; recvw_p = 0
sendbeg_m = 1 ; if ( me .GT. 0 ) sendw_m = shw ;
sendbeg_p = 1 ; if ( me .LT. nt-1 ) sendw_p = shw
recvbeg_m = 1 ; if ( me .GT. 0 ) recvw_m = shw ;
recvbeg_p = 1 ; if ( me .LT. nt-1 ) recvw_p = shw ;
! write(0,*)'shw ', shw , ' xy ',xy
! write(0,*)' ds, de, ps, pe, nds,nde ',ds, de, ps, pe, nds,nde
! write(0,*)'sendbeg_m, sendw_m, sendbeg_p, sendw_p, recvbeg_m, recvw_m, recvbeg_p, recvw_p '
! write(0,*)sendbeg_m, sendw_m, sendbeg_p, sendw_p, recvbeg_m, recvw_m, recvbeg_p, recvw_p
#endif
!if ( went ) then
! write(0,*)'shw ', shw , ' xy ',xy
! write(0,*)' ds, de, ps, pe, nds,nde ',ds, de, ps, pe, nds,nde
! write(0,*)'sendbeg_m, sendw_m, sendbeg_p, sendw_p, recvbeg_m, recvw_m, recvbeg_p, recvw_p '
! write(0,*)sendbeg_m, sendw_m, sendbeg_p, sendw_p, recvbeg_m, recvw_m, recvbeg_p, recvw_p
!endif
rsl_comm_iter = went
END FUNCTION rsl_comm_iter
INTEGER FUNCTION wrf_dm_monitor_rank()
IMPLICIT NONE
wrf_dm_monitor_rank = 0
RETURN
END FUNCTION wrf_dm_monitor_rank
SUBROUTINE wrf_get_dm_communicator ( communicator )
USE module_dm , ONLY : local_communicator
IMPLICIT NONE
INTEGER , INTENT(OUT) :: communicator
communicator = local_communicator
RETURN
END SUBROUTINE wrf_get_dm_communicator
SUBROUTINE wrf_get_dm_communicator_x ( communicator )
USE module_dm , ONLY : local_communicator_x
IMPLICIT NONE
INTEGER , INTENT(OUT) :: communicator
communicator = local_communicator_x
RETURN
END SUBROUTINE wrf_get_dm_communicator_x
SUBROUTINE wrf_get_dm_communicator_y ( communicator )
USE module_dm , ONLY : local_communicator_y
IMPLICIT NONE
INTEGER , INTENT(OUT) :: communicator
communicator = local_communicator_y
RETURN
END SUBROUTINE wrf_get_dm_communicator_y
SUBROUTINE wrf_get_dm_iocommunicator ( iocommunicator )
USE module_dm , ONLY : local_iocommunicator
IMPLICIT NONE
INTEGER , INTENT(OUT) :: iocommunicator
iocommunicator = local_iocommunicator
RETURN
END SUBROUTINE wrf_get_dm_iocommunicator
SUBROUTINE wrf_set_dm_communicator ( communicator )
USE module_dm , ONLY : local_communicator
IMPLICIT NONE
INTEGER , INTENT(IN) :: communicator
local_communicator = communicator
RETURN
END SUBROUTINE wrf_set_dm_communicator
SUBROUTINE wrf_set_dm_iocommunicator ( iocommunicator )
USE module_dm , ONLY : local_iocommunicator
IMPLICIT NONE
INTEGER , INTENT(IN) :: iocommunicator
local_iocommunicator = iocommunicator
RETURN
END SUBROUTINE wrf_set_dm_iocommunicator
SUBROUTINE wrf_get_dm_ntasks_x ( retval )
USE module_dm , ONLY : ntasks_x
IMPLICIT NONE
INTEGER , INTENT(OUT) :: retval
retval = ntasks_x
RETURN
END SUBROUTINE wrf_get_dm_ntasks_x
SUBROUTINE wrf_get_dm_ntasks_y ( retval )
USE module_dm , ONLY : ntasks_y
IMPLICIT NONE
INTEGER , INTENT(OUT) :: retval
retval = ntasks_y
RETURN
END SUBROUTINE wrf_get_dm_ntasks_y
!!!!!!!!!!!!!!!!!!!!!!! PATCH TO GLOBAL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SUBROUTINE wrf_patch_to_global_real (buf,globbuf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
REAL globbuf(*)
REAL buf(*)
CALL wrf_patch_to_global_generic (buf,globbuf,domdesc,stagger,ordering,RWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_patch_to_global_real
SUBROUTINE wrf_patch_to_global_double (buf,globbuf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
! this next declaration is REAL, not DOUBLE PRECISION because it will be autopromoted
! to double precision by the compiler when WRF is compiled for 8 byte reals. Only reason
! for having this separate routine is so we pass the correct MPI type to mpi_scatterv
! since we were not indexing the globbuf and Field arrays it does not matter
REAL globbuf(*)
REAL buf(*)
CALL wrf_patch_to_global_generic (buf,globbuf,domdesc,stagger,ordering,DWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_patch_to_global_double
SUBROUTINE wrf_patch_to_global_integer (buf,globbuf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
INTEGER globbuf(*)
INTEGER buf(*)
CALL wrf_patch_to_global_generic (buf,globbuf,domdesc,stagger,ordering,IWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_patch_to_global_integer
SUBROUTINE wrf_patch_to_global_logical (buf,globbuf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
LOGICAL globbuf(*)
LOGICAL buf(*)
CALL wrf_patch_to_global_generic (buf,globbuf,domdesc,stagger,ordering,LWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_patch_to_global_logical
#ifdef DEREF_KLUDGE
# define FRSTELEM (1)
#else
# define FRSTELEM
#endif
SUBROUTINE wrf_patch_to_global_generic (buf,globbuf,domdesc,stagger,ordering,typesize,&
DS1a,DE1a,DS2a,DE2a,DS3a,DE3a,&
MS1a,ME1a,MS2a,ME2a,MS3a,ME3a,&
PS1a,PE1a,PS2a,PE2a,PS3a,PE3a )
USE module_driver_constants
USE module_timing
USE module_wrf_error, ONLY : wrf_at_debug_level
USE module_dm, ONLY : local_communicator, ntasks
IMPLICIT NONE
INTEGER DS1a,DE1a,DS2a,DE2a,DS3a,DE3a,&
MS1a,ME1a,MS2a,ME2a,MS3a,ME3a,&
PS1a,PE1a,PS2a,PE2a,PS3a,PE3A
CHARACTER *(*) stagger,ordering
INTEGER domdesc,typesize,ierr
REAL globbuf(*)
REAL buf(*)
#ifndef STUBMPI
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
INTEGER ids,ide,jds,jde,kds,kde,&
ims,ime,jms,jme,kms,kme,&
ips,ipe,jps,jpe,kps,kpe
LOGICAL, EXTERNAL :: wrf_dm_on_monitor, has_char
INTEGER i, j, k, ndim
INTEGER Patch(3,2), Gpatch(3,2,ntasks)
! allocated further down, after the D indices are potentially recalculated for staggering
REAL, ALLOCATABLE :: tmpbuf( : )
REAL locbuf( (PE1a-PS1a+1)*(PE2a-PS2a+1)*(PE3a-PS3a+1)/RWORDSIZE*typesize+32 )
DS1 = DS1a ; DE1 = DE1a ; DS2=DS2a ; DE2 = DE2a ; DS3 = DS3a ; DE3 = DE3a
MS1 = MS1a ; ME1 = ME1a ; MS2=MS2a ; ME2 = ME2a ; MS3 = MS3a ; ME3 = ME3a
PS1 = PS1a ; PE1 = PE1a ; PS2=PS2a ; PE2 = PE2a ; PS3 = PS3a ; PE3 = PE3a
SELECT CASE ( TRIM(ordering) )
CASE ( 'xy', 'yx' )
ndim = 2
CASE DEFAULT
ndim = 3 ! where appropriate
END SELECT
SELECT CASE ( TRIM(ordering) )
CASE ( 'xyz','xy' )
! the non-staggered variables come in at one-less than
! domain dimensions, but code wants full domain spec, so
! adjust if not staggered
IF ( .NOT. has_char( stagger, 'x' ) ) DE1 = DE1+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE2 = DE2+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE3 = DE3+1
CASE ( 'yxz','yx' )
IF ( .NOT. has_char( stagger, 'x' ) ) DE2 = DE2+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE1 = DE1+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE3 = DE3+1
CASE ( 'zxy' )
IF ( .NOT. has_char( stagger, 'x' ) ) DE2 = DE2+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE3 = DE3+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE1 = DE1+1
CASE ( 'xzy' )
IF ( .NOT. has_char( stagger, 'x' ) ) DE1 = DE1+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE3 = DE3+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE2 = DE2+1
CASE DEFAULT
END SELECT
! moved to here to be after the potential recalculations of D dims
IF ( wrf_dm_on_monitor() ) THEN
ALLOCATE ( tmpbuf ( (DE1-DS1+1)*(DE2-DS2+1)*(DE3-DS3+1)/RWORDSIZE*typesize+32 ), STAT=ierr )
ELSE
ALLOCATE ( tmpbuf ( 1 ), STAT=ierr )
ENDIF
IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating tmpbuf in wrf_patch_to_global_generic')
Patch(1,1) = ps1 ; Patch(1,2) = pe1 ! use patch dims
Patch(2,1) = ps2 ; Patch(2,2) = pe2
Patch(3,1) = ps3 ; Patch(3,2) = pe3
IF ( typesize .EQ. RWORDSIZE ) THEN
CALL just_patch_r ( buf , locbuf , size(locbuf), &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ELSE IF ( typesize .EQ. IWORDSIZE ) THEN
CALL just_patch_i ( buf , locbuf , size(locbuf), &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ELSE IF ( typesize .EQ. DWORDSIZE ) THEN
CALL just_patch_d ( buf , locbuf , size(locbuf), &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ELSE IF ( typesize .EQ. LWORDSIZE ) THEN
CALL just_patch_l ( buf , locbuf , size(locbuf), &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ENDIF
! defined in external/io_quilt
CALL collect_on_comm0 ( local_communicator , IWORDSIZE , &
Patch , 6 , &
GPatch , 6*ntasks )
CALL collect_on_comm0 ( local_communicator , typesize , &
locbuf , (pe1-ps1+1)*(pe2-ps2+1)*(pe3-ps3+1), &
tmpbuf FRSTELEM , (de1-ds1+1)*(de2-ds2+1)*(de3-ds3+1) )
ndim = len(TRIM(ordering))
IF ( wrf_at_debug_level(500) ) THEN
CALL start_timing
ENDIF
IF ( ndim .GE. 2 .AND. wrf_dm_on_monitor() ) THEN
IF ( typesize .EQ. RWORDSIZE ) THEN
CALL patch_2_outbuf_r ( tmpbuf FRSTELEM , globbuf , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ELSE IF ( typesize .EQ. IWORDSIZE ) THEN
CALL patch_2_outbuf_i ( tmpbuf FRSTELEM , globbuf , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ELSE IF ( typesize .EQ. DWORDSIZE ) THEN
CALL patch_2_outbuf_d ( tmpbuf FRSTELEM , globbuf , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ELSE IF ( typesize .EQ. LWORDSIZE ) THEN
CALL patch_2_outbuf_l ( tmpbuf FRSTELEM , globbuf , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ENDIF
ENDIF
IF ( wrf_at_debug_level(500) ) THEN
CALL end_timing('wrf_patch_to_global_generic')
ENDIF
DEALLOCATE( tmpbuf )
#endif
RETURN
END SUBROUTINE wrf_patch_to_global_generic
SUBROUTINE just_patch_i ( inbuf , outbuf, noutbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
INTEGER , INTENT(IN) :: noutbuf
INTEGER , DIMENSION(noutbuf) , INTENT(OUT) :: outbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
INTEGER , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(IN) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( icurs ) = inbuf( i, j, k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE just_patch_i
SUBROUTINE just_patch_r ( inbuf , outbuf, noutbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
INTEGER , INTENT(IN) :: noutbuf
REAL , DIMENSION(noutbuf) , INTENT(OUT) :: outbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
REAL , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(in) :: inbuf
! Local
INTEGER :: i,j,k , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( icurs ) = inbuf( i, j, k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE just_patch_r
SUBROUTINE just_patch_d ( inbuf , outbuf, noutbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
INTEGER , INTENT(IN) :: noutbuf
DOUBLE PRECISION , DIMENSION(noutbuf) , INTENT(OUT) :: outbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
DOUBLE PRECISION , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(in) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( icurs ) = inbuf( i, j, k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE just_patch_d
SUBROUTINE just_patch_l ( inbuf , outbuf, noutbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
INTEGER , INTENT(IN) :: noutbuf
LOGICAL , DIMENSION(noutbuf) , INTENT(OUT) :: outbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
LOGICAL , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(in) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( icurs ) = inbuf( i, j, k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE just_patch_l
SUBROUTINE patch_2_outbuf_r( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3, &
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
REAL , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
REAL , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(out) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( i, j, k ) = inbuf( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE patch_2_outbuf_r
SUBROUTINE patch_2_outbuf_i( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3,&
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
INTEGER , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
INTEGER , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(out) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( i, j, k ) = inbuf( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE patch_2_outbuf_i
SUBROUTINE patch_2_outbuf_d( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3,&
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
DOUBLE PRECISION , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
DOUBLE PRECISION , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(out) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( i, j, k ) = inbuf( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE patch_2_outbuf_d
SUBROUTINE patch_2_outbuf_l( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3,&
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
LOGICAL , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
LOGICAL , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(out) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( i, j, k ) = inbuf( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE patch_2_outbuf_l
!!!!!!!!!!!!!!!!!!!!!!! GLOBAL TO PATCH !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SUBROUTINE wrf_global_to_patch_real (globbuf,buf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
REAL globbuf(*)
REAL buf(*)
CALL wrf_global_to_patch_generic (globbuf,buf,domdesc,stagger,ordering,RWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_global_to_patch_real
SUBROUTINE wrf_global_to_patch_double (globbuf,buf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
! this next declaration is REAL, not DOUBLE PRECISION because it will be autopromoted
! to double precision by the compiler when WRF is compiled for 8 byte reals. Only reason
! for having this separate routine is so we pass the correct MPI type to mpi_scatterv
! since we were not indexing the globbuf and Field arrays it does not matter
REAL globbuf(*)
REAL buf(*)
CALL wrf_global_to_patch_generic (globbuf,buf,domdesc,stagger,ordering,DWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_global_to_patch_double
SUBROUTINE wrf_global_to_patch_integer (globbuf,buf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
INTEGER globbuf(*)
INTEGER buf(*)
CALL wrf_global_to_patch_generic (globbuf,buf,domdesc,stagger,ordering,IWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_global_to_patch_integer
SUBROUTINE wrf_global_to_patch_logical (globbuf,buf,domdesc,stagger,ordering,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
IMPLICIT NONE
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
CHARACTER *(*) stagger,ordering
INTEGER fid,domdesc
LOGICAL globbuf(*)
LOGICAL buf(*)
CALL wrf_global_to_patch_generic (globbuf,buf,domdesc,stagger,ordering,LWORDSIZE,&
DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3 )
RETURN
END SUBROUTINE wrf_global_to_patch_logical
SUBROUTINE wrf_global_to_patch_generic (globbuf,buf,domdesc,stagger,ordering,typesize,&
DS1a,DE1a,DS2a,DE2a,DS3a,DE3a,&
MS1a,ME1a,MS2a,ME2a,MS3a,ME3a,&
PS1a,PE1a,PS2a,PE2a,PS3a,PE3a )
USE module_dm, ONLY : local_communicator, ntasks
USE module_driver_constants
IMPLICIT NONE
INTEGER DS1a,DE1a,DS2a,DE2a,DS3a,DE3a,&
MS1a,ME1a,MS2a,ME2a,MS3a,ME3a,&
PS1a,PE1a,PS2a,PE2a,PS3a,PE3A
CHARACTER *(*) stagger,ordering
INTEGER domdesc,typesize,ierr
REAL globbuf(*)
REAL buf(*)
#ifndef STUBMPI
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,&
MS1,ME1,MS2,ME2,MS3,ME3,&
PS1,PE1,PS2,PE2,PS3,PE3
LOGICAL, EXTERNAL :: wrf_dm_on_monitor, has_char
INTEGER i,j,k,ord,ord2d,ndim
INTEGER Patch(3,2), Gpatch(3,2,ntasks)
REAL, ALLOCATABLE :: tmpbuf( : )
REAL locbuf( (PE1a-PS1a+1)*(PE2a-PS2a+1)*(PE3a-PS3a+1)/RWORDSIZE*typesize+32 )
DS1 = DS1a ; DE1 = DE1a ; DS2=DS2a ; DE2 = DE2a ; DS3 = DS3a ; DE3 = DE3a
MS1 = MS1a ; ME1 = ME1a ; MS2=MS2a ; ME2 = ME2a ; MS3 = MS3a ; ME3 = ME3a
PS1 = PS1a ; PE1 = PE1a ; PS2=PS2a ; PE2 = PE2a ; PS3 = PS3a ; PE3 = PE3a
SELECT CASE ( TRIM(ordering) )
CASE ( 'xy', 'yx' )
ndim = 2
CASE DEFAULT
ndim = 3 ! where appropriate
END SELECT
SELECT CASE ( TRIM(ordering) )
CASE ( 'xyz','xy' )
! the non-staggered variables come in at one-less than
! domain dimensions, but code wants full domain spec, so
! adjust if not staggered
IF ( .NOT. has_char( stagger, 'x' ) ) DE1 = DE1+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE2 = DE2+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE3 = DE3+1
CASE ( 'yxz','yx' )
IF ( .NOT. has_char( stagger, 'x' ) ) DE2 = DE2+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE1 = DE1+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE3 = DE3+1
CASE ( 'zxy' )
IF ( .NOT. has_char( stagger, 'x' ) ) DE2 = DE2+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE3 = DE3+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE1 = DE1+1
CASE ( 'xzy' )
IF ( .NOT. has_char( stagger, 'x' ) ) DE1 = DE1+1
IF ( .NOT. has_char( stagger, 'y' ) ) DE3 = DE3+1
IF ( ndim .EQ. 3 .AND. .NOT. has_char( stagger, 'z' ) ) DE2 = DE2+1
CASE DEFAULT
END SELECT
! moved to here to be after the potential recalculations of D dims
IF ( wrf_dm_on_monitor() ) THEN
ALLOCATE ( tmpbuf ( (DE1-DS1+1)*(DE2-DS2+1)*(DE3-DS3+1)/RWORDSIZE*typesize+32 ), STAT=ierr )
ELSE
ALLOCATE ( tmpbuf ( 1 ), STAT=ierr )
ENDIF
IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating tmpbuf in wrf_global_to_patch_generic')
Patch(1,1) = ps1 ; Patch(1,2) = pe1 ! use patch dims
Patch(2,1) = ps2 ; Patch(2,2) = pe2
Patch(3,1) = ps3 ; Patch(3,2) = pe3
! defined in external/io_quilt
CALL collect_on_comm0 ( local_communicator , IWORDSIZE , &
Patch , 6 , &
GPatch , 6*ntasks )
ndim = len(TRIM(ordering))
IF ( wrf_dm_on_monitor() .AND. ndim .GE. 2 ) THEN
IF ( typesize .EQ. RWORDSIZE ) THEN
CALL outbuf_2_patch_r ( globbuf , tmpbuf FRSTELEM , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 , &
GPATCH )
ELSE IF ( typesize .EQ. IWORDSIZE ) THEN
CALL outbuf_2_patch_i ( globbuf , tmpbuf FRSTELEM , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ELSE IF ( typesize .EQ. DWORDSIZE ) THEN
CALL outbuf_2_patch_d ( globbuf , tmpbuf FRSTELEM , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ELSE IF ( typesize .EQ. LWORDSIZE ) THEN
CALL outbuf_2_patch_l ( globbuf , tmpbuf FRSTELEM , &
DS1, DE1, DS2, DE2, DS3, DE3 , &
GPATCH )
ENDIF
ENDIF
CALL dist_on_comm0 ( local_communicator , typesize , &
tmpbuf FRSTELEM , (de1-ds1+1)*(de2-ds2+1)*(de3-ds3+1) , &
locbuf , (pe1-ps1+1)*(pe2-ps2+1)*(pe3-ps3+1) )
IF ( typesize .EQ. RWORDSIZE ) THEN
CALL all_sub_r ( locbuf , buf , &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ELSE IF ( typesize .EQ. IWORDSIZE ) THEN
CALL all_sub_i ( locbuf , buf , &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ELSE IF ( typesize .EQ. DWORDSIZE ) THEN
CALL all_sub_d ( locbuf , buf , &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ELSE IF ( typesize .EQ. LWORDSIZE ) THEN
CALL all_sub_l ( locbuf , buf , &
PS1, PE1, PS2, PE2, PS3, PE3 , &
MS1, ME1, MS2, ME2, MS3, ME3 )
ENDIF
DEALLOCATE ( tmpbuf )
#endif
RETURN
END SUBROUTINE wrf_global_to_patch_generic
SUBROUTINE all_sub_i ( inbuf , outbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
INTEGER , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
INTEGER , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(OUT) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( i, j, k ) = inbuf ( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE all_sub_i
SUBROUTINE all_sub_r ( inbuf , outbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
REAL , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
REAL , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(OUT) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( i, j, k ) = inbuf ( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE all_sub_r
SUBROUTINE all_sub_d ( inbuf , outbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
DOUBLE PRECISION , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
DOUBLE PRECISION , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(OUT) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( i, j, k ) = inbuf ( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE all_sub_d
SUBROUTINE all_sub_l ( inbuf , outbuf, &
PS1,PE1,PS2,PE2,PS3,PE3, &
MS1,ME1,MS2,ME2,MS3,ME3 )
IMPLICIT NONE
LOGICAL , DIMENSION(*) , INTENT(IN) :: inbuf
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
INTEGER PS1,PE1,PS2,PE2,PS3,PE3
LOGICAL , DIMENSION( MS1:ME1,MS2:ME2,MS3:ME3 ) , INTENT(OUT) :: outbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO k = PS3, PE3
DO j = PS2, PE2
DO i = PS1, PE1
outbuf( i, j, k ) = inbuf ( icurs )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE all_sub_l
SUBROUTINE outbuf_2_patch_r( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3, &
MS1, ME1, MS2, ME2, MS3, ME3 , &
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
REAL , DIMENSION(*) , INTENT(OUT) :: outbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
INTEGER MS1,ME1,MS2,ME2,MS3,ME3
REAL , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(IN) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( icurs ) = inbuf( i,j,k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE outbuf_2_patch_r
SUBROUTINE outbuf_2_patch_i( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3,&
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
INTEGER , DIMENSION(*) , INTENT(OUT) :: outbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
INTEGER , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(IN) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( icurs ) = inbuf( i,j,k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE outbuf_2_patch_i
SUBROUTINE outbuf_2_patch_d( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3,&
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
DOUBLE PRECISION , DIMENSION(*) , INTENT(OUT) :: outbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
DOUBLE PRECISION , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(IN) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( icurs ) = inbuf( i,j,k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE outbuf_2_patch_d
SUBROUTINE outbuf_2_patch_l( inbuf, outbuf, &
DS1,DE1,DS2,DE2,DS3,DE3,&
GPATCH )
USE module_dm, ONLY : ntasks
IMPLICIT NONE
LOGICAL , DIMENSION(*) , INTENT(OUT) :: outbuf
INTEGER DS1,DE1,DS2,DE2,DS3,DE3,GPATCH(3,2,ntasks)
LOGICAL , DIMENSION( DS1:DE1,DS2:DE2,DS3:DE3 ) , INTENT(IN) :: inbuf
! Local
INTEGER :: i,j,k,n , icurs
icurs = 1
DO n = 1, ntasks
DO k = GPATCH( 3,1,n ), GPATCH( 3,2,n )
DO j = GPATCH( 2,1,n ), GPATCH( 2,2,n )
DO i = GPATCH( 1,1,n ), GPATCH( 1,2,n )
outbuf( icurs ) = inbuf( i,j,k )
icurs = icurs + 1
ENDDO
ENDDO
ENDDO
ENDDO
RETURN
END SUBROUTINE outbuf_2_patch_l
!------------------------------------------------------------------
#if ( EM_CORE == 1 && DA_CORE != 1 )
!------------------------------------------------------------------
SUBROUTINE force_domain_em_part2 ( grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, local_communicator, mytask
USE module_comm_nesting_dm, ONLY : halo_force_down_sub
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7,itrace
REAL dummy_xs, dummy_xe, dummy_ys, dummy_ye
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
#include "nest_interpdown_unpack.inc"
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#include "HALO_FORCE_DOWN.inc"
! code here to interpolate the data into the nested domain
# include "nest_forcedown_interp.inc"
RETURN
END SUBROUTINE force_domain_em_part2
!------------------------------------------------------------------
SUBROUTINE interp_domain_em_part1 ( grid, intermediate_grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, &
mytask, get_dm_max_halo_width
USE module_timing
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: intermediate_grid
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
INTEGER iparstrt,jparstrt,sw
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: iids, iide, ijds, ijde, ikds, ikde, &
iims, iime, ijms, ijme, ikms, ikme, &
iips, iipe, ijps, ijpe, ikps, ikpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER icoord, jcoord, idim_cd, jdim_cd, pgr
INTEGER thisdomain_max_halo_width
INTEGER local_comm, myproc, nproc
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_myproc( myproc )
CALL wrf_get_nproc( nproc )
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( intermediate_grid , &
iids, iide, ijds, ijde, ikds, ikde, &
iims, iime, ijms, ijme, ikms, ikme, &
iips, iipe, ijps, ijpe, ikps, ikpe )
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
CALL nl_get_parent_grid_ratio ( ngrid%id, pgr )
CALL nl_get_i_parent_start ( intermediate_grid%id, iparstrt )
CALL nl_get_j_parent_start ( intermediate_grid%id, jparstrt )
CALL nl_get_shw ( intermediate_grid%id, sw )
icoord = iparstrt - sw
jcoord = jparstrt - sw
idim_cd = iide - iids + 1
jdim_cd = ijde - ijds + 1
nlev = ckde - ckds + 1
! get max_halo_width for parent. It may be smaller if it is moad
CALL get_dm_max_halo_width ( grid%id , thisdomain_max_halo_width )
#include "nest_interpdown_pack.inc"
CALL rsl_lite_bcast_msgs( myproc, nproc, local_comm )
RETURN
END SUBROUTINE interp_domain_em_part1
!------------------------------------------------------------------
SUBROUTINE interp_domain_em_part2 ( grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, &
mytask, get_dm_max_halo_width
USE module_comm_nesting_dm, ONLY : halo_interp_down_sub
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER myproc
INTEGER ierr
INTEGER thisdomain_max_halo_width
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
CALL get_dm_max_halo_width ( ngrid%id , thisdomain_max_halo_width )
#include "nest_interpdown_unpack.inc"
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#include "HALO_INTERP_DOWN.inc"
# include "nest_interpdown_interp.inc"
RETURN
END SUBROUTINE interp_domain_em_part2
!------------------------------------------------------------------
SUBROUTINE feedback_nest_prep ( grid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask
USE module_comm_nesting_dm, ONLY : halo_interp_up_sub
IMPLICIT NONE
!
TYPE(domain), TARGET :: grid ! name of the grid being dereferenced (must be "grid")
TYPE (grid_config_rec_type) :: config_flags ! configureation flags, has vertical dim of
! soil temp, moisture, etc., has vertical dim
! of soil categories
#include
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER :: idum1, idum2
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#ifdef DM_PARALLEL
#include "HALO_INTERP_UP.inc"
#endif
END SUBROUTINE feedback_nest_prep
!------------------------------------------------------------------
SUBROUTINE feedback_domain_em_part1 ( grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type, model_config_rec, model_to_grid_config_rec
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE(domain), POINTER :: xgrid
TYPE (grid_config_rec_type) :: config_flags, nconfig_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER local_comm, myproc, nproc, idum1, idum2
INTEGER thisdomain_max_halo_width
INTERFACE
SUBROUTINE feedback_nest_prep ( grid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain
USE module_configure, ONLY : grid_config_rec_type
!
TYPE (grid_config_rec_type) :: config_flags
TYPE(domain), TARGET :: grid
#include
END SUBROUTINE feedback_nest_prep
END INTERFACE
!
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_myproc( myproc )
CALL wrf_get_nproc( nproc )
!
! intermediate grid
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
! nest grid
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
ips_save = ngrid%i_parent_start ! used in feedback_domain_em_part2 below
jps_save = ngrid%j_parent_start
ipe_save = ngrid%i_parent_start + (nide-nids+1) / ngrid%parent_grid_ratio - 1
jpe_save = ngrid%j_parent_start + (njde-njds+1) / ngrid%parent_grid_ratio - 1
! feedback_nest_prep invokes a halo exchange on the ngrid. It is done this way
! in a separate routine because the HALOs need the data to be dereference from the
! grid data structure and, in this routine, the dereferenced fields are related to
! the intermediate domain, not the nest itself. Save the current grid pointer to intermediate
! domain, switch grid to point to ngrid, invoke feedback_nest_prep, then restore grid
! to point to intermediate domain.
CALL model_to_grid_config_rec ( ngrid%id , model_config_rec , nconfig_flags )
CALL set_scalar_indices_from_config ( ngrid%id , idum1 , idum2 )
xgrid => grid
grid => ngrid
CALL feedback_nest_prep ( grid, nconfig_flags &
!
#include "actual_new_args.inc"
!
)
! put things back so grid is intermediate grid
grid => xgrid
CALL set_scalar_indices_from_config ( grid%id , idum1 , idum2 )
! "interp" (basically copy) ngrid onto intermediate grid
#include "nest_feedbackup_interp.inc"
RETURN
END SUBROUTINE feedback_domain_em_part1
!------------------------------------------------------------------
SUBROUTINE feedback_domain_em_part2 ( grid, intermediate_grid, ngrid , config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, domain_clock_get, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type, model_config_rec
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
USE module_comm_nesting_dm, ONLY : halo_interp_up_sub
USE module_utility
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: intermediate_grid
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER icoord, jcoord, idim_cd, jdim_cd
INTEGER local_comm, myproc, nproc
INTEGER iparstrt, jparstrt, sw, thisdomain_max_halo_width
REAL nest_influence
character*256 :: timestr
integer ierr
LOGICAL, EXTERNAL :: cd_feedback_mask
! On entry to this routine,
! "grid" refers to the parent domain
! "intermediate_grid" refers to local copy of parent domain that overlies this patch of nest
! "ngrid" refers to the nest, which is only needed for smoothing on the parent because
! the nest feedback data has already been transferred during em_nest_feedbackup_interp
! in part1, above.
! The way these settings c and n dimensions are set, below, looks backwards but from the point
! of view of the RSL routine rsl_lite_to_parent_info(), call to which is included by
! em_nest_feedbackup_pack, the "n" domain represents the parent domain and the "c" domain
! represents the intermediate domain. The backwards lookingness should be fixed in the gen_comms.c
! registry routine that accompanies RSL_LITE but, just as it's sometimes easier to put up a road
! sign that says "DIP" than fix the dip, at this point it was easier just to write this comment. JM
!
nest_influence = 1.
CALL domain_clock_get( grid, current_timestr=timestr )
CALL get_ijk_from_grid ( intermediate_grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( grid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
CALL nl_get_i_parent_start ( intermediate_grid%id, iparstrt )
CALL nl_get_j_parent_start ( intermediate_grid%id, jparstrt )
CALL nl_get_shw ( intermediate_grid%id, sw )
icoord = iparstrt - sw
jcoord = jparstrt - sw
idim_cd = cide - cids + 1
jdim_cd = cjde - cjds + 1
nlev = ckde - ckds + 1
CALL get_dm_max_halo_width ( grid%id , thisdomain_max_halo_width )
#include "nest_feedbackup_pack.inc"
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_myproc( myproc )
CALL wrf_get_nproc( nproc )
CALL rsl_lite_merge_msgs( myproc, nproc, local_comm )
#define NEST_INFLUENCE(A,B) A = B
#include "nest_feedbackup_unpack.inc"
! smooth coarse grid
CALL get_ijk_from_grid ( ngrid, &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#include "HALO_INTERP_UP.inc"
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
#include "nest_feedbackup_smooth.inc"
RETURN
END SUBROUTINE feedback_domain_em_part2
#endif
#if ( NMM_CORE == 1 && NMM_NEST == 1 )
!==============================================================================
! NMM nesting infrastructure extended from EM core. This is gopal's doing.
!==============================================================================
SUBROUTINE interp_domain_nmm_part1 ( grid, intermediate_grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
USE module_timing
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: intermediate_grid
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
INTEGER iparstrt,jparstrt,sw
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: iids, iide, ijds, ijde, ikds, ikde, &
iims, iime, ijms, ijme, ikms, ikme, &
iips, iipe, ijps, ijpe, ikps, ikpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER icoord, jcoord, idim_cd, jdim_cd, pgr
INTEGER local_comm, myproc, nproc
INTEGER thisdomain_max_halo_width
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_myproc( myproc )
CALL wrf_get_nproc( nproc )
!#define COPY_IN
!#include
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( intermediate_grid , &
iids, iide, ijds, ijde, ikds, ikde, &
iims, iime, ijms, ijme, ikms, ikme, &
iips, iipe, ijps, ijpe, ikps, ikpe )
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
CALL nl_get_parent_grid_ratio ( ngrid%id, pgr )
CALL nl_get_i_parent_start ( intermediate_grid%id, iparstrt )
CALL nl_get_j_parent_start ( intermediate_grid%id, jparstrt )
CALL nl_get_shw ( intermediate_grid%id, sw )
icoord = iparstrt - sw
jcoord = jparstrt - sw
idim_cd = iide - iids + 1
jdim_cd = ijde - ijds + 1
nlev = ckde - ckds + 1
CALL get_dm_max_halo_width ( ngrid%id , thisdomain_max_halo_width )
#include "nest_interpdown_pack.inc"
CALL rsl_lite_bcast_msgs( myproc, nproc, local_comm )
!#define COPY_OUT
!#include
RETURN
END SUBROUTINE interp_domain_nmm_part1
!------------------------------------------------------------------
SUBROUTINE interp_domain_nmm_part2 ( grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
USE module_comm_nesting_dm, ONLY : halo_interp_down_sub
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER myproc
INTEGER ierr
!#ifdef DEREF_KLUDGE
!! see http://www.mmm.ucar.edu/wrf/WG2/topics/deref_kludge.htm
! INTEGER :: sm31 , em31 , sm32 , em32 , sm33 , em33
! INTEGER :: sm31x, em31x, sm32x, em32x, sm33x, em33x
! INTEGER :: sm31y, em31y, sm32y, em32y, sm33y, em33y
!#endif
#include "deref_kludge.h"
!#define COPY_IN
!#include
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
#include "nest_interpdown_unpack.inc"
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#include "HALO_INTERP_DOWN.inc"
#include "nest_interpdown_interp.inc"
!#define COPY_OUT
!#include
RETURN
END SUBROUTINE interp_domain_nmm_part2
!------------------------------------------------------------------
SUBROUTINE force_domain_nmm_part1 ( grid, intermediate_grid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
USE module_timing
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: intermediate_grid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
!#define COPY_IN
!#include
!
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( intermediate_grid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
#include "nest_forcedown_pack.inc"
! WRITE(0,*)'I have completed PACKING of BCs data successfully'
!#define COPY_OUT
!#include
RETURN
END SUBROUTINE force_domain_nmm_part1
!==============================================================================================
SUBROUTINE force_domain_nmm_part2 ( grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
USE module_comm_dm, ONLY : HALO_NMM_FORCE_DOWN1_sub
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
REAL dummy_xs, dummy_xe, dummy_ys, dummy_ye
integer myproc
!#ifdef DEREF_KLUDGE
!! see http://www.mmm.ucar.edu/wrf/WG2/topics/deref_kludge.htm
! INTEGER :: sm31 , em31 , sm32 , em32 , sm33 , em33
! INTEGER :: sm31x, em31x, sm32x, em32x, sm33x, em33x
! INTEGER :: sm31y, em31y, sm32y, em32y, sm33y, em33y
!#endif
#include "deref_kludge.h"
!#define COPY_IN
!#include
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
#include "nest_interpdown_unpack.inc"
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#include "HALO_NMM_FORCE_DOWN1.inc"
! code here to interpolate the data into the nested domain
#include "nest_forcedown_interp.inc"
!#define COPY_OUT
!#include
RETURN
END SUBROUTINE force_domain_nmm_part2
!================================================================================
!
! This routine exists only to call a halo on a domain (the nest)
! gets called from feedback_domain_em_part1, below. This is needed
! because the halo code expects the fields being exchanged to have
! been dereferenced from the grid data structure, but in feedback_domain_em_part1
! the grid data structure points to the coarse domain, not the nest.
! And we want the halo exchange on the nest, so that the code in
! em_nest_feedbackup_interp.inc will work correctly on multi-p. JM 20040308
!
SUBROUTINE feedback_nest_prep_nmm ( grid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
USE module_comm_dm, ONLY : HALO_NMM_WEIGHTS_sub
IMPLICIT NONE
!
TYPE(domain), TARGET :: grid ! name of the grid being dereferenced (must be "grid")
TYPE (grid_config_rec_type) :: config_flags ! configureation flags, has vertical dim of
! soil temp, moisture, etc., has vertical dim
! of soil categories
#include
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER :: idum1, idum2
!#ifdef DEREF_KLUDGE
!! see http://www.mmm.ucar.edu/wrf/WG2/topics/deref_kludge.htm
! INTEGER :: sm31 , em31 , sm32 , em32 , sm33 , em33
! INTEGER :: sm31x, em31x, sm32x, em32x, sm33x, em33x
! INTEGER :: sm31y, em31y, sm32y, em32y, sm33y, em33y
!#endif
#include "deref_kludge.h"
!#define COPY_IN
!#include
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#ifdef DM_PARALLEL
#include "HALO_NMM_WEIGHTS.inc"
#endif
!#define COPY_OUT
!#include
END SUBROUTINE feedback_nest_prep_nmm
!------------------------------------------------------------------
SUBROUTINE feedback_domain_nmm_part1 ( grid, ngrid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type, model_config_rec, model_to_grid_config_rec
USE module_dm, ONLY : ntasks, ntasks_x, ntasks_y, itrace, local_communicator, mytask, &
ipe_save, jpe_save, ips_save, jps_save, get_dm_max_halo_width
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE(domain), POINTER :: xgrid
TYPE (grid_config_rec_type) :: config_flags, nconfig_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER local_comm, myproc, nproc, idum1, idum2
!#ifdef DEREF_KLUDGE
!! see http://www.mmm.ucar.edu/wrf/WG2/topics/deref_kludge.htm
! INTEGER :: sm31 , em31 , sm32 , em32 , sm33 , em33
! INTEGER :: sm31x, em31x, sm32x, em32x, sm33x, em33x
! INTEGER :: sm31y, em31y, sm32y, em32y, sm33y, em33y
!#endif
INTERFACE
SUBROUTINE feedback_nest_prep_nmm ( grid, config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain
USE module_configure, ONLY : grid_config_rec_type
!
TYPE (grid_config_rec_type) :: config_flags
TYPE(domain), TARGET :: grid
#include
END SUBROUTINE feedback_nest_prep_nmm
END INTERFACE
!
!#define COPY_IN
!#include
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_myproc( myproc )
CALL wrf_get_nproc( nproc )
!
! intermediate grid
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
! nest grid
CALL get_ijk_from_grid ( ngrid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nlev = ckde - ckds + 1
ips_save = ngrid%i_parent_start ! +1 not used in ipe_save & jpe_save
jps_save = ngrid%j_parent_start ! because of one extra namelist point
ipe_save = ngrid%i_parent_start + (nide-nids) / ngrid%parent_grid_ratio
jpe_save = ngrid%j_parent_start + (njde-njds) / ngrid%parent_grid_ratio
! feedback_nest_prep invokes a halo exchange on the ngrid. It is done this way
! in a separate routine because the HALOs need the data to be dereference from the
! grid data structure and, in this routine, the dereferenced fields are related to
! the intermediate domain, not the nest itself. Save the current grid pointer to intermediate
! domain, switch grid to point to ngrid, invoke feedback_nest_prep, then restore grid
! to point to intermediate domain.
CALL model_to_grid_config_rec ( ngrid%id , model_config_rec , nconfig_flags )
CALL set_scalar_indices_from_config ( ngrid%id , idum1 , idum2 )
xgrid => grid
grid => ngrid
#include "deref_kludge.h"
CALL feedback_nest_prep_nmm ( grid, config_flags &
!
#include "actual_new_args.inc"
!
)
! put things back so grid is intermediate grid
grid => xgrid
CALL set_scalar_indices_from_config ( grid%id , idum1 , idum2 )
! "interp" (basically copy) ngrid onto intermediate grid
#include "nest_feedbackup_interp.inc"
!#define COPY_OUT
!#include
RETURN
END SUBROUTINE feedback_domain_nmm_part1
!------------------------------------------------------------------
SUBROUTINE feedback_domain_nmm_part2 ( grid, intermediate_grid, ngrid , config_flags &
!
#include "dummy_new_args.inc"
!
)
USE module_state_description
USE module_domain, ONLY : domain, domain_clock_get, get_ijk_from_grid
USE module_configure, ONLY : grid_config_rec_type
USE module_dm, ONLY : get_dm_max_halo_width, ips_save, ipe_save, &
jps_save, jpe_save, ntasks, mytask, ntasks_x, ntasks_y, &
local_communicator, itrace
USE module_comm_nesting_dm, ONLY : halo_interp_up_sub
USE module_utility
IMPLICIT NONE
!
TYPE(domain), POINTER :: grid ! name of the grid being dereferenced (must be "grid")
TYPE(domain), POINTER :: intermediate_grid
TYPE(domain), POINTER :: ngrid
#include
INTEGER nlev, msize
INTEGER i,j,pig,pjg,cm,cn,nig,njg,retval,k
TYPE (grid_config_rec_type) :: config_flags
REAL xv(500)
INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe
INTEGER :: nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe
INTEGER :: ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe
INTEGER idim1,idim2,idim3,idim4,idim5,idim6,idim7
INTEGER icoord, jcoord, idim_cd, jdim_cd
INTEGER local_comm, myproc, nproc
INTEGER iparstrt, jparstrt, sw
INTEGER thisdomain_max_halo_width
character*256 :: timestr
integer ierr
REAL nest_influence
LOGICAL, EXTERNAL :: cd_feedback_mask
LOGICAL, EXTERNAL :: cd_feedback_mask_v
!#define COPY_IN
!#include
! On entry to this routine,
! "grid" refers to the parent domain
! "intermediate_grid" refers to local copy of parent domain that overlies this patch of nest
! "ngrid" refers to the nest, which is only needed for smoothing on the parent because
! the nest feedback data has already been transferred during em_nest_feedbackup_interp
! in part1, above.
! The way these settings c and n dimensions are set, below, looks backwards but from the point
! of view of the RSL routine rsl_lite_to_parent_info(), call to which is included by
! em_nest_feedbackup_pack, the "n" domain represents the parent domain and the "c" domain
! represents the intermediate domain. The backwards lookingness should be fixed in the gen_comms.c
! registry routine that accompanies RSL_LITE but, just as it's sometimes easier to put up a road
! sign that says "DIP" than fix the dip, at this point it was easier just to write this comment. JM
!
nest_influence = 0.5
#define NEST_INFLUENCE(A,B) A = nest_influence*(B) + (1.0-nest_influence)*(A)
CALL domain_clock_get( grid, current_timestr=timestr )
CALL get_ijk_from_grid ( intermediate_grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
CALL get_ijk_from_grid ( grid , &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
nide = nide - 1 !dusan
njde = njde - 1 !dusan
CALL nl_get_i_parent_start ( intermediate_grid%id, iparstrt )
CALL nl_get_j_parent_start ( intermediate_grid%id, jparstrt )
CALL nl_get_shw ( intermediate_grid%id, sw )
icoord = iparstrt - sw
jcoord = jparstrt - sw
idim_cd = cide - cids + 1
jdim_cd = cjde - cjds + 1
nlev = ckde - ckds + 1
CALL get_dm_max_halo_width ( ngrid%id , thisdomain_max_halo_width )
#include "nest_feedbackup_pack.inc"
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_myproc( myproc )
CALL wrf_get_nproc( nproc )
CALL rsl_lite_merge_msgs( myproc, nproc, local_comm )
#include "nest_feedbackup_unpack.inc"
! smooth coarse grid
CALL get_ijk_from_grid ( ngrid, &
nids, nide, njds, njde, nkds, nkde, &
nims, nime, njms, njme, nkms, nkme, &
nips, nipe, njps, njpe, nkps, nkpe )
CALL get_ijk_from_grid ( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
#include "HALO_INTERP_UP.inc"
CALL get_ijk_from_grid ( grid , &
cids, cide, cjds, cjde, ckds, ckde, &
cims, cime, cjms, cjme, ckms, ckme, &
cips, cipe, cjps, cjpe, ckps, ckpe )
#include "nest_feedbackup_smooth.inc"
!#define COPY_OUT
!#include
RETURN
END SUBROUTINE feedback_domain_nmm_part2
!=================================================================================
! End of gopal's doing
!=================================================================================
#endif
!------------------------------------------------------------------
SUBROUTINE wrf_gatherv_real (Field, field_ofst, &
my_count , & ! sendcount
globbuf, glob_ofst , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
root , & ! root
communicator , & ! communicator
ierr )
USE module_dm, ONLY : getrealmpitype
IMPLICIT NONE
INTEGER field_ofst, glob_ofst
INTEGER my_count, communicator, root, ierr
INTEGER , DIMENSION(*) :: counts, displs
REAL, DIMENSION(*) :: Field, globbuf
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL mpi_gatherv( Field( field_ofst ), & ! sendbuf
my_count , & ! sendcount
getrealmpitype() , & ! sendtype
globbuf( glob_ofst ) , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
getrealmpitype() , & ! recvtype
root , & ! root
communicator , & ! communicator
ierr )
#endif
END SUBROUTINE wrf_gatherv_real
SUBROUTINE wrf_gatherv_double (Field, field_ofst, &
my_count , & ! sendcount
globbuf, glob_ofst , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
root , & ! root
communicator , & ! communicator
ierr )
! USE module_dm
IMPLICIT NONE
INTEGER field_ofst, glob_ofst
INTEGER my_count, communicator, root, ierr
INTEGER , DIMENSION(*) :: counts, displs
! this next declaration is REAL, not DOUBLE PRECISION because it will be autopromoted
! to double precision by the compiler when WRF is compiled for 8 byte reals. Only reason
! for having this separate routine is so we pass the correct MPI type to mpi_scatterv
! if we were not indexing the globbuf and Field arrays it would not even matter
REAL, DIMENSION(*) :: Field, globbuf
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL mpi_gatherv( Field( field_ofst ), & ! sendbuf
my_count , & ! sendcount
MPI_DOUBLE_PRECISION , & ! sendtype
globbuf( glob_ofst ) , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
MPI_DOUBLE_PRECISION , & ! recvtype
root , & ! root
communicator , & ! communicator
ierr )
#endif
END SUBROUTINE wrf_gatherv_double
SUBROUTINE wrf_gatherv_integer (Field, field_ofst, &
my_count , & ! sendcount
globbuf, glob_ofst , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
root , & ! root
communicator , & ! communicator
ierr )
IMPLICIT NONE
INTEGER field_ofst, glob_ofst
INTEGER my_count, communicator, root, ierr
INTEGER , DIMENSION(*) :: counts, displs
INTEGER, DIMENSION(*) :: Field, globbuf
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL mpi_gatherv( Field( field_ofst ), & ! sendbuf
my_count , & ! sendcount
MPI_INTEGER , & ! sendtype
globbuf( glob_ofst ) , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
MPI_INTEGER , & ! recvtype
root , & ! root
communicator , & ! communicator
ierr )
#endif
END SUBROUTINE wrf_gatherv_integer
!new stuff 20070124
SUBROUTINE wrf_scatterv_real ( &
globbuf, glob_ofst , & ! recvbuf
counts , & ! recvcounts
Field, field_ofst, &
my_count , & ! sendcount
displs , & ! displs
root , & ! root
communicator , & ! communicator
ierr )
USE module_dm, ONLY : getrealmpitype
IMPLICIT NONE
INTEGER field_ofst, glob_ofst
INTEGER my_count, communicator, root, ierr
INTEGER , DIMENSION(*) :: counts, displs
REAL, DIMENSION(*) :: Field, globbuf
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL mpi_scatterv( &
globbuf( glob_ofst ) , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
getrealmpitype() , & ! recvtype
Field( field_ofst ), & ! sendbuf
my_count , & ! sendcount
getrealmpitype() , & ! sendtype
root , & ! root
communicator , & ! communicator
ierr )
#endif
END SUBROUTINE wrf_scatterv_real
SUBROUTINE wrf_scatterv_double ( &
globbuf, glob_ofst , & ! recvbuf
counts , & ! recvcounts
Field, field_ofst, &
my_count , & ! sendcount
displs , & ! displs
root , & ! root
communicator , & ! communicator
ierr )
IMPLICIT NONE
INTEGER field_ofst, glob_ofst
INTEGER my_count, communicator, root, ierr
INTEGER , DIMENSION(*) :: counts, displs
REAL, DIMENSION(*) :: Field, globbuf
#ifndef STUBMPI
INCLUDE 'mpif.h'
! this next declaration is REAL, not DOUBLE PRECISION because it will be autopromoted
! to double precision by the compiler when WRF is compiled for 8 byte reals. Only reason
! for having this separate routine is so we pass the correct MPI type to mpi_scatterv
! if we were not indexing the globbuf and Field arrays it would not even matter
CALL mpi_scatterv( &
globbuf( glob_ofst ) , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
MPI_DOUBLE_PRECISION , & ! recvtype
Field( field_ofst ), & ! sendbuf
my_count , & ! sendcount
MPI_DOUBLE_PRECISION , & ! sendtype
root , & ! root
communicator , & ! communicator
ierr )
#endif
END SUBROUTINE wrf_scatterv_double
SUBROUTINE wrf_scatterv_integer ( &
globbuf, glob_ofst , & ! recvbuf
counts , & ! recvcounts
Field, field_ofst, &
my_count , & ! sendcount
displs , & ! displs
root , & ! root
communicator , & ! communicator
ierr )
IMPLICIT NONE
INTEGER field_ofst, glob_ofst
INTEGER my_count, communicator, root, ierr
INTEGER , DIMENSION(*) :: counts, displs
INTEGER, DIMENSION(*) :: Field, globbuf
#ifndef STUBMPI
INCLUDE 'mpif.h'
CALL mpi_scatterv( &
globbuf( glob_ofst ) , & ! recvbuf
counts , & ! recvcounts
displs , & ! displs
MPI_INTEGER , & ! recvtype
Field( field_ofst ), & ! sendbuf
my_count , & ! sendcount
MPI_INTEGER , & ! sendtype
root , & ! root
communicator , & ! communicator
ierr )
#endif
END SUBROUTINE wrf_scatterv_integer
! end new stuff 20070124
SUBROUTINE wrf_dm_gatherv ( v, elemsize , km_s, km_e, wordsz )
IMPLICIT NONE
INTEGER elemsize, km_s, km_e, wordsz
REAL v(*)
IF ( wordsz .EQ. DWORDSIZE ) THEN
CALL wrf_dm_gatherv_double(v, elemsize , km_s, km_e)
ELSE
CALL wrf_dm_gatherv_single(v, elemsize , km_s, km_e)
ENDIF
END SUBROUTINE wrf_dm_gatherv
SUBROUTINE wrf_dm_gatherv_double ( v, elemsize , km_s, km_e )
IMPLICIT NONE
INTEGER elemsize, km_s, km_e
REAL*8 v(0:*)
#ifndef STUBMPI
# ifndef USE_MPI_IN_PLACE
REAL*8 v_local((km_e-km_s+1)*elemsize)
# endif
INTEGER, DIMENSION(:), ALLOCATABLE :: recvcounts, displs
INTEGER send_type, myproc, nproc, local_comm, ierr, i
INCLUDE 'mpif.h'
send_type = MPI_DOUBLE_PRECISION
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_nproc( nproc )
CALL wrf_get_myproc( myproc )
ALLOCATE( recvcounts(nproc), displs(nproc) )
i = (km_e-km_s+1)*elemsize
CALL mpi_allgather( i,1,MPI_INTEGER,recvcounts,1,MPI_INTEGER,local_comm,ierr) ;
i = (km_s)*elemsize
CALL mpi_allgather( i,1,MPI_INTEGER,displs,1,MPI_INTEGER,local_comm,ierr) ;
# ifdef USE_MPI_IN_PLACE
CALL mpi_allgatherv( MPI_IN_PLACE, &
# else
DO i = 1,elemsize*(km_e-km_s+1)
v_local(i) = v(i+km_s-1)
ENDDO
CALL mpi_allgatherv( v_local, &
# endif
(km_e-km_s+1)*elemsize, &
send_type, &
v, &
recvcounts, &
displs, &
send_type, &
local_comm, &
ierr )
DEALLOCATE(recvcounts)
DEALLOCATE(displs)
#endif
return
END SUBROUTINE wrf_dm_gatherv_double
SUBROUTINE wrf_dm_gatherv_single ( v, elemsize , km_s, km_e )
IMPLICIT NONE
INTEGER elemsize, km_s, km_e
REAL*4 v(0:*)
#ifndef STUBMPI
# ifndef USE_MPI_IN_PLACE
REAL*4 v_local((km_e-km_s+1)*elemsize)
# endif
INTEGER, DIMENSION(:), ALLOCATABLE :: recvcounts, displs
INTEGER send_type, myproc, nproc, local_comm, ierr, i
INCLUDE 'mpif.h'
send_type = MPI_REAL
CALL wrf_get_dm_communicator ( local_comm )
CALL wrf_get_nproc( nproc )
CALL wrf_get_myproc( myproc )
ALLOCATE( recvcounts(nproc), displs(nproc) )
i = (km_e-km_s+1)*elemsize
CALL mpi_allgather( i,1,MPI_INTEGER,recvcounts,1,MPI_INTEGER,local_comm,ierr) ;
i = (km_s)*elemsize
CALL mpi_allgather( i,1,MPI_INTEGER,displs,1,MPI_INTEGER,local_comm,ierr) ;
# ifdef USE_MPI_IN_PLACE
CALL mpi_allgatherv( MPI_IN_PLACE, &
# else
DO i = 1,elemsize*(km_e-km_s+1)
v_local(i) = v(i+km_s-1)
ENDDO
CALL mpi_allgatherv( v_local, &
# endif
(km_e-km_s+1)*elemsize, &
send_type, &
v, &
recvcounts, &
displs, &
send_type, &
local_comm, &
ierr )
DEALLOCATE(recvcounts)
DEALLOCATE(displs)
#endif
return
END SUBROUTINE wrf_dm_gatherv_single
SUBROUTINE wrf_dm_decomp1d( nt, km_s, km_e )
IMPLICIT NONE
INTEGER, INTENT(IN) :: nt
INTEGER, INTENT(OUT) :: km_s, km_e
! local
INTEGER nn, nnp, na, nb
INTEGER myproc, nproc
CALL wrf_get_myproc(myproc)
CALL wrf_get_nproc(nproc)
nn = nt / nproc ! min number done by this task
nnp = nn
if ( myproc .lt. mod( nt, nproc ) ) nnp = nnp + 1 ! distribute remainder
na = min( myproc, mod(nt,nproc) ) ! Number of blocks with remainder that precede this one
nb = max( 0, myproc - na ) ! number of blocks without a remainder that precede this one
km_s = na * ( nn+1) + nb * nn ! starting iteration for this task
km_e = km_s + nnp - 1 ! ending iteration for this task
END SUBROUTINE wrf_dm_decomp1d
SUBROUTINE wrf_dm_define_comms ( grid )
USE module_domain, ONLY : domain
IMPLICIT NONE
TYPE(domain) , INTENT (INOUT) :: grid
RETURN
END SUBROUTINE wrf_dm_define_comms
SUBROUTINE tfp_message( fname, lno )
CHARACTER*(*) fname
INTEGER lno
CHARACTER*1024 mess
#ifndef STUBMPI
WRITE(mess,*)'tfp_message: ',trim(fname),lno
CALL wrf_message(mess)
# ifdef ALLOW_OVERDECOMP
CALL task_for_point_message ! defined in RSL_LITE/task_for_point.c
# else
CALL wrf_error_fatal(mess)
# endif
#endif
END SUBROUTINE tfp_message
SUBROUTINE set_dm_debug
USE module_dm, ONLY : dm_debug_flag
IMPLICIT NONE
dm_debug_flag = .TRUE.
END SUBROUTINE set_dm_debug
SUBROUTINE reset_dm_debug
USE module_dm, ONLY : dm_debug_flag
IMPLICIT NONE
dm_debug_flag = .FALSE.
END SUBROUTINE reset_dm_debug
SUBROUTINE get_dm_debug ( arg )
USE module_dm, ONLY : dm_debug_flag
IMPLICIT NONE
LOGICAL arg
arg = dm_debug_flag
END SUBROUTINE get_dm_debug