tmm_cf.F90 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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. ! CF standard fields
  165. case default
  166. ! *
  167. ! check ..
  168. if ( .not. with_cf_table ) then
  169. write (gol,'("No CF table specified with rcfile key `",a,"`")') &
  170. trim(rckey_cf_table); call goErr
  171. TRACEBACK; status=1; return
  172. end if
  173. ! *
  174. ! loop over all entries:
  175. do i = 1, size(cf_table%entry)
  176. ! compare ...
  177. if ( trim(cf_table%entry(i)%id) == trim(cf_standard_name) ) then
  178. ! copy values:
  179. cf_units = trim(cf_table%entry(i)%canonical_units)
  180. ! found!
  181. exit
  182. end if
  183. end do ! CF table entries
  184. ! *
  185. ! not found yet ? then check alia:
  186. if ( len_trim(cf_units) == 0 ) then
  187. ! loop over all alia:
  188. do j = 1, size(cf_table%alias)
  189. ! compare ...
  190. if ( trim(cf_table%alias(j)%id) == trim(cf_standard_name) ) then
  191. ! match; now search real entries:
  192. do i = 1, size(cf_table%entry)
  193. ! compare ...
  194. if ( trim(cf_table%entry(i)%id) == trim(cf_table%alias(j)%entry_id) ) then
  195. ! copy values:
  196. cf_units = trim(cf_table%entry(i)%canonical_units)
  197. ! leave:
  198. exit
  199. end if
  200. end do ! CF table entries
  201. ! found!
  202. exit
  203. end if
  204. end do ! CF table alia
  205. end if
  206. ! *
  207. end select
  208. ! not found ?
  209. if ( len_trim(cf_units) == 0 ) then
  210. write (gol,'("id not found in cf standard name table : ",a)') trim(cf_standard_name); call goErr
  211. TRACEBACK; status=1; return
  212. end if
  213. ! ok
  214. status = 0
  215. end subroutine TMM_CF_Standard_Units
  216. ! ***
  217. subroutine TMM_CF_Convert_Name( tm5_name, cf_standard_name, status )
  218. ! --- in/out ---------------------------------
  219. character(len=*), intent(in) :: tm5_name
  220. character(len=*), intent(out) :: cf_standard_name
  221. integer, intent(out) :: status
  222. ! --- const ----------------------------------
  223. character(len=*), parameter :: rname = mname//'/TMM_CF_Convert_Name'
  224. ! --- local ----------------------------------
  225. ! --- begin ----------------------------------
  226. ! convert from TM5 internal name to CF standard name:
  227. select case ( trim(tm5_name) )
  228. case ( 'lon' ) ; cf_standard_name = 'longitude'
  229. case ( 'lat' ) ; cf_standard_name = 'latitude'
  230. case ( 'sp' ) ; cf_standard_name = 'surface_air_pressure'
  231. case ( 'mfu' ) ; cf_standard_name = 'tm5_integrated_eastward_mass_flux_of_air'
  232. case ( 'mfv' ) ; cf_standard_name = 'tm5_integrated_northward_mass_flux_of_air'
  233. case ( 'mfw' ) ; cf_standard_name = 'tm5_integrated_upward_mass_flux_of_air'
  234. case ( 'tsp' ) ; cf_standard_name = 'tendency_of_surface_air_pressure'
  235. case ( 'oro' ) ; cf_standard_name = 'geopotential'
  236. case ( 'T' ) ; cf_standard_name = 'air_temperature'
  237. case ( 'Q' ) ; cf_standard_name = 'specific_humidity'
  238. case ( 'CLWC' ) ; cf_standard_name = 'mass_fraction_of_cloud_liquid_water_in_air'
  239. case ( 'CIWC' ) ; cf_standard_name = 'mass_fraction_of_cloud_ice_in_air'
  240. case ( 'CC' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer'
  241. case ( 'CCO' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer' ! dummy for overhead cloud cover
  242. case ( 'CCU' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer' ! dummy for underfeet cloud cover
  243. case ( 'eu' ) ; cf_standard_name = 'atmosphere_updraft_convective_mass_flux' ! dummy for entrainement updraft
  244. case ( 'ed' ) ; cf_standard_name = 'atmosphere_downdraft_convective_mass_flux' ! dummy for entrainement downdraft
  245. case ( 'du' ) ; cf_standard_name = 'atmosphere_updraft_convective_mass_flux' ! dummy for detrainement updraft
  246. case ( 'dd' ) ; cf_standard_name = 'atmosphere_downdraft_convective_mass_flux' ! dummy for detrainement downdraft
  247. case ( 'cloud_base' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_base'
  248. case ( 'cloud_top' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_top'
  249. case ( 'cloud_lfs' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_top' ! dummy for level-of-free-sinking
  250. case ( 'ssr' ) ; cf_standard_name = 'surface_net_upward_shortwave_flux'
  251. case ( 'ssrd' ) ; cf_standard_name = 'surface_net_downward_shortwave_flux'
  252. case ( 'str' ) ; cf_standard_name = 'surface_net_upward_longwave_flux'
  253. case ( 'strd' ) ; cf_standard_name = 'surface_net_downward_longwave_flux'
  254. case ( 'lsm' ) ; cf_standard_name = 'land_area_fraction'
  255. case ( 'albedo' ) ; cf_standard_name = 'surface_albedo'
  256. case ( 'sr' ) ; cf_standard_name = 'surface_roughness_length'
  257. case ( 'srols' ) ; cf_standard_name = 'surface_roughness_length'
  258. case ( 'ci' ) ; cf_standard_name = 'sea_ice_area_fraction'
  259. case ( 'sst' ) ; cf_standard_name = 'sea_surface_temperature'
  260. case ( 'u10m' ) ; cf_standard_name = 'eastward_wind'
  261. case ( 'v10m' ) ; cf_standard_name = 'northward_wind'
  262. case ( 'g10m' ) ; cf_standard_name = 'wind_speed_of_gust'
  263. case ( 'fg10' ) ; cf_standard_name = 'wind_speed_of_gust'
  264. case ( 'd2m' ) ; cf_standard_name = 'dew_point_temperature'
  265. case ( 't2m' ) ; cf_standard_name = 'air_temperature'
  266. case ( 'skt' ) ; cf_standard_name = 'canopy_temperature'
  267. case ( 'blh' ) ; cf_standard_name = 'atmosphere_boundary_layer_thickness'
  268. case ( 'sshf' ) ; cf_standard_name = 'surface_downward_sensible_heat_flux'
  269. case ( 'slhf' ) ; cf_standard_name = 'surface_downward_latent_heat_flux'
  270. case ( 'ewss' ) ; cf_standard_name = 'surface_downward_eastward_stress'
  271. case ( 'nsss' ) ; cf_standard_name = 'surface_downward_northward_stress'
  272. case ( 'cp' ) ; cf_standard_name = 'lwe_convective_precipitation_rate'
  273. case ( 'lsp' ) ; cf_standard_name = 'lwe_large_scale_precipitation_rate'
  274. case ( 'sf' ) ; cf_standard_name = 'lwe_thickness_of_snowfall_amount'
  275. case ( 'sd' ) ; cf_standard_name = 'lwe_thickness_of_surface_snow_amount'
  276. case ( 'src' ) ; cf_standard_name = 'lwe_thickness_of_canopy_water_amount'
  277. case ( 'swvl1' ) ; cf_standard_name = 'volume_fraction_of_condensed_water_in_soil'
  278. case ( 'stl1' ) ; cf_standard_name = 'soil_temperature'
  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. !
  297. ! Return factor for conversion from "tm5_units" to "cf_units"
  298. !
  299. SUBROUTINE TMM_CF_Convert_Units( tm5_units, cf_units, tm5_to_cf_factor, status )
  300. #ifdef with_udunits1
  301. use UDUnits, only : UDUnits_ConversionFactor
  302. #endif
  303. #ifdef with_udunits2
  304. use f_udunits_2, only : UT_UNIT_PTR, CV_CONVERTER_PTR, UT_SYSTEM_PTR, f_ut_read_xml
  305. use f_udunits_2, only : UT_ASCII, f_ut_get_converter, f_ut_parse, f_cv_convert
  306. use f_udunits_2, only : f_ut_free, f_ut_free_system, f_cv_free
  307. #endif
  308. ! --- in/out ---------------------------------
  309. character(len=*), intent(in) :: tm5_units
  310. character(len=*), intent(in) :: cf_units
  311. real, intent(out) :: tm5_to_cf_factor
  312. integer, intent(out) :: status
  313. ! --- local ----------------------------------
  314. #ifdef with_udunits2
  315. type(UT_SYSTEM_PTR) :: sys
  316. type(CV_CONVERTER_PTR) :: conv1
  317. type(UT_UNIT_PTR) :: unit1, unit2
  318. real :: a
  319. integer :: charset
  320. #endif
  321. ! --- const ----------------------------------
  322. character(len=*), parameter :: rname = mname//'/TMM_CF_Convert'
  323. ! --- local ----------------------------------
  324. character(len=64) :: conversion
  325. ! --- begin ----------------------------------
  326. ! same?
  327. if ( trim(tm5_units) == trim(cf_units) ) then
  328. ! no conversion:
  329. tm5_to_cf_factor = 1.0
  330. else
  331. ! conversion:
  332. write (conversion,'(a," -> ",a)') trim(tm5_units), trim(cf_units)
  333. ! known conversions ...
  334. select case ( trim(conversion) )
  335. case ( 'kg s-1 -> kg/s', &
  336. 'm2 s-2 -> m m/s2', &
  337. '1 -> kg/kg', &
  338. 'kg m-2 s-1 -> kg/m2/s', &
  339. 'W m-2 -> W/m2', &
  340. 'Pa -> N/m2', &
  341. 'm s-1 -> m/s' )
  342. ! no conversion needed:
  343. tm5_to_cf_factor = 1.0
  344. case ( '1 -> %' )
  345. tm5_to_cf_factor = 100.0
  346. case default
  347. #ifdef with_udunits1
  348. ! unit conversion factor:
  349. call UDUnits_ConversionFactor( trim(tm5_units), trim(cf_units), tm5_to_cf_factor, status )
  350. if ( status /= UDUNITS_NOERR ) then
  351. write (gol,'("from conversion of TM5 units to CF units:")'); call goErr
  352. write (gol,'(" TM5 units : ",a)') trim(tm5_units); call goErr
  353. write (gol,'(" CF units : ",a)') trim(cf_units); call goErr
  354. TRACEBACK; status=1; return
  355. end if
  356. #elif defined(with_udunits2)
  357. charset = UT_ASCII
  358. sys = f_ut_read_xml("")
  359. unit1 = f_ut_parse(sys,tm5_units,charset)
  360. if ( .not. c_associated(unit1%ptr) ) then
  361. write (gol,'("from parsing input units `",a,"`")') trim(tm5_units); call goErr
  362. TRACEBACK; status=1; return
  363. endif
  364. unit2 = f_ut_parse(sys,cf_units,charset)
  365. if ( .not. c_associated(unit2%ptr) ) then
  366. write (gol,'("from parsing target units `",a,"`")') trim(cf_units); call goErr
  367. TRACEBACK; status=1; return
  368. endif
  369. conv1 = f_ut_get_converter(unit1,unit2)
  370. if ( .not. c_associated(conv1%ptr)) then
  371. write (gol,'("from converting input units `",a,"` to target units `",a,"`")') &
  372. trim(tm5_units), trim(cf_units); call goErr
  373. TRACEBACK; status=1; return
  374. endif
  375. a = 1.0
  376. tm5_to_cf_factor = f_cv_convert(conv1,a)
  377. call f_ut_free(unit1)
  378. call f_ut_free(unit2)
  379. call f_cv_free(conv1)
  380. call f_ut_free_system(sys)
  381. #else
  382. ! dummy assignment to avoid compiler warnings:
  383. tm5_to_cf_factor = 1.0
  384. ! error ...
  385. write (gol,'("Unsupported unit conversion `",a,"` required.")') trim(conversion); call goPr
  386. write (gol,'("Either:")'); call goErr
  387. write (gol,'(" 1. hardcode the conversion in routine `",a,"` in `",a,"`;")') &
  388. trim(rname), __FILE__; call goErr
  389. write (gol,'(" 2. enable conversion using UDunits library by defining one of the macros:")'); call goErr
  390. write (gol,'(" with_udunits1")'); call goErr
  391. write (gol,'(" with_udunits2")'); call goErr
  392. write (gol,'(" and link with appropriate library.")'); call goErr
  393. TRACEBACK; status=1; return
  394. #endif
  395. end select ! known conversions
  396. end if ! same umits
  397. ! ok
  398. status = 0
  399. END SUBROUTINE TMM_CF_Convert_Units
  400. END MODULE TMM_CF