123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- !###############################################################################
- !
- ! Converstion from TM5 names/units to CF standard names/units
- !
- ! USAGE
- !
- ! use TMM_CF
- !
- ! ! initialize module:
- ! ! o read name of CF standard table from rcfile key 'cf-standard-name-table'
- ! call TMM_CF_Init( rcf, status )
- ! type(TRcFile), intent(in) :: rcf
- ! integer, intent(out) :: status
- !
- ! ! get standard units for standard name:
- ! call TMM_CF_Standard_Units( cf_standard_name, cf_units, status )
- ! character(len=*), intent(in) :: cf_standard_name
- ! character(len=*), intent(out) :: cf_units
- ! integer, intent(out) :: status
- !
- ! ! convert from TM5 variable name to CF standard name:
- ! call TMM_CF_Convert_Name( tm5_name, cf_standard_name, status )
- ! character(len=*), intent(in) :: tm5_name
- ! character(len=*), intent(out) :: cf_standard_name
- ! integer, intent(out) :: status
- !
- ! ! get conversion factor from TM5 units to CF standard unit:
- ! call subroutine TMM_CF_Convert_Units( tm5_units, cf_units, tm5_to_cf_factor, status )
- ! character(len=*), intent(in) :: tm5_units
- ! character(len=*), intent(in) :: cf_units
- ! real, intent(out) :: tm5_to_cf_factor
- ! integer, intent(out) :: status
- !
- ! ! done with module:
- ! call TMM_CF_Done( status )
- ! integer, intent(out) :: status
- !
- !
- ! EXTERNAL LIBRARIES
- !
- ! Module uses the 'UDUnits' library (either old FORTRAN version 1.x [with_udunits1], or C version
- ! 2.x [with_udunits2]).
- !
- !###############################################################################
- !
- #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
- #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
- #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
- !
- #ifdef with_udunits1
- #define IF_UDUNITS_NOTOK_RETURN(action) if (status/=UDUNITS_NOERR) then; gol=trim(UDUnits_StrError(status)); call goErr; TRACEBACK; action; return; end if
- #endif
- !
- #include "tmm.inc"
- !
- !###############################################################################
- module TMM_CF
- use GO , only : gol, goErr, goPr
- #ifdef with_udunits1
- use UDUnits, only : UDUNITS_NOERR, UDUnits_StrError
- #endif
- #ifdef with_udunits2
- use ISO_C_BINDING
- #endif
- use Standard_Name_Table, only : T_Standard_Name_Table
- implicit none
- private
-
- public :: TMM_CF_Init, TMM_CF_Done
- public :: TMM_CF_Standard_Units
- public :: TMM_CF_Convert_Name
- public :: TMM_CF_Convert_Units
-
- ! --- const ------------------------------------
-
- character(len=*), parameter :: mname = 'TMM_CF'
- ! rcfile key with name of standard table:
- character(len=*), parameter :: rckey_cf_table = 'cf-standard-name-table'
- ! --- local ------------------------------------
- logical :: with_cf_table
- type(T_Standard_Name_Table), save :: cf_table
- contains
- ! ==============================================================
- subroutine TMM_CF_Init( rcf, status )
-
- use GO , only : TrcFile, ReadRc
- use Standard_Name_Table, only : Standard_Name_Table_Init
- #ifdef with_udunits1
- use UDUnits , only : UDUnits_Init
- #endif
- ! --- in/out ---------------------------------
-
- type(TRcFile), intent(in) :: rcf
- integer, intent(out) :: status
-
- ! --- const ----------------------------------
-
- character(len=*), parameter :: rname = mname//'/TMM_CF_Init'
-
- ! --- local ----------------------------------
-
- character(len=512) :: cf_standard_name_table
-
- ! --- begin ----------------------------------
-
- ! read full path of cf table:
- call ReadRc( rcF, rckey_cf_table, cf_standard_name_table, &
- status, default='None' )
- IF_ERROR_RETURN(status=1)
- ! set flag to false if key was not found:
- with_cf_table = trim(cf_standard_name_table) /= 'None'
- ! key provided ?
- if ( with_cf_table ) then
- ! standard names and units:
- call Standard_Name_Table_Init( cf_table, trim(cf_standard_name_table), status )
- if (status/=0) then
- write(gol,*) "problem with file '"//trim(cf_standard_name_table)//"'"; call goErr
- write(gol,*) "this file is defined through the '"//trim(rckey_cf_table)//"' rc key in your meteo file"; call goErr
- IF_NOTOK_RETURN(status=1)
- endif
- end if
- #ifdef with_udunits1
- ! initialize UDUnits module:
- call UDUnits_Init( status )
- IF_UDUNITS_NOTOK_RETURN(status=1)
- #endif
- ! ok
- status = 0
-
- end subroutine TMM_CF_Init
- ! ***
- subroutine TMM_CF_Done( status )
-
- use Standard_Name_Table, only : Standard_Name_Table_Done
- #ifdef with_udunits1
- use UDUnits , only : UDUnits_Done
- #endif
- ! --- in/out ---------------------------------
-
- integer, intent(out) :: status
-
- ! --- const ----------------------------------
-
- character(len=*), parameter :: rname = mname//'/TMM_CF_Done'
-
- ! --- local ----------------------------------
-
- ! --- begin ----------------------------------
- ! standard table present ?
- if ( with_cf_table ) then
- ! done with standard names and units:
- call Standard_Name_Table_Done( cf_table, status )
- IF_NOTOK_RETURN(status=1)
- end if
- #ifdef with_udunits1
- ! done with UDUnits module:
- call UDUnits_Done( status )
- IF_UDUNITS_NOTOK_RETURN(status=1)
- #endif
- ! ok
- status = 0
-
- end subroutine TMM_CF_Done
- ! ***
- subroutine TMM_CF_Standard_Units( cf_standard_name, cf_units, status )
- ! --- in/out ---------------------------------
-
- character(len=*), intent(in) :: cf_standard_name
- character(len=*), intent(out) :: cf_units
- integer, intent(out) :: status
- ! --- const ----------------------------------
-
- character(len=*), parameter :: rname = mname//'/TMM_CF_Standard_Units'
-
- ! --- local ----------------------------------
-
- integer :: i, j
- ! --- begin ----------------------------------
-
- ! no unit yet ...
- cf_units = ''
- ! check for specials ...
- select case ( trim(cf_standard_name) )
- ! TM5 special fields
- case ( 'tm5_integrated_eastward_mass_flux_of_air' ) ; cf_units = 'kg s-1'
- case ( 'tm5_integrated_northward_mass_flux_of_air' ) ; cf_units = 'kg s-1'
- case ( 'tm5_integrated_upward_mass_flux_of_air' ) ; cf_units = 'kg s-1'
- ! CF standard fields
- case default
- ! *
- ! check ..
- if ( .not. with_cf_table ) then
- write (gol,'("No CF table specified with rcfile key `",a,"`")') &
- trim(rckey_cf_table); call goErr
- TRACEBACK; status=1; return
- end if
- ! *
- ! loop over all entries:
- do i = 1, size(cf_table%entry)
- ! compare ...
- if ( trim(cf_table%entry(i)%id) == trim(cf_standard_name) ) then
- ! copy values:
- cf_units = trim(cf_table%entry(i)%canonical_units)
- ! found!
- exit
- end if
- end do ! CF table entries
- ! *
- ! not found yet ? then check alia:
- if ( len_trim(cf_units) == 0 ) then
- ! loop over all alia:
- do j = 1, size(cf_table%alias)
- ! compare ...
- if ( trim(cf_table%alias(j)%id) == trim(cf_standard_name) ) then
- ! match; now search real entries:
- do i = 1, size(cf_table%entry)
- ! compare ...
- if ( trim(cf_table%entry(i)%id) == trim(cf_table%alias(j)%entry_id) ) then
- ! copy values:
- cf_units = trim(cf_table%entry(i)%canonical_units)
- ! leave:
- exit
- end if
- end do ! CF table entries
- ! found!
- exit
- end if
- end do ! CF table alia
- end if
- ! *
- end select
- ! not found ?
- if ( len_trim(cf_units) == 0 ) then
- write (gol,'("id not found in cf standard name table : ",a)') trim(cf_standard_name); call goErr
- TRACEBACK; status=1; return
- end if
- ! ok
- status = 0
-
- end subroutine TMM_CF_Standard_Units
- ! ***
- subroutine TMM_CF_Convert_Name( tm5_name, cf_standard_name, status )
- ! --- in/out ---------------------------------
-
- character(len=*), intent(in) :: tm5_name
- character(len=*), intent(out) :: cf_standard_name
- integer, intent(out) :: status
- ! --- const ----------------------------------
-
- character(len=*), parameter :: rname = mname//'/TMM_CF_Convert_Name'
-
- ! --- local ----------------------------------
-
- ! --- begin ----------------------------------
-
- ! convert from TM5 internal name to CF standard name:
- select case ( trim(tm5_name) )
- case ( 'lon' ) ; cf_standard_name = 'longitude'
- case ( 'lat' ) ; cf_standard_name = 'latitude'
- case ( 'sp' ) ; cf_standard_name = 'surface_air_pressure'
- case ( 'mfu' ) ; cf_standard_name = 'tm5_integrated_eastward_mass_flux_of_air'
- case ( 'mfv' ) ; cf_standard_name = 'tm5_integrated_northward_mass_flux_of_air'
- case ( 'mfw' ) ; cf_standard_name = 'tm5_integrated_upward_mass_flux_of_air'
- case ( 'tsp' ) ; cf_standard_name = 'tendency_of_surface_air_pressure'
- case ( 'oro' ) ; cf_standard_name = 'geopotential'
- case ( 'T' ) ; cf_standard_name = 'air_temperature'
- case ( 'Q' ) ; cf_standard_name = 'specific_humidity'
- case ( 'CLWC' ) ; cf_standard_name = 'mass_fraction_of_cloud_liquid_water_in_air'
- case ( 'CIWC' ) ; cf_standard_name = 'mass_fraction_of_cloud_ice_in_air'
- case ( 'CC' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer'
- case ( 'CCO' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer' ! dummy for overhead cloud cover
- case ( 'CCU' ) ; cf_standard_name = 'cloud_area_fraction_in_atmosphere_layer' ! dummy for underfeet cloud cover
- case ( 'eu' ) ; cf_standard_name = 'atmosphere_updraft_convective_mass_flux' ! dummy for entrainement updraft
- case ( 'ed' ) ; cf_standard_name = 'atmosphere_downdraft_convective_mass_flux' ! dummy for entrainement downdraft
- case ( 'du' ) ; cf_standard_name = 'atmosphere_updraft_convective_mass_flux' ! dummy for detrainement updraft
- case ( 'dd' ) ; cf_standard_name = 'atmosphere_downdraft_convective_mass_flux' ! dummy for detrainement downdraft
- case ( 'cloud_base' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_base'
- case ( 'cloud_top' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_top'
- case ( 'cloud_lfs' ) ; cf_standard_name = 'model_level_number_at_convective_cloud_top' ! dummy for level-of-free-sinking
- case ( 'ssr' ) ; cf_standard_name = 'surface_net_upward_shortwave_flux'
- case ( 'ssrd' ) ; cf_standard_name = 'surface_net_downward_shortwave_flux'
- case ( 'str' ) ; cf_standard_name = 'surface_net_upward_longwave_flux'
- case ( 'strd' ) ; cf_standard_name = 'surface_net_downward_longwave_flux'
- case ( 'lsm' ) ; cf_standard_name = 'land_area_fraction'
- case ( 'albedo' ) ; cf_standard_name = 'surface_albedo'
- case ( 'sr' ) ; cf_standard_name = 'surface_roughness_length'
- case ( 'srols' ) ; cf_standard_name = 'surface_roughness_length'
- case ( 'ci' ) ; cf_standard_name = 'sea_ice_area_fraction'
- case ( 'sst' ) ; cf_standard_name = 'sea_surface_temperature'
- case ( 'u10m' ) ; cf_standard_name = 'eastward_wind'
- case ( 'v10m' ) ; cf_standard_name = 'northward_wind'
- case ( 'g10m' ) ; cf_standard_name = 'wind_speed_of_gust'
- case ( 'fg10' ) ; cf_standard_name = 'wind_speed_of_gust'
- case ( 'd2m' ) ; cf_standard_name = 'dew_point_temperature'
- case ( 't2m' ) ; cf_standard_name = 'air_temperature'
- case ( 'skt' ) ; cf_standard_name = 'canopy_temperature'
- case ( 'blh' ) ; cf_standard_name = 'atmosphere_boundary_layer_thickness'
- case ( 'sshf' ) ; cf_standard_name = 'surface_downward_sensible_heat_flux'
- case ( 'slhf' ) ; cf_standard_name = 'surface_downward_latent_heat_flux'
- case ( 'ewss' ) ; cf_standard_name = 'surface_downward_eastward_stress'
- case ( 'nsss' ) ; cf_standard_name = 'surface_downward_northward_stress'
- case ( 'cp' ) ; cf_standard_name = 'lwe_convective_precipitation_rate'
- case ( 'lsp' ) ; cf_standard_name = 'lwe_large_scale_precipitation_rate'
- case ( 'sf' ) ; cf_standard_name = 'lwe_thickness_of_snowfall_amount'
- case ( 'sd' ) ; cf_standard_name = 'lwe_thickness_of_surface_snow_amount'
- case ( 'src' ) ; cf_standard_name = 'lwe_thickness_of_canopy_water_amount'
- case ( 'swvl1' ) ; cf_standard_name = 'volume_fraction_of_condensed_water_in_soil'
- case ( 'stl1' ) ; cf_standard_name = 'soil_temperature'
- case ( 'tv01', 'tv02', 'tv03', 'tv04', 'tv05', &
- 'tv06', 'tv07', 'tv08', 'tv09', 'tv10', &
- 'tv11', 'tv12', 'tv13', 'tv14', 'tv15', &
- 'tv16', 'tv17', 'tv18', 'tv19', 'tv20' )
- cf_standard_name = 'vegetation_area_fraction'
- case ( 'cvl', 'cvh' ) ; cf_standard_name = 'vegetation_area_fraction'
- case ( 'K' ) ; cf_standard_name = 'atmosphere_heat_diffusivity' ! 162.109 grib code = Turbulent diffusion coefficient for heat
- case default
- !write (gol,'("do not know cf standard name for tm5 name : ",a)') trim(tm5_name); call goErr
- !TRACEBACK; status=1; return
- ! assume name follows CF already ..
- cf_standard_name = trim(tm5_name)
- end select
- ! ok
- status = 0
-
- end subroutine TMM_CF_Convert_Name
- ! ***
-
- !
- ! Return factor for conversion from "tm5_units" to "cf_units"
- !
- SUBROUTINE TMM_CF_Convert_Units( tm5_units, cf_units, tm5_to_cf_factor, status )
-
- #ifdef with_udunits1
- use UDUnits, only : UDUnits_ConversionFactor
- #endif
- #ifdef with_udunits2
- use f_udunits_2, only : UT_UNIT_PTR, CV_CONVERTER_PTR, UT_SYSTEM_PTR, f_ut_read_xml
- use f_udunits_2, only : UT_ASCII, f_ut_get_converter, f_ut_parse, f_cv_convert
- use f_udunits_2, only : f_ut_free, f_ut_free_system, f_cv_free
- #endif
-
- ! --- in/out ---------------------------------
- character(len=*), intent(in) :: tm5_units
- character(len=*), intent(in) :: cf_units
- real, intent(out) :: tm5_to_cf_factor
- integer, intent(out) :: status
-
- ! --- local ----------------------------------
- #ifdef with_udunits2
- type(UT_SYSTEM_PTR) :: sys
- type(CV_CONVERTER_PTR) :: conv1
- type(UT_UNIT_PTR) :: unit1, unit2
- real :: a
- integer :: charset
- #endif
-
- ! --- const ----------------------------------
- character(len=*), parameter :: rname = mname//'/TMM_CF_Convert'
-
- ! --- local ----------------------------------
-
- character(len=64) :: conversion
-
- ! --- begin ----------------------------------
-
- ! same?
- if ( trim(tm5_units) == trim(cf_units) ) then
-
- ! no conversion:
- tm5_to_cf_factor = 1.0
-
- else
- ! conversion:
- write (conversion,'(a," -> ",a)') trim(tm5_units), trim(cf_units)
- ! known conversions ...
- select case ( trim(conversion) )
-
- case ( 'kg s-1 -> kg/s', &
- 'm2 s-2 -> m m/s2', &
- '1 -> kg/kg', &
- 'kg m-2 s-1 -> kg/m2/s', &
- 'W m-2 -> W/m2', &
- 'Pa -> N/m2', &
- 'm s-1 -> m/s' )
- ! no conversion needed:
- tm5_to_cf_factor = 1.0
-
- case ( '1 -> %' )
- tm5_to_cf_factor = 100.0
-
- case default
- #ifdef with_udunits1
- ! unit conversion factor:
- call UDUnits_ConversionFactor( trim(tm5_units), trim(cf_units), tm5_to_cf_factor, status )
- if ( status /= UDUNITS_NOERR ) then
- write (gol,'("from conversion of TM5 units to CF units:")'); call goErr
- write (gol,'(" TM5 units : ",a)') trim(tm5_units); call goErr
- write (gol,'(" CF units : ",a)') trim(cf_units); call goErr
- TRACEBACK; status=1; return
- end if
- #elif defined(with_udunits2)
-
- charset = UT_ASCII
- sys = f_ut_read_xml("")
- unit1 = f_ut_parse(sys,tm5_units,charset)
- if ( .not. c_associated(unit1%ptr) ) then
- write (gol,'("from parsing input units `",a,"`")') trim(tm5_units); call goErr
- TRACEBACK; status=1; return
- endif
- unit2 = f_ut_parse(sys,cf_units,charset)
- if ( .not. c_associated(unit2%ptr) ) then
- write (gol,'("from parsing target units `",a,"`")') trim(cf_units); call goErr
- TRACEBACK; status=1; return
- endif
- conv1 = f_ut_get_converter(unit1,unit2)
- if ( .not. c_associated(conv1%ptr)) then
- write (gol,'("from converting input units `",a,"` to target units `",a,"`")') &
- trim(tm5_units), trim(cf_units); call goErr
- TRACEBACK; status=1; return
- endif
- a = 1.0
- tm5_to_cf_factor = f_cv_convert(conv1,a)
- call f_ut_free(unit1)
- call f_ut_free(unit2)
- call f_cv_free(conv1)
- call f_ut_free_system(sys)
- #else
- ! dummy assignment to avoid compiler warnings:
- tm5_to_cf_factor = 1.0
- ! error ...
- write (gol,'("Unsupported unit conversion `",a,"` required.")') trim(conversion); call goPr
- write (gol,'("Either:")'); call goErr
- write (gol,'(" 1. hardcode the conversion in routine `",a,"` in `",a,"`;")') &
- trim(rname), __FILE__; call goErr
- write (gol,'(" 2. enable conversion using UDunits library by defining one of the macros:")'); call goErr
- write (gol,'(" with_udunits1")'); call goErr
- write (gol,'(" with_udunits2")'); call goErr
- write (gol,'(" and link with appropriate library.")'); call goErr
- TRACEBACK; status=1; return
- #endif
- end select ! known conversions
-
- end if ! same umits
-
- ! ok
- status = 0
-
- END SUBROUTINE TMM_CF_Convert_Units
- END MODULE TMM_CF
|