PageRenderTime 62ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/wrfv2_fire/phys/module_fr_sfire_util.F

http://github.com/jbeezley/wrf-fire
FORTRAN Legacy | 1735 lines | 1049 code | 227 blank | 459 comment | 61 complexity | f811a246d3c1edaec671d733a071af64 MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. !
  2. !*** Jan Mandel August-October 2007
  3. !*** email: jmandel@ucar.edu or Jan.Mandel@gmail.com or Jan.Mandel@cudenver.edu
  4. !
  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.
  9. !
  10. module module_fr_sfire_util
  11. ! various method selection parameters
  12. ! 1. add the parameter and its static default here
  13. ! optional:
  14. ! 2. add copy from config_flags in module_fr_sfire_driver%%set_flags
  15. ! 3. add a line in Registry.EM to define the variable and set default value
  16. ! 4. add the variable and value in namelist.input
  17. ! to compile in a hook to attach debugger to a running process.
  18. !#define DEBUG_HOOK
  19. !use module_domain, only: domain
  20. !use module_model_constants, only: reradius, & ! 1/earth radiusw
  21. ! pi2 ! 2*pi
  22. implicit none
  23. integer,save:: &
  24. fire_print_msg=1, & ! print SFIRE progress
  25. fire_print_file=1, & ! write many files by write_array_m; compile with DEBUG_OUT, do not run in parallel
  26. fuel_left_method=1, & ! 1=simple, 2=exact in linear case
  27. fuel_left_irl=2, & ! refinement for fuel calculation, must be even
  28. fuel_left_jrl=2, & ! currently, 2 only supported
  29. boundary_guard=-1, & ! crash if fire gets this many cells to domain boundary, -1=off
  30. fire_grows_only=1, & ! fire can spread out only (level set functions may not increase)
  31. fire_upwinding=3, & ! upwind normal spread: 1=standard, 2=godunov, 3=eno, 4=sethian
  32. fire_test_steps=0, & ! 0=no fire, 1=normal, >1 = do specified number of steps and terminate (testing only)
  33. fire_topo_from_atm=1, & ! 0 = expect ZSF set correctly on entry, 1 = populate by interploating from atmosphere
  34. fire_advection=0, & ! 0 = fire spread from normal wind/slope (CAWFE), 1 = full speed projected
  35. fire_wind_log_interp=4,& ! kind of vertical log layer wind interpolation, see driver
  36. fire_use_windrf=0, & ! if fire_wind_log_interp.ne.4: 0=ignore wind reduction factors, 1=multiply, 2=use to set fwh
  37. fire_fmc_read=1, & ! fuel moisture: 0 from wrfinput, 1 from namelist.fire, 2 read from file in ideal
  38. fire_ignition_clamp=0, & ! if 1, clamp ignition to grid points
  39. fire_hfx_given=0, & ! "0=no, run normally, 1=from wrfinput, 2=from file input_hfx in ideal, 4=by parameters" ""
  40. fire_hfx_num_lines=1, & ! number of heatflux parameter sets defining the heaflux lines (must be 1)
  41. fndwi_from_ndwi=1, & ! interpolate ndwi from atmosphere resolution
  42. kfmc_ndwi=0 ! if>0 , number of the fuel moisture class to update from ndwi
  43. real, save:: &
  44. fire_perimeter_time=0.,& ! if >0, set lfn from tign until this time, and read tign in ideal
  45. fire_atm_feedback=1. , & ! 1 = normal, 0. = one way coupling atmosphere -> fire only
  46. fire_back_weight=0.5, & ! RK parameter, 0 = Euler method, 0.5 = Heun, 1 = fake backward Euler
  47. fire_viscosity=0.4, & ! artificial viscosity
  48. fire_lfn_ext_up=1, & ! 0.=extend level set function at boundary by reflection, 1.=always up
  49. fire_hfx_value=0., & ! heat flux value specified when given by parameterst flux value specified when given by parameters:w
  50. fire_hfx_latent_part=0.084 ! proportion of the given heat flux released as latent, the rest is sensible
  51. integer, parameter:: REAL_SUM=10, REAL_MAX=20, REAL_MIN=21, REAL_AMAX=22, RNRM_SUM=30, RNRM_MAX=40
  52. ! describe one ignition line
  53. type line_type
  54. REAL ros, & ! subscale rate of spread during the ignition process
  55. stop_time, & ! when the ignition process stops from ignition start (s)
  56. wind_red, & ! wind reduction factor at the ignition line
  57. wrdist, & ! distance from the ignition line when the wind reduction stops
  58. wrupwind, & ! use distance interpolated between 0. = nearest 1. = upwind
  59. start_x, & ! x coordinate of the ignition line start point (m, or long/lat)
  60. start_y, & ! y coordinate of the ignition line start point
  61. end_x, & ! x coordinate of the ignition line end point
  62. end_y, & ! y coordinate of the ignition line end point
  63. start_time, & ! time for the start point from simulation start (s)
  64. end_time, & ! time for the end poin from simulation start (s)
  65. trans_time, & ! transition time (s)
  66. radius, & ! thickness of the line
  67. hfx_value ! heat flux value associated with the line
  68. end type line_type
  69. integer, parameter:: fire_max_lines=5
  70. integer:: stat_lev=1 ! print level to print statistics
  71. ! container type for all ignitions and associated scalars
  72. type lines_type
  73. type(line_type):: line(fire_max_lines) ! descriptions of ignition lines
  74. integer:: num_lines, & ! number of lines used
  75. max_lines, & ! max number of lines that can be specified through namelist
  76. longlat ! 0 for ideal, 1 for real
  77. real:: unit_fxlong,unit_fxlat ! degree of longtitude/latitude in m; 1m for ideal
  78. end type lines_type
  79. contains
  80. !
  81. !*****************************
  82. !
  83. logical function isnan(a)
  84. real, intent(in):: a
  85. isnan= (a.ne.a)
  86. return
  87. end function isnan
  88. logical function isnotfinite(aa)
  89. real, intent(in)::aa
  90. isnotfinite=(aa.ne.aa.or..not.aa.le.huge(aa).or..not.aa.ge.-huge(aa))
  91. end function isnotfinite
  92. subroutine interpolate_z2fire(id, & ! for debug output, <= 0 no output
  93. istrip, & ! width of strip to extrapolate to around domain
  94. ids,ide, jds,jde, & ! atm grid dimensions
  95. ims,ime, jms,jme, &
  96. ips,ipe,jps,jpe, &
  97. its,ite,jts,jte, &
  98. ifds, ifde, jfds, jfde, & ! fire grid dimensions
  99. ifms, ifme, jfms, jfme, &
  100. ifts,ifte,jfts,jfte, &
  101. ir,jr, & ! atm/fire grid ratio
  102. zs, & ! atm grid arrays in
  103. zsf) ! fire grid arrays out
  104. implicit none
  105. !*** purpose: interpolate height
  106. !*** arguments
  107. integer, intent(in)::id, &
  108. istrip, &
  109. ids,ide, jds,jde, & ! atm domain bounds
  110. ims,ime,jms,jme, & ! atm memory bounds
  111. ips,ipe,jps,jpe, &
  112. its,ite,jts,jte, & ! atm tile bounds
  113. ifds, ifde, jfds, jfde, & ! fire domain bounds
  114. ifms, ifme, jfms, jfme, & ! fire memory bounds
  115. ifts,ifte,jfts,jfte, & ! fire tile bounds
  116. ir,jr ! atm/fire grid refinement ratio
  117. real, intent(in), dimension(ims:ime, jms:jme):: zs ! terrain height at atm cell centers & ! terrain height
  118. real,intent(out), dimension(ifms:ifme,jfms:jfme)::&
  119. zsf ! terrain height fire grid nodes
  120. !*** local
  121. real, dimension(its-2:ite+2,jts-2:jte+2):: za ! terrain height
  122. integer:: i,j,jts1,jte1,its1,ite1,jfts1,jfte1,ifts1,ifte1,itso,jtso,iteo,jteo
  123. if(istrip.gt.1)call crash('interpolate_z2fire: istrip should be 0 or 1 or less')
  124. ! terrain height
  125. jts1=max(jts-1,jds) ! lower loop limit by one less when at end of domain
  126. its1=max(its-1,ids) ! ASSUMES THE HALO IS THERE if patch != domain
  127. jte1=min(jte+1,jde)
  128. ite1=min(ite+1,ide)
  129. do j = jts1,jte1
  130. do i = its1,ite1
  131. ! copy to local array
  132. za(i,j)=zs(i,j)
  133. enddo
  134. enddo
  135. call continue_at_boundary(1,1,0., & ! do x direction or y direction
  136. its-2,ite+2,jts-2,jte+2, & ! memory dims
  137. ids,ide,jds,jde, & ! domain dims - winds defined up to +1
  138. ips,ipe,jps,jpe, & ! patch dims - winds defined up to +1
  139. its1,ite1,jts1,jte1, & ! tile dims
  140. itso,jtso,iteo,jteo, &
  141. za) ! array
  142. ! interpolate to tile plus strip along domain boundary if at boundary
  143. jfts1=snode(jfts,jfds,-istrip) ! lower loop limit by one less when at end of domain
  144. ifts1=snode(ifts,ifds,-istrip)
  145. jfte1=snode(jfte,jfde,+istrip)
  146. ifte1=snode(ifte,ifde,+istrip)
  147. call interpolate_2d( &
  148. its-2,ite+2,jts-2,jte+2, & ! memory dims atm grid tile
  149. its1-1,ite1+1,jts1-1,jte1+1, & ! where atm grid values set
  150. ifms,ifme,jfms,jfme, & ! array dims fire grid
  151. ifts1,ifte1,jfts1,jfte1, & ! dimensions fire grid tile
  152. ir,jr, & ! refinement ratio
  153. real(ids),real(jds),ifds+(ir-1)*0.5,jfds+(jr-1)*0.5, & ! line up by lower left corner of domain
  154. za, & ! in atm grid
  155. zsf) ! out fire grid
  156. end subroutine interpolate_z2fire
  157. !
  158. !***********************************************************************
  159. !
  160. !
  161. !****************
  162. !
  163. subroutine crash(s)
  164. use module_wrf_error
  165. implicit none
  166. character(len=*), intent(in)::s
  167. character(len=128)msg
  168. msg='crash: '//s
  169. call message(msg,level=0)
  170. !$OMP CRITICAL(SFIRE_MESSAGE_CRIT)
  171. call wrf_error_fatal(msg)
  172. !$OMP END CRITICAL(SFIRE_MESSAGE_CRIT)
  173. end subroutine crash
  174. !
  175. !****************
  176. !
  177. subroutine warning(s,level)
  178. implicit none
  179. !*** arguments
  180. character(len=*), intent(in)::s
  181. character(len=128)::msg
  182. integer,intent(in),optional::level
  183. msg='WARNING:'//s
  184. if(present(level))then
  185. call message(msg,level=level)
  186. else
  187. call message(msg,level=0)
  188. endif
  189. end subroutine warning
  190. subroutine message(s,level)
  191. use module_wrf_error
  192. #ifdef _OPENMP
  193. use OMP_LIB
  194. #endif
  195. implicit none
  196. !*** arguments
  197. character(len=*), intent(in)::s
  198. integer,intent(in),optional::level
  199. !*** local
  200. character(len=128)::msg
  201. character(len=118)::t
  202. integer m,mlevel
  203. logical op
  204. !*** executable
  205. if(present(level))then
  206. mlevel=level
  207. else
  208. mlevel=2 ! default message level
  209. endif
  210. if(fire_print_msg.ge.mlevel)then
  211. m=0
  212. !$OMP CRITICAL(SFIRE_MESSAGE_CRIT)
  213. #ifdef _OPENMP
  214. m=omp_get_thread_num()
  215. t=s
  216. write(msg,'(a6,i3,a1,a118)')'SFIRE:',m,':',t
  217. #else
  218. msg='SFIRE:'//s
  219. #endif
  220. call wrf_message(msg)
  221. !flush(6) ! will not work on intel compiler
  222. !flush(0)
  223. !$OMP END CRITICAL(SFIRE_MESSAGE_CRIT)
  224. endif
  225. end subroutine message
  226. !
  227. !****************
  228. !
  229. subroutine time_start
  230. use module_timing, only:start_timing
  231. implicit none
  232. call start_timing
  233. end subroutine time_start
  234. subroutine time_end(string)
  235. use module_timing, only:end_timing
  236. implicit none
  237. character(len=*)string
  238. call end_timing(string)
  239. end subroutine time_end
  240. integer function open_text_file(filename,rw)
  241. implicit none
  242. character(len=*),intent(in):: filename,rw
  243. !$ integer, external:: OMP_GET_THREAD_NUM
  244. character(len=128):: msg
  245. character(len=1)::act
  246. integer::iounit,ierr
  247. logical::op
  248. !$ if (OMP_GET_THREAD_NUM() .ne. 0)then
  249. !$ call crash('open_input_text_file: called from parallel loop')
  250. !$ endif
  251. do iounit=19,99
  252. inquire(iounit,opened=op)
  253. if(.not.op)goto 1
  254. enddo
  255. call crash('open_text_file: Cannot find any available I/O unit')
  256. 1 continue
  257. act=rw(1:1)
  258. select case (act)
  259. case ('r','R')
  260. OPEN(iounit, FILE=filename,FORM='FORMATTED',STATUS='OLD',ACTION='READ',IOSTAT=ierr)
  261. case ('w','W')
  262. OPEN(iounit, FILE=filename,FORM='FORMATTED',STATUS='UNKNOWN',ACTION='WRITE',IOSTAT=ierr)
  263. case default
  264. write(msg,*)'open_text_file: bad mode ',trim(rw),' for file ',trim(filename)
  265. end select
  266. if(ierr.ne.0)then
  267. write(msg,*)'open_text_file: Cannot open file ',filename
  268. call crash(msg)
  269. endif
  270. open_text_file=iounit
  271. end function open_text_file
  272. !
  273. !****************
  274. !
  275. subroutine set_ideal_coord( dxf,dyf, &
  276. ifds,ifde,jfds,jfde, &
  277. ifms,ifme,jfms,jfme, &
  278. ifts,ifte,jfts,jfte, &
  279. fxlong,fxlat &
  280. )
  281. implicit none
  282. ! arguments
  283. real, intent(in)::dxf,dyf
  284. integer, intent(in):: &
  285. ifds,ifde,jfds,jfde, &
  286. ifms,ifme,jfms,jfme, &
  287. ifts,ifte,jfts,jfte
  288. real, intent(out),dimension(ifms:ifme,jfms:jfme)::fxlong,fxlat
  289. ! local
  290. integer::i,j
  291. ! set fake coordinates, in m
  292. do j=jfts,jfte
  293. do i=ifts,ifte
  294. ! uniform mesh, lower left domain corner is (0,0)
  295. fxlong(i,j)=(i-ifds+0.5)*dxf
  296. fxlat (i,j)=(j-jfds+0.5)*dyf
  297. enddo
  298. enddo
  299. end subroutine set_ideal_coord
  300. !
  301. !****************
  302. !
  303. subroutine continue_at_boundary(ix,iy,bias, & ! do x direction or y direction
  304. ims,ime,jms,jme, & ! memory dims
  305. ids,ide,jds,jde, & ! domain dims
  306. ips,ipe,jps,jpe, & ! patch dims
  307. its,ite,jts,jte, & ! tile dims
  308. itso,iteo,jtso,jteo, & ! tile dims where set
  309. lfn) ! array
  310. implicit none
  311. !*** description
  312. ! extend array by one beyond the domain by linear continuation
  313. !*** arguments
  314. integer, intent(in)::ix,iy ! not 0 = do x or y (1 or 2) direction
  315. real,intent(in)::bias ! 0=none, 1.=max
  316. integer, intent(in)::ims,ime,jms,jme, & ! memory dims
  317. ids,ide,jds,jde, & ! domain dims
  318. ips,ipe,jps,jpe, & ! patch dims
  319. its,ite,jts,jte ! tile dims
  320. integer, intent(out)::itso,jtso,iteo,jteo ! where set
  321. real,intent(inout),dimension(ims:ime,jms:jme)::lfn
  322. !*** local
  323. integer i,j
  324. character(len=128)::msg
  325. integer::its1,ite1,jts1,jte1
  326. integer,parameter::halo=1 ! width of halo region to update
  327. !*** executable
  328. ! check if there is space for the extension
  329. call check_mesh_2dim(its-1,ite+1,jts-1,jte+1,ims,ime,jms,jme)
  330. ! for dislay only
  331. itso=its
  332. jtso=jts
  333. iteo=ite
  334. jteo=jte
  335. ! go halo width beyond if at patch boundary but not at domain boudnary
  336. ! assume we have halo need to compute the value we do not have
  337. ! the next thread that would conveniently computer the extended values at patch corners
  338. ! besides halo may not transfer values outside of the domain
  339. !
  340. its1=its
  341. jts1=jts
  342. ite1=ite
  343. jte1=jte
  344. if(its.eq.ips.and..not.its.eq.ids)its1=its-halo
  345. if(jts.eq.jps.and..not.jts.eq.jds)jts1=jts-halo
  346. if(ite.eq.ipe.and..not.ite.eq.ide)ite1=ite+halo
  347. if(jte.eq.jpe.and..not.jte.eq.jde)jte1=jte+halo
  348. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  349. write(msg,'(a,2i5,a,f5.2)')'continue_at_boundary: directions',ix,iy,' bias ',bias
  350. call message(msg,level=3)
  351. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  352. if(ix.ne.0)then
  353. if(its.eq.ids)then
  354. do j=jts1,jte1
  355. lfn(ids-1,j)=EX(lfn(ids,j),lfn(ids+1,j))
  356. enddo
  357. itso=ids-1
  358. endif
  359. if(ite.eq.ide)then
  360. do j=jts1,jte1
  361. lfn(ide+1,j)=EX(lfn(ide,j),lfn(ide-1,j))
  362. enddo
  363. iteo=ide+1
  364. endif
  365. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  366. write(msg,'(8(a,i5))')'continue_at_boundary: x:',its,':',ite,',',jts,':',jte,' ->',itso,':',iteo,',',jts1,':',jte1
  367. call message(msg,level=3)
  368. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  369. endif
  370. if(iy.ne.0)then
  371. if(jts.eq.jds)then
  372. do i=its1,ite1
  373. lfn(i,jds-1)=EX(lfn(i,jds),lfn(i,jds+1))
  374. enddo
  375. jtso=jds-1
  376. endif
  377. if(jte.eq.jde)then
  378. do i=its1,ite1
  379. lfn(i,jde+1)=EX(lfn(i,jde),lfn(i,jde-1))
  380. enddo
  381. jteo=jde+1
  382. endif
  383. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  384. write(msg,'(8(a,i5))')'continue_at_boundary: y:',its,':',ite,',',jts,':',jte,' ->',its1,':',ite1,',',jtso,':',jteo
  385. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  386. call message(msg,level=3)
  387. endif
  388. ! corners of the domain
  389. if(ix.ne.0.and.iy.ne.0)then
  390. if(its.eq.ids.and.jts.eq.jds)lfn(ids-1,jds-1)=EX(lfn(ids,jds),lfn(ids+1,jds+1))
  391. if(its.eq.ids.and.jte.eq.jde)lfn(ids-1,jde+1)=EX(lfn(ids,jde),lfn(ids+1,jde-1))
  392. if(ite.eq.ide.and.jts.eq.jds)lfn(ide+1,jds-1)=EX(lfn(ide,jds),lfn(ide-1,jds+1))
  393. if(ite.eq.ide.and.jte.eq.jde)lfn(ide+1,jde+1)=EX(lfn(ide,jde),lfn(ide-1,jde-1))
  394. endif
  395. return
  396. contains
  397. real function EX(a,b)
  398. !*** statement function
  399. real a,b
  400. EX=(1.-bias)*(2.*a-b)+bias*max(2.*a-b,a,b) ! extrapolation, max quarded
  401. end function EX
  402. end subroutine continue_at_boundary
  403. !
  404. !*****************************
  405. !
  406. subroutine check_mesh_2dim(ids,ide,jds,jde,ims,ime,jms,jme)
  407. implicit none
  408. integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme
  409. character(len=128)msg
  410. if(ids<ims.or.ide>ime.or.jds<jms.or.jde>jme)then
  411. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  412. write(msg,*)'mesh dimensions: ',ids,ide,jds,jde
  413. call message(msg,level=0)
  414. write(msg,*)'memory dimensions:',ims,ime,jms,jme
  415. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  416. call message(msg,level=0)
  417. call crash('check_mesh_2dim: memory dimensions too small')
  418. endif
  419. end subroutine check_mesh_2dim
  420. !
  421. !****************
  422. !
  423. subroutine check_mesh_3dim(ids,ide,kds,kde,jds,jde,ims,ime,kms,kme,jms,jme)
  424. integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme,kds,kde,kms,kme
  425. if(ids<ims.or.ide>ime.or.jds<jms.or.jde>jme.or.kds<kms.or.kde>kme) then
  426. call crash('memory dimensions too small')
  427. endif
  428. end subroutine check_mesh_3dim
  429. !
  430. !****************
  431. !
  432. subroutine sum_2d_cells( &
  433. ifms,ifme,jfms,jfme, &
  434. ifts,ifte,jtfs,jfte, &
  435. v2, & ! input
  436. ims,ime,jms,jme, &
  437. its,ite,jts,jte, &
  438. v1) ! output
  439. implicit none
  440. !*** purpose
  441. ! sum cell values in mesh2 to cell values of coarser mesh1
  442. !*** arguments
  443. ! the dimensions are in cells, not nodes!
  444. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
  445. real, intent(out)::v1(ims:ime,jms:jme)
  446. integer, intent(in)::ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme
  447. real, intent(in)::v2(ifms:ifme,jfms:jfme)
  448. !*** local
  449. integer:: i,i_f,j,j_f,ir,jr,isz1,isz2,jsz1,jsz2,ioff,joff,ibase,jbase
  450. real t
  451. character(len=128)msg
  452. !*** executable
  453. !check mesh dimensions and domain dimensions
  454. call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
  455. call check_mesh_2dim(ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme)
  456. ! compute mesh sizes
  457. isz1 = ite-its+1
  458. jsz1 = jte-jts+1
  459. isz2 = ifte-ifts+1
  460. jsz2 = jfte-jtfs+1
  461. ! check mesh sizes
  462. if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)then
  463. call message('all mesh sizes must be positive',level=0)
  464. goto 9
  465. endif
  466. ! compute mesh ratios
  467. ir=isz2/isz1
  468. jr=jsz2/jsz1
  469. if(isz2.ne.isz1*ir .or. jsz2.ne.jsz1*jr)then
  470. call message('input mesh size must be multiple of output mesh size',level=0)
  471. goto 9
  472. endif
  473. ! v1 = sum(v2)
  474. do j=jts,jte
  475. jbase=jtfs+jr*(j-jts)
  476. do i=its,ite
  477. ibase=ifts+ir*(i-its)
  478. t=0.
  479. do joff=0,jr-1
  480. j_f=joff+jbase
  481. do ioff=0,ir-1
  482. i_f=ioff+ibase
  483. t=t+v2(i_f,j_f)
  484. enddo
  485. enddo
  486. v1(i,j)=t
  487. enddo
  488. enddo
  489. return
  490. 9 continue
  491. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  492. write(msg,91)ifts,ifte,jtfs,jfte,ifms,ifme,jfms,jfme
  493. call message(msg,level=0)
  494. write(msg,91)its,ite,jts,jte,ims,ime,jms,jme
  495. call message(msg,level=0)
  496. write(msg,92)'input mesh size:',isz2,jsz2
  497. call message(msg,level=0)
  498. 91 format('dimensions: ',8i8)
  499. write(msg,92)'output mesh size:',isz1,jsz1
  500. call message(msg,level=0)
  501. 92 format(a,2i8)
  502. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  503. call crash('sum_2d_cells: bad mesh sizes')
  504. end subroutine sum_2d_cells
  505. ! module_fr_sfire_util%%interpolate_2d
  506. subroutine interpolate_2d( &
  507. ims2,ime2,jms2,jme2, & ! array coarse grid
  508. its2,ite2,jts2,jte2, & ! dimensions coarse grid
  509. ims1,ime1,jms1,jme1, & ! array coarse grid
  510. its1,ite1,jts1,jte1, & ! dimensions fine grid
  511. ir,jr, & ! refinement ratio
  512. rip2,rjp2,rip1,rjp1, & ! (rip2,rjp2) on grid 2 lines up with (rip1,rjp1) on grid 1
  513. v2, & ! in coarse grid
  514. v1 ) ! out fine grid
  515. implicit none
  516. !*** purpose
  517. ! interpolate nodal values in mesh2 to nodal values in mesh1
  518. ! interpolation runs over the mesh2 region its2:ite2,jts2:jte2
  519. ! only the part of mesh 1 in the region its1:ite1,jts1:jte1 is modified
  520. !*** arguments
  521. integer, intent(in)::its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1
  522. integer, intent(in)::its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2
  523. integer, intent(in)::ir,jr
  524. real,intent(in):: rjp1,rip1,rjp2,rip2
  525. real, intent(out)::v1(ims1:ime1,jms1:jme1)
  526. real, intent(in)::v2(ims2:ime2,jms2:jme2)
  527. !*** local
  528. integer:: i1,i2,j1,j2,is,ie,js,je
  529. real:: tx,ty,rx,ry
  530. real:: rio,rjo
  531. intrinsic::ceiling,floor
  532. !*** executable
  533. !check mesh dimensions and domain dimensions
  534. call check_mesh_2dim(its1,ite1,jts1,jte1,ims1,ime1,jms1,jme1)
  535. call check_mesh_2dim(its2,ite2,jts2,jte2,ims2,ime2,jms2,jme2)
  536. ! compute mesh ratios
  537. rx=1./ir
  538. ry=1./jr
  539. do j2=jts2,jte2-1 ! loop over mesh 2 cells
  540. rjo=rjp1+jr*(j2-rjp2) ! mesh 1 coordinate of the mesh 2 patch start
  541. js=max(jts1,ceiling(rjo)) ! lower bound of mesh 1 patch for this mesh 2 cell
  542. je=min(jte1,floor(rjo)+jr) ! upper bound of mesh 1 patch for this mesh 2 cell
  543. do i2=its2,ite2-1
  544. rio=rip1+ir*(i2-rip2)
  545. is=max(its1,ceiling(rio))
  546. ie=min(ite1,floor(rio)+ir)
  547. do j1=js,je
  548. ty = (j1-rjo)*ry
  549. do i1=is,ie
  550. ! in case mesh 1 node lies on the boundary of several mesh 2 cells
  551. ! the result will be written multiple times with the same value
  552. ! up to a rounding error
  553. tx = (i1-rio)*rx
  554. !print *,'coarse ',i2,j2,'to',i2+1,j2+1,' fine ',is,js,' to ',ie,je
  555. v1(i1,j1)= &
  556. (1-tx)*(1-ty)*v2(i2,j2) &
  557. + (1-tx)*ty *v2(i2,j2+1) &
  558. + tx*(1-ty)*v2(i2+1,j2) &
  559. + tx*ty *v2(i2+1,j2+1)
  560. !print *,'coarse ',i2,j2,' fine ',i1,j1, ' offset ',io,jo,' weights ',tx,ty, &
  561. ! 'in ',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2),v2(i2+1,j2+1),' out ',v1(i1,j1)
  562. !write(*,'(a,2i5,a,2f8.2,a,4f8.2,a,2i5,a,f8.2)') &
  563. !'coarse ',i2,j2,' coord',rio,rjo,' val',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2),v2(i2+1,j2+1),&
  564. !' fine ',i1,j1,' out ',v1(i1,j1)
  565. enddo
  566. enddo
  567. enddo
  568. enddo
  569. end subroutine interpolate_2d
  570. !
  571. !****************
  572. !
  573. subroutine interpolate_2d_cells2cells( &
  574. ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
  575. ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
  576. implicit none
  577. !*** purpose
  578. ! interpolate nodal values in mesh2 to nodal values in mesh1
  579. ! input mesh 2 is coarse output mesh 1 is fine
  580. !*** arguments
  581. integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
  582. real, intent(out)::v1(ims1:ime1,jms1:jme1)
  583. integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
  584. real, intent(in)::v2(ims2:ime2,jms2:jme2)
  585. ! Example with mesh ratio=4. | = cell boundary, x = cell center
  586. !
  587. ! mesh2 |-------x-------|-------x-------|
  588. ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|
  589. !
  590. !*** local
  591. integer:: ir,jr,isz1,isz2,jsz1,jsz2,ip,jp,ih,jh
  592. character(len=128)msg
  593. !*** executable
  594. !check mesh dimensions and domain dimensions
  595. call check_mesh_2dim(ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1)
  596. call check_mesh_2dim(ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2)
  597. ! compute mesh sizes
  598. isz1 = ide1-ids1+1
  599. jsz1 = jde1-jds1+1
  600. isz2 = ide2-ids2+1
  601. jsz2 = jde2-jds2+1
  602. ! check mesh sizes
  603. if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)goto 9
  604. if(mod(isz1,isz2).ne.0.or.mod(jsz1,jsz2).ne.0)goto 9
  605. ! compute mesh ratios
  606. ir=isz1/isz2
  607. jr=jsz1/jsz2
  608. !
  609. ! mesh2 |-------x-------|-------x-------|
  610. ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|
  611. ! mesh2 |-----x-----|-----x-----| rx=3
  612. ! mesh1 |-x-|-x-|-x-|-x-|-x-|-x-|
  613. ! i2 1 1 1 2
  614. ! i1 1 2 3 4 5
  615. ! ioff 0 1 2 0
  616. ! tx 0 1/3 2/3
  617. ! mesh2 |---x---|---x---| rx=2
  618. ! mesh1 |-x-|-x-|-x-|-x-|
  619. ! i2 1 1 2
  620. ! i1 2 3 4
  621. ! ioff 0 1 2
  622. ! tx 1/4 3/4
  623. ! offset of the last node in the 1st half of the cell
  624. ih=ir/2
  625. jh=jr/2
  626. ! 0 if coarse cell center coincides with fine, 1 if not
  627. ip=mod(ir+1,2)
  628. jp=mod(jr+1,2)
  629. call interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
  630. ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
  631. ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
  632. return
  633. 9 continue
  634. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  635. write(msg,91)ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
  636. call message(msg,level=0)
  637. write(msg,91)ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
  638. call message(msg,level=0)
  639. write(msg,92)'input mesh size:',isz2,jsz2
  640. call message(msg,level=0)
  641. 91 format('dimensions: ',8i8)
  642. write(msg,92)'output mesh size:',isz1,jsz1
  643. call message(msg,level=0)
  644. 92 format(a,2i8)
  645. call crash("module_fr_sfire_util:interpolate_2dmesh_cells: bad mesh sizes")
  646. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  647. end subroutine interpolate_2d_cells2cells
  648. !
  649. !****************
  650. !
  651. subroutine interpolate_2d_cells2nodes( &
  652. ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
  653. ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
  654. implicit none
  655. !*** purpose
  656. ! interpolate nodal values in mesh2 to nodal values in mesh1
  657. ! input mesh 2 is coarse output mesh 1 is fine
  658. !*** arguments
  659. integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
  660. real, intent(out)::v1(ims1:ime1,jms1:jme1)
  661. integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
  662. real, intent(in)::v2(ims2:ime2,jms2:jme2)
  663. ! Example with mesh ratio=4. | = cell boundary, x = cell center
  664. !
  665. ! mesh2 |-------x-------|-------x-------|
  666. ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x
  667. !
  668. !*** local
  669. integer:: ir,jr,isz1,isz2,jsz1,jsz2,ip,jp,ih,jh
  670. character(len=128)msg
  671. !*** executable
  672. !check mesh dimensions and domain dimensions
  673. call check_mesh_2dim(ids1,ide1+1,jds1,jde1+1,ims1,ime1,jms1,jme1)
  674. call check_mesh_2dim(ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2)
  675. ! compute mesh sizes
  676. isz1 = ide1-ids1+1
  677. jsz1 = jde1-jds1+1
  678. isz2 = ide2-ids2+1
  679. jsz2 = jde2-jds2+1
  680. ! check mesh sizes
  681. if(isz1.le.0.or.jsz1.le.0.or.isz2.le.0.or.jsz2.le.0)goto 9
  682. if(mod(isz1,isz2).ne.0.or.mod(jsz1,jsz2).ne.0)goto 9
  683. ! compute mesh ratios
  684. ir=isz1/isz2
  685. jr=jsz1/jsz2
  686. !
  687. ! mesh2 |-------x-------|-------x-------|
  688. ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x-|-x-|-x
  689. ! mesh2 |-----x-----|-----x-----| rx=3
  690. ! mesh1 x-|-x-|-x-|-x-|-x-|-x-|-x
  691. ! mesh2 |---x---|---x---| rx=2
  692. ! mesh1 x-|-x-|-x-|-x-|-x
  693. ! offset of the last node in the 1st half of the cell
  694. ih=(ir+1)/2
  695. jh=(jr+1)/2
  696. ! 0 if coarse cell center coincides with fine, 1 if not
  697. ip=mod(ir,2)
  698. jp=mod(jr,2)
  699. call interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
  700. ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
  701. ids1,ide1+1,jds1,jde1+1,ims1,ime1,jms1,jme1,v1 ) ! out
  702. return
  703. 9 continue
  704. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  705. write(msg,91)ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
  706. call message(msg,level=0)
  707. write(msg,91)ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
  708. call message(msg,level=0)
  709. write(msg,92)'input mesh size:',isz2,jsz2
  710. call message(msg,level=0)
  711. 91 format('dimensions: ',8i8)
  712. write(msg,92)'output mesh size:',isz1,jsz1
  713. call message(msg,level=0)
  714. 92 format(a,2i8)
  715. call crash("module_fr_sfire_util:interpolate_2d_cells2nodes: bad mesh sizes")
  716. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  717. end subroutine interpolate_2d_cells2nodes
  718. !
  719. !****************
  720. !
  721. subroutine interpolate_2d_w(ip,jp,ih,jh,ir,jr, &
  722. ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2,v2, & ! in
  723. ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1,v1 ) ! out
  724. implicit none
  725. !*** EXCEPTION: THIS SUBROUTINE IS NEITHER CELL NOR NODE BASED.
  726. integer, intent(in)::ip,jp,ih,jh,ir,jr
  727. integer, intent(in)::ids1,ide1,jds1,jde1,ims1,ime1,jms1,jme1
  728. real, intent(out)::v1(ims1:ime1,jms1:jme1)
  729. integer, intent(in)::ids2,ide2,jds2,jde2,ims2,ime2,jms2,jme2
  730. real, intent(in)::v2(ims2:ime2,jms2:jme2)
  731. real:: tx,ty,rx,ry,half,xoff,yoff
  732. integer:: i1,i2,j1,j2,ioff,joff
  733. parameter(half=0.5)
  734. rx=ir
  735. ry=jr
  736. xoff = ip*half
  737. yoff = jp*half
  738. ! the inside, ids1+ih:ide1-ih,jds1+jh:jde1-jh
  739. do j2=jds2,jde2-1 ! interpolate from nodes j2 and j2+1
  740. do i2=ids2,ide2-1
  741. do ioff=0,ir-ip
  742. do joff=0,jr-jp
  743. ! compute fine mesh index
  744. i1=ioff+(ih+ids1)+ir*(i2-ids2)
  745. j1=joff+(jh+jds1)+jr*(j2-jds2)
  746. ! weights
  747. tx = (ioff+xoff)/rx
  748. ty = (joff+yoff)/ry
  749. ! interpolation
  750. v1(i1,j1)= &
  751. (1-tx)*(1-ty)*v2(i2,j2) &
  752. + (1-tx)*ty *v2(i2,j2+1) &
  753. + tx*(1-ty)*v2(i2+1,j2) &
  754. + tx*ty *v2(i2+1,j2+1)
  755. !write(*,'(3(a,2i5),a,2f7.4)')'coarse ',i2,j2,' fine ',i1,j1, &
  756. ! ' offset ',ioff,joff,' weights ',tx,ty
  757. !write(*,'(a,4f7.4,a,f7.4)')'in ',v2(i2,j2),v2(i2,j2+1),v2(i2+1,j2), &
  758. ! v2(i2+1,j2+1),' out ',v1(i1,j1)
  759. enddo
  760. enddo
  761. enddo
  762. enddo
  763. ! extend to the boundary strips from the nearest known
  764. do ioff=0,ih-1 ! top and bottom strips
  765. do j2=jds2,jde2-1
  766. do joff=0,jr-jp
  767. j1=joff+(jh+jds1)+jr*(j2-jds2)
  768. ! weights
  769. ty = (joff+yoff)/ry
  770. ! interpolation
  771. v1(ids1+ioff,j1)=(1-ty)*v2(ids2,j2)+ty*v2(ids2,j2+1)
  772. v1(ide1-ioff,j1)=(1-ty)*v2(ide2,j2)+ty*v2(ide2,j2+1)
  773. enddo
  774. enddo
  775. enddo
  776. do joff=0,jh-1 ! left and right strips
  777. do i2=ids2,ide2-1
  778. do ioff=0,ir-ip
  779. i1=ioff+(ih+ids1)+ir*(i2-ids2)
  780. ! weights
  781. tx = (ioff+xoff)/rx
  782. ! interpolation
  783. v1(i1,jds1+joff)=(1-tx)*v2(i2,jds2)+tx*v2(i2+1,jds2)
  784. v1(i1,jde1-joff)=(1-tx)*v2(i2,jde2)+tx*v2(i2+1,jde2)
  785. enddo
  786. enddo
  787. enddo
  788. ! extend to the 4 corner squares from the nearest known
  789. do ioff=0,ih-1
  790. do joff=0,jh-1
  791. v1(ids1+ioff,jds1+joff)=v2(ids2,jds2)
  792. v1(ide1-ioff,jds1+joff)=v2(ide2,jds2)
  793. v1(ids1+ioff,jde1-joff)=v2(ids2,jde2)
  794. v1(ide1-ioff,jde1-joff)=v2(ide2,jde2)
  795. enddo
  796. enddo
  797. end subroutine interpolate_2d_w
  798. !
  799. !****************
  800. !
  801. real function interp(ids,ide,jds,jde,ims,ime,jms,jme,x,y,v)
  802. implicit none
  803. !*** purpose
  804. ! general interpolation in a rectangular
  805. !*** arguments
  806. integer, intent(in)::ids,ide,jds,jde,ims,ime,jms,jme
  807. real, intent(in)::x,y,v(ims:ime,jms:jme)
  808. ! the mesh is cell based so the used dimension of v is ids:ide+1,jds:jde+1
  809. !*** calls
  810. intrinsic floor,min,max
  811. !*** local
  812. integer i,j
  813. real tx,ty
  814. ! executable
  815. ! indices of the lower left corner of the cell in the mesh that contains (x,y)
  816. i = floor(x)
  817. i=max(min(i,ide),ids)
  818. j = floor(y)
  819. j=max(min(j,jde),jds)
  820. ! the leftover
  821. tx = x - real(i)
  822. ty = y - real(j)
  823. ! interpolate the values
  824. interp = &
  825. (1-tx)*(1-ty)*v(i,j) &
  826. + tx*(1-ty) *v(i+1,j) &
  827. + (1-tx)*ty *v(i,j+1) &
  828. + tx*ty *v(i+1,j+1)
  829. !print *,'x,y=',x,y,'i1,i2=',i1,j1,'tx,ty=',tx,ty,' interp=',interp
  830. end function interp
  831. subroutine meshdiffc_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
  832. ims1,ime1,jms1,jme1, & ! memory dimensiuons
  833. dx,dy, & ! mesh spacing
  834. lfn, & ! input
  835. diffCx,diffCy) ! output
  836. implicit none
  837. !*** purpose
  838. ! central differences on a 2d mesh
  839. !*** arguments
  840. integer, intent(in)::ids,ide,jds,jde,ims1,ime1,jms1,jme1
  841. real, intent(in):: dx,dy
  842. real, intent(in), dimension(ims1:ime1,jms1:jme1):: lfn
  843. real, intent(out), dimension(ims1:ime1,jms1:jme1):: diffCx,diffCy
  844. !*** local
  845. integer:: i,j
  846. real, dimension(ims1:ime1,jms1:jme1):: diffLx,diffRx,diffLy,diffRy
  847. ! get one-sided differences; dumb but had that already...
  848. call meshdiff_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
  849. ims1,ime1,jms1,jme1, & ! dimensions of lfn
  850. dx,dy, & ! mesh spacing
  851. lfn, & ! input
  852. diffLx,diffRx,diffLy,diffRy) ! output
  853. ! make into central
  854. do j=jds,jde+1
  855. do i=ids,ide+1
  856. diffCx(i,j)=0.5*(diffLx(i,j) + diffRx(i,j))
  857. diffCy(i,j)=0.5*(diffLy(i,j) + diffRy(i,j))
  858. enddo
  859. enddo
  860. end subroutine meshdiffc_2d
  861. subroutine meshdiff_2d(ids, ide, jds,jde , & ! mesh area used (in cells, end +1)
  862. ims1,ime1,jms1,jme1, & ! dimensions of lfn
  863. dx,dy, & ! mesh spacing
  864. lfn, & ! input
  865. diffLx,diffRx,diffLy,diffRy) ! output
  866. implicit none
  867. !*** purpose
  868. ! one-sided differences on a 2d mesh
  869. !*** arguments
  870. integer, intent(in)::ids,ide,jds,jde,ims1,ime1,jms1,jme1
  871. real, intent(in):: dx,dy
  872. real, intent(in), dimension(ims1:ime1,jms1:jme1):: lfn
  873. real, intent(out), dimension(ims1:ime1,jms1:jme1):: diffLx,diffRx,diffLy,diffRy
  874. !*** local
  875. integer:: i,j
  876. real:: tmpx,tmpy
  877. !*** executable
  878. call check_mesh_2dim(ids,ide+1,jds,jde+1,ims1,ime1,jms1,jme1)
  879. ! the bulk of the work
  880. do j=jds,jde
  881. do i=ids,ide
  882. tmpx = (lfn(i+1,j)-lfn(i,j))/dx
  883. diffLx(i+1,j) = tmpx
  884. diffRx(i,j) = tmpx
  885. tmpy = (lfn(i,j+1)-lfn(i,j))/dy
  886. diffLy(i,j+1) = tmpy
  887. diffRy(i,j) = tmpy
  888. enddo
  889. ! missing values - put there the other one
  890. diffLx(ids,j) = diffLx(ids+1,j)
  891. diffRx(ide+1,j)= diffRx(ide,j)
  892. enddo
  893. ! cleanup
  894. ! j=jde+1 from above loop
  895. do i=ids,ide
  896. tmpx = (lfn(i+1,j)-lfn(i,j))/dx
  897. diffLx(i+1,j) = tmpx
  898. diffRx(i,j) = tmpx
  899. enddo
  900. ! i=ide+1 from above loop
  901. do j=jds,jde
  902. tmpy = (lfn(i,j+1)-lfn(i,j))/dy
  903. diffLy(i,j+1) = tmpy
  904. diffRy(i,j) = tmpy
  905. enddo
  906. ! missing values - put there the other one
  907. ! j=jde+1 from above loop, j=jds:jde done before in main bulk loop
  908. diffLx(ids,j) = diffLx(ids+1,j)
  909. diffRx(ide+1,j) = diffRx(ide,j)
  910. do i=ids,ide+1
  911. diffLy(i,jds) = diffLy(i,jds+1)
  912. diffRy(i,jde+1) = diffRy(i,jde)
  913. enddo
  914. end subroutine meshdiff_2d
  915. real pure function sum_2darray( its,ite,jts,jte, &
  916. ims,ime,jms,jme, &
  917. a)
  918. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
  919. real, intent(in)::a(ims:ime,jms:jme)
  920. !*** local
  921. integer:: i,j
  922. real:: t
  923. t=0.
  924. do j=jts,jte
  925. do i=its,ite
  926. t=t+a(i,j)
  927. enddo
  928. enddo
  929. sum_2darray = t
  930. end function sum_2darray
  931. real pure function max_2darray( its,ite,jts,jte, &
  932. ims,ime,jms,jme, &
  933. a)
  934. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
  935. real, intent(in)::a(ims:ime,jms:jme)
  936. !*** local
  937. integer:: i,j
  938. real:: t
  939. t=0.
  940. do j=jts,jte
  941. do i=its,ite
  942. t=max(t,a(i,j))
  943. enddo
  944. enddo
  945. max_2darray = t
  946. end function max_2darray
  947. subroutine print_2d_stats_vec(ips,ipe,jps,jpe, &
  948. ims,ime,jms,jme, &
  949. ax,ay,name)
  950. implicit none
  951. integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme
  952. real, intent(in), dimension(ims:ime,jms:jme)::ax,ay
  953. character(len=*),intent(in)::name
  954. integer:: i,j
  955. real:: t
  956. real:: avg_a,max_a,min_a
  957. character(len=25)::id
  958. id=name
  959. call print_2d_stats(ips,ipe,jps,jpe, &
  960. ims,ime,jms,jme, &
  961. ax,id//'/x ')
  962. call print_2d_stats(ips,ipe,jps,jpe, &
  963. ims,ime,jms,jme, &
  964. ay,id//'/y ')
  965. avg_a=0
  966. max_a=-huge(max_a)
  967. min_a= huge(min_a)
  968. do j=jps,jpe
  969. do i=ips,ipe
  970. t=sqrt(ax(i,j)**2+ay(i,j)**2)
  971. max_a=max(max_a,t)
  972. min_a=min(min_a,t)
  973. avg_a=avg_a+t
  974. enddo
  975. enddo
  976. avg_a = avg_a/((ipe-ips+1)*(jpe-jps+1))
  977. call print_stat_line(id//'/sz',ips,ipe,jps,jpe,min_a,max_a,avg_a)
  978. end subroutine print_2d_stats_vec
  979. subroutine print_stat_line(name,ips,ipe,jps,jpe,min_a,max_a,avg_a)
  980. !*** encapsulate line with statistics
  981. implicit none
  982. !*** arguments
  983. integer, intent(in)::ips,ipe,jps,jpe
  984. character(len=*),intent(in)::name
  985. real,intent(in)::min_a,max_a,avg_a
  986. !*** local
  987. character(len=128)::msg
  988. character(len=24)::id
  989. !*** executable
  990. if(.not.avg_a.eq.avg_a)then
  991. msg='NaN detected in '//trim(name)
  992. call crash(msg)
  993. endif
  994. if(fire_print_msg.eq.0)return
  995. id=name
  996. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  997. write(msg,'(a,4i4,3g11.3)')id,ips,ipe,jps,jpe,min_a,max_a,avg_a
  998. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  999. call message(msg,level=2)
  1000. end subroutine print_stat_line
  1001. subroutine print_3d_stats_by_slice(ips,ipe,kps,kpe,jps,jpe, &
  1002. ims,ime,kms,kme,jms,jme, &
  1003. a,name)
  1004. implicit none
  1005. integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme,kms,kme,kps,kpe
  1006. real, intent(in)::a(ims:ime,kms:kme,jms:jme)
  1007. character(len=*),intent(in)::name
  1008. integer::k
  1009. character(len=128)::msg
  1010. do k=kps,kpe
  1011. ! print 3d stats for each horizontal slice separately
  1012. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  1013. write(msg,'(i2,1x,a)')k,name
  1014. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  1015. call print_3d_stats(ips,ipe,k,k,jps,jpe, &
  1016. ims,ime,kms,kme,jms,jme, &
  1017. a,msg)
  1018. enddo
  1019. end subroutine print_3d_stats_by_slice
  1020. subroutine print_3d_stats(ips,ipe,kps,kpe,jps,jpe, &
  1021. ims,ime,kms,kme,jms,jme, &
  1022. a,name)
  1023. implicit none
  1024. integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme,kms,kme,kps,kpe
  1025. real, intent(in)::a(ims:ime,kms:kme,jms:jme)
  1026. character(len=*),intent(in)::name
  1027. integer:: i,j,k
  1028. real:: avg_a,max_a,min_a,t,aa,bb
  1029. character(len=128)::msg
  1030. ! if(fire_print_msg.eq.0)return
  1031. ! check for nans in any case
  1032. bb=0.
  1033. do j=jps,jpe
  1034. do k=kps,kpe
  1035. do i=ips,ipe
  1036. bb=bb+a(i,k,j)
  1037. enddo
  1038. enddo
  1039. enddo
  1040. if(bb.eq.bb.and.fire_print_msg.eq.0)return
  1041. avg_a=0.
  1042. max_a=-huge(max_a)
  1043. min_a= huge(min_a)
  1044. t=huge(t)
  1045. do j=jps,jpe
  1046. do k=kps,kpe
  1047. do i=ips,ipe
  1048. aa=a(i,k,j)
  1049. if(aa.ne.aa.or..not.aa.le.t.or..not.aa.ge.-t)goto 9
  1050. max_a=max(max_a,aa)
  1051. min_a=min(min_a,aa)
  1052. avg_a=avg_a+aa
  1053. enddo
  1054. enddo
  1055. enddo
  1056. if(bb.ne.bb)goto 10 ! should never happen
  1057. if(fire_print_msg.le.0)return
  1058. avg_a = avg_a/((ipe-ips+1)*(jpe-jps+1)*(kpe-kps+1))
  1059. call print_stat_line(name,ips,ipe,jps,jpe,min_a,max_a,avg_a)
  1060. return
  1061. 9 continue
  1062. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  1063. write(msg,1)name,i,k,j,aa
  1064. call message(msg,level=0)
  1065. 1 format(a30,'(',i6,',',i6,',',i6,') = ',g13.5)
  1066. write(msg,2)'patch dimensions ',ips,ipe,kps,kpe,jps,jpe
  1067. call message(msg,level=0)
  1068. write(msg,2)'memory dimensions',ims,ime,kms,kme,jms,jme
  1069. call message(msg,level=0)
  1070. 2 format(a,6i8)
  1071. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  1072. call print_stat_line(name,ips,ipe,jps,jpe,aa,aa,aa)
  1073. if(aa.ne.aa)goto 10
  1074. msg='Invalid floating point number detected in '//name
  1075. call crash(msg)
  1076. 10 msg='NaN detected in '//name
  1077. call crash(msg)
  1078. end subroutine print_3d_stats
  1079. subroutine print_2d_stats(ips,ipe,jps,jpe, &
  1080. ims,ime,jms,jme, &
  1081. a,name)
  1082. implicit none
  1083. integer, intent(in)::ips,ipe,jps,jpe,ims,ime,jms,jme
  1084. real, intent(in)::a(ims:ime,jms:jme)
  1085. character(len=*),intent(in)::name
  1086. !!character(len=128)::msg
  1087. !if(fire_print_msg.eq.0)return
  1088. call print_3d_stats(ips,ipe,1,1,jps,jpe, &
  1089. ims,ime,1,1,jms,jme, &
  1090. a,name)
  1091. !!write(msg,'(2a,z16)')name,' address =',loc(a)
  1092. !!call message(msg)
  1093. end subroutine print_2d_stats
  1094. real pure function avg_2darray( its,ite,jts,jte, &
  1095. ims,ime,jms,jme, &
  1096. a)
  1097. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
  1098. real, intent(in)::a(ims:ime,jms:jme)
  1099. !*** local
  1100. !*** executable
  1101. avg_2darray = sum_2darray( its,ite,jts,jte, &
  1102. ims,ime,jms,jme, &
  1103. a)/((ite-its+1)*(jte-jts+1))
  1104. end function avg_2darray
  1105. real pure function avg_2darray_vec( its,ite,jts,jte, &
  1106. ims,ime,jms,jme, &
  1107. ax,ay)
  1108. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
  1109. real, intent(in), dimension(ims:ime,jms:jme):: ax,ay
  1110. !*** local
  1111. integer:: i,j
  1112. real:: t
  1113. t=0.
  1114. do j=jts,jte
  1115. do i=its,ite
  1116. t=t+sqrt(ax(i,j)**2+ay(i,j)**2)
  1117. enddo
  1118. enddo
  1119. t = t/((ite-its+1)*(jte-jts+1))
  1120. avg_2darray_vec = t
  1121. end function avg_2darray_vec
  1122. subroutine print_array(its,ite,jts,jte, &
  1123. ims,ime,jms,jme, &
  1124. a,name,id)
  1125. ! debug
  1126. !*** arguments
  1127. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,id
  1128. real, intent(in), dimension(ims:ime,jms:jme):: a
  1129. character(len=*),intent(in)::name
  1130. !****
  1131. integer i,j
  1132. character(len=128)::msg
  1133. !****
  1134. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  1135. write(msg,*)name,' start ',id,' dim ',its,ite,jts,jte
  1136. call message(msg)
  1137. do j=jts,jte
  1138. do i=its,ite
  1139. write(msg,*)i,j,a(i,j)
  1140. call message(msg)
  1141. enddo
  1142. enddo
  1143. write(msg,*)name,' end ',id
  1144. call message(msg)
  1145. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  1146. end subroutine print_array
  1147. subroutine write_array_m(its,ite,jts,jte, &
  1148. ims,ime,jms,jme, &
  1149. a,name,id)
  1150. ! debug
  1151. !*** arguments
  1152. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,id
  1153. real, intent(in), dimension(ims:ime,jms:jme):: a
  1154. character(len=*),intent(in)::name
  1155. !****
  1156. call write_array_m3(its,ite,1,1,jts,jte, &
  1157. ims,ime,1,1,jms,jme, &
  1158. a,name,id)
  1159. end subroutine write_array_m
  1160. subroutine write_array_m3(its,ite,kts,kte,jts,jte, &
  1161. ims,ime,kms,kme,jms,jme, &
  1162. a,name,id)
  1163. use module_dm
  1164. implicit none
  1165. ! debug
  1166. !*** arguments
  1167. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme,kts,kte,kms,kme,id
  1168. real, intent(in), dimension(ims:ime,kms:kme,jms:jme):: a
  1169. character(len=*),intent(in)::name
  1170. !****
  1171. integer i,j,k,iu,ilen,myproc,nprocs
  1172. logical op
  1173. character(len=128)::fname,msg
  1174. !****
  1175. if(fire_print_file.eq.0.or.id.le.0)return
  1176. call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
  1177. call wrf_get_nproc (nprocs)
  1178. call wrf_get_myproc(myproc)
  1179. !$OMP CRITICAL(SFIRE_UTIL_CRIT)
  1180. if(nprocs.eq.1)then
  1181. write(fname,3)name,'_',id,'.txt'
  1182. else
  1183. write(fname,4)name,'_',id,'.',myproc,'.txt'
  1184. endif
  1185. iu=0
  1186. do i=6,99
  1187. inquire(unit=i,opened=op)
  1188. if(.not.op.and.iu.le.0)iu=i
  1189. enddo
  1190. if(iu.gt.0)open(iu,file=trim(fname),form='formatted',status='unknown')
  1191. if(iu.le.0)call crash('write_array_m: cannot find available fortran unit')
  1192. write(iu,1)real(its)
  1193. write(iu,1)real(ite)
  1194. write(iu,1)real(jts)
  1195. write(iu,1)real(jte)
  1196. write(iu,1)real(kts)
  1197. write(iu,1)real(kte)
  1198. write(iu,1)(((a(i,k,j),i=its,ite),j=jts,jte),k=kts,kte)
  1199. close(iu)
  1200. write(msg,2)name,'(',its,':',ite,',',jts,':',jte,',', &
  1201. kts,':',kte,') -> ',trim(fname)
  1202. !$OMP END CRITICAL(SFIRE_UTIL_CRIT)
  1203. call message(msg)
  1204. return
  1205. 1 format(e20.12)
  1206. 2 format(2a,3(i5,a,i5,a),2a)
  1207. 3 format(a,a,i8.8,a)
  1208. 4 format(a,a,i8.8,a,i4.4,a)
  1209. end subroutine write_array_m3
  1210. !
  1211. !***
  1212. !
  1213. subroutine read_array_2d_real(filename,a,its,ite,jts,jte,ims,ime,jms,jme)
  1214. use module_dm
  1215. #ifdef _OPENMP
  1216. use OMP_LIB
  1217. #endif
  1218. implicit none
  1219. !*** purpose: read a 2D array from a text file
  1220. ! file format: line 1: array dimensions ni,nj
  1221. ! following lines: one row of a at a time
  1222. ! each row may be split between several lines
  1223. !*** arguments
  1224. integer, intent(in)::its,ite,jts,jte,ims,ime,jms,jme
  1225. real, intent(out), dimension(ims:ime,jms:jme):: a
  1226. character(len=*),intent(in)::filename
  1227. !*** local
  1228. integer i,j,ni,nj,mi,mj,nprocs,myproc,mythread,iu
  1229. logical op
  1230. character(len=128)::fname,msg
  1231. !*** executable
  1232. call wrf_get_nproc (nprocs)
  1233. call wrf_get_myproc( myproc )
  1234. mythread=0
  1235. #ifdef _OPENMP
  1236. mythread=omp_get_thread_num()
  1237. #endif
  1238. if(nprocs.ne.1.or.myproc.ne.0.or.mythread.ne.0) &
  1239. call crash('read_array_2d: parallel execution not supported')
  1240. ! print line
  1241. mi=ite-its+1
  1242. mj=jte-jts+1
  1243. write(msg,2)'reading array size ',mi,mj,' from file ',trim(filename)
  1244. 2 format(a,2i6,2a)
  1245. call message(msg,level=1)
  1246. ! check array index overflow
  1247. call check_mesh_2dim(its,ite,jts,jte,ims,ime,jms,jme)
  1248. ! find available unit
  1249. iu=0
  1250. do i=11,99
  1251. inquire(unit=i,opened=op)
  1252. if(.not.op.and.iu.le.0)iu=i
  1253. enddo
  1254. if(iu.le.0)call crash('read_array_2d: cannot find available fortran unit')
  1255. if(iu.gt.0)open(iu,file=filename,form='formatted',status='old',err=9)
  1256. rewind(iu,err=9)
  1257. read(iu,*,err=10)ni,nj
  1258. if(ni.ne.mi.or.nj.ne.mj)then
  1259. write(msg,'(a,2i6,a,2i6)')'Array dimensions',ni,nj,' in the input file should be ',mi,mj
  1260. call message(msg,level=0)
  1261. goto 10
  1262. endif
  1263. do i=its,ite
  1264. read(iu,*,err=10)(a(i,j),j=jts,jte)
  1265. enddo
  1266. close(iu,err=11)
  1267. call print_2d_stats(its,ite,jts,jte, &
  1268. ims,ime,jms,jme, &
  1269. a,filename)
  1270. write(6,*)its,jts,a(its,jts),loc(a(its,jts))
  1271. return
  1272. 9 msg='Error opening file '//trim(filename)
  1273. call crash(msg)
  1274. 10 msg='Error reading file '//trim(filename)
  1275. call crash(msg)
  1276. 11 msg='Error closing file '//trim(filename)
  1277. call crash(msg)
  1278. end subroutine read_array_2d_real
  1279. !
  1280. !***
  1281. !
  1282. ! general conditional expression
  1283. pure integer function ifval(l,i,j)
  1284. implicit none
  1285. logical, intent(in)::l
  1286. integer, intent(in)::i,j
  1287. if(l)then
  1288. ifval=i
  1289. else
  1290. ifval=j
  1291. endif
  1292. end function ifval
  1293. ! function to go beyond domain boundary if tile is next to it
  1294. pure integer function snode(t,d,i)
  1295. implicit none
  1296. integer, intent(in)::t,d,i
  1297. if(t.ne.d)then
  1298. snode=t
  1299. else
  1300. snode=t+i
  1301. endif
  1302. end function snode
  1303. subroutine print_chsum( id, &
  1304. ims,ime,kms,kme,jms,jme, & ! memory dims
  1305. ids,ide,kds,kde,jds,jde, & ! domain dims
  1306. ips,ipe,kps,kpe,jps,jpe, & ! patch or tile dims
  1307. istag,kstag,jstag, &
  1308. a,name)
  1309. #ifdef DM_PARALLEL
  1310. USE module_dm , only : wrf_dm_bxor_integer
  1311. #endif
  1312. integer, intent(in):: id, &
  1313. ims,ime,kms,kme,jms,jme, & ! memory dims
  1314. ids,ide,kds,kde,jds,jde, & ! domain dims
  1315. ips,ipe,kps,kpe,jps,jpe, & ! patch dims
  1316. istag,kstag,jstag
  1317. real, intent(in),dimension(ims:ime,kms:kme,jms:jme)::a
  1318. character(len=*)::name
  1319. !$ external, logical:: omp_in_parallel
  1320. !$ external, integer:: omp_get_thread_num
  1321. !*** local
  1322. integer::lsum
  1323. integer::i,j,k,n,ipe1,jpe1,kpe1,iel,thread,is,js,ks
  1324. integer, save::psum,gsum
  1325. real::rel
  1326. equivalence(rel,iel)
  1327. character(len=256)msg
  1328. if(fire_print_msg.le.0)return
  1329. ipe1=ifval(ipe.eq.ide.and.istag.ne.0,ipe+1,ipe)
  1330. kpe1=ifval(kpe.eq.kde.and.kstag.ne.0,kpe+1,kpe)
  1331. jpe1=ifval(jpe.eq.jde.and.jstag.ne.0,jpe+1,jpe)
  1332. is=ifval(istag.ne.0,1,0)
  1333. ks=ifval(kstag.ne.0,1,0)
  1334. js=ifval(jstag.ne.0,1,0)
  1335. lsum=0
  1336. do j=jps,jpe1
  1337. do k=kps,kpe1
  1338. do i=ips,ipe1
  1339. rel=a(i,k,j)
  1340. lsum=ieor(lsum,iel)
  1341. enddo
  1342. enddo
  1343. enddo
  1344. ! get process sum over all threads
  1345. thread=0
  1346. !$ thread=omp_get_thread_num()
  1347. if(thread.eq.0)psum=0
  1348. !$OMP BARRIER
  1349. !$OMP CRITICAL(CHSUM)
  1350. psum=ieor(psum,lsum)
  1351. !$OMP END CRITICAL(CHSUM)
  1352. !$OMP BARRIER
  1353. ! get global sum over all processes
  1354. if(thread.eq.0)then
  1355. #ifdef DM_PARALLEL
  1356. gsum = wrf_dm_bxor_integer ( psum )
  1357. #else
  1358. gsum = psum
  1359. #endif
  1360. write(msg,1)id,name,ids,ide+is,kds,kde+ks,jds,jde+js,gsum
  1361. 1 format(i6,1x,a10,' dims',6i5,' chsum ',z8.8)
  1362. call message(msg)
  1363. endif
  1364. end subroutine print_chsum
  1365. real function fun_real(fun, &
  1366. ims,ime,kms,kme,jms,jme, & ! memory dims
  1367. ids,ide,kds,kde,jds,jde, & ! domain dims
  1368. ips,ipe,kps,kpe,jps,jpe, & ! patch or tile dims
  1369. istag,kstag,jstag, & ! staggering
  1370. a,b)
  1371. #ifdef DM_PARALLEL
  1372. USE module_dm , only : wrf_dm_sum_real , wrf_dm_max_real
  1373. #endif
  1374. integer, intent(in):: fun, &
  1375. ims,ime,kms,kme,jms,jme, & ! memory dims
  1376. ids,ide,kds,kde,jds,jde, & ! domain dims
  1377. ips,ipe,kps,kpe,jps,jpe, & ! patch dims
  1378. istag,kstag,jstag ! staggering
  1379. real, intent(in),dimension(ims:ime,kms:kme,jms:jme)::a,b
  1380. !*** local
  1381. real::lsum,void
  1382. integer::i,j,k,n,ipe1,jpe1,kpe1,iel,thread,is,js,ks
  1383. real, save::psum,gsum
  1384. real::rel
  1385. logical:: dosum,domax,domin
  1386. character(len=256)msg
  1387. ipe1=ifval(ipe.eq.ide.and.istag.ne.0,ipe+1,ipe)
  1388. kpe1=ifval(kpe.eq.kde.and.kstag.ne.0,kpe+1,kpe)
  1389. jpe1=ifval(jpe.eq.jde.and.jstag.ne.0,jpe+1,jpe)
  1390. is=ifval(istag.ne.0,1,0)
  1391. ks=ifval(kstag.ne.0,1,0)
  1392. js=ifval(jstag.ne.0,1,0)
  1393. if(fun.eq.REAL_SUM)then
  1394. void=0.
  1395. lsum=void
  1396. do j=jps,jpe1
  1397. do k=kps,kpe1
  1398. do i=ips,ipe1
  1399. lsum=lsum+a(i,k,j)
  1400. enddo
  1401. enddo
  1402. enddo
  1403. elseif(fun.eq.RNRM_SUM)then
  1404. void=0.
  1405. lsum=void
  1406. do j=jps,jpe1
  1407. do k=kps,kpe1
  1408. do i=ips,ipe1
  1409. lsum=lsum+sqrt(a(i,k,j)*a(i,k,j)+b(i,k,j)*b(i,k,j))
  1410. enddo
  1411. enddo
  1412. enddo
  1413. elseif(fun.eq.REAL_MAX)then
  1414. void=-huge(lsum)
  1415. lsum=void
  1416. do j=jps,jpe1
  1417. do k=kps,kpe1
  1418. do i=ips,ipe1
  1419. lsum=max(lsum,a(i,k,j))
  1420. enddo
  1421. enddo
  1422. enddo
  1423. elseif(fun.eq.REAL_AMAX)then
  1424. void=-huge(lsum)
  1425. lsum=void
  1426. do j=jps,jpe1
  1427. do k=kps,kpe1
  1428. do i=ips,ipe1
  1429. lsum=max(lsum,abs(a(i,k,j)))
  1430. enddo
  1431. enddo
  1432. enddo
  1433. elseif(fun.eq.REAL_MIN)then
  1434. void=huge(lsum)
  1435. lsum=void
  1436. do j=jps,jpe1
  1437. do k=kps,kpe1
  1438. do i=ips,ipe1
  1439. lsum=min(lsum,a(i,k,j))
  1440. enddo
  1441. enddo
  1442. enddo
  1443. elseif(fun.eq.RNRM_MAX)then
  1444. void=0.
  1445. lsum=void
  1446. do j=jps,jpe1
  1447. do k=kps,kpe1
  1448. do i=ips,ipe1
  1449. lsum=max(lsum,sqrt(a(i,k,j)*a(i,k,j)+b(i,k,j)*b(i,k,j)))
  1450. enddo
  1451. enddo
  1452. enddo
  1453. else
  1454. call crash('fun_real: bad fun')
  1455. endif
  1456. if(lsum.ne.lsum)call crash('fun_real: NaN detected')
  1457. dosum=fun.eq.REAL_SUM.or.fun.eq.RNRM_SUM
  1458. domax=fun.eq.REAL_MAX.or.fun.eq.REAL_AMAX.or.fun.eq.RNRM_MAX
  1459. domin=fun.eq.REAL_MIN
  1460. ! get process sum over all threads
  1461. !$OMP SINGLE
  1462. ! only one thread should write to shared variable
  1463. psum=void
  1464. !$OMP END SINGLE

Large files files are truncated, but you can click here to view the full file