diff --git a/.gitignore b/.gitignore index fb8273d8a4..79607e39fd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ __pycache__ *.sw[a-p] ._* .DS_Store +#nohup.out - some users do not want this to be a part of .gitignore. TODO: review against best practices .idea/ .vscode/ diff --git a/parm/config/config.aero b/parm/config/config.aero old mode 100755 new mode 100644 diff --git a/parm/config/config.aerosol_init b/parm/config/config.aerosol_init old mode 100755 new mode 100644 diff --git a/parm/config/config.base.emc.dyn b/parm/config/config.base.emc.dyn index 27e8594e47..72082bf6c0 100644 --- a/parm/config/config.base.emc.dyn +++ b/parm/config/config.base.emc.dyn @@ -165,6 +165,23 @@ export DOBNDPNT_WAVE="NO" export cplwav2atm=".false." export FRAC_GRID=".true." +# Set operational resolution +export OPS_RES="C768" # Do not change + +# Resolution specific parameters +export LEVS=128 +export CASE="@CASECTL@" +export CASE_ENKF="@CASEENS@" +case "$CASE" in + "C48") export OCNRES=500;; + "C96") export OCNRES=100;; + "C192") export OCNRES=050;; + "C384") export OCNRES=025;; + "C768") export OCNRES=025;; + *) export OCNRES=025;; +esac +export ICERES=$OCNRES + case "${APP}" in ATM) export confignamevarfornems="atm" @@ -212,23 +229,6 @@ case "${APP}" in ;; esac -# Set operational resolution -export OPS_RES="C768" # Do not change - -# Resolution specific parameters -export LEVS=128 -export CASE="@CASECTL@" -export CASE_ENKF="@CASEENS@" -case "${CASE}" in - "C48") export OCNRES=500;; - "C96") export OCNRES=100;; - "C192") export OCNRES=050;; - "C384") export OCNRES=025;; - "C768") export OCNRES=025;; - *) export OCNRES=025;; -esac -export ICERES=${OCNRES} - # Surface cycle update frequency if [[ "${CDUMP}" == "gdas" ]] ; then export FHCYC=1 @@ -289,7 +289,7 @@ export IAU_DELTHRS_ENKF=6 export lobsdiag_forenkf=".true." # run GLDAS to spin up land ICs -export DO_GLDAS="YES" +export DO_GLDAS="NO" export gldas_cyc=00 # Exception handling that when DO_GLDAS is set, the FHOUT must be 1 @@ -312,7 +312,7 @@ export DO_JEDIENS="NO" export DO_JEDIOCNVAR="NO" # Hybrid related -export DOHYBVAR="YES" +export DOHYBVAR="@DOHYBVAR@" export NMEM_ENKF=@NMEM_ENKF@ export NMEM_EFCS=30 export SMOOTH_ENKF="NO" @@ -363,7 +363,7 @@ export MAKE_ACFTBUFR="@MAKE_ACFTBUFR@" # Analysis increments to zero in CALCINCEXEC export INCREMENTS_TO_ZERO="'liq_wat_inc','icmr_inc'" -# Write analysis files for early cycle EnKF +# Write analysis files for early cycle EnKF export DO_CALC_INCREMENT_ENKF_GFS="YES" # Stratospheric increments to zero diff --git a/parm/config/config.defaults.s2sw b/parm/config/config.defaults.s2sw old mode 100755 new mode 100644 index 5032a998ad..a5f992e858 --- a/parm/config/config.defaults.s2sw +++ b/parm/config/config.defaults.s2sw @@ -3,7 +3,6 @@ # Empty variables must include a space otherwise they will be overwritten # config.base -# CASE=C384 FHMAX_GFS_00=48 FHMAX_GFS_06=48 FHMAX_GFS_12=48 @@ -15,21 +14,27 @@ FHOUT_HF_GFS=-1 min_seaice="1.0e-6" use_cice_alb=".true." -# config.fv3 -DELTIM=300 -layout_x_gfs=8 -layout_y_gfs=8 -WRITE_GROUP_GFS=1 -WRTTASK_PER_GROUP_GFS=24 -#The settings below will result in S2SWA running 35 days under 8 hours wallclock on hera -#layout_x_gfs=24 -#layout_y_gfs=16 -#WRTTASK_PER_GROUP_GFS=86 -WRTIOBUF="32M" -MEDPETS=300 - +# config.fv3 # TODO: This is hard-wired for P8 and needs to be refactored. For now, use case C384 +case "${CASE}" in + "C384") + DELTIM=300 + layout_x_gfs=8 + layout_y_gfs=8 + WRITE_GROUP_GFS=1 + WRTTASK_PER_GROUP_GFS=24 + #The settings below will result in S2SWA running 35 days under 8 hours wallclock on hera + #layout_x_gfs=24 + #layout_y_gfs=16 + #WRTTASK_PER_GROUP_GFS=86 + WRTIOBUF="32M" # TODO: This value is for P8 w/ C384. Why not update/set this as default in config.fv3 C384? + MEDPETS=300 # TODO: P8 wants to use 300 instead of ATMPETS = layout_x * layout_y * 6 + ;; +esac + +# config.ice + +# TODO: These also are likely P8 hard-wired configurations. Perhaps this file should be config.P8.defaults # config.wave - waveGRD='gwes_30m' waveinterpGRD=' ' waveuoutpGRD='gwes_30m' diff --git a/parm/config/config.fcst b/parm/config/config.fcst index 6a57a804a5..dcedf7ec2f 100644 --- a/parm/config/config.fcst +++ b/parm/config/config.fcst @@ -93,7 +93,7 @@ export h2o_phys=".true." # Options of stratosphere O3 physics reaction coefficients export new_o3forc="YES" -export gwd_opt=2 +export gwd_opt=2 # --GFS.v16 uGWD.v0, used for suite FV3_GFS_v16 and UFS p6 etc # do_ugwp=T: use unified CGWD and OGWD, and turbulent orographic form drag (TOFD) @@ -121,8 +121,8 @@ if [[ "$gwd_opt" -eq 2 ]]; then #export do_gsl_drag_ss=".true." #export do_gsl_drag_tofd=".true." #export do_ugwp_v1_orog_only=".false." - - #--used for UFS p8 + + #--used for UFS p8 export knob_ugwp_version=0 export do_ugwp=".false." export do_tofd=".false." @@ -272,7 +272,7 @@ export FSICS="0" export ideflate=1 export nbits=14 export ishuffle=0 -# compression for RESTART files written by FMS +# compression for RESTART files written by FMS export shuffle=1 export deflate_level=1 @@ -283,20 +283,16 @@ export USE_COUPLER_RES="NO" if [[ "$CDUMP" == "gdas" ]] ; then # GDAS cycle specific parameters # Variables used in DA cycling - if [[ "$QUILTING" = ".true." && "$OUTPUT_GRID" = "gaussian_grid" ]]; then - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_da" - else - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_da_orig" - fi + export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_da" - # Write restart files, where $number is current model start time. + # Write restart files, where $number is current model start time. # restart_interval: $number - # number=0, writes out restart files at the end of forecast. + # number=0, writes out restart files at the end of forecast. # number>0, writes out restart files at the frequency of $number and at the end of forecast. # restart_interval: "$number -1" # writes out restart files only once at $number forecast hour. # restart_interval: "$number1 $number2 $number3 ..." - # writes out restart file at the specified forecast hours + # writes out restart file at the specified forecast hours export restart_interval=${restart_interval:-6} # For IAU, write restarts at beginning of window also @@ -313,11 +309,7 @@ if [[ "$CDUMP" == "gdas" ]] ; then # GDAS cycle specific parameters elif [[ "$CDUMP" == "gfs" ]] ; then # GFS cycle specific parameters # Write more variables to output - if [[ "$QUILTING" = ".true." && $OUTPUT_GRID = "gaussian_grid" ]]; then - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table" - else - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_orig" - fi + export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table" # Write gfs restart files to rerun fcst from any break point export restart_interval_gfs=${restart_interval_gfs:-0} @@ -359,10 +351,6 @@ elif [[ "$CDUMP" == "gfs" ]] ; then # GFS cycle specific parameters fi -if [[ "$DO_COUPLED" = "YES" ]] ; then # coupled model - export DIAG_TABLE="$HOMEgfs/parm/parm_fv3diag/diag_table_cpl" -fi - if [[ "$DO_AERO" = "YES" ]]; then # temporary settings for aerosol coupling export AERO_DIAG_TABLE="${AERO_DIAG_TABLE:-$HOMEgfs/parm/parm_fv3diag/diag_table.aero}" export AERO_FIELD_TABLE="${AERO_FIELD_TABLE:-$HOMEgfs/parm/parm_fv3diag/field_table.aero}" diff --git a/parm/config/config.fv3 b/parm/config/config.fv3 index ce39807d11..1f6fea460d 100644 --- a/parm/config/config.fv3 +++ b/parm/config/config.fv3 @@ -45,18 +45,18 @@ fi # (Standard) Model resolution dependent variables case ${case_in} in "C48") - export DELTIM=450 - export layout_x=3 - export layout_y=2 - export layout_x_gfs=3 - export layout_y_gfs=2 + export DELTIM=1200 + export layout_x=1 + export layout_y=1 + export layout_x_gfs=1 + export layout_y_gfs=1 export nth_fv3=1 export nth_fv3_gfs=1 export cdmbgwd="0.071,2.1,1.0,1.0" # mountain blocking, ogwd, cgwd, cgwd src scaling export WRITE_GROUP=1 - export WRTTASK_PER_GROUP=64 + export WRTTASK_PER_GROUP=6 export WRITE_GROUP_GFS=1 - export WRTTASK_PER_GROUP_GFS=64 + export WRTTASK_PER_GROUP_GFS=6 export WRTIOBUF="1M" ;; "C96") diff --git a/parm/config/config.ice b/parm/config/config.ice old mode 100755 new mode 100644 index 3a6916600f..3b82a1468f --- a/parm/config/config.ice +++ b/parm/config/config.ice @@ -1,4 +1,17 @@ #! /usr/bin/env bash -export NX_GLB="1440" -export NY_GLB="1080" +case "${ICERES}" in + "025") + export NX_GLB="1440" + export NY_GLB="1080" + ;; + "500") + export NX_GLB="72" + export NY_GLB="35" + export cice_processor_shape="slenderX1" + ;; + *) + echo "FATAL ERROR: Unsupported ICERES = ${ICERES}, ABORT!" + exit 1 + ;; +esac diff --git a/parm/config/config.ocn b/parm/config/config.ocn old mode 100755 new mode 100644 index 4d24c0d87f..d224dd3267 --- a/parm/config/config.ocn +++ b/parm/config/config.ocn @@ -1,11 +1,7 @@ #! /usr/bin/env bash # OCNRES is currently being set in config.base -# case "$CASE" in -# "C48") export OCNRES=500;; -# "C96") export OCNRES=100;; -# "C192") export OCNRES=050;; -# "C384") export OCNRES=025;; -# "C768") export OCNRES=025;; -# *) export OCNRES=025;; -# esac + case "$CASE" in + "C48") export OCNTIM=3600;; + *) export OCNTIM=1800;; + esac diff --git a/parm/config/config.ocnanal b/parm/config/config.ocnanal old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalpost b/parm/config/config.ocnanalpost old mode 100755 new mode 100644 diff --git a/parm/config/config.ocnanalrun b/parm/config/config.ocnanalrun old mode 100755 new mode 100644 diff --git a/parm/config/config.resources b/parm/config/config.resources index 563b8e06de..ac2e407d12 100644 --- a/parm/config/config.resources +++ b/parm/config/config.resources @@ -391,7 +391,11 @@ elif [ ${step} = "gldas" ]; then elif [ ${step} = "fcst" ]; then - export wtime_fcst="00:40:00" + if [ ${CASE} = "C48" ]; then + export wtime_fcst="00:30:00" + else + export wtime_fcst="00:40:00" + fi if [ ${CASE} = "C768" ]; then export wtime_fcst_gfs="06:00:00" elif [ ${CASE} = "C384" ]; then @@ -458,6 +462,7 @@ elif [ ${step} = "fcst" ]; then if [[ ${DO_OCN} == "YES" ]]; then case ${OCNRES} in # Except for 025, these are guesses for now + 500) export OCNPETS=8 ;; 100) export OCNPETS=20 ;; 050) export OCNPETS=60 ;; 025) export OCNPETS=220 ;; @@ -472,6 +477,7 @@ elif [ ${step} = "fcst" ]; then if [[ ${DO_ICE} == "YES" ]]; then case ${ICERES} in # Except for 025, these are guesses for now + 500) export ICEPETS=4 ;; 100) export ICEPETS=10 ;; 050) export ICEPETS=30 ;; 025) export ICEPETS=120 ;; diff --git a/parm/config/config.sfcanl b/parm/config/config.sfcanl old mode 100755 new mode 100644 diff --git a/parm/mom6/MOM_input_template_500 b/parm/mom6/MOM_input_template_500 new file mode 100644 index 0000000000..2cae7e88a9 --- /dev/null +++ b/parm/mom6/MOM_input_template_500 @@ -0,0 +1,537 @@ +! This file was written by the model and records the non-default parameters used at run-time. + +! === module MOM === + +! === module MOM_unit_scaling === +! Parameters for doing unit scaling of variables. +USE_REGRIDDING = True ! [Boolean] default = False + ! If True, use the ALE algorithm (regridding/remapping). If False, use the + ! layered isopycnal algorithm. +THICKNESSDIFFUSE = True ! [Boolean] default = False + ! If true, interface heights are diffused with a coefficient of KHTH. +THICKNESSDIFFUSE_FIRST = True ! [Boolean] default = False + ! If true, do thickness diffusion before dynamics. This is only used if + ! THICKNESSDIFFUSE is true. +DT = @[DT_DYNAM_MOM6] ! [s] + ! The (baroclinic) dynamics time step. The time-step that is actually used will + ! be an integer fraction of the forcing time-step (DT_FORCING in ocean-only mode + ! or the coupling timestep in coupled mode.) +DT_THERM = @[DT_THERM_MOM6] ! [s] default = 1800.0 + ! The thermodynamic and tracer advection time step. Ideally DT_THERM should be + ! an integer multiple of DT and less than the forcing or coupling time-step, + ! unless THERMO_SPANS_COUPLING is true, in which case DT_THERM can be an integer + ! multiple of the coupling timestep. By default DT_THERM is set to DT. +THERMO_SPANS_COUPLING = False ! [Boolean] default = False + ! If true, the MOM will take thermodynamic and tracer timesteps that can be + ! longer than the coupling timestep. The actual thermodynamic timestep that is + ! used in this case is the largest integer multiple of the coupling timestep + ! that is less than or equal to DT_THERM. +HFREEZE = 20.0 ! [m] default = -1.0 + ! If HFREEZE > 0, melt potential will be computed. The actual depth + ! over which melt potential is computed will be min(HFREEZE, OBLD) + ! where OBLD is the boundary layer depth. If HFREEZE <= 0 (default) + ! melt potential will not be computed. +FRAZIL = True ! [Boolean] default = False + ! If true, water freezes if it gets too cold, and the accumulated heat deficit + ! is returned in the surface state. FRAZIL is only used if + ! ENABLE_THERMODYNAMICS is true. +BOUND_SALINITY = True ! [Boolean] default = False + ! If true, limit salinity to being positive. (The sea-ice model may ask for more + ! salt than is available and drive the salinity negative otherwise.) + +! === module MOM_domains === +TRIPOLAR_N = True ! [Boolean] default = False + ! Use tripolar connectivity at the northern edge of the domain. With + ! TRIPOLAR_N, NIGLOBAL must be even. +NIGLOBAL = @[NX_GLB] ! + ! The total number of thickness grid points in the x-direction in the physical + ! domain. With STATIC_MEMORY_ this is set in MOM_memory.h at compile time. +NJGLOBAL = @[NY_GLB] ! + ! The total number of thickness grid points in the y-direction in the physical + ! domain. With STATIC_MEMORY_ this is set in MOM_memory.h at compile time. + +! === module MOM_hor_index === +! Sets the horizontal array index types. + +! === module MOM_fixed_initialization === +INPUTDIR = "INPUT" ! default = "." + ! The directory in which input files are found. + +! === module MOM_grid_init === +GRID_CONFIG = "mosaic" ! + ! A character string that determines the method for defining the horizontal + ! grid. Current options are: + ! mosaic - read the grid from a mosaic (supergrid) + ! file set by GRID_FILE. + ! cartesian - use a (flat) Cartesian grid. + ! spherical - use a simple spherical grid. + ! mercator - use a Mercator spherical grid. +GRID_FILE = "ocean_hgrid.nc" ! + ! Name of the file from which to read horizontal grid data. +GRID_ROTATION_ANGLE_BUGS = False ! [Boolean] default = True + ! If true, use an older algorithm to calculate the sine and + ! cosines needed rotate between grid-oriented directions and + ! true north and east. Differences arise at the tripolar fold +USE_TRIPOLAR_GEOLONB_BUG = False ! [Boolean] default = True + ! If true, use older code that incorrectly sets the longitude in some points + ! along the tripolar fold to be off by 360 degrees. +TOPO_CONFIG = "file" ! + ! This specifies how bathymetry is specified: + ! file - read bathymetric information from the file + ! specified by (TOPO_FILE). + ! flat - flat bottom set to MAXIMUM_DEPTH. + ! bowl - an analytically specified bowl-shaped basin + ! ranging between MAXIMUM_DEPTH and MINIMUM_DEPTH. + ! spoon - a similar shape to 'bowl', but with an vertical + ! wall at the southern face. + ! halfpipe - a zonally uniform channel with a half-sine + ! profile in the meridional direction. + ! bbuilder - build topography from list of functions. + ! benchmark - use the benchmark test case topography. + ! Neverworld - use the Neverworld test case topography. + ! DOME - use a slope and channel configuration for the + ! DOME sill-overflow test case. + ! ISOMIP - use a slope and channel configuration for the + ! ISOMIP test case. + ! DOME2D - use a shelf and slope configuration for the + ! DOME2D gravity current/overflow test case. + ! Kelvin - flat but with rotated land mask. + ! seamount - Gaussian bump for spontaneous motion test case. + ! dumbbell - Sloshing channel with reservoirs on both ends. + ! shelfwave - exponential slope for shelfwave test case. + ! Phillips - ACC-like idealized topography used in the Phillips config. + ! dense - Denmark Strait-like dense water formation and overflow. + ! USER - call a user modified routine. +TOPO_FILE = "ocean_topog.nc" ! default = "topog.nc" + ! The file from which the bathymetry is read. +!MAXIMUM_DEPTH = 5801.341919389728 ! [m] + ! The (diagnosed) maximum depth of the ocean. +MINIMUM_DEPTH = 10.0 ! [m] default = 0.0 + ! If MASKING_DEPTH is unspecified, then anything shallower than MINIMUM_DEPTH is + ! assumed to be land and all fluxes are masked out. If MASKING_DEPTH is + ! specified, then all depths shallower than MINIMUM_DEPTH but deeper than + ! MASKING_DEPTH are rounded to MINIMUM_DEPTH. + +! === module MOM_open_boundary === +! Controls where open boundaries are located, what kind of boundary condition to impose, and what data to apply, +! if any. +MASKING_DEPTH = 0.0 ! [m] default = -9999.0 + ! The depth below which to mask points as land points, for which all fluxes are + ! zeroed out. MASKING_DEPTH is ignored if negative. + +! === module MOM_verticalGrid === +! Parameters providing information about the vertical grid. +NK = 25 ! [nondim] + ! The number of model layers. + +! === module MOM_tracer_registry === + +! === module MOM_EOS === +TFREEZE_FORM = "MILLERO_78" ! default = "LINEAR" + ! TFREEZE_FORM determines which expression should be used for the freezing + ! point. Currently, the valid choices are "LINEAR", "MILLERO_78", "TEOS10" + +! === module MOM_restart === +RESTART_CHECKSUMS_REQUIRED = False +! === module MOM_tracer_flow_control === + +! === module MOM_coord_initialization === +COORD_CONFIG = "file" ! default = "none" + ! This specifies how layers are to be defined: + ! ALE or none - used to avoid defining layers in ALE mode + ! file - read coordinate information from the file + ! specified by (COORD_FILE). + ! BFB - Custom coords for buoyancy-forced basin case + ! based on SST_S, T_BOT and DRHO_DT. + ! linear - linear based on interfaces not layers + ! layer_ref - linear based on layer densities + ! ts_ref - use reference temperature and salinity + ! ts_range - use range of temperature and salinity + ! (T_REF and S_REF) to determine surface density + ! and GINT calculate internal densities. + ! gprime - use reference density (RHO_0) for surface + ! density and GINT calculate internal densities. + ! ts_profile - use temperature and salinity profiles + ! (read from COORD_FILE) to set layer densities. + ! USER - call a user modified routine. +COORD_FILE = "layer_coord25.nc" ! + ! The file from which the coordinate densities are read. +REGRIDDING_COORDINATE_MODE = "HYCOM1" ! default = "LAYER" + ! Coordinate mode for vertical regridding. Choose among the following + ! possibilities: LAYER - Isopycnal or stacked shallow water layers + ! ZSTAR, Z* - stretched geopotential z* + ! SIGMA_SHELF_ZSTAR - stretched geopotential z* ignoring shelf + ! SIGMA - terrain following coordinates + ! RHO - continuous isopycnal + ! HYCOM1 - HyCOM-like hybrid coordinate + ! SLIGHT - stretched coordinates above continuous isopycnal + ! ADAPTIVE - optimize for smooth neutral density surfaces +BOUNDARY_EXTRAPOLATION = True ! [Boolean] default = False + ! When defined, a proper high-order reconstruction scheme is used within + ! boundary cells rather than PCM. E.g., if PPM is used for remapping, a PPM + ! reconstruction will also be used within boundary cells. +ALE_COORDINATE_CONFIG = "HYBRID:hycom1_25.nc,sigma2,FNC1:5,4000,4.5,.01" ! default = "UNIFORM" + ! Determines how to specify the coordinate + ! resolution. Valid options are: + ! PARAM - use the vector-parameter ALE_RESOLUTION + ! UNIFORM[:N] - uniformly distributed + ! FILE:string - read from a file. The string specifies + ! the filename and variable name, separated + ! by a comma or space, e.g. FILE:lev.nc,dz + ! or FILE:lev.nc,interfaces=zw + ! WOA09[:N] - the WOA09 vertical grid (approximately) + ! FNC1:string - FNC1:dz_min,H_total,power,precision + ! HYBRID:string - read from a file. The string specifies + ! the filename and two variable names, separated + ! by a comma or space, for sigma-2 and dz. e.g. + ! HYBRID:vgrid.nc,sigma2,dz +!ALE_RESOLUTION = 2*5.0, 5.01, 5.07, 5.25, 5.68, 6.55, 8.1, 10.66, 14.620000000000001, 20.450000000000003, 28.73, 40.1, 55.32, 75.23, 100.8, 133.09, 173.26, 222.62, 282.56, 354.62, 440.47, 541.87, 660.76, 799.1800000000001 ! [m] + ! The distribution of vertical resolution for the target + ! grid used for Eulerian-like coordinates. For example, + ! in z-coordinate mode, the parameter is a list of level + ! thicknesses (in m). In sigma-coordinate mode, the list + ! is of non-dimensional fractions of the water column. +!TARGET_DENSITIES = 1010.0, 1020.843017578125, 1027.0274658203125, 1029.279541015625, 1030.862548828125, 1032.1572265625, 1033.27978515625, 1034.251953125, 1034.850830078125, 1035.28857421875, 1035.651123046875, 1035.967529296875, 1036.2410888671875, 1036.473876953125, 1036.6800537109375, 1036.8525390625, 1036.9417724609375, 1037.0052490234375, 1037.057373046875, 1037.1065673828125, 1037.15576171875, 1037.2060546875, 1037.26416015625, 1037.3388671875, 1037.4749755859375, 1038.0 ! [m] + ! HYBRID target densities for itnerfaces +REGRID_COMPRESSIBILITY_FRACTION = 0.01 ! [not defined] default = 0.0 + ! When interpolating potential density profiles we can add + ! some artificial compressibility solely to make homogenous + ! regions appear stratified. +MAXIMUM_INT_DEPTH_CONFIG = "FNC1:5,8000.0,1.0,.125" ! default = "NONE" + ! Determines how to specify the maximum interface depths. + ! Valid options are: + ! NONE - there are no maximum interface depths + ! PARAM - use the vector-parameter MAXIMUM_INTERFACE_DEPTHS + ! FILE:string - read from a file. The string specifies + ! the filename and variable name, separated + ! by a comma or space, e.g. FILE:lev.nc,Z + ! FNC1:string - FNC1:dz_min,H_total,power,precision +!MAXIMUM_INT_DEPTHS = 0.0, 5.0, 36.25, 93.75, 177.5, 287.5, 423.75, 586.25, 775.0, 990.0, 1231.25, 1498.75, 1792.5, 2112.5, 2458.75, 2831.25, 3230.0, 3655.0, 4106.25, 4583.75, 5087.5, 5617.5, 6173.75, 6756.25, 7365.0, 8000.0 ! [m] + ! The list of maximum depths for each interface. +MAX_LAYER_THICKNESS_CONFIG = "FNC1:400,31000.0,0.1,.01" ! default = "NONE" + ! Determines how to specify the maximum layer thicknesses. + ! Valid options are: + ! NONE - there are no maximum layer thicknesses + ! PARAM - use the vector-parameter MAX_LAYER_THICKNESS + ! FILE:string - read from a file. The string specifies + ! the filename and variable name, separated + ! by a comma or space, e.g. FILE:lev.nc,Z + ! FNC1:string - FNC1:dz_min,H_total,power,precision +!MAX_LAYER_THICKNESS = 400.0, 1094.2, 1144.02, 1174.81, 1197.42, 1215.4099999999999, 1230.42, 1243.3200000000002, 1254.65, 1264.78, 1273.94, 1282.31, 1290.02, 1297.17, 1303.85, 1310.1, 1316.0, 1321.5700000000002, 1326.85, 1331.87, 1336.67, 1341.25, 1345.6399999999999, 1349.85, 1353.88 ! [m] + ! The list of maximum thickness for each layer. +REMAPPING_SCHEME = "PPM_H4" ! default = "PLM" + ! This sets the reconstruction scheme used for vertical remapping for all + ! variables. It can be one of the following schemes: PCM (1st-order + ! accurate) + ! PLM (2nd-order accurate) + ! PPM_H4 (3rd-order accurate) + ! PPM_IH4 (3rd-order accurate) + ! PQM_IH4IH3 (4th-order accurate) + ! PQM_IH6IH5 (5th-order accurate) + +! === module MOM_grid === +! Parameters providing information about the lateral grid. + +! === module MOM_state_initialization === +INIT_LAYERS_FROM_Z_FILE = True ! [Boolean] default = False + ! If true, initialize the layer thicknesses, temperatures, and salinities from a + ! Z-space file on a latitude-longitude grid. + +! === module MOM_initialize_layers_from_Z === +TEMP_SALT_Z_INIT_FILE = "" ! default = "temp_salt_z.nc" + ! The name of the z-space input file used to initialize + ! temperatures (T) and salinities (S). If T and S are not + ! in the same file, TEMP_Z_INIT_FILE and SALT_Z_INIT_FILE + ! must be set. +TEMP_Z_INIT_FILE = "woa18_decav_t00_01.nc" ! default = "" + ! The name of the z-space input file used to initialize + ! temperatures, only. +SALT_Z_INIT_FILE = "woa18_decav_s00_01.nc" ! default = "" + ! The name of the z-space input file used to initialize + ! temperatures, only. +Z_INIT_FILE_PTEMP_VAR = "t_an" ! default = "ptemp" + ! The name of the potential temperature variable in + ! TEMP_Z_INIT_FILE. +Z_INIT_FILE_SALT_VAR = "s_an" ! default = "salt" + ! The name of the salinity variable in + ! SALT_Z_INIT_FILE. +Z_INIT_ALE_REMAPPING = True ! [Boolean] default = False + ! If True, then remap straight to model coordinate from file. + +! === module MOM_diag_mediator === + +! === module MOM_MEKE === +USE_MEKE = True ! [Boolean] default = False + ! If true, turns on the MEKE scheme which calculates a sub-grid mesoscale eddy + ! kinetic energy budget. + +! === module MOM_lateral_mixing_coeffs === +USE_VARIABLE_MIXING = True ! [Boolean] default = False + ! If true, the variable mixing code will be called. This allows diagnostics to + ! be created even if the scheme is not used. If KHTR_SLOPE_CFF>0 or + ! KhTh_Slope_Cff>0, this is set to true regardless of what is in the parameter + ! file. +! === module MOM_set_visc === +CHANNEL_DRAG = True ! [Boolean] default = False + ! If true, the bottom drag is exerted directly on each layer proportional to the + ! fraction of the bottom it overlies. +HBBL = 10.0 ! [m] + ! The thickness of a bottom boundary layer with a viscosity of KVBBL if + ! BOTTOMDRAGLAW is not defined, or the thickness over which near-bottom + ! velocities are averaged for the drag law if BOTTOMDRAGLAW is defined but + ! LINEAR_DRAG is not. +KV = 1.0E-04 ! [m2 s-1] + ! The background kinematic viscosity in the interior. The molecular value, ~1e-6 + ! m2 s-1, may be used. + +! === module MOM_continuity === + +! === module MOM_continuity_PPM === + +! === module MOM_CoriolisAdv === +CORIOLIS_SCHEME = "SADOURNY75_ENSTRO" ! default = "SADOURNY75_ENERGY" + ! CORIOLIS_SCHEME selects the discretization for the Coriolis terms. Valid + ! values are: + ! SADOURNY75_ENERGY - Sadourny, 1975; energy cons. + ! ARAKAWA_HSU90 - Arakawa & Hsu, 1990 + ! SADOURNY75_ENSTRO - Sadourny, 1975; enstrophy cons. + ! ARAKAWA_LAMB81 - Arakawa & Lamb, 1981; En. + Enst. + ! ARAKAWA_LAMB_BLEND - A blend of Arakawa & Lamb with + ! Arakawa & Hsu and Sadourny energy +BOUND_CORIOLIS = True ! [Boolean] default = False + ! If true, the Coriolis terms at u-points are bounded by the four estimates of + ! (f+rv)v from the four neighboring v-points, and similarly at v-points. This + ! option would have no effect on the SADOURNY Coriolis scheme if it were + ! possible to use centered difference thickness fluxes. + +! === module MOM_PressureForce === + +! === module MOM_PressureForce_AFV === +MASS_WEIGHT_IN_PRESSURE_GRADIENT = True ! [Boolean] default = False + ! If true, use mass weighting when interpolating T/S for integrals near the + ! bathymetry in AFV pressure gradient calculations. + +! === module MOM_hor_visc === +LAPLACIAN = True ! [Boolean] default = False + ! If true, use a Laplacian horizontal viscosity. +KH_VEL_SCALE = 0.01 ! [m s-1] default = 0.0 + ! The velocity scale which is multiplied by the grid spacing to calculate the + ! Laplacian viscosity. The final viscosity is the largest of this scaled + ! viscosity, the Smagorinsky and Leith viscosities, and KH. +KH_SIN_LAT = 2000.0 ! [m2 s-1] default = 0.0 + ! The amplitude of a latitudinally-dependent background viscosity of the form + ! KH_SIN_LAT*(SIN(LAT)**KH_PWR_OF_SINE). +SMAGORINSKY_KH = True ! [Boolean] default = False + ! If true, use a Smagorinsky nonlinear eddy viscosity. +SMAG_LAP_CONST = 0.15 ! [nondim] default = 0.0 + ! The nondimensional Laplacian Smagorinsky constant, often 0.15. +AH_VEL_SCALE = 0.01 ! [m s-1] default = 0.0 + ! The velocity scale which is multiplied by the cube of the grid spacing to + ! calculate the biharmonic viscosity. The final viscosity is the largest of this + ! scaled viscosity, the Smagorinsky and Leith viscosities, and AH. +SMAGORINSKY_AH = True ! [Boolean] default = False + ! If true, use a biharmonic Smagorinsky nonlinear eddy viscosity. +SMAG_BI_CONST = 0.06 ! [nondim] default = 0.0 + ! The nondimensional biharmonic Smagorinsky constant, typically 0.015 - 0.06. +USE_LAND_MASK_FOR_HVISC = True ! [Boolean] default = False + ! If true, use Use the land mask for the computation of thicknesses at velocity + ! locations. This eliminates the dependence on arbitrary values over land or + ! outside of the domain. + +! === module MOM_vert_friction === +HMIX_FIXED = 0.5 ! [m] + ! The prescribed depth over which the near-surface viscosity and diffusivity are + ! elevated when the bulk mixed layer is not used. +MAXVEL = 6.0 ! [m s-1] default = 3.0E+08 + ! The maximum velocity allowed before the velocity components are truncated. + +! === module MOM_barotropic === +BOUND_BT_CORRECTION = True ! [Boolean] default = False + ! If true, the corrective pseudo mass-fluxes into the barotropic solver are + ! limited to values that require less than maxCFL_BT_cont to be accommodated. +BT_PROJECT_VELOCITY = True ! [Boolean] default = False + ! If true, step the barotropic velocity first and project out the velocity + ! tendency by 1+BEBT when calculating the transport. The default (false) is to + ! use a predictor continuity step to find the pressure field, and then to do a + ! corrector continuity step using a weighted average of the old and new + ! velocities, with weights of (1-BEBT) and BEBT. +DYNAMIC_SURFACE_PRESSURE = False ! [Boolean] default = False + ! If true, add a dynamic pressure due to a viscous ice shelf, for instance. +BEBT = 0.2 ! [nondim] default = 0.1 + ! BEBT determines whether the barotropic time stepping uses the forward-backward + ! time-stepping scheme or a backward Euler scheme. BEBT is valid in the range + ! from 0 (for a forward-backward treatment of nonrotating gravity waves) to 1 + ! (for a backward Euler treatment). In practice, BEBT must be greater than about + ! 0.05. +DTBT = -0.9 ! [s or nondim] default = -0.98 + ! The barotropic time step, in s. DTBT is only used with the split explicit time + ! stepping. To set the time step automatically based the maximum stable value + ! use 0, or a negative value gives the fraction of the stable value. Setting + ! DTBT to 0 is the same as setting it to -0.98. The value of DTBT that will + ! actually be used is an integer fraction of DT, rounding down. + +! === module MOM_mixed_layer_restrat === +MIXEDLAYER_RESTRAT = False ! [Boolean] default = False + ! If true, a density-gradient dependent re-stratifying flow is imposed in the + ! mixed layer. Can be used in ALE mode without restriction but in layer mode can + ! only be used if BULKMIXEDLAYER is true. +FOX_KEMPER_ML_RESTRAT_COEF = 60.0 ! [nondim] default = 0.0 + ! A nondimensional coefficient that is proportional to the ratio of the + ! deformation radius to the dominant lengthscale of the submesoscale mixed layer + ! instabilities, times the minimum of the ratio of the mesoscale eddy kinetic + ! energy to the large-scale geostrophic kinetic energy or 1 plus the square of + ! the grid spacing over the deformation radius, as detailed by Fox-Kemper et al. + ! (2010) +MLE_FRONT_LENGTH = 200.0 ! [m] default = 0.0 + ! If non-zero, is the frontal-length scale used to calculate the upscaling of + ! buoyancy gradients that is otherwise represented by the parameter + ! FOX_KEMPER_ML_RESTRAT_COEF. If MLE_FRONT_LENGTH is non-zero, it is recommended + ! to set FOX_KEMPER_ML_RESTRAT_COEF=1.0. +MLE_USE_PBL_MLD = True ! [Boolean] default = False + ! If true, the MLE parameterization will use the mixed-layer depth provided by + ! the active PBL parameterization. If false, MLE will estimate a MLD based on a + ! density difference with the surface using the parameter MLE_DENSITY_DIFF. +MLE_MLD_DECAY_TIME = 2.592E+06 ! [s] default = 0.0 + ! The time-scale for a running-mean filter applied to the mixed-layer depth used + ! in the MLE restratification parameterization. When the MLD deepens below the + ! current running-mean the running-mean is instantaneously set to the current + ! MLD. + +! === module MOM_diabatic_driver === +! The following parameters are used for diabatic processes. +ENERGETICS_SFC_PBL = True ! [Boolean] default = False + ! If true, use an implied energetics planetary boundary layer scheme to + ! determine the diffusivity and viscosity in the surface boundary layer. +EPBL_IS_ADDITIVE = False ! [Boolean] default = True + ! If true, the diffusivity from ePBL is added to all other diffusivities. + ! Otherwise, the larger of kappa-shear and ePBL diffusivities are used. + +! === module MOM_CVMix_KPP === +! This is the MOM wrapper to CVMix:KPP +! See http://cvmix.github.io/ + +! === module MOM_tidal_mixing === +! Vertical Tidal Mixing Parameterization + +! === module MOM_CVMix_conv === +! Parameterization of enhanced mixing due to convection via CVMix + +! === module MOM_set_diffusivity === + +! === module MOM_bkgnd_mixing === +! Adding static vertical background mixing coefficients +KD = 1.5E-05 ! [m2 s-1] default = 0.0 + ! The background diapycnal diffusivity of density in the interior. Zero or the + ! molecular value, ~1e-7 m2 s-1, may be used. +KD_MIN = 2.0E-06 ! [m2 s-1] default = 2.0E-07 + ! The minimum diapycnal diffusivity. +HENYEY_IGW_BACKGROUND = True ! [Boolean] default = False + ! If true, use a latitude-dependent scaling for the near surface background + ! diffusivity, as described in Harrison & Hallberg, JPO 2008. + +! === module MOM_kappa_shear === +! Parameterization of shear-driven turbulence following Jackson, Hallberg and Legg, JPO 2008 +USE_JACKSON_PARAM = True ! [Boolean] default = False + ! If true, use the Jackson-Hallberg-Legg (JPO 2008) shear mixing + ! parameterization. +MAX_RINO_IT = 25 ! [nondim] default = 50 + ! The maximum number of iterations that may be used to estimate the Richardson + ! number driven mixing. + +! === module MOM_CVMix_shear === +! Parameterization of shear-driven turbulence via CVMix (various options) + +! === module MOM_CVMix_ddiff === +! Parameterization of mixing due to double diffusion processes via CVMix + +! === module MOM_diabatic_aux === +! The following parameters are used for auxiliary diabatic processes. + +! === module MOM_energetic_PBL === +EPBL_USTAR_MIN = 1.45842E-18 ! [m s-1] + ! The (tiny) minimum friction velocity used within the ePBL code, derived from + ! OMEGA and ANGSTROM.. +USE_LA_LI2016 = True ! [nondim] default = False + ! A logical to use the Li et al. 2016 (submitted) formula to determine the + ! Langmuir number. +USE_WAVES = False ! [Boolean] default = False + ! If true, enables surface wave modules. + +! === module MOM_regularize_layers === + +! === module MOM_opacity === + +! === module MOM_tracer_advect === +TRACER_ADVECTION_SCHEME = "PPM:H3" ! default = "PLM" + ! The horizontal transport scheme for tracers: + ! PLM - Piecewise Linear Method + ! PPM:H3 - Piecewise Parabolic Method (Huyhn 3rd order) + ! PPM - Piecewise Parabolic Method (Colella-Woodward) + +! === module MOM_tracer_hor_diff === +KHTR = 50.0 ! [m2 s-1] default = 0.0 + ! The background along-isopycnal tracer diffusivity. +CHECK_DIFFUSIVE_CFL = True ! [Boolean] default = False + ! If true, use enough iterations the diffusion to ensure that the diffusive + ! equivalent of the CFL limit is not violated. If false, always use the greater + ! of 1 or MAX_TR_DIFFUSION_CFL iteration. +MAX_TR_DIFFUSION_CFL = 2.0 ! [nondim] default = -1.0 + ! If positive, locally limit the along-isopycnal tracer diffusivity to keep the + ! diffusive CFL locally at or below this value. The number of diffusive + ! iterations is often this value or the next greater integer. + +! === module MOM_neutral_diffusion === +! This module implements neutral diffusion of tracers +USE_NEUTRAL_DIFFUSION = True ! [Boolean] default = False + ! If true, enables the neutral diffusion module. + +! === module MOM_sum_output === +MAXTRUNC = 1000 ! [truncations save_interval-1] default = 0 + ! The run will be stopped, and the day set to a very large value if the velocity + ! is truncated more than MAXTRUNC times between energy saves. Set MAXTRUNC to 0 + ! to stop if there is any truncation of velocities. + +! === module ocean_model_init === +ODA_INCUPD = @[MOM_IAU] ! [Boolean] default = False + ! If true, oda incremental updates will be applied + ! everywhere in the domain. +ODA_INCUPD_FILE = "inc.nc" ! The name of the file with the T,S,h increments. + +ODA_TEMPINC_VAR = "Temp" ! default = "ptemp_inc" + ! The name of the potential temperature inc. variable in + ! ODA_INCUPD_FILE. +ODA_SALTINC_VAR = "Salt" ! default = "sal_inc" + ! The name of the salinity inc. variable in + ! ODA_INCUPD_FILE. +ODA_THK_VAR = "h" ! default = "h" + ! The name of the int. depth inc. variable in + ! ODA_INCUPD_FILE. +ODA_INCUPD_UV = false ! +!ODA_UINC_VAR = "u" ! default = "u_inc" + ! The name of the zonal vel. inc. variable in + ! ODA_INCUPD_UV_FILE. +!ODA_VINC_VAR = "v" ! default = "v_inc" + ! The name of the meridional vel. inc. variable in + ! ODA_INCUPD_UV_FILE. +ODA_INCUPD_NHOURS = @[MOM_IAU_HRS] ! default=3.0 + +! === module MOM_surface_forcing === +OCEAN_SURFACE_STAGGER = "A" ! default = "C" + ! A case-insensitive character string to indicate the + ! staggering of the surface velocity field that is + ! returned to the coupler. Valid values include + ! 'A', 'B', or 'C'. + +MAX_P_SURF = 0.0 ! [Pa] default = -1.0 + ! The maximum surface pressure that can be exerted by the atmosphere and + ! floating sea-ice or ice shelves. This is needed because the FMS coupling + ! structure does not limit the water that can be frozen out of the ocean and the + ! ice-ocean heat fluxes are treated explicitly. No limit is applied if a + ! negative value is used. +WIND_STAGGER = "A" ! default = "C" + ! A case-insensitive character string to indicate the + ! staggering of the input wind stress field. Valid + ! values are 'A', 'B', or 'C'. +! === module MOM_restart === + +! === module MOM_file_parser === diff --git a/parm/parm_fv3diag/diag_table b/parm/parm_fv3diag/diag_table index bcd9a882e4..8b7982a058 100644 --- a/parm/parm_fv3diag/diag_table +++ b/parm/parm_fv3diag/diag_table @@ -1,6 +1,83 @@ "fv3_history", 0, "hours", 1, "hours", "time" "fv3_history2d", 0, "hours", 1, "hours", "time" +"ocn%4yr%2mo%2dy%2hr", 6, "hours", 1, "hours", "time", 6, "hours", "1901 1 1 0 0 0" +"ocn_daily%4yr%2mo%2dy", 1, "days", 1, "days", "time", 1, "days", "1901 1 1 0 0 0" +############## +# Ocean fields +############## +# static fields +"ocean_model", "geolon", "geolon", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat", "geolat", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolon_c", "geolon_c", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat_c", "geolat_c", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolon_u", "geolon_u", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat_u", "geolat_u", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolon_v", "geolon_v", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat_v", "geolat_v", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +# "ocean_model", "depth_ocean", "depth_ocean", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +# "ocean_model", "wet", "wet", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "wet_c", "wet_c", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "wet_u", "wet_u", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "wet_v", "wet_v", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "sin_rot", "sin_rot", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "cos_rot", "cos_rot", "ocn%4yr%2mo%2dy%2hr", "all", .false., "none", 2 + +# ocean output TSUV and others +"ocean_model", "SSH", "SSH", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SST", "SST", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SSS", "SSS", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "speed", "speed", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SSU", "SSU", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "SSV", "SSV", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "frazil", "frazil", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "ePBL_h_ML", "ePBL", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "MLD_003", "MLD_003", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "MLD_0125", "MLD_0125", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 + +# Z-Space Fields Provided for CMIP6 (CMOR Names): +"ocean_model_z", "uo", "uo", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model_z", "vo", "vo", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model_z", "so", "so", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model_z", "temp", "temp", "ocn%4yr%2mo%2dy%2hr", "all", .true., "none", 2 + +# forcing +"ocean_model", "taux", "taux", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "tauy", "tauy", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "latent", "latent", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "sensible", "sensible", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "SW", "SW", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "LW", "LW", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "evap", "evap", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "lprec", "lprec", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "lrunoff", "lrunoff", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +# "ocean_model", "frunoff", "frunoff", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "fprec", "fprec", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "LwLatSens", "LwLatSens", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 +"ocean_model", "Heat_PmE", "Heat_PmE", "ocn%4yr%2mo%2dy%2hr","all",.true.,"none",2 + +# Daily fields +"ocean_model", "geolon", "geolon", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat", "geolat", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolon_c", "geolon_c", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat_c", "geolat_c", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolon_u", "geolon_u", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat_u", "geolat_u", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolon_v", "geolon_v", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "geolat_v", "geolat_v", "ocn_daily%4yr%2mo%2dy", "all", .false., "none", 2 +"ocean_model", "SST", "sst", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "latent", "latent", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "sensible", "sensible", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "SW", "SW", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "LW", "LW", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "evap", "evap", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "lprec", "lprec", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "taux", "taux", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 +"ocean_model", "tauy", "tauy", "ocn_daily%4yr%2mo%2dy", "all", .true., "none", 2 + +################### +# Atmosphere fields +################### "gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 "gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 "gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 diff --git a/parm/parm_fv3diag/diag_table_da b/parm/parm_fv3diag/diag_table_da index d040748237..5e5bc76e5e 100644 --- a/parm/parm_fv3diag/diag_table_da +++ b/parm/parm_fv3diag/diag_table_da @@ -1,5 +1,16 @@ "fv3_history", 0, "hours", 1, "hours", "time" "fv3_history2d", 0, "hours", 1, "hours", "time" +"ocn_da%4yr%2mo%2dy%2hr", 0, "hours", 1, "hours", "time", 1, "hours", "1901 1 1 0 0 0" + +"ocean_model", "geolon", "geolon", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "geolat", "geolat", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "SSH", "ave_ssh", "ocn_da%4yr%2mo%2dy%2hr", "all", .true., "none", 2 +"ocean_model", "MLD_0125", "MLD", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "u", "u", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "v", "v", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "h", "h", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "salt", "Salt", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 +"ocean_model", "temp", "Temp", "ocn_da%4yr%2mo%2dy%2hr", "all", .false., "none", 2 "gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 "gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 diff --git a/scripts/exglobal_forecast.sh b/scripts/exglobal_forecast.sh index 5130b6602e..04ec9667c6 100755 --- a/scripts/exglobal_forecast.sh +++ b/scripts/exglobal_forecast.sh @@ -154,7 +154,7 @@ echo "MAIN: Writing name lists and model configuration" case $RUN in 'data') DATM_nml;; 'gfs' | 'gdas' | 'gefs') FV3_GFS_nml;; -esac #no namelist for data atmosphere +esac [[ $cplflx = .true. ]] && MOM6_nml [[ $cplwav = .true. ]] && WW3_nml [[ $cplice = .true. ]] && CICE_nml @@ -178,29 +178,21 @@ if [ $esmf_profile ]; then export ESMF_RUNTIME_PROFILE_OUTPUT=SUMMARY fi -if [ $machine != 'sandbox' ]; then - $NCP $FCSTEXECDIR/$FCSTEXEC $DATA/. - export OMP_NUM_THREADS=$NTHREADS_FV3 - $APRUN_FV3 $DATA/$FCSTEXEC 1>&1 2>&2 - export ERR=$? - export err=$ERR - $ERRSCRIPT || exit $err -else - echo "MAIN: mpirun launch here" -fi +$NCP $FCSTEXECDIR/$FCSTEXEC $DATA/. +export OMP_NUM_THREADS=$NTHREADS_FV3 +$APRUN_FV3 $DATA/$FCSTEXEC 1>&1 2>&2 +export ERR=$? +export err=$ERR +$ERRSCRIPT || exit $err -if [ $machine != 'sandbox' ]; then - case $RUN in - 'data') data_out_Data_ATM;; - 'gfs' | 'gdas' | 'gefs') data_out_GFS;; - esac - [[ $cplflx = .true. ]] && MOM6_out - [[ $cplwav = .true. ]] && WW3_out - [[ $cplice = .true. ]] && CICE_out - [[ $esmf_profile = .true. ]] && CPL_out -else - echo "MAIN: Running on sandbox mode, no output linking" -fi +case $RUN in + 'data') data_out_Data_ATM;; + 'gfs' | 'gdas' | 'gefs') data_out_GFS;; +esac +[[ $cplflx = .true. ]] && MOM6_out +[[ $cplwav = .true. ]] && WW3_out +[[ $cplice = .true. ]] && CICE_out +[[ $esmf_profile = .true. ]] && CPL_out echo "MAIN: Output copied to COMROT" #------------------------------------------------------------------ diff --git a/ush/forecast_postdet.sh b/ush/forecast_postdet.sh index 153312308f..2db53c5c53 100755 --- a/ush/forecast_postdet.sh +++ b/ush/forecast_postdet.sh @@ -40,26 +40,27 @@ FV3_GFS_postdet(){ if [ $RERUN = "NO" ]; then #............................. - # Link all (except sfc_data) restart files from $gmemdir + # Link all restart files from $gmemdir for file in $(ls $gmemdir/RESTART/${sPDY}.${scyc}0000.*.nc); do file2=$(echo $(basename $file)) file2=$(echo $file2 | cut -d. -f3-) # remove the date from file fsuf=$(echo $file2 | cut -d. -f1) - if [ $fsuf != "sfc_data" ]; then - $NLN $file $DATA/INPUT/$file2 - fi + $NLN $file $DATA/INPUT/$file2 done - # Link sfcanl_data restart files from $memdir - for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.*.nc); do - file2=$(echo $(basename $file)) - file2=$(echo $file2 | cut -d. -f3-) # remove the date from file - fsufanl=$(echo $file2 | cut -d. -f1) - if [ $fsufanl = "sfcanl_data" ]; then - file2=$(echo $file2 | sed -e "s/sfcanl_data/sfc_data/g") - $NLN $file $DATA/INPUT/$file2 - fi - done + # Replace sfc_data with sfcanl_data restart files from $memdir (if found) + if [ "${MODE}" = "cycled" ] && [ "${CCPP_SUITE}" = "FV3_GFS_v16" ]; then # TODO: remove if statement when global_cycle can handle NOAHMP + for file in $(ls $memdir/RESTART/${sPDY}.${scyc}0000.sfcanl_data.tile?.nc); do + if [[ -f $file ]]; then + file2=$(echo $(basename $file)) + file2=$(echo $file2 | cut -d. -f3-) # remove the date from file + fsufanl=$(echo $file2 | cut -d. -f1) + file2=$(echo $file2 | sed -e "s/sfcanl_data/sfc_data/g") + rm -f $DATA/INPUT/$file2 + $NLN $file $DATA/INPUT/$file2 + fi + done + fi # Need a coupler.res when doing IAU if [ $DOIAU = "YES" ]; then @@ -139,14 +140,10 @@ EOF fi - if [ $machine = 'sandbox' ]; then - echo SUB ${FUNCNAME[0]}: Checking initial condition, overriden in sandbox mode! - else - nfiles=$(ls -1 $DATA/INPUT/* | wc -l) - if [ $nfiles -le 0 ]; then - echo SUB ${FUNCNAME[0]}: Initial conditions must exist in $DATA/INPUT, ABORT! - exit 1 - fi + nfiles=$(ls -1 $DATA/INPUT/* | wc -l) + if [ $nfiles -le 0 ]; then + echo SUB ${FUNCNAME[0]}: Initial conditions must exist in $DATA/INPUT, ABORT! + exit 1 fi # If doing IAU, change forecast hours @@ -260,7 +257,7 @@ EOF if [ $imp_physics -eq 8 ]; then $NLN $FIX_AM/CCN_ACTIVATE.BIN $DATA/CCN_ACTIVATE.BIN $NLN $FIX_AM/freezeH2O.dat $DATA/freezeH2O.dat - $NLN $FIX_AM/qr_acr_qg.dat $DATA/qr_acr_qg.dat + $NLN $FIX_AM/qr_acr_qg.dat $DATA/qr_acr_qg.dat $NLN $FIX_AM/qr_acr_qs.dat $DATA/qr_acr_qs.dat fi @@ -534,10 +531,6 @@ EOF FV3_GFS_nml(){ # namelist output for a certain component echo SUB ${FUNCNAME[0]}: Creating name lists and model configure file for FV3 - if [ $machine = 'sandbox' ]; then - cd $SCRIPTDIR - echo "MAIN: !!!Sandbox mode, writing to current directory!!!" - fi # Call child scripts in current script directory source $SCRIPTDIR/parsing_namelists_FV3.sh FV3_namelists @@ -609,19 +602,19 @@ WW3_postdet() { for wavGRD in ${grdALL}; do $NCP $ROTDIR/${CDUMP}.${PDY}/${cyc}/wave/rundata/${COMPONENTwave}.mod_def.$wavGRD $DATA/mod_def.$wavGRD done - else - #if shel, only 1 waveGRD which is linked to mod_def.ww3 + else + #if shel, only 1 waveGRD which is linked to mod_def.ww3 $NCP $ROTDIR/${CDUMP}.${PDY}/${cyc}/wave/rundata/${COMPONENTwave}.mod_def.$waveGRD $DATA/mod_def.ww3 fi #if wave mesh is not the same as the ocn/ice mesh, linkk it in the file comparemesh=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} - if [ "$MESH_WAV" = "$comparemesh" ]; then + if [ "$MESH_WAV" = "$comparemesh" ]; then echo "Wave is on same mesh as ocean/ice" - else + else $NLN -sf $FIXwave/$MESH_WAV $DATA/ - fi + fi export WAVHCYC=${WAVHCYC:-6} export WRDATE=$($NDATE -${WAVHCYC} $CDATE) @@ -637,35 +630,35 @@ WW3_postdet() { if [ $warm_start = ".true." -o $RERUN = "YES" ]; then if [ $RERUN = "NO" ]; then waverstfile=${WRDIR}/${sPDY}.${scyc}0000.restart.${wavGRD} - else + else waverstfile=${RSTDIR_WAVE}/${PDYT}.${cyct}0000.restart.${wavGRD} fi - else + else waverstfile=${RSTDIR_WAVE}/${sPDY}.${scyc}0000.restart.${wavGRD} fi if [ ! -f ${waverstfile} ]; then if [ $RERUN = "NO" ]; then echo "WARNING: NON-FATAL ERROR wave IC is missing, will start from rest" - else - echo "ERROR: Wave IC is missing in RERUN, exiting." - exit 1 - fi + else + echo "ERROR: Wave IC is missing in RERUN, exiting." + exit 1 + fi else if [ $waveMULTIGRID = ".true." ]; then $NLN ${waverstfile} $DATA/restart.${wavGRD} - else + else $NLN ${waverstfile} $DATA/restart.ww3 fi fi - done + done if [ $waveMULTIGRID = ".true." ]; then for wavGRD in $waveGRD ; do $NLN $datwave/${wavprfx}.log.${wavGRD}.${PDY}${cyc} log.${wavGRD} done - else - $NLN $datwave/${wavprfx}.log.${waveGRD}.${PDY}${cyc} log.ww3 - fi + else + $NLN $datwave/${wavprfx}.log.${waveGRD}.${PDY}${cyc} log.ww3 + fi if [ "$WW3ICEINP" = "YES" ]; then wavicefile=$COMINwave/rundata/${CDUMPwave}.${WAVEICE_FID}.${cycle}.ice @@ -691,7 +684,7 @@ WW3_postdet() { cd $DATA if [ $waveMULTIGRID = ".true." ]; then $NLN $datwave/${wavprfx}.log.mww3.${PDY}${cyc} log.mww3 - fi + fi # Loop for gridded output (uses FHINC) fhr=$FHMIN_WAV @@ -703,9 +696,9 @@ WW3_postdet() { for wavGRD in ${waveGRD} ; do $NLN $datwave/${wavprfx}.out_grd.${wavGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_grd.${wavGRD} done - else + else $NLN $datwave/${wavprfx}.out_grd.${waveGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_grd.ww3 - fi + fi FHINC=$FHOUT_WAV if [ $FHMAX_HF_WAV -gt 0 -a $FHOUT_HF_WAV -gt 0 -a $fhr -lt $FHMAX_HF_WAV ]; then FHINC=$FHOUT_HF_WAV @@ -721,9 +714,9 @@ WW3_postdet() { HMS="$(echo $YMDH | cut -c9-10)0000" if [ $waveMULTIGRID = ".true." ]; then $NLN $datwave/${wavprfx}.out_pnt.${waveuoutpGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_pnt.${waveuoutpGRD} - else + else $NLN $datwave/${wavprfx}.out_pnt.${waveuoutpGRD}.${YMD}.${HMS} $DATA/${YMD}.${HMS}.out_pnt.ww3 - fi + fi FHINC=$FHINCP_WAV fhr=$((fhr+FHINC)) @@ -736,11 +729,11 @@ WW3_nml() { if [ "${USE_WAV_RMP:-YES}" = "YES" ]; then if (( $( ls -1 $FIXwave/rmp_src_to_dst_conserv_* > /dev/null | wc -l) > 0 )); then for file in $(ls $FIXwave/rmp_src_to_dst_conserv_*) ; do - $NLN $file $DATA/ + $NLN $file $DATA/ done else - echo 'FATAL ERROR : No rmp precomputed nc files found for wave model' - exit 4 + echo 'FATAL ERROR : No rmp precomputed nc files found for wave model' + exit 4 fi fi source $SCRIPTDIR/parsing_namelists_WW3.sh @@ -762,10 +755,23 @@ CPL_out() { MOM6_postdet() { echo "SUB ${FUNCNAME[0]}: MOM6 after run type determination" - OCNRES=${OCNRES:-"025"} + OCNRES=${OCNRES:-"025"} # TODO: remove from here and lift higher # Copy MOM6 ICs - $NCP -pf $ICSDIR/$CDATE/ocn/MOM*nc $DATA/INPUT/ + if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res.nc" "${DATA}/INPUT/MOM.res.nc" + case $OCNRES in + "025") + for nn in $(seq 1 4); do + if [[ -f "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_${nn}.nc" ]]; then + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ocean/RESTART/${PDY}.${cyc}0000.MOM.res_${nn}.nc" "${DATA}/INPUT/MOM.res_${nn}.nc" + fi + done + ;; + esac + else + $NCP -pf "${ICSDIR}/${CDATE}"/ocn/MOM*.nc "${DATA}/INPUT/" # TODO: Update files in ICSDIR to reflect COM structure naming convention + fi # Copy MOM6 fixed files $NCP -pf $FIXmom/$OCNRES/* $DATA/INPUT/ @@ -779,12 +785,29 @@ MOM6_postdet() { exit 3 fi - # Copy mediator restart files to RUNDIR - if [ $warm_start = ".true." -o $RERUN = "YES" ]; then - $NCP $ROTDIR/$CDUMP.$PDY/$cyc/med/ufs.cpld*.nc $DATA/ - $NCP $ROTDIR/$CDUMP.$PDY/$cyc/med/rpointer.cpl $DATA/ + # Copy mediator restart file to RUNDIR # TODO: mediator should have its own CMEPS_postdet() function + if [[ "${warm_start}" = '.true.' ]]; then + local mediator_file="${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/med/RESTART/${PDY}.${cyc}0000.ufs.cpld.cpl.r.nc" + if [[ -f "${mediator_file}" ]]; then + $NLN "${mediator_file}" "${DATA}/ufs.cpld.cpl.r.nc" + rm -f "${DATA}/rpointer.cpl" + touch "${DATA}/rpointer.cpl" + echo "ufs.cpld.cpl.r.nc" >> "${DATA}/rpointer.cpl" + else + # We have a choice to make here. + # Either we can FATAL ERROR out, or we can let the coupling fields initialize from zero + # cmeps_run_type is determined based on the availability of the mediator restart file + echo "WARNING: ${mediator_file} does not exist for warm_start = .true., initializing!" + #echo "FATAL ERROR: ${mediator_file} must exist for warm_start = .true. and does not, ABORT!" + #exit 4 + fi + else + # This is a cold start, so initialize the coupling fields from zero + export cmeps_run_type="startup" fi + # If using stochatic parameterizations, create a seed that does not exceed the + # largest signed integer if [ $DO_OCN_SPPT = "YES" -o $DO_OCN_PERT_EPBL = "YES" ]; then if [ ${SET_STP_SEED:-"YES"} = "YES" ]; then ISEED_OCNSPPT=$(( (CDATE*1000 + MEMBER*10 + 6) % 2147483647 )) @@ -794,52 +817,119 @@ MOM6_postdet() { fi fi + # Create COMOUTocean + [[ ! -d $COMOUTocean ]] && mkdir -p $COMOUTocean + # Link output files + if [[ "${CDUMP}" = "gfs" ]]; then + # Link output files for CDUMP = gfs - export ENSMEM=${ENSMEM:-01} - export IDATE=$CDATE + # TODO: get requirements on what files need to be written out and what these dates here are and what they mean + export ENSMEM=${ENSMEM:-01} + export IDATE=$CDATE - [[ ! -d $COMOUTocean ]] && mkdir -p $COMOUTocean + fhrlst=$OUTPUT_FH - fhrlst=$OUTPUT_FH + for fhr in $fhrlst; do + if [ $fhr = 'anl' ]; then # Looking at OUTPUT_FH, this is never true, TODO: remove this block + continue + fi + if [ -z ${last_fhr:-} ]; then + last_fhr=$fhr + continue + fi + (( interval = fhr - last_fhr )) + (( midpoint = last_fhr + interval/2 )) + VDATE=$($NDATE $fhr $IDATE) + YYYY=$(echo $VDATE | cut -c1-4) + MM=$(echo $VDATE | cut -c5-6) + DD=$(echo $VDATE | cut -c7-8) + HH=$(echo $VDATE | cut -c9-10) + SS=$((10#$HH*3600)) + + VDATE_MID=$($NDATE $midpoint $IDATE) + YYYY_MID=$(echo $VDATE_MID | cut -c1-4) + MM_MID=$(echo $VDATE_MID | cut -c5-6) + DD_MID=$(echo $VDATE_MID | cut -c7-8) + HH_MID=$(echo $VDATE_MID | cut -c9-10) + SS_MID=$((10#$HH_MID*3600)) + + source_file="ocn_${YYYY_MID}_${MM_MID}_${DD_MID}_${HH_MID}.nc" + dest_file="ocn${VDATE}.${ENSMEM}.${IDATE}.nc" + ${NLN} ${COMOUTocean}/${dest_file} ${DATA}/${source_file} + + source_file="ocn_daily_${YYYY}_${MM}_${DD}.nc" + dest_file=${source_file} + if [ ! -a "${DATA}/${source_file}" ]; then + $NLN ${COMOUTocean}/${dest_file} ${DATA}/${source_file} + fi - for fhr in $fhrlst; do - if [ $fhr = 'anl' ]; then - continue - fi - if [ -z ${last_fhr:-} ]; then last_fhr=$fhr - continue - fi - (( interval = fhr - last_fhr )) - (( midpoint = last_fhr + interval/2 )) - VDATE=$($NDATE $fhr $IDATE) - YYYY=$(echo $VDATE | cut -c1-4) - MM=$(echo $VDATE | cut -c5-6) - DD=$(echo $VDATE | cut -c7-8) - HH=$(echo $VDATE | cut -c9-10) - SS=$((10#$HH*3600)) + done - VDATE_MID=$($NDATE $midpoint $IDATE) - YYYY_MID=$(echo $VDATE_MID | cut -c1-4) - MM_MID=$(echo $VDATE_MID | cut -c5-6) - DD_MID=$(echo $VDATE_MID | cut -c7-8) - HH_MID=$(echo $VDATE_MID | cut -c9-10) - SS_MID=$((10#$HH_MID*3600)) - - source_file="ocn_${YYYY_MID}_${MM_MID}_${DD_MID}_${HH_MID}.nc" - dest_file="ocn${VDATE}.${ENSMEM}.${IDATE}.nc" - ${NLN} ${COMOUTocean}/${dest_file} ${DATA}/${source_file} - - source_file="ocn_daily_${YYYY}_${MM}_${DD}.nc" - dest_file=${source_file} - if [ ! -a "${DATA}/${source_file}" ]; then - $NLN ${COMOUTocean}/${dest_file} ${DATA}/${source_file} - fi + elif [[ "${CDUMP}" = "gdas" ]]; then + # Link output files for CDUMP = gdas + + # MOM6 does not write out the first forecast hour, so start at FHOUT + local fhr="${FHOUT}" + while [[ "${fhr}" -le "${FHMAX}" ]]; do + local idatestr=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${fhr} hours" +%Y_%m_%d_%H) + local fhr3=$(printf %03i ${fhr}) + $NLN "${COMOUTocean}/${CDUMP}.t${cyc}z.ocnf${fhr3}.nc" "${DATA}/ocn_da_${idatestr}.nc" + local fhr=$((fhr + FHOUT)) + done + + fi - last_fhr=$fhr + mkdir -p "${COMOUTocean}/RESTART" + + # end point restart does not have a timestamp, calculate + local rdate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${FHMAX} hours" +%Y%m%d%H) + + # Link ocean restarts from DATA to COM + # Coarser than 1/2 degree has a single MOM restart + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.nc" + # 1/4 degree resolution has 4 additional restarts + case ${OCNRES} in + "025") + for nn in $(seq 1 4); do + $NLN "${COMOUTocean}/RESTART/${rdate:0:8}.${rdate:8:2}0000.MOM.res_${nn}.nc" "${DATA}/MOM6_RESTART/MOM.res_${nn}.nc" + done + ;; + *) + ;; + esac + + # Loop over restart_interval frequency and link restarts from DATA to COM + local res_int=$(echo $restart_interval | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) + while [[ $idate -lt $rdate ]]; do + local idatestr=$(date +%Y-%m-%d-%H -d "${idate:0:8} ${idate:8:2}") + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res.nc" "${DATA}/MOM6_RESTART/MOM.res.${idatestr}-00-00.nc" + case ${OCNRES} in + "025") + for nn in $(seq 1 4); do + $NLN "${COMOUTocean}/RESTART/${idate:0:8}.${idate:8:2}0000.MOM.res_${nn}.nc" "${DATA}/MOM6_RESTART/MOM.res_${nn}.${idatestr}-00-00.nc" + done + ;; + esac + local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) done - $NLN ${COMOUTocean}/MOM_input $DATA/INPUT/MOM_input + + # TODO: mediator should have its own CMEPS_postdet() function + # Link mediator restarts from DATA to COM + # DANGER DANGER DANGER - Linking mediator restarts to COM causes the model to fail with a message like this below: + # Abort with message NetCDF: File exists && NC_NOCLOBBER in file pio-2.5.7/src/clib/pioc_support.c at line 2173 + # Instead of linking, copy the mediator files after the model finishes + #local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" + #mkdir -p "${COMOUTmed}/RESTART" + #local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) + #while [[ $idate -le $rdate ]]; do + # local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + # local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + # $NLN "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" + # local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) + #done echo "SUB ${FUNCNAME[0]}: MOM6 input data linked/copied" @@ -853,24 +943,57 @@ MOM6_nml() { MOM6_out() { echo "SUB ${FUNCNAME[0]}: Copying output data for MOM6" + + # Copy MOM_input from DATA to COMOUToucean after the forecast is run (and successfull) + $NCP ${DATA}/INPUT/MOM_input ${COMOUTocean}/MOM_input + + # TODO: mediator should have its own CMEPS_out() function + # Copy mediator restarts from DATA to COM + # Linking mediator restarts to COM causes the model to fail with a message. + # See MOM6_postdet() function for error message + local COMOUTmed="${ROTDIR}/${CDUMP}.${PDY}/${cyc}/med" + mkdir -p "${COMOUTmed}/RESTART" + local res_int=$(echo $restart_interval | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) + local rdate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${FHMAX} hours" +%Y%m%d%H) + while [[ $idate -le $rdate ]]; do + local seconds=$(to_seconds ${idate:8:2}0000) # use function to_seconds from forecast_predet.sh to convert HHMMSS to seconds + local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + local mediator_file="${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" + if [[ -f ${mediator_file} ]]; then + $NCP "${DATA}/RESTART/ufs.cpld.cpl.r.${idatestr}.nc" "${COMOUTmed}/RESTART/${idate:0:8}.${idate:8:2}0000.ufs.cpld.cpl.r.nc" + else + echo "Mediator restart ${mediator_file} not found." + fi + local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) + done } CICE_postdet() { echo "SUB ${FUNCNAME[0]}: CICE after run type determination" + # TODO: move configuration settings to config.ice + + # TODO: These need to be calculated in the parsing_namelists_CICE.sh script CICE_namelists() function and set as local year=$(echo $CDATE|cut -c 1-4) month=$(echo $CDATE|cut -c 5-6) day=$(echo $CDATE|cut -c 7-8) - sec=$(echo $CDATE|cut -c 9-10) + sec=$(echo $CDATE|cut -c 9-10) stepsperhr=$((3600/$ICETIM)) nhours=$($NHOUR $CDATE ${year}010100) steps=$((nhours*stepsperhr)) npt=$((FHMAX*$stepsperhr)) # Need this in order for dump_last to work + # TODO: These settings should be elevated to config.ice histfreq_n=${histfreq_n:-6} - dumpfreq_n=${dumpfreq_n:-840} # restart write interval in seconds, default 35 days - dumpfreq=${dumpfreq:-"h"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" - cice_hist_avg=${cice_hist_avg:-".true."} + dumpfreq_n=${dumpfreq_n:-1000} # Set this to a really large value, as cice, mom6 and cmeps restart interval is controlled by nems.configure + dumpfreq=${dumpfreq:-"y"} # "h","d","m" or "y" for restarts at intervals of "hours", "days", "months" or "years" + + if [[ "${CDUMP}" == "gdas" ]]; then + cice_hist_avg=".false." # DA needs instantaneous + elif [[ "${CDUMP}" == "gfs" ]]; then + cice_hist_avg=".true." # P8 wants averaged over histfreq_n + fi FRAZIL_FWSALT=${FRAZIL_FWSALT:-".true."} ktherm=${ktherm:-2} @@ -880,68 +1003,96 @@ CICE_postdet() { # restart_pond_lvl (if tr_pond_lvl=true): # -- if true, initialize the level ponds from restart (if runtype=continue) # -- if false, re-initialize level ponds to zero (if runtype=initial or continue) - - #TODO: Determine the proper way to determine if it's a 'hot start' or not - #note this is not mediator cold start or not - #if [ hotstart ]; then - # #continuing run "hot start" - # RUNTYPE='continue' - # USE_RESTART_TIME='.true.' - #fi - RUNTYPE='initial' - USE_RESTART_TIME='.false.' restart_pond_lvl=${restart_pond_lvl:-".false."} - ICERES=${ICERES:-"025"} - if [ $ICERES = '025' ]; then - ICERESdec="0.25" - fi - if [ $ICERES = '050' ]; then - ICERESdec="0.50" - fi - if [ $ICERES = '100' ]; then - ICERESdec="1.00" - fi + ICERES=${ICERES:-"025"} # TODO: similar to MOM_out, lift this higher ice_grid_file=${ice_grid_file:-"grid_cice_NEMS_mx${ICERES}.nc"} ice_kmt_file=${ice_kmt_file:-"kmtu_cice_NEMS_mx${ICERES}.nc"} export MESH_OCN_ICE=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} - iceic="cice_model.res_$CDATE.nc" - - # Copy CICE IC - $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/$iceic + # Copy/link CICE IC to DATA + if [[ "${MODE}" = 'cycled' ]]; then # TODO: remove this block after ICSDIR is corrected for forecast-only + $NLN "${ROTDIR}/${CDUMP}.${gPDY}/${gcyc}/ice/RESTART/${PDY}.${cyc}0000.cice_model.res.nc" "${DATA}/cice_model.res.nc" + else + ICERESdec=$(echo "${ICERES}" | awk '{printf "%0.2f", $1/100}') + $NCP -p $ICSDIR/$CDATE/ice/cice_model_${ICERESdec}.res_$CDATE.nc $DATA/cice_model.res.nc + fi + # TODO: add a check for the restarts to exist, if not, exit eloquently + rm -f "${DATA}/ice.restart_file" + touch "${DATA}/ice.restart_file" + echo "${DATA}/cice_model.res.nc" >> "${DATA}/ice.restart_file" echo "Link CICE fixed files" $NLN -sf $FIXcice/$ICERES/${ice_grid_file} $DATA/ $NLN -sf $FIXcice/$ICERES/${ice_kmt_file} $DATA/ $NLN -sf $FIXcice/$ICERES/$MESH_OCN_ICE $DATA/ - # Link output files - export ENSMEM=${ENSMEM:-01} - export IDATE=$CDATE + # Link CICE output files [[ ! -d $COMOUTice ]] && mkdir -p $COMOUTice - $NLN $COMOUTice/ice_in $DATA/ice_in - fhrlst=$OUTPUT_FH + mkdir -p ${COMOUTice}/RESTART - for fhr in $fhrlst; do - if [ $fhr = 'anl' ]; then - continue - fi - VDATE=$($NDATE $fhr $IDATE) - YYYY=$(echo $VDATE | cut -c1-4) - MM=$(echo $VDATE | cut -c5-6) - DD=$(echo $VDATE | cut -c7-8) - HH=$(echo $VDATE | cut -c9-10) - SS=$((10#$HH*3600)) + if [[ "${CDUMP}" = "gfs" ]]; then + # Link output files for CDUMP = gfs - if [[ 10#$fhr -eq 0 ]]; then - $NLN $COMOUTice/iceic$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_ic.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc - else - (( interval = fhr - last_fhr )) - $NLN $COMOUTice/ice$VDATE.$ENSMEM.$IDATE.nc $DATA/history/iceh_$(printf "%0.2d" $interval)h.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc - fi - last_fhr=$fhr + # TODO: make these forecast output files consistent w/ GFS output + # TODO: Work w/ NB to determine appropriate naming convention for these files + + export ENSMEM=${ENSMEM:-01} + export IDATE=$CDATE + + fhrlst=$OUTPUT_FH + + # TODO: consult w/ NB on how to improve on this. Gather requirements and more information on what these files are and how they are used to properly catalog them + for fhr in $fhrlst; do + if [ $fhr = 'anl' ]; then # Looking at OUTPUT_FH, this is never true. TODO: remove this block + continue + fi + VDATE=$($NDATE $fhr $IDATE) + YYYY=$(echo $VDATE | cut -c1-4) + MM=$(echo $VDATE | cut -c5-6) + DD=$(echo $VDATE | cut -c7-8) + HH=$(echo $VDATE | cut -c9-10) + SS=$((10#$HH*3600)) + + if [[ 10#$fhr -eq 0 ]]; then + $NLN $COMOUTice/iceic$VDATE.$ENSMEM.$IDATE.nc $DATA/CICE_OUTPUT/iceh_ic.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc + else + (( interval = fhr - last_fhr )) # Umm.. isn't this histfreq_n? + $NLN $COMOUTice/ice$VDATE.$ENSMEM.$IDATE.nc $DATA/CICE_OUTPUT/iceh_$(printf "%0.2d" $interval)h.${YYYY}-${MM}-${DD}-$(printf "%5.5d" ${SS}).nc + fi + last_fhr=$fhr + done + + elif [[ "${CDUMP}" = "gdas" ]]; then + + # Link CICE generated initial condition file from DATA/CICE_OUTPUT to COMOUTice + # This can be thought of as the f000 output from the CICE model + local seconds=$(to_seconds ${CDATE:8:2}0000) # convert HHMMSS to seconds + $NLN "${COMOUTice}/${CDUMP}.t${cyc}z.iceic.nc" "${DATA}/CICE_OUTPUT/iceh_ic.${CDATE:0:4}-${CDATE:4:2}-${CDATE:6:2}-${seconds}.nc" + + # Link instantaneous CICE forecast output files from DATA/CICE_OUTPUT to COMOUTice + local fhr="${FHOUT}" + while [[ "${fhr}" -le "${FHMAX}" ]]; do + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${fhr} hours" +%Y%m%d%H) + local seconds=$(to_seconds ${idate:8:2}0000) # convert HHMMSS to seconds + local fhr3=$(printf %03i ${fhr}) + $NLN "${COMOUTice}/${CDUMP}.t${cyc}z.icef${fhr3}.nc" "${DATA}/CICE_OUTPUT/iceh_inst.${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}.nc" + local fhr=$((fhr + FHOUT)) + done + + fi + + # Link CICE restarts from CICE_RESTART to COMOUTice/RESTART + # Loop over restart_interval and link restarts from DATA to COM + local res_int=$(echo ${restart_interval} | cut -d' ' -f1) # If this is a list, get the frequency. # This is bound to break w/ IAU + local rdate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${FHMAX} hours" +%Y%m%d%H) + local idate=$(date -d "${CDATE:0:8} ${CDATE:8:2} + ${res_int} hours" +%Y%m%d%H) + while [[ ${idate} -le ${rdate} ]]; do + local seconds=$(to_seconds ${idate:8:2}0000) # convert HHMMSS to seconds + local idatestr="${idate:0:4}-${idate:4:2}-${idate:6:2}-${seconds}" + $NLN "${COMOUTice}/RESTART/${idate:0:8}.${idate:8:2}0000.cice_model.res.nc" "${DATA}/CICE_RESTART/cice_model.res.${idatestr}.nc" + local idate=$(date -d "${idate:0:8} ${idate:8:2} + ${res_int} hours" +%Y%m%d%H) done } @@ -953,6 +1104,9 @@ CICE_nml() { CICE_out() { echo "SUB ${FUNCNAME[0]}: Copying output data for CICE" + + # Copy ice_in namelist from DATA to COMOUTice after the forecast is run (and successfull) + $NCP ${DATA}/ice_in $COMOUTice/ice_in } GOCART_rc() { diff --git a/ush/forecast_predet.sh b/ush/forecast_predet.sh index b7c1ed7388..cebdc50e16 100755 --- a/ush/forecast_predet.sh +++ b/ush/forecast_predet.sh @@ -10,6 +10,29 @@ # For all non-evironment variables # Cycling and forecast hour specific parameters + +to_seconds() { + # Function to convert HHMMSS to seconds since 00Z + local hhmmss=${1:?} + local hh=${hhmmss:0:2} + local mm=${hhmmss:2:2} + local ss=${hhmmss:4:2} + local seconds=$((10#${hh}*3600+10#${mm}*60+10#${ss})) + local padded_seconds=$(printf "%05d" ${seconds}) + echo ${padded_seconds} +} + +middle_date(){ + # Function to calculate mid-point date in YYYYMMDDHH between two dates also in YYYYMMDDHH + local date1=${1:?} + local date2=${2:?} + local date1s=$(date -d "${date1:0:8} ${date1:8:2}" +%s) + local date2s=$(date -d "${date2:0:8} ${date2:8:2}" +%s) + local dtsecsby2=$(( $((date2s - date1s)) / 2 )) + local mid_date=$(date -d "${date1:0:8} ${date1:8:2} + ${dtsecsby2} seconds" +%Y%m%d%H%M%S) + echo ${mid_date:0:10} +} + common_predet(){ echo "SUB ${FUNCNAME[0]}: Defining variables for shared through models" pwd=$(pwd) @@ -276,24 +299,12 @@ WW3_predet(){ CICE_predet(){ echo "SUB ${FUNCNAME[0]}: CICE before run type determination" - if [ ! -d $ROTDIR ]; then mkdir -p $ROTDIR; fi - if [ ! -d $DATA ]; then mkdir -p $DATA; fi - if [ ! -d $DATA/RESTART ]; then mkdir -p $DATA/RESTART; fi - if [ ! -d $DATA/INPUT ]; then mkdir -p $DATA/INPUT; fi - if [ ! -d $DATA/restart ]; then mkdir -p $DATA/restart; fi - if [ ! -d $DATA/history ]; then mkdir -p $DATA/history; fi - if [ ! -d $DATA/OUTPUT ]; then mkdir -p $DATA/OUTPUT; fi + if [ ! -d $DATA/CICE_OUTPUT ]; then mkdir -p $DATA/CICE_OUTPUT; fi + if [ ! -d $DATA/CICE_RESTART ]; then mkdir -p $DATA/CICE_RESTART; fi } MOM6_predet(){ echo "SUB ${FUNCNAME[0]}: MOM6 before run type determination" - if [ ! -d $ROTDIR ]; then mkdir -p $ROTDIR; fi - if [ ! -d $DATA ]; then mkdir -p $DATA; fi - if [ ! -d $DATA/RESTART ]; then mkdir -p $DATA/RESTART; fi - if [ ! -d $DATA/INPUT ]; then mkdir -p $DATA/INPUT; fi - if [ ! -d $DATA/restart ]; then mkdir -p $DATA/restart; fi - if [ ! -d $DATA/history ]; then mkdir -p $DATA/history; fi - if [ ! -d $DATA/OUTPUT ]; then mkdir -p $DATA/OUTPUT; fi if [ ! -d $DATA/MOM6_OUTPUT ]; then mkdir -p $DATA/MOM6_OUTPUT; fi if [ ! -d $DATA/MOM6_RESTART ]; then mkdir -p $DATA/MOM6_RESTART; fi cd "${DATA}" || exit 8 diff --git a/ush/nems_configure.sh b/ush/nems_configure.sh index 04fea90f35..c49d35a2c0 100755 --- a/ush/nems_configure.sh +++ b/ush/nems_configure.sh @@ -19,7 +19,11 @@ fi # Setup nems.configure DumpFields=${NEMSDumpFields:-false} cap_dbug_flag=${cap_dbug_flag:-0} -if [ $warm_start = ".true." ]; then +# Determine "cmeps_run_type" based on the availability of the mediator restart file +# If it is a warm_start, we already copied the mediator restart to DATA, if it was present +# If the mediator restart was not present, despite being a "warm_start", we put out a WARNING +# in forecast_postdet.sh +if [[ -f "${DATA}/ufs.cpld.cpl.r.nc" ]]; then cmeps_run_type='continue' else cmeps_run_type='startup' @@ -42,11 +46,11 @@ CHMPETS=${CHMPETS:-${ATMPETS}} USE_MOMMESH=${USE_MOMMESH:-"true"} MESH_OCN_ICE=${MESH_OCN_ICE:-"mesh.mx${ICERES}.nc"} -if [[ $OCNRES = "100" ]]; then - EPS_IMESH='2.5e-1' -else - EPS_IMESH='1.0e-1' -fi +case "${OCNRES}" in + "500") EPS_IMESH="4.0e-1";; + "100") EPS_IMESH="2.5e-1";; + *) EPS_IMESH="1.0e-1";; +esac rm -f $DATA/nems.configure diff --git a/ush/parsing_namelists_CICE.sh b/ush/parsing_namelists_CICE.sh index 64a711bffc..90f60c5719 100755 --- a/ush/parsing_namelists_CICE.sh +++ b/ush/parsing_namelists_CICE.sh @@ -4,12 +4,43 @@ CICE_namelists(){ -if [ $warm_start = ".true." ]; then - cmeps_run_type='continue' +# "warm_start" here refers to whether CICE model is warm starting or not. +# Per JM, in the case of the Prototypes, the sea-ice ICs were obtained from CPC. +# CPC sea-ice initial conditions are created from SIS2 sea-ice model. +# Hence, the prototypes always set this to "initial" +# in order for the CICE model to _initialize_ from the SIS2 ICs. +# However, in the SOCA cycled system, if starting from a previously cycled SOCA run, +# the CICE ICs are obtained from the previous cycle of the UFS S2S, +# so the CICE namelist should be set to "continue" +# TODO: Is there a way to interrogate the restart file to know if this is a +# SIS2 restart or a CICE restart, instead of relying on "${warm_start}" +if [[ "${warm_start}" = ".true." ]]; then + local runtype="continue" + local use_restart_time=".true." else - cmeps_run_type='initial' + local runtype="initial" + local use_restart_time=".false." fi +# Get correct MPI options for NPROC and grid +local cice_processor_shape=${cice_processor_shape:-'slenderX2'} +local shape=${cice_processor_shape#${cice_processor_shape%?}} +local NPX=$(( ICEPETS / shape )) #number of processors in x direction +local NPY=$(( ICEPETS / NPX )) #number of processors in y direction +if (( $(( NX_GLB % NPX )) == 0 )); then + local block_size_x=$(( NX_GLB / NPX )) +else + local block_size_x=$(( (NX_GLB / NPX) + 1 )) +fi +if (( $(( NY_GLB % NPY )) == 0 )); then + local block_size_y=$(( NY_GLB / NPY )) +else + local block_size_y=$(( (NY_GLB / NPY) + 1 )) +fi +local max_blocks=$(( (NX_GLB * NY_GLB) / (block_size_x * block_size_y * ICEPETS) )) +if (( max_blocks == 0 )) || (( max_blocks % 2 != 0 )); then + local max_blocks=-1 +fi cat > ice_in < ice_in < ice_in < ice_in <> input.nml < $DATA/INPUT/MOM_input + -e "s/@\[MOM_IAU_HRS\]/$MOM_IAU_HRS/g" \ + -e "s/@\[MOM_IAU\]/$MOM_IAU/g" $DATA/INPUT/MOM_input_template_$OCNRES > $DATA/INPUT/MOM_input rm $DATA/INPUT/MOM_input_template_$OCNRES #data table for runoff: diff --git a/workflow/applications.py b/workflow/applications.py index 11bea0a447..c1c784a448 100644 --- a/workflow/applications.py +++ b/workflow/applications.py @@ -183,6 +183,7 @@ def _cycled_configs(self): if self.do_jediocnvar: configs += ['ocnanalprep', 'ocnanalbmat', 'ocnanalrun', 'ocnanalpost'] + if self.do_ocean: configs += ['ocnpost'] configs += ['sfcanl', 'analcalc', 'fcst', 'post', 'vrfy', 'arch'] @@ -345,7 +346,10 @@ def _get_cycled_task_names(self): """ gdas_gfs_common_tasks_before_fcst = ['prep'] - gdas_gfs_common_tasks_after_fcst = ['post', 'vrfy'] + gdas_gfs_common_tasks_after_fcst = ['post'] + # if self.do_ocean: # TODO: uncomment when ocnpost is fixed in cycled mode + # gdas_gfs_common_tasks_after_fcst += ['ocnpost'] + gdas_gfs_common_tasks_after_fcst += ['vrfy'] gdas_gfs_common_cleanup_tasks = ['arch'] @@ -444,7 +448,12 @@ def _get_cycled_task_names(self): gfs_tasks += gdas_gfs_common_cleanup_tasks - tasks = {'gdas': gdas_tasks, 'gfs': gfs_tasks} + tasks = dict() + tasks['gdas'] = gdas_tasks + + # Add CDUMP=gfs tasks if running early cycle + if self.gfs_cyc > 0: + tasks['gfs'] = gfs_tasks return tasks diff --git a/workflow/rocoto/workflow_tasks.py b/workflow/rocoto/workflow_tasks.py index e375c3f908..6e560dfb5b 100644 --- a/workflow/rocoto/workflow_tasks.py +++ b/workflow/rocoto/workflow_tasks.py @@ -684,7 +684,8 @@ def post(self): return self._post_task('post', add_anl_to_post=add_anl_to_post) def ocnpost(self): - return self._post_task('ocnpost', add_anl_to_post=False) + if self.app_config.mode in ['forecast-only']: # TODO: fix ocnpost in cycled mode + return self._post_task('ocnpost', add_anl_to_post=False) def _post_task(self, task_name, add_anl_to_post=False): if task_name not in ['post', 'ocnpost']: @@ -1029,8 +1030,9 @@ def arch(self): dep_dict = {'type': 'task', 'name': f'{self.cdump}wavepostbndpnt'} deps.append(rocoto.add_dependency(dep_dict)) if self.app_config.do_ocean: - dep_dict = {'type': 'metatask', 'name': f'{self.cdump}ocnpost'} - deps.append(rocoto.add_dependency(dep_dict)) + if self.app_config.mode in ['forecast-only']: # TODO: fix ocnpost to run in cycled mode + dep_dict = {'type': 'metatask', 'name': f'{self.cdump}ocnpost'} + deps.append(rocoto.add_dependency(dep_dict)) dependencies = rocoto.create_dependency(dep_condition='and', dep=deps) cycledef = 'gdas_half,gdas' if self.cdump in ['gdas'] else self.cdump diff --git a/workflow/setup_expt.py b/workflow/setup_expt.py index df2f47703e..c84587d4e9 100755 --- a/workflow/setup_expt.py +++ b/workflow/setup_expt.py @@ -7,12 +7,12 @@ import os import glob import shutil -from datetime import datetime from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter from hosts import Host from pygw.yaml_file import YAMLFile +from pygw.timetools import to_datetime, to_timedelta, datetime_to_YMDH _here = os.path.dirname(__file__) @@ -55,46 +55,97 @@ def fill_COMROT_cycled(host, inputs): Implementation of 'fill_COMROT' for cycled mode """ - idatestr = inputs.idate.strftime('%Y%m%d%H') comrot = os.path.join(inputs.comrot, inputs.pslot) - if inputs.icsdir is not None: - # Link ensemble member initial conditions - if inputs.nens > 0: - enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' - makedirs_if_missing(os.path.join(comrot, enkfdir)) - - # Link atmospheric files (ocean, ice, coming TBD ...) - for ii in range(1, inputs.nens + 1): - memdir = f'mem{ii:03d}/atmos' - dst_dir = os.path.join(comrot, enkfdir, memdir, 'INPUT') - src_dir = os.path.join(inputs.icsdir, enkfdir, memdir, 'INPUT') - makedirs_if_missing(dst_dir) - files = os.listdir(src_dir) - for fname in files: - os.symlink(os.path.join(src_dir, fname), - os.path.join(dst_dir, fname)) - - # Link deterministic initial conditions - detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' - makedirs_if_missing(os.path.join(comrot, detdir)) + do_ocean = do_ice = do_med = False + if inputs.app in ['S2S', 'S2SW']: + do_ocean = do_ice = do_med = True - # Link atmospheric files (ocean, ice, TBD ...) - dst_dir = os.path.join(comrot, detdir, 'atmos/INPUT') - src_dir = os.path.join(inputs.icsdir, detdir, 'atmos/INPUT') - makedirs_if_missing(dst_dir) + if inputs.icsdir is None: + print("User did not provide path to stage initial conditions in COMROT") + return + + rdatestr = datetime_to_YMDH(inputs.idate - to_timedelta('T06H')) + idatestr = datetime_to_YMDH(inputs.idate) + + if inputs.start in ['warm']: # This is warm start experiment (only meaningful for atmos) + atmos_dir = med_dir = 'RESTART' + elif inputs.start in ['cold']: # This is a cold start experiment + atmos_dir = 'INPUT' + med_dir = '' # no mediator files for a "cold start" + do_med = False + ocean_dir = ice_dir = 'RESTART' # ocean and ice have the same filenames for warm and cold + + def link_files_from_src_to_dst(src_dir, dst_dir): files = os.listdir(src_dir) for fname in files: os.symlink(os.path.join(src_dir, fname), os.path.join(dst_dir, fname)) + return + + # Link ensemble member initial conditions + if inputs.nens > 0: + if inputs.start in ['warm']: + enkfdir = f'enkf{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + elif inputs.start in ['cold']: + enkfdir = f'enkf{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + + for ii in range(1, inputs.nens + 1): + memdir = f'mem{ii:03d}' + # Link atmospheric files + dst_dir = os.path.join(comrot, enkfdir, memdir, 'atmos', atmos_dir) + src_dir = os.path.join(inputs.icsdir, enkfdir, memdir, 'atmos', atmos_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + # ocean, ice, etc. TBD ... + + # Link deterministic initial conditions + + # Link atmospheric files + if inputs.start in ['warm']: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + elif inputs.start in ['cold']: + detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + + dst_dir = os.path.join(comrot, detdir, 'atmos', atmos_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'atmos', atmos_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) - # Link bias correction and radiance diagnostics files - src_dir = os.path.join(inputs.icsdir, detdir, 'atmos') - dst_dir = os.path.join(comrot, detdir, 'atmos') - for ftype in ['abias', 'abias_pc', 'abias_air', 'radstat']: - fname = f'{inputs.cdump}.t{idatestr[8:]}z.{ftype}' - os.symlink(os.path.join(src_dir, f'{fname}'), - os.path.join(dst_dir, f'{fname}')) + # Link ocean files + if do_ocean: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + dst_dir = os.path.join(comrot, detdir, 'ocean', ocean_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'ocean', ocean_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + + # Link ice files + if do_ice: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + dst_dir = os.path.join(comrot, detdir, 'ice', ice_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'ice', ice_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + + # Link mediator files + if do_med: + detdir = f'{inputs.cdump}.{rdatestr[:8]}/{rdatestr[8:]}' + dst_dir = os.path.join(comrot, detdir, 'med', med_dir) + src_dir = os.path.join(inputs.icsdir, detdir, 'med', med_dir) + makedirs_if_missing(dst_dir) + link_files_from_src_to_dst(src_dir, dst_dir) + + # Link bias correction and radiance diagnostics files + detdir = f'{inputs.cdump}.{idatestr[:8]}/{idatestr[8:]}' + src_dir = os.path.join(inputs.icsdir, detdir, 'atmos') + dst_dir = os.path.join(comrot, detdir, 'atmos') + makedirs_if_missing(dst_dir) + for ftype in ['abias', 'abias_pc', 'abias_air', 'radstat']: + fname = f'{inputs.cdump}.t{idatestr[8:]}z.{ftype}' + src_file = os.path.join(src_dir, fname) + if os.path.exists(src_file): + os.symlink(src_file, os.path.join(dst_dir, fname)) return @@ -164,8 +215,8 @@ def edit_baseconfig(host, inputs): extend_dict = dict() extend_dict = { "@PSLOT@": inputs.pslot, - "@SDATE@": inputs.idate.strftime('%Y%m%d%H'), - "@EDATE@": inputs.edate.strftime('%Y%m%d%H'), + "@SDATE@": datetime_to_YMDH(inputs.idate), + "@EDATE@": datetime_to_YMDH(inputs.edate), "@CASECTL@": f'C{inputs.resdet}', "@EXPDIR@": inputs.expdir, "@ROTDIR@": inputs.comrot, @@ -182,19 +233,20 @@ def edit_baseconfig(host, inputs): extend_dict = { "@CASEENS@": f'C{inputs.resens}', "@NMEM_ENKF@": inputs.nens, + "@DOHYBVAR@": "YES" if inputs.nens > 0 else "NO", } tmpl_dict = dict(tmpl_dict, **extend_dict) + # Determine CCPP suite and MP based on mode and app + gfsv16 = {"@CCPP_SUITE@": "FV3_GFS_v16", "@IMP_PHYSICS@": 11} + gfsv17 = {"@CCPP_SUITE@": "FV3_GFS_v17_p8", "@IMP_PHYSICS@": 8} if inputs.mode in ['cycled']: - extend_dict = { - "@CCPP_SUITE@": 'FV3_GFS_v16', - "@IMP_PHYSICS@": 11 - } + if inputs.app in ['ATM']: + extend_dict = gfsv16 + elif inputs.app in ['S2S', 'S2SW']: + extend_dict = gfsv17 elif inputs.mode in ['forecast-only']: - extend_dict = { - "@CCPP_SUITE@": 'FV3_GFS_v17_p8', - "@IMP_PHYSICS@": 8 - } + extend_dict = gfsv17 tmpl_dict = dict(tmpl_dict, **extend_dict) base_input = f'{inputs.configdir}/config.base.emc.dyn' @@ -268,8 +320,8 @@ def input_args(): subp.add_argument('--expdir', help='full path to EXPDIR', type=str, required=False, default=os.getenv('HOME')) subp.add_argument('--idate', help='starting date of experiment, initial conditions must exist!', - required=True, type=lambda dd: datetime.strptime(dd, '%Y%m%d%H')) - subp.add_argument('--edate', help='end date experiment', required=True, type=lambda dd: datetime.strptime(dd, '%Y%m%d%H')) + required=True, type=lambda dd: to_datetime(dd)) + subp.add_argument('--edate', help='end date experiment', required=True, type=lambda dd: to_datetime(dd)) subp.add_argument('--icsdir', help='full path to initial condition directory', type=str, required=False, default=None) subp.add_argument('--configdir', help='full path to directory containing the config files', type=str, required=False, default=os.path.join(_top, 'parm/config')) @@ -283,28 +335,32 @@ def input_args(): subp.add_argument('--yaml', help='Defaults to substitute from', type=str, required=False, default=os.path.join(_top, 'parm/config/yaml/defaults.yaml')) + ufs_apps = ['ATM', 'ATMA', 'ATMW', 'S2S', 'S2SW'] + # cycled mode additional arguments cycled.add_argument('--resens', help='resolution of the ensemble model forecast', type=int, required=False, default=192) cycled.add_argument('--nens', help='number of ensemble members', type=int, required=False, default=20) cycled.add_argument('--app', help='UFS application', type=str, - choices=['ATM', 'ATMW', 'ATMA'], required=False, default='ATM') + choices=ufs_apps, required=False, default='ATM') # forecast only mode additional arguments - forecasts.add_argument('--app', help='UFS application', type=str, choices=[ - 'ATM', 'ATMA', 'ATMW', 'S2S', 'S2SW', 'S2SWA', 'NG-GODAS'], required=False, default='ATM') + forecasts.add_argument('--app', help='UFS application', type=str, + choices=ufs_apps + ['S2SWA'], required=False, default='ATM') args = parser.parse_args() - if args.app in ['S2S', 'S2SW'] and args.icsdir is None: - raise SyntaxError("An IC directory must be specified with --icsdir when running the S2S or S2SW app") + if args.mode in ['forecast-only'] and args.app in ['S2S', 'S2SW'] and args.icsdir is None: + raise SyntaxError("An IC directory must be specified with --icsdir when running the S2S or S2SW app in forecast-only mode") # Add an entry for warm_start = .true. or .false. - if args.start == "warm": + if args.start in ['warm']: args.warm_start = ".true." - else: + elif args.start in ['cold']: args.warm_start = ".false." + print(args.warm_start) + return args