Skip to content

Diffrax integration - #817

Open
caprilesport wants to merge 6 commits into
geem-lab:mainfrom
caprilesport:diffrax
Open

Diffrax integration#817
caprilesport wants to merge 6 commits into
geem-lab:mainfrom
caprilesport:diffrax

Conversation

@caprilesport

@caprilesport caprilesport commented Aug 7, 2026

Copy link
Copy Markdown
Member

Initial integration of the Diffrax solvers, mainly to add the stiff solvers it provides.

The diffrax solver requires Jax, so the first question is, we now require Jax as a core feature or hide diffrax behind the fast feature flag?

In this initial implementation I've kept it behind the fast feature flag, but an option would be to replace the scipy solvers with the diffrax ones, as I think they are much more solid than the ones scipy exposes.

The only problem is that if someone wants to reproduce old simulated system this would be a bit of a breaking update, so I think it would be better to still keep the old solvers in the current proposed change? Open to feedback regarding this.

I haven't yet throughtly tested this in a "real world scenario", but the plan is to try to get some stiff system this week to compare the scipy solvers and the newly added Kvaerno solvers to see if they can handle it better.

I've also noted that I accidently linked the diffrax issue (#771) when doing the uv migration (which should have been #759, oopsie) instead of linking the correct issue. So if you want to re-open that one and close the uv issue...

@schneiderfelipe schneiderfelipe linked an issue Aug 14, 2026 that may be closed by this pull request
3 tasks

@schneiderfelipe schneiderfelipe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff!

Comment thread overreact/_cli.py
"integrator used in solving the ODE system of the microkinetic "
"simulation (Kvaerno methods require overreact[fast])"
),
choices=[

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to build those choices out of simulate._DIFFRAX_METHODS, so that all new methods are listed in a single place.

Comment thread overreact/simulate.py
method="RK23",
max_step=np.inf,
first_step=np.finfo(np.float64).eps,
first_step=None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably correct. Do you mind commenting?

Comment thread overreact/simulate.py
Comment on lines +97 to +99
First step size. If not given, Diffrax chooses one automatically,
while the SciPy backend uses `np.finfo(np.float64).eps` for backwards
compatibility.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I see. Maybe we leave with None and the first step size gets chosen automatically no matter what?

Comment thread overreact/simulate.py
Comment on lines +172 to +173
if first_step is not None:
first_step = np.min([first_step, max_step / 2.0])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to remove this if it's not needed anymore.

Comment thread overreact/simulate.py
Comment on lines +188 to +189
if first_step is None:
first_step = np.finfo(np.float64).eps

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's either pass a given first step through or let the underlying algorithms decide it. I think it is simpler and better matches diffrax?

Comment thread overreact/simulate.py
first_step=first_step,
rtol=rtol,
atol=atol,
# jac=jac, # noqa: ERA001

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: #422 is the reason why jac is not being used here. So fully migrating to diffrax would free us from having to solve #422.

Comment thread overreact/simulate.py
Comment on lines +241 to +245
stepsize_controller = diffrax.PIDController(
rtol=rtol,
atol=atol,
dtmax=max_step,
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever.

Comment thread overreact/simulate.py
return y, r


def _get_y_diffrax(dydt, y0, t_span, method, max_step, first_step, rtol, atol):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add defaults here (in principle the ones in around lines 62-65 above, but I'm open to changing them as well).

Comment thread overreact/simulate.py
Comment on lines +334 to +336
# Avoid differentiating 0**0 for compounds that do not participate in
# a reaction, this causes NaN fileed jacobians in diffrax otherwise.
bases = jnp.where(M == 0, 1.0, y)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be the cause of #422?

Comment thread pyproject.toml
Comment on lines 57 to 58
"jax>=0.4",
"jaxlib>=0.4",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are those required too or diffrax already pulls them in?

@schneiderfelipe

Copy link
Copy Markdown
Member

Initial integration of the Diffrax solvers, mainly to add the stiff solvers it provides.

This is awesome and would close #771.

The diffrax solver requires Jax, so the first question is, we now require Jax as a core feature or hide diffrax behind the fast feature flag?

In this initial implementation I've kept it behind the fast feature flag, but an option would be to replace the scipy solvers with the diffrax ones, as I think they are much more solid than the ones scipy exposes.

The only problem is that if someone wants to reproduce old simulated system this would be a bit of a breaking update, so I think it would be better to still keep the old solvers in the current proposed change? Open to feedback regarding this.

I haven't yet throughtly tested this in a "real world scenario", but the plan is to try to get some stiff system this week to compare the scipy solvers and the newly added Kvaerno solvers to see if they can handle it better.

Let's put everything behind the fast flag for now and leave having Diffrax being default a decision for the future.

I also noted that your change in _dydt might solve #422. Would you like to try solving it in this PR as well?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider migrating to diffrax

2 participants