tmm_cf.F90 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. !###############################################################################
  2. !
  3. ! Converstion from TM5 names/units to CF standard names/units
  4. !
  5. ! USAGE
  6. !
  7. ! use TMM_CF
  8. !
  9. ! ! initialize module:
  10. ! ! o read name of CF standard table from rcfile key 'cf-standard-name-table'
  11. ! call TMM_CF_Init( rcf, status )
  12. ! type(TRcFile), intent(in) :: rcf
  13. ! integer, intent(out) :: status
  14. !
  15. ! ! get standard units for standard name:
  16. ! call TMM_CF_Standard_Units( cf_standard_name, cf_units, status )
  17. ! character(len=*), intent(in) :: cf_standard_name
  18. ! character(len=*), intent(out) :: cf_units
  19. ! integer, intent(out) :: status
  20. !
  21. ! ! convert from TM5 variable name to CF standard name:
  22. ! call TMM_CF_Convert_Name( tm5_name, cf_standard_name, status )
  23. ! character(len=*), intent(in) :: tm5_name
  24. ! character(len=*), intent(out) :: cf_standard_name
  25. ! integer, intent(out) :: status
  26. !
  27. ! ! get conversion factor from TM5 units to CF standard unit:
  28. ! call subroutine TMM_CF_Convert_Units( tm5_units, cf_units, tm5_to_cf_factor, status )
  29. ! character(len=*), intent(in) :: tm5_units
  30. ! character(len=*), intent(in) :: cf_units
  31. ! real, intent(out) :: tm5_to_cf_factor
  32. ! integer, intent(out) :: status
  33. !
  34. ! ! done with module:
  35. ! call TMM_CF_Done( status )
  36. ! integer, intent(out) :: status
  37. !
  38. !
  39. ! EXTERNAL LIBRARIES
  40. !
  41. ! Module uses the 'UDUnits' library (either old FORTRAN version 1.x [with_udunits1], or C version
  42. ! 2.x [with_udunits2]).
  43. !
  44. !###############################################################################
  45. !
  46. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  47. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  48. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  49. !
  50. #ifdef with_udunits1
  51. #define IF_UDUNITS_NOTOK_RETURN(action) if (status/=UDUNITS_NOERR) then; gol=trim(UDUnits_StrError(status)); call goErr; TRACEBACK; action; return; end if
  52. #endif
  53. !
  54. #include "tmm.inc"
  55. !
  56. !###############################################################################
  57. module TMM_CF
  58. use GO , only : gol, goErr, goPr
  59. #ifdef with_udunits1
  60. use UDUnits, only : UDUNITS_NOERR, UDUnits_StrError
  61. #endif
  62. #ifdef with_udunits2
  63. use ISO_C_BINDING
  64. #endif
  65. use Standard_Name_Table, only : T_Standard_Name_Table
  66. implicit none
  67. private
  68. public :: TMM_CF_Init, TMM_CF_Done
  69. public :: TMM_CF_Standard_Units
  70. public :: TMM_CF_Convert_Name
  71. public :: TMM_CF_Convert_Units
  72. ! --- const ------------------------------------
  73. character(len=*), parameter :: mname = 'TMM_CF'
  74. ! rcfile key with name of standard table:
  75. character(len=*), parameter :: rckey_cf_table = 'cf-standard-name-table'
  76. ! --- local ------------------------------------
  77. logical :: with_cf_table
  78. type(T_Standard_Name_Table), save :: cf_table
  79. contains
  80. ! ==============================================================
  81. subroutine TMM_CF_Init( rcf, status )
  82. use GO , only : TrcFile, ReadRc
  83. use Standard_Name_Table, only : Standard_Name_Table_Init
  84. #ifdef with_udunits1
  85. use UDUnits , only : UDUnits_Init
  86. #endif
  87. ! --- in/out ---------------------------------
  88. type(TRcFile), intent(in) :: rcf
  89. integer, intent(out) :: status
  90. ! --- const ----------------------------------
  91. character(len=*), parameter :: rname = mname//'/TMM_CF_Init'
  92. ! --- local ----------------------------------
  93. character(len=512) :: cf_standard_name_table
  94. ! --- begin ----------------------------------
  95. ! read full path of cf table:
  96. call ReadRc( rcF, rckey_cf_table, cf_standard_name_table, &
  97. status, default='None' )
  98. IF_ERROR_RETURN(status=1)
  99. ! set flag to false if key was not found:
  100. with_cf_table = trim(cf_standard_name_table) /= 'None'
  101. ! key provided ?
  102. if ( with_cf_table ) then
  103. ! standard names and units:
  104. call Standard_Name_Table_Init( cf_table, trim(cf_standard_name_table), status )
  105. if (status/=0) then
  106. write(gol,*) "problem with file '"//trim(cf_standard_name_table)//"'"; call goErr
  107. write(gol,*) "this file is defined through the '"//trim(rckey_cf_table)//"' rc key in your meteo file"; call goErr
  108. IF_NOTOK_RETURN(status=1)
  109. endif
  110. end if
  111. #ifdef with_udunits1
  112. ! initialize UDUnits module:
  113. call UDUnits_Init( status )
  114. IF_UDUNITS_NOTOK_RETURN(status=1)
  115. #endif
  116. ! ok
  117. status = 0
  118. end subroutine TMM_CF_Init
  119. ! ***
  120. subroutine TMM_CF_Done( status )
  121. use Standard_Name_Table, only : Standard_Name_Table_Done
  122. #ifdef with_udunits1
  123. use UDUnits , only : UDUnits_Done
  124. #endif
  125. ! --- in/out ---------------------------------
  126. integer, intent(out) :: status
  127. ! --- const ----------------------------------
  128. character(len=*), parameter :: rname = mname//'/TMM_CF_Done'
  129. ! --- local ----------------------------------
  130. ! --- begin ----------------------------------
  131. ! standard table present ?
  132. if ( with_cf_table ) then
  133. ! done with standard names and units:
  134. call Standard_Name_Table_Done( cf_table, status )
  135. IF_NOTOK_RETURN(status=1)
  136. end if
  137. #ifdef with_udunits1
  138. ! done with UDUnits module:
  139. call UDUnits_Done( status )
  140. IF_UDUNITS_NOTOK_RETURN(status=1)
  141. #endif
  142. ! ok
  143. status = 0
  144. end subroutine TMM_CF_Done
  145. ! ***
  146. subroutine TMM_CF_Standard_Units( cf_standard_name, cf_units, status )
  147. ! --- in/out ---------------------------------
  148. character(len=*), intent(in) :: cf_standard_name
  149. character(len=*), intent(out) :: cf_units
  150. integer, intent(out) :: status
  151. ! --- const ----------------------------------
  152. character(len=*), parameter :: rname = mname//'/TMM_CF_Standard_Units'
  153. ! --- local ----------------------------------
  154. integer :: i, j
  155. ! --- begin ----------------------------------
  156. ! no unit yet ...
  157. cf_units = ''
  158. ! check for specials ...
  159. select case ( trim(cf_standard_name) )
  160. ! TM5 special fields
  161. case ( 'tm5_integrated_eastward_mass_flux_of_air' ) ; cf_units = 'kg s-1'
  162. case ( 'tm5_integrated_northward_mass_flux_of_air' ) ; cf_units = 'kg s-1'
  163. case ( 'tm5_integrated_upward_mass_flux_of_air' ) ; cf_units = 'kg s-1'
  164. case ( 'ch4fire' ) ; cf_units = 'kg m-2 s-1'
  165. ! CF standard fields
  166. case default
  167. ! *
  168. ! check ..
  169. if ( .not. with_cf_table ) then
  170. write (gol,'("No CF table specified with rcfile key `",a,"`")') &
  171. trim(rckey_cf_table); call goErr
  172. TRACEBACK; status=1; return
  173. end if
  174. ! *
  175. ! loop over all entries:
  176. do i = 1, size(cf_table%entry)
  177. ! compare ...
  178. if ( trim(cf_table%entry(i)%id) == trim(cf_standard_name) ) then
  179. ! copy values:
  180. cf_units = trim(cf_table%entry(i)%canonical_units)
  181. ! found!
  182. exit
  183. end if
  184. end do ! CF table entries
  185. ! *
  186. ! not found yet ? then check alia:
  187. if ( len_trim(cf_units) == 0 ) then
  188. ! loop over all alia:
  189. do j = 1, size(cf_table%alias)
  190. ! compare ...
  191. if ( trim(cf_table%alias(j)%id) == trim(cf_standard_name) ) then
  192. ! match; now search real entries:
  193. do i = 1, size(cf_table%entry)
  194. ! compare ...
  195. if ( trim(cf_table%entry(i)%id) == trim(cf_table%alias(j)%entry_id) ) then
  196. ! copy values:
  197. cf_units = trim(cf_table%entry(i)%canonical_units)
  198. ! leave:
  199. exit
  200. end if
  201. end do ! CF table entries
  202. ! found!
  203. exit
  204. end if
  205. end do ! CF table alia
  206. end if
  207. ! *
  208. end select
  209. ! not found ?
  210. if ( len_trim(cf_units) == 0 ) then
  211. write (gol,'("id not found in cf standard name table : ",a)') trim(cf_standard_name); call goErr
  212. TRACEBACK; status=1; return
  213. end if
  214. ! ok
  215. status = 0
  216. end subroutine TMM_CF_Standard_Units
  217. ! ***
  218. subroutine TMM_CF_Convert_Name( tm5_name, cf_standard_name, status )
  219. ! --- in/out ---------------------------------
  220. character(len=*), intent(in) :: tm5_name
  221. character(len=*), intent(out) :: cf_standard_name
  222. integer, intent(out) :: status
  223. ! --- const ----------------------------------
  224. character(len=*), parameter :: rname = mname//'/TMM_CF_Convert_Name'
  225. ! --- local ----------------------------------
  226. ! --- begin ----------------------------------
  227. ! convert from TM5 internal name to CF standard name:
  228. select case ( trim(tm5_name) )
  229. case ( 'lon' ) ; cf_standard_name = 'longitude'
  230. case ( 'lat' ) ; cf_standard_name = 'latitude'
  231. case ( 'sp' ) ; cf_standard_name = 'surface_air_pressure'
  232. case ( 'mfu' ) ; cf_standard_name = 'tm5_integrated_eastward_mass_flux_of_air'
  233. case ( 'mfv' ) ; cf_standard_name = 'tm5_integrated_northward_mass_flux_of_air'
  234. case ( 'mfw' ) ; cf_standard_name = 'tm5_integrated_upward_mass_flux_of_air'
  235. case ( 'tsp' ) ; cf_standard_name = 'tendency_of_surface_air_pressure'
  236. case ( 'oro' ) ; cf_standard_name = 'geopotential'
  237. case ( 'T' ) ; cf_standard_name = 'air_temperature'
  238. case ( 'Q' ) ; cf_standard_name = 'specific_humidity'
  239. case ( 'CLWC' ) ; cf_standard_name = 'mass_fraction_of_cloud_liquid_water_in_air'
  240. case ( 'CIWC' ) ; cf_standard_name = 'mass_fraction_of_cloud_ice_in_air'
  241. case ( 'CC' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer'
  242. case ( 'CCO' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer' ! dummy for overhead cloud cover
  243. case ( 'CCU' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer' ! dummy for underfeet cloud cover
  244. case ( 'eu' ) ; cf_standard_name = 'atmosphere_updraft_convective_mass_flux' ! dummy for entrainement updraft
  245. case ( 'ed' ) ; cf_standard_name = 'atmosphere_downdraft_convective_mass_flux' ! dummy for entrainement downdraft
  246. case ( 'du' ) ; cf_standard_name = 'atmosphere_updraft_convective_mass_flux' ! dummy for detrainement updraft
  247. case ( 'dd' ) ; cf_standard_name = 'atmosphere_downdraft_convective_mass_flux' ! dummy for detrainement downdraft
  248. case ( 'cloud_base' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_base'
  249. case ( 'cloud_top' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_top'
  250. case ( 'cloud_lfs' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_top' ! dummy for level-of-free-sinking
  251. case ( 'ssr' ) ; cf_standard_name = 'surface_net_upward_shortwave_flux'
  252. case ( 'ssrd' ) ; cf_standard_name = 'surface_net_downward_shortwave_flux'
  253. case ( 'str' ) ; cf_standard_name = 'surface_net_upward_longwave_flux'
  254. case ( 'strd' ) ; cf_standard_name = 'surface_net_downward_longwave_flux'
  255. case ( 'lsm' ) ; cf_standard_name = 'land_area_fraction'
  256. case ( 'albedo' ) ; cf_standard_name = 'surface_albedo'
  257. case ( 'sr' ) ; cf_standard_name = 'surface_roughness_length'
  258. case ( 'srols' ) ; cf_standard_name = 'surface_roughness_length'
  259. case ( 'ci' ) ; cf_standard_name = 'sea_ice_area_fraction'
  260. case ( 'sst' ) ; cf_standard_name = 'sea_surface_temperature'
  261. case ( 'u10m' ) ; cf_standard_name = 'eastward_wind'
  262. case ( 'v10m' ) ; cf_standard_name = 'northward_wind'
  263. case ( 'g10m' ) ; cf_standard_name = 'wind_speed_of_gust'
  264. case ( 'fg10' ) ; cf_standard_name = 'wind_speed_of_gust'
  265. case ( 'd2m' ) ; cf_standard_name = 'dew_point_temperature'
  266. case ( 't2m' ) ; cf_standard_name = 'air_temperature'
  267. case ( 'skt' ) ; cf_standard_name = 'canopy_temperature'
  268. case ( 'blh' ) ; cf_standard_name = 'atmosphere_boundary_layer_thickness'
  269. case ( 'sshf' ) ; cf_standard_name = 'surface_downward_sensible_heat_flux'
  270. case ( 'slhf' ) ; cf_standard_name = 'surface_downward_latent_heat_flux'
  271. case ( 'ewss' ) ; cf_standard_name = 'surface_downward_eastward_stress'
  272. case ( 'nsss' ) ; cf_standard_name = 'surface_downward_northward_stress'
  273. case ( 'cp' ) ; cf_standard_name = 'lwe_convective_precipitation_rate'
  274. case ( 'lsp' ) ; cf_standard_name = 'lwe_large_scale_precipitation_rate'
  275. case ( 'sf' ) ; cf_standard_name = 'lwe_thickness_of_snowfall_amount'
  276. case ( 'sd' ) ; cf_standard_name = 'lwe_thickness_of_surface_snow_amount'
  277. case ( 'src' ) ; cf_standard_name = 'lwe_thickness_of_canopy_water_amount'
  278. case ( 'swvl1' ) ; cf_standard_name = 'volume_fraction_of_condensed_water_in_soil'
  279. case ( 'tv01', 'tv02', 'tv03', 'tv04', 'tv05', &
  280. 'tv06', 'tv07', 'tv08', 'tv09', 'tv10', &
  281. 'tv11', 'tv12', 'tv13', 'tv14', 'tv15', &
  282. 'tv16', 'tv17', 'tv18', 'tv19', 'tv20' )
  283. cf_standard_name = 'vegetation_area_fraction'
  284. case ( 'cvl', 'cvh' ) ; cf_standard_name = 'vegetation_area_fraction'
  285. case ( 'K' ) ; cf_standard_name = 'atmosphere_heat_diffusivity' ! 162.109 grib code = Turbulent diffusion coefficient for heat
  286. case default
  287. !write (gol,'("do not know cf standard name for tm5 name : ",a)') trim(tm5_name); call goErr
  288. !TRACEBACK; status=1; return
  289. ! assume name follows CF already ..
  290. cf_standard_name = trim(tm5_name)
  291. end select
  292. ! ok
  293. status = 0
  294. end subroutine TMM_CF_Convert_Name
  295. ! ***
  296. SUBROUTINE TMM_CF_Convert_Units( tm5_units, cf_units, tm5_to_cf_factor, status )
  297. #ifdef with_udunits1
  298. use UDUnits, only : UDUnits_ConversionFactor
  299. #endif
  300. #ifdef with_udunits2
  301. use f_udunits_2, only : UT_UNIT_PTR, CV_CONVERTER_PTR, UT_SYSTEM_PTR, f_ut_read_xml
  302. use f_udunits_2, only : UT_ASCII, f_ut_get_converter, f_ut_parse, f_cv_convert
  303. use f_udunits_2, only : f_ut_free, f_ut_free_system, f_cv_free
  304. #endif
  305. ! --- in/out ---------------------------------
  306. character(len=*), intent(in) :: tm5_units
  307. character(len=*), intent(in) :: cf_units
  308. real, intent(out) :: tm5_to_cf_factor
  309. integer, intent(out) :: status
  310. ! --- local ----------------------------------
  311. #ifdef with_udunits2
  312. type(UT_SYSTEM_PTR) :: sys
  313. type(CV_CONVERTER_PTR) :: conv1
  314. type(UT_UNIT_PTR) :: unit1, unit2
  315. real :: a
  316. integer :: charset
  317. #endif
  318. ! --- const ----------------------------------
  319. character(len=*), parameter :: rname = mname//'/TMM_CF_Convert'
  320. ! --- begin ----------------------------------
  321. #ifdef with_udunits1
  322. ! unit conversion factor:
  323. call UDUnits_ConversionFactor( trim(tm5_units), trim(cf_units), tm5_to_cf_factor, status )
  324. if ( status /= UDUNITS_NOERR ) then
  325. write (gol,'("from conversion of TM5 units to CF units:")'); call goErr
  326. write (gol,'(" TM5 units : ",a)') trim(tm5_units); call goErr
  327. write (gol,'(" CF units : ",a)') trim(cf_units); call goErr
  328. TRACEBACK; status=1; return
  329. end if
  330. #elif defined(with_udunits2)
  331. charset = UT_ASCII
  332. sys = f_ut_read_xml("")
  333. unit1 = f_ut_parse(sys,tm5_units,charset)
  334. if(.not. c_associated(unit1%ptr)) then
  335. write(gol,*) 'ERROR from '//trim(tm5_units)//' unit' ; call goErr
  336. TRACEBACK; status=1; return
  337. endif
  338. unit2 = f_ut_parse(sys,cf_units,charset)
  339. if(.not. c_associated(unit2%ptr)) then
  340. write(gol,*) 'ERROR from '//trim(cf_units)//' unit' ; call goErr
  341. TRACEBACK; status=1; return
  342. endif
  343. conv1 = f_ut_get_converter(unit1,unit2)
  344. if(.not. c_associated(conv1%ptr)) then
  345. write(gol,*) 'ERROR from '//trim(cf_units)//' unit' ; call goErr
  346. TRACEBACK; status=1; return
  347. endif
  348. a =1.
  349. tm5_to_cf_factor = f_cv_convert(conv1,a)
  350. call f_ut_free(unit1)
  351. call f_ut_free(unit2)
  352. call f_cv_free(conv1)
  353. call f_ut_free_system(sys)
  354. #else
  355. ! dummy assignment to avoid compiler warnings:
  356. tm5_to_cf_factor = 1.0
  357. ! error ...
  358. write (gol,'("Unit conversion requires `with_udunits1` or `with_udunits2` macro.")'); call goErr
  359. TRACEBACK; status=1; return
  360. #endif
  361. status = 0
  362. END SUBROUTINE TMM_CF_Convert_Units
  363. END MODULE TMM_CF