Article URL: https://docs.pasteurlabs.ai/projects/tesseract-core/latest/blog/2026-07-09-enzyme-lfortran-autodiff.html Comments URL: https://news.ycombinator.com/item?id=48905667 Po…

What if you could backpropagate through existing Fortran, C, or C++ simulation code, embed it into JAX and torch, and use it as a high-performance differentiable physics engine? Turns out, you can — if you’re brave enough… Decades of validated physics code in CFD, climate, aerospace, and nuclear sit behind a wall that modern ML pipelines can’t cross, because they don’t expose gradients. The usual answer is to rewrite it all in JAX or PyTorch. The alternative we explore here is to leave the code where it is and get exact gradients out anyway, thanks to some LLVM-level magic. This is possible because Enzyme applies autodiff at the LLVM IR level, so we can differentiate any code that compiles to LLVM! All we need is to duct-tape LFortran, LLVM, and Enzyme together, point the result at a Fortran thermal solver, and get exact gradients out the other end. From there, Tesseract wraps the result as a custom JAX primitive, so a Fortran solver becomes a differentiable layer in arbitrary JAX code. This is all pretty experimental, so be prepared to spend some time chasing a gradient that returned NaN and manually compare LLVM IR diffs to make it work. But if you put in the labor, you’ll get gradients through the entire multi-step time loop that match an analytic answer, and it’s amazing to see that a stack combining some of the oldest and newest technologies can work together at all. But let’s start at the beginning. What follows is the full story, including the compilation pipeline, the sharp edges we hit, and application on a challenging inverse problem (that wouldn’t be possible without AD). If you work in scientific computing, you might have run into this: you have a simulation written in Fortran (or C, or C++), and now someone needs gradients (the derivatives of the simulation’s outputs with respect to its inputs). Maybe it’s for optimization, maybe inverse problems, maybe plugging the sim into an ML pipeline. Now your options are: Hand-written adjoints. Boils down to hand-implementing the derivative of every line of code, which means months of expert effort. Error-prone and a maintenance nightmare that slowly drifts out of sync with the forward code. Finite differences. Perturb every input and difference the outputs. Slow (\(O(n)\) evaluations for n parameters), inaccurate, and poorly conditioned for stiff problems.