diff --git a/.github/workflows/pull_request_ci.yml b/.github/workflows/pull_request_ci.yml index 2372710..c951b99 100644 --- a/.github/workflows/pull_request_ci.yml +++ b/.github/workflows/pull_request_ci.yml @@ -8,6 +8,27 @@ on: - release/* jobs: + check-tools: + name: Pylint all python files under tools/ + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install pylint pyyaml + + - name: Run pylint + run: | + pylint tools/**py + validate-xml: name: Use xmlllint to validate the xml file against the schema file runs-on: ubuntu-latest @@ -43,8 +64,9 @@ jobs: - name: Check for duplicate standard names, descriptions run: | - tools/check_xml_unique.py standard_names.xml - tools/check_xml_unique.py standard_names.xml --field="description" + tools/check_xml_unique.py -s standard_names.xml + tools/check_xml_unique.py -s standard_names.xml --field="description" + tools/check_xml_unique.py -s standard_names.xml --field="cfname" check-name-rules: name: Check standard names against rules @@ -89,7 +111,7 @@ jobs: - name: Test that sections are alphabetized run: | - tools/sort_standard_names.py standard_names.xml + tools/sort_standard_names.py -s standard_names.xml if ! git diff --exit-code --quiet; then echo "❌ Standard Names are not alphabetized within each section" echo "Run tools/sort_standard_names.py and commit changes" @@ -103,11 +125,11 @@ jobs: run: | # Checks if the saved markdown matches freshly rendered markdown. # If this fails, prompt user to update - tools/write_standard_name_table.py --output-format md standard_names.xml + tools/write_standard_name_table.py --output-format md -s standard_names.xml if ! git diff --exit-code --quiet; then echo "❌ Detected that Metadata-standard-names.md is not consistent with standard_names.xml" echo "✅ To fix: Run the following command locally and commit the result:" - echo " tools/write_standard_name_table.py --output-format md standard_names.xml" + echo " tools/write_standard_name_table.py --output-format md -s standard_names.xml" echo "📘 This script requires the pyyaml Python package; to install with pip use command:" echo " python -m pip install PyYaml" echo "📘 For conda users, environment file tools/environment.yml is provided." @@ -117,11 +139,11 @@ jobs: - name: Test rendering xml file to yaml run: | - tools/write_standard_name_table.py --output-format yaml standard_names.xml + tools/write_standard_name_table.py --output-format yaml -s standard_names.xml if ! git diff --exit-code --quiet; then echo "❌ Detected that Metadata-standard-names.yaml is not consistent with standard_names.xml" echo "✅ To fix: Run the following command locally and commit the result:" - echo " tools/write_standard_name_table.py --output-format yaml standard_names.xml" + echo " tools/write_standard_name_table.py --output-format yaml -s standard_names.xml" echo "📘 This script requires the pyyaml Python package; to install with pip use command:" echo " python -m pip install PyYaml" echo "📘 For conda users, environment file tools/environment.yml is provided." diff --git a/Metadata-standard-names.md b/Metadata-standard-names.md index 733a1cd..f213358 100644 --- a/Metadata-standard-names.md +++ b/Metadata-standard-names.md @@ -31,6 +31,7 @@ The following names are too general to be chosen as standard names, but they can * `area`: Area * `real`: units = m2 * `area_fraction`: The fraction of an area where some condition applies + * Equivalent CF name: area_fraction * `real`: units = 1 * `binary_mask`: A field consisting of either 0 or 1 at every point * `integer`: units = 1 @@ -143,16 +144,20 @@ These names are used as bases for other names, but may also be considered standa * `absolute_vorticity`: Vorticity of fluid relative to an inertial frame; the sum of relative and planetary vorticities * `real`: units = s-1 * `air_pressure`: The pressure of air + * Equivalent CF name: air_pressure * `real`: units = Pa * `air_pressure_thickness`: The difference in air pressure between two vertical layers * `real`: units = Pa * `air_temperature`: The temperature of air + * Equivalent CF name: air_temperature * `real`: units = K * `albedo`: The fraction of incident radiation reflected by a surface * `real`: units = 1 * `atmosphere_heat_diffusivity`: Atmosphere heat diffusivity + * Equivalent CF name: atmosphere_heat_diffusivity * `real`: units = m2 s-1 * `cloud_area_fraction`: Fraction of an area (usually within a grid cell) containing cloud + * Equivalent CF name: cloud_area_fraction * `real`: units = fraction * `cloud_condensate`: Amount of condensed water in cloud * `cloud_ice_water`: Cloud particles consisting of solid water (ice) @@ -168,6 +173,7 @@ These names are used as bases for other names, but may also be considered standa * `diffuse_vis_albedo`: Albedo of diffuse incident visible radiation * `real`: units = 1 * `dimensionless_exner_function`: Dimensionless formulation of the Exner function with respect to 1000 hPa + * Equivalent CF name: dimensionless_exner_function * `real`: units = 1 * `direct_nir_albedo`: Albedo of direct incident near-infrared radiation * `real`: units = 1 @@ -192,8 +198,10 @@ These names are used as bases for other names, but may also be considered standa * `friction_velocity`: A measure of shear stress within a fluid layer with units of distance per time * `real`: units = m s-1 * `geopotential`: Gravitational potential energy of a unit mass relative to sea level + * Equivalent CF name: geopotential * `real`: units = m2 s-2 * `geopotential_height`: Geopotential divided by the gravitational constant + * Equivalent CF name: geopotential_height * `real`: units = m * `graupel`: Precipitation consisting of heavily rimed ice crystals * `gravitational_acceleration`: Gravitational acceleration @@ -206,21 +214,20 @@ These names are used as bases for other names, but may also be considered standa * `liquid_water`: Liquid water * `longwave_flux`: Flux of longwave radiation across a unit surface * `real`: units = W m-2 -* `momentum_flux`: Flux of momentum across a unit surface - * `real`: units = Pa * `nonhygroscopic_ice_nucleating_aerosols`: Ice-nucleating aerosols with the property of not accumulating liquid water -* `pressure`: Pressure - * `real`: units = Pa * `rain`: Precipitation of liquid water from clouds * `random_number`: Random number * `real`: units = 1 * `random_number_seed`: Random number seed * `integer`: units = 1 * `reference_pressure`: Some pressure value for comparison to or calculation of other values + * Equivalent CF name: reference_pressure * `real`: units = Pa * `relative_humidity`: Ratio of the vapor pressure to the saturation vapor pressure (for liquid water unless otherwise specified) + * Equivalent CF name: relative_humidity * `real`: units = fraction * `roughness_length`: Also called surface roughness length; the height above a surface where the wind speed would be zero according to an idealized logarithmic wind profile + * Equivalent CF name: surface_roughness_length * `real`: units = m * `sensible_heat_flux`: Flux of sensible heat across a unit surface * `real`: units = W m-2 @@ -231,12 +238,15 @@ These names are used as bases for other names, but may also be considered standa * `real`: units = fraction * `soil_moisture`: Water contained within a soil layer * `soil_temperature`: Temperature of a soil layer + * Equivalent CF name: soil_temperature * `real`: units = K * `solar_declination_angle`: The angle between the equator and Earth's orbital plane with the Sun + * `real`: units = degrees * `solar_zenith_angle`: The angle between the direction to the sun and the local zenith (vertical direction) + * Equivalent CF name: solar_zenith_angle + * `real`: units = degrees * `surface_skin_temperature`: The temperature of the topmost layer of the surface - * `real`: units = K -* `temperature`: Temperature + * Equivalent CF name: surface_skin_temperature * `real`: units = K * `temperature_flux`: Flux of temperature across a unit surface * `real`: units = K m s-1 @@ -251,10 +261,12 @@ These names are used as bases for other names, but may also be considered standa * `virtual_potential_temperature`: The theoretical potential temperature of dry air that would have the same density as moist air * `real`: units = K * `virtual_temperature`: The theoretical temperature of dry air that would have the same density as moist air + * Equivalent CF name: virtual_temperature * `real`: units = K * `water_vapor`: Water in the gaseous phase * `wind`: Movement of air with a net displacement * `wind_speed`: Speed of moving air + * Equivalent CF name: wind_speed * `real`: units = m s-1 * `wind_stress`: Shear stress exerted by wind parallel to the surface * `real`: units = Pa @@ -324,7 +336,8 @@ Constant parameters that should be identical across a full modeling system * `real`: units = m s-2 ## Coordinates Parameters defining or relating to the coordinate system of the model -* `cell_area`: Cell area +* `cell_area`: horizontal area of a grid cell + * Equivalent CF name: cell_area * `real`: units = m2 * `cell_scaling_factor`: Cell scaling factor * `real`: units = 1 @@ -333,18 +346,22 @@ Parameters defining or relating to the coordinate system of the model * `cosine_of_latitude`: Cosine of latitude * `real`: units = 1 * `height_above_mean_sea_level`: Height above mean sea level + * Equivalent CF name: height_above_mean_sea_level * `real`: units = m * `height_above_mean_sea_level_at_surface`: Height above mean sea level at local surface * `real`: units = m * `latitude`: Latitude + * Equivalent CF name: latitude * `real`: units = degree_north * `longitude`: Longitude + * Equivalent CF name: longitude * `real`: units = degree_east * `sigma_pressure_hybrid_coordinate_a_coefficient`: Sigma pressure hybrid coordinate a coefficient * `real`: units = Pa * `sigma_pressure_hybrid_coordinate_b_coefficient`: Sigma pressure hybrid coordinate b coefficient * `real`: units = 1 * `sigma_pressure_hybrid_vertical_coordinate`: Sigma pressure hybrid vertical coordinate + * Equivalent CF name: atmosphere_hybrid_sigma_pressure_coordinate * `real`: units = 1 * `sine_of_latitude`: Sine of latitude * `real`: units = 1 @@ -360,8 +377,6 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `real`: units = radian * `forecast_julian_day`: Forecast julian day * `real`: units = days -* `forecast_time`: Forecast time - * `real`: units = h * `forecast_time_in_seconds`: Forecast time in seconds * `real`: units = s * `forecast_time_on_previous_timestep`: Forecast time on previous timestep @@ -379,19 +394,20 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `timestep_for_dynamics`: Timestep for dynamics * `real`: units = s ## Atmospheric properties -* `air_pressure`: Midpoint air pressure - * `real`: units = Pa * `air_pressure_at_interfaces`: Air pressure at interfaces * `real`: units = Pa * `air_pressure_at_lowest_model_interface`: Air pressure at lowest model interface * `real`: units = Pa * `air_pressure_at_sea_level`: Air pressure at sea level + * Equivalent CF name: air_pressure_at_mean_sea_level * `real`: units = Pa * `air_pressure_at_surface`: Air pressure at local surface + * Equivalent CF name: surface_air_pressure * `real`: units = Pa * `air_pressure_at_surface_adjacent_layer`: Air pressure at surface adjacent layer * `real`: units = Pa * `air_pressure_at_top_of_atmosphere_model`: Air pressure at top of atmosphere model + * Equivalent CF name: air_pressure_at_top_of_atmosphere_model * `real`: units = Pa * `air_pressure_extended_up_by_1`: Air pressure extended up by 1 * `real`: units = Pa @@ -399,12 +415,8 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `real`: units = Pa * `air_pressure_of_dry_air_at_interfaces`: Air pressure of dry air at interfaces * `real`: units = Pa -* `air_pressure_thickness`: Air pressure thickness - * `real`: units = Pa * `air_pressure_thickness_of_dry_air`: Air pressure thickness of dry air * `real`: units = Pa -* `air_temperature`: Air temperature - * `real`: units = K * `air_temperature_at_2m`: Air temperature at 2m * `real`: units = K * `air_temperature_at_surface_adjacent_layer`: Air temperature at surface adjacent layer @@ -422,6 +434,7 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `air_temperature_two_timesteps_back`: Air temperature two timesteps back * `real`: units = K * `atmosphere_boundary_layer_thickness`: Atmosphere boundary layer thickness + * Equivalent CF name: atmosphere_boundary_layer_thickness * `real`: units = m * `atmosphere_heat_diffusivity_due_to_background`: Atmosphere heat diffusivity due to background * `real`: units = m2 s-1 @@ -450,21 +463,19 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `dimensionless_exner_function_wrt_surface_pressure`: Dimensionless exner function with respect to surface pressure, (p/ps)^(Rd/cp) * `real`: units = 1 * `dry_static_energy`: Dry static energy content of atmosphere layer + * Equivalent CF name: dry_static_energy_content_of_atmosphere_layer * `real`: units = J kg-1 * `eastward_wind`: Wind vector component, positive when directed eastward + * Equivalent CF name: eastward_wind * `real`: units = m s-1 * `eastward_wind_at_10m`: Wind vector component at 10 meters above surface, positive when directed eastward * `real`: units = m s-1 * `eastward_wind_at_surface`: Wind vector component closest to surface, positive when directed eastward * `real`: units = m s-1 -* `geopotential`: Geopotential - * `real`: units = m2 s-2 * `geopotential_at_interfaces`: Geopotential at interfaces * `real`: units = m2 s-2 * `geopotential_at_surface`: Geopotential at surface * `real`: units = m2 s-2 -* `geopotential_height`: geopotential height with respect to sea level - * `real`: units = m * `geopotential_height_at_interfaces`: Geopotential height at interfaces * `real`: units = m * `geopotential_height_at_surface`: Geopotential height at local surface with respect to sea level @@ -473,13 +484,13 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `real`: units = m * `geopotential_height_wrt_surface_at_interfaces`: geopotential height with respect to local surface at interfaces * `real`: units = m -* `gravitational_acceleration`: Gravitational acceleration - * `real`: units = m s-2 * `horizontal_divergence_of_air`: The horizontal divergence of the 2-D vector wind field + * Equivalent CF name: divergence_of_wind * `real`: units = s-1 * `horizontal_streamfunction_of_air`: Scalar function describing the streamlines of the horizontal wind * `real`: units = m2 s-1 * `horizontal_velocity_potential_of_air`: Scalar potential of the horizontal wind + * Equivalent CF name: atmosphere_horizontal_velocity_potential * `real`: units = m2 s-1 * `is_initialized_physics_grid`: Flag to indicate if physics grid is initialized * `logical`: units = flag @@ -512,8 +523,10 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `nonadvected_tke_multiplied_by_2`: Non-advected turbulent kinetic energy multiplied by 2 * `real`: units = m2 s-2 * `nonconvective_cloud_area_fraction_in_atmosphere_layer`: cloud area fraction in atmosphere layer excluding clouds produced by the convective schemes + * Equivalent CF name: stratiform_cloud_area_fraction_in_atmosphere_layer * `real`: units = fraction * `northward_wind`: Wind vector component, positive when directed northward + * Equivalent CF name: northward_wind * `real`: units = m s-1 * `northward_wind_at_10m`: Wind vector component at 10 meters above surface, positive when directed northward * `real`: units = m s-1 @@ -522,6 +535,7 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `physics_state_due_to_dynamics`: Physics state due to dynamics * `ddt`: units = none * `potential_temperature_of_air`: air potential temperature + * Equivalent CF name: air_potential_temperature * `real`: units = K * `potential_temperature_of_air_at_2m`: Potential temperature of air at 2m * `real`: units = K @@ -543,8 +557,6 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `real`: units = Pa * `reference_pressure_in_atmosphere_layer_normalized_by_surface_reference_pressure`: Reference pressure in atmosphere layer normalized by surface reference pressure * `real`: units = 1 -* `relative_humidity`: Relative humidity - * `real`: units = fraction * `relative_humidity_at_2m`: Relative humidity at 2m * `real`: units = fraction * `specific_heat_of_dry_air_at_constant_pressure`: Specific heat of dry air at constant pressure @@ -562,8 +574,10 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `timestep_for_physics`: Timestep for physics * `integer`: units = s * `upward_absolute_vorticity_of_air`: The upward (kth) component of the curl of the vector wind field + * Equivalent CF name: atmosphere_upward_absolute_vorticity * `real`: units = s-1 * `upward_heat_flux_in_air_at_surface`: Upward heat flux in air at surface + * Equivalent CF name: surface_upward_heat_flux_in_air * `real`: units = W m-2 * `us_standard_air_pressure_at_sea_level`: US Standard Atmospheric pressure at sea level * `real`: units = Pa @@ -592,6 +606,7 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `wind_speed_at_surface`: Scalar wind speed closest to surface * `real`: units = m s-1 * `x_wind`: Horizontal wind in a direction perpendicular to y_wind + * Equivalent CF name: x_wind * `real`: units = m s-1 * `x_wind_at_surface_adjacent_layer`: X wind at surface adjacent layer * `real`: units = m s-1 @@ -600,6 +615,7 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `x_wind_of_new_state_at_surface_adjacent_layer`: X wind of new state at surface adjacent layer * `real`: units = m s-1 * `y_wind`: Horizontal wind in a direction perpendicular to x_wind + * Equivalent CF name: y_wind * `real`: units = m s-1 * `y_wind_at_surface_adjacent_layer`: Y wind at surface adjacent layer * `real`: units = m s-1 @@ -618,23 +634,34 @@ Variables defining or relating to timing, dates, calendar, and related concepts * `real`: units = m * `heat_content_in_diurnal_thermocline`: Heat content in diurnal thermocline * `real`: units = K m +* `molecular_sublayer_temperature_correction_in_sea_water`: Molecular sublayer temperature correction in sea water + * `real`: units = K +* `molecular_sublayer_thickness_in_sea_water`: Molecular sublayer thickness in sea water + * `real`: units = m * `ocean_mixed_layer_thickness`: Ocean mixed layer thickness + * Equivalent CF name: ocean_mixed_layer_thickness * `real`: units = m * `reference_sea_surface_temperature`: Foundation/reference temperature for calculating diurnal ocean temperature changes * `real`: units = K * `sea_surface_temperature`: Sea surface temperature + * Equivalent CF name: sea_surface_temperature * `real`: units = K * `sea_water_absolute_salinity`: The absolute salinity of sea water + * Equivalent CF name: sea_water_absolute_salinity * `real`: units = g kg-1 * `sea_water_depth`: The depth of the ocean floor below the surface of the sea + * Equivalent CF name: sea_floor_depth_below_geoid * `real`: units = m * `sea_water_potential_temperature`: sea water potential temperature + * Equivalent CF name: sea_water_potential_temperature * `real`: units = K * `sea_water_practical_salinity`: The practical salinity of sea water + * Equivalent CF name: sea_water_practical_salinity * `real`: units = PSU * `sea_water_salinity_in_diurnal_thermocline`: Sea water salinity in diurnal thermocline * `real`: units = ppt m * `sea_water_temperature`: The temperature of sea water + * Equivalent CF name: sea_water_temperature * `real`: units = K * `x_current_in_diurnal_thermocline`: X current in diurnal thermocline * `real`: units = m2 s-1 @@ -663,10 +690,13 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re * `derivative_of_ln_water_vapor_partial_pressure_assuming_saturation_wrt_air_temperature_at_top_interfaces`: derivative of the natural logarithm of water vapor partial pressure at saturation with respect to air temperature at all interfaces excluding surface * `real`: units = K-1 * `mole_fraction_of_co2_in_air`: Mole fraction of co2 in air + * Equivalent CF name: mole_fraction_of_carbon_dioxide_in_air * `real`: units = mol mol-1 * `mole_fraction_of_ozone_in_air`: Mole fraction of ozone in air + * Equivalent CF name: mole_fraction_of_ozone_in_air * `real`: units = mol mol-1 * `mole_fraction_of_water_vapor`: Mole fraction of water vapor + * Equivalent CF name: mole_fraction_of_water_vapor_in_air * `real`: units = mol mol-1 * `number_density_of_anomalous_oxygen`: Number density of energetic, non-thermal atomic oxygen as defined in MSIS * `real`: units = m-3 @@ -747,10 +777,12 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re * `volume_mixing_ratio_of_so2`: Sulfur dioxide volume mixing ratio * `real`: units = mol mol-1 * `water_vapor_mixing_ratio_wrt_dry_air`: Ratio of the mass of water vapor to the mass of dry air + * Equivalent CF name: humidity_mixing_ratio * `real`: units = kg kg-1 * `water_vapor_mixing_ratio_wrt_dry_air_at_top_interfaces`: Ratio of the mass of water vapor to the mass of dry air at all interfaces excluding surface * `real`: units = kg kg-1 * `water_vapor_mixing_ratio_wrt_moist_air`: Ratio of the mass of water vapor to the mass of moist air + * Equivalent CF name: specific_humidity * `real`: units = kg kg-1 * `water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water`: Ratio of the mass of water vapor to the mass of moist air and hydrometeors * `real`: units = kg kg-1 @@ -770,6 +802,7 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re * `cloud_condensed_water_mixing_ratio_wrt_moist_air_at_surface_over_land`: Cloud condensed water mass mixing ratio with respect to moist air at surface over land * `real`: units = kg kg-1 * `cloud_ice_mixing_ratio_wrt_dry_air`: Ratio of the mass of cloud ice to the mass of dry air + * Equivalent CF name: cloud_ice_mixing_ratio * `real`: units = kg kg-1 * `cloud_ice_mixing_ratio_wrt_dry_air_at_top_interfaces`: Ratio of the mass of cloud ice to the mass of dry air at all interfaces excluding surface * `real`: units = kg kg-1 @@ -782,6 +815,7 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re * `cloud_ice_mixing_ratio_wrt_moist_air_of_new_state`: Cloud ice mass mixing ratio with respect to moist air of new state * `real`: units = kg kg-1 * `cloud_liquid_water_mixing_ratio_wrt_dry_air`: Ratio of the mass of cloud liquid water to the mass of dry air + * Equivalent CF name: cloud_liquid_water_mixing_ratio * `real`: units = kg kg-1 * `cloud_liquid_water_mixing_ratio_wrt_dry_air_at_top_interfaces`: Ratio of the mass of cloud liquid water to the mass of dry air at all interfaces excluding surface * `real`: units = kg kg-1 @@ -798,6 +832,7 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re * `cloud_liquid_water_mixing_ratio_wrt_moist_air_of_new_state`: Cloud liquid water mass mixing ratio with respect to moist air of new state * `real`: units = kg kg-1 * `convective_cloud_area_fraction`: Convective cloud area fraction + * Equivalent CF name: convective_cloud_area_fraction * `real`: units = fraction * `convective_cloud_condensate_after_rainout`: Convective cloud condensate after rainout * `real`: units = kg kg-1 @@ -806,14 +841,19 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re * `convective_precipitation_rate_on_previous_timestep`: Convective precipitation rate on previous timestep * `real`: units = mm s-1 * `effective_radius_of_stratiform_cloud_graupel_particle`: Effective radius of stratiform cloud graupel particle + * Equivalent CF name: effective_radius_of_stratiform_cloud_graupel_particles * `real`: units = um * `effective_radius_of_stratiform_cloud_ice_particle`: Effective radius of stratiform cloud ice particle + * Equivalent CF name: effective_radius_of_stratiform_cloud_ice_particles * `real`: units = um * `effective_radius_of_stratiform_cloud_liquid_water_particle`: Effective radius of stratiform cloud liquid water particle + * Equivalent CF name: effective_radius_of_stratiform_cloud_liquid_water_particles * `real`: units = um * `effective_radius_of_stratiform_cloud_rain_particle`: Effective radius of stratiform cloud rain particle + * Equivalent CF name: effective_radius_of_stratiform_cloud_rain_particles * `real`: units = um * `effective_radius_of_stratiform_cloud_snow_particle`: Effective radius of stratiform cloud snow particle + * Equivalent CF name: effective_radius_of_stratiform_cloud_snow_particles * `real`: units = um * `graupel_mixing_ratio_wrt_moist_air`: Graupel mass mixing ratio with respect to moist air * `real`: units = kg kg-1 @@ -898,13 +938,13 @@ Tracers are numerically zero-mass particles advected in fluid flow, typically re ### Aerosols * `mass_fraction_of_dust001_in_air`: GOCART Dust bin1 mass fraction * `real`: units = kg kg-1 -* `mass_fraction_of_dust002_in_air`: GOCART DUst bin2 mass fraction +* `mass_fraction_of_dust002_in_air`: GOCART Dust bin2 mass fraction * `real`: units = kg kg-1 -* `mass_fraction_of_dust003_in_air`: GOCART DUst bin3 mass fraction +* `mass_fraction_of_dust003_in_air`: GOCART Dust bin3 mass fraction * `real`: units = kg kg-1 -* `mass_fraction_of_dust004_in_air`: GOCART DUst bin4 mass fraction +* `mass_fraction_of_dust004_in_air`: GOCART Dust bin4 mass fraction * `real`: units = kg kg-1 -* `mass_fraction_of_dust005_in_air`: GOCART DUst bin5 mass fraction +* `mass_fraction_of_dust005_in_air`: GOCART Dust bin5 mass fraction * `real`: units = kg kg-1 * `mass_fraction_of_dust_accumulation_aerosol_particles_in_air`: Mass fraction of accumulation mode dust aerosol particles * `real`: units = kg kg-1 @@ -1849,6 +1889,8 @@ Thresholds represent some value at which the behavior of some process changes, i * `real`: units = fraction * `max_grid_scale`: Maximum grid scale * `real`: units = m2 rad-2 +* `max_soil_moisture_content_for_lsm`: Maximum soil moisture content for land surface model + * `real`: units = m * `max_tendency_of_potential_temperature_of_air_due_to_large_scale_precipitation`: Maximum tendency of air potential temperature due to large-scale precipitation * `real`: units = K s-1 * `max_vegetation_area_fraction`: Maximum vegetation area fraction @@ -2074,8 +2116,6 @@ Thresholds represent some value at which the behavior of some process changes, i * `real`: units = Pa s * `cumulative_y_momentum_flux_at_surface_for_coupling_multiplied_by_timestep`: Cumulative y momentum flux at surface for coupling multiplied by timestep * `real`: units = Pa s -* `lwe_surface_snow_from_coupled_process`: Liquid water equivalent surface snow from coupled process - * `real`: units = m * `monin_obukhov_similarity_function_for_heat`: Monin obukhov similarity function for heat * `real`: units = 1 * `monin_obukhov_similarity_function_for_momentum`: Monin obukhov similarity function for momentum @@ -2154,6 +2194,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `albedo_on_previous_timestep_assuming_deep_snow`: Albedo on previous timestep assuming deep snow * `real`: units = fraction * `area_type`: Area type + * Equivalent CF name: area_type * `real`: units = 1 * `area_type_from_coupled_process`: Area type from coupled process * `real`: units = 1 @@ -2166,8 +2207,10 @@ Thresholds represent some value at which the behavior of some process changes, i * `canopy_intercepted_liquid_water`: Canopy intercepted liquid water * `real`: units = mm * `canopy_temperature`: Canopy temperature + * Equivalent CF name: canopy_temperature * `real`: units = K -* `canopy_water_mass_content`: Canopy water mass content +* `canopy_water_mass_content`: Water mass per unit area in the canopy + * Equivalent CF name: canopy_water_amount * `real`: units = kg m-2 * `cumulative_lwe_thickness_of_convective_precipitation_between_sw_radiation_calls`: Cumulative liquid water equivalent thickness of convective precipitation amount between shortwave radiation calls * `real`: units = m @@ -2179,7 +2222,8 @@ Thresholds represent some value at which the behavior of some process changes, i * `real`: units = m * `deep_soil_temperature`: Deep soil temperature * `real`: units = K -* `density_of_snow_at_surface`: Density of snow at surface +* `density_of_snow_at_surface`: Density of snow accumulated on ground surface + * Equivalent CF name: surface_snow_density * `real`: units = kg m-3 * `depth_from_snow_surface_at_bottom_interface`: depth from the top of the snow surface at the bottom of the soil layer * `real`: units = m @@ -2220,6 +2264,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `explicit_precipitation_rate_on_previous_timestep`: Explicit precipitation rate on previous timestep * `real`: units = mm s-1 * `fast_soil_pool_mass_content_of_carbon`: Fast soil pool mass content of carbon + * Equivalent CF name: fast_soil_pool_mass_content_of_carbon * `real`: units = g m-2 * `fine_root_mass_content`: Fine root mass content * `real`: units = g m-2 @@ -2236,19 +2281,25 @@ Thresholds represent some value at which the behavior of some process changes, i * `lake_depth`: Lake depth * `real`: units = m * `land_area_fraction`: Land area fraction + * Equivalent CF name: land_area_fraction * `real`: units = fraction * `land_ice_area_fraction_of_cell_area`: fraction of horizontal area of grid cell that is ice over land + * Equivalent CF name: land_ice_area_fraction * `real`: units = frac * `land_surface_perturbation_variables`: Land surface perturbation variables * `character`: units = none * `leaf_area_index`: Leaf area index + * Equivalent CF name: leaf_area_index * `real`: units = 1 * `leaf_mass_content`: Leaf mass content * `real`: units = g m-2 * `lwe_snowfall_rate`: Liquid water equivalent snowfall rate + * Equivalent CF name: lwe_snowfall_rate * `real`: units = mm s-1 * `lwe_surface_snow`: Liquid water equivalent surface snow * `real`: units = mm +* `lwe_surface_snow_from_coupled_process`: Liquid water equivalent surface snow from coupled process + * `real`: units = m * `lwe_thickness_of_convective_precipitation_on_previous_timestep`: Liquid water equivalent thickness of convective precipitation amount on previous timestep * `real`: units = m * `lwe_thickness_of_explicit_precipitation_on_previous_timestep`: Liquid water equivalent thickness of explicit precipitation amount on previous timestep @@ -2268,15 +2319,10 @@ Thresholds represent some value at which the behavior of some process changes, i * `lwe_thickness_of_snowfall_on_previous_timestep`: Liquid water equivalent thickness of snowfall amount on previous timestep * `real`: units = mm * `lwe_thickness_of_surface_snow`: Liquid water equivalent thickness of surface snow amount + * Equivalent CF name: lwe_thickness_of_surface_snow_amount * `real`: units = mm * `mass_content_of_water_in_top_soil_layer`: mass per unit area of water in top layer of soil * `real`: units = kg m-2 -* `max_soil_moisture_content_for_lsm`: Maximum soil moisture content for land surface model - * `real`: units = m -* `molecular_sublayer_temperature_correction_in_sea_water`: Molecular sublayer temperature correction in sea water - * `real`: units = K -* `molecular_sublayer_thickness_in_sea_water`: Molecular sublayer thickness in sea water - * `real`: units = m * `nir_albedo_strong_cosz`: albedo for near-infrared radiation with strong dependence on cosine of the zenith angle * `real`: units = fraction * `nir_albedo_weak_cosz`: albedo for near-infrared radiation with weak dependence on cosine of the zenith angle @@ -2285,8 +2331,6 @@ Thresholds represent some value at which the behavior of some process changes, i * `real`: units = m * `normalized_soil_wetness_for_lsm`: Normalized soil wetness for land surface model * `real`: units = fraction -* `roughness_length`: surface roughness length - * `real`: units = cm * `roughness_length_from_wave_model`: surface roughness length from wave model * `real`: units = cm * `roughness_length_over_ice`: surface roughness length over ice @@ -2300,11 +2344,11 @@ Thresholds represent some value at which the behavior of some process changes, i * `sea_ice_area_fraction_of_sea_area_fraction`: Sea ice area fraction of sea area fraction * `real`: units = fraction * `sea_ice_temperature`: Sea ice temperature + * Equivalent CF name: sea_ice_temperature * `real`: units = K * `sea_ice_thickness`: Sea ice thickness + * Equivalent CF name: sea_ice_thickness * `real`: units = m -* `skin_temperature_at_surface`: Skin temperature at surface - * `real`: units = K * `skin_temperature_at_surface_over_ice`: Skin temperature at surface over (or where) ice * `real`: units = K * `skin_temperature_at_surface_over_land`: Skin temperature at surface over (or where) land @@ -2314,6 +2358,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `skin_temperature_at_surface_over_snow`: Skin temperature at surface over (or where) snow * `real`: units = K * `slow_soil_pool_mass_content_of_carbon`: Slow soil pool mass content of carbon + * Equivalent CF name: slow_soil_pool_mass_content_of_carbon * `real`: units = g m-2 * `snow_area_fraction_at_surface_over_ice`: Snow area fraction at surface over ice * `real`: units = fraction @@ -2323,8 +2368,6 @@ Thresholds represent some value at which the behavior of some process changes, i * `real`: units = m * `snowfall_rate_on_previous_timestep`: Snowfall rate on previous timestep * `real`: units = mm s-1 -* `soil_temperature`: Soil temperature - * `real`: units = K * `soil_temperature_for_lsm`: Soil temperature for land surface model * `real`: units = K * `specified_upward_flux_of_water_vapor_mixing_ratio_wrt_moist_air_at_surface`: Specified upward specific humidity (water vapor mass mixing ratio with respect to moist air) flux at surface @@ -2346,6 +2389,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `surface_friction_velocity_for_momentum`: Surface friction velocity for momentum * `real`: units = m s-1 * `surface_longwave_emissivity`: Surface longwave emissivity + * Equivalent CF name: surface_longwave_emissivity * `real`: units = fraction * `surface_longwave_emissivity_over_ice`: Surface longwave emissivity over ice * `real`: units = fraction @@ -2376,16 +2420,19 @@ Thresholds represent some value at which the behavior of some process changes, i * `upper_bound_of_max_albedo_assuming_deep_snow`: Upper bound of maximum albedo assuming deep snow * `real`: units = fraction * `upward_latent_heat_flux_at_surface`: Upward latent heat flux at surface + * Equivalent CF name: surface_upward_latent_heat_flux * `real`: units = W m-2 * `urban_area_fraction_of_cell_area`: fraction of horizontal area of grid cell that is urban * `real`: units = frac * `vegetation_area_fraction`: Vegetation area fraction + * Equivalent CF name: vegetation_area_fraction * `real`: units = fraction * `vis_albedo_strong_cosz`: albedo for visible radiation with strong dependence on cosine of the zenith angle * `real`: units = fraction * `vis_albedo_weak_cosz`: albedo for visible radiation with weak dependence on cosine of the zenith angle * `real`: units = fraction * `volume_fraction_of_condensed_water_in_soil`: Volume fraction of condensed water in soil + * Equivalent CF name: volume_fraction_of_condensed_water_in_soil * `real`: units = fraction * `volume_fraction_of_frozen_soil_moisture_for_lsm`: Volume fraction of frozen soil moisture for land surface model * `real`: units = fraction @@ -2465,6 +2512,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `real`: units = m ## Tendencies * `lagrangian_tendency_of_air_pressure`: Vertical pressure velocity + * Equivalent CF name: lagrangian_tendency_of_air_pressure * `real`: units = Pa s-1 * `process_split_cumulative_tendency_of_air_temperature`: Process split cumulative tendency of air temperature * `real`: units = K s-1 @@ -2501,6 +2549,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `tendency_of_activated_cloud_condensation_nuclei_from_climatology`: Change of activated cloud condensation nuclei from climatology per unit time * `real`: units = kg-1 s-1 * `tendency_of_air_temperature`: Change in temperature per unit time + * Equivalent CF name: tendency_of_air_temperature * `real`: units = K s-1 * `tendency_of_air_temperature_due_to_integrated_dynamics_through_earths_atmosphere`: Tendency of air temperature due to integrated dynamics through earths atmosphere * `real`: units = K s-1 @@ -2509,6 +2558,7 @@ Thresholds represent some value at which the behavior of some process changes, i * `tendency_of_air_temperature_due_to_longwave_heating_on_radiation_timestep`: Tendency of air temperature due to longwave heating on radiation timestep * `real`: units = K s-1 * `tendency_of_air_temperature_due_to_model_physics`: Change in air temperature due to model physics per unit time + * Equivalent CF name: tendency_of_air_temperature_due_to_model_physics * `real`: units = K s-1 * `tendency_of_air_temperature_due_to_nonphysics`: Tendency of air temperature due to nonphysics * `real`: units = K s-1 @@ -2519,16 +2569,20 @@ Thresholds represent some value at which the behavior of some process changes, i * `tendency_of_dry_air_enthalpy_at_constant_pressure`: Change of dry air enthalpy per unit time at constant pressure; d/dt(Cp*T) * `real`: units = J kg-1 s-1 * `tendency_of_eastward_wind`: Change in eastward wind per unit time + * Equivalent CF name: tendency_of_eastward_wind * `real`: units = m s-2 * `tendency_of_eastward_wind_due_to_model_physics`: Change in eastward wind due to model physics per unit time + * Equivalent CF name: tendency_of_eastward_wind_due_to_parameterized_physics * `real`: units = m s-2 * `tendency_of_hygroscopic_aerosols_at_surface_adjacent_layer`: Tendency of hygroscopic aerosols at surface adjacent layer * `real`: units = kg-1 s-1 * `tendency_of_nonhygroscopic_ice_nucleating_aerosols_at_surface_adjacent_layer`: Tendency of nonhygroscopic ice nucleating aerosols at surface adjacent layer * `real`: units = kg-1 s-1 * `tendency_of_northward_wind`: Change in northward wind per unit time + * Equivalent CF name: tendency_of_northward_wind * `real`: units = m s-2 * `tendency_of_northward_wind_due_to_model_physics`: Change in northward wind due to model physics per unit time + * Equivalent CF name: tendency_of_northward_wind_due_to_parameterized_physics * `real`: units = m s-2 * `tendency_of_potential_temperature_of_air`: Change in potential temperature per unit time * `real`: units = K s-1 diff --git a/Metadata-standard-names.yaml b/Metadata-standard-names.yaml index 40b9a34..72cff48 100644 --- a/Metadata-standard-names.yaml +++ b/Metadata-standard-names.yaml @@ -14,6 +14,7 @@ section: type: real units: m2 - name: area_fraction + cfname: area_fraction description: The fraction of an area where some condition applies type: real units: 1 @@ -251,6 +252,7 @@ section: type: real units: s-1 - name: air_pressure + cfname: air_pressure description: The pressure of air type: real units: Pa @@ -259,6 +261,7 @@ section: type: real units: Pa - name: air_temperature + cfname: air_temperature description: The temperature of air type: real units: K @@ -267,10 +270,12 @@ section: type: real units: 1 - name: atmosphere_heat_diffusivity + cfname: atmosphere_heat_diffusivity description: Atmosphere heat diffusivity type: real units: m2 s-1 - name: cloud_area_fraction + cfname: cloud_area_fraction description: Fraction of an area (usually within a grid cell) containing cloud type: real units: fraction @@ -301,6 +306,7 @@ section: type: real units: 1 - name: dimensionless_exner_function + cfname: dimensionless_exner_function description: Dimensionless formulation of the Exner function with respect to 1000 hPa type: real @@ -354,10 +360,12 @@ section: type: real units: m s-1 - name: geopotential + cfname: geopotential description: Gravitational potential energy of a unit mass relative to sea level type: real units: m2 s-2 - name: geopotential_height + cfname: geopotential_height description: Geopotential divided by the gravitational constant type: real units: m @@ -384,17 +392,9 @@ section: description: Flux of longwave radiation across a unit surface type: real units: W m-2 - - name: momentum_flux - description: Flux of momentum across a unit surface - type: real - units: Pa - name: nonhygroscopic_ice_nucleating_aerosols description: Ice-nucleating aerosols with the property of not accumulating liquid water - - name: pressure - description: Pressure - type: real - units: Pa - name: rain description: Precipitation of liquid water from clouds - name: random_number @@ -406,15 +406,18 @@ section: type: integer units: 1 - name: reference_pressure + cfname: reference_pressure description: Some pressure value for comparison to or calculation of other values type: real units: Pa - name: relative_humidity + cfname: relative_humidity description: Ratio of the vapor pressure to the saturation vapor pressure (for liquid water unless otherwise specified) type: real units: fraction - name: roughness_length + cfname: surface_roughness_length description: Also called surface roughness length; the height above a surface where the wind speed would be zero according to an idealized logarithmic wind profile @@ -437,23 +440,26 @@ section: - name: soil_moisture description: Water contained within a soil layer - name: soil_temperature + cfname: soil_temperature description: Temperature of a soil layer type: real units: K - name: solar_declination_angle description: The angle between the equator and Earth's orbital plane with the Sun + type: real + units: degrees - name: solar_zenith_angle + cfname: solar_zenith_angle description: The angle between the direction to the sun and the local zenith (vertical direction) + type: real + units: degrees - name: surface_skin_temperature + cfname: surface_skin_temperature description: The temperature of the topmost layer of the surface type: real units: K - - name: temperature - description: Temperature - type: real - units: K - name: temperature_flux description: Flux of temperature across a unit surface type: real @@ -480,6 +486,7 @@ section: type: real units: K - name: virtual_temperature + cfname: virtual_temperature description: The theoretical temperature of dry air that would have the same density as moist air type: real @@ -489,6 +496,7 @@ section: - name: wind description: Movement of air with a net displacement - name: wind_speed + cfname: wind_speed description: Speed of moving air type: real units: m s-1 @@ -628,7 +636,8 @@ section: comment: Parameters defining or relating to the coordinate system of the model standard_names: - name: cell_area - description: Cell area + cfname: cell_area + description: horizontal area of a grid cell type: real units: m2 - name: cell_scaling_factor @@ -644,6 +653,7 @@ section: type: real units: 1 - name: height_above_mean_sea_level + cfname: height_above_mean_sea_level description: Height above mean sea level type: real units: m @@ -652,10 +662,12 @@ section: type: real units: m - name: latitude + cfname: latitude description: Latitude type: real units: degree_north - name: longitude + cfname: longitude description: Longitude type: real units: degree_east @@ -668,6 +680,7 @@ section: type: real units: 1 - name: sigma_pressure_hybrid_vertical_coordinate + cfname: atmosphere_hybrid_sigma_pressure_coordinate description: Sigma pressure hybrid vertical coordinate type: real units: 1 @@ -702,10 +715,6 @@ section: description: Forecast julian day type: real units: days - - name: forecast_time - description: Forecast time - type: real - units: h - name: forecast_time_in_seconds description: Forecast time in seconds type: real @@ -741,10 +750,6 @@ section: - name: Atmospheric properties comment: null standard_names: - - name: air_pressure - description: Midpoint air pressure - type: real - units: Pa - name: air_pressure_at_interfaces description: Air pressure at interfaces type: real @@ -754,10 +759,12 @@ section: type: real units: Pa - name: air_pressure_at_sea_level + cfname: air_pressure_at_mean_sea_level description: Air pressure at sea level type: real units: Pa - name: air_pressure_at_surface + cfname: surface_air_pressure description: Air pressure at local surface type: real units: Pa @@ -766,6 +773,7 @@ section: type: real units: Pa - name: air_pressure_at_top_of_atmosphere_model + cfname: air_pressure_at_top_of_atmosphere_model description: Air pressure at top of atmosphere model type: real units: Pa @@ -781,18 +789,10 @@ section: description: Air pressure of dry air at interfaces type: real units: Pa - - name: air_pressure_thickness - description: Air pressure thickness - type: real - units: Pa - name: air_pressure_thickness_of_dry_air description: Air pressure thickness of dry air type: real units: Pa - - name: air_temperature - description: Air temperature - type: real - units: K - name: air_temperature_at_2m description: Air temperature at 2m type: real @@ -826,6 +826,7 @@ section: type: real units: K - name: atmosphere_boundary_layer_thickness + cfname: atmosphere_boundary_layer_thickness description: Atmosphere boundary layer thickness type: real units: m @@ -886,10 +887,12 @@ section: type: real units: 1 - name: dry_static_energy + cfname: dry_static_energy_content_of_atmosphere_layer description: Dry static energy content of atmosphere layer type: real units: J kg-1 - name: eastward_wind + cfname: eastward_wind description: Wind vector component, positive when directed eastward type: real units: m s-1 @@ -903,10 +906,6 @@ section: eastward type: real units: m s-1 - - name: geopotential - description: Geopotential - type: real - units: m2 s-2 - name: geopotential_at_interfaces description: Geopotential at interfaces type: real @@ -915,10 +914,6 @@ section: description: Geopotential at surface type: real units: m2 s-2 - - name: geopotential_height - description: geopotential height with respect to sea level - type: real - units: m - name: geopotential_height_at_interfaces description: Geopotential height at interfaces type: real @@ -935,11 +930,8 @@ section: description: geopotential height with respect to local surface at interfaces type: real units: m - - name: gravitational_acceleration - description: Gravitational acceleration - type: real - units: m s-2 - name: horizontal_divergence_of_air + cfname: divergence_of_wind description: The horizontal divergence of the 2-D vector wind field type: real units: s-1 @@ -948,6 +940,7 @@ section: type: real units: m2 s-1 - name: horizontal_velocity_potential_of_air + cfname: atmosphere_horizontal_velocity_potential description: Scalar potential of the horizontal wind type: real units: m2 s-1 @@ -1012,11 +1005,13 @@ section: type: real units: m2 s-2 - name: nonconvective_cloud_area_fraction_in_atmosphere_layer + cfname: stratiform_cloud_area_fraction_in_atmosphere_layer description: cloud area fraction in atmosphere layer excluding clouds produced by the convective schemes type: real units: fraction - name: northward_wind + cfname: northward_wind description: Wind vector component, positive when directed northward type: real units: m s-1 @@ -1035,6 +1030,7 @@ section: type: ddt units: none - name: potential_temperature_of_air + cfname: air_potential_temperature description: air potential temperature type: real units: K @@ -1081,10 +1077,6 @@ section: pressure type: real units: 1 - - name: relative_humidity - description: Relative humidity - type: real - units: fraction - name: relative_humidity_at_2m description: Relative humidity at 2m type: real @@ -1120,10 +1112,12 @@ section: type: integer units: s - name: upward_absolute_vorticity_of_air + cfname: atmosphere_upward_absolute_vorticity description: The upward (kth) component of the curl of the vector wind field type: real units: s-1 - name: upward_heat_flux_in_air_at_surface + cfname: surface_upward_heat_flux_in_air description: Upward heat flux in air at surface type: real units: W m-2 @@ -1185,6 +1179,7 @@ section: type: real units: m s-1 - name: x_wind + cfname: x_wind description: Horizontal wind in a direction perpendicular to y_wind type: real units: m s-1 @@ -1201,6 +1196,7 @@ section: type: real units: m s-1 - name: y_wind + cfname: y_wind description: Horizontal wind in a direction perpendicular to x_wind type: real units: m s-1 @@ -1241,7 +1237,16 @@ section: description: Heat content in diurnal thermocline type: real units: K m + - name: molecular_sublayer_temperature_correction_in_sea_water + description: Molecular sublayer temperature correction in sea water + type: real + units: K + - name: molecular_sublayer_thickness_in_sea_water + description: Molecular sublayer thickness in sea water + type: real + units: m - name: ocean_mixed_layer_thickness + cfname: ocean_mixed_layer_thickness description: Ocean mixed layer thickness type: real units: m @@ -1251,22 +1256,27 @@ section: type: real units: K - name: sea_surface_temperature + cfname: sea_surface_temperature description: Sea surface temperature type: real units: K - name: sea_water_absolute_salinity + cfname: sea_water_absolute_salinity description: The absolute salinity of sea water type: real units: g kg-1 - name: sea_water_depth + cfname: sea_floor_depth_below_geoid description: The depth of the ocean floor below the surface of the sea type: real units: m - name: sea_water_potential_temperature + cfname: sea_water_potential_temperature description: sea water potential temperature type: real units: K - name: sea_water_practical_salinity + cfname: sea_water_practical_salinity description: The practical salinity of sea water type: real units: PSU @@ -1275,6 +1285,7 @@ section: type: real units: ppt m - name: sea_water_temperature + cfname: sea_water_temperature description: The temperature of sea water type: real units: K @@ -1336,14 +1347,17 @@ section: type: real units: K-1 - name: mole_fraction_of_co2_in_air + cfname: mole_fraction_of_carbon_dioxide_in_air description: Mole fraction of co2 in air type: real units: mol mol-1 - name: mole_fraction_of_ozone_in_air + cfname: mole_fraction_of_ozone_in_air description: Mole fraction of ozone in air type: real units: mol mol-1 - name: mole_fraction_of_water_vapor + cfname: mole_fraction_of_water_vapor_in_air description: Mole fraction of water vapor type: real units: mol mol-1 @@ -1513,6 +1527,7 @@ section: type: real units: mol mol-1 - name: water_vapor_mixing_ratio_wrt_dry_air + cfname: humidity_mixing_ratio description: Ratio of the mass of water vapor to the mass of dry air type: real units: kg kg-1 @@ -1522,6 +1537,7 @@ section: type: real units: kg kg-1 - name: water_vapor_mixing_ratio_wrt_moist_air + cfname: specific_humidity description: Ratio of the mass of water vapor to the mass of moist air type: real units: kg kg-1 @@ -1568,6 +1584,7 @@ section: type: real units: kg kg-1 - name: cloud_ice_mixing_ratio_wrt_dry_air + cfname: cloud_ice_mixing_ratio description: Ratio of the mass of cloud ice to the mass of dry air type: real units: kg kg-1 @@ -1596,6 +1613,7 @@ section: type: real units: kg kg-1 - name: cloud_liquid_water_mixing_ratio_wrt_dry_air + cfname: cloud_liquid_water_mixing_ratio description: Ratio of the mass of cloud liquid water to the mass of dry air type: real units: kg kg-1 @@ -1634,6 +1652,7 @@ section: type: real units: kg kg-1 - name: convective_cloud_area_fraction + cfname: convective_cloud_area_fraction description: Convective cloud area fraction type: real units: fraction @@ -1651,22 +1670,27 @@ section: type: real units: mm s-1 - name: effective_radius_of_stratiform_cloud_graupel_particle + cfname: effective_radius_of_stratiform_cloud_graupel_particles description: Effective radius of stratiform cloud graupel particle type: real units: um - name: effective_radius_of_stratiform_cloud_ice_particle + cfname: effective_radius_of_stratiform_cloud_ice_particles description: Effective radius of stratiform cloud ice particle type: real units: um - name: effective_radius_of_stratiform_cloud_liquid_water_particle + cfname: effective_radius_of_stratiform_cloud_liquid_water_particles description: Effective radius of stratiform cloud liquid water particle type: real units: um - name: effective_radius_of_stratiform_cloud_rain_particle + cfname: effective_radius_of_stratiform_cloud_rain_particles description: Effective radius of stratiform cloud rain particle type: real units: um - name: effective_radius_of_stratiform_cloud_snow_particle + cfname: effective_radius_of_stratiform_cloud_snow_particles description: Effective radius of stratiform cloud snow particle type: real units: um @@ -1848,19 +1872,19 @@ section: type: real units: kg kg-1 - name: mass_fraction_of_dust002_in_air - description: GOCART DUst bin2 mass fraction + description: GOCART Dust bin2 mass fraction type: real units: kg kg-1 - name: mass_fraction_of_dust003_in_air - description: GOCART DUst bin3 mass fraction + description: GOCART Dust bin3 mass fraction type: real units: kg kg-1 - name: mass_fraction_of_dust004_in_air - description: GOCART DUst bin4 mass fraction + description: GOCART Dust bin4 mass fraction type: real units: kg kg-1 - name: mass_fraction_of_dust005_in_air - description: GOCART DUst bin5 mass fraction + description: GOCART Dust bin5 mass fraction type: real units: kg kg-1 - name: mass_fraction_of_dust_accumulation_aerosol_particles_in_air @@ -3868,6 +3892,10 @@ section: description: Maximum grid scale type: real units: m2 rad-2 + - name: max_soil_moisture_content_for_lsm + description: Maximum soil moisture content for land surface model + type: real + units: m - name: max_tendency_of_potential_temperature_of_air_due_to_large_scale_precipitation description: Maximum tendency of air potential temperature due to large-scale precipitation @@ -4376,10 +4404,6 @@ section: timestep type: real units: Pa s - - name: lwe_surface_snow_from_coupled_process - description: Liquid water equivalent surface snow from coupled process - type: real - units: m - name: monin_obukhov_similarity_function_for_heat description: Monin obukhov similarity function for heat type: real @@ -4543,6 +4567,7 @@ section: type: real units: fraction - name: area_type + cfname: area_type description: Area type type: real units: 1 @@ -4567,11 +4592,13 @@ section: type: real units: mm - name: canopy_temperature + cfname: canopy_temperature description: Canopy temperature type: real units: K - name: canopy_water_mass_content - description: Canopy water mass content + cfname: canopy_water_amount + description: Water mass per unit area in the canopy type: real units: kg m-2 - name: cumulative_lwe_thickness_of_convective_precipitation_between_sw_radiation_calls @@ -4598,7 +4625,8 @@ section: type: real units: K - name: density_of_snow_at_surface - description: Density of snow at surface + cfname: surface_snow_density + description: Density of snow accumulated on ground surface type: real units: kg m-3 - name: depth_from_snow_surface_at_bottom_interface @@ -4680,6 +4708,7 @@ section: type: real units: mm s-1 - name: fast_soil_pool_mass_content_of_carbon + cfname: fast_soil_pool_mass_content_of_carbon description: Fast soil pool mass content of carbon type: real units: g m-2 @@ -4712,10 +4741,12 @@ section: type: real units: m - name: land_area_fraction + cfname: land_area_fraction description: Land area fraction type: real units: fraction - name: land_ice_area_fraction_of_cell_area + cfname: land_ice_area_fraction description: fraction of horizontal area of grid cell that is ice over land type: real units: frac @@ -4724,6 +4755,7 @@ section: type: character units: none - name: leaf_area_index + cfname: leaf_area_index description: Leaf area index type: real units: 1 @@ -4732,6 +4764,7 @@ section: type: real units: g m-2 - name: lwe_snowfall_rate + cfname: lwe_snowfall_rate description: Liquid water equivalent snowfall rate type: real units: mm s-1 @@ -4739,6 +4772,10 @@ section: description: Liquid water equivalent surface snow type: real units: mm + - name: lwe_surface_snow_from_coupled_process + description: Liquid water equivalent surface snow from coupled process + type: real + units: m - name: lwe_thickness_of_convective_precipitation_on_previous_timestep description: Liquid water equivalent thickness of convective precipitation amount on previous timestep @@ -4782,6 +4819,7 @@ section: type: real units: mm - name: lwe_thickness_of_surface_snow + cfname: lwe_thickness_of_surface_snow_amount description: Liquid water equivalent thickness of surface snow amount type: real units: mm @@ -4789,18 +4827,6 @@ section: description: mass per unit area of water in top layer of soil type: real units: kg m-2 - - name: max_soil_moisture_content_for_lsm - description: Maximum soil moisture content for land surface model - type: real - units: m - - name: molecular_sublayer_temperature_correction_in_sea_water - description: Molecular sublayer temperature correction in sea water - type: real - units: K - - name: molecular_sublayer_thickness_in_sea_water - description: Molecular sublayer thickness in sea water - type: real - units: m - name: nir_albedo_strong_cosz description: albedo for near-infrared radiation with strong dependence on cosine of the zenith angle @@ -4820,10 +4846,6 @@ section: description: Normalized soil wetness for land surface model type: real units: fraction - - name: roughness_length - description: surface roughness length - type: real - units: cm - name: roughness_length_from_wave_model description: surface roughness length from wave model type: real @@ -4849,17 +4871,15 @@ section: type: real units: fraction - name: sea_ice_temperature + cfname: sea_ice_temperature description: Sea ice temperature type: real units: K - name: sea_ice_thickness + cfname: sea_ice_thickness description: Sea ice thickness type: real units: m - - name: skin_temperature_at_surface - description: Skin temperature at surface - type: real - units: K - name: skin_temperature_at_surface_over_ice description: Skin temperature at surface over (or where) ice type: real @@ -4877,6 +4897,7 @@ section: type: real units: K - name: slow_soil_pool_mass_content_of_carbon + cfname: slow_soil_pool_mass_content_of_carbon description: Slow soil pool mass content of carbon type: real units: g m-2 @@ -4896,10 +4917,6 @@ section: description: Snowfall rate on previous timestep type: real units: mm s-1 - - name: soil_temperature - description: Soil temperature - type: real - units: K - name: soil_temperature_for_lsm description: Soil temperature for land surface model type: real @@ -4943,6 +4960,7 @@ section: type: real units: m s-1 - name: surface_longwave_emissivity + cfname: surface_longwave_emissivity description: Surface longwave emissivity type: real units: fraction @@ -5003,6 +5021,7 @@ section: type: real units: fraction - name: upward_latent_heat_flux_at_surface + cfname: surface_upward_latent_heat_flux description: Upward latent heat flux at surface type: real units: W m-2 @@ -5011,6 +5030,7 @@ section: type: real units: frac - name: vegetation_area_fraction + cfname: vegetation_area_fraction description: Vegetation area fraction type: real units: fraction @@ -5025,6 +5045,7 @@ section: type: real units: fraction - name: volume_fraction_of_condensed_water_in_soil + cfname: volume_fraction_of_condensed_water_in_soil description: Volume fraction of condensed water in soil type: real units: fraction @@ -5193,6 +5214,7 @@ section: comment: null standard_names: - name: lagrangian_tendency_of_air_pressure + cfname: lagrangian_tendency_of_air_pressure description: Vertical pressure velocity type: real units: Pa s-1 @@ -5278,6 +5300,7 @@ section: type: real units: kg-1 s-1 - name: tendency_of_air_temperature + cfname: tendency_of_air_temperature description: Change in temperature per unit time type: real units: K s-1 @@ -5297,6 +5320,7 @@ section: type: real units: K s-1 - name: tendency_of_air_temperature_due_to_model_physics + cfname: tendency_of_air_temperature_due_to_model_physics description: Change in air temperature due to model physics per unit time type: real units: K s-1 @@ -5319,10 +5343,12 @@ section: type: real units: J kg-1 s-1 - name: tendency_of_eastward_wind + cfname: tendency_of_eastward_wind description: Change in eastward wind per unit time type: real units: m s-2 - name: tendency_of_eastward_wind_due_to_model_physics + cfname: tendency_of_eastward_wind_due_to_parameterized_physics description: Change in eastward wind due to model physics per unit time type: real units: m s-2 @@ -5336,10 +5362,12 @@ section: type: real units: kg-1 s-1 - name: tendency_of_northward_wind + cfname: tendency_of_northward_wind description: Change in northward wind per unit time type: real units: m s-2 - name: tendency_of_northward_wind_due_to_model_physics + cfname: tendency_of_northward_wind_due_to_parameterized_physics description: Change in northward wind due to model physics per unit time type: real units: m s-2 diff --git a/standard_names.xml b/standard_names.xml index 787a5fb..c3a41db 100644 --- a/standard_names.xml +++ b/standard_names.xml @@ -6,6 +6,7 @@ real + area_fraction real @@ -185,21 +186,25 @@ real + air_pressure real real + air_temperature real real + atmosphere_heat_diffusivity real + cloud_area_fraction real @@ -224,6 +229,7 @@ real + dimensionless_exner_function real @@ -260,9 +266,11 @@ real + geopotential real + geopotential_height real @@ -284,14 +292,8 @@ real - - real - - - real - @@ -301,12 +303,15 @@ integer + reference_pressure real + relative_humidity real + surface_roughness_length real @@ -323,16 +328,18 @@ + soil_temperature real + real + solar_zenith_angle + real - real - - + surface_skin_temperature real @@ -356,6 +363,7 @@ real + virtual_temperature real @@ -363,6 +371,7 @@ + wind_speed real @@ -465,7 +474,8 @@
- + + cell_area real @@ -478,15 +488,18 @@ real + height_above_mean_sea_level real real + latitude real + longitude real @@ -496,6 +509,7 @@ real + atmosphere_hybrid_sigma_pressure_coordinate real @@ -518,9 +532,6 @@ real - - real - real @@ -547,9 +558,6 @@
- - real - real @@ -557,15 +565,18 @@ real + air_pressure_at_mean_sea_level real + surface_air_pressure real real + air_pressure_at_top_of_atmosphere_model real @@ -577,15 +588,9 @@ real - - real - real - - real - real @@ -611,6 +616,7 @@ real + atmosphere_boundary_layer_thickness real @@ -653,9 +659,11 @@ real + dry_static_energy_content_of_atmosphere_layer real + eastward_wind real @@ -664,18 +672,12 @@ real - - real - real real - - real - real @@ -688,16 +690,15 @@ real - - real - + divergence_of_wind real real + atmosphere_horizontal_velocity_potential real @@ -746,9 +747,11 @@ real + stratiform_cloud_area_fraction_in_atmosphere_layer real + northward_wind real @@ -761,6 +764,7 @@ ddt + air_potential_temperature real @@ -793,9 +797,6 @@ real - - real - real @@ -821,9 +822,11 @@ integer + atmosphere_upward_absolute_vorticity real + surface_upward_heat_flux_in_air real @@ -866,6 +869,7 @@ real + x_wind real @@ -878,6 +882,7 @@ real + y_wind real @@ -906,31 +911,44 @@ real + + real + + + real + + ocean_mixed_layer_thickness real real + sea_surface_temperature real + sea_water_absolute_salinity real + sea_floor_depth_below_geoid real + sea_water_potential_temperature real + sea_water_practical_salinity real real + sea_water_temperature real @@ -972,12 +990,15 @@ real + mole_fraction_of_carbon_dioxide_in_air real + mole_fraction_of_ozone_in_air real + mole_fraction_of_water_vapor_in_air real @@ -1098,12 +1119,14 @@ real + humidity_mixing_ratio real real + specific_humidity real @@ -1133,6 +1156,7 @@ real + cloud_ice_mixing_ratio real @@ -1151,6 +1175,7 @@ real + cloud_liquid_water_mixing_ratio real @@ -1175,6 +1200,7 @@ real + convective_cloud_area_fraction real @@ -1187,18 +1213,23 @@ real + effective_radius_of_stratiform_cloud_graupel_particles real + effective_radius_of_stratiform_cloud_ice_particles real + effective_radius_of_stratiform_cloud_liquid_water_particles real + effective_radius_of_stratiform_cloud_rain_particles real + effective_radius_of_stratiform_cloud_snow_particles real @@ -1326,16 +1357,16 @@ real - + real - + real - + real - + real @@ -2746,6 +2777,9 @@ real + + real + real @@ -3085,9 +3119,6 @@ real - - real - real @@ -3205,6 +3236,7 @@ real + area_type real @@ -3223,9 +3255,11 @@ real + canopy_temperature real - + + canopy_water_amount real @@ -3243,7 +3277,8 @@ real - + + surface_snow_density real @@ -3304,6 +3339,7 @@ real + fast_soil_pool_mass_content_of_carbon real @@ -3328,26 +3364,33 @@ real + land_area_fraction real + land_ice_area_fraction real character + leaf_area_index real real + lwe_snowfall_rate real real + + real + real @@ -3376,20 +3419,12 @@ real + lwe_thickness_of_surface_snow_amount real real - - real - - - real - - - real - real @@ -3402,9 +3437,6 @@ real - - real - real @@ -3424,14 +3456,13 @@ real + sea_ice_temperature real + sea_ice_thickness real - - real - real @@ -3445,6 +3476,7 @@ real + slow_soil_pool_mass_content_of_carbon real @@ -3459,9 +3491,6 @@ real - - real - real @@ -3493,6 +3522,7 @@ real + surface_longwave_emissivity real @@ -3538,12 +3568,14 @@ real + surface_upward_latent_heat_flux real real + vegetation_area_fraction real @@ -3553,6 +3585,7 @@ real + volume_fraction_of_condensed_water_in_soil real @@ -3673,6 +3706,7 @@
+ lagrangian_tendency_of_air_pressure real @@ -3727,6 +3761,7 @@ real + tendency_of_air_temperature real @@ -3739,6 +3774,7 @@ real + tendency_of_air_temperature_due_to_model_physics real @@ -3754,9 +3790,11 @@ real + tendency_of_eastward_wind real + tendency_of_eastward_wind_due_to_parameterized_physics real @@ -3766,9 +3804,11 @@ real + tendency_of_northward_wind real + tendency_of_northward_wind_due_to_parameterized_physics real diff --git a/standard_names.xsd b/standard_names.xsd index a8fc18e..e19493a 100644 --- a/standard_names.xsd +++ b/standard_names.xsd @@ -48,6 +48,10 @@ + 127) for elem in ET.tostringlist(root, encoding='unicode'): violations = [] @@ -84,7 +62,7 @@ def main(): violators[elem] = f'Non-ascii characters found: {badchars}' if violators: - raise Exception(f"Violating entries found:\n{violators}") + raise Exception(f"Violating entries found:\n{violators}") # pylint: disable=broad-exception-raised print(f'Success! All entries in {args.standard_name_file} follow the rules.') diff --git a/tools/check_xml_unique.py b/tools/check_xml_unique.py index cea4349..616ef38 100755 --- a/tools/check_xml_unique.py +++ b/tools/check_xml_unique.py @@ -7,33 +7,18 @@ import argparse import sys import os.path -import xml.etree.ElementTree as ET -import copy -################################################ -# Add lib modules to python path -################################################ +#Import custom helper functions from lib/ directory +from lib import validate_xml_file, read_xml_file -_CURR_DIR = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.join(_CURR_DIR, "lib")) - -####################################### -#Import needed framework python modules -####################################### - -from xml_tools import find_schema_file, validate_xml_file, read_xml_file - -############################################################################### def parse_command_line(args, description): -############################################################################### + """Parse and return command-line arguments""" parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument("standard_name_file", + parser.add_argument("-s", "--standard_name_file", default="standard_names.xml", metavar='', type=str, help="XML file with standard name library") - parser.add_argument("--overwrite", action='store_true', - help="flag to remove duplicates and overwrite the file") parser.add_argument("--field", type=str, default="name", help="Field to check for uniqueness; default is 'name'") parser.add_argument("--debug", action='store_true', @@ -42,38 +27,37 @@ def parse_command_line(args, description): pargs = parser.parse_args(args) return pargs -############################################################################### def main_func(): -############################################################################### + # pylint: disable=too-many-branches """Parse the standard names database file and notify of duplicates. """ # Parse command line arguments args = parse_command_line(sys.argv[1:], __doc__) stdname_file = os.path.abspath(args.standard_name_file) - tree, root = read_xml_file(stdname_file) + _, root = read_xml_file(stdname_file) # Validate the XML file - schema_name = os.path.basename(stdname_file)[0:-4] schema_root = os.path.dirname(stdname_file) - schema_path = os.path.join(schema_root,schema_name) - schema_file = find_schema_file(schema_path) - if schema_file: - try: - validate_xml_file(stdname_file, schema_name, None, - schema_path=schema_root, error_on_noxmllint=True) - except ValueError: - raise ValueError(f"Invalid standard names file, {stdname_file}") - else: - raise ValueError(f'Cannot find schema file, {schema_name}') + schema_path = os.path.join(schema_root,"standard_names.xsd") + validate_xml_file(stdname_file, schema_path, logger=None, error_on_noxmllint=True) #get list of all standard names all_std_names = [] - for name in root.findall('./section/standard_name'): + for name in root.findall('.//standard_name'): try: - all_std_names.append(name.attrib[args.field]) + if args.field == 'cfname': + # Extract from cfname subelement + cfname_elem = name.find('cfname') + if cfname_elem is not None and cfname_elem.text is not None: + all_std_names.append(cfname_elem.text.strip()) + elif args.debug: + print(f"WARNING: no cfname subelement for standard name {name.attrib['name']}") + else: + # Extract from attribute + all_std_names.append(name.attrib[args.field]) except KeyError: - if (args.debug): - print(f"WARNING: no field '{args.field}' for standard name '{name.attrib['name']}' ") + if args.debug: + print(f"WARNING: no field {args.field} for standard name {name.attrib['name']} ") #get list of all unique and duplicate standard names, in source order seen = set() uniq_std_names = [] @@ -88,30 +72,16 @@ def main_func(): if len(dup_std_names)>0: print(f'The following duplicate {args.field} entries were found:') for dup in dup_std_names: - rm_elements = root.findall(f'./section/standard_name[@{args.field}="{dup}"]')[1:] + if args.field == 'cfname': + rm_elements = root.findall(f'.//standard_name[cfname="{dup}"]')[1:] + else: + rm_elements = root.findall(f'.//standard_name[@{args.field}="{dup}"]')[1:] print(f"{dup}, ({len(rm_elements)} duplicate(s))") - if args.overwrite: - print(f'Removing duplicates and overwriting {stdname_file}') - for dup in dup_std_names: - first_use = True #Logical that indicates the first use of the duplicated name - rm_parents = root.findall('./section/standard_name[@name="%s"]..'%dup) - for par in rm_parents: - rm_ele = par.findall('./standard_name[@name="%s"]'%dup) - for ele in rm_ele: - if first_use: - #Now all future uses of the name will be removed: - first_use = False - else: - par.remove(ele) - #Overwrite the xml file with the new, duplicate-free element tree: - tree.write(stdname_file, "utf-8") - else: - # If not overwriting, exit with status 1 to indicate failure + # exit with status 1 to indicate failure sys.exit(1) else: print(f'No duplicate {args.field}s were found.') -############################################################################### if __name__ == "__main__": main_func() diff --git a/tools/lib/__init__.py b/tools/lib/__init__.py new file mode 100644 index 0000000..1a345f3 --- /dev/null +++ b/tools/lib/__init__.py @@ -0,0 +1,8 @@ +"""Shared utilities for ESM Standard Names tools.""" + +from .xml_tools import ( + call_command, + validate_xml_file, + read_xml_file, + get_standard_names_as_set, +) diff --git a/tools/lib/xml_tools.py b/tools/lib/xml_tools.py index b9b4d6f..d3da7e1 100644 --- a/tools/lib/xml_tools.py +++ b/tools/lib/xml_tools.py @@ -16,7 +16,6 @@ _XMLLINT = which('xmllint') except ImportError: _XMLLINT = None -# end try # Find python version _LOGGER = None @@ -24,6 +23,7 @@ ############################################################################### def call_command(commands, logger, silent=False): ############################################################################### + # pylint: disable=line-too-long """ Try a command line and return the output on success (None on failure) >>> call_command(['ls', 'really__improbable_fffilename.foo'], _LOGGER) #doctest: +IGNORE_EXCEPTION_DETAIL @@ -39,48 +39,25 @@ def call_command(commands, logger, silent=False): outstr = '' if logger is None: silent = True - # end if try: cproc = subprocess.run(commands, check=True, capture_output=True) if not silent: logger.debug(cproc.stdout) - # end if result = cproc.returncode == 0 except (OSError, RuntimeError, subprocess.CalledProcessError) as err: if silent: result = False else: cmd = ' '.join(commands) - emsg = "Execution of '{}' failed with code:\n" + emsg = "Execution of '{cmd}' failed with code: {err.returncode}\n" outstr = emsg.format(cmd, err.returncode) - outstr += "{}".format(err.output) - raise RuntimeError(outstr) - # end if - # end of try + outstr += f"{err.output}" + raise RuntimeError(outstr) from err return result -############################################################################### -def find_schema_file(schema_root, schema_path=None): -############################################################################### - """Find and return the schema file based on or return None. - If is present, use that as the directory to find the - appropriate schema file. Otherwise, just look in the current directory.""" - schema_filename = f"{schema_root}.xsd".format(schema_root) - if schema_path: - schema_file = os.path.join(schema_path, schema_filename) - else: - schema_file = schema_filename - # end if - if os.path.exists(schema_file): - return schema_file - # end if - return None - -############################################################################### -def validate_xml_file(filename, schema_root, logger, - schema_path=None, error_on_noxmllint=False): +def validate_xml_file(filename, schema_file, logger, error_on_noxmllint=False): ############################################################################### """ Find the appropriate schema and validate the XML file, , @@ -88,80 +65,70 @@ def validate_xml_file(filename, schema_root, logger, """ # Check the filename if not os.path.isfile(filename): - raise ValueError("validate_xml_file: Filename, '{}', does not exist".format(filename)) - # end if + raise ValueError("validate_xml_file: Filename, '{filename}', does not exist") if not os.access(filename, os.R_OK): - raise ValueError("validate_xml_file: Cannot open '{}'".format(filename)) - # end if - if not schema_path: - # Find the schema file - thispath = os.path.abspath(__file__) - pdir = os.path.dirname(os.path.dirname(os.path.dirname(thispath))) - schema_path = os.path.join(pdir, 'schema') - # end if - schema_file = find_schema_file(schema_root, schema_path) - if not (schema_file and os.path.isfile(schema_file)): + raise ValueError("validate_xml_file: Cannot open '{filename}'") + if not os.path.isfile(schema_file): raise ValueError(f"validate_xml_file: Cannot find schema file {schema_file}") - # end if if not os.access(schema_file, os.R_OK): emsg = "validate_xml_file: Cannot open schema, '{}'" raise ValueError(emsg.format(schema_file)) - # end if if _XMLLINT is not None: if logger is not None: lmsg = "Checking file {} against schema {}" logger.debug(lmsg.format(filename, schema_file)) - # end if cmd = [_XMLLINT, '--noout', '--schema', schema_file, filename] result = call_command(cmd, logger) return result - # end if lmsg = "xmllint not found, could not validate file {}" if error_on_noxmllint: raise ValueError("validate_xml_file: " + lmsg.format(filename)) - # end if if logger is not None: logger.warning(lmsg.format(filename)) - # end if return True # We could not check but still need to proceed ############################################################################### def read_xml_file(filename, logger=None): ############################################################################### """Read the XML file, , and return its tree and root""" - if os.path.isfile(filename) and os.access(filename, os.R_OK): - file_open = (lambda x: open(x, 'r')) - # end if - with file_open(filename) as file_: - try: - tree = ET.parse(file_) - root = tree.getroot() - except ET.ParseError as perr: - emsg = "read_xml_file: Cannot read {}, {}" - raise ValueError(emsg.format(filename, perr)) - elif not os.access(filename, os.R_OK): - raise ValueError("read_xml_file: Cannot open '{}'".format(filename)) - else: - emsg = "read_xml_file: Filename, '{}', does not exist" - raise ValueError(emsg.format(filename)) - # end if + if not os.path.isfile(filename): + raise ValueError(f"read_xml_file: Filename, '{filename}', does not exist") + if not os.access(filename, os.R_OK): + raise ValueError(f"read_xml_file: Cannot open '{filename}'") + + try: + with open(filename, 'r', encoding="utf-8") as file_: + tree = ET.parse(file_) + root = tree.getroot() + except ET.ParseError as perr: + raise ValueError(f"read_xml_file: Cannot read {filename}, {perr}") from perr + if logger: - logger.debug("Read XML file, '{}'".format(filename)) - # end if + logger.debug(f"Read XML file, '{filename}'") return tree, root +############################################################################### +def get_standard_names_as_set(root): +############################################################################### + """ + Extract all standard_name elements from root (at any nesting depth), + collect their 'name' attributes, and return as a set. + """ + std_names = set() + for stdname in root.findall('.//standard_name'): + std_names.add(stdname.attrib['name']) + return std_names + ############################################################################### if __name__ == "__main__": _LOGGER = logging.getLogger('xml_tools') for handler in list(_LOGGER.handlers): _LOGGER.removeHandler(handler) - # end for _LOGGER.addHandler(logging.NullHandler()) try: # First, run doctest import doctest doctest.testmod() except ValueError as cerr: - print("{}".format(cerr)) -# no else: + print("{cerr}") diff --git a/tools/list_names.py b/tools/list_names.py index 3f9d393..67b8a9d 100755 --- a/tools/list_names.py +++ b/tools/list_names.py @@ -28,6 +28,7 @@ def extract_names(xml_path: Path) -> list[str]: def main() -> None: + """Main function for command-line execution""" if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} ", file=sys.stderr) sys.exit(1) @@ -43,4 +44,3 @@ def main() -> None: if __name__ == "__main__": main() - diff --git a/tools/sort_standard_names.py b/tools/sort_standard_names.py index cec673c..94c524c 100755 --- a/tools/sort_standard_names.py +++ b/tools/sort_standard_names.py @@ -63,12 +63,16 @@ def process_file(xml_path: Path) -> ET.ElementTree: def main() -> None: - parser = argparse.ArgumentParser(description="Alphabetically sort standard names within each subsection of the ESM Standard Names XML file.") - parser.add_argument("input", nargs="?", default="standard_names.xml", help="Input XML file (default: standard_names.xml)") - parser.add_argument("output", nargs="?", default="", help="Output file (default: overwrite input)") + """Main function for command-line execution""" + parser = argparse.ArgumentParser(description="Alphabetically sort standard names within each "\ + "subsection of the ESM Standard Names XML file.") + parser.add_argument("-s", "--standard_name_file", nargs="?", default="standard_names.xml", + help="Input XML file (default: standard_names.xml)") + parser.add_argument("-o", "--output", nargs="?", default="", + help="Output file (default: overwrite input)") args = parser.parse_args() - input_path = Path(args.input) + input_path = Path(args.standard_name_file) if not input_path.exists(): print(f"Error: input file {input_path} does not exist.", file=sys.stderr) sys.exit(1) diff --git a/tools/write_standard_name_table.py b/tools/write_standard_name_table.py index 09b63cb..6ba767d 100755 --- a/tools/write_standard_name_table.py +++ b/tools/write_standard_name_table.py @@ -6,26 +6,14 @@ # Python library imports from collections import OrderedDict -import xml.etree.ElementTree as ET import os.path import argparse import sys import re import yaml -################################################ -# Add lib modules to python path -################################################ - -_CURR_DIR = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.join(_CURR_DIR, "lib")) - -####################################### -# Import needed framework python modules -####################################### - -from xml_tools import validate_xml_file, read_xml_file -from xml_tools import find_schema_file +#Import custom helper functions from lib/ directory +from lib import validate_xml_file, read_xml_file ####################################### # Regular expressions @@ -35,11 +23,12 @@ _DROPPED_LINK_CHARS_RE = re.compile(r"[^a-z_-]") -####################################### -# Custom representer for OrderedDict -####################################### +######################################################################## +# Custom representer for OrderedDict allows neat representation of written YAML Metadata file +######################################################################## def ordered_dict_representer(dumper, data): + """Custom YAML representer for OrderedDict to allow for nice format YAML output.""" return dumper.represent_mapping(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, data.items()) yaml.add_representer(OrderedDict, ordered_dict_representer) @@ -47,10 +36,8 @@ def ordered_dict_representer(dumper, data): def convert_text_to_link(text_str): ######################################################################## """ - When Markdown converts a header string into - an internal document link it applies certain - text conversion rules. This function thus - applies those same rules to a given string + When Markdown converts a header string into an internal document link it applies certain + text conversion rules. This function thus applies those same rules to a given string in order to produce the correct link. """ @@ -70,25 +57,9 @@ def convert_text_to_link(text_str): return link_str ######################################################################## -def standard_name_to_description(prop_dict, context=None): +def standard_name_to_description(prop_dict): ######################################################################## - """Translate a standard_name to its default description - Note: This code is copied from the CCPP Framework. - >>> standard_name_to_description({'standard_name':'cloud_optical_depth_layers_from_0p55mu_to_0p99mu'}) - 'Cloud optical depth layers from 0.55mu to 0.99mu' - >>> standard_name_to_description({'local_name':'foo'}) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - CCPPError: No standard name to convert foo to description - >>> standard_name_to_description({}) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - CCPPError: No standard name to convert to description - >>> standard_name_to_description({'local_name':'foo'}, context=ParseContext(linenum=3, filename='foo.F90')) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - CCPPError: No standard name to convert foo to description at foo.F90:3 - >>> standard_name_to_description({}, context=ParseContext(linenum=3, filename='foo.F90')) #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - CCPPError: No standard name to convert to description at foo.F90:3 - """ + """Translate a standard_name to its default description""" # We assume that standard_name has been checked for validity # Make the first char uppercase and replace each underscore with a space if 'standard_name' in prop_dict: @@ -98,33 +69,22 @@ def standard_name_to_description(prop_dict, context=None): standard_name[1:]) else: description = '' - # end if # Next, substitute a decimal point for the p in [:digit]p[:digit] match = _REAL_SUBST_RE.match(description) while match is not None: description = match.group(1) + '.' + match.group(2) match = _REAL_SUBST_RE.match(description) - # end while else: - description = '' - if 'local_name' in prop_dict: - lname = ' {}'.format(prop_dict['local_name']) - else: - lname = '' - # end if - ctxt = context_string(context) - emsg = 'No standard name to convert{} to description{}' - raise CCPPError(emsg.format(lname, ctxt)) - # end if + raise KeyError('No standard_name found in dictionary') return description -############################################################################### + def parse_command_line(args, program_description): -############################################################################### + """Function to parse command line arguments""" parser = argparse.ArgumentParser(description=program_description, formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument("standard_name_file", + parser.add_argument("-s","--standard_name_file",default="standard_names.xml", metavar='', type=str, help="XML file with standard name library") parser.add_argument("--output-filename", metavar='', @@ -135,24 +95,23 @@ def parse_command_line(args, program_description): pargs = parser.parse_args(args) return pargs -############################################################################### + def convert_xml_to_markdown(root, library_name, snl): -############################################################################### - snl.write('# {}\n'.format(library_name)) + """Convert XML root element to Markdown format and write to file object snl.""" + snl.write(f'# {library_name}\n') # Write a table of contents for top-level sections snl.write('#### Table of Contents\n') for section in root: sec_name = section.get('name') sec_name_link = convert_text_to_link(sec_name) # convert string to link text snl.write(f"* [{sec_name}](#{sec_name_link})\n") - # end for snl.write('\n') for section in root: parse_section(snl, section) -############################################################################### + def parse_section(snl, sec, level='##'): -############################################################################### + """Parse a section element and its children, writing Markdown to snl file object.""" # Step through the sections sec_name = sec.get('name') sec_comment = sec.get('comment') @@ -165,14 +124,11 @@ def parse_section(snl, sec, level='##'): sec_comment = sec_comment.lstrip() cind = sec_comment.find('\\n') if cind > 0: - snl.write('{}\n'.format(sec_comment[0:cind])) + snl.write(f'{sec_comment[0:cind]}\n') sec_comment = sec_comment[cind + 2:] else: - snl.write('{}\n'.format(sec_comment)) + snl.write(f'{sec_comment}\n') sec_comment = '' - # end if - # end while - # end if for std_name in sec: if std_name.tag == 'section': parse_section(snl, std_name, level + '#') @@ -182,25 +138,22 @@ def parse_section(snl, sec, level='##'): if stdn_description is None: sdict = {'standard_name': stdn_name} stdn_description = standard_name_to_description(sdict) - # end if - snl.write("* `{}`: {}\n".format(stdn_name, stdn_description)) - # Should only be a type in the standard_name text + snl.write(f"* `{stdn_name}`: {stdn_description}\n") + # Should only be type or cfname as subelements of standard_name for item in std_name: - if item.tag == 'type': + if item.tag == 'cfname': + snl.write(f" * Equivalent CF name: {item.text}\n") + elif item.tag == 'type': txt = item.text units = item.get('units') - snl.write(' * `{}`: units = {}\n'.format(txt, units)) + snl.write(f' * `{txt}`: units = {units}\n') else: emsg = "Unknown standard name property, '{}'" raise ValueError(emsg.format(item.tag)) - # end if - # end for - # end for -# end for -############################################################################### + def convert_xml_to_yaml(root, library_name, yaml_file): -############################################################################### + """Convert XML root element to YAML format and write to file object yaml_file.""" yaml_data = OrderedDict() yaml_data['library_name'] = library_name yaml_data['section'] = [] @@ -211,9 +164,8 @@ def convert_xml_to_yaml(root, library_name, yaml_file): yaml.dump(yaml_data, yaml_file, default_flow_style=False) -############################################################################### def parse_section_for_yaml(section): -############################################################################### + """Parse a section element into an OrderedDict suitable for YAML output.""" sec_data = OrderedDict() sec_data['name'] = section.get('name') @@ -231,6 +183,11 @@ def parse_section_for_yaml(section): for std_name in section.findall('standard_name'): stdn_name = std_name.get('name') + cfname_elem = std_name.find('cfname') + if cfname_elem is not None and cfname_elem.text is not None: + stdn_cfname = cfname_elem.text.strip() + else: + stdn_cfname = None stdn_description = std_name.get('description') if stdn_description is None: @@ -241,6 +198,8 @@ def parse_section_for_yaml(section): std_name_data = OrderedDict() std_name_data['name'] = stdn_name + if stdn_cfname: + std_name_data['cfname'] = stdn_cfname std_name_data['description'] = stdn_description if std_type is not None: std_name_data['type'] = std_type.text @@ -267,9 +226,8 @@ def parse_section_for_yaml(section): return sec_data -############################################################################### + def main_func(): -############################################################################### """Validate and parse the standard names database file and generate a document containing the data.""" # Parse command line arguments @@ -279,44 +237,19 @@ def main_func(): _, root = read_xml_file(stdname_file) library_name = root.get('name') # Validate the XML file - schema_name = os.path.basename(stdname_file)[0:-4] schema_root = os.path.dirname(stdname_file) - schema_file = find_schema_file(schema_name) - if not schema_file: - raise ValueError(f'Cannot find schema file {schema_name}') - # end if - - try: - emsg = "Invalid standard names file, {}".format(stdname_file) - file_ok = validate_xml_file(stdname_file, schema_name, - None, schema_path=schema_root, - error_on_noxmllint=True) - except ValueError as valerr: - cemsg = "{}".format(valerr).split('\n')[0] - if cemsg[0:12] == 'Execution of': - xstart = cemsg.find("'") - if xstart >= 0: - xend = cemsg[xstart + 1:].find("'") + xstart + 1 - emsg += '\n' + cemsg[xstart + 1:xend] - # end if (else, just keep original message) - elif cemsg[0:18] == 'validate_xml_file:': - emsg += "\n" + cemsg - # end if - raise ValueError(emsg) - # end try + schema_path = os.path.join(schema_root,"standard_names.xsd") + validate_xml_file(stdname_file, schema_path, logger=None, error_on_noxmllint=True) outfile_name = args.output_filename if args.output_format == 'md': - with open(f"{outfile_name}.md", "w") as md_file: + with open(f"{outfile_name}.md", "w", encoding="utf-8") as md_file: convert_xml_to_markdown(root, library_name, md_file) elif args.output_format == 'yaml': - with open(f"{outfile_name}.yaml", "w") as yaml_file: + with open(f"{outfile_name}.yaml", "w", encoding="utf-8") as yaml_file: convert_xml_to_yaml(root, library_name, yaml_file) else: - emsg = "Unsupported output format, '{}'" - raise ValueError(emsg.format(args.output_format)) - # end if + raise ValueError(f"Unsupported output format, {args.output_format}") -############################################################################### if __name__ == "__main__": main_func()