2017-06-02 13:25:34 -05:00
|
|
|
from numbers import Integral
|
|
|
|
|
from warnings import warn
|
|
|
|
|
|
2016-08-17 05:07:29 -04:00
|
|
|
import numpy as np
|
|
|
|
|
|
2017-06-02 13:25:34 -05:00
|
|
|
import openmc.checkvalue as cv
|
|
|
|
|
|
2016-08-17 05:07:29 -04:00
|
|
|
|
2020-03-19 15:21:15 -05:00
|
|
|
class EqualityMixin:
|
2020-04-01 13:40:17 -05:00
|
|
|
"""A Class which provides a generic __eq__ method that can be inherited
|
|
|
|
|
by downstream classes.
|
2016-08-17 05:07:29 -04:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
|
if isinstance(other, type(self)):
|
|
|
|
|
for key, value in self.__dict__.items():
|
2022-07-22 07:46:34 -05:00
|
|
|
if isinstance(value, np.ndarray):
|
|
|
|
|
if not np.array_equal(value, other.__dict__.get(key)):
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return value == other.__dict__.get(key)
|
2016-08-17 05:07:29 -04:00
|
|
|
else:
|
2016-08-19 19:24:51 -04:00
|
|
|
return False
|
2016-08-17 05:07:29 -04:00
|
|
|
|
2016-08-19 19:24:51 -04:00
|
|
|
return True
|
2016-08-17 05:07:29 -04:00
|
|
|
|
2017-06-02 13:25:34 -05:00
|
|
|
|
2017-06-15 14:38:25 -05:00
|
|
|
class IDWarning(UserWarning):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2020-03-19 15:21:15 -05:00
|
|
|
class IDManagerMixin:
|
2017-06-02 13:25:34 -05:00
|
|
|
"""A Class which automatically manages unique IDs.
|
|
|
|
|
|
|
|
|
|
This mixin gives any subclass the ability to assign unique IDs through an
|
|
|
|
|
'id' property and keeps track of which ones have already been
|
|
|
|
|
assigned. Crucially, each subclass must define class variables 'next_id' and
|
|
|
|
|
'used_ids' as they are used in the 'id' property that is supplied here.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
2026-02-06 20:44:16 +02:00
|
|
|
min_id = 0
|
|
|
|
|
|
2017-06-02 13:25:34 -05:00
|
|
|
@property
|
|
|
|
|
def id(self):
|
|
|
|
|
return self._id
|
|
|
|
|
|
|
|
|
|
@id.setter
|
|
|
|
|
def id(self, uid):
|
2018-01-29 10:52:36 -06:00
|
|
|
# The first time this is called for a class, we search through the MRO
|
|
|
|
|
# to determine which class actually holds next_id and used_ids. Since
|
|
|
|
|
# next_id is an integer (immutable), we can't modify it directly through
|
|
|
|
|
# the instance without just creating a new attribute
|
|
|
|
|
try:
|
|
|
|
|
cls = self._id_class
|
|
|
|
|
except AttributeError:
|
|
|
|
|
for cls in self.__class__.__mro__:
|
|
|
|
|
if 'next_id' in cls.__dict__:
|
|
|
|
|
break
|
|
|
|
|
|
2017-06-02 13:25:34 -05:00
|
|
|
if uid is None:
|
|
|
|
|
while cls.next_id in cls.used_ids:
|
|
|
|
|
cls.next_id += 1
|
|
|
|
|
self._id = cls.next_id
|
|
|
|
|
cls.used_ids.add(cls.next_id)
|
|
|
|
|
else:
|
2018-01-29 10:52:36 -06:00
|
|
|
name = cls.__name__
|
2021-07-29 18:25:37 +01:00
|
|
|
cv.check_type(f'{name} ID', uid, Integral)
|
2026-02-06 20:44:16 +02:00
|
|
|
cv.check_greater_than(f'{name} ID', uid, cls.min_id, equality=True)
|
2017-06-02 13:25:34 -05:00
|
|
|
if uid in cls.used_ids:
|
2021-07-29 18:25:37 +01:00
|
|
|
msg = f'Another {name} instance already exists with id={uid}.'
|
2017-06-15 14:38:25 -05:00
|
|
|
warn(msg, IDWarning)
|
2017-06-02 13:25:34 -05:00
|
|
|
else:
|
|
|
|
|
cls.used_ids.add(uid)
|
|
|
|
|
self._id = uid
|
2017-06-07 20:48:36 -05:00
|
|
|
|
2024-09-27 02:31:59 +02:00
|
|
|
@classmethod
|
|
|
|
|
def reset_ids(cls):
|
|
|
|
|
"""Reset counters"""
|
|
|
|
|
cls.used_ids.clear()
|
|
|
|
|
cls.next_id = 1
|
|
|
|
|
|
2017-06-07 20:48:36 -05:00
|
|
|
|
|
|
|
|
def reset_auto_ids():
|
|
|
|
|
"""Reset counters for all auto-generated IDs"""
|
|
|
|
|
for cls in IDManagerMixin.__subclasses__():
|
2024-09-27 02:31:59 +02:00
|
|
|
cls.reset_ids()
|
2017-06-07 20:48:36 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def reserve_ids(ids, cls=None):
|
|
|
|
|
"""Reserve a set of IDs that won't be used for auto-generated IDs.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
ids : iterable of int
|
|
|
|
|
IDs to reserve
|
2017-06-08 19:44:31 -05:00
|
|
|
cls : type or None
|
2017-06-15 14:38:25 -05:00
|
|
|
Class for which IDs should be reserved (e.g., :class:`openmc.Cell`). If
|
|
|
|
|
None, all classes that have auto-generated IDs will be used.
|
2017-06-07 20:48:36 -05:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
if cls is None:
|
|
|
|
|
for cls in IDManagerMixin.__subclasses__():
|
|
|
|
|
cls.used_ids |= set(ids)
|
|
|
|
|
else:
|
|
|
|
|
cls.used_ids |= set(ids)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_auto_id(next_id):
|
|
|
|
|
"""Set the next ID for auto-generated IDs.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
next_id : int
|
|
|
|
|
The next ID to assign to objects with auto-generated IDs.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
for cls in IDManagerMixin.__subclasses__():
|
|
|
|
|
cls.next_id = next_id
|