1 module process_domain_module
5 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10 subroutine process_domain(n, extra_row, extra_col)
14 use interp_option_module
15 use misc_definitions_module
22 integer, intent(in) :: n
23 logical, intent(in) :: extra_row, extra_col
26 integer :: i, t, dyn_opt, &
27 we_dom_s, we_dom_e, sn_dom_s, sn_dom_e, &
28 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
29 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
30 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
31 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
33 west_east_dim, south_north_dim, bottom_top_dim, map_proj, &
34 is_water, is_lake, is_ice, is_urban, i_soilwater, &
35 grid_id, parent_id, i_parent_start, j_parent_start, &
36 i_parent_end, j_parent_end, parent_grid_ratio, sub_x, sub_y, num_land_cat, process_bdy_width
37 real :: cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
38 dom_dx, dom_dy, pole_lat, pole_lon
39 real, dimension(16) :: corner_lats, corner_lons
40 real, pointer, dimension(:,:) :: landmask
41 real, pointer, dimension(:,:) :: xlat, xlon, xlat_u, xlon_u, xlat_v, xlon_v
42 logical, allocatable, dimension(:) :: got_this_field, got_const_field
43 character (len=19) :: valid_date, temp_date
44 character (len=128) :: title, mminlu
45 character (len=128), allocatable, dimension(:) :: output_flags, td_output_flags
46 character (len=128), dimension(:), pointer :: geogrid_flags
48 ! CWH Initialize local pointer variables
56 nullify(geogrid_flags)
58 ! Compute number of times that we will process
59 call geth_idts(end_date(n), start_date(n), idiff)
60 call mprintf((idiff < 0),ERROR,'Ending date is earlier than starting date in namelist for domain %i.', i1=n)
62 n_times = idiff / interval_seconds
64 ! Check that the interval evenly divides the range of times to process
65 call mprintf((mod(idiff, interval_seconds) /= 0),WARN, &
66 'In namelist, interval_seconds does not evenly divide '// &
67 '(end_date - start_date) for domain %i. Only %i time periods '// &
68 'will be processed.', i1=n, i2=n_times)
70 ! Initialize the storage module
71 call mprintf(.true.,LOGFILE,'Initializing storage module')
75 ! Do time-independent processing
77 call get_static_fields(n, dyn_opt, west_east_dim, south_north_dim, bottom_top_dim, map_proj, &
78 we_dom_s, we_dom_e, sn_dom_s, sn_dom_e, &
79 we_patch_s, we_patch_e, &
80 we_patch_stag_s, we_patch_stag_e, &
81 sn_patch_s, sn_patch_e, &
82 sn_patch_stag_s, sn_patch_stag_e, &
83 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
84 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
85 mminlu, num_land_cat, is_water, is_lake, is_ice, is_urban, i_soilwater, &
87 i_parent_start, j_parent_start, i_parent_end, j_parent_end, &
88 parent_grid_ratio, sub_x, sub_y, &
89 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
90 pole_lat, pole_lon, dom_dx, dom_dy, landmask, xlat, xlon, xlat_u, xlon_u, &
91 xlat_v, xlon_v, corner_lats, corner_lons, title, geogrid_flags)
94 allocate(output_flags(num_entries))
95 allocate(got_const_field(num_entries))
99 got_const_field(i) = .false.
102 ! This call is to process the constant met fields (SST or SEAICE, for example)
103 ! That we process constant fields is indicated by the first argument
104 call process_single_met_time(.true., temp_date, n, extra_row, extra_col, xlat, xlon, &
105 xlat_u, xlon_u, xlat_v, xlon_v, landmask, &
107 west_east_dim, south_north_dim, &
108 we_dom_s, we_dom_e, sn_dom_s, sn_dom_e, &
109 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
110 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
111 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
112 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
114 map_proj, mminlu, num_land_cat, is_water, is_lake, is_ice, is_urban, i_soilwater, &
115 grid_id, parent_id, i_parent_start, &
116 j_parent_start, i_parent_end, j_parent_end, dom_dx, dom_dy, &
117 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
118 pole_lat, pole_lon, parent_grid_ratio, sub_x, sub_y, &
119 corner_lats, corner_lons, output_flags, geogrid_flags, 0)
122 ! Begin time-dependent processing
125 allocate(td_output_flags(num_entries))
126 allocate(got_this_field (num_entries))
128 ! Loop over all times to be processed for this domain
131 call geth_newdate(valid_date, trim(start_date(n)), t*interval_seconds)
134 if (mod(interval_seconds,3600) == 0) then
135 write(temp_date,'(a13)') valid_date(1:10)//'_'//valid_date(12:13)
136 else if (mod(interval_seconds,60) == 0) then
137 write(temp_date,'(a16)') valid_date(1:10)//'_'//valid_date(12:16)
139 write(temp_date,'(a19)') valid_date(1:10)//'_'//valid_date(12:19)
142 call mprintf(.true.,STDOUT, ' Processing %s', s1=trim(temp_date))
143 call mprintf(.true.,LOGFILE, 'Preparing to process output time %s', s1=temp_date)
146 td_output_flags(i) = output_flags(i)
147 got_this_field(i) = got_const_field(i)
151 process_bdy_width = process_only_bdy
153 process_bdy_width = 0
156 call process_single_met_time(.false., temp_date, n, extra_row, extra_col, xlat, xlon, &
157 xlat_u, xlon_u, xlat_v, xlon_v, landmask, &
159 west_east_dim, south_north_dim, &
160 we_dom_s, we_dom_e, sn_dom_s, sn_dom_e, &
161 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
162 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
163 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
164 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
166 map_proj, mminlu, num_land_cat, is_water, is_lake, is_ice, is_urban, i_soilwater, &
167 grid_id, parent_id, i_parent_start, &
168 j_parent_start, i_parent_end, j_parent_end, dom_dx, dom_dy, &
169 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
170 pole_lat, pole_lon, parent_grid_ratio, sub_x, sub_y, &
171 corner_lats, corner_lons, td_output_flags, geogrid_flags, process_bdy_width)
173 end do ! Loop over n_times
176 deallocate(td_output_flags)
177 deallocate(got_this_field)
179 deallocate(output_flags)
180 deallocate(got_const_field)
182 if (associated(geogrid_flags)) deallocate(geogrid_flags)
184 call storage_delete_all()
186 end subroutine process_domain
189 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
190 ! Name: get_static_fields
193 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
194 subroutine get_static_fields(n, dyn_opt, west_east_dim, south_north_dim, bottom_top_dim, &
196 we_dom_s, we_dom_e, sn_dom_s, sn_dom_e, &
197 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
198 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
199 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
200 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
201 mminlu, num_land_cat, is_water, is_lake, is_ice, is_urban, i_soilwater, &
202 grid_id, parent_id, &
203 i_parent_start, j_parent_start, i_parent_end, j_parent_end, &
204 parent_grid_ratio, sub_x, sub_y, &
205 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
206 pole_lat, pole_lon, dom_dx, dom_dy, landmask, xlat, xlon, xlat_u, xlon_u, &
207 xlat_v, xlon_v, corner_lats, corner_lons, title, geogrid_flags)
220 integer, intent(in) :: n
221 integer, intent(inout) :: dyn_opt, west_east_dim, south_north_dim, bottom_top_dim, &
223 we_dom_s, we_dom_e, sn_dom_s, sn_dom_e, &
224 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
225 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
226 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
227 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
228 is_water, is_lake, is_ice, is_urban, i_soilwater, grid_id, parent_id, &
229 i_parent_start, j_parent_start, i_parent_end, j_parent_end, &
230 parent_grid_ratio, sub_x, sub_y, num_land_cat
231 real, pointer, dimension(:,:) :: landmask
232 real, intent(inout) :: cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
233 dom_dx, dom_dy, pole_lat, pole_lon
234 real, pointer, dimension(:,:) :: xlat, xlon, xlat_u, xlon_u, xlat_v, xlon_v
235 real, dimension(16), intent(out) :: corner_lats, corner_lons
236 character (len=128), intent(inout) :: title, mminlu
237 character (len=128), dimension(:), pointer :: geogrid_flags
240 integer :: istatus, i, j, k, sp1, ep1, sp2, ep2, sp3, ep3, &
241 lh_mult, rh_mult, bh_mult, th_mult, subx, suby
242 integer :: we_mem_subgrid_s, we_mem_subgrid_e, &
243 sn_mem_subgrid_s, sn_mem_subgrid_e
244 integer :: we_patch_subgrid_s, we_patch_subgrid_e, &
245 sn_patch_subgrid_s, sn_patch_subgrid_e
246 real, pointer, dimension(:,:,:) :: real_array
247 character (len=3) :: memorder
248 character (len=128) :: grid_type, datestr, cname, stagger, cunits, cdesc, ctemp
249 character (len=128), dimension(3) :: dimnames
250 type (fg_input) :: field
251 type (list) :: static_list, flag_list
252 type (list_item), dimension(:), pointer :: static_list_array
254 call list_init(static_list)
256 ! CWH Initialize local pointer variables
259 ! Initialize the input module to read static input data for this domain
260 call mprintf(.true.,LOGFILE,'Opening static input file.')
261 call input_init(n, istatus)
262 call mprintf((istatus /= 0),ERROR, 'input_init(): Error opening input for domain %i.', i1=n)
264 ! Read global attributes from the static data input file
265 call mprintf(.true.,LOGFILE,'Reading static global attributes.')
266 call read_global_attrs(title, datestr, grid_type, dyn_opt, west_east_dim, &
267 south_north_dim, bottom_top_dim, &
268 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
269 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
270 map_proj, mminlu, num_land_cat, &
271 is_water, is_lake, is_ice, is_urban, i_soilwater, &
272 grid_id, parent_id, i_parent_start, &
273 j_parent_start, i_parent_end, j_parent_end, dom_dx, dom_dy, &
274 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, &
275 truelat2, pole_lat, pole_lon, parent_grid_ratio, &
276 corner_lats, corner_lons, sub_x, sub_y)
280 if (grid_type(1:1) == 'C') then
281 we_dom_e = west_east_dim - 1
282 sn_dom_e = south_north_dim - 1
283 else if (grid_type(1:1) == 'E') then
284 we_dom_e = west_east_dim
285 sn_dom_e = south_north_dim
288 ! Given the full dimensions of this domain, find out the range of indices
289 ! that will be worked on by this processor. This information is given by
290 ! my_minx, my_miny, my_maxx, my_maxy
291 call parallel_get_tile_dims(west_east_dim, south_north_dim)
293 ! Must figure out patch dimensions from info in parallel module
294 if (nprocs > 1 .and. .not. do_tiled_input) then
297 we_patch_stag_s = my_minx
298 we_patch_e = my_maxx - 1
300 sn_patch_stag_s = my_miny
301 sn_patch_e = my_maxy - 1
303 if (gridtype == 'C') then
304 if (my_x /= nproc_x - 1) then
305 we_patch_e = we_patch_e + 1
306 we_patch_stag_e = we_patch_e
308 we_patch_stag_e = we_patch_e + 1
310 if (my_y /= nproc_y - 1) then
311 sn_patch_e = sn_patch_e + 1
312 sn_patch_stag_e = sn_patch_e
314 sn_patch_stag_e = sn_patch_e + 1
316 else if (gridtype == 'E') then
317 we_patch_e = we_patch_e + 1
318 sn_patch_e = sn_patch_e + 1
319 we_patch_stag_e = we_patch_e
320 sn_patch_stag_e = sn_patch_e
325 ! Compute multipliers for halo width; these must be 0/1
331 if (my_x /= (nproc_x-1)) then
341 if (my_y /= (nproc_y-1)) then
347 we_mem_s = we_patch_s - HALO_WIDTH*lh_mult
348 we_mem_e = we_patch_e + HALO_WIDTH*rh_mult
349 sn_mem_s = sn_patch_s - HALO_WIDTH*bh_mult
350 sn_mem_e = sn_patch_e + HALO_WIDTH*th_mult
351 we_mem_stag_s = we_patch_stag_s - HALO_WIDTH*lh_mult
352 we_mem_stag_e = we_patch_stag_e + HALO_WIDTH*rh_mult
353 sn_mem_stag_s = sn_patch_stag_s - HALO_WIDTH*bh_mult
354 sn_mem_stag_e = sn_patch_stag_e + HALO_WIDTH*th_mult
356 ! Initialize a proj_info type for the destination grid projection. This will
357 ! primarily be used for rotating Earth-relative winds to grid-relative winds
358 call set_domain_projection(map_proj, stand_lon, truelat1, truelat2, &
359 dom_dx, dom_dy, dom_dx, dom_dy, west_east_dim, &
360 south_north_dim, real(west_east_dim)/2., &
361 real(south_north_dim)/2.,cen_lat, cen_lon, &
364 ! Read static fields using the input module; we know that there are no more
365 ! fields to be read when read_next_field() returns a non-zero status.
367 do while (istatus == 0)
368 call read_next_field(sp1, ep1, sp2, ep2, sp3, ep3, cname, cunits, cdesc, &
369 memorder, stagger, dimnames, subx, suby, &
371 if (istatus == 0) then
373 call mprintf(.true.,LOGFILE, 'Read in static field %s.',s1=cname)
374 call list_insert(static_list, ckey=cname, cvalue=cname)
376 ! We will also keep copies in core of the lat/lon arrays, for use in
377 ! interpolation of the met fields to the model grid.
378 ! For now, we assume that the lat/lon arrays will have known field names
379 if (index(cname, 'XLAT_M') /= 0 .and. &
380 len_trim(cname) == len_trim('XLAT_M')) then
381 allocate(xlat(we_mem_s:we_mem_e,sn_mem_s:sn_mem_e))
382 xlat(we_patch_s:we_patch_e,sn_patch_s:sn_patch_e) = real_array(:,:,1)
383 call exchange_halo_r(xlat, &
384 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, 1, 1, &
385 we_patch_s, we_patch_e, sn_patch_s, sn_patch_e, 1, 1)
387 else if (index(cname, 'XLONG_M') /= 0 .and. &
388 len_trim(cname) == len_trim('XLONG_M')) then
389 allocate(xlon(we_mem_s:we_mem_e,sn_mem_s:sn_mem_e))
390 xlon(we_patch_s:we_patch_e,sn_patch_s:sn_patch_e) = real_array(:,:,1)
391 call exchange_halo_r(xlon, &
392 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, 1, 1, &
393 we_patch_s, we_patch_e, sn_patch_s, sn_patch_e, 1, 1)
395 else if (index(cname, 'XLAT_U') /= 0 .and. &
396 len_trim(cname) == len_trim('XLAT_U')) then
397 allocate(xlat_u(we_mem_stag_s:we_mem_stag_e,sn_mem_s:sn_mem_e))
398 xlat_u(we_patch_stag_s:we_patch_stag_e,sn_patch_s:sn_patch_e) = real_array(:,:,1)
399 call exchange_halo_r(xlat_u, &
400 we_mem_stag_s, we_mem_stag_e, sn_mem_s, sn_mem_e, 1, 1, &
401 we_patch_stag_s, we_patch_stag_e, sn_patch_s, sn_patch_e, 1, 1)
403 else if (index(cname, 'XLONG_U') /= 0 .and. &
404 len_trim(cname) == len_trim('XLONG_U')) then
405 allocate(xlon_u(we_mem_stag_s:we_mem_stag_e,sn_mem_s:sn_mem_e))
406 xlon_u(we_patch_stag_s:we_patch_stag_e,sn_patch_s:sn_patch_e) = real_array(:,:,1)
407 call exchange_halo_r(xlon_u, &
408 we_mem_stag_s, we_mem_stag_e, sn_mem_s, sn_mem_e, 1, 1, &
409 we_patch_stag_s, we_patch_stag_e, sn_patch_s, sn_patch_e, 1, 1)
411 else if (index(cname, 'XLAT_V') /= 0 .and. &
412 len_trim(cname) == len_trim('XLAT_V')) then
413 allocate(xlat_v(we_mem_s:we_mem_e,sn_mem_stag_s:sn_mem_stag_e))
414 xlat_v(we_patch_s:we_patch_e,sn_patch_stag_s:sn_patch_stag_e) = real_array(:,:,1)
415 call exchange_halo_r(xlat_v, &
416 we_mem_s, we_mem_e, sn_mem_stag_s, sn_mem_stag_e, 1, 1, &
417 we_patch_s, we_patch_e, sn_patch_stag_s, sn_patch_stag_e, 1, 1)
419 else if (index(cname, 'XLONG_V') /= 0 .and. &
420 len_trim(cname) == len_trim('XLONG_V')) then
421 allocate(xlon_v(we_mem_s:we_mem_e,sn_mem_stag_s:sn_mem_stag_e))
422 xlon_v(we_patch_s:we_patch_e,sn_patch_stag_s:sn_patch_stag_e) = real_array(:,:,1)
423 call exchange_halo_r(xlon_v, &
424 we_mem_s, we_mem_e, sn_mem_stag_s, sn_mem_stag_e, 1, 1, &
425 we_patch_s, we_patch_e, sn_patch_stag_s, sn_patch_stag_e, 1, 1)
427 else if (index(cname, 'LANDMASK') /= 0 .and. &
428 len_trim(cname) == len_trim('LANDMASK')) then
429 allocate(landmask(we_mem_s:we_mem_e,sn_mem_s:sn_mem_e))
430 landmask(we_patch_s:we_patch_e,sn_patch_s:sn_patch_e) = real_array(:,:,1)
431 call exchange_halo_r(landmask, &
432 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, 1, 1, &
433 we_patch_s, we_patch_e, sn_patch_s, sn_patch_e, 1, 1)
438 we_mem_subgrid_s = (we_mem_s + HALO_WIDTH*lh_mult - 1)*subx - HALO_WIDTH*lh_mult + 1
439 we_mem_subgrid_e = (we_mem_e + (1-rh_mult) - HALO_WIDTH*rh_mult )*subx + HALO_WIDTH*rh_mult
440 we_patch_subgrid_s = (we_patch_s - 1)*subx + 1
441 we_patch_subgrid_e = (we_patch_e + (1-rh_mult) )*subx
444 sn_mem_subgrid_s = (sn_mem_s + HALO_WIDTH*bh_mult - 1)*suby - HALO_WIDTH*bh_mult + 1
445 sn_mem_subgrid_e = (sn_mem_e + (1-th_mult) - HALO_WIDTH*th_mult )*suby + HALO_WIDTH*th_mult
446 sn_patch_subgrid_s = (sn_patch_s - 1)*suby + 1
447 sn_patch_subgrid_e = (sn_patch_e + (1-th_mult) )*suby
450 ! Having read in a field, we write each level individually to the
451 ! storage module; levels will be reassembled later on when they
454 field%header%sr_x=subx
455 field%header%sr_y=suby
456 field%header%version = 1
457 field%header%date = start_date(n)
458 field%header%time_dependent = .false.
459 field%header%mask_field = .false.
460 field%header%constant_field = .false.
461 field%header%forecast_hour = 0.0
462 field%header%fg_source = 'geogrid_model'
463 field%header%field = cname
464 field%header%units = cunits
465 field%header%description = cdesc
466 field%header%vertical_coord = dimnames(3)
467 field%header%vertical_level = k
468 field%header%array_order = memorder
469 field%header%is_wind_grid_rel = .true.
470 field%header%array_has_missing_values = .false.
471 if (gridtype == 'C') then
472 if (subx > 1 .or. suby > 1) then
473 field%map%stagger = M
474 field%header%dim1(1) = we_mem_subgrid_s
475 field%header%dim1(2) = we_mem_subgrid_e
476 field%header%dim2(1) = sn_mem_subgrid_s
477 field%header%dim2(2) = sn_mem_subgrid_e
478 else if (trim(stagger) == 'M') then
479 field%map%stagger = M
480 field%header%dim1(1) = we_mem_s
481 field%header%dim1(2) = we_mem_e
482 field%header%dim2(1) = sn_mem_s
483 field%header%dim2(2) = sn_mem_e
484 else if (trim(stagger) == 'U') then
485 field%map%stagger = U
486 field%header%dim1(1) = we_mem_stag_s
487 field%header%dim1(2) = we_mem_stag_e
488 field%header%dim2(1) = sn_mem_s
489 field%header%dim2(2) = sn_mem_e
490 else if (trim(stagger) == 'V') then
491 field%map%stagger = V
492 field%header%dim1(1) = we_mem_s
493 field%header%dim1(2) = we_mem_e
494 field%header%dim2(1) = sn_mem_stag_s
495 field%header%dim2(2) = sn_mem_stag_e
497 else if (gridtype == 'E') then
498 if (trim(stagger) == 'M') then
499 field%map%stagger = HH
500 else if (trim(stagger) == 'V') then
501 field%map%stagger = VV
503 field%header%dim1(1) = we_mem_s
504 field%header%dim1(2) = we_mem_e
505 field%header%dim2(1) = sn_mem_s
506 field%header%dim2(2) = sn_mem_e
509 allocate(field%valid_mask)
511 if (subx > 1 .or. suby > 1) then
512 allocate(field%r_arr(we_mem_subgrid_s:we_mem_subgrid_e,&
513 sn_mem_subgrid_s:sn_mem_subgrid_e))
514 field%r_arr(we_patch_subgrid_s:we_patch_subgrid_e,sn_patch_subgrid_s:sn_patch_subgrid_e) = &
515 real_array(sp1:ep1,sp2:ep2,k)
516 call exchange_halo_r(field%r_arr, &
517 we_mem_subgrid_s, we_mem_subgrid_e, sn_mem_subgrid_s, sn_mem_subgrid_e, 1, 1, &
518 we_patch_subgrid_s, we_patch_subgrid_e, sn_patch_subgrid_s, sn_patch_subgrid_e, 1, 1)
519 call bitarray_create(field%valid_mask, &
520 (we_mem_subgrid_e-we_mem_subgrid_s)+1, &
521 (sn_mem_subgrid_e-sn_mem_subgrid_s)+1)
522 do j=1,(sn_mem_subgrid_e-sn_mem_subgrid_s)+1
523 do i=1,(we_mem_subgrid_e-we_mem_subgrid_s)+1
524 call bitarray_set(field%valid_mask, i, j)
528 else if (field%map%stagger == M .or. &
529 field%map%stagger == HH .or. &
530 field%map%stagger == VV) then
531 allocate(field%r_arr(we_mem_s:we_mem_e,&
533 field%r_arr(we_patch_s:we_patch_e,sn_patch_s:sn_patch_e) = real_array(sp1:ep1,sp2:ep2,k)
534 call exchange_halo_r(field%r_arr, &
535 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, 1, 1, &
536 we_patch_s, we_patch_e, sn_patch_s, sn_patch_e, 1, 1)
537 call bitarray_create(field%valid_mask, &
538 (we_mem_e-we_mem_s)+1, &
539 (sn_mem_e-sn_mem_s)+1)
540 do j=1,(sn_mem_e-sn_mem_s)+1
541 do i=1,(we_mem_e-we_mem_s)+1
542 call bitarray_set(field%valid_mask, i, j)
545 else if (field%map%stagger == U) then
546 allocate(field%r_arr(we_mem_stag_s:we_mem_stag_e,&
548 field%r_arr(we_patch_stag_s:we_patch_stag_e,sn_patch_s:sn_patch_e) = real_array(sp1:ep1,sp2:ep2,k)
549 call exchange_halo_r(field%r_arr, &
550 we_mem_stag_s, we_mem_stag_e, sn_mem_s, sn_mem_e, 1, 1, &
551 we_patch_stag_s, we_patch_stag_e, sn_patch_s, sn_patch_e, 1, 1)
552 call bitarray_create(field%valid_mask, &
553 (we_mem_stag_e-we_mem_stag_s)+1, &
554 (sn_mem_e-sn_mem_s)+1)
555 do j=1,(sn_mem_e-sn_mem_s)+1
556 do i=1,(we_mem_stag_e-we_mem_stag_s)+1
557 call bitarray_set(field%valid_mask, i, j)
560 else if (field%map%stagger == V) then
561 allocate(field%r_arr(we_mem_s:we_mem_e,&
562 sn_mem_stag_s:sn_mem_stag_e))
563 field%r_arr(we_patch_s:we_patch_e,sn_patch_stag_s:sn_patch_stag_e) = real_array(sp1:ep1,sp2:ep2,k)
564 call exchange_halo_r(field%r_arr, &
565 we_mem_s, we_mem_e, sn_mem_stag_s, sn_mem_stag_e, 1, 1, &
566 we_patch_s, we_patch_e, sn_patch_stag_s, sn_patch_stag_e, 1, 1)
567 call bitarray_create(field%valid_mask, &
568 (we_mem_e-we_mem_s)+1, &
569 (sn_mem_stag_e-sn_mem_stag_s)+1)
570 do j=1,(sn_mem_stag_e-sn_mem_stag_s)+1
571 do i=1,(we_mem_e-we_mem_s)+1
572 call bitarray_set(field%valid_mask, i, j)
577 nullify(field%modified_mask)
579 call storage_put_field(field)
586 static_list_array => list_get_keys(static_list)
587 call list_init(flag_list)
588 do i=1,size(static_list_array)
590 ctemp = 'FLAG_'//trim(static_list_array(i)%ckey)
591 call ext_get_dom_ti_integer_scalar(ctemp, istatus, suppress_errors=.true.)
592 if (istatus == 1) call list_insert(flag_list, ckey=ctemp, cvalue=ctemp)
594 deallocate(static_list_array)
595 call list_destroy(static_list)
597 ! Done reading all static fields for this domain
600 static_list_array => list_get_keys(flag_list)
601 allocate(geogrid_flags(size(static_list_array)))
602 do i=1,size(static_list_array)
603 geogrid_flags(i) = static_list_array(i)%ckey
605 deallocate(static_list_array)
607 call list_destroy(flag_list)
609 end subroutine get_static_fields
612 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
613 ! Name: process_single_met_time
616 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
617 subroutine process_single_met_time(do_const_processing, &
618 temp_date, n, extra_row, extra_col, xlat, xlon, &
619 xlat_u, xlon_u, xlat_v, xlon_v, landmask, &
621 west_east_dim, south_north_dim, &
622 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
623 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
624 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
625 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
626 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
628 map_proj, mminlu, num_land_cat, is_water, is_lake, is_ice, is_urban, i_soilwater, &
629 grid_id, parent_id, i_parent_start, &
630 j_parent_start, i_parent_end, j_parent_end, dom_dx, dom_dy, &
631 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
632 pole_lat, pole_lon, parent_grid_ratio, sub_x, sub_y, &
633 corner_lats, corner_lons, output_flags, geogrid_flags, process_bdy_width)
638 use interp_option_module
640 use misc_definitions_module
645 use rotate_winds_module
651 logical, intent(in) :: do_const_processing
652 integer, intent(in) :: n, dyn_opt, west_east_dim, south_north_dim, map_proj, &
653 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
654 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
655 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
656 we_mem_s, we_mem_e, we_mem_stag_s, we_mem_stag_e, &
657 sn_mem_s, sn_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
658 is_water, is_lake, is_ice, is_urban, i_soilwater, &
659 grid_id, parent_id, i_parent_start, j_parent_start, &
660 i_parent_end, j_parent_end, parent_grid_ratio, sub_x, sub_y, num_land_cat, &
662 ! BUG: Should we be passing these around as pointers, or just declare them as arrays?
663 real, pointer, dimension(:,:) :: landmask
664 real, intent(in) :: dom_dx, dom_dy, cen_lat, moad_cen_lat, cen_lon, stand_lon, &
665 truelat1, truelat2, pole_lat, pole_lon
666 real, dimension(16), intent(in) :: corner_lats, corner_lons
667 real, pointer, dimension(:,:) :: xlat, xlon, xlat_u, xlon_u, xlat_v, xlon_v
668 logical, intent(in) :: extra_row, extra_col
669 logical, dimension(:), intent(inout) :: got_this_field
670 character (len=19), intent(in) :: temp_date
671 character (len=128), intent(in) :: mminlu
672 character (len=128), dimension(:), intent(inout) :: output_flags
673 character (len=128), dimension(:), pointer :: geogrid_flags
675 ! BUG: Move this constant to misc_definitions_module?
676 integer, parameter :: BDR_WIDTH = 3
679 integer :: istatus, iqstatus, fg_idx, idx, idxt, i, j, bottom_top_dim, &
680 sm1, em1, sm2, em2, sm3, em3, &
681 sp1, ep1, sp2, ep2, sp3, ep3, &
682 sd1, ed1, sd2, ed2, sd3, ed3, &
684 integer :: nmet_flags
685 integer :: num_metgrid_soil_levs
686 integer, pointer, dimension(:) :: soil_levels
689 logical :: do_gcell_interp
690 integer, pointer, dimension(:) :: u_levels, v_levels
691 real, pointer, dimension(:,:) :: halo_slab
692 real, pointer, dimension(:,:,:) :: real_array
693 character (len=19) :: output_date
694 character (len=128) :: cname, title
695 character (len=MAX_FILENAME_LEN) :: input_name
696 character (len=128), allocatable, dimension(:) :: met_flags
697 type (fg_input) :: field, u_field, v_field
698 type (met_data) :: fg_data
700 ! CWH Initialize local pointer variables
708 ! For this time, we need to process all first-guess filename roots. When we
709 ! hit a root containing a '*', we assume we have hit the end of the list
711 if (do_const_processing) then
712 input_name = constants_name(fg_idx)
714 input_name = fg_name(fg_idx)
716 do while (input_name /= '*')
718 call mprintf(.true.,STDOUT, ' %s', s1=input_name)
719 call mprintf(.true.,LOGFILE, 'Getting input fields from %s', s1=input_name)
721 ! Do a first pass through this fg source to get all mask fields used
722 ! during interpolation
723 call get_interp_masks(trim(input_name), do_const_processing, temp_date)
727 ! Initialize the module for reading in the met fields
728 call read_met_init(trim(input_name), do_const_processing, temp_date, istatus)
730 if (istatus == 0) then
732 ! Process all fields and levels from the current file; read_next_met_field()
733 ! will return a non-zero status when there are no more fields to be read.
734 do while (istatus == 0)
736 call read_next_met_field(fg_data, istatus)
738 if (istatus == 0) then
740 ! Find index into fieldname, interp_method, masked, and fill_missing
741 ! of the current field
742 idxt = num_entries + 1
744 if ((index(fieldname(idx), trim(fg_data%field)) /= 0) .and. &
745 (len_trim(fieldname(idx)) == len_trim(fg_data%field))) then
747 got_this_field(idx) = .true.
749 if (index(input_name,trim(from_input(idx))) /= 0 .or. &
750 (from_input(idx) == '*' .and. idxt == num_entries + 1)) then
757 if (idx > num_entries) idx = num_entries ! The last entry is a default
759 ! Do we need to rename this field?
760 if (output_name(idx) /= ' ') then
761 fg_data%field = output_name(idx)(1:9)
763 idxt = num_entries + 1
765 if ((index(fieldname(idx), trim(fg_data%field)) /= 0) .and. &
766 (len_trim(fieldname(idx)) == len_trim(fg_data%field))) then
768 got_this_field(idx) = .true.
770 if (index(input_name,trim(from_input(idx))) /= 0 .or. &
771 (from_input(idx) == '*' .and. idxt == num_entries + 1)) then
778 if (idx > num_entries) idx = num_entries ! The last entry is a default
781 ! Do a simple check to see whether this is a global dataset
782 ! Note that we do not currently support regional Gaussian grids
783 if ((fg_data%iproj == PROJ_LATLON .and. abs(fg_data%nx * fg_data%deltalon - 360.) < 0.0001) &
784 .or. (fg_data%iproj == PROJ_GAUSS)) then
786 allocate(halo_slab(1-BDR_WIDTH:fg_data%nx+BDR_WIDTH,1:fg_data%ny))
788 halo_slab(1:fg_data%nx, 1:fg_data%ny) = &
789 fg_data%slab(1:fg_data%nx, 1:fg_data%ny)
791 halo_slab(1-BDR_WIDTH:0, 1:fg_data%ny) = &
792 fg_data%slab(fg_data%nx-BDR_WIDTH+1:fg_data%nx, 1:fg_data%ny)
794 halo_slab(fg_data%nx+1:fg_data%nx+BDR_WIDTH, 1:fg_data%ny) = &
795 fg_data%slab(1:BDR_WIDTH, 1:fg_data%ny)
797 deallocate(fg_data%slab)
800 halo_slab => fg_data%slab
801 nullify(fg_data%slab)
804 call mprintf(.true.,LOGFILE,'Processing %s at level %f.',s1=fg_data%field,f1=fg_data%xlvl)
806 call push_source_projection(fg_data%iproj, fg_data%xlonc, fg_data%truelat1, &
807 fg_data%truelat2, fg_data%dx, fg_data%dy, fg_data%deltalat, &
808 fg_data%deltalon, fg_data%starti, fg_data%startj, &
809 fg_data%startlat, fg_data%startlon, earth_radius=fg_data%earth_radius*1000.)
811 ! Initialize fg_input structure to store the field
812 field%header%version = 1
813 field%header%date = fg_data%hdate//' '
814 if (do_const_processing) then
815 field%header%time_dependent = .false.
816 field%header%constant_field = .true.
818 field%header%time_dependent = .true.
819 field%header%constant_field = .false.
821 field%header%forecast_hour = fg_data%xfcst
822 field%header%fg_source = 'FG'
823 field%header%field = ' '
824 field%header%field(1:9) = fg_data%field
825 field%header%units = ' '
826 field%header%units(1:25) = fg_data%units
827 field%header%description = ' '
828 field%header%description(1:46) = fg_data%desc
829 call get_z_dim_name(fg_data%field,field%header%vertical_coord)
830 field%header%vertical_level = nint(fg_data%xlvl)
831 field%header%sr_x = 1
832 field%header%sr_y = 1
833 field%header%array_order = 'XY '
834 field%header%is_wind_grid_rel = fg_data%is_wind_grid_rel
835 field%header%array_has_missing_values = .false.
837 nullify(field%valid_mask)
838 nullify(field%modified_mask)
840 if (output_this_field(idx) .and. flag_in_output(idx) /= ' ') then
841 output_flags(idx) = flag_in_output(idx)
844 ! If we should not output this field, just list it as a mask field
845 if (output_this_field(idx)) then
846 field%header%mask_field = .false.
848 field%header%mask_field = .true.
852 ! Before actually doing any interpolation to the model grid, we must check
853 ! whether we will be using the average_gcell interpolator that averages all
854 ! source points in each model grid cell
856 do_gcell_interp = .false.
857 if (index(interp_method(idx),'average_gcell') /= 0) then
859 call get_gcell_threshold(interp_method(idx), threshold, istatus)
860 if (istatus == 0) then
861 if (fg_data%dx == 0. .and. fg_data%dy == 0. .and. &
862 fg_data%deltalat /= 0. .and. fg_data%deltalon /= 0.) then
863 fg_data%dx = abs(fg_data%deltalon)
864 fg_data%dy = abs(fg_data%deltalat)
866 ! BUG: Need to more correctly handle dx/dy in meters.
867 fg_data%dx = fg_data%dx / 111000. ! Convert meters to approximate degrees
868 fg_data%dy = fg_data%dy / 111000.
870 if (gridtype == 'C') then
871 if (threshold*max(fg_data%dx,fg_data%dy)*111. <= max(dom_dx,dom_dy)/1000.) &
872 do_gcell_interp = .true.
873 else if (gridtype == 'E') then
874 if (threshold*max(fg_data%dx,fg_data%dy) <= max(dom_dx,dom_dy)) &
875 do_gcell_interp = .true.
880 ! Interpolate to U staggering
881 if (output_stagger(idx) == U) then
883 call storage_query_field(field, iqstatus)
884 if (iqstatus == 0) then
885 call storage_get_field(field, iqstatus)
886 call mprintf((iqstatus /= 0),ERROR,'Queried field %s at level %i and found it,'// &
887 ' but could not get data.',s1=fg_data%field,i1=nint(fg_data%xlvl))
888 if (associated(field%modified_mask)) then
889 call bitarray_destroy(field%modified_mask)
890 nullify(field%modified_mask)
893 allocate(field%valid_mask)
894 call bitarray_create(field%valid_mask, we_mem_stag_e-we_mem_stag_s+1, sn_mem_e-sn_mem_s+1)
897 ! Save a copy of the fg_input structure for the U field so that we can find it later
898 if (is_u_field(idx)) call dup(field, u_field)
900 allocate(field%modified_mask)
901 call bitarray_create(field%modified_mask, we_mem_stag_e-we_mem_stag_s+1, sn_mem_e-sn_mem_s+1)
903 if (do_const_processing .or. field%header%time_dependent) then
904 call interp_met_field(input_name, fg_data%field, U, M, &
905 field, xlat_u, xlon_u, we_mem_stag_s, we_mem_stag_e, sn_mem_s, sn_mem_e, &
906 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
907 halo_slab, 1-bdr_wdth, fg_data%nx+bdr_wdth, 1, fg_data%ny, bdr_wdth, do_gcell_interp, &
908 field%modified_mask, process_bdy_width)
910 call mprintf(.true.,INFORM,' - already processed this field from constant file.')
913 ! Interpolate to V staggering
914 else if (output_stagger(idx) == V) then
916 call storage_query_field(field, iqstatus)
917 if (iqstatus == 0) then
918 call storage_get_field(field, iqstatus)
919 call mprintf((iqstatus /= 0),ERROR,'Queried field %s at level %i and found it,'// &
920 ' but could not get data.',s1=fg_data%field,i1=nint(fg_data%xlvl))
921 if (associated(field%modified_mask)) then
922 call bitarray_destroy(field%modified_mask)
923 nullify(field%modified_mask)
926 allocate(field%valid_mask)
927 call bitarray_create(field%valid_mask, we_mem_e-we_mem_s+1, sn_mem_stag_e-sn_mem_stag_s+1)
930 ! Save a copy of the fg_input structure for the V field so that we can find it later
931 if (is_v_field(idx)) call dup(field, v_field)
933 allocate(field%modified_mask)
934 call bitarray_create(field%modified_mask, we_mem_e-we_mem_s+1, sn_mem_stag_e-sn_mem_stag_s+1)
936 if (do_const_processing .or. field%header%time_dependent) then
937 call interp_met_field(input_name, fg_data%field, V, M, &
938 field, xlat_v, xlon_v, we_mem_s, we_mem_e, sn_mem_stag_s, sn_mem_stag_e, &
939 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
940 halo_slab, 1-bdr_wdth, fg_data%nx+bdr_wdth, 1, fg_data%ny, bdr_wdth, do_gcell_interp, &
941 field%modified_mask, process_bdy_width)
943 call mprintf(.true.,INFORM,' - already processed this field from constant file.')
946 ! Interpolate to VV staggering
947 else if (output_stagger(idx) == VV) then
949 call storage_query_field(field, iqstatus)
950 if (iqstatus == 0) then
951 call storage_get_field(field, iqstatus)
952 call mprintf((iqstatus /= 0),ERROR,'Queried field %s at level %i and found it,'// &
953 ' but could not get data.',s1=fg_data%field,i1=nint(fg_data%xlvl))
954 if (associated(field%modified_mask)) then
955 call bitarray_destroy(field%modified_mask)
956 nullify(field%modified_mask)
959 allocate(field%valid_mask)
960 call bitarray_create(field%valid_mask, we_mem_e-we_mem_s+1, sn_mem_e-sn_mem_s+1)
963 ! Save a copy of the fg_input structure for the U field so that we can find it later
964 if (is_u_field(idx)) call dup(field, u_field)
966 ! Save a copy of the fg_input structure for the V field so that we can find it later
967 if (is_v_field(idx)) call dup(field, v_field)
969 allocate(field%modified_mask)
970 call bitarray_create(field%modified_mask, we_mem_e-we_mem_s+1, sn_mem_e-sn_mem_s+1)
972 if (do_const_processing .or. field%header%time_dependent) then
973 call interp_met_field(input_name, fg_data%field, VV, M, &
974 field, xlat_v, xlon_v, we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
975 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
976 halo_slab, 1-bdr_wdth, fg_data%nx+bdr_wdth, 1, fg_data%ny, bdr_wdth, do_gcell_interp, &
977 field%modified_mask, process_bdy_width)
979 call mprintf(.true.,INFORM,' - already processed this field from constant file.')
982 ! All other fields interpolated to M staggering for C grid, H staggering for E grid
985 call storage_query_field(field, iqstatus)
986 if (iqstatus == 0) then
987 call storage_get_field(field, iqstatus)
988 call mprintf((iqstatus /= 0),ERROR,'Queried field %s at level %i and found it,'// &
989 ' but could not get data.',s1=fg_data%field,i1=nint(fg_data%xlvl))
990 if (associated(field%modified_mask)) then
991 call bitarray_destroy(field%modified_mask)
992 nullify(field%modified_mask)
995 allocate(field%valid_mask)
996 call bitarray_create(field%valid_mask, we_mem_e-we_mem_s+1, sn_mem_e-sn_mem_s+1)
999 allocate(field%modified_mask)
1000 call bitarray_create(field%modified_mask, we_mem_e-we_mem_s+1, sn_mem_e-sn_mem_s+1)
1002 if (do_const_processing .or. field%header%time_dependent) then
1003 if (gridtype == 'C') then
1004 call interp_met_field(input_name, fg_data%field, M, M, &
1005 field, xlat, xlon, we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
1006 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
1007 halo_slab, 1-bdr_wdth, fg_data%nx+bdr_wdth, 1, fg_data%ny, bdr_wdth, do_gcell_interp, &
1008 field%modified_mask, process_bdy_width, landmask)
1010 else if (gridtype == 'E') then
1011 call interp_met_field(input_name, fg_data%field, HH, M, &
1012 field, xlat, xlon, we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
1013 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
1014 halo_slab, 1-bdr_wdth, fg_data%nx+bdr_wdth, 1, fg_data%ny, bdr_wdth, do_gcell_interp, &
1015 field%modified_mask, process_bdy_width, landmask)
1018 call mprintf(.true.,INFORM,' - already processed this field from constant file.')
1023 call bitarray_merge(field%valid_mask, field%modified_mask)
1025 deallocate(halo_slab)
1027 ! Store the interpolated field
1028 call storage_put_field(field)
1030 call pop_source_projection()
1035 call read_met_close()
1037 call push_source_projection(fg_data%iproj, fg_data%xlonc, fg_data%truelat1, &
1038 fg_data%truelat2, fg_data%dx, fg_data%dy, fg_data%deltalat, &
1039 fg_data%deltalon, fg_data%starti, fg_data%startj, &
1040 fg_data%startlat, fg_data%startlon, earth_radius=fg_data%earth_radius*1000.)
1043 ! If necessary, rotate winds to earth-relative for this fg source
1046 call storage_get_levels(u_field, u_levels)
1047 call storage_get_levels(v_field, v_levels)
1049 if (associated(u_levels) .and. associated(v_levels)) then
1051 do u_idx = 1, size(u_levels)
1052 u_field%header%vertical_level = u_levels(u_idx)
1053 call storage_get_field(u_field, istatus)
1054 v_field%header%vertical_level = v_levels(u_idx)
1055 call storage_get_field(v_field, istatus)
1057 if (associated(u_field%modified_mask) .and. &
1058 associated(v_field%modified_mask)) then
1060 if (u_field%header%is_wind_grid_rel) then
1061 if (gridtype == 'C') then
1062 call map_to_met(u_field%r_arr, u_field%modified_mask, &
1063 v_field%r_arr, v_field%modified_mask, &
1064 we_mem_stag_s, sn_mem_s, &
1065 we_mem_stag_e, sn_mem_e, &
1066 we_mem_s, sn_mem_stag_s, &
1067 we_mem_e, sn_mem_stag_e, &
1068 xlon_u, xlon_v, xlat_u, xlat_v)
1069 else if (gridtype == 'E') then
1070 call map_to_met_nmm(u_field%r_arr, u_field%modified_mask, &
1071 v_field%r_arr, v_field%modified_mask, &
1072 we_mem_s, sn_mem_s, &
1073 we_mem_e, sn_mem_e, &
1078 call bitarray_destroy(u_field%modified_mask)
1079 call bitarray_destroy(v_field%modified_mask)
1080 nullify(u_field%modified_mask)
1081 nullify(v_field%modified_mask)
1082 call storage_put_field(u_field)
1083 call storage_put_field(v_field)
1088 deallocate(u_levels)
1089 deallocate(v_levels)
1093 call pop_source_projection()
1096 if (do_const_processing) then
1097 call mprintf(.true.,WARN,'Couldn''t open file %s for input.',s1=input_name)
1099 call mprintf(.true.,WARN,'Couldn''t open file %s for input.',s1=trim(input_name)//':'//trim(temp_date))
1104 if (do_const_processing) then
1105 input_name = constants_name(fg_idx)
1107 input_name = fg_name(fg_idx)
1109 end do ! while (input_name /= '*')
1112 ! Rotate winds from earth-relative to grid-relative
1115 call storage_get_levels(u_field, u_levels)
1116 call storage_get_levels(v_field, v_levels)
1118 if (associated(u_levels) .and. associated(v_levels)) then
1120 do u_idx = 1, size(u_levels)
1121 u_field%header%vertical_level = u_levels(u_idx)
1122 call storage_get_field(u_field, istatus)
1123 v_field%header%vertical_level = v_levels(u_idx)
1124 call storage_get_field(v_field, istatus)
1126 if (gridtype == 'C') then
1127 call met_to_map(u_field%r_arr, u_field%valid_mask, &
1128 v_field%r_arr, v_field%valid_mask, &
1129 we_mem_stag_s, sn_mem_s, &
1130 we_mem_stag_e, sn_mem_e, &
1131 we_mem_s, sn_mem_stag_s, &
1132 we_mem_e, sn_mem_stag_e, &
1133 xlon_u, xlon_v, xlat_u, xlat_v)
1134 else if (gridtype == 'E') then
1135 call met_to_map_nmm(u_field%r_arr, u_field%valid_mask, &
1136 v_field%r_arr, v_field%valid_mask, &
1137 we_mem_s, sn_mem_s, &
1138 we_mem_e, sn_mem_e, &
1144 deallocate(u_levels)
1145 deallocate(v_levels)
1149 if (do_const_processing) return
1152 ! Now that we have all degribbed fields, we build a 3-d pressure field, and fill in any
1153 ! missing levels in the other 3-d fields
1155 call mprintf(.true.,LOGFILE,'Filling missing levels.')
1156 call fill_missing_levels(output_flags)
1158 call mprintf(.true.,LOGFILE,'Creating derived fields.')
1159 call create_derived_fields(gridtype, fg_data%hdate, fg_data%xfcst, &
1160 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
1161 we_mem_stag_s, we_mem_stag_e, sn_mem_stag_s, sn_mem_stag_e, &
1162 got_this_field, output_flags)
1165 ! Check that every mandatory field was found in input data
1168 if (is_mandatory(i) .and. .not. got_this_field(i)) then
1169 call mprintf(.true.,ERROR,'The mandatory field %s was not found in any input data.',s1=fieldname(i))
1174 ! Before we begin to write fields, if debug_level is set high enough, we
1175 ! write a table of which fields are available at which levels to the
1176 ! metgrid.log file, and then we check to see if any fields are not
1177 ! completely covered with data.
1179 call storage_print_fields()
1180 call find_missing_values()
1183 ! All of the processing is now done for this time period for this domain;
1184 ! now we simply output every field from the storage module.
1187 title = 'OUTPUT FROM METGRID V3.6.1'
1189 ! Initialize the output module for this domain and time
1190 call mprintf(.true.,LOGFILE,'Initializing output module.')
1191 output_date = temp_date
1192 if ( .not. nocolons ) then
1193 if (len_trim(temp_date) == 13) then
1194 output_date(14:19) = ':00:00'
1195 else if (len_trim(temp_date) == 16) then
1196 output_date(17:19) = ':00'
1199 if (len_trim(temp_date) == 13) then
1200 output_date(14:19) = '_00_00'
1201 else if (len_trim(temp_date) == 16) then
1202 output_date(17:19) = '_00'
1206 call output_init(n, title, output_date, gridtype, dyn_opt, &
1207 corner_lats, corner_lons, &
1208 we_domain_s, we_domain_e, sn_domain_s, sn_domain_e, &
1209 we_patch_s, we_patch_e, sn_patch_s, sn_patch_e, &
1210 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
1211 extra_col, extra_row)
1213 call get_bottom_top_dim(bottom_top_dim)
1215 ! Add in a flag to tell real that we have seven new msf fields
1216 nmet_flags = num_entries + 1
1217 if (associated(geogrid_flags)) nmet_flags = nmet_flags + size(geogrid_flags)
1218 allocate(met_flags(nmet_flags))
1220 met_flags(i) = output_flags(i)
1222 if (gridtype == 'C') then
1223 met_flags(num_entries+1) = 'FLAG_MF_XY'
1225 met_flags(num_entries+1) = ' '
1227 if (associated(geogrid_flags)) then
1228 do i=1,size(geogrid_flags)
1229 met_flags(num_entries+1+i) = geogrid_flags(i)
1233 ! Find out how many soil levels or layers we have; this assumes a field named ST
1234 field % header % field = 'ST'
1235 nullify(soil_levels)
1236 call storage_get_levels(field, soil_levels)
1238 if (.not. associated(soil_levels)) then
1239 field % header % field = 'SOILT'
1240 nullify(soil_levels)
1241 call storage_get_levels(field, soil_levels)
1244 if (.not. associated(soil_levels)) then
1245 field % header % field = 'STC_WPS'
1246 nullify(soil_levels)
1247 call storage_get_levels(field, soil_levels)
1250 if (associated(soil_levels)) then
1251 num_metgrid_soil_levs = size(soil_levels)
1252 deallocate(soil_levels)
1254 num_metgrid_soil_levs = 0
1257 ! First write out global attributes
1258 call mprintf(.true.,LOGFILE,'Writing global attributes to output.')
1259 call write_global_attrs(title, output_date, gridtype, dyn_opt, west_east_dim, &
1260 south_north_dim, bottom_top_dim, &
1261 we_patch_s, we_patch_e, we_patch_stag_s, we_patch_stag_e, &
1262 sn_patch_s, sn_patch_e, sn_patch_stag_s, sn_patch_stag_e, &
1263 map_proj, mminlu, num_land_cat, &
1264 is_water, is_lake, is_ice, is_urban, i_soilwater, &
1265 grid_id, parent_id, i_parent_start, &
1266 j_parent_start, i_parent_end, j_parent_end, dom_dx, dom_dy, &
1267 cen_lat, moad_cen_lat, cen_lon, stand_lon, truelat1, truelat2, &
1268 pole_lat, pole_lon, parent_grid_ratio, sub_x, sub_y, &
1269 corner_lats, corner_lons, num_metgrid_soil_levs, &
1270 met_flags, nmet_flags, process_bdy_width)
1272 deallocate(met_flags)
1274 call reset_next_field()
1278 ! Now loop over all output fields, writing each to the output module
1279 do while (istatus == 0)
1280 call get_next_output_field(cname, real_array, &
1281 sm1, em1, sm2, em2, sm3, em3, istatus)
1282 if (istatus == 0) then
1284 call mprintf(.true.,LOGFILE,'Writing field %s to output.',s1=cname)
1285 call write_field(sm1, em1, sm2, em2, sm3, em3, &
1286 cname, output_date, real_array)
1287 deallocate(real_array)
1293 call mprintf(.true.,LOGFILE,'Closing output file.')
1296 ! Free up memory used by met fields for this valid time
1297 call storage_delete_all_td()
1299 end subroutine process_single_met_time
1302 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1303 ! Name: get_interp_masks
1306 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1307 subroutine get_interp_masks(fg_prefix, is_constants, fg_date)
1309 use interp_option_module
1316 logical, intent(in) :: is_constants
1317 character (len=*), intent(in) :: fg_prefix, fg_date
1319 ! BUG: Move this constant to misc_definitions_module?
1320 integer, parameter :: BDR_WIDTH = 3
1323 integer :: i, istatus, idx, idxt
1324 type (fg_input) :: mask_field
1325 type (met_data) :: fg_data
1329 call read_met_init(fg_prefix, is_constants, fg_date, istatus)
1331 do while (istatus == 0)
1333 call read_next_met_field(fg_data, istatus)
1335 if (istatus == 0) then
1337 ! Find out which METGRID.TBL entry goes with this field
1338 idxt = num_entries + 1
1339 do idx=1,num_entries
1340 if ((index(fieldname(idx), trim(fg_data%field)) /= 0) .and. &
1341 (len_trim(fieldname(idx)) == len_trim(fg_data%field))) then
1343 if (index(fg_prefix,trim(from_input(idx))) /= 0 .or. &
1344 (from_input(idx) == '*' .and. idxt == num_entries + 1)) then
1351 if (idx > num_entries) idx = num_entries ! The last entry is a default
1353 ! Do we need to rename this field?
1354 if (output_name(idx) /= ' ') then
1355 fg_data%field = output_name(idx)(1:9)
1357 idxt = num_entries + 1
1358 do idx=1,num_entries
1359 if ((index(fieldname(idx), trim(fg_data%field)) /= 0) .and. &
1360 (len_trim(fieldname(idx)) == len_trim(fg_data%field))) then
1362 if (index(fg_prefix,trim(from_input(idx))) /= 0 .or. &
1363 (from_input(idx) == '*' .and. idxt == num_entries + 1)) then
1370 if (idx > num_entries) idx = num_entries ! The last entry is a default
1374 if (interp_mask(i) /= ' ' .and. (trim(interp_mask(i)) == trim(fg_data%field))) then
1376 mask_field%header%version = 1
1377 mask_field%header%date = ' '
1378 mask_field%header%date = fg_date
1379 if (is_constants) then
1380 mask_field%header%time_dependent = .false.
1381 mask_field%header%constant_field = .true.
1383 mask_field%header%time_dependent = .true.
1384 mask_field%header%constant_field = .false.
1386 mask_field%header%mask_field = .true.
1387 mask_field%header%forecast_hour = 0.
1388 mask_field%header%fg_source = 'degribbed met data'
1389 mask_field%header%field = trim(fg_data%field)//'.mask'
1390 mask_field%header%units = '-'
1391 mask_field%header%description = '-'
1392 mask_field%header%vertical_coord = 'none'
1393 mask_field%header%vertical_level = 1
1394 mask_field%header%sr_x = 1
1395 mask_field%header%sr_y = 1
1396 mask_field%header%array_order = 'XY'
1397 mask_field%header%dim1(1) = 1
1398 mask_field%header%dim1(2) = fg_data%nx
1399 mask_field%header%dim2(1) = 1
1400 mask_field%header%dim2(2) = fg_data%ny
1401 mask_field%header%is_wind_grid_rel = .true.
1402 mask_field%header%array_has_missing_values = .false.
1403 mask_field%map%stagger = M
1405 ! Do a simple check to see whether this is a global lat/lon dataset
1406 ! Note that we do not currently support regional Gaussian grids
1407 if ((fg_data%iproj == PROJ_LATLON .and. abs(fg_data%nx * fg_data%deltalon - 360.) < 0.0001) &
1408 .or. (fg_data%iproj == PROJ_GAUSS)) then
1409 allocate(mask_field%r_arr(1-BDR_WIDTH:fg_data%nx+BDR_WIDTH,1:fg_data%ny))
1411 mask_field%r_arr(1:fg_data%nx, 1:fg_data%ny) = &
1412 fg_data%slab(1:fg_data%nx, 1:fg_data%ny)
1414 mask_field%r_arr(1-BDR_WIDTH:0, 1:fg_data%ny) = &
1415 fg_data%slab(fg_data%nx-BDR_WIDTH+1:fg_data%nx, 1:fg_data%ny)
1417 mask_field%r_arr(fg_data%nx+1:fg_data%nx+BDR_WIDTH, 1:fg_data%ny) = &
1418 fg_data%slab(1:BDR_WIDTH, 1:fg_data%ny)
1421 allocate(mask_field%r_arr(1:fg_data%nx,1:fg_data%ny))
1422 mask_field%r_arr = fg_data%slab
1425 nullify(mask_field%valid_mask)
1426 nullify(mask_field%modified_mask)
1428 call storage_put_field(mask_field)
1435 if (associated(fg_data%slab)) deallocate(fg_data%slab)
1441 call read_met_close()
1443 end subroutine get_interp_masks
1446 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1447 ! Name: interp_met_field
1450 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1451 subroutine interp_met_field(input_name, short_fieldnm, ifieldstagger, istagger, &
1452 field, xlat, xlon, sm1, em1, sm2, em2, &
1453 sd1, ed1, sd2, ed2, &
1454 slab, minx, maxx, miny, maxy, bdr, do_gcell_interp, &
1455 new_pts, process_bdy_width, landmask)
1459 use interp_option_module
1461 use misc_definitions_module
1467 integer, intent(in) :: ifieldstagger, istagger, &
1468 sm1, em1, sm2, em2, &
1469 sd1, ed1, sd2, ed2, &
1470 minx, maxx, miny, maxy, bdr, &
1472 real, dimension(minx:maxx,miny:maxy), intent(in) :: slab
1473 real, dimension(sm1:em1,sm2:em2), intent(in) :: xlat, xlon
1474 real, dimension(sm1:em1,sm2:em2), intent(in), optional :: landmask
1475 logical, intent(in) :: do_gcell_interp
1476 character (len=9), intent(in) :: short_fieldnm
1477 character (len=MAX_FILENAME_LEN), intent(in) :: input_name
1478 type (fg_input), intent(inout) :: field
1479 type (bitarray), intent(inout) :: new_pts
1482 integer :: i, j, idx, idxt, orig_selected_proj, interp_mask_status, &
1483 interp_land_mask_status, interp_water_mask_status, process_width
1484 integer, pointer, dimension(:) :: interp_array, interp_opts
1485 real :: rx, ry, temp
1486 real, pointer, dimension(:,:) :: data_count
1487 type (fg_input) :: mask_field, mask_water_field, mask_land_field
1489 real, dimension(sm1:em1,sm2:em2) :: r_arr_cur_source
1492 ! CWH Initialize local pointer variables
1493 nullify(interp_array)
1494 nullify(interp_opts)
1497 ! Find index into fieldname, interp_method, masked, and fill_missing
1498 ! of the current field
1499 idxt = num_entries + 1
1500 do idx=1,num_entries
1501 if ((index(fieldname(idx), trim(short_fieldnm)) /= 0) .and. &
1502 (len_trim(fieldname(idx)) == len_trim(short_fieldnm))) then
1503 if (index(input_name,trim(from_input(idx))) /= 0 .or. &
1504 (from_input(idx) == '*' .and. idxt == num_entries + 1)) then
1510 if (idx > num_entries) then
1511 call mprintf(.true.,WARN,'Entry in METGRID.TBL not found for field %s. '// &
1512 'Default options will be used for this field!', s1=short_fieldnm)
1513 idx = num_entries ! The last entry is a default
1516 if (process_bdy_width == 0) then
1517 process_width = max(ed1-sd1+1, ed2-sd2+1)
1519 process_width = process_bdy_width
1520 ! Add two extra rows/cols to accommodate staggered fields: one extra row/col for
1521 ! averaging to mass points in real, and one beyond that for averaging during
1523 if (ifieldstagger /= M) process_width = process_width + 2
1526 field%header%dim1(1) = sm1
1527 field%header%dim1(2) = em1
1528 field%header%dim2(1) = sm2
1529 field%header%dim2(2) = em2
1530 field%map%stagger = ifieldstagger
1531 if (.not. associated(field%r_arr)) then
1532 allocate(field%r_arr(sm1:em1,sm2:em2))
1535 interp_mask_status = 1
1536 interp_land_mask_status = 1
1537 interp_water_mask_status = 1
1539 if (interp_mask(idx) /= ' ') then
1540 mask_field%header%version = 1
1541 mask_field%header%forecast_hour = 0.
1542 mask_field%header%field = trim(interp_mask(idx))//'.mask'
1543 mask_field%header%vertical_coord = 'none'
1544 mask_field%header%vertical_level = 1
1546 call storage_get_field(mask_field, interp_mask_status)
1549 if (interp_land_mask(idx) /= ' ') then
1550 mask_land_field%header%version = 1
1551 mask_land_field%header%forecast_hour = 0.
1552 mask_land_field%header%field = trim(interp_land_mask(idx))//'.mask'
1553 mask_land_field%header%vertical_coord = 'none'
1554 mask_land_field%header%vertical_level = 1
1556 call storage_get_field(mask_land_field, interp_land_mask_status)
1559 if (interp_water_mask(idx) /= ' ') then
1560 mask_water_field%header%version = 1
1561 mask_water_field%header%forecast_hour = 0.
1562 mask_water_field%header%field = trim(interp_water_mask(idx))//'.mask'
1563 mask_water_field%header%vertical_coord = 'none'
1564 mask_water_field%header%vertical_level = 1
1566 call storage_get_field(mask_water_field, interp_water_mask_status)
1570 interp_array => interp_array_from_string(interp_method(idx))
1571 interp_opts => interp_options_from_string(interp_method(idx))
1575 ! Interpolate using average_gcell interpolation method
1577 if (do_gcell_interp) then
1579 !If a lower priority source of the current field has already been read
1580 !in, the results of that input are currently in field%r_arr
1581 !Pass COPY of field%r_arr into accum_continous because in accum_continuous
1582 !it will set the input variable to zero over points covered by the
1583 !current source and then determine the appropriate value to place at
1584 !that point. This will overwrite data already put in field%r_arr by
1585 !lower priority sources.
1586 !This is problematic if the current source results in missing values
1587 !over parts of the area covered by the current source where a lower
1588 !priority source has already provided a value. In this case, if one
1589 !passes in field%r_arr, it will overwrite the value provided by the
1590 !lower priority source with zero.
1591 r_arr_cur_source = field%r_arr
1593 allocate(data_count(sm1:em1,sm2:em2))
1596 if (interp_mask_status == 0) then
1597 call accum_continuous(slab, &
1598 minx, maxx, miny, maxy, 1, 1, bdr, &
1600 !Pass COPY of field%r_arr instead of field%r_arr itself
1601 !field%r_arr, data_count, &
1602 r_arr_cur_source, data_count, &
1604 sm1, em1, sm2, em2, 1, 1, &
1606 new_pts, missing_value(idx), interp_mask_val(idx), interp_mask_relational(idx), mask_field%r_arr)
1608 call accum_continuous(slab, &
1609 minx, maxx, miny, maxy, 1, 1, bdr, &
1611 !Pass COPY of field%r_arr instead of field%r_arr itself
1612 !field%r_arr, data_count, &
1613 r_arr_cur_source, data_count, &
1615 sm1, em1, sm2, em2, 1, 1, &
1617 new_pts, missing_value(idx), -1.) ! The -1 is the maskval, but since we
1618 ! we do not give an optional mask, no
1619 ! no need to worry about -1s in data
1622 orig_selected_proj = iget_selected_domain()
1623 call select_domain(SOURCE_PROJ)
1627 if (abs(i - sd1) >= process_width .and. (abs(i - ed1) >= process_width) .and. &
1628 abs(j - sd2) >= process_width .and. (abs(j - ed2) >= process_width)) then
1629 field%r_arr(i,j) = fill_missing(idx)
1630 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1634 if (present(landmask)) then
1636 if (landmask(i,j) /= masked(idx)) then
1637 if (data_count(i,j) > 0.) then
1639 !accum_continuous is now passed a copy of field%r_arr (r_arr_cur_source)
1640 !instead of field%r_arr itself so that it does not set
1641 !field%r_arr to zero where the input source is marked as missing
1642 !field%r_arr(i,j) = field%r_arr(i,j) / data_count(i,j)
1643 field%r_arr(i,j) = r_arr_cur_source(i,j) / data_count(i,j)
1645 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1648 if (interp_mask_status == 0) then
1649 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1650 minx, maxx, miny, maxy, bdr, missing_value(idx), &
1651 mask_relational=interp_mask_relational(idx), &
1652 mask_val=interp_mask_val(idx), mask_field=mask_field%r_arr)
1654 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1655 minx, maxx, miny, maxy, bdr, missing_value(idx))
1658 if (temp /= missing_value(idx)) then
1659 field%r_arr(i,j) = temp
1660 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1665 field%r_arr(i,j) = fill_missing(idx)
1666 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1669 if (.not. bitarray_test(new_pts, i-sm1+1, j-sm2+1) .and. &
1670 .not. bitarray_test(field%valid_mask, i-sm1+1, j-sm2+1)) then
1671 field%r_arr(i,j) = fill_missing(idx)
1673 ! Assume that if missing fill value is other than default, then user has asked
1674 ! to fill in any missing values, and we can consider this point to have
1675 ! received a valid value
1676 if (fill_missing(idx) /= NAN) call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1681 if (data_count(i,j) > 0.) then
1683 !accum_continuous is now passed a copy of field%r_arr (r_arr_cur_source)
1684 !instead of field%r_arr itself so that it does not set
1685 !field%r_arr to zero where the input source is marked as missing
1686 !field%r_arr(i,j) = field%r_arr(i,j) / data_count(i,j)
1687 field%r_arr(i,j) = r_arr_cur_source(i,j) / data_count(i,j)
1689 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1692 if (interp_mask_status == 0) then
1693 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1694 minx, maxx, miny, maxy, bdr, missing_value(idx), &
1695 mask_relational=interp_mask_relational(idx), &
1696 mask_val=interp_mask_val(idx), mask_field=mask_field%r_arr)
1698 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1699 minx, maxx, miny, maxy, bdr, missing_value(idx))
1702 if (temp /= missing_value(idx)) then
1703 field%r_arr(i,j) = temp
1704 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1709 if (.not. bitarray_test(new_pts, i-sm1+1, j-sm2+1) .and. &
1710 .not. bitarray_test(field%valid_mask, i-sm1+1, j-sm2+1)) then
1711 field%r_arr(i,j) = fill_missing(idx)
1713 ! Assume that if missing fill value is other than default, then user has asked
1714 ! to fill in any missing values, and we can consider this point to have
1715 ! received a valid value
1716 if (fill_missing(idx) /= NAN) call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1723 call select_domain(orig_selected_proj)
1724 deallocate(data_count)
1727 ! No average_gcell interpolation method
1731 orig_selected_proj = iget_selected_domain()
1732 call select_domain(SOURCE_PROJ)
1736 if (abs(i - sd1) >= process_width .and. (abs(i - ed1) >= process_width) .and. &
1737 abs(j - sd2) >= process_width .and. (abs(j - ed2) >= process_width)) then
1738 field%r_arr(i,j) = fill_missing(idx)
1739 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1743 if (present(landmask)) then
1745 if (masked(idx) == MASKED_BOTH) then
1747 if (landmask(i,j) == 0) then ! WATER POINT
1749 if (interp_land_mask_status == 0) then
1750 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1751 minx, maxx, miny, maxy, bdr, missing_value(idx), &
1752 mask_relational=interp_land_mask_relational(idx), &
1753 mask_val=interp_land_mask_val(idx), mask_field=mask_land_field%r_arr)
1755 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1756 minx, maxx, miny, maxy, bdr, missing_value(idx))
1759 else if (landmask(i,j) == 1) then ! LAND POINT
1761 if (interp_water_mask_status == 0) then
1762 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1763 minx, maxx, miny, maxy, bdr, missing_value(idx), &
1764 mask_relational=interp_water_mask_relational(idx), &
1765 mask_val=interp_water_mask_val(idx), mask_field=mask_water_field%r_arr)
1767 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1768 minx, maxx, miny, maxy, bdr, missing_value(idx))
1773 else if (landmask(i,j) /= masked(idx)) then
1775 if (interp_mask_status == 0) then
1776 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1777 minx, maxx, miny, maxy, bdr, missing_value(idx), &
1778 mask_relational=interp_mask_relational(idx), &
1779 mask_val=interp_mask_val(idx), mask_field=mask_field%r_arr)
1781 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1782 minx, maxx, miny, maxy, bdr, missing_value(idx))
1786 temp = missing_value(idx)
1789 ! No landmask for this field
1792 if (interp_mask_status == 0) then
1793 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1794 minx, maxx, miny, maxy, bdr, missing_value(idx), &
1795 mask_relational=interp_mask_relational(idx), &
1796 mask_val=interp_mask_val(idx), mask_field=mask_field%r_arr)
1798 temp = interp_to_latlon(xlat(i,j), xlon(i,j), istagger, interp_array, interp_opts, slab, &
1799 minx, maxx, miny, maxy, bdr, missing_value(idx))
1804 if (temp /= missing_value(idx)) then
1805 field%r_arr(i,j) = temp
1806 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1807 else if (present(landmask)) then
1808 if (landmask(i,j) == masked(idx)) then
1809 field%r_arr(i,j) = fill_missing(idx)
1810 call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1814 if (.not. bitarray_test(new_pts, i-sm1+1, j-sm2+1) .and. &
1815 .not. bitarray_test(field%valid_mask, i-sm1+1, j-sm2+1)) then
1816 field%r_arr(i,j) = fill_missing(idx)
1818 ! Assume that if missing fill value is other than default, then user has asked
1819 ! to fill in any missing values, and we can consider this point to have
1820 ! received a valid value
1821 if (fill_missing(idx) /= NAN) call bitarray_set(new_pts, i-sm1+1, j-sm2+1)
1826 call select_domain(orig_selected_proj)
1829 deallocate(interp_array)
1830 deallocate(interp_opts)
1832 end subroutine interp_met_field
1835 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1836 ! Name: interp_to_latlon
1839 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1840 function interp_to_latlon(rlat, rlon, istagger, interp_method_list, interp_opt_list, slab, &
1841 minx, maxx, miny, maxy, bdr, source_missing_value, &
1842 mask_field, mask_relational, mask_val)
1850 integer, intent(in) :: minx, maxx, miny, maxy, bdr, istagger
1851 integer, dimension(:), intent(in) :: interp_method_list
1852 integer, dimension(:), intent(in) :: interp_opt_list
1853 real, intent(in) :: rlat, rlon, source_missing_value
1854 real, dimension(minx:maxx,miny:maxy), intent(in) :: slab
1855 real, intent(in), optional :: mask_val
1856 real, dimension(minx:maxx,miny:maxy), intent(in), optional :: mask_field
1857 character(len=1), intent(in), optional :: mask_relational
1860 real :: interp_to_latlon
1865 interp_to_latlon = source_missing_value
1867 call lltoxy(rlat, rlon, rx, ry, istagger)
1868 if (rx >= minx+bdr-0.5 .and. rx <= maxx-bdr+0.5) then
1869 if (present(mask_field) .and. present(mask_val) .and. present (mask_relational)) then
1870 interp_to_latlon = interp_sequence(rx, ry, 1, slab, minx, maxx, miny, maxy, 1, 1, source_missing_value, &
1871 interp_method_list, interp_opt_list, 1, mask_relational, mask_val, mask_field)
1872 else if (present(mask_field) .and. present(mask_val)) then
1873 interp_to_latlon = interp_sequence(rx, ry, 1, slab, minx, maxx, miny, maxy, 1, 1, source_missing_value, &
1874 interp_method_list, interp_opt_list, 1, maskval=mask_val, mask_array=mask_field)
1876 interp_to_latlon = interp_sequence(rx, ry, 1, slab, minx, maxx, miny, maxy, 1, 1, source_missing_value, &
1877 interp_method_list, interp_opt_list, 1)
1880 interp_to_latlon = source_missing_value
1883 if (interp_to_latlon == source_missing_value) then
1885 ! Try a lon in the range 0. to 360.; all lons in the xlon
1886 ! array should be in the range -180. to 180.
1888 call lltoxy(rlat, rlon+360., rx, ry, istagger)
1889 if (rx >= minx+bdr-0.5 .and. rx <= maxx-bdr+0.5) then
1890 if (present(mask_field) .and. present(mask_val) .and. present(mask_relational)) then
1891 interp_to_latlon = interp_sequence(rx, ry, 1, slab, minx, maxx, miny, maxy, &
1892 1, 1, source_missing_value, &
1893 interp_method_list, interp_opt_list, 1, &
1894 mask_relational, mask_val, mask_field)
1895 else if (present(mask_field) .and. present(mask_val)) then
1896 interp_to_latlon = interp_sequence(rx, ry, 1, slab, minx, maxx, miny, maxy, &
1897 1, 1, source_missing_value, &
1898 interp_method_list, interp_opt_list, 1, &
1899 maskval=mask_val, mask_array=mask_field)
1901 interp_to_latlon = interp_sequence(rx, ry, 1, slab, minx, maxx, miny, maxy, &
1902 1, 1, source_missing_value, &
1903 interp_method_list, interp_opt_list, 1)
1906 interp_to_latlon = source_missing_value
1915 end function interp_to_latlon
1918 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1919 ! Name: get_bottom_top_dim
1922 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1923 subroutine get_bottom_top_dim(bottom_top_dim)
1925 use interp_option_module
1932 integer, intent(out) :: bottom_top_dim
1936 integer, pointer, dimension(:) :: field_levels
1937 character (len=32) :: z_dim
1938 type (fg_input), pointer, dimension(:) :: headers
1939 type (list) :: temp_levels
1941 !CWH Initialize local pointer variables
1942 nullify(field_levels)
1945 ! Initialize a list to store levels that are found for 3-d fields
1946 call list_init(temp_levels)
1948 ! Get a list of all time-dependent fields (given by their headers) from
1949 ! the storage module
1950 call storage_get_td_headers(headers)
1953 ! Given headers of all fields, we first build a list of all possible levels
1954 ! for 3-d met fields (excluding sea-level, though).
1956 do i=1,size(headers)
1957 call get_z_dim_name(headers(i)%header%field, z_dim)
1959 ! We only want to consider 3-d met fields
1960 if (z_dim(1:18) == 'num_metgrid_levels') then
1962 ! Find out what levels the current field has
1963 call storage_get_levels(headers(i), field_levels)
1964 do j=1,size(field_levels)
1966 ! If this level has not yet been encountered, add it to our list
1967 if (.not. list_search(temp_levels, ikey=field_levels(j), ivalue=field_levels(j))) then
1968 if (field_levels(j) /= 201300) then
1969 call list_insert(temp_levels, ikey=field_levels(j), ivalue=field_levels(j))
1975 deallocate(field_levels)
1981 bottom_top_dim = list_length(temp_levels)
1983 call list_destroy(temp_levels)
1986 end subroutine get_bottom_top_dim
1989 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1990 ! Name: fill_missing_levels
1993 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1994 subroutine fill_missing_levels(output_flags)
1996 use interp_option_module
1999 use module_mergesort
2005 character (len=128), dimension(:), intent(inout) :: output_flags
2008 integer :: i, ii, j, ix, jx, k, lower, upper, temp, istatus
2009 integer, pointer, dimension(:) :: union_levels, field_levels
2010 real, pointer, dimension(:) :: r_union_levels
2011 character (len=128) :: clevel
2012 type (fg_input) :: lower_field, upper_field, new_field, search_field
2013 type (fg_input), pointer, dimension(:) :: headers, all_headers
2014 type (list) :: temp_levels
2015 type (list_item), pointer, dimension(:) :: keys
2017 ! CWH Initialize local pointer variables
2018 nullify(union_levels)
2019 nullify(field_levels)
2020 nullify(r_union_levels)
2022 nullify(all_headers)
2025 ! Initialize a list to store levels that are found for 3-d fields
2026 call list_init(temp_levels)
2028 ! Get a list of all fields (given by their headers) from the storage module
2029 call storage_get_td_headers(headers)
2030 call storage_get_all_headers(all_headers)
2033 ! Given headers of all fields, we first build a list of all possible levels
2034 ! for 3-d met fields (excluding sea-level, though).
2036 do i=1,size(headers)
2038 ! Find out what levels the current field has
2039 call storage_get_levels(headers(i), field_levels)
2040 do j=1,size(field_levels)
2042 ! If this level has not yet been encountered, add it to our list
2043 if (.not. list_search(temp_levels, ikey=field_levels(j), ivalue=field_levels(j))) then
2044 if (field_levels(j) /= 201300) then
2045 call list_insert(temp_levels, ikey=field_levels(j), ivalue=field_levels(j))
2051 deallocate(field_levels)
2055 if (list_length(temp_levels) > 0) then
2058 ! With all possible levels stored in a list, get an array of levels, sorted
2059 ! in decreasing order
2062 allocate(union_levels(list_length(temp_levels)))
2063 do while (list_length(temp_levels) > 0)
2065 call list_get_first_item(temp_levels, ikey=union_levels(i), ivalue=temp)
2067 call mergesort(union_levels, 1, size(union_levels))
2069 allocate(r_union_levels(size(union_levels)))
2070 do i=1,size(union_levels)
2071 r_union_levels(i) = real(union_levels(i))
2075 ! With a sorted, complete list of levels, we need
2076 ! to go back and fill in missing levels for each 3-d field
2078 do i=1,size(headers)
2081 ! Find entry in METGRID.TBL for this field, if one exists; if it does, then the
2082 ! entry may tell us how to get values for the current field at the missing level
2085 if (fieldname(ii) == headers(i)%header%field) exit
2087 if (ii <= num_entries) then
2088 call dup(headers(i),new_field)
2089 nullify(new_field%valid_mask)
2090 nullify(new_field%modified_mask)
2091 call fill_field(new_field, ii, output_flags, r_union_levels)
2096 deallocate(union_levels)
2097 deallocate(r_union_levels)
2100 call storage_get_td_headers(headers)
2103 ! Now we may need to vertically interpolate to missing values in 3-d fields
2105 do i=1,size(headers)
2107 call storage_get_levels(headers(i), field_levels)
2109 ! If this isn't a 3-d array, nothing to do
2110 if (size(field_levels) > 1) then
2112 do k=1,size(field_levels)
2113 call dup(headers(i),search_field)
2114 search_field%header%vertical_level = field_levels(k)
2115 call storage_get_field(search_field,istatus)
2116 if (istatus == 0) then
2117 JLOOP: do jx=search_field%header%dim2(1),search_field%header%dim2(2)
2118 ILOOP: do ix=search_field%header%dim1(1),search_field%header%dim1(2)
2119 if (.not. bitarray_test(search_field%valid_mask, &
2120 ix-search_field%header%dim1(1)+1, &
2121 jx-search_field%header%dim2(1)+1)) then
2123 call dup(search_field, lower_field)
2125 lower_field%header%vertical_level = field_levels(lower)
2126 call storage_get_field(lower_field,istatus)
2127 if (bitarray_test(lower_field%valid_mask, &
2128 ix-search_field%header%dim1(1)+1, &
2129 jx-search_field%header%dim2(1)+1)) &
2134 call dup(search_field, upper_field)
2135 do upper=k+1,size(field_levels)
2136 upper_field%header%vertical_level = field_levels(upper)
2137 call storage_get_field(upper_field,istatus)
2138 if (bitarray_test(upper_field%valid_mask, &
2139 ix-search_field%header%dim1(1)+1, &
2140 jx-search_field%header%dim2(1)+1)) &
2144 if (upper <= size(field_levels) .and. lower >= 1) then
2145 search_field%r_arr(ix,jx) = real(abs(field_levels(upper)-field_levels(k))) &
2146 / real(abs(field_levels(upper)-field_levels(lower))) &
2147 * lower_field%r_arr(ix,jx) &
2148 + real(abs(field_levels(k)-field_levels(lower))) &
2149 / real(abs(field_levels(upper)-field_levels(lower))) &
2150 * upper_field%r_arr(ix,jx)
2151 call bitarray_set(search_field%valid_mask, &
2152 ix-search_field%header%dim1(1)+1, &
2153 jx-search_field%header%dim2(1)+1)
2159 call mprintf(.true.,ERROR, &
2160 'This is bad, could not get %s at level %i.', &
2161 s1=trim(search_field%header%field), i1=field_levels(k))
2167 deallocate(field_levels)
2173 call list_destroy(temp_levels)
2174 deallocate(all_headers)
2177 end subroutine fill_missing_levels
2180 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2181 ! Name: create_derived_fields
2184 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2185 subroutine create_derived_fields(arg_gridtype, hdate, xfcst, &
2186 we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
2187 we_mem_stag_s, we_mem_stag_e, sn_mem_stag_s, sn_mem_stag_e, &
2188 created_this_field, output_flags)
2190 use interp_option_module
2192 use module_mergesort
2198 integer, intent(in) :: we_mem_s, we_mem_e, sn_mem_s, sn_mem_e, &
2199 we_mem_stag_s, we_mem_stag_e, sn_mem_stag_s, sn_mem_stag_e
2200 real, intent(in) :: xfcst
2201 logical, dimension(:), intent(inout) :: created_this_field
2202 character (len=1), intent(in) :: arg_gridtype
2203 character (len=24), intent(in) :: hdate
2204 character (len=128), dimension(:), intent(inout) :: output_flags
2207 integer :: idx, i, j, istatus
2208 type (fg_input) :: field
2210 ! Initialize fg_input structure to store the field
2211 field%header%version = 1
2212 field%header%date = hdate//' '
2213 field%header%time_dependent = .true.
2214 field%header%mask_field = .false.
2215 field%header%constant_field = .false.
2216 field%header%forecast_hour = xfcst
2217 field%header%fg_source = 'Derived from FG'
2218 field%header%field = ' '
2219 field%header%units = ' '
2220 field%header%description = ' '
2221 field%header%vertical_level = 0
2222 field%header%sr_x = 1
2223 field%header%sr_y = 1
2224 field%header%array_order = 'XY '
2225 field%header%is_wind_grid_rel = .true.
2226 field%header%array_has_missing_values = .false.
2227 nullify(field%r_arr)
2228 nullify(field%valid_mask)
2229 nullify(field%modified_mask)
2232 ! Check each entry in METGRID.TBL to see whether it is a derive field
2234 do idx=1,num_entries
2235 if (is_derived_field(idx)) then
2237 created_this_field(idx) = .true.
2239 call mprintf(.true.,INFORM,'Going to create the field %s',s1=fieldname(idx))
2241 ! Intialize more fields in storage structure
2242 field%header%field = fieldname(idx)
2243 call get_z_dim_name(fieldname(idx),field%header%vertical_coord)
2244 field%map%stagger = output_stagger(idx)
2245 if (arg_gridtype == 'E') then
2246 field%header%dim1(1) = we_mem_s
2247 field%header%dim1(2) = we_mem_e
2248 field%header%dim2(1) = sn_mem_s
2249 field%header%dim2(2) = sn_mem_e
2250 else if (arg_gridtype == 'C') then
2251 if (output_stagger(idx) == M) then
2252 field%header%dim1(1) = we_mem_s
2253 field%header%dim1(2) = we_mem_e
2254 field%header%dim2(1) = sn_mem_s
2255 field%header%dim2(2) = sn_mem_e
2256 else if (output_stagger(idx) == U) then
2257 field%header%dim1(1) = we_mem_stag_s
2258 field%header%dim1(2) = we_mem_stag_e
2259 field%header%dim2(1) = sn_mem_s
2260 field%header%dim2(2) = sn_mem_e
2261 else if (output_stagger(idx) == V) then
2262 field%header%dim1(1) = we_mem_s
2263 field%header%dim1(2) = we_mem_e
2264 field%header%dim2(1) = sn_mem_stag_s
2265 field%header%dim2(2) = sn_mem_stag_e
2269 call fill_field(field, idx, output_flags)
2275 end subroutine create_derived_fields
2278 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2282 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2283 subroutine fill_field(field, idx, output_flags, all_level_list)
2285 use interp_option_module
2287 use module_mergesort
2293 integer, intent(in) :: idx
2294 type (fg_input), intent(inout) :: field
2295 character (len=128), dimension(:), intent(inout) :: output_flags
2296 real, dimension(:), intent(in), optional :: all_level_list
2299 integer :: i, j, istatus, isrclevel
2300 integer, pointer, dimension(:) :: all_list
2301 real :: rfillconst, rlevel, rsrclevel
2302 type (fg_input) :: query_field
2303 type (list_item), pointer, dimension(:) :: keys
2304 character (len=128) :: asrcname
2305 logical :: filled_all_lev
2307 !CWH Initialize local pointer variables
2311 filled_all_lev = .false.
2314 ! Get a list of all levels to be filled for this field
2316 keys => list_get_keys(fill_lev_list(idx))
2318 do i=1,list_length(fill_lev_list(idx))
2321 ! First handle a specification for levels "all"
2323 if (trim(keys(i)%ckey) == 'all') then
2325 ! We only want to fill all levels if we haven't already filled "all" of them
2326 if (.not. filled_all_lev) then
2328 filled_all_lev = .true.
2330 query_field%header%time_dependent = .true.
2331 query_field%header%field = ' '
2332 nullify(query_field%r_arr)
2333 nullify(query_field%valid_mask)
2334 nullify(query_field%modified_mask)
2336 ! See if we are filling this level with a constant
2337 call get_constant_fill_lev(keys(i)%cvalue, rfillconst, istatus)
2338 if (istatus == 0) then
2339 if (present(all_level_list)) then
2340 do j=1,size(all_level_list)
2341 call create_level(field, real(all_level_list(j)), idx, output_flags, rfillconst=rfillconst)
2344 query_field%header%field = level_template(idx)
2346 call storage_get_levels(query_field, all_list)
2347 if (associated(all_list)) then
2348 do j=1,size(all_list)
2349 call create_level(field, real(all_list(j)), idx, output_flags, rfillconst=rfillconst)
2351 deallocate(all_list)
2355 ! Else see if we are filling this level with a constant equal
2356 ! to the value of the level
2357 else if (trim(keys(i)%cvalue) == 'vertical_index') then
2358 if (present(all_level_list)) then
2359 do j=1,size(all_level_list)
2360 call create_level(field, real(all_level_list(j)), idx, output_flags, &
2361 rfillconst=real(all_level_list(j)))
2364 query_field%header%field = level_template(idx)
2366 call storage_get_levels(query_field, all_list)
2367 if (associated(all_list)) then
2368 do j=1,size(all_list)
2369 call create_level(field, real(all_list(j)), idx, output_flags, rfillconst=real(all_list(j)))
2371 deallocate(all_list)
2375 ! Else, we assume that it is a field from which we are copying levels
2377 if (present(all_level_list)) then
2378 do j=1,size(all_level_list)
2379 call create_level(field, real(all_level_list(j)), idx, output_flags, &
2380 asrcname=keys(i)%cvalue, rsrclevel=real(all_level_list(j)))
2383 query_field%header%field = keys(i)%cvalue ! Use same levels as source field, not level_template
2385 call storage_get_levels(query_field, all_list)
2386 if (associated(all_list)) then
2387 do j=1,size(all_list)
2388 call create_level(field, real(all_list(j)), idx, output_flags, &
2389 asrcname=keys(i)%cvalue, rsrclevel=real(all_list(j)))
2391 deallocate(all_list)
2395 ! If the field doesn't have any levels (or does not exist) then we have not
2396 ! really filled all levels at this point.
2397 filled_all_lev = .false.
2405 ! Handle individually specified levels
2409 read(keys(i)%ckey,*) rlevel
2411 ! See if we are filling this level with a constant
2412 call get_constant_fill_lev(keys(i)%cvalue, rfillconst, istatus)
2413 if (istatus == 0) then
2414 call create_level(field, rlevel, idx, output_flags, rfillconst=rfillconst)
2416 ! Otherwise, we are filling from another level
2418 call get_fill_src_level(keys(i)%cvalue, asrcname, isrclevel)
2419 rsrclevel = real(isrclevel)
2420 call create_level(field, rlevel, idx, output_flags, &
2421 asrcname=asrcname, rsrclevel=rsrclevel)
2427 if (associated(keys)) deallocate(keys)
2429 end subroutine fill_field
2432 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2433 ! Name: create_level
2436 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2437 subroutine create_level(field_template, rlevel, idx, output_flags, &
2438 rfillconst, asrcname, rsrclevel)
2441 use interp_option_module
2446 type (fg_input), intent(inout) :: field_template
2447 real, intent(in) :: rlevel
2448 integer, intent(in) :: idx
2449 character (len=128), dimension(:), intent(inout) :: output_flags
2450 real, intent(in), optional :: rfillconst, rsrclevel
2451 character (len=128), intent(in), optional :: asrcname
2454 integer :: i, j, istatus
2455 integer :: sm1,em1,sm2,em2
2456 type (fg_input) :: query_field
2459 ! Check to make sure optional arguments are sane
2461 if (present(rfillconst) .and. (present(asrcname) .or. present(rsrclevel))) then
2462 call mprintf(.true.,ERROR,'A call to create_level() cannot be given specifications '// &
2463 'for both a constant fill value and a source level.')
2465 else if ((present(asrcname) .and. .not. present(rsrclevel)) .or. &
2466 (.not. present(asrcname) .and. present(rsrclevel))) then
2467 call mprintf(.true.,ERROR,'Neither or both of optional arguments asrcname and '// &
2468 'rsrclevel must be specified to subroutine create_level().')
2470 else if (.not. present(rfillconst) .and. &
2471 .not. present(asrcname) .and. &
2472 .not. present(rsrclevel)) then
2473 call mprintf(.true.,ERROR,'A call to create_level() must be given either a specification '// &
2474 'for a constant fill value or a source level.')
2477 query_field%header%time_dependent = .true.
2478 query_field%header%field = field_template%header%field
2479 query_field%header%vertical_level = rlevel
2480 nullify(query_field%r_arr)
2481 nullify(query_field%valid_mask)
2482 nullify(query_field%modified_mask)
2484 call storage_query_field(query_field, istatus)
2485 if (istatus == 0) then
2486 call mprintf(.true.,INFORM,'%s at level %f already exists; leaving it alone.', &
2487 s1=field_template%header%field, f1=rlevel)
2491 sm1 = field_template%header%dim1(1)
2492 em1 = field_template%header%dim1(2)
2493 sm2 = field_template%header%dim2(1)
2494 em2 = field_template%header%dim2(2)
2497 ! Handle constant fill value case
2499 if (present(rfillconst)) then
2501 field_template%header%vertical_level = rlevel
2502 allocate(field_template%r_arr(sm1:em1,sm2:em2))
2503 allocate(field_template%valid_mask)
2504 allocate(field_template%modified_mask)
2505 call bitarray_create(field_template%valid_mask, em1-sm1+1, em2-sm2+1)
2506 call bitarray_create(field_template%modified_mask, em1-sm1+1, em2-sm2+1)
2508 field_template%r_arr = rfillconst
2512 call bitarray_set(field_template%valid_mask, i-sm1+1, j-sm2+1)
2516 call storage_put_field(field_template)
2518 if (output_this_field(idx) .and. flag_in_output(idx) /= ' ') then
2519 output_flags(idx) = flag_in_output(idx)
2523 ! Handle source field and source level case
2525 else if (present(asrcname) .and. present(rsrclevel)) then
2527 query_field%header%field = ' '
2528 query_field%header%field = asrcname
2529 query_field%header%vertical_level = rsrclevel
2531 ! Check to see whether the requested source field exists at the requested level
2532 call storage_query_field(query_field, istatus)
2534 if (istatus == 0) then
2536 ! Read in requested field at requested level
2537 call storage_get_field(query_field, istatus)
2538 if ((query_field%header%dim1(1) /= field_template%header%dim1(1)) .or. &
2539 (query_field%header%dim1(2) /= field_template%header%dim1(2)) .or. &
2540 (query_field%header%dim2(1) /= field_template%header%dim2(1)) .or. &
2541 (query_field%header%dim2(2) /= field_template%header%dim2(2))) then
2542 call mprintf(.true.,ERROR,'Dimensions for %s do not match those of %s. This is '// &
2543 'probably because the staggerings of the fields do not match.', &
2544 s1=query_field%header%field, s2=field_template%header%field)
2547 field_template%header%vertical_level = rlevel
2548 allocate(field_template%r_arr(sm1:em1,sm2:em2))
2549 allocate(field_template%valid_mask)
2550 allocate(field_template%modified_mask)
2551 call bitarray_create(field_template%valid_mask, em1-sm1+1, em2-sm2+1)
2552 call bitarray_create(field_template%modified_mask, em1-sm1+1, em2-sm2+1)
2554 field_template%r_arr = query_field%r_arr
2556 ! We should retain information about which points in the field are valid
2559 if (bitarray_test(query_field%valid_mask, i-sm1+1, j-sm2+1)) then
2560 call bitarray_set(field_template%valid_mask, i-sm1+1, j-sm2+1)
2565 call storage_put_field(field_template)
2567 if (output_this_field(idx) .and. flag_in_output(idx) /= ' ') then
2568 output_flags(idx) = flag_in_output(idx)
2572 call mprintf(.true.,INFORM,'Couldn''t find %s at level %f to fill level %f of %s.', &
2573 s1=asrcname,f1=rsrclevel,f2=rlevel,s2=field_template%header%field)
2578 end subroutine create_level
2581 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2582 ! Name: accum_continuous
2584 ! Purpose: Sum up all of the source data points whose nearest neighbor in the
2585 ! model grid is the specified model grid point.
2587 ! NOTE: When processing the source tile, those source points that are
2588 ! closest to a different model grid point will be added to the totals for
2589 ! such grid points; thus, an entire source tile will be processed at a time.
2590 ! This routine really processes for all model grid points that are
2591 ! within a source tile, and not just for a single grid point.
2592 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2593 subroutine accum_continuous(src_array, &
2594 src_min_x, src_max_x, src_min_y, src_max_y, src_min_z, src_max_z, bdr_width, &
2596 start_i, end_i, start_j, end_j, start_k, end_k, &
2598 new_pts, msgval, maskval, mask_relational, mask_array, sr_x, sr_y)
2601 use misc_definitions_module
2606 integer, intent(in) :: start_i, end_i, start_j, end_j, start_k, end_k, istagger, &
2607 src_min_x, src_max_x, src_min_y, src_max_y, src_min_z, src_max_z, bdr_width
2608 real, intent(in) :: maskval, msgval
2609 real, dimension(src_min_x:src_max_x, src_min_y:src_max_y, src_min_z:src_max_z), intent(in) :: src_array
2610 real, dimension(start_i:end_i, start_j:end_j, start_k:end_k), intent(inout) :: dst_array, n
2611 real, dimension(src_min_x:src_max_x, src_min_y:src_max_y), intent(in), optional :: mask_array
2612 integer, intent(in), optional :: sr_x, sr_y
2613 type (bitarray), intent(inout) :: new_pts
2614 character(len=1), intent(in), optional :: mask_relational
2618 integer, pointer, dimension(:,:,:) :: where_maps_to
2619 real :: rsr_x, rsr_y
2623 if (present(sr_x)) rsr_x = real(sr_x)
2624 if (present(sr_y)) rsr_y = real(sr_y)
2626 allocate(where_maps_to(src_min_x:src_max_x,src_min_y:src_max_y,2))
2627 do i=src_min_x,src_max_x
2628 do j=src_min_y,src_max_y
2629 where_maps_to(i,j,1) = NOT_PROCESSED
2633 call process_continuous_block(src_array, where_maps_to, &
2634 src_min_x, src_min_y, src_min_z, src_max_x, src_max_y, src_max_z, &
2635 src_min_x+bdr_width, src_min_y, src_min_z, &
2636 src_max_x-bdr_width, src_max_y, src_max_z, &
2637 dst_array, n, start_i, end_i, start_j, end_j, start_k, end_k, &
2639 new_pts, rsr_x, rsr_y, msgval, maskval, mask_relational, mask_array)
2641 deallocate(where_maps_to)
2643 end subroutine accum_continuous
2646 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2647 ! Name: process_continuous_block
2649 ! Purpose: To recursively process a subarray of continuous data, adding the
2650 ! points in a block to the sum for their nearest grid point. The nearest
2651 ! neighbor may be estimated in some cases; for example, if the four corners
2652 ! of a subarray all have the same nearest grid point, all elements in the
2653 ! subarray are added to that grid point.
2654 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2655 recursive subroutine process_continuous_block(tile_array, where_maps_to, &
2656 src_min_x, src_min_y, src_min_z, src_max_x, src_max_y, src_max_z, &
2657 min_i, min_j, min_k, max_i, max_j, max_k, &
2659 start_x, end_x, start_y, end_y, start_z, end_z, &
2661 new_pts, sr_x, sr_y, msgval, maskval, mask_relational, mask_array)
2665 use misc_definitions_module
2670 integer, intent(in) :: min_i, min_j, min_k, max_i, max_j, max_k, &
2671 src_min_x, src_min_y, src_min_z, src_max_x, src_max_y, src_max_z, &
2672 start_x, end_x, start_y, end_y, start_z, end_z, istagger
2673 integer, dimension(src_min_x:src_max_x,src_min_y:src_max_y,2), intent(inout) :: where_maps_to
2674 real, intent(in) :: sr_x, sr_y, maskval, msgval
2675 real, dimension(src_min_x:src_max_x,src_min_y:src_max_y,src_min_z:src_max_z), intent(in) :: tile_array
2676 real, dimension(src_min_x:src_max_x,src_min_y:src_max_y), intent(in), optional :: mask_array
2677 real, dimension(start_x:end_x,start_y:end_y,start_z:end_z), intent(inout) :: dst_array, n
2678 type (bitarray), intent(inout) :: new_pts
2679 character(len=1), intent(in), optional :: mask_relational
2682 integer :: orig_selected_domain, x_dest, y_dest, i, j, k, center_i, center_j
2683 real :: lat_corner, lon_corner, rx, ry
2685 ! Compute the model grid point that the corners of the rectangle to be
2688 if (where_maps_to(min_i,min_j,1) == NOT_PROCESSED) then
2689 orig_selected_domain = iget_selected_domain()
2690 call select_domain(SOURCE_PROJ)
2691 call xytoll(real(min_i), real(min_j), lat_corner, lon_corner, istagger)
2692 call select_domain(1)
2693 call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
2694 rx = (rx - 1.0)*sr_x + 1.0
2695 ry = (ry - 1.0)*sr_y + 1.0
2696 call select_domain(orig_selected_domain)
2697 if (real(start_x) <= rx .and. rx <= real(end_x) .and. &
2698 real(start_y) <= ry .and. ry <= real(end_y)) then
2699 where_maps_to(min_i,min_j,1) = nint(rx)
2700 where_maps_to(min_i,min_j,2) = nint(ry)
2702 where_maps_to(min_i,min_j,1) = OUTSIDE_DOMAIN
2707 if (where_maps_to(min_i,max_j,1) == NOT_PROCESSED) then
2708 orig_selected_domain = iget_selected_domain()
2709 call select_domain(SOURCE_PROJ)
2710 call xytoll(real(min_i), real(max_j), lat_corner, lon_corner, istagger)
2711 call select_domain(1)
2712 call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
2713 rx = (rx - 1.0)*sr_x + 1.0
2714 ry = (ry - 1.0)*sr_y + 1.0
2715 call select_domain(orig_selected_domain)
2716 if (real(start_x) <= rx .and. rx <= real(end_x) .and. &
2717 real(start_y) <= ry .and. ry <= real(end_y)) then
2718 where_maps_to(min_i,max_j,1) = nint(rx)
2719 where_maps_to(min_i,max_j,2) = nint(ry)
2721 where_maps_to(min_i,max_j,1) = OUTSIDE_DOMAIN
2725 ! Upper-right corner
2726 if (where_maps_to(max_i,max_j,1) == NOT_PROCESSED) then
2727 orig_selected_domain = iget_selected_domain()
2728 call select_domain(SOURCE_PROJ)
2729 call xytoll(real(max_i), real(max_j), lat_corner, lon_corner, istagger)
2730 call select_domain(1)
2731 call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
2732 rx = (rx - 1.0)*sr_x + 1.0
2733 ry = (ry - 1.0)*sr_y + 1.0
2734 call select_domain(orig_selected_domain)
2735 if (real(start_x) <= rx .and. rx <= real(end_x) .and. &
2736 real(start_y) <= ry .and. ry <= real(end_y)) then
2737 where_maps_to(max_i,max_j,1) = nint(rx)
2738 where_maps_to(max_i,max_j,2) = nint(ry)
2740 where_maps_to(max_i,max_j,1) = OUTSIDE_DOMAIN
2744 ! Lower-right corner
2745 if (where_maps_to(max_i,min_j,1) == NOT_PROCESSED) then
2746 orig_selected_domain = iget_selected_domain()
2747 call select_domain(SOURCE_PROJ)
2748 call xytoll(real(max_i), real(min_j), lat_corner, lon_corner, istagger)
2749 call select_domain(1)
2750 call lltoxy(lat_corner, lon_corner, rx, ry, istagger)
2751 rx = (rx - 1.0)*sr_x + 1.0
2752 ry = (ry - 1.0)*sr_y + 1.0
2753 call select_domain(orig_selected_domain)
2754 if (real(start_x) <= rx .and. rx <= real(end_x) .and. &
2755 real(start_y) <= ry .and. ry <= real(end_y)) then
2756 where_maps_to(max_i,min_j,1) = nint(rx)
2757 where_maps_to(max_i,min_j,2) = nint(ry)
2759 where_maps_to(max_i,min_j,1) = OUTSIDE_DOMAIN
2763 ! If all four corners map to same model grid point, accumulate the
2765 if (where_maps_to(min_i,min_j,1) == where_maps_to(min_i,max_j,1) .and. &
2766 where_maps_to(min_i,min_j,1) == where_maps_to(max_i,max_j,1) .and. &
2767 where_maps_to(min_i,min_j,1) == where_maps_to(max_i,min_j,1) .and. &
2768 where_maps_to(min_i,min_j,2) == where_maps_to(min_i,max_j,2) .and. &
2769 where_maps_to(min_i,min_j,2) == where_maps_to(max_i,max_j,2) .and. &
2770 where_maps_to(min_i,min_j,2) == where_maps_to(max_i,min_j,2) .and. &
2771 where_maps_to(min_i,min_j,1) /= OUTSIDE_DOMAIN) then
2772 x_dest = where_maps_to(min_i,min_j,1)
2773 y_dest = where_maps_to(min_i,min_j,2)
2775 ! If this grid point was already given a value from higher-priority source data,
2776 ! there is nothing to do.
2777 ! if (.not. bitarray_test(processed_pts, x_dest-start_x+1, y_dest-start_y+1)) then
2779 ! If this grid point has never been given a value by this level of source data,
2780 ! initialize the point
2781 if (.not. bitarray_test(new_pts, x_dest-start_x+1, y_dest-start_y+1)) then
2783 dst_array(x_dest,y_dest,k) = 0.
2787 ! Sum all the points whose nearest neighbor is this grid point
2788 if (present(mask_array) .and. present(mask_relational)) then
2792 ! Ignore masked/missing values in the source data
2793 if (tile_array(i,j,k) /= msgval) then
2794 if (mask_relational == ' ' .and. mask_array(i,j) /= maskval) then
2795 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2796 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2797 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2798 else if (mask_relational == '<' .and. mask_array(i,j) >= maskval) then
2799 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2800 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2801 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2802 else if (mask_relational == '>' .and. mask_array(i,j) <= maskval) then
2803 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2804 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2805 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2811 else if (present(mask_array)) then
2815 ! Ignore masked/missing values in the source data
2816 if ((tile_array(i,j,k) /= msgval) .and. &
2817 (mask_array(i,j) /= maskval)) then
2818 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2819 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2820 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2829 ! Ignore masked/missing values in the source data
2830 if ((tile_array(i,j,k) /= msgval)) then
2831 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2832 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2833 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2842 ! Rectangle is a square of four points, and we can simply deal with each of the points
2843 else if (((max_i - min_i + 1) <= 2) .and. ((max_j - min_j + 1) <= 2)) then
2846 x_dest = where_maps_to(i,j,1)
2847 y_dest = where_maps_to(i,j,2)
2849 if (x_dest /= OUTSIDE_DOMAIN) then
2851 ! if (.not. bitarray_test(processed_pts, x_dest-start_x+1, y_dest-start_y+1)) then
2852 if (.not. bitarray_test(new_pts, x_dest-start_x+1, y_dest-start_y+1)) then
2854 dst_array(x_dest,y_dest,k) = 0.
2858 if (present(mask_array) .and. present(mask_relational)) then
2860 ! Ignore masked/missing values
2861 if (tile_array(i,j,k) /= msgval) then
2862 if (mask_relational == ' ' .and. mask_array(i,j) /= maskval) then
2863 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2864 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2865 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2866 else if (mask_relational == '<' .and. mask_array(i,j) >= maskval) then
2867 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2868 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2869 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2870 else if (mask_relational == '>' .and. mask_array(i,j) <= maskval) then
2871 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2872 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2873 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2877 else if (present(mask_array)) then
2879 ! Ignore masked/missing values
2880 if ((tile_array(i,j,k) /= msgval) .and. &
2881 (mask_array(i,j) /= maskval)) then
2882 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2883 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2884 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2889 ! Ignore masked/missing values
2890 if ((tile_array(i,j,k) /= msgval)) then
2891 dst_array(x_dest,y_dest,k) = dst_array(x_dest,y_dest,k) + tile_array(i,j,k)
2892 n(x_dest,y_dest,k) = n(x_dest,y_dest,k) + 1.0
2893 call bitarray_set(new_pts, x_dest-start_x+1, y_dest-start_y+1)
2903 ! Not all corners map to the same grid point, and the rectangle contains more than
2906 center_i = (max_i + min_i)/2
2907 center_j = (max_j + min_j)/2
2909 ! Recursively process lower-left rectangle
2910 call process_continuous_block(tile_array, where_maps_to, &
2911 src_min_x, src_min_y, src_min_z, &
2912 src_max_x, src_max_y, src_max_z, &
2913 min_i, min_j, min_k, &
2914 center_i, center_j, max_k, &
2916 start_x, end_x, start_y, end_y, start_z, end_z, &
2918 new_pts, sr_x, sr_y, msgval, maskval, mask_relational, mask_array)
2920 if (center_i < max_i) then
2921 ! Recursively process lower-right rectangle
2922 call process_continuous_block(tile_array, where_maps_to, &
2923 src_min_x, src_min_y, src_min_z, &
2924 src_max_x, src_max_y, src_max_z, &
2925 center_i+1, min_j, min_k, max_i, &
2928 start_x, end_x, start_y, &
2929 end_y, start_z, end_z, &
2931 new_pts, sr_x, sr_y, msgval, maskval, mask_relational, mask_array)
2934 if (center_j < max_j) then
2935 ! Recursively process upper-left rectangle
2936 call process_continuous_block(tile_array, where_maps_to, &
2937 src_min_x, src_min_y, src_min_z, &
2938 src_max_x, src_max_y, src_max_z, &
2939 min_i, center_j+1, min_k, center_i, &
2942 start_x, end_x, start_y, &
2943 end_y, start_z, end_z, &
2945 new_pts, sr_x, sr_y, msgval, maskval, mask_relational, mask_array)
2948 if (center_i < max_i .and. center_j < max_j) then
2949 ! Recursively process upper-right rectangle
2950 call process_continuous_block(tile_array, where_maps_to, &
2951 src_min_x, src_min_y, src_min_z, &
2952 src_max_x, src_max_y, src_max_z, &
2953 center_i+1, center_j+1, min_k, max_i, &
2956 start_x, end_x, start_y, &
2957 end_y, start_z, end_z, &
2959 new_pts, sr_x, sr_y, msgval, maskval, mask_relational, mask_array)
2963 end subroutine process_continuous_block
2965 end module process_domain_module