Skip to content

Conversation

@balos1
Copy link
Member

@balos1 balos1 commented Nov 11, 2025

This PR adds sundials4py, which is a Python interface to SUNDIALS.

The generator code can be found here: https://github.com/sundials-codes/sundials4py-generate.

Rendered docs: https://sundials--796.org.readthedocs.build/en/796/.

Review Requests

@drreynolds:

  • doc/
  • bindings/sundials4py/arkode
  • bindings/sundials4py/idas
  • bindings/sundials4py/kinsol
  • bindings/sundials4py/sundomeigest
  • bindings/sundials4py/sunlinsol
  • bindings/sundials4py/sunmatrix
  • bindings/sundials4py/examples

@gardner48:

Everything but can skip:

  • _generated.hpp files (Steven and I will review these)
  • bindings/sundials4py/examples (Steven and Dan are both reviewing these)
  • bindings/sundials4py/arkode (Steven and Dan both reviewing these)
  • bindings/sundials4py/idas (Steven and Dan both reviewing these)

@Steven-Roberts

  • Skim _generated.hpp files in bindings/sundials4py
  • bindings/sundials4py/arkode
  • bindings/sundials4py/idas
  • bindings/sundials4py/include
  • bindings/sundials4py/sundials
  • bindings/sundials4py/nvector
  • bindings/sundials4py/sunadaptcontroller
  • bindings/sundials4py/sunadjointcheckpointscheme
  • bindings/sundials4py/sunnonlinsol
  • bindings/sundials4py/sunmemory
  • bindings/sundials4py/examples
  • https://github.com/sundials-codes/sundials4py-generate

Copy link
Member

@gardner48 gardner48 left a comment

Choose a reason for hiding this comment

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

Finished a pass over the PR updates. Still need to make a pass over the docs.

merge-multiple: true

- name: Upload wheels to release
uses: softprops/action-gh-release@v1
Copy link
Member

Choose a reason for hiding this comment

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

I was going to suggest we enable immutable releases in the repo, do you know if this action would work with a draft release (see the suggested workflow)?

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe that it should work with drafts.

Copy link
Member

Choose a reason for hiding this comment

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

Only actions from a limited number for sources are allowed (see the error here), so we'll need to remove this job.


if (cv_mem->proj_mem) { cvProjFree(&(cv_mem->proj_mem)); }

free(cv_mem->python);
Copy link
Member

Choose a reason for hiding this comment

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

Should we remove python from CVodeMemRec?

Copy link
Member

Choose a reason for hiding this comment

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

Also need to remove free(IDA_mem->python); in src/ida.c (and maybe remove python from IDAMemRec).

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, we could remove it from CVode and IDA. I will do that.

Copy link
Member

@gardner48 gardner48 left a comment

Choose a reason for hiding this comment

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

Starting in on the docs

sphinx-toolbox
sphinxcontrib-googleanalytics
sphinx-multitoc-numbering
sphinxcontrib.bibtex
git+https://github.com/LLNL/sundials.git@feature/python-nanobind
Copy link
Member

Choose a reason for hiding this comment

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

This works for building the docs in this PR but what should this be after this is merged?

Copy link
Member Author

@balos1 balos1 Jan 13, 2026

Choose a reason for hiding this comment

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

sundials4py or the main/develop branch

Copy link
Member

@gardner48 gardner48 Jan 13, 2026

Choose a reason for hiding this comment

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

Would this work for newly added functions in a PR?

Copy link
Member Author

@balos1 balos1 Jan 13, 2026

Choose a reason for hiding this comment

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

We probably need to replace the entry in the requirements.txt with a pip install command in the driver script(s) that uses the cloned branch. Now, though, I am curious how this may work with RTD builds. Particularly, for features like CUDA support. RTD would need to have a build with CUDA enabled. We may need to generate the API files offline.

Copy link
Member

Choose a reason for hiding this comment

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

We could probably setup up a workflow for CUDA like we have for SYCL where it's just for build testing. AMReX has something like this here (and similarly for hip here).


void bind_sunadjointcheckpointscheme_fixed(nb::module_& m);

void bind_sundomeigest_power(nb::module_& m);
Copy link
Member

@gardner48 gardner48 Jan 13, 2026

Choose a reason for hiding this comment

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

It might be helpful to users to have a table like we do for Fortran e.g., we list the core but it's not clear which of the implementations of the core classes are included without searching the list of functions provided by the core module.

status = ARKodeSetLinearSolver(ark.get(), ls, A)
assert status == ARK_SUCCESS

def jac_fn(t, yvec, fyvec, J, tmp1, tmp2, tmp3, _):
Copy link
Member

Choose a reason for hiding this comment

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

Is the underscore in the right place?

Suggested change
def jac_fn(t, yvec, fyvec, J, tmp1, tmp2, tmp3, _):
def jac_fn(t, yvec, fyvec, J, _, tmp1, tmp2, tmp3):

# sunrealtype* lambdaR, sunrealtype* lambdaI,
# void* user_data, N_Vector temp1,
# N_Vector temp2, N_Vector temp3)
def dom_eig(t, yvec, fnvec, temp1, temp2, temp3, _):
Copy link
Member

Choose a reason for hiding this comment

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

Is this ordering correct?

Suggested change
def dom_eig(t, yvec, fnvec, temp1, temp2, temp3, _):
def dom_eig(t, yvec, fnvec, _, temp1, temp2, temp3):


Introduction.rst
Usage.rst
sundials4py-core-functions.rst
Copy link
Member

@gardner48 gardner48 Jan 14, 2026

Choose a reason for hiding this comment

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

A couple of comments from looking over the autogenerated docs. Not sure how easy some of these are to address (or if they need to be), so this might be something that we work on while the interface is in beta.

  • The SUNErrCode enum is listed but I thought these values were not accessible from Python (see this comment)
  • Maybe some things should be excluded from the docs e.g.,
    • Enumerations, since they have the same values as in C
    • Structures the user shouldn't need to interact with like class sundials4py.core._generic_N_Vector_Ops(*args, **kwargs). The addition of (*args, **kwargs) might also be confusing (I assume they are unused)
  • It might be more useful to co-locate the python signatures with the C functions since they are mostly a link back to the C docs for additional details about the function and its inputs/outputs.
  • The signatures are maybe more verbose than necessary e.g.,
    sundials4py.core.N_VMake_Serial(vec_length: int, v_data_1d: numpy.ndarray[dtype=float64, shape=(*), order='C'], sunctx: sundials4py.core.SUNContext_) → [sundials4py.core._generic_N_Vector]
    
    could maybe be more like
    N_VMake_Serial(vec_length, v_data_1d, sunctx) → [N_Vector]
    
    or the additional details about the types could be in the body of the function documentation.

cd sundials_root_directory
python -m venv .venv # create python virtual environment
. .venv/bin/activate # activate the python virtual environment
pip install scikit-build-core[pyproject] hatchling nanobind # this is a prerequisite for the next step
Copy link
Member

Choose a reason for hiding this comment

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

To build the interface I had to do

pip install scikit-build-core[pyproject] hatchling nanobind setuptools scikit-build pybind11


If you are developing new features inside of sundials, you may also need to install the Python code generator package,
`sundials4py-generate <https://github.com/sundials-codes/sundials4py-generate>`__. The steps to install this package are
found in its repo.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe I'm missing it, but I don't see install instructions in the repo

merge-multiple: true

- name: Upload wheels to release
uses: softprops/action-gh-release@v1
Copy link
Member

Choose a reason for hiding this comment

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

Only actions from a limited number for sources are allowed (see the error here), so we'll need to remove this job.

Copy link
Member

@gardner48 gardner48 left a comment

Choose a reason for hiding this comment

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

Finished a pass over the docs

not the correctness of SUNDIALS itself.


User-supplied functions
Copy link
Member

Choose a reason for hiding this comment

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

Add a note about about when/why we need the StdFn version of the wrappers (see this comment).

*jcurPtrB = std::get<1>(result);

return std::get<0>(result);
}
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to add a section on things to note when handwriting wrappers. A few things that came up in the review:

  • When a wrapper can't be autogenerated and needs to be handwritten (for example this comment)
  • Using keep_alive (see this comment)
  • Use .none() when we need to allow for passing None (see this comment)

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants