Repository: yt-project/yt

Issue:
Commit a8b395e prevents dark matter-only Enzo simulations from being analyzed
<!--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-->
As of commit a8b395e1833381d1647d1b91c7ecda99a09ec75b, yt appears to fail with dark matter-only Enzo simulations as soon as frontends.enzo.fields.setup_energy_field() is called (e.g., via ds.all_data() or ds.add_particle_filter()). These simulations do not have an explicit energy field, so an error is triggered at [line 278 of frontends/enzo/fields.py](https://github.com/yt-project/yt/blob/main/yt/frontends/enzo/fields.py#L278), since ('enzo', None) is not a valid field name.

**Code for reproduction**

<!--A minimum code snippet required to reproduce the bug, also minimizing the
number of dependencies required.-->

<!-- If you need to use a data file to trigger the issue you're having, consider
using one of the datasets from the yt data hub (http://yt-project.org/data). If
your issue cannot be triggered using a public dataset, you can use the yt
curldrop (https://docs.hub.yt/services.html#curldrop) to share data
files. Please include a link to the dataset in the issue if you use the
curldrop.-->

```python
import yt
ds = yt.load('DD0064/DD0064')
ads = ds.all_data()
```
Sample dataset that generates error at: http://use.yt/upload/35be3369

**Actual outcome**

<!--The output produced by the above code, which may be a screenshot, console
output, etc.-->

```
Traceback (most recent call last):
  File "Research/Outputs/TestSphere.py", line 15, in <module>
    ads = ds.all_data()
  File "/Users/anna/yt/yt/data_objects/static_output.py", line 1052, in all_data
    self.index
  File "/Users/anna/yt/yt/data_objects/static_output.py", line 546, in index
    self.create_field_info()
  File "/Users/anna/yt/yt/data_objects/static_output.py", line 592, in create_field_info
    self.field_info.setup_fluid_fields()
  File "/Users/anna/yt/yt/frontends/enzo/fields.py", line 189, in setup_fluid_fields
    self.setup_energy_field()
  File "/Users/anna/yt/yt/frontends/enzo/fields.py", line 280, in setup_energy_field
    ("enzo", te_name), sampling_type="cell", units="code_velocity**2"
  File "/Users/anna/yt/yt/fields/field_info_container.py", line 425, in add_output_field
    self[name] = DerivedField(name, sampling_type, NullFunc, **kwargs)
  File "/Users/anna/yt/yt/fields/derived_field.py", line 134, in __init__
    validate_field_key(name)
  File "/Users/anna/yt/yt/funcs.py", line 1206, in validate_field_key
    "Expected a 2-tuple of strings formatted as\n"
TypeError: Expected a 2-tuple of strings formatted as
(field or particle type, field name)
Received invalid field key: ('enzo', None), with type <class 'tuple'>
```

**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-->
This shouldn't usually produce any output. As far as I can tell, it works on commits prior to a8b395e1833381d1647d1b91c7ecda99a09ec75b

**Version Information**
<!--Please specify your platform and versions of the relevant libraries you are
using:-->
  * Operating System: macOS 10.15.7
  * Python Version: 3.7.7
  * yt version: 4.1.dev0
  * Other Libraries (if applicable): N/A

<!--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-->
yt installed from source 


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.

Thank you for reporting this regression with such care, pinning the exact commit the problem bisects to and providing a usable dataset for reproduction. I assume for now that this reveals a bug in the Enzo frontend, so I'm going to triage it as such. I'll take a deeper look soon.
Awesome! Thanks!
@anchwr thank you so much for reporting!

I think a fix for this should go into 4.0.3.  @brittonsmith I wanted to CC you on this just to make sure you saw it.
@matthewturk Unless I'm mistaken this bug only appeared on the main branch so far (#3433) so there's no need to backport a fix to 4.0.x
@neutrinoceros good catch

Resolving patch:
diff --git a/yt/frontends/enzo/fields.py b/yt/frontends/enzo/fields.py
--- a/yt/frontends/enzo/fields.py
+++ b/yt/frontends/enzo/fields.py
@@ -214,7 +214,7 @@ def setup_energy_field(self):
         elif ("enzo", "TotalEnergy") in self.field_list:
             te_name = "TotalEnergy"
 
-        if hydro_method == 2:
+        if hydro_method == 2 and te_name is not None:
             self.add_output_field(
                 ("enzo", te_name), sampling_type="cell", units="code_velocity**2"
             )
@@ -235,23 +235,25 @@ def _ge_plus_kin(field, data):
                 units=unit_system["specific_energy"],
             )
         elif dual_energy == 1:
-            self.add_output_field(
-                ("enzo", te_name), sampling_type="cell", units="code_velocity**2"
-            )
-            self.alias(
-                ("gas", "specific_total_energy"),
-                ("enzo", te_name),
-                units=unit_system["specific_energy"],
-            )
-            self.add_output_field(
-                ("enzo", ge_name), sampling_type="cell", units="code_velocity**2"
-            )
-            self.alias(
-                ("gas", "specific_thermal_energy"),
-                ("enzo", ge_name),
-                units=unit_system["specific_energy"],
-            )
-        elif hydro_method in (4, 6):
+            if te_name is not None:
+                self.add_output_field(
+                    ("enzo", te_name), sampling_type="cell", units="code_velocity**2"
+                )
+                self.alias(
+                    ("gas", "specific_total_energy"),
+                    ("enzo", te_name),
+                    units=unit_system["specific_energy"],
+                )
+            if ge_name is not None:
+                self.add_output_field(
+                    ("enzo", ge_name), sampling_type="cell", units="code_velocity**2"
+                )
+                self.alias(
+                    ("gas", "specific_thermal_energy"),
+                    ("enzo", ge_name),
+                    units=unit_system["specific_energy"],
+                )
+        elif hydro_method in (4, 6) and te_name is not None:
             self.add_output_field(
                 ("enzo", te_name), sampling_type="cell", units="code_velocity**2"
             )
@@ -274,7 +276,7 @@ def _sub_b(field, data):
                 function=_sub_b,
                 units=unit_system["specific_energy"],
             )
-        else:  # Otherwise, we assume TotalEnergy is kinetic+thermal
+        elif te_name is not None:  # Otherwise, we assume TotalEnergy is kinetic+thermal
             self.add_output_field(
                 ("enzo", te_name), sampling_type="cell", units="code_velocity**2"
             )


Test patch: