-
Notifications
You must be signed in to change notification settings - Fork 32
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
Point In Face #1056
base: main
Are you sure you want to change the base?
Point In Face #1056
Conversation
@ philipc2 do you think this should be an internal function or exposed to the user? |
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.
Please include an ASV benchmark. I'd suggest doing a parameterized benchmark for the 120 and 480 km MPAS grids.
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.
Please use the optimized functions from #1072 and try to write the function entirely in Numba. This may require us to pass in both the cartesian and spherical versions of point & polygon. Let me know if you have any questions!
ASV BenchmarkingBenchmark Comparison ResultsBenchmarks that have improved:
Benchmarks that have stayed the same:
|
uxarray/grid/grid.py
Outdated
# Get the face's edges for the whole subset | ||
face_edge_cartesian = _get_cartesian_face_edge_nodes( | ||
subset.face_node_connectivity.values, | ||
subset.n_face, | ||
subset.n_max_face_nodes, | ||
subset.node_x.values, | ||
subset.node_y.values, | ||
subset.node_z.values, | ||
) |
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.
This is very expensive to re-compute each time we call this function. Consider adding an internal property or storing this in Grid._ds
like we do with our other methods.
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.
I can do that, but it is a new subset each time the operation is run. So won't it be recomputed anyway? It should only be a face or a few at max for each subset.
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.
A more efficient approach would be to store it in the original Grid
, where it can be computed once, and then once we subset, it should return a Grid
with the face_edge_nodes_xyx
appropriately indexed.
Though, if it is only a few faces at most, the perfromance may be negligible, but we need to consider the cases where we may be running millions of point in polygon queries for higher-resolution grids.
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.
Oh, okay yeah that would work. I didn't realize it would keep it through the subset operation.
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 subset actually keeps the entire array for the whole grid. I can still make it work, that way, but that is why the tests where failing.
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 the subset actually keeps the entire array for the whole grid. I can still make it work, that way, but that is why the tests where failing.
Yeah, we should always ensure that the subset never contains the entire array for any variable.
benchmarks/mpas_ocean.py
Outdated
class PointInPolygon(GridBenchmark): | ||
def time_whole_grid(self, resolution): | ||
point_xyz = np.array([self.uxgrid.face_x[0].values, self.uxgrid.face_y[0].values, self.uxgrid.face_z[0].values]) | ||
|
||
self.uxgrid.get_faces_containing_point(point_xyz=point_xyz) |
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.
From the GH Actions report, it appears that a single Point in Face query is taking approximately 27.0±0.1ms
Ideally, we want to get this number significantly down.
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.
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.
Also, consider including a single sample point query in the setup, since there is also some overhead with the KD tree construction.
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.
This is the performance I get for a 30km grid after doing the things mentioned above. pretty good for 30km grids
Only issue, is that it doesn't find any faces.
Here is my sample code I used.
import uxarray as ux
import numpy as np
import cProfile
profiler = cProfile.Profile()
grid_path = "/Users/philipc/PycharmProjects/uxarray/unstructured-grid-viz-cookbook/meshfiles/x1.655362.grid.nc"
data_path = "/Users/philipc/PycharmProjects/uxarray/unstructured-grid-viz-cookbook/meshfiles/x1.655362.data.nc"
uxds = ux.open_dataset(grid_path, data_path)
uxds.uxgrid.normalize_cartesian_coordinates()
_ = uxds.uxgrid.face_edge_connectivity
point = np.array([0.0, 0.0, 1.0])
res = uxds.uxgrid.get_faces_containing_point(point)
profiler.enable()
res = uxds.uxgrid.get_faces_containing_point(point)
profiler.disable()
profiler.dump_stats('pface.prof')
print(res)
Can do snakeviz pface.prof
to view the profiler.
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.
Thanks for looking into this for me! I am trying to implement these changes now. In terms of it not finding any faces, does the mesh have holes in it? There may not be a face at the pole possibly?
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 grid is a global MPAS atmosphere grid with no holes.
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.
I may have been on an older version of the code. Just ran it again after pulling and it works. A single face is detected. Going to run a few more tests.
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.
Is it working locally for you? It does for me, but the CI is failing. Not sure why.
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 seems like it is working for the poles at least on my end. Haven't tested other points
Try to print array shape and check why is it assesing this? works on my local also, it must be something with dependency or library versions. |
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.
Please add the following to our API
Grid.max_face_radius
Grid.get_faces_containing_point
Lets not include Grid.face_edge_nodes_xyz
in the API for now.
uxarray/grid/grid.py
Outdated
@@ -2415,3 +2443,26 @@ def get_faces_at_constant_longitude(self, lon: float): | |||
|
|||
faces = constant_lon_intersections_face_bounds(lon, self.face_bounds_lon.values) | |||
return faces | |||
|
|||
def get_faces_containing_point(self, point_xyz): |
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.
We should change point_xyz
to point
, which can be either cartesian or spherical. Many times the user will want to query a spherical point, which we can convert to x, y, z.
Closes #905
Overview
Expected Usage
PR Checklist
General
Testing
Documentation
_
) and have been added todocs/internal_api/index.rst
docs/user_api/index.rst