Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a ParticleCollection class #948

Closed
namurphy opened this issue Oct 30, 2020 · 1 comment · Fixed by #1017
Closed

Create a ParticleCollection class #948

namurphy opened this issue Oct 30, 2020 · 1 comment · Fixed by #1017
Labels
feature request Issues requesting a new feature or enhancement plasmapy.particles Related to the plasmapy.particles subpackage
Milestone

Comments

@namurphy
Copy link
Member

The Particle class currently provides a means of representing a single particle, and we also have CustomParticle and DimensionlessParticle. It would be helpful to have a ParticleCollection class that we could use to represent multiple particles together. That class could have attributes like mass that would return an array with units of mass so that we can do array operations and the like...and the same for other properties like charge too.

Here's a use case that came from a discussion on Element. Suppose we want to find the thermal velocities of all of the ions in a multi-component plasma. If we have a ParticleCollection class, we could do something like:

>>> particles = ParticleCollection(['p+', 'He-4 1+', 'O-16 1+'])
>>> v_th = thermal_speed(1 * u.MK, particles)

If we make it iterable then we could also do things like:

particles = ParticleCollection([...])
for particle in particles:
    print(thermal_speed(1 * u.MK, particle)

This class shouldn't include transitory properties like temperature, since that's not what the Particle class does. That should be in a different class...perhaps something like MultiComponentPlasma and/or we could have something like Species that keeps track of the plasma parameters for a single species in a plasma...but that is not for this issue.

Probably the best way to approach this class would be to split up development into multiple pull requests. The first could create a prototype of the class, the next could add __iter__ and __next__ to make it iterable, and so on. That'd make code review more manageable.

@namurphy namurphy added plasmapy.particles Related to the plasmapy.particles subpackage feature request Issues requesting a new feature or enhancement labels Oct 30, 2020
@StanczakDominik
Copy link
Member

StanczakDominik commented Nov 4, 2020

I think a common problem here is that we ask ourselves how to do things, and not whether we should...

This kind of call:

>>> particles = ParticleCollection(['p+', 'He-4 1+', 'O-16 1+'])
>>> v_th = thermal_speed(1 * u.MK, particles)

is supposedly necessary because we don't currently have, in Python, a good way of saying "apply this function, in a fast and vectorized way, for each of these arguments". The closest we come is the good old list comprehension:

>>> particles = ['p+', 'He-4 1+', 'O-16 1+']
>>> v_th = [thermal_speed(1 * u.MK, p) for p in particles]

Which has the advantage of being common Python syntax, but is still slow-ish.

For comparison with an alternate approach, here's broadly how this is handled in Julia:

>>> particles = ['p+', 'He-4 1+', 'O-16 1+']
>>> v_th = thermal_speed.(1 * u.MK, particles)  # note the dot

Where the dot basically signifies broadcasting/loop fusion - "apply this to each element".

My problem here is that I don't see a way of sidestepping the speed issue with any ParticleCollection custom object, and I don't currently see any real gain otherwise - either we make the user wrap their Particles in a custom collection of them (as opposed to a list, set, dictionary, or something from collections), or we make them write an explicit list comprehension.

Both approaches kind of suck, but the latter creates less surface area for us as a library, introduces less maintenance overhead... So I'm in favor of closing this.


Hypothetically, we could instead mess around with trying to turn our Formulary functions into NumPy ufuncs through Numba; to quote:

Using vectorize(), you write your function as operating over input scalars, rather than arrays. Numba will generate the surrounding loop (or kernel) allowing efficient iteration over the actual inputs.

But of course, the problem with that is, as usual, going to be units. I imagine we could potentially sidestep that somehow, but... I don't know just yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues requesting a new feature or enhancement plasmapy.particles Related to the plasmapy.particles subpackage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants