Source code for armi.reactor.excoreStructure

# Copyright 2024 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module provides the simplest base-class tools for representing reactor objects that are
outside the reactor core.

The idea here is that all ex-core objects will be represented first as a spatial grid, and then
arbitrary ArmiObjects can be added to that grid.
"""

import copy

from armi.reactor.composites import Composite


[docs] class ExcoreStructure(Composite): """This is meant as the simplest baseclass needed to represent an ex-core reactor thing. An ex-core structure is expected to: - be a child of the Reactor, - have a grid associated with it, - contain a hierarchical set of ArmiObjects. """ def __init__(self, name, parent=None): Composite.__init__(self, name) self.parent = parent self.spatialGrid = None def __repr__(self): return "<{}: {} id:{}>".format(self.__class__.__name__, self.name, id(self)) @property def r(self): return self.getAncestor(fn=lambda x: x.__class__.__name__ == "Reactor")
[docs] def add(self, obj, loc=None): """Add an ArmiObject to a particular grid location, in this structure. Parameters ---------- assem : ArmiObject Any generic ArmiObject to add to the structure. loc : LocationBase, optional The location on this structure's grid. If omitted, will come from the object. """ # if a location is not provided, we demand the object has one if loc is None: loc = obj.spatialLocator if loc.grid is not self.spatialGrid: raise ValueError(f"An Composite cannot be added to {self} using a spatial locator from another grid.") # If an assembly is added and it has a negative ID, that is a placeholder, fix it. if "assemNum" in obj.p and obj.p.assemNum < 0: # update the assembly count in the Reactor newNum = self.r.incrementAssemNum() obj.renumber(newNum) obj.spatialLocator = loc super().add(obj)
[docs] class ExcoreCollection(dict): """ A collection that allows ex-core structures to be accessed like a dict, or class attributes. Examples -------- Build some sample data:: >>> sfp = ExcoreStructure("sfp") >>> ivs = ExcoreStructure("ivs") Build THIS collection:: >>> excore = ExcoreCollection() Now you can add data to this collection like it were a dictionary, and access freely:: >>> excore["sfp"] = sfp >>> excore["sfp"] <ExcoreStructure: sfp id:2311582653024> >>> excore.sfp <ExcoreStructure: sfp id:2311582653024> Or you can add data as if it were a class attribute, and still have dual access:: >>> excore.ivs = ivs >>> excore.ivs <ExcoreStructure: ivs id:2311590971136> >>> excore["ivs"] <ExcoreStructure: ivs id:2311590971136> """ def __getattr__(self, key): """Override the class attribute getter. First check if the class attribute exists. If not, check if the key is in the dictionary. """ try: # try to get a real class attribute return self.__dict__[key] except KeyError: try: # if it's not a class attribute, maybe it is a dictionary key? return self.__getitem__(key) except Exception: pass # it is neither, just raise the usual error raise def __setattr__(self, key, value): """Override the class attribute setting. If the value has an ExcoreStructure type, assume we want to store this in the dictionary. """ if type(value) is ExcoreStructure: self.__setitem__(key, value) else: self.__dict__[key] = value def __getstate__(self): """Needed to support pickling and unpickling the Reactor.""" return self.__dict__.copy() def __setstate__(self, state): """Needed to support pickling and unpickling the Reactor.""" self.__dict__.update(state) def __deepcopy__(self, memo): """Needed to support pickling and unpickling the Reactor.""" memo[id(self)] = newE = self.__class__.__new__(self.__class__) newE.__setstate__(copy.deepcopy(self.__getstate__(), memo)) return newE def __repr__(self): return "<{}: {} id:{}>".format(self.__class__.__name__, self.name, id(self))