2 SUBROUTINE med_nest_move ( parent, nest )
4 USE module_domain, ONLY : domain, get_ijk_from_grid, adjust_domain_dims_for_move
5 USE module_driver_constants, ONLY : max_nests
8 USE module_configure, ONLY : grid_config_rec_type, model_config_rec, model_to_grid_config_rec
9 USE module_state_description
10 ! USE module_io_domain
11 #if defined(DM_PARALLEL) && ! defined(STUBMPI)
12 USE module_dm, ONLY : wrf_dm_move_nest,nest_task_offsets,mpi_comm_to_kid,mpi_comm_to_mom, which_kid
15 TYPE(domain) , POINTER :: parent, nest, grid
16 INTEGER dx, dy, origdy ! number of parent domain points to move
20 INTEGER i, j, k, p, parent_grid_ratio
21 INTEGER px, py ! number and direction of nd points to move
22 INTEGER :: ids , ide , jds , jde , kds , kde , &
23 ims , ime , jms , jme , kms , kme , &
24 ips , ipe , jps , jpe , kps , kpe
25 INTEGER ierr, fid, comzilla, kid
26 LOGICAL input_from_hires
27 LOGICAL saved_restart_value
28 TYPE (grid_config_rec_type) :: config_flags
29 LOGICAL, EXTERNAL :: wrf_dm_on_monitor
30 LOGICAL, EXTERNAL :: should_not_move
33 SUBROUTINE med_interp_domain ( parent , nest )
34 USE module_domain, ONLY : domain
36 TYPE(domain) , POINTER :: parent , nest
37 END SUBROUTINE med_interp_domain
38 SUBROUTINE start_domain ( grid , allowed_to_move )
39 USE module_domain, ONLY : domain
42 LOGICAL, INTENT(IN) :: allowed_to_move
43 END SUBROUTINE start_domain
45 SUBROUTINE shift_domain_em ( grid, disp_x, disp_y &
47 # include "dummy_new_args.inc"
50 USE module_domain, ONLY : domain
51 USE module_state_description
53 INTEGER disp_x, disp_y
54 TYPE(domain) , POINTER :: grid
55 # include "dummy_new_decl.inc"
56 END SUBROUTINE shift_domain_em
58 LOGICAL FUNCTION time_for_move ( parent , nest , dx , dy )
59 USE module_domain, ONLY : domain
61 TYPE(domain) , POINTER :: parent , nest
62 INTEGER, INTENT(OUT) :: dx , dy
63 END FUNCTION time_for_move
65 SUBROUTINE input_terrain_rsmas ( grid , &
66 ids , ide , jds , jde , kds , kde , &
67 ims , ime , jms , jme , kms , kme , &
68 ips , ipe , jps , jpe , kps , kpe )
69 USE module_domain, ONLY : domain
71 TYPE ( domain ) :: grid
72 INTEGER :: ids , ide , jds , jde , kds , kde , &
73 ims , ime , jms , jme , kms , kme , &
74 ips , ipe , jps , jpe , kps , kpe
75 END SUBROUTINE input_terrain_rsmas
76 SUBROUTINE med_nest_feedback ( parent , nest , config_flags )
77 USE module_domain, ONLY : domain
78 USE module_configure, ONLY : grid_config_rec_type
80 TYPE (domain), POINTER :: nest , parent
81 TYPE (grid_config_rec_type) config_flags
82 END SUBROUTINE med_nest_feedback
83 SUBROUTINE blend_terrain ( ter_interpolated , ter_input , &
84 ids , ide , jds , jde , kds , kde , &
85 ims , ime , jms , jme , kms , kme , &
86 ips , ipe , jps , jpe , kps , kpe )
88 INTEGER :: ids , ide , jds , jde , kds , kde , &
89 ims , ime , jms , jme , kms , kme , &
90 ips , ipe , jps , jpe , kps , kpe
91 REAL , DIMENSION(ims:ime,jms:jme) :: ter_interpolated
92 REAL , DIMENSION(ims:ime,jms:jme) :: ter_input
93 END SUBROUTINE blend_terrain
94 SUBROUTINE copy_3d_field ( ter_interpolated , ter_input , &
95 ids , ide , jds , jde , kds , kde , &
96 ims , ime , jms , jme , kms , kme , &
97 ips , ipe , jps , jpe , kps , kpe )
99 INTEGER :: ids , ide , jds , jde , kds , kde , &
100 ims , ime , jms , jme , kms , kme , &
101 ips , ipe , jps , jpe , kps , kpe
102 REAL , DIMENSION(ims:ime,jms:jme) :: ter_interpolated
103 REAL , DIMENSION(ims:ime,jms:jme) :: ter_input
104 END SUBROUTINE copy_3d_field
107 ! set grid pointer for code in deref_kludge (if used)
110 IF ( should_not_move( nest%id ) ) THEN
111 CALL wrf_message( 'Nest movement is disabled because of namelist settings' )
115 ! if the nest has stopped don't do all this
116 IF ( WRFU_ClockIsStopTime(nest%domain_clock ,rc=ierr) ) RETURN
118 ! mask should be defined in nest domain
120 check_for_move: IF ( time_for_move ( parent , nest , dx, dy ) ) THEN
123 IF ( (dx .gt. 1 .or. dx .lt. -1 ) .or. &
124 (dy .gt. 1 .or. dy .lt. -1 ) ) THEN
125 WRITE(mess,*)' invalid move: dx, dy ', dx, dy
126 CALL wrf_error_fatal( mess )
130 IF ( wrf_dm_on_monitor() ) THEN
131 WRITE(mess,*)' moving ',grid%id,dx,dy
132 CALL wrf_message(mess)
135 CALL get_ijk_from_grid ( grid , &
136 ids, ide, jds, jde, kds, kde, &
137 ims, ime, jms, jme, kms, kme, &
138 ips, ipe, jps, jpe, kps, kpe )
140 CALL wrf_dm_move_nest ( parent, nest%intermediate_grid, dx, dy )
142 CALL adjust_domain_dims_for_move( nest%intermediate_grid , dx, dy )
144 CALL get_ijk_from_grid ( grid , &
145 ids, ide, jds, jde, kds, kde, &
146 ims, ime, jms, jme, kms, kme, &
147 ips, ipe, jps, jpe, kps, kpe )
152 CALL shift_domain_em( grid, dx, dy &
154 # include "actual_new_args.inc"
159 px = grid%parent_grid_ratio*dx
160 py = grid%parent_grid_ratio*dy
162 grid%i_parent_start = grid%i_parent_start + px / grid%parent_grid_ratio
163 grid%j_parent_start = grid%j_parent_start + py / grid%parent_grid_ratio
165 #if defined(DM_PARALLEL) && ! defined(STUBMPI)
166 IF ( (parent%active_this_task .OR. grid%active_this_task) ) THEN
167 IF ( parent%active_this_task ) THEN
168 comzilla = mpi_comm_to_kid( which_kid( grid%id ) , parent%id )
170 comzilla = mpi_comm_to_mom( grid%id )
172 CALL BYTE_BCAST_FROM_ROOT( grid%i_parent_start, IWORDSIZE, nest_task_offsets(nest%id), comzilla ) !
173 CALL BYTE_BCAST_FROM_ROOT( grid%j_parent_start, IWORDSIZE, nest_task_offsets(nest%id), comzilla ) !
176 CALL nl_set_i_parent_start( grid%id, grid%i_parent_start )
177 CALL nl_set_j_parent_start( grid%id, grid%j_parent_start )
179 CALL push_communicators_for_domain(grid%id)
180 IF ( wrf_dm_on_monitor() ) THEN
182 'Grid ',grid%id,' New SW corner (in parent x and y):',grid%i_parent_start, grid%j_parent_start
183 CALL wrf_message(TRIM(mess))
185 CALL pop_communicators_for_domain(grid%id)
188 CALL med_interp_domain( parent, nest )
191 CALL nl_get_input_from_hires( nest%id , input_from_hires )
192 IF ( input_from_hires ) THEN
194 IF ( nest%active_this_task ) THEN
195 ! store horizontally interpolated terrain in temp location
196 CALL copy_3d_field ( nest%ht_fine , nest%ht , &
197 ids , ide , jds , jde , 1 , 1 , &
198 ims , ime , jms , jme , 1 , 1 , &
199 ips , ipe , jps , jpe , 1 , 1 )
200 CALL copy_3d_field ( nest%mub_fine , nest%mub , &
201 ids , ide , jds , jde , 1 , 1 , &
202 ims , ime , jms , jme , 1 , 1 , &
203 ips , ipe , jps , jpe , 1 , 1 )
204 CALL copy_3d_field ( nest%phb_fine , nest%phb , &
205 ids , ide , jds , jde , kds , kde , &
206 ims , ime , jms , jme , kms , kme , &
207 ips , ipe , jps , jpe , kps , kpe )
209 CALL input_terrain_rsmas ( nest, &
210 ids , ide , jds , jde , 1 , 1 , &
211 ims , ime , jms , jme , 1 , 1 , &
212 ips , ipe , jps , jpe , 1 , 1 )
214 CALL blend_terrain ( nest%ht_fine , nest%ht , &
215 ids , ide , jds , jde , 1 , 1 , &
216 ims , ime , jms , jme , 1 , 1 , &
217 ips , ipe , jps , jpe , 1 , 1 )
218 CALL blend_terrain ( nest%mub_fine , nest%mub , &
219 ids , ide , jds , jde , 1 , 1 , &
220 ims , ime , jms , jme , 1 , 1 , &
221 ips , ipe , jps , jpe , 1 , 1 )
222 CALL blend_terrain ( nest%phb_fine , nest%phb , &
223 ids , ide , jds , jde , kds , kde , &
224 ims , ime , jms , jme , kms , kme , &
225 ips , ipe , jps , jpe , kps , kpe )
228 CALL model_to_grid_config_rec ( parent%id , model_config_rec , config_flags )
230 CALL med_nest_feedback ( parent , nest , config_flags )
231 parent%imask_nostag = 1
232 parent%imask_xstag = 1
233 parent%imask_ystag = 1
234 parent%imask_xystag = 1
236 ! start_domain will key off "restart". Even if this is a restart run
237 ! we don't want it to here. Save the value, set it to false, and restore afterwards
238 saved_restart_value = config_flags%restart
239 config_flags%restart = .FALSE.
240 grid%restart = .FALSE.
241 CALL nl_set_restart ( 1, .FALSE. )
242 grid%press_adj = .FALSE.
243 CALL start_domain ( parent , .FALSE. )
244 config_flags%restart = saved_restart_value
245 grid%restart = saved_restart_value
246 CALL nl_set_restart ( 1, saved_restart_value )
252 ! masks associated with nest will have been set by shift_domain_em above
254 ! start_domain will key off "restart". Even if this is a restart run
255 ! we don't want it to here. Save the value, set it to false, and restore afterwards
256 saved_restart_value = config_flags%restart
257 config_flags%restart = .FALSE.
258 CALL nl_set_restart ( 1, .FALSE. )
259 grid%restart = .FALSE.
261 nest%press_adj = .FALSE.
264 #if defined(DM_PARALLEL) && ! defined(STUBMPI)
266 IF ( nest%active_this_task ) THEN
267 CALL push_communicators_for_domain(nest%id)
268 CALL start_domain ( nest , .FALSE. )
269 CALL pop_communicators_for_domain
272 config_flags%restart = saved_restart_value
273 grid%restart = saved_restart_value
274 CALL nl_set_restart ( 1, saved_restart_value )
278 ! copy time level 2 to time level 1 in new regions of multi-time level fields
279 ! this should be registry generated.
282 IF ( nest%active_this_task ) THEN
284 where ( nest%imask_xstag .EQ. 1 ) nest%u_1(:,k,:) = nest%u_2(:,k,:)
285 where ( nest%imask_ystag .EQ. 1 ) nest%v_1(:,k,:) = nest%v_2(:,k,:)
286 where ( nest%imask_nostag .EQ. 1 ) nest%t_1(:,k,:) = nest%t_2(:,k,:)
287 where ( nest%imask_nostag .EQ. 1 ) nest%w_1(:,k,:) = nest%w_2(:,k,:)
288 where ( nest%imask_nostag .EQ. 1 ) nest%ph_1(:,k,:) = nest%ph_2(:,k,:)
289 where ( nest%imask_nostag .EQ. 1 ) nest%tke_1(:,k,:) = nest%tke_2(:,k,:)
291 where ( nest%imask_nostag .EQ. 1 ) nest%mu_1(:,:) = nest%mu_2(:,:)
298 END SUBROUTINE med_nest_move
300 LOGICAL FUNCTION time_for_move2 ( parent , grid , move_cd_x, move_cd_y )
302 USE module_domain, ONLY : domain, domain_clock_get, get_ijk_from_grid, adjust_domain_dims_for_move
303 ! USE module_configure
304 USE module_driver_constants, ONLY : max_moves
305 USE module_compute_geop
306 USE module_dm, ONLY : wrf_dm_max_real, wrf_dm_move_nest
308 USE module_streams, ONLY : compute_vortex_center_alarm
311 TYPE(domain) , POINTER :: parent, grid
312 INTEGER, INTENT(OUT) :: move_cd_x , move_cd_y
315 INTEGER num_moves, rc
316 INTEGER move_interval , move_id
317 TYPE(WRFU_Time) :: ct, st
318 TYPE(WRFU_TimeInterval) :: ti
319 CHARACTER*256 mess, timestr
320 INTEGER :: ids, ide, jds, jde, kds, kde, &
321 ims, ime, jms, jme, kms, kme, &
322 ips, ipe, jps, jpe, kps, kpe
323 INTEGER :: is, ie, js, je, ierr
324 REAL :: ipbar, pbar, jpbar, fact
325 REAL :: last_vc_i , last_vc_j
327 REAL, ALLOCATABLE, DIMENSION(:,:) :: height_l, height
328 REAL, ALLOCATABLE, DIMENSION(:,:) :: psfc, xlat, xlong, terrain
330 INTEGER :: mini, minj, maxi, maxj, i, j, pgr, irad
331 REAL :: disp_x, disp_y, lag, radius, center_i, center_j, dx
332 REAL :: dijsmooth, vmax, vmin, a, b
333 REAL :: dc_i, dc_j ! domain center
336 INTEGER imploc, jmploc
338 INTEGER :: fje, fjs, fie, fis, fimloc, fjmloc, imloc, jmloc
339 INTEGER :: i_parent_start, j_parent_start
340 INTEGER :: max_vortex_speed, vortex_interval ! meters per second and seconds
341 INTEGER :: track_level
342 REAL :: rsmooth = 100000. ! in meters
344 LOGICAL, EXTERNAL :: wrf_dm_on_monitor
346 character*256 message, message2
348 !#define MOVING_DIAGS
349 # ifdef VORTEX_CENTER
352 CALL nl_get_parent_grid_ratio ( grid%id , pgr )
353 CALL nl_get_i_parent_start ( grid%id , i_parent_start )
354 CALL nl_get_j_parent_start ( grid%id , j_parent_start )
355 CALL nl_get_track_level ( grid%id , track_level )
357 ! WRITE(mess,*)'Vortex is tracked at ', track_level
358 ! CALL wrf_message(mess)
360 CALL get_ijk_from_grid ( grid , &
361 ids, ide, jds, jde, kds, kde, &
362 ims, ime, jms, jme, kms, kme, &
363 ips, ipe, jps, jpe, kps, kpe )
365 ! If the alarm is ringing, recompute the Vortex Center (VC); otherwise
366 ! use the previous position of VC. VC is not recomputed ever step to
367 ! save on cost for global collection of height field and broadcast
371 write(message,*)'Check to see if COMPUTE_VORTEX_CENTER_ALARM is ringing? '
372 call wrf_debug(1,message)
374 CALL nl_get_parent_grid_ratio ( grid%id , pgr )
375 CALL nl_get_dx ( grid%id , dx )
377 IF ( WRFU_AlarmIsRinging( grid%alarms( COMPUTE_VORTEX_CENTER_ALARM ), rc=rc ) ) THEN
380 write(message,*)'COMPUTE_VORTEX_CENTER_ALARM is ringing '
381 call wrf_debug(1,message)
383 CALL WRFU_AlarmRingerOff( grid%alarms( COMPUTE_VORTEX_CENTER_ALARM ), rc=rc )
384 CALL domain_clock_get( grid, current_timestr=timestr )
386 last_vc_i = grid%vc_i
387 last_vc_j = grid%vc_j
389 ALLOCATE ( height_l ( ims:ime , jms:jme ), STAT=ierr )
390 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating height_l in time_for_move2')
391 IF ( wrf_dm_on_monitor() ) THEN
392 ALLOCATE ( height ( ids:ide , jds:jde ), STAT=ierr )
393 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating height in time_for_move2')
394 ALLOCATE ( psfc ( ids:ide , jds:jde ), STAT=ierr )
395 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating psfc in time_for_move2')
396 ALLOCATE ( xlat ( ids:ide , jds:jde ), STAT=ierr )
397 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating xlat in time_for_move2')
398 ALLOCATE ( xlong ( ids:ide , jds:jde ), STAT=ierr )
399 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating xlong in time_for_move2')
400 ALLOCATE ( terrain ( ids:ide , jds:jde ), STAT=ierr )
401 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating terrain in time_for_move2')
403 ALLOCATE ( height ( 1:1 , 1:1 ), STAT=ierr )
404 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating height in time_for_move2')
405 ALLOCATE ( psfc ( 1:1 , 1:1 ), STAT=ierr )
406 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating psfc in time_for_move2')
407 ALLOCATE ( xlat ( 1:1 , 1:1 ), STAT=ierr )
408 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating xlat in time_for_move2')
409 ALLOCATE ( xlong ( 1:1 , 1:1 ), STAT=ierr )
410 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating xlong in time_for_move2')
411 ALLOCATE ( terrain ( 1:1 , 1:1 ), STAT=ierr )
412 IF ( ierr .ne. 0 ) CALL wrf_error_fatal ('allocating terrain in time_for_move2')
416 CALL compute_500mb_height ( grid%ph_2 , grid%phb, grid%p, grid%pb, height_l , &
418 ids, ide, jds, jde, kds, kde, &
419 ims, ime, jms, jme, kms, kme, &
420 ips, ipe, jps, jpe, kps, kpe )
423 CALL wrf_patch_to_global_real ( height_l , height , grid%domdesc, "z", "xy", &
424 ids, ide-1 , jds , jde-1 , 1 , 1 , &
425 ims, ime , jms , jme , 1 , 1 , &
426 ips, ipe , jps , jpe , 1 , 1 )
427 CALL wrf_patch_to_global_real ( grid%psfc , psfc , grid%domdesc, "z", "xy", &
428 ids, ide-1 , jds , jde-1 , 1 , 1 , &
429 ims, ime , jms , jme , 1 , 1 , &
430 ips, ipe , jps , jpe , 1 , 1 )
431 CALL wrf_patch_to_global_real ( grid%xlat , xlat , grid%domdesc, "z", "xy", &
432 ids, ide-1 , jds , jde-1 , 1 , 1 , &
433 ims, ime , jms , jme , 1 , 1 , &
434 ips, ipe , jps , jpe , 1 , 1 )
435 CALL wrf_patch_to_global_real ( grid%xlong , xlong , grid%domdesc, "z", "xy", &
436 ids, ide-1 , jds , jde-1 , 1 , 1 , &
437 ims, ime , jms , jme , 1 , 1 , &
438 ips, ipe , jps , jpe , 1 , 1 )
439 CALL wrf_patch_to_global_real ( grid%ht , terrain , grid%domdesc, "z", "xy", &
440 ids, ide-1 , jds , jde-1 , 1 , 1 , &
441 ims, ime , jms , jme , 1 , 1 , &
442 ips, ipe , jps , jpe , 1 , 1 )
444 ! calculate max wind speed
448 ws = grid%u10(i,j) * grid%u10(i,j) + grid%v10(i,j) * grid%v10(i,j)
449 if ( ws > maxws ) maxws = ws
452 maxws = sqrt ( maxws )
453 maxws = wrf_dm_max_real ( maxws )
455 monitor_only : IF ( wrf_dm_on_monitor() ) THEN
458 ! This vortex center finding code adapted from the Hurricane version of MM5,
461 ! Shuyi Chen et al., Rosenstiel School of Marine and Atmos. Sci., U. Miami.
464 ! Get the first guess vortex center about which we do our search
465 ! as mini and minh; minimum value is minh
468 CALL nl_get_vortex_interval( grid%id , vortex_interval )
469 CALL nl_get_max_vortex_speed( grid%id , max_vortex_speed )
471 IF ( grid%vc_i < 0. .AND. grid%vc_j < 0. ) THEN
478 ! limit the search to an area around the vortex
479 ! that is limited by max_vortex_speed (default 40) meters per second from
480 ! previous location over vortex_interval (default 15 mins)
482 is = max( grid%vc_i - 60 * vortex_interval * max_vortex_speed / dx , 1.0 * ids )
483 js = max( grid%vc_j - 60 * vortex_interval * max_vortex_speed / dx , 1.0 * jds )
484 ie = min( grid%vc_i + 60 * vortex_interval * max_vortex_speed / dx , 1.0 * (ide-1) )
485 je = min( grid%vc_j + 60 * vortex_interval * max_vortex_speed / dx , 1.0 * (jde-1) )
490 write(message,*)'search set around last position '
491 call wrf_debug(1,message)
492 write(message,*)' is, ids-1, ie, ide-1 ', is, ids-1, ie, ide-1
493 call wrf_debug(1,message)
494 write(message,*)' js, jds-1, je, jde-1 ', js, jds-1, je, jde-1
495 call wrf_debug(1,message)
502 pmin = 99999999.0 ! make this very large to be sure we find a minumum
505 ! adjust approximately to sea level pressure (same as below: ATCF)
506 psfc(i,j)=psfc(i,j)+11.38*terrain(i,j)
507 IF ( psfc(i,j) .LT. pmin ) THEN
515 IF ( imploc .EQ. -1 .OR. jmploc .EQ. -1 ) THEN ! if we fail to find a min there is something seriously wrong
516 WRITE(mess,*)'i,j,is,ie,js,je,imploc,jmploc ',i,j,is,ie,js,je,imploc,jmploc
517 CALL wrf_message(mess)
518 CALL wrf_error_fatal('time_for_move2: Method failure searching for minimum psfc.')
526 ! find local min, max
531 IF ( height(i,j) .LT. vmin ) THEN
536 IF ( height(i,j) .GT. vmax ) THEN
544 IF ( imloc .EQ. -1 .OR. jmloc .EQ. -1 .OR. maxi .EQ. -1 .OR. maxj .EQ. -1 ) THEN
545 WRITE(mess,*)'i,j,is,ie,js,je,imloc,jmloc,maxi,maxj ',i,j,is,ie,js,je,imloc,jmloc,maxi,maxj
546 CALL wrf_message(mess)
547 CALL wrf_error_fatal('time_for_move2: Method failure searching max/min of height.')
553 if ( grid%xi .EQ. -1. ) grid%xi = fimloc
554 if ( grid%xj .EQ. -1. ) grid%xj = fjmloc
556 dijsmooth = rsmooth / dx
558 fjs = max(fjmloc-dijsmooth,1.0)
559 fje = min(fjmloc+dijsmooth,jde-2.0)
560 fis = max(fimloc-dijsmooth,1.0)
561 fie = min(fimloc+dijsmooth,ide-2.0)
571 IF ( height(i,j) .GT. vmax ) THEN
583 fact = vmax - height(i,j)
585 ipbar = ipbar + fact*(i-is)
586 jpbar = jpbar + fact*(j-js)
590 IF ( pbar .NE. 0. ) THEN
592 ! Compute an adjusted, smoothed, vortex center location in cross
594 ! Time average. A is coef for old information; B is new
595 ! If pbar is zero then just skip this, leave xi and xj alone,
596 ! result will be no movement.
599 grid%xi = (a * grid%xi + b * (is + ipbar / pbar)) / ( a + b )
600 grid%xj = (a * grid%xj + b * (js + jpbar / pbar)) / ( a + b )
602 grid%vc_i = grid%xi + .5
603 grid%vc_j = grid%xj + .5
609 write(message,*)'computed grid%vc_i, grid%vc_j ',grid%vc_i, grid%vc_j
610 call wrf_debug(1,message)
611 i = grid%vc_i ; j = grid%vc_j ; height( i,j ) = height(i,j) * 1.2 !mark the center
612 CALL domain_clock_get( grid, current_timestr=message2 )
613 WRITE ( message , FMT = '(A," on domain ",I3)' ) TRIM(message2), grid%id
619 write(mess,'("ATCF"," ",A19," ",f8.2," ",f8.2," ",f6.1," ",f6.1)') &
624 !already computed above 0.01*pmin+0.1138*terrain(imploc,jmploc), &
626 CALL wrf_message(TRIM(mess))
635 DEALLOCATE ( terrain )
636 DEALLOCATE ( height )
637 DEALLOCATE ( height_l )
639 CALL wrf_dm_bcast_real( grid%vc_i , 1 )
640 CALL wrf_dm_bcast_real( grid%vc_j , 1 )
642 CALL wrf_dm_bcast_real( pmin , 1 )
643 CALL wrf_dm_bcast_integer( imploc , 1 )
644 CALL wrf_dm_bcast_integer( jmploc , 1 )
647 write(message,*)'after bcast : grid%vc_i, grid%vc_j ',grid%vc_i, grid%vc_j
648 call wrf_debug(1,message)
652 ENDIF ! COMPUTE_VORTEX_CENTER_ALARM ringing
655 write(message,*)'After ENDIF : grid%vc_i, grid%vc_j ',grid%vc_i, grid%vc_j
656 call wrf_debug(1,message)
659 dc_i = (ide-ids+1)/2. ! domain center
660 dc_j = (jde-jds+1)/2.
662 disp_x = grid%vc_i - dc_i * 1.0
663 disp_y = grid%vc_j - dc_j * 1.0
666 ! This appears to be an old, redundant, and perhaps even misnamed parameter.
667 ! Remove it from the namelist and Registry and just hard code it to
668 ! the default of 6. JM 20050721
669 CALL nl_get_vortex_search_radius( 1, irad )
676 if ( disp_x .GT. 0 ) disp_x = min( disp_x , radius )
677 if ( disp_y .GT. 0 ) disp_y = min( disp_y , radius )
679 if ( disp_x .LT. 0 ) disp_x = max( disp_x , -radius )
680 if ( disp_y .LT. 0 ) disp_y = max( disp_y , -radius )
682 move_cd_x = int ( disp_x / pgr )
683 move_cd_y = int ( disp_y / pgr )
685 IF ( move_cd_x .GT. 0 ) move_cd_x = min ( move_cd_x , 1 )
686 IF ( move_cd_y .GT. 0 ) move_cd_y = min ( move_cd_y , 1 )
687 IF ( move_cd_x .LT. 0 ) move_cd_x = max ( move_cd_x , -1 )
688 IF ( move_cd_y .LT. 0 ) move_cd_y = max ( move_cd_y , -1 )
690 CALL domain_clock_get( grid, current_timestr=timestr )
692 IF ( wrf_dm_on_monitor() ) THEN
693 WRITE(mess,*)timestr(1:19),' vortex center (in nest x and y): ',grid%vc_i, grid%vc_j
694 CALL wrf_message(TRIM(mess))
695 WRITE(mess,*)timestr(1:19),' grid center (in nest x and y): ', dc_i, dc_j
696 CALL wrf_message(TRIM(mess))
697 WRITE(mess,*)timestr(1:19),' disp : ', disp_x, disp_y
698 CALL wrf_message(TRIM(mess))
699 WRITE(mess,*)timestr(1:19),' move (rel cd) : ',move_cd_x, move_cd_y
700 CALL wrf_message(TRIM(mess))
703 grid%vc_i = grid%vc_i - move_cd_x * pgr
704 grid%vc_j = grid%vc_j - move_cd_y * pgr
707 IF ( wrf_dm_on_monitor() ) THEN
708 write(mess,*)' changing grid%vc_i, move_cd_x * pgr ', grid%vc_i, move_cd_x * pgr, move_cd_x, pgr
709 call wrf_debug(1,mess)
713 IF ( ( move_cd_x .NE. 0 ) .OR. ( move_cd_y .NE. 0 ) ) THEN
714 time_for_move2 = .TRUE.
716 time_for_move2 = .FALSE.
723 time_for_move2 = .FALSE.
724 CALL domain_clock_get( grid, current_time=ct, start_time=st )
725 CALL nl_get_num_moves( 1, num_moves )
726 IF ( num_moves .GT. max_moves ) THEN
727 WRITE(mess,*)'time_for_moves2: num_moves (',num_moves,') .GT. max_moves (',max_moves,')'
728 CALL wrf_error_fatal( TRIM(mess) )
731 CALL nl_get_move_id( i, move_id )
732 IF ( move_id .EQ. grid%id ) THEN
733 CALL nl_get_move_interval( i, move_interval )
734 IF ( move_interval .LT. 999999999 ) THEN
735 CALL WRFU_TimeIntervalSet ( ti, M=move_interval, rc=rc )
736 IF ( ct .GE. st + ti ) THEN
737 CALL nl_get_move_cd_x ( i, move_cd_x )
738 CALL nl_get_move_cd_y ( i, move_cd_y )
739 CALL nl_set_move_interval ( i, 999999999 )
740 time_for_move2 = .TRUE.
749 time_for_move2 = .FALSE.
751 END FUNCTION time_for_move2
753 LOGICAL FUNCTION time_for_move ( parent , grid , move_cd_x, move_cd_y )
754 USE module_domain, ONLY : domain, get_ijk_from_grid, adjust_domain_dims_for_move
755 ! USE module_configure
756 USE module_dm, ONLY : wrf_dm_move_nest
761 TYPE(domain) , POINTER :: parent, grid, par, nst
762 INTEGER, INTENT(OUT) :: move_cd_x , move_cd_y
765 INTEGER :: corral_dist, kid
766 INTEGER :: dw, de, ds, dn, pgr
767 INTEGER :: would_move_x, would_move_y
768 INTEGER :: cids, cide, cjds, cjde, ckds, ckde, &
769 cims, cime, cjms, cjme, ckms, ckme, &
770 cips, cipe, cjps, cjpe, ckps, ckpe, &
771 nids, nide, njds, njde, nkds, nkde, &
772 nims, nime, njms, njme, nkms, nkme, &
773 nips, nipe, njps, njpe, nkps, nkpe
774 REAL :: xtime, time_to_move
777 LOGICAL FUNCTION time_for_move2 ( parent , nest , dx , dy )
778 USE module_domain, ONLY : domain
779 TYPE(domain) , POINTER :: parent , nest
780 INTEGER, INTENT(OUT) :: dx , dy
781 END FUNCTION time_for_move2
785 ! Simplifying assumption: domains in moving nest simulations have only
786 ! one parent and only one child.
788 IF ( grid%num_nests .GT. 1 ) THEN
789 CALL wrf_error_fatal ( 'domains in moving nest simulations can have only 1 nest' )
794 ! Check if it is time to move the nest
796 CALL nl_get_time_to_move ( grid%id , time_to_move )
797 if ( xtime .lt. time_to_move ) then
798 time_for_move = .FALSE.
801 ! write(0,*) 'it is not the time to move ', xtime, time_to_move
806 ! find out if this is the innermost nest (will not have kids)
807 IF ( grid%num_nests .EQ. 0 ) THEN
808 ! code that executes on innermost nest
809 time_for_move = time_for_move2 ( parent , grid , move_cd_x, move_cd_y )
811 ! Make sure the parent can move before allowing the nest to approach
813 par => grid%parents(1)%ptr
816 would_move_x = move_cd_x
817 would_move_y = move_cd_y
821 CALL nl_get_corral_dist ( nst%id , corral_dist )
822 CALL get_ijk_from_grid ( nst , &
823 nids, nide, njds, njde, nkds, nkde, &
824 nims, nime, njms, njme, nkms, nkme, &
825 nips, nipe, njps, njpe, nkps, nkpe )
826 CALL get_ijk_from_grid ( par , &
827 cids, cide, cjds, cjde, ckds, ckde, &
828 cims, cime, cjms, cjme, ckms, ckme, &
829 cips, cipe, cjps, cjpe, ckps, ckpe )
830 CALL nl_get_parent_grid_ratio ( nst%id , pgr )
831 ! perform measurements...
832 ! from western boundary
833 dw = nst%i_parent_start + would_move_x - cids
834 ! from southern boundary
835 ds = nst%j_parent_start + would_move_y - cjds
836 ! from eastern boundary
837 de = cide - ( nst%i_parent_start + (nide-nids+1)/pgr + would_move_x )
838 ! from northern boundary
839 dn = cjde - ( nst%j_parent_start + (njde-njds+1)/pgr + would_move_y )
841 ! would this generate a move on the parent?
844 if ( dw .LE. corral_dist ) would_move_x = would_move_x - 1
845 if ( de .LE. corral_dist ) would_move_x = would_move_x + 1
846 if ( ds .LE. corral_dist ) would_move_y = would_move_y - 1
847 if ( dn .LE. corral_dist ) would_move_y = would_move_y + 1
849 IF ( par%id .EQ. 1 ) THEN
850 IF ( would_move_x .NE. 0 .AND. move_cd_x .NE. 0 ) THEN
851 CALL wrf_message('MOAD can not move. Cancelling nest move in X')
852 if ( grid%num_nests .eq. 0 ) grid%vc_i = grid%vc_i + move_cd_x * pgr ! cancel effect of move
855 IF ( would_move_y .NE. 0 .AND. move_cd_y .NE. 0 ) THEN
856 CALL wrf_message('MOAD can not move. Cancelling nest move in Y')
857 if ( grid%num_nests .eq. 0 ) grid%vc_j = grid%vc_j + move_cd_y * pgr ! cancel effect of move
862 par => nst%parents(1)%ptr
866 ! bottom of until loop
867 time_for_move = ( move_cd_x .NE. 0 ) .OR. ( move_cd_y .NE. 0 )
870 ! code that executes on parent to see if parent needs to move
871 ! get closest number of cells we'll allow nest edge to approach parent bdy
872 CALL nl_get_corral_dist ( grid%nests(kid)%ptr%id , corral_dist )
874 CALL get_ijk_from_grid ( grid%nests(kid)%ptr , &
875 nids, nide, njds, njde, nkds, nkde, &
876 nims, nime, njms, njme, nkms, nkme, &
877 nips, nipe, njps, njpe, nkps, nkpe )
878 CALL get_ijk_from_grid ( grid , &
879 cids, cide, cjds, cjde, ckds, ckde, &
880 cims, cime, cjms, cjme, ckms, ckme, &
881 cips, cipe, cjps, cjpe, ckps, ckpe )
882 CALL nl_get_parent_grid_ratio ( grid%nests(kid)%ptr%id , pgr )
883 ! perform measurements...
884 ! from western boundary
885 dw = grid%nests(kid)%ptr%i_parent_start - 1
886 ! from southern boundary
887 ds = grid%nests(kid)%ptr%j_parent_start - 1
888 ! from eastern boundary
889 de = cide - ( grid%nests(kid)%ptr%i_parent_start + (nide-nids+1)/pgr )
890 ! from northern boundary
891 dn = cjde - ( grid%nests(kid)%ptr%j_parent_start + (njde-njds+1)/pgr )
893 ! move this domain (the parent containing the moving nest)
894 ! in a direction that reestablishes the distance from
898 if ( dw .LE. corral_dist ) move_cd_x = move_cd_x - 1
899 if ( de .LE. corral_dist ) move_cd_x = move_cd_x + 1
900 if ( ds .LE. corral_dist ) move_cd_y = move_cd_y - 1
901 if ( dn .LE. corral_dist ) move_cd_y = move_cd_y + 1
903 time_for_move = ( move_cd_x .NE. 0 ) .OR. ( move_cd_y .NE. 0 )
905 IF ( time_for_move ) THEN
906 IF ( grid%id .EQ. 1 ) THEN
908 CALL wrf_message( 'DANGER: Nest has moved too close to boundary of outermost domain.' )
909 time_for_move = .FALSE.
912 ! need to adjust the intermediate domain of the nest in relation to this
913 ! domain since we're moving
915 CALL wrf_dm_move_nest ( grid , grid%nests(kid)%ptr%intermediate_grid , -move_cd_x*pgr, -move_cd_y*pgr )
916 CALL adjust_domain_dims_for_move( grid%nests(kid)%ptr%intermediate_grid , -move_cd_x*pgr, -move_cd_y*pgr )
917 grid%nests(kid)%ptr%i_parent_start = grid%nests(kid)%ptr%i_parent_start - move_cd_x*pgr
918 grid%nests(kid)%ptr%j_parent_start = grid%nests(kid)%ptr%j_parent_start - move_cd_y*pgr
920 CALL nl_set_i_parent_start( grid%nests(kid)%ptr%id, grid%nests(kid)%ptr%i_parent_start )
921 CALL nl_set_j_parent_start( grid%nests(kid)%ptr%id, grid%nests(kid)%ptr%j_parent_start )
930 time_for_move = .FALSE.
932 END FUNCTION time_for_move
934 ! Put any tests for non-moving options or conditions in here
935 LOGICAL FUNCTION should_not_move ( id )
936 USE module_state_description
937 ! USE module_configure
939 INTEGER, INTENT(IN) :: id
942 INTEGER cu_physics, ra_sw_physics, ra_lw_physics, sf_urban_physics, sf_surface_physics, obs_nudge_opt
945 ! check for GD ensemble cumulus, which can not move
946 CALL nl_get_cu_physics( id , cu_physics )
947 IF ( cu_physics .EQ. GDSCHEME ) THEN
948 CALL wrf_message('Grell cumulus can not be specified with moving nests. Movement disabled.')
951 ! check for CAM radiation scheme , which can not move
952 CALL nl_get_ra_sw_physics( id , ra_sw_physics )
953 IF ( ra_sw_physics .EQ. CAMSWSCHEME ) THEN
954 CALL wrf_message('CAM SW radiation can not be specified with moving nests. Movement disabled.')
957 CALL nl_get_ra_lw_physics( id , ra_lw_physics )
958 IF ( ra_lw_physics .EQ. CAMLWSCHEME ) THEN
959 CALL wrf_message('CAM LW radiation can not be specified with moving nests. Movement disabled.')
962 ! check for urban canopy Noah LSM, which can not move
963 CALL nl_get_sf_urban_physics( id , sf_urban_physics )
964 IF ( sf_urban_physics .EQ. 1 .OR. sf_urban_physics .EQ. 2 ) THEN
965 CALL wrf_message('UCMs Noah LSM can not be specified with moving nests. Movement disabled.')
968 ! check for PX lsm scheme, which can not move
969 CALL nl_get_sf_surface_physics( id , sf_surface_physics )
970 IF ( sf_surface_physics .EQ. PXLSMSCHEME ) THEN
971 CALL wrf_message('PX LSM can not be specified with moving nests. Movement disabled.')
975 ! check for observation nudging, which can not move
976 CALL nl_get_obs_nudge_opt( id , obs_nudge_opt )
977 IF ( obs_nudge_opt .EQ. 1 ) THEN
978 CALL wrf_message('Observation nudging can not be specified with moving nests. Movement disabled.')
982 should_not_move = retval
985 SUBROUTINE reconcile_nest_positions_over_tasks ( grid )
986 USE module_driver_constants, ONLY : max_nests, max_domains
987 USE module_domain, ONLY : domain, find_grid_by_id
989 USE module_configure, ONLY : grid_config_rec_type, model_config_rec, model_to_grid_config_rec
990 USE module_state_description
992 USE module_dm, ONLY : wrf_dm_move_nest, nest_task_offsets,mpi_comm_to_kid,mpi_comm_to_mom, which_kid &
993 ,comm_start, nest_pes_x, nest_pes_y,local_communicator
995 TYPE(domain) , POINTER :: grid, result_grid
1000 INTEGER buf(max_domains,2)
1002 CALL nl_get_max_dom( 1 , max_dom )
1003 IF ( grid%num_nests .GT. 1 ) THEN
1004 IF ( grid%active_this_task ) THEN
1005 DO kid = 1, max_nests
1006 ! which task is active?
1007 IF ( ASSOCIATED( grid%nests(kid)%ptr ) ) THEN
1008 ! check to see if the starting task for the nest is within the range of tasks
1009 ! of the parent's local communicator; that task should be the root of the bcast on this grid's (the parent's) communicator
1010 ! since it is active in both the parent and nest and should have valid parent_start information;
1011 ! otoh, if it is outside then the parent and nest are not sharing processors
1012 itask = comm_start( grid%nests(kid)%ptr%id ) - comm_start( grid%id )
1013 buf(:,1) = model_config_rec%i_parent_start
1014 buf(:,2) = model_config_rec%j_parent_start
1015 IF ( itask .GE. 0 .AND. itask .LT. nest_pes_x(grid%id)*nest_pes_y(grid%id) ) THEN
1016 CALL push_communicators_for_domain(grid%id)
1017 CALL BYTE_BCAST_FROM_ROOT( buf, 2*max_domains*IWORDSIZE, itask, local_communicator)
1018 CALL pop_communicators_for_domain
1021 CALL find_grid_by_id ( id, grid%nests(kid)%ptr, result_grid )
1022 IF ( ASSOCIATED(result_grid) .AND. .NOT. result_grid%active_this_task ) THEN
1023 model_config_rec%i_parent_start(id) = buf(id,1)
1024 model_config_rec%j_parent_start(id) = buf(id,2)
1025 result_grid%i_parent_start = model_config_rec%i_parent_start(id)
1026 result_grid%j_parent_start = model_config_rec%j_parent_start(id)
1034 END SUBROUTINE reconcile_nest_positions_over_tasks