2 !*** Jan Mandel August-October 2007
3 !*** email: jmandel@ucar.edu or Jan.Mandel@gmail.com or Jan.Mandel@cudenver.edu
5 ! This module contains general purpose utilities and WRF wrappers because I want the
6 ! model to be able to run standalone. No physics here.
7 ! Some are dependent on WRF indexing scheme. Some violate WRF conventions but these
8 ! are not called from the WRF dependent code. Some are not called at all.
11 module module_fr_sfire_util
13 ! various method selection parameters
14 ! 1. add the parameter and its static default here
15 ! 2. add copy from config_flags in module_fr_sfire_driver%%set_flags
16 ! 3. (optional) add a line in Registry.EM to define the variable and set default value
20 fire_print_msg=1, & ! print SFIRE progress
21 fire_print_file=1, & ! write many files by write_array_m; compile with DEBUG_OUT, do not run in parallel
22 fuel_left_method=1, & ! 1=simple, 2=exact in linear case
23 fuel_left_irl=2, & ! refinement for fuel calculation, must be even
25 boundary_guard=-1, & ! crash if fire gets this many cells to domain boundary, -1=off
26 fire_grows_only=1, & ! fire can spread out only (level set functions may not increase)
27 fire_upwinding=3, & ! upwind normal spread: 1=standard, 2=godunov, 3=eno, 4=sethian
28 fire_upwind_split=0, & ! 1=upwind advection separately from normal direction spread
29 fire_test_steps=0, & ! 0=no fire, 1=normal, >1 = do specified number of steps and terminate (testing only)
30 fire_topo_from_atm=1 ! 0 = expect ZSF set correctly on entry, 1 = populate by interploating from atmosphere
36 fire_atm_feedback=1. , & ! 1 = normal, 0. = one way coupling atmosphere -> fire only
37 fire_back_weight=0.5, & ! RK parameter, 0 = Euler method, 0.5 = Heun, 1 = fake backward Euler
38 fire_viscosity=0.4, & ! artificial viscosity
39 fire_lfn_ext_up=1. ! 0.=extend level set function at boundary by reflection, 1.=always up
49 character(len=*), intent(in)::s
52 call wrf_error_fatal(msg)
63 character(len=*), intent(in)::s
65 character(len=1)thread
68 !$ m=omp_get_thread_num()
72 write(thread,'(i1,a)')m
73 msg='SFIRE'//thread//s
75 if(fire_print_msg.gt.0)then
78 end subroutine message
84 subroutine set_ideal_coord( dxf,dyf, &
85 ifds,ifde,jfds,jfde, &
86 ifms,ifme,jfms,jfme, &
87 ifts,ifte,jfts,jfte, &
92 real, intent(in)::dxf,dyf
93 integer, intent(in):: &
94 ifds,ifde,jfds,jfde, &
95 ifms,ifme,jfms,jfme, &
97 real, intent(out),dimension(ifms:ifme,jfms:jfme)::fxlong,fxlat
100 ! set fake coordinates, in m
103 ! uniform mesh, lower left domain corner is (0,0)
104 fxlong(i,j)=(i-ifds+0.5)*dxf
105 fxlat (i,j)=(j-jfds+0.5)*dyf
108 end subroutine set_ideal_coord
115 subroutine continue_at_boundary(ix,iy,bias, & ! do x direction or y direction
116 ims,ime,jms,jme, & ! memory dims
117 ids,ide,jds,jde, & ! domain dims
118 ips,ipe,jps,jpe, & ! patch dims
119 its,ite,jts,jte, & ! tile dims
123 ! extend array by one beyond the domain by linear continuation
125 integer, intent(in)::ix,iy ! not 0 = do x or y (1 or 2) direction
126 real,intent(in)::bias ! 0=none, 1.=max
127 integer, intent(in)::ims,ime,jms,jme, & ! memory dims
128 ids,ide,jds,jde, & ! domain dims
129 ips,ipe,jps,jpe, & ! patch dims
130 its,ite,jts,jte ! tile dims
131 real,intent(inout),dimension(ims:ime,jms:jme)::lfn
133 integer i,j,itso,jtso,iteo,jteo
134 character(len=128)::msg
135 integer::its1,ite1,jts1,jte1
136 integer,parameter::halo=1 ! width of halo region to update
138 ! check if there is space for the extension
139 call check_mesh_2dim(its-1,ite+1,jts-1,jte+1,ims,ime,jms,jme)
145 ! go halo width beyond if at patch boundary but not at domain boudnary
146 ! assume we have halo need to compute the value we do not have
147 ! the next thread that would conveniently computer the extended values at patch corners
148 ! besides halo may not transfer values outside of the domain
154 if(its.eq.ips.and..not.its.eq.ids)its1=its-halo
155 if(jts.eq.jps.and..not.jts.eq.jds)jts1=jts-halo
156 if(ite.eq.ipe.and..not.ite.eq.ide)ite1=ite+halo
157 if(jte.eq.jpe.and..not.jte.eq.jde)jte1=jte+halo
158 write(msg,'(a,2i5,a,f5.2)')'continue_at_boundary: directions',ix,iy,' bias ',bias
163 lfn(ids-1,j)=EX(lfn(ids,j),lfn(ids+1,j))
169 lfn(ide+1,j)=EX(lfn(ide,j),lfn(ide-1,j))
173 write(msg,'(8(a,i5))')'continue_at_boundary: x:',its,':',ite,',',jts,':',jte,' ->',itso,':',iteo,',',jts1,':',jte1
179 lfn(i,jds-1)=EX(lfn(i,jds),lfn(i,jds+1))
185 lfn(i,jde+1)=EX(lfn(i,jde),lfn(i,jde-1))
189 write(msg,'(8(a,i5))')'continue_at_boundary: y:',its,':',ite,',',jts,':',jte,' ->',its1,':',ite1,',',jtso,':',jteo
192 ! corners of the domain
193 if(ix.ne.0.and.iy.ne.0)then
194 if(its.eq.ids.and.jts.eq.jds)lfn(ids-1,jds-1)=EX(lfn(ids,jds),lfn(ids+1,jds+1))
195 if(its.eq.ids.and.jte.eq.jde)lfn(ids-1,jde+1)=EX(lfn(ids,jde),lfn(ids+1,jde-1))
196 if(ite.eq.ide.and.jts.eq.jds)lfn(ide+1,jds-1)=EX(lfn(ide,jds),lfn(ide-1,jds+1))
197 if(ite.eq.ide.and.jte.eq.jde)lfn(ide+1,jde+1)=EX(lfn(ide,jde),lfn(ide-1,jde-1))
201 real function EX(a,b)
202 !*** statement function
204 EX=(1.-bias)*(2.*a-b)+bias*max(2.*a-b,a,b) ! extrapolation, max quarded
206 end subroutine continue_at_boundary
209 !*****************************
212 subroutine check_mesh_2dim(ids,ide,jds,jde,ims,ime,jms,jme)
214 integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme
215 character(len=128)msg
216 if(ids<ims.or.ide>ime.or.jds<jms.or.jde>jme)then
217 write(msg,*)'mesh dimensions: ',ids,ide,jds,jde
219 write(msg,*)'memory dimensions:',ims,ime,jms,jme
221 call crash('check_mesh_2dim: memory dimensions too small')
223 end subroutine check_mesh_2dim
229 subroutine check_mesh_3dim(ids,ide,kds,kde,jds,jde,ims,ime,kms,kme,jms,jme)
230 integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme,kds,kde,kms,kme
231 if(ids<ims.or.ide>ime.or.jds<jms.or.jde>jme.or.kds<kms.or.kde>kme) then
232 call crash('memory dimensions too small')
234 end subroutine check_mesh_3dim
240 subroutine sum_2d_cells( &
241 ims2,ime2,jms2,jme2, &
242 its2,ite2,jts2,jte2, &
244 ims1,ime1,jms1,jme1, &
245 its1,ite1,jts1,jte1, &
250 ! sum cell values in mesh2 to cell values of coarser mesh1
253 ! the dimensions are in cells, not nodes!
255 integer, intent(in)::its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
256 real, intent(out)::v1(ims1:ime1,jms1:jme1)
257 integer, intent(in)::its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
258 real, intent(in)::v2(ims2:ime2,jms2:jme2)
261 integer:: i1,i2,j1,j2,ir,jr,isz1,isz2,jsz1,jsz2,ioff,joff,ibase,jbase
263 character(len=128)msg
267 !check mesh dimensions and domain dimensions
268 call check_mesh_2dim(its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1)
269 call check_mesh_2dim(its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2)
278 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)then
279 call message('all mesh sizes must be positive')
283 ! compute mesh ratios
287 if(isz2.ne.isz1*ir .or. jsz2.ne.jsz1*jr)then
288 call message('input mesh size must be multiple of output mesh size')
295 jbase=jts2+jr*(j1-jts1)
297 ibase=its2+ir*(i1-its1)
313 write(msg,91)its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
315 write(msg,91)its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
317 write(msg,92)'input mesh size:',isz2,jsz2
319 91 format('dimensions: ',8i8)
320 write(msg,92)'output mesh size:',isz1,jsz1
323 call crash('module_fr_spread_util:sum_mesh_cells: bad mesh sizes')
325 end subroutine sum_2d_cells
329 ! module_fr_sfire_util%%interpolate_2d
330 subroutine interpolate_2d( &
331 ims2,ime2,jms2,jme2, & ! array coarse grid
332 its2,ite2,jts2,jte2, & ! dimensions coarse grid
333 ims1,ime1,jms1,jme1, & ! array coarse grid
334 its1,ite1,jts1,jte1, & ! dimensions fine grid
335 ir,jr, & ! refinement ratio
336 rip2,rjp2,rip1,rjp1, & ! (rip2,rjp2) on grid 2 lines up with (rip1,rjp1) on grid 1
337 v2, & ! in coarse grid
342 ! interpolate nodal values in mesh2 to nodal values in mesh1
343 ! input mesh 2 is coarse output mesh 1 is fine
344 ! interpolation runs over mesh2 region its2:ite2,jts2:jte2
345 ! only the part of mesh 1 region its1:ite1,jts1:jte1 is modified
349 integer, intent(in)::its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
350 integer, intent(in)::its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
351 integer, intent(in)::ir,jr
352 real,intent(in):: rjp1,rip1,rjp2,rip2
353 real, intent(out)::v1(ims1:ime1,jms1:jme1)
354 real, intent(in)::v2(ims2:ime2,jms2:jme2)
357 integer:: i1,i2,j1,j2,is,ie,js,je
360 intrinsic::ceiling,floor
364 !check mesh dimensions and domain dimensions
365 call check_mesh_2dim(its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1)
366 call check_mesh_2dim(its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2)
368 ! compute mesh ratios
372 do j2=jts2,jte2-1 ! loop over coarse mesh cells
373 rjo=rjp1+jr*(j2-rjp2) ! fine grid coordinate of the coarse grid patch start
374 js=max(jts1,ceiling(rjo)) ! lower bound of fine grid patch for this cell
375 je=min(jte1,floor(rjo)+jr) ! upper bound of fine grid patch for this cell
377 rio=rip1+ir*(i2-rip2)
378 is=max(its1,ceiling(rio))
379 ie=min(ite1,floor(rio)+ir)
383 ! in case fine grid lies on the boundary of several cells
384 ! the result will be written multiple times with the same value
385 ! up to a rounding error
387 !print *,'coarse ',i2,j2,'to',i2+1,j2+1,' fine ',is,js,' to ',ie,je
389 (1-tx)*(1-ty)*v2(i2,j2) &
390 + (1-tx)*ty *v2(i2,j2+1) &
391 + tx*(1-ty)*v2(i2+1,j2) &
392 + tx*ty *v2(i2+1,j2+1)
393 !print *,'coarse ',i2,j2,' fine ',i1,j1, ' offset ',io,jo,' weights ',tx,ty, &
394 ! 'in ',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2),v2(i2+1,j2+1),' out ',v1(i1,j1)
395 !write(*,'(a,2i5,a,2f8.2,a,4f8.2,a,2i5,a,f8.2)') &
396 !'coarse ',i2,j2,' coord',rio,rjo,' val',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2),v2(i2+1,j2+1),&
397 !' fine ',i1,j1,' out ',v1(i1,j1)
403 end subroutine interpolate_2d
409 subroutine interpolate_2d_cells2cells( &
410 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
411 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
415 ! interpolate nodal values in mesh2 to nodal values in mesh1
416 ! input mesh 2 is coarse output mesh 1 is fine
420 integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
421 real, intent(out)::v1(ims1:ime1,jms1:jme1)
422 integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
423 real, intent(in)::v2(ims2:ime2,jms2:jme2)
425 ! Example with mesh ratio=4. | = cell boundary, x = cell center
427 ! mesh2 |-------x-------|-------x-------|
428 ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|
432 integer:: ir,jr,isz1,isz2,jsz1,jsz2,ip,jp,ih,jh
433 character(len=128)msg
437 !check mesh dimensions and domain dimensions
438 call check_mesh_2dim(ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1)
439 call check_mesh_2dim(ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2)
448 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)goto 9
449 if(mod(isz1,isz2).ne.0.or.mod(jsz1,jsz2).ne.0)goto 9
451 ! compute mesh ratios
455 ! mesh2 |-------x-------|-------x-------|
456 ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|
458 ! mesh2 |-----x-----|-----x-----| rx=3
459 ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|
465 ! mesh2 |---x---|---x---| rx=2
466 ! mesh1 |-x-|-x-|-x-|-x-|
473 ! offset of the last node in the 1st half of the cell
476 ! 0 if coarse cell center coincides with fine, 1 if not
480 call interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
481 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
482 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
487 write(msg,91)ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
489 write(msg,91)ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
491 write(msg,92)'input mesh size:',isz2,jsz2
493 91 format('dimensions: ',8i8)
494 write(msg,92)'output mesh size:',isz1,jsz1
497 call crash("module_fr_sfire_util:interpolate_2dmesh_cells: bad mesh sizes")
498 end subroutine interpolate_2d_cells2cells
504 subroutine interpolate_2d_cells2nodes( &
505 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
506 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
510 ! interpolate nodal values in mesh2 to nodal values in mesh1
511 ! input mesh 2 is coarse output mesh 1 is fine
515 integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
516 real, intent(out)::v1(ims1:ime1,jms1:jme1)
517 integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
518 real, intent(in)::v2(ims2:ime2,jms2:jme2)
520 ! Example with mesh ratio=4. | = cell boundary, x = cell center
522 ! mesh2 |-------x-------|-------x-------|
523 ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x
527 integer:: ir,jr,isz1,isz2,jsz1,jsz2,ip,jp,ih,jh
528 character(len=128)msg
532 !check mesh dimensions and domain dimensions
533 call check_mesh_2dim(ids1,ide1+1,jds1,jde1+1,ims1,ime1,jms1,jme1)
534 call check_mesh_2dim(ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2)
543 if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)goto 9
544 if(mod(isz1,isz2).ne.0.or.mod(jsz1,jsz2).ne.0)goto 9
546 ! compute mesh ratios
550 ! mesh2 |-------x-------|-------x-------|
551 ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x
553 ! mesh2 |-----x-----|-----x-----| rx=3
554 ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x
556 ! mesh2 |---x---|---x---| rx=2
557 ! mesh1 x-|-x-|-x-|-x-|-x
559 ! offset of the last node in the 1st half of the cell
562 ! 0 if coarse cell center coincides with fine, 1 if not
567 call interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
568 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
569 ids1,ide1+1,jds1,jde1+1,ims1,ime1,jms1,jme1,v1 ) ! out
574 write(msg,91)ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
576 write(msg,91)ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
578 write(msg,92)'input mesh size:',isz2,jsz2
580 91 format('dimensions: ',8i8)
581 write(msg,92)'output mesh size:',isz1,jsz1
584 call crash("module_fr_sfire_util:interpolate_2d_cells2nodes: bad mesh sizes")
585 end subroutine interpolate_2d_cells2nodes
590 subroutine interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
591 ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
592 ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
594 !*** EXCEPTION: THIS SUBROUTINE IS NEITHER CELL NOR NODE BASED.
596 integer, intent(in)::ip,jp,ih,jh,ir,jr
597 integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
598 real, intent(out)::v1(ims1:ime1,jms1:jme1)
599 integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
600 real, intent(in)::v2(ims2:ime2,jms2:jme2)
602 real:: tx,ty,rx,ry,half,xoff,yoff
603 integer:: i1,i2,j1,j2,ioff,joff
612 ! the inside, ids1+ih:ide1-ih,jds1+jh:jde1-jh
613 do j2=jds2,jde2-1 ! interpolate from nodes j2 and j2+1
617 ! compute fine mesh index
618 i1=ioff+(ih+ids1)+ir*(i2-ids2)
619 j1=joff+(jh+jds1)+jr*(j2-jds2)
625 (1-tx)*(1-ty)*v2(i2,j2) &
626 + (1-tx)*ty *v2(i2,j2+1) &
627 + tx*(1-ty)*v2(i2+1,j2) &
628 + tx*ty *v2(i2+1,j2+1)
629 !write(*,'(3(a,2i5),a,2f7.4)')'coarse ',i2,j2,' fine ',i1,j1, &
630 ! ' offset ',ioff,joff,' weights ',tx,ty
631 !write(*,'(a,4f7.4,a,f7.4)')'in ',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2), &
632 ! v2(i2+1,j2+1),' out ',v1(i1,j1)
638 ! extend to the boundary strips from the nearest known
639 do ioff=0,ih-1 ! top and bottom strips
642 j1=joff+(jh+jds1)+jr*(j2-jds2)
646 v1(ids1+ioff,j1)=(1-ty)*v2(ids2,j2)+ty*v2(ids2,j2+1)
647 v1(ide1-ioff,j1)=(1-ty)*v2(ide2,j2)+ty*v2(ide2,j2+1)
651 do joff=0,jh-1 ! left and right strips
654 i1=ioff+(ih+ids1)+ir*(i2-ids2)
658 v1(i1,jds1+joff)=(1-tx)*v2(i2,jds2)+tx*v2(i2+1,jds2)
659 v1(i1,jde1-joff)=(1-tx)*v2(i2,jde2)+tx*v2(i2+1,jde2)
663 ! extend to the 4 corner squares from the nearest known
666 v1(ids1+ioff,jds1+joff)=v2(ids2,jds2)
667 v1(ide1-ioff,jds1+joff)=v2(ide2,jds2)
668 v1(ids1+ioff,jde1-joff)=v2(ids2,jde2)
669 v1(ide1-ioff,jde1-joff)=v2(ide2,jde2)
672 end subroutine interpolate_2d_w
678 real function interp(ids,ide,jds,jde,ims,ime,jms,jme,x,y,v)
681 ! general interpolation in a rectangular
685 integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme
686 real, intent(in)::x,y,v(ims:ime,jms:jme)
687 ! the mesh is cell based so the used dimension of v is ids:ide+1,jds:jde+1
690 intrinsic floor,min,max
698 ! indices of the lower left corner of the cell in the mesh that contains (x,y)
700 i=max(min(i,ide),ids)
702 j=max(min(j,jde),jds)
708 ! interpolate the values
710 (1-tx)*(1-ty)*v(i,j) &
711 + tx*(1-ty) *v(i+1,j) &
712 + (1-tx)*ty *v(i,j+1) &
715 !print *,'x,y=',x,y,'i1,i2=',i1,j1,'tx,ty=',tx,ty,' interp=',interp
718 subroutine meshdiffc_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
719 ims1,ime1,jms1,jme1, & ! memory dimensiuons
720 dx,dy, & ! mesh spacing
722 diffCx,diffCy) ! output
726 ! central differences on a 2d mesh
730 integer, intent(in)::ids,ide,jds,jde,ims1,ime1,jms1,jme1
731 real, intent(in):: dx,dy
732 real, intent(in), dimension(ims1:ime1,jms1:jme1):: lfn
733 real, intent(out), dimension(ims1:ime1,jms1:jme1):: diffCx,diffCy
737 real, dimension(ims1:ime1,jms1:jme1):: diffLx,diffRx,diffLy,diffRy
739 ! get one-sided differences; dumb but had that already...
740 call meshdiff_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
741 ims1,ime1,jms1,jme1, & ! dimensions of lfn
742 dx,dy, & ! mesh spacing
744 diffLx,diffRx,diffLy,diffRy) ! output
749 diffCx(i,j)=0.5*(diffLx(i,j) + diffRx(i,j))
750 diffCy(i,j)=0.5*(diffLy(i,j) + diffRy(i,j))
753 end subroutine meshdiffc_2d
755 subroutine meshdiff_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
756 ims1,ime1,jms1,jme1, & ! dimensions of lfn
757 dx,dy, & ! mesh spacing
759 diffLx,diffRx,diffLy,diffRy) ! output
763 ! one-sided differences on a 2d mesh
767 integer, intent(in)::ids,ide,jds,jde,ims1,ime1,jms1,jme1
768 real, intent(in):: dx,dy
769 real, intent(in), dimension(ims1:ime1,jms1:jme1):: lfn
770 real, intent(out), dimension(ims1:ime1,jms1:jme1):: diffLx,diffRx,diffLy,diffRy
778 call check_mesh_2dim(ids,ide+1,jds,jde+1,ims1,ime1,jms1,jme1)
780 ! the bulk of the work
783 tmpx = (lfn(i+1,j)-lfn(i,j))/dx
786 tmpy = (lfn(i,j+1)-lfn(i,j))/dy
790 ! missing values - put there the other one
791 diffLx(ids,j) = diffLx(ids+1,j)
792 diffRx(ide+1,j)= diffRx(ide,j)
795 ! j=jde+1 from above loop
797 tmpx = (lfn(i+1,j)-lfn(i,j))/dx
801 ! i=ide+1 from above loop
803 tmpy = (lfn(i,j+1)-lfn(i,j))/dy
807 ! missing values - put there the other one
808 ! j=jde+1 from above loop, j=jds:jde done before in main bulk loop
809 diffLx(ids,j) = diffLx(ids+1,j)
810 diffRx(ide+1,j) = diffRx(ide,j)
812 diffLy(i,jds) = diffLy(i,jds+1)
813 diffRy(i,jde+1) = diffRy(i,jde)
816 end subroutine meshdiff_2d
821 real pure function sum_2darray( its,ite,jts,jte, &
824 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
825 real, intent(in)::a(ims:ime,jms:jme)
836 end function sum_2darray
838 real pure function max_2darray( its,ite,jts,jte, &
841 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
842 real, intent(in)::a(ims:ime,jms:jme)
853 end function max_2darray
855 subroutine print_2d_stats_vec(ips,ipe,jps,jpe, &
859 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme
860 real, intent(in), dimension(ims:ime,jms:jme)::ax,ay
861 character(len=*),intent(in)::name
864 real:: avg_a,max_a,min_a
867 call print_2d_stats(ips,ipe,jps,jpe, &
870 call print_2d_stats(ips,ipe,jps,jpe, &
878 t=sqrt(ax(i,j)**2+ay(i,j)**2)
884 avg_a = avg_a/((ipe-ips+1)*(jpe-jps+1))
885 call print_stat_line(id//'/sz',ips,ipe,jps,jpe,min_a,max_a,avg_a)
886 end subroutine print_2d_stats_vec
889 subroutine print_stat_line(name,ips,ipe,jps,jpe,min_a,max_a,avg_a)
890 !*** encapsulate line with statistics
893 integer, intent(in)::ips,ipe,jps,jpe
894 character(len=*),intent(in)::name
895 real,intent(in)::min_a,max_a,avg_a
897 character(len=128)msg
899 if(fire_print_msg.eq.0)return
901 write(msg,'(a,4i4,3g11.3)')id,ips,ipe,jps,jpe,min_a,max_a,avg_a
903 if(.not.avg_a.eq.avg_a)call crash('NaN detected')
904 end subroutine print_stat_line
907 subroutine print_3d_stats(ips,ipe,kps,kpe,jps,jpe, &
908 ims,ime,kms,kme,jms,jme, &
911 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme,kms,kme,kps,kpe
912 real, intent(in)::a(ims:ime,kms:kme,jms:jme)
913 character(len=*),intent(in)::name
915 real:: avg_a,max_a,min_a,t,aa
916 character(len=128)msg
917 if(fire_print_msg.eq.0)return
927 write(msg,1)name,i,k,j,'NaN'
931 write(msg,1)name,i,k,j,'Inf'
934 if(.not.aa.ge.-t)then
935 write(msg,1)name,i,k,j,'-Inf'
944 1 format(a,'(',i6,',',i6,',',i6,') = ',a)
945 avg_a = avg_a/((ipe-ips+1)*(jpe-jps+1)*(kpe-kps+1))
946 call print_stat_line(name,ips,ipe,jps,jpe,min_a,max_a,avg_a)
947 end subroutine print_3d_stats
949 subroutine print_2d_stats(ips,ipe,jps,jpe, &
953 integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme
954 real, intent(in)::a(ims:ime,jms:jme)
955 character(len=*),intent(in)::name
956 !!character(len=128)msg
957 if(fire_print_msg.eq.0)return
958 call print_3d_stats(ips,ipe,1,1,jps,jpe, &
959 ims,ime,1,1,jms,jme, &
961 !!write(msg,'(2a,z16)')name,' address =',loc(a)
963 end subroutine print_2d_stats
965 real pure function avg_2darray( its,ite,jts,jte, &
968 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
969 real, intent(in)::a(ims:ime,jms:jme)
972 avg_2darray = sum_2darray( its,ite,jts,jte, &
974 a)/((ite-its+1)*(jte-jts+1))
975 end function avg_2darray
977 real pure function avg_2darray_vec( its,ite,jts,jte, &
980 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
981 real, intent(in), dimension(ims:ime,jms:jme):: ax,ay
988 t=t+sqrt(ax(i,j)**2+ay(i,j)**2)
991 t = t/((ite-its+1)*(jte-jts+1))
993 end function avg_2darray_vec
996 subroutine print_array(its,ite,jts,jte, &
1001 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,id
1002 real, intent(in), dimension(ims:ime,jms:jme):: a
1003 character(len=*),intent(in)::name
1006 character(len=128)::msg
1008 write(msg,*)name,' start ',id,' dim ',its,ite,jts,jte
1012 write(msg,*)i,j,a(i,j)
1016 write(msg,*)name,' end ',id
1018 end subroutine print_array
1020 subroutine write_array_m(its,ite,jts,jte, &
1025 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,id
1026 real, intent(in), dimension(ims:ime,jms:jme):: a
1027 character(len=*),intent(in)::name
1029 call write_array_m3(its,ite,1,1,jts,jte, &
1030 ims,ime,1,1,jms,jme, &
1032 end subroutine write_array_m
1035 subroutine write_array_m3(its,ite,kts,kte,jts,jte, &
1036 ims,ime,kms,kme,jms,jme, &
1043 integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,kts,kte,kms,kme,id
1044 real, intent(in), dimension(ims:ime,kms:kme,jms:jme):: a
1045 character(len=*),intent(in)::name
1047 integer i,j,k,iu,ilen,myproc,nprocs
1049 character(len=128)::fname,msg
1051 if(fire_print_file.eq.0.or.id.le.0)return
1052 call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
1053 call wrf_get_nproc (nprocs)
1054 call wrf_get_myproc( myproc )
1057 write(fname,3)name,'_',id,'.txt'
1059 write(fname,4)name,'_',id,'.',myproc,'.txt'
1061 do ilen=len(fname),2,-1
1062 if(fname(ilen:ilen).ne.' ')goto 19
1070 inquire(unit=i,opened=op)
1071 if(.not.op.and.iu.le.0)iu=i
1073 if(iu.gt.0)open(iu,file=fname(1:ilen),form='formatted',status='unknown')
1076 if(iu.le.0)call crash('write_array_m: cannot find available fortran unit')
1078 write(iu,1)real(its)
1079 write(iu,1)real(ite)
1080 write(iu,1)real(jts)
1081 write(iu,1)real(jte)
1082 write(iu,1)real(kts)
1083 write(iu,1)real(kte)
1084 write(iu,1)(((a(i,k,j),i=its,ite),j=jts,jte),k=kts,kte)
1086 write(msg,2)name,'(',its,':',ite,',',jts,':',jte,',', &
1087 kts,':',kte,') -> ',fname(1:ilen)
1092 2 format(2a,3(i5,a,i5,a),2a)
1093 3 format(a,a,i5.5,a)
1094 4 format(a,a,i5.5,a,i4.4,a)
1096 9 write(msg,'(3a)')'Cannot open file ',fname(1:ilen),' for writing'
1099 end subroutine write_array_m3
1101 ! function to go beyond domain boundary if tile is next to it
1102 pure integer function snode(t,d,i)
1104 integer, intent(in)::t,d,i
1112 end module module_fr_sfire_util