Skip to content

Conversation

@theo-brown
Copy link
Collaborator

@theo-brown theo-brown commented Dec 15, 2025

Prompted by JINTRAC NCLASS comparison of Sauter and Redl models, this has been bumped up my priority list!

When I have time, I'll try and rearrange some of the definitions and files so there's less duplication.

Closes #1612.

@theo-brown
Copy link
Collaborator Author

theo-brown commented Dec 15, 2025

STEP (dashed Redl, solid Sauter)

Figure_1

ITER (dashed Redl, solid Sauter)

Figure_1

@theo-brown
Copy link
Collaborator Author

@jcitrin as this is really an extension of the Sauter model, would you like it as a separate class, subclass, or flag within Sauter?

@jcitrin
Copy link
Collaborator

jcitrin commented Dec 24, 2025

Excellent, thanks for this.

It would be good to have redl as a separate class, even if it's quite similar to sauter, and ensure that "sauter" and "redl" can be distinct model names. Possibly a lot from both can be separated out to use the common formulas module and duplication minimized, as you say.

It may be good to do this in more than 1 PR, separating out refactoring and new feature.

lmk when review is necessary and we can get back to this in the new year. Have a great holiday period!

@theo-brown
Copy link
Collaborator Author

theo-brown commented Dec 30, 2025

I suggest the following design:

  1. Move neoclassical.formulas to a subpackage, so that we can have neoclassical.formulas.shared, neoclassical.formulas.sauter and neoclassical.formulas.redl.

  2. Extract the shared code from

    # calculate bootstrap current
    prefactor = -geo.F_face * bootstrap_multiplier * 2 * jnp.pi / geo.B_0
    pe = p_e.face_value()
    pi = p_i.face_value()
    dpsi_drnorm = psi.face_grad()
    dlnne_drnorm = n_e.face_grad() / n_e.face_value()
    dlnni_drnorm = n_i.face_grad() / n_i.face_value()
    dlnte_drnorm = T_e.face_grad() / T_e.face_value()
    dlnti_drnorm = T_i.face_grad() / T_i.face_value()
    global_coeff = prefactor[1:] / dpsi_drnorm[1:]
    global_coeff = jnp.concatenate([jnp.zeros(1), global_coeff])
    necoeff = L31 * pe
    nicoeff = L31 * pi
    tecoeff = (L31 + L32) * pe
    ticoeff = (L31 + alpha * L34) * pi
    j_parallel_bootstrap_face = global_coeff * (
    necoeff * dlnne_drnorm
    + nicoeff * dlnni_drnorm
    + tecoeff * dlnte_drnorm
    + ticoeff * dlnti_drnorm
    )
    j_parallel_bootstrap = geometry_lib.face_to_cell(j_parallel_bootstrap_face)
    return base.BootstrapCurrent(
    j_parallel_bootstrap=j_parallel_bootstrap,
    j_parallel_bootstrap_face=j_parallel_bootstrap_face,
    )

    into a new function

neoclassical.formulas.shared._calculate_analytic_bootstrap_current(
    *,
    bootstrap_multiplier: float,
    n_e: cell_variable.CellVariable,
    n_i: cell_variable.CellVariable,
    T_e: cell_variable.CellVariable,
    T_i: cell_variable.CellVariable,
    p_e: cell_variable.CellVariable,
    p_i: cell_variable.CellVariable,
    geo: geometry_lib.Geometry,
    L31: array_typing.FloatVectorFace,
    L32: array_typing.FloatVectorFace,
    L34: array_typing.FloatVectorFace,
    alpha: array_typing.FloatVectorFace,
  ) -> base.BootstrapCurrent
  1. Make a new function for each of Sauter and Redl that computes the terms that are different, e.g.
neoclassical.bootstrap.sauter.calculate_bootstrap_terms(...) -> ...:
  f_trap = neoclassical.formulas.sauter.calculate_ftrap(...)
  log_lambda_ei = collisions.calculate_log_lambda_ei(...)
  log_lambda_ii = collisions.calculate_log_lambda_ii(...)
  nu_e_star = collisions.calculate_nu_e_star(...)
  nu_e_star = collisions.calculate_nu_i_star(...)

  L31 = neoclassical.formulas.sauter.calculate_L31(...)
  L32 = neoclassical.formulas.sauter.calculate_L32(...)
  L34 = neoclassical.formulas.sauter.calculate_L34(...)
  alpha = neoclassical.formulas.sauter.calculate_alpha(...)
 
  return L31, L32, L34, alpha

I think this is the most simple option that minimises duplication. Also I think this structure sets up Andreas' intent to do the new conductivity model. @jcitrin thoughts?

@jcitrin
Copy link
Collaborator

jcitrin commented Jan 2, 2026

@theo-brown this structure sounds good to me.

@tamaranorman , @Nush395 , any thoughts on the proposed structure? Context: Theo and Andreas Redl are implementing the Redl model for bootstrap current and conductivity, which is an upgrade on the sauter model. Structurally it's very similar to the sauter models, but have slightly different formulas and coefficients. Theo's proposal aims to minimize the duplication and still have both sauter and redl as model types.

@theo-brown theo-brown requested review from Nush395 and tamaranorman and removed request for tamaranorman January 5, 2026 09:46
@theo-brown theo-brown added the ready for review Add to PRs when they are ready for review unsure of who to assign as reviewer label Jan 5, 2026
from absl.testing import parameterized
import numpy as np
import xarray as xr
from absl.testing import absltest, parameterized
Copy link
Member

Choose a reason for hiding this comment

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

Revert these changes the google style guide recommend everything be imported per module excluding types or similar

Copy link
Member

Choose a reason for hiding this comment

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

Can we add a unit test on the numerics of this file etc instead of just testing through integration tests?

Copy link
Member

Choose a reason for hiding this comment

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

Do we need this if its also tested as part of the step case? Just that as we add more and more of these the time taken for tests change - it would be cleaner if this could be tested in a unit test

@tamaranorman
Copy link
Member

Looks good in its current form - one question is when we talk about rearranging what does that look like as this currently is just adding another implementation

@theo-brown
Copy link
Collaborator Author

theo-brown commented Jan 5, 2026

Thanks for your review @tamaranorman! I was mainly @'ing you for your thoughts on the comment, sorry.

See my comment above for my proposed structure (link) - I didn't want to waste time implementing before a design had been chosen.

The "changes to structure" are just moving things around, rather than introducing any new classes etc. I think Jonathan was just to check whether there's an alternative (eg create a new superclass that both of these inherit from) or whether having this level of code duplication is ok/acceptable/avoidable.

@theo-brown theo-brown removed the ready for review Add to PRs when they are ready for review unsure of who to assign as reviewer label Jan 5, 2026
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.

Add Redl model of bootstrap current

3 participants