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

Starting an attempt to remove default particle assumptions #911

Merged
merged 28 commits into from
Oct 14, 2020
Merged

Starting an attempt to remove default particle assumptions #911

merged 28 commits into from
Oct 14, 2020

Conversation

arichar6
Copy link
Contributor

@arichar6 arichar6 commented Oct 5, 2020

This is my attempt to remove default values from functions that take a particle as input in formulary/parameters.py.

This is described in issue #453.

  • I have added a changelog entry for this pull request.
  • If adding new functionality, I have added tests and docstrings. (Well, mostly I changed the docstrings to reflect the fact that some arguments that used to be optional now are required.
  • I have fixed any newly failing tests.

@rocco8773 rocco8773 added refactoring ♻️ Improving an implementation without adding new functionality plasmapy.formulary Related to the plasmapy.formulary subpackage labels Oct 5, 2020
@rocco8773
Copy link
Member

@arichar6 Thanks for taking this on! Issue #453 was created before I started working on plasmapy, but I absolutely agree with it. With that said, we shouldn't even give the ion and particle keywords are default value of None. Instead we should make them a required argument like...

def Alfven_speed(B, density, ion, z_mean=None):
    ...

or

def Alfven_speed(B, density, *, ion, z_mean=None):
    ...

The latter keeps ion as a keyword-only argument, whereas, the former makes it a keyword and positional argument.

Additionally, we should add a proper annotation Union[str, Particle], which would look something like...

def Alfven_speed(B: u.T, density: [u.m ** -3, u.kg / u.m ** 3], *, ion: Union[str, Particle], z_mean=None):
    ...

@arichar6
Copy link
Contributor Author

arichar6 commented Oct 6, 2020

Thanks for the feedback!

I'll remove the None defaults, and add the type annotations.

Also added type annotations for the particles. Still need to fix the tests.
@arichar6
Copy link
Contributor Author

arichar6 commented Oct 6, 2020

I still have to fix the tests that now fail. But the defaults should be fixed now, and type annotations added.

@arichar6
Copy link
Contributor Author

arichar6 commented Oct 6, 2020

As I was working on the tests, I realized that one change might introduce a backwards-incompatibility.
I made the ion argument in the ion_sound_speed function a keyword-only argument. I'm not sure how to remove the default value without making it keyword-only, since arguments that come before it have default values.

An alternative would be to change the order of the arguments to the function, but that seems worse somehow.

Thoughts?

** edit **
Thinking about this more, I suspect it's ok. Removing the defaults is going to break backwards compatibility anyway. But I still would like to hear your thoughts on this.

@codecov
Copy link

codecov bot commented Oct 6, 2020

Codecov Report

Merging #911 into master will decrease coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #911      +/-   ##
==========================================
- Coverage   96.21%   96.21%   -0.01%     
==========================================
  Files          60       60              
  Lines        5417     5416       -1     
==========================================
- Hits         5212     5211       -1     
  Misses        205      205              
Impacted Files Coverage Δ
plasmapy/formulary/collisions.py 97.19% <100.00%> (+0.43%) ⬆️
plasmapy/formulary/parameters.py 99.01% <100.00%> (+<0.01%) ⬆️
plasmapy/utils/pytest_helpers/pytest_helpers.py 93.04% <0.00%> (-0.37%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6d5651c...c1d3213. Read the comment docs.

Copy link
Member

@namurphy namurphy left a comment

Choose a reason for hiding this comment

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

Thank you for working on this! Most of my suggestions are related to annotations for particle inputs, in particular that the annotation will need to be Particle for when we eventually implement the @particle_input decorator to this file (#341). Otherwise, all of the changes look great. Thank you again!

Many of the suggested changes are related to the @particle_input decorator which still needs to implemented in the formulary

Otherwise, all of the changes look great.

plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
@arichar6
Copy link
Contributor Author

arichar6 commented Oct 8, 2020

One more question. Now that we are using Particle as the type annotation, the docstrings should probably be updated from saying something like ion : str to ion : Particle, correct?

@arichar6 arichar6 marked this pull request as ready for review October 9, 2020 16:48
@rocco8773
Copy link
Member

@arichar6 It appears the documentation build errors are due to the jupyter notebooks not being updated, specifically /docs/notebooks/physics.ipynb. Do you want to give fixing this a try? Just make sure before committing your changes that you clear all cell outputs.

Copy link
Member

@rocco8773 rocco8773 left a comment

Choose a reason for hiding this comment

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

This is looking good! I only have a few minor changes plus the update of the jupyter notebook.


The rest of the plasmapy.formulary needs this treatment too, but I'm ok keeping that to a separate/followup PR.

Comment on lines 284 to 285
*,
ion: Particle,
Copy link
Member

Choose a reason for hiding this comment

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

This should look like....

def ion_sound_speed(
    T_e: u.K,
    T_i: u.K,
    ion: Particle,
    n_e: u.m ** -3 = None,
    k: u.m ** -1 = None,
    gamma_e=1,
    gamma_i=3,
    z_mean=None,
) -> u.m / u.s:

*, overly simplified, indicates the end to the positional arguments, so keyword-only arguments should not be defined before it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So you are ok with changing the order of the arguments in this function call? I was using the * entry so that I could keep the order of arguments the same, but have ion (with no default) come after the other arguments which do have defaults.

Copy link
Member

Choose a reason for hiding this comment

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

Keywords have no order associated with them, so doing this does not change the order at all. It does make ion a required argument that is either positional or keyword. So, the suggested makes the interface behave like...

ion_sound_speed(2*u.eV, 3*u.eV, "He+")

# or

ion_sound_speed(2*u.eV, 3*u.eV, ion="He+")

All the other arguments are keyword-only, so they can be specified in any order.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure why you say that all other arguments are keyword-only. I just tried, and you can specify an electron density and k by just giving them as the next arguments. No keywords needed.

>>> ion_sound_speed(2*u.eV, 3*u.eV, "He+", 1 * u.m**-3, 1 * u.m ** -1)
<Quantity 1.54899987 m / s>

plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
changelog/911.breaking.rst Outdated Show resolved Hide resolved
@arichar6
Copy link
Contributor Author

arichar6 commented Oct 9, 2020

Any insights into why the codecov test is failing now? I'm don't really quite know what it is check for, exactly.

@rocco8773
Copy link
Member

Any insights into why the codecov test is failing now? I'm don't really quite know what it is check for, exactly.

Looks like line 339 in collisions.py is not getting hit by tests. Without digging more, I'm not sure why this is the case.

@arichar6
Copy link
Contributor Author

arichar6 commented Oct 13, 2020

Looks like line 339 in collisions.py is not getting hit by tests. Without digging more, I'm not sure why this is the case.

I might be wrong, but it looks like line 339 in collisions.py is not accessible. Here are the preceding lines:

elif np.any(np.isnan(V)):
    if np.isscalar(V.value) and np.isscalar(T.value):
        V = parameters.thermal_speed(T, "e-", mass=m)
    elif np.isscalar(V.value):
        V = parameters.thermal_speed(T, "e-", mass=m)

I just tried this, and if np.any(np.isnan(V)) returns True for a numpy array (with astropy units), then np.isscalar(V.value) returns False. Was there some other case that this was trying to test for?

@namurphy
Copy link
Member

I might be wrong, but it looks like line 339 in collisions.py is not accessible. Here are the preceding lines:

I just tried this, and if np.any(np.isnan(V)) returns True for a numpy array (with astropy units), then np.isscalar(V.value) returns False. Was there some other case that this was trying to test for?

Hm...that's a good question. That's a bit strange so it would be worth looking into it further. It does seem outside of the intended scope of this pull request, so my suggestion would be to create a brief issue on it so that we can address it in a different pull request. I'm not a fan of long extensive if/elif statements so I'm wondering if there's a way to replace these if/elif blocks with polymorphism...but that is definitely for another day.

@namurphy
Copy link
Member

To follow up: there are a few other things in collisions.py that should probably be cleaned up, so I can create the other issue.

@namurphy namurphy mentioned this pull request Oct 13, 2020
7 tasks
changelog/911.breaking.rst Outdated Show resolved Hide resolved
plasmapy/formulary/parameters.py Outdated Show resolved Hide resolved
@arichar6
Copy link
Contributor Author

Ok. I think this PR is finally done. While this does not complete the changes required for #453, it does complete the changes needed in parameters.py.

Copy link
Member

@rocco8773 rocco8773 left a comment

Choose a reason for hiding this comment

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

Looks good to me! Thanks making these improvement.

Copy link
Member

@namurphy namurphy left a comment

Choose a reason for hiding this comment

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

Thank you again for doing this! It looks good to me so I think it's ready to merge.

@rocco8773 rocco8773 merged commit 3ecf372 into PlasmaPy:master Oct 14, 2020
@arichar6 arichar6 deleted the 453-remove-default-particles branch October 14, 2020 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plasmapy.formulary Related to the plasmapy.formulary subpackage refactoring ♻️ Improving an implementation without adding new functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants