diff --git a/CMakeLists.txt b/CMakeLists.txt index f4f2fd98f..60c85bbf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,13 @@ option(BUILD_GDASBUNDLE "Build GDAS Bundle" ON) option(CLONE_JCSDADATA "Clone JCSDA test data repositories" OFF) option(WORKFLOW_TESTS "Include global-workflow dependent tests" OFF) +# Build GDAS-managed JEDI executables +if( BUILD_GDASBUNDLE ) + find_package( fv3jedi REQUIRED ) + find_package( soca REQUIRED ) + add_subdirectory( mains ) +endif() + # Install utility scripts. add_subdirectory(ush) diff --git a/build.sh b/build.sh index 3a9e98fa8..2922d45e5 100755 --- a/build.sh +++ b/build.sh @@ -126,7 +126,7 @@ set -x if [[ $BUILD_JCSDA == 'YES' ]]; then make -j ${BUILD_JOBS:-6} VERBOSE=$BUILD_VERBOSE else - builddirs="fv3-jedi soca iodaconv land-imsproc land-jediincr gdas-utils" + builddirs="gdas iodaconv land-imsproc land-jediincr gdas-utils" for b in $builddirs; do cd $b make -j ${BUILD_JOBS:-6} VERBOSE=$BUILD_VERBOSE diff --git a/mains/CMakeLists.txt b/mains/CMakeLists.txt new file mode 100644 index 000000000..c73b68a4e --- /dev/null +++ b/mains/CMakeLists.txt @@ -0,0 +1,28 @@ +# Build the big gdas executable used for all generic JEDI applications +# -------------------------------------------------------------------- +ecbuild_add_executable( TARGET gdas.x + SOURCES gdas.cc + LIBS fv3jedi soca + ) + +# Build the soca executables that are not OOPS-based +# -------------------------------------------------- +ecbuild_add_executable( TARGET gdas_soca_gridgen.x + SOURCES ${CMAKE_SOURCE_DIR}/soca/src/mains/GridGen.cc + LIBS soca + ) + +ecbuild_add_executable( TARGET gdas_soca_error_covariance_toolbox.x + SOURCES ${CMAKE_SOURCE_DIR}/soca/src/mains/ErrorCovarianceToolbox.cc + LIBS soca saber + ) + +ecbuild_add_executable( TARGET gdas_soca_setcorscales.x + SOURCES ${CMAKE_SOURCE_DIR}/soca/src/mains/SetCorScales.cc + LIBS soca + ) + +ecbuild_add_executable( TARGET gdas_fv3jedi_error_covariance_toolbox.x + SOURCES ${CMAKE_SOURCE_DIR}/fv3-jedi/src/mains/fv3jediErrorCovarianceToolbox.cc + LIBS fv3jedi saber + ) diff --git a/mains/gdas.cc b/mains/gdas.cc new file mode 100644 index 000000000..7fdbee0b1 --- /dev/null +++ b/mains/gdas.cc @@ -0,0 +1,122 @@ +// ------------------------------------------------------------------------------------------------- + +#include +#include + +#include "fv3jedi/ObsLocalization/instantiateObsLocFactory.h" +#include "fv3jedi/Utilities/Traits.h" + +#include "soca/Traits.h" + +#include "oops/generic/instantiateModelFactory.h" +#include "saber/oops/instantiateCovarFactory.h" +#include "ufo/instantiateObsErrorFactory.h" +#include "ufo/instantiateObsFilterFactory.h" +#include "ufo/ObsTraits.h" + +#include "oops/runs/ConvertState.h" +#include "oops/runs/HofX4D.h" +#include "oops/runs/LocalEnsembleDA.h" +#include "oops/runs/Run.h" +#include "oops/runs/Variational.h" + +// ------------------------------------------------------------------------------------------------- + +template +int runApp(int argc, char** argv, const std::string traits, const std::string appName) { + // Create the Run object + oops::Run run(argc, argv); + + // Instantiate oops factories + oops::instantiateModelFactory(); + + // Instantiate saber factories + saber::instantiateCovarFactory(); + + // Intantiate ufo factories + ufo::instantiateObsErrorFactory(); + ufo::instantiateObsFilterFactory(); + + // Localization for ensemble DA + if (appName == "localensembleda") { + if (traits == "fv3jedi") { + fv3jedi::instantiateObsLocFactory(); + } else if (traits == "soca") { + ufo::instantiateObsLocFactory(); + } + } + + // Application pointer + std::unique_ptr app; + + // Define a map from app names to lambda functions that create unique_ptr to Applications + std::map()>> apps; + + apps["convertstate"] = []() { + return std::make_unique>(); + }; + apps["hofx4d"] = []() { + return std::make_unique>(); + }; + apps["localensembleda"] = []() { + return std::make_unique>(); + }; + apps["variational"] = []() { + return std::make_unique>(); + }; + + // Create application object and point to it + auto it = apps.find(appName); + + // Run the application + return run.execute(*(it->second())); +} + +// ------------------------------------------------------------------------------------------------- + +int main(int argc, char ** argv) { + // Check that the number of arguments is correct + // ---------------------------------------------- + ASSERT_MSG(argc >= 3, "Usage: " + std::string(argv[0]) + " "); + + // Get traits from second argument passed to executable + // ---------------------------------------------------- + std::string traits = argv[1]; + for (char &c : traits) {c = std::tolower(c);} + + // Get the application to be run + std::string app = argv[2]; + for (char &c : app) {c = std::tolower(c);} + + // Check that the traits are recognized + // ------------------------------------ + const std::set validTraits = {"fv3jedi", "soca"}; + ASSERT_MSG(validTraits.find(traits) != validTraits.end(), "Traits not recognized: " + traits); + + // Check that the application is recognized + // ---------------------------------------- + const std::set validApps = { + "convertstate", + "hofx4d", + "localensembleda", + "variational" + }; + ASSERT_MSG(validApps.find(app) != validApps.end(), "Application not recognized: " + app); + + // Remove traits and program from argc and argv + // -------------------------------------------- + argv[2] = argv[0]; // Move executable name to third position + argv += 2; // Move pointer up two + argc -= 2; // Remove 2 from count + + // Call application specific main functions + // ---------------------------------------- + if (traits == "fv3jedi") { + fv3jedi::instantiateObsLocFactory(); + return runApp(argc, argv, traits, app); + } else if (traits == "soca") { + return runApp(argc, argv, traits, app); + } +} + +// ------------------------------------------------------------------------------------------------- diff --git a/scripts/exgdas_global_marine_analysis_bmat.sh b/scripts/exgdas_global_marine_analysis_bmat.sh index 4845ec7c0..315e9fdc7 100755 --- a/scripts/exgdas_global_marine_analysis_bmat.sh +++ b/scripts/exgdas_global_marine_analysis_bmat.sh @@ -47,9 +47,9 @@ function clean_yaml() if [[ -e 'soca_gridspec.nc' ]]; then echo "soca_gridspc.nc already exists, skip the grid generation step" else - # Run soca_gridgen.x if the grid was not staged + # Run gdas_soca_gridgen.x if the grid was not staged # TODO (Guillaume): Should not use all pe's for the grid generation - $APRUN_OCNANAL $JEDI_BIN/soca_gridgen.x gridgen.yaml + $APRUN_OCNANAL $JEDI_BIN/gdas_soca_gridgen.x gridgen.yaml export err=$?; err_chk if [ $err -gt 0 ]; then exit $err @@ -101,14 +101,14 @@ fi # Horizontal diffusion if [ ! -f "ocn.cor_rh.incr.0001-01-01T00:00:00Z.nc" ]; then # Set decorrelation scales for the static B - $APRUN_OCNANAL $JEDI_BIN/soca_setcorscales.x soca_setcorscales.yaml + $APRUN_OCNANAL $JEDI_BIN/gdas_soca_setcorscales.x soca_setcorscales.yaml export err=$?; err_chk if [ $err -gt 0 ]; then exit $err fi # Initialize the horizontal diffusion block and normalize clean_yaml soca_parameters_diffusion_hz.yaml - $APRUN_OCNANAL $JEDI_BIN/soca_error_covariance_toolbox.x soca_parameters_diffusion_hz.yaml + $APRUN_OCNANAL $JEDI_BIN/gdas_soca_error_covariance_toolbox.x soca_parameters_diffusion_hz.yaml export err=$?; err_chk if [ $err -gt 0 ]; then exit $err @@ -125,7 +125,7 @@ python ${HOMEgfs}/sorc/gdas.cd/sorc/soca/tools/calc_scales.py soca_vtscales.yaml clean_yaml soca_parameters_diffusion_vt.yaml # Initialize the vertical diffusion block and normalize -$APRUN_OCNANAL $JEDI_BIN/soca_error_covariance_toolbox.x soca_parameters_diffusion_vt.yaml +$APRUN_OCNANAL $JEDI_BIN/gdas_soca_error_covariance_toolbox.x soca_parameters_diffusion_vt.yaml export err=$?; err_chk if [ $err -gt 0 ]; then exit $err diff --git a/scripts/exgdas_global_marine_analysis_chkpt.sh b/scripts/exgdas_global_marine_analysis_chkpt.sh index 8b585693d..f6ada550f 100755 --- a/scripts/exgdas_global_marine_analysis_chkpt.sh +++ b/scripts/exgdas_global_marine_analysis_chkpt.sh @@ -67,8 +67,8 @@ fi # TODO: This should probably be in a separate j-job, that includes # the mom6 incr postprocessing from above. -$APRUN_OCNANAL ${JEDI_BIN}/soca_convertstate.x soca_2cice_arctic.yaml -$APRUN_OCNANAL ${JEDI_BIN}/soca_convertstate.x soca_2cice_antarctic.yaml +$APRUN_OCNANAL ${JEDI_BIN}/gdas.x soca convertstate soca_2cice_arctic.yaml +$APRUN_OCNANAL ${JEDI_BIN}/gdas.x soca convertstate soca_2cice_antarctic.yaml export err=$?; err_chk ################################################################################ diff --git a/scripts/exgdas_global_marine_analysis_run.sh b/scripts/exgdas_global_marine_analysis_run.sh index 7ee52cd5f..29668b261 100755 --- a/scripts/exgdas_global_marine_analysis_run.sh +++ b/scripts/exgdas_global_marine_analysis_run.sh @@ -41,7 +41,7 @@ function clean_yaml() # run the variational application cp var.yaml var_original.yaml clean_yaml var.yaml -$APRUN_OCNANAL $JEDI_BIN/soca_var.x var.yaml +$APRUN_OCNANAL $JEDI_BIN/gdas.x soca variational var.yaml export err=$?; err_chk ################################################################################ diff --git a/test/aero/global-workflow/config.aeroanl b/test/aero/global-workflow/config.aeroanl index 911d62478..a2c4768c1 100644 --- a/test/aero/global-workflow/config.aeroanl +++ b/test/aero/global-workflow/config.aeroanl @@ -18,6 +18,6 @@ export BERROR_DATE="20160630.000000" export io_layout_x=1 export io_layout_y=1 -export JEDIEXE=${HOMEgfs}/exec/fv3jedi_var.x +export JEDIEXE=${HOMEgfs}/exec/gdas.x echo "END: config.aeroanl" diff --git a/test/atm/global-workflow/config.atmanl b/test/atm/global-workflow/config.atmanl index 5649f70bb..2a0f7d6d4 100755 --- a/test/atm/global-workflow/config.atmanl +++ b/test/atm/global-workflow/config.atmanl @@ -28,6 +28,6 @@ export layout_y_atmanl=@LAYOUT_Y_ATMANL@ export io_layout_x=@IO_LAYOUT_X@ export io_layout_y=@IO_LAYOUT_Y@ -export JEDIEXE=${EXECgfs}/fv3jedi_var.x +export JEDIEXE=${EXECgfs}/gdas.x echo "END: config.atmanl" diff --git a/test/atm/global-workflow/config.atmensanl b/test/atm/global-workflow/config.atmensanl index c7bddbdf6..1afe2e22c 100644 --- a/test/atm/global-workflow/config.atmensanl +++ b/test/atm/global-workflow/config.atmensanl @@ -18,6 +18,6 @@ export layout_y_atmensanl=@LAYOUT_Y_ATMENSANL@ export io_layout_x=@IO_LAYOUT_X@ export io_layout_y=@IO_LAYOUT_Y@ -export JEDIEXE=${EXECgfs}/fv3jedi_letkf.x +export JEDIEXE=${EXECgfs}/gdas.x echo "END: config.atmensanl" diff --git a/test/snow/create_bkg_ens.sh b/test/snow/create_bkg_ens.sh index 81128afcc..bc2232654 100755 --- a/test/snow/create_bkg_ens.sh +++ b/test/snow/create_bkg_ens.sh @@ -30,7 +30,7 @@ if [[ ${DAtype} == 'letkfoi_snow' ]]; then B=30 # background error std for LETKFOI - JEDI_EXEC="fv3jedi_letkf.x" + JEDI_EXEC="gdas.x fv3jedi localensembleda" # FOR LETKFOI, CREATE THE PSEUDO-ENSEMBLE for ens in 001 002 diff --git a/test/snow/letkfoi_snowda.sh b/test/snow/letkfoi_snowda.sh index e3c4499a1..8b09ebca4 100755 --- a/test/snow/letkfoi_snowda.sh +++ b/test/snow/letkfoi_snowda.sh @@ -38,7 +38,7 @@ if [[ ${DAtype} == 'letkfoi_snow' ]]; then B=30 # background error std for LETKFOI - JEDI_EXEC="fv3jedi_letkf.x" + JEDI_EXEC="gdas.x fv3jedi localensembleda" # FOR LETKFOI, CREATE THE PSEUDO-ENSEMBLE for ens in 001 002 diff --git a/ush/soca/marine_recenter.py b/ush/soca/marine_recenter.py index 5bb689e71..fccacd7c6 100644 --- a/ush/soca/marine_recenter.py +++ b/ush/soca/marine_recenter.py @@ -180,7 +180,7 @@ def run(self): chdir(self.runtime_config.DATA) exec_cmd_gridgen = Executable(self.config.APRUN_OCNANALECEN) - exec_name_gridgen = os.path.join(self.config.JEDI_BIN, 'soca_gridgen.x') + exec_name_gridgen = os.path.join(self.config.JEDI_BIN, 'gdas_soca_gridgen.x') exec_cmd_gridgen.add_default_arg(exec_name_gridgen) exec_cmd_gridgen.add_default_arg(self.config.gridgen_yaml)