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

Support unstructured grid (Issue #125) #126

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

Conversation

airwarriorg91
Copy link

Hey !
I am looked into uxarray and attempted two methods to include support for unstructured grids. The fundamental working of both the methods is same.

Proposed Methodology

  • Step 1: Use readnek to import the data
  • Step 2: Create an array of nodes, elements, and fields
  • Step 3: Create a grid and xarray dataset from the data array
  • Step 4: Create a uxarray dataset and return it.

Method 1
Extend the current xarray method to uxarray as uxarray also supports the creation of dataset through load_store(). But unfortunately, it doesn't work. I get the following error.

conflicting sizes for dimension 'y': length 6 on 'xmesh' and length 36 on {'x': 'x', 'y': 'y', 'z': 'z'}.

Method 2
It is manual method to extract data from elements and store them as numpy arrays, use them to form a xarray dataset. I am able to make an xarray dataset which can be used for most post-processing stuff like plotting, POD calculations, etc. It lacks the element connectivity data, so is it required ? If not, this method can be used to handle structured and unstructured arrays both.

extract_elem_data is the implementation of Method 2. We may not require the use of uxarray.

A uxarray Grid can be constructed from the coordinates and connectivity data through uxarray.Grid.from_dataset and used with the available values to create a uxarray dataset using uxarray.UxDataset. Can someone help me in extracting the connectivity, so I can attempt creation of an uxarray dataset.

Thanks !
Gaurav

@ashwinvis
Copy link
Member

You got an error with the existing _NekDataStore because of this method:

    def meshgrid_to_dim(self, mesh):
        """Reverse of np.meshgrid. This method extracts one-dimensional
        coordinates from a cubical array format for every direction
        """

I don't see a proper way of building 1D coordinate arrays for an unstructured arrays. We can add the DataStore later, but a working implementation is more important. Good that you chose to go for simpler functions.

@ashwinvis
Copy link
Member

You can get the connectivity data at least for the EXODUS mesh like this:

import xarray as xr
mesh = xr.open_dataset("naca(10x4).e")
print(mesh.data_vars)
mesh.connect1

This integer data array has the dimensions connect1 (num_el_in_blk1, num_nod_per_el1) int32 766kB ... and looks like this:

array([[    3,     2,     1, ...,     5,     8,     7],
       [   10,     9,     2, ...,    11,     6,    13],
       [   15,    14,     9, ...,    16,    12,    18],
       ...,
       [72683, 72686, 32640, ..., 72732, 32642, 72731],
       [72686, 72689, 32645, ..., 72733, 32647, 72732],
       [72689, 72692, 32650, ..., 72734, 32652, 72733]], dtype=int32)

I am guessing it denotes one cell per row, and along the column denotes the 8 cells which surround it: 4 on each corner and 4 on each face (you need to double check it). Somebody wrote a short blog post looking at this using netCDF4, but above I used xarray (which also uses netCDF4 / h5netcdf behind the scenes).

https://johnfoster.pge.utexas.edu/blog/posts/extracting-exodus-information-with-netcdf-python/

@ashwinvis
Copy link
Member

One thing I was not able to get it working was opening the EXODUS mesh file directly from Uxarray, although they claim it to be supported:

https://uxarray.readthedocs.io/en/latest/user-guide/grid-formats.html#exodus

@airwarriorg91
Copy link
Author

Yeah ! But I think extracting mesh or any mesh data from the exodus file will not provide us with the correct mesh data. The NEK5000 visualization file has the polynomial nodes data along with the nodes of the original mesh. Correct me, if I am wrong but I think this is the case only. So, in that case how to extract the connectivity data from the visualization file.

Thanks, I will try to implement a working function first then we can establish a class like for xarray.

@airwarriorg91
Copy link
Author

What was your error ?

One thing I was not able to get it working was opening the EXODUS mesh file directly from Uxarray, although they claim it to be supported:

https://uxarray.readthedocs.io/en/latest/user-guide/grid-formats.html#exodus

@ashwinvis
Copy link
Member

import uxarray as ux
ux.open_grid("naca(10x4).e")

It assumes a 3D grid

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/xarray/core/dataset.py in ?(self, name)
   1482             variable = self._variables[name]
   1483         except KeyError:
-> 1484             _, name, variable = _get_virtual_variable(self._variables, name, self.sizes)
   1485

KeyError: 'node_z'

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/xarray/core/dataset.py in ?(self, key)
   1585                 if isinstance(key, tuple):
   1586                     message += f"\nHint: use a list to select multiple variables, for example `ds[{[d for d in key]}]`"
-> 1587                 raise KeyError(message) from e
   1588

~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/xarray/core/dataset.py in ?(self, name)
   1482             variable = self._variables[name]
   1483         except KeyError:
-> 1484             _, name, variable = _get_virtual_variable(self._variables, name, self.sizes)
   1485

~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/xarray/core/dataset.py in ?(variables, key, dim_sizes)
    216     split_key = key.split(".", 1)
    217     if len(split_key) != 2:
--> 218         raise KeyError(key)
    219

KeyError: 'node_z'

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
<ipython-input-7-18c901787b96> in ?()
----> 1 ux.open_grid("naca(10x4).e")

~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/uxarray/core/api.py in ?(grid_filename_or_obj, latlon, use_dual, **kwargs)
     84         try:
     85             grid_ds = xr.open_dataset(grid_filename_or_obj, **kwargs)
     86
     87             uxgrid = Grid.from_dataset(grid_ds, use_dual=use_dual)
---> 88         except ValueError:
     89             raise ValueError("Inputted grid_filename_or_obj not supported.")
     90
     91     return uxgrid

~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/uxarray/grid/grid.py in ?(cls, dataset, use_dual, **kwargs)
    250             # parse to detect source grid spec
    251
    252             source_grid_spec = _parse_grid_type(dataset)
    253             if source_grid_spec == "Exodus":
--> 254                 grid_ds, source_dims_dict = _read_exodus(dataset)
    255             elif source_grid_spec == "Scrip":
    256                 grid_ds, source_dims_dict = _read_scrip(dataset)
    257             elif source_grid_spec == "UGRID":

~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/uxarray/io/_exodus.py in ?(ext_ds)
    101     )
    102
    103     # populate lon/lat coordinates
    104     lon, lat = _xyz_to_lonlat_deg(
--> 105         ds["node_x"].values, ds["node_y"].values, ds["node_z"].values
    106     )
    107
    108     # populate dataset

~/Sources/foss/pymech/.venv/lib/python3.12/site-packages/xarray/core/dataset.py in ?(self, key)
   1583                 message = f"No variable named {key!r}. Variables on the dataset include {shorten_list_repr(list(self.variables.keys()), max_items=10)}"
   1584                 # If someone attempts `ds['foo' , 'bar']` instead of `ds[['foo', 'bar']]`
   1585                 if isinstance(key, tuple):
   1586                     message += f"\nHint: use a list to select multiple variables, for example `ds[{[d for d in key]}]`"
-> 1587                 raise KeyError(message) from e
   1588
   1589         if utils.iterable_of_hashable(key):
   1590             return self._copy_listed(key)

KeyError: "No variable named 'node_z'. Variables on the dataset include ['node_x', 'node_y', 'face_node_connectivity']"

@ashwinvis
Copy link
Member

Yeah ! But I think extracting mesh or any mesh data from the exodus file will not provide us with the correct mesh data. The NEK5000 visualization file has the polynomial nodes data along with the nodes of the original mesh. Correct me, if I am wrong but I think this is the case only. So, in that case how to extract the connectivity data from the visualization file.

That is true. Nek5000's element numbering may be different. In that case we need its connectivity. Do you use gencon command or the genmap? If it is the latter, #40 implemented a reader for the .ma2 files. I didn't get a chance to explore it, but now is the time!

@ashwinvis
Copy link
Member

It could also be that .ma2 file does not contain this information. If getting the connectivity out of Nek5000 is too hard, we could tap into uxarray's methods to do that. The test suite TestConnectivity suggest that it should be possible:

https://github.com/UXARRAY/uxarray/blob/bd8901f665d455cf324f9773790af118f2f48ef3/test/test_grid.py#L885-L900

@airwarriorg91
Copy link
Author

Yeah ! But I think extracting mesh or any mesh data from the exodus file will not provide us with the correct mesh data. The NEK5000 visualization file has the polynomial nodes data along with the nodes of the original mesh. Correct me, if I am wrong but I think this is the case only. So, in that case how to extract the connectivity data from the visualization file.

That is true. Nek5000's element numbering may be different. In that case we need its connectivity. Do you use gencon command or the genmap? If it is the latter, #40 implemented a reader for the .ma2 files. I didn't get a chance to explore it, but now is the time!

Yeah, it is essential for simulations, so we build the .ma2. Although, I am also not sure whether it will contain the exact nodes numbering as that of the visualization file. As far as I know, it only depends on the input mesh and doesn't account for the polynomial nodes since it is generated prior to simulations.

We should work on extracting connectivity data from the .f00001 files itself. The uxarray method _build_face_face_connectivity can be helpful but no mention about it in the documentation. I will look into this. Maybe ask in the discussion section of uxarray.

@airwarriorg91
Copy link
Author

@ashwinvis You probably missed my question, I am able to make an xarray dataset which can be used for most post-processing stuff like plotting, POD calculations, etc. It lacks the element connectivity data, so is it required ? If not, this method can be used to handle structured and unstructured arrays both. It is a very simple approach.

@ashwinvis
Copy link
Member

I don't know. It depends on what you can do now. Without connectivity you may be able to plot, select a slice.

Sometimes you need to integrate or differentiate (by finite difference to roughly calculate a gradient) or interpolate along a direction. Without connectivity information that will be incredibly inconvenient.

@airwarriorg91
Copy link
Author

You can get the connectivity data at least for the EXODUS mesh like this:

import xarray as xr
mesh = xr.open_dataset("naca(10x4).e")
print(mesh.data_vars)
mesh.connect1

This integer data array has the dimensions connect1 (num_el_in_blk1, num_nod_per_el1) int32 766kB ... and looks like this:

array([[    3,     2,     1, ...,     5,     8,     7],
       [   10,     9,     2, ...,    11,     6,    13],
       [   15,    14,     9, ...,    16,    12,    18],
       ...,
       [72683, 72686, 32640, ..., 72732, 32642, 72731],
       [72686, 72689, 32645, ..., 72733, 32647, 72732],
       [72689, 72692, 32650, ..., 72734, 32652, 72733]], dtype=int32)

I am guessing it denotes one cell per row, and along the column denotes the 8 cells which surround it: 4 on each corner and 4 on each face (you need to double check it). Somebody wrote a short blog post looking at this using netCDF4, but above I used xarray (which also uses netCDF4 / h5netcdf behind the scenes).

https://johnfoster.pge.utexas.edu/blog/posts/extracting-exodus-information-with-netcdf-python/

I have an idea on how to build the connection data. The each face in the exodus file is further divided by polynomial nodes. So, each edge is a line with the polynomial as well as geometric nodes. We can get the slope of the edge and find which polynomial nodes lie on these edge and sort them based on the distance. This way we can find out how the nodes in each element object is form the face. This will work provided we can get connectivity of geometric nodes from exodus file.

Rough diagram of a 2D element (can be extended to 3D)
image

Red nodes are the polynomial nodes that we get from the .f00001 files and blue nodes are the geometric nodes.

@ashwinvis
Copy link
Member

@airwarriorg91 it has been a while. Did you work more on this?

I know it is a hard problem. It will be nice if we can try to complete this or at least document what the next steps are. Just so that we don't forget.

@airwarriorg91
Copy link
Author

@airwarriorg91 it has been a while. Did you work more on this?

I know it is a hard problem. It will be nice if we can try to complete this or at least document what the next steps are. Just so that we don't forget.

Hey !
I was a little busy with the semester end. I need to try the above idea and check its feasibility. I will probably start working on it again after Dec 15 and let you know.

Thanks,
Gaurav

@ashwinvis
Copy link
Member

Ok sounds good! It would make for a nice xmas project 🎄

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

Successfully merging this pull request may close these issues.

2 participants