2 ! This module contains general purpose utilities and WRF wrappers because some
3 ! applications require this module to run standalone. No physics here.
4 ! Some are dependent on WRF indexing scheme. Some violate WRF conventions but these
5 ! are not called from the WRF dependent code. Some are not called at all.
8 module module_fr_fire_util
10 ! various method selection parameters
11 ! 1. add the parameter and its static default here
13 ! 2. add copy from config_flags in module_fr_fire_driver%%set_flags
14 ! 3. add a line in Registry.EM to define the variable and set default value
15 ! 4. add the variable and value in namelist.input
19 fire_print_msg=2, & ! print FIRE progress
20 fire_print_file=1, & ! write many files by write_array_m; compile with DEBUG_OUT, do not run in parallel
21 fuel_left_method=1, & ! 1=simple, 2=exact in linear case
22 fuel_left_irl=2, & ! refinement for fuel calculation, must be even
24 boundary_guard=-1, & ! crash if fire gets this many cells to domain boundary, -1=off
25 fire_grows_only=1, & ! fire can spread out only (level set functions may not increase)
26 fire_upwinding=9, & ! upwind normal spread: 1=standard, 2=godunov, 3=eno, 4=sethian, 5=2nd-order, 6=WENO3, 7=WENO5, 8=hybrid WENO3/ENO1, 9=hybrid WENO5/ENO1
27 fire_upwind_split=0, & ! 1=upwind advection separately from normal direction spread
28 fire_test_steps=0, & ! 0=no fire, 1=normal, >1 = do specified number of steps and terminate (testing only)
29 fire_topo_from_atm=1, & ! 0 = expect ZSF set correctly on entry, 1 = populate by interploating from atmosphere
30 fire_advection=0, & ! 0 = fire spread from normal wind/slope (CAWFE), 1 = full speed projected
31 fire_fmc_read=1, & ! fuel moisture: 0 from wrfinput, 1 from namelist.fire, 2 read from file in ideal
32 fire_upwinding_reinit=4, & ! spatial discretization for reinitialization PDE: 1=WENO3, 2=WENO5, 3=hybrid WENO3-ENO1, 4=hybrid WENO5-ENO1
33 fire_lsm_reinit_iter=1, & ! number of iterations for the reinitialization PDE
34 fire_lsm_band_ngp=4, & ! number of grid points around lfn=0 that the higher-order scheme WENO5/WENO3 is used (ENO1 elsewhere), for ire_upwinding=8,9 and fire_upwinding_reinit=3,4 and
35 fire_viscosity_ngp=4 ! number of grid points around lfn=0 where low artificial viscosity is used = fire_viscosity_bg
38 fire_const_time=-1, & ! time from ignition to start constant heat output <0=never
39 fire_const_grnhfx=-1., & ! if both >=0, the constant heat flux to output then
40 fire_const_grnqfx=-1., & ! if both >=0, the constant heat flux to output then
41 fire_atm_feedback=1. , & ! 1 = normal, 0. = one way coupling atmosphere -> fire only
42 fire_viscosity=0.4, & ! artificial viscosity
43 fire_lfn_ext_up=1., & ! 0.=extend level set function at boundary by reflection, 1.=always up
44 fire_lsm_zcoupling_ref=50., & ! Reference height from wich u at fire_wind_hegiht is calculated using a logarithmic profile
45 fire_viscosity_bg=0.4, & ! artificial viscosity in the near-front region
46 fire_viscosity_band=0.5, & ! number of times the hybrid advection band to transition from fire_viscosity_bg to fire_viscosity
47 fire_slope_factor=1.0 ! slope correction factor
50 fire_lsm_reinit=.true., & ! flag to activate reinitialization of level set method
51 fire_lsm_zcoupling=.false. ! flag to activate reference velocity at a different height from fire_wind_height
53 integer, parameter:: REAL_SUM=10, REAL_MAX=20, RNRM_SUM=30, RNRM_MAX=40
58 subroutine interpolate_z2fire(id, & ! for debug output, <= 0 no output
59 ids,ide, jds,jde, & ! atm grid dimensions
63 ifds, ifde, jfds, jfde, & ! fire grid dimensions
64 ifms, ifme, jfms, jfme, &
65 ifts,ifte,jfts,jfte, &
66 ir,jr, & ! atm/fire grid ratio
67 zs, & ! atm grid arrays in
68 zsf,flag_z0) ! fire grid arrays out
71 !*** purpose: interpolate height or any other 2d variable defined at mesh cell centers
74 integer, intent(in)::id, &
75 ids,ide, jds,jde, & ! atm domain bounds
76 ims,ime,jms,jme, & ! atm memory bounds
78 its,ite,jts,jte, & ! atm tile bounds
79 ifds, ifde, jfds, jfde, & ! fire domain bounds
80 ifms, ifme, jfms, jfme, & ! fire memory bounds
81 ifts,ifte,jfts,jfte, & ! fire tile bounds
82 ir,jr ! atm/fire grid refinement ratio
83 real, intent(in), dimension(ims:ime, jms:jme):: zs ! terrain height at atm cell centers & ! terrain height
84 real,intent(out), dimension(ifms:ifme,jfms:jfme)::&
85 zsf ! terrain height fire grid nodes
86 integer,intent(in)::flag_z0
90 real, dimension(its-2:ite+2,jts-2:jte+2):: za ! terrain height
91 integer:: i,j,jts1,jte1,its1,ite1,jfts1,jfte1,ifts1,ifte1,itso,jtso,iteo,jteo
95 jts1=max(jts-1,jds) ! lower loop limit by one less when at end of domain
96 its1=max(its-1,ids) ! ASSUMES THE HALO IS THERE if patch != domain
101 ! copy to local array
106 call continue_at_boundary(1,1,0., & ! do x direction or y direction
107 its-2,ite+2,jts-2,jte+2, & ! memory dims
108 ids,ide,jds,jde, & ! domain dims - winds defined up to +1
109 ips,ipe,jps,jpe, & ! patch dims - winds defined up to +1
110 its1,ite1,jts1,jte1, & ! tile dims
111 itso,jtso,iteo,jteo, &
114 ! interpolate to tile plus strip along domain boundary if at boundary
115 jfts1=snode(jfts,jfds,-1) ! lower loop limit by one less when at end of domain
116 ifts1=snode(ifts,ifds,-1)
117 jfte1=snode(jfte,jfde,+1)
118 ifte1=snode(ifte,ifde,+1)
120 call interpolate_2d( &
121 its-2,ite+2,jts-2,jte+2, & ! memory dims atm grid tile
122 its1-1,ite1+1,jts1-1,jte1+1, & ! where atm grid values set
123 ifms,ifme,jfms,jfme, & ! array dims fire grid
124 ifts1,ifte1,jfts1,jfte1, & ! dimensions fire grid tile
125 ir,jr, & ! refinement ratio
126 real(ids),real(jds),ifds+(ir-1)*0.5,jfds+(jr-1)*0.5, & ! line up by lower left corner of domain
130 if (flag_z0 .eq. 1 ) then
133 zsf(i,j)=max(zsf(i,j),0.001)
138 end subroutine interpolate_z2fire
147 character(len=*), intent(in)::s
148 character(len=128)msg
150 call message(msg,level=0)
151 !$OMP CRITICAL(FIRE_MESSAGE_CRIT)
152 call wrf_error_fatal(msg)
153 !$OMP END CRITICAL(FIRE_MESSAGE_CRIT)
160 subroutine message(s,level)
167 character(len=*), intent(in)::s
168 integer,intent(in),optional::level
170 character(len=128)::msg
171 character(len=118)::t
175 if(present(level))then
178 mlevel=2 ! default message level
180 if(fire_print_msg.ge.mlevel)then
182 !$OMP CRITICAL(FIRE_MESSAGE_CRIT)
184 m=omp_get_thread_num()
186 write(msg,'(a6,i3,a1,a118)')'FIRE:',m,':',t
190 call wrf_message(msg)
193 !$OMP END CRITICAL(FIRE_MESSAGE_CRIT)
195 end subroutine message
202 integer function open_text_file(filename,rw,allow_fail)
204 character(len=*),intent(in):: filename,rw
205 logical, intent(in), optional:: allow_fail
207 !integer, external:: OMP_GET_THREAD_NUM
209 character(len=128):: msg
210 character(len=1)::act
215 ! if (OMP_GET_THREAD_NUM() .ne. 0)then
216 ! call crash('open_input_text_file: called from parallel loop')
219 if(present(allow_fail))then
226 inquire(iounit,opened=op)
229 call crash('open_text_file: Cannot find any available I/O unit')
234 OPEN(iounit, FILE=filename,FORM='FORMATTED',STATUS='OLD',ACTION='READ',IOSTAT=ierr)
236 OPEN(iounit, FILE=filename,FORM='FORMATTED',STATUS='UNKNOWN',ACTION='WRITE',IOSTAT=ierr)
238 write(msg,*)'open_text_file: bad mode ',trim(rw),' for file ',trim(filename)
242 write(msg,*)'Cannot open file ',filename
250 open_text_file=iounit
253 end function open_text_file
260 subroutine set_ideal_coord( dxf,dyf, &
261 ifds,ifde,jfds,jfde, &
262 ifms,ifme,jfms,jfme, &
263 ifts,ifte,jfts,jfte, &
268 real, intent(in)::dxf,dyf
269 integer, intent(in):: &
270 ifds,ifde,jfds,jfde, &
271 ifms,ifme,jfms,jfme, &
273 real, intent(out),dimension(ifms:ifme,jfms:jfme)::fxlong,fxlat
276 ! could we not just as easily get something that
277 ! that looks like a lat/lon
278 ! set fake coordinates, in m
281 ! uniform mesh, lower left domain corner is (0,0)
282 fxlong(i,j)=(i-ifds+0.5)*dxf
283 fxlat (i,j)=(j-jfds+0.5)*dyf
286 end subroutine set_ideal_coord
293 subroutine continue_at_boundary(ix,iy,bias, & ! do x direction or y direction
294 ims,ime,jms,jme, & ! memory dims
295 ids,ide,jds,jde, & ! domain dims
296 ips,ipe,jps,jpe, & ! patch dims
297 its,ite,jts,jte, & ! tile dims
298 itso,iteo,jtso,jteo, & ! tile dims where set
302 ! extend array by one beyond the domain by linear continuation
304 integer, intent(in)::ix,iy ! not 0 = do x or y (1 or 2) direction
305 real,intent(in)::bias ! 0=none, 1.=max
306 integer, intent(in)::ims,ime,jms,jme, & ! memory dims
307 ids,ide,jds,jde, & ! domain dims
308 ips,ipe,jps,jpe, & ! patch dims
309 its,ite,jts,jte ! tile dims
310 integer, intent(out)::itso,jtso,iteo,jteo ! where set
311 real,intent(inout),dimension(ims:ime,jms:jme)::lfn
314 character(len=128)::msg
315 integer::its1,ite1,jts1,jte1
316 integer,parameter::halo=1 ! only 1 domain halo is needed since ENO1 is used near domain boundaries
324 ! go halo width beyond if at patch boundary but not at domain boudnary
325 ! assume we have halo need to compute the value we do not have
326 ! the next thread that would conveniently computer the extended values at patch corners
327 ! besides halo may not transfer values outside of the domain
333 if(its.eq.ips.and..not.its.eq.ids)its1=its-halo
334 if(jts.eq.jps.and..not.jts.eq.jds)jts1=jts-halo
335 if(ite.eq.ipe.and..not.ite.eq.ide)ite1=ite+halo
336 if(jte.eq.jpe.and..not.jte.eq.jde)jte1=jte+halo
337 !$OMP CRITICAL(FIRE_UTIL_CRIT)
338 write(msg,'(a,2i5,a,f5.2)')'continue_at_boundary: directions',ix,iy,' bias ',bias
340 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
344 lfn(ids-1,j)=EX(lfn(ids,j),lfn(ids+1,j))
350 lfn(ide+1,j)=EX(lfn(ide,j),lfn(ide-1,j))
354 !$OMP CRITICAL(FIRE_UTIL_CRIT)
355 write(msg,'(8(a,i5))')'continue_at_boundary: x:',its,':',ite,',',jts,':',jte,' ->',itso,':',iteo,',',jts1,':',jte1
357 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
362 lfn(i,jds-1)=EX(lfn(i,jds),lfn(i,jds+1))
368 lfn(i,jde+1)=EX(lfn(i,jde),lfn(i,jde-1))
372 !$OMP CRITICAL(FIRE_UTIL_CRIT)
373 write(msg,'(8(a,i5))')'continue_at_boundary: y:',its,':',ite,',',jts,':',jte,' ->',its1,':',ite1,',',jtso,':',jteo
374 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
377 ! corners of the domain
378 if(ix.ne.0.and.iy.ne.0)then
379 if(its.eq.ids.and.jts.eq.jds)lfn(ids-1,jds-1)=EX(lfn(ids,jds),lfn(ids+1,jds+1))
380 if(its.eq.ids.and.jte.eq.jde)lfn(ids-1,jde+1)=EX(lfn(ids,jde),lfn(ids+1,jde-1))
381 if(ite.eq.ide.and.jts.eq.jds)lfn(ide+1,jds-1)=EX(lfn(ide,jds),lfn(ide-1,jds+1))
382 if(ite.eq.ide.and.jte.eq.jde)lfn(ide+1,jde+1)=EX(lfn(ide,jde),lfn(ide-1,jde-1))
386 real function EX(a,b)
387 !*** statement function
389 EX=(1.-bias)*(2.*a-b)+bias*max(2.*a-b,a,b) ! extrapolation, max quarded
391 end subroutine continue_at_boundary
394 !*****************************
397 subroutine check_mesh_2dim(ids,ide,jds,jde,ims,ime,jms,jme)
399 integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme
400 character(len=128)msg
401 if(ids<ims.or.ide>ime.or.jds<jms.or.jde>jme)then
402 !$OMP CRITICAL(FIRE_UTIL_CRIT)
403 write(msg,*)'mesh dimensions: ',ids,ide,jds,jde
405 write(msg,*)'memory dimensions:',ims,ime,jms,jme
406 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
408 call crash('check_mesh_2dim: memory dimensions too small')
410 end subroutine check_mesh_2dim
416 subroutine check_mesh_3dim(ids,ide,kds,kde,jds,jde,ims,ime,kms,kme,jms,jme)
417 integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme,kds,kde,kms,kme
418 if(ids<ims.or.ide>ime.or.jds<jms.or.jde>jme.or.kds<kms.or.kde>kme) then
419 call crash('memory dimensions too small')
421 end subroutine check_mesh_3dim
427 subroutine sum_2d_cells( &
428 ims2,ime2,jms2,jme2, &
429 its2,ite2,jts2,jte2, &
431 ims1,ime1,jms1,jme1, &
432 its1,ite1,jts1,jte1, &
437 ! sum cell values in mesh2 to cell values of coarser mesh1
440 ! the dimensions are in cells, not nodes!
442 integer, intent(in)::its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
443 real, intent(out)::v1(ims1:ime1,jms1:jme1)
444 integer, intent(in)::its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
445 real, intent(in)::v2(ims2:ime2,jms2:jme2)
448 integer:: i1,i2,j1,j2,ir,jr,isz1,isz2,jsz1,jsz2,ioff,joff,ibase,jbase
450 character(len=128)msg
454 !check mesh dimensions and domain dimensions
455 call check_mesh_2dim(its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1)
456 call check_mesh_2dim(its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2)
465 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)then
466 call message('all mesh sizes must be positive')
470 ! compute mesh ratios
474 if(isz2.ne.isz1*ir .or. jsz2.ne.jsz1*jr)then
475 call message('input mesh size must be multiple of output mesh size')
482 jbase=jts2+jr*(j1-jts1)
484 ibase=its2+ir*(i1-its1)
500 !$OMP CRITICAL(FIRE_UTIL_CRIT)
501 write(msg,91)its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
503 write(msg,91)its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
505 write(msg,92)'input mesh size:',isz2,jsz2
507 91 format('dimensions: ',8i8)
508 write(msg,92)'output mesh size:',isz1,jsz1
511 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
512 call crash('module_fr_spread_util:sum_mesh_cells: bad mesh sizes')
514 end subroutine sum_2d_cells
518 ! module_fr_fire_util%%interpolate_2d
519 subroutine interpolate_2d( &
520 ims2,ime2,jms2,jme2, & ! array coarse grid
521 its2,ite2,jts2,jte2, & ! dimensions coarse grid
522 ims1,ime1,jms1,jme1, & ! array coarse grid
523 its1,ite1,jts1,jte1, & ! dimensions fine grid
524 ir,jr, & ! refinement ratio
525 rip2,rjp2,rip1,rjp1, & ! (rip2,rjp2) on grid 2 lines up with (rip1,rjp1) on grid 1
526 v2, & ! in coarse grid
531 ! interpolate nodal values in mesh2 to nodal values in mesh1
532 ! interpolation runs over the mesh2 region its2:ite2,jts2:jte2
533 ! only the part of mesh 1 in the region its1:ite1,jts1:jte1 is modified
537 integer, intent(in)::its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
538 integer, intent(in)::its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
539 integer, intent(in)::ir,jr
540 real,intent(in):: rjp1,rip1,rjp2,rip2
541 real, intent(out)::v1(ims1:ime1,jms1:jme1)
542 real, intent(in)::v2(ims2:ime2,jms2:jme2)
545 integer:: i1,i2,j1,j2,is,ie,js,je
548 intrinsic::ceiling,floor
552 !check mesh dimensions and domain dimensions
553 call check_mesh_2dim(its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1)
554 call check_mesh_2dim(its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2)
556 ! compute mesh ratios
560 do j2=jts2,jte2-1 ! loop over mesh 2 cells
561 rjo=rjp1+jr*(j2-rjp2) ! mesh 1 coordinate of the mesh 2 patch start
562 js=max(jts1,ceiling(rjo)) ! lower bound of mesh 1 patch for this mesh 2 cell
563 je=min(jte1,floor(rjo)+jr) ! upper bound of mesh 1 patch for this mesh 2 cell
565 rio=rip1+ir*(i2-rip2)
566 is=max(its1,ceiling(rio))
567 ie=min(ite1,floor(rio)+ir)
571 ! in case mesh 1 node lies on the boundary of several mesh 2 cells
572 ! the result will be written multiple times with the same value
573 ! up to a rounding error
575 !print *,'coarse ',i2,j2,'to',i2+1,j2+1,' fine ',is,js,' to ',ie,je
577 (1-tx)*(1-ty)*v2(i2,j2) &
578 + (1-tx)*ty *v2(i2,j2+1) &
579 + tx*(1-ty)*v2(i2+1,j2) &
580 + tx*ty *v2(i2+1,j2+1)
581 !print *,'coarse ',i2,j2,' fine ',i1,j1, ' offset ',io,jo,' weights ',tx,ty, &
582 ! 'in ',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2),v2(i2+1,j2+1),' out ',v1(i1,j1)
583 !write(*,'(a,2i5,a,2f8.2,a,4f8.2,a,2i5,a,f8.2)') &
584 !'coarse ',i2,j2,' coord',rio,rjo,' val',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2),v2(i2+1,j2+1),&
585 !' fine ',i1,j1,' out ',v1(i1,j1)
591 end subroutine interpolate_2d
597 subroutine interpolate_2d_cells2cells( &
598 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
599 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
603 ! interpolate nodal values in mesh2 to nodal values in mesh1
604 ! input mesh 2 is coarse output mesh 1 is fine
608 integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
609 real, intent(out)::v1(ims1:ime1,jms1:jme1)
610 integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
611 real, intent(in)::v2(ims2:ime2,jms2:jme2)
613 ! Example with mesh ratio=4. | = cell boundary, x = cell center
615 ! mesh2 |-------x-------|-------x-------|
616 ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|
620 integer:: ir,jr,isz1,isz2,jsz1,jsz2,ip,jp,ih,jh
621 character(len=128)msg
625 !check mesh dimensions and domain dimensions
626 call check_mesh_2dim(ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1)
627 call check_mesh_2dim(ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2)
636 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)goto 9
637 if(mod(isz1,isz2).ne.0.or.mod(jsz1,jsz2).ne.0)goto 9
639 ! compute mesh ratios
643 ! mesh2 |-------x-------|-------x-------|
644 ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|
646 ! mesh2 |-----x-----|-----x-----| rx=3
647 ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|
653 ! mesh2 |---x---|---x---| rx=2
654 ! mesh1 |-x-|-x-|-x-|-x-|
661 ! offset of the last node in the 1st half of the cell
664 ! 0 if coarse cell center coincides with fine, 1 if not
668 call interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
669 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
670 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
675 !$OMP CRITICAL(FIRE_UTIL_CRIT)
676 write(msg,91)ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
678 write(msg,91)ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
680 write(msg,92)'input mesh size:',isz2,jsz2
682 91 format('dimensions: ',8i8)
683 write(msg,92)'output mesh size:',isz1,jsz1
686 call crash("module_fr_fire_util:interpolate_2dmesh_cells: bad mesh sizes")
687 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
688 end subroutine interpolate_2d_cells2cells
694 subroutine interpolate_2d_cells2nodes( &
695 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
696 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
700 ! interpolate nodal values in mesh2 to nodal values in mesh1
701 ! input mesh 2 is coarse output mesh 1 is fine
705 integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
706 real, intent(out)::v1(ims1:ime1,jms1:jme1)
707 integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
708 real, intent(in)::v2(ims2:ime2,jms2:jme2)
710 ! Example with mesh ratio=4. | = cell boundary, x = cell center
712 ! mesh2 |-------x-------|-------x-------|
713 ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x
717 integer:: ir,jr,isz1,isz2,jsz1,jsz2,ip,jp,ih,jh
718 character(len=128)msg
722 !check mesh dimensions and domain dimensions
723 call check_mesh_2dim(ids1,ide1+1,jds1,jde1+1,ims1,ime1,jms1,jme1)
724 call check_mesh_2dim(ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2)
733 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)goto 9
734 if(mod(isz1,isz2).ne.0.or.mod(jsz1,jsz2).ne.0)goto 9
736 ! compute mesh ratios
740 ! mesh2 |-------x-------|-------x-------|
741 ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x
743 ! mesh2 |-----x-----|-----x-----| rx=3
744 ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x
746 ! mesh2 |---x---|---x---| rx=2
747 ! mesh1 x-|-x-|-x-|-x-|-x
749 ! offset of the last node in the 1st half of the cell
752 ! 0 if coarse cell center coincides with fine, 1 if not
757 call interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
758 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
759 ids1,ide1+1,jds1,jde1+1,ims1,ime1,jms1,jme1,v1 ) ! out
764 !$OMP CRITICAL(FIRE_UTIL_CRIT)
765 write(msg,91)ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
767 write(msg,91)ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
769 write(msg,92)'input mesh size:',isz2,jsz2
771 91 format('dimensions: ',8i8)
772 write(msg,92)'output mesh size:',isz1,jsz1
775 call crash("module_fr_fire_util:interpolate_2d_cells2nodes: bad mesh sizes")
776 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
777 end subroutine interpolate_2d_cells2nodes
782 subroutine interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
783 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
784 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
786 !*** EXCEPTION: THIS SUBROUTINE IS NEITHER CELL NOR NODE BASED.
788 integer, intent(in)::ip,jp,ih,jh,ir,jr
789 integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
790 real, intent(out)::v1(ims1:ime1,jms1:jme1)
791 integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
792 real, intent(in)::v2(ims2:ime2,jms2:jme2)
794 real:: tx,ty,rx,ry,half,xoff,yoff
795 integer:: i1,i2,j1,j2,ioff,joff
804 ! the inside, ids1+ih:ide1-ih,jds1+jh:jde1-jh
805 do j2=jds2,jde2-1 ! interpolate from nodes j2 and j2+1
809 ! compute fine mesh index
810 i1=ioff+(ih+ids1)+ir*(i2-ids2)
811 j1=joff+(jh+jds1)+jr*(j2-jds2)
817 (1-tx)*(1-ty)*v2(i2,j2) &
818 + (1-tx)*ty *v2(i2,j2+1) &
819 + tx*(1-ty)*v2(i2+1,j2) &
820 + tx*ty *v2(i2+1,j2+1)
821 !write(*,'(3(a,2i5),a,2f7.4)')'coarse ',i2,j2,' fine ',i1,j1, &
822 ! ' offset ',ioff,joff,' weights ',tx,ty
823 !write(*,'(a,4f7.4,a,f7.4)')'in ',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2), &
824 ! v2(i2+1,j2+1),' out ',v1(i1,j1)
830 ! extend to the boundary strips from the nearest known
831 do ioff=0,ih-1 ! top and bottom strips
834 j1=joff+(jh+jds1)+jr*(j2-jds2)
838 v1(ids1+ioff,j1)=(1-ty)*v2(ids2,j2)+ty*v2(ids2,j2+1)
839 v1(ide1-ioff,j1)=(1-ty)*v2(ide2,j2)+ty*v2(ide2,j2+1)
843 do joff=0,jh-1 ! left and right strips
846 i1=ioff+(ih+ids1)+ir*(i2-ids2)
850 v1(i1,jds1+joff)=(1-tx)*v2(i2,jds2)+tx*v2(i2+1,jds2)
851 v1(i1,jde1-joff)=(1-tx)*v2(i2,jde2)+tx*v2(i2+1,jde2)
855 ! extend to the 4 corner squares from the nearest known
858 v1(ids1+ioff,jds1+joff)=v2(ids2,jds2)
859 v1(ide1-ioff,jds1+joff)=v2(ide2,jds2)
860 v1(ids1+ioff,jde1-joff)=v2(ids2,jde2)
861 v1(ide1-ioff,jde1-joff)=v2(ide2,jde2)
864 end subroutine interpolate_2d_w
870 real function interp(ids,ide,jds,jde,ims,ime,jms,jme,x,y,v)
873 ! general interpolation in a rectangular
877 integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme
878 real, intent(in)::x,y,v(ims:ime,jms:jme)
879 ! the mesh is cell based so the used dimension of v is ids:ide+1,jds:jde+1
882 intrinsic floor,min,max
890 ! indices of the lower left corner of the cell in the mesh that contains (x,y)
892 i=max(min(i,ide),ids)
894 j=max(min(j,jde),jds)
900 ! interpolate the values
902 (1-tx)*(1-ty)*v(i,j) &
903 + tx*(1-ty) *v(i+1,j) &
904 + (1-tx)*ty *v(i,j+1) &
907 !print *,'x,y=',x,y,'i1,i2=',i1,j1,'tx,ty=',tx,ty,' interp=',interp
910 subroutine meshdiffc_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
911 ims1,ime1,jms1,jme1, & ! memory dimensiuons
912 dx,dy, & ! mesh spacing
914 diffCx,diffCy) ! output
918 ! central differences on a 2d mesh
922 integer, intent(in)::ids,ide,jds,jde,ims1,ime1,jms1,jme1
923 real, intent(in):: dx,dy
924 real, intent(in), dimension(ims1:ime1,jms1:jme1):: lfn
925 real, intent(out), dimension(ims1:ime1,jms1:jme1):: diffCx,diffCy
929 real, dimension(ims1:ime1,jms1:jme1):: diffLx,diffRx,diffLy,diffRy
931 ! get one-sided differences; dumb but had that already...
932 call meshdiff_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
933 ims1,ime1,jms1,jme1, & ! dimensions of lfn
934 dx,dy, & ! mesh spacing
936 diffLx,diffRx,diffLy,diffRy) ! output
941 diffCx(i,j)=0.5*(diffLx(i,j) + diffRx(i,j))
942 diffCy(i,j)=0.5*(diffLy(i,j) + diffRy(i,j))
945 end subroutine meshdiffc_2d
947 subroutine meshdiff_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
948 ims1,ime1,jms1,jme1, & ! dimensions of lfn
949 dx,dy, & ! mesh spacing
951 diffLx,diffRx,diffLy,diffRy) ! output
955 ! one-sided differences on a 2d mesh
959 integer, intent(in)::ids,ide,jds,jde,ims1,ime1,jms1,jme1
960 real, intent(in):: dx,dy
961 real, intent(in), dimension(ims1:ime1,jms1:jme1):: lfn
962 real, intent(out), dimension(ims1:ime1,jms1:jme1):: diffLx,diffRx,diffLy,diffRy
970 call check_mesh_2dim(ids,ide+1,jds,jde+1,ims1,ime1,jms1,jme1)
972 ! the bulk of the work
975 tmpx = (lfn(i+1,j)-lfn(i,j))/dx
978 tmpy = (lfn(i,j+1)-lfn(i,j))/dy
982 ! missing values - put there the other one
983 diffLx(ids,j) = diffLx(ids+1,j)
984 diffRx(ide+1,j)= diffRx(ide,j)
987 ! j=jde+1 from above loop
989 tmpx = (lfn(i+1,j)-lfn(i,j))/dx
993 ! i=ide+1 from above loop
995 tmpy = (lfn(i,j+1)-lfn(i,j))/dy
999 ! missing values - put there the other one
1000 ! j=jde+1 from above loop, j=jds:jde done before in main bulk loop
1001 diffLx(ids,j) = diffLx(ids+1,j)
1002 diffRx(ide+1,j) = diffRx(ide,j)
1004 diffLy(i,jds) = diffLy(i,jds+1)
1005 diffRy(i,jde+1) = diffRy(i,jde)
1008 end subroutine meshdiff_2d
1013 real pure function sum_2darray( its,ite,jts,jte, &
1016 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
1017 real, intent(in)::a(ims:ime,jms:jme)
1028 end function sum_2darray
1030 real pure function max_2darray( its,ite,jts,jte, &
1033 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
1034 real, intent(in)::a(ims:ime,jms:jme)
1045 end function max_2darray
1047 subroutine print_2d_stats_vec(ips,ipe,jps,jpe, &
1051 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme
1052 real, intent(in), dimension(ims:ime,jms:jme)::ax,ay
1053 character(len=*),intent(in)::name
1056 real:: avg_a,max_a,min_a
1057 character(len=25)::id
1059 call print_2d_stats(ips,ipe,jps,jpe, &
1062 call print_2d_stats(ips,ipe,jps,jpe, &
1070 t=sqrt(ax(i,j)**2+ay(i,j)**2)
1076 avg_a = avg_a/((ipe-ips+1)*(jpe-jps+1))
1077 call print_stat_line(id//'/sz',ips,ipe,jps,jpe,min_a,max_a,avg_a)
1078 end subroutine print_2d_stats_vec
1081 subroutine print_stat_line(name,ips,ipe,jps,jpe,min_a,max_a,avg_a)
1082 !*** encapsulate line with statistics
1085 integer, intent(in)::ips,ipe,jps,jpe
1086 character(len=*),intent(in)::name
1087 real,intent(in)::min_a,max_a,avg_a
1089 character(len=128)::msg
1090 character(len=24)::id
1091 if(fire_print_msg.eq.0)return
1093 !$OMP CRITICAL(FIRE_UTIL_CRIT)
1094 write(msg,'(a,4i4,3g11.3)')id,ips,ipe,jps,jpe,min_a,max_a,avg_a
1095 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
1097 if(.not.avg_a.eq.avg_a)call crash('NaN detected')
1098 end subroutine print_stat_line
1101 subroutine print_3d_stats_by_slice(ips,ipe,kps,kpe,jps,jpe, &
1102 ims,ime,kms,kme,jms,jme, &
1105 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme,kms,kme,kps,kpe
1106 real, intent(in)::a(ims:ime,kms:kme,jms:jme)
1107 character(len=*),intent(in)::name
1109 character(len=128)::msg
1111 ! print 3d stats for each horizontal slice separately
1112 !$OMP CRITICAL(SFIRE_UTIL_CRIT)
1113 write(msg,'(i2,1x,a)')k,name
1114 !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
1115 call print_3d_stats(ips,ipe,k,k,jps,jpe, &
1116 ims,ime,kms,kme,jms,jme, &
1119 end subroutine print_3d_stats_by_slice
1122 subroutine print_3d_stats(ips,ipe,kps,kpe,jps,jpe, &
1123 ims,ime,kms,kme,jms,jme, &
1126 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme,kms,kme,kps,kpe
1127 real, intent(in)::a(ims:ime,kms:kme,jms:jme)
1128 character(len=*),intent(in)::name
1130 real:: avg_a,max_a,min_a,t,aa,bb
1131 character(len=128)::msg
1132 ! if(fire_print_msg.eq.0)return
1133 ! check for nans in any case
1142 if(bb.eq.bb.and.fire_print_msg.eq.0)return
1151 if(aa.ne.aa.or..not.aa.le.t.or..not.aa.ge.-t)goto 9
1158 if(bb.ne.bb)goto 10 ! should never happen
1159 if(fire_print_msg.eq.0)return
1160 avg_a = avg_a/((ipe-ips+1)*(jpe-jps+1)*(kpe-kps+1))
1161 call print_stat_line(name,ips,ipe,jps,jpe,min_a,max_a,avg_a)
1164 !$OMP CRITICAL(FIRE_UTIL_CRIT)
1165 write(msg,1)name,i,k,j,aa
1167 1 format(a30,'(',i6,',',i6,',',i6,') = ',g13.5)
1168 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
1169 call print_stat_line(name,ips,ipe,jps,jpe,aa,aa,aa)
1171 msg='Invalid floating point number detected in '//name
1173 10 msg='NaN detected in '//name
1175 end subroutine print_3d_stats
1177 subroutine print_2d_stats(ips,ipe,jps,jpe, &
1181 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme
1182 real, intent(in)::a(ims:ime,jms:jme)
1183 character(len=*),intent(in)::name
1184 !!character(len=128)::msg
1185 !if(fire_print_msg.eq.0)return
1186 call print_3d_stats(ips,ipe,1,1,jps,jpe, &
1187 ims,ime,1,1,jms,jme, &
1189 !!write(msg,'(2a,z16)')name,' address =',loc(a)
1191 end subroutine print_2d_stats
1193 real pure function avg_2darray( its,ite,jts,jte, &
1196 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
1197 real, intent(in)::a(ims:ime,jms:jme)
1200 avg_2darray = sum_2darray( its,ite,jts,jte, &
1202 a)/((ite-its+1)*(jte-jts+1))
1203 end function avg_2darray
1205 real pure function avg_2darray_vec( its,ite,jts,jte, &
1208 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
1209 real, intent(in), dimension(ims:ime,jms:jme):: ax,ay
1216 t=t+sqrt(ax(i,j)**2+ay(i,j)**2)
1219 t = t/((ite-its+1)*(jte-jts+1))
1221 end function avg_2darray_vec
1224 subroutine print_array(its,ite,jts,jte, &
1229 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,id
1230 real, intent(in), dimension(ims:ime,jms:jme):: a
1231 character(len=*),intent(in)::name
1234 character(len=128)::msg
1236 !$OMP CRITICAL(FIRE_UTIL_CRIT)
1237 write(msg,*)name,' start ',id,' dim ',its,ite,jts,jte
1241 write(msg,*)i,j,a(i,j)
1245 write(msg,*)name,' end ',id
1247 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
1248 end subroutine print_array
1250 subroutine write_array_m(its,ite,jts,jte, &
1255 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,id
1256 real, intent(in), dimension(ims:ime,jms:jme):: a
1257 character(len=*),intent(in)::name
1259 call write_array_m3(its,ite,1,1,jts,jte, &
1260 ims,ime,1,1,jms,jme, &
1262 end subroutine write_array_m
1265 subroutine write_array_m3(its,ite,kts,kte,jts,jte, &
1266 ims,ime,kms,kme,jms,jme, &
1272 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,kts,kte,kms,kme,id
1273 real, intent(in), dimension(ims:ime,kms:kme,jms:jme):: a
1274 character(len=*),intent(in)::name
1276 integer i,j,k,iu,ilen,myproc,nprocs
1278 character(len=128)::fname,msg
1280 if(fire_print_file.eq.0.or.id.le.0)return
1281 call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
1282 call wrf_get_nproc (nprocs)
1283 call wrf_get_myproc(myproc)
1285 !$OMP CRITICAL(FIRE_UTIL_CRIT)
1287 write(fname,3)name,'_',id,'.txt'
1289 write(fname,4)name,'_',id,'.',myproc,'.txt'
1294 inquire(unit=i,opened=op)
1295 if(.not.op.and.iu.le.0)iu=i
1297 if(iu.gt.0)open(iu,file=trim(fname),form='formatted',status='unknown')
1299 if(iu.le.0)call crash('write_array_m: cannot find available fortran unit')
1301 write(iu,1)real(its)
1302 write(iu,1)real(ite)
1303 write(iu,1)real(jts)
1304 write(iu,1)real(jte)
1305 write(iu,1)real(kts)
1306 write(iu,1)real(kte)
1307 write(iu,1)(((a(i,k,j),i=its,ite),j=jts,jte),k=kts,kte)
1309 write(msg,2)name,'(',its,':',ite,',',jts,':',jte,',', &
1310 kts,':',kte,') -> ',trim(fname)
1311 !$OMP END CRITICAL(FIRE_UTIL_CRIT)
1316 2 format(2a,3(i5,a,i5,a),2a)
1317 3 format(a,a,i8.8,a)
1318 4 format(a,a,i8.8,a,i4.4,a)
1321 end subroutine write_array_m3
1325 subroutine read_array_2d_integer(filename,ia,its,ite,jts,jte,ims,ime,jms,jme)
1327 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
1328 integer, intent(out), dimension(ims:ime,jms:jme):: ia
1329 character(len=*),intent(in)::filename
1331 real, allocatable, dimension(:,:)::a
1334 character(len=256)msg
1336 allocate(a(ims:ime,jms:jme))
1337 call read_array_2d_real(filename,a,its,ite,jts,jte,ims,ime,jms,jme)
1343 write(6,*)'Reading file ',trim(filename)
1344 write(6,*)'value at position ',i,j,' cannot be converted to integer'
1345 write(6,*)'read ',a(i,j),' converted as',ia(i,j),' converted as ',r
1346 msg=trim(filename)//' is not integer file'
1351 end subroutine read_array_2d_integer
1355 subroutine read_array_2d_real(filename,a,its,ite,jts,jte,ims,ime,jms,jme)
1360 !*** purpose: read a 2D array from a text file
1361 ! file format: line 1: array dimensions ni,nj
1362 ! following lines: one row of a at a time
1363 ! each row may be split between several lines
1365 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
1366 real, intent(out), dimension(ims:ime,jms:jme):: a
1367 character(len=*),intent(in)::filename
1369 integer i,j,ni,nj,mi,mj,nprocs,myproc,mythread,iu
1371 character(len=128)::fname,msg
1374 call wrf_get_nproc (nprocs)
1375 call wrf_get_myproc( myproc )
1378 mythread=omp_get_thread_num()
1380 if(nprocs.ne.1.or.myproc.ne.0.or.mythread.ne.0) &
1381 call crash('read_array_2d: parallel execution not supported')
1386 write(msg,2)'reading array size ',mi,mj,' from file ',trim(filename)
1390 ! check array index overflow
1391 call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
1393 ! find available unit
1396 inquire(unit=i,opened=op)
1397 if(.not.op.and.iu.le.0)iu=i
1399 if(iu.le.0)call crash('read_array_2d: cannot find available fortran unit')
1401 if(iu.gt.0)open(iu,file=filename,form='formatted',status='old',err=9)
1404 read(iu,*,err=10)ni,nj
1405 if(ni.ne.mi.or.nj.ne.mj)then
1406 write(msg,'(a,2i6,a,2i6)')'Array dimensions',ni,nj,' in the input file should be ',mi,mj
1411 read(iu,*,err=10)(a(i,j),j=jts,jte)
1416 9 msg='Error opening file '//trim(filename)
1418 10 msg='Error reading file '//trim(filename)
1420 11 msg='Error closing file '//trim(filename)
1422 end subroutine read_array_2d_real
1427 ! general conditional expression
1428 pure integer function ifval(l,i,j)
1430 logical, intent(in)::l
1431 integer, intent(in)::i,j
1439 ! function to go beyond domain boundary if tile is next to it
1440 pure integer function snode(t,d,i)
1442 integer, intent(in)::t,d,i
1450 subroutine print_chsum( id, &
1451 ims,ime,kms,kme,jms,jme, & ! memory dims
1452 ids,ide,kds,kde,jds,jde, & ! domain dims
1453 ips,ipe,kps,kpe,jps,jpe, & ! patch or tile dims
1454 istag,kstag,jstag, &
1458 USE module_dm , only : wrf_dm_bxor_integer
1461 integer, intent(in):: id, &
1462 ims,ime,kms,kme,jms,jme, & ! memory dims
1463 ids,ide,kds,kde,jds,jde, & ! domain dims
1464 ips,ipe,kps,kpe,jps,jpe, & ! patch dims
1466 real, intent(in),dimension(ims:ime,kms:kme,jms:jme)::a
1467 character(len=*)::name
1470 !external, logical:: omp_in_parallel
1471 !external, integer:: omp_get_thread_num
1476 integer::i,j,k,n,ipe1,jpe1,kpe1,iel,thread,is,js,ks
1477 integer, save::psum,gsum
1479 equivalence(rel,iel)
1480 character(len=256)msg
1482 if(fire_print_msg.le.0)return
1484 ipe1=ifval(ipe.eq.ide.and.istag.ne.0,ipe+1,ipe)
1485 kpe1=ifval(kpe.eq.kde.and.kstag.ne.0,kpe+1,kpe)
1486 jpe1=ifval(jpe.eq.jde.and.jstag.ne.0,jpe+1,jpe)
1487 is=ifval(istag.ne.0,1,0)
1488 ks=ifval(kstag.ne.0,1,0)
1489 js=ifval(jstag.ne.0,1,0)
1501 ! get process sum over all threads
1504 !thread=omp_get_thread_num()
1506 if(thread.eq.0)psum=0
1508 !$OMP CRITICAL(CHSUM)
1509 psum=ieor(psum,lsum)
1510 !$OMP END CRITICAL(CHSUM)
1513 ! get global sum over all processes
1516 gsum = wrf_dm_bxor_integer ( psum )
1520 write(msg,1)id,name,ids,ide+is,kds,kde+ks,jds,jde+js,gsum
1521 1 format(i6,1x,a10,' dims',6i5,' chsum ',z8.8)
1525 end subroutine print_chsum
1528 real function fun_real(fun, &
1529 ims,ime,kms,kme,jms,jme, & ! memory dims
1530 ids,ide,kds,kde,jds,jde, & ! domain dims
1531 ips,ipe,kps,kpe,jps,jpe, & ! patch or tile dims
1532 istag,kstag,jstag, & ! staggering
1536 USE module_dm , only : wrf_dm_sum_real , wrf_dm_max_real
1539 integer, intent(in):: fun, &
1540 ims,ime,kms,kme,jms,jme, & ! memory dims
1541 ids,ide,kds,kde,jds,jde, & ! domain dims
1542 ips,ipe,kps,kpe,jps,jpe, & ! patch dims
1543 istag,kstag,jstag ! staggering
1544 real, intent(in),dimension(ims:ime,kms:kme,jms:jme)::a,b
1548 integer::i,j,k,n,ipe1,jpe1,kpe1,iel,thread,is,js,ks
1549 real, save::psum,gsum
1551 logical:: dosum,domax
1552 character(len=256)msg
1554 ipe1=ifval(ipe.eq.ide.and.istag.ne.0,ipe+1,ipe)
1555 kpe1=ifval(kpe.eq.kde.and.kstag.ne.0,kpe+1,kpe)
1556 jpe1=ifval(jpe.eq.jde.and.jstag.ne.0,jpe+1,jpe)
1557 is=ifval(istag.ne.0,1,0)
1558 ks=ifval(kstag.ne.0,1,0)
1559 js=ifval(jstag.ne.0,1,0)
1561 if(fun.eq.REAL_SUM)then
1571 elseif(fun.eq.RNRM_SUM)then
1577 lsum=lsum+sqrt(a(i,k,j)*a(i,k,j)+b(i,k,j)*b(i,k,j))
1581 elseif(fun.eq.REAL_MAX)then
1587 lsum=max(lsum,a(i,k,j))
1591 elseif(fun.eq.RNRM_MAX)then
1597 lsum=max(lsum,sqrt(a(i,k,j)*a(i,k,j)+b(i,k,j)*b(i,k,j)))
1602 call crash('fun_real: bad fun')
1605 if(lsum.ne.lsum)call crash('fun_real: NaN detected')
1607 dosum=fun.eq.REAL_SUM.or.fun.eq.RNRM_SUM
1608 domax=fun.eq.REAL_MAX.or.fun.eq.RNRM_MAX
1610 ! get process sum over all threads
1612 ! only one thread should write to shared variable
1616 ! now all threads know psum
1618 !$OMP CRITICAL(RDSUM)
1619 ! each thread adds its own lsum
1620 if(dosum)psum=psum+lsum
1621 if(domax)psum=max(psum,lsum)
1622 !$OMP END CRITICAL(RDSUM)
1624 ! wait till all theads are done
1627 ! get global sum over all processes
1629 ! only one threads will do the mpi communication
1631 if(dosum) gsum = wrf_dm_sum_real ( psum )
1632 if(domax) gsum = wrf_dm_max_real ( psum )
1636 if(gsum.ne.gsum)call crash('fun_real: NaN detected')
1640 ! now gsum is known to all threads
1644 end function fun_real
1646 end module module_fr_fire_util