9 use iso_c_binding,
only: c_bool, c_int64_t, c_ptr, c_double, c_float
14 public run_ifi, set_ifi_dims, ifi_real_t, write_ifi_debug_files, &
15 first_supported_ifi_hour, last_supported_ifi_hour
17 logical :: write_ifi_debug_files = .false.
18 real,
parameter :: first_supported_ifi_hour = 1
19 real,
parameter :: last_supported_ifi_hour = 21
23 integer,
parameter :: ifi_real_t = c_float
28 real,
parameter :: feet2meters = 0.3048
30 type(IFIConfig) :: ifi_config
31 logical :: have_read_ifi_config = .false.
38 integer :: ifi_mpi_real_kind=-999
39 integer :: row_comm = -999
40 integer :: col_comm = -999
41 integer :: row_comm_rank=-999, col_comm_rank=-999
42 integer :: row_comm_size=-999, col_comm_size=-999
45 integer,
allocatable :: ista_grid(:)
46 integer,
allocatable :: jsta_grid(:)
48 real,
allocatable :: rearrange(:,:)
49 integer,
allocatable :: row_comm_count(:)
50 integer,
allocatable :: row_comm_displ(:)
51 integer,
allocatable :: row_ista(:)
52 integer,
allocatable :: row_iend(:)
53 real,
allocatable :: rearrange_row1d(:)
55 real,
allocatable :: rearrange_row2d(:,:)
56 integer,
allocatable :: col_comm_count(:)
57 integer,
allocatable :: col_comm_displ(:)
58 integer,
allocatable :: col_jsta(:)
59 integer,
allocatable :: col_jend(:)
61 integer,
allocatable :: isize_grid(:)
66 subroutine send_missing_data(ient)
72 use ctlblk_mod,
only: ifi_nflight, ifi_flight_levels
73 use ctlblk_mod,
only: spval, ista, iend, jsta, jend, lm, im, cfld, datapd, fld_info, ifi_flight_levels, jsta_2l, jend_2u,me
74 use rqstfld_mod,
only: iget, iavblfld, lvlsxml, lvls
77 integer,
intent(in) :: ient
82 logical,
save :: wrote_message = .false.
84 if(
size(iget)<ient)
then
88 if(iget(ient)<1 .or. iget(ient)>
size(lvls,2))
then
94 if(k>
size(lvls,1))
then
95 write(0,*)
'ERROR: LVLS is too small to handle ',ifi_nflight,
' vertical levels'
98 if(lvls(k,iget(ient))>0)
then
99 if(.not.wrote_message)
then
101 if(.not.wrote_message.and.me==0)
then
102 write(*,*)
'This post cannot produce IFI icing products because it was not compiled with libIFI.'
103 wrote_message = .true.
109 fld_info(cfld)%ifld = iavblfld(iget(ient))
110 fld_info(cfld)%lvl = k
115 datapd(i-ista+1,j-jsta+1,cfld) = spval
120 end subroutine send_missing_data
125 subroutine set_ifi_dims()
126 use ctlblk_mod,
only: ifi_nflight, ifi_flight_levels
132 if(
allocated(ifi_flight_levels))
then
133 deallocate(ifi_flight_levels)
135 allocate(ifi_flight_levels(ifi_nflight))
137 ifi_flight_levels(i) = 500*i
139 end subroutine set_ifi_dims
145 call send_missing_data(1007)
146 call send_missing_data(1008)
147 call send_missing_data(1009)
148 call send_missing_data(1010)
149 end subroutine run_ifi
159 subroutine make_communicators
160 use ctlblk_mod,
only: jsta, jend, ista, iend, mpi_comm_comp, im, jm
162 use iso_c_binding,
only: c_sizeof
165 integer,
allocatable :: key(:)
166 integer :: size, ierr, local_count, accum, irank, i
167 real(kind=ifi_real_t) :: testreal
169 if(
allocated(jsta_grid))
then
174 if(c_sizeof(testreal)==4)
then
175 ifi_mpi_real_kind=mpi_real4
177 ifi_mpi_real_kind=mpi_real8
181 call mpi_comm_size(mpi_comm_comp,
size,ierr)
182 call mpi_comm_rank(mpi_comm_comp,grid_rank,ierr)
187 if(
allocated(ista_grid))
then
188 deallocate(ista_grid)
189 deallocate(jsta_grid)
190 deallocate(rearrange)
191 deallocate(rearrange_row1d)
192 deallocate(rearrange_row2d)
195 deallocate(row_comm_count)
196 deallocate(row_comm_displ)
199 deallocate(col_comm_count)
200 deallocate(col_comm_displ)
205 allocate(ista_grid(size))
206 allocate(jsta_grid(size))
209 call mpi_allgather(ista,1,mpi_integer,ista_grid,1,mpi_integer,mpi_comm_comp,ierr)
210 call mpi_allgather(jsta,1,mpi_integer,jsta_grid,1,mpi_integer,mpi_comm_comp,ierr)
215 if(ista_grid(i)==-1)
then
216 write(0,*)
'invalid ista_grid ',ista_grid(i)
217 call mpi_abort(mpi_comm_world,1,ierr)
219 if(jsta_grid(i)==-1)
then
220 write(0,*)
'invalid jsta_grid ',jsta_grid(i)
221 call mpi_abort(mpi_comm_world,1,ierr)
223 key(i) = ista_grid(i) + im*(jsta_grid(i)-1)
227 if(all(jsta_grid==jsta_grid(1)))
then
228 row_comm = mpi_comm_comp
230 call mpi_comm_split(mpi_comm_comp,jsta_grid(grid_rank+1),key(grid_rank+1),row_comm,ierr)
232 if(row_comm==mpi_comm_null .or. row_comm==0)
then
233 write(0,*)
'MPI_Comm_split gave MPI_COMM_NULL for row_comm'
234 call mpi_abort(mpi_comm_world,1,ierr)
236 call mpi_comm_rank(row_comm,row_comm_rank,ierr)
237 call mpi_comm_size(row_comm,row_comm_size,ierr)
240 if(all(ista_grid==ista_grid(1)))
then
241 col_comm = mpi_comm_comp
243 call mpi_comm_split(mpi_comm_comp,ista_grid(grid_rank+1),key(grid_rank+1),col_comm,ierr)
245 if(col_comm==mpi_comm_null .or. col_comm==0)
then
246 write(0,*)
'MPI_Comm_split gave MPI_COMM_NULL for col_comm'
247 call mpi_abort(mpi_comm_world,1,ierr)
249 call mpi_comm_rank(col_comm,col_comm_rank,ierr)
250 call mpi_comm_size(col_comm,col_comm_size,ierr)
256 allocate(rearrange(ista:iend,jsta:jend))
257 allocate(rearrange_row1d(im*(jend-jsta+1)))
258 allocate(rearrange_row2d(1:im,jsta:jend))
261 allocate(row_ista(row_comm_size))
262 call mpi_allgather(ista,1,mpi_integer,row_ista,1,mpi_integer,row_comm,ierr)
263 allocate(row_iend(row_comm_size))
264 call mpi_allgather(iend,1,mpi_integer,row_iend,1,mpi_integer,row_comm,ierr)
265 allocate(row_comm_count(row_comm_size))
266 allocate(row_comm_displ(row_comm_size))
267 call get_count_and_displ(row_comm,row_comm_size,(iend-ista+1)*(jend-jsta+1), &
268 row_comm_count,row_comm_displ)
271 allocate(col_jsta(col_comm_size))
272 call mpi_allgather(jsta,1,mpi_integer,col_jsta,1,mpi_integer,col_comm,ierr)
273 allocate(col_jend(col_comm_size))
274 call mpi_allgather(jend,1,mpi_integer,col_jend,1,mpi_integer,col_comm,ierr)
275 allocate(col_comm_count(col_comm_size))
276 allocate(col_comm_displ(col_comm_size))
277 call get_count_and_displ(col_comm,col_comm_size,im*(jend-jsta+1), &
278 col_comm_count,col_comm_displ)
280 end subroutine make_communicators
284 subroutine get_count_and_displ(comm,comm_size,here,counts,displacements)
287 integer,
intent(in) :: comm,comm_size,here
288 integer,
intent(inout) :: counts(comm_size),displacements(comm_size)
289 integer :: accum, ierr, i
292 call mpi_allgather(here,1,mpi_integer,counts,1,mpi_integer,comm,ierr)
297 displacements(i) = accum
298 accum = accum+counts(i)
300 end subroutine get_count_and_displ
304 subroutine find_comm_roots(global_rank,row_root,col_root)
311 integer,
intent(in) :: global_rank
312 integer,
intent(inout) :: row_root,col_root
313 integer :: r, destination_ista, destination_jsta, ierr
317 destination_ista=ista_grid(global_rank+1)
318 destination_jsta=jsta_grid(global_rank+1)
322 if(row_ista(r)==destination_ista)
then
330 if(col_jsta(r)==destination_jsta)
then
339 if(col_root==-1)
then
340 write(0,
'(A,I0)')
'ABORT: Could not find column root rank for rank ',global_rank
341 call mpi_abort(mpi_comm_world,1,ierr)
343 if(row_root==-1)
then
344 write(0,
'(A,I0)')
'ABORT: Could not find row root rank for rank ',global_rank
345 call mpi_abort(mpi_comm_world,1,ierr)
347 end subroutine find_comm_roots
351 subroutine global_gather(local,global,global_rank,ista_local,iend_local,jsta_local,jend_local)
354 use ctlblk_mod,
only: jsta, jend, ista, iend, im, jm
355 use iso_c_binding,
only: c_sizeof
358 real(kind=ifi_real_t),
intent(in) :: local(ista_local:iend_local,jsta_local:jend_local)
359 real(kind=ifi_real_t),
intent(out) :: global(im,jm)
360 integer,
intent(in) :: global_rank,ista_local,iend_local,jsta_local,jend_local
362 integer :: i,j,r,inindex,row_root,col_root, destination_ista, destination_jsta,ni_rank,nj_rank,idxstart, ierr
364 if(col_comm==0 .or. col_comm==mpi_comm_null)
then
365 write(0,*)
'somehow, col_comm became invalid ',col_comm
366 call mpi_abort(mpi_comm_world,1,ierr)
369 if(row_comm==0 .or. row_comm==mpi_comm_null)
then
370 write(0,*)
'somehow, row_comm became invalid ',row_comm
371 call mpi_abort(mpi_comm_world,1,ierr)
375 call find_comm_roots(global_rank,row_root,col_root)
381 rearrange(i,j) = local(i,j)
386 call mpi_gatherv(rearrange,(jend-jsta+1)*(iend-ista+1),ifi_mpi_real_kind, &
387 rearrange_row1d,row_comm_count,row_comm_displ,ifi_mpi_real_kind,row_root,row_comm,ierr)
389 if(row_comm_rank==row_root)
then
394 ni_rank=row_iend(r)-row_ista(r)+1
401 inindex = idxstart + i + ni_rank*j
402 rearrange_row2d(i+row_ista(r),j+jsta) = rearrange_row1d(inindex)
406 idxstart = idxstart + ni_rank*nj_rank
411 call mpi_gatherv(rearrange_row2d,im*(jend-jsta+1),ifi_mpi_real_kind, &
412 global,col_comm_count,col_comm_displ,ifi_mpi_real_kind,col_root,col_comm,ierr)
416 end subroutine global_gather
420 subroutine global_scatter(local,global,global_rank,ista_local,iend_local,jsta_local,jend_local)
424 use ctlblk_mod,
only: jsta, jend, ista, iend, im, jm
425 use iso_c_binding,
only: c_sizeof
428 real(kind=ifi_real_t),
intent(out) :: local(ista_local:iend_local,jsta_local:jend_local)
429 real(kind=ifi_real_t),
intent(in) :: global(im,jm)
430 integer,
intent(in) :: global_rank,ista_local,iend_local,jsta_local,jend_local
432 integer :: i,j,r,outindex,idxstart,ni_rank,nj_rank,col_root,ierr,row_root
434 if(col_comm==0 .or. col_comm==mpi_comm_null)
then
435 write(0,*)
'somehow, col_comm became invalid ',col_comm
436 call mpi_abort(mpi_comm_world,1,ierr)
439 if(row_comm==0 .or. row_comm==mpi_comm_null)
then
440 write(0,*)
'somehow, row_comm became invalid ',row_comm
441 call mpi_abort(mpi_comm_world,1,ierr)
445 call find_comm_roots(global_rank,row_root,col_root)
447 if(row_comm_rank==row_root)
then
450 call mpi_scatterv(global, col_comm_count, col_comm_displ, ifi_mpi_real_kind, &
451 rearrange_row2d ,im*(jend-jsta+1), ifi_mpi_real_kind, col_root, col_comm, ierr)
456 ni_rank=row_iend(r)-row_ista(r)+1
462 outindex = idxstart + i + ni_rank*j
463 rearrange_row1d(outindex) = rearrange_row2d(i+row_ista(r),j+jsta)
467 idxstart = idxstart + ni_rank*nj_rank
472 call mpi_scatterv(rearrange_row1d,row_comm_count,row_comm_displ,ifi_mpi_real_kind, &
473 rearrange,(iend-ista+1)*(jend-jsta+1),ifi_mpi_real_kind,row_root,row_comm,ierr)
480 local(i,j) = rearrange(i,j)
486 end subroutine global_scatter
490 subroutine ifi_check(status,error_message)
491 use mpi,
only: mpi_abort, mpi_comm_world
493 integer(c_int64_t),
intent(in) :: status
494 character(*),
intent(in) :: error_message
499 write(0,
'("IFI Failed: ",A)') trim(error_message)
500 call mpi_abort(mpi_comm_world,1,ierr)
502 end subroutine ifi_check
506 subroutine read_ifi_config()
509 if(.not.have_read_ifi_config)
then
510 call ifi_check(ifi_config%init(),
'read IFI config')
511 have_read_ifi_config = .true.
513 end subroutine read_ifi_config
517 subroutine set_ifi_dims()
518 use ctlblk_mod,
only: ifi_nflight, ifi_flight_levels
523 integer(kind=c_int64_t),
pointer :: config_flight_levels_feet(:)
527 call read_ifi_config()
530 call ifi_check(ifi_config%get_flight_levels_feet(config_flight_levels_feet), &
531 'cannot get flight levels in feet from IFI config')
534 ifi_nflight =
size(config_flight_levels_feet)
535 if(
allocated(ifi_flight_levels))
then
536 deallocate(ifi_flight_levels)
538 allocate(ifi_flight_levels(ifi_nflight))
539 ifi_flight_levels = config_flight_levels_feet
547 end subroutine set_ifi_dims
551 subroutine send_data(vars,name,ient)
552 use ctlblk_mod,
only: spval, jsta, jend, lm, cfld, datapd, fld_info, ifi_flight_levels, jsta_2l, jend_2u, ista, iend, ista_2l, iend_2u
553 use rqstfld_mod,
only: iget, iavblfld, lvlsxml, lvls
556 class(IFIData) :: vars
557 integer,
intent(in) :: ient
558 character(*),
intent(in) :: name
561 integer(c_int64_t) :: &
562 ims,ime,jms,jme,kms,kme, ids,ide,jds,jde,kds,kde, ips,ipe,jps,jpe,kps,kpe
563 real(kind=ifi_real_t),
pointer ::
data(:)
564 logical(c_bool) :: missing_value_is_set
565 real(kind=ifi_real_t) :: missing_value
566 integer :: i,j,k,nj_local,jpad,ilen,jlen,kstartm1,jstartm1,iloc,ndata,ji,ni_local,ipad
568 if(.not. iget(ient)>0)
then
573 data => vars%get_data(trim(name),missing_value_is_set,missing_value, &
574 ims,ime,jms,jme,kms,kme, ids,ide,jds,jde,kds,kde, ips,ipe,jps,jpe,kps,kpe)
575 if(.not.missing_value_is_set)
then
576 missing_value = missing
584 if(nj_local/=jend-jsta+1 .or. jpad/=jsta-jsta_2l .or. ni_local/=iend-ista+1 .or. ipad/=ista-ista_2l)
then
58594
format(
' ',a,
' = ',i0,
', ',i0)
58683
format(
'Warning: ',a,
': IFI output j bounds do not match UPP j bounds')
588 print 94,
'jps,jsta',jps,jsta
589 print 94,
'jpe,jend',jpe,jend
590 print 94,
'jms,jsta_2l',jms,jsta_2l
591 print 94,
'jme,jend_2u',jme,jend_2u
592 print 94,
'jpad,jsta-jsta_2l',jpad,jsta-jsta_2l
593 print 94,
'nj_local,jend-jsta+1',nj_local,jend-jsta+1
594 print 94,
'ips,ista',ips,ista
595 print 94,
'ipe,iend',ipe,iend
596 print 94,
'ims,ista_2l',ims,ista_2l
597 print 94,
'ime,iend_2u',ime,iend_2u
598 print 94,
'ipad,ista-ista_2l',ipad,ista-ista_2l
599 print 94,
'ni_local,iend-ista+1',ni_local,iend-ista+1
604 ndata=ilen*jlen*(kme-kms+1)
608 kstartm1=ilen*jlen*(k-kms)
609 if(lvls(k,iget(ient))>0)
then
611 fld_info(cfld)%ifld = iavblfld(iget(ient))
612 fld_info(cfld)%lvl = k
616 jstartm1 = kstartm1 + (j-jms)*ilen
617 iloc = jstartm1+(i-ims)+1
618 if(iloc<1 .or. iloc>
size(data))
then
619 call ifi_check(-1,
'Internal error: out of bounds in send_data.')
621 if(
data(iloc)==missing_value)
then
622 datapd(i-ips+1,j-jps+1,cfld) = spval
624 datapd(i-ips+1,j-jps+1,cfld) =
data(iloc)
630 end subroutine send_data
634 subroutine gather_ifi(local_buf_c,global_buf_c,receiving_rank)
bind(C)
635 use iso_c_binding,
only: c_float, c_double,c_int64_t,c_f_pointer
637 use ctlblk_mod,
only: me, mpi_comm_comp, jsta, jend, im, jm, icnt, idsp, ista, iend
640 integer(kind=c_int64_t),
value :: receiving_rank
641 type(c_ptr),
value :: global_buf_c, local_buf_c
642 real(kind=ifi_real_t),
pointer :: global_buf(:,:), local_buf(:,:)
644 integer ::
type, iret
646 call c_f_pointer(local_buf_c,local_buf,(/ iend-ista+1, jend-jsta+1 /))
647 if(me==receiving_rank)
then
648 call c_f_pointer(global_buf_c,global_buf,(/ im, jm /))
650 call c_f_pointer(global_buf_c,global_buf,(/ 1,1 /))
653 call gather_for_write(local_buf,global_buf,receiving_rank)
655 end subroutine gather_ifi
659 subroutine gather_for_write(local_buf,global_buf,receiving_rank_c)
bind(C)
660 use iso_c_binding,
only: c_float, c_double,c_int64_t,c_f_pointer
662 use ctlblk_mod,
only: me, mpi_comm_comp, jsta, jend, im, jm, ista, ista, iend
665 integer(kind=c_int64_t),
value :: receiving_rank_c
666 real(kind=ifi_real_t) :: global_buf(:,:), local_buf(:,:)
667 integer :: receiving_rank
668 receiving_rank = receiving_rank_c
669 call global_gather(local_buf,global_buf,receiving_rank,ista,iend,jsta,jend)
670 end subroutine gather_for_write
674 subroutine scatter_ifi(local_buf_c,global_buf_c,sending_rank_c)
bind(C)
675 use iso_c_binding,
only: c_float, c_double, c_int64_t, c_f_pointer
677 use ctlblk_mod,
only: jsta, jend, im, jm, ista, iend, me
680 integer(kind=c_int64_t),
value :: sending_rank_c
681 type(c_ptr),
value :: global_buf_c, local_buf_c
682 real(kind=ifi_real_t),
pointer :: global_buf(:,:), local_buf(:,:)
683 integer :: sending_rank
685 sending_rank=sending_rank_c
687 call c_f_pointer(local_buf_c,local_buf,(/ iend-ista+1, jend-jsta+1 /))
688 if(me==sending_rank)
then
689 call c_f_pointer(global_buf_c,global_buf,(/ im, jm /))
691 call c_f_pointer(global_buf_c,global_buf,(/ 1,1 /))
694 call global_scatter(local_buf,global_buf,sending_rank,ista,iend,jsta,jend)
695 end subroutine scatter_ifi
700 use ctlblk_mod,
only: spval, lm, lp1, im, jsta_2l,jend_2u, itprec, ifhr, ifmin, grib, &
701 jm, jsta,jend, me, num_procs, mpi_comm_comp, ista, iend, ista_2l, iend_2u, dtq2
714 use vrbls2d,
only : &
718 use rqstfld_mod,
only: iget
719 use iso_c_binding,
only: c_bool, c_int64_t
725 use ifi_type_mod,
only: ifi_real_t
727 real(kind=ifi_real_t) :: a(*)
731 type(IFIData) :: hybr_vars, pres_vars, derived_vars, fip_algo_vars, flight_vars, cat_vars
732 type(IFIAlgo) :: algo
733 character(88) :: outfile
735 real(c_double) :: fcst_lead_sec
738 if(ifhr < first_supported_ifi_hour .or. ifhr > last_supported_ifi_hour)
then
7391838
format(
'You requested IFI fields for hour ',i0)
7411839
format(
'IFI fields are only available from hours ',i0,
' through ',i0,
'.')
742 print 1839, first_supported_ifi_hour, last_supported_ifi_hour
744 print 1840,
'Will output missing data for IFI fields for this time.'
745 call send_missing_data(1007)
746 call send_missing_data(1008)
747 call send_missing_data(1009)
748 call send_missing_data(1010)
754 if(grib/=
'grib2' .or. (iget(1007)<=0 .and. iget(1008)<=0 .and. iget(1009)<=0 .and. iget(1010)<=0))
then
756 print
'(A)',
'IFI fields were not requested; skipping IFI'
762 print
'(A)',
'Running libIFI to get icing products.'
763 call ifi_print_copyright()
765 if(write_ifi_debug_files)
then
766 print
'(A)',
'Will output IFI debug files.'
768 print
'(A)',
'Will NOT output IFI debug files.'
772 if(write_ifi_debug_files)
then
773 call make_communicators()
778 call read_ifi_config()
779 call ifi_check(hybr_vars%init(int(1,c_int64_t),int(im,c_int64_t),int(1,c_int64_t),int(jm,c_int64_t),&
780 int(1,c_int64_t),int(lm,c_int64_t),int( ista,c_int64_t),int(iend,c_int64_t),int(jsta,c_int64_t),&
781 int(jend,c_int64_t),int(1,c_int64_t),int(lm,c_int64_t)),&
782 'could not initialize IFI input data structures')
786 call ifi_check(hybr_vars%add_ij_var(
'topography',int(ista_2l,c_int64_t),int(iend_2u,c_int64_t),&
787 int(jsta_2l,c_int64_t),int(jend_2u,c_int64_t), &
788 zint(:,:,lp1)),
'could not send topography to IFI')
790 to_hourly=3600*1000.0/dtq2
794 if(ifi_apcp(i,j)>9e9 .or. ifi_apcp(i,j)<-9e9 .or. ifi_apcp(i,j)==0)
then
795 ifi_apcp(i,j) = avgprec_cont(i,j)*to_hourly
796 else if(itprec>1e-5)
then
797 ifi_apcp(i,j) = ifi_apcp(i,j)/itprec
802 call ifi_check(hybr_vars%add_ij_var(
'APCP_surface',int(ista_2l,c_int64_t),int(iend_2u,c_int64_t),&
803 int(jsta_2l,c_int64_t),int(jend_2u,c_int64_t), &
804 ifi_apcp),
'could not send IFI_APCP to IFI')
805 call ifi_check(hybr_vars%add_ij_var(
'CAPE_surface',int(ista_2l,c_int64_t),int(iend_2u,c_int64_t), &
806 int(jsta_2l,c_int64_t),int(jend_2u,c_int64_t),cape), &
807 'could not send CAPE to IFI')
808 call ifi_check(hybr_vars%add_ij_var(
'CIN_surface',int(ista_2l,c_int64_t),int(iend_2u,c_int64_t), &
809 int(jsta_2l,c_int64_t),int(jend_2u,c_int64_t),cin), &
810 'could not send CIN to IFI')
814 call add_ijk_var(
'HGT',
'zmid',zmid)
815 call add_ijk_var(
'CIMIXR',
'QQI',qqi)
816 call add_ijk_var(
'CLMR',
'QQW',qqw)
817 call add_ijk_var(
'GRLE',
'QQG',qqg)
818 call add_ijk_var(
'PRES',
'pmid',pmid)
819 call add_ijk_var(
'RWMR',
'QQR',qqr)
820 call add_ijk_var(
'SPFH',
'Q',q)
821 call add_ijk_var(
'TMP',
'T',t)
822 call add_ijk_var(
'SNMR',
'QQS',qqs)
823 call add_ijk_var(
'VVEL',
'OMGA',omga)
825308
format(a,
'_',i0,
'.nc')
827 fcst_lead_sec=ifhr*3600.0+ifmin*60.0
829 if(write_ifi_debug_files)
then
830 write(outfile,308)
'hybr_vars',me
831 call write_fip_output(hybr_vars,fcst_lead_sec,trim(outfile),.true.,
'z0',
'z1')
836 call ifi_check(algo%init(ifi_config,fcst_lead_sec,hybr_vars,me,num_procs,mpi_comm_comp), &
837 'could not initialize IFI algorithm')
841 call ifi_check(algo%calc_exner(),
'calc_exner() failed')
842 call ifi_check(algo%hybrid_to_pressure(),
'hybrid_to_pressure() failed')
844 call ifi_check(algo%get_pres_vars(pres_vars),
'get_pres_vars()')
845 if(write_ifi_debug_files)
then
846 write(outfile,308)
'pres_vars',me
847 call write_fip_output(pres_vars,fcst_lead_sec,trim(outfile),.true.,
'z1',
'z0')
850 call ifi_check(algo%discard_hybrid_level_vars(),
'discard_hybrid_level_vars() failed')
852 call ifi_check(algo%derive_fields(),
'derive_fields() failed')
854 call ifi_check(algo%get_derived_vars(derived_vars),
'get_derived_vars()')
855 if(write_ifi_debug_files)
then
856 write(outfile,308)
'derived_vars',me
857 call write_fip_output(derived_vars,fcst_lead_sec,trim(outfile),.false.,
'z1',
'z0')
860 call ifi_check(algo%run_fip_algo(),
'run_fip_algo() failed')
862 call ifi_check(algo%get_fip_algo_vars(pres_vars),
'get_fip_algo_vars()')
863 if(write_ifi_debug_files)
then
864 write(outfile,308)
'fip_algo_vars',me
865 call write_fip_output(pres_vars,fcst_lead_sec,trim(outfile),.false.,
'z1',
'z0')
868 call ifi_check(algo%discard_pressure_level_vars(),
'discard_pressure_level_vars() failed')
869 call ifi_check(algo%discard_derived_vars(),
'discard_derived_vars() failed')
870 call ifi_check(algo%pressure_to_flight(),
'pressure_to_flight() failed')
872 call ifi_check(algo%get_flight_vars(flight_vars),
'get_flight_vars()')
873 if(write_ifi_debug_files)
then
874 write(outfile,308)
'flight_vars',me
875 call write_fip_output(flight_vars,fcst_lead_sec,trim(outfile),.false.,
'z1',
'z0')
878 call ifi_check(algo%discard_fip_algo_vars(),
'discard_fip_algo_vars() failed')
879 call ifi_check(algo%make_icing_category(),
'make_icing_category() failed')
883 call ifi_check(algo%get_cat_vars(cat_vars),
'get_cat_vars()')
885 if(write_ifi_debug_files)
then
886 write(outfile,308)
'cat_vars',me
887 call write_fip_output(cat_vars,fcst_lead_sec,trim(outfile),.false.,
'z1',
'z0')
890 call send_data(cat_vars,
'ICE_PROB',1007)
891 call send_data(cat_vars,
'SLD',1008)
892 call send_data(cat_vars,
'ICE_SEV_CAT',1009)
893 call send_data(cat_vars,
'WMO_ICE_SEV_CAT',1010)
901 subroutine add_ijk_var(ifi_name,upp_name,upp_var)
903 character(len=*),
intent(in) :: ifi_name,upp_name
904 real,
intent(in) :: upp_var(ISTA_2L:IEND_2U,JSTA_2L:JEND_2U,LM)
905 real(kind=ifi_real_t) :: ifi_var(ista_2l:iend_2u,jsta_2l:jend_2u,lm)
912 ifi_var(i,j,k) = upp_var(i,j,lm-k+1)
917 call ifi_check(hybr_vars%add_ijk_var(ifi_name,int(ista_2l,c_int64_t),int(iend_2u,c_int64_t),&
918 int(jsta_2l,c_int64_t),int(jend_2u,c_int64_t),&
919 int(1,c_int64_t),int(lm,c_int64_t),ifi_var), &
920 'could not send '//ifi_name//
' ('//upp_name//
') to IFI')
921 end subroutine add_ijk_var
923 end subroutine run_ifi
927 subroutine find_range(var,count,missing_value_is_set,missing_value,min_not_miss,max_not_miss,all_missing)
930 use ctlblk_mod,
only: mpi_comm_comp
932 real(kind=ifi_real_t),
intent(in) :: var(*)
933 real(kind=ifi_real_t),
intent(in) :: missing_value
934 real(kind=ifi_real_t),
intent(out) :: min_not_miss,max_not_miss
935 integer,
intent(in) :: count
936 logical,
intent(out) :: all_missing
937 logical(c_bool),
intent(in) :: missing_value_is_set
939 real(kind=ifi_real_t) :: minv,maxv,epsilon, global_minv,global_maxv
940 integer :: i,
type,iret
941 real(kind=ifi_real_t),
parameter :: zero = 0
943 print *,
'find range begin'
945 if(missing_value_is_set)
then
946 epsilon = abs(missing_value)*1e-4
947 if(.not. epsilon+1>epsilon)
then
957 if(missing_value_is_set)
then
960 if(.not. abs(var(i)-missing_value)>epsilon .and. var(i)<9e9 .and. var(i)>-9e9)
then
961 minv=min(minv,var(i))
962 maxv=max(maxv,var(i))
968 if(var(i)+1>var(i))
then
969 if(var(i)<9e9 .and. var(i)>-9e9)
then
970 minv=min(minv,var(i))
971 maxv=max(maxv,var(i))
977 if(ifi_real_t==c_double)
then
989 all_missing = global_minv<-9e9 .or. global_minv>9e9 .or. global_maxv<-9e9 .or. global_maxv>9e9
991 print *,
'range min,max = ',global_minv,global_maxv
997 min_not_miss=global_minv
998 max_not_miss=global_maxv
1001 print *,
'find range end'
1002 end subroutine find_range
1006 subroutine nc_check(code,file,message)
1010 integer,
intent(in) :: code
1011 character(*),
intent(in) :: file, message
1014 write(0,93) trim(file),trim(message),trim(nf90_strerror(code)),code
1015 call mpi_abort(mpi_comm_world,1,ierr)
1017 93
format(a,
': ',a,
': ',a,
'(',i0,
')')
1018 end subroutine nc_check
1020 subroutine write_fip_output(ifi_data,fcst_lead_sec,output_file,rename,z2dname,z3dname)
1024 use ctlblk_mod,
only: me
1026 integer,
parameter :: maxname=80
1027 integer,
parameter :: maxvars=999
1028 logical,
intent(in) :: rename
1029 double precision,
intent(in) :: fcst_lead_sec
1030 character(len=*),
intent(in) :: z2dname,z3dname
1032 character(len=maxname) :: varname, outname
1033 integer :: varid, ndims, dims(4), dimids(4), count
1034 real(ifi_real_t),
pointer :: data(:)
1035 integer :: ims,ime,jms,jme,kms,kme
1036 integer :: ids,ide,jds,jde,kds,kde
1037 integer :: ips,ipe,jps,jpe,kps,kpe
1038 logical :: should_dealloc
1039 real(kind=ifi_real_t) :: missing_value
1040 real(kind=ifi_real_t) :: min_not_miss,max_not_miss
1041 logical(c_bool) :: missing_value_is_set
1042 logical :: all_missing
1044 character(len=*),
intent(in) :: output_file
1046 type(IFIData) :: ifi_data
1047 integer(c_int64_t) :: ids,ide, jds,jde, kds,kde
1048 integer(c_int64_t) :: ips,ipe, jps,jpe, kps,kpe
1049 integer(c_int64_t) :: ims,ime, jms,jme, kms,kme
1052 character(len=200) :: varname,nextname
1054 integer :: dimids(4), ncid, ivar, id, nvars, nx0, ny0, nz0, ntime, dims(4)
1055 type(var_info),
target :: var_data(maxvars)
1058 write(*,
'(A,A)') trim(output_file),
': writing IFI debug data'
1061 call ifi_check(ifi_data%get_dims(ids,ide, jds,jde, kds,kde, ips,ipe, jps,jpe, kps,kpe),
"get_dims")
1068 dims = (/nx0,ny0,nz0,ntime/)
1073 do while(ivar<maxvars)
1074 nextname=
'internal_error_nextname_was_not_updated'
1075 call ifi_check(ifi_data%next_varname(varname,nextname),
"next_varname")
1078 if(len_trim(nextname)<1)
then
1084 if(ivar==1 .and. me==0)
then
108559
format(a,
': write to file')
1086 print 59,output_file
1088 call nc_check(nf90_create(output_file,ior(nf90_noclobber,nf90_64bit_offset),ncid),&
1089 output_file,
'nf90_create')
1091 call nc_check(nf90_put_att(ncid,nf90_global,
"fcst_lead_sec",fcst_lead_sec),&
1092 output_file,
"nf90_put_att fcst_lead_sec")
1094 call nc_check(nf90_def_dim(ncid,
"x0",nx0,dimids(1)),output_file,
"nf90_def_dim x0")
1095 call nc_check(nf90_def_dim(ncid,
"y0",ny0,dimids(2)),output_file,
"nf90_def_dim y0")
1096 call nc_check(nf90_def_dim(ncid,z3dname,nz0,dimids(3)),output_file,
"nf90_def_dim "//z3dname)
1097 call nc_check(nf90_def_dim(ncid,
"time",ntime,dimids(4)),output_file,
"nf90_def_dim time")
1100 var_data(ivar)%varname = varname
1101 var_data(ivar)%outname = varname
1102 var_data(ivar)%should_dealloc = .false.
1103 var_data(ivar)%data => read_var(var_data(ivar),trim(varname),var_data(ivar)%should_dealloc)
1105 call set_dims(var_data(ivar),dims,dimids)
1106 var_data(ivar)%varid = def_var(var_data(ivar),rename)
1118 write(*,
"(A,A)") output_file,
': no data to write!'
1122 call nc_check(nf90_enddef(ncid),output_file,
'nf90_enddef')
1124 write(*,*)
'before write loop ',me
112624
format(
' put var ',a)
1127 print 24,trim(var_data(ivar)%varname)
1129 call find_range(var_data(ivar)%data,var_data(ivar)%count, &
1130 var_data(ivar)%missing_value_is_set,var_data(ivar)%missing_value,&
1131 var_data(ivar)%min_not_miss,var_data(ivar)%max_not_miss, &
1132 var_data(ivar)%all_missing)
1133 call write_var(var_data(ivar))
1134 if(var_data(ivar)%should_dealloc)
then
1135 deallocate(var_data(ivar)%data)
1137 nullify(var_data(ivar)%data)
1140 call nc_check(nf90_close(ncid),output_file,
"nf90_close")
1143 subroutine set_dims(var,dims,dimids)
1145 type(var_info),
intent(inout),
target :: var
1146 integer,
intent(in) :: dims(:), dimids(:)
1147 character(len=:),
pointer :: varname
1149 varname=>var%varname(1:len_trim(var%varname))
1158 if(varname==
'x' .or. varname==
'x0')
then
1159 var%dims=(/nx0,1,1,1/)
1160 var%dimids=(/dimids(1),-1,-1,-1/)
1162 else if(varname==
'y' .or. varname==
'y0')
then
1163 var%dims=(/ny0,1,1,1/)
1164 var%dimids=(/dimids(2),-1,-1,-1/)
1166 else if(varname==
'z' .or. varname==
'z0' .or. varname==
'z1' .or. &
1167 varname==
'pressure_levels' .or. varname==
'exner_levels')
then
1168 var%dims=(/nz0,1,1,1/)
1169 var%dimids=(/dimids(3),-1,-1,-1/)
1171 else if(varname==
'latitude' .or. varname==
'longitude')
then
1172 var%dims=(/nx0,ny0,1,1/)
1173 var%dimids=(/dimids(1),dimids(2),-1,-1/)
1175 else if(varname==
'time')
then
1176 var%dims=(/ntime,1,1,1/)
1177 var%dimids=(/dimids(4),-1,-1,-1/)
1179 else if(kme<=kms)
then
1180 var%dims=(/nx0,ny0,ntime,1/)
1181 var%dimids=(/dimids(1),dimids(2),dimids(4),-1/)
1184 var%dims=(/nx0,ny0,nz0,ntime/)
1189 var%count=var%dims(1)*var%dims(2)*var%dims(3)*var%dims(4)
1190 end subroutine set_dims
1192 subroutine write_var(var)
1194 type(var_info),
intent(inout) :: var
1196 integer :: ones(var%ndims), dims(var%ndims)
1197 real(ifi_real_t) :: put(var%count)
1198 integer :: i,j,k,n,ilen,jlen,m,imlen,jmlen
1201 dims = var%dims(1:var%ndims)
1208 call nc_check(nf90_put_var(ncid=ncid,varid=var%varid,values=var%data, &
1209 start=ones,count=dims), &
1210 output_file,
"nf90_put_var "//trim(var%outname))
1212 call nc_check(nf90_put_att(ncid,var%varid,
"min_value",var%min_not_miss), &
1213 output_file,
"nf90_put_att "//trim(var%outname)//
" min_value")
1215 call nc_check(nf90_put_att(ncid,var%varid,
"max_value",var%max_not_miss), &
1216 output_file,
"nf90_put_att "//trim(var%outname)//
" max_value")
1218 end subroutine write_var
1220 integer function def_var(var,rename)
1221 use iso_c_binding,
only: c_float
1224 type(var_info),
intent(inout) :: var
1226 integer :: varid, xtype, dimids(var%ndims)
1227 character(len=100) :: outname
1230 var%outname=var%varname
1231 select case(trim(var%varname))
1233 var%outname =
'ICMR'
1235 var%outname =
'MIXR'
1237 var%outname =
'GRMR'
1238 case(
'CAPE_surface')
1239 var%outname =
'CAPE'
1243 var%outname =
'CLWMR'
1244 case(
'APCP_surface')
1245 var%outname =
'APCP1Hr'
1249 var%ims=ims ; var%ime=ime ; var%jms=jms ; var%jme=jme ; var%kms=kms ; var%kme=kme
1250 var%ids=ids ; var%ide=ide ; var%jds=jds ; var%jde=jde ; var%kds=kds ; var%kde=kde
1251 var%ips=ips ; var%ipe=ipe ; var%jps=jps ; var%jpe=jpe ; var%kps=kps ; var%kpe=kpe
1253 dimids = var%dimids(1:var%ndims)
1255 if(ifi_real_t==c_float)
then
1261 call nc_check(nf90_def_var(ncid,trim(var%outname),xtype,dimids,def_var), &
1262 output_file,
"nf90_def_var "//trim(var%outname))
1264 call nc_check(nf90_put_att(ncid,def_var,
"min_value",var%min_not_miss), &
1265 output_file,
"nf90_put_att "//trim(var%outname)//
" min_value")
1267 call nc_check(nf90_put_att(ncid,def_var,
"max_value",var%max_not_miss), &
1268 output_file,
"nf90_put_att "//trim(var%outname)//
" max_value")
1270 if(var%missing_value_is_set)
then
1271 call nc_check(nf90_put_att(ncid,def_var,
"_FillValue",-9999.0), &
1272 output_file,
"nf90_put_att "//trim(var%outname)//
" _FillValue")
1275 end function def_var
1277 function read_var(var,varname,should_dealloc)
1280 type(var_info),
intent(inout) :: var
1281 real(kind=ifi_real_t),
pointer :: read_var(:)
1282 real(kind=ifi_real_t),
pointer :: local_data_1d(:)
1283 character(len=*),
intent(in) :: varname
1284 logical,
intent(out) :: should_dealloc
1286 real(kind=ifi_real_t),
allocatable :: local_data(:,:),global_data(:,:)
1287 real(kind=ifi_real_t),
pointer :: global_data_1d(:)
1289 integer :: nxny_local,nxny_global,nz,count,i,j,k
1290 integer :: local_ilen,local_jlen,local_klen,local_index
1291 integer :: global_ilen,global_jlen,global_klen,global_index, ierr
1292 type(c_ptr) :: global_cptr,local_cptr
1294 local_data_1d => ifi_data%get_data(trim(varname),var%missing_value_is_set,var%missing_value, &
1295 ims,ime,jms,jme,kms,kme, ids,ide,jds,jde,kds,kde, ips,ipe,jps,jpe,kps,kpe)
1297 global_ilen=ide-ids+1
1298 global_jlen=jde-jds+1
1299 global_klen=kde-kds+1
1300 local_ilen=ipe-ips+1
1301 local_jlen=jpe-jps+1
1302 local_klen=kpe-kps+1
1304 if(.not.
associated(local_data_1d))
then
1305 write(0,38) trim(varname)
130638
format(
"IFI did not produce ",a,
" variable.")
1307 call mpi_abort(mpi_comm_world,1,ierr)
1310 count=global_ilen*global_jlen*global_klen
1312 write(0,39) trim(varname),count
131339
format(
"IFI variable ",a,
" had no data (size=",i0,
")")
1314 call mpi_abort(mpi_comm_world,1,ierr)
1317 if(ids==ide .or. jds==jde)
then
1319 read_var => local_data_1d
1320 should_dealloc = .false.
132440
format(
'var ',a,
' has bad ',a,
'. Got: ',i0,
' but expected: ',i0)
1326 if(global_ilen /= nx0)
then
1327 write(0,40) trim(varname),
'global_ilen',global_ilen,nx0
1328 call mpi_abort(mpi_comm_world,1,ierr)
1331 if(global_jlen /= ny0)
then
1332 write(0,40) trim(varname),
'global_jlen',global_jlen,ny0
1333 call mpi_abort(mpi_comm_world,1,ierr)
1336 if(global_klen/=1 .and. global_klen /= nz0)
then
1337 write(0,40) trim(varname),
'global_klen',global_klen,nz0
1338 call mpi_abort(mpi_comm_world,1,ierr)
1342 allocate(local_data(local_ilen,local_jlen))
1344 allocate(global_data(global_ilen,global_jlen))
1345 allocate(global_data_1d(global_ilen*global_jlen*global_klen))
1347 allocate(global_data(1,1))
1348 allocate(global_data_1d(1))
1354 local_data(i-ips+1,j-jps+1) = local_data_1d( 1 + (i-ims) + ((j-jms) + (k-kms)*(jme-jms+1))*(ime-ims+1) )
1357 call gather_for_write(local_data,global_data,0)
1361 global_data_1d(1 + (i-1) + ((j-1) + (k-kds)*global_jlen)*global_ilen) = &
1373 read_var => local_data_1d
1374 should_dealloc = .false.
1375 deallocate(global_data_1d)
1377 read_var => global_data_1d
1378 should_dealloc = .true.
1381 deallocate(global_data)
1382 deallocate(local_data)
1383 end function read_var
1384 end subroutine write_fip_output
1388end module upp_ifi_mod
subroutine exch_c_float(a)
EXCH_c_float Subroutines that exchange one halo row.