From 06a918c1b579b3a5a373fa55ed891e706d2dde08 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 9 Apr 2017 16:30:33 -0400 Subject: [PATCH 1/9] First stab at implementing clone() methods for geometric and material primitives --- openmc/cell.py | 14 ++++++++++++++ openmc/lattice.py | 19 +++++++++++++++++++ openmc/material.py | 7 +++++++ openmc/region.py | 31 +++++++++++++++++++++++++++++++ openmc/surface.py | 16 ++++++++++++++++ openmc/universe.py | 14 ++++++++++++++ 6 files changed, 101 insertions(+) diff --git a/openmc/cell.py b/openmc/cell.py index 9993175efd..ba7a41435b 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -504,6 +504,20 @@ class Cell(object): return universes + def clone(self): + """Create a copy of this cell with a new unique ID, and clones + the cell's region and fill.""" + + clone = copy.deepcopy(self) + clone.id = None + + if self.region is not None: + clone.region = self.region.clone() + if self.fill is not None: + clone.fill = self.fill.clone() + + return clone + def create_xml_subelement(self, xml_element): element = ET.Element("cell") element.set("id", str(self.id)) diff --git a/openmc/lattice.py b/openmc/lattice.py index 08ca24a192..9f3f303859 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -414,6 +414,25 @@ class Lattice(object): return [] return [(self, idx)] + u.find(p) + def clone(self): + """Create a copy of this lattice with a new unique ID, and clones + all universes within this lattice.""" + + clone = copy.deepcopy(self) + clone.id = None + + # Clone all unique universes in the lattice + univ_clones = self.get_unique_universes() + for univ_id in univ_clones: + univ_clones[univ_id] = univ_clones[univ_id].clone() + + # Assign universe clones to the lattice clone + for index in self.indices: + univ_id = self.universe[index].id + clone.universes[index] = univ_clones[univ_id] + + return clone + class RectLattice(Lattice): """A lattice consisting of rectangular prisms. diff --git a/openmc/material.py b/openmc/material.py index 26b1bce8fc..cb1482b8e0 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1100,6 +1100,13 @@ class Materials(cv.CheckedList): for material in self: material.make_isotropic_in_lab() + def clone(self): + """Create a copy of this material with a new unique ID.""" + + clone = copy.deepcopy(self) + clone.id = None + return clone + def _create_material_subelements(self, root_element): for material in self: root_element.append(material.to_xml_element(self.cross_sections)) diff --git a/openmc/region.py b/openmc/region.py index a2a92c15a3..1ac4d8c948 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -221,6 +221,12 @@ class Region(object): # at the end return output[0] + @abstractmethod + def clone(self): + """Create a copy of this region - each of the surfaces in the + region's nodes will be cloned and will have new unique IDs.""" + return False + class Intersection(Region): r"""Intersection of two or more regions. @@ -300,6 +306,15 @@ class Intersection(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes + @abstractmethod + def clone(self): + """Create a copy of this region - each of the surfaces in the + intersection's nodes will be cloned and will have new unique IDs.""" + + clone = copy.deepcopy(self) + clone.nodes = [n.clone() for n in self.nodes] + return clone + class Union(Region): r"""Union of two or more regions. @@ -377,6 +392,14 @@ class Union(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes + def clone(self): + """Create a copy of this region - each of the surfaces in the + union's nodes will be cloned and will have new unique IDs.""" + + clone = copy.deepcopy(self) + clone.nodes = [n.clone() for n in self.nodes] + return clone + class Complement(Region): """Complement of a region. @@ -473,3 +496,11 @@ class Complement(Region): for region in self.node: surfaces = region.get_surfaces(surfaces) return surfaces + + def clone(self): + """Create a copy of this region - each of the surfaces in the + complement's node will be cloned and will have new unique IDs.""" + + clone = copy.deepcopy(self) + clone.node = self.node.clone() + return clone diff --git a/openmc/surface.py b/openmc/surface.py index 9c6be78a77..b0aa250c03 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -171,6 +171,13 @@ class Surface(object): return (np.array([-np.inf, -np.inf, -np.inf]), np.array([np.inf, np.inf, np.inf])) + def clone(self): + """Create a copy of this surface with a new unique ID.""" + + clone = copy.deepcopy(self) + clone.id = None + return clone + def to_xml_element(self): """Return XML representation of the surface @@ -1822,6 +1829,15 @@ class Halfspace(Region): self.surface = surface self.side = side + @abstractmethod + def clone(self): + """Create a copy of this halfspace, with a cloned surface with a + unique ID.""" + + clone = copy.deepcopy(self) + clone.surface = self.surface.clone() + return clone + def __and__(self, other): if isinstance(other, Intersection): return Intersection(self, *other.nodes) diff --git a/openmc/universe.py b/openmc/universe.py index 1c631e7e07..0f5e2da140 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -517,6 +517,20 @@ class Universe(object): return universes + def clone(self): + """Create a copy of this universe with a new unique ID, and clones + all cells within this universe.""" + + clone = copy.deepcopy(self) + clone.id = None + + # Clone all cells for the universe clone + clone._cells = OrderedDict() + for cell in self._cells.values(): + clone.add_cell(cell.clone()) + + return clone + def create_xml_subelement(self, xml_element): # Iterate over all Cells for cell_id, cell in self._cells.items(): From 45af8a29379b9398565afdea751f67933ac47682 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 9 Apr 2017 22:23:49 -0400 Subject: [PATCH 2/9] Tested geometry cloning with examples and fixed a few bugs --- openmc/cell.py | 3 ++- openmc/lattice.py | 17 +++++++++++++---- openmc/material.py | 14 +++++++------- openmc/region.py | 4 ++-- openmc/surface.py | 20 ++++++++++---------- openmc/universe.py | 4 ++-- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index ba7a41435b..522f9ab5d3 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -1,4 +1,5 @@ from collections import OrderedDict, Iterable +from copy import deepcopy from math import cos, sin, pi from numbers import Real, Integral from xml.etree import ElementTree as ET @@ -508,7 +509,7 @@ class Cell(object): """Create a copy of this cell with a new unique ID, and clones the cell's region and fill.""" - clone = copy.deepcopy(self) + clone = deepcopy(self) clone.id = None if self.region is not None: diff --git a/openmc/lattice.py b/openmc/lattice.py index 9f3f303859..b98ef00877 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -2,6 +2,7 @@ from __future__ import division from abc import ABCMeta from collections import OrderedDict, Iterable +from copy import deepcopy from math import sqrt, floor from numbers import Real, Integral from xml.etree import ElementTree as ET @@ -418,7 +419,7 @@ class Lattice(object): """Create a copy of this lattice with a new unique ID, and clones all universes within this lattice.""" - clone = copy.deepcopy(self) + clone = deepcopy(self) clone.id = None # Clone all unique universes in the lattice @@ -427,9 +428,17 @@ class Lattice(object): univ_clones[univ_id] = univ_clones[univ_id].clone() # Assign universe clones to the lattice clone - for index in self.indices: - univ_id = self.universe[index].id - clone.universes[index] = univ_clones[univ_id] + for i in self.indices: + if isinstance(self, RectLattice): + univ_id = self.universes[i].id + clone.universes[i] = univ_clones[univ_id] + else: + if self.ndim == 2: + univ_id = self.universes[i[0]][i[1]].id + clone.universes[i[0]][i[1]] = univ_clones[univ_id] + else: + univ_id = self.universes[i[0]][i[1]][i[2]].id + clone.universes[i[0]][i[1]][i[2]] = univ_clones[univ_id] return clone diff --git a/openmc/material.py b/openmc/material.py index cb1482b8e0..be13d619fe 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -799,6 +799,13 @@ class Material(object): return nuclides + def clone(self): + """Create a copy of this material with a new unique ID.""" + + clone = deepcopy(self) + clone.id = None + return clone + def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") xml_element.set("name", nuclide[0].name) @@ -1100,13 +1107,6 @@ class Materials(cv.CheckedList): for material in self: material.make_isotropic_in_lab() - def clone(self): - """Create a copy of this material with a new unique ID.""" - - clone = copy.deepcopy(self) - clone.id = None - return clone - def _create_material_subelements(self, root_element): for material in self: root_element.append(material.to_xml_element(self.cross_sections)) diff --git a/openmc/region.py b/openmc/region.py index 1ac4d8c948..b93d305fea 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,5 +1,6 @@ from abc import ABCMeta, abstractmethod from collections import Iterable, OrderedDict +from copy import deepcopy from six import add_metaclass import numpy as np @@ -306,12 +307,11 @@ class Intersection(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes - @abstractmethod def clone(self): """Create a copy of this region - each of the surfaces in the intersection's nodes will be cloned and will have new unique IDs.""" - clone = copy.deepcopy(self) + clone = deepcopy(self) clone.nodes = [n.clone() for n in self.nodes] return clone diff --git a/openmc/surface.py b/openmc/surface.py index b0aa250c03..866a9e2b98 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,5 +1,6 @@ from abc import ABCMeta from collections import Iterable, OrderedDict +from copy import deepcopy from numbers import Real, Integral from xml.etree import ElementTree as ET from math import sqrt @@ -174,7 +175,7 @@ class Surface(object): def clone(self): """Create a copy of this surface with a new unique ID.""" - clone = copy.deepcopy(self) + clone = deepcopy(self) clone.id = None return clone @@ -1828,15 +1829,6 @@ class Halfspace(Region): def __init__(self, surface, side): self.surface = surface self.side = side - - @abstractmethod - def clone(self): - """Create a copy of this halfspace, with a cloned surface with a - unique ID.""" - - clone = copy.deepcopy(self) - clone.surface = self.surface.clone() - return clone def __and__(self, other): if isinstance(other, Intersection): @@ -1918,6 +1910,14 @@ class Halfspace(Region): surfaces[self.surface.id] = self.surface return surfaces + def clone(self): + """Create a copy of this halfspace, with a cloned surface with a + unique ID.""" + + clone = deepcopy(self) + clone.surface = self.surface.clone() + return clone + def get_rectangular_prism(width, height, axis='z', origin=(0., 0.), boundary_type='transmission'): diff --git a/openmc/universe.py b/openmc/universe.py index 0f5e2da140..a2157f1d78 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -1,6 +1,6 @@ from __future__ import division -from copy import copy from collections import OrderedDict, Iterable +from copy import copy, deepcopy from numbers import Integral, Real import random import sys @@ -521,7 +521,7 @@ class Universe(object): """Create a copy of this universe with a new unique ID, and clones all cells within this universe.""" - clone = copy.deepcopy(self) + clone = deepcopy(self) clone.id = None # Clone all cells for the universe clone From c4fe563395b2cd471163fc876112535d5983babc Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 9 Apr 2017 22:26:09 -0400 Subject: [PATCH 3/9] Added clone method to Geometry class --- openmc/geometry.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openmc/geometry.py b/openmc/geometry.py index ce7d47d9e2..424a7053e5 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -1,4 +1,5 @@ from collections import OrderedDict, Iterable +from copy import deepcopy from xml.etree import ElementTree as ET from six import string_types @@ -497,3 +498,11 @@ class Geometry(object): # Recursively traverse the CSG tree to count all cell instances self.root_universe._determine_paths() + + def clone(self): + """Create a copy of this geometry with new unique IDs for all of its + enclosed materials, surfaces, cells, universes and lattices.""" + + clone = deepcopy(self) + clone.root_universe = deepcopy(self.root_universe) + return clone From 364543b96771b36926ac978b1d632ff6056836e9 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Mon, 10 Apr 2017 10:06:32 -0400 Subject: [PATCH 4/9] Now use memoization for geometry and materials cloning --- openmc/cell.py | 28 ++++++++++++++++++--------- openmc/geometry.py | 2 +- openmc/lattice.py | 48 +++++++++++++++++++++++++++------------------- openmc/material.py | 19 +++++++++++++----- openmc/region.py | 28 ++++++++++++++++++--------- openmc/surface.py | 26 ++++++++++++++++++------- openmc/universe.py | 23 +++++++++++++--------- 7 files changed, 114 insertions(+), 60 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 522f9ab5d3..46da0c45d9 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -1,4 +1,4 @@ -from collections import OrderedDict, Iterable +from collections import OrderedDict, Iterable, defaultdict from copy import deepcopy from math import cos, sin, pi from numbers import Real, Integral @@ -505,19 +505,29 @@ class Cell(object): return universes - def clone(self): + def clone(self, memoize=None): """Create a copy of this cell with a new unique ID, and clones the cell's region and fill.""" - clone = deepcopy(self) - clone.id = None + if memoize is None: + memoize = defaultdict(dict) - if self.region is not None: - clone.region = self.region.clone() - if self.fill is not None: - clone.fill = self.fill.clone() + # If no nemoize'd clone exists, instantiate one + if self.id not in memoize['cells']: + clone = deepcopy(self) + clone.id = None + if self.region is not None: + clone.region = self.region.clone(memoize) + if self.fill is not None: + if self.fill_type == 'distribmat': + clone.fill = [fill.clone(memoize) for fill in self.fill] + else: + clone.fill = self.fill.clone(memoize) - return clone + # Memoize the clone + memoize['cells'][self.id] = clone + + return memoize['cells'][self.id] def create_xml_subelement(self, xml_element): element = ET.Element("cell") diff --git a/openmc/geometry.py b/openmc/geometry.py index 424a7053e5..27fee65739 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -504,5 +504,5 @@ class Geometry(object): enclosed materials, surfaces, cells, universes and lattices.""" clone = deepcopy(self) - clone.root_universe = deepcopy(self.root_universe) + clone.root_universe = self.root_universe.clone() return clone diff --git a/openmc/lattice.py b/openmc/lattice.py index b98ef00877..d92753ae3c 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -1,7 +1,7 @@ from __future__ import division from abc import ABCMeta -from collections import OrderedDict, Iterable +from collections import OrderedDict, Iterable, defaultdict from copy import deepcopy from math import sqrt, floor from numbers import Real, Integral @@ -415,32 +415,40 @@ class Lattice(object): return [] return [(self, idx)] + u.find(p) - def clone(self): + def clone(self, memoize=None): """Create a copy of this lattice with a new unique ID, and clones all universes within this lattice.""" - clone = deepcopy(self) - clone.id = None + if memoize is None: + memoize = defaultdict(dict) - # Clone all unique universes in the lattice - univ_clones = self.get_unique_universes() - for univ_id in univ_clones: - univ_clones[univ_id] = univ_clones[univ_id].clone() + # If no nemoize'd clone exists, instantiate one + if self.id not in memoize['lattices']: + clone = deepcopy(self) + clone.id = None - # Assign universe clones to the lattice clone - for i in self.indices: - if isinstance(self, RectLattice): - univ_id = self.universes[i].id - clone.universes[i] = univ_clones[univ_id] - else: - if self.ndim == 2: - univ_id = self.universes[i[0]][i[1]].id - clone.universes[i[0]][i[1]] = univ_clones[univ_id] + # Clone all unique universes in the lattice + univ_clones = self.get_unique_universes() + for univ_id in univ_clones: + univ_clones[univ_id] = univ_clones[univ_id].clone(memoize) + + # Assign universe clones to the lattice clone + for i in self.indices: + if isinstance(self, RectLattice): + univ_id = self.universes[i].id + clone.universes[i] = univ_clones[univ_id] else: - univ_id = self.universes[i[0]][i[1]][i[2]].id - clone.universes[i[0]][i[1]][i[2]] = univ_clones[univ_id] + if self.ndim == 2: + univ_id = self.universes[i[0]][i[1]].id + clone.universes[i[0]][i[1]] = univ_clones[univ_id] + else: + univ_id = self.universes[i[0]][i[1]][i[2]].id + clone.universes[i[0]][i[1]][i[2]] = univ_clones[univ_id] - return clone + # Memoize the clone + memoize['lattices'][self.id] = clone + + return memoize['lattices'][self.id] class RectLattice(Lattice): diff --git a/openmc/material.py b/openmc/material.py index be13d619fe..06ba41ddf1 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1,4 +1,4 @@ -from collections import OrderedDict +from collections import OrderedDict, defaultdict from copy import deepcopy from numbers import Real, Integral import warnings @@ -799,12 +799,21 @@ class Material(object): return nuclides - def clone(self): + def clone(self, memoize=None): """Create a copy of this material with a new unique ID.""" - clone = deepcopy(self) - clone.id = None - return clone + if memoize is None: + memoize = defaultdict(dict) + + # If no nemoize'd clone exists, instantiate one + if self.id not in memoize['materials']: + clone = deepcopy(self) + clone.id = None + + # Memoize the clone + memoize['materials'][self.id] = clone + + return memoize['materials'][self.id] def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") diff --git a/openmc/region.py b/openmc/region.py index b93d305fea..8c9c4e59d2 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,5 +1,5 @@ from abc import ABCMeta, abstractmethod -from collections import Iterable, OrderedDict +from collections import Iterable, OrderedDict, defaultdict from copy import deepcopy from six import add_metaclass @@ -223,10 +223,11 @@ class Region(object): return output[0] @abstractmethod - def clone(self): + def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the region's nodes will be cloned and will have new unique IDs.""" - return False + raise NotImplementedError('The clone method is not implemented for ' + 'the abstract region class.') class Intersection(Region): @@ -307,12 +308,15 @@ class Intersection(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes - def clone(self): + def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the intersection's nodes will be cloned and will have new unique IDs.""" + if memoize is None: + memoize = defaultdict(dict) + clone = deepcopy(self) - clone.nodes = [n.clone() for n in self.nodes] + clone.nodes = [n.clone(memoize) for n in self.nodes] return clone @@ -392,12 +396,15 @@ class Union(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes - def clone(self): + def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the union's nodes will be cloned and will have new unique IDs.""" + if memoize is None: + memoize = defaultdict(dict) + clone = copy.deepcopy(self) - clone.nodes = [n.clone() for n in self.nodes] + clone.nodes = [n.clone(memoize) for n in self.nodes] return clone @@ -497,10 +504,13 @@ class Complement(Region): surfaces = region.get_surfaces(surfaces) return surfaces - def clone(self): + def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the complement's node will be cloned and will have new unique IDs.""" + if memoize is None: + memoize = defaultdict(dict) + clone = copy.deepcopy(self) - clone.node = self.node.clone() + clone.node = self.node.clone(memoize) return clone diff --git a/openmc/surface.py b/openmc/surface.py index 866a9e2b98..14c1692d0e 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,5 +1,5 @@ from abc import ABCMeta -from collections import Iterable, OrderedDict +from collections import Iterable, OrderedDict, defaultdict from copy import deepcopy from numbers import Real, Integral from xml.etree import ElementTree as ET @@ -172,12 +172,21 @@ class Surface(object): return (np.array([-np.inf, -np.inf, -np.inf]), np.array([np.inf, np.inf, np.inf])) - def clone(self): + def clone(self, memoize=None): """Create a copy of this surface with a new unique ID.""" - clone = deepcopy(self) - clone.id = None - return clone + if memoize is None: + memoize = defaultdict(dict) + + # If no nemoize'd clone exists, instantiate one + if self.id not in memoize['surfaces']: + clone = deepcopy(self) + clone.id = None + + # Memoize the clone + memoize['surfaces'][self.id] = clone + + return memoize['surfaces'][self.id] def to_xml_element(self): """Return XML representation of the surface @@ -1910,12 +1919,15 @@ class Halfspace(Region): surfaces[self.surface.id] = self.surface return surfaces - def clone(self): + def clone(self, memoize=None): """Create a copy of this halfspace, with a cloned surface with a unique ID.""" + if memoize is None: + memoize = defaultdict(dict) + clone = deepcopy(self) - clone.surface = self.surface.clone() + clone.surface = self.surface.clone(memoize) return clone diff --git a/openmc/universe.py b/openmc/universe.py index a2157f1d78..5f272c6e56 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -1,5 +1,5 @@ from __future__ import division -from collections import OrderedDict, Iterable +from collections import OrderedDict, Iterable, defaultdict from copy import copy, deepcopy from numbers import Integral, Real import random @@ -517,19 +517,24 @@ class Universe(object): return universes - def clone(self): + def clone(self, memoize=None): """Create a copy of this universe with a new unique ID, and clones all cells within this universe.""" - clone = deepcopy(self) - clone.id = None + if memoize is None: + memoize = defaultdict(dict) - # Clone all cells for the universe clone - clone._cells = OrderedDict() - for cell in self._cells.values(): - clone.add_cell(cell.clone()) + # If no nemoize'd clone exists, instantiate one + if self.id not in memoize['universes']: + memoize['universes'][self.id] = deepcopy(self) + memoize['universes'][self.id].id = None - return clone + # Clone all cells for the universe clone + memoize['universes'][self.id]._cells = OrderedDict() + for cell in self._cells.values(): + memoize['universes'][self.id].add_cell(cell.clone(memoize)) + + return memoize['universes'][self.id] def create_xml_subelement(self, xml_element): # Iterate over all Cells From 12a0e00305c881c9bbaa1626a725372e14e2e96c Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Mon, 10 Apr 2017 10:13:59 -0400 Subject: [PATCH 5/9] Expanded docstrings for all clone methods --- openmc/cell.py | 15 ++++++++++- openmc/lattice.py | 15 ++++++++++- openmc/material.py | 15 ++++++++++- openmc/region.py | 65 +++++++++++++++++++++++++++++++++++++++++++--- openmc/surface.py | 30 +++++++++++++++++++-- openmc/universe.py | 15 ++++++++++- 6 files changed, 145 insertions(+), 10 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 46da0c45d9..61690e98c3 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -507,7 +507,20 @@ class Cell(object): def clone(self, memoize=None): """Create a copy of this cell with a new unique ID, and clones - the cell's region and fill.""" + the cell's region and fill. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Cell + The clone of this cell + + """ if memoize is None: memoize = defaultdict(dict) diff --git a/openmc/lattice.py b/openmc/lattice.py index d92753ae3c..26eadbe7ff 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -417,7 +417,20 @@ class Lattice(object): def clone(self, memoize=None): """Create a copy of this lattice with a new unique ID, and clones - all universes within this lattice.""" + all universes within this lattice. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Lattice + The clone of this lattice + + """ if memoize is None: memoize = defaultdict(dict) diff --git a/openmc/material.py b/openmc/material.py index 06ba41ddf1..75c31f37c8 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -800,7 +800,20 @@ class Material(object): return nuclides def clone(self, memoize=None): - """Create a copy of this material with a new unique ID.""" + """Create a copy of this material with a new unique ID. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Material + The clone of this material + + """ if memoize is None: memoize = defaultdict(dict) diff --git a/openmc/region.py b/openmc/region.py index 8c9c4e59d2..37078eda85 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -225,7 +225,25 @@ class Region(object): @abstractmethod def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the - region's nodes will be cloned and will have new unique IDs.""" + region's nodes will be cloned and will have new unique IDs. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Region + The clone of this region + + Raises + ------ + NotImplementedError + This method is not implemented for the abstract region class. + + """ raise NotImplementedError('The clone method is not implemented for ' 'the abstract region class.') @@ -310,7 +328,20 @@ class Intersection(Region): def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the - intersection's nodes will be cloned and will have new unique IDs.""" + intersection's nodes will be cloned and will have new unique IDs. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Intersection + The clone of this intersection + + """ if memoize is None: memoize = defaultdict(dict) @@ -398,7 +429,20 @@ class Union(Region): def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the - union's nodes will be cloned and will have new unique IDs.""" + union's nodes will be cloned and will have new unique IDs. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Union + The clone of this union + + """ if memoize is None: memoize = defaultdict(dict) @@ -506,7 +550,20 @@ class Complement(Region): def clone(self, memoize=None): """Create a copy of this region - each of the surfaces in the - complement's node will be cloned and will have new unique IDs.""" + complement's node will be cloned and will have new unique IDs. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Complement + The clone of this complement + + """ if memoize is None: memoize = defaultdict(dict) diff --git a/openmc/surface.py b/openmc/surface.py index 14c1692d0e..1eb69d2db6 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -173,7 +173,20 @@ class Surface(object): np.array([np.inf, np.inf, np.inf])) def clone(self, memoize=None): - """Create a copy of this surface with a new unique ID.""" + """Create a copy of this surface with a new unique ID. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Surface + The clone of this surface + + """ if memoize is None: memoize = defaultdict(dict) @@ -1921,7 +1934,20 @@ class Halfspace(Region): def clone(self, memoize=None): """Create a copy of this halfspace, with a cloned surface with a - unique ID.""" + unique ID. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Halfspace + The clone of this halfspace + + """ if memoize is None: memoize = defaultdict(dict) diff --git a/openmc/universe.py b/openmc/universe.py index 5f272c6e56..9453dfb11a 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -519,7 +519,20 @@ class Universe(object): def clone(self, memoize=None): """Create a copy of this universe with a new unique ID, and clones - all cells within this universe.""" + all cells within this universe. + + Parameters + ---------- + memoize : defaultdict(dict) or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Universe + The clone of this universe + + """ if memoize is None: memoize = defaultdict(dict) From 120dca77035e5c6989e6f4bffe19c9e67bee743f Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Mon, 10 Apr 2017 12:10:34 -0400 Subject: [PATCH 6/9] Renamed clone memoize param as memo per request by @paulromano --- openmc/cell.py | 21 +++++++++++---------- openmc/lattice.py | 19 +++++++++++-------- openmc/material.py | 14 +++++++------- openmc/region.py | 34 +++++++++++++++++----------------- openmc/surface.py | 24 ++++++++++++------------ openmc/universe.py | 23 +++++++++++++---------- 6 files changed, 71 insertions(+), 64 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 61690e98c3..b0847fc047 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -505,13 +505,13 @@ class Cell(object): return universes - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this cell with a new unique ID, and clones the cell's region and fill. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -522,25 +522,26 @@ class Cell(object): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) # If no nemoize'd clone exists, instantiate one - if self.id not in memoize['cells']: + if self.id not in memo['cells']: clone = deepcopy(self) clone.id = None if self.region is not None: - clone.region = self.region.clone(memoize) + clone.region = self.region.clone(memo) if self.fill is not None: if self.fill_type == 'distribmat': - clone.fill = [fill.clone(memoize) for fill in self.fill] + clone.fill = [fill.clone(memo) if fill is not None else None + for fill in self.fill] else: - clone.fill = self.fill.clone(memoize) + clone.fill = self.fill.clone(memo) # Memoize the clone - memoize['cells'][self.id] = clone + memo['cells'][self.id] = clone - return memoize['cells'][self.id] + return memo['cells'][self.id] def create_xml_subelement(self, xml_element): element = ET.Element("cell") diff --git a/openmc/lattice.py b/openmc/lattice.py index 26eadbe7ff..f9fa63331a 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -415,13 +415,13 @@ class Lattice(object): return [] return [(self, idx)] + u.find(p) - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this lattice with a new unique ID, and clones all universes within this lattice. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -432,18 +432,21 @@ class Lattice(object): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) # If no nemoize'd clone exists, instantiate one - if self.id not in memoize['lattices']: + if self.id not in memo['lattices']: clone = deepcopy(self) clone.id = None + if self.outer is not None: + clone.outer = self.outer.clone() + # Clone all unique universes in the lattice univ_clones = self.get_unique_universes() for univ_id in univ_clones: - univ_clones[univ_id] = univ_clones[univ_id].clone(memoize) + univ_clones[univ_id] = univ_clones[univ_id].clone(memo) # Assign universe clones to the lattice clone for i in self.indices: @@ -459,9 +462,9 @@ class Lattice(object): clone.universes[i[0]][i[1]][i[2]] = univ_clones[univ_id] # Memoize the clone - memoize['lattices'][self.id] = clone + memo['lattices'][self.id] = clone - return memoize['lattices'][self.id] + return memo['lattices'][self.id] class RectLattice(Lattice): diff --git a/openmc/material.py b/openmc/material.py index 75c31f37c8..cdb82da03d 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -799,12 +799,12 @@ class Material(object): return nuclides - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this material with a new unique ID. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -815,18 +815,18 @@ class Material(object): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) # If no nemoize'd clone exists, instantiate one - if self.id not in memoize['materials']: + if self.id not in memo['materials']: clone = deepcopy(self) clone.id = None # Memoize the clone - memoize['materials'][self.id] = clone + memo['materials'][self.id] = clone - return memoize['materials'][self.id] + return memo['materials'][self.id] def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") diff --git a/openmc/region.py b/openmc/region.py index 37078eda85..0b1f970840 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -223,13 +223,13 @@ class Region(object): return output[0] @abstractmethod - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this region - each of the surfaces in the region's nodes will be cloned and will have new unique IDs. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -326,13 +326,13 @@ class Intersection(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this region - each of the surfaces in the intersection's nodes will be cloned and will have new unique IDs. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -343,11 +343,11 @@ class Intersection(Region): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) clone = deepcopy(self) - clone.nodes = [n.clone(memoize) for n in self.nodes] + clone.nodes = [n.clone(memo) for n in self.nodes] return clone @@ -427,13 +427,13 @@ class Union(Region): check_type('nodes', nodes, Iterable, Region) self._nodes = nodes - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this region - each of the surfaces in the union's nodes will be cloned and will have new unique IDs. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -444,11 +444,11 @@ class Union(Region): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) clone = copy.deepcopy(self) - clone.nodes = [n.clone(memoize) for n in self.nodes] + clone.nodes = [n.clone(memo) for n in self.nodes] return clone @@ -548,13 +548,13 @@ class Complement(Region): surfaces = region.get_surfaces(surfaces) return surfaces - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this region - each of the surfaces in the complement's node will be cloned and will have new unique IDs. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -565,9 +565,9 @@ class Complement(Region): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) clone = copy.deepcopy(self) - clone.node = self.node.clone(memoize) + clone.node = self.node.clone(memo) return clone diff --git a/openmc/surface.py b/openmc/surface.py index 1eb69d2db6..1edae2cae7 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -172,12 +172,12 @@ class Surface(object): return (np.array([-np.inf, -np.inf, -np.inf]), np.array([np.inf, np.inf, np.inf])) - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this surface with a new unique ID. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -188,18 +188,18 @@ class Surface(object): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) # If no nemoize'd clone exists, instantiate one - if self.id not in memoize['surfaces']: + if self.id not in memo['surfaces']: clone = deepcopy(self) clone.id = None # Memoize the clone - memoize['surfaces'][self.id] = clone + memo['surfaces'][self.id] = clone - return memoize['surfaces'][self.id] + return memo['surfaces'][self.id] def to_xml_element(self): """Return XML representation of the surface @@ -1932,13 +1932,13 @@ class Halfspace(Region): surfaces[self.surface.id] = self.surface return surfaces - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this halfspace, with a cloned surface with a unique ID. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -1949,11 +1949,11 @@ class Halfspace(Region): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) clone = deepcopy(self) - clone.surface = self.surface.clone(memoize) + clone.surface = self.surface.clone(memo) return clone diff --git a/openmc/universe.py b/openmc/universe.py index 9453dfb11a..1fefa2372c 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -517,13 +517,13 @@ class Universe(object): return universes - def clone(self, memoize=None): + def clone(self, memo=None): """Create a copy of this universe with a new unique ID, and clones all cells within this universe. Parameters ---------- - memoize : defaultdict(dict) or None + memo : defaultdict(dict) or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -534,20 +534,23 @@ class Universe(object): """ - if memoize is None: - memoize = defaultdict(dict) + if memo is None: + memo = defaultdict(dict) # If no nemoize'd clone exists, instantiate one - if self.id not in memoize['universes']: - memoize['universes'][self.id] = deepcopy(self) - memoize['universes'][self.id].id = None + if self.id not in memo['universes']: + clone = deepcopy(self) + clone.id = None # Clone all cells for the universe clone - memoize['universes'][self.id]._cells = OrderedDict() + clone._cells = OrderedDict() for cell in self._cells.values(): - memoize['universes'][self.id].add_cell(cell.clone(memoize)) + clone.add_cell(cell.clone(memo)) - return memoize['universes'][self.id] + # Memoize the clone + memo['universes'][self.id] = clone + + return memo['universes'][self.id] def create_xml_subelement(self, xml_element): # Iterate over all Cells From 400b5e2c1df2a00f6d5da39353466bb16316dae0 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Mon, 10 Apr 2017 17:17:17 -0400 Subject: [PATCH 7/9] Added __hash__ method to Surface class; revised clone methods memo param to use objects as keys --- openmc/cell.py | 12 ++++++------ openmc/lattice.py | 14 +++++++------- openmc/material.py | 12 ++++++------ openmc/region.py | 16 ++++++++-------- openmc/surface.py | 19 +++++++++++-------- openmc/universe.py | 12 ++++++------ 6 files changed, 44 insertions(+), 41 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index b0847fc047..4496062f7f 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -1,4 +1,4 @@ -from collections import OrderedDict, Iterable, defaultdict +from collections import OrderedDict, Iterable from copy import deepcopy from math import cos, sin, pi from numbers import Real, Integral @@ -511,7 +511,7 @@ class Cell(object): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -523,10 +523,10 @@ class Cell(object): """ if memo is None: - memo = defaultdict(dict) + memo = {} # If no nemoize'd clone exists, instantiate one - if self.id not in memo['cells']: + if self not in memo: clone = deepcopy(self) clone.id = None if self.region is not None: @@ -539,9 +539,9 @@ class Cell(object): clone.fill = self.fill.clone(memo) # Memoize the clone - memo['cells'][self.id] = clone + memo[self] = clone - return memo['cells'][self.id] + return memo[self] def create_xml_subelement(self, xml_element): element = ET.Element("cell") diff --git a/openmc/lattice.py b/openmc/lattice.py index f9fa63331a..0fbd74f28e 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -1,7 +1,7 @@ from __future__ import division from abc import ABCMeta -from collections import OrderedDict, Iterable, defaultdict +from collections import OrderedDict, Iterable from copy import deepcopy from math import sqrt, floor from numbers import Real, Integral @@ -421,7 +421,7 @@ class Lattice(object): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -433,15 +433,15 @@ class Lattice(object): """ if memo is None: - memo = defaultdict(dict) + memo = {} # If no nemoize'd clone exists, instantiate one - if self.id not in memo['lattices']: + if self not in memo: clone = deepcopy(self) clone.id = None if self.outer is not None: - clone.outer = self.outer.clone() + clone.outer = self.outer.clone(memo) # Clone all unique universes in the lattice univ_clones = self.get_unique_universes() @@ -462,9 +462,9 @@ class Lattice(object): clone.universes[i[0]][i[1]][i[2]] = univ_clones[univ_id] # Memoize the clone - memo['lattices'][self.id] = clone + memo[self] = clone - return memo['lattices'][self.id] + return memo[self] class RectLattice(Lattice): diff --git a/openmc/material.py b/openmc/material.py index cdb82da03d..762337659a 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1,4 +1,4 @@ -from collections import OrderedDict, defaultdict +from collections import OrderedDict from copy import deepcopy from numbers import Real, Integral import warnings @@ -804,7 +804,7 @@ class Material(object): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -816,17 +816,17 @@ class Material(object): """ if memo is None: - memo = defaultdict(dict) + memo = dict # If no nemoize'd clone exists, instantiate one - if self.id not in memo['materials']: + if self not in memo: clone = deepcopy(self) clone.id = None # Memoize the clone - memo['materials'][self.id] = clone + memo[self] = clone - return memo['materials'][self.id] + return memo[self] def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") diff --git a/openmc/region.py b/openmc/region.py index 0b1f970840..854852ba41 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,5 +1,5 @@ from abc import ABCMeta, abstractmethod -from collections import Iterable, OrderedDict, defaultdict +from collections import Iterable, OrderedDict from copy import deepcopy from six import add_metaclass @@ -229,7 +229,7 @@ class Region(object): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -332,7 +332,7 @@ class Intersection(Region): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -344,7 +344,7 @@ class Intersection(Region): """ if memo is None: - memo = defaultdict(dict) + memo = {} clone = deepcopy(self) clone.nodes = [n.clone(memo) for n in self.nodes] @@ -433,7 +433,7 @@ class Union(Region): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -445,7 +445,7 @@ class Union(Region): """ if memo is None: - memo = defaultdict(dict) + memo = {} clone = copy.deepcopy(self) clone.nodes = [n.clone(memo) for n in self.nodes] @@ -554,7 +554,7 @@ class Complement(Region): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -566,7 +566,7 @@ class Complement(Region): """ if memo is None: - memo = defaultdict(dict) + memo = {} clone = copy.deepcopy(self) clone.node = self.node.clone(memo) diff --git a/openmc/surface.py b/openmc/surface.py index 1edae2cae7..5db15138d4 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,5 +1,5 @@ from abc import ABCMeta -from collections import Iterable, OrderedDict, defaultdict +from collections import Iterable, OrderedDict from copy import deepcopy from numbers import Real, Integral from xml.etree import ElementTree as ET @@ -83,6 +83,9 @@ class Surface(object): def __pos__(self): return Halfspace(self, '+') + def __hash__(self): + return hash(repr(self)) + def __repr__(self): string = 'Surface\n' string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) @@ -177,7 +180,7 @@ class Surface(object): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -189,17 +192,17 @@ class Surface(object): """ if memo is None: - memo = defaultdict(dict) + memo = {} # If no nemoize'd clone exists, instantiate one - if self.id not in memo['surfaces']: + if self not in memo: clone = deepcopy(self) clone.id = None # Memoize the clone - memo['surfaces'][self.id] = clone + memo[self] = clone - return memo['surfaces'][self.id] + return memo[self] def to_xml_element(self): """Return XML representation of the surface @@ -1938,7 +1941,7 @@ class Halfspace(Region): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -1950,7 +1953,7 @@ class Halfspace(Region): """ if memo is None: - memo = defaultdict(dict) + memo = dict clone = deepcopy(self) clone.surface = self.surface.clone(memo) diff --git a/openmc/universe.py b/openmc/universe.py index 1fefa2372c..c955934f2a 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -1,5 +1,5 @@ from __future__ import division -from collections import OrderedDict, Iterable, defaultdict +from collections import OrderedDict, Iterable from copy import copy, deepcopy from numbers import Integral, Real import random @@ -523,7 +523,7 @@ class Universe(object): Parameters ---------- - memo : defaultdict(dict) or None + memo : dict or None A nested dictionary of previously cloned objects. This parameter is used internally and should not be specified by the user. @@ -535,10 +535,10 @@ class Universe(object): """ if memo is None: - memo = defaultdict(dict) + memo = {} # If no nemoize'd clone exists, instantiate one - if self.id not in memo['universes']: + if self not in memo: clone = deepcopy(self) clone.id = None @@ -548,9 +548,9 @@ class Universe(object): clone.add_cell(cell.clone(memo)) # Memoize the clone - memo['universes'][self.id] = clone + memo[self] = clone - return memo['universes'][self.id] + return memo[self] def create_xml_subelement(self, xml_element): # Iterate over all Cells From d0f871e7db07ed83494bdc466aa1c999175cc1c1 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Tue, 11 Apr 2017 07:36:00 -0400 Subject: [PATCH 8/9] Simplified universe cloning in lattice clone method --- openmc/lattice.py | 16 +++++----------- openmc/material.py | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/openmc/lattice.py b/openmc/lattice.py index 0fbd74f28e..b78b8b9e46 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -443,23 +443,17 @@ class Lattice(object): if self.outer is not None: clone.outer = self.outer.clone(memo) - # Clone all unique universes in the lattice - univ_clones = self.get_unique_universes() - for univ_id in univ_clones: - univ_clones[univ_id] = univ_clones[univ_id].clone(memo) - # Assign universe clones to the lattice clone for i in self.indices: if isinstance(self, RectLattice): - univ_id = self.universes[i].id - clone.universes[i] = univ_clones[univ_id] + clone.universes[i] = self.universes[i].clone() else: if self.ndim == 2: - univ_id = self.universes[i[0]][i[1]].id - clone.universes[i[0]][i[1]] = univ_clones[univ_id] + clone.universes[i[0]][i[1]] = \ + self.universes[i[0]][i[1]].clone() else: - univ_id = self.universes[i[0]][i[1]][i[2]].id - clone.universes[i[0]][i[1]][i[2]] = univ_clones[univ_id] + clone.universes[i[0]][i[1]][i[2]] = \ + self.universes[i[0]][i[1]][i[2]].clone() # Memoize the clone memo[self] = clone diff --git a/openmc/material.py b/openmc/material.py index 762337659a..87cc6befaa 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -816,7 +816,7 @@ class Material(object): """ if memo is None: - memo = dict + memo = {} # If no nemoize'd clone exists, instantiate one if self not in memo: From 398635c84a5ed87c9b480989110df05ae12038ec Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Tue, 11 Apr 2017 07:36:49 -0400 Subject: [PATCH 9/9] Added memo param to universe cloning in lattice clone method --- openmc/lattice.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openmc/lattice.py b/openmc/lattice.py index b78b8b9e46..3bb6e825e1 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -446,14 +446,14 @@ class Lattice(object): # Assign universe clones to the lattice clone for i in self.indices: if isinstance(self, RectLattice): - clone.universes[i] = self.universes[i].clone() + clone.universes[i] = self.universes[i].clone(memo) else: if self.ndim == 2: clone.universes[i[0]][i[1]] = \ - self.universes[i[0]][i[1]].clone() + self.universes[i[0]][i[1]].clone(memo) else: clone.universes[i[0]][i[1]][i[2]] = \ - self.universes[i[0]][i[1]][i[2]].clone() + self.universes[i[0]][i[1]][i[2]].clone(memo) # Memoize the clone memo[self] = clone