Source code for ogstools.physics.nuclearwasteheat.nuclearwaste
# Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
# Distributed under a Modified BSD License.
# See accompanying file LICENSE.txt or
# http://www.opengeosys.org/project/license
#
from dataclasses import dataclass
import numpy as np
from pint.facets.plain import PlainQuantity
from ._unitsetup import Q_
[docs]
@dataclass
class NuclearWaste:
"Models the heat generated by one type of nuclear fuel waste."
name: str
"Name of this type of waste."
nuclide_powers: PlainQuantity | np.ndarray
"Powers for the different leading nuclides."
decay_consts: PlainQuantity | np.ndarray
"Decay constants for the different leading nuclides."
num_bundles: int
"Number of nuclear waste bundles."
time_interim: PlainQuantity | float
"Interim storage time before heat evaluation."
time_deposit: PlainQuantity | float = 0.0
"Number of active bundles linearly increases until this time is reached."
factor: PlainQuantity | float = 1.0
"Scale the calculated heat by this factor."
[docs]
def heat(
self,
t: PlainQuantity | float | np.ndarray,
baseline: bool = False,
ncl_id: int | None = None,
time_unit: str = "s",
power_unit: str = "W",
) -> float | np.ndarray:
"""Calculate the heat of a nuclear waste proxy model.
:param t: Timevalue(s) at which the heat is calculated.
:param ncl_id: If given, only output the heat by nuclide with this
id, else sum the heat over all nuclides.
:param baseline: If True, evaluate one bundle with no interim or
deposition time delay.
:returns: Heat generated by the nuclear waste at time t.
"""
_t = Q_(t).magnitude
_nuclide_powers = Q_(self.nuclide_powers, power_unit).magnitude
_decay_consts = Q_(self.decay_consts, f"1/{time_unit}").magnitude
_num_bundles = self.num_bundles
_time_interim = Q_(self.time_interim, time_unit).magnitude
_time_deposit = Q_(self.time_deposit, time_unit).magnitude
if baseline:
_num_bundles, _time_interim, _time_deposit = 1, 0.0, 0.0
t_per_bundle = np.linspace(_t - _time_deposit, _t, _num_bundles)
t_per_bundle = np.ma.masked_less(t_per_bundle, 0) + _time_interim
# decay values for each nuclide via matrix multiplicaation
# results in shape (num_bundles, len(t), len(decay_consts))
decay = np.exp(-t_per_bundle[..., None] @ _decay_consts[None, ...])
# sum over all bundles
res = np.sum(self.factor * _nuclide_powers * decay, axis=0)
# optionally sum over nuclides
return np.sum(res, axis=-1) if ncl_id is None else res[..., ncl_id]
[docs]
@dataclass
class Repository:
"Models the heat generated by total repository inventory."
waste: list[NuclearWaste]
"Waste inventory of the repository."
[docs]
def time_deposit(self, time_unit: str = "s") -> float | list[float]:
"Deposition time for each nuclear waste type."
if len(self.waste) == 1:
return Q_(self.waste[0].time_deposit).to(time_unit).magnitude
return [
Q_(nw.time_deposit).to(time_unit).magnitude for nw in self.waste
]
[docs]
def heat(
self,
t: PlainQuantity | float | np.ndarray,
baseline: bool = False,
ncl_id: int | None = None,
time_unit: str = "s",
power_unit: str = "W",
) -> float | np.ndarray:
"""Calculate the heat produced by the repository at time t.
:param t: Timevalue(s) at which the heat is calculated.
:param ncl_id: If given, only output the heat by nuclide with this
id, else sum the heat over all nuclides.
:param baseline: If True, evaluate one bundle for each waste with no
interim or deposition time delay.
:returns: Heat generated by the repository at time t.
"""
result = [
nw.heat(t, baseline, ncl_id, time_unit, power_unit)
for nw in self.waste
]
return np.sum(np.array(result), axis=0)