4 USE module_model_constants
6 CHARACTER (LEN=256) , PRIVATE :: a_message
10 SUBROUTINE couple_scalars_for_filter ( field &
12 ,ids,ide,jds,jde,kds,kde &
13 ,ims,ime,jms,jme,kms,kme &
14 ,ips,ipe,jps,jpe,kps,kpe )
16 INTEGER, INTENT(IN) :: ids,ide,jds,jde,kds,kde &
17 ,ims,ime,jms,jme,kms,kme &
18 ,ips,ipe,jps,jpe,kps,kpe
19 REAL , DIMENSION(ims:ime,kms:kme,jms:jme) , INTENT(INOUT) :: field
20 REAL , DIMENSION(ims:ime,jms:jme) , INTENT(IN) :: mu,mub
21 REAL , DIMENSION(kms:kme) , INTENT(IN) :: c1,c2
25 DO j = jps, MIN(jpe,jde-1)
27 DO i = ips, MIN(ipe,ide-1)
28 field(i,k,j)=field(i,k,j)*( (c1(k)*mu(i,j))+(c1(k)*mub(i,j)+c2(k)))
33 END SUBROUTINE couple_scalars_for_filter
35 SUBROUTINE uncouple_scalars_for_filter ( field &
37 ,ids,ide,jds,jde,kds,kde &
38 ,ims,ime,jms,jme,kms,kme &
39 ,ips,ipe,jps,jpe,kps,kpe )
41 INTEGER, INTENT(IN) :: ids,ide,jds,jde,kds,kde &
42 ,ims,ime,jms,jme,kms,kme &
43 ,ips,ipe,jps,jpe,kps,kpe
44 REAL , DIMENSION(ims:ime,kms:kme,jms:jme) , INTENT(INOUT) :: field
45 REAL , DIMENSION(ims:ime,jms:jme) , INTENT(IN) :: mu,mub
46 REAL , DIMENSION(kms:kme) , INTENT(IN) :: c1,c2
50 DO j = jps, MIN(jpe,jde-1)
52 DO i = ips, MIN(ipe,ide-1)
53 field(i,k,j)=field(i,k,j)/( (c1(k)*mu(i,j))+(c1(k)*mub(i,j)+c2(k)))
58 END SUBROUTINE uncouple_scalars_for_filter
60 SUBROUTINE pxft ( grid &
70 ,fft_filter_lat, dclat &
71 ,actual_distance_average &
73 ,swap_pole_with_next_j &
74 ,moist,chem,tracer,scalar &
75 ,ids,ide,jds,jde,kds,kde &
76 ,ims,ime,jms,jme,kms,kme &
77 ,ips,ipe,jps,jpe,kps,kpe &
78 ,imsx,imex,jmsx,jmex,kmsx,kmex &
79 ,ipsx,ipex,jpsx,jpex,kpsx,kpex )
80 USE module_state_description
81 USE module_domain, ONLY : domain
83 USE module_dm, ONLY : local_communicator, mytask, ntasks, ntasks_x, ntasks_y &
84 , local_communicator_periodic, itrace &
85 , local_communicator_x
86 USE module_driver_constants
88 USE module_comm_dm, ONLY : &
89 XPOSE_POLAR_FILTER_V_z2x_sub &
90 ,XPOSE_POLAR_FILTER_V_x2z_sub &
91 ,XPOSE_POLAR_FILTER_U_z2x_sub &
92 ,XPOSE_POLAR_FILTER_U_x2z_sub &
93 ,XPOSE_POLAR_FILTER_T_z2x_sub &
94 ,XPOSE_POLAR_FILTER_T_x2z_sub &
95 ,XPOSE_POLAR_FILTER_W_z2x_sub &
96 ,XPOSE_POLAR_FILTER_W_x2z_sub &
97 ,XPOSE_POLAR_FILTER_PH_z2x_sub &
98 ,XPOSE_POLAR_FILTER_PH_x2z_sub &
99 ,XPOSE_POLAR_FILTER_WW_z2x_sub &
100 ,XPOSE_POLAR_FILTER_WW_x2z_sub &
101 ,XPOSE_POLAR_FILTER_RV_z2x_sub &
102 ,XPOSE_POLAR_FILTER_RV_x2z_sub &
103 ,XPOSE_POLAR_FILTER_RU_z2x_sub &
104 ,XPOSE_POLAR_FILTER_RU_x2z_sub &
105 ,XPOSE_POLAR_FILTER_MOIST_z2x_sub &
106 ,XPOSE_POLAR_FILTER_MOIST_x2z_sub &
107 ,XPOSE_POLAR_FILTER_CHEM_z2x_sub &
108 ,XPOSE_POLAR_FILTER_MOIST_x2z_sub &
109 ,XPOSE_POLAR_FILTER_TRACER_z2x_sub &
110 ,XPOSE_POLAR_FILTER_TRACER_x2z_sub &
111 ,XPOSE_POLAR_FILTER_SCALAR_z2x_sub &
112 ,XPOSE_POLAR_FILTER_SCALAR_x2z_sub
119 TYPE(domain) , TARGET :: grid
120 integer, intent(in) :: lineno
121 integer myproc, i, j, k
122 LOGICAL, INTENT(IN) :: actual_distance_average
123 LOGICAL, INTENT(IN) :: pos_def
124 LOGICAL, INTENT(IN) :: swap_pole_with_next_j
125 INTEGER, INTENT(IN) :: ids,ide,jds,jde,kds,kde &
126 ,ims,ime,jms,jme,kms,kme &
127 ,ips,ipe,jps,jpe,kps,kpe &
128 ,imsx,imex,jmsx,jmex,kmsx,kmex &
129 ,ipsx,ipex,jpsx,jpex,kpsx,kpex
130 REAL , INTENT(IN) :: fft_filter_lat
131 REAL, INTENT(IN) :: dclat
132 INTEGER, INTENT(IN) :: flag_uv &
141 REAL, DIMENSION(ims:ime,kms:kme,jms:jme,*) , INTENT(INOUT) :: moist, chem, scalar,tracer
144 LOGICAL piggyback_mu, piggyback_mut
153 piggyback_mu = flag_mu .EQ. 1
154 piggyback_mut = flag_mut .EQ. 1
158 ! The idea is that this parallel transpose fft routine can be
159 ! called at various points in the solver (solve_em) and it will filter
160 ! the correct fields based on the flag arguments. There are two 2d
161 ! fields mu_2 and mut that may need to be filtered too. Since a two-d
162 ! parallel transpose would be inefficient and because the fields that are
163 ! not staggered in z have an extra layer anyway, these can be
164 ! piggybacked. This is handled using latches to makes sure that *somebody*
165 ! carries one or both of these on their back through the filtering and then
166 ! copies them back afterwards. IMPORTANT NOTE: for simplicity, this routine
167 ! is not completely general. It makes the following assumptions:
169 ! 1) If both flag_mu and flag_mut are specified then flag_uv is also specified
171 ! 2) If flag_uv is not specified, then only flag_mu and not flag_mut can be
173 ! 3) If flag_mu is specified than either flag_uv or flag_t must be
175 ! This is designed to keep the clutter to a minimum in solve_em.
176 ! This is not intended to be a general abstraction of the polar filtering
177 ! calls in in WRF solvers or if the solve_em algorithms change.
178 ! If the needs of the calling solver change, this logic may have to be
182 !write(0,*)"<stdin>",__LINE__,' short circuit '
185 !write(0,*)'pxft called from ',lineno
186 call wrf_get_myproc(myproc)
187 !write(20+myproc,*)ipex-ipsx+1,jpex-jpsx+1,' clat_xxx '
190 !write(20+myproc,*)grid%clat_xxx(i,j)
194 !!!!!!!!!!!!!!!!!!!!!!!
196 IF ( flag_uv .EQ. 1 ) THEN
197 IF ( piggyback_mu ) THEN
198 grid%u_2(ips:ipe,kde,jps:jpe) = grid%mu_2(ips:ipe,jps:jpe)
200 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
201 # include "XPOSE_POLAR_FILTER_V_z2x.inc"
203 CALL polar_filter_3d( grid%v_xxx, grid%clat_xxx, .false., &
204 fft_filter_lat, dclat, &
205 ids, ide, jds, jde, kds, kde-1, &
206 imsx, imex, jmsx, jmex, kmsx, kmex, &
207 ipsx, ipex, jpsx, jpex, kpsx, MIN(kde-1,kpex ) )
209 # include "XPOSE_POLAR_FILTER_V_x2z.inc"
210 # include "XPOSE_POLAR_FILTER_U_z2x.inc"
211 k_end = MIN(kde-1,kpex)
212 IF ( piggyback_mu ) k_end = MIN(kde,kpex)
214 CALL polar_filter_3d( grid%u_xxx, grid%clat_xxx, piggyback_mu, &
215 fft_filter_lat, 0., &
216 ids, ide, jds, jde, kds, kde, &
217 imsx, imex, jmsx, jmex, kmsx, kmex, &
218 ipsx, ipex, jpsx, jpex, kpsx, k_end )
220 # include "XPOSE_POLAR_FILTER_U_x2z.inc"
223 CALL polar_filter_3d( grid%v_2, grid%clat, .false., &
224 fft_filter_lat, dclat, &
225 ids, ide, jds, jde, kds, kde, &
226 ims, ime, jms, jme, kms, kme, &
227 ips, ipe, jps, jpe, kps, MIN(kde-1,kpe) )
229 k_end = MIN(kde-1,kpe)
230 IF ( piggyback_mu ) k_end = MIN(kde,kpe)
232 CALL polar_filter_3d( grid%u_2, grid%clat, piggyback_mu, &
233 fft_filter_lat, 0., &
234 ids, ide, jds, jde, kds, kde-1, &
235 ims, ime, jms, jme, kms, kme, &
236 ips, ipe, jps, jpe, kps, k_end )
240 IF ( piggyback_mu ) THEN
241 grid%mu_2(ips:ipe,jps:jpe) = grid%u_2(ips:ipe,kde,jps:jpe)
242 piggyback_mu = .FALSE.
246 !!!!!!!!!!!!!!!!!!!!!!!
248 IF ( flag_t .EQ. 1 ) THEN
249 IF ( piggyback_mu ) THEN
250 grid%t_2(ips:ipe,kde,jps:jpe) = grid%mu_2(ips:ipe,jps:jpe)
252 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
253 # include "XPOSE_POLAR_FILTER_T_z2x.inc"
254 k_end = MIN(kde-1,kpex)
255 IF ( piggyback_mu ) k_end = MIN(kde,kpex)
257 CALL polar_filter_3d( grid%t_xxx, grid%clat_xxx,piggyback_mu, &
258 fft_filter_lat, 0., &
259 ids, ide, jds, jde, kds, kde-1, &
260 imsx, imex, jmsx, jmex, kmsx, kmex, &
261 ipsx, ipex, jpsx, jpex, kpsx, k_end )
263 IF ( actual_distance_average ) THEN
264 CALL filter_tracer ( grid%t_xxx , grid%clat_xxx , grid%mf_xxx , &
265 grid%fft_filter_lat , grid%mf_fft , &
266 pos_def, swap_pole_with_next_j , &
267 ids, ide, jds, jde, kds, kde , &
268 imsx, imex, jmsx, jmex, kmsx, kmex, &
269 ipsx, ipex, jpsx, jpex, kpsx, kpex )
272 # include "XPOSE_POLAR_FILTER_T_x2z.inc"
274 k_end = MIN(kde-1,kpe)
275 IF ( piggyback_mu ) k_end = MIN(kde,kpe)
277 CALL polar_filter_3d( grid%t_2, grid%clat, piggyback_mu, &
278 fft_filter_lat, 0., &
279 ids, ide, jds, jde, kds, kde-1, &
280 ims, ime, jms, jme, kms, kme, &
281 ips, ipe, jps, jpe, kps, k_end )
283 IF ( actual_distance_average ) THEN
284 CALL filter_tracer ( grid%t_2 , grid%clat , grid%msft , &
285 grid%fft_filter_lat , grid%mf_fft , &
286 pos_def, swap_pole_with_next_j , &
287 ids, ide, jds, jde, kds, kde , &
288 ims, ime, jms, jme, kms, kme, &
289 ips, ipe, jps, jpe, kps, k_end )
293 IF ( piggyback_mu ) THEN
294 grid%mu_2(ips:ipe,jps:jpe) = grid%t_2(ips:ipe,kde,jps:jpe)
295 piggyback_mu = .FALSE.
299 !!!!!!!!!!!!!!!!!!!!!!!
301 IF ( flag_wph .EQ. 1 ) THEN
302 ! W AND PH USE ALL LEVELS SO NEVER PIGGYBACK, MU IS OUT OF LUCK HERE
303 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
304 # include "XPOSE_POLAR_FILTER_W_z2x.inc"
305 CALL polar_filter_3d( grid%w_xxx, grid%clat_xxx, .false., &
306 fft_filter_lat, 0., &
307 ids, ide, jds, jde, kds, kde, &
308 imsx, imex, jmsx, jmex, kmsx, kmex, &
309 ipsx, ipex, jpsx, jpex, kpsx, kpex )
311 # include "XPOSE_POLAR_FILTER_W_x2z.inc"
312 # include "XPOSE_POLAR_FILTER_PH_z2x.inc"
314 CALL polar_filter_3d( grid%ph_xxx, grid%clat_xxx, .false., &
315 fft_filter_lat, 0., &
316 ids, ide, jds, jde, kds, kde, &
317 imsx, imex, jmsx, jmex, kmsx, kmex, &
318 ipsx, ipex, jpsx, jpex, kpsx, kpex )
320 # include "XPOSE_POLAR_FILTER_PH_x2z.inc"
323 CALL polar_filter_3d( grid%w_2, grid%clat, .false., &
324 fft_filter_lat, 0., &
325 ids, ide, jds, jde, kds, kde, &
326 ims, ime, jms, jme, kms, kme, &
327 ips, ipe, jps, jpe, kps, kpe )
329 CALL polar_filter_3d( grid%ph_2, grid%clat, .false., &
330 fft_filter_lat, 0., &
331 ids, ide, jds, jde, kds, kde, &
332 ims, ime, jms, jme, kms, kme, &
333 ips, ipe, jps, jpe, kps, kpe )
337 !!!!!!!!!!!!!!!!!!!!!!!
339 IF ( flag_ww .EQ. 1 ) THEN
340 ! WW USES ALL LEVELS SO NEVER PIGGYBACK, MU IS OUT OF LUCK HERE
341 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
342 # include "XPOSE_POLAR_FILTER_WW_z2x.inc"
343 CALL polar_filter_3d( grid%ww_xxx, grid%clat_xxx, .false., &
344 fft_filter_lat, 0., &
345 ids, ide, jds, jde, kds, kde, &
346 imsx, imex, jmsx, jmex, kmsx, kmex, &
347 ipsx, ipex, jpsx, jpex, kpsx, kpex )
349 # include "XPOSE_POLAR_FILTER_WW_x2z.inc"
351 CALL polar_filter_3d( grid%ww_m, grid%clat, .false., &
352 fft_filter_lat, 0., &
353 ids, ide, jds, jde, kds, kde, &
354 ims, ime, jms, jme, kms, kme, &
355 ips, ipe, jps, jpe, kps, kpe )
359 !!!!!!!!!!!!!!!!!!!!!!!
361 IF ( flag_rurv .EQ. 1 ) THEN
362 IF ( piggyback_mut ) THEN
363 grid%ru_m(ips:ipe,kde,jps:jpe) = grid%mut(ips:ipe,jps:jpe)
365 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
366 # include "XPOSE_POLAR_FILTER_RV_z2x.inc"
367 CALL polar_filter_3d( grid%rv_xxx, grid%clat_xxx, .false., &
368 fft_filter_lat, dclat, &
369 ids, ide, jds, jde, kds, kde, &
370 imsx, imex, jmsx, jmex, kmsx, kmex, &
371 ipsx, ipex, jpsx, jpex, kpsx, MIN(kpex,kde-1) )
373 # include "XPOSE_POLAR_FILTER_RV_x2z.inc"
374 # include "XPOSE_POLAR_FILTER_RU_z2x.inc"
375 k_end = MIN(kde-1,kpex)
376 IF ( piggyback_mut ) k_end = MIN(kde,kpex)
378 CALL polar_filter_3d( grid%ru_xxx, grid%clat_xxx, piggyback_mut, &
379 fft_filter_lat, 0., &
380 ids, ide, jds, jde, kds, kde, &
381 imsx, imex, jmsx, jmex, kmsx, kmex, &
382 ipsx, ipex, jpsx, jpex, kpsx, k_end )
383 #include "XPOSE_POLAR_FILTER_RU_x2z.inc"
386 CALL polar_filter_3d( grid%rv_m, grid%clat, .false., &
387 fft_filter_lat, dclat, &
388 ids, ide, jds, jde, kds, kde, &
389 ims, ime, jms, jme, kms, kme, &
390 ips, ipe, jps, jpe, kps, MIN(kde-1,kpe) )
392 k_end = MIN(kde-1,kpe)
393 IF ( piggyback_mut ) k_end = MIN(kde,kpe)
395 CALL polar_filter_3d( grid%ru_m, grid%clat, piggyback_mut, &
396 fft_filter_lat, 0., &
397 ids, ide, jds, jde, kds, kde-1, &
398 ims, ime, jms, jme, kms, kme, &
399 ips, ipe, jps, jpe, kps, k_end )
401 IF ( piggyback_mut ) THEN
402 grid%mut(ips:ipe,jps:jpe) = grid%ru_m(ips:ipe,kde,jps:jpe)
403 piggyback_mut = .FALSE.
407 !!!!!!!!!!!!!!!!!!!!!!!
409 IF ( flag_moist .GE. PARAM_FIRST_SCALAR ) THEN
411 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
412 # include "XPOSE_POLAR_FILTER_MOIST_z2x.inc"
413 CALL polar_filter_3d( grid%fourd_xxx, grid%clat_xxx, .false. , &
414 fft_filter_lat, 0., &
415 ids, ide, jds, jde, kds, kde, &
416 imsx, imex, jmsx, jmex, kmsx, kmex, &
417 ipsx, ipex, jpsx, jpex, kpsx, MIN(kpex,kde-1) )
419 IF ( actual_distance_average ) THEN
420 CALL filter_tracer ( grid%fourd_xxx , grid%clat_xxx , grid%mf_xxx , &
421 grid%fft_filter_lat , grid%mf_fft , &
422 pos_def, swap_pole_with_next_j , &
423 ids, ide, jds, jde, kds, kde , &
424 imsx, imex, jmsx, jmex, kmsx, kmex, &
425 ipsx, ipex, jpsx, jpex, kpsx, kpex )
427 # include "XPOSE_POLAR_FILTER_MOIST_x2z.inc"
429 CALL polar_filter_3d( moist(ims,kms,jms,itrace), grid%clat, .false., &
430 fft_filter_lat, 0., &
431 ids, ide, jds, jde, kds, kde, &
432 ims, ime, jms, jme, kms, kme, &
433 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
435 IF ( actual_distance_average ) THEN
436 CALL filter_tracer ( moist(ims,kms,jms,itrace) , grid%clat , grid%msft , &
437 grid%fft_filter_lat , grid%mf_fft , &
438 pos_def, swap_pole_with_next_j , &
439 ids, ide, jds, jde, kds, kde , &
440 ims, ime, jms, jme, kms, kme, &
441 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
446 !!!!!!!!!!!!!!!!!!!!!!!
448 IF ( flag_chem .GE. PARAM_FIRST_SCALAR ) THEN
450 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
451 # include "XPOSE_POLAR_FILTER_CHEM_z2x.inc"
452 CALL polar_filter_3d( grid%fourd_xxx, grid%clat_xxx, .false. , &
453 fft_filter_lat, 0., &
454 ids, ide, jds, jde, kds, kde, &
455 imsx, imex, jmsx, jmex, kmsx, kmex, &
456 ipsx, ipex, jpsx, jpex, kpsx, MIN(kpex,kde-1) )
458 IF ( actual_distance_average ) THEN
459 CALL filter_tracer ( grid%fourd_xxx , grid%clat_xxx , grid%mf_xxx , &
460 grid%fft_filter_lat , grid%mf_fft , &
461 pos_def, swap_pole_with_next_j , &
462 ids, ide, jds, jde, kds, kde , &
463 imsx, imex, jmsx, jmex, kmsx, kmex, &
464 ipsx, ipex, jpsx, jpex, kpsx, kpex )
466 # include "XPOSE_POLAR_FILTER_CHEM_x2z.inc"
468 CALL polar_filter_3d( chem(ims,kms,jms,itrace), grid%clat, .false. , &
469 fft_filter_lat, 0., &
470 ids, ide, jds, jde, kds, kde, &
471 ims, ime, jms, jme, kms, kme, &
472 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
474 IF ( actual_distance_average ) THEN
475 CALL filter_tracer ( chem(ims,kms,jms,itrace) , grid%clat , grid%msft , &
476 grid%fft_filter_lat , grid%mf_fft , &
477 pos_def, swap_pole_with_next_j , &
478 ids, ide, jds, jde, kds, kde , &
479 ims, ime, jms, jme, kms, kme, &
480 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
485 !!!!!!!!!!!!!!!!!!!!!!!
487 IF ( flag_tracer .GE. PARAM_FIRST_SCALAR ) THEN
489 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
490 # include "XPOSE_POLAR_FILTER_TRACER_z2x.inc"
492 CALL polar_filter_3d( grid%fourd_xxx, grid%clat_xxx, .false. , &
493 fft_filter_lat, 0., &
494 ids, ide, jds, jde, kds, kde, &
495 imsx, imex, jmsx, jmex, kmsx, kmex, &
496 ipsx, ipex, jpsx, jpex, kpsx, MIN(kpex,kde-1) )
498 IF ( actual_distance_average ) THEN
499 CALL filter_tracer ( grid%fourd_xxx , grid%clat_xxx , grid%mf_xxx , &
500 grid%fft_filter_lat , grid%mf_fft , &
501 pos_def, swap_pole_with_next_j , &
502 ids, ide, jds, jde, kds, kde , &
503 imsx, imex, jmsx, jmex, kmsx, kmex, &
504 ipsx, ipex, jpsx, jpex, kpsx, kpex )
507 # include "XPOSE_POLAR_FILTER_TRACER_x2z.inc"
509 CALL polar_filter_3d( tracer(ims,kms,jms,itrace), grid%clat, .false. , &
510 fft_filter_lat, 0., &
511 ids, ide, jds, jde, kds, kde, &
512 ims, ime, jms, jme, kms, kme, &
513 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
515 IF ( actual_distance_average ) THEN
516 CALL filter_tracer ( tracer(ims,kms,jms,itrace) , grid%clat , grid%msft , &
517 grid%fft_filter_lat , grid%mf_fft , &
518 pos_def, swap_pole_with_next_j , &
519 ids, ide, jds, jde, kds, kde , &
520 ims, ime, jms, jme, kms, kme, &
521 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
526 !!!!!!!!!!!!!!!!!!!!!!!
528 IF ( flag_scalar .GE. PARAM_FIRST_SCALAR ) THEN
530 #if ( defined( DM_PARALLEL ) && ( ! defined( STUBMPI ) ) )
531 # include "XPOSE_POLAR_FILTER_SCALAR_z2x.inc"
532 CALL polar_filter_3d( grid%fourd_xxx , grid%clat_xxx, .false. , &
533 fft_filter_lat, 0., &
534 ids, ide, jds, jde, kds, kde, &
535 imsx, imex, jmsx, jmex, kmsx, kmex, &
536 ipsx, ipex, jpsx, jpex, kpsx, MIN(kpex,kde-1) )
538 IF ( actual_distance_average ) THEN
539 CALL filter_tracer ( grid%fourd_xxx , grid%clat_xxx , grid%mf_xxx , &
540 grid%fft_filter_lat , grid%mf_fft , &
541 pos_def, swap_pole_with_next_j , &
542 ids, ide, jds, jde, kds, kde , &
543 imsx, imex, jmsx, jmex, kmsx, kmex, &
544 ipsx, ipex, jpsx, jpex, kpsx, kpex )
546 # include "XPOSE_POLAR_FILTER_SCALAR_x2z.inc"
548 CALL polar_filter_3d( scalar(ims,kms,jms,itrace) , grid%clat, .false. , &
549 fft_filter_lat, 0., &
550 ids, ide, jds, jde, kds, kde, &
551 ims, ime, jms, jme, kms, kme, &
552 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
554 IF ( actual_distance_average ) THEN
555 CALL filter_tracer ( scalar(ims,kms,jms,itrace) , grid%clat , grid%msft , &
556 grid%fft_filter_lat , grid%mf_fft , &
557 pos_def, swap_pole_with_next_j , &
558 ids, ide, jds, jde, kds, kde , &
559 ims, ime, jms, jme, kms, kme, &
560 ips, ipe, jps, jpe, kps, MIN(kpe,kde-1) )
565 IF ( flag_mu .EQ. 1 .AND. piggyback_mu ) THEN
566 CALL wrf_error_fatal("mu needed to get piggybacked on a transpose and did not")
568 IF ( flag_mut .EQ. 1 .AND. piggyback_mut ) THEN
569 CALL wrf_error_fatal("mut needed to get piggybacked on a transpose and did not")
572 !write(0,*)'pxft back to ',lineno
576 SUBROUTINE polar_filter_3d( f, xlat, piggyback, fft_filter_lat, dvlat, &
577 ids, ide, jds, jde, kds, kde, &
578 ims, ime, jms, jme, kms, kme, &
579 its, ite, jts, jte, kts, kte )
583 INTEGER , INTENT(IN ) :: ids, ide, jds, jde, kds, kde, &
584 ims, ime, jms, jme, kms, kme, &
585 its, ite, jts, jte, kts, kte
586 REAL , INTENT(IN ) :: fft_filter_lat
588 REAL , DIMENSION( ims:ime , kms:kme, jms:jme ) , INTENT(INOUT) :: f
589 REAL , DIMENSION( ims:ime , jms:jme ) , INTENT(IN) :: xlat
590 REAL , INTENT(IN) :: dvlat
591 LOGICAL , INTENT(IN) :: piggyback
593 REAL , DIMENSION(1:ide-ids,1:kte-kts+1) :: sheet
594 REAL , DIMENSION(1:kte-kts+1) :: sheet_total
595 REAL :: lat, avg, rnboxw
596 INTEGER :: ig, jg, i, j, j_end, nx, ny, nmax, kw
597 INTEGER :: k, nboxw, nbox2, istart, iend, overlap
598 INTEGER, DIMENSION(6) :: wavenumber = (/ 1, 3, 7, 10, 13, 16 /)
602 ! Variables will stay in domain form since this routine is meaningless
603 ! unless tile extent is the same as domain extent in E/W direction, i.e.,
604 ! the processor has access to all grid points in E/W direction.
605 ! There may be other ways of doing FFTs, but we have not learned them yet...
607 ! Check to make sure we have full access to all E/W points
608 IF ((its /= ids) .OR. (ite /= ide)) THEN
609 WRITE ( wrf_err_message , * ) 'module_polarfft: 3d: (its /= ids) or (ite /= ide)',its,ids,ite,ide
610 CALL wrf_error_fatal ( TRIM( wrf_err_message ) )
613 fftflag= 1 ! call double-precision fft
614 ! fftflag= 0 ! call single-precision fft
616 nx = ide-ids ! "U" stagger variables will be repeated by periodic BCs
617 ny = kte-kts+1 ! we can filter extra level for variables that are non-Z-staggered
619 j_end = MIN(jte, jde-1)
620 IF (dvlat /= 0. .and. j_end == jde-1) j_end = jde
622 ! jg is the J index in the global (domain) span of the array.
625 ! determine whether or not to filter the data
627 if(xlat(ids,j).gt.0.) then
628 lat = xlat(ids,j)-dvlat
630 lat = xlat(ids,j)+dvlat
633 IF (abs(lat) >= fft_filter_lat) THEN
637 sheet(i-ids+1,k-kts+1) = f(i,k,j)
641 call polar_filter_fft_2d_ncar(nx,ny,sheet,lat,fft_filter_lat,piggyback,fftflag)
645 f(i,k,j) = sheet(i-ids+1,k-kts+1)
647 ! setting up ims-ime with x periodicity:
648 ! enforce periodicity as in set_physical_bc3d
651 f(ids-i,k,j)=f(ide-i,k,j)
654 f(ide+i-1,k,j)=f(ids+i-1,k,j)
659 END DO ! outer j (latitude) loop
661 END SUBROUTINE polar_filter_3d
663 !------------------------------------------------------------------------------
665 SUBROUTINE polar_filter_fft_2d_ncar(nx,ny,fin,lat,filter_latitude,piggyback,fftflag)
667 INTEGER , INTENT(IN) :: nx, ny
668 REAL , DIMENSION(nx,ny), INTENT(INOUT) :: fin
669 REAL , INTENT(IN) :: lat, filter_latitude
670 LOGICAL, INTENT(IN) :: piggyback
672 REAL :: pi, rcosref, freq, c, cf
674 INTEGER :: k, fftflag
675 REAL, DIMENSION(NX,NY) :: work
676 REAL, DIMENSION(NX+15) :: wsave
677 REAL(KIND=8), DIMENSION(NX,NY) :: fin8, work8
678 REAL(KIND=8), DIMENSION(NX+15) :: wsave8
681 REAL, dimension(nx,ny) :: fp
683 INTEGER :: lensave, ier, nh, n1
684 INTEGER :: lot, jump, n, inc, lenr, lensav, lenwrk
686 REAL, PARAMETER :: alpha = 0.0
692 rcosref = 1./COS(filter_latitude*pi/180.)
694 ! we are following the naming convention of the fftpack5 routines
704 IF(piggyback) ntop = ny-1
707 ! initialize coefficients, place in wsave
708 ! (should place this in init and save wsave at program start)
710 if(fftflag.eq.0) then
711 call rfftmi(n,wsave,lensav,ier)
713 call dfft1i(n,wsave8,lensav,ier)
717 write(a_message,*) ' error in rfftmi ',ier
718 CALL wrf_message ( a_message )
721 ! do the forward transform
723 if(fftflag.eq.0) then
724 call rfftmf(lot, jump, n, inc, fin, lenr, wsave, lensav, work, lenwrk, ier)
728 call dfft1f(n, inc, fin8(1,k), lenr, wsave8, lensav, work8, lenwrk, ier)
733 write(a_message,*) ' error in rfftmf ',ier
734 CALL wrf_message ( a_message )
737 if(MOD(n,2) == 0) then
748 freq=REAL(i-1)/REAL(n)
749 c = (rcosref*COS(lat*pi/180.)/SIN(freq*pi))**2
751 ! c = MAX(0.,MIN(1.,c))
753 factor_k = (1.-alpha)+alpha*min(1.,float(ntop - j)/10.)
754 cf = c*factor_k*factor_k
755 cf = MAX(0.,MIN(1.,cf))
760 cf = MAX(0.,MIN(1.,c))
762 fp(2*(i-1)+1,ny) = cf
766 IF(MOD(n,2) == 0) THEN
767 c = (rcosref*COS(lat*pi/180.))**2
768 ! c = MAX(0.,MIN(1.,c))
770 factor_k = (1.-alpha)+alpha*min(1.,float(ntop - j)/10.)
771 cf = c*factor_k*factor_k
772 cf = MAX(0.,MIN(1.,cf))
776 cf = MAX(0.,MIN(1.,c))
781 if(fftflag.eq.0) then
784 fin(i,j) = fp(i,j)*fin(i,j)
790 fin8(i,j) = fp(i,j)*fin8(i,j)
795 ! do the backward transform
797 if(fftflag.eq.0) then
798 call rfftmb(lot, jump, n, inc, fin, lenr, wsave, lensav, work, lenwrk, ier)
801 call dfft1b(n, inc, fin8(1,k), lenr, wsave8, lensav, work8, lenwrk, ier)
807 write(a_message,*) ' error in rfftmb ',ier
808 CALL wrf_message ( a_message )
811 END SUBROUTINE polar_filter_fft_2d_ncar
813 !---------------------------------------------------------------------
815 SUBROUTINE filter_tracer ( tr3d_in , xlat , msftx , &
816 fft_filter_lat , mf_fft , &
817 pos_def , swap_pole_with_next_j , &
818 ids , ide , jds , jde , kds , kde , &
819 ims , ime , jms , jme , kms , kme , &
820 its , ite , jts , jte , kts , kte )
824 INTEGER , INTENT(IN) :: ids , ide , jds , jde , kds , kde , &
825 ims , ime , jms , jme , kms , kme , &
826 its , ite , jts , jte , kts , kte
828 REAL , INTENT(IN) :: fft_filter_lat , mf_fft
829 REAL , DIMENSION(ims:ime,kms:kme,jms:jme) , INTENT(INOUT) :: tr3d_in
830 REAL , DIMENSION(ims:ime,jms:jme) , INTENT(IN) :: xlat , msftx
831 LOGICAL , INTENT(IN) :: pos_def , swap_pole_with_next_j
836 INTEGER :: i , j , j_lat_pos , j_lat_neg , k
837 INTEGER :: i_kicker , ik , i1, i2, i3, i4
838 INTEGER :: i_left , i_right , ii , count
839 REAL :: length_scale , sum
840 REAL , DIMENSION(its:ite,jts:jte) :: tr_in, tr_out
841 CHARACTER (LEN=256) :: message
843 ! The filtering is a simple average on a latitude loop. Possibly a LONG list of
844 ! numbers. We assume that ALL of the 2d arrays have been transposed so that
845 ! each patch has the entire domain size of the i-dimension available.
847 IF ( ( its .NE. ids ) .OR. ( ite .NE. ide ) ) THEN
848 CALL wrf_error_fatal ( 'filtering assumes all values on X' )
851 ! Starting at the south pole, we find where the
852 ! grid distance is big enough, then go back a point. Continuing to the
853 ! north pole, we find the first small grid distance. These are the
854 ! computational latitude loops and the associated computational poles.
858 loop_neg : DO j = MIN(jde-1,jte) , jts , -1
859 IF ( xlat(its,j) .LT. 0.0 ) THEN
860 IF ( ABS(xlat(its,j)) .GE. fft_filter_lat ) THEN
867 loop_pos : DO j = jts , MIN(jde-1,jte)
868 IF ( xlat(its,j) .GT. 0.0 ) THEN
869 IF ( xlat(its,j) .GE. fft_filter_lat ) THEN
876 ! Initialize the starting values for the averages.
879 DO j = jts , MIN(jde-1,jte)
880 DO i = its , MIN(ide-1,ite)
881 tr_in(i,j) = tr3d_in(i,k,j)
882 tr_out(i,j) = tr_in(i,j)
886 ! Filter the fields at the negative lats.
888 DO j = MIN(j_lat_neg,jte) , jts , -1
889 ! i_kicker = MIN( MAX ( NINT(msftx(its,j)/2) , 1 ) , (ide - ids) / 2 )
890 i_kicker = MIN( MAX ( NINT(msftx(its,j)/mf_fft/2) , 1 ) , (ide - ids) / 2 )
891 ! WRITE (message,FMT='(a,i4,a,i4,f6.2,1x,f6.1,f6.1)') 'SOUTH j = ' , j, ', kicker = ',i_kicker,xlat(its,j),msftx(its,j),mf_fft
892 ! CALL wrf_debug ( 0 , TRIM(message) )
893 DO i = its , MIN(ide-1,ite)
896 DO ik = 1 , i_kicker/2
898 IF ( ii .GE. ids ) THEN
901 i_left = ( ii - ids ) + (ide-1)+1
904 IF ( ii .LE. ide-1 ) THEN
907 i_right = ( ii - (ide-1) ) + its-1
909 sum = sum + tr_in(i_left,j) + tr_in(i_right,j)
912 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * count + 1 )
916 ! Filter the fields at the positive lats.
918 DO j = MAX(j_lat_pos,jts) , MIN(jde-1,jte)
919 ! i_kicker = MIN( MAX ( NINT(msftx(its,j)/2) , 1 ) , (ide - ids) / 2 )
920 i_kicker = MIN( MAX ( NINT(msftx(its,j)/mf_fft/2) , 1 ) , (ide - ids) / 2 )
921 ! WRITE (message,FMT='(a,i4,a,i4,f6.2,1x,f6.1,f6.1)') 'NORTH j = ' , j, ', kicker = ',i_kicker,xlat(its,j),msftx(its,j),mf_fft
922 ! CALL wrf_debug ( 0 , TRIM(message) )
923 DO i = its , MIN(ide-1,ite)
926 DO ik = 1 , i_kicker/2
928 IF ( ii .GE. ids ) THEN
931 i_left = ( ii - ids ) + (ide-1)+1
934 IF ( ii .LE. ide-1 ) THEN
937 i_right = ( ii - (ide-1) ) + its-1
939 sum = sum + tr_in(i_left,j) + tr_in(i_right,j)
942 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * count + 1 )
946 ! Set output values for whole patch.
948 DO j = jts , MIN(jde-1,jte)
949 DO i = its , MIN(ide-1,ite)
950 tr3d_in(i,k,j) = tr_out(i,j)
954 ! Positive definite on scalars?
957 DO j = jts , MIN(jde-1,jte)
958 DO i = its , MIN(ide-1,ite)
959 tr3d_in(i,k,j) = MAX( tr3d_in(i,k,j) , 0. )
964 ! Remove values at j=1 and j=jde-1 locations, set them to the rows just next to them.
966 IF ( swap_pole_with_next_j ) THEN
967 IF ( jts .EQ. jds ) THEN
968 DO i = its , MIN(ide-1,ite)
969 tr3d_in(i,k,jts) = tr3d_in(i,k,jts+1)
973 IF ( jte .EQ. jde ) THEN
974 DO i = its , MIN(ide-1,ite)
975 tr3d_in(i,k,jte-1) = tr3d_in(i,k,jte-2)
982 END SUBROUTINE filter_tracer
984 !---------------------------------------------------------------------
986 SUBROUTINE filter_tracer_old ( tr3d_in , xlat , msftx , fft_filter_lat , &
987 ids , ide , jds , jde , kds , kde , &
988 ims , ime , jms , jme , kms , kme , &
989 its , ite , jts , jte , kts , kte )
993 INTEGER , INTENT(IN) :: ids , ide , jds , jde , kds , kde , &
994 ims , ime , jms , jme , kms , kme , &
995 its , ite , jts , jte , kts , kte
997 REAL , INTENT(IN) :: fft_filter_lat
998 REAL , DIMENSION(ims:ime,kms:kme,jms:jme) , INTENT(INOUT) :: tr3d_in
999 REAL , DIMENSION(ims:ime,jms:jme) , INTENT(IN) :: xlat , msftx
1004 INTEGER :: i , j , j_lat_pos , j_lat_neg , k
1005 INTEGER :: i_kicker , ik , i1, i2, i3, i4
1006 REAL :: length_scale , sum
1007 REAL , DIMENSION(its:ite,jts:jte) :: tr_in, tr_out
1009 ! The filtering is a simple average on a latitude loop. Possibly a LONG list of
1010 ! numbers. We assume that ALL of the 2d arrays have been transposed so that
1011 ! each patch has the entire domain size of the i-dim local.
1013 IF ( ( its .NE. ids ) .OR. ( ite .NE. ide ) ) THEN
1014 CALL wrf_error_fatal ( 'filtering assumes all values on X' )
1017 ! Starting at the south pole, we find where the
1018 ! grid distance is big enough, then go back a point. Continuing to the
1019 ! north pole, we find the first small grid distance. These are the
1020 ! computational latitude loops and the associated computational poles.
1024 loop_neg : DO j = jts , MIN(jde-1,jte)
1025 IF ( xlat(its,j) .LT. 0.0 ) THEN
1026 IF ( ABS(xlat(its,j)) .LT. fft_filter_lat ) THEN
1033 loop_pos : DO j = jts , MIN(jde-1,jte)
1034 IF ( xlat(its,j) .GT. 0.0 ) THEN
1035 IF ( xlat(its,j) .GE. fft_filter_lat ) THEN
1042 ! Set output values to initial input topo values for whole patch.
1045 DO j = jts , MIN(jde-1,jte)
1046 DO i = its , MIN(ide-1,ite)
1047 tr_in(i,j) = tr3d_in(i,k,j)
1048 tr_out(i,j) = tr_in(i,j)
1052 ! Filter the topo at the negative lats.
1054 DO j = j_lat_neg , jts , -1
1055 i_kicker = MIN( MAX ( NINT(msftx(its,j)) , 1 ) , (ide - ids) / 2 )
1056 ! print *,'j = ' , j, ', kicker = ',i_kicker
1057 DO i = its , MIN(ide-1,ite)
1058 IF ( ( i - i_kicker .GE. its ) .AND. ( i + i_kicker .LE. ide-1 ) ) THEN
1060 DO ik = 1 , i_kicker
1061 sum = sum + tr_in(i+ik,j) + tr_in(i-ik,j)
1063 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * i_kicker + 1 )
1064 ELSE IF ( ( i - i_kicker .LT. its ) .AND. ( i + i_kicker .LE. ide-1 ) ) THEN
1066 DO ik = 1 , i_kicker
1067 sum = sum + tr_in(i+ik,j)
1069 i1 = i - i_kicker + ide -1
1074 sum = sum + tr_in(ik,j)
1077 sum = sum + tr_in(ik,j)
1079 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * i_kicker + 1 )
1080 ELSE IF ( ( i - i_kicker .GE. its ) .AND. ( i + i_kicker .GT. ide-1 ) ) THEN
1082 DO ik = 1 , i_kicker
1083 sum = sum + tr_in(i-ik,j)
1088 i4 = ids + ( i_kicker+i ) - ide
1090 sum = sum + tr_in(ik,j)
1093 sum = sum + tr_in(ik,j)
1095 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * i_kicker + 1 )
1100 ! Filter the topo at the positive lats.
1102 DO j = j_lat_pos , MIN(jde-1,jte)
1103 i_kicker = MIN( MAX ( NINT(msftx(its,j)) , 1 ) , (ide - ids) / 2 )
1104 ! print *,'j = ' , j, ', kicker = ',i_kicker
1105 DO i = its , MIN(ide-1,ite)
1106 IF ( ( i - i_kicker .GE. its ) .AND. ( i + i_kicker .LE. ide-1 ) ) THEN
1108 DO ik = 1 , i_kicker
1109 sum = sum + tr_in(i+ik,j) + tr_in(i-ik,j)
1111 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * i_kicker + 1 )
1112 ELSE IF ( ( i - i_kicker .LT. its ) .AND. ( i + i_kicker .LE. ide-1 ) ) THEN
1114 DO ik = 1 , i_kicker
1115 sum = sum + tr_in(i+ik,j)
1117 i1 = i - i_kicker + ide -1
1122 sum = sum + tr_in(ik,j)
1125 sum = sum + tr_in(ik,j)
1127 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * i_kicker + 1 )
1128 ELSE IF ( ( i - i_kicker .GE. its ) .AND. ( i + i_kicker .GT. ide-1 ) ) THEN
1130 DO ik = 1 , i_kicker
1131 sum = sum + tr_in(i-ik,j)
1136 i4 = ids + ( i_kicker+i ) - ide
1138 sum = sum + tr_in(ik,j)
1141 sum = sum + tr_in(ik,j)
1143 tr_out(i,j) = ( tr_in(i,j) + sum ) / REAL ( 2 * i_kicker + 1 )
1148 ! Set output values to initial input topo values for whole patch.
1150 DO j = jts , MIN(jde-1,jte)
1151 DO i = its , MIN(ide-1,ite)
1152 tr3d_in(i,k,j) = tr_out(i,j)
1157 END SUBROUTINE filter_tracer_old
1159 !---------------------------------------------------------------------
1160 END MODULE module_polarfft