Plasmapy: Decorator @from_particle

Created on 11 Oct 2020  Â·  4Comments  Â·  Source: PlasmaPy/PlasmaPy

I'm proposing a new decorator @from_particle that would act is similar fashion to @angular_freq_to_hz.

Why am I proposing this decorator? Using particle objects is a great way to simplify the passing of mass, charge, etc. parameters into a function. It's clean and simple. However, there are time where a user might want to define a custom mass, Z_mean, etc., which creates conflicts around which values to take and ensuring a function requires the arguments it needs to perform it's task. This occurs with many functions throughout the package.

Here's my solution and how it works.

@from_particle(mass={"grab": "mass"}, Z_mean={"grab": "integer_charge"}, kwarg_name="particle")
def plasma_frequency(n: u.m ** -3, *, mass: u.kg, Z_mean: float):
    # do calculation
    return wp

This would inject a kwarg named particle=None into the plasma_frequency function. If the particle kwarg is used, then getatttr(particle, "mass") would be mapped to arg mass and getatttr(particle, "interger_charge") would be mapped to arg Z_mean. If mass or Z_mean are defined, then they will override the getting from particle.

This would allows plasma_frequency to be used like...

plasma_frequency(2e18 * u.cm**-3, particle="He+")
plasma_frequency(2e18 * u.cm**-3, particle="He+", Z_mean=1.2)
plasma_frequency(2e18 * u.cm**-3, particle="He+", Z_mean=1.2, mass=5.0e-27 * u.kg)
plasma_frequency(2e18 * u.cm**-3, Z_mean=1.2, mass=5.0e-27 * u.kg)

I prefer this interface because (1) it keeps the clean, simplistic use of the particle kwarg, (2) keeps a function signature that is inline with the real formula (i.e. requiring mass, Z_mean, etc.), (3) keeps a clean use when using mass, Z_mean, etc., (4) standardizes the reconciliation between the use of particle and required non-particle arguments, and (5) by building this functionality into a decorator we can easily apply it throughout the package.

Formulary Particles Utilities

All 4 comments

Some thoughts:

  • I'd prefer to drop arguments like Z_mean and mass entirely, and require users to supply a Particle, CustomParticle, or a unique representation of a particle that gets transformed into a Particle or CustomParticle. (_Edit: I was convinced that having the classical interface is helpful for new users._) At present, the purpose of @particle_input is to transform representations of particles into Particle instances, so there's some overlap between @particle_input and this decorator.
  • I expect that CustomParticle will be used much less frequently than Particle or something particle-like. Most use cases for the formulary involve using known particles, and I'd rather encourage users to start using Particle and CustomParticle instead. Hence we probably shouldn't prioritize use cases involving custom particles when designing our API.

The alternative I'm supporting at the moment would be for @particle_input to treat a mass or a charge as a unique (particle-like) representation of a CustomParticle, and then transform the corresponding argument to a CustomParticle instance (noting that a CustomParticle presently does not need to be supplied with _both_ a charge and a mass).

I think it'd be helpful to talk about this again during our community meeting this week or next, since we could probably come to a consensus that way.

I see this solution as a "having your cake and eating to" solution. I absolutely agree that the primary interface should be using particle, and this allows for that. However, I disagree with dropping arguments like mass, Z, etc. altogether. Why? (1) I think some users would still want to have a more traditional interface, even though I think a lot of them would migrate over once they get use to the idea. Not having that traditional interface could discourage their initial adoption. This is exactly how I can around to the particle interface. (2) A big part of our charter is being educational and, I feel, hiding the traditional interface could be side-effects to that effort.

There is some cross-over with @particle_input but I view what is discussed here as a different problem and would be too much to include in @particle_input. That could change after some prototyping, but I'm doubtful.

We talked about this issue at the community meeting today, and here were the points that were made and opinions that were expressed...at least as much as I can remember them!

  1. Requiring that people use Particle or CustomParticle could be a barrier to entry because it would be one more thing they would need to figure out before they get started. It is helpful for new users to have access to the "classical" interface where they can put in things like the charge and mass directly.
  2. In this code...
    Python plasma_frequency(2e18 * u.cm**-3, particle="He+", Z_mean=1.2)
    There is a contradiction between the charge given by the particle and Z_mean arguments. Possibilities for dealing with this contradiction include:

    • Raising an exception because it's not clear that Z_mean overrides the charge, with an error message saying something like "He+" should be changed to "He"

    • Issuing a warning that Z_mean overrides the charge in the particle argument so that this doesn't happen silently

    • Putting in the documentation that Z_mean overrides the charge in the particle argument

  3. There was discussion about whether or not the Particle or CustomParticle instances should be used inside functions. There were differing opinions on whether it was preferable to use things like ion.mass (more explicit) or just mass (shorter) inside a function. There was a concern that it might not be immediately clear what mass refers to, and another concern that mass and charge would be decoupled from each other when they should be part of the same object. The decorator would be doing something that is effectively like:
    Python mass = particle.mass Z_mean = particle.charge
  4. With respect to the last point, @from_particle would kind of go in the opposite direction as @particle_input. @from_particle would (sometimes) take a Particle argument and decompose it into mass and charge, whereas @particle_input takes a representation of a particle and converts it into a Particle.
  5. For more complicated functions that, say, deal with multiple particles, @from_particle should not be used. Instead, it should be required to use a Particle or CustomParticle.

@rocco8773 — please feel free to add or correct anything I didn't capture completely!

My preference right now would be to expand the capabilities of @particle_input:

  1. Have @particle_input look for mass and Z or Z_mean keyword arguments.
  2. If these keyword arguments are found, transform them into a CustomParticle
  3. Do the calculations with a Particle or CustomParticle inside the function, rather than having separate variables for, e.g., mass and charge.

But I'm still thinking about it!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

namurphy picture namurphy  Â·  4Comments

lemmatum picture lemmatum  Â·  6Comments

lemmatum picture lemmatum  Â·  5Comments

ritiek picture ritiek  Â·  6Comments

lemmatum picture lemmatum  Â·  4Comments