Merge pull request #854 from wbinventor/clone

Cloning of geometry and materials
This commit is contained in:
Paul Romano 2017-04-11 09:00:27 -05:00 committed by GitHub
commit 7f41ab2bab
7 changed files with 315 additions and 2 deletions

View file

@ -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
@ -504,6 +505,44 @@ class Cell(object):
return universes
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
----------
memo : 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 memo is None:
memo = {}
# If no nemoize'd clone exists, instantiate one
if self not in memo:
clone = deepcopy(self)
clone.id = None
if self.region is not None:
clone.region = self.region.clone(memo)
if self.fill is not None:
if self.fill_type == 'distribmat':
clone.fill = [fill.clone(memo) if fill is not None else None
for fill in self.fill]
else:
clone.fill = self.fill.clone(memo)
# Memoize the clone
memo[self] = clone
return memo[self]
def create_xml_subelement(self, xml_element):
element = ET.Element("cell")
element.set("id", str(self.id))

View file

@ -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 = self.root_universe.clone()
return clone

View file

@ -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
@ -414,6 +415,51 @@ class Lattice(object):
return []
return [(self, idx)] + u.find(p)
def clone(self, memo=None):
"""Create a copy of this lattice with a new unique ID, and clones
all universes within this lattice.
Parameters
----------
memo : 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 memo is None:
memo = {}
# If no nemoize'd clone exists, instantiate one
if self not in memo:
clone = deepcopy(self)
clone.id = None
if self.outer is not None:
clone.outer = self.outer.clone(memo)
# Assign universe clones to the lattice clone
for i in self.indices:
if isinstance(self, RectLattice):
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(memo)
else:
clone.universes[i[0]][i[1]][i[2]] = \
self.universes[i[0]][i[1]][i[2]].clone(memo)
# Memoize the clone
memo[self] = clone
return memo[self]
class RectLattice(Lattice):
"""A lattice consisting of rectangular prisms.

View file

@ -799,6 +799,35 @@ class Material(object):
return nuclides
def clone(self, memo=None):
"""Create a copy of this material with a new unique ID.
Parameters
----------
memo : 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 memo is None:
memo = {}
# If no nemoize'd clone exists, instantiate one
if self not in memo:
clone = deepcopy(self)
clone.id = None
# Memoize the clone
memo[self] = clone
return memo[self]
def _get_nuclide_xml(self, nuclide, distrib=False):
xml_element = ET.Element("nuclide")
xml_element.set("name", nuclide[0].name)

View file

@ -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
@ -221,6 +222,31 @@ class Region(object):
# at the end
return output[0]
@abstractmethod
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
----------
memo : 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.')
class Intersection(Region):
r"""Intersection of two or more regions.
@ -300,6 +326,30 @@ class Intersection(Region):
check_type('nodes', nodes, Iterable, Region)
self._nodes = nodes
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
----------
memo : 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 memo is None:
memo = {}
clone = deepcopy(self)
clone.nodes = [n.clone(memo) for n in self.nodes]
return clone
class Union(Region):
r"""Union of two or more regions.
@ -377,6 +427,30 @@ class Union(Region):
check_type('nodes', nodes, Iterable, Region)
self._nodes = nodes
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
----------
memo : 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 memo is None:
memo = {}
clone = copy.deepcopy(self)
clone.nodes = [n.clone(memo) for n in self.nodes]
return clone
class Complement(Region):
"""Complement of a region.
@ -473,3 +547,27 @@ class Complement(Region):
for region in self.node:
surfaces = region.get_surfaces(surfaces)
return surfaces
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
----------
memo : 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 memo is None:
memo = {}
clone = copy.deepcopy(self)
clone.node = self.node.clone(memo)
return clone

View file

@ -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
@ -82,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)
@ -171,6 +175,35 @@ class Surface(object):
return (np.array([-np.inf, -np.inf, -np.inf]),
np.array([np.inf, np.inf, np.inf]))
def clone(self, memo=None):
"""Create a copy of this surface with a new unique ID.
Parameters
----------
memo : 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 memo is None:
memo = {}
# If no nemoize'd clone exists, instantiate one
if self not in memo:
clone = deepcopy(self)
clone.id = None
# Memoize the clone
memo[self] = clone
return memo[self]
def to_xml_element(self):
"""Return XML representation of the surface
@ -1821,7 +1854,7 @@ class Halfspace(Region):
def __init__(self, surface, side):
self.surface = surface
self.side = side
def __and__(self, other):
if isinstance(other, Intersection):
return Intersection(self, *other.nodes)
@ -1902,6 +1935,30 @@ class Halfspace(Region):
surfaces[self.surface.id] = self.surface
return surfaces
def clone(self, memo=None):
"""Create a copy of this halfspace, with a cloned surface with a
unique ID.
Parameters
----------
memo : 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 memo is None:
memo = dict
clone = deepcopy(self)
clone.surface = self.surface.clone(memo)
return clone
def get_rectangular_prism(width, height, axis='z', origin=(0., 0.),
boundary_type='transmission'):

View file

@ -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
@ -517,6 +517,41 @@ class Universe(object):
return universes
def clone(self, memo=None):
"""Create a copy of this universe with a new unique ID, and clones
all cells within this universe.
Parameters
----------
memo : 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 memo is None:
memo = {}
# If no nemoize'd clone exists, instantiate one
if self not in memo:
clone = 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(memo))
# Memoize the clone
memo[self] = clone
return memo[self]
def create_xml_subelement(self, xml_element):
# Iterate over all Cells
for cell_id, cell in self._cells.items():