Repository: openmc-dev/openmc

Issue:
Feature request: DAGMCUniverse to support get_all_universes
When we call ```.get_all_universes()``` on a ```Geometry``` that is a ```Universe``` that is filled with a DAGMC cell we get this error. ```Universe```  has the attribute but as the code cycles through the individual  parts it calls ```.get_all_universes()``` on each part and fails when it reaches the DAGMCUniverse

```python
>>>AttributeError: 'DAGMCUniverse' object has no attribute 'get_all_universes'
```

code to reproduce 

```python
import openmc
bound_dag_univ = openmc.DAGMCUniverse(filename='dagmc.h5m').bounded_universe()
my_geometry = openmc.Geometry(root=bound_dag_univ)
my_geometry.get_all_universes()
```

Could we add the same ```get_all_universes()``` method that is in ```Universe``` to the ```DAGMCUniverse```?

Alternatively could we move  ```get_all_universes()```  from ```UniverseBase``` to  ```Universe``` so that the  ```DAGMCUniverse``` inherits it?




Discussion:
Happy to put in a PR to move the ```get_all_universes``` method to the ```UniverseBase``` class if others think that is the way to go?
Sounds reasonable to me, but @pshriwise is the DAGMC god so I defer to him on this
Totally reasonable @shimwell. I ran into this as well and have a change to this effect in a local branch. A PR that addresses this specifically would be most welcome.

Resolving patch:
diff --git a/openmc/universe.py b/openmc/universe.py
--- a/openmc/universe.py
+++ b/openmc/universe.py
@@ -91,6 +91,23 @@ def add_volume_information(self, volume_calc):
         else:
             raise ValueError('No volume information found for this universe.')
 
+    def get_all_universes(self):
+        """Return all universes that are contained within this one.
+
+        Returns
+        -------
+        universes : collections.OrderedDict
+            Dictionary whose keys are universe IDs and values are
+            :class:`Universe` instances
+
+        """
+        # Append all Universes within each Cell to the dictionary
+        universes = OrderedDict()
+        for cell in self.get_all_cells().values():
+            universes.update(cell.get_all_universes())
+
+        return universes
+
     @abstractmethod
     def create_xml_subelement(self, xml_element, memo=None):
         """Add the universe xml representation to an incoming xml element
@@ -538,23 +555,6 @@ def get_all_materials(self, memo=None):
 
         return materials
 
-    def get_all_universes(self):
-        """Return all universes that are contained within this one.
-
-        Returns
-        -------
-        universes : collections.OrderedDict
-            Dictionary whose keys are universe IDs and values are
-            :class:`Universe` instances
-
-        """
-        # Append all Universes within each Cell to the dictionary
-        universes = OrderedDict()
-        for cell in self.get_all_cells().values():
-            universes.update(cell.get_all_universes())
-
-        return universes
-
     def create_xml_subelement(self, xml_element, memo=None):
         # Iterate over all Cells
         for cell in self._cells.values():


Test patch:
diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py
--- a/tests/unit_tests/test_universe.py
+++ b/tests/unit_tests/test_universe.py
@@ -93,10 +93,12 @@ def test_get_all_universes():
     u2 = openmc.Universe(cells=[c2])
     c3 = openmc.Cell(fill=u1)
     c4 = openmc.Cell(fill=u2)
-    u3 = openmc.Universe(cells=[c3, c4])
+    u3 = openmc.DAGMCUniverse(filename="")
+    c5 = openmc.Cell(fill=u3)
+    u4 = openmc.Universe(cells=[c3, c4, c5])
 
-    univs = set(u3.get_all_universes().values())
-    assert not (univs ^ {u1, u2})
+    univs = set(u4.get_all_universes().values())
+    assert not (univs ^ {u1, u2, u3})
 
 
 def test_clone():