From 39cd31c7b6621579966bc36906da65128406e965 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 8 Mar 2020 17:58:08 -0400 Subject: [PATCH 1/4] Reduce memory usage of Materials.export_to_xml --- openmc/material.py | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 3952fe4e99..453154524e 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1163,15 +1163,6 @@ class Materials(cv.CheckedList): for material in self: material.make_isotropic_in_lab() - def _create_material_subelements(self, root_element): - for material in sorted(self, key=lambda x: x.id): - root_element.append(material.to_xml_element(self.cross_sections)) - - def _create_cross_sections_subelement(self, root_element): - if self._cross_sections is not None: - element = ET.SubElement(root_element, "cross_sections") - element.text = str(self._cross_sections) - def export_to_xml(self, path='materials.xml'): """Export material collection to an XML file. @@ -1181,22 +1172,32 @@ class Materials(cv.CheckedList): Path to file to write. Defaults to 'materials.xml'. """ - - root_element = ET.Element("materials") - self._create_cross_sections_subelement(root_element) - self._create_material_subelements(root_element) - - # Clean the indentation in the file to be user-readable - clean_indentation(root_element) - # Check if path is a directory p = Path(path) if p.is_dir(): p /= 'materials.xml' - # Write the XML Tree to the materials.xml file - tree = ET.ElementTree(root_element) - tree.write(str(p), xml_declaration=True, encoding='utf-8') + # Open the file in write mode. + with open(str(p), 'wb') as fh: + # Write the header and the opening tag for the root element. + fh.write(b"\n") + fh.write(b'\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) + fh.write(b' ' + ET.tostring(element).strip() + b'\n') + + # Write the elements. + for material in sorted(self, key=lambda x: x.id): + element = material.to_xml_element(self.cross_sections) + clean_indentation(element, level=1) + fh.write(b' ' + ET.tostring(element).strip() + b'\n') + + # Write the closing tag for the root element. + fh.write(b'\n') @classmethod def from_xml(cls, path='materials.xml'): From 40ec4a20f1d513faee508e8bb1132a7a448babd6 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 8 Mar 2020 19:01:26 -0400 Subject: [PATCH 2/4] Fix UTF-8 handling --- openmc/material.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 453154524e..49806b9ab7 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1178,26 +1178,30 @@ class Materials(cv.CheckedList): p /= 'materials.xml' # Open the file in write mode. - with open(str(p), 'wb') as fh: + with open(str(p), 'w', encoding='utf-8', + errors='xmlcharrefreplace') as fh: + # Write the header and the opening tag for the root element. - fh.write(b"\n") - fh.write(b'\n') + fh.write("\n") + fh.write('\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) - fh.write(b' ' + ET.tostring(element).strip() + b'\n') + out = ET.tostring(element, encoding='utf-8').strip() + fh.write(' ' + str(out, encoding='utf-8') + '\n') # Write the elements. for material in sorted(self, key=lambda x: x.id): element = material.to_xml_element(self.cross_sections) clean_indentation(element, level=1) - fh.write(b' ' + ET.tostring(element).strip() + b'\n') + out = ET.tostring(element, encoding='utf-8').strip() + fh.write(' ' + str(out, encoding='utf-8') + '\n') # Write the closing tag for the root element. - fh.write(b'\n') + fh.write('\n') @classmethod def from_xml(cls, path='materials.xml'): From b083e35f2ed2c80ae26ef4ef55fc58f832a8fdb0 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 8 Mar 2020 19:49:03 -0400 Subject: [PATCH 3/4] Fix write speed degradation --- openmc/material.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 49806b9ab7..2c81d1e7d5 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1190,15 +1190,17 @@ class Materials(cv.CheckedList): element = ET.Element('cross_sections') element.text = str(self._cross_sections) clean_indentation(element, level=1) - out = ET.tostring(element, encoding='utf-8').strip() - fh.write(' ' + str(out, encoding='utf-8') + '\n') + element.tail = element.tail.strip(' ') + fh.write(' ') + ET.ElementTree(element).write(fh, encoding='unicode') # Write the elements. for material in sorted(self, key=lambda x: x.id): element = material.to_xml_element(self.cross_sections) clean_indentation(element, level=1) - out = ET.tostring(element, encoding='utf-8').strip() - fh.write(' ' + str(out, encoding='utf-8') + '\n') + element.tail = element.tail.strip(' ') + fh.write(' ') + ET.ElementTree(element).write(fh, encoding='unicode') # Write the closing tag for the root element. fh.write('\n') From a6bd9a86c5ce7f3062f25bc6d48399b35cb8ce01 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 11 Mar 2020 23:30:14 -0400 Subject: [PATCH 4/4] Improve Materials.export_to_xml comment --- openmc/material.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openmc/material.py b/openmc/material.py index 2c81d1e7d5..f19cf12915 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1177,7 +1177,9 @@ class Materials(cv.CheckedList): if p.is_dir(): p /= 'materials.xml' - # Open the file in write mode. + # Write materials to the file one-at-a-time. This significantly reduces + # memory demand over allocating a complete ElementTree and writing it in + # one go. with open(str(p), 'w', encoding='utf-8', errors='xmlcharrefreplace') as fh: