diff --git a/openmc/_xml.py b/openmc/_xml.py index 32679fd89e..b4e08c7519 100644 --- a/openmc/_xml.py +++ b/openmc/_xml.py @@ -1,22 +1,36 @@ -def clean_indentation(element, level=0, spaces_per_level=2): - """ - copy and paste from https://effbot.org/zone/element-lib.htm#prettyprint - it basically walks your tree and adds spaces and newlines so the tree is - printed in a nice way +def clean_indentation(element, level=0, spaces_per_level=2, trailing_indent=True): + """Set indentation of XML element and its sub-elements. + Copied and pastee from https://effbot.org/zone/element-lib.htm#prettyprint. + It walks your tree and adds spaces and newlines so the tree is + printed in a nice way. + + Parameters + ---------- + level : int + Indentation level for the element passed in (default 0) + spaces_per_level : int + Number of spaces per indentation level (default 2) + trailing_indent : bool + Whether or not to include an indentation after closing the element + """ i = "\n" + level*spaces_per_level*" " + # ensure there's awlays some tail for the element passed in + if not element.tail: + element.tail = "" + if len(element): if not element.text or not element.text.strip(): element.text = i + spaces_per_level*" " - if not element.tail or not element.tail.strip(): + if trailing_indent and (not element.tail or not element.tail.strip()): element.tail = i for sub_element in element: clean_indentation(sub_element, level+1, spaces_per_level) if not sub_element.tail or not sub_element.tail.strip(): sub_element.tail = i else: - if level and (not element.tail or not element.tail.strip()): + if trailing_indent and level and (not element.tail or not element.tail.strip()): element.tail = i diff --git a/openmc/material.py b/openmc/material.py index c335968002..332f8c9659 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1449,7 +1449,7 @@ class Materials(cv.CheckedList): for material in self: material.make_isotropic_in_lab() - def _write_xml(self, file, header=True): + def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_indent=True): """Writes XML content of the materials to an open file handle. Parameters @@ -1458,33 +1458,46 @@ class Materials(cv.CheckedList): Open file handle to write content into. header : bool Whether or not to write the XML header + level : int + Indentation level of materials element + spaces_per_level : int + Number of spaces per indentation + trailing_indentation : bool + Whether or not to write a trailing indentation for the materials element + """ + indentation = level*spaces_per_level*' ' # Write the header and the opening tag for the root element. if header: file.write("\n") - file.write('\n') + file.write(indentation+'\n') # Write the element. if self.cross_sections is not None: element = ET.Element('cross_sections') element.text = str(self.cross_sections) - clean_indentation(element, level=1) + clean_indentation(element, level=level+1) element.tail = element.tail.strip(' ') - file.write(' ') + file.write((level+1)*spaces_per_level*' ') reorder_attributes(element) # TODO: Remove when support is Python 3.8+ ET.ElementTree(element).write(file, encoding='unicode') # Write the elements. for material in sorted(self, key=lambda x: x.id): element = material.to_xml_element() - clean_indentation(element, level=1) + clean_indentation(element, level=level+1) element.tail = element.tail.strip(' ') - file.write(' ') + file.write((level+1)*spaces_per_level*' ') reorder_attributes(element) # TODO: Remove when support is Python 3.8+ ET.ElementTree(element).write(file, encoding='unicode') # Write the closing tag for the root element. - file.write('\n') + file.write(indentation+'\n') + + # Write a trailing indentation for the next element + # at this level if needed + if trailing_indent: + file.write(indentation) def export_to_xml(self, path: PathLike = 'materials.xml'): diff --git a/openmc/model/model.py b/openmc/model/model.py index 15effd3e4c..9c38d27c32 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -552,6 +552,9 @@ class Model: settings_element = self.settings.to_xml_element(memo) geometry_element = self.geometry.to_xml_element() + xml.clean_indentation(geometry_element, level=1) + xml.clean_indentation(settings_element, level=1) + # If a materials collection was specified, export it. Otherwise, look # for all materials in the geometry and use that to automatically build # a collection. @@ -567,16 +570,18 @@ class Model: fh.write("\n") # Write the materials collection to the open XML file first. # This will write the XML header also - materials._write_xml(fh, False) + materials._write_xml(fh, False, level=1) # Write remaining elements as a tree ET.ElementTree(geometry_element).write(fh, encoding='unicode') ET.ElementTree(settings_element).write(fh, encoding='unicode') if self.tallies: tallies_element = self.tallies.to_xml_element(memo) + xml.clean_indentation(tallies_element, level=1, trailing_indent=self.plots) ET.ElementTree(tallies_element).write(fh, encoding='unicode') if self.plots: plots_element = self.plots.to_xml_element() + xml.clean_indentation(plots_element, level=1, trailing_indent=False) ET.ElementTree(plots_element).write(fh, encoding='unicode') fh.write("\n") diff --git a/tests/regression_tests/model_xml/inputs_true.dat b/tests/regression_tests/model_xml/inputs_true.dat index 5aedbfa143..c408026316 100644 --- a/tests/regression_tests/model_xml/inputs_true.dat +++ b/tests/regression_tests/model_xml/inputs_true.dat @@ -1,38 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 10000 - 10 - 5 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - + + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 14000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + 16 + + + neutron photon electron positron + + + 1 2 + current + + + 2 + Al27 total + total (n,gamma) + tracklength + + + 2 + Al27 total + total heating (n,gamma) + collision + + + 2 + Al27 total + total heating (n,gamma) + analog + +