Repository: yt-project/yt

Issue:
Unstructured mesh slices return data with inconsistent shapes
<!--To help us understand and resolve your issue, please fill out the form to
the best of your ability.-->
<!--You can feel free to delete the sections that do not apply.-->

### Bug report

**Bug summary**

<!--A short 1-2 sentences that succinctly describes the bug-->

This was initially reported on the mailing list as a failure in the annotate_contours plot callback.

The issue is illustrated with the following script:

```
import yt
ds = yt.load('source.e', step=-1)

slc = ds.slice(2, 1.0)

# fcoords expects four elements in the slice
print(slc.fcoords)

# but we seem to have 8 elements returned
print(slc['all', 'group_0'])
```

Right now this prints:

```
[[0.5 0.5 1.5]
 [1.5 0.5 1.5]
 [0.5 1.5 1.5]
 [1.5 1.5 1.5]] code_length
[0.02927492 0.00967331 0.00967331 0.00469298 0.         0.
 0.         0.        ] dimensionless
```

**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-->

```
[[0.5 0.5 1.5]
 [1.5 0.5 1.5]
 [0.5 1.5 1.5]
 [1.5 1.5 1.5]] code_length
[0.02927492 0.00967331 0.00967331 0.00469298] dimensionless
```

**Version Information**
<!--Please specify your platform and versions of the relevant libraries you are
using:-->
  * Operating System: mac
  * Python Version: 3.7.0
  * yt version: current master branch
  * 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-->




Discussion:
here's a patch that i'm pretty sure is wrong (don't think the mask is correct) but it allows the script to run without crashing:

```
diff --git a/yt/frontends/exodus_ii/io.py b/yt/frontends/exodus_ii/io.py
index fa9de1d0a..a639026b7 100644
--- a/yt/frontends/exodus_ii/io.py
+++ b/yt/frontends/exodus_ii/io.py
@@ -72,20 +72,32 @@ class IOHandlerExodusII(BaseIOHandler):
                     mesh_ids = [int(ftype[-1])]
                     chunk = chunks[mesh_ids[0] - 1]
                     objs = chunk.objs
+                masks = []
                 if fname in self.node_fields:
                     field_ind = self.node_fields.index(fname)
                     fdata = ds.variables['vals_nod_var%d' % (field_ind + 1)]
                     for g in objs:
+                        mask = g._get_selector_mask(selector)
+                        if mask is None:
+                            mask = np.array([False])
+                        masks.append(mask)
                         ci = g.connectivity_indices - self._INDEX_OFFSET
                         data = fdata[self.ds.step][ci]
                         ind += g.select(selector, data, rv[field], ind)  # caches
                 if fname in self.elem_fields:
                     field_ind = self.elem_fields.index(fname)
                     for g, mesh_id in zip(objs, mesh_ids):
+                        mask = g._get_selector_mask(selector)
+                        if mask is None:
+                            mask = np.array([False])
+                        masks.append(mask)
                         fdata = ds.variables['vals_elem_var%deb%s' %
                                                        (field_ind + 1, mesh_id)][:]
                         data = fdata[self.ds.step, :]
                         ind += g.select(selector, data, rv[field], ind)  # caches
+                mask = np.concatenate(masks)
+                rv[field] = rv[field][mask]
             return rv

     def _read_chunk_data(self, chunk, fields):
```
ping @MatthewTurk @atmyers 
<img width="374" alt="image" src="https://user-images.githubusercontent.com/3126246/43156798-bad619c8-8f40-11e8-99b3-674824dd6d9a.png">

Is this a heavy or a light task?
Relatively heavy, if you've never touched yt internals before I probably wouldn't try it.
Yep, I'm definitely realizing that. oh well, was worth a try
I think I have a fix though. Does this look right to you?

https://i.imgur.com/ikVIZ5W.png
That dataset is _extremely_ scaled down... so I can't guarantee for sure but for what is given it looks correct


Resolving patch:
diff --git a/yt/frontends/exodus_ii/io.py b/yt/frontends/exodus_ii/io.py
--- a/yt/frontends/exodus_ii/io.py
+++ b/yt/frontends/exodus_ii/io.py
@@ -86,6 +86,7 @@ def _read_fluid_selection(self, chunks, selector, fields, size):
                                                        (field_ind + 1, mesh_id)][:]
                         data = fdata[self.ds.step, :]
                         ind += g.select(selector, data, rv[field], ind)  # caches
+                rv[field] = rv[field][:ind]
             return rv
 
     def _read_chunk_data(self, chunk, fields):
diff --git a/yt/frontends/stream/io.py b/yt/frontends/stream/io.py
--- a/yt/frontends/stream/io.py
+++ b/yt/frontends/stream/io.py
@@ -294,5 +294,6 @@ def _read_fluid_selection(self, chunks, selector, fields, size):
                     f = ('connect%d' % (g.mesh_id + 1), fname)
                     ds = self.fields[g.mesh_id][f]
                 ind += g.select(selector, ds, rv[field], ind) # caches
+            rv[field] = rv[field][:ind]
         return rv
 


Test patch:
diff --git a/yt/visualization/tests/test_mesh_slices.py b/yt/visualization/tests/test_mesh_slices.py
--- a/yt/visualization/tests/test_mesh_slices.py
+++ b/yt/visualization/tests/test_mesh_slices.py
@@ -52,21 +52,37 @@ def test_mesh_slices_amr():
 @attr(ANSWER_TEST_TAG)
 def test_mesh_slices_tetrahedral():
     ds = fake_tetrahedral_ds()
+
+    mesh = ds.index.meshes[0]
+    ad = ds.all_data()
+
     for field in ds.field_list:
         for idir in [0, 1, 2]:
             prefix = "%s_%s_%s" % (field[0], field[1], idir)
             yield compare(ds, field, idir, test_prefix=prefix,
                           test_name="mesh_slices_tetrahedral", annotate=True)
 
+            sl_obj = ds.slice(idir, ds.domain_center[idir])
+            assert sl_obj[field].shape[0] == mesh.count(sl_obj.selector)
+            assert sl_obj[field].shape[0] < ad[field].shape[0]
+
 @attr(ANSWER_TEST_TAG)
 def test_mesh_slices_hexahedral():
+    # hexahedral ds
     ds = fake_hexahedral_ds()
+    ad = ds.all_data()
+    mesh = ds.index.meshes[0]
+
     for field in ds.field_list:
         for idir in [0, 1, 2]:
             prefix = "%s_%s_%s" % (field[0], field[1], idir)
             yield compare(ds, field, idir, test_prefix=prefix,
                           test_name="mesh_slices_hexahedral", annotate=True)
 
+            sl_obj = ds.slice(idir, ds.domain_center[idir])
+            assert sl_obj[field].shape[0] == mesh.count(sl_obj.selector)
+            assert sl_obj[field].shape[0] < ad[field].shape[0]
+
 def test_perfect_element_intersection():
     # This test tests mesh line annotation where a z=0 slice
     # perfectly intersects the top of a hexahedral element with node