The main differences for supporting moving nests over what is needed to support static (non-moving) nests in the WRF software infrastructure have to do with:
The top-level routine that controls and supports nest movement is med_nest_move , called from within the main time loop of WRF in the integrate routine. The med_nest_move routine is called with a pointer to the parent and an active nest after the nest has been integrated forward to the current time and fed back (if two-way nesting is employed) onto the parent. This ensures that both the parent and nest solutions are at the same time at the time of movement.
Med_nest_move calls a function time_for_move, which returns a value of true if it is time to move the nest and passes back displacements in X and Y for the move as integer arguments. If false, med_nest_move does nothing and returns control to integrate. The displacements represent the number of coarse-domain points the nest is to move in X (positive is east and negative is west) and Y (positive is north and negative is south). In the current implementation of moving nests in WRF, the absolute value of the displacement may not be greater than 1. This limitation will be addressed in later versions.
The RSL library routine RSL_MOVE_NEST is called to adjust the spatial relationship between points on the nest and their corresponding parent domain point. This is done indirectly. Recall from the discussion of non-moving nests in WRF (not written yet) that the interprocessor communication of forcing and feedback data between parent and nest is actually done via an intermediate domain that has the same resolution as the parent but that is (1) logically only as large as the amount of the parent domain that overlays the nest (plus some halo) and that is (2) decomposed over distributed-memory patches (MPI tasks) using the nested domains decomposition. RSL stores information about the parent and the intermediate domains, including information about their spatial relationship, when the domains are defined in wrf_dm_patch_domain which calls , calls rsl_patch_domain. The integer descriptors for the parent and intermediate domain have been stored in
parent%domdesc and nest%intermediate_grid%domdesc, respectively. These descriptors, along with the X and Y displacement for the new spatial relationship are arguments to RSL_MOVE_NEST. On return, all future data movements between the parent and intermediate domains through RSL use this new spatial relationship. That is, if a given nested point was previously listed as underlying parent domain point i,j, afterwards, it underlies the parent domain point i+X, j+Y. Note: it is a violation of the WRF coding standards for a mediation layer routine to call a routine from an external package directly, as is being done here, with med_nest_move calling RSL_MOVE_NEST. At this time, the moving nest capability is a research prototype, is not fully supported to the community, and is #ifdef’d out of the code unless the –DMOVE_NESTS setting is added to ARCH_FLAGS in the configure.wrf file at compile time. The implementation of moving nests will be brought in line with the WRF coding standards in a later release of WRF.
The adjust_domain_dims_for_move is called to adjust starts and ends of the intermediate domain’s memory and patch dimensions to reflect the new location of the nest within the coarse domain, the old intermediate domain object and its data structures are deallocated, and a new intermediate domain object and its state data structures are allocated. Note that the grid argument to adjust_domain_dims_for_move is a POINTER. Likewise, the routines that adjust_domain_dims_for_move also expect a POINTER argument. The call to adjust_domain_dims_for_move is inside #ifdef RSL … #endif, with the call to RSL_MOVE_NESTS, because the use of an intermediate domain to parallelize parent-nest forcing and feedback is an RSL-specific implementation (other external packages may not use this organization).
The calls to get_ijk_from_grid around the RSL calls are also needed because the indices this routine returns will change after the spatial relationship between the parent and the nest has been adjusted.
At this point, the parent domain and the intermediate domain are ready to exchange data that can be used to force and feedback the nest. But the domain object representing the nest itself has not yet been modified. This is done with a call to shift_domain_em. Some initial notes on the shift_domain_em routine.
! shift the nest domain in x
do ii = 1,abs(disp_x)
#include <em_shift_halo_x.inc>
enddo
! shift the nest domain in y
do ii = 1,abs(disp_y)
#include <em_shift_halo_y.inc>
enddo
The variables disp_x and disp_y are the X and Y displacements in coarse-domain coordinates. (Recall that in this version of the code, the absolute value of these may not be greater than 1). Each execution of the code in em_shift_halo_x.inc performs a very large halo-update communication: every state array in the nest is updated 5 points to the east and west on each subdomain. Then the each field is shifted px points where px is equal to the nesting ratio in X, either positive or negative depending on the direction of the shift. For an arbitrary 3-D field V on the nest a shift operation in X, that is, one iteration of the loop above, works as follows:
stencil exchange updates V east and west halos on subdomain
V (ips:min(ide-1,ipe),:,jms:jme) = V (ips+px:min(ide-1,ipe)+px,:,jms:jme)
V’s storage order is i,k,j. The ips variable is the starting index of the field on the local subdomain (patch) and min(ide-1,ipe) is the ending index of the field assuming it is unstaggered (on a mass point). X-staggered fields (u-velocity on a C-grid) go all the way out to ide on the domain so the ending index for X-staggered fields is min(ide,ipe), or just ipe. The other dimensions, Y and Z, are shifted in their entirety (memory dimensions or just ‘:’ are used for these copies). Note the use of Fortran90 array syntax for these copies; this is at variance with the normal WRF coding convention of avoiding array syntax. It was chosen, for now, for simplicity of code generation in the Registry mechanism. This may be revisited as an efficiency concern.
Once the nested arrays have been shifted, shift_domain_em returns control to the caller, med_nest_move.
The new coordinates of the south-west (lower-left) corner of the nested domain within the coarse domain, i_parent_start and j_parent_start, are computed and the configuration information stored in model_config_rec (module_configure) are updated in calls to nl_set_i_parent_start and nl_set_j_parent_start.
The nest is initialized in the same way as if it were a newly instantiated nest, with a call to med_interp_domain. The imask variables that were set and shifted in step 3.d above are used by the subroutine interp_domain_em_part2 to control whether a nest point is initialized with interpolated data from the coarse domain (through the intermediate domain). More specifically the mask arrays are passed to nest interpolation routines in the Registry-generated calls #included here in the interp_domain_em_part2 routine:
# include "em_nest_interpdown_interp.inc"
For example, the Registry-generated call to interpolate the U_2 (second time level of U) array with the mask argument highlighted is:
CALL interp_fcn ( &
u_2, & ! CD field
cids, cide, ckds, ckde, cjds, cjde, & ! CD dims
cims, cime, ckms, ckme, cjms, cjme, & ! CD dims
cips, cipe, ckps, ckpe, cjps, cjpe, & ! CD dims
ngrid%em_u_2, & ! ND field
nids, nide, nkds, nkde, njds, njde, & ! ND dims
nims, nime, nkms, nkme, njms, njme, & ! ND dims
nips, nipe, nkps, nkpe, njps, njpe, & ! ND dims
shw, & ! Stencil half Width
ngrid%imask_xstag, & ! Interpolation mask
.TRUE., .FALSE., & ! xstag, ystag
ngrid%i_parent_start, ngrid%j_parent_start, &
ngrid%parent_grid_ratio, ngrid%parent_grid_ratio )
The interp_fcn routine only interpolates nested domain points where imask_xstag is set to 1. In this way, only the new parts of the nested domain on the leading edge of the moved nest are initialized.
Likewise, the code in start_domain_em,
called from med_nest_move
after med_interp_domain,
uses the imask values to determine which
parts of the nested domain need initialization.