Repository: yt-project/yt

Issue:
NaNs generated in grid edges for 1D FLASH data
### Bug report

After loading 1D FLASH data index.grid_left_edge and index.grid_right edge contain NaN values for the z axis, which are not present in the HDF5 file. This appears to then lead to errors when trying to generate data arrays.

Link to data:
http://use.yt/upload/e175762f

```python
ds = yt.load('pp_shock_hdf5_plt_cnt_0000')
dens = ds.r['gas','density']
```


```python-traceback
RuntimeError                              Traceback (most recent call last)
Cell In[4], line 1
----> 1 dens = ds.r['gas','density']

File /export/slavin/anaconda3/envs/py38/lib/python3.8/site-packages/yt/data_objects/region_expression.py:30, in RegionExpression.__getitem__(self, item)
     25 def __getitem__(self, item):
     26     # At first, we will only implement this as accepting a slice that is
     27     # (optionally) unitful corresponding to a specific set of coordinates
     28     # that result in a rectangular prism or a slice.
     29     try:
---> 30         return self.all_data[item]
     31     except (TypeError, YTFieldNotParseable):
     32         pass

File /export/slavin/anaconda3/envs/py38/lib/python3.8/site-packages/yt/data_objects/data_containers.py:264, in YTDataContainer.__getitem__(self, key)
    262         return self.field_data[f]
    263     else:
--> 264         self.get_data(f)
    265 # fi.units is the unit expression string. We depend on the registry
    266 # hanging off the dataset to define this unit object.
    267 # Note that this is less succinct so that we can account for the case
    268 # when there are, for example, no elements in the object.
    269 try:

File /export/slavin/anaconda3/envs/py38/lib/python3.8/site-packages/yt/data_objects/selection_objects/data_selection_objects.py:131, in YTSelectionContainer.get_data(self, fields)
    129 def get_data(self, fields=None):
    130     if self._current_chunk is None:
--> 131         self.index._identify_base_chunk(self)
    132     if fields is None:
    133         return

File /export/slavin/anaconda3/envs/py38/lib/python3.8/site-packages/yt/geometry/grid_geometry_handler.py:336, in GridIndex._identify_base_chunk(self, dobj)
    334     dobj._chunk_info[0] = weakref.proxy(dobj)
    335 elif getattr(dobj, "_grids", None) is None:
--> 336     gi = dobj.selector.select_grids(
    337         self.grid_left_edge, self.grid_right_edge, self.grid_levels
    338     )
    339     if any([g.filename is not None for g in self.grids[gi]]):
    340         _gsort = _grid_sort_mixed

File /export/slavin/anaconda3/envs/py38/lib/python3.8/site-packages/yt/data_objects/selection_objects/data_selection_objects.py:81, in YTSelectionContainer.selector(self)
     77     self._selector = compose_selector(
     78         self, self._data_source.selector, sclass(self)
     79     )
     80 else:
---> 81     self._selector = sclass(self)
     82 return self._selector

File /export/slavin/anaconda3/envs/py38/lib/python3.8/site-packages/yt/geometry/_selection_routines/region_selector.pxi:39, in yt.geometry.selection_routines.RegionSelector.__init__()

RuntimeError: Region right edge[2] < left edge: width = 0.0
```

**Expected outcome**

<!--A description of the expected outcome from the code snippet-->
<!--If this used to work in an earlier version of yt, please note the
version it used to work on-->

dens should be a 1D unyt_array

**Version Information**
<!--Please specify your platform and versions of the relevant libraries you are
using:-->
  * Operating System: Linux 4.18.0-425.3.1.el8.x86_64
  * Python Version: Python 3.8.13
  * yt version: 4.1.1
  * Other Libraries (if applicable):

<!--Please tell us how you installed yt and python e.g., from source,
pip, conda. If you installed from conda, please specify which channel you used
if not the default-->

conda


edited by @neutrinoceros (formatting)


Discussion:
Hi, and welcome to yt!  Thanks for opening your first issue.  We have an issue template that helps us to gather relevant information to help diagnosing and fixing the issue.

Hi, thanks for reporting this.
I can reproduce the error, however I'm not certain about your conclusions (I don't see where NaNs are involved).
If I , I get:
```
>>> print(ds.domain_left_edge)
[0. 0. 0.] code_length
>>> print(ds.domain_right_edge)
[3.08568e+19 1.00000e+00 0.00000e+00] code_length
```
we see that the width of the domain is parsed as exactly 0 in the third direction, and I believe the crash you are experiencing is a mere consequence of that.

I also see that
```
>>> ds.dimensionality
1
```
So I think what's happening is that we are not padding the "right edge" of the domain as we should.
Can you please confirm that the dimensionality is parsed correctly ?

edit: nevermind I see you already stated it's 1D in the message

In fact this edge case seems to be acknowledged in the FLASH frontend already:
https://github.com/yt-project/yt/blob/97307f4ebc78294717b718b77ecab2c1516d601a/yt/frontends/flash/data_structures.py#L404-L410

and there's a sneaky off-by-one error in there. Here's the fix:
```patch
diff --git a/yt/frontends/flash/data_structures.py b/yt/frontends/flash/data_structures.py
index 2362610a6..f1610b6b3 100644
--- a/yt/frontends/flash/data_structures.py
+++ b/yt/frontends/flash/data_structures.py
@@ -400,7 +400,7 @@ class FLASHDataset(Dataset):
         dle = np.array([self.parameters[f"{ax}min"] for ax in "xyz"]).astype("float64")
         dre = np.array([self.parameters[f"{ax}max"] for ax in "xyz"]).astype("float64")
         if self.dimensionality < 3:
-            for d in [dimensionality] + list(range(3 - dimensionality)):
+            for d in [dimensionality] + list(range(3 - dimensionality + 1)):
                 if dle[d] == dre[d]:
                     mylog.warning(
                         "Identical domain left edge and right edges "
```

I'll submit a PR with a more readable version of it
Hi Robert,

You can see the NaNs if you look at ds.index.grid_left_edge or
ds.index.grid_right_edge.
The dimensionality is correct -- the data is 1D.
I'll try your fix.

Thanks,
Jon

On Thu, Jan 12, 2023 at 11:29 AM Clément Robert ***@***.***>
wrote:

> Hi, thanks for reporting this.
> I can reproduce the error, however I'm not certain about your conclusions
> (I don't see where NaNs are involved).
> If I , I get:
>
> >>> print(ds.domain_left_edge)
> [0. 0. 0.] code_length
> >>> print(ds.domain_right_edge)
> [3.08568e+19 1.00000e+00 0.00000e+00] code_length
>
> we see that the width of the domain is parsed as exactly 0 in the third
> direction, and I believe the crash you are experiencing is a mere
> consequence of that.
>
> I also see that
>
> >>> ds.dimensionality
> 1
>
> So I think what's happening is that we are not padding the "right edge" of
> the domain as we should.
> Can you please confirm that the dimensionality is parsed correctly ?
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/yt-project/yt/issues/4296#issuecomment-1380684599>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAE5OY7HXWRVFUBKEW3DEQLWSAWONANCNFSM6AAAAAATZNYW2Y>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>


Resolving patch:
diff --git a/yt/frontends/flash/data_structures.py b/yt/frontends/flash/data_structures.py
--- a/yt/frontends/flash/data_structures.py
+++ b/yt/frontends/flash/data_structures.py
@@ -400,7 +400,7 @@ def _parse_parameter_file(self):
         dle = np.array([self.parameters[f"{ax}min"] for ax in "xyz"]).astype("float64")
         dre = np.array([self.parameters[f"{ax}max"] for ax in "xyz"]).astype("float64")
         if self.dimensionality < 3:
-            for d in [dimensionality] + list(range(3 - dimensionality)):
+            for d in range(self.dimensionality, 3):
                 if dle[d] == dre[d]:
                     mylog.warning(
                         "Identical domain left edge and right edges "


Test patch: