Skip to content

Add a python wrapper#465

Open
henry2004y wants to merge 2 commits intomasterfrom
python-wrapper
Open

Add a python wrapper#465
henry2004y wants to merge 2 commits intomasterfrom
python-wrapper

Conversation

@henry2004y
Copy link
Owner

Handles #464

@gemini-code-assist
Copy link

Summary of Changes

Hello @henry2004y, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a Python wrapper for the TestParticle.jl Julia package, enabling Python users to leverage its functionality for tracing charged particles in electromagnetic fields. It establishes the necessary project structure, dependencies, and an API that mirrors the Julia package, facilitating cross-language scientific computing and expanding the accessibility of the TestParticle.jl library.

Highlights

  • Python Wrapper Creation: A new python/ directory was introduced to house the Python wrapper for TestParticle.jl.
  • Julia-Python Interoperability: The juliacall library was integrated to enable seamless interaction between Python and Julia code.
  • API Exposure: Numerous functions and types from TestParticle.jl were exposed to Python, including particle definitions, field functions, and tracing algorithms.
  • Julia '!' Convention Handling: Julia functions ending with ! (indicating in-place modification) are made available with a _b suffix in the Python wrapper for clarity.
  • Documentation and Project Setup: A README.md was added with installation and usage instructions, and pyproject.toml, MANIFEST.in, and juliapkg.json were configured for proper package management and build.
  • Initial Testing: Basic unit tests were included to verify the wrapper's functionality and the correct exposure of Julia types and functions.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • python/MANIFEST.in
    • Included the juliapkg.json file to ensure it is part of the Python package distribution.
  • python/README.md
    • Provided comprehensive installation instructions for the Python wrapper via pip.
    • Included basic usage examples to demonstrate how to initialize particles and define fields.
    • Detailed the API conventions, specifically how Julia functions with ! suffixes are handled.
  • python/juliapkg.json
    • Configured the Julia environment for juliacall, specifying the TestParticle package as a dependency and its local path.
  • python/pyproject.toml
    • Defined the Python project's metadata, including name, version, description, and license.
    • Specified Python version requirements and keywords for the package.
    • Declared juliacall as a core dependency and configured the build system using pdm-backend.
  • python/src/testparticle/init.py
    • Implemented the core logic for the Python wrapper, loading TestParticle.jl using juliacall.
    • Re-exported a wide array of TestParticle.jl functions and types, making them directly accessible in Python.
    • Established a convention for Julia functions ending with ! by appending _b to their Python counterparts.
  • python/tests/test_wrapper.py
    • Added a test to confirm that the testparticle module can be successfully imported.
    • Included tests to verify the accessibility of basic Julia types like Proton and Electron and their properties.
    • Implemented a test for the get_gyrofrequency function to ensure correct numerical output.
Activity
  • No activity has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a Python wrapper for the TestParticle.jl Julia package. The overall structure is sound, with a pyproject.toml for packaging, juliacall for interoperability, and basic tests. However, there are a few critical issues that need to be addressed before this package can be distributed and used reliably. The juliapkg.json is configured for local development only, which will break installation for end-users. The pyproject.toml contains a syntax error and inconsistent URLs. Additionally, the usage example in the README is incomplete, and the test suite lacks coverage for the core tracing functionality. Addressing these points will significantly improve the quality and usability of the Python wrapper.

Comment on lines +3 to +8
"packages": {
"TestParticle": {
"uuid": "953b605b-f162-4481-8f7f-a191c2bb40e3",
"path": ".."
}
}

Choose a reason for hiding this comment

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

critical

The "path": ".." configuration is suitable for local development but will cause installation to fail for users who install this package from PyPI. When a user installs testparticle-jl, juliacall will try to find the Julia package at a relative path .. which won't exist on their system. To make this package distributable, please replace the path with a version since TestParticle.jl is in the General registry.

Suggested change
"packages": {
"TestParticle": {
"uuid": "953b605b-f162-4481-8f7f-a191c2bb40e3",
"path": ".."
}
}
"packages": {
"TestParticle": {
"uuid": "953b605b-f162-4481-8f7f-a191c2bb40e3",
"version": "0.18.6"
}
}

Comment on lines +30 to +33
# Prepare the trace problem
# Note: Complex setup might require using Julia types directly via `jl` or helper functions
# This is a placeholder for actual usage logic dependent on TestParticle.jl API
```

Choose a reason for hiding this comment

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

medium

The usage example is currently a placeholder and doesn't show how to perform a particle trace. To improve usability for new users, please provide a complete, minimal working example that demonstrates a call to one of the trace functions and shows what the output looks like. This would be much more helpful than the current placeholder.

Comment on lines +88 to +110
__all__ = [
"prepare", "prepare_gc", "get_gc", "get_gc_func",
"trace_b", "trace_relativistic_b", "trace_normalized_b", "trace_relativistic_normalized_b",
"trace", "trace_relativistic", "trace_normalized", "trace_relativistic_normalized",
"trace_gc_b",
"trace_gc_drifts_b", "trace_gc_flr_b", "trace_gc_exb_b", "trace_fieldline_b", "trace_fieldline",
"get_gc_velocity", "full_to_gc", "gc_to_full",
"Proton", "Electron", "Ion",
"Maxwellian", "BiMaxwellian", "Kappa", "BiKappa",
"AdaptiveBoris", "AdaptiveHybrid",
"CurrentLoop", "getB_loop",
"get_gyrofrequency",
"get_gyroperiod", "get_gyroradius", "get_velocity", "get_energy", "get_mean_magnitude",
"energy2velocity", "get_curvature_radius", "get_adiabaticity",
"sample_unit_sphere", "get_number_density_flux",
"getB_zpinch", "getB_bottle", "getB_mirror", "getB_tokamak_coil",
"orbit", "monitor",
"get_fields", "get_work",
"LazyTimeInterpolator",
"TraceProblem", "TraceGCProblem", "TraceHybridProblem",
"CartesianGrid", "RectilinearGrid", "StructuredGrid",
"__version__", "jl"
]

Choose a reason for hiding this comment

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

medium

The __all__ list is quite long and manually maintained, which can be prone to errors and omissions as the wrapped Julia API evolves. While acceptable, you might consider generating this list dynamically to improve maintainability. For example, you could iterate over dir(jl.TestParticle) and filter for public functions/types to build the list and perform the assignments.

Comment on lines +20 to +29
def test_gyrofrequency():
import testparticle as tp

# B = 1.0 (scalar or magnitude), q = 1.0, m = 1.0
# The signature in Julia is usually get_gyrofrequency(B, species) or (B, q, m)
# Let's check (B, q, m)

omega = tp.get_gyrofrequency(1.0, 1.0, 1.0)
assert abs(omega - 1.0) < 1e-6

Choose a reason for hiding this comment

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

medium

The current tests are a good start, but they only cover basic type checks and one utility function. The core functionality of the wrapper, which is particle tracing via the trace functions, is not tested. Please add a test case for at least one of the trace functions. This will increase confidence in the wrapper's correctness and also serve as a valuable usage example for developers and users.

@codecov
Copy link

codecov bot commented Feb 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.04%. Comparing base (66ce307) to head (75af27a).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #465   +/-   ##
=======================================
  Coverage   82.04%   82.04%           
=======================================
  Files          21       21           
  Lines        2061     2061           
=======================================
  Hits         1691     1691           
  Misses        370      370           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

Benchmark Results (Julia v1)

Time benchmarks
master 75af27a... master / 75af27a...
interpolation/cartesian 0.131 ± 0.002 μs 0.107 ± 0.003 μs 1.22 ± 0.039
interpolation/spherical 0.476 ± 0.005 μs 0.452 ± 0.044 μs 1.05 ± 0.1
interpolation/time-dependent 3.65 ± 0.47 μs 3.98 ± 2.5 μs 0.917 ± 0.58
trace/GC/DiffEq Vern6 5.44 ± 1.2 μs 5.45 ± 1.1 μs 0.998 ± 0.3
trace/GC/Native RK4 0.132 ± 6.4e-05 s 0.129 ± 4e-05 s 1.03 ± 0.00059
trace/GC/Native RK45 3.24 ± 0.16 μs 3.2 ± 0.15 μs 1.01 ± 0.068
trace/Hybrid/Sheared 1.96 ± 0.16 μs 1.94 ± 0.16 μs 1.01 ± 0.12
trace/analytic field/in place 0.0633 ± 0.028 ms 0.0629 ± 0.027 ms 1.01 ± 0.61
trace/analytic field/in place relativistic 0.0823 ± 0.027 ms 0.0829 ± 0.026 ms 0.992 ± 0.46
trace/analytic field/out of place 0.0451 ± 0.026 ms 0.045 ± 0.02 ms 1 ± 0.73
trace/normalized/out of place 15.7 ± 6.5 μs 15.7 ± 6.2 μs 1 ± 0.57
trace/numerical field/Adaptive Boris 4.52 ± 0.11 ms 4.52 ± 0.083 ms 0.998 ± 0.03
trace/numerical field/Boris 8.03 ± 0.11 μs 8.01 ± 0.11 μs 1 ± 0.019
trace/numerical field/Boris ensemble 16 ± 0.16 μs 16 ± 0.17 μs 1 ± 0.015
trace/numerical field/Boris kernel 9.34 ± 0.17 μs 9.37 ± 0.16 μs 0.997 ± 0.025
trace/numerical field/Boris with fields 8.77 ± 0.14 μs 8.76 ± 0.11 μs 1 ± 0.02
trace/numerical field/Multistep Boris 11 ± 0.12 μs 11 ± 0.12 μs 1 ± 0.015
trace/numerical field/in place 27.4 ± 3.8 μs 26.3 ± 3.8 μs 1.04 ± 0.21
trace/numerical field/out of place 19.4 ± 3.7 μs 19.7 ± 3.7 μs 0.988 ± 0.26
trace/time-dependent field/in place 0.132 ± 0.0099 ms 0.134 ± 0.0098 ms 0.986 ± 0.1
trace/time-dependent field/out of place 0.109 ± 0.0093 ms 0.113 ± 0.0095 ms 0.967 ± 0.12
time_to_load 2.1 ± 0.052 s 2.09 ± 0.017 s 1.01 ± 0.026
Memory benchmarks
master 75af27a... master / 75af27a...
interpolation/cartesian 2 allocs: 0.234 kB 2 allocs: 0.234 kB 1
interpolation/spherical 2 allocs: 0.203 kB 2 allocs: 0.203 kB 1
interpolation/time-dependent 0.044 k allocs: 9.62 kB 0.044 k allocs: 9.62 kB 1
trace/GC/DiffEq Vern6 0.177 k allocs: 12.1 kB 0.177 k allocs: 12.1 kB 1
trace/GC/Native RK4 13 allocs: 0.382 MB 13 allocs: 0.382 MB 1
trace/GC/Native RK45 16 allocs: 2.44 kB 16 allocs: 2.44 kB 1
trace/Hybrid/Sheared 8 allocs: 2.98 kB 8 allocs: 2.98 kB 1
trace/analytic field/in place 2.07 k allocs: 0.0883 MB 2.07 k allocs: 0.0883 MB 1
trace/analytic field/in place relativistic 2.07 k allocs: 0.0883 MB 2.07 k allocs: 0.0883 MB 1
trace/analytic field/out of place 2.03 k allocs: 0.0865 MB 2.03 k allocs: 0.0865 MB 1
trace/normalized/out of place 0.753 k allocs: 0.0321 MB 0.753 k allocs: 0.0321 MB 1
trace/numerical field/Adaptive Boris 27 allocs: 1.5 MB 27 allocs: 1.5 MB 1
trace/numerical field/Boris 6 allocs: 1.16 kB 6 allocs: 1.16 kB 1
trace/numerical field/Boris ensemble 10 allocs: 2.28 kB 10 allocs: 2.28 kB 1
trace/numerical field/Boris kernel 0.038 k allocs: 2.12 kB 0.038 k allocs: 2.12 kB 1
trace/numerical field/Boris with fields 6 allocs: 1.52 kB 6 allocs: 1.52 kB 1
trace/numerical field/Multistep Boris 6 allocs: 1.16 kB 6 allocs: 1.16 kB 1
trace/numerical field/in place 0.432 k allocs: 20.7 kB 0.432 k allocs: 20.7 kB 1
trace/numerical field/out of place 0.393 k allocs: 18.5 kB 0.393 k allocs: 18.5 kB 1
trace/time-dependent field/in place 3.97 k allocs: 0.177 MB 3.97 k allocs: 0.177 MB 1
trace/time-dependent field/out of place 3.93 k allocs: 0.175 MB 3.93 k allocs: 0.175 MB 1
time_to_load 0.145 k allocs: 11 kB 0.145 k allocs: 11 kB 1

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.

1 participant