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

ENH: Streamplot control for integration max step and error #29333

Merged
merged 3 commits into from
Dec 22, 2024

Conversation

eytanadler
Copy link
Contributor

@eytanadler eytanadler commented Dec 17, 2024

PR summary

In some cases, it is desirable to control the step size or allowable error in the streamline integration routine. One that has come up for me is forcing smaller integration steps to better align the edges of a streamline to the boundary of a region where streamlines are added. In other cases, maybe the streamline integration is taking too long and it'd be desirable to allow it to take bigger steps.

This PR adds two two optional arguments to matplotlib's streamplot function to control this behavior as desired:

  • integration_max_step: a multiplier on the maximum step computed in the integration routine
  • integration_max_error: a multiplier on the default maximum error allowed by the integration routine (which is just a hard-coded, hand-tuned value)

PR checklist

@oscargus
Copy link
Member

This makes sense (as in no harm in adding it and useful when needed).

Two things:

  1. The reason that the tests are failing is that pyplot is not updated, please run python tools/boilerplate.py to generate a version with the new arguments.
  2. Please add a note in doc/users/next_whats_new (using the template) which simply states that these are added. I think it would be nice for users to know this as others may have similar need to control it.

One may consider adding a bit more description about the effects of changing the value. Although, it may be obvious once you're into it, it may take a bit of thinking to figure out what a larger or smaller value will lead to. Maybe just a simple statement as "For a value larger than 1, the streamline computation will be faster, but less accurate." or something (if that now is correct...). Can go in the note or doc-string.

@eytanadler
Copy link
Contributor Author

Thanks for the helpful review, @oscargus! Hopefully these changes should cover all the bases.

@eytanadler eytanadler requested a review from oscargus December 17, 2024 13:57
Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

This could use a test of the new behaviour, not just the error checking. It would also be great if there was a demo showing the effect of the new parameters added to examples pages.

Copy link
Member

@oscargus oscargus left a comment

Choose a reason for hiding this comment

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

Good updates! I agree that an example where the effect of changing this is shown would be great! And then base a test on that example to make sure that it is not broken later.

@github-actions github-actions bot added the Documentation: examples files in galleries/examples label Dec 17, 2024
@eytanadler
Copy link
Contributor Author

@jklymak I’ve now added an example and associated test showing the results from varying the new parameters.

I’m not sure the best way to handle the failing PR cleanliness test.

Also, will these changes have to wait until the next minor release or will they be in the next patch release? I’m wondering what to put in the version added directive.

@jklymak
Copy link
Member

jklymak commented Dec 17, 2024

Looks good. I'd include the default, and maybe consider showing the analytical result?

@eytanadler
Copy link
Contributor Author

eytanadler commented Dec 18, 2024

Sounds good! I added the default and timings. I could add the analytical result (contours of the streamfunction), but it's essentially identical to the streamlines with the smallest steps and might make the code more complicated to understand.

@jklymak
Copy link
Member

jklymak commented Dec 18, 2024

Well my secret reason for suggesting it was that many folks seem to want a super precise streamlines when they have a non-divergent field that they could more precisely represent by contouring the streamfunction. Indeed contouring the streamfunction is superior in many cases because the distance between evenly spaced contours is proportional to the flow speed, a property the streamline method can only approximate if the upstream flow is constant.

@eytanadler
Copy link
Contributor Author

Ah I see. Since it'd complicate the code, there would be limited visual difference, and it's a little bit of a tangent for this case (though certainly important for streamlines of analytic functions), I'm inclined to skip it for this example. But if you feel strongly about it, I can add it.

@jklymak
Copy link
Member

jklymak commented Dec 18, 2024

Nope, fair enough. If I fell strongly enough about it, I'll write a follow up PR. This looks great as-is. Thanks!

@eytanadler
Copy link
Contributor Author

Great, makes sense. Thanks for the review!

@eytanadler eytanadler requested a review from jklymak December 18, 2024 20:54
lib/matplotlib/pyplot.py Outdated Show resolved Hide resolved
@eytanadler eytanadler requested a review from tacaswell December 18, 2024 21:21
@tacaswell
Copy link
Member

I am in general 👍 on this change and the test and docs look good.

However I think the parameter names are very confusing and should make clearer that these are scales not absolute numbers.


For the clenliness test, it looks like you tried to do a rebase and then merged the original branch back in. I can try to clean it up for you, but if you would like to try yourself:

git rebase upstream/main       # or whatever you named the upstream remote to matpotlib/matplotlib
git push --force-with-lease    # maybe with a branch name 

@tacaswell tacaswell added this to the v3.11.0 milestone Dec 18, 2024
@eytanadler
Copy link
Contributor Author

@tacaswell is your comment about the parameter names before or after my latest commit?

I gave the git fix a shot, but it is giving me errors locally. I think there was also a cleanliness complaint that I added and edited the new pdf to test against in the same PR, which I also don't know the best way to fix. If you have quick changes that you know would solve these, it'd be super if you're willing to make the edits. If not, I can look into it.

lib/matplotlib/tests/test_streamplot.py Outdated Show resolved Hide resolved
lib/matplotlib/tests/test_streamplot.py Outdated Show resolved Hide resolved
lib/matplotlib/tests/test_streamplot.py Outdated Show resolved Hide resolved
lib/matplotlib/tests/test_streamplot.py Outdated Show resolved Hide resolved
lib/matplotlib/tests/test_streamplot.py Outdated Show resolved Hide resolved
@tacaswell
Copy link
Member

@tacaswell is your comment about the parameter names before or after my latest commit?

typed before, posted after 🤣


I think there was also a cleanliness complaint that I added and edited the new pdf to test against in the same PR, which I also don't know the best way to fix

squash it all to one commit, see https://matplotlib.org/devdocs/devel/development_workflow.html#rewrite-commit-history

@eytanadler
Copy link
Contributor Author

I think I've addressed all the comments now! We'll see if the tests pass with an image comparison tolerance of 0. Thanks again for the reviews

@eytanadler eytanadler requested a review from QuLogic December 19, 2024 16:42
@jklymak
Copy link
Member

jklymak commented Dec 19, 2024

OK, so full-circling on this; do these parameters actually matter? It seems by allowing max_step_size >1 we are giving the user a foot cannon because the integration exceeds the CFL criterion. For max_step_size < 1 does it really help? The interpolation is linear, and stopping inside a grid cell and checking it a bunch of times is not likely to change the resulting vector.

If there are situations where this helps, it would be useful to put one in the example. It is also worth considering not allowing max_step_size>1,

@eytanadler
Copy link
Contributor Author

eytanadler commented Dec 19, 2024

Well this change was motivated because my coworker and I have a CFD solution (which is obviously too big to be included in the examples) where we were plotting streamlines of characteristics rather than velocities. With the default step size, the streamlines do not accurately stop at the edge of the supersonic region. In the images, you can see how the larger step size looks somewhat quantized and the streamline placement is much less precise.

Default error and step size:
image

100x tighter error and step size:
image

Another motivation is that we have seen cases where streamlines that go close to the geometry "jump" into the undefined geometry region rather than picking up the boundary layer and following the fluid domain solution around the shape. There is so much resolution in meshes in the boundary layer that linear interpolation within a cell is not a problem.

Finally, others online seem to have found use in smaller step sizes. However, they had to edit the source code because it's a hardcoded value and the parameters are not exposed.

I'm open to limiting step size and error scaling parameters to <= 1. I just figured it wouldn't hurt to keep this general in case there are other scenarios where it's useful to take bigger steps. I kind of assumed that if users are getting to the point of even looking for these options, they might have some idea of what they'd like to see (and if they change it and it looks bad, they'd change it back).

@jklymak
Copy link
Member

jklymak commented Dec 20, 2024

Well if the issue is lots of curvature could you use potential flow around an ellipse transverse to the flow instead of a circle? I mean it's probably fine to just include this and folks who need it can use it, but it would be preferable to show its utility.

@eytanadler
Copy link
Contributor Author

I tried the transverse ellipse but it didn't show the intended behavior where the defaults go through it (though the coarsest step version did). But I have an alternate proposal. If you seed streamlines inside the circle (of radius 1), they should stay inside the circle. Here I seed points at x = 0 (center) from y = -0.999 to y = 0.999. The only case where they stay inside is with the smallest step size and tightest error. I checked that this isn't caused by interpolating a coarse grid because the result is the same even if I change the 50 x 50 grid of velocities to 500 x 500 (perhaps it requires even finer, but I think it's the step/error as intended). Is this preferred to the original example?

To be honest, part of the benefit of a smaller step size is to making the streamlines very smooth. In the original example, you can observe jaggedness in the streamlines with the default settings (look closely near the stagnation point). This alone would be enough for me to want a smaller step size for a publication figure if it costs me only a few seconds extra of computation. I think the original example shows this feature better than this newly-proposed one (maybe I could zoom in on that region in the original example?).

streamplot_integration

@jklymak
Copy link
Member

jklymak commented Dec 21, 2024

Sure, if you can zoom, that would really help show why this helps. Agree that if it's a subtle effect it may still be important.

@eytanadler
Copy link
Contributor Author

Sure thing, I’ll add a zoom box!

@eytanadler
Copy link
Contributor Author

I see the mypy tests failing now, but it doesn't look like it references any changes made in this PR. Did I do something wrong to cause it to fail?

@QuLogic
Copy link
Member

QuLogic commented Dec 21, 2024

It is unrelated: #29362

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

Sorry a small suggestion to make more concise. Otherwise looks good. Thanks for your hard work.

lib/matplotlib/streamplot.py Outdated Show resolved Hide resolved
lib/matplotlib/streamplot.py Outdated Show resolved Hide resolved
Co-authored-by: Jody Klymak <jklymak@gmail.com>
@eytanadler
Copy link
Contributor Author

Thanks for your detailed review, definitely improved the addition!

@jklymak jklymak merged commit c01eb01 into matplotlib:main Dec 22, 2024
37 of 39 checks passed
@jklymak
Copy link
Member

jklymak commented Dec 22, 2024

Thanks again @eytanadler - appreciate your patience with the process, which can take a while.

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

Successfully merging this pull request may close these issues.

5 participants