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

Non-Conservative Zonal Mean #785

Open
wants to merge 115 commits into
base: main
Choose a base branch
from
Open

Non-Conservative Zonal Mean #785

wants to merge 115 commits into from

Conversation

philipc2
Copy link
Member

@philipc2 philipc2 commented May 10, 2024

Closes #93

Overview

  • Implement Non-Conservative Zonal Mean.
  • Bug fixes for _get_zonal_faces_weight_at_constLat algorithm
  • Bug fixes for gca_constlat_intersection algorithm
  • Bug fixes for _pole_point_inside_polygon algorithm

Expected Usage

import uxarray as ux

grid_path = "/path/to/grid.nc"
data_path = "/path/to/data.nc"

uxds = ux.open_dataset(grid_path, data_path)

# compute the zonal average for the default start_lat_deg=-90, end_lat_deg=90, step_deg=5
zonal_result = uxds['data_var'].zonal_mean()

# Compute the zonal mean for a single latitude:
zonal_result = uxds["t2m"].zonal_mean(30.0)

PR Checklist

General

  • An issue is linked created and linked
  • Add appropriate labels
  • Filled out Overview and Expected Usage (if applicable) sections

Testing

  • Adequate tests are created if there is new functionality
  • Tests cover all possible logical paths in your function
  • Tests are not too basic (such as simply calling a function and nothing else)

Documentation

  • Docstrings have been added to all new functions
  • Docstrings have updated with any function changes
  • Internal functions have a preceding underscore (_) and have been added to docs/internal_api/index.rst
  • User functions have been added to docs/user_api/index.rst

Examples

  • Any new notebook examples added to docs/examples/ folder
  • Clear the output of all cells before committing
  • New notebook files added to docs/examples.rst toctree
  • New notebook files added to new entry in docs/gallery.yml with appropriate thumbnail photo in docs/_static/thumbnails/

@philipc2
Copy link
Member Author

Hi @hongyuchen1030

I've set up the initial boilerplate for your implementation. If you'd like to discuss anything about the implementation before getting started, we can chat about it here.

One question though: will this implementation be the conservative or non-conservative one?

@hongyuchen1030
Copy link
Contributor

hongyuchen1030 commented May 10, 2024

Hi @hongyuchen1030

I've set up the initial boilerplate for your implementation. If you'd like to discuss anything about the implementation before getting started, we can chat about it here.

One question though: will this implementation be the conservative or non-conservative one?

Thank you very much for your great help!
I plan to implement the non-conservative one.

And can you also fill up the expected usage for me please? so that I have a better idea to start? Thanks

@philipc2 philipc2 changed the title DRAFT: Zonal Mean DRAFT: Non-Conservative Zonal Mean May 11, 2024
@philipc2 philipc2 removed the request for review from hongyuchen1030 May 12, 2024 18:42
@philipc2
Copy link
Member Author

Hi @hongyuchen1030
I've set up the initial boilerplate for your implementation. If you'd like to discuss anything about the implementation before getting started, we can chat about it here.
One question though: will this implementation be the conservative or non-conservative one?

Thank you very much for your great help! I plan to implement the non-conservative one.

And can you also fill up the expected usage for me please? so that I have a better idea to start? Thanks

Should be good now.

I wanted to ask and see how you think this type of functionality will work on data variables mapped to different elements. For example, we want to support data mapped to:

  • Nodes
  • Edges
  • Faces

Does your algorithm work on all these of these?

@hongyuchen1030
Copy link
Contributor

hongyuchen1030 commented May 13, 2024

Hi @hongyuchen1030
I've set up the initial boilerplate for your implementation. If you'd like to discuss anything about the implementation before getting started, we can chat about it here.
One question though: will this implementation be the conservative or non-conservative one?

Thank you very much for your great help! I plan to implement the non-conservative one.
And can you also fill up the expected usage for me please? so that I have a better idea to start? Thanks

Should be good now.

I wanted to ask and see how you think this type of functionality will work on data variables mapped to different elements. For example, we want to support data mapped to:

  • Nodes
  • Edges
  • Faces

Does your algorithm work on all these of these?

A non-conservative zonal average is an average value on a constant latitude. So I will say it might be mapped to the faces on that latitude.

In your example function call, where is the place that users input latitude for query? And how do users know it's a non-conservative zonal average?

Such query should looks like res = grid.nc_zonal_mean(60, "Temperature")#60 degree for temperature mean

@philipc2
Copy link
Member Author

philipc2 commented May 13, 2024

I may have worded the first part of my question incorrectly. I was asking whether your zonal average algorithm can compute the zonal average of data variables that either node, edge, or face centered. Typically the data variables are mapped to the faces, but less commonly data can be stored on each node or edge. For this application thought, I think it should only apply to edge or face centered data, since computing the zonal average of data on each node doesn't make much spatial sense.

For the second part, I can update it to reflect that (I put a very bare-bone outline)

Below is a zonal-average figure, with the righthand plot being the zonal average across the latitudes.

image

I think our UxDataArray.zonal_average()should compute the zonal average across a discrete range of lattitudes, something like -90 to 90 with a step size of 5 for example. This would generate a plot like the one above.

The example you gave would be computing the zonal average at a specific latitude. This should be a helper function under uxarray.core.zonal and can be called:

# helper function
_zonal_average_at_lattitude(data: np.ndarray, lat: float, conservative: bool = False)

This would contain the bulk of the artihmatic.

This would allow the one implemented at for the UxDataArray to call the helper depending on the user's parameters

# default, returns the zonal average for latitudes in the range [-90, 90] with a step size of 5
uxds['t2m'].zonal_average()

# specify range and step size
uxds['t2m'].zonal_average(lat = (-45, 45, 5))

# compute the zonal average for a single longitude
uxds['t2m'].zonal_average(lat = 45)


# parameter for conservative
uxds['t2m'].zonal_average(conservative=False)

Just a thought, we may want some Grid helper functions for getting the indices of the edges or faces that intersect a latitude line.

@philipc2
Copy link
Member Author

Here's a reference from NCL's zonal average page (which is where I got the figure above from) https://www.ncl.ucar.edu/Applications/zonal.shtml

@hongyuchen1030
Copy link
Contributor

I may have worded the first part of my question incorrectly. I was asking whether your zonal average algorithm can compute the zonal average of data variables that either node, edge, or face centered. Typically the data variables are mapped to the faces, but less commonly data can be stored on each node or edge. For this application thought, I think it should only apply to edge or face centered data, since computing the zonal average of data on each node doesn't make much spatial sense.

For the second part, I can update it to reflect that (I put a very bare-bone outline)

Below is a zonal-average figure, with the righthand plot being the zonal average across the latitudes.

image

I think our UxDataArray.zonal_average()should compute the zonal average across a discrete range of lattitudes, something like -90 to 90 with a step size of 5 for example. This would generate a plot like the one above.

The example you gave would be computing the zonal average at a specific latitude. This should be a helper function under uxarray.core.zonal and can be called:

# helper function
_zonal_average_at_lattitude(lat: float, conservative: bool = False)

This would contain the bulk of the artihmatic.

This would allow the one implemented at for the UxDataArray to call the helper depending on the user's parameters

# default, returns the zonal average for latitudes in the range [-90, 90] with a step size of 5
uxds['t2m'].zonal_average()

# specify range and step size
uxds['t2m'].zonal_average(lat = (-45, 45, 5))

# compute the zonal average for a single longitude
uxds['t2m'].zonal_average(lat = 45)


# parameter for conservative
uxds['t2m'].zonal_average(conservative=False)

Just a thought, we may want some Grid helper functions for getting the indices of the edges or faces that intersect a latitude line.

Thank you for your information. I was told that this function will be averaging the data for each face. So I only implemented for the scenario where: a data is attached to each face.

So I expected this current branch to be for a single zonal_average only, the helper function you mentioned. Once I finished this helper function, you can feel free to implement the discrete values function by calling my function.

@philipc2
Copy link
Member Author

Thank you for your information. I was told that this function will be averaging the data for each face. So I only implemented for the scenario where: a data is attached to each face.

Got it! Face-centered data is by far the most common scenario anyone will run into, so no worries.

So I expected this current branch to be for a single zonal_average only, the helper function you mentioned. Once I finished this helper function, you can feel free to implement the discrete values function by calling my function.

Sounds good, I can handle the UxDataArray implementation in this PR once you finish up the helper function.

I'll get the boilerplate updated with what we just discussed.

@hongyuchen1030
Copy link
Contributor

Thank you for your information. I was told that this function will be averaging the data for each face. So I only implemented for the scenario where: a data is attached to each face.

Got it! Face-centered data is by far the most common scenario anyone will run into, so no worries.

So I expected this current branch to be for a single zonal_average only, the helper function you mentioned. Once I finished this helper function, you can feel free to implement the discrete values function by calling my function.

Sounds good, I can handle the UxDataArray implementation in this PR once you finish up the helper function.

I'll get the boilerplate updated with what we just discussed.

Great! Thank you very much for your help!

uxarray/core/zonal.py Outdated Show resolved Hide resolved
@philipc2
Copy link
Member Author

Thank you for your information. I was told that this function will be averaging the data for each face. So I only implemented for the scenario where: a data is attached to each face.

Got it! Face-centered data is by far the most common scenario anyone will run into, so no worries.

So I expected this current branch to be for a single zonal_average only, the helper function you mentioned. Once I finished this helper function, you can feel free to implement the discrete values function by calling my function.

Sounds good, I can handle the UxDataArray implementation in this PR once you finish up the helper function.
I'll get the boilerplate updated with what we just discussed.

Great! Thank you very much for your help!

Always happy to help!

@philipc2 philipc2 self-assigned this May 13, 2024
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@philipc2
Copy link
Member Author

@hongyuchen1030

As part of this PR, I'll be putting together a user-guide section too.

@amberchen122
Copy link
Collaborator

Hi @philipc2,

I have a question regarding the expected usage of the zonal_mean in the PR description:

zonal_mean is a member function of UxDataArray class,

However, zonal_mean is accessed as UxDataset.zonal_mean in the PR description.

I checked api.py and noticed that it does not have a function similar to open_dataset that returns the UxDataArray class.

Could you please clarify if UxDataArray and UxDataset are both expected to be returned by open_dataset function in the future?

Thank you! --Amber

@philipc2
Copy link
Member Author

Hi @philipc2,

I have a question regarding the expected usage of the zonal_mean in the PR description:

zonal_mean is a member function of UxDataArray class,

However, zonal_mean is accessed as UxDataset.zonal_mean in the PR description.

I checked api.py and noticed that it does not have a function similar to open_dataset that returns the UxDataArray class.

Could you please clarify if UxDataArray and UxDataset are both expected to be returned by open_dataset function in the future?

Thank you! --Amber

Hi @amberchen122

uxds is an instance of a UxDataset, however once we access the data variable of interested, in our case uxds['data_var'], we are now working with a UxDataArray`.

You can think of a UxDataset as a collection of UxDataArrays

I'd suggest giving this section in our user guide a read, it should hopefully clarify it!

Let me know if you have any other questions!

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [f159bb1] After [01761c9] Ratio Benchmark (Parameter)
- 64.7±2ms 57.5±0.7ms 0.89 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
- 408M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')

Benchmarks that have stayed the same:

Change Before [f159bb1] After [01761c9] Ratio Benchmark (Parameter)
384M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
385M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
384M 387M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 385M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.59±0.01s 1.58±0s 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
230±2ms 224±0.2ms 0.97 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.04±0.03s 2.01±0.01s 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
10.4±1ms 7.48±0.09ms ~0.72 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.80±0.03s 1.76±0.01s 0.98 import.Imports.timeraw_import_uxarray
662±5ms 640±6ms 0.97 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
41.5±0.2ms 40.4±0.9ms 0.97 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
1.75±0.09ms 1.97±0.1ms ~1.12 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
533±30μs 504±4μs 0.94 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.23±0.01μs 1.24±0.01μs 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
308±10ns 315±2ns 1.02 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
847±8ns 872±2ns 1.03 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
304±6ns 294±2ns 0.97 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
402M 399M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
390M 387M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.05±0s 1.04±0.01s 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
81.8±1ms 79.0±0.7ms 0.97 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.91±0.2ms 5.61±0.09ms 0.95 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
264M 266M 1.01 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.76±0.04ms 2.72±0.03ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
294±2μs 293±2μs 1.00 mpas_ocean.Gradient.time_gradient('480km')
244±5μs 256±10μs 1.05 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
124±1μs 124±1μs 1.00 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
370M 371M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
175±5ms 177±0.9ms 1.01 mpas_ocean.Integrate.time_integrate('120km')
11.9±0.1ms 12.0±0.02ms 1.01 mpas_ocean.Integrate.time_integrate('480km')
351±4ms 352±3ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
358±2ms 352±6ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
350±3ms 351±1ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
23.4±0.5ms 23.3±0.6ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
23.3±0.2ms 23.2±0.5ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
24.3±0.4ms 22.9±0.4ms 0.94 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
54.8±0.4ms 55.3±0.2ms 1.01 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
45.0±0.4ms 44.6±0.3ms 0.99 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
360±1ms 360±0.7ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
265±0.8ms 264±0.7ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
237M 239M 1.01 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
7.20±0.5ms 6.59±0.07ms 0.91 quad_hexagon.QuadHexagon.time_open_dataset
6.39±0.5ms 5.63±0.3ms ~0.88 quad_hexagon.QuadHexagon.time_open_grid
failed failed n/a zonal_mean.ZonalMean.time_zonal_mean

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [f159bb1] After [bfaf9c6] Ratio Benchmark (Parameter)
- 407M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')

Benchmarks that have stayed the same:

Change Before [f159bb1] After [bfaf9c6] Ratio Benchmark (Parameter)
384M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
385M 385M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
384M 388M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 386M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.55±0.01s 1.58±0s 1.02 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
221±1ms 220±1ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.01±0.02s 2.03±0.02s 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.64±0.1ms 7.87±0.08ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.81±0.02s 1.82±0.02s 1.00 import.Imports.timeraw_import_uxarray
653±5ms 656±7ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
42.4±0.3ms 42.6±1ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
1.89±0.03ms 2.00±0.1ms 1.06 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
517±10μs 502±10μs 0.97 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.20±0.01μs 1.25±0.01μs 1.05 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
320±6ns 317±7ns 0.99 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
800±10ns 857±8ns 1.07 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
296±10ns 295±1ns 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
403M 399M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
391M 389M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.06±0.01s 1.05±0.01s 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
60.9±1ms 60.6±2ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
80.4±1ms 79.7±0.7ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.91±0.2ms 5.75±0.04ms 0.97 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
266M 266M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.72±0.02ms 2.73±0.03ms 1.00 mpas_ocean.Gradient.time_gradient('120km')
291±2μs 295±0.7μs 1.01 mpas_ocean.Gradient.time_gradient('480km')
245±6μs 229±20μs 0.94 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
120±1μs 121±0.8μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
371M 371M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
185±6ms 177±1ms 0.95 mpas_ocean.Integrate.time_integrate('120km')
12.7±0.07ms 12.5±0.08ms 0.98 mpas_ocean.Integrate.time_integrate('480km')
359±5ms 355±3ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
357±3ms 353±2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
356±3ms 355±6ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
23.7±0.4ms 22.7±0.3ms 0.96 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
23.6±0.4ms 23.3±0.3ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
23.1±0.5ms 23.3±0.4ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
55.2±0.06ms 55.1±0.2ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.7±0.2ms 44.4±0.2ms 0.99 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
359±0.7ms 360±0.6ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
264±0.4ms 263±0.5ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
239M 239M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.65±0.2ms 6.67±0.05ms 1.00 quad_hexagon.QuadHexagon.time_open_dataset
5.73±0.06ms 5.57±0.05ms 0.97 quad_hexagon.QuadHexagon.time_open_grid

@philipc2 philipc2 removed the bug Something isn't working label Sep 18, 2024
@philipc2
Copy link
Member Author

philipc2 commented Sep 18, 2024

Results are looking great. Let's get #878 merged so we can test on more dataset (the plot below was on an MPAS ocean grid after normalizing coordinates)

480km Ocean Grid

image

120km Ocean Grid

image

@philipc2
Copy link
Member Author

With fma disabled, only the MacOS tests are passing. Wondering if either if you have any input on this.

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [0f7282c] After [1a94750] Ratio Benchmark (Parameter)
- 408M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')

Benchmarks that have stayed the same:

Change Before [0f7282c] After [1a94750] Ratio Benchmark (Parameter)
383M 383M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
384M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
383M 387M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 385M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.55±0.01s 1.58±0s 1.02 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
224±2ms 221±1ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.01±0.01s 2.03±0.01s 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.66±0.07ms 7.51±0.03ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.70±0.01s 1.72±0.01s 1.01 import.Imports.timeraw_import_uxarray
651±5μs 674±5μs 1.04 mpas_ocean.CheckNorm.time_check_norm('120km')
430±6μs 425±10μs 0.99 mpas_ocean.CheckNorm.time_check_norm('480km')
616±2ms 647±9ms 1.05 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
40.3±0.2ms 41.3±0.9ms 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
1.96±0.07ms 1.82±0.03ms 0.93 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
479±5μs 485±3μs 1.01 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.35±0μs 1.29±0.01μs 0.95 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
317±3ns 314±10ns 0.99 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
831±2ns 832±5ns 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
292±5ns 296±4ns 1.01 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
399M 399M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
389M 388M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.03±0.01s 1.04±0.01s 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
55.4±1ms 55.2±0.4ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
77.4±0.5ms 76.2±0.5ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.37±0.1ms 5.25±0.09ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
263M 263M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.68±0.01ms 2.70±0.04ms 1.01 mpas_ocean.Gradient.time_gradient('120km')
290±2μs 286±2μs 0.99 mpas_ocean.Gradient.time_gradient('480km')
227±10μs 243±6μs 1.07 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
120±0.9μs 120±0.5μs 1.00 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
370M 370M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
177±0.7ms 175±1ms 0.99 mpas_ocean.Integrate.time_integrate('120km')
12.2±0.06ms 12.1±0.04ms 0.99 mpas_ocean.Integrate.time_integrate('480km')
348±7ms 345±2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
342±2ms 345±3ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
343±2ms 348±1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
21.4±0.1ms 21.6±0.2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
21.5±0.2ms 21.2±0.1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
21.3±0.2ms 21.7±0.3ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
54.9±0.2ms 54.6±0.1ms 0.99 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.2±0.04ms 44.3±0.08ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
360±1ms 359±0.8ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
264±0.7ms 263±1ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
237M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.50±0.03ms 6.55±0.06ms 1.01 quad_hexagon.QuadHexagon.time_open_dataset
5.66±0.1ms 5.68±0.03ms 1.00 quad_hexagon.QuadHexagon.time_open_grid

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [0f7282c] After [ef1723e] Ratio Benchmark (Parameter)
- 406M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')
failed 3.71±0.01s n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
failed 2.33±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 20)
failed 1.25±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 40)
failed 1.19±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 10)
failed 612±9ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 20)
failed 310±4ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 40)
failed 2.46±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 5)

Benchmarks that have stayed the same:

Change Before [0f7282c] After [ef1723e] Ratio Benchmark (Parameter)
384M 383M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
384M 385M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
384M 388M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 385M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.57±0.01s 1.59±0s 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
224±2ms 220±0.2ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
1.99±0.02s 2.03±0.01s 1.02 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.73±0.2ms 7.53±0.1ms 0.97 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.73±0.02s 1.76±0.02s 1.02 import.Imports.timeraw_import_uxarray
661±6μs 651±10μs 0.98 mpas_ocean.CheckNorm.time_check_norm('120km')
434±5μs 429±2μs 0.99 mpas_ocean.CheckNorm.time_check_norm('480km')
656±10ms 655±10ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
41.0±0.7ms 41.2±0.4ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
1.89±0.03ms 1.87±0.02ms 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
502±20μs 490±5μs 0.98 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.23±0μs 1.28±0μs 1.04 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
302±4ns 308±1ns 1.02 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
782±0.9ns 783±0.8ns 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
286±1ns 281±1ns 0.98 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
402M 399M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
390M 389M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.04±0.01s 1.04±0.01s 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
57.7±1ms 57.5±0.7ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
77.6±0.4ms 78.6±0.9ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.54±0.2ms 5.54±0.03ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
263M 264M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.68±0.01ms 2.73±0.02ms 1.02 mpas_ocean.Gradient.time_gradient('120km')
294±5μs 290±0.5μs 0.99 mpas_ocean.Gradient.time_gradient('480km')
238±4μs 254±2μs 1.07 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
121±0.8μs 122±2μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
371M 371M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
175±0.9ms 176±2ms 1.00 mpas_ocean.Integrate.time_integrate('120km')
12.0±0.04ms 12.4±0.3ms 1.04 mpas_ocean.Integrate.time_integrate('480km')
354±5ms 350±2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
352±1ms 354±2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
352±3ms 349±1ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
23.3±0.8ms 23.0±0.5ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
22.6±0.2ms 22.7±0.3ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
22.5±0.3ms 23.4±0.3ms 1.04 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
54.7±0.09ms 54.7±0.08ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.5±0.1ms 44.8±0.2ms 1.01 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
360±1ms 360±1ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
263±0.4ms 271±6ms 1.03 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 10)
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 5)
237M 237M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.55±0.02ms 6.66±0.1ms 1.02 quad_hexagon.QuadHexagon.time_open_dataset
5.72±0.08ms 5.62±0.04ms 0.98 quad_hexagon.QuadHexagon.time_open_grid

@hongyuchen1030
Copy link
Contributor

hongyuchen1030 commented Sep 18, 2024

With fma disabled, only the MacOS tests are passing. Wondering if either if you have any input on this.

Hi @philipc2 @amberchen122

The floating point precision causes this. One possible cause is:

Different compilers optimize the existing codes in different ways. In fact, GCC by default will use the fma in (-ffp-contract=on is by default) to improve the performance, ignoring the accuracy of operations, making the results varies. In other words, even if we disable the fma here by ourselves, GCC will still use it for faster performance. And what's even worse is they use it wherever they think it can improve the speed, overlooking if it's correct to be used. And yes this already breaks the IEEE754 standards

Clang makes the FMA off by default so we are good.

One workaround is using another magic number error tolerance like MANUAL_TOLERANCE that is set to 100 * MACHINE_EPSILON, or 10 (or any number that works), to replace the current MACHINE_EPSILON. Don't try to set it to things around 10^-8, which is our global error_tolerence, more things will break. The floating point precision is very hectic.

Or if numba can allow you to turn -ffp-contract=off and --ffast-math = off, you can also try it when numba use gcc as the compiler

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [0f7282c] After [8ff264e] Ratio Benchmark (Parameter)
- 408M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')
failed 3.40±0.01s n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
failed 2.03±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 20)
failed 1.05±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 40)
failed 1.04±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 10)
failed 532±3ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 20)
failed 271±2ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 40)
failed 2.14±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 5)

Benchmarks that have stayed the same:

Change Before [0f7282c] After [8ff264e] Ratio Benchmark (Parameter)
383M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
384M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
384M 388M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 385M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.58±0.01s 1.57±0.01s 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
224±1ms 227±2ms 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.02±0.02s 2.02±0s 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.71±0.2ms 7.73±0.3ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.72±0.01s 1.72±0.01s 1.00 import.Imports.timeraw_import_uxarray
653±8μs 654±3μs 1.00 mpas_ocean.CheckNorm.time_check_norm('120km')
426±2μs 426±3μs 1.00 mpas_ocean.CheckNorm.time_check_norm('480km')
632±10ms 643±3ms 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
39.9±0.3ms 41.3±0.8ms 1.04 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
1.90±0.09ms 1.62±0.2ms ~0.85 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
484±6μs 492±9μs 1.02 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
306±1ns 309±3ns 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
830±4ns 811±6ns 0.98 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
292±3ns 293±4ns 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
403M 399M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
391M 388M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.05±0.02s 1.04±0.01s 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
56.8±2ms 58.9±2ms 1.04 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
77.4±1ms 78.5±0.4ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.60±0.07ms 5.56±0.1ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
263M 266M 1.01 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.68±0.01ms 2.70±0.01ms 1.01 mpas_ocean.Gradient.time_gradient('120km')
293±3μs 286±1μs 0.98 mpas_ocean.Gradient.time_gradient('480km')
232±2μs 249±3μs 1.08 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
120±2μs 121±0.8μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
371M 370M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
176±2ms 177±2ms 1.01 mpas_ocean.Integrate.time_integrate('120km')
12.1±0.02ms 11.7±0.05ms 0.97 mpas_ocean.Integrate.time_integrate('480km')
345±3ms 347±0.5ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
343±1ms 348±2ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
348±2ms 349±4ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
21.8±0.4ms 22.5±0.5ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
21.3±0.1ms 21.9±0.4ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
21.4±0.2ms 22.2±0.4ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
54.9±0.2ms 54.6±0.3ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.5±0.2ms 44.5±0.1ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
363±2ms 359±0.5ms 0.99 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
265±0.4ms 265±0.8ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 10)
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 5)
237M 239M 1.01 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.62±0.1ms 6.50±0.06ms 0.98 quad_hexagon.QuadHexagon.time_open_dataset
5.62±0.03ms 5.60±0.04ms 1.00 quad_hexagon.QuadHexagon.time_open_grid

Benchmarks that have got worse:

Change Before [0f7282c] After [8ff264e] Ratio Benchmark (Parameter)
+ 1.22±0.01μs 1.41±0.01μs 1.15 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')

@hongyuchen1030
Copy link
Contributor

@hongyuchen1030 @amberchen122

Is there any way to implement this without using pyfma?

def _inv_jacobian(x0, x1, y0, y1, z0, z1, x_i_old, y_i_old):
"""Calculate the inverse Jacobian matrix for a given set of parameters.
Parameters
----------
x0 : float
Description of x0.
x1 : float
Description of x1.
y0 : float
Description of y0.
y1 : float
Description of y1.
z0 : float
Description of z0.
z1 : float
Description of z1.
x_i_old : float
Description of x_i_old.
y_i_old : float
Description of y_i_old.
Returns
-------
numpy.ndarray or None
The inverse Jacobian matrix if it is non-singular, or None if a singular matrix is encountered.
Notes
-----
This function calculates the inverse Jacobian matrix based on the provided parameters. If the Jacobian matrix
is singular, a warning is printed, and None is returned.
"""
# d_dx = (x0 * x_i_old - x1 * x_i_old * z0 + y0 * y_i_old * z1 - y1 * y_i_old * z0 - y1 * y_i_old * z0)
# d_dy = 2 * (x0 * x_i_old * z1 - x1 * x_i_old * z0 + y0 * y_i_old * z1 - y1 * y_i_old * z0)
#
# # row 1
# J[0, 0] = y_i_old / d_dx
# J[0, 1] = (x0 * z1 - z0 * x1) / d_dy
# # row 2
# J[1, 0] = x_i_old / d_dx
# J[1, 1] = (y0 * z1 - z0 * y1) / d_dy
# The Jacobian Matrix
jacobian = [
[ac_utils._fmms(y0, z1, z0, y1), ac_utils._fmms(x0, z1, z0, x1)],
[2 * x_i_old, 2 * y_i_old],
]
# First check if the Jacobian matrix is singular
if np.linalg.matrix_rank(jacobian) < 2:
warnings.warn("The Jacobian matrix is singular.")
return None
try:
inverse_jacobian = np.linalg.inv(jacobian)
except np.linalg.LinAlgError as e:
# Print out the error message
cond_number = np.linalg.cond(jacobian)
print(f"Condition number: {cond_number}")
print(f"Jacobian matrix:\n{jacobian}")
print(f"An error occurred: {e}")
raise
return inverse_jacobian

fmms

@hongyuchen1030 @amberchen122

Is there any way to implement this without using pyfma?

def _inv_jacobian(x0, x1, y0, y1, z0, z1, x_i_old, y_i_old):
"""Calculate the inverse Jacobian matrix for a given set of parameters.
Parameters
----------
x0 : float
Description of x0.
x1 : float
Description of x1.
y0 : float
Description of y0.
y1 : float
Description of y1.
z0 : float
Description of z0.
z1 : float
Description of z1.
x_i_old : float
Description of x_i_old.
y_i_old : float
Description of y_i_old.
Returns
-------
numpy.ndarray or None
The inverse Jacobian matrix if it is non-singular, or None if a singular matrix is encountered.
Notes
-----
This function calculates the inverse Jacobian matrix based on the provided parameters. If the Jacobian matrix
is singular, a warning is printed, and None is returned.
"""
# d_dx = (x0 * x_i_old - x1 * x_i_old * z0 + y0 * y_i_old * z1 - y1 * y_i_old * z0 - y1 * y_i_old * z0)
# d_dy = 2 * (x0 * x_i_old * z1 - x1 * x_i_old * z0 + y0 * y_i_old * z1 - y1 * y_i_old * z0)
#
# # row 1
# J[0, 0] = y_i_old / d_dx
# J[0, 1] = (x0 * z1 - z0 * x1) / d_dy
# # row 2
# J[1, 0] = x_i_old / d_dx
# J[1, 1] = (y0 * z1 - z0 * y1) / d_dy
# The Jacobian Matrix
jacobian = [
[ac_utils._fmms(y0, z1, z0, y1), ac_utils._fmms(x0, z1, z0, x1)],
[2 * x_i_old, 2 * y_i_old],
]
# First check if the Jacobian matrix is singular
if np.linalg.matrix_rank(jacobian) < 2:
warnings.warn("The Jacobian matrix is singular.")
return None
try:
inverse_jacobian = np.linalg.inv(jacobian)
except np.linalg.LinAlgError as e:
# Print out the error message
cond_number = np.linalg.cond(jacobian)
print(f"Condition number: {cond_number}")
print(f"Jacobian matrix:\n{jacobian}")
print(f"An error occurred: {e}")
raise
return inverse_jacobian

def _fmms(a, b, c, d):
    """
    Calculate the difference of products using the FMA (fused multiply-add) operation: (a * b) - (c * d).

So really just need to replace _fmms(a, b, c, d) with (a * b) - (c * d)

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [0f7282c] After [71a0f04] Ratio Benchmark (Parameter)
- 898±4ns 811±2ns 0.90 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
- 408M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')
failed 3.32±0s n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
failed 3.87±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 10)
failed 1.91±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 20)
failed 997±7ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 40)
failed 966±6ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 10)
failed 499±4ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 20)
failed 248±2ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 40)
failed 1.99±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 5)

Benchmarks that have stayed the same:

Change Before [0f7282c] After [71a0f04] Ratio Benchmark (Parameter)
384M 383M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
385M 385M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
383M 388M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 385M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.60±0.02s 1.60±0.01s 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
223±2ms 223±0.5ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.05±0s 1.99±0.01s 0.97 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
8.00±0.1ms 8.01±0.2ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.73±0s 1.79±0.02s 1.04 import.Imports.timeraw_import_uxarray
667±7μs 663±5μs 0.99 mpas_ocean.CheckNorm.time_check_norm('120km')
435±2μs 446±3μs 1.03 mpas_ocean.CheckNorm.time_check_norm('480km')
653±5ms 659±5ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
41.1±0.7ms 41.9±0.04ms 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
511±10μs 515±10μs 1.01 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.32±0.01μs 1.32±0.01μs 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
319±8ns 308±3ns 0.97 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
298±7ns 285±2ns 0.96 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
399M 399M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
389M 389M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.04±0.01s 1.04±0.01s 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
58.9±4ms 60.7±0.4ms 1.03 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
78.4±0.8ms 79.6±1ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.73±0.4ms 6.04±0.6ms 1.05 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
263M 264M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.72±0.01ms 2.80±0.03ms 1.03 mpas_ocean.Gradient.time_gradient('120km')
291±3μs 289±2μs 0.99 mpas_ocean.Gradient.time_gradient('480km')
238±9μs 235±20μs 0.99 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
122±0.7μs 123±2μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
371M 371M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
174±1ms 179±1ms 1.03 mpas_ocean.Integrate.time_integrate('120km')
11.9±0.2ms 12.1±0.03ms 1.02 mpas_ocean.Integrate.time_integrate('480km')
349±2ms 352±7ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
347±2ms 356±5ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
350±2ms 349±6ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
21.6±0.3ms 23.3±0.3ms 1.08 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
22.3±0.2ms 23.5±0.8ms 1.05 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
21.5±0.09ms 22.7±0.4ms 1.05 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
54.9±0.3ms 54.9±0.2ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.4±0.2ms 44.7±0.2ms 1.01 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
360±0.6ms 359±0.3ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
264±0.4ms 264±0.9ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 5)
237M 237M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.56±0.06ms 6.87±0.05ms 1.05 quad_hexagon.QuadHexagon.time_open_dataset
5.76±0.1ms 6.06±0.3ms 1.05 quad_hexagon.QuadHexagon.time_open_grid

Benchmarks that have got worse:

Change Before [0f7282c] After [71a0f04] Ratio Benchmark (Parameter)
+ 1.73±0.07ms 2.00±0.04ms 1.16 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [2b60860] After [40cc518] Ratio Benchmark (Parameter)
- 2.01±0.03ms 1.62±0.3ms 0.80 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
- 407M 354M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')
failed 3.20±0s n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
failed 1.87±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 20)
failed 969±4ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 40)
failed 955±10ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 10)
failed 487±6ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 20)
failed 246±4ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 40)
failed 1.96±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 5)

Benchmarks that have stayed the same:

Change Before [2b60860] After [40cc518] Ratio Benchmark (Parameter)
383M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
384M 385M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
384M 388M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 385M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.56±0.02s 1.56±0s 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
222±0.06ms 219±1ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.03±0.03s 1.99±0.01s 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.74±0.09ms 7.48±0.1ms 0.97 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.71±0.01s 1.73±0.01s 1.01 import.Imports.timeraw_import_uxarray
646±4μs 648±6μs 1.00 mpas_ocean.CheckNorm.time_check_norm('120km')
425±2μs 428±6μs 1.01 mpas_ocean.CheckNorm.time_check_norm('480km')
632±5ms 630±10ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
40.2±0.3ms 40.6±1ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
487±2μs 509±10μs 1.05 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.26±0.01μs 1.28±0.01μs 1.02 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
306±4ns 320±2ns 1.04 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
844±4ns 876±4ns 1.04 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
289±2ns 297±4ns 1.03 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
399M 399M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
389M 389M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
362M 362M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.04±0s 1.03±0s 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
55.6±0.3ms 55.9±0.5ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
77.4±0.7ms 76.5±0.8ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.22±0.08ms 5.24±0.2ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
263M 264M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
241M 241M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.68±0.01ms 2.68±0.01ms 1.00 mpas_ocean.Gradient.time_gradient('120km')
287±1μs 286±5μs 1.00 mpas_ocean.Gradient.time_gradient('480km')
233±5μs 223±6μs 0.96 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
121±0.8μs 122±0.9μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
371M 371M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
177±3ms 176±4ms 1.00 mpas_ocean.Integrate.time_integrate('120km')
11.9±0.2ms 11.8±0.07ms 0.99 mpas_ocean.Integrate.time_integrate('480km')
343±3ms 346±2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
344±1ms 346±3ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
348±4ms 343±4ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
22.1±0.2ms 21.8±0.2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
21.6±0.3ms 21.8±0.1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
22.0±0.1ms 22.0±0.5ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
54.5±0.04ms 54.4±0.2ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.2±0.03ms 44.4±0.1ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
360±0.2ms 360±1ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
265±0.8ms 264±0.7ms 0.99 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 10)
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 5)
237M 237M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.41±0.02ms 6.47±0.01ms 1.01 quad_hexagon.QuadHexagon.time_open_dataset
5.55±0.02ms 5.54±0.03ms 1.00 quad_hexagon.QuadHexagon.time_open_grid

Copy link

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [7f16498] After [23105c0] Ratio Benchmark (Parameter)
- 407M 353M 0.87 mpas_ocean.Integrate.peakmem_integrate('480km')
failed 3.26±0s n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
failed 1.90±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 20)
failed 989±0.8ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 40)
failed 971±10ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 10)
failed 495±3ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 20)
failed 250±4ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 40)
failed 2.02±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 5)

Benchmarks that have stayed the same:

Change Before [7f16498] After [23105c0] Ratio Benchmark (Parameter)
380M 380M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
381M 381M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
384M 384M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
382M 381M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.59±0.01s 1.57±0s 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
222±0.5ms 228±3ms 1.02 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.03±0.01s 2.03±0.01s 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.76±0.1ms 7.60±0.07ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.68±0s 1.72±0.01s 1.02 import.Imports.timeraw_import_uxarray
656±3μs 666±6μs 1.02 mpas_ocean.CheckNorm.time_check_norm('120km')
427±2μs 427±3μs 1.00 mpas_ocean.CheckNorm.time_check_norm('480km')
660±5ms 654±10ms 0.99 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
41.2±0.3ms 41.4±0.7ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
2.01±0.02ms 2.04±0.2ms 1.02 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
491±10μs 494±10μs 1.01 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.27±0μs 1.25±0μs 0.99 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
311±5ns 314±2ns 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
852±4ns 815±3ns 0.96 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
290±3ns 305±9ns 1.05 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
400M 398M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', False)
389M 387M 0.99 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('120km', True)
361M 361M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', False)
360M 360M 1.00 mpas_ocean.GeoDataFrame.peakmem_to_geodataframe('480km', True)
1.06±0.01s 1.05±0.01s 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
56.9±0.3ms 58.4±0.7ms 1.03 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
78.9±1ms 77.6±1ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.25±0.2ms 5.53±0.09ms 1.05 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
263M 263M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
240M 240M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.70±0.01ms 2.70±0.01ms 1.00 mpas_ocean.Gradient.time_gradient('120km')
289±2μs 292±3μs 1.01 mpas_ocean.Gradient.time_gradient('480km')
234±9μs 239±3μs 1.02 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
122±0.3μs 122±0.8μs 1.00 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
370M 369M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
179±2ms 175±2ms 0.98 mpas_ocean.Integrate.time_integrate('120km')
12.1±0.05ms 12.4±0.01ms 1.02 mpas_ocean.Integrate.time_integrate('480km')
354±2ms 347±4ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
356±5ms 349±6ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
353±2ms 352±4ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
22.4±0.4ms 22.6±0.7ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
21.8±0.3ms 23.0±0.8ms 1.06 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
22.8±0.6ms 22.2±0.7ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
55.2±0.3ms 54.9±0.3ms 0.99 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.6±0.07ms 44.6±0.08ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
361±1ms 362±1ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
265±0.5ms 266±0.8ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 10)
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 5)
236M 236M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
235M 235M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.56±0.03ms 6.58±0.01ms 1.00 quad_hexagon.QuadHexagon.time_open_dataset
5.66±0.01ms 5.70±0.1ms 1.01 quad_hexagon.QuadHexagon.time_open_grid

Copy link

github-actions bot commented Oct 4, 2024

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [86284d6] After [cfe242c] Ratio Benchmark (Parameter)
- 1.01±0.02μs 817±2ns 0.81 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
- 330±20ns 297±5ns 0.90 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
- 463M 406M 0.88 mpas_ocean.Integrate.peakmem_integrate('480km')
failed 3.30±0.01s n/a mpas_ocean.ZonalMean.time_zonal_mean('480km')
failed 1.94±0.01s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 20)
failed 1.01±0s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 40)
failed 987±5ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 10)
failed 502±5ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 20)
failed 254±2ms n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 40)
failed 2.01±0.02s n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('480km', 5)

Benchmarks that have stayed the same:

Change Before [86284d6] After [cfe242c] Ratio Benchmark (Parameter)
440M 440M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
440M 440M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
443M 443M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
441M 440M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.64±0.02s 1.61±0s 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
236±0.5ms 228±1ms 0.97 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.07±0.02s 2.10±0s 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
7.77±0.1ms 7.70±0.2ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
3.05±0.01s 3.02±0.01s 0.99 import.Imports.timeraw_import_uxarray
665±3μs 689±2μs 1.04 mpas_ocean.CheckNorm.time_check_norm('120km')
434±3μs 439±3μs 1.01 mpas_ocean.CheckNorm.time_check_norm('480km')
663±10ms 676±20ms 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
42.0±1ms 42.2±0.3ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
1.88±0.05ms 1.73±0.09ms 0.92 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
521±10μs 501±6μs 0.96 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
1.31±0μs 1.24±0.01μs 0.95 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
325±20ns 314±10ns 0.96 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
1.07±0.01s 1.06±0.01s 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
55.9±1ms 56.2±0.8ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
79.8±2ms 79.4±1ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.43±0.08ms 5.35±0.2ms 0.99 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
316M 316M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
293M 294M 1.00 mpas_ocean.Gradient.peakmem_gradient('480km')
2.76±0.02ms 2.73±0.03ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
296±5μs 290±3μs 0.98 mpas_ocean.Gradient.time_gradient('480km')
245±4μs 246±4μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
124±2μs 125±3μs 1.01 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
423M 423M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
194±10ms 177±2ms 0.91 mpas_ocean.Integrate.time_integrate('120km')
14.0±0.02ms 12.5±0.06ms ~0.89 mpas_ocean.Integrate.time_integrate('480km')
356±4ms 356±2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
359±4ms 355±2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
366±4ms 354±2ms 0.97 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
24.7±0.9ms 23.8±0.4ms 0.96 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
24.5±0.8ms 23.8±0.4ms 0.97 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
24.1±0.2ms 24.4±0.3ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
55.4±0.1ms 54.9±0.1ms 0.99 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
44.6±0.2ms 44.6±0.07ms 1.00 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
361±0.8ms 361±0.6ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
265±0.6ms 265±0.5ms 1.00 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
failed failed n/a mpas_ocean.ZonalMean.time_zonal_mean('120km')
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 10)
failed failed n/a mpas_ocean.ZonalMeanExcludingBounds.time_zonal_mean('120km', 5)
289M 290M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
289M 289M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.62±0.02ms 6.61±0.1ms 1.00 quad_hexagon.QuadHexagon.time_open_dataset
5.71±0.04ms 5.85±0.1ms 1.03 quad_hexagon.QuadHexagon.time_open_grid

@philipc2 philipc2 removed the run-benchmark Run ASV benchmark workflow label Oct 10, 2024
uxarray/core/dataarray.py Outdated Show resolved Hide resolved
test_zonal.py Outdated Show resolved Hide resolved
Comment on lines +103 to +115
weight_df = _get_zonal_faces_weight_at_constLat(
candidate_face_edges_cart,
np.sin(np.deg2rad(constLat_deg)),
candidate_face_bounds,
is_directed=False,
is_latlonface=is_latlonface,
)

# Compute the zonal mean(weighted average) of the candidate faces
weights = weight_df["weight"].values
zonal_mean = np.sum(candidate_face_data * weights, axis=-1) / np.sum(weights)

return zonal_mean
Copy link
Member Author

Choose a reason for hiding this comment

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

@hongyuchen1030

Wouldn't taking the weighted average here mean that we have a Conservative Zonal Average?

Copy link
Contributor

Choose a reason for hiding this comment

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

Non-conservative and conservative both take weighted averages.

Non-conservative tasks the edge length as the weight factor while the conservative ones take the area.

Copy link
Member Author

Choose a reason for hiding this comment

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

So if we take the non-conservative zonal average of a face-centered data variable, the length of the edge that the line intersects would be used as the weight?

Would this weight be applied to both faces that saddle that edge?

Copy link
Contributor

@hongyuchen1030 hongyuchen1030 Oct 10, 2024

Choose a reason for hiding this comment

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

“the length of the edge that the line intersects would be used as the weight?” Yes

"Would this weight be applied to both faces that saddle that edge?" It's already taken care of, they will split the shared section

@philipc2 philipc2 mentioned this pull request Oct 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hardcoded File Path Causing Test Failure Add zonal means (non-conservative)
4 participants