openmc icon indicating copy to clipboard operation
openmc copied to clipboard

Object state is not enforced for Lattice

Open MicahGale opened this issue 1 year ago • 3 comments

Bug Description

While trying to use a lattice in a geometry that isn't fully specified (not having set lower_left) the errors produced during export are very non-intuitive and not user friendly.

Prior to exporting an object possibly some state enforcement should be done. In MontePy we have a validate function that is meant to do basically sanity checking (e.g., checking there is a density set for a non-void cell, etc.), and raise an IllegalStateException that explains what properties are causing the issue.

Steps to Reproduce

universe_1 = openmc.Universe(...)
universe_2 = openmc.Universe(...)
latt = openmc.RectLattice()
latt.pitch = (4,4)
lattice_fill = [[universe_1, universe_2]]
latt.universes = lattice_fill

parent_cell = openmc.Cell(fill=latt)
parent_cell.plot()
plt.show()

This leads to the following error, which is caused by not setting latt.lower_left:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[14], line 13
     10 #latt.lower_left=None
     12 parent_cell = openmc.Cell(fill=latt)
---> 13 parent_cell.plot()
     14 plt.show()

File /usr/local/lib/python3.9/dist-packages/openmc/cell.py:624, in Cell.plot(self, *args, **kwargs)
    622 u = openmc.Universe(cells=[self], universe_id=openmc.Universe.next_id + 1)
    623 openmc.Universe.used_ids.remove(u.id)
--> 624 return u.plot(*args, **kwargs)

File /usr/local/lib/python3.9/dist-packages/openmc/universe.py:446, in Universe.plot(self, origin, width, pixels, basis, color_by, colors, seed, openmc_exec, axes, legend, axis_units, legend_kwargs, outline, **kwargs)
    443 model.plots.append(plot)
    445 # Run OpenMC in geometry plotting mode
--> 446 model.plot_geometry(False, cwd=tmpdir, openmc_exec=openmc_exec)
    448 # Read image from file
    449 img_path = Path(tmpdir) / f'plot_{plot.id}.png'

File /usr/local/lib/python3.9/dist-packages/openmc/model/model.py:827, in Model.plot_geometry(self, output, cwd, openmc_exec)
    825     openmc.lib.plot_geometry(output)
    826 else:
--> 827     self.export_to_xml()
    828     openmc.plot_geometry(output=output, openmc_exec=openmc_exec)

File /usr/local/lib/python3.9/dist-packages/openmc/model/model.py:454, in Model.export_to_xml(self, directory, remove_surfs)
    451     d.mkdir(parents=True)
    453 self.settings.export_to_xml(d)
--> 454 self.geometry.export_to_xml(d, remove_surfs=remove_surfs)
    456 # If a materials collection was specified, export it. Otherwise, look
    457 # for all materials in the geometry and use that to automatically build
    458 # a collection.
    459 if self.materials:

File /usr/local/lib/python3.9/dist-packages/openmc/geometry.py:163, in Geometry.export_to_xml(self, path, remove_surfs)
    149 def export_to_xml(self, path='geometry.xml', remove_surfs=False):
    150     """Export geometry to an XML file.
    151 
    152     Parameters
   (...)
    161 
    162     """
--> 163     root_element = self.to_xml_element(remove_surfs)
    165     # Check if path is a directory
    166     p = Path(path)

File /usr/local/lib/python3.9/dist-packages/openmc/geometry.py:137, in Geometry.to_xml_element(self, remove_surfs)
    135 # Create XML representation
    136 element = ET.Element("geometry")
--> 137 self.root_universe.create_xml_subelement(element, memo=set())
    139 # Sort the elements in the file
    140 element[:] = sorted(element, key=lambda x: (
    141     x.tag, int(x.get('id'))))

File /usr/local/lib/python3.9/dist-packages/openmc/universe.py:695, in Universe.create_xml_subelement(self, xml_element, memo)
    692     memo.add(cell)
    694 # Create XML subelement for this Cell
--> 695 cell_element = cell.create_xml_subelement(xml_element, memo)
    697 # Append the Universe ID to the subelement and add to Element
    698 cell_element.set("universe", str(self._id))

File /usr/local/lib/python3.9/dist-packages/openmc/cell.py:662, in Cell.create_xml_subelement(self, xml_element, memo)
    660 elif self.fill_type in ('universe', 'lattice'):
    661     element.set("fill", str(self.fill.id))
--> 662     self.fill.create_xml_subelement(xml_element, memo)
    664 if self.region is not None:
    665     # Set the region attribute with the region specification
    666     region = str(self.region)

File /usr/local/lib/python3.9/dist-packages/openmc/lattice.py:880, in RectLattice.create_xml_subelement(self, xml_element, memo)
    878 # Export Lattice lower left
    879 lower_left = ET.SubElement(lattice_subelement, "lower_left")
--> 880 lower_left.text = ' '.join(map(str, self._lower_left))
    882 # Export the Lattice nested Universe IDs
    883 universe_ids = '\n'

TypeError: 'NoneType' object is not iterable

Environment

@pshriwise's CAE environment at UW-Madison.

MicahGale avatar Mar 09 '24 23:03 MicahGale

Yikes, I agree! This hearkens back to your comment a while ago about slots. For instance if you put mylat.lower_letf this same error would pop up, and that can be a real pain to figure out what's going wrong in a big input script.

gridley avatar Mar 10 '24 17:03 gridley

To be clear though __slots__ wouldn't enforce a valid state.

MicahGale avatar Mar 10 '24 20:03 MicahGale

I almost opened this issue again. -_-

MicahGale avatar Apr 15 '24 03:04 MicahGale