-
Notifications
You must be signed in to change notification settings - Fork 161
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
Streamplot #1670
Streamplot #1670
Conversation
Lawrence and I discussed replacing the use of |
Yes, I just tried replacing CellSize with CellDiameter and running the streamplot test on a quad mesh and everything worked just fine. Do you think we should handle that as part of this PR or save it for later? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly small style comments.
y = x + ds * v | ||
v1 = direction * function.at(y, tolerance=loc_tolerance) | ||
yield y, v1, ds | ||
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's kind of a shame that the boundary handling has to be repeated, but I see it's slightly different both times, so meh.
start_points = generator.permutation(np.array(start_points)) | ||
|
||
for x in start_points: | ||
streamplotter.add_streamline(x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that you add all the points, what is the rationale for permuting them? Is it that streamlines are merged in the order they're seen?
Minor, just do:
for x in generator.permutation(...):
streamplotter.add_streamline(x)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The algorithm tries every grid point to initialize a streamline, but many of them will get "covered" by an earlier streamline and thus not used at all. I've found that randomizing the insertion order usually starts the streamlines far apart at first, which gives you longer streamlines. The Right Thing To Do is to use farthest point seeding, but that requires spatial data structures we don't have if you want it to run in less than O(n^2). Randomized approaches happen to work pretty well and could be improved on using Poisson disk sampling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we have some r-trees lying around, but I don't know what spatial data structures you need.
I think I addressed everything. Once it's good then I'll rebase from master to fix the conflict. I can do another rebase to make the history sensible or squash it all down to one commit. The approach for seeding points right now is pretty blunt but I think it's at least tolerably good. I have some ideas for how to improve that by finding the fixed points of the vector field first, but I'll save that for later. |
Can you rebase/squash and resolve the conflicts, then I think this is good. |
All squashed and I've switched quiver to streamplot in the Stokes demo notebooks. |
Thanks! |
Resolves #1634 . This patch adds:
streamline
function to generate integral curves of vector fieldsStreamplotter
to accumulate all the calculated streamlines and, most importantly, to calculate whether a point is too close to these streamlinesstreamplot
function that picks some seed points and uses the above to generate a streamline plotThe streamline generator uses an adaptive Runge-Kutta 1/2 scheme. The adaptivity needs a length scale, for which we use the
mesh.cell_size
member. This is really convenient but it means this is restricted to triangular and not quad meshes for now.The streamlines are constrained to have a minimum length and stay a certain distance apart. When one streamline can pass very near itself -- for example spiraling around an attracting fixed point -- things get difficult. If you're too stringent in keeping a streamline far away from itself, you can terminate early because each proposed point is, obviously, close to the previous point. To fix this, I made the streamline integration work on chunks of some length that exceeds the spacing. Updating the grid that tracks distance to the streamlines is lagged by one chunk, which means you can have a maximum of one chunk length of self-proximity. With a reasonable chunk length, the streamlines stay far enough apart from themselves and others while also growing long enough. Hopefully this explains why there's so much code here.