Skip to content

feat(ftorch): finish CTSM FTorch integration: add system test calling FTorch inference - #4265

Open
johnpaulalex wants to merge 7 commits into
ESCOMP:b4b-devfrom
johnpaulalex:feature/issue3228-bring-in-ftorch
Open

johnpaulalex wants to merge 7 commits into
ESCOMP:b4b-devfrom
johnpaulalex:feature/issue3228-bring-in-ftorch

Conversation

@johnpaulalex

@johnpaulalex johnpaulalex commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Description of changes

Add FTorch hooks at various places to enable FTorch inference and all necessary backing infra.

Relies on FTorch_Interface PR ESCOMP/FTorch_interface#2

Overview (Execution sequencing)

Listed in execution order, with the deltas from this PR's commits called out:

0. Human user prep:

  • Documentation (Commit 3): Read the new Running-with-FTorch.rst documentation in the User's Guide for build and execution instructions.
  • Model Export (Commit 2): Call the export library or CLI tool (./tools/ftorch/export_torchscript) to serialize trained PyTorch models to TorchScript (.pt) format.

1a. Source Code Initialization (Pre-build)

  • Submodule Population (Commit 1): In CTSM .gitmodules, defines the libraries/FTorch submodule pointing at ESCOMP/FTorch_interface (fxrequired = ToplevelRequired).

1b. Setup & Configuration (create_test / case.setup)

  • Parse Build Flags: Reads default USE_FTORCH=FALSE from the CIME environment XMLs (cime/CIME/build.py).
  • Test Definition (New test definitions added to CTSM's testlist_clm.xml in Commit 4): Two system tests (SMS_D_Ld1.f10_f10_mg37.I2000Clm60Sp and SMS_D_Ld1_Mmpi-serial.1x1_brazil.I2000Clm60SpRsGs with testmods="clm/default--clm/nofireemis--clm/ftorch_demo") added in cime_config/testdefs/testlist_clm.xml for both intel and gnu on Derecho. They compile with USE_FTORCH=TRUE and execute runtime FTorch inference during CTSM initialization: one tests multi-process MPI on a global 10x15 grid (SMS_D_Ld1.f10_f10_mg37.I2000Clm60Sp), and the second tests single-point mpi-serial execution on 1x1_brazil (SMS_D_Ld1_Mmpi-serial.1x1_brazil.I2000Clm60SpRsGs, representing the LEAP/M2LInES single-point workflow).
  • Model Staging (Testmods and shell_commands added in Commit 4): CIME processes clm/ftorch_demo, whose include_user_mods automatically pulls in ../ftorch (clm/ftorch/shell_commands, which sets ./xmlchange USE_FTORCH=TRUE), while clm/ftorch_demo/shell_commands stages the pre-generated TorchScript model (constant_model.pt) into $RUNDIR and clm/ftorch_demo/user_nl_clm enables use_ftorch_demo = .true..

2. Compilation (case.build)

  • Build Hook Invocation: cime/CIME/build.py invokes $SRCROOT/libraries/FTorch/buildlib, and cime/CIME/Tools/Makefile passes -DUSE_FTORCH and links -lftorch / -ltorch_cpu when USE_FTORCH=TRUE (or links only the libftorch_wrapper stub when USE_FTORCH=FALSE).
  • Library Compilation (companion ESCOMP/FTorch_interface PR):
    1. When USE_FTORCH=FALSE (default): libraries/FTorch/buildlib skips checking TORCH_DIR and compiles only FTorch_cesm_interface.F90 into libftorch_wrapper using the #else stub (which calls shr_abort_abort if invoked at runtime).
    2. When USE_FTORCH=TRUE: libraries/FTorch/buildlib validates that the C++ inference TORCH_DIR exists, compiles the FTorch Fortran-to-C++ bridge and FTorch_cesm_interface.F90 (libftorch_wrapper), and places ftorch.mod in ${CMAKE_BINARY_DIR}/modules to match INCLDIR += -I$(FTORCH_DIR)/modules in cime/CIME/Tools/Makefile.
    3. Cray Dynamic Linking: The FTorch_interface library PR enables shared libraries on Cray, allowing ftorch and ftorch_wrapper to build cleanly as shared libraries on Cray for both USE_FTORCH=TRUE and USE_FTORCH=FALSE. buildlib runs FTMakefile unconditionally so USE_FTORCH changes are re-evaluated by CMake.

3. Runtime Execution (mpiexec cesm.exe)

  • Dynamic Linking: At job launch, the OS dynamic loader resolves libtorch_cpu.so and libftorch via the rpath ($(TORCH_DIR)/lib and $(FTORCH_DIR)/src) embedded into cesm.exe at link time.
  • Model Initialization (Commit 4): Gated at runtime by if (use_ftorch_demo) on all MPI ranks (with zero #ifdef USE_FTORCH in clm_initializeMod.F90, matching the CESM/CAM convention, and gating only write(iulog,*) log messages on masterproc), clm_initializeMod.F90 calls torch_model_load and maps Fortran arrays to PyTorch tensors via torch_tensor_from_array.
  • Inference & Teardown (Commit 4): Gated as above across all MPI ranks, executes the neural network using torch_model_forward and deallocates memory via torch_delete.

Specific notes

Contributors other than yourself, if any:

  • (Replace this text and add more list items as needed)

CTSM issues resolved or otherwise addressed, if any:

If answers are expected to change, describe (delete this line otherwise):

  • B4B: The FTorch demo inference logic merely populates temporary variables in the clm_initialize block and logs status output when use_ftorch_demo is .true.. It does not mutate any prognostic physics state.

Any user interface changes (namelist or namelist defaults changes)?

  • Added namelist boolean: use_ftorch_demo (default: .false.) in namelist_definition_ctsm.xml.

Testing planned or performed, if any:

  • Verified Python unit tests in python/ctsm/test/test_unit_export_torchscript.py pass cleanly both without PyTorch (3/3 on local Mac) and with pytorch-cpu in ctsm_pylib (3/3 on Derecho).
  • Verified standard CTSM Fortran pFUnit suite (python3 cime/scripts/fortran_unit_testing/run_tests.py --test-spec-dir src) builds and passes cleanly (59/59 PASS).
  • Verified all $2 \times 2$ (USE_FTORCH, use_ftorch_demo) system test permutations on NCAR Derecho (-t ftorch_perm_1):
    • 1a (USE_FTORCH=TRUE, use_ftorch_demo=.true., Intel MPI): SMS_D_Ld1.f10_f10_mg37.I2000Clm60Sp.derecho_intel.clm-default--clm-nofireemis--clm-ftorch_demo (PASS; FTORCH INFERENCE SUCCESSFUL: output = 1.00000000000000 in lnd.log).
    • 1b (USE_FTORCH=TRUE, use_ftorch_demo=.true., GNU mpi-serial): SMS_D_Ld1_Mmpi-serial.1x1_brazil.I2000Clm60SpRsGs.derecho_gnu.clm-default--clm-nofireemis--clm-ftorch_demo (PASS; FTORCH INFERENCE SUCCESSFUL: output = 1.00000000000000 in lnd.log).
    • 2 (USE_FTORCH=TRUE, use_ftorch_demo=.false., Intel MPI): SMS_D_Ld1.f10_f10_mg37.I2000Clm60Sp.derecho_intel.clm-default--clm-nofireemis--clm-ftorch (PASS; clean no-op with zero FTORCH lines in lnd.log).
    • 3 (USE_FTORCH=FALSE, use_ftorch_demo=.false., GNU mpi-serial): SMS_D_Ld1_Mmpi-serial.1x1_brazil.I2000Clm60SpRsGs.derecho_gnu.clm-default--clm-nofireemis (PASS; compiles and links without #ifdef USE_FTORCH against FTorch_cesm_interface stub).
    • 4 (USE_FTORCH=FALSE, use_ftorch_demo=.true., GNU mpi-serial): SMS_D_Ld1_Mmpi-serial.1x1_brazil.I2000Clm60SpRsGs.derecho_gnu.clm-default--clm-nofireemis--clm-ftorch_demo_only (RUN aborts as expected with ERROR: Using FTorch Interface without USE_FTORCH=TRUE).
  • Verified negative control on NCAR Derecho (USE_FTORCH=FALSE, default): SMS_D_Ld5.f10_f10_mg37.IHistClm60BgcCrop.derecho_intel.interim_restart builds and runs uninterrupted without FTorch (PASS).
  • Validated system test with latest PR 1 (fab11fa) and PR 2 (212bda8d0) on NCAR Derecho (Task T15, output root /glade/derecho/scratch/jpalex/tests_ftorch_t15): SMS_D_Ld1.f10_f10_mg37.I2000Clm60Sp.derecho_intel.clm-default--clm-nofireemis--clm-ftorch_demo (PASS; confirmed FTORCH INFERENCE SUCCESSFUL: output = 1.00000000000000).
  • Verified full parallel test campaign on NCAR Derecho (scratch root /glade/derecho/scratch/jpalex/tests_ftorch_rerun): all standalone CTSM tests (SMS_D_Ld1...clm-ftorch_demo and generic SMS_D_Ld1...clm-ftorch) and coupled CESM checkout tests (SMS_D_Ld1...clm-ftorch_demo Intel MPI, Intel MPI USE_FTORCH=FALSE, and GNU mpi-serial USE_FTORCH=FALSE) passed.

Requirements before merge:

  • I have followed the CTSM contribution guidelines.
  • The code in this PR branch builds with no errors.
  • The code in this PR branch runs with no errors. Briefly describe tested configuration(s): Derecho Intel/GNU aux_clm system tests and full $2 \times 2$ (USE_FTORCH, use_ftorch_demo) permutation matrix.
  • This either (a) does not change answers, (b) it only changes answers at roundoff level, or (c) I have performed a scientific evaluation of the answer changes. Which?: (a)
  • I have reviewed relevant parts of the CLM documentation Tech Note or User's Guide to determine if anything needs to be changed or added. If it does, describe: Added Running-with-FTorch.rst to the User's Guide under running-special-cases.
  • This PR either (a) does not create a need to update the documentation or (b) includes required documentation updates (see guidelines for contributing documentation). Which?: (b)

Google Gemini Argon 4 was used to write the code and tests, followed by human-guided verification.

John Alex added 4 commits October 18, 2026 20:09
Registers ESCOMP/FTorch_interface as TopLevelRequired CTSM submodule. It is 'TopLevel' because CESM already has it. It is 'Required' because it needs to show up as stubs by default (enabling linking in F90 code that calls ftorch, behind gated bool vars).
…l for generating toy test models

As a tool, this creates toy models for testing. As a library, it converts a PyTorch nn.Module to a TorchScript file.
Wires an end-to-end runtime verification test for FTorch inference into CTSM initialization and CIME system testing:
1. Adds generic ftorch testmod to turn on USE_FTORCH, and on top of that, adds ftorch_demo testmod to enable new use_ftorch_demo logical namelist variable, and copies in constant_model.pt.
2. Imports FTorch_cesm_interface in clm_initializeMod.F90 (initialize2) and, when use_ftorch_demo = .true., runs constant_model.pt inference, logs the output tensor, and deletes the model.
3. Registers two Derecho aux_clm system tests (intel and gnu) in testlist_clm.xml:
   - SMS_D_Ld1.f10_f10_mg37.I2000Clm60Sp: Tests multi-process MPI on a global 10x15 grid, verifying dynamic linking of multi-threaded libtorch_cpu.so under Cray MPI across distributed ranks.
   - SMS_D_Ld1_Mmpi-serial.1x1_brazil.I2000Clm60SpRsGs: Tests single-point mpi-serial execution on 1x1_brazil, representing the lightweight single-point workflow heavily relied upon by the LEAP and M2LInES machine learning research communities without requiring full MPI libraries.
@github-actions

Copy link
Copy Markdown

❌ Docs build failed

Build logs
Cleaning documentation build directory...
Done.
Building documentation...
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:3: WARNING: Title overline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:39: WARNING: Title underline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:39: WARNING: Title underline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:61: WARNING: Title underline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:61: WARNING: Title underline too short.
Documentation build completed, but with problems that must be resolved.
Re-run with --verbose for full output.

Points the libraries/FTorch gitlink to v0.0.6 (6d03d7c) matching fxtag
in .gitmodules, resolving the git-fleximod check-cleanliness CI failure
in GitHub Actions.
@johnpaulalex

Copy link
Copy Markdown
Contributor Author

@ekluzek Here's the other half of CTSM FTorch support (paired with ESCOMP/FTorch_interface#2).

@github-actions

Copy link
Copy Markdown

❌ Docs build failed

Build logs
Cleaning documentation build directory...
Done.
Building documentation...
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:3: WARNING: Title overline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:39: WARNING: Title underline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:39: WARNING: Title underline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:61: WARNING: Title underline too short.
/home/user/mounted_home/doc/source/users_guide/running-special-cases/Running-with-FTorch.rst:61: WARNING: Title underline too short.
Documentation build completed, but with problems that must be resolved.
Re-run with --verbose for full output.

@wwieder

wwieder commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Thanks, @johnpaulalex. It looks like some of the documentation build tests failed. Are you able to correct these?

Who's been handling the ftorch feature request who would be able to review this PR & do testing? Marking as next to discuss at the meeting Thursday.

@wwieder wwieder added the next this should get some attention in the next week or two. Normally each Thursday SE meeting. label Oct 19, 2026
@johnpaulalex

Copy link
Copy Markdown
Contributor Author

hey @wwieder , I pinged a couple people on the Ftorch_interface PR, it's only the second PR ever so I guess it's early days.

Docs build is all fixed.

@wwieder wwieder removed the next this should get some attention in the next week or two. Normally each Thursday SE meeting. label Oct 22, 2026
@wwieder
wwieder removed the request for review from linniahawkins October 22, 2026 16:26
@wwieder wwieder added this to the ctsm6.1.0 milestone Oct 22, 2026
@wwieder

wwieder commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

This isn't critical for the CLM6 release, so we decided to mark this with a later milestone, but reviewing the code isn't a priority right now.

@wwieder wwieder added enhancement new capability or improved behavior of existing capability b4b bit-for-bit science Enhancement to or bug impacting science labels Oct 22, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

b4b bit-for-bit enhancement new capability or improved behavior of existing capability science Enhancement to or bug impacting science

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants