diff --git a/CHANGELOG.md b/CHANGELOG.md index 6299694..2c9e84b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,18 +9,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add CI step to make PR to MAPL3 on push to `main` - ### Changed ### Fixed ### Removed -- Use of haswell nodes on NCCS machines - ### Deprecated +## [2.0.4] - 2023-11-17 + +### Added + +- Add CI step to make PR to MAPL3 on push to `main` + +### Changed + +- Add/update command_line options: more items such as label and altbcs were added to `remap_params.tpl` +- Updated paths to the legacy bcs data by pointing to the new "bcs_shared" directory in the GMAO project space. +- Support for new boundary conditions package output layout + +### Removed + +- Use of haswell nodes on NCCS machines for `cube_BCs.pl` + ## [2.0.3] - 2023-08-24 ### Changed diff --git a/post/CMakeLists.txt b/post/CMakeLists.txt index bf50d8f..dca4991 100644 --- a/post/CMakeLists.txt +++ b/post/CMakeLists.txt @@ -162,5 +162,3 @@ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/3CH.j DESTINATION post ) - -add_subdirectory(tests) diff --git a/post/tests/CMakeLists.txt b/post/tests/CMakeLists.txt deleted file mode 100644 index 80ddc86..0000000 --- a/post/tests/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ - -file(GLOB test_scripts CONFIGURE_DEPENDS ./*.py ./*.yaml) -install( - PROGRAMS ${test_scripts} - DESTINATION bin) diff --git a/post/tests/s2sv3Toc12MOM6.yaml b/post/tests/s2sv3Toc12MOM6.yaml deleted file mode 100644 index d280414..0000000 --- a/post/tests/s2sv3Toc12MOM6.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# -# This template file can be filled with questionary or manually -# -# - -input: - air: - drymass: 1 - hydrostatic: 0 - shared: - MERRA-2: false - agrid: C180 - bcs_dir: /discover/nobackup/projects/gmao/ssd/aogcm/atmosphere_bcs/Icarus/MOM5//CF0180x6C_TM1440xTM1080/ - expid: M2OCEAN_S2SV3 - ogrid: 1440X1080 - rst_dir: /discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/s2sv3Toc12MOM6/inputs - yyyymmddhh: '1982010100' - surface: - zoom: '2' - wemin: '26' - # it supports three models: catch, catchcnclm40, catchcnclm45 - catch_model: catch - # if catch_tilefile is null, it searches bcs_dir - catch_tilefile: -output: - shared: - agrid: C12 - bcs_dir: /discover/nobackup/projects/gmao/ssd/aogcm/atmosphere_bcs/Icarus-NLv3/MOM6//CF0012x6C_TM0072xTM0036/ - expid: C12-MOM6-from-S2Sv3 - ogrid: 72X36 - out_dir: $NOBACKUP/REMAP_TESTS/s2sv3Toc12MOM6/ - air: - # remap upper air or not - remap: true - nlevel: '72' - surface: - split_saltwater: true - surflay: 50.0 - wemin: '13' - # remap lake, saltwater, landicet - remap_water: true - # remap catch(cn) - remap_catch: true - # if catch_tilefile is null, it searches bcs_dir - catch_tilefile: - analysis: - bkg: false - aqua: true - lcv: false - -slurm: - account: g0620 - qos: debug - constraint: cas diff --git a/pre/CMakeLists.txt b/pre/CMakeLists.txt index bbc0167..4653c7c 100644 --- a/pre/CMakeLists.txt +++ b/pre/CMakeLists.txt @@ -1,7 +1,7 @@ add_subdirectory(NSIDC-OSTIA_SST-ICE_blend) add_subdirectory(prepare_ocnExtData) -file(GLOB pythonscripts CONFIGURE_DEPENDS ./remap_restart/remap*) +file(GLOB pythonscripts CONFIGURE_DEPENDS ./remap_restart/remap* ./remap_restart/bin2nc_merra2* ./remap_restart/tests/*.*) install( PROGRAMS ${pythonscripts} DESTINATION bin) diff --git a/pre/remap_restart/bin2nc_merra2_agcm.yaml b/pre/remap_restart/bin2nc_merra2_agcm.yaml new file mode 100644 index 0000000..d2c12e7 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_agcm.yaml @@ -0,0 +1,48 @@ +variables: + - short_name: DUDT + long_name: eastward_wind_analysis_increment + units: 'm s-1' + dimension: + - lev + - lat + - lon + - short_name: DVDT + long_name: northward_wind_analysis_increment + units: 'm s-1' + dimension: + - lev + - lat + - lon + - short_name: DTDT + long_name: temperature_analysis_increment + units: 'K' + dimension: + - lev + - lat + - lon + - short_name: DPEDT + long_name: edge_pressure_analysis_increment + units: 'Pa' + dimension: + - lev + - lat + - lon + - short_name: DQVDT + long_name: specific_humidity_analysis_increment + units: 'kg kg-1' + dimension: + - lev + - lat + - lon + - short_name: DO3DT + long_name: ozone_analysis_increment + units: 'ppmv' + dimension: + - lev + - lat + - lon +dimensions: + lon: 180 + lat: 1080 + lev: 72 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_catch.yaml b/pre/remap_restart/bin2nc_merra2_catch.yaml new file mode 100644 index 0000000..077ca94 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_catch.yaml @@ -0,0 +1,297 @@ +variables: + - short_name: 'BF1' + long_name: 'topo_baseflow_param_1' + units: 'kg m-4' + dimension: + - tile + - short_name: 'BF2' + long_name: 'topo_baseflow_param_2' + units: 'm' + dimension: + - tile + - short_name: 'BF3' + long_name: 'topo_baseflow_param_3' + units: 'log(m)' + dimension: + - tile + - short_name: 'VGWMAX' + long_name: 'max_rootzone_water_content' + units: 'kg m-2' + dimension: + - tile + - short_name: 'CDCR1' + long_name: 'moisture_threshold' + units: 'kg m-2' + dimension: + - tile + - short_name: 'CDCR2' + long_name: 'max_water_content' + units: 'kg m-2' + dimension: + - tile + - short_name: 'PSIS' + long_name: 'saturated_matric_potential' + units: 'm' + dimension: + - tile + - short_name: 'BEE' + long_name: 'clapp_hornberger_b' + units: '1' + dimension: + - tile + - short_name: 'POROS' + long_name: 'soil_porosity' + units: '1' + dimension: + - tile + - short_name: 'WPWET' + long_name: 'wetness_at_wilting_point' + units: '1' + dimension: + - tile + - short_name: 'COND' + long_name: 'sfc_sat_hydraulic_conduct' + units: 'm s-1' + dimension: + - tile + - short_name: 'GNU' + long_name: 'vertical_transmissivity' + units: 'm-1' + dimension: + - tile + - short_name: 'ARS1' + long_name: 'wetness_param_1' + units: 'm+2 kg-1' + dimension: + - tile + - short_name: 'ARS2' + long_name: 'wetness_param_2' + units: 'm+2 kg-1' + dimension: + - tile + - short_name: 'ARS3' + long_name: 'wetness_param_3' + units: 'm+4 kg-2' + dimension: + - tile + - short_name: 'ARA1' + long_name: 'shape_param_1' + units: 'm+2 kg-1' + dimension: + - tile + - short_name: 'ARA2' + long_name: 'shape_param_2' + units: '1' + dimension: + - tile + - short_name: 'ARA3' + long_name: 'shape_param_3' + units: 'm+2 kg-1' + dimension: + - tile + - short_name: 'ARA4' + long_name: 'shape_param_4' + units: '1' + dimension: + - tile + - short_name: 'ARW1' + long_name: 'min_theta_param_1' + units: 'm+2 kg-1' + dimension: + - tile + - short_name: 'ARW2' + long_name: 'min_theta_param_2' + units: 'm+2 kg-1' + dimension: + - tile + - short_name: 'ARW3' + long_name: 'min_theta_param_3' + units: 'm+4 kg-2' + dimension: + - tile + - short_name: 'ARW4' + long_name: 'min_theta_param_4' + units: '1' + dimension: + - tile + - short_name: 'TSA1' + long_name: 'water_transfer_param_1' + units: '1' + dimension: + - tile + - short_name: 'TSA2' + long_name: 'water_transfer_param_2' + units: '1' + dimension: + - tile + - short_name: 'TSB1' + long_name: 'water_transfer_param_3' + units: '1' + dimension: + - tile + - short_name: 'TSB2' + long_name: 'water_transfer_param_4' + units: '1' + dimension: + - tile + - short_name: 'ATAU' + long_name: 'water_transfer_param_5' + units: '1' + dimension: + - tile + - short_name: 'BTAU' + long_name: 'water_transfer_param_6' + units: '1' + dimension: + - tile + - short_name: 'OLD_ITY' + long_name: 'Placeholder. Used to be vegetation_type.' + units: '1' + dimension: + - tile + - short_name: 'TC' + long_name: 'canopy_temperature' + units: 'K' + dimension: + - subtile + - tile + - short_name: 'QC' + long_name: 'canopy_specific_humidity' + units: 'kg kg-1' + dimension: + - subtile + - tile + - short_name: 'CAPAC' + long_name: 'interception_reservoir_capac' + units: 'kg m-2' + dimension: + - tile + - short_name: 'CATDEF' + long_name: 'catchment_deficit' + units: 'kg m-2' + dimension: + - tile + - short_name: 'RZEXC' + long_name: 'root_zone_excess' + units: 'kg m-2' + dimension: + - tile + - short_name: 'SRFEXC' + long_name: 'surface_excess' + units: 'kg m-2' + dimension: + - tile + - short_name: 'GHTCNT1' + long_name: 'soil_heat_content_layer_1' + units: 'J m-2' + dimension: + - tile + - short_name: 'GHTCNT2' + long_name: 'soil_heat_content_layer_2' + units: 'J_m-2' + dimension: + - tile + - short_name: 'GHTCNT3' + long_name: 'soil_heat_content_layer_3' + units: 'J m-2' + dimension: + - tile + - short_name: 'GHTCNT4' + long_name: 'soil_heat_content_layer_4' + units: 'J m-2' + dimension: + - tile + - short_name: 'GHTCNT5' + long_name: 'soil_heat_content_layer_5' + units: 'J m-2' + dimension: + - tile + - short_name: 'GHTCNT6' + long_name: 'soil_heat_content_layer_6' + units: 'J m-2' + dimension: + - tile + - short_name: 'TSURF' + long_name: 'mean_catchment_temp_incl_snw' + units: 'K' + dimension: + - tile + - short_name: 'WESNN1' + long_name: 'snow_mass_layer_1' + units: 'kg m-2' + dimension: + - tile + - short_name: 'WESNN2' + long_name: 'snow_mass_layer_2' + units: 'kg m-2' + dimension: + - tile + - short_name: 'WESNN3' + long_name: 'snow_mass_layer_3' + units: 'kg m-2' + dimension: + - tile + - short_name: 'HTSNNN1' + long_name: 'heat_content_snow_layer_1' + units: 'J m-2' + dimension: + - tile + - short_name: 'HTSNNN2' + long_name: 'heat_content_snow_layer_2' + units: 'J m-2' + dimension: + - tile + - short_name: 'HTSNNN3' + long_name: 'heat_content_snow_layer_3' + units: 'J m-2' + dimension: + - tile + - short_name: 'SNDZN1' + long_name: 'snow_depth_layer_1' + units: 'm' + dimension: + - tile + - short_name: 'SNDZN2' + long_name: 'snow_depth_layer_2' + units: 'm' + dimension: + - tile + - short_name: 'SNDZN3' + long_name: 'snow_depth_layer_3' + units: 'm' + dimension: + - tile + - short_name: 'CH' + long_name: 'surface_heat_exchange_coefficient' + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: 'CM' + long_name: 'surface_momentum_exchange_coefficient' + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: 'CQ' + long_name: 'surface_moisture_exchange_coffiecient' + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: 'FR' + long_name: 'subtile_fractions' + units: '1' + dimension: + - subtile + - tile + - short_name: 'WW' + long_name: 'vertical_velocity_scale_squared' + units: 'm+2 s-2' + dimension: + - subtile + - tile +dimensions: + tile: 195136 + subtile: 4 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_fv.yaml b/pre/remap_restart/bin2nc_merra2_fv.yaml new file mode 100644 index 0000000..4756f29 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_fv.yaml @@ -0,0 +1,66 @@ +variables: + - short_name: AK + long_name: hybrid_sigma_pressure_a + units: 'Pa' + dimension: + - edges + - short_name: BK + long_name: hybrid_sigma_pressure_b + units: '1' + dimension: + - edges + - short_name: U + long_name: eastward_wind + units: 'm s-1' + dimension: + - lev + - lat + - lon + - short_name: V + long_name: northward_wind + units: 'm s-1' + dimension: + - lev + - lat + - lon + - short_name: PT + long_name: scaled_potential_temperature + units: 'K Pa$^{-\kappa}$' + dimension: + - lev + - lat + - lon + - short_name: PE + long_name: air_pressure + units: 'Pa' + dimension: + - edges + - lat + - lon + - short_name: PKZ + long_name: pressure_to_kappa + units: 'Pa$^\kappa$' + dimension: + - lev + - lat + - lon + - short_name: DZ + long_name: height_thickness + units: 'm' + dimension: + - lev + - lat + - lon + - short_name: W + long_name: vertical_velocity + units: 'm s-1' + dimension: + - lev + - lat + - lon +dimensions: + lon: 180 + lat: 1080 + lev: 72 + edges: 73 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_gocart.yaml b/pre/remap_restart/bin2nc_merra2_gocart.yaml new file mode 100644 index 0000000..6140738 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_gocart.yaml @@ -0,0 +1,48 @@ +variables: + - short_name: OX + long_name: odd_oxygen_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: N20 + long_name: nitrous_oxide_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: CFC11 + long_name: CFC11_(CCl3F)_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: CFC12 + long_name: CFC12_(CCl2F2)_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: HCFC22 + long_name: HCFC22_(CHClF2)_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: CH4 + long_name: methane_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon +dimensions: + lon: 180 + lat: 1080 + lev: 72 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_lake.yaml b/pre/remap_restart/bin2nc_merra2_lake.yaml new file mode 100644 index 0000000..0719e94 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_lake.yaml @@ -0,0 +1,41 @@ +variables: + - short_name: TS + long_name: surface_skin_temperature + units: 'K' + dimension: + - subtile + - tile + - short_name: QS + long_name: surface_specific_humidity + units: 'kg kg-1' + dimension: + - subtile + - tile + - short_name: FR + long_name: ice_fraction + units: '1' + dimension: + - subtile + - tile + - short_name: CH + long_name: surface_heat_exchange_coefficient + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: CM + long_name: surface_momentum_exchange_coefficient + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: CQ + long_name: surface_moisture_exchange_coefficient + units: 'kg m-2 s-1' + dimension: + - subtile + - tile +dimensions: + tile: 14910 + subtile: 2 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_landice.yaml b/pre/remap_restart/bin2nc_merra2_landice.yaml new file mode 100644 index 0000000..6d66370 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_landice.yaml @@ -0,0 +1,67 @@ +variables: + - short_name: TS + long_name: surface_skin_temperature + units: 'K' + dimension: + - unknown_dim1 + - tile + - short_name: QS + long_name: surface_specific_humidity + units: 'kg kg-1' + dimension: + - unknown_dim1 + - tile + - short_name: FR + long_name: ice_fraction + units: '1' + dimension: + - unknown_dim1 + - tile + - short_name: CH + long_name: surface_heat_exchange_coefficient + units: 'kg m-2 s-1' + dimension: + - unknown_dim1 + - tile + - short_name: CM + long_name: surface_momentum_exchange_coefficient + units: 'kg m-2 s-1' + dimension: + - unknown_dim1 + - tile + - short_name: CQ + long_name: surface_moisture_exchange_coefficient + units: 'kg m-2 s-1' + dimension: + - unknown_dim1 + - tile + - short_name: WESN + long_name: snow_layer_mass + units: 'kg m-2' + dimension: + - unknown_dim2 + - tile + - short_name: HTSN + long_name: snow_layer_heat_content + units: 'J m-2' + dimension: + - unknown_dim2 + - tile + - short_name: SNDZ + long_name: snow_layer_heat_depth + units: 'm' + dimension: + - unknown_dim2 + - tile + - short_name: TICE + long_name: ice_layer_temperature + units: 'k' + dimension: + - unknown_dim2 + - unknown_dim1 + - tile +dimensions: + tile: 5997 + unknown_dim1: 2 + unknown_dim2: 15 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_moist.yaml b/pre/remap_restart/bin2nc_merra2_moist.yaml new file mode 100644 index 0000000..5fae226 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_moist.yaml @@ -0,0 +1,55 @@ +variables: + - short_name: Q + long_name: specific_humidity + units: 'kg kg-1' + dimension: + - lev + - lat + - lon + - short_name: QLLS + long_name: mass_fraction_of_large_scale_cloud_liquid_water + units: 'kg kg-1' + dimension: + - lev + - lat + - lon + - short_name: QLCN + long_name: mass_fraction_of_convective_cloud_liquid_water + units: 'kg kg-1' + dimension: + - lev + - lat + - lon + - short_name: CLLS + long_name: large_scale_cloud_area_fraction + units: '1' + dimension: + - lev + - lat + - lon + - short_name: CLCN + long_name: convective_cloud_area_fraction + units: '1' + dimension: + - lev + - lat + - lon + - short_name: QILS + long_name: mass_fraction_of_large_scale_cloud_ice_water + units: '1' + dimension: + - lev + - lat + - lon + - short_name: QICN + long_name: mass_fraction_of_convective_cloud_ice_water + units: '1' + dimension: + - lev + - lat + - lon +dimensions: + lon: 180 + lat: 1080 + lev: 72 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_pchem.yaml b/pre/remap_restart/bin2nc_merra2_pchem.yaml new file mode 100644 index 0000000..6140738 --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_pchem.yaml @@ -0,0 +1,48 @@ +variables: + - short_name: OX + long_name: odd_oxygen_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: N20 + long_name: nitrous_oxide_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: CFC11 + long_name: CFC11_(CCl3F)_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: CFC12 + long_name: CFC12_(CCl2F2)_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: HCFC22 + long_name: HCFC22_(CHClF2)_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon + - short_name: CH4 + long_name: methane_volume_mixing_ratio + units: 'mol mol-1' + dimension: + - lev + - lat + - lon +dimensions: + lon: 180 + lat: 1080 + lev: 72 + time: 1 diff --git a/pre/remap_restart/bin2nc_merra2_salt.yaml b/pre/remap_restart/bin2nc_merra2_salt.yaml new file mode 100644 index 0000000..c65e09a --- /dev/null +++ b/pre/remap_restart/bin2nc_merra2_salt.yaml @@ -0,0 +1,81 @@ +variables: + - short_name: 'HSKINW' + long_name: 'water_skin_layer_mass' + units: 'kg m-2' + dimension: + - tile + - short_name: 'TSKINW' + long_name: 'water_skin_temperature' + units: 'K' + dimension: + - tile + - short_name: 'SSKINW' + long_name: 'water_skin_salinity' + units: 'psu' + dimension: + - tile + - short_name: 'HSKINI' + long_name: 'ice_skin_layer_mass' + units: 'kg m-2' + dimension: + - tile + - short_name: 'TSKINI' + long_name: 'ice_skin_temperature' + units: 'K' + dimension: + - tile + - short_name: 'SSKINI' + long_name: 'ice_skin_salinity' + units: 'psu' + dimension: + - tile + - short_name: 'QS' + long_name: 'surface_specific_humidity' + units: 'kg kg-1' + dimension: + - subtile + - tile + - short_name: 'CH' + long_name: 'surface_heat_exchange_coefficient' + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: 'CM' + long_name: 'surface_momentum_exchange_coefficient' + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: 'CQ' + long_name: 'surface_moisture_exchange_coefficient' + units: 'kg m-2 s-1' + dimension: + - subtile + - tile + - short_name: 'Z0' + long_name: 'aerodynamic_roughness' + units: 'm' + dimension: + - subtile + - tile + - short_name: 'WW' + long_name: 'vertical_velocity_scale_squared' + units: 'm+2 s-2' + dimension: + - subtile + - tile + - short_name: 'TWMTS' + long_name: 'departure_of_skin_temperature_from_mean_interface_temperature' + units: 'K' + dimension: + - tile + - short_name: 'DTWARM' + long_name: 'departure_of_departure_of_TDEL_from_TS_FOUND' + units: 'K' + dimension: + - tile +dimensions: + tile: 1385431 + subtile: 2 + time: 1 diff --git a/pre/remap_restart/remap_analysis.py b/pre/remap_restart/remap_analysis.py index 6754514..5236c66 100755 --- a/pre/remap_restart/remap_analysis.py +++ b/pre/remap_restart/remap_analysis.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 # -# source install/bin/g5_modules +# remap_restarts package: +# remap_analysis.py remaps atmospheric analysis restarts using config inputs from `remap_params.yaml` # -# Newer GEOS code should load a module with GEOSpyD Python3 if not run: -# module load python/GEOSpyD/Min4.10.3_py3.9 +# to run, must first load modules (incl. python3) as follows: +# +# source g5_modules.sh [bash] +# source g5_modules [csh] # - import os from datetime import datetime, timedelta import subprocess @@ -15,6 +17,8 @@ import fileinput import ruamel.yaml from remap_base import remap_base +from remap_utils import get_label +import fnmatch class analysis(remap_base): def __init__(self, **configs): @@ -61,12 +65,18 @@ def remap(self): else: expid_out = '' + label = get_label(config) + aqua = config['output']['analysis']['aqua'] local_fs=[] for f in analysis_in: - print(f) fname = os.path.basename(f) - out_name = fname.replace(expid_in + '.', expid_out) + out_name = '' + if (expid_in) : + out_name = fname.replace(expid_in + '.', expid_out) + else: + out_name = expid_out+fname + f_tmp = tmpdir+'/'+out_name local_fs.append(f_tmp) shutil.copy(f,f_tmp) @@ -74,30 +84,41 @@ def remap(self): if (aqua): f_ = open(f_tmp, 'w') for line in fileinput.input(f): + # This is unlikely to be the case with new files f_.write(line.replace('airs281SUBSET_aqua', 'airs281_aqua ')) f_.close() nlevel = config['output']['air']['nlevel'] agrid_out = config['output']['shared']['agrid'] flags = "-g5 -res " + self.get_grid_kind(agrid_out.upper()) + " -nlevs " + str(nlevel) - bkg_files = glob.glob(tmpdir+'/*.bkg??_eta_rst*') - for f in bkg_files: - f_orig = f + ".orig" - shutil.move(f,f_orig) - cmd = bindir + '/dyn2dyn.x ' + flags + ' -o ' + f + ' ' + f_orig - print(cmd) - subprocess.call(shlex.split(cmd)) + + dyn2dyn = fnmatch.filter(local_fs, '*bkg??_eta_rst*') + for f in dyn2dyn: + if "cbkg" not in f: + f_orig = f + ".orig" + shutil.move(f,f_orig) + cmd = bindir + '/dyn2dyn.x ' + flags + ' -o ' + f + ' ' + f_orig + print(cmd) + subprocess.call(shlex.split(cmd)) for f in local_fs: fname = os.path.basename(f) + fname = fname + label shutil.move(f, out_dir+'/'+fname) - # write lcv + # write lcv file + # (Info about "lcv" file provided by Ricardo Todling via email, 1 Sep 2023, + # paraphrased by Rolf Reichle: + # The lcv file is binary and inherits the nomenclature of the old GCM primary restarts [GEOS-4]. + # The file simply carries the date of the restarts, e.g., 20231201 210000. + # The file is required by the ADAS. + # LCV stands for Lagrangian Control Volume, which is what the grid coordinates of the model are + # [on the cubed-sphere for GEOS-5].) lcv = config['output']['analysis']['lcv'] if lcv : ymd_ = yyyymmddhh_[0:8] hh_ = yyyymmddhh_[8:10] hms_ = hh_+'0000' - rstlcvOut = out_dir+'/'+expid_out+'rst.lcv.'+ymd_+'_'+hh_+'z.bin' + rstlcvOut = out_dir+'/'+expid_out+'rst.lcv.'+ymd_+'_'+hh_+'z.bin' + label cmd = bindir+'/mkdrstdate.x ' + ymd_ + ' ' + hms_ +' ' + rstlcvOut print(cmd) subprocess.call(shlex.split(cmd)) @@ -151,11 +172,12 @@ def copy_merra2(self): merra_2_rst_dir = '/archive/users/gmao_ops/MERRA2/gmao_ops/GEOSadas-5_12_4/'+expid +'/rs/Y'+yyyy_ +'/M'+mm_+'/' rst_dir = self.config['input']['shared']['rst_dir'] + '/' os.makedirs(rst_dir, exist_ok = True) - print(' Copy MERRA-2 analysis files \n from \n ' + merra_2_rst_dir + '\n to\n '+ rst_dir +'\n') + print(' Stage MERRA-2 analysis files \n from \n ' + merra_2_rst_dir + '\n to\n '+ rst_dir +'\n') rst_time = datetime(year=int(yyyy_), month=int(mm_), day=int(dd_), hour = int(hh_)) anafiles=[] + canafiles=[] for h in [3,4,5,6,7,8,9]: delt = timedelta(hours = h-3) new_time = rst_time + delt @@ -182,6 +204,24 @@ def copy_merra2(self): anafiles.append(f) else: print('Warning: Cannot find '+f) + + # cbkg files + fname = expid + '.cbkg'+hh+'_eta_rst.'+ymd+'_'+newhh+'z.nc4' + f = m2_rst_dir+'/'+fname + if(os.path.isfile(f)): + canafiles.append(f) + else: + print('Warning: Cannot find '+f) + + # satb files + for ftype in ['satbias', 'satbang']: + fname = expid + '.ana_'+ftype+'_rst.'+ymd+'_'+newhh+'z.txt' + f = m2_rst_dir+'/'+fname + if(os.path.isfile(f)): + canafiles.append(f) + else: + print('Warning: Cannot find '+f) + # trak.GDA.rst file delt = timedelta(hours = 3) new_time = rst_time - delt @@ -193,10 +233,10 @@ def copy_merra2(self): f = m2_rst_dir+'/'+fname if (os.path.isfile(f)): anafiles.append(f) - for f in anafiles: + for f in anafiles + canafiles: fname = os.path.basename(f) f_tmp = rst_dir+'/'+fname - print("Copy file "+f +" to " + rst_dir) + print("Stage file "+f +" to " + rst_dir) shutil.copy(f,f_tmp) if __name__ == '__main__' : diff --git a/pre/remap_restart/remap_base.py b/pre/remap_restart/remap_base.py index 5163c91..990456b 100755 --- a/pre/remap_restart/remap_base.py +++ b/pre/remap_restart/remap_base.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 # +# remap_restarts package: +# remap_base.py does [???] +# import os import ruamel.yaml import shutil diff --git a/pre/remap_restart/remap_bin2nc.py b/pre/remap_restart/remap_bin2nc.py new file mode 100755 index 0000000..f7b94ed --- /dev/null +++ b/pre/remap_restart/remap_bin2nc.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# +# remap_restarts package: +# remap_bin2nc.py converts binary MERRA-2 restarts to nc4 +# +# As of Sep 2023, MERRA-2 restarts are the only binary restarts that may need to be +# remapped. The set of yaml config files "bin2nc_merra2_*.yaml" include hard-wired +# variables names, long names, and tile/grid dimensions specific to MERRA-2 restarts. + +from yaml import safe_load, load, dump +from netCDF4 import Dataset +import numpy as np +from scipy.io import FortranFile + +def writeCVars(coordVars,dimensions): + + for v in coordVars: + if v=='time': + coordVars[v][:]=0 + elif (v=='lat') | (v=='lon') | (v=='lev') | (v=='edges'): + dsize=dimensions[v] + coords=np.arange(1,dsize+1) + coordVars[v][:]=coords + +def writeVar(v, vars, dimensions, bintype, binf): + var=vars[v['short_name']] + dims = v['dimension'] + # is tile? + if 'tile' in dims: + if ('subtile' in dims) & (len(dims)==2): + rec=binf.read_reals(dtype=bintype) + tilesize=dimensions.get('tile') + for i in range(dimensions.get('subtile')): + var[i,:]=rec[i*tilesize:(i+1)*tilesize] + elif (len(dims)==2) & ( ('unknown_dim1' in dims) | ('unknown_dim2' in dims) ): + if 'unknown_dim1' in dims: + dsize=dimensions.get('unknown_dim1') + if 'unknown_dim2' in dims: + dsize=dimensions.get('unknown_dim2') + for i in range(dsize): + rec = binf.read_reals(dtype=bintype) + var[i,:]=rec + elif (len(dims)==3) & ('unknown_dim1' in dims) & ('unknown_dim2' in dims): + for j in range(dimensions.get('unknown_dim2')): + for i in range(dimensions.get('unknown_dim1')): + rec = binf.read_reals(dtype=bintype) + var[j,i,:]=rec + elif (len(dims)==1): + rec = binf.read_reals(dtype=bintype) + var[:]=rec + + # is gridded + elif 'lat' in dims: + if 'lev' in dims: + for i in range(dimensions.get('lev')): + rec = binf.read_reals(dtype=bintype) + var[i,:,:]=rec + elif 'edges' in dims: + for i in range(dimensions.get('edges')): + rec = binf.read_reals(dtype=bintype) + var[i,:,:]=rec + else: + rec = binf.read_reals(dtype=bintype) + var[:,:]=rec + # is just lev + else: + if 'edges' in dims: + rec = binf.read_reals(dtype=bintype) + var[:]=rec + +def defineDimVars(fid,dims): + coordVars = {} + for d in dims: + if d=="lon": + newVar=fid.createVariable(d,'f8',d) + setattr(newVar,'units','degrees_east') + setattr(newVar,'long_name','Longitude') + coordVars.update([(d,newVar)]) + if d=="lat": + newVar=fid.createVariable(d,'f8',d) + setattr(newVar,'units','degrees_north') + setattr(newVar,'long_name','Latitude') + coordVars.update([(d,newVar)]) + if d=="lev": + newVar=fid.createVariable(d,'f8',d) + setattr(newVar,'units','layer') + setattr(newVar,'long_name','sigma_at_layer_midpoints') + setattr(newVar,'standard_name','atmosphere_hybrid_sigma_pressure_coordinate') + setattr(newVar,'coordinate','eta') + setattr(newVar,'positive','down') + setattr(newVar,'formulaTerms','ap: ak b: bk ps: ps p0: p00') + coordVars.update([(d,newVar)]) + if d=="edges": + newVar=fid.createVariable(d,'f8',d) + setattr(newVar,'units','level') + setattr(newVar,'long_name','sigma_at_layer edges') + setattr(newVar,'standard_name','atmosphere_hybrid_sigma_pressure_coordinate') + setattr(newVar,'coordinate','eta') + setattr(newVar,'positive','down') + setattr(newVar,'formulaTerms','ap: ak b: bk ps: ps p0: p00') + coordVars.update([(d,newVar)]) + if d=="time": + newVar=fid.createVariable(d,'f8',d) + setattr(newVar,'units','minutes since ') + setattr(newVar,'long_name','time') + coordVars.update([(d,newVar)]) + + return coordVars + +def bin2nc(binfile, ncfile, yamlfile, isDouble=False, hasHeader=False, debug=False): + + bintype=np.float32 + if (isDouble): + bintype=np.float64 + + + f=open(yamlfile,'r') + + data=safe_load(f) + + dimensions = data["dimensions"] + variables = data["variables"] + + if debug: + print(dump(variables)) + print(dump(dimensions)) + + ncfid = Dataset(ncfile,mode='w',format='NETCDF4') + + dimids = {} + for d in dimensions: + dsize = dimensions.get(d) + newDim = ncfid.createDimension(d,dsize) + dimids.update([(d,newDim)]) + + cVars = defineDimVars(ncfid,dimids) + + vars = {} + for v in variables: + sname = v['short_name'] + lname = v['long_name'] + units = v['units'] + dims = v['dimension'] + newVar = ncfid.createVariable(sname,'f4',dims) + setattr(newVar,'long_name',lname) + setattr(newVar,'units',units) + vars.update([(sname,newVar)]) + + writeCVars(cVars,dimensions) + + binf =FortranFile(binfile,'r') + if hasHeader: + if debug: + print("reading header") + rec = binf.read_ints(dtype=np.int32) + if debug: + print(rec) + rec = binf.read_ints(dtype=np.int32) + if debug: + print(rec) + + for v in variables: + writeVar(v,vars,dimensions,bintype, binf) + + ncfid.close() + +if __name__ == "__main__": + + bin2nc('fvcore_internal_rst', 'fvcore_internal_rst.nc4', 'bin2nc_merra2_fv.yaml', isDouble=True, hasHeader=True) + bin2nc('moist_internal_rst', 'moist_internal_rst.nc4', 'bin2nc_merra2_moist.yaml') + bin2nc('pchem_internal_rst', 'pchem_internal_rst.nc4', 'bin2nc_merra2_pchem.yaml') + bin2nc('agcm_import_rst', 'agcm_import_rst.nc4', 'bin2nc_merra2_agcm.yaml') + bin2nc('gocart_internal_rst', 'gocart_internal_rst.nc4', 'bin2nc_merra2_gocart.yaml') + bin2nc('lake_internal_rst', 'lake_internal_rst.nc4', 'bin2nc_merra2_lake.yaml') + bin2nc('landice_internal_rst', 'landice_internal_rst.nc4', 'bin2nc_merra2_landice.yaml') + bin2nc('saltwater_internal_rst','saltwater_internal_rst.nc4', 'bin2nc_merra2_saltwater.yaml') + bin2nc('catch_internal_rst', 'catch_internal_rst.nc4', 'bin2nc_merra2_catch.yaml') diff --git a/pre/remap_restart/remap_catchANDcn.py b/pre/remap_restart/remap_catchANDcn.py index b83a537..c374f49 100755 --- a/pre/remap_restart/remap_catchANDcn.py +++ b/pre/remap_restart/remap_catchANDcn.py @@ -1,5 +1,13 @@ #!/usr/bin/env python3 # +# remap_restarts package: +# remap_catchANDcn.py remaps Catchment[CN] land model restarts using config inputs from `remap_params.yaml` +# +# to run, must first load modules (incl. python3) as follows: +# +# source g5_modules.sh [bash] +# source g5_modules [csh] +# import os import sys import subprocess @@ -10,14 +18,9 @@ import mimetypes import netCDF4 as nc from remap_base import remap_base - -def get_landdir(bcsdir): - k = bcsdir.find('/geometry/') - if k != -1 : - while bcsdir[-1] == '/': bcsdir = bcsdir[0:-1] # remove extra '/' - sub_grids = os.path.basename(bcsdir) - bcsdir = bcsdir[0:k]+'/land/'+ sub_grids - return bcsdir +from remap_utils import get_landdir +from remap_utils import get_geomdir +from remap_utils import get_label class catchANDcn(remap_base): def __init__(self, **configs): @@ -44,25 +47,38 @@ def remap(self): print("\nRemapping " + model + ".....\n") - cwdir = os.getcwd() - bindir = os.path.dirname(os.path.realpath(__file__)) - in_bcsdir = config['input']['shared']['bcs_dir'] - out_bcsdir = config['output']['shared']['bcs_dir'] - out_dir = config['output']['shared']['out_dir'] - expid = config['output']['shared']['expid'] - in_wemin = config['input']['surface']['wemin'] - out_wemin = config['output']['surface']['wemin'] - surflay = config['output']['surface']['surflay'] - in_tilefile = config['input']['surface']['catch_tilefile'] + cwdir = os.getcwd() + bindir = os.path.dirname(os.path.realpath(__file__)) + in_bc_base = config['input']['shared']['bc_base'] + in_bc_version = config['input']['shared']['bc_version'] + out_bc_base = config['output']['shared']['bc_base'] + out_bc_version = config['output']['shared']['bc_version'] + out_dir = config['output']['shared']['out_dir'] + expid = config['output']['shared']['expid'] + in_wemin = config['input']['surface']['wemin'] + out_wemin = config['output']['surface']['wemin'] + surflay = config['output']['surface']['surflay'] + in_tilefile = config['input']['surface']['catch_tilefile'] if not in_tilefile : - if not in_bcsdir: - exit("Must provide either input tile file or input bcs directory") - in_tilefile = glob.glob(in_bcsdir+ '/*.til')[0] - + agrid = config['input']['shared']['agrid'] + ogrid = config['input']['shared']['ogrid'] + omodel = config['input']['shared']['omodel'] + stretch = config['input']['shared']['stretch'] + bc_geomdir = get_geomdir(in_bc_base, in_bc_version, agrid, ogrid, omodel, stretch) + in_tilefile = glob.glob(bc_geomdir + '/*.til')[0] + + agrid = config['output']['shared']['agrid'] + ogrid = config['output']['shared']['ogrid'] + omodel = config['output']['shared']['omodel'] + stretch = config['output']['shared']['stretch'] out_tilefile = config['output']['surface']['catch_tilefile'] + if not out_tilefile : - out_tilefile = glob.glob(out_bcsdir+ '/*.til')[0] + bc_geomdir = get_geomdir(out_bc_base, out_bc_version, agrid, ogrid, omodel, stretch) + out_tilefile = glob.glob(bc_geomdir+ '/*.til')[0] + + out_bc_landdir = get_landdir(out_bc_base, out_bc_version, agrid, ogrid, omodel, stretch) # determine NPE based on *approximate* number of input and output tile @@ -75,7 +91,7 @@ def remap(self): in_Ntile = ds.dimensions['tile'].size out_Ntile = 0 - with open( out_bcsdir+'/clsm/catchment.def') as f: + with open( out_bc_landdir+'/clsm/catchment.def') as f: out_Ntile = int(next(f)) max_Ntile = max(in_Ntile, out_Ntile) NPE = 0 @@ -87,10 +103,19 @@ def remap(self): NPE = 120 else: NPE = 160 + + QOS = "#SBATCH --qos="+config['slurm']['qos'] + TIME ="#SBATCH --time=1:00:00" + if NPE >= 160: + assert config['slurm']['qos'] != 'debug', "qos should be allnccs" + TIME = "#SBATCH --time=12:00:00" + PARTITION = "#SBATCH --partition=" + config['slurm']['partition'] account = config['slurm']['account'] - # even the input is binary, the output si nc4 - suffix = time+'z.nc4' + # even if the (MERRA-2) input restarts are binary, the output restarts will always be nc4 (remap_bin2nc.py) + label = get_label(config) + + suffix = time+'z.nc4' + label if (expid) : expid = expid + '.' @@ -114,15 +139,15 @@ def remap(self): shutil.copyfile(in_rstfile,dest) in_rstfile = dest - out_bcsdir = get_landdir(out_bcsdir) log_name = out_dir+'/'+'mk_catchANDcn_log' mk_catch_j_template = """#!/bin/csh -f #SBATCH --account={account} #SBATCH --ntasks={NPE} -#SBATCH --time=1:00:00 #SBATCH --job-name=mk_catchANDcn -#SBATCH --qos=debug #SBATCH --output={log_name} +{TIME} +{QOS} +{PARTITION} # source {Bin}/g5_modules @@ -139,10 +164,10 @@ def remap(self): $esma_mpirun_X $mk_catchANDcnRestarts_X $params """ - catch1script = mk_catch_j_template.format(Bin = bindir, account = account, out_bcs = out_bcsdir, \ + catch1script = mk_catch_j_template.format(Bin = bindir, account = account, out_bcs = out_bc_landdir, \ model = model, out_dir = out_dir, surflay = surflay, log_name = log_name, NPE = NPE, \ in_wemin = in_wemin, out_wemin = out_wemin, out_tilefile = out_tilefile, in_tilefile = in_tilefile, \ - in_rstfile = in_rstfile, out_rstfile = out_rstfile, time = yyyymmddhh_ ) + in_rstfile = in_rstfile, out_rstfile = out_rstfile, time = yyyymmddhh_, TIME = TIME, PARTITION = PARTITION, QOS=QOS ) script_name = './mk_catchANDcn.j' diff --git a/pre/remap_restart/remap_command_line.py b/pre/remap_restart/remap_command_line.py new file mode 100755 index 0000000..2a7693f --- /dev/null +++ b/pre/remap_restart/remap_command_line.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# +# remap_restarts package: +# remap_command_line.py parses and converts the command-line arguments and converts the information +# into matching "Answers" for the questionary (remap_questions.py) +# +import os +import subprocess +import shlex +import ruamel.yaml +import shutil +import questionary +import glob +import argparse +from remap_utils import * +from remap_params import * + +def parse_args(program_description): + + # See remap_utils.py for definitions of "choices", "message" strings, and "validate" lists + # that are used multiple times. + + parser = argparse.ArgumentParser(description='Remap restarts',epilog=program_description,formatter_class=argparse.RawDescriptionHelpFormatter) + + p_sub = parser.add_subparsers(help = 'Sub command help') + p_config = p_sub.add_parser( + 'config_file', + help = "Use config file as input", + ) + + p_config.add_argument('-c', '--config_file', help='YAML config file') + + p_command = p_sub.add_parser( + 'command_line', + help = "Use command line as input", + ) + p_command.add_argument('-merra2', action='store_true', default= False, help='use merra2 restarts') + + p_command.add_argument('-ymdh', help='yyyymmddhh year month date hour of input and new restarts') + p_command.add_argument('-grout', help='Grid ID/resolution of new restarts, format C[xxx] (cubed-sphere only for now)') + p_command.add_argument('-levsout', help='No. of levels for new restarts') + + p_command.add_argument('-rst_dir', help='Directory of input restarts') + p_command.add_argument('-out_dir', help='Directory for new restarts') + + p_command.add_argument('-expid', help='Experiment ID of input restarts') + p_command.add_argument('-newid', default="", help='Experiment ID for new restarts') + + p_command.add_argument('-bcvin', help='Boundary conditions version of input restarts', choices= choices_bc_cmd) + p_command.add_argument('-bcvout', help='Boundary conditions version for new restarts', choices= choices_bc_cmd) + + p_command.add_argument('-in_wemin', help='Min. snow water equivalent param. used with input restarts') + p_command.add_argument('-out_wemin', help='Min. snow water equivalent param. to be used with new restarts') + + p_command.add_argument('-oceanin', help='Ocean resolution of input restarts. See remap_questions.py for choices.\n', choices=choices_ogrid_cmd) + p_command.add_argument('-oceanout', help='Ocean resolution of new restarts. See remap_questions.py for choices.\n', choices=choices_ogrid_cmd) + + p_command.add_argument('-ocnmdlin', default='data', help='Ocean model of input restarts', choices=choices_omodel) + p_command.add_argument('-ocnmdlout', default='data', help='Ocean model for new restarts', choices=choices_omodel) + p_command.add_argument('-in_stretch', default=False, help='Stretched CS params of input restarts', choices=choices_stretch) + p_command.add_argument('-out_stretch', default=False, help='Stretched CS params for new restarts', choices=choices_stretch) + + # Unlike remap_questions.py, command-line feature does not deduce Catch vs. CatchCN[40,45] for simplicity, thus requires input argument + p_command.add_argument('-catch_model',default='catch', help='Catchment[CN] model', choices=choices_catchmodel) + + p_command.add_argument('-nobkg', action='store_true', help="Do not remap bkg files") + p_command.add_argument('-nolcv', action='store_true', help="Do not write lcv file") + p_command.add_argument('-np', action='store_true', help="No prompt. Overwrite config files without prompting questions") + p_command.add_argument('-lbl', action='store_true', help="Label output restarts with bc_versions and resolutions") + p_command.add_argument('-noagcm_import_rst', action='store_true', help="Do not remap agcm_import_rst file") + p_command.add_argument('-in_bc_base', default="", help="Boundary conditions base dir (w/o bc_version and resolution info) for input restarts") + p_command.add_argument('-out_bc_base',default="", help="Boundary conditions base dir (w/o bc_version and resolution info) for new restarts") + p_command.add_argument('-zoom', help= "Zoom parameter (search radius) for input surface restarts") + + p_command.add_argument('-qos', default="debug", help="SLURM quality-of-service", choices=['debug', 'allnccs']) + account = get_account() + p_command.add_argument('-account', default=account, help="SLURM account") + p_command.add_argument('-partition', default='compute', help="SLURM partition") + p_command.add_argument('-rs', default='3', help="Flag indicating which restarts to regrid: 1 (upper air); 2 (surface); 3 (both)", choices=['1','2','3']) + + # Parse using parse_known_args so we can pass the rest to the remap scripts + args, extra_args = parser.parse_known_args() + return args, extra_args + + +def get_answers_from_command_line(cml): + + answers = {} + answers["input:shared:MERRA-2"] = cml.merra2 + answers["input:shared:yyyymmddhh"] = cml.ymdh + answers["input:shared:omodel"] = cml.ocnmdlin + answers["output:shared:out_dir"] = os.path.abspath(cml.out_dir + '/') + if cml.merra2: + init_merra2(answers) + else: + answers["input:shared:bc_version"] = cml.bcvin + answers["input:surface:catch_model"] = cml.catch_model + answers["input:shared:rst_dir"] = os.path.abspath(cml.rst_dir + '/') + fvcore_info(answers) + ogrid = cml.oceanin + if ogrid == "CS": + ogrid = answers["input:shared:agrid"] + answers["input:shared:ogrid"] = ogrid + + answers["output:shared:agrid"] = cml.grout + answers["output:air:nlevel"] = cml.levsout + answers["output:shared:expid"] = cml.newid + answers["output:shared:bc_version"] = cml.bcvout + answers["output:shared:omodel"] = cml.ocnmdlout + answers["output:shared:label"] = cml.lbl + ogrid = cml.oceanout + if ogrid == "CS": + ogrid = answers["output:shared:agrid"] + answers["output:shared:ogrid"] = ogrid + + answers["input:shared:bc_base"] = cml.in_bc_base + answers["output:shared:bc_base"] = cml.out_bc_base + + answers["output:shared:stretch"] = cml.out_stretch + answers["input:shared:stretch"] = cml.in_stretch + answers["output:analysis:bkg"] = not cml.nobkg + answers["output:analysis:lcv"] = not cml.nolcv + if cml.rs == '1': + answers["output:air:remap"] = True + if cml.rs == '2': + answers["output:surface:remap"] = True + if cml.rs == '3': + answers["output:surface:remap"] = True + answers["output:air:remap"] = True + + answers["output:air:agcm_import_rst"] = not cml.noagcm_import_rst + + if cml.zoom: + answers["input:surface:zoom"] = cml.zoom + else: + # zoom_default fills 'input:shared:agrid' + answers["input:surface:zoom"] = zoom_default(answers) + + if cml.in_wemin : + answers["input:surface:wemin"] = cml.in_wemin + else: + answers["input:surface:wemin"] = wemin_default(answers['input:shared:bc_version']) + + if cml.out_wemin : + answers["output:surface:wemin"] = cml.out_wemin + else: + answers["output:surface:wemin"] = wemin_default(answers['output:shared:bc_version']) + + answers["slurm:account"] = cml.account + answers["slurm:qos"] = cml.qos + answers["slurm:partition"] = cml.partition + + return answers + +if __name__ == "__main__": + + yaml = ruamel.yaml.YAML() + cmdl, extra_args = parse_args("test_args") + print(cmdl) + answers = get_answers_from_command_line(cmdl) + config = get_config_from_answers(answers) + with open("raw_command.yaml", "w") as f: + yaml.dump(config, f) + + params = remap_params(config) + with open("params_from_command.yaml", "w") as f: + yaml.dump(params.config, f) + diff --git a/pre/remap_restart/remap_lake_landice_saltwater.py b/pre/remap_restart/remap_lake_landice_saltwater.py index 45c1c1d..486c421 100755 --- a/pre/remap_restart/remap_lake_landice_saltwater.py +++ b/pre/remap_restart/remap_lake_landice_saltwater.py @@ -1,5 +1,14 @@ #!/usr/bin/env python3 # +# remap_restarts package: +# remap_lake_landice_saltwater.py remaps lake, landice, and (data) ocean restarts +# using config inputs from `remap_params.yaml` +# +# to run, must first load modules (incl. python3) as follows: +# +# source g5_modules.sh [bash] +# source g5_modules [csh] +# import os import subprocess import shutil @@ -7,6 +16,9 @@ import ruamel.yaml import shlex from remap_base import remap_base +from remap_utils import get_label +from remap_utils import get_geomdir +from remap_bin2nc import bin2nc class lake_landice_saltwater(remap_base): def __init__(self, **configs): @@ -25,8 +37,11 @@ def remap(self): config = self.config cwdir = os.getcwd() bindir = os.path.dirname(os.path.realpath(__file__)) - in_bcsdir = config['input']['shared']['bcs_dir'] - out_bcsdir = config['output']['shared']['bcs_dir'] + in_bc_base = config['input']['shared']['bc_base'] + in_bc_version = config['input']['shared']['bc_version'] + out_bc_base = config['output']['shared']['bc_base'] + out_bc_version= config['output']['shared']['bc_version'] + out_dir = config['output']['shared']['out_dir'] if not os.path.exists(out_dir) : os.makedirs(out_dir) @@ -43,13 +58,15 @@ def remap(self): print ("mkdir " + OutData_dir) os.makedirs(OutData_dir) - types = 'z.bin' + types = '.bin' type_str = subprocess.check_output(['file','-b', restarts_in[0]]) type_str = str(type_str) if 'Hierarchical' in type_str: - types = 'z.nc4' + types = '.nc4' yyyymmddhh_ = str(config['input']['shared']['yyyymmddhh']) - suffix = yyyymmddhh_[0:8]+'_'+yyyymmddhh_[8:10]+ types + + label = get_label(config) + suffix = yyyymmddhh_[0:8]+'_'+yyyymmddhh_[8:10] +'z' + types + label saltwater = '' seaice = '' @@ -70,10 +87,21 @@ def remap(self): if 'roue' in f : route = f if 'openwater' in f : openwater = f - in_tile_file = glob.glob(in_bcsdir+ '/*-Pfafstetter.til')[0] - out_tile_file = glob.glob(out_bcsdir+ '/*-Pfafstetter.til')[0] - - in_til = InData_dir+'/' + os.path.basename(in_tile_file) + agrid = config['input']['shared']['agrid'] + ogrid = config['input']['shared']['ogrid'] + omodel = config['input']['shared']['omodel'] + stretch = config['input']['shared']['stretch'] + in_geomdir = get_geomdir(in_bc_base, in_bc_version, agrid, ogrid, omodel, stretch) + in_tile_file = glob.glob(in_geomdir+ '/*-Pfafstetter.til')[0] + + agrid = config['output']['shared']['agrid'] + ogrid = config['output']['shared']['ogrid'] + omodel = config['output']['shared']['omodel'] + stretch = config['output']['shared']['stretch'] + out_geomdir = get_geomdir(out_bc_base, out_bc_version, agrid, ogrid, omodel, stretch) + out_tile_file = glob.glob(out_geomdir+ '/*-Pfafstetter.til')[0] + + in_til = InData_dir+'/' + os.path.basename(in_tile_file) out_til = OutData_dir+'/'+ os.path.basename(out_tile_file) if os.path.exists(in_til) : shutil.remove(in_til) @@ -187,12 +215,18 @@ def copy_merra2(self): surfin = [ merra_2_rst_dir + expid+'.lake_internal_rst.' + suffix, merra_2_rst_dir + expid+'.landice_internal_rst.' + suffix, merra_2_rst_dir + expid+'.saltwater_internal_rst.'+ suffix] - - for f in surfin : + bin2nc_yaml = ['bin2nc_merra2_lake.yaml', 'bin2nc_merra2_landice.yaml','bin2nc_merra2_salt.yaml'] + bin_path = os.path.dirname(os.path.realpath(__file__)) + for (f,yf) in zip(surfin, bin2nc_yaml): fname = os.path.basename(f) dest = rst_dir + '/'+fname print("Copy file "+f +" to " + rst_dir) shutil.copy(f, dest) + ncdest = dest.replace('z.bin', 'z.nc4') + yaml_file = bin_path + '/'+yf + print('Convert bin to nc4:' + dest + ' to \n' + ncdest + '\n') + bin2nc(dest, ncdest, yaml_file) + os.remove(dest) if __name__ == '__main__' : lls = lake_landice_saltwater(params_file='remap_params.yaml') diff --git a/pre/remap_restart/remap_params.py b/pre/remap_restart/remap_params.py index ca97af1..045edc1 100755 --- a/pre/remap_restart/remap_params.py +++ b/pre/remap_restart/remap_params.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 # +# remap_restarts package: +# remap_params.py uses the dictionary `answers` (from remap_questions.py) as inputs and +# generates a yaml config file named `remap_params.yaml`. +# import os,sys import ruamel.yaml import shutil @@ -9,7 +13,7 @@ import subprocess from datetime import datetime from datetime import timedelta -from remap_utils import config_to_yaml, merra2_expid +from remap_utils import * class remap_params(object): def __init__(self, config_from_question): @@ -17,14 +21,9 @@ def __init__(self, config_from_question): self.common_out = config_from_question['output']['shared'] self.upper_out = config_from_question['output']['air'] self.slurm_options = config_from_question['slurm'] - self.surf_in = config_from_question['input']['surface'] - self.surf_out = config_from_question['output']['surface'] - self.ana_out = config_from_question['output']['analysis'] - - self.init_time() - self.init_tags() - self.init_merra2() - + self.surf_in = config_from_question['input']['surface'] + self.surf_out = config_from_question['output']['surface'] + self.ana_out = config_from_question['output']['analysis'] # load input yaml yaml = ruamel.yaml.YAML() @@ -35,22 +34,32 @@ def __init__(self, config_from_question): config_tpl = yaml.load(stream) # params for shared - config_tpl['input']['shared']['MERRA-2'] = self.common_in.get('MERRA-2') - config_tpl['input']['shared']['agrid'] = self.common_in.get('agrid') - config_tpl['input']['shared']['ogrid'] = self.common_in.get('ogrid') - config_tpl['input']['shared']['rst_dir'] = self.common_in['rst_dir']+'/' - config_tpl['input']['shared']['expid'] = self.common_in.get('expid') - config_tpl['input']['shared']['yyyymmddhh'] = self.common_in['yyyymmddhh'] - - config_tpl['output']['air']['nlevel'] = self.upper_out.get('nlevel') - config_tpl['output']['air']['remap'] = self.upper_out.get('remap') - config_tpl['input']['surface']['catch_model'] = self.surf_in.get('catch_model') - config_tpl['output']['surface']['remap_water'] = self.surf_out.get('remap') - config_tpl['output']['surface']['remap_catch'] = self.surf_out.get('remap') - config_tpl['output']['shared']['agrid'] = self.common_out['agrid'] - config_tpl['output']['shared']['ogrid'] = self.common_out['ogrid'] - config_tpl['output']['shared']['out_dir'] = self.common_out['out_dir'] + '/' - config_tpl['output']['shared']['expid'] = self.common_out['expid'] + config_tpl['input']['shared']['MERRA-2'] = self.common_in.get('MERRA-2') + config_tpl['input']['shared']['agrid'] = self.common_in.get('agrid') + config_tpl['input']['shared']['ogrid'] = self.common_in.get('ogrid') + config_tpl['input']['shared']['omodel'] = self.common_in.get('omodel') + config_tpl['input']['shared']['rst_dir'] = self.common_in['rst_dir']+'/' + config_tpl['input']['shared']['expid'] = self.common_in.get('expid') + config_tpl['input']['shared']['yyyymmddhh'] = self.common_in['yyyymmddhh'] + config_tpl['input']['shared']['bc_version'] = self.common_in.get('bc_version') + config_tpl['input']['shared']['stretch'] = self.common_in.get('stretch') + config_tpl['input']['shared']['bc_base'] = self.common_in['bc_base'] + config_tpl['input']['surface']['catch_model'] = self.surf_in.get('catch_model') + + config_tpl['output']['air']['nlevel'] = self.upper_out.get('nlevel') + config_tpl['output']['air']['agcm_import_rst'] = self.upper_out.get('agcm_import_rst') + config_tpl['output']['air']['remap'] = self.upper_out.get('remap') + config_tpl['output']['surface']['remap_water'] = self.surf_out.get('remap') + config_tpl['output']['surface']['remap_catch'] = self.surf_out.get('remap') + config_tpl['output']['shared']['agrid'] = self.common_out['agrid'] + config_tpl['output']['shared']['ogrid'] = self.common_out['ogrid'] + config_tpl['output']['shared']['omodel'] = self.common_out['omodel'] + config_tpl['output']['shared']['out_dir'] = self.common_out['out_dir'] + '/' + config_tpl['output']['shared']['expid'] = self.common_out['expid'] + config_tpl['output']['shared']['bc_version'] = self.common_out.get('bc_version') + config_tpl['output']['shared']['label'] = self.common_out.get('label') + config_tpl['output']['shared']['stretch'] = self.common_out.get('stretch') + config_tpl['output']['shared']['bc_base'] = self.common_out['bc_base'] # params for upper air config_tpl = self.params_for_air(config_tpl) @@ -58,440 +67,40 @@ def __init__(self, config_from_question): config_tpl = self.params_for_analysis(config_tpl) config_tpl = self.options_for_slurm(config_tpl) - # get bc directory and tile file - in_bcsdir = self.get_bcdir("IN") - out_bcsdir = self.get_bcdir("OUT") - config_tpl['input']['shared']['bcs_dir'] = in_bcsdir+ '/' - config_tpl['output']['shared']['bcs_dir'] = out_bcsdir + '/' - self.config = config_tpl - def init_tags(self): - # copy and paste from remap.pl - # minor change. Add "D" to the number for each group - # BCS Tag: Fortuna-1_4 - F14 = ( 'F14', 'Fortuna-1_4', 'Fortuna-1_4_p1' ) - D214 = ( 'D214', 'GEOSdas-2_1_4', 'GEOSdas-2_1_4-m1', - 'GEOSdas-2_1_4-m2', 'GEOSdas-2_1_4-m3', 'GEOSdas-2_1_4-m4' ) - D540 = ( 'D540', 'GEOSadas-5_4_0', 'GEOSadas-5_4_0_p1', - 'GEOSadas-5_4_0_p2', 'GEOSadas-5_4_0_p3', 'GEOSadas-5_4_0_p4', - 'GEOSadas-5_4_1', 'GEOSadas-5_4_1_p1', 'GEOSadas-5_4_2', - 'GEOSadas-5_4_3', 'GEOSadas-5_4_4', 'GEOSadas-5_5_0', - 'GEOSadas-5_5_1', 'GEOSadas-5_5_2', 'GEOSadas-5_5_3' ) - - # BCS Tag: Fortuna-2_0 - #--------------------- - F20 = ( 'F20', 'Fortuna-2_0') - - # BCS Tag: Fortuna-2_1 - #--------------------- - F21 = ( 'F21', 'Fortuna-2_1', 'Fortuna-2_1_p1', - 'Fortuna-2_1_p2', 'Fortuna-2_1_p3', 'Fortuna-2_2', - 'Fortuna-2_2_p1', 'Fortuna-2_2_p2', 'Fortuna-2_3', - 'Fortuna-2_3_p1', 'Fortuna-2_4', 'Fortuna-2_4_p1', - 'Fortuna-2_4_p2', 'Fortuna-2_5', 'Fortuna-2_5_BETA0', - 'Fortuna-2_5_p1', 'Fortuna-2_5_p2', 'Fortuna-2_5_p3', - 'Fortuna-2_5_p4', 'Fortuna-2_5_p5', 'Fortuna-2_5_p6', - 'Fortuna-2_5_pp2' ) - D561 = ( 'D561', 'GEOSadas-5_6_1', 'GEOSadas-5_6_1_p1', - 'GEOSadas-5_6_1_p2', 'GEOSadas-5_6_1_p3', 'GEOSadas-5_6_1_p4', - 'GEOSadas-5_6_2', 'GEOSadas-5_6_2_p1', 'GEOSadas-5_6_2_p2', - 'GEOSadas-5_6_2_p3', 'GEOSadas-5_6_2_p4', 'GEOSadas-5_6_2_p5', - 'GEOSadas-5_6_2_p6', 'GEOSadas-5_7_1', 'GEOSadas-5_7_1_p1', - 'GEOSadas-5_7_1_p2', 'GEOSadas-5_7_2', 'GEOSadas-5_7_2_p1', - 'GEOSadas-5_7_2_p2', 'GEOSadas-5_7_2_p2_m1','GEOSadas-5_7_2_p3', - 'GEOSadas-5_7_2_p3_m1', 'GEOSadas-5_7_2_p3_m2','GEOSadas-5_7_2_p4', - 'GEOSadas-5_7_2_p5', 'GEOSadas-5_7_2_p5_m1','GEOSadas-5_7_3', - 'GEOSadas-5_7_3_p1', 'GEOSadas-5_7_3_p2', 'GEOSadas-5_7_3_p2' ) - - # BCS Tag: Ganymed-1_0 - #--------------------- - G10 = ( 'G10', 'Ganymed-1_0', 'Ganymed-1_0_BETA', - 'Ganymed-1_0_BETA1', 'Ganymed-1_0_BETA2', 'Ganymed-1_0_BETA3', - 'Ganymed-1_0_BETA4' ) - - D580 = ( 'D580', 'GEOSadas-5_8_0', 'GEOSadas-5_9_0', - 'GEOSadas-5_9_1' ) - - # BCS Tags: Ganymed-1_0_M and Ganymed-1_0_D - #------------------------------------------ - G10p = ( 'G10p', 'Ganymed-1_0_p1', 'Ganymed-1_0_p2', - 'Ganymed-1_0_p3', 'Ganymed-1_0_p4', 'Ganymed-1_0_p5', - 'Ganymed-1_0_p6' ) - - D591p= ( 'D591p', 'GEOSadas-5_9_1_p1', 'GEOSadas-5_9_1_p2', - 'GEOSadas-5_9_1_p3', 'GEOSadas-5_9_1_p4', 'GEOSadas-5_9_1_p5', - 'GEOSadas-5_9_1_p6', 'GEOSadas-5_9_1_p7', 'GEOSadas-5_9_1_p8', - 'GEOSadas-5_9_1_p9' ) - - # BCS Tags: Ganymed-1_0_M and Ganymed-1_0_D w/ new landice rst - #------------------------------------------------------------------------ - G20 = ( 'G20', 'Ganymed-2_0', 'Ganymed-2_1', - 'Ganymed-2_1_p1', 'Ganymed-2_1_p2', 'Ganymed-2_1_p3', - 'Ganymed-2_1_p4', 'Ganymed-2_1_p5', 'Ganymed-2_1_p6' ) - D5A0 = ( 'D5A0', 'GEOSadas-5_10_0', 'GEOSadas-5_10_0_p1' ) - - - # BCS Tags: Ganymed-1_0_Reynolds and Ganymed-1_0_Ostia - #----------------------------------------------------- - G30 = ( 'G30', 'Ganymed-3_0', 'Ganymed-3_0_p1' ) - D5B0 = ( '5B0', 'GEOSadas-5_10_0_p2', 'GEOSadas-5_11_0' ) - - # BCS Tags: Ganymed-4_0_Reynolds, Ganymed-4_0_MERRA-2, and Ganymed-4_0_Ostia - #--------------------------------------------------------------------------- - G40 = ( 'G40', 'Ganymed-4_0', 'Ganymed-4_0_p1', - 'Ganymed-4_1', 'Heracles-1_0', 'Heracles-1_1', - 'Heracles-2_0', 'Heracles-2_1', 'Heracles-3_0', - 'Heracles-4_0', 'Heracles-5_4_p3' ) - D512 = ( '512', 'GEOSadas-5_12_2', 'GEOSadas-5_12_4', - 'GEOSadas-5_12_4_p1', 'GEOSadas-5_12_4_p2', 'GEOSadas-5_12_4_p3', - 'GEOSadas-5_12_5', 'GEOSadas-5_13_0_p1', 'GEOSadas-5_13_0_p2', - 'GEOSadas-5_13_1', 'GEOSadas-5_16_5' ) - - # BCS Tags: Icarus (New Land Parameters, New Topography) - #--------------------------------------------------------------------------- - ICA = ( 'ICA', 'Icarus', 'Jason' ) - D517 = ( '517', 'GEOSadas-5_17_0', 'GEOSadas-5_17_1', 'GEOSadas-5_18_0', - 'GEOSadas-5_18_1', 'GEOSadas-5_18_2', 'GEOSadas-5_18_3', - 'GEOSadas-5_18_3_p1', 'GEOSadas-5_19_0', 'GEOSadas-5_20_0', - 'GEOSadas-5_20_0_p1', 'GEOSadas-5_20_0_p2', 'GEOSadas-5_21_0', - 'GEOSadas-5_21_2', 'GEOSadas-5_21_3_p1', 'GEOSadas-5_22_0', - 'GEOSadas-5_22_0_p1', 'GEOSadas-5_22_0_p2', 'GEOSadas-5_23_0', - 'GEOSadas-5_23_0_p1', 'GEOSadas-5_24_0', 'GEOSadas-5_24_0_p1' ) - GITOL = ( 'GITOL', '10.3', '10.4', '10.5', - '10.6', '10.7', '10.8', - '10.9', '10.10', '10.11', - '10.12', '10.13', '10.14', - '10.15', '10.16', '10.17', - '10.18' ) - - # BCS Tags: Icarus-NLv3 (New Land Parameters) - #--------------------------------------------------------------------------- - INL = ( 'INL', 'Icarus-NL', 'Icarus-NLv3', 'Jason-NL' ) - GITNL = ( 'GITNL', '10.19', '10.20', '10.21', '10.22', '10.23' ) - D525 = ( '525', 'GEOSadas-5_25_1', 'GEOSadas-5_25_1_p5', 'GEOSadas-5_25_p7', - 'GEOSadas-5_27_1', 'GEOSadas-5_29_3', 'GEOSadas-5_29_4' ) - self.newStructure = ('NL3', 'NL4', 'NL5', 'v06', 'v07', 'v08', 'v09') - - self.bcsTag={} - for tag in F14: self.bcsTag[tag]= "Fortuna-1_4" - for tag in F20: self.bcsTag[tag]= "Fortuna-2_0" - for tag in F21: self.bcsTag[tag]= "Fortuna-2_1" - for tag in G10: self.bcsTag[tag]= "Ganymed-1_0" - for tag in G10p: self.bcsTag[tag]= "Ganymed-1_0_M" - for tag in G20: self.bcsTag[tag]= "Ganymed-1_0_M" - for tag in G30: self.bcsTag[tag]= "Ganymed-1_0_Reynolds" - for tag in G40: self.bcsTag[tag]= "Ganymed-4_0_Reynolds" - for tag in ICA: self.bcsTag[tag]= "Icarus_Reynolds" - for tag in GITOL: self.bcsTag[tag]= "Icarus_Reynolds" - for tag in INL: self.bcsTag[tag]= "Icarus-NLv3_Reynolds" - for tag in GITNL: self.bcsTag[tag]= "Icarus-NLv3_Reynolds" - for tag in self.newStructure: self.bcsTag[tag]= tag - - - for tag in D214: self.bcsTag[tag]= "Fortuna-1_4" - for tag in D540: self.bcsTag[tag]= "Fortuna-1_4" - for tag in D561: self.bcsTag[tag]= "Fortuna-2_1" - for tag in D580: self.bcsTag[tag]= "Ganymed-1_0" - for tag in D591p: self.bcsTag[tag]= "Ganymed-1_0_M" - for tag in D5A0: self.bcsTag[tag]= "Ganymed-1_0_M" - for tag in D5B0: self.bcsTag[tag]= "Ganymed-1_0_Reynolds" - for tag in D512: self.bcsTag[tag]= "Ganymed-4_0_Reynolds" - for tag in D517: self.bcsTag[tag]= "Icarus_Reynolds" - for tag in D525: self.bcsTag[tag]= "Icarus-NLv3_Reynolds" - - self.tagsRank ={} - self.tagsRank['Fortuna-1_4'] = 1 - self.tagsRank['Fortuna-1_5'] = 2 - self.tagsRank['Fortuna-2_0'] = 3 - self.tagsRank['Fortuna-2_1'] = 4 - self.tagsRank['Ganymed-1_0'] = 5 - self.tagsRank['Ganymed-1_0_m1'] = 6 - self.tagsRank['Ganymed-1_0_m2'] = 7 - self.tagsRank['Ganymed-1_0_M'] = 8 - self.tagsRank['Ganymed-1_0_D'] = 9 - self.tagsRank['Ganymed-1_0_Reynolds'] = 10 - self.tagsRank['Ganymed-1_0_Ostia'] = 11 - self.tagsRank['Ganymed-4_0_Reynolds'] = 12 - self.tagsRank['Ganymed-4_0_Ostia'] = 13 - self.tagsRank['Ganymed-4_0_MERRA-2'] = 14 - self.tagsRank['Icarus_Reynolds'] = 15 - self.tagsRank['Icarus_MERRA-2'] = 16 - self.tagsRank['Icarus_Ostia'] = 17 - self.tagsRank['Icarus-NLv3_Reynolds'] = 18 - self.tagsRank['Icarus-NLv3_MERRA-2'] = 19 - self.tagsRank['Icarus-NLv3_Ostia'] = 20 - for tag in self.newStructure: self.tagsRank[tag] = 21 - - self.bcbase={} - self.bcbase['discover_ops'] = "/discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs" - self.bcbase['discover_legacy'] = "/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs" - self.bcbase['discover_couple'] = "/discover/nobackup/projects/gmao/ssd/aogcm/atmosphere_bcs" - self.bcbase['discover_ns'] = "/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles" - - def init_time(self): - ymdh = self.common_in.get('yyyymmddhh') - self.yyyymm = ymdh[0:6] - self.yyyy = ymdh[0:4] - self.mm = ymdh[4:6] - self.dd = ymdh[6:8] - self.hh = ymdh[8:10] - self.ymd = ymdh[0:8] - - def init_merra2(self): - if not self.common_in['MERRA-2']: - return - self.common_in = merra2_expid(self.common_in) - - self.common_in['agrid'] = 'C180' - self.common_in['ogrid'] = '1440x720' - self.common_in['bc_base']= 'discover_ops' - self.common_in['tag']= 'Ganymed-4_0' - self.surf_in['catch_model'] = 'catch' - - def get_bcbase(self, opt): - base = '' - model = '' - - if opt.upper() == 'IN': - model = self.common_in.get('model') - base = self.common_in.get('bc_base') - if base == 'discover_ns': - return self.bcbase[base] - - if model == 'MOM6' or model == 'MOM5': - base = 'discover_couple' - - if opt.upper() == 'OUT': - model = self.common_out.get('model') - base = self.common_out.get('bc_base') - if base == 'discover_ns': - return self.bcbase[base] - if model == 'MOM6' or model == 'MOM5': - base = 'discover_couple' - assert base, 'please specify bc_base: discover_ops, discover_legacy, discover_couple or an absolute path' - if base == 'discover_ops' or base == 'discover_legacy' or base=='discover_couple': - return self.bcbase[base] - else: - return base - - def get_bcdir(self, opt): - tag = self.common_in['tag'] - ogrid = self.common_in['ogrid'] - model = self.common_in['model'] - bcdir = self.common_in.get('alt_bcs', None) - if opt.upper() == "OUT": - tag = self.common_out['tag'] - ogrid = self.common_out['ogrid'] - model = self.common_out['model'] - bcdir = self.common_out.get('alt_bcs', None) - - if bcdir is None : - bc_base = self.get_bcbase(opt) - bctag = self.get_bcTag(tag,ogrid) - tagrank = self.tagsRank[bctag] - - if (tagrank >= self.tagsRank['NL3']) : - bcdir = bc_base+'/'+ bctag+'/geometry/' - elif (tagrank >= self.tagsRank['Icarus-NLv3_Reynolds']) : - bcdir = bc_base+'/Icarus-NLv3/'+bctag+'/' - if model == 'MOM6' or model == 'MOM5': - bcdir = bc_base+'/Icarus-NLv3/'+model+'/' - elif (tagrank >= self.tagsRank['Icarus_Reynolds']): - if bc_base == self.bcbase['discover_ops']: - bcdir = bc_base+'/Icarus_Updated/'+bctag+'/' - else: - bcdir = bc_base+'/Icarus/'+bctag+'/' - if model == 'MOM6' or model == 'MOM5': - bcdir = bc_base+'/Icarus/'+model+'/' - elif(tagrank >= self.tagsRank["Ganymed-4_0_Reynolds"]): - bcdir = bc_base + '/Ganymed-4_0/'+bctag+'/' - if model == 'MOM6' or model == 'MOM5': - bcdir = bc_base+'/Ganymed/'+model+'/' - else: - bcdir = bc_base + '/' + bctag + '/' - if model == 'MOM6' or model == 'MOM5': - bcdir = bc_base+'/Ganymed/'+model+'/' - - if not os.path.exists(bcdir): - exit("Cannot find bc dir " + bcdir) - - gridStr = self.get_grid_subdir(bcdir,opt) - bcdir = bcdir + '/' + gridStr - - return bcdir - - def get_grid_subdir(self, bcdir, opt): - - def get_name_with_grid( grid, names, a_o): - if not grid : - return names - namex = [] - if (grid[0].upper() == 'C'): - n = int(grid[1:]) - s1 ='{:04d}x6C'.format(n) - j=n*6 - s2 =str(n) - s3 =str(j) - # first try - for aoname in names: - name = '' - if(a_o == 'a'): - name = aoname.split('_')[0] - else: - name = aoname.split('_')[-1] - if (name.find(s1) != -1 or (name.find(s2) != -1 and name.find(s3) != -1 )): - namex.append(aoname) - else: - xy = grid.upper().split('X') - s2 = xy[0] - s3 = xy[1] - for aoname in names: - name = '' - if(a_o == 'a'): - name = aoname.split('_')[0] - else: - name = aoname.split('_')[-1] - if (name.find(s2) != -1 and name.find(s3) != -1): namex.append(aoname) - return namex - #v3.5 - #dirnames = [ f.name for f in os.scandir(bcdir) if f.is_dir()] - #v2.7 - dirnames = [f for f in os.listdir(bcdir) if os.path.isdir(os.path.join(bcdir,f))] - - agrid_ = self.common_in['agrid'] - ogrid_ = self.common_in['ogrid'] - omodel_ = self.common_in.get('model') - if opt.upper() == "OUT" : - agrid_ = self.common_out['agrid'] - ogrid_ = self.common_out['ogrid'] - omodel_ = self.common_out.get('model') - - anames = get_name_with_grid(agrid_, dirnames, 'a') - gridID = get_name_with_grid(ogrid_, anames, 'o') - if len(gridID) == 0 : - exit("cannot find the grid subdirctory of agrid: " +agrid_+ " and ogrid " + ogrid_ + " under "+ bcdir) - g = '' - gridID.sort(key=len) - g = gridID[0] - - # For new structure BC - for g_ in gridID : - if omodel_ == 'MOM5': - if '_M5_' in g_ : g = g_ - if omodel_ == 'MOM6': - if '_M6_' in g_ : g = g_ - - if len(gridID) >= 2 : - print("\n Warning! Find many GridIDs in " + bcdir) - print(" GridIDs found: ", gridID) - #WY note, found many string in the directory - print(" This GridID is chosen: " + g) - return g - - def get_bcTag(self, tag, ogrid): - bctag = self.bcsTag[tag] - if bctag in self.newStructure : return bctag - if ogrid[0].upper() == "C": - bctag=bctag.replace('_Reynolds','_Ostia') - else: - xy = ogrid.upper().split('X') - x = int(xy[0]) - if x == 1440: bctag=bctag.replace('_Reynolds','_MERRA-2') - if x == 2880: - bctag=bctag.replace('_Reynolds','_Ostia') - bctag=bctag.replace('_M','_D') - return bctag - def params_for_air(self, config_tpl): if self.common_in['MERRA-2']: return config_tpl - # verify agrid - rst_dir = self.common_in['rst_dir'] + '/' - time = self.ymd + '_'+ self.hh - files = glob.glob(rst_dir +'/*fvcore_*'+time+'*') - if len(files) == 0 : - fname_ = rst_dir +'/fvcore_internal_rst' - if os.path.exists(fname_) : - files.append(fname_) - - # get expid - if (len(files) >0) : - fname = os.path.basename(files[0]) - expid = fname.split('fvcore')[0] - config_tpl['input']['shared']['expid'] = expid[0:-1] #remove the last '.' - - agrid_ = self.common_in['agrid'] - if self.common_in['ogrid'] == 'CS' : - config_tpl['input']['shared']['ogrid'] = agrid_ - self.common_in['ogrid'] = agrid_ - - ogrid = config_tpl['input']['shared']['ogrid'] - tagout = self.common_out['tag'] - bctag = self.get_bcTag(tagout, ogrid) - tagrank = self.tagsRank[bctag] if ( not config_tpl['input']['air']['drymass']) : - config_tpl['input']['air']['drymass'] = 0 - if tagrank >=12 : - config_tpl['input']['air']['drymass'] = 1 + config_tpl['input']['air']['drymass'] = 1 return config_tpl def options_for_slurm(self, config_tpl): - config_tpl['slurm']['account'] = self.slurm_options['account'] - config_tpl['slurm']['qos'] = self.slurm_options['qos'] - config_tpl['slurm']['constraint'] = self.slurm_options['constraint'] + config_tpl['slurm']['account'] = self.slurm_options['account'] + config_tpl['slurm']['qos'] = self.slurm_options['qos'] + config_tpl['slurm']['partition'] = self.slurm_options['partition'] return config_tpl def params_for_surface(self, config_tpl): - config_tpl['output']['surface']['surflay'] = 20. - tagout = self.common_out['tag'] - ogrid = self.common_out['ogrid'] - bctag = self.get_bcTag(tagout, ogrid) - tagrank = self.tagsRank[bctag] - if tagrank >=12 : - config_tpl['output']['surface']['surflay'] = 50. - if tagrank >= self.tagsRank["Icarus_Reynolds"]: - config_tpl['output']['surface']['split_saltwater'] = True - config_tpl['input']['surface']['zoom']= self.surf_in['zoom'] - config_tpl['input']['surface']['wemin']= self.surf_in['wemin'] - config_tpl['output']['surface']['wemin']= self.surf_out['wemout'] - - rst_dir = self.common_in['rst_dir'] + '/' - time = self.ymd + '_'+ self.hh - files = glob.glob(rst_dir +'/*catch_*'+time+'*') - if (len(files)== 0) : - files = glob.glob(rst_dir +'/*catch_*') - - if (len(files) > 0) : - config_tpl['input']['surface']['catch_model'] = 'catch' - - files = glob.glob(rst_dir +'/*catchcnclm40_*'+time+'*') - if (len(files)== 0) : - files = glob.glob(rst_dir +'/*catchcnclm40_*') - - if (len(files) > 0) : - config_tpl['input']['surface']['catch_model'] = 'catchcnclm40' - - files = glob.glob(rst_dir +'/*catchcnclm45_*'+time+'*') - if (len(files)== 0) : - files = glob.glob(rst_dir +'/*catchcnclm45_*') - - if (len(files) > 0) : - config_tpl['input']['surface']['catch_model'] = 'catchcnclm45' - + config_tpl['output']['surface']['surflay'] = 50. + bc_version = self.common_out['bc_version'] + ogrid = self.common_out['ogrid'] + config_tpl['output']['surface']['split_saltwater'] = True + if 'Ganymed' in bc_version : + config_tpl['output']['surface']['split_saltwater'] = False + config_tpl['input']['surface']['zoom'] = self.surf_in['zoom'] + config_tpl['input']['surface']['wemin'] = self.surf_in['wemin'] + config_tpl['output']['surface']['wemin'] = self.surf_out['wemin'] + config_tpl['input']['surface']['catch_model'] = self.surf_in.get('catch_model') return config_tpl def params_for_analysis(self, config_tpl): - config_tpl['output']['analysis']['lcv'] = self.ana_out.get('lcv') - config_tpl['output']['analysis']['bkg'] = self.ana_out.get('bkg') + config_tpl['output']['analysis']['lcv'] = self.ana_out.get('lcv') + config_tpl['output']['analysis']['bkg'] = self.ana_out.get('bkg') + config_tpl['output']['analysis']['aqua'] = True - ogrid = self.common_out['ogrid'] - tagout = self.common_out['tag'] - bctag = self.get_bcTag(tagout, ogrid) - tagrank = self.tagsRank[bctag] - if tagrank >= self.tagsRank["Ganymed-4_0_Reynolds"] : - config_tpl['output']['analysis']['aqua'] = True return config_tpl if __name__ == "__main__": diff --git a/pre/remap_restart/remap_params.tpl b/pre/remap_restart/remap_params.tpl index a8ca9ac..3a78a20 100644 --- a/pre/remap_restart/remap_params.tpl +++ b/pre/remap_restart/remap_params.tpl @@ -1,5 +1,6 @@ # -# This template file can be filled with questionary or manually +# remap_restarts package: +# this template file can be filled via the questionary (remap_questions.py) or manually # # @@ -9,8 +10,12 @@ input: hydrostatic: 0 shared: MERRA-2: false + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data agrid: - bcs_dir: + bc_base: + bc_version: none expid: ogrid: rst_dir: @@ -20,12 +25,18 @@ input: wemin: # it supports three models: catch, catchcnclm40, catchcnclm45 catch_model: null - # if catch_tilefile is null, it searches bcs_dir + # if catch_tilefile is null, it searches bc_dir catch_tilefile: null output: shared: + label: false + # SG001,SG002 + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data agrid: - bcs_dir: + bc_base: + bc_version: none expid: ogrid: out_dir: @@ -35,20 +46,19 @@ output: nlevel: surface: split_saltwater: false - surflay: 20. + surflay: 50. wemin: # remap lake, saltwater, landicet remap_water: true # remap catch(cn) remap_catch: true - # if catch_tilefile is null, it searches bcs_dir + # if catch_tilefile is null, it searches bc_dir catch_tilefile: null analysis: bkg: true aqua: False lcv: false - slurm: account: qos: - constraint: + partition: diff --git a/pre/remap_restart/remap_questions.py b/pre/remap_restart/remap_questions.py index 3892c7c..b383900 100755 --- a/pre/remap_restart/remap_questions.py +++ b/pre/remap_restart/remap_questions.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 # -# source install/bin/g5_modules +# remap_restarts package: +# interactive questionary to create a yaml configuration file (remap_params.yaml) and +# a matching command line argument string (remap_restarts.CMD) # -# Newer GEOS code should load a module with GEOSpyD Python3 if not run: -# module load python/GEOSpyD/Min4.10.3_py3.9 # - import os import subprocess import shlex @@ -13,383 +12,437 @@ import shutil import questionary import glob +from remap_utils import * -def fvcore_name(x): - ymdh = x['input:shared:yyyymmddhh'] - time = ymdh[0:8] + '_'+ymdh[8:10] - rst_dir = x.get('input:shared:rst_dir') - if not rst_dir : return False - files = glob.glob(rst_dir+'/*fvcore_*'+time+'*') - if len(files) ==1 : - fname = files[0] - print('\nFound ' + fname) - return fname +def remove_ogrid_comment(x, opt): + ogrid = '' + if opt == "IN": + ogrid = x.get('input:shared:ogrid') + else: + ogrid = x.get('output:shared:ogrid') + if not ogrid: return False + + ogrid = ogrid.split()[0] + if opt == "IN": + if ogrid == 'CS': + ogrid = x['input:shared:agrid'] + x['input:shared:ogrid'] = ogrid else: - fname = rst_dir+'/fvcore_internal_rst' - if os.path.exists(fname): - print('\nFound ' + fname) - return fname - return False - -def tmp_merra2_dir(x): - tmp_merra2 = x['output:shared:out_dir']+ '/merra2_tmp_'+x['input:shared:yyyymmddhh']+'/' - return tmp_merra2 - -def data_ocean_default(resolution): - default_ = 'CS' - if resolution in ['C12','C24', 'C48'] : default_ = '360X180' - return default_ - -def we_default(tag): - default_ = '26' - if tag in ['INL','GITNL', '525'] : default_ = '13' - if tag in ['NL3','NL4', 'NL5', 'v06','v07', 'v08', 'v09'] : default_ = '13' - return default_ - -def zoom_default(x): - zoom_ = '8' - fvcore = fvcore_name(x) - if fvcore : - fvrst = os.path.dirname(os.path.realpath(__file__)) + '/fvrst.x -h ' - cmd = fvrst + fvcore - print(cmd +'\n') - p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) - (output, err) = p.communicate() - p_status = p.wait() - ss = output.decode().split() - x['input:shared:agrid'] = "C"+ss[0] # save for air parameter - lat = int(ss[0]) - lon = int(ss[1]) - if (lon != lat*6) : - sys.exit('This is not a cubed-sphere grid fvcore restart. Please contact SI team') - ymdh = x.get('input:shared:yyyymmddhh') - ymdh_ = str(ss[3]) + str(ss[4])[0:2] - if (ymdh_ != ymdh) : - print("Warning: The date in fvcore is different from the date you input\n") - zoom = lat /90.0 - zoom_ = str(int(zoom)) - if zoom < 1 : zoom_ = '1' - if zoom > 8 : zoom_ = '8' - if x['input:shared:MERRA-2'] : - zoom_ = '2' - return zoom_ - -def get_account(): - cmd = 'id -gn' - p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) - (accounts, err) = p.communicate() - p_status = p.wait() - accounts = accounts.decode().split() - return accounts[0] + if ogrid == 'CS': + ogrid = x['output:shared:agrid'] + x['output:shared:ogrid'] = ogrid + + return False + +def echo_level(x): + if x["output:air:nlevel"] != str(x.get("input:air:nlevel")) : + print("NOTE: Different # atm levels in input and new restarts. Cannot remap agcm_import_rst (a.k.a. IAU) file.") + x['output:air:agcm_import_rst'] = False + return False + return True + +def echo_bcs(x,opt): + base = x.get(opt+':shared:bc_base').split(': ')[-1] + bcv = x.get(opt+':shared:bc_version') + agrid = x.get(opt+':shared:agrid') + ogrid = x.get(opt+':shared:ogrid') + model = x.get(opt+':shared:omodel') + stretch = x.get(opt+':shared:stretch') + x[opt+':shared:bc_base'] = base + land_dir = get_landdir(base, bcv, agrid, ogrid, model, stretch) + if not os.path.isdir(land_dir): + exit("cannot find grid subdirectory for agrid=" + agrid + " and ogrid=" + ogrid + " under " + base+'/'+bcv+'/land/') + print("\n Land BCs for " + opt + " restarts: " + land_dir ) + return False + +def default_partition(x): + if x['slurm:qos'] == 'debug': + x['slurm:partition'] = 'compute' + return False + return True + +def validate_merra2_time(text): + if len(text) == 10 : + hh = text[8:] + if hh in ['03','09','15','21']: + return True + else: + return False + else: + return False def ask_questions(): + # See remap_utils.py for definitions of "choices", "message" strings, and "validate" lists + # that are used multiple times. + questions = [ { "type": "confirm", "name": "input:shared:MERRA-2", - "message": "Would you like to remap archived MERRA-2 restarts?", + "message": "Remap archived MERRA-2 restarts? (NCCS/Discover only; elsewhere, select 'N' and complete full config; requires nc4 restarts.)\n", "default": False, }, { "type": "path", "name": "input:shared:rst_dir", - "message": "Enter the directory containing restart files to be remapped:", + "message": "Enter input directory with restart files to be remapped:\n", "when": lambda x: not x['input:shared:MERRA-2'], }, { "type": "text", "name": "input:shared:yyyymmddhh", - "message": "From what restart date/time would you like to remap? (must be 10 digits: yyyymmddhh)", + "message": "Enter restart date/time: (Must be 10 digits: yyyymmddhh.)\n", "validate": lambda text: len(text)==10 , + "when": lambda x: not x['input:shared:MERRA-2'] and not fvcore_info(x), + }, + { + "type": "text", + "name": "input:shared:yyyymmddhh", + "message": "Enter restart date: (Must be 10 digits: yyyymmddhh; hour = 03, 09, 15, or 21 [z].)\n", + "validate": lambda text: validate_merra2_time(text) , + "when": lambda x: x['input:shared:MERRA-2'], + }, + { + "type": "path", + "name": "output:shared:out_dir", + "message": "Enter output directory for new restarts:\n" }, + # dummy (invisible) question to run function that initializes MERRA-2 config { "type": "path", "name": "output:shared:out_dir", - "message": "Enter the directory for new restarts:\n" + "message": "init merra2\n", + # always return false, so question never shows but changes x + "when": lambda x: init_merra2(x), }, { "type": "text", "name": "input:shared:agrid", - "message": "Enter input atmospheric grid: \n C12 C180 C1000 C270\n C24 C360 C1440 C540\n C48 C500 C2880 C1080\n C90 C720 C5760 C2160 C1536\n ", - "default": 'C360', + "message": message_agrid_in, + "validate": lambda text : text in validate_agrid, # if it is merra-2 or has_fvcore, agrid is deduced - "when": lambda x: not x['input:shared:MERRA-2'] and not fvcore_name(x), + "when": lambda x: not x['input:shared:MERRA-2'] and not fvcore_info(x), + }, + + { + "type": "select", + "name": "input:shared:omodel", + "message": "Select ocean model of input restarts:\n", + "choices": choices_omodel, + "default": "data", + "when": lambda x: not x['input:shared:MERRA-2'] + }, + + { + "type": "select", + "name": "input:shared:ogrid", + "message": "Select data ocean grid/resolution of input restarts:\n", + "choices": choices_ogrid_data, + "default": lambda x: data_ocean_default(x.get('input:shared:agrid')), + "when": lambda x: x.get('input:shared:omodel') == 'data' and not x['input:shared:MERRA-2'], }, + # dummy (invisible) question to remove parenthetical comments from selected input:shared:ogrid + { + "type": "text", + "name": "input:shared:ogrid", + "message": "remove the comment of ogrid", + # always return false, so question never shows but changes ogrid + "when": lambda x: remove_ogrid_comment(x, 'IN') + }, + + { + "type": "select", + "name": "input:shared:ogrid", + "message": "Select coupled ocean resolution of input restarts:\n", + "choices": choices_ogrid_cpld, + "when": lambda x: x.get('input:shared:omodel') == 'MOM5' or x.get('input:shared:omodel')== 'MOM6' + }, + + { + "type": "confirm", + "name": "output:shared:stretch", + "message": "Remap to a stretched cubed-sphere grid?", + "default": False, + }, { "type": "text", "name": "output:shared:agrid", - "message": "Enter new atmospheric grid: \n C12 C180 C1000 C270\n C24 C360 C1440 C540\n C48 C500 C2880 C1080\n C90 C720 C5760 C2160 C1536\n ", + "message": message_agrid_new, "default": 'C360', + "validate": lambda text : text in validate_agrid, + "when": lambda x : not x['output:shared:stretch'], }, { - "type": "text", - "name": "output:air:nlevel", - "message": "Enter new atmospheric levels: (71 72 91 127 132 137 144 181)", - "default": "72", + "type": "select", + "name": "output:shared:stretch", + "message": message_stretch, + "choices": choices_stretch[1:3], + "when": lambda x : x['output:shared:stretch'], }, { "type": "select", - "name": "input:shared:model", - "message": "Select input ocean model:", - "choices": ["data", "MOM5", "MOM6"], - "default": "data", - "when": lambda x: not x['input:shared:MERRA-2'] + "name": "output:shared:agrid", + "message": "Select resolution of SG001 grid for new restarts: \n", + "choices": choices_res_SG001, + "when": lambda x : x.get('output:shared:stretch') == 'SG001', }, { "type": "select", - "name": "input:shared:ogrid", - "message": "Input Ocean grid: \n \ - Data Ocean Grids \n \ - ------------------- \n \ - 360X180 (Reynolds) \n \ - 1440X720 (MERRA-2) \n \ - 2880X1440 (OSTIA) \n \ - CS = same as atmosphere grid (OSTIA cubed-sphere) \n", - "choices": ['360X180','1440X720','2880X1440','CS'], - "default": lambda x: data_ocean_default(x.get('input:shared:agrid')), - "when": lambda x: x.get('input:shared:model') == 'data' and not x['input:shared:MERRA-2'], + "name": "output:shared:agrid", + "message": "Select resolution of SG002 grid for new restarts: \n", + "choices": choices_res_SG002, + "when": lambda x : x.get('output:shared:stretch') == 'SG002', }, { "type": "select", - "name": "output:shared:model", - "message": "Select ocean model for new restarts:", - "choices": ["data", "MOM5", "MOM6"], + "name": "output:shared:omodel", + "message": "Select ocean model for new restarts:\n", + "choices": choices_omodel, "default": "data", }, { "type": "select", "name": "output:shared:ogrid", - "message": "Select new ocean grid:", - "choices": ['360X180','1440X720','2880X1440','CS'], + "message": "Select data ocean grid/resolution for new restarts:\n", + "choices": choices_ogrid_data, "default": lambda x: data_ocean_default(x.get('output:shared:agrid')), - "when": lambda x: x['output:shared:model'] == 'data', + "when": lambda x: x['output:shared:omodel'] == 'data', }, + # dummy (invisible) question to remove parenthetical comments from selected output:shared:ogrid { - "type": "select", - "name": "input:shared:ogrid", - "message": "Input ocean grid: \n \ - Coupled Ocean Grids \n \ - ------------------- \n \ - 72X36 \n \ - 360X200 \n \ - 720X410 \n \ - 1440X1080 \n ", - "choices": ['72X36','360X200','720X410','1440X1080'], - "when": lambda x: x.get('input:shared:model') == 'MOM5' or x.get('input:shared:model')== 'MOM6' + "type": "text", + "name": "output:shared:ogrid", + "message": "remove the comment of ogrid", + # always return false, so questions never shows but changes ogrid + "when": lambda x: remove_ogrid_comment(x, 'OUT') }, { "type": "select", "name": "output:shared:ogrid", - "message": "Select new ocean grid: \n \ - Coupled Ocean Grids \n \ - ------------------- \n \ - 72X36 \n \ - 360X200 \n \ - 720X410 \n \ - 1440X1080 \n ", - "choices": ['72X36','360X200','720X410','1440X1080'], - "when": lambda x: x['output:shared:model'] != 'data', + "message": "Select coupled ocean resolution for new restarts:\n", + "choices": choices_ogrid_cpld, + "when": lambda x: x['output:shared:omodel'] != 'data', + }, + + { + "type": "text", + "name": "output:air:nlevel", + "message": "Enter number of atmospheric levels for new restarts: (71 72 91 127 132 137 144 181)\n", + "default": "72", }, + # to show the message, we ask output first { "type": "select", - "name": "input:shared:bc_base", - "message": "Select bcs base \n \ - discover_ops: /discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs \n \ - discover_legacy: /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs \n \ - discover_couple: /discover/nobackup/projects/gmao/ssd/aogcm/atmosphere_bcs \n \ - discover_ns: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles \n \ -\n \ -Sample GCM tags for discover_ops, discover_legacy, discover_couple bc base :\n \ ---------------- \n \ -G40 : Ganymed-4_0 ......... Heracles-5_4_p3 \n \ -ICA : Icarus .............. Jason \n \ -GITOL : 10.3 ................ 10.18 \n \ -INL : Icarus-NL ........... Jason-NL \n \ -GITNL : 10.19 ............... 10.23 \n \ -\n \ -Sample DAS tags for discover_ops, discover_legacy, discover_couple bc base :\n \ ---------------- \n \ -5B0 : GEOSadas-5_10_0_p2 .. GEOSadas-5_11_0 \n \ -512 : GEOSadas-5_12_2 ..... GEOSadas-5_16_5\n \ -517 : GEOSadas-5_17_0 ..... GEOSadas-5_24_0_p1\n \ -525 : GEOSadas-5_25_1 ..... GEOSadas-5_29_4\n \ -\n \ -Sample BC version for discover_ns ( new structure BC base): \n \ --------------- \n \ -NL3 : Newland version 3 \n \ -NL4 : Newland version 4 \n \ -NL5 : Newland version 5 \n \ -v06 : Not generated yet \n", - "choices": ["discover_ops", "discover_legacy", "discover_couple","discover_ns", "other"], - "when": lambda x: not x['input:shared:MERRA-2'], + "name": "input:shared:bc_version", + "message": message_bc_ops_in, + "choices": choices_bc_ops, + "when": lambda x: not x["input:shared:MERRA-2"], }, { - "type": "text", - "name": "input:shared:tag", - "message": "Enter GCM or DAS tag for input:", - "default": "INL", - "when": lambda x: not x["input:shared:MERRA-2"] and not x["input:shared:bc_base"]== "discover_ns", + "type": "select", + "name": "input:shared:bc_version", + "message": message_bc_other_in, + "choices": choices_bc_other, + "when": lambda x: x["input:shared:bc_version"] == 'Other', }, { - "type": "text", - "name": "input:shared:tag", - "message": "Enter BC version for input:", + "type": "select", + "name": "output:shared:bc_version", + "message": message_bc_ops_new, + "choices": choices_bc_ops, "default": "NL3", - "when": lambda x: not x["input:shared:MERRA-2"] and x["input:shared:bc_base"]== "discover_ns", + "when": lambda x: x["input:shared:MERRA-2"], }, { "type": "select", - "name": "output:shared:bc_base", - "message": "Select bcs base for new restarts:", - "choices": ["discover_ops", "discover_legacy", "discover_couple","discover_ns", "other"], + "name": "output:shared:bc_version", + "message": "Select BCs version for new restarts:\n", + "choices": choices_bc_ops, + "default": "NL3", + "when": lambda x: not x["input:shared:MERRA-2"], }, { - "type": "text", - "name": "output:shared:tag", - "message": "Enter GCM or DAS tag for new restarts:", - "default": "INL", - "when": lambda x: not x["output:shared:bc_base"] == "discover_ns", + "type": "select", + "name": "output:shared:bc_version", + "message": message_bc_other_new, + "choices": choices_bc_other, + "when": lambda x: x["output:shared:bc_version"] == 'Other' and x["input:shared:bc_version"] not in ['v06','v11'], + }, + + { + "type": "select", + "name": "output:shared:bc_version", + "message": "\nSelect BCs version of input restarts:\n", + "choices": choices_bc_other, + "when": lambda x: x["output:shared:bc_version"] == 'Other' and x["input:shared:bc_version"] in ['v06','v11'], }, + { - "type": "text", - "name": "output:shared:tag", - "message": "Enter BC version for new restarts:", - "default": "NL3", - "when": lambda x: x["output:shared:bc_base"] == "discover_ns", + "type": "select", + "name": "input:shared:bc_base", + "message": "\nSelect BCs base directory for input restarts: \n", + "choices": choices_bc_base, + "default": get_default_bc_base(), + "when": lambda x: not x.get('input:shared:bc_base'), }, { "type": "path", - "name": "input:shared:alt_bcs", - "message": "Specify your own bcs absolute path (do not contain grid info) for restarts: \n ", - "when": lambda x: x.get("input:shared:bc_base")=="other", + "name": "input:shared:bc_base", + "message": "\nEnter BCs base directory for input restarts: \n", + "when": lambda x: 'Custom ' in x.get('input:shared:bc_base'), + }, + # dummy (invisible) question to retrieve input:shared:bc_base + { + "type": "text", + "name": "input:shared:bc_base", + "message": "retrieve and echo bcs", + # always return false, so questions never shows + "when": lambda x: echo_bcs(x, 'input') + }, + + { + "type": "select", + "name": "output:shared:bc_base", + "message": "\nSelect BCs base directory for new restarts: \n", + "choices": choices_bc_base, + "default": get_default_bc_base(), }, { "type": "path", - "name": "output:shared:alt_bcs", - "message": "Specify your own bcs path (do not contain grid info) for new restarts: \n ", - "when": lambda x: x.get("output:shared:bc_base")=="other", + "name": "output:shared:bc_base", + "message": "\nEnter BCs base directory for new restarts: \n", + "when": lambda x: 'Custom ' in x.get('output:shared:bc_base'), + }, + # dummy (invisible) question to retrieve output:shared:bc_base + { + "type": "text", + "name": "output:shared:bc_base", + "message": "retrieve and echo bcs", + # always return false, so questions never shows + "when": lambda x: echo_bcs(x, 'output') }, { "type": "confirm", "name": "output:air:remap", - "message": "Would you like to remap upper air?", + "message": "Remap upper air restarts?", "default": True, }, + + { + "type": "confirm", + "name": "output:air:agcm_import_rst", + "message": f'''Remap agcm_import_rst (a.k.a. IAU) file needed for REPLAY runs? + (NOTE: Preferred method is to regenerate IAU file, + but IF requested, remapping will be performed.)''', + "default": False, + "when": lambda x: echo_level(x), + }, + + { "type": "confirm", "name": "output:surface:remap", - "message": "Would you like to remap surface?", + "message": "Remap surface restarts?", "default": True, }, + { "type": "confirm", "name": "output:analysis:bkg", - "message": "Regrid bkg files?", + "message": "Remap bkg files? (Required by ADAS but not mapped onto ADAS grid; run one ADAS cycle to spin up.) ", "default": False, }, + { "type": "confirm", "name": "output:analysis:lcv", - "message": "Write lcv?", + "message": "Write lcv file? (Required by ADAS.) ", "default": False, }, { "type": "text", "name": "input:surface:wemin", - "message": "What is value of Wemin?", - "default": lambda x: we_default(x.get('input:shared:tag')) + "message": "Enter value of WEMIN (min. snow water equivalent parameter) used in simulation that produced input restarts.\n", + "default": lambda x: wemin_default(x.get('input:shared:bc_version')), + "when": lambda x: show_wemin_default(x), }, { "type": "text", - "name": "output:surface:wemout", - "message": "What is value of Wemout?", - "default": lambda x: we_default(x.get('output:shared:tag')) + "name": "output:surface:wemin", + "message": "Enter value of WEMIN (min. snow water equivalent parameter) to be used in simulation with new restarts.\n", + "default": lambda x: wemin_default(x.get('output:shared:bc_version')) }, { "type": "text", "name": "input:surface:zoom", - "message": "What is value of zoom [1-8]?", + "message": "Enter value of zoom parameter for surface restarts [1-8]? (Search radius, smaller value means larger radius.)\n", "default": lambda x: zoom_default(x) }, { "type": "text", "name": "output:shared:expid", - "message": "Enter new restarts expid:", + "message": "Enter experiment ID for new restarts: (Added as prefix to new restart file names; can leave blank.)\n", "default": "", }, + { + "type": "confirm", + "name": "output:shared:label", + "message": "Add labels for BCs version and atm/ocean resolutions to restart file names?", + "default": False, + }, { "type": "text", "name": "slurm:qos", - "message": "qos?", + "message": "SLURM quality-of-service (qos)? (If on NCCS and atm resolution is c1440 or higher, enter allnccs.) ", "default": "debug", }, { "type": "text", "name": "slurm:account", - "message": "account?", + "message": "SLURM account?", "default": get_account(), }, { - "type": "select", - "name": "slurm:constraint", - "message": "constraint?", - "choices": ['sky', 'cas'], + "type": "text", + "name": "slurm:partition", + "message": "SLURM partition?", + "default": "compute", + "when": lambda x : default_partition(x), }, ] answers = questionary.prompt(questions) - if not answers.get('input:shared:model') : - answers['input:shared:model'] = 'data' - if answers['input:shared:MERRA-2']: - answers['input:shared:rst_dir'] = tmp_merra2_dir(answers) - answers['input:shared:rst_dir'] = os.path.abspath(answers['input:shared:rst_dir']) - if answers.get('output:shared:ogrid') == 'CS': - answers['output:shared:ogrid'] = answers['output:shared:agrid'] - answers['output:shared:out_dir'] = os.path.abspath(answers['output:shared:out_dir']) + answers['input:shared:rst_dir'] = os.path.abspath(answers['input:shared:rst_dir']) + answers['output:shared:out_dir'] = os.path.abspath(answers['output:shared:out_dir']) + if answers.get('input:air:nlevel') : del answers['input:air:nlevel'] + if answers["output:surface:remap"] and not answers["input:shared:MERRA-2"]: + answers["input:surface:catch_model"] = catch_model(answers) + return answers -def get_config_from_questionary(): - answers = ask_questions() - config = {} - config['input'] = {} - config['input']['shared'] = {} - config['input']['surface'] = {} - config['output'] = {} - config['output']['shared'] = {} - config['output']['air'] = {} - config['output']['surface'] = {} - config['output']['analysis'] = {} - config['slurm'] = {} - for key, value in answers.items(): - keys = key.split(":") - if len(keys) == 2: - config[keys[0]][keys[1]] = value - if len(keys) == 3: - config[keys[0]][keys[1]][keys[2]] = value - - return config - if __name__ == "__main__": - config = get_config_from_questionary() + answers = ask_questions() + cmdl = get_command_line_from_answers(answers) + config = get_config_from_answers(answers) yaml = ruamel.yaml.YAML() with open("raw_answers.yaml", "w") as f: yaml.dump(config, f) diff --git a/pre/remap_restart/remap_restarts.py b/pre/remap_restart/remap_restarts.py old mode 100644 new mode 100755 index d9a0958..4f1124c --- a/pre/remap_restart/remap_restarts.py +++ b/pre/remap_restart/remap_restarts.py @@ -1,104 +1,114 @@ #!/usr/bin/env python3 # -# source install/bin/g5_modules +# remap_restarts package: +# remap_restarts.py is the main script for remapping GEOS restart files to a different +# resolution and/or a different version of the associated model boundary conditions # -# Newer GEOS code should load a module with GEOSpyD Python3 if not run: -# module load python/GEOSpyD/Min4.11.0_py3.9 +# to run, must first load modules (incl. python3) as follows: +# +# source g5_modules.sh [bash] +# source g5_modules [csh] # - import sys import argparse import textwrap import ruamel.yaml import questionary from remap_utils import * -from remap_questions import get_config_from_questionary +from remap_questions import * +from remap_command_line import * from remap_params import * from remap_upper import * from remap_lake_landice_saltwater import * from remap_analysis import * from remap_catchANDcn import * -# Define the argument parser -def parse_args(): - program_description = textwrap.dedent(f''' +program_description = textwrap.dedent(f''' USAGE: - There are three ways to use this script to remap restarts. - - 1. Use an existing config file to remap: - ./remap_restarts.py -c my_config.yaml + This script provides three options for remapping GEOS restart files: - 2. Use questionary to convert template remap_params.tpl to - remap_params.yaml and then remap: + 1. Use the interactive questionary: ./remap_restarts.py + The questionary concludes with the option to submit the remapping job. + It also creates a yaml configuration file (`remap_params.yaml`) and + a command line options string (`remap_restarts.CMD`), which can be edited + manually and used in the other two ways of running `remap_restarts.py`. - 3. Use command line to input a flattened yaml file: - ./remap_restarts.py -o input:air:drymass=1 input:air:hydrostatic=0 ... + 2. Use an existing yaml config file: + ./remap_restarts.py config_file -c my_config.yaml - NOTE: Each individual script can be executed independently - 1. remap_questions.py generates raw_answer.yaml - 2. remap_params.py uses raw_answer.yaml and remap_params.tpl as inputs and generates remap_params.yaml - 3. remap_upper.py uses remap_params.yaml as input for remapping - 4. remap_lake_landice_saltwater.py uses remap_params.yaml as input for remapping - 5. remap_catchANDcn.py uses remap_params.yaml as input for remapping - 6. remap_analysis.py uses remap_params.yaml as input for remapping - ''') + 3. Use command line arguments: + ./remap_restarts.py command_line -ymdh 2004041421 .... - parser = argparse.ArgumentParser(description='Remap restarts',epilog=program_description,formatter_class=argparse.RawDescriptionHelpFormatter) - # define a mutually exclusive group of arguments - group = parser.add_mutually_exclusive_group() - group.add_argument('-c', '--config_file', help='YAML config file') - group.add_argument('-o', '--flattened_yaml', help='Flattened YAML config', metavar='input:air:drymass=1 input:air:hydrostatic=0 ...') + Help commands: + ./remap_restarts.py -h + ./remap_restarts.py config_file -h + ./remap_restarts.py command_line -h - # Parse using parse_known_args so we can pass the rest to the remap scripts - # If config_file is used, then extra_args will be empty - # If flattened_yaml is used, then extra_args will be populated - args, extra_args = parser.parse_known_args() - return args, extra_args + For more information, refer to https://github.com/GEOS-ESM/GEOS_Util/wiki + ''') def main(): question_flag = False config = '' - + yaml = ruamel.yaml.YAML() # Parse the command line arguments from parse_args() capturing the arguments and the rest - command_line_args, extra_args = parse_args() - config_yaml = command_line_args.config_file - flattened_yaml = command_line_args.flattened_yaml - - if config_yaml: - config = yaml_to_config(config_yaml) - elif flattened_yaml: - config_yaml = 'remap_params.yaml' - config = args_to_config(extra_args) - else: - raw_config = get_config_from_questionary() + cmdl, extra_args = parse_args(program_description) + answers = {} + config_yaml ='' + noprompt = False + if (len(sys.argv) > 1) : + if sys.argv[1] == 'config_file' : + config_yaml = cmdl.config_file + if sys.argv[1] == 'command_line': + answers = get_answers_from_command_line(cmdl) + noprompt = cmdl.np + if (len(sys.argv) == 1 or answers) : + if not answers: + answers = ask_questions() + question_flag = True + raw_config = get_config_from_answers(answers) + cmd = get_command_line_from_answers(answers) + write_cmd(answers['output:shared:out_dir'], cmd) + # just for debugging + # with open("raw_answers.yaml", "w") as f: + # yaml.dump(raw_config, f) params = remap_params(raw_config) config = params.config - question_flag = True - config_yaml = 'remap_params.yaml' + config_yaml = answers['output:shared:out_dir']+'/remap_params.yaml' print('\n') - print_config(config) - - questions = [ - { - "type": "confirm", - "name": "Continue", - "message": "Above is the YAML config file, would you like to continue?", - "default": True - },] - answer = questionary.prompt(questions) - - if not answer['Continue'] : - print("\nYou answered not to continue, exiting.\n") - sys.exit(0) - - if config_yaml or question_flag: write_cmd(config) - if flattened_yaml or question_flag: config_to_yaml(config, config_yaml) - + if config: + print_config(config) + + if not noprompt : + questions = [ + { + "type": "confirm", + "name": "Continue", + "message": "Above is the YAML config file, would you like to continue?", + "default": True + },] + answer = questionary.prompt(questions) + + if not answer['Continue'] : + print("\nYou answered not to continue, exiting.\n") + sys.exit(0) + + # write config to yaml file + config_to_yaml(config, config_yaml,noprompt = noprompt) + + if not noprompt : + submit = questionary.confirm("Submit the jobs now ?" , default=True).ask() + if not submit : + print("\nYou can submit the jobs by the command later on: \n") + print("./remap_restarts.py config_file -c " + config_yaml + "\n") + sys.exit(0) + + print(config_yaml) # upper air upper = upperair(params_file=config_yaml) upper.remap() @@ -117,4 +127,4 @@ def main(): if __name__ == '__main__' : main() - + diff --git a/pre/remap_restart/remap_upper.py b/pre/remap_restart/remap_upper.py index d3e3e40..30ceacb 100755 --- a/pre/remap_restart/remap_upper.py +++ b/pre/remap_restart/remap_upper.py @@ -1,5 +1,13 @@ #!/usr/bin/env python3 # +# remap_restarts package: +# remap_upper.py remaps atmospheric model restarts using config inputs from `remap_params.yaml` +# +# to run, must first load modules (incl. python3) as follows: +# +# source g5_modules.sh [bash] +# source g5_modules [csh] +# import os import ruamel.yaml import subprocess @@ -7,14 +15,10 @@ import shutil import glob from remap_base import remap_base - -def get_topodir(bcsdir): - k = bcsdir.find('/geometry/') - if k != -1 : - while bcsdir[-1] == '/': bcsdir = bcsdir[0:-1] # remove extra '/' - agrid_name = os.path.basename(bcsdir).split('_')[0] - bcsdir = bcsdir[0:k]+'/TOPO/TOPO_'+agrid_name + '/smoothed' - return bcsdir +from remap_utils import get_label +from remap_utils import STRETCH_GRID +from remap_utils import get_topodir +from remap_bin2nc import bin2nc class upperair(remap_base): def __init__(self, **configs): @@ -54,8 +58,6 @@ def remap(self): config = self.config cwdir = os.getcwd() bindir = os.path.dirname(os.path.realpath(__file__)) - in_bcsdir = config['input']['shared']['bcs_dir'] - out_bcsdir = config['output']['shared']['bcs_dir'] out_dir = config['output']['shared']['out_dir'] if not os.path.exists(out_dir) : os.makedirs(out_dir) @@ -71,34 +73,45 @@ def remap(self): os.chdir(tmpdir) print('\nUpper air restart file names link from "_rst" to "_restart_in" \n') - - types = 'z.bin' + types = '.bin' type_str = subprocess.check_output(['file','-b', restarts_in[0]]) type_str = str(type_str) if type_str.find('Hierarchical') >=0: - types = 'z.nc4' + types = '.nc4' yyyymmddhh_ = str(config['input']['shared']['yyyymmddhh']) - suffix = yyyymmddhh_[0:8]+'_'+yyyymmddhh_[8:10]+ types + label = get_label(config) + suffix = yyyymmddhh_[0:8]+'_'+yyyymmddhh_[8:10] +'z' + types + label for rst in restarts_in : f = os.path.basename(rst).split('_rst')[0].split('.')[-1]+'_restart_in' cmd = '/bin/ln -s ' + rst + ' ' + f print('\n'+cmd) subprocess.call(shlex.split(cmd)) - - in_bcsdir=get_topodir(in_bcsdir) - - topoin = glob.glob(in_bcsdir+'/topo_DYN_ave*.data')[0] + in_bc_base = config['input']['shared']['bc_base'] + in_bc_version = config['input']['shared']['bc_version'] + agrid = config['input']['shared']['agrid'] + ogrid = config['input']['shared']['ogrid'] + omodel = config['input']['shared']['omodel'] + stretch = config['input']['shared']['stretch'] + topo_bcsdir = get_topodir(in_bc_base, in_bc_version, agrid, ogrid, omodel, stretch) + + topoin = glob.glob(topo_bcsdir+'/topo_DYN_ave*.data')[0] # link topo file cmd = '/bin/ln -s ' + topoin + ' .' print('\n'+cmd) subprocess.call(shlex.split(cmd)) + out_bc_base = config['output']['shared']['bc_base'] + out_bc_version = config['output']['shared']['bc_version'] + agrid = config['output']['shared']['agrid'] + ogrid = config['output']['shared']['ogrid'] + omodel = config['output']['shared']['omodel'] + stretch = config['output']['shared']['stretch'] + topo_bcsdir = get_topodir(out_bc_base, out_bc_version, agrid, ogrid, omodel, stretch) - out_bcsdir=get_topodir(out_bcsdir) - topoout = glob.glob(out_bcsdir+'/topo_DYN_ave*.data')[0] + topoout = glob.glob(topo_bcsdir+'/topo_DYN_ave*.data')[0] cmd = '/bin/ln -s ' + topoout + ' topo_dynave.data' print('\n'+cmd) subprocess.call(shlex.split(cmd)) @@ -114,52 +127,54 @@ def remap(self): exit("Only support cs grid so far") if (imout <90): - NPE = 12; nwrit = 1 + NPE = 12; nwrit = 1 elif (imout<=180): - NPE = 24; nwrit = 1 + NPE = 24; nwrit = 1 elif (imout<=540): - NPE = 96; nwrit = 1 + NPE = 96; nwrit = 1 elif (imout<=720): - NPE = 192; nwrit = 2 + NPE = 192; nwrit = 2 elif (imout<=1080): - NPE = 384; nwrit = 2 + NPE = 384; nwrit = 2 elif (imout<=1440): - NPE = 576; nwrit = 2 + NPE = 576; nwrit = 2 elif (imout< 2880): - NPE = 768; nwrit = 2 + NPE = 768; nwrit = 2 elif (imout>=2880): - NPE = 5400; nwrit= 6 + NPE = 5400; nwrit = 6 QOS = "#SBATCH --qos="+config['slurm']['qos'] - if NPE > 532: QOS = "###" + QOS - CONSTR = "#SBATCH --constraint=" + config['slurm']['constraint'] + TIME ="#SBATCH --time=1:00:00" + if NPE > 532: + assert config['slurm']['qos'] != 'debug', "qos should be allnccs" + TIME = "#SBATCH --time=12:00:00" + + PARTITION = "#SBATCH --partition=" + config['slurm']['partition'] log_name = out_dir+'/remap_upper_log' # We need to create an input.nml file which is different if we are running stretched grid - # First, let's define a boolean for whether we are running stretched grid - # If we are running with imout of 270, 540, 1080, 1536 or 2160, then we are running stretched grid - if imout in [270, 540, 1080, 2160]: - stretched_grid = True - target_lat = 39.5 - target_lon = -98.35 - stretch_fac = 2.5 - elif imout in [1536]: - stretched_grid = True - target_lat = 39.5 - target_lon = -98.35 - stretch_fac = 3.0 - else: - stretched_grid = False - - # If we are running stretched grid, we need to pass in the target lat, lon, and stretch factor + # If we are running stretched grid, we need to pass in the target lon+lat and stretch factor # to interp_restarts.x. Per the code we use: # -stretched_grid target_lon target_lat stretch_fac # If we are not running stretched grid, we should pass in a blank string - if stretched_grid: + stretch = config['output']['shared']['stretch'] + stretch_str = "" + if stretch: + if stretch == 'SG001': + stretch_fac = STRETCH_GRID['SG001'][0] + target_lat = STRETCH_GRID['SG001'][1] + target_lon = STRETCH_GRID['SG001'][2] + elif stretch == 'SG002': + stretch_fac = STRETCH_GRID['SG002'][0] + target_lat = STRETCH_GRID['SG002'][1] + target_lon = STRETCH_GRID['SG002'][2] + else: + exit("This stretched grid option is not supported " + str(stretch)) + + # note "reversed" order of args (relative to order in definition of STRETCH_GRID) + stretch_str = "-stretched_grid " + str(target_lon) + " " + str(target_lat) + " " + str(stretch_fac) - else: - stretch_str = "" # Now, let's create the input.nml file # We need to create a namelist for the upper air remapping @@ -176,12 +191,12 @@ def remap(self): remap_template="""#!/bin/csh -xf #SBATCH --account={account} -#SBATCH --time=1:00:00 #SBATCH --ntasks={NPE} #SBATCH --job-name=remap_upper #SBATCH --output={log_name} +{TIME} {QOS} -{CONSTR} +{PARTITION} unlimit @@ -208,7 +223,7 @@ def remap(self): set outfils = () foreach infile ( *_restart_in ) if ( $infile == fvcore_internal_restart_in ) continue - if ( $infile == moist_internal_restart_in ) continue + if ( $infile == moist_internal_restart_in ) continue set infiles = ( $infiles $infile ) set outfil = `echo $infile | sed "s/restart_in/rst_out/"` @@ -245,7 +260,7 @@ def remap(self): remap_upper_script = remap_template.format(Bin=bindir, account = account, \ out_dir = out_dir, log_name = log_name, drymassFLG = drymassFLG, \ imout = imout, nwrit = nwrit, NPE = NPE, \ - QOS = QOS,CONSTR = CONSTR, nlevel = nlevel, hydrostatic = hydrostatic, + QOS = QOS, TIME = TIME, PARTITION = PARTITION, nlevel = nlevel, hydrostatic = hydrostatic, stretch_str = stretch_str) script_name = './remap_upper.j' @@ -283,6 +298,7 @@ def remap(self): else: expid = '' suffix = '_rst.' + suffix + for out_rst in glob.glob("*_rst*"): filename = expid + os.path.basename(out_rst).split('_rst')[0].split('.')[-1]+suffix print('\n Move ' + out_rst + ' to ' + out_dir+"/"+filename) @@ -290,6 +306,11 @@ def remap(self): print('\n Move remap_upper.j to ' + out_dir) shutil.move('remap_upper.j', out_dir+"/remap_upper.j") + with open(out_dir+'/cap_restart', 'w') as f: + yyyymmddhh_ = str(config['input']['shared']['yyyymmddhh']) + time = yyyymmddhh_[0:8]+' '+yyyymmddhh_[8:10]+'0000' + print('Create cap_restart') + f.write(time) print('cd ' + cwdir) os.chdir(cwdir) @@ -328,19 +349,28 @@ def copy_merra2(self): merra_2_rst_dir = '/archive/users/gmao_ops/MERRA2/gmao_ops/GEOSadas-5_12_4/'+expid +'/rs/Y'+yyyy_ +'/M'+mm_+'/' rst_dir = self.config['input']['shared']['rst_dir'] + '/' os.makedirs(rst_dir, exist_ok = True) - print(' Copy MERRA-2 upper air restarts \n from \n ' + merra_2_rst_dir + '\n to\n '+ rst_dir +'\n') + print(' Stage MERRA-2 upper air restarts \n from \n ' + merra_2_rst_dir + '\n to\n '+ rst_dir +'\n') upperin =[merra_2_rst_dir + expid+'.fvcore_internal_rst.' + suffix, merra_2_rst_dir + expid+'.moist_internal_rst.' + suffix, - merra_2_rst_dir + expid+'.agcm_import_rst.' + suffix, merra_2_rst_dir + expid+'.gocart_internal_rst.' + suffix, - merra_2_rst_dir + expid+'.pchem_internal_rst.' + suffix ] - - for f in upperin : + merra_2_rst_dir + expid+'.pchem_internal_rst.' + suffix, + merra_2_rst_dir + expid+'.agcm_import_rst.' + suffix ] + bin2nc_yaml = ['bin2nc_merra2_fv.yaml', 'bin2nc_merra2_moist.yaml', 'bin2nc_merra2_gocart.yaml', 'bin2nc_merra2_pchem.yaml','bin2nc_merra2_agcm.yaml'] + bin_path = os.path.dirname(os.path.realpath(__file__)) + for (f, yf) in zip(upperin,bin2nc_yaml) : fname = os.path.basename(f) dest = rst_dir + '/'+fname - print("Copy file "+f +" to " + rst_dir) + print("Stage file "+f +" to " + rst_dir) shutil.copy(f, dest) + ncdest = dest.replace('z.bin', 'z.nc4') + yaml_file = bin_path + '/'+yf + print('Convert bin to nc4:' + dest + ' to \n' + ncdest + '\n') + if '_fv' in yf: + bin2nc(dest, ncdest, yaml_file, isDouble=True, hasHeader=True) + else: + bin2nc(dest, ncdest, yaml_file) + os.remove(dest) if __name__ == '__main__' : air = upperair(params_file='remap_params.yaml') diff --git a/pre/remap_restart/remap_utils.py b/pre/remap_restart/remap_utils.py old mode 100644 new mode 100755 index 3f71429..68b838e --- a/pre/remap_restart/remap_utils.py +++ b/pre/remap_restart/remap_utils.py @@ -1,14 +1,286 @@ #!/usr/bin/env python3 # +# remap_restarts package: +# remap_utils.py contains utility functions and definitions +# import os import subprocess import ruamel.yaml from collections import OrderedDict import shutil import questionary +import glob +import shlex +import netCDF4 as nc + +# shared global variables + +# top-level directory for BCs (machine-dependent) + +choices_bc_base =[ "NCCS/Discover : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles", + "NAS : /nobackup/gmao_SIteam/ModelData/bcs_shared/fvInput/ExtData/esm/tiles", + "Custom " ] + +# define "choices", "message" strings, and "validate" lists that are used multiple times +# (and related definitions, even if they are used just once). + +choices_bc_ops = ['NL3', 'ICA', 'GM4', 'Other'] + +choices_bc_other = ['v06','v11'] + +choices_bc_cmd = ['NL3', 'ICA', 'GM4', 'v06', 'v11'] + +choices_omodel = ['data', 'MOM5', 'MOM6'] + +choices_catchmodel = ['catch', 'catchcnclm40', 'catchcnclm45'] + +choices_ogrid_data = ['360x180 (Reynolds)','1440x720 (MERRA-2)','2880x1440 (OSTIA)','CS (same as atmosphere OSTIA cubed-sphere grid)'] + +choices_ogrid_cpld = ['72x36', '360x200', '720x410', '1440x1080'] + +choices_ogrid_cmd = ['360x180', '1440x720', '2880x1440', 'CS'] + choices_ogrid_cpld + +# the following needs more cleanup; e.g., first define list of SGxxx names and parameters (i.e., STRETCH_GRID), +# then assemble message_stretch and choices_stretch using this definition + +message_stretch = f'''\n + Select parameters of stretched cubed-sphere grid for new restarts: + + Name Stretch_Factor Focus_Lat Focus_Lon + ----- -------------- --------- --------- + SG001 2.5 39.5 -98.35 + SG002 3.0 39.5 -98.35 + \n\n''' + +STRETCH_GRID = {} +STRETCH_GRID['SG001'] = ['2.50', '39.50', '-98.35'] +STRETCH_GRID['SG002'] = ['3.00', '39.50', '-98.35'] + +choices_stretch = [False, 'SG001', 'SG002'] + +choices_res_SG001 = ['C270', 'C540', 'C1080', 'C2160'] + +choices_res_SG002 = ['C1536'] + +message_bc_ops = f'''\n + BCs version | ADAS tags | GCM tags typically used with BCs version + -----------------|----------------------|----------------------------------------- + GM4: Ganymed-4_0 | 5_12_2 ... 5_16_5 | Ganymed-4_0 ... Heracles-5_4_p3 + ICA: Icarus | 5_17_0 ... 5_24_0_p1 | Icarus, Jason ... 10.18 + NL3: Icarus-NLv3 | 5_25_1 ... present | Icarus_NL, 10.19 ... present + ---------------------------------------------------------------------------------- + Other: Additional choices used in model or DAS development. + \n\n ''' + +message_bc_ops_in = ("Select boundary conditions (BCs) version of input restarts:\n" + message_bc_ops) +message_bc_ops_new = ("Select boundary conditions (BCs) version for new restarts:\n" + message_bc_ops) + +message_bc_other = f'''\n + + v06: NL3 + JPL veg height + PEATMAP + MODIS snow alb\n + v11: NL3 + JPL veg height + PEATMAP + MODIS snow alb v2\n\n'''\ + +message_bc_other_in = ("Select BCs version of input restarts:\n" + message_bc_other) +message_bc_other_new = ("Select BCs version for new restarts:\n" + message_bc_other) + +message_agrid_list = f''' + C12 C180 C1440 + C24 C360 C2880 + C48 C720 C5760 + C90 C1000 \n''' + +message_agrid_in = ("Enter atmospheric grid of input restarts:\n" + message_agrid_list) + +message_agrid_new = ("Enter atmospheric grid for new restarts:\n" + message_agrid_list) + +validate_agrid = ['C12','C24','C48','C90','C180','C360','C720','C1000','C1440','C2880','C5760'] + +# -------------------------------------------------------------------------------- + +def init_merra2(x): + if not x.get('input:shared:MERRA-2') : return False + + yyyymm = int(x.get('input:shared:yyyymmddhh')[0:6]) + if yyyymm < 197901 : + exit("Error. MERRA-2 data < 1979 not available\n") + elif (yyyymm < 199201): + expid = "d5124_m2_jan79" + elif (yyyymm < 200106): + expid = "d5124_m2_jan91" + elif (yyyymm < 201101): + expid = "d5124_m2_jan00" + elif (yyyymm < 202106): + expid = "d5124_m2_jan10" + # There was a rewind in MERRA2 from Jun 2021 to Sept 2021 + elif (yyyymm < 202110): + expid = "d5124_m2_jun21" + else: + expid = "d5124_m2_jan10" + x['input:shared:expid'] = expid + x['input:shared:omodel'] = 'data' + x['input:shared:agrid'] = 'C180' + x['input:shared:ogrid'] = '1440x720' + x['input:shared:omodel'] = 'data' + x['input:shared:bc_version'] = 'GM4' + x['input:shared:bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + x['input:surface:catch_model'] = 'catch' + x['input:shared:stretch'] = False + x['input:shared:rst_dir'] = x['output:shared:out_dir'] + '/merra2_tmp_'+x['input:shared:yyyymmddhh']+'/' + x['input:air:nlevel'] = 72 + + return False + +def fvcore_info(x): + if 'input:shared:agrid' in x.keys(): + return True + rst_dir = x.get('input:shared:rst_dir') + if not rst_dir : return False + x['input:shared:rst_dir'] = rst_dir.strip() # remove extra space + + files = glob.glob(rst_dir+'/*fvcore_*') + if len (files) == 0 : return False + + fname ='' + ymdh ='' + + if len(files) > 1 : + ymdh = x.get('input:shared:yyyymmddhh') + if (not ymdh): return False + time = ymdh[0:8] + '_'+ymdh[8:10] + files = glob.glob(rst_dir+'/*fvcore_*'+time+'*') + fname = files[0] + + if len(files) == 1: + fname = files[0] + + fvrst = nc.Dataset(fname) + lon = fvrst.dimensions['lon'].size + lat = fvrst.dimensions['lat'].size + lev = fvrst.dimensions['lev'].size + x['input:air:nlevel'] = lev + ymdh = fvrst.variables['time'].units.split('since ')[1].split(":")[0].replace('-','').replace(' ', "") + if (lat != lon*6) : + print("(N_lon, N_lat) = ", lon, lat) + exit('This is not a cubed-sphere grid fvcore restart. Please contact SI team') + x['input:shared:yyyymmddhh'] = ymdh + x['input:shared:agrid'] = "C"+str(lon) + print("The input fvcore restart has atm grid: " + "C" + str(lon) + '\n') + print("The input fvcore restart has time: " + ymdh + '\n') + expid = os.path.basename(fname).split('fvcore')[0] + expid = expid[0:-1] + x['input:shared:expid'] = expid + if (expid) : print("The input fvcore restart has experiment ID " + expid + '\n') + + # get stretch parameters from input restart file + x['input:shared:stretch'] = False + stretch_factor = fvrst.__dict__.get('STRETCH_FACTOR') + if (stretch_factor) : + target_lat = fvrst.__dict__.get('TARGET_LAT') + target_lon = fvrst.__dict__.get('TARGET_LON') + sg = [stretch_factor, target_lat, target_lon] + # verify that stretched cubed-sphere grid is supported by remap_restarts.py + f_ = [f"{number:.{2}f}" for number in sg] + print("[stretch_factor, target_lat, target_lon]: ", f_) + if f_ == STRETCH_GRID['SG001']: + x['input:shared:stretch'] = 'SG001' + elif f_ == STRETCH_GRID['SG002'] : + x['input:shared:stretch'] = 'SG002' + else: + exit("This stretched cubed-sphere grid is not supported ") + return True + +def catch_model(x): + ymdh = x['input:shared:yyyymmddhh'] + time = ymdh[0:8] + '_'+ymdh[8:10] + rst_dir = x.get('input:shared:rst_dir') + if not rst_dir : return False + + x['input:shared:rst_dir'] = rst_dir.strip() # remove extra space + + files = glob.glob(rst_dir+'/*catch*') + + if len (files) == 0 : return False + fname= '' + if len(files) == 1: + fname = os.path.basename(files[0]) -def config_to_yaml(config, yaml_file): - if os.path.exists(yaml_file) : + if len(files) > 1 : + files = glob.glob(rst_dir+'/*fvcore_*'+time+'*') + fname = os.path.basename(files[0]) + model = 'catch' + if 'cnclm40' in fname.lower(): + model = 'catchcnclm40' + if 'cnclm45' in fname.lower(): + model = 'catchcnclm45' + return model + +def data_ocean_default(resolution): + # the default string should match the choice in remapl_question.py + default_ = 'CS (same as atmosphere OSTIA cubed-sphere grid)' + if resolution in ['C12','C24', 'C48'] : default_ = '360x180 (Reynolds)' + return default_ + +def get_label(config): + label = '' + if config['output']['shared']['label']: + agrid = config['output']['shared']['agrid'] + ogrid = config['output']['shared']['ogrid'] + model = config['output']['shared']['omodel'] + stretch = config['output']['shared']['stretch'] + out_resolution = get_resolutions(agrid, ogrid, model, stretch) + + agrid = config['input']['shared']['agrid'] + ogrid = config['input']['shared']['ogrid'] + model = config['input']['shared']['omodel'] + stretch = config['input']['shared']['stretch'] + in_resolution = get_resolutions(agrid, ogrid, model, stretch) + + in_bcv = config['input']['shared']['bc_version'] + out_bcv = config['output']['shared']['bc_version'] + label = '.' + in_bcv + '.' + in_resolution + \ + '.' + out_bcv + '.' + out_resolution + return label + +# NOTE: "wemin" is a configurable parameter that can be set to anything, independent +# of the bcs version. The default set here is simply the "wemin" value that is +# typically used with the bcs version. The user needs to confirm the default +# value or overwrite it with the "wemin" value used in the simulation that is +# associated with the given set of restarts. +def wemin_default(bc_version): + default_ = '13' + if bc_version =='GM4' or bc_version == 'ICA' : default_ = '26' + return default_ + +def show_wemin_default(x): + if not x['input:shared:MERRA-2']: + return True + else: + x['input:surface:wemin'] = '26' + return False + +def zoom_default(x): + zoom_ = '8' + cxx = x.get('input:shared:agrid') + if cxx : + lat = int(cxx[1:]) + zoom = lat /90.0 + zoom_ = str(int(zoom)) + if zoom < 1 : zoom_ = '1' + if zoom > 8 : zoom_ = '8' + if x['input:shared:MERRA-2'] : + zoom_ = '2' + return zoom_ + +def get_account(): + cmd = 'id -gn' + p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) + (accounts, err) = p.communicate() + p_status = p.wait() + accounts = accounts.decode().split() + return accounts[0] + +def config_to_yaml(config, yaml_file, noprompt = False): + if os.path.exists(yaml_file) and not noprompt : overwrite = questionary.confirm("Do you want to overwrite " + yaml_file + "?" , default=False).ask() if not overwrite : while True: @@ -30,61 +302,16 @@ def yaml_to_config(yaml_file): config = yaml.load(stream) return config -def write_cmd(config) : - def flatten_nested(nested_dict, result=None, prefix=''): - if result is None: - result = dict() - for k, v in nested_dict.items(): - new_k = ':'.join((prefix, k)) if prefix else k - if not (isinstance(v, dict) or isinstance(v, OrderedDict)): - result.update({new_k: v}) - else: - flatten_nested(v, result, new_k) - return result - - out_dir = config['output']['shared']['out_dir'] +def write_cmd( out_dir, cmdl) : + + out_dir = os.path.realpath(out_dir) if not os.path.exists(out_dir) : os.makedirs(out_dir) bin_path = os.path.dirname(os.path.realpath(__file__)) - - cmd = '#!/usr/local/bin/csh \n' - cmd = cmd + 'set BINPATH=' + bin_path +'\n' - cmd = cmd + 'source $BINPATH/g5_modules \n' - - flat_dict = flatten_nested(config) - - k = 1 - for key, value in flat_dict.items(): - if isinstance(value, int) or isinstance(value, float) or isinstance(value, bool) or isinstance(value, type(None)): value = str(value) - if k == 1: - cmd = cmd + 'set FLAT_YAML="' + key+"="+ value+ '"\n' - else: - cmd = cmd + 'set FLAT_YAML="$FLAT_YAML '+ key+"="+ value+ '"\n' - k = k+1 - - cmd = cmd + '$BINPATH/remap_restarts.py -o $FLAT_YAML' - + cmdl = bin_path+'/'+ cmdl with open(out_dir + '/remap_restarts.CMD', 'w') as f: - f.write(cmd) - subprocess.call(['chmod', '+x',out_dir + '/remap_restarts.CMD']) - -def args_to_config(args): - # template file should be with this util file - remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' - config = yaml_to_config(remap_tpl) - # fill in the config with args - for values in args: - [keys, value] = values.split("=") - key = keys.split(':') - if value.lower() in ['false', 'null', 'none'] : - value = False - elif value.lower() in ['true'] : - value = True - if len(key) == 2: - config[key[0]][key[1]] = value - if len(key) == 3: - config[key[0]][key[1]][key[2]] = value - - return config + f.write(cmdl) + # Don't run remap_ressatrs.CMD directly. It may overwrite itself + #subprocess.call(['chmod', '+x',out_dir + '/remap_restarts.CMD']) def print_config( config, indent = 0 ): for k, v in config.items(): @@ -94,29 +321,197 @@ def print_config( config, indent = 0 ): else: print(" " * indent, f"{k}: {v}") -def merra2_expid(config): - if not config['MERRA-2']: - return config - yyyymm = int(config.get('yyyymmddhh')[0:6]) - if yyyymm < 197901 : - exit("Error. MERRA-2 data < 1979 not available\n") - elif (yyyymm < 199201): - expid = "d5124_m2_jan79" - elif (yyyymm < 200106): - expid = "d5124_m2_jan91" - elif (yyyymm < 201101): - expid = "d5124_m2_jan00" - elif (yyyymm < 202106): - expid = "d5124_m2_jan10" - # There was a rewind in MERRA2 from Jun 2021 to Sept 2021 - elif (yyyymm < 202110): - expid = "d5124_m2_jun21" - else: - expid = "d5124_m2_jan10" - config['expid'] = expid +def get_command_line_from_answers(answers): + + merra2 = " -merra2 " if answers["input:shared:MERRA-2"] else "" + ymdh = " -ymdh " + answers["input:shared:yyyymmddhh"] + rst_dir = " -rst_dir " + answers["input:shared:rst_dir"] + + grout = ' -grout ' + answers["output:shared:agrid"] + levsout = ' -levsout ' + answers["output:air:nlevel"] + + out_dir = ' -out_dir ' + answers["output:shared:out_dir"] + newid = answers["output:shared:expid"] + + out_newid='' + if newid.strip(): + out_newid = " -newid " + newid + + bcvin = '' + if answers.get("input:shared:bc_version"): + bcvin = " -bcvin " + answers["input:shared:bc_version"] + bcvout = " -bcvout " + answers["output:shared:bc_version"] + + ocnmdlin = '-ocnmdlin data' + if answers.get("input:shared:omodel"): + ocnmdlin = ' -ocnmdlin ' + answers.get("input:shared:omodel") + + ocnmdlout = ' -ocnmdlout data' + if answers.get("output:shared:omodel"): + ocnmdlout = ' -ocnmdlout ' + answers["output:shared:omodel"] + + oceanin='' + ogrid = answers.get("input:shared:ogrid") + if ogrid : + if ogrid[0] == 'C': + ogrid = "CS" + oceanin = ' -oceanin ' + ogrid + + ogrid = answers.get("output:shared:ogrid") + if ogrid[0] == 'C': + ogrid = "CS" + oceanout = ' -oceanout ' + ogrid + + nobkg = '' if answers["output:analysis:bkg"] else " -nobkg " + nolcv = '' if answers["output:analysis:lcv"] else " -nolcv " + + label = ' -lbl ' if answers["output:shared:label"] else "" + + in_bc_base = ' -in_bc_base ' + answers.get("input:shared:bc_base") + out_bc_base = ' -out_bc_base ' + answers.get("output:shared:bc_base") + + out_stretch = '' + if answers["output:shared:stretch"]: + out_stretch = ' -out_stretch ' + answers["output:shared:stretch"] + in_stretch = '' + if answers["input:shared:stretch"]: + in_stretch = ' -in_stretch ' + answers["input:shared:stretch"] + + zoom = " -zoom " + answers["input:surface:zoom"] + wemin = " -in_wemin " + answers["input:surface:wemin"] + wemout = " -out_wemin " + answers["output:surface:wemin"] + catch_model ='' + if answers.get("input:surface:catch_model"): + catch_model = " -catch_model " + answers["input:surface:catch_model"] + + out_rs = " -rs " + rs = 3 + if answers['output:air:remap'] and not answers['output:surface:remap']: + rs = 1 + if answers['output:surface:remap'] and not answers['output:air:remap']: + rs = 2 + out_rs = out_rs + str(rs) + + noagcm_import_rst = '' if answers["output:air:agcm_import_rst"] else " -noagcm_import_rst " + + account = " -account " + answers["slurm:account"] + qos = " -qos " + answers["slurm:qos"] + partition = " -partition " + answers["slurm:partition"] + + + cmdl = "remap_restarts.py command_line " + merra2 + \ + ymdh + \ + grout + \ + levsout + \ + out_newid + \ + ocnmdlin + \ + ocnmdlout + \ + oceanin + \ + oceanout + \ + bcvin + \ + bcvout + \ + rst_dir + \ + out_dir + \ + in_bc_base + \ + out_bc_base + \ + out_stretch + \ + in_stretch + \ + catch_model + \ + zoom + \ + wemin + \ + wemout + \ + label + \ + nobkg + \ + noagcm_import_rst + \ + nolcv + \ + out_rs + \ + account + \ + qos + \ + partition + + + return cmdl + +def get_config_from_answers(answers): + config = {} + config['input'] = {} + config['input']['air'] = {} + config['input']['shared'] = {} + config['input']['surface'] = {} + config['output'] = {} + config['output']['shared'] = {} + config['output']['air'] = {} + config['output']['surface'] = {} + config['output']['analysis'] = {} + config['slurm'] = {} + for key, value in answers.items(): + keys = key.split(":") + if len(keys) == 2: + config[keys[0]][keys[1]] = value + if len(keys) == 3: + config[keys[0]][keys[1]][keys[2]] = value return config +def get_resolutions(agrid, ogrid, model, stretch): + aname = '' + oname = '' + if (agrid[0].upper() == 'C'): + n = int(agrid[1:]) + aname ='CF{:04d}x6C'.format(n) + + if (ogrid[0].upper() == 'C'): + oname = aname + else: + xy = ogrid.upper().split('X') + s0 = int(xy[0]) + s1 = int(xy[1]) + if model == 'data': + oname = 'DE{:04d}xPE{:04d}'.format(s0,s1) + if model == 'MOM5': + oname = 'M5TP{:04d}x{:04d}'.format(s0,s1) + if model == 'MOM6': + oname = 'M6TP{:04d}x{:04d}'.format(s0,s1) + if stretch: + aname = aname + '-' + stretch + + resolutions = aname +'_' + oname + + return resolutions + +def get_default_bc_base(): + cmd = 'uname -n' + p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) + (node, err) = p.communicate() + p_status = p.wait() + node = node.decode().split() + node0 = node[0] + discover = ['dirac', 'borg','warp', 'discover'] + for node in discover: + if node in node0: + return choices_bc_base[0] + return choices_bc_base[1] + +def get_topodir(bc_base, bc_version, agrid, ogrid, model, stretch): + gridStr = get_resolutions(agrid, ogrid, model,stretch) + agrid_name = gridStr.split('_')[0] + bc_topo = '' + if 'GM4' == bc_version: + bc_topo = bc_base + '/' + bc_version + '/TOPO/TOPO_' + agrid_name + else: + bc_topo = bc_base + '/' + bc_version + '/TOPO/TOPO_' + agrid_name + '/smoothed' + + return bc_topo + +def get_landdir(bc_base, bc_version, agrid, ogrid, model, stretch): + gridStr = get_resolutions(agrid, ogrid, model,stretch) + bc_land = bc_base+'/'+ bc_version+'/land/'+gridStr + return bc_land + +def get_geomdir(bc_base, bc_version, agrid, ogrid, model, stretch): + bc_geom = get_landdir(bc_base, bc_version, agrid, ogrid, model, stretch). replace('/land/', '/geometry/') + return bc_geom + if __name__ == '__main__' : config = yaml_to_config('c24Toc12.yaml') print_config(config) diff --git a/post/tests/amip_c180Toc90.yaml b/pre/remap_restart/tests/amip_c180Toc90.yaml similarity index 66% rename from post/tests/amip_c180Toc90.yaml rename to pre/remap_restart/tests/amip_c180Toc90.yaml index 9e93f70..b3b7096 100644 --- a/post/tests/amip_c180Toc90.yaml +++ b/pre/remap_restart/tests/amip_c180Toc90.yaml @@ -9,8 +9,12 @@ input: hydrostatic: 0 shared: MERRA-2: false + stretch: false agrid: C180 - bcs_dir: /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_MERRA-2//CF0180x6C_DE1440xPE0720/ + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: JM_v10.22.2_L072_C180_AMIP ogrid: 1440X720 rst_dir: /discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/amip_c180Toc90/inputs/ @@ -24,10 +28,15 @@ input: output: shared: agrid: C90 - bcs_dir: /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_Ostia//CF0090x6C_CF0090x6C/ + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: C90CS_JM_v10.22.2_L072_C180_AMIP ogrid: C90 out_dir: $NOBACKUP/REMAP_TESTS/amip_c180Toc90/ + label: False air: # remap upper air or not remap: true @@ -47,6 +56,7 @@ output: lcv: false slurm: - account: g0620 + # account will be set to user's primary account automatically by test_remap_restarts.py + account: qos: debug - constraint: sky + partition: compute diff --git a/post/tests/c180Toc360.yaml b/pre/remap_restart/tests/c180Toc360.yaml similarity index 66% rename from post/tests/c180Toc360.yaml rename to pre/remap_restart/tests/c180Toc360.yaml index 1f919ef..10b4c32 100644 --- a/post/tests/c180Toc360.yaml +++ b/pre/remap_restart/tests/c180Toc360.yaml @@ -9,8 +9,12 @@ input: hydrostatic: 0 shared: MERRA-2: false + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data agrid: C180 - bcs_dir: /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_MERRA-2//CF0180x6C_DE1440xPE0720/ + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: Jason-3_4_NL_REAMIP_MERRA2_C180 ogrid: 1440X720 rst_dir: /discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/c180Toc360/inputs/ @@ -24,10 +28,15 @@ input: output: shared: agrid: C360 - bcs_dir: /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_Ostia//CF0360x6C_CF0360x6C/ + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: C360CS_Jason-3_4_NL_REAMIP_MERRA2_C180 ogrid: C360 out_dir: $NOBACKUP/REMAP_TESTS/c360Toc24/ + label: False air: # remap upper air or not remap: true @@ -47,6 +56,7 @@ output: lcv: false slurm: - account: g0620 + # account will be set to user's primary account automatically by test_remap_restarts.py + account: qos: debug - constraint: sky + partition: compute diff --git a/post/tests/c24Toc12.yaml b/pre/remap_restart/tests/c24Toc12.yaml similarity index 64% rename from post/tests/c24Toc12.yaml rename to pre/remap_restart/tests/c24Toc12.yaml index 0b96e65..ed9ec24 100644 --- a/post/tests/c24Toc12.yaml +++ b/pre/remap_restart/tests/c24Toc12.yaml @@ -9,8 +9,12 @@ input: hydrostatic: 0 shared: MERRA-2: false + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data agrid: C24 - bcs_dir: /discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs/Icarus-NLv3/Icarus-NLv3_Reynolds//CF0024x6C_DE0360xPE0180/ + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: '' ogrid: 360X180 rst_dir: /discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/c24Toc12/inputs @@ -24,10 +28,15 @@ input: output: shared: agrid: C12 - bcs_dir: /discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs/Icarus-NLv3/Icarus-NLv3_Reynolds//CF0012x6C_DE0360xPE0180/ + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: hello ogrid: 360X180 out_dir: $NOBACKUP/REMAP_TESTS/c24Toc12/ + label: False air: # remap upper air or not remap: true @@ -47,6 +56,7 @@ output: lcv: false slurm: - account: g0610 + # account will be set to user's primary account automatically by test_remap_restarts.py + account: qos: debug - constraint: hasw + partition: compute diff --git a/post/tests/c360Toc24.yaml b/pre/remap_restart/tests/c360Toc24.yaml similarity index 64% rename from post/tests/c360Toc24.yaml rename to pre/remap_restart/tests/c360Toc24.yaml index 08812fa..e566fc9 100644 --- a/post/tests/c360Toc24.yaml +++ b/pre/remap_restart/tests/c360Toc24.yaml @@ -10,7 +10,11 @@ input: shared: MERRA-2: false agrid: C360 - bcs_dir: /discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs/Icarus-NLv3/Icarus-NLv3_Ostia//CF0360x6C_CF0360x6C/ + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: x0046a ogrid: C360 rst_dir: /discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/c360Toc24/inputs @@ -24,10 +28,15 @@ input: output: shared: agrid: C24 - bcs_dir: /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_Reynolds//CF0024x6C_DE0360xPE0180/ + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: C24c_x0046a ogrid: 360X180 out_dir: $NOBACKUP/REMAP_TESTS/c360Toc24/ + label: False air: # remap upper air or not remap: true @@ -47,6 +56,7 @@ output: lcv: false slurm: - account: g0620 + # account will be set to user's primary account automatically by test_remap_restarts.py + account: qos: debug - constraint: sky + partition: compute diff --git a/post/tests/f522Toc360.yaml b/pre/remap_restart/tests/f522Toc360.yaml similarity index 60% rename from post/tests/f522Toc360.yaml rename to pre/remap_restart/tests/f522Toc360.yaml index 17deaa6..4c58aab 100644 --- a/post/tests/f522Toc360.yaml +++ b/pre/remap_restart/tests/f522Toc360.yaml @@ -9,8 +9,12 @@ input: hydrostatic: 0 shared: MERRA-2: false + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data agrid: C720 - bcs_dir: /discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs/Icarus_Updated/Icarus_Ostia//CF0720x6C_CF0720x6C/ + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: ICA expid: f522_fp ogrid: C720 rst_dir: /discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/f522Toc360/inputs/ @@ -23,10 +27,15 @@ input: output: shared: agrid: C360 - bcs_dir: /discover/nobackup/projects/gmao/share/gmao_ops/fvInput/g5gcm/bcs/Icarus-NLv3/Icarus-NLv3_Reynolds//CF0360x6C_DE0360xPE0180/ + stretch: false + # (coupled) ocean model: data, MOM5, MOM6 + omodel: data + bc_base: /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles + bc_version: NL3 expid: remap ogrid: 360X180 out_dir: $NOBACKUP/REMAP_TESTS/f522Toc360/ + label: False air: nlevel: '72' remap: true @@ -43,6 +52,7 @@ output: lcv: true slurm: - account: g0610 + # account will be set to user's primary account automatically by test_remap_restarts.py + account: qos: debug - constraint: hasw + partition: compute diff --git a/post/tests/test_remap_cases.yaml b/pre/remap_restart/tests/test_remap_cases.yaml similarity index 82% rename from post/tests/test_remap_cases.yaml rename to pre/remap_restart/tests/test_remap_cases.yaml index 166d091..b4df816 100644 --- a/post/tests/test_remap_cases.yaml +++ b/pre/remap_restart/tests/test_remap_cases.yaml @@ -13,6 +13,3 @@ c180Toc360: c360Toc24: base_line: '/discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/c360Toc24/baseline/' config: 'c360Toc24.yaml' -s2sv3Toc12MOM6: - base_line: '/discover/nobackup/projects/gmao/SIteam/Remapping_Test_Cases/s2sv3Toc12MOM6/baseline/' - config: 's2sv3Toc12MOM6.yaml' diff --git a/post/tests/test_remap_restarts.py b/pre/remap_restart/tests/test_remap_restarts.py similarity index 90% rename from post/tests/test_remap_restarts.py rename to pre/remap_restart/tests/test_remap_restarts.py index 69c6707..0fcb075 100755 --- a/post/tests/test_remap_restarts.py +++ b/pre/remap_restart/tests/test_remap_restarts.py @@ -5,14 +5,14 @@ # Newer GEOS code should load a module with GEOSpyD Python3 if not run: # module load python/GEOSpyD/Min4.10.3_py3.9 # - +import os import sys, getopt import ruamel.yaml import questionary import glob import subprocess as sp import remap_restarts -from remap_questions import get_config_from_questionary +import remap_utils from remap_params import * from remap_upper import * from remap_lake_landice_saltwater import * @@ -29,8 +29,10 @@ def compare(base, result): return False bases.sort() results.sort() + basedir = os.environ['BASEDIR'] + NCCMP = basedir+'/Linux/bin/nccmp' for b, r in zip(bases, results): - cmd = 'nccmp -dmgfs '+ b + ' ' + r + cmd = NCCMP + ' -dmgfs '+ b + ' ' + r print(cmd) p = sp.Popen(shlex.split(cmd), stdout=subprocess.PIPE) (out, err) = p.communicate() @@ -39,7 +41,7 @@ def compare(base, result): if "identical." in out : print('identical') else: - print ( f + ' is different from ' + r) + print ( b + ' is different from ' + r) return False return True @@ -82,6 +84,7 @@ def test_remap(config): out_dir = '/discover/nobackup/'+user+'/REMAP_TESTS/'+case+'/' config['output']['shared']['out_dir'] = out_dir + config['slurm']['account'] = get_account() test_remap(config)