From fe2e7f73c4897eb5b544a09e3166add5627768f7 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 2 May 2025 21:59:23 +0100 Subject: [PATCH 01/98] First commit - made a mockup of NeutronFluxProfile calculator. --- process/neutronics.py | 376 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 process/neutronics.py diff --git a/process/neutronics.py b/process/neutronics.py new file mode 100644 index 0000000000..36c191e695 --- /dev/null +++ b/process/neutronics.py @@ -0,0 +1,376 @@ +""" +Most of derivation is basd on the book Reactor Analysis, Duderstadt and Hamilton, 1976, +ISBN:9780471223634. +""" + +import functools + +import numpy as np +from numpy import testing as npt +from scipy.constants import Avogadro +from to_be_built_later import extract_atomic_mass, get_avg_atomic_mass + +BARNS_CM2 = 1e-24 +N_A = Avogadro + +material_density_data_bank = ... +material_composition_data_bank = ... +xs_data_bank = ... + + +def groupwise(func): + """Rename the current func as groupwise_func, and over-write the current method + as one that sums up all group-wise func. + """ + method_name = func.__name__ + groupwise_name = f"groupwise_{method_name}" + + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + groupwise_func = getattr(self, groupwise_name) + return np.sum( + [groupwise_func(n, *args, **kwargs) for n in range(1, self.n_groups + 1)], + axis=0, + ) + + def wrapper_setattr(cls): + """Save the decorated (groupwise) function under a different name after it has + been created, then overwrite the current method with the np.sum implementation. + """ + setattr(cls, groupwise_name, func) + setattr(cls, method_name, wrapper) + return cls + + # Instead of returning a function, we return a descriptor that registers itself later + return RegisterLater(wrapper_setattr) + + +class RegisterLater: + """Descriptor class""" + + def __init__(self, installer): + """Modifies the class AFTER it has been created.""" + self.installer = installer + + def __set_name__(self, owner, name): + """Re-write method name""" + self.installer(owner) + + +def get_diffusion_coefficient( + total_xs: float, scattering_xs: float, avg_atomic_mass: float +) -> float: + r""" + Calculate the diffusion coefficient for a given scattering and total macro-scopic + cross-section in a given medium. + + Parameters + ---------- + total_xs: + macroscopic total cross-section `\sigma_{total}`, i.e. any reaction between + nuclei and neutrons, that either changes the neutron's path or remove it from + that energy group. + Unit: cm^-1 + scattering_xs: + macroscopic total cross-section `\sigma_{scatter}`, i.e. number of reactions per + unit distance travelled by the neutron that leads to it being scattered (without + getting absorbed). + Unit: cm^-1 + avg_atomic_mass: + Average atomic mass in [amu]. This can be approximated by the atomic number 'A' + of the medium that the neutron passes through. The effect of the more-anisotropic + scattering due to smaller atomic number can be accounted for by increasing the + diffusion coefficient (which decreases the transport macroscopic cross-section, + :math:`\Sigma_{tr}=\frac{1}{3D}`). + + Returns + ------- + : + The diffusion coefficient as given by Reactor Analysis, Duderstadt and Hamilton. + unit: [cm] + """ + + transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs + return 1 / 3 / transport_xs + + +def extrapolation_length(diffusion_coefficient: float) -> float: + """Get the extrapolation length of the final medium :math:`\\delta`. + + Notes + ----- + Diffusion theory breaks down at the vacuum boundary, where once the neutron exits, + it will travel indefinitely into free space, never to return. To counteract this + problem, we can approximate the neutron profile quite closely by assuming that the + flux goes to 0 at an extended boundary, rather than at the vacuum boundary. + THis yields a very close approximation. All of this equation is provided by + Duderstadt and Hamilton. + """ + return 0.7104 * 3 * diffusion_coefficient + + +def calculate_average_macro_xs( + composition: dict[str, float], + micro_xs: dict[str, float | npt.NDArray[np.float64]], + density: float, +) -> float | npt.NDArray[np.float64]: + r""" + Calculate the macroscopic cross-section for a specific energy group and a specific + reaction (a scalar value), when given the microscopic cross-section values of its + components and its density. + + Parameters + ---------- + composition: + Fraction of each species of atoms of the medium. Does not have to be normalised. + Given in the format {'species': float(fraction)}. + micro_xs: + A dictionary of each species, and their microscopic cross-sections, given in + [barns]. + Given in the format {'species': float(microscopic cross-section)}. + density: + Density of the medium, given in [g/cm^3] + + Notes + ----- + .. math:: + \Sigma &= N_d\sigma + &= \frac{N_A}{A} \rho \sigma + """ + + total_fraction = sum(composition.values()) + weighted_micro_xs, weighted_atomic_mass = [], [] + if composition.keys() != micro_xs.keys(): + raise KeyError( + "The two dictionaries 'composition' and 'micro_xs' must have matching keys." + ) + for species, fraction in composition.items(): + normalized_fraction = fraction / total_fraction + weighted_atomic_mass.append(normalized_fraction * extract_atomic_mass(species)) + weighted_micro_xs.append(normalized_fraction * micro_xs[species]) + avg_sigma = np.sum(weighted_micro_xs, axis=0) + avg_mass_amu = sum(weighted_atomic_mass) + return (BARNS_CM2 * N_A) / avg_mass_amu * avg_sigma * density # N_A/A * rho * sigma + + +def discretize_xs( + continuous_xs, group_structure: list[float] +) -> npt.NDArray[np.float64]: + """ + Discretise a continuous cross-section function into a group structure of n discrete + flaots. + + Parameters + ---------- + continuous_xs: + continuous cross-section function to be discretized. + group_structure: + group structure of neutron energies, the n+1 energy bin boundaries for the n + neutron groups, in descending energies. + + Returns + ------- + : + microscopic cross-section values discretized according to the group structure. + """ + return + + +def scattering_weight_matrix( + group_structure: list[float], atomic_mass: float +) -> npt.NDArray: + """ + Parameters + ---------- + group_structure: + the n+1 energy bin boundaries for the n neutron groups, in descending energies. + atomic_mass: + atomic mass of the medium + + Returns + ------- + : + A lower triangular matrix, where the i-th row contains the normalized weights for + scattering down from the i-th bin to the j-th bin. The main-diagonal contains + the self-scattering cross-section. + e.g. [2,1] would be the fraction of elastic scattering reactions that causes + neutrons from group 3 to scatter into group 2. + The upper triangle must be all zeros. + np.sum(axis=1) == np.ones(len(group_structure)-1). + """ + return + + +def get_material_nuclear_data( + material: str, group_structure: list[float] +) -> tuple[npt.NDArray[np.float64], npt.NDArray]: + """ + The constants that is directly used. + + Parameters + ---------- + materials: + Which material that we want to get the data out of. + group_structure: + the n+1 energy bin boundaries for the n neutron groups, in descending energies. + + Returns + ------- + discrete_macro_total_xs: + All group-wise total cross-sections, given in ascending order. + macroscopic scattering cross-section matrix: + A lower-triangular matrix of total scattering cross-sections, + e.g. [2,1] would be the scattering cross-section from neutron group 3 to group 2. + The upper triangle MUST be zeros. + avg_atomic_mass: + average atomic mass, used for further calcuations + + Notes + ----- + When calculating the group-wise diffusion coefficients, the i-th group's scattering + cross-section :math:`\\Sigma_{s}` is the i-th element on the main diagonal of the + macroscopic scattering cross-section matrix. + """ + density = material_density_data_bank[material] + composition = material_composition_data_bank[material] + avg_atomic_mass = get_avg_atomic_mass(composition) + + micro_total_xs, micro_scattering_xs = {} # [str, 1D numpy array] + for species in composition: + total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[species] + micro_total_xs[species] = discretize_xs(total_xs_continuous, group_structure) + micro_scattering_xs[species] = discretize_xs( + elastic_scattering_xs_continuous, group_structure + ) + + discrete_macro_total_xs = calculate_average_macro_xs( + composition, micro_total_xs, density + ) + discrete_macro_scattering_xs = calculate_average_macro_xs( + composition, micro_scattering_xs, density + ) + discrete_macro_scattering_xs_matrix = ( + scattering_weight_matrix(group_structure, avg_atomic_mass).T + * discrete_macro_scattering_xs + ).T + + return discrete_macro_total_xs, discrete_macro_scattering_xs_matrix, avg_atomic_mass + + +class NeutronFluxProfile: + """Neutron flux in the first wall or the blanket.""" + + def __init__(self, fw_mat, x_fw, bz_mat, x_bz, n_groups: int = 1): + """ + Parameters + ---------- + fw_mat: + first wall material + x_fw: + thickness of the first wall [m]. It will be converted and stored in [cm]. + bz_mat: + blanket material + x_bz: + thickness of the blanket [m]. It will be converted and stored in [cm]. + n_groups: + number of groups used to approximate this. + """ + if not (0 < x_fw < x_bz): + raise ValueError( + f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." + ) + self.fw_mat = fw_mat + self.x_fw = x_fw * 100 + self.bz_mat = bz_mat + self.x_bz = x_bz * 100 + self.n_groups = n_groups + + self.fw_sigma_t, self.fw_sigma_s, self.fw_A = get_material_nuclear_data( + self.fw_mat, n_groups + ) + self.bz_sigma_t, self.bz_sigma_s, self.bz_A = get_material_nuclear_data( + self.bz_mat, n_groups + ) + # Dictionaries indexed by integers, so that we don't have to worry about ordering + self.integration_constants = {} + self.extended_boundary = {} + + def solve_one_group(self): + i = 0 + if i in self.integration_constants: + return # skip if it has already been solved. + c1 = ... + c2 = ... + c3 = ... + c4 = ... + d_bz = get_diffusion_coefficient( + self.bz_sigma_t[i], + self.bz_sigma_s[i, i], + self.bz_A, + ) + self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) + self.integration_constants[i] = [c1, c2, c3, c4] + + def solve_group_n(self, n: int): + if n not in range(1, self.n_groups): + raise ValueError( + f"n must be a positive integer between 1 and {self.n_groups}!" + ) + for k in range(1, n): + if k not in self.integration_constants: + self.solve_group_n(k) + if n == 1: + self.solve_one_group() + i = n - 1 + if i in self.integration_constants: + return # skip if it has already been solved. + c1 = ... + c2 = ... + c3 = ... + c4 = ... + d_bz = get_diffusion_coefficient( + self.bz_sigma_t[i], + self.bz_sigma_s[i, i], + self.bz_A, + ) + self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) + self.integration_constants[i] = [c1, c2, c3, c4] + + @groupwise + def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: + """Neutron flux at the first wall.""" + + return + + @groupwise + def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: + """Neutron flux at the blanket.""" + + return + + @groupwise + def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: + """ + Neutron flux + Parameters + ---------- + n: + Neutron group number + x: + The depth where we want the neutron flux (m). + """ + if np.isscalar(x): + return self.groupwise_neutron_flux_at(n, [x])[0] + x = np.asarray(x) + in_fw = x <= self.x_fw + in_bz = np.logical_and(self.x_fw < x, x <= self.x_bz) + if (~np.logical_or(in_fw, in_bz)).any(): + raise ValueError( + f"for neutron group {n}, neutron flux can only be calculated up to " + f"{self.extended_boundary[n]}, which {x} violates!" + ) + + out_flux = np.zeros_like(x) + out_flux[in_fw] = self.groupwise_neutron_flux_fw(x[in_fw]) + out_flux[in_bz] = self.groupwise_neutron_flux_bz(x[in_bz]) + return out_flux From 99d62d2d79ad09afe16c4df5684884b1be0b8b06 Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 3 May 2025 02:35:02 +0100 Subject: [PATCH 02/98] Added the effect of neutron multiplication, which is done by increasing the strength of the macroscopic (self and other) scattering matrix. --- process/neutronics.py | 174 ++++++++++++++++++++++++++++++++---------- ruff.toml | 2 + 2 files changed, 137 insertions(+), 39 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 36c191e695..8c253d8a44 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -6,16 +6,18 @@ import functools import numpy as np +from continuous_functions import ZeroContinuousFunc from numpy import testing as npt from scipy.constants import Avogadro from to_be_built_later import extract_atomic_mass, get_avg_atomic_mass BARNS_CM2 = 1e-24 N_A = Avogadro - +N2N_Q_VALUE = ... material_density_data_bank = ... material_composition_data_bank = ... xs_data_bank = ... +breeding_xs_data_bank = ... def groupwise(func): @@ -29,7 +31,10 @@ def groupwise(func): def wrapper(self, *args, **kwargs): groupwise_func = getattr(self, groupwise_name) return np.sum( - [groupwise_func(n, *args, **kwargs) for n in range(1, self.n_groups + 1)], + [ + groupwise_func(n, *args, **kwargs) + for n in range(1, self.n_groups + 1) + ], axis=0, ) @@ -57,9 +62,9 @@ def __set_name__(self, owner, name): self.installer(owner) -def get_diffusion_coefficient( +def get_diffusion_coefficient_and_length( total_xs: float, scattering_xs: float, avg_atomic_mass: float -) -> float: +) -> tuple[float, np.complex128]: r""" Calculate the diffusion coefficient for a given scattering and total macro-scopic cross-section in a given medium. @@ -85,13 +90,21 @@ def get_diffusion_coefficient( Returns ------- - : + diffusion_coef: The diffusion coefficient as given by Reactor Analysis, Duderstadt and Hamilton. unit: [cm] + diffusion_len: + The characteristic diffusion length as given by Reactor Analysis, Duderstadt and + Hamilton. + unit: [cm] """ transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs - return 1 / 3 / transport_xs + diffusion_coef = 1 / 3 / transport_xs + diffusion_len = np.sqrt( + complex(diffusion_coef / (total_xs - scattering_xs), 0.0) + ) + return diffusion_coef, diffusion_len def extrapolation_length(diffusion_coefficient: float) -> float: @@ -146,11 +159,15 @@ def calculate_average_macro_xs( ) for species, fraction in composition.items(): normalized_fraction = fraction / total_fraction - weighted_atomic_mass.append(normalized_fraction * extract_atomic_mass(species)) + weighted_atomic_mass.append( + normalized_fraction * extract_atomic_mass(species) + ) weighted_micro_xs.append(normalized_fraction * micro_xs[species]) avg_sigma = np.sum(weighted_micro_xs, axis=0) avg_mass_amu = sum(weighted_atomic_mass) - return (BARNS_CM2 * N_A) / avg_mass_amu * avg_sigma * density # N_A/A * rho * sigma + return ( + (BARNS_CM2 * N_A) / avg_mass_amu * avg_sigma * density + ) # N_A/A * rho * sigma def discretize_xs( @@ -201,6 +218,30 @@ def scattering_weight_matrix( return +def expand_macro_neutron_multiplication_xs_into_matrix( + discrete_n2n_xs: npt.NDArray[np.float64], + group_structure: list[float], + q_value: float, +) -> npt.NDArray: + """Instead of only having the macroscopic cross-section values for the (n,2n) + reaction for each group, calculate the macroscopic cross-section of neutron in the + [i]-th bin producing a neutron in the [j]-bin, recorded as the [i,j] element in the + matrix. + + Returns + ------- + : + A macroscopic neutron multiplication cross-section matrix, such that each row + should sum to = 2 * discrete_n2n_xs (since two neutrons should be produced per + neutron consumed in the (n,2n) reaction). + + Notes + ----- + This is a three body problem. TODO: further investigation is needed to figure out + how to distribute the two outputted neutron's energies! + """ + + def get_material_nuclear_data( material: str, group_structure: list[float] ) -> tuple[npt.NDArray[np.float64], npt.NDArray]: @@ -235,13 +276,26 @@ def get_material_nuclear_data( composition = material_composition_data_bank[material] avg_atomic_mass = get_avg_atomic_mass(composition) - micro_total_xs, micro_scattering_xs = {} # [str, 1D numpy array] + # dicts of {"isotope": npt.NDArray[np.float64] 1D arrays} + micro_total_xs = {} + micro_scattering_xs = {} + micro_n2n_xs = {} for species in composition: - total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[species] - micro_total_xs[species] = discretize_xs(total_xs_continuous, group_structure) + total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[ + species + ] + n2n_xs_continuous = breeding_xs_data_bank.get( + species, ZeroContinuousFunc + ) + micro_total_xs[species] = discretize_xs( + total_xs_continuous, group_structure + ) micro_scattering_xs[species] = discretize_xs( elastic_scattering_xs_continuous, group_structure ) + micro_n2n_xs[species] = discretize_xs( + n2n_xs_continuous, group_structure + ) discrete_macro_total_xs = calculate_average_macro_xs( composition, micro_total_xs, density @@ -253,17 +307,41 @@ def get_material_nuclear_data( scattering_weight_matrix(group_structure, avg_atomic_mass).T * discrete_macro_scattering_xs ).T + discrete_n2n_xs = calculate_average_macro_xs( + composition, micro_n2n_xs, density + ) + discrete_macro_mult_xs_matrix = ( + expand_macro_neutron_multiplication_xs_into_matrix( + discrete_n2n_xs, group_structure, N2N_Q_VALUE + ) + ) + source_matrix = ( + discrete_macro_scattering_xs_matrix + discrete_macro_mult_xs_matrix + ) - return discrete_macro_total_xs, discrete_macro_scattering_xs_matrix, avg_atomic_mass + return discrete_macro_total_xs, source_matrix, avg_atomic_mass class NeutronFluxProfile: """Neutron flux in the first wall or the blanket.""" - def __init__(self, fw_mat, x_fw, bz_mat, x_bz, n_groups: int = 1): - """ + def __init__( + self, + flux: float, + fw_mat: str, + x_fw: float, + bz_mat: str, + x_bz: float, + n_groups: int = 1, + ): + """Initialize a particular FW-BZ geometry and neutron flux. + Parameters ---------- + flux: + Nuetron flux directly emitted by the plasma, incident on the first wall. + unit: arbitrary, but whichever unit used here will be the same unit used at + the output neutron_flux. fw_mat: first wall material x_fw: @@ -275,6 +353,7 @@ def __init__(self, fw_mat, x_fw, bz_mat, x_bz, n_groups: int = 1): n_groups: number of groups used to approximate this. """ + self.flux = flux if not (0 < x_fw < x_bz): raise ValueError( f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." @@ -285,25 +364,31 @@ def __init__(self, fw_mat, x_fw, bz_mat, x_bz, n_groups: int = 1): self.x_bz = x_bz * 100 self.n_groups = n_groups - self.fw_sigma_t, self.fw_sigma_s, self.fw_A = get_material_nuclear_data( - self.fw_mat, n_groups + self.fw_sigma_t, self.fw_sigma_s, self.fw_A = ( + get_material_nuclear_data(self.fw_mat, n_groups) ) - self.bz_sigma_t, self.bz_sigma_s, self.bz_A = get_material_nuclear_data( - self.bz_mat, n_groups + self.bz_sigma_t, self.bz_sigma_s, self.bz_A = ( + get_material_nuclear_data(self.bz_mat, n_groups) ) # Dictionaries indexed by integers, so that we don't have to worry about ordering self.integration_constants = {} self.extended_boundary = {} + self.l_fw, self.l_bz = {}, {} - def solve_one_group(self): + def solve_one_group(self) -> None: i = 0 if i in self.integration_constants: return # skip if it has already been solved. - c1 = ... - c2 = ... - c3 = ... - c4 = ... - d_bz = get_diffusion_coefficient( + c1 = self.flux * ... + c2 = self.flux * ... + c3 = self.flux * ... + c4 = self.flux * ... + self.l_fw[i], d_fw = get_diffusion_coefficient_and_length( + self.fw_sigma_t[i], + self.fw_sigma_s[i, i], + self.fw_A, + ) + self.l_bz[i], d_bz = get_diffusion_coefficient_and_length( self.bz_sigma_t[i], self.bz_sigma_s[i, i], self.bz_A, @@ -311,24 +396,29 @@ def solve_one_group(self): self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) self.integration_constants[i] = [c1, c2, c3, c4] - def solve_group_n(self, n: int): + def solve_group_n(self, n: int) -> None: if n not in range(1, self.n_groups): raise ValueError( f"n must be a positive integer between 1 and {self.n_groups}!" ) - for k in range(1, n): - if k not in self.integration_constants: - self.solve_group_n(k) if n == 1: self.solve_one_group() + for k in range(n - 1): + if k not in self.integration_constants: + self.solve_group_n(k) i = n - 1 if i in self.integration_constants: return # skip if it has already been solved. - c1 = ... - c2 = ... - c3 = ... - c4 = ... - d_bz = get_diffusion_coefficient( + c1 = self.flux * ... + c2 = self.flux * ... + c3 = self.flux * ... + c4 = self.flux * ... + self.l_fw[i], d_fw = get_diffusion_coefficient_and_length( + self.fw_sigma_t[i], + self.fw_sigma_s[i, i], + self.fw_A, + ) + self.l_bz[i], d_bz = get_diffusion_coefficient_and_length( self.bz_sigma_t[i], self.bz_sigma_s[i, i], self.bz_A, @@ -339,14 +429,20 @@ def solve_group_n(self, n: int): @groupwise def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: """Neutron flux at the first wall.""" - - return + i = n - 1 + c1, c2 = self.integration_constants[i][:2] + return np.real( + c1 * np.sinh(x / self.l_fw[i]) + c2 * np.cosh(x / self.l_fw[i]) + ) @groupwise def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: """Neutron flux at the blanket.""" - - return + i = n - 1 + c3, c4 = self.integration_constants[i][2:] + return np.real( + c3 * np.sinh(x / self.l_bz[i]) + c4 * np.cosh(x / self.l_bz[i]) + ) @groupwise def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: @@ -362,8 +458,8 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] x = np.asarray(x) - in_fw = x <= self.x_fw - in_bz = np.logical_and(self.x_fw < x, x <= self.x_bz) + in_fw = abs(x) <= self.x_fw + in_bz = np.logical_and(self.x_fw < abs(x), abs(x) <= self.x_bz) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated up to " diff --git a/ruff.toml b/ruff.toml index 9db7a11a87..2a43213ee2 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,7 @@ extend-exclude = ["env", ".env"] target-version = "py310" +output-format= "concise" +line-length = 79 [lint] extend-select = [ From d4204cf093f3c7ca6c0eb61f5b11b49c15884198 Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 3 May 2025 03:52:16 +0100 Subject: [PATCH 03/98] relocated some functions --- process/neutronics.py | 16 ++++++++++------ process/neutronics_data.py | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 process/neutronics_data.py diff --git a/process/neutronics.py b/process/neutronics.py index 8c253d8a44..1c03512980 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -6,18 +6,20 @@ import functools import numpy as np -from continuous_functions import ZeroContinuousFunc from numpy import testing as npt from scipy.constants import Avogadro -from to_be_built_later import extract_atomic_mass, get_avg_atomic_mass +from neutronics_data import (ZeroContinuousFunc, + extract_atomic_mass, + get_avg_atomic_mass, + material_density_data_bank, + material_composition_data_bank, + xs_data_bank, + breeding_xs_data_bank +) BARNS_CM2 = 1e-24 N_A = Avogadro N2N_Q_VALUE = ... -material_density_data_bank = ... -material_composition_data_bank = ... -xs_data_bank = ... -breeding_xs_data_bank = ... def groupwise(func): @@ -313,6 +315,8 @@ def get_material_nuclear_data( discrete_macro_mult_xs_matrix = ( expand_macro_neutron_multiplication_xs_into_matrix( discrete_n2n_xs, group_structure, N2N_Q_VALUE + # TODO: need to restructure this as we may have more than one types of (n,2n) + # reactions, requiring different values of N2N_Q_VALUE. ) ) source_matrix = ( diff --git a/process/neutronics_data.py b/process/neutronics_data.py new file mode 100644 index 0000000000..ac8b6f78f0 --- /dev/null +++ b/process/neutronics_data.py @@ -0,0 +1,27 @@ +import numpy as np + +class ZeroContinuousFunc: + """A dummy class that returns 0 whenever called.""" + def __call__(self, x): + """Return 0 for al cases.""" + if np.isscalar(x): + return 0.0 + return np.zeros_like(x) + +def get_avg_atomic_mass(composition: dict[str, float]) -> float: + """Calculate the average atomic mass number. + Parameters + ---------- + composition: + a dictionary showing the fraction that each species makes up. + """ + total_fraction = sum(composition.values()) + return sum(extract_atomic_mass(species) * fraction / total_fraction for species, fraction in composition.items()) + +def extract_atomic_mass(str) -> float: + return + +material_density_data_bank = ... +material_composition_data_bank = ... +xs_data_bank = ... +breeding_xs_data_bank = ... \ No newline at end of file From d44f11706d02bd3e9f1613d2b4f8a80686f22b48 Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 3 May 2025 03:54:06 +0100 Subject: [PATCH 04/98] Ruff improvements. --- process/neutronics.py | 15 +++++++++------ process/neutronics_data.py | 14 +++++++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 1c03512980..5d4d8fb72b 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -6,16 +6,17 @@ import functools import numpy as np -from numpy import testing as npt -from scipy.constants import Avogadro -from neutronics_data import (ZeroContinuousFunc, +from neutronics_data import ( + ZeroContinuousFunc, + breeding_xs_data_bank, extract_atomic_mass, get_avg_atomic_mass, - material_density_data_bank, material_composition_data_bank, + material_density_data_bank, xs_data_bank, - breeding_xs_data_bank ) +from numpy import testing as npt +from scipy.constants import Avogadro BARNS_CM2 = 1e-24 N_A = Avogadro @@ -314,7 +315,9 @@ def get_material_nuclear_data( ) discrete_macro_mult_xs_matrix = ( expand_macro_neutron_multiplication_xs_into_matrix( - discrete_n2n_xs, group_structure, N2N_Q_VALUE + discrete_n2n_xs, + group_structure, + N2N_Q_VALUE, # TODO: need to restructure this as we may have more than one types of (n,2n) # reactions, requiring different values of N2N_Q_VALUE. ) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index ac8b6f78f0..a0a188d049 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -1,13 +1,16 @@ import numpy as np + class ZeroContinuousFunc: """A dummy class that returns 0 whenever called.""" + def __call__(self, x): """Return 0 for al cases.""" if np.isscalar(x): return 0.0 return np.zeros_like(x) + def get_avg_atomic_mass(composition: dict[str, float]) -> float: """Calculate the average atomic mass number. Parameters @@ -16,12 +19,17 @@ def get_avg_atomic_mass(composition: dict[str, float]) -> float: a dictionary showing the fraction that each species makes up. """ total_fraction = sum(composition.values()) - return sum(extract_atomic_mass(species) * fraction / total_fraction for species, fraction in composition.items()) + return sum( + extract_atomic_mass(species) * fraction / total_fraction + for species, fraction in composition.items() + ) -def extract_atomic_mass(str) -> float: + +def extract_atomic_mass(species: str) -> float: return + material_density_data_bank = ... material_composition_data_bank = ... xs_data_bank = ... -breeding_xs_data_bank = ... \ No newline at end of file +breeding_xs_data_bank = ... From f68533bafcd64bff01ccadc18adfaa54fb675898 Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 3 May 2025 16:13:07 +0100 Subject: [PATCH 05/98] Decided to implement a switch case for sinh(x/sqrt(-...))=-sin(x/sqrt(...)), instead of using complex number to cover both +ve and -ve sign in the sqrt. --- process/neutronics.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 5d4d8fb72b..f8e2e2b8e5 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -67,7 +67,7 @@ def __set_name__(self, owner, name): def get_diffusion_coefficient_and_length( total_xs: float, scattering_xs: float, avg_atomic_mass: float -) -> tuple[float, np.complex128]: +) -> tuple[float, float]: r""" Calculate the diffusion coefficient for a given scattering and total macro-scopic cross-section in a given medium. @@ -96,18 +96,16 @@ def get_diffusion_coefficient_and_length( diffusion_coef: The diffusion coefficient as given by Reactor Analysis, Duderstadt and Hamilton. unit: [cm] - diffusion_len: - The characteristic diffusion length as given by Reactor Analysis, Duderstadt and - Hamilton. + diffusion_len_2: + The square of the characteristic diffusion length as given by Reactor Analysis, + Duderstadt and Hamilton. unit: [cm] """ transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs diffusion_coef = 1 / 3 / transport_xs - diffusion_len = np.sqrt( - complex(diffusion_coef / (total_xs - scattering_xs), 0.0) - ) - return diffusion_coef, diffusion_len + diffusion_len_2 = diffusion_coef / (total_xs - scattering_xs) + return diffusion_coef, diffusion_len_2 def extrapolation_length(diffusion_coefficient: float) -> float: @@ -380,7 +378,7 @@ def __init__( # Dictionaries indexed by integers, so that we don't have to worry about ordering self.integration_constants = {} self.extended_boundary = {} - self.l_fw, self.l_bz = {}, {} + self.l_fw_2, self.l_bz_2 = {}, {} def solve_one_group(self) -> None: i = 0 @@ -390,12 +388,12 @@ def solve_one_group(self) -> None: c2 = self.flux * ... c3 = self.flux * ... c4 = self.flux * ... - self.l_fw[i], d_fw = get_diffusion_coefficient_and_length( + self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( self.fw_sigma_t[i], self.fw_sigma_s[i, i], self.fw_A, ) - self.l_bz[i], d_bz = get_diffusion_coefficient_and_length( + self.l_bz_2[i], d_bz = get_diffusion_coefficient_and_length( self.bz_sigma_t[i], self.bz_sigma_s[i, i], self.bz_A, @@ -420,12 +418,12 @@ def solve_group_n(self, n: int) -> None: c2 = self.flux * ... c3 = self.flux * ... c4 = self.flux * ... - self.l_fw[i], d_fw = get_diffusion_coefficient_and_length( + self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( self.fw_sigma_t[i], self.fw_sigma_s[i, i], self.fw_A, ) - self.l_bz[i], d_bz = get_diffusion_coefficient_and_length( + self.l_bz_2[i], d_bz = get_diffusion_coefficient_and_length( self.bz_sigma_t[i], self.bz_sigma_s[i, i], self.bz_A, @@ -438,18 +436,20 @@ def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: """Neutron flux at the first wall.""" i = n - 1 c1, c2 = self.integration_constants[i][:2] - return np.real( - c1 * np.sinh(x / self.l_fw[i]) + c2 * np.cosh(x / self.l_fw[i]) - ) + l_fw = np.sqrt(abs(self.l_fw_2[i])) + if self.l_fw_2 < 0: + return c1 * -np.sin(x / l_fw) + c2 * np.cos(x / l_fw) + return c1 * np.sinh(x / l_fw) + c2 * np.cosh(x / l_fw) @groupwise def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: """Neutron flux at the blanket.""" i = n - 1 c3, c4 = self.integration_constants[i][2:] - return np.real( - c3 * np.sinh(x / self.l_bz[i]) + c4 * np.cosh(x / self.l_bz[i]) - ) + l_bz = np.sqrt(abs(self.l_bz_2[i])) + if self.l_bz_2 < 0: + return c3 * -np.sin(x / l_bz) + c4 * np.cos(x / l_bz) + return c3 * np.sinh(x / l_bz) + c4 * np.cosh(x / l_bz) @groupwise def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: From 555e625ceb2b3802f59211ad9a580f693b57a5c7 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 9 May 2025 10:47:46 +0100 Subject: [PATCH 06/98] Some further progress on docstrings and equations. --- process/neutronics.py | 88 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 16 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index f8e2e2b8e5..03674c22dd 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -381,13 +381,14 @@ def __init__( self.l_fw_2, self.l_bz_2 = {}, {} def solve_one_group(self) -> None: + """ + Solve the first-group's neutron diffusion equation. + Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], + self.l_bz_2[0], and self.integration_constants[0]. + """ i = 0 if i in self.integration_constants: return # skip if it has already been solved. - c1 = self.flux * ... - c2 = self.flux * ... - c3 = self.flux * ... - c4 = self.flux * ... self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( self.fw_sigma_t[i], self.fw_sigma_s[i, i], @@ -398,10 +399,29 @@ def solve_one_group(self) -> None: self.bz_sigma_s[i, i], self.bz_A, ) + l_fw = np.sqrt(abs(self.l_fw_2)) + l_bz = np.sqrt(abs(self.l_bz_2)) + c1 = self.flux * ... * l_fw + c2 = self.flux * ... * l_bz + c3 = self.flux * ... + c4 = self.flux * ... self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) self.integration_constants[i] = [c1, c2, c3, c4] def solve_group_n(self, n: int) -> None: + """ + Solve the n-th group of neutron's diffusion equation. + Store the solved constants in self.extended_boundary[n-1], self.l_fw_2[n-1], + self.l_bz_2[n-1], and self.integration_constants[n-1]. + + Parameters + ---------- + n: + The index of the neutron group whose constants are being solved. + allowed range: [1, self.n_groups] + This gets translated to the index i=n-1 used for the dictionaries of + constants attached to self. + """ if n not in range(1, self.n_groups): raise ValueError( f"n must be a positive integer between 1 and {self.n_groups}!" @@ -414,10 +434,6 @@ def solve_group_n(self, n: int) -> None: i = n - 1 if i in self.integration_constants: return # skip if it has already been solved. - c1 = self.flux * ... - c2 = self.flux * ... - c3 = self.flux * ... - c4 = self.flux * ... self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( self.fw_sigma_t[i], self.fw_sigma_s[i, i], @@ -428,28 +444,67 @@ def solve_group_n(self, n: int) -> None: self.bz_sigma_s[i, i], self.bz_A, ) + l_fw = np.sqrt(abs(self.l_fw_2)) + l_bz = np.sqrt(abs(self.l_bz_2)) + c1 = self.flux * ... * l_fw + c2 = self.flux * ... * l_bz + c3 = self.flux * ... + c4 = self.flux * ... self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) self.integration_constants[i] = [c1, c2, c3, c4] @groupwise def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: - """Neutron flux at the first wall.""" + """Neutron flux at the first wall. + + Parameters + ---------- + n: + The index of the neutron group whose flux is being evaluated. + x: + The position where the neutron flux has to be evaluated. + Note that this function does not enforce a check for x=inside the first-wall, + thus if x is outside the first-wall, an extrapolated first-wall flux value up + to that point will be given, this flux is still guaranteed to be non-singular + i.e. finite, but not guaranteed to be positive. + """ i = n - 1 c1, c2 = self.integration_constants[i][:2] l_fw = np.sqrt(abs(self.l_fw_2[i])) - if self.l_fw_2 < 0: - return c1 * -np.sin(x / l_fw) + c2 * np.cos(x / l_fw) - return c1 * np.sinh(x / l_fw) + c2 * np.cosh(x / l_fw) + x_l_fw = abs(x) / l_fw + sinh, cosh = ( + (np.sinh, np.cosh) if self.l_fw_2 > 0 else (np.sin, np.cos) + ) + # we specially store c1 and c2 such that if l_fw_2 is imaginary, then a different + # then c1 * sin and c2 * cos becomes real again. + return c1 * sinh(x_l_fw) + c2 * cosh(x_l_fw) @groupwise def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: - """Neutron flux at the blanket.""" + """ + Neutron flux at the blanket. + + Parameters + ---------- + n: + The index of the neutron group whose flux is being evaluated. + x: + The position where the neutron flux has to be evaluated. + Note that this function does not enforce a check for x=inside the blanket, + thus if x is outside the blanket, an extrapolated blanket flux value up to + that point will be given, this flux is still guaranteed to be non-singular + i.e. finite, but not guaranteed to be positive. + """ i = n - 1 c3, c4 = self.integration_constants[i][2:] l_bz = np.sqrt(abs(self.l_bz_2[i])) - if self.l_bz_2 < 0: - return c3 * -np.sin(x / l_bz) + c4 * np.cos(x / l_bz) - return c3 * np.sinh(x / l_bz) + c4 * np.cosh(x / l_bz) + x_l_bz = x / abs(l_bz) + sinh, cosh = ( + (np.sinh, np.cosh) if self.l_bz_2 > 0 else (np.sin, np.cos) + ) + # we specially store c3 and c4 such that if l_bz_2 is imaginary, then a different + # then c3 * sin and c4 * cos becomes real again. + return c3 * sinh(x_l_bz) + c4 * cosh(x_l_bz) @groupwise def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: @@ -461,6 +516,7 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: Neutron group number x: The depth where we want the neutron flux (m). + Valid only between x= -extended boundary to +-extended boundary of that group """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] From 390c38a526d85926d62816a08bc69beb279d0197 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 4 Jun 2025 16:44:57 +0100 Subject: [PATCH 07/98] WIP - pushing to save progress. --- process/neutronics.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 03674c22dd..81cdd1da15 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -229,6 +229,16 @@ def expand_macro_neutron_multiplication_xs_into_matrix( [i]-th bin producing a neutron in the [j]-bin, recorded as the [i,j] element in the matrix. + Parameters + ---------- + discrete_n2n_xs: + The group-wise macroscopic cross-section for the n2n reaction. + A 1D numpy array, with len==number of neutron groups. + group_structure: + The n+1 energy bin boundaries for the n neutron groups, in descending energies. + q_value: + The difference in q-value. + Returns ------- : @@ -245,7 +255,7 @@ def expand_macro_neutron_multiplication_xs_into_matrix( def get_material_nuclear_data( material: str, group_structure: list[float] -) -> tuple[npt.NDArray[np.float64], npt.NDArray]: +) -> tuple[npt.NDArray[np.float64], npt.NDArray, float]: """ The constants that is directly used. @@ -304,25 +314,18 @@ def get_material_nuclear_data( discrete_macro_scattering_xs = calculate_average_macro_xs( composition, micro_scattering_xs, density ) - discrete_macro_scattering_xs_matrix = ( + source_matrix = ( scattering_weight_matrix(group_structure, avg_atomic_mass).T * discrete_macro_scattering_xs ).T - discrete_n2n_xs = calculate_average_macro_xs( - composition, micro_n2n_xs, density - ) - discrete_macro_mult_xs_matrix = ( - expand_macro_neutron_multiplication_xs_into_matrix( - discrete_n2n_xs, + for modified_composition_file, modified_density, q_value in n2n_susceptible_species: + source_matrix += expand_macro_neutron_multiplication_xs_into_matrix( + calculate_average_macro_xs( + composition, micro_n2n_xs, density + ), group_structure, - N2N_Q_VALUE, - # TODO: need to restructure this as we may have more than one types of (n,2n) - # reactions, requiring different values of N2N_Q_VALUE. + q_value, ) - ) - source_matrix = ( - discrete_macro_scattering_xs_matrix + discrete_macro_mult_xs_matrix - ) return discrete_macro_total_xs, source_matrix, avg_atomic_mass From 83c2464f9a8102376109937f04e7cdf530b8b486 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 13 Jul 2025 20:06:42 +0100 Subject: [PATCH 08/98] Transcribed the one-group constant (manually solved and verified by Desmos). Next step is to write the program for solving multi-group fluxes. --- process/neutronics.py | 115 +++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 35 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 81cdd1da15..e502441337 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -318,11 +318,13 @@ def get_material_nuclear_data( scattering_weight_matrix(group_structure, avg_atomic_mass).T * discrete_macro_scattering_xs ).T - for modified_composition_file, modified_density, q_value in n2n_susceptible_species: + for ( + modified_composition_file, + modified_density, + q_value, + ) in n2n_susceptible_species: source_matrix += expand_macro_neutron_multiplication_xs_into_matrix( - calculate_average_macro_xs( - composition, micro_n2n_xs, density - ), + calculate_average_macro_xs(composition, micro_n2n_xs, density), group_structure, q_value, ) @@ -402,13 +404,43 @@ def solve_one_group(self) -> None: self.bz_sigma_s[i, i], self.bz_A, ) - l_fw = np.sqrt(abs(self.l_fw_2)) - l_bz = np.sqrt(abs(self.l_bz_2)) - c1 = self.flux * ... * l_fw - c2 = self.flux * ... * l_bz - c3 = self.flux * ... - c4 = self.flux * ... - self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) + l_fw = np.sqrt(abs(self.l_fw_2[i])) + l_bz = np.sqrt(abs(self.l_bz_2[i])) + x_fw, x_bz = self.x_fw, self.x_bz + self.extended_boundary[i] = x_bz + extrapolation_length(d_bz) + if self.l_fw_2[i] > 0: + sinh_fw = np.sinh(x_fw / l_fw) + cosh_fw = np.cosh(x_fw / l_fw) + tanh_fw = np.tanh(x_fw / l_fw) + else: + sinh_fw = np.sin(x_fw / l_fw) + cosh_fw = np.cos(x_fw / l_fw) + tanh_fw = np.tan(x_fw / l_fw) + if self.l_bz_2[i] > 0: + sinh_bz = np.sinh((self.extended_boundary[i] - x_fw) / l_bz) + cosh_bz = np.cosh((self.extended_boundary[i] - x_fw) / l_bz) + tanh_bz = np.tanh((self.extended_boundary[i] - x_fw) / l_bz) + sinh_bz_full = np.sinh((self.extended_boundary[i]) / l_bz) + cosh_bz_full = np.cosh((self.extended_boundary[i]) / l_bz) + else: + sinh_bz = np.sin((self.extended_boundary[i] - x_fw) / l_bz) + cosh_bz = np.cos((self.extended_boundary[i] - x_fw) / l_bz) + tanh_bz = np.tan((self.extended_boundary[i] - x_fw) / l_bz) + sinh_bz_full = np.sin((self.extended_boundary[i]) / l_bz) + cosh_bz_full = np.cos((self.extended_boundary[i]) / l_bz) + + c1 = l_fw / d_fw + c2 = l_fw / d_fw - np.exp(x_fw / l_fw) * ( + (l_fw / d_fw) + (l_bz / d_bz) * tanh_bz + ) / (cosh_fw + sinh_fw * tanh_bz * (d_fw / l_fw) * (l_bz / d_bz)) + + c3_c4_common_factor = ( + np.exp(x_fw / l_fw) + * (1 - tanh_fw) + / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) + ) + c3 = c3_c4_common_factor * -cosh_bz_full + c4 = c3_c4_common_factor * sinh_bz_full self.integration_constants[i] = [c1, c2, c3, c4] def solve_group_n(self, n: int) -> None: @@ -430,13 +462,13 @@ def solve_group_n(self, n: int) -> None: f"n must be a positive integer between 1 and {self.n_groups}!" ) if n == 1: - self.solve_one_group() + return self.solve_one_group() for k in range(n - 1): if k not in self.integration_constants: self.solve_group_n(k) i = n - 1 if i in self.integration_constants: - return # skip if it has already been solved. + return None # skip if it has already been solved. self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( self.fw_sigma_t[i], self.fw_sigma_s[i, i], @@ -447,18 +479,19 @@ def solve_group_n(self, n: int) -> None: self.bz_sigma_s[i, i], self.bz_A, ) - l_fw = np.sqrt(abs(self.l_fw_2)) - l_bz = np.sqrt(abs(self.l_bz_2)) - c1 = self.flux * ... * l_fw - c2 = self.flux * ... * l_bz - c3 = self.flux * ... - c4 = self.flux * ... + l_fw = np.sqrt(abs(self.l_fw_2[i])) + l_bz = np.sqrt(abs(self.l_bz_2[i])) + c1 = ... + c2 = ... + c3 = ... + c4 = ... self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) self.integration_constants[i] = [c1, c2, c3, c4] + return None @groupwise def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: - """Neutron flux at the first wall. + """Neutron flux of the n-th group at the first wall, at location x [m]. Parameters ---------- @@ -470,49 +503,56 @@ def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: thus if x is outside the first-wall, an extrapolated first-wall flux value up to that point will be given, this flux is still guaranteed to be non-singular i.e. finite, but not guaranteed to be positive. + + Returns + ------- + flux: + Neutron flux at x meter from the first wall. """ i = n - 1 c1, c2 = self.integration_constants[i][:2] l_fw = np.sqrt(abs(self.l_fw_2[i])) x_l_fw = abs(x) / l_fw - sinh, cosh = ( - (np.sinh, np.cosh) if self.l_fw_2 > 0 else (np.sin, np.cos) - ) - # we specially store c1 and c2 such that if l_fw_2 is imaginary, then a different - # then c1 * sin and c2 * cos becomes real again. - return c1 * sinh(x_l_fw) + c2 * cosh(x_l_fw) + s, c = (np.sinh, np.cosh) if self.l_fw_2[i] > 0 else (np.sin, np.cos) + # we specially store c1 and c2 as real values, such that if l_fw_2 is + # imaginary, then c1 * sin and c2 * cos is still real. + return self.flux * (c1 * s(x_l_fw) + c2 * c(x_l_fw)) @groupwise def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: - """ - Neutron flux at the blanket. + """Neutron flux of the n-th groupat the blanket, at location x [m]. Parameters ---------- n: The index of the neutron group whose flux is being evaluated. x: - The position where the neutron flux has to be evaluated. + The position where the neutron flux has to be evaluated. [m] Note that this function does not enforce a check for x=inside the blanket, thus if x is outside the blanket, an extrapolated blanket flux value up to that point will be given, this flux is still guaranteed to be non-singular i.e. finite, but not guaranteed to be positive. + + Returns + ------- + flux: + Neutron flux at x meter from the first wall. """ i = n - 1 c3, c4 = self.integration_constants[i][2:] l_bz = np.sqrt(abs(self.l_bz_2[i])) x_l_bz = x / abs(l_bz) - sinh, cosh = ( - (np.sinh, np.cosh) if self.l_bz_2 > 0 else (np.sin, np.cos) - ) + s, c = (np.sinh, np.cosh) if self.l_bz_2[i] > 0 else (np.sin, np.cos) # we specially store c3 and c4 such that if l_bz_2 is imaginary, then a different # then c3 * sin and c4 * cos becomes real again. - return c3 * sinh(x_l_bz) + c4 * cosh(x_l_bz) + return self.flux * (c3 * s(x_l_bz) + c4 * c(x_l_bz)) @groupwise def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: """ - Neutron flux + Neutron flux anywhere within the valid range of x, + i.e. from -self.x_bz to self.x_bz. + Parameters ---------- n: @@ -520,6 +560,11 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: x: The depth where we want the neutron flux (m). Valid only between x= -extended boundary to +-extended boundary of that group + + Raises + ------ + ValueError + The inputted x """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] @@ -529,7 +574,7 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated up to " - f"{self.extended_boundary[n]}, which {x} violates!" + f"{self.extended_boundary[n]} cm, which {x * 100} cm violates!" ) out_flux = np.zeros_like(x) From 18874998a08980aeeb90bc090651191f62e47c2d Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 13 Jul 2025 21:04:29 +0100 Subject: [PATCH 09/98] Modified expression into sum-of-exponentials form, rather than sum-of-cosh+sinh. --- process/neutronics.py | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index e502441337..c1c4bb2f0c 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -420,27 +420,27 @@ def solve_one_group(self) -> None: sinh_bz = np.sinh((self.extended_boundary[i] - x_fw) / l_bz) cosh_bz = np.cosh((self.extended_boundary[i] - x_fw) / l_bz) tanh_bz = np.tanh((self.extended_boundary[i] - x_fw) / l_bz) - sinh_bz_full = np.sinh((self.extended_boundary[i]) / l_bz) - cosh_bz_full = np.cosh((self.extended_boundary[i]) / l_bz) else: sinh_bz = np.sin((self.extended_boundary[i] - x_fw) / l_bz) cosh_bz = np.cos((self.extended_boundary[i] - x_fw) / l_bz) tanh_bz = np.tan((self.extended_boundary[i] - x_fw) / l_bz) - sinh_bz_full = np.sin((self.extended_boundary[i]) / l_bz) - cosh_bz_full = np.cos((self.extended_boundary[i]) / l_bz) - c1 = l_fw / d_fw - c2 = l_fw / d_fw - np.exp(x_fw / l_fw) * ( - (l_fw / d_fw) + (l_bz / d_bz) * tanh_bz - ) / (cosh_fw + sinh_fw * tanh_bz * (d_fw / l_fw) * (l_bz / d_bz)) + c2 = ( + np.exp(x_fw / l_fw) + / 2 + * ((l_fw / d_fw) + (l_bz / d_bz) * tanh_bz) + / (cosh_fw + sinh_fw * tanh_bz * (d_fw / l_fw) * (l_bz / d_bz)) + ) + c1 = c2 - l_fw / d_fw c3_c4_common_factor = ( np.exp(x_fw / l_fw) + / 2 * (1 - tanh_fw) / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) ) - c3 = c3_c4_common_factor * -cosh_bz_full - c4 = c3_c4_common_factor * sinh_bz_full + c3 = c3_c4_common_factor * np.exp(self.extended_boundary[i] / l_bz) + c4 = -c3_c4_common_factor * np.exp(-self.extended_boundary[i] / l_bz) self.integration_constants[i] = [c1, c2, c3, c4] def solve_group_n(self, n: int) -> None: @@ -513,10 +513,7 @@ def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: c1, c2 = self.integration_constants[i][:2] l_fw = np.sqrt(abs(self.l_fw_2[i])) x_l_fw = abs(x) / l_fw - s, c = (np.sinh, np.cosh) if self.l_fw_2[i] > 0 else (np.sin, np.cos) - # we specially store c1 and c2 as real values, such that if l_fw_2 is - # imaginary, then c1 * sin and c2 * cos is still real. - return self.flux * (c1 * s(x_l_fw) + c2 * c(x_l_fw)) + return self.flux * (c1 * np.exp(x_l_fw) + c2 * np.exp(-x_l_fw)) @groupwise def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: @@ -541,11 +538,8 @@ def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: i = n - 1 c3, c4 = self.integration_constants[i][2:] l_bz = np.sqrt(abs(self.l_bz_2[i])) - x_l_bz = x / abs(l_bz) - s, c = (np.sinh, np.cosh) if self.l_bz_2[i] > 0 else (np.sin, np.cos) - # we specially store c3 and c4 such that if l_bz_2 is imaginary, then a different - # then c3 * sin and c4 * cos becomes real again. - return self.flux * (c3 * s(x_l_bz) + c4 * c(x_l_bz)) + x_l_bz = abs(x) / l_bz + return self.flux * (c3 * np.exp(x_l_bz) + c4 * np.exp(-x_l_bz)) @groupwise def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: From 210bb85dcdf3377f89f282dd457b73a90376a1ae Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 14 Jul 2025 02:32:04 +0100 Subject: [PATCH 10/98] Added reaction rates calculations and neutron passage/escape flux. --- process/neutronics.py | 128 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 14 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index c1c4bb2f0c..7949161a65 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -17,6 +17,7 @@ ) from numpy import testing as npt from scipy.constants import Avogadro +from scipy.special import expm1 BARNS_CM2 = 1e-24 N_A = Avogadro @@ -33,12 +34,11 @@ def groupwise(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): groupwise_func = getattr(self, groupwise_name) - return np.sum( + return np.array( [ groupwise_func(n, *args, **kwargs) for n in range(1, self.n_groups + 1) ], - axis=0, ) def wrapper_setattr(cls): @@ -350,8 +350,7 @@ def __init__( ---------- flux: Nuetron flux directly emitted by the plasma, incident on the first wall. - unit: arbitrary, but whichever unit used here will be the same unit used at - the output neutron_flux. + unit: cm^-2 s^-1 fw_mat: first wall material x_fw: @@ -363,7 +362,7 @@ def __init__( n_groups: number of groups used to approximate this. """ - self.flux = flux + self.flux = flux # flux incident on the first wall. if not (0 < x_fw < x_bz): raise ValueError( f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." @@ -374,16 +373,18 @@ def __init__( self.x_bz = x_bz * 100 self.n_groups = n_groups + # macroscopic cross-sections Sigma saved here. Not capitalized due to style self.fw_sigma_t, self.fw_sigma_s, self.fw_A = ( get_material_nuclear_data(self.fw_mat, n_groups) ) self.bz_sigma_t, self.bz_sigma_s, self.bz_A = ( get_material_nuclear_data(self.bz_mat, n_groups) ) - # Dictionaries indexed by integers, so that we don't have to worry about ordering + # Dictionaries indexed by integers, so that we can create these values + # out of sequence without messing up the order. self.integration_constants = {} - self.extended_boundary = {} self.l_fw_2, self.l_bz_2 = {}, {} + self.extended_boundary = {} def solve_one_group(self) -> None: """ @@ -426,15 +427,17 @@ def solve_one_group(self) -> None: tanh_bz = np.tan((self.extended_boundary[i] - x_fw) / l_bz) c2 = ( - np.exp(x_fw / l_fw) + self.flux + * np.exp(x_fw / l_fw) / 2 * ((l_fw / d_fw) + (l_bz / d_bz) * tanh_bz) / (cosh_fw + sinh_fw * tanh_bz * (d_fw / l_fw) * (l_bz / d_bz)) ) - c1 = c2 - l_fw / d_fw + c1 = c2 - l_fw / d_fw * self.flux c3_c4_common_factor = ( - np.exp(x_fw / l_fw) + self.flux + * np.exp(x_fw / l_fw) / 2 * (1 - tanh_fw) / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) @@ -513,7 +516,7 @@ def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: c1, c2 = self.integration_constants[i][:2] l_fw = np.sqrt(abs(self.l_fw_2[i])) x_l_fw = abs(x) / l_fw - return self.flux * (c1 * np.exp(x_l_fw) + c2 * np.exp(-x_l_fw)) + return c1 * np.exp(x_l_fw) + c2 * np.exp(-x_l_fw) @groupwise def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: @@ -539,7 +542,7 @@ def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: c3, c4 = self.integration_constants[i][2:] l_bz = np.sqrt(abs(self.l_bz_2[i])) x_l_bz = abs(x) / l_bz - return self.flux * (c3 * np.exp(x_l_bz) + c4 * np.exp(-x_l_bz)) + return c3 * np.exp(x_l_bz) + c4 * np.exp(-x_l_bz) @groupwise def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: @@ -572,6 +575,103 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: ) out_flux = np.zeros_like(x) - out_flux[in_fw] = self.groupwise_neutron_flux_fw(x[in_fw]) - out_flux[in_bz] = self.groupwise_neutron_flux_bz(x[in_bz]) + out_flux[in_fw] = self.groupwise_neutron_flux_fw(n, x[in_fw]) + out_flux[in_bz] = self.groupwise_neutron_flux_bz(n, x[in_bz]) return out_flux + + # scalar values (one or two such floats per neutron group.) + @groupwise + def reaction_rate_fw(self, n: int, reaction_type: str) -> float: + """Calculate the reaction rate in the first wall. + + Parameters + ---------- + n: + The index of the neutron group that needs to be solved. + reaction_type: + Two options: "total" or "non-scattering". + + """ + self.solve_group_n(n) + i = n - 1 + l_fw = np.sqrt(abs(self.l_fw_2[i])) + c1, c2, c3, c4 = self.integration_constants[i] + if reaction_type == "non-scattering": + sigma = self.fw_sigma_t[i] - self.fw_sigma_s[i, i] + elif reaction_type == "total": + sigma = self.fw_sigma_t[i] + else: + raise NotImplementedError( + f"Not yet implemented the reaction type {reaction_type}" + ) + return sigma * ( + c1 * expm1(self.x_fw / l_fw) - c2 * expm1(-self.x_fw / l_fw) + ) + + @groupwise + def reaction_rate_bz(self, n: int, reaction_type: str) -> float: + """Calculate the reaction rate in the blanket. + + Parameters + ---------- + n: + The index of the neutron group that needs to be solved. + reaction_type: + Two options: "total" or "non-scattering". + + """ + self.solve_group_n(n) + i = n - 1 + l_bz = np.sqrt(abs(self.l_bz_2[i])) + c1, c2, c3, c4 = self.integration_constants[i] + if reaction_type == "non-scattering": + sigma = self.bz_sigma_t[i] - self.bz_sigma_s[i, i] + elif reaction_type == "total": + sigma = self.bz_sigma_t[i] + else: + raise NotImplementedError( + f"Not yet implemented the reaction type {reaction_type}" + ) + # thicknesses in terms of bz path lengths + bz_thick = (self.x_bz - self.x_fw) / l_bz + fw_thick = self.x_fw / l_bz + return sigma * ( + c3 * np.exp(fw_thick) * expm1(bz_thick) + - c4 * np.exp(-fw_thick) * expm1(-bz_thick) + ) + + @groupwise + def flux_fw2bz(self, n: int) -> float: + self.solve_group_n(n) + i = n - 1 + c1, c2, c3, c4 = self.integration_constants[i] + l_bz_2, d_bz = get_diffusion_coefficient_and_length( + self.bz_sigma_t[i], + self.bz_sigma_s[i, i], + self.bz_A, + ) + l_bz = np.sqrt(abs(l_bz_2)) + return ( + -d_bz + / l_bz + * (c3 * np.exp(self.x_fw / l_bz) - c4 * np.exp(-self.x_fw / l_bz)) + ) + # equivalent definition below: (should yield the same answer) + # self.flux_fw2bz[i] = - d_fw / l_fw * (c1 * np.exp(x_fw/l_fw) - c2 * np.exp(-x_fw/l_fw)) + + @groupwise + def flux_escaped(self, n: int) -> float: + self.solve_group_n(n) + i = n - 1 + c1, c2, c3, c4 = self.integration_constants[i] + l_bz_2, d_bz = get_diffusion_coefficient_and_length( + self.bz_sigma_t[i], + self.bz_sigma_s[i, i], + self.bz_A, + ) + l_bz = np.sqrt(abs(l_bz_2)) + self.flux_escaped[i] = ( + -d_bz + / l_bz + * (c3 * np.exp(self.x_bz / l_bz) - c4 * np.exp(-self.x_bz / l_bz)) + ) From 93c5e9c6c1fe2503b77c57b471bab94199189388 Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 14 Jul 2025 20:56:19 +0100 Subject: [PATCH 11/98] Added a unit test. --- tests/unit/test_neutronics.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/unit/test_neutronics.py diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py new file mode 100644 index 0000000000..8f41310411 --- /dev/null +++ b/tests/unit/test_neutronics.py @@ -0,0 +1,25 @@ +import pytest + +profile = NeutronFluxProfile( + 1.0, #flux + "dummy-FW-mat", + 0.01, #1cm + "dummy-BZ-mat", + 0.11, #10cm thick blanket + n_groups=2, + ) +def test_has_fluxes(): + assert hasattr(profile, "neutron_flux_at") + assert hasattr(profile, "groupwise_neutron_flux_at") + assert hasattr(profile, "neutron_flux_fw") + assert hasattr(profile, "groupwise_neutron_flux_fw") + assert hasattr(profile, "neutron_flux_bz") + assert hasattr(profile, "groupwise_neutron_flux_bz") + +def test_reactions(): + assert hasattr(profile, "groupwise_reaction_rate_fw") + assert hasattr(profile, "reaction_rate_fw") + assert hasattr(profile, "groupwise_reaction_rate_bz") + assert hasattr(profile, "reaction_rate_bz") + assert hasattr(profile, "flux_fw2bz") + assert hasattr(profile, "flux_escaped") \ No newline at end of file From f991262bcdae267512f1dcfb306970ea3b3bc42b Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 29 Oct 2025 19:06:50 +0000 Subject: [PATCH 12/98] Re-distributed where functions and classes live. Materials data related classes and functions are now in neutronics_data. --- process/neutronics.py | 326 +++++++------------------------------ process/neutronics_data.py | 294 +++++++++++++++++++++++++++++++-- 2 files changed, 340 insertions(+), 280 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 7949161a65..d6262e87f5 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -6,22 +6,11 @@ import functools import numpy as np -from neutronics_data import ( - ZeroContinuousFunc, - breeding_xs_data_bank, - extract_atomic_mass, - get_avg_atomic_mass, - material_composition_data_bank, - material_density_data_bank, - xs_data_bank, -) -from numpy import testing as npt -from scipy.constants import Avogadro +from neutronics_data import MaterialMacroInfo +from numpy import typing as npt from scipy.special import expm1 -BARNS_CM2 = 1e-24 -N_A = Avogadro -N2N_Q_VALUE = ... +from process.exceptions import ProcessValidationError def groupwise(func): @@ -123,226 +112,16 @@ def extrapolation_length(diffusion_coefficient: float) -> float: return 0.7104 * 3 * diffusion_coefficient -def calculate_average_macro_xs( - composition: dict[str, float], - micro_xs: dict[str, float | npt.NDArray[np.float64]], - density: float, -) -> float | npt.NDArray[np.float64]: - r""" - Calculate the macroscopic cross-section for a specific energy group and a specific - reaction (a scalar value), when given the microscopic cross-section values of its - components and its density. - - Parameters - ---------- - composition: - Fraction of each species of atoms of the medium. Does not have to be normalised. - Given in the format {'species': float(fraction)}. - micro_xs: - A dictionary of each species, and their microscopic cross-sections, given in - [barns]. - Given in the format {'species': float(microscopic cross-section)}. - density: - Density of the medium, given in [g/cm^3] - - Notes - ----- - .. math:: - \Sigma &= N_d\sigma - &= \frac{N_A}{A} \rho \sigma - """ - - total_fraction = sum(composition.values()) - weighted_micro_xs, weighted_atomic_mass = [], [] - if composition.keys() != micro_xs.keys(): - raise KeyError( - "The two dictionaries 'composition' and 'micro_xs' must have matching keys." - ) - for species, fraction in composition.items(): - normalized_fraction = fraction / total_fraction - weighted_atomic_mass.append( - normalized_fraction * extract_atomic_mass(species) - ) - weighted_micro_xs.append(normalized_fraction * micro_xs[species]) - avg_sigma = np.sum(weighted_micro_xs, axis=0) - avg_mass_amu = sum(weighted_atomic_mass) - return ( - (BARNS_CM2 * N_A) / avg_mass_amu * avg_sigma * density - ) # N_A/A * rho * sigma - - -def discretize_xs( - continuous_xs, group_structure: list[float] -) -> npt.NDArray[np.float64]: - """ - Discretise a continuous cross-section function into a group structure of n discrete - flaots. - - Parameters - ---------- - continuous_xs: - continuous cross-section function to be discretized. - group_structure: - group structure of neutron energies, the n+1 energy bin boundaries for the n - neutron groups, in descending energies. - - Returns - ------- - : - microscopic cross-section values discretized according to the group structure. - """ - return - - -def scattering_weight_matrix( - group_structure: list[float], atomic_mass: float -) -> npt.NDArray: - """ - Parameters - ---------- - group_structure: - the n+1 energy bin boundaries for the n neutron groups, in descending energies. - atomic_mass: - atomic mass of the medium - - Returns - ------- - : - A lower triangular matrix, where the i-th row contains the normalized weights for - scattering down from the i-th bin to the j-th bin. The main-diagonal contains - the self-scattering cross-section. - e.g. [2,1] would be the fraction of elastic scattering reactions that causes - neutrons from group 3 to scatter into group 2. - The upper triangle must be all zeros. - np.sum(axis=1) == np.ones(len(group_structure)-1). - """ - return - - -def expand_macro_neutron_multiplication_xs_into_matrix( - discrete_n2n_xs: npt.NDArray[np.float64], - group_structure: list[float], - q_value: float, -) -> npt.NDArray: - """Instead of only having the macroscopic cross-section values for the (n,2n) - reaction for each group, calculate the macroscopic cross-section of neutron in the - [i]-th bin producing a neutron in the [j]-bin, recorded as the [i,j] element in the - matrix. - - Parameters - ---------- - discrete_n2n_xs: - The group-wise macroscopic cross-section for the n2n reaction. - A 1D numpy array, with len==number of neutron groups. - group_structure: - The n+1 energy bin boundaries for the n neutron groups, in descending energies. - q_value: - The difference in q-value. - - Returns - ------- - : - A macroscopic neutron multiplication cross-section matrix, such that each row - should sum to = 2 * discrete_n2n_xs (since two neutrons should be produced per - neutron consumed in the (n,2n) reaction). - - Notes - ----- - This is a three body problem. TODO: further investigation is needed to figure out - how to distribute the two outputted neutron's energies! - """ - - -def get_material_nuclear_data( - material: str, group_structure: list[float] -) -> tuple[npt.NDArray[np.float64], npt.NDArray, float]: - """ - The constants that is directly used. - - Parameters - ---------- - materials: - Which material that we want to get the data out of. - group_structure: - the n+1 energy bin boundaries for the n neutron groups, in descending energies. - - Returns - ------- - discrete_macro_total_xs: - All group-wise total cross-sections, given in ascending order. - macroscopic scattering cross-section matrix: - A lower-triangular matrix of total scattering cross-sections, - e.g. [2,1] would be the scattering cross-section from neutron group 3 to group 2. - The upper triangle MUST be zeros. - avg_atomic_mass: - average atomic mass, used for further calcuations - - Notes - ----- - When calculating the group-wise diffusion coefficients, the i-th group's scattering - cross-section :math:`\\Sigma_{s}` is the i-th element on the main diagonal of the - macroscopic scattering cross-section matrix. - """ - density = material_density_data_bank[material] - composition = material_composition_data_bank[material] - avg_atomic_mass = get_avg_atomic_mass(composition) - - # dicts of {"isotope": npt.NDArray[np.float64] 1D arrays} - micro_total_xs = {} - micro_scattering_xs = {} - micro_n2n_xs = {} - for species in composition: - total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[ - species - ] - n2n_xs_continuous = breeding_xs_data_bank.get( - species, ZeroContinuousFunc - ) - micro_total_xs[species] = discretize_xs( - total_xs_continuous, group_structure - ) - micro_scattering_xs[species] = discretize_xs( - elastic_scattering_xs_continuous, group_structure - ) - micro_n2n_xs[species] = discretize_xs( - n2n_xs_continuous, group_structure - ) - - discrete_macro_total_xs = calculate_average_macro_xs( - composition, micro_total_xs, density - ) - discrete_macro_scattering_xs = calculate_average_macro_xs( - composition, micro_scattering_xs, density - ) - source_matrix = ( - scattering_weight_matrix(group_structure, avg_atomic_mass).T - * discrete_macro_scattering_xs - ).T - for ( - modified_composition_file, - modified_density, - q_value, - ) in n2n_susceptible_species: - source_matrix += expand_macro_neutron_multiplication_xs_into_matrix( - calculate_average_macro_xs(composition, micro_n2n_xs, density), - group_structure, - q_value, - ) - - return discrete_macro_total_xs, source_matrix, avg_atomic_mass - - class NeutronFluxProfile: """Neutron flux in the first wall or the blanket.""" def __init__( self, flux: float, - fw_mat: str, x_fw: float, - bz_mat: str, x_bz: float, - n_groups: int = 1, + fw_mat: MaterialMacroInfo, + bz_mat: MaterialMacroInfo, ): """Initialize a particular FW-BZ geometry and neutron flux. @@ -351,44 +130,55 @@ def __init__( flux: Nuetron flux directly emitted by the plasma, incident on the first wall. unit: cm^-2 s^-1 - fw_mat: - first wall material x_fw: thickness of the first wall [m]. It will be converted and stored in [cm]. - bz_mat: - blanket material x_bz: thickness of the blanket [m]. It will be converted and stored in [cm]. + fw_mat: + first wall material information + bz_mat: + blanket material information + + Attributes + ---------- + x_fw: + thickness of the first wall, converted from [m] into [cm]. + x_bz: + thickness of the blanket, converted from [m] into [cm]. n_groups: - number of groups used to approximate this. + number of groups in the group structure + group_structure: + energy bin edges, 1D array of len = n_groups+1 """ self.flux = flux # flux incident on the first wall. if not (0 < x_fw < x_bz): raise ValueError( f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." ) - self.fw_mat = fw_mat self.x_fw = x_fw * 100 - self.bz_mat = bz_mat self.x_bz = x_bz * 100 - self.n_groups = n_groups + self.fw_mat = fw_mat + self.bz_mat = bz_mat + self.n_groups = self.fw_mat.n_groups + self.group_structure = self.fw_mat.group_structure + if not np.isclose( + self.fw_mat.group_structure, self.bz_mat.group_structure + ): + raise ProcessValidationError( + "The first-wall material info and breeding zone material info" + "must have the same group structure!" + ) - # macroscopic cross-sections Sigma saved here. Not capitalized due to style - self.fw_sigma_t, self.fw_sigma_s, self.fw_A = ( - get_material_nuclear_data(self.fw_mat, n_groups) - ) - self.bz_sigma_t, self.bz_sigma_s, self.bz_A = ( - get_material_nuclear_data(self.bz_mat, n_groups) - ) + # macroscopic cross-sections Sigma saved here. # Dictionaries indexed by integers, so that we can create these values - # out of sequence without messing up the order. + # out of sequence. self.integration_constants = {} - self.l_fw_2, self.l_bz_2 = {}, {} + self.l_fw_2, self.l_bz_2 = {}, {} # diffusion lengths squared self.extended_boundary = {} - def solve_one_group(self) -> None: + def solve_lowest_group(self) -> None: """ - Solve the first-group's neutron diffusion equation. + Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], self.l_bz_2[0], and self.integration_constants[0]. """ @@ -396,14 +186,14 @@ def solve_one_group(self) -> None: if i in self.integration_constants: return # skip if it has already been solved. self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( - self.fw_sigma_t[i], - self.fw_sigma_s[i, i], - self.fw_A, + self.fw_mat.sigma_t[i], + self.fw_mat.sigma_s[i, i], + self.fw_mat.avg_atomic_mass, ) self.l_bz_2[i], d_bz = get_diffusion_coefficient_and_length( - self.bz_sigma_t[i], - self.bz_sigma_s[i, i], - self.bz_A, + self.bz_mat.sigma_t[i], + self.bz_mat.sigma_s[i, i], + self.bz_mat.avg_atomic_mass, ) l_fw = np.sqrt(abs(self.l_fw_2[i])) l_bz = np.sqrt(abs(self.l_bz_2[i])) @@ -465,7 +255,7 @@ def solve_group_n(self, n: int) -> None: f"n must be a positive integer between 1 and {self.n_groups}!" ) if n == 1: - return self.solve_one_group() + return self.solve_lowest_group() for k in range(n - 1): if k not in self.integration_constants: self.solve_group_n(k) @@ -473,14 +263,14 @@ def solve_group_n(self, n: int) -> None: if i in self.integration_constants: return None # skip if it has already been solved. self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( - self.fw_sigma_t[i], - self.fw_sigma_s[i, i], - self.fw_A, + self.fw_mat.sigma_t[i], + self.fw_mat.sigma_s[i, i], + self.fw_mat.avg_atomic_mass, ) self.l_bz_2[i], d_bz = get_diffusion_coefficient_and_length( - self.bz_sigma_t[i], - self.bz_sigma_s[i, i], - self.bz_A, + self.bz_mat.sigma_t[i], + self.bz_mat.sigma_s[i, i], + self.bz_mat.avg_atomic_mass, ) l_fw = np.sqrt(abs(self.l_fw_2[i])) l_bz = np.sqrt(abs(self.l_bz_2[i])) @@ -597,9 +387,9 @@ def reaction_rate_fw(self, n: int, reaction_type: str) -> float: l_fw = np.sqrt(abs(self.l_fw_2[i])) c1, c2, c3, c4 = self.integration_constants[i] if reaction_type == "non-scattering": - sigma = self.fw_sigma_t[i] - self.fw_sigma_s[i, i] + sigma = self.fw_mat.sigma_t[i] - self.fw_mat.sigma_s[i, i] elif reaction_type == "total": - sigma = self.fw_sigma_t[i] + sigma = self.fw_mat.sigma_t[i] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" @@ -625,9 +415,9 @@ def reaction_rate_bz(self, n: int, reaction_type: str) -> float: l_bz = np.sqrt(abs(self.l_bz_2[i])) c1, c2, c3, c4 = self.integration_constants[i] if reaction_type == "non-scattering": - sigma = self.bz_sigma_t[i] - self.bz_sigma_s[i, i] + sigma = self.bz_mat.sigma_t[i] - self.bz_mat.sigma_s[i, i] elif reaction_type == "total": - sigma = self.bz_sigma_t[i] + sigma = self.bz_mat.sigma_t[i] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" @@ -646,9 +436,9 @@ def flux_fw2bz(self, n: int) -> float: i = n - 1 c1, c2, c3, c4 = self.integration_constants[i] l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_sigma_t[i], - self.bz_sigma_s[i, i], - self.bz_A, + self.bz_mat.sigma_t[i], + self.bz_mat.sigma_s[i, i], + self.bz_mat.avg_atomic_mass, ) l_bz = np.sqrt(abs(l_bz_2)) return ( @@ -665,9 +455,9 @@ def flux_escaped(self, n: int) -> float: i = n - 1 c1, c2, c3, c4 = self.integration_constants[i] l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_sigma_t[i], - self.bz_sigma_s[i, i], - self.bz_A, + self.bz_mat.sigma_t[i], + self.bz_mat.sigma_s[i, i], + self.bz_mat.avg_atomic_mass, ) l_bz = np.sqrt(abs(l_bz_2)) self.flux_escaped[i] = ( diff --git a/process/neutronics_data.py b/process/neutronics_data.py index a0a188d049..a7c29f05f1 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -1,14 +1,32 @@ +from dataclasses import dataclass +from itertools import islice +from pathlib import Path + import numpy as np +from numpy import typing as npt +from scipy.constants import Avogadro +from process.exceptions import ProcessValidationError -class ZeroContinuousFunc: - """A dummy class that returns 0 whenever called.""" +BARNS_CM2 = 1e-24 +N_A = Avogadro +N2N_Q_VALUE = ... +_ATOMIC_MASS = {} - def __call__(self, x): - """Return 0 for al cases.""" - if np.isscalar(x): - return 0.0 - return np.zeros_like(x) + +def extract_atomic_mass(isotope: str) -> float: + """Copied from openmc 0.15.2: openmc.data.data""" + if not _ATOMIC_MASS: + mass_file = Path(__file__) / "data" / "mass_1.mas20.txt" + with open(mass_file) as ame: + # Read lines in file starting at line 37 + for line in islice(ame, 36, None): + name = f"{line[20:22].strip()}{int(line[16:19])}" + mass = float(line[106:109]) + 1e-6 * float( + line[110:116] + "." + line[117:123] + ) + _ATOMIC_MASS[name.lower()] = mass + return _ATOMIC_MASS[isotope.lower()] def get_avg_atomic_mass(composition: dict[str, float]) -> float: @@ -20,16 +38,268 @@ def get_avg_atomic_mass(composition: dict[str, float]) -> float: """ total_fraction = sum(composition.values()) return sum( - extract_atomic_mass(species) * fraction / total_fraction + extract_atomic_mass(species) * (fraction / total_fraction) for species, fraction in composition.items() ) -def extract_atomic_mass(species: str) -> float: - return - - material_density_data_bank = ... material_composition_data_bank = ... xs_data_bank = ... breeding_xs_data_bank = ... + + +def calculate_average_macro_xs( + composition: dict[str, float], + micro_xs: dict[str, float | npt.NDArray[np.float64]], + density: float, +) -> float | npt.NDArray[np.float64]: + r""" + Calculate the macroscopic cross-section for a specific energy group and a specific + reaction (a scalar value), when given the microscopic cross-section values of its + components and its density. + + Parameters + ---------- + composition: + Fraction of each species of atoms of the medium. Does not have to be normalised. + Given in the format {'species': float(fraction)}. + micro_xs: + A dictionary of each species, and their microscopic cross-sections, given in + [barns]. + Given in the format {'species': float(microscopic cross-section)}. + density: + Density of the medium, given in [g/cm^3] + + Notes + ----- + .. math:: + \Sigma &= N_d\sigma + &= \frac{N_A}{A} \rho \sigma + """ + + total_fraction = sum(composition.values()) + weighted_micro_xs, weighted_atomic_mass = [], [] + if composition.keys() != micro_xs.keys(): + raise KeyError( + "The two dictionaries 'composition' and 'micro_xs' must have matching keys." + ) + for species, fraction in composition.items(): + normalized_fraction = fraction / total_fraction + weighted_atomic_mass.append( + normalized_fraction * extract_atomic_mass(species) + ) + weighted_micro_xs.append(normalized_fraction * micro_xs[species]) + avg_sigma = np.sum(weighted_micro_xs, axis=0) + avg_mass_amu = sum(weighted_atomic_mass) + return ( + (BARNS_CM2 * N_A) / avg_mass_amu * avg_sigma * density + ) # N_A/A * rho * sigma + + +def discretize_xs( + continuous_xs, group_structure: list[float] +) -> npt.NDArray[np.float64]: + """ + Discretise a continuous cross-section function into a group structure of n discrete + flaots. + + Parameters + ---------- + continuous_xs: + continuous cross-section function to be discretized. + group_structure: + group structure of neutron energies, the n+1 energy bin boundaries for the n + neutron groups, in descending energies. + + Returns + ------- + : + microscopic cross-section values discretized according to the group structure. + """ + return group_structure, continuous_xs + + +def scattering_weight_matrix( + group_structure: list[float], atomic_mass: float +) -> npt.NDArray: + """ + Parameters + ---------- + group_structure: + the n+1 energy bin boundaries for the n neutron groups, in descending energies. + atomic_mass: + atomic mass of the medium + + Returns + ------- + : + A lower triangular matrix, where the i-th row contains the normalized weights for + scattering down from the i-th bin to the j-th bin. The main-diagonal contains + the self-scattering cross-section. + e.g. [2,1] would be the fraction of elastic scattering reactions that causes + neutrons from group 3 to scatter into group 2. + The upper triangle must be all zeros. + np.sum(axis=1) == np.ones(len(group_structure)-1). + """ + return atomic_mass, group_structure + + +def expand_macro_neutron_multiplication_xs_into_matrix( + discrete_n2n_xs: npt.NDArray[np.float64], + group_structure: list[float], + q_value: float, +) -> npt.NDArray: + """Instead of only having the macroscopic cross-section values for the (n,2n) + reaction for each group, calculate the macroscopic cross-section of neutron in the + [i]-th bin producing a neutron in the [j]-bin, recorded as the [i,j] element in the + matrix. + + Parameters + ---------- + discrete_n2n_xs: + The group-wise macroscopic cross-section for the n2n reaction. + A 1D numpy array, with len==number of neutron groups. + group_structure: + The n+1 energy bin boundaries for the n neutron groups, in descending energies. + q_value: + The difference in q-value. + + Returns + ------- + : + A macroscopic neutron multiplication cross-section matrix, such that each row + should sum to = 2 * discrete_n2n_xs (since two neutrons should be produced per + neutron consumed in the (n,2n) reaction). + + Notes + ----- + This is a three body problem. TODO: further investigation is needed to figure out + how to distribute the two outputted neutron's energies! + """ + + +class ZeroContinuousFunc: + """A dummy class that returns 0 whenever called.""" + + def __call__(self, x): + """Return 0 for al cases.""" + if np.isscalar(x): + return 0.0 + return np.zeros_like(x) + + +@dataclass +class MaterialMacroInfo: + """Material information""" + + sigma_t: npt.NDArray[np.float64] # Sigma_total, 1D array of len = n + sigma_s: npt.NDArray # Sigma_scattering from group i to j, 2D array of n*n + group_structure: npt.NDArray # energy bin edges, 1D array of len = n+1 + avg_atomic_mass: float # average atomic mass (weighted by fraction) + + def __post_init__(self): + """Validation to confirm the shape is correct.""" + if len(self.sigma_t) != self.n_groups: + raise ProcessValidationError( + f"total group-wise cross-sections should have {self.n_groups} " + "groups as specified by the group_structure." + ) + if np.shape(self.sigma_s) != (self.n_groups, self.n_groups): + raise ProcessValidationError( + "Group-wise scattering cross-sections be a square matrix of " + f"shape n*n, where n= number of groups = {self.n_groups}." + ) + self.avg_atomic_mass = float(self.avg_atomic_mass) # force into float + + @property + def n_groups(self): + """Store this attribute upon first retrieval.""" + if not hasattr(self, "_n_groups"): + self._n_groups = len(self.group_structure) - 1 + return self._n_groups + + +def get_material_nuclear_data( + material: str, group_structure: list[float] +) -> MaterialMacroInfo: + """ + The constants that is directly used. + + Parameters + ---------- + materials: + Which material that we want to get the data out of. + group_structure: + the n+1 energy bin boundaries for the n neutron groups, in descending energies. + + Returns + ------- + discrete_macro_total_xs: + All group-wise total cross-sections, given in ascending order. + macroscopic scattering cross-section matrix: + A lower-triangular matrix of total scattering cross-sections, + e.g. [2,1] would be the scattering cross-section from neutron group 3 to group 2. + The upper triangle MUST be zeros. + avg_atomic_mass: + average atomic mass, used for further calcuations + + Notes + ----- + When calculating the group-wise diffusion coefficients, the i-th group's scattering + cross-section :math:`\\Sigma_{s}` is the i-th element on the main diagonal of the + macroscopic scattering cross-section matrix. + """ + density = material_density_data_bank[material] + composition = material_composition_data_bank[material] + avg_atomic_mass = get_avg_atomic_mass(composition) + + # dicts of {"isotope": npt.NDArray[np.float64] 1D arrays} + micro_total_xs = {} + micro_scattering_xs = {} + micro_n2n_xs = {} + for species in composition: + total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[ + species + ] + n2n_xs_continuous = breeding_xs_data_bank.get( + species, ZeroContinuousFunc + ) + micro_total_xs[species] = discretize_xs( + total_xs_continuous, group_structure + ) + micro_scattering_xs[species] = discretize_xs( + elastic_scattering_xs_continuous, group_structure + ) + micro_n2n_xs[species] = discretize_xs( + n2n_xs_continuous, group_structure + ) + + discrete_macro_total_xs = calculate_average_macro_xs( + composition, micro_total_xs, density + ) + discrete_macro_scattering_xs = calculate_average_macro_xs( + composition, micro_scattering_xs, density + ) + source_matrix = ( + scattering_weight_matrix(group_structure, avg_atomic_mass).T + * discrete_macro_scattering_xs + ).T + n2n_susceptible_species = ... + for ( + modified_composition_file, + modified_density, + q_value, + ) in n2n_susceptible_species: + source_matrix += expand_macro_neutron_multiplication_xs_into_matrix( + calculate_average_macro_xs(composition, micro_n2n_xs, density), + group_structure, + q_value, + ) + + return MaterialMacroInfo( + discrete_macro_total_xs, + source_matrix, + group_structure, + avg_atomic_mass, + ) From 5f6d6253f5d1482b8044f189506939f82c997f31 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 29 Oct 2025 19:07:28 +0000 Subject: [PATCH 13/98] Added publically available data (same source as openmc), so we don't have to import openmc. --- process/data/mass_1.mas20.txt | 3594 +++++++++++++++++++++++++++++++++ 1 file changed, 3594 insertions(+) create mode 100644 process/data/mass_1.mas20.txt diff --git a/process/data/mass_1.mas20.txt b/process/data/mass_1.mas20.txt new file mode 100644 index 0000000000..ce12b2c4a5 --- /dev/null +++ b/process/data/mass_1.mas20.txt @@ -0,0 +1,3594 @@ +1 a0dsskgw A T O M I C M A S S A D J U S T M E N T +0 DATE 3 Mar 2021 TIME 22:41 +0 ********************* A= 0 TO 295 + * file : mass.mas20 * + ********************* + + This is one file out of a series of 3 files published in: + "The Ame2020 atomic mass evaluation (I)" by W.J.Huang, M.Wang, F.G.Kondev, G.Audi and S.Naimi + Chinese Physics C45, 030002, March 2021. + "The Ame2020 atomic mass evaluation (II)" by M.Wang, W.J.Huang, F.G.Kondev, G.Audi and S.Naimi + Chinese Physics C45, 030003, March 2021. + for files : mass.mas20 : atomic masses + rct1.mas20 : react and sep energies, part 1 + rct2.mas20 : react and sep energies, part 2 + A fourth file is the "Rounded" version of the atomic mass table (the first file) + massround.mas20 atomic masses "Rounded" version + + Values in files 1, 2 and 3 are unrounded version of the published ones + Values in file 4 are exact copy of the published ones + + col 1 : Fortran character control: 1 = page feed 0 = line feed + format : a1,i3,i5,i5,i5,1x,a3,a4,1x,f14.6,f12.6,f13.5,1x,f10.5,1x,a2,f13.5,f11.5,1x,i3,1x,f13.6,f12.6 + cc NZ N Z A el o mass unc binding unc B beta unc atomic_mass unc + Warnings : this format is not identical to that used in AME2016; + one more digit is added to the "BINDING ENERGY/A", "BETA-DECAY ENERGY" and "ATOMIC-MASS" values and their uncertainties; + # in a place of decimal point : estimated (non-experimental) value; + * in a place of value : the not calculable quantity + +....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+...10....+...11....+...12....+...13 + + + MASS LIST + for analysis + +1N-Z N Z A EL O MASS EXCESS BINDING ENERGY/A BETA-DECAY ENERGY ATOMIC MASS + (keV) (keV) (keV) (micro-u) +0 1 1 0 1 n 8071.31806 0.00044 0.0 0.0 B- 782.3470 0.0004 1 008664.91590 0.00047 + -1 0 1 1 H 7288.971064 0.000013 0.0 0.0 B- * 1 007825.031898 0.000014 +0 0 1 1 2 H 13135.722895 0.000015 1112.2831 0.0002 B- * 2 014101.777844 0.000015 +0 1 2 1 3 H 14949.81090 0.00008 2827.2654 0.0003 B- 18.59202 0.00006 3 016049.28132 0.00008 + -1 1 2 3 He 14931.21888 0.00006 2572.68044 0.00015 B- -13736# 2000# 3 016029.32197 0.00006 + -3 0 3 3 Li -pp 28667# 2000# -2267# 667# B- * 3 030775# 2147# +0 2 3 1 4 H -n 24621.129 100.000 1720.4491 25.0000 B- 22196.2131 100.0000 4 026431.867 107.354 + 0 2 2 4 He 2424.91587 0.00015 7073.9156 0.0002 B- -22898.2740 212.1320 4 002603.25413 0.00016 + -2 1 3 4 Li -p 25323.190 212.132 1153.7603 53.0330 B- * 4 027185.561 227.733 +0 3 4 1 5 H -nn 32892.447 89.443 1336.3592 17.8885 B- 21661.2131 91.6515 5 035311.492 96.020 + 1 3 2 5 He -n 11231.234 20.000 5512.1325 4.0000 B- -447.6529 53.8516 5 012057.224 21.470 + -1 2 3 5 Li -p 11678.887 50.000 5266.1325 10.0000 B- -25460# 2003# 5 012537.800 53.677 + -3 1 4 5 Be x 37139# 2003# 18# 401# B- * 5 039870# 2150# +0 4 5 1 6 H -3n 41875.725 254.127 961.6395 42.3545 B- 24283.6294 254.1268 6 044955.437 272.816 + 2 4 2 6 He 17592.095 0.053 4878.5199 0.0089 B- 3505.2147 0.0532 6 018885.889 0.057 + 0 3 3 6 Li 14086.88044 0.00144 5332.3312 0.0003 B- -4288.1534 5.4478 6 015122.88742 0.00155 + -2 2 4 6 Be - 18375.034 5.448 4487.2478 0.9080 B- -28945# 2003# 6 019726.409 5.848 + -4 1 5 6 B x 47320# 2003# -467# 334# B- * 6 050800# 2150# +0 5 6 1 7 H -nn 49135# 1004# 940# 143# B- 23062# 1004# 7 052749# 1078# + 3 5 2 7 He -n 26073.128 7.559 4123.0578 1.0799 B- 11166.0229 7.5595 7 027990.652 8.115 + 1 4 3 7 Li 14907.10463 0.00419 5606.4401 0.0006 B- -861.8930 0.0707 7 016003.43426 0.00450 + -1 3 4 7 Be 15768.998 0.071 5371.5487 0.0101 B- -11907.5551 25.1504 7 016928.714 0.076 + -3 2 5 7 B p4n 27676.553 25.150 3558.7055 3.5929 B- * 7 029712.000 27.000 +0 4 6 2 8 He 31609.683 0.089 3924.5210 0.0111 B- 10663.8784 0.1005 8 033934.388 0.095 + 2 5 3 8 Li 20945.805 0.047 5159.7124 0.0059 B- 16004.1329 0.0591 8 022486.244 0.050 + 0 4 4 8 Be -a 4941.672 0.035 7062.4356 0.0044 B- -17979.8973 1.0005 8 005305.102 0.037 + -2 3 5 8 B 22921.569 1.000 4717.1551 0.1250 B- -12142.7002 18.2704 8 024607.315 1.073 + -4 2 6 8 C 35064.269 18.243 3101.5242 2.2804 B- * 8 037643.039 19.584 +0 5 7 2 9 He 40935.826 46.816 3349.0380 5.2018 B- 15980.9213 46.8169 9 043946.414 50.259 + 3 6 3 9 Li -3n 24954.905 0.186 5037.7685 0.0207 B- 13606.4541 0.2014 9 026790.191 0.200 + 1 5 4 9 Be 11348.451 0.076 6462.6693 0.0085 B- -1068.0349 0.8994 9 012183.062 0.082 + -1 4 5 9 B - 12416.486 0.903 6257.0713 0.1003 B- -16494.4854 2.3195 9 013329.645 0.969 + -3 3 6 9 C -pp 28910.971 2.137 4337.4233 0.2374 B- * 9 031037.202 2.293 +0 6 8 2 10 He -nn 49197.147 92.848 2995.1340 9.2848 B- 16144.5191 93.7152 10 052815.306 99.676 + 4 7 3 10 Li -n 33052.628 12.721 4531.3512 1.2721 B- 20445.1411 12.7216 10 035483.453 13.656 + 2 6 4 10 Be 12607.487 0.081 6497.6306 0.0081 B- 556.8759 0.0822 10 013534.692 0.086 + 0 5 5 10 B 12050.611 0.015 6475.0835 0.0015 B- -3648.0623 0.0687 10 012936.862 0.016 + -2 4 6 10 C 15698.673 0.070 6032.0426 0.0070 B- -23101.3545 400.0000 10 016853.217 0.075 + -4 3 7 10 N -- 38800.027 400.000 3643.6724 40.0000 B- * 10 041653.540 429.417 +0 5 8 3 11 Li x 40728.259 0.615 4155.3817 0.0559 B- 20551.0898 0.6591 11 043723.581 0.660 + 3 7 4 11 Be 20177.169 0.238 5952.5402 0.0216 B- 11509.4607 0.2380 11 021661.080 0.255 + 1 6 5 11 B 8667.708 0.012 6927.7323 0.0011 B- -1981.6889 0.0608 11 009305.166 0.013 + -1 5 6 11 C 10649.397 0.060 6676.4563 0.0054 B- -13716.2469 5.0008 11 011432.597 0.064 + -3 4 7 11 N -p 24365.644 5.000 5358.4023 0.4546 B- -23373.2693 60.2459 11 026157.593 5.368 + -5 3 8 11 O -pp 47738.913 60.038 3162.4372 5.4580 B- * 11 051249.828 64.453 +0 6 9 3 12 Li -n 49009.577 30.006 3791.5999 2.5005 B- 23931.8152 30.0669 12 052613.942 32.213 + 4 8 4 12 Be 25077.761 1.909 5720.7223 0.1590 B- 11708.3636 2.3214 12 026922.082 2.048 + 2 7 5 12 B 13369.398 1.321 6631.2237 0.1101 B- 13369.3979 1.3214 12 014352.638 1.418 + 0 6 6 12 C 0.0 0.0 7680.1446 0.0002 B- -17338.0681 0.9999 12 000000.0 0.0 + -2 5 7 12 N 17338.068 1.000 6170.1100 0.0833 B- -14675.2668 12.0418 12 018613.180 1.073 + -4 4 8 12 O -pp 32013.335 12.000 4881.9755 1.0000 B- * 12 034367.726 12.882 +0 7 10 3 13 Li -nn 56980.895 70.003 3507.6307 5.3848 B- 23321.8152 70.7391 13 061171.503 75.150 + 5 9 4 13 Be -n 33659.080 10.180 5241.4359 0.7831 B- 17097.1315 10.2295 13 036134.506 10.929 + 3 8 5 13 B -nn 16561.948 1.000 6496.4194 0.0769 B- 13436.9387 1.0001 13 017779.981 1.073 + 1 7 6 13 C 3125.00933 0.00023 7469.8495 0.0002 B- -2220.4718 0.2695 13 003354.83534 0.00025 + -1 6 7 13 N -p 5345.481 0.270 7238.8634 0.0207 B- -17769.9506 9.5301 13 005738.609 0.289 + -3 5 8 13 O +3n 23115.432 9.526 5811.7636 0.7328 B- -18915# 500# 13 024815.435 10.226 + -5 4 9 13 F x 42030# 500# 4297# 38# B- * 13 045121# 537# +0 6 10 4 14 Be x 39954.502 132.245 4993.8973 9.4461 B- 16290.8166 133.9357 14 042892.920 141.970 + 4 9 5 14 B 23663.686 21.213 6101.6451 1.5152 B- 20643.7926 21.2133 14 025404.010 22.773 + 2 8 6 14 C 3019.89328 0.00375 7520.3198 0.0004 B- 156.4765 0.0037 14 003241.98862 0.00403 + 0 7 7 14 N 2863.41683 0.00022 7475.6148 0.0002 B- -5144.3643 0.0252 14 003074.00425 0.00024 + -2 6 8 14 O 8007.781 0.025 7052.2783 0.0018 B- -23956.6215 41.1187 14 008596.706 0.027 + -4 5 9 14 F -p 31964.403 41.119 5285.2091 2.9371 B- * 14 034315.196 44.142 +0 7 11 4 15 Be -n 49825.821 165.797 4540.9708 11.0532 B- 20868.4411 167.1256 15 053490.215 177.990 + 5 10 5 15 B 28957.379 21.029 5880.0438 1.4019 B- 19084.2343 21.0442 15 031087.023 22.575 + 3 9 6 15 C -n 9873.145 0.800 7100.1696 0.0533 B- 9771.7071 0.8000 15 010599.256 0.858 + 1 8 7 15 N 101.43809 0.00058 7699.4603 0.0002 B- -2754.1841 0.4902 15 000108.89827 0.00062 + -1 7 8 15 O 2855.622 0.490 7463.6915 0.0327 B- -13711.1300 14.0086 15 003065.636 0.526 + -3 6 9 15 F -p 16566.752 14.000 6497.4597 0.9333 B- -23648.6215 68.1377 15 017785.139 15.029 + -5 5 10 15 Ne -pp 40215.374 66.684 4868.7285 4.4456 B- * 15 043172.977 71.588 +0 8 12 4 16 Be -nn 57447.139 165.797 4285.2851 10.3623 B- 20335.4399 167.6075 16 061672.036 177.990 + 6 11 5 16 B 37111.699 24.566 5507.3535 1.5354 B- 23417.5656 24.8254 16 039841.045 26.373 + 4 10 6 16 C -nn 13694.133 3.578 6922.0546 0.2236 B- 8010.2260 4.2540 16 014701.255 3.840 + 2 9 7 16 N -n 5683.907 2.301 7373.7971 0.1438 B- 10420.9094 2.3014 16 006101.925 2.470 + 0 8 8 16 O -4737.00217 0.00030 7976.2072 0.0002 B- -15412.1840 5.3642 15 994914.61926 0.00032 + -2 7 9 16 F 10675.182 5.364 6964.0490 0.3353 B- -13311.5932 21.1709 16 011460.278 5.758 + -4 6 10 16 Ne -- 23986.775 20.480 6083.1777 1.2800 B- * 16 025750.860 21.986 +0 7 12 5 17 B x 43716.322 204.104 5269.6677 12.0061 B- 22684.4422 204.8410 17 046931.399 219.114 + 5 11 6 17 C 2p-n 21031.880 17.365 6558.0262 1.0215 B- 13161.8007 22.9464 17 022578.650 18.641 + 3 10 7 17 N +p 7870.079 15.000 7286.2294 0.8824 B- 8678.8430 15.0000 17 008448.876 16.103 + 1 9 8 17 O -808.76421 0.00064 7750.7291 0.0002 B- -2760.4655 0.2479 16 999131.75595 0.00069 + -1 8 9 17 F 1951.701 0.248 7542.3284 0.0146 B- -14548.7507 0.4323 17 002095.237 0.266 + -3 7 10 17 Ne 16500.452 0.354 6640.4991 0.0208 B- -18219.1277 59.6167 17 017713.962 0.380 + -5 6 11 17 Na x 34719.580 59.616 5522.7653 3.5068 B- * 17 037273.000 64.000 +0 8 13 5 18 B -n 51792.640 204.165 4976.6306 11.3425 B- 26873.3742 206.3572 18 055601.683 219.180 + 6 12 6 18 C ++ 24919.266 30.000 6426.1321 1.6667 B- 11806.0982 35.2821 18 026751.930 32.206 + 4 11 7 18 N + 13113.167 18.570 7038.5627 1.0316 B- 13895.9838 18.5695 18 014077.563 19.935 + 2 10 8 18 O -782.81634 0.00064 7767.0981 0.0002 B- -1655.9288 0.4633 17 999159.61214 0.00069 + 0 9 9 18 F 873.112 0.463 7631.6383 0.0257 B- -4444.5049 0.5888 18 000937.324 0.497 + -2 8 10 18 Ne 5317.617 0.363 7341.2577 0.0202 B- -19720.3745 93.8819 18 005708.696 0.390 + -4 7 11 18 Na 25037.992 93.881 6202.2176 5.2156 B- * 18 026879.388 100.785 +0 9 14 5 19 B x 59770.251 525.363 4719.6346 27.6507 B- 27356.4961 534.4964 19 064166.000 564.000 + 7 13 6 19 C -n 32413.754 98.389 6118.2740 5.1784 B- 16557.4995 99.7475 19 034797.594 105.625 + 5 12 7 19 N p-2n 15856.255 16.404 6948.5452 0.8634 B- 12523.3972 16.6143 19 017022.389 17.610 + 3 11 8 19 O -n 3332.858 2.637 7566.4952 0.1388 B- 4820.3029 2.6370 19 003577.969 2.830 + 1 10 9 19 F -1487.44512 0.00082 7779.0192 0.0002 B- -3239.4986 0.1601 18 998403.16207 0.00088 + -1 9 10 19 Ne +3n 1752.054 0.160 7567.3431 0.0084 B- -11177.3310 10.5364 19 001880.906 0.171 + -3 8 11 19 Na 12929.384 10.535 6937.8864 0.5545 B- -18909.0095 60.9189 19 013880.264 11.309 + -5 7 12 19 Mg -pp 31838.394 60.001 5901.4992 3.1579 B- * 19 034179.920 64.413 +0 10 15 5 20 B -n 69401.569 546.357 4405.6529 27.3178 B- 31898.0019 593.0377 20 074505.644 586.538 + 8 14 6 20 C x 37503.567 230.625 5961.4356 11.5312 B- 15737.0689 243.7459 20 040261.732 247.585 + 6 13 7 20 N x 21766.498 78.894 6709.1717 3.9447 B- 17970.3261 78.8991 20 023367.295 84.696 + 4 12 8 20 O -nn 3796.172 0.885 7568.5707 0.0442 B- 3813.6349 0.8854 20 004075.357 0.950 + 2 11 9 20 F -n -17.463 0.030 7720.1351 0.0015 B- 7024.4689 0.0297 19 999981.252 0.031 + 0 10 10 20 Ne -7041.93217 0.00154 8032.2412 0.0002 B- -13892.4207 1.1090 19 992440.17525 0.00165 + -2 9 11 20 Na 6850.489 1.109 7298.5028 0.0554 B- -10627.2054 2.1681 20 007354.301 1.190 + -4 8 12 20 Mg +t 17477.694 1.863 6728.0252 0.0931 B- * 20 018763.075 2.000 +0 11 16 5 21 B -nn 78382.887 558.664 4152.5265 26.6031 B- 32740# 817# 21 084147.485 599.750 + 9 15 6 21 C x 45643# 596# 5674# 28# B- 20411# 611# 21 049000# 640# + 7 14 7 21 N x 25231.915 134.048 6609.0159 6.3832 B- 17169.8816 134.5840 21 027087.573 143.906 + 5 13 8 21 O -3n 8062.034 12.000 7389.3747 0.5714 B- 8109.6390 12.1342 21 008654.948 12.882 + 3 12 9 21 F -nn -47.605 1.800 7738.2934 0.0857 B- 5684.1712 1.8004 20 999948.893 1.932 + 1 11 10 21 Ne -5731.776 0.038 7971.7136 0.0018 B- -3546.9190 0.0177 20 993846.685 0.041 + -1 10 11 21 Na -2184.857 0.042 7765.5581 0.0020 B- -13088.7080 0.7557 20 997654.459 0.045 + -3 9 12 21 Mg x 10903.851 0.755 7105.0317 0.0359 B- -16186# 600# 21 011705.764 0.810 + -5 8 13 21 Al x 27090# 600# 6297# 29# B- * 21 029082# 644# +0 10 16 6 22 C -nn 53611.203 231.490 5421.0778 10.5223 B- 21846.3983 311.0627 22 057553.990 248.515 + 8 15 7 22 N x 31764.805 207.779 6378.5347 9.4445 B- 22481.7725 215.4350 22 034100.918 223.060 + 6 14 8 22 O -4n 9283.032 56.921 7364.8722 2.5873 B- 6489.6562 58.2558 22 009965.744 61.107 + 4 13 9 22 F + 2793.376 12.399 7624.2954 0.5636 B- 10818.0916 12.3990 22 002998.812 13.310 + 2 12 10 22 Ne -8024.716 0.018 8080.4656 0.0008 B- -2843.3243 0.1325 21 991385.113 0.018 + 0 11 11 22 Na -5181.391 0.132 7915.6624 0.0060 B- -4781.4051 0.1631 21 994437.547 0.141 + -2 10 12 22 Mg -399.986 0.159 7662.7645 0.0072 B- -18601# 401# 21 999570.597 0.170 + -4 9 13 22 Al x 18201# 401# 6782# 18# B- -15439# 641# 22 019540# 430# + -6 8 14 22 Si x 33640# 500# 6044# 23# B- * 22 036114# 537# +0 11 17 6 23 C x 64171# 997# 5077# 43# B- 27450# 1082# 23 068890# 1070# + 9 16 7 23 N x 36720.429 420.570 6236.6721 18.2856 B- 22099.0584 437.8271 23 039421.000 451.500 + 7 15 8 23 O x 14621.371 121.712 7163.4856 5.2918 B- 11336.1072 126.1904 23 015696.686 130.663 + 5 14 9 23 F 3285.263 33.320 7622.3447 1.4487 B- 8439.3084 33.3206 23 003526.875 35.770 + 3 13 10 23 Ne -n -5154.045 0.104 7955.2561 0.0045 B- 4375.8085 0.1044 22 994466.905 0.112 + 1 12 11 23 Na -9529.85352 0.00181 8111.4936 0.0002 B- -4056.1790 0.0317 22 989769.28195 0.00194 + -1 11 12 23 Mg - -5473.675 0.032 7901.1229 0.0014 B- -12221.7457 0.3461 22 994123.768 0.034 + -3 10 13 23 Al -- 6748.071 0.345 7335.7275 0.0150 B- -17202# 500# 23 007244.351 0.370 + -5 9 14 23 Si x 23950# 500# 6554# 22# B- * 23 025711# 537# +0 10 17 7 24 N x 46938# 401# 5887# 17# B- 28438# 433# 24 050390# 430# + 8 16 8 24 O x 18500.404 164.874 7039.6855 6.8698 B- 10955.8885 191.6327 24 019861.000 177.000 + 6 15 9 24 F x 7544.516 97.670 7463.5831 4.0696 B- 13496.1583 97.6717 24 008099.370 104.853 + 4 14 10 24 Ne -nn -5951.642 0.513 7993.3252 0.0214 B- 2466.2583 0.5130 23 993610.649 0.550 + 2 13 11 24 Na -n -8417.901 0.017 8063.4882 0.0007 B- 5515.6774 0.0210 23 990963.012 0.017 + 0 12 12 24 Mg -13933.578 0.013 8260.7103 0.0006 B- -13884.7660 0.2282 23 985041.689 0.013 + -2 11 13 24 Al -48.812 0.228 7649.5806 0.0095 B- -10793.9978 19.4734 23 999947.598 0.244 + -4 10 14 24 Si -- 10745.186 19.472 7167.2329 0.8113 B- -23275# 501# 24 011535.430 20.904 + -6 9 15 24 P x 34020# 500# 6165# 21# B- * 24 036522# 537# +0 11 18 7 25 N x 55983# 503# 5613# 20# B- 28654# 529# 25 060100# 540# + 9 17 8 25 O -n 27329.030 165.084 6727.8058 6.6034 B- 15994.8633 191.1909 25 029338.919 177.225 + 7 16 9 25 F x 11334.167 96.442 7336.3065 3.8577 B- 13369.6698 100.7212 25 012167.727 103.535 + 5 15 10 25 Ne -2035.503 29.045 7839.7994 1.1618 B- 7322.3107 29.0701 24 997814.797 31.181 + 3 14 11 25 Na -nn -9357.814 1.200 8101.3979 0.0480 B- 3834.9684 1.2009 24 989953.974 1.288 + 1 13 12 25 Mg -13192.782 0.047 8223.5028 0.0019 B- -4276.8080 0.0447 24 985836.966 0.050 + -1 12 13 25 Al -8915.974 0.065 8021.1366 0.0026 B- -12743.2956 10.0002 24 990428.308 0.069 + -3 11 14 25 Si +3n 3827.322 10.000 7480.1109 0.4000 B- -16363# 400# 25 004108.798 10.735 + -5 10 15 25 P x 20190# 400# 6794# 16# B- * 25 021675# 429# +0 10 18 8 26 O -nn 34661.041 164.950 6497.4790 6.3442 B- 15986.3855 196.6301 26 037210.155 177.081 + 8 17 9 26 F 18674.655 107.027 7082.2497 4.1164 B- 18193.5414 108.6022 26 020048.065 114.898 + 6 16 10 26 Ne x 481.114 18.429 7751.9110 0.7088 B- 7341.8940 18.7585 26 000516.496 19.784 + 4 15 11 26 Na x -6860.780 3.502 8004.2013 0.1347 B- 9353.7631 3.5018 25 992634.649 3.759 + 2 14 12 26 Mg -16214.544 0.029 8333.8711 0.0011 B- -4004.4042 0.0629 25 982592.972 0.031 + 0 13 13 26 Al -12210.139 0.066 8149.7653 0.0026 B- -5069.1361 0.0849 25 986891.876 0.071 + -2 12 14 26 Si - -7141.003 0.108 7924.7083 0.0041 B- -18114# 196# 25 992333.818 0.115 + -4 11 15 26 P x 10973# 196# 7198# 8# B- -16707# 631# 26 011780# 210# + -6 10 16 26 S x 27680# 600# 6525# 23# B- * 26 029716# 644# +0 11 19 8 27 O x 44670# 500# 6185# 19# B- 19536# 514# 27 047955# 537# + 9 18 9 27 F 25133.478 120.198 6879.6662 4.4518 B- 18082.5680 150.6211 27 026981.897 129.037 + 7 17 10 27 Ne x 7050.910 90.770 7520.4151 3.3619 B- 12568.7005 90.8467 27 007569.462 97.445 + 5 16 11 27 Na ++ -5517.791 3.726 7956.9467 0.1380 B- 9068.8037 3.7266 26 994076.408 4.000 + 3 15 12 27 Mg -14586.594 0.047 8263.8525 0.0018 B- 2610.2694 0.0669 26 984340.647 0.050 + 1 14 13 27 Al -17196.864 0.047 8331.5533 0.0018 B- -4812.3583 0.0964 26 981538.408 0.050 + -1 13 14 27 Si - -12384.505 0.107 8124.3420 0.0040 B- -11725.4730 9.0013 26 986704.687 0.115 + -3 12 15 27 P -p -659.032 9.001 7661.0894 0.3334 B- -18150# 400# 26 999292.499 9.662 + -5 11 16 27 S - 17491# 400# 6960# 15# B- * 27 018777# 430# +0 12 20 8 28 O x 52080# 699# 5988# 25# B- 18676# 709# 28 055910# 750# + 10 19 9 28 F -n 33403.796 120.347 6626.8567 4.2981 B- 22104.0579 174.2886 28 035860.448 129.198 + 8 18 10 28 Ne x 11299.738 126.068 7388.3463 4.5024 B- 12288.0534 126.4833 28 012130.767 135.339 + 6 17 11 28 Na x -988.315 10.246 7799.2644 0.3659 B- 14031.6303 10.2498 27 998939.000 11.000 + 4 16 12 28 Mg x -15019.946 0.261 8272.4531 0.0093 B- 1830.7740 0.2653 27 983875.426 0.280 + 2 15 13 28 Al -n -16850.719 0.049 8309.8969 0.0018 B- 4642.0776 0.0486 27 981910.009 0.052 + 0 14 14 28 Si -21492.79711 0.00051 8447.7445 0.0002 B- -14344.9407 1.1473 27 976926.53442 0.00055 + -2 13 15 28 P -7147.856 1.147 7907.4842 0.0410 B- -11221.0593 160.0041 27 992326.460 1.231 + -4 12 16 28 S -- 4073.203 160.000 7478.7911 5.7143 B- -24197# 525# 28 004372.762 171.767 + -6 11 17 28 Cl -p 28270# 500# 6587# 18# B- * 28 030349# 537# +0 11 20 9 29 F x 40150.190 525.363 6444.0314 18.1160 B- 21750.3873 546.2212 29 043103.000 564.000 + 9 19 10 29 Ne x 18399.803 149.505 7167.0673 5.1553 B- 15719.8092 149.6847 29 019753.000 160.500 + 7 18 11 29 Na 2679.994 7.337 7682.1522 0.2530 B- 13292.3538 7.3447 29 002877.091 7.876 + 5 17 12 29 Mg -10612.360 0.345 8113.5317 0.0119 B- 7595.4023 0.4873 28 988607.163 0.369 + 3 16 13 29 Al x -18207.762 0.345 8348.4647 0.0119 B- 3687.3192 0.3447 28 980453.164 0.370 + 1 15 14 29 Si -21895.08154 0.00056 8448.6361 0.0002 B- -4942.2325 0.3589 28 976494.66434 0.00060 + -1 14 15 29 P -16952.849 0.359 8251.2368 0.0124 B- -13858.4257 13.0459 28 981800.368 0.385 + -3 13 16 29 S x -3094.423 13.041 7746.3826 0.4497 B- -17117# 189# 28 996678.000 14.000 + -5 12 17 29 Cl -p 14022# 189# 7129# 7# B- -23947# 478# 29 015053# 203# + -7 11 18 29 Ar -pp 37969# 439# 6276# 15# B- * 29 040761# 471# +0 12 21 9 30 F x 48960# 500# 6205# 17# B- 25680# 561# 30 052561# 537# + 10 20 10 30 Ne 23280.120 253.250 7034.5317 8.4417 B- 14805.4501 253.2946 30 024992.235 271.875 + 8 19 11 30 Na 8474.670 4.727 7501.9685 0.1576 B- 17356.0423 4.9011 30 009097.931 5.074 + 6 18 12 30 Mg -8881.373 1.295 8054.4250 0.0432 B- 6982.7440 2.3287 29 990465.454 1.390 + 4 17 13 30 Al -15864.116 1.936 8261.1049 0.0645 B- 8568.8459 1.9357 29 982969.171 2.077 + 2 16 14 30 Si -n -24432.962 0.022 8520.6549 0.0008 B- -4232.1065 0.0615 29 973770.137 0.023 + 0 15 15 30 P - -20200.856 0.065 8353.5064 0.0022 B- -6141.6014 0.1956 29 978313.490 0.069 + -2 14 16 30 S - -14059.254 0.206 8122.7081 0.0069 B- -18733.8020 23.8769 29 984906.770 0.221 + -4 13 17 30 Cl -p 4674.548 23.876 7472.1698 0.7959 B- -17397# 180# 30 005018.333 25.631 + -6 12 18 30 Ar -pp 22071# 179# 6866# 6# B- * 30 023694# 192# +0 13 22 9 31 F -nn 56843# 535# 6011# 17# B- 25661# 597# 31 061023# 574# + 11 21 10 31 Ne 31181.594 266.195 6813.0902 8.5869 B- 18935.5625 266.5617 31 033474.816 285.772 + 9 20 11 31 Na x 12246.031 13.972 7398.6778 0.4507 B- 15368.1833 14.3065 31 013146.654 15.000 + 7 19 12 31 Mg x -3122.152 3.074 7869.1886 0.0992 B- 11828.5569 3.8009 30 996648.232 3.300 + 5 18 13 31 Al x -14950.709 2.236 8225.5180 0.0721 B- 7998.3286 2.2360 30 983949.754 2.400 + 3 17 14 31 Si -n -22949.037 0.043 8458.2916 0.0014 B- 1491.5071 0.0434 30 975363.196 0.046 + 1 16 15 31 P -24440.54442 0.00075 8481.1677 0.0002 B- -5398.0130 0.2292 30 973761.99768 0.00080 + -1 15 16 31 S -19042.531 0.229 8281.8013 0.0074 B- -12007.9790 3.4541 30 979557.002 0.246 + -3 14 17 31 Cl -- -7034.552 3.447 7869.2101 0.1112 B- -18360# 200# 30 992448.097 3.700 + -5 13 18 31 Ar - 11325# 200# 7252# 6# B- -22935# 361# 31 012158# 215# + -7 12 19 31 K x 34260# 300# 6487# 10# B- * 31 036780# 322# +0 12 22 10 32 Ne x 36999# 503# 6671# 16# B- 18359# 504# 32 039720# 540# + 10 21 11 32 Na x 18640.152 37.260 7219.8815 1.1644 B- 19469.0523 37.4021 32 020011.024 40.000 + 8 20 12 32 Mg x -828.901 3.260 7803.8411 0.1019 B- 10270.4677 7.8787 31 999110.138 3.500 + 6 19 13 32 Al x -11099.368 7.173 8100.3449 0.2241 B- 12978.3208 7.1787 31 988084.338 7.700 + 4 18 14 32 Si x -24077.689 0.298 8481.4690 0.0093 B- 227.1872 0.3008 31 974151.538 0.320 + 2 17 15 32 P -n -24304.876 0.040 8464.1203 0.0013 B- 1710.6608 0.0400 31 973907.643 0.042 + 0 16 16 32 S -26015.53714 0.00131 8493.1301 0.0002 B- -12680.8313 0.5617 31 972071.17354 0.00141 + -2 15 17 32 Cl -13334.706 0.562 8072.4058 0.0176 B- -11134.3536 1.8568 31 985684.605 0.603 + -4 14 18 32 Ar x -2200.352 1.770 7700.0089 0.0553 B- -24190# 400# 31 997637.824 1.900 + -6 13 19 32 K x 21990# 400# 6920# 12# B- * 32 023607# 429# +0 13 23 10 33 Ne x 46130# 600# 6436# 18# B- 22350# 750# 33 049523# 644# + 11 22 11 33 Na x 23780.113 449.912 7089.9262 13.6337 B- 18817.2400 449.9195 33 025529.000 483.000 + 9 21 12 33 Mg 4962.873 2.663 7636.4382 0.0807 B- 13460.2550 7.4767 33 005327.862 2.859 + 7 20 13 33 Al x -8497.382 6.986 8020.6172 0.2117 B- 12016.9460 7.0211 32 990877.685 7.500 + 5 19 14 33 Si x -20514.328 0.699 8361.0596 0.0212 B- 5823.0223 1.2947 32 977976.964 0.750 + 3 18 15 33 P + -26337.350 1.090 8513.8073 0.0330 B- 248.5079 1.0900 32 971725.692 1.170 + 1 17 16 33 S -26585.85830 0.00134 8497.6304 0.0002 B- -5582.5182 0.3908 32 971458.90862 0.00144 + -1 16 17 33 Cl -21003.340 0.391 8304.7557 0.0118 B- -11619.0452 0.5596 32 977451.988 0.419 + -3 15 18 33 Ar x -9384.295 0.401 7928.9559 0.0121 B- -16925# 200# 32 989925.545 0.430 + -5 14 19 33 K x 7540# 200# 7392# 6# B- -23489# 447# 33 008095# 215# + -7 13 20 33 Ca x 31030# 400# 6657# 12# B- * 33 033312# 429# +0 14 24 10 34 Ne -nn 52842# 513# 6287# 15# B- 21161# 789# 34 056728# 551# + 12 23 11 34 Na x 31680.114 599.416 6886.4377 17.6299 B- 23356.7903 599.4561 34 034010.000 643.500 + 10 22 12 34 Mg x 8323.324 6.893 7550.3919 0.2027 B- 11320.9428 7.2072 34 008935.455 7.400 + 8 21 13 34 Al x -2997.619 2.105 7860.3506 0.0619 B- 16994.0653 2.2519 33 996781.924 2.259 + 6 20 14 34 Si x -19991.684 0.801 8337.1659 0.0236 B- 4557.0175 1.1395 33 978538.045 0.860 + 4 19 15 34 P x -24548.702 0.810 8448.1856 0.0238 B- 5382.9879 0.8116 33 973645.886 0.870 + 2 18 16 34 S -29931.689 0.045 8583.4986 0.0013 B- -5491.6037 0.0378 33 967867.011 0.047 + 0 17 17 34 Cl -24440.086 0.049 8398.9706 0.0014 B- -6061.7930 0.0631 33 973762.490 0.052 + -2 16 18 34 Ar -18378.293 0.078 8197.6724 0.0023 B- -17158# 196# 33 980270.092 0.083 + -4 15 19 34 K x -1220# 196# 7670# 6# B- -16110# 358# 33 998690# 210# + -6 14 20 34 Ca x 14890# 300# 7173# 9# B- * 34 015985# 322# +0 13 24 11 35 Na -n 37831# 670# 6745# 19# B- 22192# 723# 35 040614# 720# + 11 23 12 35 Mg x 15639.786 269.668 7356.2338 7.7048 B- 15863.5156 269.7679 35 016790.000 289.500 + 9 22 13 35 Al x -223.730 7.359 7787.1243 0.2103 B- 14167.7504 36.6047 34 999759.816 7.900 + 7 21 14 35 Si 2p-n -14391.480 35.857 8169.5644 1.0245 B- 10466.3291 35.9049 34 984550.111 38.494 + 5 20 15 35 P +p -24857.809 1.866 8446.2496 0.0533 B- 3988.4006 1.8667 34 973314.045 2.003 + 3 19 16 35 S -28846.210 0.040 8537.8511 0.0012 B- 167.3218 0.0257 34 969032.321 0.043 + 1 18 17 35 Cl -29013.532 0.035 8520.2790 0.0010 B- -5966.2429 0.6794 34 968852.694 0.038 + -1 17 18 35 Ar - -23047.289 0.680 8327.4621 0.0194 B- -11874.3955 0.8516 34 975257.719 0.730 + -3 16 19 35 K 4n -11172.893 0.512 7965.8409 0.0146 B- -16363# 200# 34 988005.406 0.550 + -5 15 20 35 Ca x 5190# 200# 7476# 6# B- -21910# 447# 35 005572# 215# + -7 14 21 35 Sc x 27100# 400# 6828# 11# B- * 35 029093# 429# +0 14 25 11 36 Na -n 45903# 687# 6557# 19# B- 25523# 974# 36 049279# 737# + 12 24 12 36 Mg x 20380.159 690.237 7244.4202 19.1733 B- 14429.7751 706.2429 36 021879.000 741.000 + 10 23 13 36 Al x 5950.384 149.505 7623.5154 4.1529 B- 18386.5096 165.8510 36 006388.000 160.500 + 8 22 14 36 Si x -12436.125 71.797 8112.5199 1.9944 B- 7814.9194 72.9852 35 986649.271 77.077 + 6 21 15 36 P + -20251.045 13.114 8307.8692 0.3643 B- 10413.0962 13.1124 35 978259.610 14.078 + 4 20 16 36 S -30664.141 0.188 8575.3900 0.0052 B- -1142.1329 0.1893 35 967080.692 0.201 + 2 19 17 36 Cl -29522.008 0.036 8521.9322 0.0010 B- 709.5343 0.0449 35 968306.822 0.038 + 0 18 18 36 Ar -30231.542 0.027 8519.9096 0.0008 B- -12814.3607 0.3259 35 967545.106 0.028 + -2 17 19 36 K -17417.182 0.325 8142.2233 0.0090 B- -10966.0155 40.0013 35 981301.887 0.349 + -4 16 20 36 Ca 4n -6451.166 40.000 7815.8799 1.1111 B- -22601# 303# 35 993074.388 42.941 + -6 15 21 36 Sc x 16150# 300# 7166# 8# B- * 36 017338# 322# +0 15 26 11 37 Na -nn 53134# 687# 6403# 19# B- 24923# 980# 37 057042# 737# + 13 25 12 37 Mg -n 28211.478 698.947 7055.1115 18.8905 B- 18401.9132 721.8139 37 030286.265 750.350 + 11 24 13 37 Al x 9809.564 180.244 7531.3160 4.8715 B- 16381.0765 213.1678 37 010531.000 193.500 + 9 23 14 37 Si x -6571.512 113.809 7952.9033 3.0759 B- 12424.5003 119.9691 36 992945.191 122.179 + 7 22 15 37 P p-2n -18996.012 37.948 8267.5561 1.0256 B- 7900.4135 37.9474 36 979606.942 40.738 + 5 21 16 37 S -n -26896.426 0.198 8459.9363 0.0054 B- 4865.1258 0.1965 36 971125.500 0.212 + 3 20 17 37 Cl -31761.552 0.052 8570.2816 0.0014 B- -813.8729 0.2000 36 965902.573 0.055 + 1 19 18 37 Ar - -30947.679 0.207 8527.1406 0.0056 B- -6147.4775 0.2270 36 966776.301 0.221 + -1 18 19 37 K -p -24800.201 0.094 8339.8480 0.0025 B- -11664.1314 0.6412 36 973375.890 0.100 + -3 17 20 37 Ca x -13136.070 0.634 8003.4567 0.0171 B- -16916# 300# 36 985897.849 0.680 + -5 16 21 37 Sc x 3780# 300# 7525# 8# B- -21390# 500# 37 004058# 322# + -7 15 22 37 Ti x 25170# 400# 6926# 11# B- * 37 027021# 429# +0 16 27 11 38 Na -n 61905# 715# 6216# 19# B- 27831# 875# 38 066458# 768# + 14 26 12 38 Mg x 34074# 503# 6928# 13# B- 17604# 525# 38 036580# 540# + 12 25 13 38 Al x 16470# 150# 7370# 4# B- 20640# 183# 38 017681# 161# + 10 24 14 38 Si x -4170.299 104.793 7892.8297 2.7577 B- 10451.2656 127.4736 37 995523.000 112.500 + 8 23 15 38 P x -14621.565 72.581 8147.2749 1.9100 B- 12239.6512 72.9340 37 984303.105 77.918 + 6 22 16 38 S + -26861.216 7.172 8448.7829 0.1887 B- 2936.9000 7.1714 37 971163.300 7.699 + 4 21 17 38 Cl -n -29798.116 0.098 8505.4817 0.0026 B- 4916.7109 0.2182 37 968010.408 0.105 + 2 20 18 38 Ar -34714.827 0.195 8614.2807 0.0051 B- -5914.0671 0.0448 37 962732.102 0.209 + 0 19 19 38 K -28800.760 0.195 8438.0593 0.0051 B- -6742.2563 0.0626 37 969081.114 0.209 + -2 18 20 38 Ca -22058.503 0.194 8240.0434 0.0051 B- -17809# 200# 37 976319.223 0.208 + -4 17 21 38 Sc x -4249# 200# 7751# 5# B- -15619# 361# 37 995438# 215# + -6 16 22 38 Ti x 11370# 300# 7319# 8# B- * 38 012206# 322# +0 17 28 11 39 Na -n 69977# 743# 6056# 19# B- 27201# 903# 39 075123# 797# + 15 27 12 39 Mg -n 42775# 513# 6734# 13# B- 21286# 594# 39 045921# 551# + 13 26 13 39 Al x 21490# 300# 7260# 8# B- 19169# 329# 39 023070# 322# + 11 25 14 39 Si x 2320.352 135.532 7730.9793 3.4752 B- 15094.9874 176.2324 39 002491.000 145.500 + 9 24 15 39 P x -12774.636 112.645 8097.9701 2.8883 B- 10388.0361 123.2430 38 986285.865 120.929 + 7 23 16 39 S 2p-n -23162.672 50.000 8344.2698 1.2821 B- 6637.5463 50.0300 38 975133.850 53.677 + 5 22 17 39 Cl -nn -29800.218 1.732 8494.4032 0.0444 B- 3441.9774 5.2915 38 968008.151 1.859 + 3 21 18 39 Ar + -33242.195 5.000 8562.5988 0.1282 B- 565.0000 5.0000 38 964313.037 5.367 + 1 20 19 39 K -33807.19535 0.00456 8557.0258 0.0003 B- -6524.4888 0.5962 38 963706.48482 0.00489 + -1 19 20 39 Ca -27282.707 0.596 8369.6711 0.0153 B- -13109.9804 24.0074 38 970710.811 0.640 + -3 18 21 39 Sc 2n-p -14172.726 24.000 8013.4575 0.6154 B- -16673# 202# 38 984784.953 25.765 + -5 17 22 39 Ti x 2500# 200# 7566# 5# B- -20070# 447# 39 002684# 215# + -7 16 23 39 V x 22570# 400# 7031# 10# B- * 39 024230# 429# +0 16 28 12 40 Mg x 49550# 500# 6598# 13# B- 20729# 583# 40 053194# 537# + 14 27 13 40 Al x 28820# 300# 7097# 7# B- 23154# 324# 40 030940# 322# + 12 26 14 40 Si x 5666.876 121.991 7655.8247 3.0498 B- 13806.0653 147.8912 40 006083.641 130.962 + 10 25 15 40 P x -8139.189 83.607 7981.4177 2.0902 B- 14698.6603 83.7017 39 991262.221 89.755 + 8 24 16 40 S -22837.850 3.982 8329.3255 0.0996 B- 4719.9687 32.3118 39 975482.561 4.274 + 6 23 17 40 Cl + -27557.818 32.066 8427.7660 0.8016 B- 7482.0816 32.0655 39 970415.466 34.423 + 4 22 18 40 Ar -35039.89997 0.00218 8595.2594 0.0002 B- -1504.4031 0.0559 39 962383.12204 0.00234 + 2 21 19 40 K -33535.497 0.056 8538.0907 0.0014 B- 1310.9051 0.0596 39 963998.165 0.060 + 0 20 20 40 Ca -34846.402 0.020 8551.3046 0.0006 B- -14323.0493 2.8281 39 962590.850 0.022 + -2 19 21 40 Sc - -20523.353 2.828 8173.6697 0.0707 B- -11529.9139 68.3023 39 977967.275 3.036 + -4 18 22 40 Ti -8993.439 68.244 7865.8632 1.7061 B- -21463# 308# 39 990345.146 73.262 + -6 17 23 40 V x 12470# 300# 7310# 7# B- * 40 013387# 322# +0 17 29 12 41 Mg x 58100# 500# 6425# 12# B- 23510# 640# 41 062373# 537# + 15 28 13 41 Al x 34590# 400# 6980# 10# B- 21390# 500# 41 037134# 429# + 13 27 14 41 Si x 13200# 300# 7482# 7# B- 18180# 323# 41 014171# 322# + 11 26 15 41 P x -4979.767 120.163 7906.5513 2.9308 B- 14028.8125 120.2326 40 994654.000 129.000 + 9 25 16 41 S x -19008.580 4.099 8229.6358 0.1000 B- 8298.6116 68.8456 40 979593.451 4.400 + 7 24 17 41 Cl x -27307.192 68.723 8412.9593 1.6762 B- 5760.3180 68.7243 40 970684.525 73.777 + 5 23 18 41 Ar -n -33067.510 0.347 8534.3733 0.0085 B- 2492.0392 0.3473 40 964500.570 0.372 + 3 22 19 41 K -35559.54880 0.00376 8576.0731 0.0003 B- -421.6406 0.1377 40 961825.25611 0.00403 + 1 21 20 41 Ca -35137.908 0.138 8546.7075 0.0034 B- -6495.5482 0.1553 40 962277.905 0.147 + -1 20 21 41 Sc -28642.360 0.077 8369.1979 0.0019 B- -12944.8214 27.9449 40 969251.163 0.083 + -3 19 22 41 Ti x -15697.539 27.945 8034.3889 0.6816 B- -16008# 202# 40 983148.000 30.000 + -5 18 23 41 V x 310# 200# 7625# 5# B- -20100# 447# 41 000333# 215# + -7 17 24 41 Cr x 20410# 400# 7116# 10# B- * 41 021911# 429# +0 16 29 13 42 Al x 41990# 500# 6829# 12# B- 25150# 583# 42 045078# 537# + 14 28 14 42 Si x 16840# 300# 7410# 7# B- 15748# 315# 42 018078# 322# + 12 27 15 42 P x 1091.842 95.009 7765.9122 2.2621 B- 18729.5899 95.0504 42 001172.140 101.996 + 10 26 16 42 S x -17637.748 2.794 8193.2275 0.0665 B- 7194.0221 59.6811 41 981065.100 3.000 + 8 25 17 42 Cl x -24831.770 59.616 8345.8864 1.4194 B- 9590.9082 59.8947 41 973342.000 64.000 + 6 24 18 42 Ar x -34422.678 5.775 8555.6141 0.1375 B- 599.3527 5.7763 41 963045.737 6.200 + 4 23 19 42 K -n -35022.031 0.106 8551.2571 0.0025 B- 3525.2626 0.1825 41 962402.305 0.113 + 2 22 20 42 Ca -38547.293 0.148 8616.5646 0.0035 B- -6426.2904 0.0485 41 958617.780 0.159 + 0 21 21 42 Sc -32121.003 0.154 8444.9303 0.0037 B- -7016.6496 0.2239 41 965516.686 0.165 + -2 20 22 42 Ti -25104.353 0.269 8259.2400 0.0064 B- -17485# 196# 41 973049.369 0.289 + -4 19 23 42 V x -7620# 196# 7824# 5# B- -14679# 358# 41 991820# 210# + -6 18 24 42 Cr x 7060# 300# 7456# 7# B- * 42 007579# 322# +0 17 30 13 43 Al x 48270# 600# 6712# 14# B- 23940# 721# 43 051820# 644# + 15 29 14 43 Si x 24330# 400# 7251# 9# B- 19289# 500# 43 026119# 429# + 13 28 15 43 P x 5040# 300# 7681# 7# B- 17236# 300# 43 005411# 322# + 11 27 16 43 S x -12195.461 4.970 8063.8276 0.1156 B- 11964.0500 62.0579 42 986907.635 5.335 + 9 26 17 43 Cl x -24159.510 61.859 8323.8672 1.4386 B- 7850.3002 62.0860 42 974063.700 66.407 + 7 25 18 43 Ar x -32009.811 5.310 8488.2382 0.1235 B- 4565.5836 5.3254 42 965636.056 5.700 + 5 24 19 43 K -4n -36575.394 0.410 8576.2204 0.0095 B- 1833.4783 0.4687 42 960734.701 0.440 + 3 23 20 43 Ca -38408.873 0.227 8600.6653 0.0053 B- -2220.7227 1.8650 42 958766.381 0.244 + 1 22 21 43 Sc -p -36188.150 1.863 8530.8265 0.0433 B- -6872.5591 6.0147 42 961150.425 1.999 + -1 21 22 43 Ti -29315.591 5.719 8352.8054 0.1330 B- -11399.2333 43.2287 42 968528.420 6.139 + -3 20 23 43 V x -17916.358 42.849 8069.5129 0.9965 B- -15946# 205# 42 980766.000 46.000 + -5 19 24 43 Cr x -1970# 200# 7680# 5# B- -19340# 447# 42 997885# 215# + -7 18 25 43 Mn x 17370# 400# 7213# 9# B- * 43 018647# 429# +0 16 30 14 44 Si x 29310# 500# 7156# 11# B- 18200# 640# 44 031466# 537# + 14 29 15 44 P x 11110# 400# 7552# 9# B- 20314# 400# 44 011927# 429# + 12 28 16 44 S x -9204.236 5.216 7996.0154 0.1186 B- 11274.7373 85.7253 43 990118.846 5.600 + 10 27 17 44 Cl x -20478.973 85.566 8234.4788 1.9447 B- 12194.2869 85.5811 43 978014.918 91.859 + 8 26 18 44 Ar x -32673.260 1.584 8493.8411 0.0360 B- 3108.2375 1.6381 43 964923.814 1.700 + 6 25 19 44 K x -35781.498 0.419 8546.7023 0.0095 B- 5687.2319 0.5303 43 961586.984 0.450 + 4 24 20 44 Ca -41468.730 0.325 8658.1769 0.0074 B- -3652.6948 1.7565 43 955481.489 0.348 + 2 23 21 44 Sc -p -37816.035 1.756 8557.3805 0.0399 B- -267.4488 1.8899 43 959402.818 1.884 + 0 22 22 44 Ti -a -37548.586 0.700 8533.5215 0.0159 B- -13740.5071 7.2986 43 959689.936 0.751 + -2 21 23 44 V -23808.079 7.265 8203.4567 0.1651 B- -10386.1805 51.7447 43 974440.977 7.799 + -4 20 24 44 Cr x -13421.899 51.232 7949.6265 1.1644 B- -20882# 304# 43 985591.000 55.000 + -6 19 25 44 Mn x 7460# 300# 7457# 7# B- * 44 008009# 322# +0 17 31 14 45 Si x 37090# 600# 7004# 13# B- 21130# 781# 45 039818# 644# + 15 30 15 45 P x 15960# 500# 7456# 11# B- 19301# 583# 45 017134# 537# + 13 29 16 45 S x -3340# 300# 7867# 7# B- 14922# 329# 44 996414# 322# + 11 28 17 45 Cl x -18262.544 136.163 8181.5991 3.0259 B- 11508.2568 136.1643 44 980394.353 146.177 + 9 27 18 45 Ar x -29770.801 0.512 8419.9526 0.0114 B- 6844.8422 0.7311 44 968039.731 0.550 + 7 26 19 45 K x -36615.643 0.522 8554.6747 0.0116 B- 4196.5868 0.6369 44 960691.491 0.560 + 5 25 20 45 Ca -40812.230 0.365 8630.5467 0.0081 B- 260.0910 0.7377 44 956186.270 0.392 + 3 24 21 45 Sc -41072.321 0.663 8618.9410 0.0147 B- -2062.0551 0.5086 44 955907.051 0.712 + 1 23 22 45 Ti -39010.266 0.836 8555.7321 0.0186 B- -7123.8247 0.2142 44 958120.758 0.897 + -1 22 23 45 V -31886.441 0.863 8380.0394 0.0192 B- -12371.6400 35.4073 44 965768.498 0.926 + -3 21 24 45 Cr x -19514.801 35.397 8087.7286 0.7866 B- -14535# 302# 44 979050.000 38.000 + -5 20 25 45 Mn x -4980# 300# 7747# 7# B- -19388# 412# 44 994654# 322# + -7 19 26 45 Fe -pp 14408# 283# 7299# 6# B- * 45 015467# 304# +0 16 31 15 46 P x 22840# 500# 7320# 11# B- 22200# 640# 46 024520# 537# + 14 30 16 46 S x 640# 400# 7785# 9# B- 14375# 411# 46 000687# 429# + 12 29 17 46 Cl x -13734.949 97.249 8080.7757 2.1141 B- 16036.3062 97.2766 45 985254.926 104.400 + 10 28 18 46 Ar x -29771.255 2.329 8412.3835 0.0506 B- 5642.6746 2.4394 45 968039.244 2.500 + 8 27 19 46 K x -35413.929 0.727 8518.0428 0.0158 B- 7725.6802 2.3490 45 961981.584 0.780 + 6 26 20 46 Ca -43139.610 2.234 8668.9848 0.0486 B- -1377.9665 2.3305 45 953687.726 2.398 + 4 25 21 46 Sc -n -41761.643 0.671 8622.0215 0.0146 B- 2366.6260 0.6666 45 955167.034 0.720 + 2 24 22 46 Ti -44128.269 0.090 8656.4623 0.0020 B- -7052.3723 0.0923 45 952626.356 0.097 + 0 23 23 46 V -37075.897 0.134 8486.1423 0.0029 B- -7604.3264 11.4538 45 960197.389 0.143 + -2 22 24 46 Cr -29471.570 11.453 8303.8233 0.2490 B- -17053.8226 87.3828 45 968360.969 12.295 + -4 21 25 46 Mn x -12417.748 86.629 7916.0805 1.8832 B- -13628# 312# 45 986669.000 93.000 + -6 20 26 46 Fe x 1210# 300# 7603# 7# B- * 46 001299# 322# +0 17 32 15 47 P x 28810# 600# 7209# 13# B- 21610# 721# 47 030929# 644# + 15 31 16 47 S x 7200# 400# 7652# 9# B- 16781# 447# 47 007730# 429# + 13 30 17 47 Cl x -9580# 200# 7992# 4# B- 15787# 200# 46 989715# 215# + 11 29 18 47 Ar x -25367.274 1.211 8311.4250 0.0258 B- 10344.7078 1.8490 46 972767.112 1.300 + 9 28 19 47 K x -35711.982 1.397 8514.8795 0.0297 B- 6632.6837 2.6237 46 961661.612 1.500 + 7 27 20 47 Ca -42344.665 2.221 8639.3548 0.0473 B- 1992.1770 1.1849 46 954541.134 2.384 + 5 26 21 47 Sc -44336.842 1.931 8665.0958 0.0411 B- 600.7694 1.9292 46 952402.444 2.072 + 3 25 22 47 Ti -44937.612 0.080 8661.2325 0.0017 B- -2930.5422 0.0879 46 951757.491 0.085 + 1 24 23 47 V -42007.070 0.110 8582.2348 0.0024 B- -7443.9769 5.1976 46 954903.558 0.118 + -1 23 24 47 Cr -34563.093 5.197 8407.2067 0.1106 B- -11996.7167 32.0943 46 962894.995 5.578 + -3 22 25 47 Mn x -22566.376 31.671 8135.3117 0.6738 B- -15437# 501# 46 975774.000 34.000 + -5 21 26 47 Fe x -7130# 500# 7790# 11# B- -17750# 781# 46 992346# 537# + -7 20 27 47 Co x 10620# 600# 7396# 13# B- * 47 011401# 644# +0 16 32 16 48 S x 12390# 500# 7552# 10# B- 16670# 707# 48 013301# 537# + 14 31 17 48 Cl x -4280# 500# 7883# 10# B- 18075# 500# 47 995405# 537# + 12 30 18 48 Ar x -22354.927 16.767 8243.6656 0.3493 B- 9929.5550 16.7847 47 976001.000 18.000 + 10 29 19 48 K x -32284.482 0.773 8434.2324 0.0161 B- 11940.3857 0.7734 47 965341.184 0.830 + 8 28 20 48 Ca -44224.868 0.018 8666.6916 0.0004 B- 279.2155 4.9499 47 952522.654 0.018 + 6 27 21 48 Sc -44504.083 4.950 8656.2097 0.1031 B- 3988.8685 4.9499 47 952222.903 5.313 + 4 26 22 48 Ti -48492.952 0.074 8723.0122 0.0016 B- -4014.9467 0.9691 47 947940.677 0.079 + 2 25 23 48 V -44478.005 0.972 8623.0686 0.0202 B- -1656.6918 7.3746 47 952250.900 1.043 + 0 24 24 48 Cr +nn -42821.313 7.311 8572.2553 0.1523 B- -13524.6692 9.9157 47 954029.431 7.848 + -2 23 25 48 Mn -29296.644 6.699 8274.1924 0.1396 B- -11288.0685 92.4609 47 968548.760 7.191 + -4 22 26 48 Fe x -18008.575 92.218 8022.7254 1.9212 B- -19738# 509# 47 980667.000 99.000 + -6 21 27 48 Co x 1730# 500# 7595# 10# B- -16448# 656# 48 001857# 537# + -8 20 28 48 Ni -pp 18178# 424# 7236# 9# B- * 48 019515# 455# +0 17 33 16 49 S -n 20391# 583# 7400# 12# B- 19652# 707# 49 021891# 626# + 15 32 17 49 Cl x 740# 400# 7785# 8# B- 17800# 565# 49 000794# 429# + 13 31 18 49 Ar x -17060# 400# 8132# 8# B- 12551# 400# 48 981685# 429# + 11 30 19 49 K x -29611.496 0.801 8372.2753 0.0164 B- 11688.5069 0.8205 48 968210.753 0.860 + 9 29 20 49 Ca -n -41300.003 0.178 8594.8500 0.0036 B- 5262.4445 2.2745 48 955662.625 0.190 + 7 28 21 49 Sc -46562.447 2.268 8686.2805 0.0463 B- 2001.5652 2.2684 48 950013.159 2.434 + 5 27 22 49 Ti -48564.012 0.078 8711.1625 0.0016 B- -601.8555 0.8203 48 947864.391 0.084 + 3 26 23 49 V - -47962.157 0.824 8682.9135 0.0168 B- -2629.8047 2.3487 48 948510.509 0.884 + 1 25 24 49 Cr -45332.352 2.202 8613.2777 0.0449 B- -7712.4265 0.2329 48 951333.720 2.363 + -1 24 25 49 Mn -37619.925 2.214 8439.9150 0.0452 B- -12869.1957 24.3199 48 959613.350 2.377 + -3 23 26 49 Fe x -24750.730 24.219 8161.3121 0.4943 B- -14971# 501# 48 973429.000 26.000 + -5 22 27 49 Co x -9780# 500# 7840# 10# B- -18309# 781# 48 989501# 537# + -7 21 28 49 Ni x 8530# 600# 7450# 12# B- * 49 009157# 644# +0 16 33 17 50 Cl x 7700# 400# 7651# 8# B- 20930# 640# 50 008266# 429# + 14 32 18 50 Ar x -13230# 500# 8054# 10# B- 12498# 500# 49 985797# 537# + 12 31 19 50 K x -25727.853 7.731 8288.5833 0.1546 B- 13861.3774 7.8919 49 972380.015 8.300 + 10 30 20 50 Ca x -39589.230 1.584 8550.1639 0.0317 B- 4947.8903 2.9723 49 957499.215 1.700 + 8 29 21 50 Sc -44537.120 2.515 8633.4747 0.0503 B- 6894.7470 2.5166 49 952187.437 2.700 + 6 28 22 50 Ti -51431.867 0.082 8755.7227 0.0017 B- -2208.6274 0.0579 49 944785.622 0.088 + 4 27 23 50 V -49223.240 0.093 8695.9032 0.0019 B- 1038.1240 0.0551 49 947156.681 0.099 + 2 26 24 50 Cr -50261.364 0.094 8701.0188 0.0019 B- -7634.4776 0.0672 49 946042.209 0.100 + 0 25 25 50 Mn -42626.886 0.115 8532.6823 0.0023 B- -8150.4267 8.3842 49 954238.157 0.123 + -2 24 26 50 Fe x -34476.460 8.383 8354.0268 0.1677 B- -16887.0566 126.0308 49 962988.000 9.000 + -4 23 27 50 Co x -17589.403 125.752 8000.6387 2.5150 B- -14130# 516# 49 981117.000 135.000 + -6 22 28 50 Ni x -3460# 500# 7702# 10# B- * 49 996286# 537# +0 17 34 17 51 Cl x 14290# 700# 7530# 14# B- 20780# 806# 51 015341# 751# + 15 33 18 51 Ar x -6490# 400# 7922# 8# B- 16026# 400# 50 993033# 429# + 13 32 19 51 K x -22515.457 13.041 8221.3350 0.2557 B- 13816.8529 13.0517 50 975828.664 14.000 + 11 31 20 51 Ca x -36332.310 0.522 8476.9135 0.0102 B- 6918.0432 2.5686 50 960995.663 0.560 + 9 30 21 51 Sc -43250.353 2.515 8597.2213 0.0493 B- 6482.6122 2.5612 50 953568.838 2.700 + 7 29 22 51 Ti -49732.965 0.484 8708.9912 0.0095 B- 2470.1402 0.4820 50 946609.468 0.519 + 5 28 23 51 V -52203.105 0.097 8742.0852 0.0019 B- -752.3907 0.1494 50 943957.664 0.104 + 3 27 24 51 Cr -51450.715 0.167 8711.9923 0.0033 B- -3207.4893 0.3256 50 944765.388 0.178 + 1 26 25 51 Mn -48243.225 0.304 8633.7602 0.0060 B- -8054.0400 1.4309 50 948208.770 0.326 + -1 25 26 51 Fe x -40189.185 1.398 8460.4977 0.0274 B- -12847.0389 48.4579 50 956855.137 1.501 + -3 24 27 51 Co x -27342.146 48.438 8193.2549 0.9498 B- -15692# 503# 50 970647.000 52.000 + -5 23 28 51 Ni x -11650# 500# 7870# 10# B- * 50 987493# 537# +0 18 35 17 52 Cl x 22360# 700# 7386# 13# B- 23739# 922# 52 024004# 751# + 16 34 18 52 Ar x -1380# 600# 7827# 12# B- 15758# 601# 51 998519# 644# + 14 33 19 52 K x -17137.628 33.534 8115.0303 0.6449 B- 17128.6431 33.5405 51 981602.000 36.000 + 12 32 20 52 Ca x -34266.272 0.671 8429.3821 0.0129 B- 6257.2889 3.1463 51 963213.646 0.720 + 10 31 21 52 Sc -40523.560 3.074 8534.6695 0.0591 B- 8954.1372 4.1223 51 956496.170 3.300 + 8 30 22 52 Ti -49477.698 2.747 8691.8193 0.0528 B- 1965.3340 2.7510 51 946883.509 2.948 + 6 29 23 52 V -n -51443.032 0.159 8714.5690 0.0031 B- 3976.4763 0.1601 51 944773.636 0.170 + 4 28 24 52 Cr -55419.508 0.112 8775.9946 0.0022 B- -4708.1214 0.0633 51 940504.714 0.120 + 2 27 25 52 Mn - -50711.387 0.129 8670.4087 0.0025 B- -2379.2912 0.1534 51 945559.090 0.138 + 0 26 26 52 Fe -- -48332.095 0.179 8609.6079 0.0035 B- -13988.1167 5.2831 51 948113.364 0.192 + -2 25 27 52 Co -34343.979 5.282 8325.5606 0.1016 B- -11784.1230 83.0710 51 963130.224 5.669 + -4 24 28 52 Ni x -22559.856 82.903 8083.8977 1.5943 B- -20680# 606# 51 975781.000 89.000 + -6 23 29 52 Cu x -1880# 600# 7671# 12# B- * 51 997982# 644# +0 17 35 18 53 Ar x 6791# 699# 7677# 13# B- 19086# 708# 53 007290# 750# + 15 34 19 53 K x -12295.722 111.779 8022.8488 2.1090 B- 17091.9853 120.0471 52 986800.000 120.000 + 13 33 20 53 Ca x -29387.707 43.780 8330.5778 0.8260 B- 9381.8471 47.2223 52 968451.000 47.000 + 11 32 21 53 Sc -38769.555 17.698 8492.8325 0.3339 B- 8111.8785 17.9325 52 958379.173 19.000 + 9 31 22 53 Ti x -46881.433 2.888 8631.1256 0.0545 B- 4970.2419 4.2386 52 949670.714 3.100 + 7 30 23 53 V +p -51851.675 3.103 8710.1425 0.0585 B- 3435.9426 3.1017 52 944334.940 3.331 + 5 29 24 53 Cr -55287.618 0.116 8760.2103 0.0022 B- -597.2679 0.3430 52 940646.304 0.124 + 3 28 25 53 Mn -54690.350 0.346 8734.1798 0.0065 B- -3742.8664 1.6971 52 941287.497 0.371 + 1 27 26 53 Fe -50947.483 1.669 8648.7985 0.0315 B- -8288.1073 0.4431 52 945305.629 1.792 + -1 26 27 53 Co -42659.376 1.727 8477.6578 0.0326 B- -13028.5485 25.2096 52 954203.278 1.854 + -3 25 28 53 Ni x -29630.827 25.150 8217.0749 0.4745 B- -16491# 501# 52 968190.000 27.000 + -5 24 29 53 Cu x -13140# 500# 7891# 9# B- * 52 985894# 537# +0 18 36 18 54 Ar x 12560# 800# 7578# 15# B- 17710# 894# 54 013484# 859# + 16 35 19 54 K x -5150# 400# 7891# 7# B- 20010# 403# 53 994471# 429# + 14 34 20 54 Ca x -25160.587 48.438 8247.4967 0.8970 B- 9277.3463 50.4129 53 972989.000 52.000 + 12 33 21 54 Sc x -34437.934 13.973 8404.8115 0.2588 B- 11305.8789 21.1188 53 963029.359 15.000 + 10 32 22 54 Ti x -45743.812 15.835 8599.6917 0.2932 B- 4154.4548 19.3840 53 950892.000 17.000 + 8 31 23 54 V -49898.267 11.180 8662.1382 0.2070 B- 7037.1118 11.1794 53 946432.009 12.001 + 6 30 24 54 Cr -56935.379 0.132 8777.9672 0.0025 B- -1377.1325 1.0051 53 938877.359 0.142 + 4 29 25 54 Mn -p -55558.247 1.007 8737.9768 0.0186 B- 696.3688 1.0587 53 940355.772 1.080 + 2 28 26 54 Fe -56254.615 0.343 8736.3846 0.0064 B- -8244.5478 0.0893 53 939608.189 0.368 + 0 27 27 54 Co -48010.068 0.355 8569.2199 0.0066 B- -8731.7558 4.6710 53 948459.075 0.380 + -2 26 28 54 Ni x -39278.312 4.657 8393.0328 0.0862 B- -18038# 400# 53 957833.000 5.000 + -4 25 29 54 Cu x -21240# 400# 8045# 7# B- -15538# 454# 53 977198# 429# + -6 24 30 54 Zn -pp -5702# 217# 7742# 4# B- * 53 993879# 232# +0 17 36 19 55 K x 470# 500# 7792# 9# B- 19121# 525# 55 000505# 537# + 15 35 20 55 Ca x -18650.375 160.217 8125.9260 2.9130 B- 12191.7329 171.9435 54 979978.000 172.000 + 13 34 21 55 Sc x -30842.108 62.411 8333.3694 1.1347 B- 10990.3608 68.7671 54 966889.637 67.000 + 11 33 22 55 Ti x -41832.469 28.876 8518.9696 0.5250 B- 7292.6673 39.5419 54 955091.000 31.000 + 9 32 23 55 V x -49125.136 27.013 8637.3391 0.4912 B- 5985.1877 27.0143 54 947262.000 29.000 + 7 31 24 55 Cr -n -55110.324 0.228 8731.9362 0.0042 B- 2602.2183 0.3219 54 940836.637 0.245 + 5 30 25 55 Mn -57712.542 0.260 8765.0247 0.0047 B- -231.1204 0.1786 54 938043.040 0.279 + 3 29 26 55 Fe -57481.422 0.308 8746.5981 0.0056 B- -3451.4254 0.3241 54 938291.158 0.330 + 1 28 27 55 Co -54029.996 0.405 8669.6204 0.0074 B- -8694.0350 0.5775 54 941996.416 0.434 + -1 27 28 55 Ni - -45335.961 0.705 8497.3225 0.0128 B- -13700.5585 155.5611 54 951329.846 0.757 + -3 26 29 55 Cu x -31635.403 155.560 8233.9970 2.8284 B- -17366# 429# 54 966038.000 167.000 + -5 25 30 55 Zn x -14270# 400# 7904# 7# B- * 54 984681# 429# +0 18 37 19 56 K x 7980# 600# 7663# 11# B- 21491# 650# 56 008567# 644# + 16 36 20 56 Ca x -13510.390 249.640 8033.1654 4.4579 B- 12005.4580 360.2029 55 985496.000 268.000 + 14 35 21 56 Sc x -25515.848 259.665 8233.5781 4.6369 B- 13907.1470 278.3271 55 972607.611 278.761 + 12 34 22 56 Ti -39422.995 100.201 8467.9495 1.7893 B- 6760.4051 188.1842 55 957677.675 107.569 + 10 33 23 56 V -46183.401 175.884 8574.7006 3.1408 B- 9101.7270 175.8854 55 950420.082 188.819 + 8 32 24 56 Cr ++ -55285.128 0.578 8723.2609 0.0103 B- 1626.5384 0.5524 55 940648.977 0.620 + 6 31 25 56 Mn -n -56911.666 0.293 8738.3358 0.0052 B- 3695.4973 0.2065 55 938902.816 0.314 + 4 30 26 56 Fe -60607.163 0.268 8790.3563 0.0048 B- -4566.6455 0.4104 55 934935.537 0.287 + 2 29 27 56 Co -56040.518 0.475 8694.8386 0.0085 B- -2132.8689 0.3735 55 939838.032 0.510 + 0 28 28 56 Ni -53907.649 0.399 8642.7811 0.0071 B- -15277.9163 6.4070 55 942127.761 0.428 + -2 27 29 56 Cu x -38629.733 6.395 8355.9907 0.1142 B- -13240# 400# 55 958529.278 6.864 + -4 26 30 56 Zn x -25390# 400# 8106# 7# B- -21550# 640# 55 972743# 429# + -6 25 31 56 Ga x -3840# 500# 7707# 9# B- * 55 995878# 537# +0 19 38 19 57 K x 14130# 600# 7563# 11# B- 20689# 721# 57 015169# 644# + 17 37 20 57 Ca x -6560# 400# 7912# 7# B- 14820# 438# 56 992958# 429# + 15 36 21 57 Sc x -21379.653 179.778 8158.1666 3.1540 B- 13022.1957 273.3249 56 977048.000 193.000 + 13 35 22 57 Ti x -34401.848 205.879 8372.9008 3.6119 B- 10033.2148 222.6466 56 963068.098 221.020 + 11 34 23 57 V x -44435.063 84.766 8535.1967 1.4871 B- 8089.9214 84.7864 56 952297.000 91.000 + 9 33 24 57 Cr x -52524.985 1.863 8663.3998 0.0327 B- 4961.2946 2.3948 56 943612.112 2.000 + 7 32 25 57 Mn -57486.279 1.505 8736.7146 0.0264 B- 2695.7375 1.5219 56 938285.944 1.615 + 5 31 26 57 Fe -60182.017 0.268 8770.2829 0.0047 B- -836.3589 0.4493 56 935391.950 0.287 + 3 30 27 57 Co -59345.658 0.516 8741.8845 0.0090 B- -3261.6970 0.6417 56 936289.819 0.553 + 1 29 28 57 Ni -56083.961 0.566 8670.9364 0.0099 B- -8774.9466 0.4393 56 939791.394 0.608 + -1 28 29 57 Cu -47309.014 0.501 8503.2646 0.0088 B- -14759# 200# 56 949211.686 0.537 + -3 27 30 57 Zn x -32550# 200# 8231# 4# B- -17140# 447# 56 965056# 215# + -5 26 31 57 Ga x -15410# 400# 7916# 7# B- * 56 983457# 429# +0 20 39 19 58 K x 21930# 700# 7437# 12# B- 23461# 860# 58 023543# 751# + 18 38 20 58 Ca x -1530# 500# 7828# 9# B- 13949# 535# 57 998357# 537# + 16 37 21 58 Sc x -15479.569 190.025 8054.9436 3.2763 B- 15438.0995 264.0509 57 983382.000 204.000 + 14 36 22 58 Ti x -30917.668 183.340 8307.6290 3.1610 B- 9512.9152 206.8675 57 966808.519 196.823 + 12 35 23 58 V x -40430.584 95.816 8458.1560 1.6520 B- 11561.2240 95.8625 57 956595.985 102.862 + 10 34 24 58 Cr x -51991.808 2.981 8643.9987 0.0514 B- 3835.7607 4.0227 57 944184.501 3.200 + 8 33 25 58 Mn x -55827.568 2.701 8696.6438 0.0466 B- 6327.7027 2.7198 57 940066.643 2.900 + 6 32 26 58 Fe -62155.271 0.316 8792.2534 0.0055 B- -2307.9785 1.1389 57 933273.575 0.339 + 4 31 27 58 Co -59847.292 1.153 8738.9719 0.0199 B- 381.5789 1.1071 57 935751.292 1.237 + 2 30 28 58 Ni -60228.871 0.349 8732.0621 0.0060 B- -8561.0204 0.4425 57 935341.650 0.374 + 0 29 29 58 Cu -51667.851 0.564 8570.9696 0.0097 B- -9368.9796 50.0020 57 944532.283 0.604 + -2 28 30 58 Zn -- -42298.871 50.001 8395.9467 0.8621 B- -18759# 304# 57 954590.296 53.678 + -4 27 31 58 Ga x -23540# 300# 8059# 5# B- -15960# 583# 57 974729# 322# + -6 26 32 58 Ge x -7580# 500# 7770# 9# B- * 57 991863# 537# +0 21 40 19 59 K x 28750# 800# 7332# 14# B- 22940# 1000# 59 030864# 859# + 19 39 20 59 Ca x 5810# 600# 7708# 10# B- 16639# 650# 59 006237# 644# + 17 38 21 59 Sc x -10829.550 249.640 7976.4073 4.2312 B- 15050# 390# 58 988374.000 268.000 + 15 37 22 59 Ti x -25880# 300# 8218# 5# B- 11731# 330# 58 972217# 322# + 13 36 23 59 V x -37610.617 137.400 8403.8034 2.3288 B- 10505.3137 137.4021 58 959623.343 147.505 + 11 35 24 59 Cr x -48115.931 0.671 8568.5995 0.0114 B- 7409.3977 2.4234 58 948345.426 0.720 + 9 34 25 59 Mn x -55525.328 2.329 8680.9224 0.0395 B- 5139.6290 2.3520 58 940391.111 2.500 + 7 33 26 59 Fe -60664.957 0.330 8754.7746 0.0056 B- 1564.8804 0.3690 58 934873.492 0.354 + 5 32 27 59 Co -62229.838 0.397 8768.0379 0.0067 B- -1073.0050 0.1944 58 933193.524 0.426 + 3 31 28 59 Ni -61156.833 0.351 8736.5912 0.0060 B- -4798.3786 0.3973 58 934345.442 0.376 + 1 30 29 59 Cu -56358.454 0.528 8642.0027 0.0090 B- -9142.7760 0.6018 58 939496.713 0.566 + -1 29 30 59 Zn -47215.678 0.759 8473.7802 0.0129 B- -13456# 170# 58 949311.886 0.814 + -3 28 31 59 Ga x -33760# 170# 8232# 3# B- -17390# 434# 58 963757# 183# + -5 27 32 59 Ge x -16370# 400# 7924# 7# B- * 58 982426# 429# +0 20 40 20 60 Ca x 11000# 700# 7627# 12# B- 15550# 860# 60 011809# 751# + 18 39 21 60 Sc x -4550# 500# 7873# 8# B- 17549# 555# 59 995115# 537# + 16 38 22 60 Ti x -22099.698 240.325 8152.7858 4.0054 B- 10987.7040 301.4311 59 976275.000 258.000 + 14 37 23 60 V x -33087.402 181.946 8322.8751 3.0324 B- 13821.0986 181.9496 59 964479.215 195.327 + 12 36 24 60 Cr x -46908.500 1.118 8540.1876 0.0186 B- 6059.4457 2.5831 59 949641.656 1.200 + 10 35 25 60 Mn x -52967.946 2.329 8628.1392 0.0388 B- 8445.2283 4.1261 59 943136.574 2.500 + 8 34 26 60 Fe -nn -61413.174 3.406 8755.8539 0.0568 B- 237.2633 3.4106 59 934070.249 3.656 + 6 33 27 60 Co -n -61650.437 0.403 8746.7692 0.0067 B- 2822.8058 0.2124 59 933815.536 0.433 + 4 32 28 60 Ni -64473.243 0.353 8780.7769 0.0059 B- -6127.9810 1.5735 59 930785.129 0.378 + 2 31 29 60 Cu - -58345.262 1.613 8665.6047 0.0269 B- -4170.7922 1.6286 59 937363.787 1.731 + 0 30 30 60 Zn -54174.470 0.548 8583.0524 0.0091 B- -14584# 200# 59 941841.317 0.588 + -2 29 31 60 Ga x -39590# 200# 8327# 3# B- -12060# 361# 59 957498# 215# + -4 28 32 60 Ge x -27530# 300# 8113# 5# B- -21890# 500# 59 970445# 322# + -6 27 33 60 As x -5640# 400# 7735# 7# B- * 59 993945# 429# +0 21 41 20 61 Ca x 19010# 800# 7503# 13# B- 18510# 1000# 61 020408# 859# + 19 40 21 61 Sc x 500# 600# 7794# 10# B- 16870# 671# 61 000537# 644# + 17 39 22 61 Ti x -16370# 300# 8058# 5# B- 13807# 381# 60 982426# 322# + 15 38 23 61 V x -30177.121 234.920 8271.0417 3.8511 B- 12319.3807 234.9272 60 967603.529 252.196 + 13 37 24 61 Cr x -42496.502 1.863 8460.1734 0.0305 B- 9245.6277 2.9822 60 954378.130 2.000 + 11 36 25 61 Mn x -51742.130 2.329 8598.9157 0.0382 B- 7178.3730 3.4965 60 944452.541 2.500 + 9 35 26 61 Fe x -58920.503 2.608 8703.7686 0.0428 B- 3977.6759 2.7399 60 936746.241 2.800 + 7 34 27 61 Co p2n -62898.179 0.839 8756.1510 0.0138 B- 1323.8504 0.7899 60 932476.031 0.901 + 5 33 28 61 Ni -64222.029 0.355 8765.0281 0.0058 B- -2237.9663 0.9617 60 931054.819 0.381 + 3 32 29 61 Cu p2n -61984.063 0.951 8715.5148 0.0156 B- -5635.1565 15.9028 60 933457.375 1.020 + 1 31 30 61 Zn -56348.906 15.899 8610.3098 0.2606 B- -9214.2438 37.6786 60 939506.964 17.068 + -1 30 31 61 Ga -47134.662 37.994 8446.4313 0.6228 B- -13345# 302# 60 949398.861 40.787 + -3 29 32 61 Ge x -33790# 300# 8215# 5# B- -16590# 424# 60 963725# 322# + -5 28 33 61 As x -17200# 300# 7930# 5# B- * 60 981535# 322# +0 20 41 21 62 Sc x 7310# 600# 7688# 10# B- 19510# 721# 62 007848# 644# + 18 40 22 62 Ti x -12200# 400# 7990# 6# B- 13013# 479# 61 986903# 429# + 16 39 23 62 V x -25213.164 264.287 8187.7565 4.2627 B- 15639.4478 264.3094 61 972932.556 283.723 + 14 38 24 62 Cr x -40852.611 3.447 8427.3871 0.0556 B- 7671.3532 7.3947 61 956142.920 3.700 + 12 37 25 62 Mn IT -48523.965 6.542 8538.5002 0.1055 B- 10354.0920 7.1142 61 947907.384 7.023 + 10 36 26 62 Fe x -58878.057 2.794 8692.8831 0.0451 B- 2546.3427 18.7834 61 936791.809 3.000 + 8 35 27 62 Co + -61424.399 18.574 8721.3347 0.2996 B- 5322.0404 18.5695 61 934058.198 19.940 + 6 34 28 62 Ni -66746.440 0.425 8794.5555 0.0069 B- -3958.8965 0.4751 61 928344.753 0.455 + 4 33 29 62 Cu - -62787.543 0.637 8718.0839 0.0103 B- -1619.4548 0.6507 61 932594.803 0.683 + 2 32 30 62 Zn -61168.088 0.615 8679.3451 0.0099 B- -9181.0666 0.3763 61 934333.359 0.660 + 0 31 31 62 Ga -51987.022 0.637 8518.6449 0.0103 B- -9847# 140# 61 944189.639 0.684 + -2 30 32 62 Ge x -42140# 140# 8347# 2# B- -17720# 331# 61 954761# 150# + -4 29 33 62 As x -24420# 300# 8049# 5# B- * 61 973784# 322# +0 21 42 21 63 Sc x 13070# 700# 7603# 11# B- 18930# 860# 63 014031# 751# + 19 41 22 63 Ti x -5860# 500# 7891# 8# B- 15880# 605# 62 993709# 537# + 17 40 23 63 V x -21740.141 339.995 8130.7809 5.3968 B- 14438.1586 347.6720 62 976661.000 365.000 + 15 39 24 63 Cr x -36178.299 72.657 8347.5398 1.1533 B- 10708.7611 72.7520 62 961161.000 78.000 + 13 38 25 63 Mn x -46887.061 3.726 8505.1020 0.0591 B- 8748.5685 5.6915 62 949664.672 4.000 + 11 37 26 63 Fe -55635.629 4.302 8631.5499 0.0683 B- 6215.9238 19.0668 62 940272.698 4.618 + 9 36 27 63 Co -61851.553 18.575 8717.7972 0.2948 B- 3661.3385 18.5704 62 933599.630 19.941 + 7 35 28 63 Ni -65512.891 0.426 8763.4955 0.0068 B- 66.9768 0.0149 62 929669.021 0.457 + 5 34 29 63 Cu -65579.868 0.426 8752.1404 0.0068 B- -3366.4392 1.5450 62 929597.119 0.457 + 3 33 30 63 Zn -62213.429 1.560 8686.2866 0.0248 B- -5666.3294 2.0330 62 933211.140 1.674 + 1 32 31 63 Ga x -56547.100 1.304 8583.9267 0.0207 B- -9625.8787 37.2826 62 939294.194 1.400 + -1 31 32 63 Ge x -46921.221 37.260 8418.7167 0.5914 B- -13421# 204# 62 949628.000 40.000 + -3 30 33 63 As x -33500# 200# 8193# 3# B- -16650# 539# 62 964036# 215# + -5 29 34 63 Se x -16850# 500# 7917# 8# B- * 62 981911# 537# +0 20 42 22 64 Ti x -1480# 600# 7826# 9# B- 14840# 721# 63 998411# 644# + 18 41 23 64 V x -16320# 400# 8045# 6# B- 17320# 500# 63 982480# 429# + 16 40 24 64 Cr x -33639.978 299.941 8303.5626 4.6866 B- 9349.0622 299.9620 63 963886.000 322.000 + 14 39 25 64 Mn x -42989.040 3.540 8437.4175 0.0553 B- 11980.5117 6.1402 63 953849.369 3.800 + 12 38 26 64 Fe x -54969.552 5.017 8612.3888 0.0784 B- 4822.8898 20.6249 63 940987.761 5.386 + 10 37 27 64 Co + -59792.442 20.005 8675.5223 0.3126 B- 7306.5921 20.0000 63 935810.176 21.476 + 8 36 28 64 Ni -67099.034 0.463 8777.4637 0.0072 B- -1674.6156 0.2055 63 927966.228 0.497 + 6 35 29 64 Cu -65424.418 0.427 8739.0736 0.0067 B- 579.5996 0.6447 63 929764.001 0.458 + 4 34 30 64 Zn -66004.018 0.644 8735.9057 0.0101 B- -7171.1912 1.4825 63 929141.776 0.690 + 2 33 31 64 Ga -58832.827 1.429 8611.6317 0.0223 B- -4517.3237 3.9905 63 936840.366 1.533 + 0 32 32 64 Ge x -54315.503 3.726 8528.8243 0.0582 B- -14783# 203# 63 941689.912 4.000 + -2 31 33 64 As -p -39532# 203# 8286# 3# B- -12673# 540# 63 957560# 218# + -4 30 34 64 Se x -26860# 500# 8075# 8# B- * 63 971165# 537# +0 21 43 22 65 Ti x 5210# 700# 7726# 11# B- 17320# 860# 65 005593# 751# + 19 42 23 65 V x -12110# 500# 7981# 8# B- 16200# 539# 64 986999# 537# + 17 41 24 65 Cr x -28310# 200# 8218# 3# B- 12657# 200# 64 969608# 215# + 15 40 25 65 Mn x -40967.344 3.726 8400.6822 0.0573 B- 10250.5576 6.3257 64 956019.749 4.000 + 13 39 26 65 Fe x -51217.902 5.112 8546.3470 0.0786 B- 7967.3036 5.5198 64 945015.323 5.487 + 11 38 27 65 Co x -59185.205 2.083 8656.8848 0.0320 B- 5940.5911 2.1379 64 936462.071 2.235 + 9 37 28 65 Ni -n -65125.796 0.483 8736.2424 0.0074 B- 2137.8808 0.6997 64 930084.585 0.518 + 7 36 29 65 Cu -67263.677 0.643 8757.0967 0.0099 B- -1351.6527 0.3557 64 927789.476 0.690 + 5 35 30 65 Zn -65912.024 0.646 8724.2660 0.0099 B- -3254.5380 0.6305 64 929240.534 0.693 + 3 34 31 65 Ga -62657.486 0.791 8662.1601 0.0122 B- -6179.2631 2.3046 64 932734.424 0.849 + 1 33 32 65 Ge -56478.223 2.165 8555.0584 0.0333 B- -9541.1670 84.7936 64 939368.136 2.323 + -1 32 33 65 As x -46937.056 84.766 8396.2351 1.3041 B- -13917# 312# 64 949611.000 91.000 + -3 31 34 65 Se x -33020# 300# 8170# 5# B- -16529# 583# 64 964552# 322# + -5 30 35 65 Br x -16490# 500# 7904# 8# B- * 64 982297# 537# +0 20 43 23 66 V x -6300# 500# 7894# 8# B- 18840# 583# 65 993237# 537# + 18 42 24 66 Cr x -25140# 300# 8168# 5# B- 11610# 300# 65 973011# 322# + 16 41 25 66 Mn x -36750.392 11.178 8331.7986 0.1694 B- 13317.4543 11.9056 65 960546.833 12.000 + 14 40 26 66 Fe x -50067.847 4.099 8521.7245 0.0621 B- 6340.6944 14.5611 65 946249.958 4.400 + 12 39 27 66 Co x -56408.541 13.972 8605.9419 0.2117 B- 9597.7522 14.0421 65 939442.943 15.000 + 10 38 28 66 Ni x -66006.293 1.397 8739.5086 0.0212 B- 251.9958 1.5405 65 929139.333 1.500 + 8 37 29 66 Cu -66258.289 0.649 8731.4730 0.0098 B- 2640.9396 0.9255 65 928868.804 0.696 + 6 36 30 66 Zn -68899.229 0.744 8759.6335 0.0113 B- -5175.5000 0.8000 65 926033.639 0.798 + 4 35 31 66 Ga - -63723.729 1.092 8669.3631 0.0166 B- -2116.6879 2.6376 65 931589.766 1.172 + 2 34 32 66 Ge x -61607.041 2.401 8625.4383 0.0364 B- -9581.9570 6.1685 65 933862.124 2.577 + 0 33 33 66 As x -52025.084 5.682 8468.4034 0.0861 B- -10365# 200# 65 944148.778 6.100 + -2 32 34 66 Se x -41660# 200# 8300# 3# B- -18091# 447# 65 955276# 215# + -4 31 35 66 Br x -23570# 400# 8014# 6# B- * 65 974697# 429# +0 21 44 23 67 V x -1744# 600# 7829# 9# B- 17526# 721# 66 998128# 644# + 19 43 24 67 Cr x -19270# 400# 8079# 6# B- 14311# 447# 66 979313# 429# + 17 42 25 67 Mn x -33580# 200# 8281# 3# B- 12128# 200# 66 963950# 215# + 15 41 26 67 Fe x -45708.416 3.819 8449.9359 0.0570 B- 9613.3678 7.4900 66 950930.000 4.100 + 13 40 27 67 Co x -55321.783 6.443 8581.7422 0.0962 B- 8420.9047 7.0607 66 940609.625 6.917 + 11 39 28 67 Ni x -63742.688 2.888 8695.7505 0.0431 B- 3576.8654 3.0223 66 931569.413 3.100 + 9 38 29 67 Cu -67319.553 0.892 8737.4597 0.0133 B- 560.8226 0.8296 66 927729.490 0.957 + 7 37 30 67 Zn -67880.376 0.755 8734.1534 0.0113 B- -1001.2201 1.1196 66 927127.422 0.810 + 5 36 31 67 Ga -66879.156 1.176 8707.5330 0.0176 B- -4205.4380 4.4066 66 928202.276 1.262 + 3 35 32 67 Ge -62673.718 4.319 8633.0884 0.0645 B- -6086.4858 4.3418 66 932716.999 4.636 + 1 34 33 67 As -56587.232 0.443 8530.5685 0.0066 B- -10006.9381 67.0690 66 939251.110 0.475 + -1 33 34 67 Se x -46580.294 67.068 8369.5344 1.0010 B- -14051# 307# 66 949994.000 72.000 + -3 32 35 67 Br x -32530# 300# 8148# 4# B- -16978# 520# 66 965078# 322# + -5 31 36 67 Kr -pp -15552# 424# 7883# 6# B- * 66 983305# 455# +0 20 44 24 68 Cr x -15690# 500# 8026# 7# B- 13230# 583# 67 983156# 537# + 18 43 25 68 Mn x -28920# 300# 8209# 4# B- 14977# 356# 67 968953# 322# + 16 42 26 68 Fe x -43897# 193# 8418# 3# B- 7746# 193# 67 952875# 207# + 14 41 27 68 Co -51642.591 3.859 8520.1301 0.0567 B- 11821.2318 4.8760 67 944559.401 4.142 + 12 40 28 68 Ni x -63463.822 2.981 8682.4667 0.0438 B- 2103.2205 3.3753 67 931868.787 3.200 + 10 39 29 68 Cu x -65567.043 1.584 8701.8913 0.0233 B- 4440.1115 1.7645 67 929610.887 1.700 + 8 38 30 68 Zn -70007.154 0.778 8755.6820 0.0115 B- -2921.1000 1.2000 67 924844.232 0.835 + 6 37 31 68 Ga - -67086.054 1.430 8701.2195 0.0210 B- -107.2555 2.3594 67 927980.161 1.535 + 4 36 32 68 Ge x -66978.799 1.876 8688.1371 0.0276 B- -8084.2715 2.6320 67 928095.305 2.014 + 2 35 33 68 As -58894.527 1.846 8557.7457 0.0271 B- -4705.0786 1.9112 67 936774.127 1.981 + 0 34 34 68 Se x -54189.449 0.496 8477.0482 0.0073 B- -15398# 259# 67 941825.236 0.532 + -2 33 35 68 Br -p -38791# 259# 8239# 4# B- -13165# 563# 67 958356# 278# + -4 32 36 68 Kr x -25626# 500# 8034# 7# B- * 67 972489# 537# +0 21 45 24 69 Cr x -9630# 500# 7939# 7# B- 15730# 640# 68 989662# 537# + 19 44 25 69 Mn x -25360# 400# 8155# 6# B- 13839# 447# 68 972775# 429# + 17 43 26 69 Fe x -39199# 200# 8345# 3# B- 11186# 218# 68 957918# 215# + 15 42 27 69 Co x -50385.447 85.697 8495.4062 1.2420 B- 9593.2084 85.7784 68 945909.000 92.000 + 13 41 28 69 Ni x -59978.656 3.726 8623.0998 0.0540 B- 5757.5650 3.9793 68 935610.267 4.000 + 11 40 29 69 Cu x -65736.221 1.397 8695.2044 0.0203 B- 2681.6854 1.6075 68 929429.267 1.500 + 9 39 30 69 Zn -n -68417.906 0.795 8722.7311 0.0115 B- 909.9134 1.4234 68 926550.360 0.853 + 7 38 31 69 Ga -69327.820 1.197 8724.5798 0.0174 B- -2227.1455 0.5500 68 925573.528 1.285 + 5 37 32 69 Ge -67100.674 1.318 8680.9640 0.0191 B- -3988.4927 31.9822 68 927964.467 1.414 + 3 36 33 69 As -63112.181 31.999 8611.8214 0.4638 B- -6677.4672 32.0215 68 932246.289 34.352 + 1 35 34 69 Se -56434.714 1.490 8503.7082 0.0216 B- -10175.2364 42.0293 68 939414.845 1.599 + -1 34 35 69 Br -p -46259.478 42.003 8344.9026 0.6087 B- -14119# 303# 68 950338.410 45.091 + -3 33 36 69 Kr x -32140# 300# 8129# 4# B- * 68 965496# 322# +0 22 46 24 70 Cr x -5640# 600# 7884# 9# B- 14810# 781# 69 993945# 644# + 20 45 25 70 Mn x -20450# 500# 8084# 7# B- 16440# 583# 69 978046# 537# + 18 44 26 70 Fe x -36890# 300# 8308# 4# B- 9635# 300# 69 960397# 322# + 16 43 27 70 Co x -46524.963 10.992 8434.1980 0.1570 B- 12688.9049 11.1987 69 950053.400 11.800 + 14 42 28 70 Ni x -59213.868 2.144 8604.2917 0.0306 B- 3762.5123 2.4011 69 936431.300 2.301 + 12 41 29 70 Cu x -62976.381 1.082 8646.8655 0.0155 B- 6588.3675 2.2018 69 932392.078 1.161 + 10 40 30 70 Zn -69564.748 1.918 8729.8086 0.0274 B- -654.5979 1.5737 69 925319.175 2.058 + 8 39 31 70 Ga -68910.150 1.201 8709.2808 0.0172 B- 1651.8861 1.4520 69 926021.914 1.289 + 6 38 32 70 Ge -70562.036 0.820 8721.7028 0.0117 B- -6228.0630 1.6200 69 924248.542 0.880 + 4 37 33 70 As x -64333.973 1.397 8621.5541 0.0200 B- -2404.0737 2.1118 69 930934.642 1.500 + 2 36 34 70 Se x -61929.900 1.584 8576.0338 0.0226 B- -10504.2727 14.9878 69 933515.521 1.700 + 0 35 35 70 Br x -51425.627 14.904 8414.7964 0.2129 B- -10325# 201# 69 944792.321 16.000 + -2 34 36 70 Kr x -41100# 200# 8256# 3# B- * 69 955877# 215# +0 21 46 25 71 Mn x -16620# 500# 8030# 7# B- 15310# 640# 70 982158# 537# + 19 45 26 71 Fe x -31930# 400# 8235# 6# B- 12440# 613# 70 965722# 429# + 17 44 27 71 Co x -44369.930 465.030 8398.7344 6.5497 B- 11036.3053 465.0353 70 952366.923 499.230 + 15 43 28 71 Ni x -55406.236 2.237 8543.1564 0.0315 B- 7304.8989 2.6879 70 940518.962 2.401 + 13 42 29 71 Cu x -62711.134 1.490 8635.0233 0.0210 B- 4617.6517 3.0437 70 932676.831 1.600 + 11 41 30 71 Zn -67328.786 2.654 8689.0417 0.0374 B- 2810.3405 2.7748 70 927719.578 2.849 + 9 40 31 71 Ga -70139.127 0.811 8717.6050 0.0114 B- -232.4698 0.0934 70 924702.554 0.870 + 7 39 32 71 Ge -69906.657 0.815 8703.3118 0.0115 B- -2013.4000 4.0825 70 924952.120 0.874 + 5 38 33 71 As - -67893.257 4.163 8663.9350 0.0586 B- -4746.7420 5.0140 70 927113.594 4.469 + 3 37 34 71 Se x -63146.515 2.794 8586.0606 0.0394 B- -6644.0883 6.0820 70 932209.431 3.000 + 1 36 35 71 Br -56502.426 5.402 8481.4629 0.0761 B- -10175.2155 128.8452 70 939342.153 5.799 + -1 35 36 71 Kr -46327.211 128.769 8327.1310 1.8136 B- -14037# 420# 70 950265.695 138.238 + -3 34 37 71 Rb x -32290# 400# 8118# 6# B- * 70 965335# 429# +0 22 47 25 72 Mn x -11170# 600# 7955# 8# B- 18080# 781# 71 988009# 644# + 20 46 26 72 Fe x -29250# 500# 8195# 7# B- 11050# 583# 71 968599# 537# + 18 45 27 72 Co x -40300# 300# 8338# 4# B- 13926# 300# 71 956736# 322# + 16 44 28 72 Ni x -54226.068 2.237 8520.2118 0.0311 B- 5556.9381 2.6374 71 941785.924 2.401 + 14 43 29 72 Cu x -59783.006 1.397 8586.5256 0.0194 B- 8362.4883 2.5578 71 935820.306 1.500 + 12 42 30 72 Zn x -68145.495 2.142 8691.8053 0.0298 B- 442.7892 2.2934 71 926842.806 2.300 + 10 41 31 72 Ga -68588.284 0.818 8687.0893 0.0114 B- 3997.6263 0.8217 71 926367.452 0.878 + 8 40 32 72 Ge -72585.910 0.076 8731.7459 0.0011 B- -4356.1019 4.0825 71 922075.824 0.081 + 6 39 33 72 As - -68229.808 4.083 8660.3786 0.0567 B- -361.6194 4.5276 71 926752.291 4.383 + 4 38 34 72 Se x -67868.189 1.956 8644.4902 0.0272 B- -8806.4384 2.2083 71 927140.506 2.100 + 2 37 35 72 Br x -59061.750 1.025 8511.3126 0.0142 B- -5121.1683 8.0761 71 936594.606 1.100 + 0 36 36 72 Kr x -53940.582 8.011 8429.3193 0.1113 B- -15611# 500# 71 942092.406 8.600 + -2 35 37 72 Rb x -38330# 500# 8202# 7# B- * 71 958851# 537# +0 23 48 25 73 Mn x -6700# 600# 7895# 8# B- 17289# 781# 72 992807# 644# + 21 47 26 73 Fe x -23990# 500# 8121# 7# B- 13980# 583# 72 974246# 537# + 19 46 27 73 Co x -37970# 300# 8302# 4# B- 12139# 300# 72 959238# 322# + 17 45 28 73 Ni x -50108.159 2.423 8457.6529 0.0332 B- 8879.2856 3.1038 72 946206.681 2.601 + 15 44 29 73 Cu -58987.445 1.942 8568.5699 0.0266 B- 6605.9659 2.6910 72 936674.376 2.084 + 13 43 30 73 Zn x -65593.411 1.863 8648.3455 0.0255 B- 4105.9329 2.5064 72 929582.580 2.000 + 11 42 31 73 Ga x -69699.343 1.677 8693.8740 0.0230 B- 1598.1889 1.6777 72 925174.680 1.800 + 9 41 32 73 Ge -71297.532 0.057 8705.0500 0.0008 B- -344.7759 3.8528 72 923458.954 0.061 + 7 40 33 73 As -70952.757 3.853 8689.6099 0.0528 B- -2725.3604 7.3993 72 923829.086 4.136 + 5 39 34 73 Se -68227.396 7.424 8641.5591 0.1017 B- -4581.6095 10.0278 72 926754.881 7.969 + 3 38 35 73 Br -63645.787 6.741 8568.0803 0.0923 B- -7094.0287 9.4187 72 931673.441 7.237 + 1 37 36 73 Kr x -56551.758 6.578 8460.1847 0.0901 B- -10540.1468 41.3212 72 939289.193 7.061 + -1 36 37 73 Rb -p -46011.611 40.794 8305.0821 0.5588 B- -14061# 403# 72 950604.506 43.794 + -3 35 38 73 Sr x -31950# 401# 8102# 5# B- * 72 965700# 430# +0 22 48 26 74 Fe x -20660# 500# 8076# 7# B- 12881# 640# 73 977821# 537# + 20 47 27 74 Co x -33540# 400# 8239# 5# B- 15160# 447# 73 963993# 429# + 18 46 28 74 Ni x -48700# 200# 8433# 3# B- 7306# 200# 73 947718# 215# + 16 45 29 74 Cu x -56006.213 6.148 8521.5633 0.0831 B- 9750.5077 6.6424 73 939874.860 6.600 + 14 44 30 74 Zn x -65756.720 2.515 8642.7547 0.0340 B- 2292.9057 3.9102 73 929407.260 2.700 + 12 43 31 74 Ga x -68049.626 2.994 8663.1676 0.0405 B- 5372.8249 2.9941 73 926945.725 3.214 + 10 42 32 74 Ge -73422.451 0.013 8725.2011 0.0003 B- -2562.3871 1.6931 73 921177.760 0.013 + 8 41 33 74 As -70860.064 1.693 8680.0020 0.0229 B- 1353.1467 1.6931 73 923928.596 1.817 + 6 40 34 74 Se -72213.210 0.015 8687.7155 0.0003 B- -6925.0492 5.8354 73 922475.933 0.015 + 4 39 35 74 Br -65288.161 5.835 8583.5615 0.0789 B- -2956.3173 6.1730 73 929910.279 6.264 + 2 38 36 74 Kr -62331.844 2.013 8533.0390 0.0272 B- -10415.8280 3.4240 73 933084.016 2.161 + 0 37 37 74 Rb -51916.016 3.027 8381.7123 0.0409 B- -11089# 100# 73 944265.867 3.249 + -2 36 38 74 Sr x -40827# 100# 8221# 1# B- * 73 956170# 107# +0 23 49 26 75 Fe x -14700# 600# 7996# 8# B- 15861# 721# 74 984219# 644# + 21 48 27 75 Co x -30560# 400# 8197# 5# B- 13680# 447# 74 967192# 429# + 19 47 28 75 Ni x -44240# 200# 8369# 3# B- 10230# 200# 74 952506# 215# + 17 46 29 75 Cu -54470.219 0.718 8495.0801 0.0096 B- 8088.6967 2.0837 74 941523.817 0.770 + 15 45 30 75 Zn x -62558.916 1.956 8592.4981 0.0261 B- 5901.7231 2.0679 74 932840.244 2.100 + 13 44 31 75 Ga x -68460.639 0.671 8660.7565 0.0089 B- 3396.3337 0.6727 74 926504.484 0.720 + 11 43 32 75 Ge -n -71856.973 0.052 8695.6096 0.0007 B- 1177.2301 0.8851 74 922858.370 0.055 + 9 42 33 75 As -73034.203 0.884 8700.8748 0.0118 B- -864.7139 0.8816 74 921594.562 0.948 + 7 41 34 75 Se -72169.489 0.073 8678.9139 0.0010 B- -3062.4694 4.2855 74 922522.870 0.078 + 5 40 35 75 Br x -69107.020 4.285 8627.6497 0.0571 B- -4783.3880 9.1671 74 925810.566 4.600 + 3 39 36 75 Kr x -64323.632 8.104 8553.4399 0.1081 B- -7104.9299 8.1895 74 930945.744 8.700 + 1 38 37 75 Rb x -57218.702 1.180 8448.2762 0.0157 B- -10600.0000 220.0000 74 938573.200 1.266 + -1 37 38 75 Sr - -46618.702 220.003 8296.5116 2.9334 B- -14799# 372# 74 949952.767 236.183 + -3 36 39 75 Y x -31820# 300# 8089# 4# B- * 74 965840# 322# +0 24 50 26 76 Fe x -10590# 600# 7943# 8# B- 15070# 781# 75 988631# 644# + 22 49 27 76 Co x -25660# 500# 8131# 7# B- 16530# 583# 75 972453# 537# + 20 48 28 76 Ni x -42190# 300# 8338# 4# B- 8791# 300# 75 954707# 322# + 18 47 29 76 Cu x -50981.627 0.913 8443.6018 0.0120 B- 11321.3964 1.7183 75 945268.974 0.980 + 16 46 30 76 Zn -62303.024 1.456 8582.2735 0.0192 B- 3993.6241 2.4384 75 933114.956 1.562 + 14 45 31 76 Ga x -66296.648 1.956 8624.5272 0.0257 B- 6916.2501 1.9562 75 928827.624 2.100 + 12 44 32 76 Ge -73212.898 0.018 8705.2364 0.0003 B- -921.5145 0.8864 75 921402.725 0.019 + 10 43 33 76 As -n -72291.384 0.886 8682.8172 0.0117 B- 2960.5756 0.8864 75 922392.011 0.951 + 8 42 34 76 Se -75251.959 0.016 8711.4781 0.0003 B- -4962.8810 9.3218 75 919213.702 0.017 + 6 41 35 76 Br - -70289.078 9.322 8635.8830 0.1227 B- -1275.3724 10.1490 75 924541.574 10.007 + 4 40 36 76 Kr -69013.706 4.013 8608.8077 0.0528 B- -8534.6172 4.1214 75 925910.743 4.308 + 2 39 37 76 Rb x -60479.089 0.938 8486.2161 0.0123 B- -6231.4432 34.4780 75 935073.031 1.006 + 0 38 38 76 Sr x -54247.645 34.465 8393.9294 0.4535 B- -15998# 302# 75 941762.760 37.000 + -2 37 39 76 Y x -38250# 300# 8173# 4# B- * 75 958937# 322# +0 23 50 27 77 Co x -21910# 600# 8082# 8# B- 15440# 721# 76 976479# 644# + 21 49 28 77 Ni x -37350# 400# 8272# 5# B- 11513# 400# 76 959903# 429# + 19 48 29 77 Cu x -48862.828 1.211 8411.2501 0.0157 B- 9926.3750 2.3148 76 947543.599 1.300 + 17 47 30 77 Zn -58789.203 1.973 8530.0037 0.0256 B- 7203.1495 3.1237 76 936887.197 2.117 + 15 46 31 77 Ga x -65992.352 2.422 8613.3907 0.0315 B- 5220.5176 2.4225 76 929154.299 2.600 + 13 45 32 77 Ge -n -71212.870 0.053 8671.0293 0.0007 B- 2703.4642 1.6926 76 923549.843 0.056 + 11 44 33 77 As -73916.334 1.692 8695.9789 0.0220 B- 683.1627 1.6920 76 920647.555 1.816 + 9 43 34 77 Se -74599.497 0.062 8694.6908 0.0008 B- -1364.6792 2.8099 76 919914.150 0.067 + 7 42 35 77 Br - -73234.818 2.811 8666.8073 0.0365 B- -3065.3663 3.4244 76 921379.193 3.017 + 5 41 36 77 Kr x -70169.451 1.956 8616.8370 0.0254 B- -5338.9516 2.3510 76 924669.999 2.100 + 3 40 37 77 Rb x -64830.500 1.304 8537.3396 0.0169 B- -7027.0566 8.0244 76 930401.599 1.400 + 1 39 38 77 Sr x -57803.443 7.918 8435.9188 0.1028 B- -11365# 203# 76 937945.454 8.500 + -1 38 39 77 Y -p -46439# 203# 8278# 3# B- -14839# 448# 76 950146# 218# + -3 37 40 77 Zr x -31600# 400# 8075# 5# B- * 76 966076# 429# +0 24 51 27 78 Co x -15320# 700# 7997# 9# B- 19560# 806# 77 983553# 751# + 22 50 28 78 Ni x -34880# 400# 8238# 5# B- 9910# 400# 77 962555# 429# + 20 49 29 78 Cu -44789.474 13.332 8354.6695 0.1709 B- 12693.7680 13.4727 77 951916.524 14.312 + 18 48 30 78 Zn -57483.242 1.944 8507.3800 0.0249 B- 6220.8433 2.2088 77 938289.204 2.086 + 16 47 31 78 Ga -63704.085 1.051 8577.1043 0.0135 B- 8157.9729 3.6884 77 931610.854 1.127 + 14 46 32 78 Ge -nn -71862.058 3.536 8671.6636 0.0453 B- 954.9114 10.3987 77 922852.911 3.795 + 12 45 33 78 As +pn -72816.970 9.779 8673.8760 0.1254 B- 4208.9819 9.7801 77 921827.771 10.498 + 10 44 34 78 Se -77025.952 0.179 8717.8072 0.0023 B- -3573.7836 3.5750 77 917309.244 0.191 + 8 43 35 78 Br - -73452.168 3.580 8661.9594 0.0459 B- 726.1153 3.5845 77 921145.858 3.842 + 6 42 36 78 Kr -74178.283 0.307 8661.2385 0.0039 B- -7242.8560 3.2520 77 920366.341 0.329 + 4 41 37 78 Rb x -66935.427 3.237 8558.3512 0.0415 B- -3761.4779 8.1248 77 928141.866 3.475 + 2 40 38 78 Sr x -63173.949 7.452 8500.0971 0.0955 B- -11001# 298# 77 932179.979 8.000 + 0 39 39 78 Y x -52173# 298# 8349# 4# B- -11323# 499# 77 943990# 320# + -2 38 40 78 Zr x -40850# 400# 8194# 5# B- * 77 956146# 429# +0 23 51 28 79 Ni x -28160# 500# 8150# 6# B- 14248# 511# 78 969769# 537# + 21 50 29 79 Cu x -42408.039 104.979 8320.9380 1.3289 B- 11024.2629 105.0030 78 954473.100 112.700 + 19 49 30 79 Zn -53432.302 2.225 8450.5825 0.0282 B- 9116.0536 2.5295 78 942638.067 2.388 + 17 48 31 79 Ga -62548.355 1.208 8556.0725 0.0153 B- 6978.8242 37.1467 78 932851.582 1.296 + 15 47 32 79 Ge -69527.180 37.161 8634.5089 0.4704 B- 4108.9014 37.4361 78 925359.506 39.893 + 13 46 33 79 As -73636.081 5.325 8676.6172 0.0674 B- 2281.3849 5.3284 78 920948.419 5.716 + 11 45 34 79 Se -n -75917.466 0.223 8695.5923 0.0028 B- 150.6016 1.0186 78 918499.252 0.238 + 9 44 35 79 Br -76068.067 1.001 8687.5956 0.0127 B- -1625.7778 3.3333 78 918337.574 1.074 + 7 43 36 79 Kr - -74442.290 3.480 8657.1130 0.0441 B- -3639.5114 3.9423 78 920082.919 3.736 + 5 42 37 79 Rb -70802.778 1.943 8601.1401 0.0246 B- -5323.1140 7.5630 78 923990.095 2.085 + 3 41 38 79 Sr -65479.664 7.421 8523.8558 0.0939 B- -7676.7291 80.4515 78 929704.692 7.967 + 1 40 39 79 Y x -57802.935 80.108 8416.7788 1.0140 B- -11033# 310# 78 937946.000 86.000 + -1 39 40 79 Zr x -46770# 300# 8267# 4# B- -15120# 583# 78 949790# 322# + -3 38 41 79 Nb x -31650# 500# 8066# 6# B- * 78 966022# 537# +0 24 52 28 80 Ni x -23240# 600# 8088# 7# B- 13440# 671# 79 975051# 644# + 22 51 29 80 Cu x -36679# 300# 8246# 4# B- 14969# 300# 79 960623# 322# + 20 50 30 80 Zn -51648.619 2.585 8423.5457 0.0323 B- 7575.0553 3.8774 79 944552.929 2.774 + 18 49 31 80 Ga x -59223.675 2.891 8508.4545 0.0361 B- 10311.6397 3.5409 79 936420.773 3.103 + 16 48 32 80 Ge x -69535.314 2.054 8627.5707 0.0257 B- 2679.2869 3.9156 79 925350.773 2.205 + 14 47 33 80 As x -72214.601 3.333 8651.2824 0.0417 B- 5544.8861 3.4412 79 922474.440 3.578 + 12 46 34 80 Se -77759.487 0.947 8710.8142 0.0118 B- -1870.4623 0.3095 79 916521.761 1.016 + 10 45 35 80 Br -75889.025 0.993 8677.6541 0.0124 B- 2004.4299 1.1413 79 918529.784 1.065 + 8 44 36 80 Kr -77893.455 0.695 8692.9301 0.0087 B- -5717.9785 1.9883 79 916377.940 0.745 + 6 43 37 80 Rb x -72175.476 1.863 8611.6760 0.0233 B- -1864.0090 3.9331 79 922516.442 2.000 + 4 42 38 80 Sr x -70311.467 3.464 8578.5966 0.0433 B- -9163.3050 7.1389 79 924517.538 3.718 + 2 41 39 80 Y x -61148.162 6.242 8454.2759 0.0780 B- -6388# 300# 79 934354.750 6.701 + 0 40 40 80 Zr x -54760# 300# 8365# 4# B- -16339# 500# 79 941213# 322# + -2 39 41 80 Nb x -38420# 400# 8151# 5# B- * 79 958754# 429# +0 25 53 28 81 Ni x -16090# 700# 8000# 9# B- 15820# 761# 80 982727# 751# + 23 52 29 81 Cu x -31910# 300# 8185# 4# B- 14289# 300# 80 965743# 322# + 21 51 30 81 Zn x -46199.669 5.030 8351.9262 0.0621 B- 11428.2924 5.9960 80 950402.617 5.400 + 19 50 31 81 Ga x -57627.962 3.264 8483.3576 0.0403 B- 8663.7335 3.8508 80 938133.841 3.503 + 17 49 32 81 Ge x -66291.695 2.055 8580.6587 0.0254 B- 6241.6189 3.3436 80 928832.941 2.205 + 15 48 33 81 As -72533.314 2.644 8648.0571 0.0326 B- 3855.7050 2.8072 80 922132.288 2.838 + 13 47 34 81 Se -76389.019 0.977 8685.9998 0.0121 B- 1588.0317 1.3787 80 917993.019 1.049 + 11 46 35 81 Br -77977.051 0.978 8695.9465 0.0121 B- -280.8517 0.4713 80 916288.197 1.049 + 9 45 36 81 Kr -77696.199 1.074 8682.8206 0.0133 B- -2239.4954 5.0188 80 916589.703 1.152 + 7 44 37 81 Rb -75456.704 4.904 8645.5139 0.0605 B- -3928.5695 5.8170 80 918993.900 5.265 + 5 43 38 81 Sr x -71528.134 3.128 8587.3545 0.0386 B- -5815.2156 6.2451 80 923211.393 3.358 + 3 42 39 81 Y x -65712.919 5.405 8505.9031 0.0667 B- -8188.5003 92.3762 80 929454.283 5.802 + 1 41 40 81 Zr x -57524.418 92.218 8395.1519 1.1385 B- -11164# 410# 80 938245.000 99.000 + -1 40 41 81 Nb x -46360# 400# 8248# 5# B- -14900# 640# 80 950230# 429# + -3 39 42 81 Mo x -31460# 500# 8054# 6# B- * 80 966226# 537# +0 26 54 28 82 Ni x -10720# 800# 7935# 10# B- 15010# 894# 81 988492# 859# + 24 53 29 82 Cu x -25730# 400# 8108# 5# B- 16584# 400# 81 972378# 429# + 22 52 30 82 Zn x -42313.960 3.074 8301.1175 0.0375 B- 10616.7652 3.9162 81 954574.097 3.300 + 20 51 31 82 Ga x -52930.725 2.426 8421.0494 0.0296 B- 12484.3497 3.2960 81 943176.531 2.604 + 18 50 32 82 Ge x -65415.075 2.240 8563.7567 0.0273 B- 4690.3523 4.3452 81 929774.031 2.405 + 16 49 33 82 As x -70105.427 3.729 8611.4153 0.0455 B- 7488.4677 3.7579 81 924738.731 4.003 + 14 48 34 82 Se -77593.895 0.466 8693.1973 0.0057 B- -95.2184 1.0767 81 916699.531 0.500 + 12 47 35 82 Br -77498.677 0.971 8682.4953 0.0118 B- 3093.1185 0.9714 81 916801.752 1.042 + 10 46 36 82 Kr -80591.79509 0.00551 8710.6754 0.0003 B- -4403.9824 3.0088 81 913481.15368 0.00591 + 8 45 37 82 Rb IT -76187.813 3.009 8647.4275 0.0367 B- -177.7503 6.7048 81 918209.023 3.230 + 6 44 38 82 Sr -76010.062 5.992 8635.7190 0.0731 B- -7945.9650 8.1324 81 918399.845 6.432 + 4 43 39 82 Y x -68064.097 5.499 8529.2762 0.0671 B- -4450.0341 5.7221 81 926930.189 5.902 + 2 42 40 82 Zr x -63614.063 1.584 8465.4666 0.0193 B- -11804# 300# 81 931707.497 1.700 + 0 41 41 82 Nb x -51810# 300# 8312# 4# B- -11440# 500# 81 944380# 322# + -2 40 42 82 Mo x -40370# 400# 8163# 5# B- * 81 956661# 429# +0 25 54 29 83 Cu x -20390# 500# 8044# 6# B- 15900# 583# 82 978110# 537# + 23 53 30 83 Zn x -36290# 300# 8226# 4# B- 12967# 300# 82 961041# 322# + 21 52 31 83 Ga x -49257.129 2.612 8372.5756 0.0315 B- 11719.3136 3.5592 82 947120.300 2.804 + 19 51 32 83 Ge x -60976.442 2.427 8504.3462 0.0292 B- 8692.8893 3.6979 82 934539.100 2.604 + 17 50 33 83 As x -69669.331 2.799 8599.6540 0.0337 B- 5671.2117 4.1290 82 925206.900 3.004 + 15 49 34 83 Se -n -75340.543 3.036 8658.5560 0.0366 B- 3673.1780 4.8392 82 919118.604 3.259 + 13 48 35 83 Br -79013.721 3.795 8693.3852 0.0457 B- 976.9222 3.7947 82 915175.285 4.073 + 11 47 36 83 Kr -79990.643 0.009 8695.7295 0.0003 B- -920.0039 2.3288 82 914126.516 0.009 + 9 46 37 83 Rb -79070.639 2.329 8675.2193 0.0281 B- -2273.0239 6.4245 82 915114.181 2.500 + 7 45 38 83 Sr -76797.616 6.834 8638.4076 0.0823 B- -4591.9435 19.8444 82 917554.372 7.336 + 5 44 39 83 Y x -72205.672 18.631 8573.6571 0.2245 B- -6294.0125 19.7074 82 922484.026 20.000 + 3 43 40 83 Zr x -65911.659 6.430 8488.3997 0.0775 B- -8298.7493 162.2075 82 929240.926 6.902 + 1 42 41 83 Nb x -57612.910 162.080 8378.9889 1.9528 B- -11273# 432# 82 938150.000 174.000 + -1 41 42 83 Mo x -46340# 401# 8234# 5# B- -15020# 641# 82 950252# 430# + -3 40 43 83 Tc x -31320# 500# 8043# 6# B- * 82 966377# 537# +0 26 55 29 84 Cu x -13720# 500# 7965# 6# B- 18110# 640# 83 985271# 537# + 24 54 30 84 Zn x -31830# 400# 8171# 5# B- 12264# 401# 83 965829# 429# + 22 53 31 84 Ga x -44094.136 29.808 8307.5250 0.3549 B- 14054.2989 29.9760 83 952663.000 32.000 + 20 52 32 84 Ge x -58148.435 3.171 8465.5244 0.0377 B- 7705.1329 4.4789 83 937575.090 3.403 + 18 51 33 84 As x -65853.568 3.171 8547.9385 0.0377 B- 10094.1624 3.7219 83 929303.290 3.403 + 16 50 34 84 Se -75947.731 1.961 8658.7935 0.0233 B- 1835.3638 25.7652 83 918466.761 2.105 + 14 49 35 84 Br -77783.094 25.730 8671.3294 0.3063 B- 4656.2510 25.7300 83 916496.417 27.622 + 12 48 36 84 Kr -82439.34527 0.00382 8717.4473 0.0003 B- -2680.3708 2.1940 83 911497.72708 0.00410 + 10 47 37 84 Rb -79758.975 2.194 8676.2244 0.0261 B- 890.6058 2.3356 83 914375.223 2.355 + 8 46 38 84 Sr -80649.580 1.243 8677.5132 0.0148 B- -6755.1411 4.4114 83 913419.118 1.334 + 6 45 39 84 Y -73894.439 4.299 8587.7812 0.0512 B- -2472.7471 6.9767 83 920671.060 4.615 + 4 44 40 84 Zr x -71421.692 5.499 8549.0301 0.0655 B- -10227.8497 5.5133 83 923325.663 5.903 + 2 43 41 84 Nb x -61193.842 0.401 8417.9563 0.0048 B- -7024# 298# 83 934305.711 0.430 + 0 42 42 84 Mo x -54170# 298# 8325# 4# B- -16470# 499# 83 941846# 320# + -2 41 43 84 Tc x -37700# 400# 8120# 5# B- * 83 959527# 429# +0 25 55 30 85 Zn x -25100# 500# 8090# 6# B- 14644# 502# 84 973054# 537# + 23 54 31 85 Ga x -39744.059 37.260 8253.5687 0.4384 B- 13379.3679 37.4459 84 957333.000 40.000 + 21 53 32 85 Ge x -53123.427 3.729 8401.7689 0.0439 B- 10065.7253 4.8303 84 942969.658 4.003 + 19 52 33 85 As x -63189.152 3.078 8510.9851 0.0362 B- 9224.4929 4.0313 84 932163.658 3.304 + 17 51 34 85 Se +3p -72413.645 2.613 8610.3045 0.0307 B- 6161.8335 4.0313 84 922260.758 2.804 + 15 50 35 85 Br +n2p -78575.478 3.078 8673.5926 0.0362 B- 2904.8622 3.6705 84 915645.758 3.304 + 13 49 36 85 Kr + -81480.341 2.000 8698.5633 0.0235 B- 687.0000 2.0000 84 912527.260 2.147 + 11 48 37 85 Rb -82167.34065 0.00500 8697.4416 0.0003 B- -1064.0510 2.8132 84 911789.73604 0.00537 + 9 47 38 85 Sr -81103.290 2.813 8675.7193 0.0331 B- -3261.1584 19.1729 84 912932.041 3.020 + 7 46 39 85 Y x -77842.131 18.965 8628.1486 0.2231 B- -4666.9352 20.0257 84 916433.039 20.360 + 5 45 40 85 Zr x -73175.196 6.430 8564.0394 0.0756 B- -6895.5120 7.6250 84 921443.199 6.902 + 3 44 41 85 Nb x -66279.684 4.099 8473.7117 0.0482 B- -8769.9238 16.3572 84 928845.836 4.400 + 1 43 42 85 Mo x -57509.760 15.835 8361.3320 0.1863 B- -11660# 400# 84 938260.736 17.000 + -1 42 43 85 Tc x -45850# 400# 8215# 5# B- -15220# 640# 84 950778# 429# + -3 41 44 85 Ru x -30630# 500# 8027# 6# B- * 84 967117# 537# +0 26 56 30 86 Zn x -20062# 500# 8032# 6# B- 13699# 640# 85 978463# 537# + 24 55 31 86 Ga x -33760# 400# 8182# 5# B- 15640# 593# 85 963757# 429# + 22 54 32 86 Ge x -49399.927 437.802 8354.6300 5.0907 B- 9562.2229 437.8158 85 946967.000 470.000 + 20 53 33 86 As x -58962.150 3.450 8456.7215 0.0401 B- 11541.0256 4.2666 85 936701.532 3.703 + 18 52 34 86 Se x -70503.175 2.520 8581.8224 0.0293 B- 5129.0860 3.9717 85 924311.732 2.705 + 16 51 35 86 Br +pp -75632.261 3.078 8632.3659 0.0358 B- 7633.4147 3.0779 85 918805.432 3.304 + 14 50 36 86 Kr -83265.67593 0.00372 8712.0295 0.0003 B- -518.6734 0.2000 85 910610.62468 0.00399 + 12 49 37 86 Rb -n -82747.003 0.200 8696.9014 0.0023 B- 1776.0972 0.2001 85 911167.443 0.214 + 10 48 38 86 Sr -84523.09977 0.00524 8708.4566 0.0003 B- -5240.0000 14.1421 85 909260.72473 0.00563 + 8 47 39 86 Y - -79283.100 14.142 8638.4293 0.1644 B- -1314.0763 14.5847 85 914886.095 15.182 + 6 46 40 86 Zr -77969.023 3.566 8614.0523 0.0415 B- -8834.9627 6.5521 85 916296.814 3.827 + 4 45 41 86 Nb x -69134.061 5.499 8502.2231 0.0639 B- -5023.1337 6.2316 85 925781.536 5.903 + 2 44 42 86 Mo x -64110.927 2.932 8434.7175 0.0341 B- -12541# 300# 85 931174.092 3.147 + 0 43 43 86 Tc x -51570# 300# 8280# 3# B- -11800# 500# 85 944637# 322# + -2 42 44 86 Ru x -39770# 400# 8133# 5# B- * 85 957305# 429# +0 25 56 31 87 Ga x -28870# 500# 8124# 6# B- 14720# 583# 86 969007# 537# + 23 55 32 87 Ge x -43590# 300# 8285# 3# B- 12028# 300# 86 953204# 322# + 21 54 33 87 As x -55617.914 2.985 8413.8521 0.0343 B- 10808.2192 3.7260 86 940291.716 3.204 + 19 53 34 87 Se x -66426.133 2.241 8529.0920 0.0258 B- 7465.5526 3.8766 86 928688.616 2.405 + 17 52 35 87 Br 2p-n -73891.685 3.171 8605.9105 0.0364 B- 6817.8455 3.1805 86 920674.016 3.404 + 15 51 36 87 Kr -n -80709.531 0.246 8675.2840 0.0028 B- 3888.2706 0.2463 86 913354.759 0.264 + 13 50 37 87 Rb -84597.802 0.006 8710.9843 0.0003 B- 282.2749 0.0063 86 909180.529 0.006 + 11 49 38 87 Sr -84880.07643 0.00513 8705.2363 0.0003 B- -1861.6894 1.1278 86 908877.49454 0.00550 + 9 48 39 87 Y - -83018.387 1.128 8674.8451 0.0130 B- -3671.2405 4.2962 86 910876.100 1.210 + 7 47 40 87 Zr -79347.147 4.146 8623.6545 0.0477 B- -5472.6536 7.9633 86 914817.338 4.450 + 5 46 41 87 Nb x -73874.493 6.802 8551.7579 0.0782 B- -6989.6757 7.3781 86 920692.473 7.302 + 3 45 42 87 Mo -66884.817 2.857 8462.4243 0.0328 B- -9194.7656 5.0729 86 928196.198 3.067 + 1 44 43 87 Tc x -57690.052 4.192 8347.7449 0.0482 B- -11960# 400# 86 938067.185 4.500 + -1 43 44 87 Ru x -45730# 400# 8201# 5# B- * 86 950907# 429# +0 26 57 31 88 Ga x -22390# 500# 8050# 6# B- 17129# 640# 87 975963# 537# + 24 56 32 88 Ge x -39520# 400# 8236# 5# B- 10930# 447# 87 957574# 429# + 22 55 33 88 As x -50450# 200# 8351# 2# B- 13434# 200# 87 945840# 215# + 20 54 34 88 Se x -63884.203 3.357 8495.0045 0.0382 B- 6831.7640 4.6125 87 931417.490 3.604 + 18 53 35 88 Br ++ -70715.967 3.171 8563.7479 0.0360 B- 8975.3282 4.1059 87 924083.290 3.404 + 16 52 36 88 Kr x -79691.295 2.608 8656.8499 0.0296 B- 2917.7090 2.6130 87 914447.879 2.800 + 14 51 37 88 Rb -82609.004 0.159 8681.1154 0.0018 B- 5312.6243 0.1590 87 911315.590 0.170 + 12 50 38 88 Sr -87921.62876 0.00561 8732.5958 0.0003 B- -3622.6000 1.5000 87 905612.253 0.006 + 10 49 39 88 Y - -84299.029 1.500 8682.5396 0.0170 B- -670.1549 5.6076 87 909501.274 1.610 + 8 48 40 88 Zr -83628.874 5.403 8666.0339 0.0614 B- -7457.3187 57.8921 87 910220.715 5.800 + 6 47 41 88 Nb -76171.555 57.808 8572.4013 0.6569 B- -3485.0021 57.9345 87 918226.476 62.059 + 4 46 42 88 Mo x -72686.553 3.819 8523.9087 0.0434 B- -11016.2515 5.6021 87 921967.779 4.100 + 2 45 43 88 Tc x -61670.301 4.099 8389.8338 0.0466 B- -7331# 300# 87 933794.211 4.400 + 0 44 44 88 Ru x -54340# 300# 8298# 3# B- -17479# 500# 87 941664# 322# + -2 43 45 88 Rh x -36860# 400# 8090# 5# B- * 87 960429# 429# +0 25 57 32 89 Ge x -33040# 400# 8161# 4# B- 13490# 500# 88 964530# 429# + 23 56 33 89 As x -46530# 300# 8304# 3# B- 12462# 300# 88 950048# 322# + 21 55 34 89 Se x -58992.398 3.729 8435.2799 0.0419 B- 9281.8730 4.9510 88 936669.058 4.003 + 19 54 35 89 Br x -68274.271 3.264 8530.7802 0.0367 B- 8261.5231 3.9045 88 926704.558 3.504 + 17 53 36 89 Kr x -76535.795 2.142 8614.8158 0.0241 B- 5176.6042 5.8342 88 917835.449 2.300 + 15 52 37 89 Rb -81712.399 5.427 8664.1895 0.0610 B- 4496.6278 5.4265 88 912278.136 5.825 + 13 51 38 89 Sr -86209.026 0.092 8705.9230 0.0011 B- 1502.1757 0.3510 88 907450.808 0.098 + 11 50 39 89 Y -87711.202 0.339 8714.0110 0.0038 B- -2833.2285 2.7652 88 905838.156 0.363 + 9 49 40 89 Zr -84877.974 2.780 8673.3865 0.0312 B- -4252.2191 23.7199 88 908879.751 2.983 + 7 48 41 89 Nb -80625.755 23.630 8616.8184 0.2655 B- -5610.8105 23.9513 88 913444.696 25.367 + 5 47 42 89 Mo x -75014.944 3.912 8544.9851 0.0440 B- -7620.0875 5.4673 88 919468.149 4.200 + 3 46 43 89 Tc x -67394.857 3.819 8450.5758 0.0429 B- -9025.4327 24.5181 88 927648.649 4.100 + 1 45 44 89 Ru x -58369.424 24.219 8340.3760 0.2721 B- -12719# 361# 88 937337.849 26.000 + -1 44 45 89 Rh -p -45651# 361# 8189# 4# B- * 88 950992# 387# +0 26 58 32 90 Ge x -28470# 500# 8109# 6# B- 12520# 640# 89 969436# 537# + 24 57 33 90 As x -40990# 400# 8240# 4# B- 14810# 518# 89 955995# 429# + 22 56 34 90 Se x -55800.223 329.749 8395.7672 3.6639 B- 8200.0834 329.7660 89 940096.000 354.000 + 20 55 35 90 Br x -64000.306 3.357 8478.1865 0.0373 B- 10958.9533 3.8396 89 931292.848 3.604 + 18 54 36 90 Kr x -74959.259 1.863 8591.2599 0.0207 B- 4406.3133 6.7158 89 919527.929 2.000 + 16 53 37 90 Rb -79365.573 6.452 8631.5262 0.0717 B- 6585.3721 6.4806 89 914797.557 6.926 + 14 52 38 90 Sr -85950.945 1.449 8696.0043 0.0161 B- 545.9674 1.4060 89 907727.870 1.555 + 12 51 39 90 Y -86496.912 0.354 8693.3778 0.0039 B- 2275.6350 0.3726 89 907141.749 0.379 + 10 50 40 90 Zr -88772.547 0.118 8709.9699 0.0013 B- -6111.0165 3.3163 89 904698.755 0.126 + 8 49 41 90 Nb -82661.531 3.317 8633.3770 0.0369 B- -2489.0165 3.3163 89 911259.201 3.561 + 6 48 42 90 Mo -80172.514 3.463 8597.0285 0.0385 B- -9447.8181 3.6110 89 913931.270 3.717 + 4 47 43 90 Tc x -70724.696 1.025 8483.3600 0.0114 B- -5840.8951 3.8685 89 924073.919 1.100 + 2 46 44 90 Ru -64883.801 3.730 8409.7684 0.0414 B- -13250# 200# 89 930344.378 4.004 + 0 45 45 90 Rh - -51634# 200# 8254# 2# B- -11924# 447# 89 944569# 215# + -2 44 46 90 Pd x -39710# 400# 8113# 4# B- * 89 957370# 429# +0 25 58 33 91 As x -36500# 400# 8189# 4# B- 14080# 589# 90 960816# 429# + 23 57 34 91 Se x -50580.130 433.145 8334.8382 4.7598 B- 10527.1716 433.1593 90 945700.000 465.000 + 21 56 35 91 Br -n2p -61107.301 3.543 8441.9242 0.0389 B- 9866.6724 4.1898 90 934398.617 3.804 + 19 55 36 91 Kr x -70973.974 2.236 8541.7519 0.0246 B- 6771.0748 8.1153 90 923806.309 2.400 + 17 54 37 91 Rb -77745.049 7.801 8607.5621 0.0857 B- 5906.9010 8.8732 90 916537.261 8.375 + 15 53 38 91 Sr -83651.950 5.453 8663.8759 0.0599 B- 2699.3714 5.2468 90 910195.942 5.853 + 13 52 39 91 Y -86351.321 1.843 8684.9421 0.0203 B- 1544.2710 1.8403 90 907298.048 1.978 + 11 51 40 91 Zr -87895.592 0.095 8693.3149 0.0011 B- -1257.5644 2.9243 90 905640.205 0.101 + 9 50 41 91 Nb -86638.028 2.926 8670.8983 0.0322 B- -4429.1934 6.7439 90 906990.256 3.140 + 7 49 42 91 Mo -82208.834 6.238 8613.6286 0.0686 B- -6222.1768 6.6706 90 911745.190 6.696 + 5 48 43 91 Tc -75986.657 2.363 8536.6558 0.0260 B- -7746.8246 3.2422 90 918424.972 2.536 + 3 47 44 91 Ru -68239.833 2.221 8442.9287 0.0244 B- -9670# 298# 90 926741.530 2.384 + 1 46 45 91 Rh x -58570# 298# 8328# 3# B- -12400# 300# 90 937123# 320# + -1 45 46 91 Pd - -46170# 423# 8183# 5# B- * 90 950435# 454# +0 26 59 33 92 As x -30380# 500# 8121# 5# B- 16344# 640# 91 967386# 537# + 24 58 34 92 Se x -46724# 400# 8290# 4# B- 9509# 400# 91 949840# 429# + 22 57 35 92 Br x -56232.812 6.709 8384.9123 0.0729 B- 12536.5161 7.2322 91 939631.595 7.202 + 20 56 36 92 Kr x -68769.329 2.701 8512.6750 0.0294 B- 6003.1210 6.6924 91 926173.092 2.900 + 18 55 37 92 Rb -74772.450 6.123 8569.4225 0.0666 B- 8094.9212 6.4187 91 919728.477 6.573 + 16 54 38 92 Sr -82867.371 3.423 8648.9070 0.0372 B- 1949.1237 9.3841 91 911038.222 3.675 + 14 53 39 92 Y -84816.494 9.127 8661.5894 0.0992 B- 3642.5294 9.1271 91 908945.752 9.798 + 12 52 40 92 Zr -88459.024 0.094 8692.6783 0.0011 B- -2005.7335 1.7823 91 905035.336 0.101 + 10 51 41 92 Nb -86453.290 1.784 8662.3731 0.0194 B- 355.2968 1.7911 91 907188.580 1.915 + 8 50 42 92 Mo -86808.587 0.157 8657.7312 0.0017 B- -7882.8841 3.1063 91 906807.153 0.168 + 6 49 43 92 Tc -78925.703 3.102 8563.5440 0.0337 B- -4624.4922 4.1246 91 915269.777 3.330 + 4 48 44 92 Ru -74301.211 2.718 8504.7740 0.0295 B- -11302.1155 5.1531 91 920234.373 2.917 + 2 47 45 92 Rh x -62999.095 4.378 8373.4211 0.0476 B- -8220.0000 345.0000 91 932367.692 4.700 + 0 46 46 92 Pd - -54779.095 345.028 8275.5695 3.7503 B- -17249# 528# 91 941192.225 370.402 + -2 45 47 92 Ag x -37530# 400# 8080# 4# B- * 91 959710# 429# +0 25 59 34 93 Se x -40860# 400# 8225# 4# B- 12030# 588# 92 956135# 429# + 23 58 35 93 Br x -52890.235 430.816 8345.5986 4.6324 B- 11245.7673 430.8234 92 943220.000 462.500 + 21 57 36 93 Kr x -64136.002 2.515 8458.1085 0.0270 B- 8483.8977 8.2243 92 931147.172 2.700 + 19 56 37 93 Rb -72619.900 7.830 8540.9209 0.0842 B- 7465.9434 8.8761 92 922039.334 8.406 + 17 55 38 93 Sr -80085.844 7.554 8612.7875 0.0812 B- 4141.3118 11.6972 92 914024.314 8.109 + 15 54 39 93 Y -84227.155 10.488 8648.9054 0.1128 B- 2894.8723 10.4830 92 909578.434 11.259 + 13 53 40 93 Zr -87122.028 0.456 8671.6207 0.0049 B- 90.8123 1.4838 92 906470.661 0.489 + 11 52 41 93 Nb -87212.840 1.490 8664.1849 0.0160 B- -405.7609 1.5012 92 906373.170 1.599 + 9 51 42 93 Mo -n -86807.079 0.181 8651.4095 0.0020 B- -3200.9629 1.0040 92 906808.772 0.193 + 7 50 43 93 Tc -p -83606.116 1.012 8608.5782 0.0109 B- -6389.3929 2.2995 92 910245.147 1.086 + 5 49 44 93 Ru -77216.723 2.065 8531.4627 0.0222 B- -8204.9136 3.3425 92 917104.442 2.216 + 3 48 45 93 Rh -69011.810 2.629 8434.8255 0.0283 B- -10030.0000 370.0000 92 925912.778 2.821 + 1 47 46 93 Pd - -58981.810 370.009 8318.5637 3.9786 B- -12582# 545# 92 936680.426 397.221 + -1 46 47 93 Ag x -46400# 401# 8175# 4# B- * 92 950188# 430# +0 26 60 34 94 Se x -36803# 500# 8180# 5# B- 10846# 539# 93 960490# 537# + 24 59 35 94 Br x -47650# 200# 8287# 2# B- 13698# 201# 93 948846# 215# + 22 58 36 94 Kr x -61347.780 12.109 8424.3318 0.1288 B- 7215.0114 12.2782 93 934140.452 13.000 + 20 57 37 94 Rb -68562.791 2.029 8492.7644 0.0216 B- 10282.9297 2.6230 93 926394.819 2.177 + 18 56 38 94 Sr -78845.721 1.663 8593.8344 0.0177 B- 3505.7517 6.4220 93 915355.641 1.785 + 16 55 39 94 Y -82351.473 6.380 8622.8068 0.0679 B- 4917.8589 6.3799 93 911592.062 6.849 + 14 54 40 94 Zr -87269.332 0.164 8666.8016 0.0018 B- -900.2684 1.5000 93 906312.523 0.175 + 12 53 41 94 Nb -86369.063 1.491 8648.9014 0.0159 B- 2045.0163 1.4937 93 907279.001 1.600 + 10 52 42 94 Mo -88414.079 0.141 8662.3341 0.0015 B- -4255.7476 4.0687 93 905083.586 0.151 + 8 51 43 94 Tc - -84158.332 4.071 8608.7373 0.0433 B- -1574.7296 5.1433 93 909652.319 4.370 + 6 50 44 94 Ru -82583.602 3.143 8583.6620 0.0334 B- -9675.9789 4.6150 93 911342.860 3.374 + 4 49 45 94 Rh -72907.623 3.379 8472.4033 0.0359 B- -6805.3428 5.4588 93 921730.450 3.627 + 2 48 46 94 Pd x -66102.281 4.287 8391.6832 0.0456 B- -13700# 400# 93 929036.286 4.602 + 0 47 47 94 Ag - -52402# 400# 8238# 4# B- -11962# 640# 93 943744# 429# + -2 46 48 94 Cd x -40440# 500# 8102# 5# B- * 93 956586# 537# +0 27 61 34 95 Se x -30460# 500# 8112# 5# B- 13390# 583# 94 967300# 537# + 25 60 35 95 Br x -43850# 300# 8245# 3# B- 12309# 301# 94 952925# 322# + 23 59 36 95 Kr x -56158.920 18.630 8365.9963 0.1961 B- 9731.3868 27.5124 94 939710.922 20.000 + 21 58 37 95 Rb -65890.307 20.245 8460.1967 0.2131 B- 9226.9772 20.2036 94 929263.849 21.733 + 19 57 38 95 Sr -75117.284 5.810 8549.0875 0.0612 B- 6090.6528 7.2395 94 919358.282 6.237 + 17 56 39 95 Y -81207.937 6.779 8604.9644 0.0714 B- 4452.0031 6.7718 94 912819.697 7.277 + 15 55 40 95 Zr -85659.940 0.869 8643.5924 0.0092 B- 1126.3312 0.9854 94 908040.276 0.933 + 13 54 41 95 Nb -86786.272 0.508 8647.2133 0.0054 B- 925.6009 0.4938 94 906831.110 0.545 + 11 53 42 95 Mo -87711.872 0.123 8648.7212 0.0013 B- -1690.5175 5.0782 94 905837.436 0.132 + 9 52 43 95 Tc -86021.355 5.080 8622.6911 0.0535 B- -2563.5961 10.5310 94 907652.281 5.453 + 7 51 44 95 Ru -83457.759 9.502 8587.4706 0.1000 B- -5117.1423 10.2656 94 910404.415 10.200 + 5 50 45 95 Rh -78340.616 3.886 8525.3707 0.0409 B- -8374.7035 4.9281 94 915897.893 4.171 + 3 49 46 95 Pd x -69965.913 3.031 8428.9807 0.0319 B- -10060# 400# 94 924888.506 3.253 + 1 48 47 95 Ag - -59906# 400# 8315# 4# B- -12850# 400# 94 935688# 429# + -1 47 48 95 Cd - -47056# 566# 8171# 6# B- * 94 949483# 607# +0 26 61 35 96 Br x -38210# 300# 8184# 3# B- 14872# 301# 95 958980# 322# + 24 60 36 96 Kr -53081.682 19.277 8330.8721 0.2008 B- 8272.6693 19.5669 95 943014.473 20.695 + 22 59 37 96 Rb -61354.351 3.353 8408.8963 0.0349 B- 11563.8970 9.1062 95 934133.398 3.599 + 20 58 38 96 Sr -72918.248 8.466 8521.2041 0.0882 B- 5411.7380 9.7257 95 921719.045 9.089 + 18 57 39 96 Y -78329.986 6.075 8569.4269 0.0633 B- 7108.8741 6.0740 95 915909.305 6.521 + 16 56 40 96 Zr -85438.860 0.114 8635.3283 0.0012 B- 163.9704 0.1000 95 908277.615 0.122 + 14 55 41 96 Nb -85602.830 0.147 8628.8868 0.0015 B- 3192.0590 0.1070 95 908101.586 0.157 + 12 54 42 96 Mo -88794.889 0.120 8653.9880 0.0013 B- -2973.2411 5.1450 95 904674.770 0.128 + 10 53 43 96 Tc - -85821.648 5.146 8614.8673 0.0536 B- 258.7369 5.1464 95 907866.675 5.524 + 8 52 44 96 Ru -86080.385 0.170 8609.4130 0.0018 B- -6392.6529 10.0000 95 907588.910 0.182 + 6 51 45 96 Rh - -79687.732 10.001 8534.6735 0.1042 B- -3504.3127 10.8442 95 914451.705 10.737 + 4 50 46 96 Pd x -76183.420 4.194 8490.0207 0.0437 B- -11671.7741 90.1814 95 918213.739 4.502 + 2 49 47 96 Ag ep -64511.645 90.084 8360.2903 0.9384 B- -8940# 400# 95 930743.903 96.708 + 0 48 48 96 Cd - -55572# 410# 8259# 4# B- -17482# 647# 95 940341# 440# + -2 47 49 96 In x -38090# 500# 8069# 5# B- * 95 959109# 537# +0 27 62 35 97 Br x -34000# 400# 8140# 4# B- 13423# 420# 96 963499# 429# + 25 61 36 97 Kr x -47423.499 130.409 8269.8645 1.3444 B- 11095.6460 130.4232 96 949088.782 140.000 + 23 60 37 97 Rb -58519.145 1.912 8376.1872 0.0197 B- 10061.5295 3.8872 96 937177.117 2.052 + 21 59 38 97 Sr -68580.674 3.385 8471.8489 0.0349 B- 7534.7807 7.5131 96 926375.621 3.633 + 19 58 39 97 Y + -76115.455 6.708 8541.4616 0.0692 B- 6821.2382 6.7068 96 918286.702 7.201 + 17 57 40 97 Zr -82936.693 0.121 8603.7182 0.0013 B- 2666.1038 4.2435 96 910963.802 0.130 + 15 56 41 97 Nb -85602.797 4.244 8623.1384 0.0438 B- 1941.9038 4.2435 96 908101.622 4.556 + 13 55 42 97 Mo -87544.700 0.165 8635.0926 0.0017 B- -320.2640 4.1169 96 906016.903 0.176 + 11 54 43 97 Tc -87224.436 4.118 8623.7254 0.0425 B- -1103.8722 4.9563 96 906360.720 4.420 + 9 53 44 97 Ru -n -86120.564 2.763 8604.2799 0.0285 B- -3523.0000 35.3553 96 907545.776 2.965 + 7 52 45 97 Rh - -82597.564 35.463 8559.8949 0.3656 B- -4791.7118 35.7924 96 911327.872 38.071 + 5 51 46 97 Pd x -77805.852 4.844 8502.4303 0.0499 B- -6901.8255 12.9558 96 916471.985 5.200 + 3 50 47 97 Ag x -70904.027 12.016 8423.2121 0.1239 B- -10170.0000 420.0000 96 923881.400 12.900 + 1 49 48 97 Cd - -60734.027 420.172 8310.3013 4.3317 B- -13344# 580# 96 934799.343 451.073 + -1 48 49 97 In x -47390# 401# 8165# 4# B- * 96 949125# 430# +0 28 63 35 98 Br x -28050# 400# 8078# 4# B- 16070# 500# 97 969887# 429# + 26 62 36 98 Kr x -44120# 300# 8234# 3# B- 10249# 300# 97 952635# 322# + 24 61 37 98 Rb -54369.152 16.083 8330.7294 0.1641 B- 12053.2361 16.4029 97 941632.317 17.265 + 22 60 38 98 Sr -66422.389 3.226 8445.7385 0.0329 B- 5866.3591 8.5504 97 928692.636 3.463 + 20 59 39 98 Y p-2n -72288.748 7.919 8497.6162 0.0808 B- 8993.0098 11.5755 97 922394.841 8.501 + 18 58 40 98 Zr -81281.757 8.445 8581.3984 0.0862 B- 2242.8547 9.8134 97 912740.448 9.065 + 16 57 41 98 Nb -pn -83524.612 5.001 8596.3016 0.0510 B- 4591.3681 5.0032 97 910332.645 5.369 + 14 56 42 98 Mo -88115.980 0.174 8635.1691 0.0018 B- -1683.7664 3.3768 97 905403.609 0.186 + 12 55 43 98 Tc -86432.214 3.380 8610.0047 0.0345 B- 1792.6575 7.1568 97 907211.206 3.628 + 10 54 44 98 Ru -88224.871 6.463 8620.3140 0.0659 B- -5049.6529 10.0000 97 905286.709 6.937 + 8 53 45 98 Rh - -83175.219 11.906 8560.8038 0.1215 B- -1854.2331 12.8161 97 910707.734 12.782 + 6 52 46 98 Pd -81320.985 4.742 8533.8999 0.0484 B- -8254.5607 33.0975 97 912698.335 5.090 + 4 51 47 98 Ag -73066.425 32.907 8441.6866 0.3358 B- -5430.0000 40.0000 97 921559.970 35.327 + 2 50 48 98 Cd - -67636.425 51.797 8378.2953 0.5285 B- -13730# 300# 97 927389.315 55.605 + 0 49 49 98 In - -53906# 304# 8230# 3# B- * 97 942129# 327# +0 27 63 36 99 Kr x -38400# 400# 8175# 4# B- 12721# 400# 98 958776# 429# + 25 62 37 99 Rb x -51121.150 4.031 8295.3010 0.0407 B- 11397.3767 6.2201 98 945119.190 4.327 + 23 61 38 99 Sr -62518.527 4.737 8402.5235 0.0479 B- 8125.2037 8.1353 98 932883.604 5.085 + 21 60 39 99 Y x -70643.730 6.615 8476.6938 0.0668 B- 6972.9398 12.4082 98 924160.839 7.101 + 19 59 40 99 Zr -77616.670 10.499 8539.2250 0.1061 B- 4718.6736 15.9474 98 916675.081 11.271 + 17 58 41 99 Nb +p -82335.344 12.004 8578.9859 0.1213 B- 3634.7623 12.0059 98 911609.377 12.886 + 15 57 42 99 Mo -85970.106 0.229 8607.7982 0.0023 B- 1357.7631 0.8905 98 907707.299 0.245 + 13 56 43 99 Tc -87327.869 0.908 8613.6105 0.0092 B- 297.5156 0.9453 98 906249.681 0.974 + 11 55 44 99 Ru -87625.385 0.343 8608.7132 0.0035 B- -2040.8632 19.4529 98 905930.284 0.368 + 9 54 45 99 Rh -85584.522 19.451 8580.1959 0.1965 B- -3401.6603 18.9153 98 908121.241 20.881 + 7 53 46 99 Pd -82182.861 5.107 8537.9332 0.0516 B- -5470.3785 8.0829 98 911773.073 5.482 + 5 52 47 99 Ag x -76712.483 6.265 8474.7744 0.0633 B- -6781.3511 6.4622 98 917645.766 6.725 + 3 51 48 99 Cd x -69931.132 1.584 8398.3734 0.0160 B- -8555# 298# 98 924925.845 1.700 + 1 50 49 99 In x -61376# 298# 8304# 3# B- -13400# 500# 98 934110# 320# + -1 49 50 99 Sn - -47976# 582# 8161# 6# B- * 98 948495# 625# +0 28 64 36 100 Kr x -34470# 400# 8134# 4# B- 11796# 400# 99 962995# 429# + 26 63 37 100 Rb -46265.884 13.124 8244.5085 0.1312 B- 13551.6204 14.8355 99 950331.532 14.089 + 24 62 38 100 Sr -59817.505 6.918 8372.2012 0.0692 B- 7503.7365 13.1453 99 935783.270 7.426 + 22 61 39 100 Y x -67321.241 11.179 8439.4151 0.1118 B- 9051.4949 13.8293 99 927727.678 12.000 + 20 60 40 100 Zr -76372.736 8.143 8522.1066 0.0814 B- 3418.5098 11.3976 99 918010.499 8.742 + 18 59 41 100 Nb IT -79791.246 7.976 8548.4683 0.0798 B- 6401.7829 7.9817 99 914340.578 8.562 + 16 58 42 100 Mo -86193.029 0.301 8604.6626 0.0030 B- -172.0776 1.3704 99 907467.982 0.322 + 14 57 43 100 Tc -n -86020.951 1.351 8595.1184 0.0135 B- 3206.4401 1.3760 99 907652.715 1.450 + 12 56 44 100 Ru -89227.391 0.342 8619.3593 0.0034 B- -3636.2612 18.1231 99 904210.460 0.367 + 10 55 45 100 Rh -85591.130 18.125 8575.1732 0.1813 B- -378.4577 25.2879 99 908114.147 19.458 + 8 54 46 100 Pd -85212.672 17.637 8563.5652 0.1764 B- -7074.7030 18.3319 99 908520.438 18.934 + 6 53 47 100 Ag x -78137.969 5.000 8484.9947 0.0500 B- -3943.3740 5.2735 99 916115.443 5.367 + 4 52 48 100 Cd x -74194.595 1.677 8437.7375 0.0168 B- -10016.4492 2.7945 99 920348.829 1.800 + 2 51 49 100 In x -64178.146 2.236 8329.7495 0.0224 B- -7030.0000 240.0000 99 931101.929 2.400 + 0 50 50 100 Sn - -57148.146 240.010 8251.6260 2.4001 B- * 99 938648.944 257.661 +0 29 65 36 101 Kr x -28580# 500# 8075# 5# B- 13987# 501# 100 969318# 537# + 27 64 37 101 Rb x -42567.417 20.493 8206.1753 0.2029 B- 12757.4969 22.1781 100 954302.000 22.000 + 25 63 38 101 Sr x -55324.914 8.480 8324.7411 0.0840 B- 9729.8721 11.0473 100 940606.264 9.103 + 23 62 39 101 Y x -65054.787 7.080 8413.3305 0.0701 B- 8106.2003 10.9331 100 930160.817 7.601 + 21 61 40 101 Zr -73160.987 8.332 8485.8439 0.0825 B- 5730.5011 9.1366 100 921458.454 8.944 + 19 60 41 101 Nb x -78891.488 3.749 8534.8355 0.0371 B- 4628.4637 3.7378 100 915306.508 4.024 + 17 59 42 101 Mo -n -83519.952 0.308 8572.9159 0.0031 B- 2824.6411 24.0018 100 910337.648 0.331 + 15 58 43 101 Tc + -86344.593 24.004 8593.1366 0.2377 B- 1613.5200 24.0000 100 907305.271 25.768 + 13 57 44 101 Ru -87958.113 0.413 8601.3660 0.0041 B- -545.6846 5.8518 100 905573.086 0.443 + 11 56 45 101 Rh -87412.428 5.841 8588.2172 0.0578 B- -1980.2833 3.9027 100 906158.903 6.270 + 9 55 46 101 Pd -85432.145 4.588 8560.8644 0.0454 B- -4097.7606 6.6679 100 908284.824 4.925 + 7 54 47 101 Ag x -81334.384 4.838 8512.5465 0.0479 B- -5497.9186 5.0625 100 912683.951 5.193 + 5 53 48 101 Cd x -75836.466 1.490 8450.3657 0.0148 B- -7291.5642 11.7569 100 918586.209 1.600 + 3 52 49 101 In x -68544.901 11.662 8370.4260 0.1155 B- -8239.2770 300.2313 100 926414.025 12.519 + 1 51 50 101 Sn ep -60305.624 300.005 8281.1030 2.9703 B- * 100 935259.252 322.068 +0 28 65 37 102 Rb x -37252.312 82.903 8152.7443 0.8128 B- 14906.9991 106.6347 101 960008.000 89.000 + 26 64 38 102 Sr x -52159.311 67.068 8291.2213 0.6575 B- 9013.3301 67.1916 101 944004.679 72.000 + 24 63 39 102 Y x -61172.641 4.081 8371.9172 0.0400 B- 10408.7856 9.6618 101 934328.471 4.381 + 22 62 40 102 Zr -71581.427 8.758 8466.2940 0.0859 B- 4716.8380 9.0530 101 923154.181 9.401 + 20 61 41 102 Nb -76298.265 2.511 8504.8675 0.0246 B- 7262.6008 8.6750 101 918090.447 2.695 + 18 60 42 102 Mo -83560.866 8.305 8568.3994 0.0814 B- 1012.0557 12.3682 101 910293.725 8.916 + 16 59 43 102 Tc -84572.921 9.166 8570.6514 0.0899 B- 4533.5134 9.1646 101 909207.239 9.840 + 14 58 44 102 Ru -89106.435 0.416 8607.4275 0.0041 B- -2323.1187 6.3960 101 904340.312 0.446 + 12 57 45 102 Rh - -86783.316 6.410 8576.9818 0.0628 B- 1119.6470 6.3962 101 906834.282 6.880 + 10 56 46 102 Pd -87902.963 0.419 8580.2887 0.0041 B- -5656.2615 8.1816 101 905632.292 0.449 + 8 55 47 102 Ag + -82246.702 8.171 8517.1650 0.0801 B- -2587.0000 8.0000 101 911704.538 8.771 + 6 54 48 102 Cd -79659.702 1.662 8484.1322 0.0163 B- -8964.8059 4.8654 101 914481.797 1.784 + 4 53 49 102 In -70694.896 4.573 8388.5719 0.0448 B- -5760.0000 100.0000 101 924105.911 4.909 + 2 52 50 102 Sn - -64934.896 100.105 8324.4313 0.9814 B- -13835# 412# 101 930289.525 107.466 + 0 51 51 102 Sb x -51100# 400# 8181# 4# B- * 101 945142# 429# +0 29 66 37 103 Rb x -33160# 400# 8112# 4# B- 14120# 447# 102 964401# 429# + 27 65 38 103 Sr x -47280# 200# 8242# 2# B- 11177# 201# 102 949243# 215# + 25 64 39 103 Y x -58457.034 11.206 8342.6336 0.1088 B- 9351.9600 14.5130 102 937243.796 12.029 + 23 63 40 103 Zr x -67808.993 9.223 8425.8337 0.0895 B- 7219.6740 10.0270 102 927204.054 9.900 + 21 62 41 103 Nb x -75028.667 3.935 8488.3320 0.0382 B- 5925.6639 10.0270 102 919453.416 4.224 + 19 61 42 103 Mo x -80954.331 9.223 8538.2672 0.0895 B- 3649.5889 13.4648 102 913091.954 9.900 + 17 60 43 103 Tc +p -84603.920 9.810 8566.1045 0.0952 B- 2663.2474 9.8086 102 909173.960 10.531 + 15 59 44 103 Ru -87267.168 0.441 8584.3656 0.0043 B- 764.5378 2.2598 102 906314.846 0.473 + 13 58 45 103 Rh -88031.705 2.301 8584.1927 0.0223 B- -574.7252 2.3928 102 905494.081 2.470 + 11 57 46 103 Pd -n -87456.980 0.878 8571.0173 0.0085 B- -2654.2778 4.1916 102 906111.074 0.942 + 9 56 47 103 Ag x -84802.702 4.099 8537.6520 0.0398 B- -4151.0761 4.4806 102 908960.558 4.400 + 7 55 48 103 Cd -80651.626 1.811 8489.7547 0.0176 B- -6019.2293 9.1242 102 913416.922 1.943 + 5 54 49 103 In -74632.397 8.980 8423.7199 0.0872 B- -7540# 100# 102 919878.830 9.640 + 3 53 50 103 Sn - -67092# 100# 8343# 1# B- -10422# 316# 102 927973# 108# + 1 52 51 103 Sb x -56670# 300# 8234# 3# B- * 102 939162# 322# +0 30 67 37 104 Rb x -27450# 500# 8057# 5# B- 16310# 583# 103 970531# 537# + 28 66 38 104 Sr x -43760# 300# 8206# 3# B- 10320# 361# 103 953022# 322# + 26 65 39 104 Y x -54080# 200# 8298# 2# B- 11638# 200# 103 941943# 215# + 24 64 40 104 Zr x -65717.660 9.316 8402.3159 0.0896 B- 6093.3367 9.4851 103 929449.193 10.000 + 22 63 41 104 Nb x -71810.997 1.784 8453.3832 0.0172 B- 8532.7512 9.0879 103 922907.728 1.915 + 20 62 42 104 Mo -80343.748 8.911 8527.9063 0.0857 B- 2155.2212 24.1665 103 913747.443 9.566 + 18 61 43 104 Tc -82498.969 24.886 8541.1070 0.2393 B- 5596.7945 24.9370 103 911433.718 26.716 + 16 60 44 104 Ru -88095.763 2.498 8587.3998 0.0240 B- -1136.4195 3.3643 103 905425.312 2.682 + 14 59 45 104 Rh -n -86959.344 2.303 8568.9501 0.0221 B- 2435.7789 2.6595 103 906645.309 2.471 + 12 58 46 104 Pd +n -89395.123 1.336 8584.8485 0.0129 B- -4278.6529 4.0000 103 904030.393 1.434 + 10 57 47 104 Ag - -85116.470 4.217 8536.1850 0.0406 B- -1148.0787 4.5370 103 908623.715 4.527 + 8 56 48 104 Cd -83968.391 1.673 8517.6232 0.0161 B- -7785.7166 6.0127 103 909856.228 1.795 + 6 55 49 104 In x -76182.675 5.775 8435.2380 0.0555 B- -4555.6174 8.1461 103 918214.538 6.200 + 4 54 50 104 Sn -71627.057 5.745 8383.9114 0.0552 B- -12332# 102# 103 923105.195 6.167 + 2 53 51 104 Sb +a -59295# 101# 8258# 1# B- -9668# 333# 103 936344# 109# + 0 52 52 104 Te -a -49626.831 317.609 8157.3256 3.0539 B- * 103 946723.408 340.967 +0 29 67 38 105 Sr x -38190# 500# 8152# 5# B- 12380# 640# 104 959001# 537# + 27 66 39 105 Y x -50570# 400# 8262# 4# B- 10888# 400# 104 945711# 429# + 25 65 40 105 Zr x -61458.274 12.110 8358.5980 0.1153 B- 8457.2728 12.7625 104 934021.832 13.000 + 23 64 41 105 Nb x -69915.547 4.028 8431.6925 0.0384 B- 7415.2411 9.9106 104 924942.577 4.324 + 21 63 42 105 Mo -77330.788 9.055 8494.8630 0.0862 B- 4955.5157 35.0307 104 916981.989 9.721 + 19 62 43 105 Tc -82286.303 35.263 8534.6074 0.3358 B- 3648.2396 35.2787 104 911662.024 37.856 + 17 61 44 105 Ru -85934.543 2.499 8561.9016 0.0238 B- 1916.7271 2.8508 104 907745.478 2.683 + 15 60 45 105 Rh -87851.270 2.502 8572.7053 0.0238 B- 566.6347 2.3459 104 905687.787 2.685 + 13 59 46 105 Pd -88417.905 1.138 8570.6509 0.0108 B- -1347.0564 4.6695 104 905079.479 1.222 + 11 58 47 105 Ag -87070.848 4.544 8550.3708 0.0433 B- -2736.9989 4.3618 104 906525.604 4.877 + 9 57 48 105 Cd -84333.849 1.392 8516.8532 0.0133 B- -4693.2673 10.3405 104 909463.893 1.494 + 7 56 49 105 In x -79640.582 10.246 8464.7045 0.0976 B- -6302.5807 10.9891 104 914502.322 11.000 + 5 55 50 105 Sn -73338.001 3.971 8397.2290 0.0378 B- -9322.5103 22.1849 104 921268.421 4.263 + 3 54 51 105 Sb +a -64015.491 21.827 8300.9923 0.2079 B- -11203.9825 300.8126 104 931276.547 23.431 + 1 53 52 105 Te -a -52811.509 300.020 8186.8368 2.8573 B- * 104 943304.516 322.084 +0 30 68 38 106 Sr x -34300# 600# 8114# 6# B- 11490# 781# 105 963177# 644# + 28 67 39 106 Y x -45790# 500# 8215# 5# B- 12959# 539# 105 950842# 537# + 26 66 40 106 Zr x -58749# 200# 8330# 2# B- 7453# 200# 105 936930# 215# + 24 65 41 106 Nb -66202.678 1.416 8393.2657 0.0134 B- 9925.3249 9.2388 105 928928.505 1.520 + 22 64 42 106 Mo x -76128.003 9.130 8479.5202 0.0861 B- 3648.2494 15.2778 105 918273.231 9.801 + 20 63 43 106 Tc + -79776.253 12.250 8506.5570 0.1156 B- 6547.0000 11.0000 105 914356.674 13.150 + 18 62 44 106 Ru -86323.253 5.391 8560.9406 0.0509 B- 39.4038 0.2121 105 907328.181 5.787 + 16 61 45 106 Rh -86362.656 5.390 8553.9317 0.0508 B- 3544.8865 5.3348 105 907285.879 5.786 + 14 60 46 106 Pd -89907.543 1.106 8579.9934 0.0104 B- -2965.1434 2.8172 105 903480.287 1.186 + 12 59 47 106 Ag -86942.399 3.016 8544.6397 0.0285 B- 189.7534 2.8190 105 906663.499 3.237 + 10 58 48 106 Cd -87132.153 1.104 8539.0492 0.0104 B- -6524.0031 12.1765 105 906459.791 1.184 + 8 57 49 106 In - -80608.150 12.226 8470.1213 0.1153 B- -3254.4521 13.2439 105 913463.596 13.125 + 6 56 50 106 Sn -77353.698 5.091 8432.0383 0.0480 B- -10880.3964 9.0249 105 916957.394 5.465 + 4 55 51 106 Sb x -66473.301 7.452 8322.0124 0.0703 B- -8253.5423 100.8163 105 928637.979 8.000 + 2 54 52 106 Te -a -58219.759 100.541 8236.7682 0.9485 B- -14920# 412# 105 937498.521 107.934 + 0 53 53 106 I x -43300# 400# 8089# 4# B- * 105 953516# 429# +0 31 69 38 107 Sr x -28250# 700# 8057# 7# B- 13720# 860# 106 969672# 751# + 29 68 39 107 Y x -41970# 500# 8178# 5# B- 12050# 583# 106 954943# 537# + 27 67 40 107 Zr x -54020# 300# 8284# 3# B- 9704# 300# 106 942007# 322# + 25 66 41 107 Nb x -63723.805 8.023 8367.0898 0.0750 B- 8821.1703 12.2239 106 931589.685 8.612 + 23 65 42 107 Mo x -72544.975 9.223 8442.2190 0.0862 B- 6204.9921 12.6599 106 922119.770 9.901 + 21 64 43 107 Tc x -78749.967 8.673 8492.8979 0.0811 B- 5112.5985 11.7243 106 915458.437 9.310 + 19 63 44 107 Ru -nn -83862.565 8.673 8533.3676 0.0811 B- 3001.1457 14.8473 106 909969.837 9.310 + 17 62 45 107 Rh +p -86863.711 12.051 8554.1040 0.1126 B- 1508.9427 12.1108 106 906747.975 12.937 + 15 61 46 107 Pd -88372.654 1.201 8560.8946 0.0112 B- 34.0458 2.3174 106 905128.058 1.289 + 13 60 47 107 Ag -88406.700 2.382 8553.9012 0.0223 B- -1416.3741 2.5654 106 905091.509 2.556 + 11 59 48 107 Cd -86990.325 1.660 8533.3524 0.0155 B- -3423.6586 9.5800 106 906612.049 1.782 + 9 58 49 107 In -83566.667 9.654 8494.0439 0.0902 B- -5054.4281 11.0175 106 910287.497 10.363 + 7 57 50 107 Sn x -78512.239 5.310 8439.4946 0.0496 B- -7858.9903 6.7377 106 915713.649 5.700 + 5 56 51 107 Sb -70653.248 4.148 8358.7344 0.0388 B- -9996# 101# 106 924150.621 4.452 + 3 55 52 107 Te -a -60657# 101# 8258# 1# B- -11227# 316# 106 934882# 108# + 1 54 53 107 I x -49430# 300# 8146# 3# B- * 106 946935# 322# +0 30 69 39 108 Y x -36780# 600# 8129# 6# B- 14170# 721# 107 960515# 644# + 28 68 40 108 Zr x -50950# 400# 8253# 4# B- 8595# 400# 107 945303# 429# + 26 67 41 108 Nb x -59545.198 8.239 8325.6604 0.0763 B- 11204.0998 12.3668 107 936075.604 8.844 + 24 66 42 108 Mo x -70749.297 9.223 8422.1581 0.0854 B- 5173.5330 12.7262 107 924047.508 9.901 + 22 65 43 108 Tc x -75922.831 8.769 8462.8172 0.0812 B- 7738.5736 11.7903 107 918493.493 9.413 + 20 64 44 108 Ru -3n -83661.404 8.680 8527.2267 0.0804 B- 1369.7517 16.4699 107 910185.793 9.318 + 18 63 45 108 Rh x -85031.156 13.997 8532.6657 0.1296 B- 4493.0596 14.0405 107 908715.304 15.026 + 16 62 46 108 Pd -89524.215 1.108 8567.0241 0.0103 B- -1917.4238 2.6323 107 903891.806 1.189 + 14 61 47 108 Ag -n -87606.792 2.388 8542.0262 0.0221 B- 1645.6311 2.6386 107 905950.245 2.563 + 12 60 48 108 Cd -89252.423 1.123 8550.0196 0.0104 B- -5132.5944 8.5845 107 904183.588 1.205 + 10 59 49 108 In -84119.828 8.641 8495.2516 0.0800 B- -2049.8794 9.8365 107 909693.654 9.276 + 8 58 50 108 Sn -82069.949 5.382 8469.0273 0.0498 B- -9624.6079 7.6925 107 911894.290 5.778 + 6 57 51 108 Sb x -72445.341 5.496 8372.6666 0.0509 B- -6663.6646 7.7125 107 922226.731 5.900 + 4 56 52 108 Te -65781.676 5.411 8303.7221 0.0501 B- -13011# 101# 107 929380.469 5.808 + 2 55 53 108 I -p -52771# 101# 8176# 1# B- -10139# 393# 107 943348# 109# + 0 54 54 108 Xe -a -42632.357 379.497 8074.8886 3.5139 B- * 107 954232.285 407.406 +0 31 70 39 109 Y x -32480# 700# 8089# 6# B- 13250# 860# 108 965131# 751# + 29 69 40 109 Zr x -45730# 500# 8204# 5# B- 10960# 660# 108 950907# 537# + 27 68 41 109 Nb x -56689.800 430.816 8297.1307 3.9524 B- 9969.4851 430.9610 108 939141.000 462.500 + 25 67 42 109 Mo x -66659.285 11.179 8381.4163 0.1026 B- 7623.5438 14.7805 108 928438.318 12.000 + 23 66 43 109 Tc x -74282.828 9.669 8444.1796 0.0887 B- 6455.6267 12.6574 108 920254.107 10.380 + 21 65 44 109 Ru -4n -80738.455 8.954 8496.2280 0.0821 B- 4260.7958 9.8229 108 913323.707 9.612 + 19 64 45 109 Rh -84999.251 4.040 8528.1404 0.0371 B- 2607.2327 4.1874 108 908749.555 4.336 + 17 63 46 109 Pd -87606.484 1.114 8544.8825 0.0102 B- 1112.9469 1.4024 108 905950.576 1.195 + 15 62 47 109 Ag -88719.431 1.287 8547.9155 0.0118 B- -215.1002 1.7795 108 904755.778 1.381 + 13 61 48 109 Cd -88504.330 1.536 8538.7646 0.0141 B- -2014.8047 4.0662 108 904986.697 1.649 + 11 60 49 109 In -86489.526 3.969 8513.1027 0.0364 B- -3859.3453 8.8866 108 907149.679 4.261 + 9 59 50 109 Sn -82630.180 7.949 8470.5183 0.0729 B- -6379.1940 8.8074 108 911292.857 8.533 + 7 58 51 109 Sb -76250.986 5.265 8404.8161 0.0483 B- -8535.5871 6.8502 108 918141.203 5.652 + 5 57 52 109 Te -67715.399 4.382 8319.3305 0.0402 B- -10042.8941 8.0301 108 927304.532 4.704 + 3 56 53 109 I -p -57672.505 6.729 8220.0164 0.0617 B- -11502.9589 300.1831 108 938086.022 7.223 + 1 55 54 109 Xe -a -46169.546 300.108 8107.3071 2.7533 B- * 108 950434.955 322.178 +0 30 70 40 110 Zr x -42220# 500# 8171# 5# B- 10090# 976# 109 954675# 537# + 28 69 41 110 Nb x -52309.914 838.345 8255.2607 7.6213 B- 12225.9002 838.6945 109 943843.000 900.000 + 26 68 42 110 Mo x -64535.814 24.219 8359.2930 0.2202 B- 6498.7491 26.0147 109 930717.956 26.000 + 24 67 43 110 Tc x -71034.564 9.497 8411.2603 0.0863 B- 9038.0654 12.5086 109 923741.263 10.195 + 22 66 44 110 Ru -80072.629 8.924 8486.3123 0.0811 B- 2756.0638 19.4044 109 914038.501 9.580 + 20 65 45 110 Rh -82828.693 17.805 8504.2551 0.1619 B- 5502.2116 17.7967 109 911079.745 19.114 + 18 64 46 110 Pd -88330.904 0.612 8547.1630 0.0056 B- -873.5982 1.3777 109 905172.878 0.657 + 16 63 47 110 Ag -87457.306 1.286 8532.1089 0.0117 B- 2890.6633 1.2771 109 906110.724 1.380 + 14 62 48 110 Cd -90347.969 0.380 8551.2755 0.0035 B- -3878.0000 11.5470 109 903007.470 0.407 + 12 61 49 110 In - -86469.969 11.553 8508.9087 0.1050 B- -627.9769 17.9802 109 907170.674 12.402 + 10 60 50 110 Sn x -85841.993 13.777 8496.0875 0.1252 B- -8392.2480 15.0117 109 907844.835 14.790 + 8 59 51 110 Sb x -77449.745 5.962 8412.6821 0.0542 B- -5219.9240 8.8753 109 916854.283 6.400 + 6 58 52 110 Te -72229.821 6.575 8358.1160 0.0598 B- -11761.9766 62.2875 109 922458.102 7.058 + 4 57 53 110 I -a -60467.844 61.940 8244.0767 0.5631 B- -8545.2075 118.4700 109 935085.102 66.494 + 2 56 54 110 Xe -a -51922.636 100.988 8159.2808 0.9181 B- * 109 944258.759 108.415 +0 31 71 40 111 Zr x -36480# 600# 8118# 5# B- 12480# 671# 110 960837# 644# + 29 70 41 111 Nb x -48960# 300# 8223# 3# B- 10980# 300# 110 947439# 322# + 27 69 42 111 Mo + -59939.813 12.578 8315.2932 0.1133 B- 9084.8620 6.7999 110 935651.966 13.503 + 25 68 43 111 Tc x -69024.675 10.582 8390.0906 0.0953 B- 7760.6500 13.8477 110 925898.966 11.359 + 23 67 44 111 Ru x -76785.325 9.682 8452.9582 0.0872 B- 5518.5456 11.8621 110 917567.566 10.394 + 21 66 45 111 Rh -82303.871 6.853 8495.6267 0.0617 B- 3682.0153 6.8899 110 911643.164 7.356 + 19 65 46 111 Pd -n -85985.886 0.731 8521.7498 0.0066 B- 2229.5607 1.5721 110 907690.358 0.785 + 17 64 47 111 Ag + -88215.447 1.459 8534.7878 0.0131 B- 1036.8000 1.4142 110 905296.827 1.565 + 15 63 48 111 Cd -89252.247 0.357 8537.0801 0.0032 B- -860.1972 3.4170 110 904183.776 0.383 + 13 62 49 111 In -88392.050 3.424 8522.2824 0.0308 B- -2453.4692 6.3368 110 905107.236 3.675 + 11 61 50 111 Sn +n -85938.581 5.336 8493.1310 0.0481 B- -5101.8340 10.3337 110 907741.143 5.728 + 9 60 51 111 Sb x -80836.747 8.849 8440.1203 0.0797 B- -7249.2597 10.9370 110 913218.187 9.500 + 7 59 52 111 Te x -73587.487 6.427 8367.7635 0.0579 B- -8633.6922 7.9943 110 921000.587 6.900 + 5 58 53 111 I -64953.795 4.754 8282.9343 0.0428 B- -10434# 116# 110 930269.236 5.103 + 3 57 54 111 Xe -a -54520# 115# 8182# 1# B- -11620# 231# 110 941470# 124# + 1 56 55 111 Cs x -42900# 200# 8070# 2# B- * 110 953945# 215# +0 32 72 40 112 Zr x -32420# 700# 8081# 6# B- 11650# 761# 111 965196# 751# + 30 71 41 112 Nb x -44070# 300# 8178# 3# B- 13410# 361# 111 952689# 322# + 28 70 42 112 Mo x -57480# 200# 8291# 2# B- 7779# 200# 111 938293# 215# + 26 69 43 112 Tc x -65258.932 5.515 8353.6217 0.0492 B- 10371.9409 11.0602 111 929941.658 5.920 + 24 68 44 112 Ru x -75630.873 9.600 8439.2431 0.0857 B- 4100.1790 45.1185 111 918806.922 10.305 + 22 67 45 112 Rh -79731.052 44.085 8468.8666 0.3936 B- 6589.9874 43.9269 111 914405.199 47.327 + 20 66 46 112 Pd -86321.039 6.546 8520.7205 0.0584 B- 262.6897 6.9799 111 907330.557 7.027 + 18 65 47 112 Ag x -86583.729 2.422 8516.0807 0.0216 B- 3991.1283 2.4348 111 907048.548 2.600 + 16 64 48 112 Cd -90574.857 0.250 8544.7306 0.0022 B- -2584.7306 4.2434 111 902763.896 0.268 + 14 63 49 112 In -87990.127 4.251 8514.6674 0.0380 B- 664.9224 4.2434 111 905538.718 4.563 + 12 62 50 112 Sn -88655.049 0.294 8513.6189 0.0026 B- -7056.0760 17.8317 111 904824.894 0.315 + 10 61 51 112 Sb x -81598.973 17.829 8443.6330 0.1592 B- -4031.4550 19.7019 111 912399.903 19.140 + 8 60 52 112 Te x -77567.518 8.383 8400.6527 0.0749 B- -10504.1795 13.2390 111 916727.848 9.000 + 6 59 53 112 I x -67063.339 10.246 8299.8801 0.0915 B- -7036.9910 13.1754 111 928004.548 11.000 + 4 58 54 112 Xe -a -60026.348 8.283 8230.0646 0.0740 B- -13612# 116# 111 935559.068 8.891 + 2 57 55 112 Cs -p -46415# 116# 8102# 1# B- * 111 950172# 124# +0 33 73 40 113 Zr x -26340# 300# 8027# 3# B- 13870# 500# 112 971723# 322# + 31 72 41 113 Nb x -40210# 400# 8143# 4# B- 12440# 500# 112 956833# 429# + 29 71 42 113 Mo x -52650# 300# 8246# 3# B- 10162# 300# 112 943478# 322# + 27 70 43 113 Tc x -62811.549 3.353 8329.4652 0.0297 B- 9056.2674 38.4285 112 932569.032 3.600 + 25 69 44 113 Ru -71867.816 38.282 8402.6857 0.3388 B- 6899.1276 38.9406 112 922846.729 41.097 + 23 68 45 113 Rh x -78766.944 7.132 8456.8165 0.0631 B- 4823.5559 9.8809 112 915440.212 7.656 + 21 67 46 113 Pd x -83590.500 6.947 8492.5795 0.0615 B- 3436.3252 18.0341 112 910261.912 7.458 + 19 66 47 113 Ag + -87026.825 16.643 8516.0660 0.1473 B- 2016.4615 16.6410 112 906572.865 17.866 + 17 65 48 113 Cd -89043.286 0.245 8526.9874 0.0022 B- 323.8370 0.2653 112 904408.105 0.262 + 15 64 49 113 In -89367.123 0.188 8522.9297 0.0017 B- -1038.9941 1.5733 112 904060.451 0.202 + 13 63 50 113 Sn -88328.129 1.575 8506.8117 0.0139 B- -3911.1637 17.1206 112 905175.857 1.690 + 11 62 51 113 Sb - -84416.966 17.193 8465.2762 0.1521 B- -6069.9281 32.8102 112 909374.664 18.457 + 9 61 52 113 Te x -78347.037 27.945 8404.6366 0.2473 B- -7227.5210 29.0704 112 915891.000 30.000 + 7 60 53 113 I x -71119.517 8.011 8333.7528 0.0709 B- -8915.8902 10.5334 112 923650.062 8.600 + 5 59 54 113 Xe -62203.626 6.840 8247.9277 0.0605 B- -10439.0876 10.9702 112 933221.663 7.342 + 3 58 55 113 Cs -p -51764.539 8.577 8148.6230 0.0759 B- -12055# 300# 112 944428.484 9.207 + 1 57 56 113 Ba x -39710# 300# 8035# 3# B- * 112 957370# 322# +0 32 73 41 114 Nb x -34960# 500# 8097# 4# B- 14720# 583# 113 962469# 537# + 30 72 42 114 Mo x -49680# 300# 8219# 3# B- 8920# 527# 113 946666# 322# + 28 71 43 114 Tc x -58600.294 433.145 8290.2599 3.7995 B- 11620.9190 433.1594 113 937090.000 465.000 + 26 70 44 114 Ru x -70221.213 3.556 8385.3351 0.0312 B- 5489.0622 71.6432 113 924614.430 3.817 + 24 69 45 114 Rh -75710.275 71.561 8426.6221 0.6277 B- 7780.0712 71.8915 113 918721.680 76.824 + 22 68 46 114 Pd x -83490.346 6.948 8488.0056 0.0610 B- 1440.4642 8.3133 113 910369.430 7.459 + 20 67 47 114 Ag x -84930.811 4.564 8493.7786 0.0400 B- 5084.1233 4.5727 113 908823.029 4.900 + 18 66 48 114 Cd -90014.934 0.276 8531.5135 0.0024 B- -1445.1268 0.3817 113 903364.998 0.296 + 16 65 49 114 In -88569.807 0.301 8511.9742 0.0027 B- 1989.9281 0.3018 113 904916.405 0.323 + 14 64 50 114 Sn -90559.735 0.029 8522.5671 0.0004 B- -6063.1189 19.7724 113 902780.130 0.031 + 12 63 51 114 Sb -84496.616 19.772 8462.5191 0.1734 B- -2606.9398 31.4275 113 909289.155 21.226 + 10 62 52 114 Te x -81889.676 24.428 8432.7885 0.2143 B- -9250.7417 31.5883 113 912087.820 26.224 + 8 61 53 114 I x -72638.935 20.027 8344.7790 0.1757 B- -5553.0360 22.9354 113 922018.900 21.500 + 6 60 54 114 Xe x -67085.899 11.178 8289.2054 0.0981 B- -12399.9706 85.7989 113 927980.329 12.000 + 4 59 55 114 Cs -a -54685.928 85.068 8173.5711 0.7462 B- -8780.4915 133.3375 113 941292.244 91.323 + 2 58 56 114 Ba -a -45905.437 102.676 8089.6865 0.9007 B- * 113 950718.489 110.227 +0 33 74 41 115 Nb x -30880# 500# 8061# 4# B- 13670# 640# 114 966849# 537# + 31 73 42 115 Mo x -44550# 400# 8173# 3# B- 11247# 445# 114 952174# 429# + 29 72 43 115 Tc x -55796# 196# 8264# 2# B- 10309# 197# 114 940100# 210# + 27 71 44 115 Ru x -66105.296 25.166 8346.8140 0.2188 B- 8123.9327 26.1788 114 929033.049 27.016 + 25 70 45 115 Rh x -74229.228 7.319 8410.6538 0.0636 B- 6196.5938 15.3503 114 920311.649 7.857 + 23 69 46 115 Pd -80425.822 13.547 8457.7342 0.1178 B- 4556.7647 21.6496 114 913659.333 14.543 + 21 68 47 115 Ag -84982.587 18.268 8490.5553 0.1589 B- 3101.8930 18.2744 114 908767.445 19.611 + 19 67 48 115 Cd -88084.480 0.651 8510.7252 0.0057 B- 1451.8768 0.6514 114 905437.426 0.699 + 17 66 49 115 In -89536.357 0.012 8516.5472 0.0003 B- 497.4892 0.0097 114 903878.772 0.012 + 15 65 50 115 Sn -90033.846 0.015 8514.0702 0.0003 B- -3030.4336 16.0253 114 903344.695 0.016 + 13 64 51 115 Sb x -87003.412 16.025 8480.9156 0.1394 B- -4940.6447 32.2137 114 906598.000 17.203 + 11 63 52 115 Te x -82062.767 27.945 8431.1504 0.2430 B- -5724.9628 40.1840 114 911902.000 30.000 + 9 62 53 115 I x -76337.805 28.876 8374.5651 0.2511 B- -7681.0475 31.3126 114 918048.000 31.000 + 7 61 54 115 Xe x -68656.757 12.109 8300.9704 0.1053 B- -8957# 103# 114 926293.943 13.000 + 5 60 55 115 Cs x -59699# 102# 8216# 1# B- -10779# 225# 114 935910# 110# + 3 59 56 115 Ba x -48920# 200# 8116# 2# B- * 114 947482# 215# +0 34 75 41 116 Nb x -25230# 300# 8012# 3# B- 15980# 583# 115 972914# 322# + 32 74 42 116 Mo x -41210# 500# 8143# 4# B- 10003# 582# 115 955759# 537# + 30 73 43 116 Tc x -51214# 298# 8223# 3# B- 12855# 298# 115 945020# 320# + 28 72 44 116 Ru x -64068.917 3.726 8326.8840 0.0321 B- 6666.8252 73.9257 115 931219.191 4.000 + 26 71 45 116 Rh -70735.742 73.832 8377.6123 0.6365 B- 9095.2839 74.1690 115 924062.060 79.261 + 24 70 46 116 Pd x -79831.026 7.135 8449.2755 0.0615 B- 2711.6378 7.8446 115 914297.872 7.659 + 22 69 47 116 Ag x -82542.664 3.260 8465.9073 0.0281 B- 6169.8248 3.2642 115 911386.809 3.500 + 20 68 48 116 Cd -88712.489 0.160 8512.3511 0.0014 B- -462.7305 0.2720 115 904763.230 0.172 + 18 67 49 116 In -n -88249.758 0.220 8501.6177 0.0019 B- 3276.2204 0.2397 115 905259.992 0.236 + 16 66 50 116 Sn -91525.979 0.096 8523.1166 0.0009 B- -4703.9591 5.1540 115 901742.825 0.103 + 14 65 51 116 Sb -86822.020 5.154 8475.8208 0.0444 B- -1558.2272 24.7485 115 906792.732 5.533 + 12 64 52 116 Te -85263.793 24.206 8455.6435 0.2087 B- -7843.1388 75.3230 115 908465.558 25.986 + 10 63 53 116 I -77420.654 75.037 8381.2858 0.6469 B- -4373.7764 75.8444 115 916885.513 80.555 + 8 62 54 116 Xe -73046.877 13.017 8336.8365 0.1122 B- -11004# 101# 115 921580.955 13.974 + 6 61 55 116 Cs ea -62043# 100# 8235# 1# B- -7663# 224# 115 933395# 108# + 4 60 56 116 Ba x -54380# 200# 8162# 2# B- -14330# 379# 115 941621# 215# + 2 59 57 116 La -a -40050# 321# 8032# 3# B- * 115 957005# 345# +0 33 75 42 117 Mo x -35689# 500# 8096# 4# B- 12450# 640# 116 961686# 537# + 31 74 43 117 Tc x -48140# 400# 8195# 3# B- 11350# 589# 116 948320# 429# + 29 73 44 117 Ru x -59489.871 433.145 8285.5625 3.7021 B- 9406.8875 433.2361 116 936135.000 465.000 + 27 72 45 117 Rh x -68896.758 8.895 8359.2766 0.0760 B- 7527.1313 11.4108 116 926036.291 9.548 + 25 71 46 117 Pd -76423.890 7.255 8416.9243 0.0620 B- 5758.0284 14.7674 116 917955.584 7.788 + 23 70 47 117 Ag -82181.918 13.572 8459.4515 0.1160 B- 4236.4790 13.6099 116 911774.086 14.570 + 21 69 48 117 Cd -n -86418.397 1.013 8488.9740 0.0087 B- 2524.6381 4.9829 116 907226.039 1.087 + 19 68 49 117 In -88943.035 4.881 8503.8653 0.0417 B- 1454.7073 4.8567 116 904515.729 5.239 + 17 67 50 117 Sn -90397.742 0.483 8509.6120 0.0041 B- -1758.1788 8.4449 116 902954.036 0.518 + 15 66 51 117 Sb -88639.564 8.437 8487.8981 0.0721 B- -3544.0634 13.0785 116 904841.519 9.057 + 13 65 52 117 Te -85095.500 13.455 8450.9203 0.1150 B- -4656.9321 28.1284 116 908646.227 14.444 + 11 64 53 117 I -80438.568 25.558 8404.4307 0.2184 B- -6253.2213 27.5845 116 913645.649 27.437 + 9 63 54 117 Xe x -74185.347 10.378 8344.2976 0.0887 B- -7692.2462 63.2672 116 920358.758 11.141 + 7 62 55 117 Cs x -66493.101 62.410 8271.8652 0.5334 B- -9035.1943 258.0009 116 928616.723 67.000 + 5 61 56 117 Ba ep -57457.906 250.339 8187.9546 2.1396 B- -11187# 321# 116 938316.403 268.749 + 3 60 57 117 La -p -46271# 200# 8086# 2# B- * 116 950326# 215# +0 34 76 42 118 Mo x -32370# 500# 8067# 4# B- 10920# 640# 117 965249# 537# + 32 75 43 118 Tc x -43290# 400# 8153# 3# B- 13710# 447# 117 953526# 429# + 30 74 44 118 Ru x -57000# 200# 8263# 2# B- 7887# 202# 117 938808# 215# + 28 73 45 118 Rh x -64886.840 24.236 8322.8539 0.2054 B- 10501.5182 24.3424 117 930341.116 26.018 + 26 72 46 118 Pd -75388.358 2.494 8405.2197 0.0211 B- 4165.4444 3.5419 117 919067.273 2.677 + 24 71 47 118 Ag x -79553.802 2.515 8433.8900 0.0213 B- 7147.8469 20.1582 117 914595.484 2.700 + 22 70 48 118 Cd -nn -86701.649 20.001 8487.8350 0.1695 B- 526.5277 21.4501 117 906921.956 21.471 + 20 69 49 118 In -87228.177 7.752 8485.6670 0.0657 B- 4424.6664 7.7396 117 906356.705 8.322 + 18 68 50 118 Sn -91652.843 0.499 8516.5341 0.0042 B- -3656.6393 2.9745 117 901606.630 0.536 + 16 67 51 118 Sb - -87996.204 3.016 8478.9156 0.0256 B- -305.4459 18.5521 117 905532.194 3.237 + 14 66 52 118 Te +nn -87690.758 18.306 8469.6970 0.1551 B- -6719.7015 26.9364 117 905860.104 19.652 + 12 65 53 118 I x -80971.056 19.760 8406.1203 0.1675 B- -2891.9893 22.3197 117 913074.000 21.213 + 10 64 54 118 Xe x -78079.067 10.378 8374.9819 0.0880 B- -9669.6905 16.4423 117 916178.678 11.141 + 8 63 55 118 Cs IT -68409.377 12.753 8286.4053 0.1081 B- -6210# 201# 117 926559.517 13.690 + 6 62 56 118 Ba x -62200# 200# 8227# 2# B- -12580# 361# 117 933226# 215# + 4 61 57 118 La x -49620# 300# 8114# 3# B- * 117 946731# 322# +0 35 77 42 119 Mo x -26580# 300# 8019# 3# B- 13590# 583# 118 971465# 322# + 33 76 43 119 Tc x -40170# 500# 8126# 4# B- 11910# 583# 118 956876# 537# + 31 75 44 119 Ru x -52080# 300# 8220# 3# B- 10743# 300# 118 944090# 322# + 29 74 45 119 Rh x -62822.802 9.315 8303.3953 0.0783 B- 8584.4751 12.4416 118 932556.951 10.000 + 27 73 46 119 Pd x -71407.277 8.248 8368.9594 0.0693 B- 7238.4816 16.8566 118 923341.138 8.854 + 25 72 47 119 Ag -78645.759 14.703 8423.2126 0.1236 B- 5331.1799 35.9259 118 915570.309 15.783 + 23 71 48 119 Cd -83976.939 37.695 8461.4381 0.3168 B- 3721.7197 38.0880 118 909847.052 40.467 + 21 70 49 119 In -87698.658 7.310 8486.1387 0.0614 B- 2366.3263 7.3381 118 905851.622 7.847 + 19 69 50 119 Sn -90064.985 0.725 8499.4494 0.0061 B- -589.4452 6.9937 118 903311.266 0.778 + 17 68 51 119 Sb -89475.539 6.998 8487.9218 0.0588 B- -2293.0000 2.0000 118 903944.062 7.512 + 15 67 52 119 Te - -87182.539 7.278 8462.0785 0.0612 B- -3404.8080 22.8941 118 906405.699 7.813 + 13 66 53 119 I x -83777.731 21.706 8426.8924 0.1824 B- -4983.2433 24.0598 118 910060.910 23.302 + 11 65 54 119 Xe -78794.488 10.378 8378.4420 0.0872 B- -6489.4269 17.3790 118 915410.641 11.141 + 9 64 55 119 Cs IT -72305.061 13.940 8317.3347 0.1171 B- -7714.9651 200.7537 118 922377.327 14.965 + 7 63 56 119 Ba ep -64590.096 200.269 8245.9287 1.6829 B- -9570# 361# 118 930659.683 214.997 + 5 62 57 119 La x -55020# 300# 8159# 3# B- -11199# 583# 118 940934# 322# + 3 61 58 119 Ce x -43820# 500# 8058# 4# B- * 118 952957# 537# +0 34 77 43 120 Tc x -35000# 500# 8083# 4# B- 14720# 640# 119 962426# 537# + 32 76 44 120 Ru x -49720# 400# 8199# 3# B- 8899# 447# 119 946623# 429# + 30 75 45 120 Rh x -58620# 200# 8266# 2# B- 11660# 200# 119 937069# 215# + 28 74 46 120 Pd -70279.604 2.296 8357.0817 0.0191 B- 5371.9076 5.0261 119 924551.745 2.464 + 26 73 47 120 Ag x -75651.512 4.471 8395.3281 0.0373 B- 8305.8535 5.8202 119 918784.765 4.800 + 24 72 48 120 Cd x -83957.365 3.726 8458.0240 0.0311 B- 1770.3754 40.1837 119 909868.065 4.000 + 22 71 49 120 In + -85727.741 40.011 8466.2575 0.3334 B- 5370.0000 40.0000 119 907967.489 42.953 + 20 70 50 120 Sn -91097.741 0.920 8504.4880 0.0077 B- -2680.6076 7.1399 119 902202.557 0.987 + 18 69 51 120 Sb - -88417.133 7.199 8475.6300 0.0600 B- 945.0271 7.3530 119 905080.308 7.728 + 16 68 52 120 Te -89362.160 1.751 8476.9857 0.0146 B- -5615.0000 15.0000 119 904065.779 1.880 + 14 67 53 120 I - -83747.160 15.102 8423.6745 0.1258 B- -1574.7260 19.1760 119 910093.729 16.212 + 12 66 54 120 Xe x -82172.434 11.817 8404.0322 0.0985 B- -8283.7857 15.4611 119 911784.267 12.686 + 10 65 55 120 Cs IT -73888.649 9.970 8328.4811 0.0831 B- -5000.0000 300.0000 119 920677.277 10.702 + 8 64 56 120 Ba - -68888.649 300.166 8280.2949 2.5014 B- -11319# 424# 119 926044.997 322.241 + 6 63 57 120 La x -57570# 300# 8179# 2# B- -7840# 583# 119 938196# 322# + 4 62 58 120 Ce x -49730# 500# 8108# 4# B- * 119 946613# 537# +0 35 78 43 121 Tc x -31540# 500# 8054# 4# B- 13080# 640# 120 966140# 537# + 33 77 44 121 Ru x -44620# 400# 8156# 3# B- 11630# 737# 120 952098# 429# + 31 76 45 121 Rh x -56250.134 619.444 8245.2397 5.1194 B- 9932.2030 619.4527 120 939613.000 665.000 + 29 75 46 121 Pd x -66182.337 3.353 8320.8584 0.0277 B- 8220.4934 12.5652 120 928950.342 3.600 + 27 74 47 121 Ag x -74402.831 12.109 8382.3306 0.1001 B- 6671.0057 12.2642 120 920125.279 13.000 + 25 73 48 121 Cd x -81073.837 1.942 8430.9972 0.0161 B- 4760.7564 27.4876 120 912963.660 2.085 + 23 72 49 121 In +p -85834.593 27.419 8463.8767 0.2266 B- 3362.0331 27.4098 120 907852.778 29.435 + 21 71 50 121 Sn -89196.626 0.978 8485.1964 0.0081 B- 402.5306 2.5239 120 904243.488 1.050 + 19 70 51 121 Sb -89599.157 2.506 8482.0574 0.0207 B- -1056.0462 25.7587 120 903811.353 2.690 + 17 69 52 121 Te -88543.111 25.835 8466.8641 0.2135 B- -2297.4615 25.9856 120 904945.065 27.734 + 15 68 53 121 I -86245.649 4.723 8441.4111 0.0390 B- -3764.6525 11.2790 120 907411.492 5.070 + 13 67 54 121 Xe -82480.997 10.243 8403.8326 0.0847 B- -5378.6549 13.9791 120 911453.012 10.995 + 11 66 55 121 Cs -77102.342 14.290 8352.9152 0.1181 B- -6357.4948 141.1765 120 917227.235 15.340 + 9 65 56 121 Ba - -70744.847 141.898 8293.9083 1.1727 B- -8555# 332# 120 924052.286 152.333 + 7 64 57 121 La x -62190# 300# 8217# 2# B- -9500# 500# 120 933236# 322# + 5 63 58 121 Ce x -52690# 401# 8132# 3# B- -11139# 641# 120 943435# 430# + 3 62 59 121 Pr -p -41551# 500# 8033# 4# B- * 120 955393# 537# +0 36 79 43 122 Tc x -26305# 300# 8011# 2# B- 15475# 583# 121 971760# 322# + 34 78 44 122 Ru x -41780# 500# 8132# 4# B- 10099# 583# 121 955147# 537# + 32 77 45 122 Rh x -51880# 300# 8208# 2# B- 12737# 301# 121 944305# 322# + 30 76 46 122 Pd x -64616.169 19.561 8305.9755 0.1603 B- 6489.9492 42.9094 121 930631.693 21.000 + 28 75 47 122 Ag x -71106.118 38.191 8352.7591 0.3130 B- 9506.2662 38.2604 121 923664.446 41.000 + 26 74 48 122 Cd -80612.384 2.299 8424.2667 0.0188 B- 2958.9765 50.1126 121 913459.050 2.468 + 24 73 49 122 In + -83571.361 50.060 8442.1079 0.4103 B- 6368.5921 50.0000 121 910282.458 53.741 + 22 72 50 122 Sn -89939.953 2.448 8487.8968 0.0201 B- -1605.7483 3.2135 121 903445.494 2.627 + 20 71 51 122 Sb -88334.205 2.503 8468.3222 0.0205 B- 1979.0772 2.1265 121 905169.335 2.687 + 18 70 52 122 Te -90313.282 1.357 8478.1315 0.0111 B- -4234.0000 5.0000 121 903044.708 1.456 + 16 69 53 122 I - -86079.282 5.181 8437.0139 0.0425 B- -724.2937 12.2596 121 907590.094 5.561 + 14 68 54 122 Xe x -85354.988 11.111 8424.6644 0.0911 B- -7210.2195 35.4720 121 908367.655 11.928 + 12 67 55 122 Cs -78144.769 33.687 8359.1515 0.2761 B- -3535.8170 43.7690 121 916108.144 36.164 + 10 66 56 122 Ba x -74608.952 27.945 8323.7567 0.2291 B- -10066# 299# 121 919904.000 30.000 + 8 65 57 122 La x -64543# 298# 8235# 2# B- -6669# 499# 121 930710# 320# + 6 64 58 122 Ce x -57874# 401# 8174# 3# B- -13094# 641# 121 937870# 430# + 4 63 59 122 Pr x -44780# 500# 8060# 4# B- * 121 951927# 537# +0 35 79 44 123 Ru x -36550# 500# 8089# 4# B- 12640# 640# 122 960762# 537# + 33 78 45 123 Rh x -49190# 400# 8185# 3# B- 11239# 885# 122 947192# 429# + 31 77 46 123 Pd x -60429.748 789.441 8270.0318 6.4182 B- 9138.8323 790.1142 122 935126.000 847.500 + 29 76 47 123 Ag x -69568.581 32.602 8337.9707 0.2651 B- 7845.6026 32.7136 122 925315.060 35.000 + 27 75 48 123 Cd -77414.183 2.696 8395.3955 0.0219 B- 6014.8503 19.8980 122 916892.460 2.894 + 25 74 49 123 In -83429.034 19.832 8437.9362 0.1612 B- 4385.6489 19.8392 122 910435.252 21.290 + 23 73 50 123 Sn -87814.683 2.479 8467.2313 0.0202 B- 1408.2079 2.4203 122 905727.065 2.661 + 21 72 51 123 Sb -89222.890 1.356 8472.3196 0.0110 B- -51.9128 0.0661 122 904215.292 1.456 + 19 71 52 123 Te -89170.978 1.355 8465.5370 0.0110 B- -1228.3898 3.4448 122 904271.022 1.454 + 17 70 53 123 I -87942.588 3.686 8449.1896 0.0300 B- -2694.3302 9.6829 122 905589.753 3.956 + 15 69 54 123 Xe -85248.258 9.534 8420.9239 0.0775 B- -4204.6012 15.4121 122 908482.235 10.234 + 13 68 55 123 Cs x -81043.657 12.109 8380.3796 0.0985 B- -5388.6934 17.1253 122 912996.060 13.000 + 11 67 56 123 Ba x -75654.963 12.109 8330.2086 0.0985 B- -7004# 196# 122 918781.060 13.000 + 9 66 57 123 La x -68651# 196# 8267# 2# B- -8365# 357# 122 926300# 210# + 7 65 58 123 Ce x -60286# 298# 8193# 2# B- -10056# 499# 122 935280# 320# + 5 64 59 123 Pr x -50230# 400# 8104# 3# B- * 122 946076# 429# +0 36 80 44 124 Ru x -33590# 600# 8065# 5# B- 11120# 721# 123 963940# 644# + 34 79 45 124 Rh x -44710# 400# 8148# 3# B- 13690# 500# 123 952002# 429# + 32 78 46 124 Pd x -58400# 300# 8252# 2# B- 7830# 391# 123 937305# 322# + 30 77 47 124 Ag x -66229.951 251.503 8308.8958 2.0283 B- 10469.4858 251.5169 123 928899.227 270.000 + 28 76 48 124 Cd -76699.436 2.609 8387.0179 0.0210 B- 4168.3420 30.5355 123 917659.772 2.800 + 26 75 49 124 In -80867.778 30.561 8414.3243 0.2465 B- 7363.6970 30.5668 123 913184.873 32.808 + 24 74 50 124 Sn -88231.475 1.314 8467.3997 0.0106 B- -612.4067 0.4101 123 905279.619 1.410 + 22 73 51 124 Sb -n -87619.069 1.358 8456.1517 0.0110 B- 2905.0730 0.1317 123 905937.065 1.457 + 20 72 52 124 Te -90524.142 1.352 8473.2705 0.0109 B- -3159.5870 1.8593 123 902818.341 1.451 + 18 71 53 124 I - -87364.555 2.299 8441.4807 0.0185 B- 302.8501 1.8639 123 906210.297 2.467 + 16 70 54 124 Xe -87667.405 1.358 8437.6138 0.0110 B- -5926.3445 9.2512 123 905885.174 1.457 + 14 69 55 124 Cs x -81741.060 9.151 8383.5114 0.0738 B- -2651.2748 15.4894 123 912247.366 9.823 + 12 68 56 124 Ba x -79089.786 12.497 8355.8209 0.1008 B- -8831.1685 58.0305 123 915093.627 13.416 + 10 67 57 124 La x -70258.617 56.669 8278.2926 0.4570 B- -5343# 303# 123 924574.275 60.836 + 8 66 58 124 Ce x -64916# 298# 8229# 2# B- -11765# 499# 123 930310# 320# + 6 65 59 124 Pr x -53151# 401# 8128# 3# B- -8321# 641# 123 942940# 430# + 4 64 60 124 Nd x -44830# 500# 8054# 4# B- * 123 951873# 537# +0 37 81 44 125 Ru x -28370# 300# 8023# 2# B- 13460# 583# 124 969544# 322# + 35 80 45 125 Rh x -41830# 500# 8124# 4# B- 12130# 640# 124 955094# 537# + 33 79 46 125 Pd x -53960# 400# 8215# 3# B- 10560# 589# 124 942072# 429# + 31 78 47 125 Ag x -64519.939 433.145 8293.3151 3.4652 B- 8828.1511 433.1544 124 930735.000 465.000 + 29 77 48 125 Cd x -73348.090 2.888 8357.6815 0.0231 B- 7064.2177 3.3869 124 921257.590 3.100 + 27 76 49 125 In x -80412.308 1.770 8407.9365 0.0142 B- 5481.3495 2.2131 124 913673.841 1.900 + 25 75 50 125 Sn -n -85893.657 1.329 8445.5285 0.0106 B- 2361.4366 2.1661 124 907789.370 1.426 + 23 74 51 125 Sb + -88255.094 2.515 8458.1612 0.0201 B- 766.7000 2.1213 124 905254.264 2.700 + 21 73 52 125 Te -89021.794 1.352 8458.0361 0.0108 B- -185.7700 0.0600 124 904431.178 1.451 + 19 72 53 125 I - -88836.024 1.353 8450.2911 0.0108 B- -1636.6632 0.4259 124 904630.610 1.452 + 17 71 54 125 Xe -87199.361 1.415 8430.9390 0.0113 B- -3109.6184 7.7879 124 906387.640 1.518 + 15 70 55 125 Cs -84089.742 7.736 8399.8033 0.0619 B- -4420.7663 13.4415 124 909725.953 8.304 + 13 69 56 125 Ba -79668.976 10.992 8358.1784 0.0879 B- -5909.4836 27.6308 124 914471.840 11.800 + 11 68 57 125 La -73759.492 25.997 8304.6438 0.2080 B- -7102# 197# 124 920815.931 27.909 + 9 67 58 125 Ce x -66658# 196# 8242# 2# B- -8587# 358# 124 928440# 210# + 7 66 59 125 Pr x -58070# 300# 8167# 2# B- -10001# 500# 124 937659# 322# + 5 65 60 125 Nd x -48070# 400# 8080# 3# B- * 124 948395# 429# +0 36 81 45 126 Rh x -37200# 500# 8087# 4# B- 14590# 640# 125 960064# 537# + 34 80 46 126 Pd x -51790# 400# 8197# 3# B- 8930# 447# 125 944401# 429# + 32 79 47 126 Ag x -60720# 200# 8261# 2# B- 11535# 200# 125 934814# 215# + 30 78 48 126 Cd -72255.727 2.304 8346.7393 0.0183 B- 5553.6500 4.7831 125 922430.290 2.473 + 28 77 49 126 In x -77809.377 4.192 8384.6067 0.0333 B- 8205.7585 11.4802 125 916468.202 4.500 + 26 76 50 126 Sn -nn -86015.135 10.688 8443.5227 0.0848 B- 378.0000 30.0000 125 907658.958 11.473 + 24 75 51 126 Sb - -86393.135 31.847 8440.3136 0.2528 B- 3671.0321 31.8223 125 907253.158 34.189 + 22 74 52 126 Te -90064.168 1.354 8463.2397 0.0107 B- -2153.6712 3.6717 125 903312.144 1.453 + 20 73 53 126 I -87910.496 3.778 8439.9379 0.0300 B- 1235.8904 3.7779 125 905624.205 4.055 + 18 72 54 126 Xe -89146.38687 0.00562 8443.5375 0.0003 B- -4795.7039 10.3587 125 904297.422 0.006 + 16 71 55 126 Cs -84350.683 10.359 8399.2673 0.0822 B- -1680.7697 16.2322 125 909445.821 11.120 + 14 70 56 126 Ba x -82669.913 12.497 8379.7187 0.0992 B- -7696.4376 91.3663 125 911250.202 13.416 + 12 69 57 126 La x -74973.476 90.508 8312.4268 0.7183 B- -4152.9106 94.7235 125 919512.667 97.163 + 10 68 58 126 Ce x -70820.565 27.945 8273.2581 0.2218 B- -10497# 198# 125 923971.000 30.000 + 8 67 59 126 Pr x -60324# 196# 8184# 2# B- -6943# 358# 125 935240# 210# + 6 66 60 126 Nd x -53380# 300# 8122# 2# B- -13631# 583# 125 942694# 322# + 4 65 61 126 Pm x -39750# 500# 8008# 4# B- * 125 957327# 537# +0 37 82 45 127 Rh x -33730# 600# 8060# 5# B- 13490# 781# 126 963789# 644# + 35 81 46 127 Pd x -47220# 500# 8160# 4# B- 11429# 539# 126 949307# 537# + 33 80 47 127 Ag x -58650# 200# 8244# 2# B- 10092# 200# 126 937037# 215# + 31 79 48 127 Cd x -68741.199 6.200 8316.8971 0.0488 B- 8138.6978 11.7675 126 926203.291 6.656 + 29 78 49 127 In -76879.897 10.001 8374.8212 0.0788 B- 6589.6810 12.0260 126 917466.040 10.736 + 27 77 50 127 Sn -83469.578 9.226 8420.5482 0.0726 B- 3228.7160 10.1668 126 910391.726 9.904 + 25 76 51 127 Sb -86698.294 5.083 8439.8110 0.0400 B- 1582.2030 4.9102 126 906925.557 5.457 + 23 75 52 127 Te -88280.497 1.365 8446.1090 0.0108 B- 702.7199 3.5652 126 905226.993 1.465 + 21 74 53 127 I -88983.217 3.621 8445.4820 0.0285 B- -662.3336 2.0442 126 904472.592 3.887 + 19 73 54 127 Xe -88320.883 4.088 8434.1066 0.0322 B- -2080.8562 6.4115 126 905183.636 4.388 + 17 72 55 127 Cs -86240.027 5.578 8411.5617 0.0439 B- -3422.0719 12.6525 126 907417.527 5.987 + 15 71 56 127 Ba -82817.955 11.357 8378.4560 0.0894 B- -4921.8386 27.7403 126 911091.272 12.192 + 13 70 57 127 La -77896.116 26.000 8333.5412 0.2047 B- -5916.7727 38.8567 126 916375.083 27.912 + 11 69 58 127 Ce x -71979.344 28.876 8280.7922 0.2274 B- -7436# 198# 126 922727.000 31.000 + 9 68 59 127 Pr x -64543# 196# 8216# 2# B- -8633# 358# 126 930710# 210# + 7 67 60 127 Nd x -55910# 300# 8142# 2# B- -10600# 500# 126 939978# 322# + 5 66 61 127 Pm x -45310# 400# 8052# 3# B- * 126 951358# 429# +0 38 83 45 128 Rh x -27340# 300# 8010# 2# B- 17050# 583# 127 970649# 322# + 36 82 46 128 Pd x -44390# 500# 8137# 4# B- 10320# 583# 127 952345# 537# + 34 81 47 128 Ag x -54710# 300# 8211# 2# B- 12528# 300# 127 941266# 322# + 32 80 48 128 Cd -67238.245 6.432 8303.2367 0.0503 B- 6951.8716 6.5665 127 927816.778 6.905 + 30 79 49 128 In x -74190.117 1.322 8351.4361 0.0103 B- 9171.3131 17.7194 127 920353.637 1.419 + 28 78 50 128 Sn -83361.430 17.682 8416.9749 0.1381 B- 1268.4219 13.3175 127 910507.828 18.982 + 26 77 51 128 Sb IT -84629.852 18.788 8420.7724 0.1468 B- 4363.9419 18.7862 127 909146.121 20.169 + 24 76 52 128 Te -88993.794 0.706 8448.7536 0.0055 B- -1255.7634 3.6807 127 904461.237 0.758 + 22 75 53 128 I -87738.030 3.621 8432.8309 0.0283 B- 2122.5041 3.6211 127 905809.355 3.887 + 20 74 54 128 Xe -89860.53427 0.00520 8443.3008 0.0003 B- -3928.7617 5.3762 127 903530.75341 0.00558 + 18 73 55 128 Cs -85931.773 5.376 8406.4953 0.0420 B- -562.6171 5.6122 127 907748.452 5.771 + 16 72 56 128 Ba -85369.156 1.610 8395.9878 0.0126 B- -6743.7167 54.4716 127 908352.446 1.728 + 14 71 57 128 La x -78625.439 54.448 8337.1904 0.4254 B- -3091.5136 61.2003 127 915592.123 58.452 + 12 70 58 128 Ce x -75533.925 27.945 8306.9259 0.2183 B- -9203.1617 40.8585 127 918911.000 30.000 + 10 69 59 128 Pr x -66330.764 29.808 8228.9141 0.2329 B- -5800# 202# 127 928791.000 32.000 + 8 68 60 128 Nd x -60530# 200# 8177# 2# B- -12311# 361# 127 935018# 215# + 6 67 61 128 Pm x -48220# 300# 8075# 2# B- -9070# 583# 127 948234# 322# + 4 66 62 128 Sm x -39150# 500# 7998# 4# B- * 127 957971# 537# +0 37 83 46 129 Pd x -37880# 600# 8086# 5# B- 13990# 721# 128 959334# 644# + 35 82 47 129 Ag x -51870# 400# 8188# 3# B- 11252# 400# 128 944315# 429# + 33 81 48 129 Cd x -63122.142 5.310 8269.5311 0.0412 B- 9712.7471 5.6637 128 932235.597 5.700 + 31 80 49 129 In -72834.889 1.971 8338.7590 0.0153 B- 7755.7081 17.2376 128 921808.534 2.116 + 29 79 50 129 Sn -80590.597 17.270 8392.8161 0.1339 B- 4038.7874 27.3634 128 913482.440 18.540 + 27 78 51 129 Sb + -84629.384 21.225 8418.0598 0.1645 B- 2375.5000 21.2132 128 909146.623 22.786 + 25 77 52 129 Te -87004.884 0.711 8430.4098 0.0055 B- 1502.2919 3.1358 128 906596.419 0.763 + 23 76 53 129 I -88507.176 3.153 8435.9908 0.0244 B- 188.8936 3.1534 128 904983.643 3.385 + 21 75 54 129 Xe -88696.06975 0.00505 8431.3904 0.0003 B- -1197.0197 4.5532 128 904780.85742 0.00542 + 19 74 55 129 Cs -87499.050 4.553 8416.0465 0.0353 B- -2438.1843 10.5627 128 906065.910 4.888 + 17 73 56 129 Ba -85060.866 10.504 8391.0811 0.0814 B- -3737.3247 21.6280 128 908683.409 11.276 + 15 72 57 129 La -81323.541 21.343 8356.0449 0.1655 B- -5036.0370 35.1633 128 912695.592 22.913 + 13 71 58 129 Ce x -76287.504 27.945 8310.9411 0.2166 B- -6513.9383 40.8585 128 918102.000 30.000 + 11 70 59 129 Pr x -69773.566 29.808 8254.3808 0.2311 B- -7399# 204# 128 925095.000 32.000 + 9 69 60 129 Nd ep -62375# 202# 8191# 2# B- -9195# 362# 128 933038# 217# + 7 68 61 129 Pm x -53180# 300# 8114# 2# B- -10850# 583# 128 942909# 322# + 5 67 62 129 Sm x -42330# 500# 8023# 4# B- * 128 954557# 537# +0 38 84 46 130 Pd x -32730# 300# 8046# 2# B- 13168# 520# 129 964863# 322# + 36 83 47 130 Ag -nn -45898# 424# 8142# 3# B- 15220# 425# 129 950727# 455# + 34 82 48 130 Cd x -61117.597 22.356 8252.5868 0.1720 B- 8788.9322 22.4274 129 934387.563 24.000 + 32 81 49 130 In -69906.530 1.790 8314.1760 0.0138 B- 10225.6870 2.5905 129 924952.257 1.921 + 30 80 50 130 Sn -80132.217 1.873 8386.8170 0.0144 B- 2153.4702 14.1129 129 913974.531 2.010 + 28 79 51 130 Sb -82285.687 14.212 8397.3641 0.1093 B- 5067.2728 14.2124 129 911662.686 15.257 + 26 78 52 130 Te -87352.960 0.011 8430.3251 0.0003 B- -416.7716 3.1537 129 906222.745 0.011 + 24 77 53 130 I -n -86936.188 3.154 8421.1011 0.0243 B- 2944.2864 3.1537 129 906670.168 3.385 + 22 76 54 130 Xe -89880.474 0.009 8437.7314 0.0003 B- -2980.7199 8.3567 129 903509.346 0.010 + 20 75 55 130 Cs -86899.754 8.357 8408.7848 0.0643 B- 357.0219 8.3617 129 906709.281 8.971 + 18 74 56 130 Ba -87256.776 0.287 8405.5130 0.0022 B- -5629.4021 25.9477 129 906326.002 0.308 + 16 73 57 130 La x -81627.374 25.946 8356.1919 0.1996 B- -2204.4611 38.1328 129 912369.413 27.854 + 14 72 58 130 Ce x -79422.913 27.945 8333.2164 0.2150 B- -8247.4488 70.0853 129 914736.000 30.000 + 12 71 59 130 Pr x -71175.464 64.273 8263.7565 0.4944 B- -4579.2250 70.0853 129 923590.000 69.000 + 10 70 60 130 Nd x -66596.239 27.945 8222.5136 0.2150 B- -11127# 202# 129 928506.000 30.000 + 8 69 61 130 Pm x -55470# 200# 8131# 2# B- -7770# 447# 129 940451# 215# + 6 68 62 130 Sm x -47700# 400# 8065# 3# B- -14187# 671# 129 948792# 429# + 4 67 63 130 Eu -p -33513# 539# 7950# 4# B- * 129 964022# 578# +0 39 85 46 131 Pd x -25740# 300# 7993# 2# B- 15010# 583# 130 972367# 322# + 37 84 47 131 Ag x -40750# 500# 8102# 4# B- 14462# 501# 130 956253# 537# + 35 83 48 131 Cd -55211.760 19.238 8206.1204 0.1469 B- 12812.6089 19.3644 130 940727.740 20.653 + 33 82 49 131 In -68024.369 2.205 8297.9544 0.0168 B- 9240.2095 4.2397 130 926972.839 2.367 + 31 81 50 131 Sn -77264.579 3.621 8362.5183 0.0276 B- 4716.8328 3.9621 130 917053.067 3.887 + 29 80 51 131 Sb -81981.412 2.084 8392.5525 0.0159 B- 3229.6099 2.0845 130 911989.339 2.236 + 27 79 52 131 Te -n -85211.022 0.061 8411.2339 0.0005 B- 2231.7057 0.6077 130 908522.210 0.065 + 25 78 53 131 I + -87442.727 0.605 8422.2977 0.0046 B- 970.8477 0.6046 130 906126.375 0.649 + 23 77 54 131 Xe -88413.57492 0.00512 8423.7367 0.0003 B- -358.0009 0.1771 130 905084.12808 0.00549 + 21 76 55 131 Cs +nn -88055.574 0.177 8415.0317 0.0014 B- -1376.6158 0.4515 130 905468.457 0.190 + 19 75 56 131 Ba -n -86678.958 0.415 8398.5511 0.0032 B- -2909.6936 27.9479 130 906946.315 0.445 + 17 74 57 131 La x -83769.265 27.945 8370.3676 0.2133 B- -4060.8167 43.0918 130 910070.000 30.000 + 15 73 58 131 Ce -79708.448 32.802 8333.3969 0.2504 B- -5407.7842 55.4462 130 914429.465 35.214 + 13 72 59 131 Pr -74300.664 46.995 8286.1439 0.3587 B- -6532.6235 53.0809 130 920234.960 50.451 + 11 71 60 131 Nd -67768.040 27.517 8230.3045 0.2101 B- -7998# 202# 130 927248.020 29.541 + 9 70 61 131 Pm x -59770# 200# 8163# 2# B- -9490# 447# 130 935834# 215# + 7 69 62 131 Sm x -50280# 400# 8085# 3# B- -10816# 565# 130 946022# 429# + 5 68 63 131 Eu -p -39464# 400# 7996# 3# B- * 130 957634# 429# +0 38 85 47 132 Ag x -34400# 500# 8053# 4# B- 16065# 504# 131 963070# 537# + 36 84 48 132 Cd x -50465.429 60.068 8169.1421 0.4551 B- 11946.1243 84.9236 131 945823.136 64.485 + 34 83 49 132 In + -62411.554 60.033 8253.7162 0.4548 B- 14135.0000 60.0000 131 932998.444 64.447 + 32 82 50 132 Sn -76546.554 1.976 8354.8726 0.0150 B- 3088.7280 3.1606 131 917823.898 2.121 + 30 81 51 132 Sb -79635.282 2.467 8372.3452 0.0187 B- 5552.9155 4.2708 131 914508.013 2.648 + 28 80 52 132 Te -85188.197 3.486 8408.4859 0.0264 B- 515.3046 3.4830 131 908546.713 3.742 + 26 79 53 132 I -85703.502 4.065 8406.4628 0.0308 B- 3575.4729 4.0654 131 907993.511 4.364 + 24 78 54 132 Xe -89278.97451 0.00507 8427.6229 0.0003 B- -2126.2813 1.0359 131 904155.08346 0.00544 + 22 77 55 132 Cs -87152.693 1.036 8405.5878 0.0079 B- 1282.2099 1.4773 131 906437.740 1.112 + 20 76 56 132 Ba -88434.903 1.053 8409.3747 0.0080 B- -4711.3256 36.3537 131 905061.231 1.130 + 18 75 57 132 La -83723.578 36.359 8367.7559 0.2754 B- -1254.8898 41.7025 131 910119.047 39.032 + 16 74 58 132 Ce -82468.688 20.407 8352.3223 0.1546 B- -7241.2240 35.3594 131 911466.226 21.907 + 14 73 59 132 Pr x -75227.464 28.876 8291.5377 0.2188 B- -3801.6487 37.6795 131 919240.000 31.000 + 12 72 60 132 Nd x -71425.815 24.205 8256.8104 0.1834 B- -9798# 151# 131 923321.237 25.985 + 10 71 61 132 Pm x -61628# 149# 8177# 1# B- -6488# 335# 131 933840# 160# + 8 70 62 132 Sm x -55140# 300# 8122# 2# B- -12939# 500# 131 940805# 322# + 6 69 63 132 Eu x -42200# 400# 8018# 3# B- * 131 954696# 429# +0 39 86 47 133 Ag x -29080# 500# 8013# 4# B- 15059# 539# 132 968781# 537# + 37 85 48 133 Cd x -44140# 200# 8121# 2# B- 13550# 283# 132 952614# 215# + 35 84 49 133 In x -57690# 200# 8217# 2# B- 13184# 200# 132 938067# 215# + 33 83 50 133 Sn -70873.890 1.904 8310.0890 0.0143 B- 8049.6228 3.6617 132 923913.753 2.043 + 31 82 51 133 Sb -78923.513 3.128 8364.7302 0.0235 B- 4013.6198 3.5179 132 915272.128 3.357 + 29 81 52 133 Te -82937.133 2.066 8389.0255 0.0155 B- 2920.1690 6.2531 132 910963.330 2.218 + 27 80 53 133 I -85857.302 5.902 8405.0993 0.0444 B- 1786.2812 6.3712 132 907828.400 6.335 + 25 79 54 133 Xe + -87643.583 2.400 8412.6477 0.0180 B- 427.3600 2.4000 132 905910.748 2.576 + 23 78 55 133 Cs -88070.943 0.008 8409.9786 0.0003 B- -517.4310 0.9920 132 905451.958 0.008 + 21 77 56 133 Ba -87553.512 0.992 8400.2059 0.0075 B- -2059.1203 27.9624 132 906007.443 1.065 + 19 76 57 133 La x -85494.392 27.945 8378.8415 0.2101 B- -3076.1685 32.3786 132 908218.000 30.000 + 17 75 58 133 Ce x -82418.223 16.354 8349.8301 0.1230 B- -4480.6319 20.5826 132 911520.402 17.557 + 15 74 59 133 Pr x -77937.591 12.497 8310.2588 0.0940 B- -5605.2112 48.2223 132 916330.558 13.416 + 13 73 60 133 Nd x -72332.380 46.575 8262.2320 0.3502 B- -6924.7272 68.5519 132 922348.000 50.000 + 11 72 61 133 Pm x -65407.653 50.301 8204.2841 0.3782 B- -8177# 302# 132 929782.000 54.000 + 9 71 62 133 Sm x -57231# 298# 8137# 2# B- -9995# 422# 132 938560# 320# + 7 70 63 133 Eu x -47236# 298# 8056# 2# B- -11176# 582# 132 949290# 320# + 5 69 64 133 Gd x -36060# 500# 7966# 4# B- * 132 961288# 537# +0 38 86 48 134 Cd x -39460# 300# 8086# 2# B- 12510# 361# 133 957638# 322# + 36 85 49 134 In x -51970# 200# 8173# 1# B- 14464# 200# 133 944208# 215# + 34 84 50 134 Sn x -66433.759 3.167 8275.1719 0.0236 B- 7585.2453 4.4136 133 928680.430 3.400 + 32 83 51 134 Sb x -74019.004 3.074 8325.9398 0.0229 B- 8514.7483 4.1221 133 920537.334 3.300 + 30 82 52 134 Te -82533.752 2.746 8383.6442 0.0205 B- 1509.6875 4.9335 133 911396.376 2.948 + 28 81 53 134 I -84043.440 4.857 8389.0722 0.0362 B- 4082.3946 4.8567 133 909775.660 5.213 + 26 80 54 134 Xe -88125.83443 0.00577 8413.6994 0.0003 B- -1234.6691 0.0160 133 905393.030 0.006 + 24 79 55 134 Cs -86891.165 0.016 8398.6470 0.0003 B- 2058.8368 0.2508 133 906718.501 0.017 + 22 78 56 134 Ba -88950.002 0.251 8408.1731 0.0019 B- -3731.3434 19.9312 133 904508.249 0.269 + 20 77 57 134 La x -85218.659 19.930 8374.4888 0.1487 B- -385.7605 28.5098 133 908514.011 21.395 + 18 76 58 134 Ce x -84832.898 20.387 8365.7716 0.1521 B- -6304.8987 28.7814 133 908928.142 21.886 + 16 75 59 134 Pr x -78528.000 20.316 8312.8817 0.1516 B- -2881.5569 23.5032 133 915696.729 21.810 + 14 74 60 134 Nd x -75646.443 11.817 8285.5391 0.0882 B- -8882.5343 43.5512 133 918790.207 12.686 + 12 73 61 134 Pm x -66763.908 41.917 8213.4131 0.3128 B- -5388# 200# 133 928326.000 45.000 + 10 72 62 134 Sm x -61376# 196# 8167# 1# B- -11576# 358# 133 934110# 210# + 8 71 63 134 Eu x -49800# 300# 8075# 2# B- -8271# 500# 133 946537# 322# + 6 70 64 134 Gd x -41530# 400# 8008# 3# B- * 133 955416# 429# +0 39 87 48 135 Cd x -32820# 400# 8036# 3# B- 14290# 500# 134 964766# 429# + 37 86 49 135 In x -47110# 300# 8136# 2# B- 13522# 300# 134 949425# 322# + 35 85 50 135 Sn x -60632.252 3.074 8230.6877 0.0228 B- 9058.0800 4.0522 134 934908.603 3.300 + 33 84 51 135 Sb -69690.332 2.640 8291.9894 0.0196 B- 8038.4581 3.1524 134 925184.354 2.834 + 31 83 52 135 Te -77728.790 1.722 8345.7384 0.0128 B- 6050.3894 2.6850 134 916554.715 1.848 + 29 82 53 135 I -83779.180 2.060 8384.7609 0.0153 B- 2634.1851 3.8284 134 910059.355 2.211 + 27 81 54 135 Xe -86413.365 3.668 8398.4783 0.0272 B- 1168.5917 3.6623 134 907231.441 3.938 + 25 80 55 135 Cs -87581.956 0.364 8401.3393 0.0027 B- 268.6983 0.2862 134 905976.907 0.390 + 23 79 56 135 Ba -87850.655 0.245 8397.5345 0.0018 B- -1207.1973 9.4299 134 905688.447 0.263 + 21 78 57 135 La -86643.458 9.432 8382.7972 0.0699 B- -2027.1499 4.6101 134 906984.427 10.126 + 19 77 58 135 Ce -84616.308 10.266 8361.9861 0.0760 B- -3680.4357 15.6540 134 909160.662 11.021 + 17 76 59 135 Pr x -80935.872 11.817 8328.9284 0.0875 B- -4722.2522 22.4837 134 913111.772 12.686 + 15 75 60 135 Nd x -76213.620 19.128 8288.1536 0.1417 B- -6151.2907 85.0809 134 918181.318 20.534 + 13 74 61 135 Pm x -70062.329 82.903 8236.7933 0.6141 B- -7205.1069 175.4501 134 924785.000 89.000 + 11 73 62 135 Sm x -62857.222 154.628 8177.6270 1.1454 B- -8709# 249# 134 932520.000 166.000 + 9 72 63 135 Eu x -54148# 196# 8107# 1# B- -9898# 445# 134 941870# 210# + 7 71 64 135 Gd x -44250# 400# 8028# 3# B- -11197# 565# 134 952496# 429# + 5 70 65 135 Tb -p -33053# 400# 7939# 3# B- * 134 964516# 429# +0 38 87 49 136 In x -40970# 300# 8091# 2# B- 15200# 361# 135 956017# 322# + 36 86 50 136 Sn x -56170# 200# 8197# 1# B- 8337# 200# 135 939699# 215# + 34 85 51 136 Sb -64506.890 5.830 8252.2533 0.0429 B- 9918.3897 6.2599 135 930749.009 6.258 + 32 84 52 136 Te -74425.279 2.281 8319.4301 0.0168 B- 5119.9455 14.1880 135 920101.180 2.448 + 30 83 53 136 I -79545.225 14.188 8351.3242 0.1043 B- 6883.9455 14.1880 135 914604.693 15.231 + 28 82 54 136 Xe -86429.170 0.007 8396.1889 0.0003 B- -90.3151 1.8730 135 907214.474 0.007 + 26 81 55 136 Cs + -86338.855 1.873 8389.7723 0.0138 B- 2548.2241 1.8570 135 907311.431 2.010 + 24 80 56 136 Ba -88887.079 0.245 8402.7566 0.0018 B- -2849.5915 53.1715 135 904575.800 0.262 + 22 79 57 136 La x -86037.488 53.171 8376.0512 0.3910 B- 471.0621 53.1720 135 907634.962 57.081 + 20 78 58 136 Ce -86508.550 0.324 8373.7624 0.0024 B- -5168.1290 11.4561 135 907129.256 0.348 + 18 77 59 136 Pr -81340.421 11.455 8330.0089 0.0842 B- -2141.1234 16.4578 135 912677.470 12.296 + 16 76 60 136 Nd x -79199.297 11.817 8308.5127 0.0869 B- -8029.3747 70.0764 135 914976.061 12.686 + 14 75 61 136 Pm x -71169.923 69.073 8243.7207 0.5079 B- -4359.0237 70.1942 135 923595.949 74.152 + 12 74 62 136 Sm x -66810.899 12.497 8205.9165 0.0919 B- -10567# 196# 135 928275.553 13.416 + 10 73 63 136 Eu x -56244# 196# 8122# 1# B- -7154# 357# 135 939620# 210# + 8 72 64 136 Gd x -49090# 298# 8064# 2# B- -13190# 582# 135 947300# 320# + 6 71 65 136 Tb x -35900# 500# 7961# 4# B- * 135 961460# 537# +0 39 88 49 137 In x -35830# 400# 8053# 3# B- 14320# 500# 136 961535# 429# + 37 87 50 137 Sn x -50150# 300# 8152# 2# B- 9911# 304# 136 946162# 322# + 35 86 51 137 Sb x -60060.392 52.164 8218.4764 0.3808 B- 9243.3698 52.2059 136 935522.519 56.000 + 33 85 52 137 Te -69303.762 2.100 8280.2357 0.0153 B- 7052.5063 8.6426 136 925599.354 2.254 + 31 84 53 137 I p-2n -76356.268 8.383 8326.0033 0.0612 B- 6027.1455 8.3841 136 918028.178 9.000 + 29 83 54 137 Xe -n -82383.414 0.104 8364.2865 0.0008 B- 4162.3582 0.3193 136 911557.771 0.111 + 27 82 55 137 Cs + -86545.772 0.302 8388.9581 0.0022 B- 1175.6285 0.1723 136 907089.296 0.324 + 25 81 56 137 Ba -87721.401 0.248 8391.8288 0.0018 B- -580.5356 1.6231 136 905827.207 0.266 + 23 80 57 137 La + -87140.865 1.640 8381.8807 0.0120 B- -1222.1000 1.6000 136 906450.438 1.760 + 21 79 58 137 Ce -85918.765 0.360 8367.2497 0.0026 B- -2716.9515 8.1328 136 907762.416 0.386 + 19 78 59 137 Pr -83201.814 8.135 8341.7074 0.0594 B- -3617.8447 14.2706 136 910679.183 8.733 + 17 77 60 137 Nd -79583.969 11.725 8309.5892 0.0856 B- -5511.1108 17.5366 136 914563.099 12.586 + 15 76 61 137 Pm x -74072.858 13.041 8263.6516 0.0952 B- -6081.2029 31.4460 136 920479.519 14.000 + 13 75 62 137 Sm -67991.655 28.614 8213.5527 0.2089 B- -7845.7518 28.9474 136 927007.959 30.718 + 11 74 63 137 Eu x -60145.904 4.378 8150.5738 0.0320 B- -8932# 298# 136 935430.719 4.700 + 9 73 64 137 Gd x -51214# 298# 8080# 2# B- -10246# 499# 136 945020# 320# + 7 72 65 137 Tb x -40967# 401# 7999# 3# B- * 136 956020# 430# +0 38 88 50 138 Sn x -45510# 400# 8118# 3# B- 9140# 500# 137 951143# 429# + 36 87 51 138 Sb x -54650# 300# 8178# 2# B- 11046# 300# 137 941331# 322# + 34 86 52 138 Te -65695.995 3.787 8252.5786 0.0274 B- 6283.9149 7.0625 137 929472.452 4.065 + 32 85 53 138 I x -71979.910 5.962 8292.4450 0.0432 B- 7992.3346 6.5881 137 922726.392 6.400 + 30 84 54 138 Xe -79972.244 2.804 8344.6913 0.0203 B- 2914.7839 9.5780 137 914146.268 3.010 + 28 83 55 138 Cs -82887.028 9.158 8360.1437 0.0664 B- 5374.7776 9.1584 137 911017.119 9.831 + 26 82 56 138 Ba -88261.806 0.249 8393.4222 0.0018 B- -1748.3977 0.3384 137 905247.059 0.267 + 24 81 57 138 La -86513.408 0.416 8375.0835 0.0030 B- 1052.4585 0.4018 137 907124.041 0.446 + 22 80 58 138 Ce -87565.867 0.499 8377.0408 0.0036 B- -4437.0000 10.0000 137 905994.180 0.536 + 20 79 59 138 Pr - -83128.867 10.012 8339.2195 0.0726 B- -1111.6847 15.3256 137 910757.495 10.748 + 18 78 60 138 Nd -82017.182 11.603 8325.4946 0.0841 B- -7102.8119 16.0995 137 911950.938 12.456 + 16 77 61 138 Pm -74914.370 11.603 8268.3558 0.0841 B- -3416.5976 16.5613 137 919576.119 12.456 + 14 76 62 138 Sm x -71497.772 11.817 8237.9286 0.0856 B- -9748.0968 30.3408 137 923243.988 12.686 + 12 75 63 138 Eu x -61749.676 27.945 8161.6211 0.2025 B- -6090# 202# 137 933709.000 30.000 + 10 74 64 138 Gd x -55660# 200# 8112# 1# B- -12059# 361# 137 940247# 215# + 8 73 65 138 Tb x -43600# 300# 8019# 2# B- -8669# 586# 137 953193# 322# + 6 72 66 138 Dy x -34931# 503# 7950# 4# B- * 137 962500# 540# +0 39 89 50 139 Sn x -39310# 400# 8073# 3# B- 10740# 565# 138 957799# 429# + 37 88 51 139 Sb x -50050# 400# 8144# 3# B- 10155# 400# 138 946269# 429# + 35 87 52 139 Te x -60205.080 3.540 8211.7716 0.0255 B- 8265.8835 5.3454 138 935367.191 3.800 + 33 86 53 139 I x -68470.964 4.005 8265.6100 0.0288 B- 7173.6224 4.5424 138 926493.400 4.300 + 31 85 54 139 Xe x -75644.586 2.142 8311.5904 0.0154 B- 5056.5023 3.7960 138 918792.200 2.300 + 29 84 55 139 Cs + -80701.088 3.134 8342.3397 0.0225 B- 4212.8293 3.1235 138 913363.822 3.364 + 27 83 56 139 Ba -n -84913.918 0.253 8367.0194 0.0018 B- 2308.4632 0.6571 138 908841.164 0.271 + 25 82 57 139 La -87222.381 0.607 8377.9987 0.0044 B- -264.6396 1.9989 138 906362.927 0.651 + 23 81 58 139 Ce -86957.741 2.089 8370.4664 0.0150 B- -2129.0890 2.9962 138 906647.029 2.242 + 21 80 59 139 Pr -84828.652 3.649 8349.5208 0.0263 B- -2811.7226 27.6166 138 908932.700 3.917 + 19 79 60 139 Nd -82016.930 27.521 8323.6642 0.1980 B- -4515.9014 25.8700 138 911951.208 29.545 + 17 78 61 139 Pm -77501.028 13.588 8285.5473 0.0978 B- -5120.7993 17.4098 138 916799.228 14.587 + 15 77 62 139 Sm x -72380.229 10.884 8243.0786 0.0783 B- -6982.1777 17.0705 138 922296.631 11.684 + 13 76 63 139 Eu x -65398.051 13.151 8187.2187 0.0946 B- -7767# 196# 138 929792.307 14.117 + 11 75 64 139 Gd x -57632# 196# 8126# 1# B- -9501# 357# 138 938130# 210# + 9 74 65 139 Tb x -48130# 298# 8052# 2# B- -10430# 582# 138 948330# 320# + 7 73 66 139 Dy x -37700# 500# 7971# 4# B- * 138 959527# 537# +0 40 90 50 140 Sn x -34490# 300# 8038# 2# B- 9900# 671# 139 962973# 322# + 38 89 51 140 Sb x -44390# 600# 8103# 4# B- 11977# 600# 139 952345# 644# + 36 88 52 140 Te -56367.449 14.377 8183.3567 0.1027 B- 7238.7734 18.7976 139 939487.057 15.434 + 34 87 53 140 I x -63606.223 12.109 8229.4740 0.0865 B- 9380.2388 12.3313 139 931715.914 13.000 + 32 86 54 140 Xe x -72986.461 2.329 8290.8875 0.0166 B- 4063.2768 8.5232 139 921645.814 2.500 + 30 85 55 140 Cs -77049.738 8.199 8314.3227 0.0586 B- 6218.1669 9.8671 139 917283.707 8.801 + 28 84 56 140 Ba -83267.905 7.900 8353.1500 0.0564 B- 1044.1542 7.9051 139 910608.231 8.480 + 26 83 57 140 La -84312.059 0.607 8355.0201 0.0043 B- 3762.1676 1.3364 139 909487.285 0.651 + 24 82 58 140 Ce -88074.227 1.313 8376.3045 0.0094 B- -3388.0000 6.0000 139 905448.433 1.409 + 22 81 59 140 Pr - -84686.227 6.142 8346.5163 0.0439 B- -428.9806 6.9536 139 909085.600 6.593 + 20 80 60 140 Nd x -84257.246 3.260 8337.8640 0.0233 B- -6045.2000 24.0000 139 909546.130 3.500 + 18 79 61 140 Pm - -78212.046 24.220 8289.0958 0.1730 B- -2756.1010 27.2546 139 916035.918 26.001 + 16 78 62 140 Sm x -75455.945 12.497 8263.8211 0.0893 B- -8470.0000 50.0000 139 918994.714 13.416 + 14 77 63 140 Eu - -66985.945 51.538 8197.7330 0.3681 B- -5203.6675 58.6268 139 928087.633 55.328 + 12 76 64 140 Gd x -61782.278 27.945 8154.9757 0.1996 B- -11300.0000 800.0000 139 933674.000 30.000 + 10 75 65 140 Tb - -50482.278 800.488 8068.6732 5.7178 B- -7652# 895# 139 945805.048 859.359 + 8 74 66 140 Dy x -42830# 401# 8008# 3# B- -13513# 641# 139 954020# 430# + 6 73 67 140 Ho -p -29317# 500# 7906# 4# B- * 139 968526# 537# +0 39 90 51 141 Sb x -39540# 500# 8069# 4# B- 11129# 640# 140 957552# 537# + 37 89 52 141 Te x -50670# 400# 8142# 3# B- 9257# 400# 140 945604# 429# + 35 88 53 141 I x -59926.666 15.835 8202.2562 0.1123 B- 8270.6430 16.0965 140 935666.081 17.000 + 33 87 54 141 Xe x -68197.309 2.888 8255.3647 0.0205 B- 6280.0423 9.6378 140 926787.181 3.100 + 31 86 55 141 Cs -74477.351 9.195 8294.3554 0.0652 B- 5255.1410 9.6174 140 920045.279 9.871 + 29 85 56 141 Ba -79732.492 5.318 8326.0774 0.0377 B- 3197.3515 6.5510 140 914403.653 5.709 + 27 84 57 141 La -82929.844 4.127 8343.2050 0.0293 B- 2501.2141 3.9279 140 910971.155 4.430 + 25 83 58 141 Ce -85431.058 1.315 8355.3956 0.0093 B- 583.4758 1.1784 140 908285.991 1.411 + 23 82 59 141 Pr -86014.533 1.498 8353.9852 0.0106 B- -1823.0137 2.8090 140 907659.604 1.607 + 21 81 60 141 Nd - -84191.520 3.183 8335.5074 0.0226 B- -3668.5879 14.3304 140 909616.690 3.417 + 19 80 61 141 Pm x -80522.932 13.972 8303.9405 0.0991 B- -4588.9724 16.3730 140 913555.081 15.000 + 17 79 62 141 Sm -75933.959 8.535 8265.8460 0.0605 B- -6008.3127 14.2829 140 918481.545 9.162 + 15 78 63 141 Eu -69925.647 12.639 8217.6853 0.0896 B- -6701.4161 23.4562 140 924931.734 13.568 + 13 77 64 141 Gd x -63224.231 19.760 8164.6090 0.1401 B- -8683.3880 107.0975 140 932126.000 21.213 + 11 76 65 141 Tb x -54540.843 105.259 8097.4761 0.7465 B- -9158# 316# 140 941448.000 113.000 + 9 75 66 141 Dy x -45382# 298# 8027# 2# B- -11018# 499# 140 951280# 320# + 7 74 67 141 Ho -p -34364# 401# 7943# 3# B- * 140 963108# 430# +0 40 91 51 142 Sb x -33610# 300# 8027# 2# B- 12939# 583# 141 963918# 322# + 38 90 52 142 Te x -46550# 500# 8113# 4# B- 8253# 500# 141 950027# 537# + 36 89 53 142 I x -54802.969 4.937 8165.2517 0.0348 B- 10426.6792 5.6276 141 941166.595 5.300 + 34 88 54 142 Xe x -65229.648 2.701 8233.1695 0.0190 B- 5284.9078 7.5655 141 929973.095 2.900 + 32 87 55 142 Cs -70514.556 7.067 8264.8777 0.0498 B- 7327.7007 8.3627 141 924299.514 7.586 + 30 86 56 142 Ba -77842.257 5.920 8310.9718 0.0417 B- 2181.6932 8.3754 141 916432.904 6.355 + 28 85 57 142 La -80023.950 6.286 8320.8263 0.0443 B- 4508.9455 5.8446 141 914090.760 6.748 + 26 84 58 142 Ce -84532.896 2.443 8347.0700 0.0172 B- -746.5288 2.4868 141 909250.208 2.623 + 24 83 59 142 Pr -83786.367 1.498 8336.3032 0.0106 B- 2163.6885 1.3656 141 910051.640 1.607 + 22 82 60 142 Nd -85950.055 1.256 8346.0310 0.0088 B- -4808.5196 23.6216 141 907728.824 1.348 + 20 81 61 142 Pm -81141.536 23.596 8306.6587 0.1662 B- -2159.6062 23.6524 141 912890.982 25.330 + 18 80 62 142 Sm -78981.930 1.866 8285.9407 0.0131 B- -7673.0000 30.0000 141 915209.415 2.002 + 16 79 63 142 Eu - -71308.930 30.058 8226.3960 0.2117 B- -4349.4074 41.0414 141 923446.719 32.268 + 14 78 64 142 Gd x -66959.522 27.945 8190.2569 0.1968 B- -10400.0000 700.0000 141 928116.000 30.000 + 12 77 65 142 Tb - -56559.522 700.558 8111.5080 4.9335 B- -6440# 200# 141 939280.858 752.079 + 10 76 66 142 Dy - -50120# 729# 8061# 5# B- -12869# 831# 141 946194# 782# + 8 75 67 142 Ho x -37250# 401# 7965# 3# B- -9321# 641# 141 960010# 430# + 6 74 68 142 Er x -27930# 500# 7893# 4# B- * 141 970016# 537# +0 39 91 52 143 Te x -40530# 500# 8070# 3# B- 10259# 539# 142 956489# 537# + 37 90 53 143 I x -50790# 200# 8137# 1# B- 9413# 200# 142 945475# 215# + 35 89 54 143 Xe x -60202.882 4.657 8196.8855 0.0326 B- 7472.6365 8.8908 142 935369.550 5.000 + 33 88 55 143 Cs -67675.519 7.573 8243.6707 0.0530 B- 6261.6865 9.7303 142 927347.346 8.130 + 31 87 56 143 Ba -73937.205 6.756 8281.9878 0.0472 B- 4234.2623 9.9682 142 920625.149 7.253 + 29 86 57 143 La -78171.467 7.329 8306.1271 0.0513 B- 3434.9108 7.5812 142 916079.482 7.868 + 27 85 58 143 Ce -81606.378 2.442 8324.6765 0.0171 B- 1461.8214 1.8649 142 912391.953 2.621 + 25 84 59 143 Pr -83068.200 1.816 8329.4280 0.0127 B- 934.1107 1.3673 142 910822.624 1.949 + 23 83 60 143 Nd -84002.310 1.255 8330.4893 0.0088 B- -1041.6463 2.6830 142 909819.815 1.347 + 21 82 61 143 Pm -82960.664 2.944 8317.7341 0.0206 B- -3443.5291 3.5604 142 910938.068 3.160 + 19 81 62 143 Sm -79517.135 2.750 8288.1825 0.0192 B- -5275.8240 11.3245 142 914634.848 2.951 + 17 80 63 143 Eu x -74241.311 10.986 8245.8177 0.0768 B- -6010.0000 200.0000 142 920298.678 11.793 + 15 79 64 143 Gd - -68231.311 200.301 8198.3188 1.4007 B- -7812.1185 206.7497 142 926750.678 215.032 + 13 78 65 143 Tb x -60419.192 51.232 8138.2176 0.3583 B- -8250.2433 52.8659 142 935137.332 55.000 + 11 77 66 143 Dy x -52168.949 13.041 8075.0527 0.0912 B- -10121# 298# 142 943994.332 14.000 + 9 76 67 143 Ho x -42048# 298# 7999# 2# B- -10887# 499# 142 954860# 320# + 7 75 68 143 Er x -31160# 400# 7917# 3# B- * 142 966548# 429# +0 40 92 52 144 Te x -36220# 300# 8040# 2# B- 9110# 500# 143 961116# 322# + 38 91 53 144 I x -45330# 400# 8098# 3# B- 11542# 400# 143 951336# 429# + 36 90 54 144 Xe x -56872.301 5.310 8172.8845 0.0369 B- 6399.0606 20.8203 143 938945.076 5.700 + 34 89 55 144 Cs -63271.362 20.132 8211.8894 0.1398 B- 8495.7679 20.4163 143 932075.402 21.612 + 32 88 56 144 Ba -71767.130 7.136 8265.4549 0.0496 B- 3082.5300 14.7744 143 922954.821 7.661 + 30 87 57 144 La x -74849.660 12.937 8281.4283 0.0898 B- 5582.2823 13.2432 143 919645.589 13.888 + 28 86 58 144 Ce + -80431.942 2.833 8314.7612 0.0197 B- 318.6462 0.8321 143 913652.763 3.041 + 26 85 59 144 Pr + -80750.588 2.708 8311.5411 0.0188 B- 2997.4400 2.4000 143 913310.682 2.907 + 24 84 60 144 Nd -83748.028 1.255 8326.9237 0.0087 B- -2331.9117 2.6464 143 910092.798 1.346 + 22 83 61 144 Pm -81416.116 2.912 8305.2969 0.0202 B- 549.5096 2.6679 143 912596.208 3.126 + 20 82 62 144 Sm -81965.626 1.459 8303.6800 0.0101 B- -6346.4515 10.8092 143 912006.285 1.566 + 18 81 63 144 Eu -75619.175 10.787 8254.1744 0.0749 B- -3859.6633 29.9546 143 918819.481 11.580 + 16 80 64 144 Gd x -71759.511 27.945 8221.9382 0.1941 B- -9391.3235 39.5199 143 922963.000 30.000 + 14 79 65 144 Tb x -62368.188 27.945 8151.2877 0.1941 B- -5798.0965 28.8506 143 933045.000 30.000 + 12 78 66 144 Dy x -56570.091 7.173 8105.5902 0.0498 B- -11960.5706 11.1039 143 939269.512 7.700 + 10 77 67 144 Ho x -44609.521 8.477 8017.0977 0.0589 B- -8002# 196# 143 952109.712 9.100 + 8 76 68 144 Er x -36608# 196# 7956# 1# B- -14448# 445# 143 960700# 210# + 6 75 69 144 Tm -p -22159# 400# 7850# 3# B- * 143 976211# 429# +0 41 93 52 145 Te x -30010# 300# 7998# 2# B- 11120# 583# 144 967783# 322# + 39 92 53 145 I x -41130# 500# 8069# 3# B- 10363# 500# 144 955845# 537# + 37 91 54 145 Xe x -51493.337 11.178 8135.0877 0.0771 B- 8561.0867 14.3929 144 944719.631 12.000 + 35 90 55 145 Cs -60054.424 9.067 8188.7342 0.0625 B- 7461.7591 12.4121 144 935528.927 9.733 + 33 89 56 145 Ba x -67516.183 8.477 8234.7991 0.0585 B- 5319.1425 14.9122 144 927518.400 9.100 + 31 88 57 145 La -72835.325 12.269 8266.0873 0.0846 B- 4231.7331 35.2977 144 921808.065 13.170 + 29 87 58 145 Ce -77067.059 33.900 8289.8762 0.2338 B- 2558.9318 33.6347 144 917265.113 36.393 + 27 86 59 145 Pr -79625.990 7.149 8302.1285 0.0493 B- 1806.0140 7.0370 144 914517.987 7.674 + 25 85 60 145 Nd -81432.004 1.271 8309.1883 0.0088 B- -164.4982 2.5361 144 912579.151 1.364 + 23 84 61 145 Pm -81267.506 2.805 8302.6583 0.0193 B- -616.0990 2.5390 144 912755.748 3.011 + 21 83 62 145 Sm -80651.407 1.485 8293.0139 0.0102 B- -2659.8832 2.7224 144 913417.157 1.594 + 19 82 63 145 Eu -77991.524 3.060 8269.2744 0.0211 B- -5064.8984 19.9521 144 916272.659 3.285 + 17 81 64 145 Gd -72926.626 19.716 8228.9485 0.1360 B- -6526.9329 109.7144 144 921710.051 21.165 + 15 80 65 145 Tb -66399.693 110.896 8178.5397 0.7648 B- -8157.0853 111.0872 144 928717.001 119.051 + 13 79 66 145 Dy x -58242.607 6.520 8116.8884 0.0450 B- -9122.4943 9.9019 144 937473.992 7.000 + 11 78 67 145 Ho x -49120.113 7.452 8048.5792 0.0514 B- -9880# 200# 144 947267.392 8.000 + 9 77 68 145 Er x -39240# 200# 7975# 1# B- -11657# 280# 144 957874# 215# + 7 76 69 145 Tm -p -27583# 196# 7889# 1# B- * 144 970389# 210# +0 40 93 53 146 I x -35540# 300# 8031# 2# B- 12415# 301# 145 961846# 322# + 38 92 54 146 Xe x -47954.950 24.219 8110.4154 0.1659 B- 7355.4298 24.3911 145 948518.245 26.000 + 36 91 55 146 Cs x -55310.380 2.893 8155.4365 0.0198 B- 9555.8882 3.3918 145 940621.867 3.106 + 34 90 56 146 Ba x -64866.269 1.770 8215.5293 0.0121 B- 4354.9052 2.4366 145 930363.200 1.900 + 32 89 57 146 La -69221.174 1.675 8239.9988 0.0115 B- 6404.6947 14.7146 145 925688.017 1.797 + 30 88 58 146 Ce -75625.868 14.665 8278.5081 0.1004 B- 1047.6178 32.4842 145 918812.294 15.743 + 28 87 59 146 Pr -76673.486 34.356 8280.3250 0.2353 B- 4252.4300 34.3686 145 917687.630 36.882 + 26 86 60 146 Nd -80925.916 1.273 8304.0927 0.0087 B- -1471.5560 4.1194 145 913122.459 1.366 + 24 85 61 146 Pm + -79454.360 4.275 8288.6550 0.0293 B- 1542.0000 3.0000 145 914702.240 4.589 + 22 84 62 146 Sm -80996.360 3.045 8293.8581 0.0209 B- -3878.7573 5.8685 145 913046.835 3.269 + 20 83 63 146 Eu -77117.603 6.009 8261.9327 0.0412 B- -1031.7798 7.0750 145 917210.852 6.451 + 18 82 64 146 Gd -76085.823 4.076 8249.5072 0.0279 B- -8322.1791 44.7488 145 918318.513 4.376 + 16 81 65 146 Tb -67763.644 44.860 8187.1474 0.3073 B- -5208.7165 45.1580 145 927252.739 48.159 + 14 80 66 146 Dy -62554.928 6.695 8146.1128 0.0459 B- -11316.7007 9.3917 145 932844.526 7.187 + 12 79 67 146 Ho -51238.227 6.587 8063.2426 0.0451 B- -6916.2074 9.3987 145 944993.503 7.071 + 10 78 68 146 Er -44322.019 6.705 8010.5127 0.0459 B- -13267# 200# 145 952418.357 7.197 + 8 77 69 146 Tm -p -31055# 200# 7914# 1# B- * 145 966661# 215# +0 41 94 53 147 I x -31200# 300# 8001# 2# B- 11199# 361# 146 966505# 322# + 39 93 54 147 Xe x -42400# 200# 8072# 1# B- 9520# 200# 146 954482# 215# + 37 92 55 147 Cs x -51920.073 8.383 8131.8010 0.0570 B- 8343.9631 21.4535 146 944261.512 9.000 + 35 91 56 147 Ba x -60264.036 19.748 8183.2405 0.1343 B- 6414.3615 22.4660 146 935303.900 21.200 + 33 90 57 147 La x -66678.397 10.712 8221.5536 0.0729 B- 5335.5046 13.7248 146 928417.800 11.500 + 31 89 58 147 Ce -72013.902 8.580 8252.5274 0.0584 B- 3430.1913 15.5317 146 922689.900 9.211 + 29 88 59 147 Pr -75444.093 15.855 8270.5400 0.1079 B- 2702.7013 15.8571 146 919007.438 17.020 + 27 87 60 147 Nd -78146.794 1.275 8283.6036 0.0087 B- 895.1896 0.5664 146 916105.969 1.368 + 25 86 61 147 Pm -79041.984 1.288 8284.3712 0.0088 B- 224.0638 0.2940 146 915144.944 1.382 + 23 85 62 147 Sm -79266.048 1.262 8280.5734 0.0086 B- -1721.4367 2.2832 146 914904.401 1.354 + 21 84 63 147 Eu -77544.611 2.569 8263.5409 0.0175 B- -2187.6833 2.5273 146 916752.440 2.758 + 19 83 64 147 Gd -75356.928 1.887 8243.3366 0.0128 B- -4614.2543 8.1414 146 919101.014 2.025 + 17 82 65 147 Tb -70742.674 8.096 8206.6250 0.0551 B- -6546.6266 11.9939 146 924054.620 8.691 + 15 81 66 147 Dy x -64196.047 8.849 8156.7680 0.0602 B- -8438.9460 10.1644 146 931082.712 9.500 + 13 80 67 147 Ho -55757.101 5.001 8094.0381 0.0340 B- -9149.2869 38.5173 146 940142.293 5.368 + 11 79 68 147 Er x -46607.814 38.191 8026.4760 0.2598 B- -10633.4071 38.7987 146 949964.456 41.000 + 9 78 69 147 Tm -35974.407 6.839 7948.8178 0.0465 B- * 146 961379.887 7.341 +0 40 94 54 148 Xe x -38650# 300# 8047# 2# B- 8261# 300# 147 958508# 322# + 38 93 55 148 Cs x -46910.950 13.041 8097.5469 0.0881 B- 10633.9614 13.1258 147 949639.026 14.000 + 36 92 56 148 Ba x -57544.911 1.490 8164.1118 0.0101 B- 5163.8307 19.5252 147 938223.000 1.600 + 34 91 57 148 La x -62708.742 19.468 8193.7165 0.1315 B- 7689.6824 22.4573 147 932679.400 20.900 + 32 90 58 148 Ce -70398.424 11.195 8240.3876 0.0756 B- 2137.0282 12.5663 147 924424.186 12.017 + 30 89 59 148 Pr -72535.452 15.041 8249.5409 0.1016 B- 4872.6133 15.0858 147 922129.992 16.147 + 28 88 60 148 Nd -77408.066 2.053 8277.1778 0.0139 B- -542.1891 5.8755 147 916899.027 2.203 + 26 87 61 148 Pm +p -76865.877 5.690 8268.2283 0.0384 B- 2470.1898 5.6409 147 917481.091 6.108 + 24 86 62 148 Sm -79336.067 1.246 8279.6326 0.0084 B- -3038.5844 9.9657 147 914829.233 1.337 + 22 85 63 148 Eu -76297.482 9.961 8253.8155 0.0673 B- -28.0630 9.9633 147 918091.288 10.693 + 20 84 64 148 Gd -76269.419 1.460 8248.3398 0.0099 B- -5732.4723 12.5208 147 918121.414 1.566 + 18 83 65 148 Tb -70536.947 12.463 8204.3207 0.0842 B- -2677.5501 9.5961 147 924275.476 13.379 + 16 82 66 148 Dy -67859.397 8.724 8180.9430 0.0589 B- -9868.2304 84.2872 147 927149.944 9.365 + 14 81 67 148 Ho x -57991.166 83.834 8108.9797 0.5664 B- -6512.1694 84.4583 147 937743.925 90.000 + 12 80 68 148 Er x -51478.997 10.246 8059.6924 0.0692 B- -12713.9630 14.4906 147 944735.026 11.000 + 10 79 69 148 Tm x -38765.034 10.246 7968.5011 0.0692 B- -8535# 400# 147 958384.026 11.000 + 8 78 70 148 Yb x -30230# 400# 7906# 3# B- * 147 967547# 429# +0 41 95 54 149 Xe x -33000# 300# 8009# 2# B- 10300# 500# 148 964573# 322# + 39 94 55 149 Cs x -43300# 400# 8073# 3# B- 9531# 400# 148 953516# 429# + 37 93 56 149 Ba x -52830.620 2.515 8131.8495 0.0169 B- 7389.3010 200.2781 148 943284.000 2.700 + 35 92 57 149 La + -60219.921 200.262 8176.1915 1.3440 B- 6450.0000 200.0000 148 935351.259 214.990 + 33 91 58 149 Ce x -66669.921 10.246 8214.2294 0.0688 B- 4369.4525 14.2296 148 928426.900 11.000 + 31 90 59 149 Pr x -71039.373 9.874 8238.3040 0.0663 B- 3336.1617 10.0853 148 923736.100 10.600 + 29 89 60 149 Nd -n -74375.535 2.054 8255.4437 0.0138 B- 1688.8697 2.4588 148 920154.583 2.205 + 27 88 61 149 Pm -76064.404 2.184 8261.5277 0.0147 B- 1071.4936 1.8747 148 918341.507 2.344 + 25 87 62 149 Sm -77135.898 1.157 8263.4683 0.0078 B- -694.5812 3.7881 148 917191.211 1.241 + 23 86 63 149 Eu -76441.317 3.903 8253.5560 0.0262 B- -1314.1437 4.1361 148 917936.875 4.190 + 21 85 64 149 Gd -75127.173 3.310 8239.4856 0.0222 B- -3638.5336 4.3388 148 919347.666 3.553 + 19 84 65 149 Tb -71488.639 3.629 8209.8153 0.0244 B- -3794.6493 9.1335 148 923253.792 3.895 + 17 83 66 149 Dy -67693.990 9.183 8179.0972 0.0616 B- -6048.1366 12.7928 148 927327.516 9.858 + 15 82 67 149 Ho -61645.854 11.985 8133.2550 0.0804 B- -7904.2328 30.4066 148 933820.457 12.866 + 13 81 68 149 Er x -53741.621 27.945 8074.9558 0.1875 B- -9801# 202# 148 942306.000 30.000 + 11 80 69 149 Tm x -43940# 200# 8004# 1# B- -10611# 361# 148 952828# 215# + 9 79 70 149 Yb x -33330# 300# 7927# 2# B- * 148 964219# 322# +0 42 96 54 150 Xe x -28990# 300# 7983# 2# B- 9180# 500# 149 968878# 322# + 40 95 55 150 Cs x -38170# 400# 8039# 3# B- 11720# 400# 149 959023# 429# + 38 94 56 150 Ba x -49889.799 5.682 8111.8405 0.0379 B- 6421.3477 6.2138 149 946441.100 6.100 + 36 93 57 150 La x -56311.147 2.515 8149.4339 0.0168 B- 8535.7155 11.9641 149 939547.500 2.700 + 34 92 58 150 Ce -64846.863 11.697 8201.1230 0.0780 B- 3453.6462 14.2913 149 930384.032 12.556 + 32 91 59 150 Pr -68300.509 9.015 8218.9316 0.0601 B- 5379.4422 9.0682 149 926676.391 9.677 + 30 90 60 150 Nd -73679.951 1.129 8249.5789 0.0075 B- -82.6155 20.0010 149 920901.322 1.211 + 28 89 61 150 Pm + -73597.336 20.031 8243.8125 0.1335 B- 3454.0000 20.0000 149 920990.014 21.504 + 26 88 62 150 Sm -77051.336 1.112 8261.6235 0.0074 B- -2258.9662 6.1803 149 917281.993 1.193 + 24 87 63 150 Eu -74792.369 6.231 8241.3481 0.0415 B- 971.6815 3.5428 149 919707.092 6.688 + 22 86 64 150 Gd -75764.051 6.055 8242.6103 0.0404 B- -4658.2621 8.3784 149 918663.949 6.500 + 20 85 65 150 Tb -71105.789 7.371 8206.3396 0.0491 B- -1796.1707 8.3886 149 923664.799 7.912 + 18 84 66 150 Dy -69309.618 4.319 8189.1495 0.0288 B- -7363.7264 14.4629 149 925593.068 4.636 + 16 83 67 150 Ho -61945.892 14.168 8134.8423 0.0945 B- -4114.5689 13.5910 149 933498.353 15.209 + 14 82 68 150 Er -57831.323 17.194 8102.1962 0.1146 B- -11340# 196# 149 937915.524 18.458 + 12 81 69 150 Tm x -46491# 196# 8021# 1# B- -7661# 358# 149 950090# 210# + 10 80 70 150 Yb x -38830# 300# 7965# 2# B- -14059# 424# 149 958314# 322# + 8 79 71 150 Lu -p -24771# 300# 7866# 2# B- * 149 973407# 322# +0 41 96 55 151 Cs x -34280# 500# 8013# 3# B- 10660# 640# 150 963199# 537# + 39 95 56 151 Ba x -44940# 400# 8079# 3# B- 8370# 591# 150 951755# 429# + 37 94 57 151 La x -53310.339 435.473 8129.0436 2.8839 B- 7914.7191 435.8330 150 942769.000 467.500 + 35 93 58 151 Ce x -61225.058 17.698 8176.2779 0.1172 B- 5554.6233 21.1885 150 934272.200 19.000 + 33 92 59 151 Pr -66779.681 11.650 8207.8824 0.0772 B- 4163.5021 11.6789 150 928309.066 12.506 + 31 91 60 151 Nd -70943.183 1.133 8230.2741 0.0075 B- 2443.0767 4.4734 150 923839.363 1.215 + 29 90 61 151 Pm -73386.260 4.611 8241.2723 0.0305 B- 1190.2198 4.4757 150 921216.613 4.949 + 27 89 62 151 Sm -74576.480 1.110 8243.9735 0.0074 B- 76.6182 0.5375 150 919938.859 1.191 + 25 88 63 151 Eu -74653.098 1.166 8239.2998 0.0077 B- -464.1779 2.7791 150 919856.606 1.251 + 23 87 64 151 Gd -74188.920 2.993 8231.0446 0.0198 B- -2565.3796 3.7615 150 920354.922 3.212 + 21 86 65 151 Tb -71623.541 4.094 8208.8743 0.0271 B- -2871.1525 4.9455 150 923108.970 4.395 + 19 85 66 151 Dy -a -68752.388 3.247 8184.6789 0.0215 B- -5129.6421 8.7507 150 926191.279 3.486 + 17 84 67 151 Ho -a -63622.746 8.298 8145.5267 0.0550 B- -5356.4558 18.4420 150 931698.176 8.908 + 15 83 68 151 Er x -58266.290 16.470 8104.8723 0.1091 B- -7494.6768 25.4292 150 937448.567 17.681 + 13 82 69 151 Tm -50771.613 19.375 8050.0576 0.1283 B- -9229.2615 300.1329 150 945494.433 20.799 + 11 81 70 151 Yb ep -41542.352 300.492 7983.7556 1.9900 B- -11242# 425# 150 955402.453 322.591 + 9 80 71 151 Lu -p -30300# 300# 7904# 2# B- * 150 967471# 322# +0 42 97 55 152 Cs x -29130# 500# 7980# 3# B- 12480# 640# 151 968728# 537# + 40 96 56 152 Ba x -41610# 400# 8057# 3# B- 7680# 500# 151 955330# 429# + 38 95 57 152 La x -49290# 300# 8102# 2# B- 9690# 361# 151 947085# 322# + 36 94 58 152 Ce x -58980# 200# 8161# 1# B- 4778# 201# 151 936682# 215# + 34 93 59 152 Pr x -63758.070 18.537 8187.1049 0.1220 B- 6391.5934 30.7035 151 931552.900 19.900 + 32 92 60 152 Nd -70149.663 24.476 8224.0078 0.1610 B- 1104.8050 18.5011 151 924691.242 26.276 + 30 91 61 152 Pm -71254.468 25.904 8226.1293 0.1704 B- 3508.5089 25.8859 151 923505.185 27.809 + 28 90 62 152 Sm -74762.977 1.016 8244.0645 0.0067 B- -1874.4774 0.6857 151 919738.646 1.090 + 26 89 63 152 Eu -72888.500 1.166 8226.5854 0.0077 B- 1818.8037 0.7002 151 921750.980 1.252 + 24 88 64 152 Gd -74707.304 1.007 8233.4042 0.0066 B- -3990.0000 40.0000 151 919798.414 1.081 + 22 87 65 152 Tb - -70717.304 40.013 8202.0072 0.2632 B- -599.3405 40.2575 151 924081.855 42.955 + 20 86 66 152 Dy -a -70117.963 4.593 8192.9171 0.0302 B- -6513.3275 13.3176 151 924725.274 4.930 + 18 85 67 152 Ho -63604.636 12.528 8144.9193 0.0824 B- -3104.4174 9.8150 151 931717.618 13.449 + 16 84 68 152 Er -60500.218 8.830 8119.3485 0.0581 B- -8779.9397 54.7434 151 935050.347 9.478 + 14 83 69 152 Tm -51720.279 54.027 8056.4387 0.3554 B- -5449.8923 139.6200 151 944476.000 58.000 + 12 82 70 152 Yb -46270.386 149.708 8015.4371 0.9849 B- -12848# 246# 151 950326.699 160.718 + 10 81 71 152 Lu x -33422# 196# 7926# 1# B- * 151 964120# 210# +0 41 97 56 153 Ba x -36470# 400# 8023# 3# B- 9590# 500# 152 960848# 429# + 39 96 57 153 La x -46060# 300# 8081# 2# B- 8850# 361# 152 950553# 322# + 37 95 58 153 Ce x -54910# 200# 8134# 1# B- 6659# 201# 152 941052# 215# + 35 94 59 153 Pr -61568.490 11.882 8172.0371 0.0777 B- 5761.8901 12.1896 152 933903.511 12.755 + 33 93 60 153 Nd -67330.380 2.747 8204.5832 0.0180 B- 3317.6236 9.3521 152 927717.868 2.949 + 31 92 61 153 Pm -70648.003 9.063 8221.1536 0.0592 B- 1912.0559 9.0829 152 924156.252 9.729 + 29 91 62 153 Sm -n -72560.059 1.025 8228.5373 0.0067 B- 807.4073 0.7063 152 922103.576 1.100 + 27 90 63 153 Eu -73367.466 1.171 8228.7011 0.0077 B- -484.5225 0.7150 152 921236.789 1.257 + 25 89 64 153 Gd -72882.944 1.002 8220.4209 0.0066 B- -1569.3340 3.8444 152 921756.945 1.075 + 23 88 65 153 Tb -71313.610 3.947 8205.0504 0.0258 B- -2170.4134 1.9335 152 923441.694 4.237 + 21 87 66 153 Dy -69143.197 4.001 8185.7514 0.0262 B- -4131.1229 6.1571 152 925771.729 4.295 + 19 86 67 153 Ho -a -65012.074 5.066 8153.6372 0.0331 B- -4545.3918 9.8899 152 930206.671 5.438 + 17 85 68 153 Er -60466.682 9.285 8118.8154 0.0607 B- -6494.0723 12.8812 152 935086.350 9.967 + 15 84 69 153 Tm -53972.610 11.979 8071.2571 0.0783 B- -6813# 201# 152 942058.023 12.860 + 13 83 70 153 Yb x -47160# 200# 8022# 1# B- -8784# 250# 152 949372# 215# + 11 82 71 153 Lu +a -38375.462 150.017 7959.0882 0.9805 B- -11075# 335# 152 958802.248 161.050 + 9 81 72 153 Hf x -27300# 300# 7882# 2# B- * 152 970692# 322# +0 42 98 56 154 Ba x -32920# 500# 8001# 3# B- 8610# 583# 153 964659# 537# + 40 97 57 154 La x -41530# 300# 8051# 2# B- 10690# 361# 153 955416# 322# + 38 96 58 154 Ce x -52220# 200# 8116# 1# B- 5640# 224# 153 943940# 215# + 36 95 59 154 Pr + -57859.602 100.005 8147.2994 0.6494 B- 7720.0000 100.0000 153 937885.165 107.360 + 34 94 60 154 Nd x -65579.602 1.025 8192.3491 0.0067 B- 2687.0000 25.0000 153 929597.404 1.100 + 32 93 61 154 Pm - -68266.602 25.021 8204.7170 0.1625 B- 4188.9614 25.0550 153 926712.791 26.861 + 30 92 62 154 Sm -72455.564 1.305 8226.8379 0.0085 B- -717.1969 1.1019 153 922215.756 1.400 + 28 91 63 154 Eu -71738.367 1.188 8217.1006 0.0077 B- 1967.9913 0.7535 153 922985.699 1.275 + 26 90 64 154 Gd -73706.358 0.994 8224.7996 0.0065 B- -3549.6514 45.2983 153 920872.974 1.066 + 24 89 65 154 Tb - -70156.707 45.309 8196.6697 0.2942 B- 237.3080 45.9008 153 924683.681 48.641 + 22 88 66 154 Dy -70394.015 7.431 8193.1305 0.0483 B- -5754.6363 10.1785 153 924428.920 7.977 + 20 87 67 154 Ho -a -64639.378 8.216 8150.6825 0.0534 B- -2034.4045 9.4621 153 930606.776 8.820 + 18 86 68 154 Er -62604.974 4.961 8132.3919 0.0322 B- -8177.8316 14.9113 153 932790.799 5.325 + 16 85 69 154 Tm -a -54427.142 14.412 8074.2090 0.0936 B- -4495.0495 13.9528 153 941570.062 15.471 + 14 84 70 154 Yb -49932.093 17.281 8039.9402 0.1122 B- -10265# 201# 153 946395.696 18.551 + 12 83 71 154 Lu +a -39667# 201# 7968# 1# B- -6937# 361# 153 957416# 216# + 10 82 72 154 Hf x -32730# 300# 7918# 2# B- * 153 964863# 322# +0 41 98 57 155 La x -37930# 400# 8028# 3# B- 9850# 500# 154 959280# 429# + 39 97 58 155 Ce x -47780# 300# 8087# 2# B- 7635# 300# 154 948706# 322# + 37 96 59 155 Pr -55415.335 17.198 8131.0398 0.1110 B- 6868.4609 19.4725 154 940509.193 18.462 + 35 95 60 155 Nd -62283.796 9.154 8170.3050 0.0591 B- 4656.2095 10.2781 154 933135.598 9.826 + 33 94 61 155 Pm -66940.006 4.719 8195.2977 0.0304 B- 3251.1999 4.9024 154 928136.951 5.065 + 31 93 62 155 Sm -n -70191.206 1.332 8211.2258 0.0086 B- 1627.1314 1.2016 154 924646.645 1.429 + 29 92 63 155 Eu -71818.337 1.252 8216.6760 0.0081 B- 251.9612 0.8682 154 922899.847 1.343 + 27 91 64 155 Gd -72070.298 0.983 8213.2541 0.0063 B- -819.8588 9.7884 154 922629.356 1.055 + 25 90 65 155 Tb + -71250.439 9.830 8202.9173 0.0634 B- -2094.5000 1.8974 154 923509.511 10.552 + 23 89 66 155 Dy -69155.939 9.645 8184.3570 0.0622 B- -3116.1405 16.5887 154 925758.049 10.354 + 21 88 67 155 Ho -66039.799 17.470 8159.2055 0.1127 B- -3830.6268 18.4730 154 929103.363 18.754 + 19 87 68 155 Er -a -62209.172 6.074 8129.4444 0.0392 B- -5583.2509 11.5109 154 933215.710 6.520 + 17 86 69 155 Tm -a -56625.921 9.921 8088.3760 0.0640 B- -6123.3072 19.3388 154 939209.576 10.651 + 15 85 70 155 Yb -a -50502.614 16.600 8043.8234 0.1071 B- -7957.5578 25.4153 154 945783.216 17.820 + 13 84 71 155 Lu -42545.056 19.245 7987.4369 0.1242 B- -8235# 301# 154 954326.005 20.660 + 11 83 72 155 Hf x -34310# 300# 7929# 2# B- -10322# 424# 154 963167# 322# + 9 82 73 155 Ta -p -23988# 300# 7858# 2# B- * 154 974248# 322# +0 42 99 57 156 La x -33050# 400# 7997# 3# B- 11769# 500# 155 964519# 429# + 40 98 58 156 Ce x -44820# 300# 8068# 2# B- 6630# 300# 155 951884# 322# + 38 97 59 156 Pr x -51449.307 1.025 8105.2337 0.0066 B- 8752.8229 1.6585 155 944766.900 1.100 + 36 96 60 156 Nd x -60202.130 1.304 8156.3265 0.0084 B- 3964.7175 1.7642 155 935370.358 1.400 + 34 95 61 156 Pm -64166.847 1.188 8176.7263 0.0076 B- 5193.8878 8.6044 155 931114.059 1.275 + 32 94 62 156 Sm -69360.735 8.522 8205.0054 0.0546 B- 722.1090 7.9025 155 925538.191 9.148 + 30 93 63 156 Eu -70082.844 3.532 8204.6192 0.0226 B- 2452.4891 3.4083 155 924762.976 3.791 + 28 92 64 156 Gd -72535.333 0.983 8215.3253 0.0063 B- -2444.3230 3.6774 155 922130.120 1.054 + 26 91 65 156 Tb -70091.010 3.768 8194.6415 0.0242 B- 438.3762 3.6789 155 924754.209 4.044 + 24 90 66 156 Dy -70529.386 0.988 8192.4366 0.0063 B- -4990.9836 38.4111 155 924283.593 1.060 + 22 89 67 156 Ho - -65538.403 38.424 8155.4280 0.2463 B- -1326.7201 45.6391 155 929641.634 41.249 + 20 88 68 156 Er -64211.683 24.629 8141.9084 0.1579 B- -7377.2657 26.7099 155 931065.926 26.440 + 18 87 69 156 Tm -56834.417 14.279 8089.6032 0.0915 B- -3568.8794 12.5484 155 938985.746 15.328 + 16 86 70 156 Yb -53265.538 9.308 8061.7107 0.0597 B- -9565.9880 54.9162 155 942817.096 9.992 + 14 85 71 156 Lu -a -43699.550 54.122 7995.3752 0.3469 B- -5880.0352 139.6908 155 953086.606 58.102 + 12 84 72 156 Hf -37819.514 149.740 7952.6676 0.9599 B- -11819# 335# 155 959399.083 160.752 + 10 83 73 156 Ta -p -26001# 300# 7872# 2# B- * 155 972087# 322# +0 43 100 57 157 La x -29070# 300# 7972# 2# B- 10860# 500# 156 968792# 322# + 41 99 58 157 Ce x -39930# 400# 8037# 3# B- 8504# 400# 156 957133# 429# + 39 98 59 157 Pr x -48434.806 3.167 8085.8170 0.0202 B- 8059.3109 3.8207 156 948003.100 3.400 + 37 97 60 157 Nd -56494.117 2.137 8132.1671 0.0136 B- 5802.9994 7.3246 156 939351.074 2.294 + 35 96 61 157 Pm -62297.116 7.006 8164.1458 0.0446 B- 4380.5376 8.2650 156 933121.298 7.521 + 33 95 62 157 Sm -66677.654 4.434 8187.0642 0.0282 B- 2781.4807 6.1191 156 928418.598 4.759 + 31 94 63 157 Eu -69459.134 4.234 8199.7975 0.0270 B- 1364.7614 4.1973 156 925432.556 4.545 + 29 93 64 157 Gd -70823.896 0.977 8203.5072 0.0062 B- -60.0473 0.2972 156 923967.424 1.048 + 27 92 65 157 Tb -70763.848 1.018 8198.1416 0.0065 B- -1339.1791 5.1297 156 924031.888 1.092 + 25 91 66 157 Dy -69424.669 5.154 8184.6287 0.0328 B- -2591.8068 23.7839 156 925469.555 5.532 + 23 90 67 157 Ho -66832.862 23.469 8163.1373 0.1495 B- -3419.2146 33.6675 156 928251.974 25.194 + 21 89 68 157 Er -63413.648 26.505 8136.3757 0.1688 B- -4704.3690 38.5152 156 931922.652 28.454 + 19 88 69 157 Tm x -58709.279 27.945 8101.4285 0.1780 B- -5289.3667 29.9971 156 936973.000 30.000 + 17 87 70 157 Yb -53419.912 10.905 8062.7551 0.0695 B- -6980.0942 14.2406 156 942651.368 11.706 + 15 86 71 157 Lu -46439.818 12.074 8013.3128 0.0769 B- -7585# 201# 156 950144.807 12.961 + 13 85 72 157 Hf -a -38855# 200# 7960# 1# B- -9259# 250# 156 958288# 215# + 11 84 73 157 Ta IT -29595.948 150.052 7896.0608 0.9557 B- -9906# 427# 156 968227.445 161.087 + 9 83 74 157 W x -19690# 400# 7828# 3# B- * 156 978862# 429# +0 42 100 58 158 Ce x -36540# 400# 8015# 3# B- 7610# 500# 157 960773# 429# + 40 99 59 158 Pr x -44150# 300# 8059# 2# B- 9685# 300# 157 952603# 322# + 38 98 60 158 Nd x -53835.123 1.304 8114.9529 0.0083 B- 5271.0196 1.5776 157 942205.620 1.400 + 36 97 61 158 Pm -59106.143 0.888 8143.3622 0.0056 B- 6145.7062 4.8634 157 936546.948 0.953 + 34 96 62 158 Sm -65251.849 4.782 8177.3075 0.0303 B- 2018.6123 5.1146 157 929949.262 5.133 + 32 95 63 158 Eu -67270.461 2.032 8185.1320 0.0129 B- 3419.5081 2.2547 157 927782.192 2.181 + 30 94 64 158 Gd -70689.969 0.976 8201.8229 0.0062 B- -1219.0862 0.9799 157 924111.200 1.048 + 28 93 65 158 Tb -69470.883 1.268 8189.1556 0.0080 B- 936.2686 2.4750 157 925419.942 1.360 + 26 92 66 158 Dy -70407.152 2.337 8190.1298 0.0148 B- -4219.7555 27.0048 157 924414.817 2.509 + 24 91 67 158 Ho - -66187.396 27.106 8158.4709 0.1716 B- -883.5812 37.0236 157 928944.910 29.099 + 22 90 68 158 Er -65303.815 25.219 8147.9270 0.1596 B- -6600.6151 31.3411 157 929893.474 27.074 + 20 89 69 158 Tm -58703.200 25.219 8101.1994 0.1596 B- -2693.5796 26.4499 157 936979.525 27.074 + 18 88 70 158 Yb -56009.620 7.973 8079.1999 0.0505 B- -8797.4201 16.8655 157 939871.202 8.559 + 16 87 71 158 Lu -a -47212.200 15.125 8018.5685 0.0957 B- -5109.8010 14.9373 157 949315.620 16.236 + 14 86 72 158 Hf -42102.399 17.494 7981.2764 0.1107 B- -10984# 201# 157 954801.217 18.780 + 12 85 73 158 Ta +a -31118# 201# 7907# 1# B- -7426# 361# 157 966593# 215# + 10 84 74 158 W -a -23693# 300# 7855# 2# B- * 157 974565# 322# +0 43 101 58 159 Ce x -31340# 500# 7983# 3# B- 9430# 640# 158 966355# 537# + 41 100 59 159 Pr x -40770# 400# 8037# 3# B- 8954# 401# 158 956232# 429# + 39 99 60 159 Nd x -49724.007 29.808 8088.8224 0.1875 B- 6830.3441 31.4529 158 946619.085 32.000 + 37 98 61 159 Pm -56554.351 10.039 8126.8601 0.0631 B- 5653.4982 11.6438 158 939286.409 10.777 + 35 97 62 159 Sm -62207.849 5.934 8157.4963 0.0373 B- 3835.5363 7.3211 158 933217.130 6.370 + 33 96 63 159 Eu -66043.386 4.320 8176.6987 0.0272 B- 2518.4717 4.3657 158 929099.512 4.637 + 31 95 64 159 Gd -68561.857 0.980 8187.6177 0.0062 B- 970.7242 0.7495 158 926395.822 1.051 + 29 94 65 159 Tb -69532.582 1.103 8188.8025 0.0069 B- -365.3613 1.1573 158 925353.707 1.184 + 27 93 66 159 Dy -69167.220 1.439 8181.5842 0.0091 B- -1837.6000 2.6833 158 925745.938 1.544 + 25 92 67 159 Ho - -67329.620 3.045 8165.1066 0.0192 B- -2768.5000 2.0000 158 927718.683 3.268 + 23 91 68 159 Er - -64561.120 3.643 8142.7742 0.0229 B- -3990.7162 28.1813 158 930690.790 3.910 + 21 90 69 159 Tm x -60570.404 27.945 8112.7549 0.1758 B- -4736.8869 33.0155 158 934975.000 30.000 + 19 89 70 159 Yb x -55833.517 17.582 8078.0428 0.1106 B- -6124.9081 41.5648 158 940060.257 18.874 + 17 88 71 159 Lu x -49708.609 37.663 8034.6009 0.2369 B- -6856.0030 41.2456 158 946635.615 40.433 + 15 87 72 159 Hf -a -42852.606 16.813 7986.5610 0.1057 B- -8413.4492 25.8909 158 953995.837 18.049 + 13 86 73 159 Ta IT -34439.157 19.689 7928.7258 0.1238 B- -9005# 301# 158 963028.046 21.137 + 11 85 74 159 W -a -25434# 300# 7867# 2# B- -10629# 427# 158 972696# 322# + 9 84 75 159 Re IT -14805# 305# 7795# 2# B- * 158 984106# 327# +0 42 101 59 160 Pr x -36200# 400# 8009# 2# B- 10525# 402# 159 961138# 429# + 40 100 60 160 Nd x -46724.515 46.575 8069.9662 0.2911 B- 6170.1238 46.6198 159 949839.172 50.000 + 38 99 61 160 Pm x -52894.639 2.049 8103.6398 0.0128 B- 7338.5338 2.8330 159 943215.272 2.200 + 36 98 62 160 Sm x -60233.172 1.956 8144.6159 0.0122 B- 3260.2763 2.1547 159 935337.032 2.100 + 34 97 63 160 Eu x -63493.449 0.904 8160.1030 0.0057 B- 4448.6112 1.4417 159 931836.982 0.970 + 32 96 64 160 Gd -67942.060 1.123 8183.0171 0.0070 B- -105.5863 1.0207 159 927061.202 1.206 + 30 95 65 160 Tb -67836.474 1.110 8177.4676 0.0069 B- 1835.9516 1.1011 159 927174.553 1.191 + 28 94 66 160 Dy -69672.425 0.700 8184.0526 0.0044 B- -3290.0000 15.0000 159 925203.578 0.751 + 26 93 67 160 Ho - -66382.425 15.016 8158.6004 0.0939 B- -318.2488 28.5197 159 928735.538 16.120 + 24 92 68 160 Er -66064.176 24.246 8151.7217 0.1515 B- -5763.1395 39.1333 159 929077.193 26.029 + 22 91 69 160 Tm -60301.037 32.686 8110.8124 0.2043 B- -2137.8101 33.1447 159 935264.177 35.089 + 20 90 70 160 Yb x -58163.227 5.496 8092.5614 0.0343 B- -7893.2846 57.0863 159 937559.210 5.900 + 18 89 71 160 Lu x -50269.942 56.821 8038.3387 0.3551 B- -4331.1951 57.6165 159 946033.000 61.000 + 16 88 72 160 Hf -45938.747 9.540 8006.3791 0.0596 B- -10115.0475 55.1472 159 950682.728 10.241 + 14 87 73 160 Ta -a -35823.700 54.316 7938.2704 0.3395 B- -6494.6267 139.8413 159 961541.678 58.310 + 12 86 74 160 W -29329.073 149.810 7892.7893 0.9363 B- -12451# 335# 159 968513.946 160.828 + 10 85 75 160 Re -a -16878# 300# 7810# 2# B- * 159 981880# 322# +0 43 102 59 161 Pr x -32490# 500# 7986# 3# B- 9741# 640# 160 965121# 537# + 41 101 60 161 Nd x -42230# 400# 8042# 2# B- 7856# 400# 160 954664# 429# + 39 100 61 161 Pm x -50086.589 9.035 8085.9977 0.0561 B- 6585.4546 11.3187 160 946229.837 9.700 + 37 99 62 161 Sm -56672.043 6.817 8122.0418 0.0423 B- 5119.5577 12.4147 160 939160.062 7.318 + 35 98 63 161 Eu -61791.601 10.400 8148.9810 0.0646 B- 3714.5406 10.5074 160 933663.991 11.164 + 33 97 64 161 Gd -n -65506.142 1.504 8167.1934 0.0093 B- 1955.6357 1.4402 160 929676.267 1.614 + 31 96 65 161 Tb -67461.778 1.218 8174.4809 0.0076 B- 593.7166 1.2010 160 927576.806 1.308 + 29 95 66 161 Dy -68055.494 0.697 8173.3093 0.0043 B- -859.2003 2.1368 160 926939.425 0.748 + 27 94 67 161 Ho -67196.294 2.151 8163.1134 0.0134 B- -1994.9954 9.0041 160 927861.815 2.309 + 25 93 68 161 Er +n -65201.298 8.774 8145.8628 0.0545 B- -3302.5839 29.2899 160 930003.530 9.419 + 23 92 69 161 Tm x -61898.715 27.945 8120.4906 0.1736 B- -4064.4665 31.7640 160 933549.000 30.000 + 21 91 70 161 Yb x -57834.248 15.101 8090.3861 0.0938 B- -5271.8989 31.7640 160 937912.384 16.211 + 19 90 71 161 Lu x -52562.349 27.945 8052.7821 0.1736 B- -6246.5319 36.4805 160 943572.000 30.000 + 17 89 72 161 Hf -46315.817 23.450 8009.1245 0.1457 B- -7537.2421 33.7278 160 950277.927 25.174 + 15 88 73 161 Ta +a -38778.575 24.381 7957.4500 0.1514 B- -8272# 202# 160 958369.489 26.174 + 13 87 74 161 W -a -30507# 200# 7901# 1# B- -9664# 250# 160 967249# 215# + 11 86 75 161 Re -20842.820 149.905 7836.3292 0.9311 B- -10647# 427# 160 977624.313 160.930 + 9 85 76 161 Os -a -10196# 400# 7765# 2# B- * 160 989054# 429# +0 42 102 60 162 Nd x -39010# 400# 8022# 2# B- 7030# 500# 161 958121# 429# + 40 101 61 162 Pm x -46040# 300# 8061# 2# B- 8339# 300# 161 950574# 322# + 38 100 62 162 Sm -54379.053 3.523 8107.5745 0.0218 B- 4343.8905 3.7605 161 941621.687 3.782 + 36 99 63 162 Eu -58722.944 1.314 8129.5593 0.0081 B- 5557.7761 4.1748 161 936958.329 1.410 + 34 98 64 162 Gd -nn -64280.720 3.963 8159.0373 0.0245 B- 1598.8278 4.4611 161 930991.812 4.254 + 32 97 65 162 Tb x -65879.548 2.049 8164.0773 0.0127 B- 2301.6217 2.1640 161 929275.400 2.200 + 30 96 66 162 Dy -68181.169 0.695 8173.4555 0.0043 B- -2140.6068 3.0926 161 926804.507 0.746 + 28 95 67 162 Ho -66040.563 3.102 8155.4126 0.0192 B- 293.6478 3.1069 161 929102.543 3.330 + 26 94 68 162 Er -66334.210 0.756 8152.3959 0.0047 B- -4856.7282 26.0475 161 928787.299 0.811 + 24 93 69 162 Tm - -61477.482 26.058 8117.5868 0.1609 B- -1656.3190 30.1127 161 934001.211 27.974 + 22 92 70 162 Yb x -59821.163 15.103 8102.5333 0.0932 B- -6989.4042 76.5406 161 935779.342 16.213 + 20 91 71 162 Lu x -52831.759 75.036 8054.5596 0.4632 B- -3663.3333 75.5679 161 943282.776 80.554 + 18 90 72 162 Hf -49168.426 8.952 8027.1171 0.0553 B- -9387.0211 63.8938 161 947215.526 9.610 + 16 89 73 162 Ta -a -39781.405 63.322 7964.3432 0.3909 B- -5782.1880 63.3235 161 957292.907 67.979 + 14 88 74 162 W -33999.217 17.657 7923.8214 0.1090 B- -11546# 201# 161 963500.341 18.955 + 12 87 75 162 Re +a -22453# 201# 7848# 1# B- -7953# 361# 161 975896# 215# + 10 86 76 162 Os -a -14500# 300# 7794# 2# B- * 161 984434# 322# +0 43 103 60 163 Nd x -34080# 500# 7992# 3# B- 8880# 640# 162 963414# 537# + 41 102 61 163 Pm x -42960# 400# 8042# 2# B- 7640# 400# 162 953881# 429# + 39 101 62 163 Sm x -50599.612 7.359 8084.1653 0.0451 B- 5974.2073 7.4141 162 945679.085 7.900 + 37 100 63 163 Eu x -56573.819 0.904 8116.0172 0.0056 B- 4814.7720 1.2046 162 939265.510 0.970 + 35 99 64 163 Gd -61388.591 0.797 8140.7560 0.0049 B- 3207.1628 4.1374 162 934096.640 0.855 + 33 98 65 163 Tb +p -64595.754 4.060 8155.6322 0.0249 B- 1785.1041 4.0006 162 930653.609 4.358 + 31 97 66 163 Dy -66380.858 0.693 8161.7840 0.0043 B- -2.8309 0.0222 162 928737.221 0.744 + 29 96 67 163 Ho -66378.027 0.693 8156.9670 0.0043 B- -1210.6141 4.5755 162 928740.260 0.744 + 27 95 68 163 Er -65167.413 4.628 8144.7403 0.0284 B- -2439.0000 3.0000 162 930039.908 4.967 + 25 94 69 163 Tm - -62728.413 5.515 8124.9774 0.0338 B- -3434.5345 16.0687 162 932658.282 5.920 + 23 93 70 163 Yb x -59293.878 15.105 8099.1069 0.0927 B- -4502.4636 31.7657 162 936345.406 16.215 + 21 92 71 163 Lu x -54791.415 27.945 8066.6848 0.1714 B- -5522.0944 37.9611 162 941179.000 30.000 + 19 91 72 163 Hf -49269.320 25.693 8028.0072 0.1576 B- -6734.6864 45.9217 162 947107.211 27.582 + 17 90 73 163 Ta -a -42534.634 38.061 7981.8905 0.2335 B- -7626.1952 69.7301 162 954337.194 40.860 + 15 89 74 163 W -a -34908.439 58.426 7930.3043 0.3584 B- -8906.1859 61.2953 162 962524.251 62.722 + 13 88 75 163 Re +a -26002.253 18.534 7870.8655 0.1137 B- -9666# 301# 162 972085.434 19.897 + 11 87 76 163 Os -a -16336# 300# 7807# 2# B- -11026# 500# 162 982462# 322# + 9 86 77 163 Ir x -5310# 400# 7734# 2# B- * 162 994299# 429# +0 42 103 61 164 Pm x -38360# 400# 8014# 2# B- 9565# 400# 163 958819# 429# + 40 102 62 164 Sm x -47925.314 4.099 8067.7803 0.0250 B- 5306.8315 4.5907 163 948550.061 4.400 + 38 101 63 164 Eu -53232.146 2.068 8095.3686 0.0126 B- 6461.5416 2.2969 163 942852.943 2.219 + 36 100 64 164 Gd -59693.688 1.000 8129.9978 0.0061 B- 2411.2959 2.1143 163 935916.193 1.073 + 34 99 65 164 Tb x -62104.983 1.863 8139.9304 0.0114 B- 3862.6653 1.9884 163 933327.561 2.000 + 32 98 66 164 Dy -65967.649 0.695 8158.7129 0.0042 B- -987.1315 1.3710 163 929180.819 0.746 + 30 97 67 164 Ho -64980.517 1.390 8147.9234 0.0085 B- 962.0559 1.3756 163 930240.548 1.492 + 28 96 68 164 Er -65942.573 0.704 8149.0191 0.0043 B- -4033.6302 25.0113 163 929207.739 0.755 + 26 95 69 164 Tm -61908.943 25.006 8119.6534 0.1525 B- -896.7722 29.2135 163 933538.019 26.845 + 24 94 70 164 Yb x -61012.171 15.106 8109.4149 0.0921 B- -6369.7952 31.7666 163 934500.743 16.217 + 22 93 71 164 Lu x -54642.376 27.945 8065.8043 0.1704 B- -2824.0194 32.1083 163 941339.000 30.000 + 20 92 72 164 Hf -51818.356 15.812 8043.8142 0.0964 B- -8535.5511 32.1083 163 944370.709 16.975 + 18 91 73 164 Ta x -43282.805 27.945 7986.9978 0.1704 B- -5047.2500 29.5717 163 953534.000 30.000 + 16 90 74 164 W -38235.555 9.673 7951.4515 0.0590 B- -10763.1138 55.4055 163 958952.445 10.384 + 14 89 75 164 Re -a -27472.441 54.555 7881.0523 0.3326 B- -7047.7180 140.0330 163 970507.122 58.566 + 12 88 76 164 Os -20424.723 149.903 7833.3080 0.9140 B- -12941# 350# 163 978073.158 160.927 + 10 87 77 164 Ir -a -7483# 316# 7750# 2# B- * 163 991966# 339# +0 43 104 61 165 Pm x -34670# 500# 7992# 3# B- 8840# 640# 164 962780# 537# + 41 103 62 165 Sm x -43510# 400# 8041# 2# B- 7219# 400# 164 953290# 429# + 39 102 63 165 Eu -50729.103 5.213 8080.0529 0.0316 B- 5796.6788 5.3733 164 945540.070 5.596 + 37 101 64 165 Gd -56525.782 1.304 8110.4428 0.0079 B- 4063.0674 2.0189 164 939317.080 1.400 + 35 100 65 165 Tb -60588.849 1.541 8130.3259 0.0093 B- 3023.4392 1.6915 164 934955.198 1.654 + 33 99 66 165 Dy -n -63612.289 0.697 8143.9083 0.0042 B- 1285.7287 0.7502 164 931709.402 0.748 + 31 98 67 165 Ho -64898.017 0.786 8146.9591 0.0048 B- -376.6648 0.9575 164 930329.116 0.844 + 29 97 68 165 Er -64521.353 0.918 8139.9348 0.0056 B- -1591.3282 1.4891 164 930733.482 0.985 + 27 96 69 165 Tm -62930.024 1.658 8125.5489 0.0101 B- -2634.6364 26.5907 164 932441.843 1.779 + 25 95 70 165 Yb -60295.388 26.539 8104.8399 0.1608 B- -3853.1403 35.4324 164 935270.241 28.490 + 23 94 71 165 Lu -56442.248 26.539 8076.7460 0.1608 B- -4806.7350 38.5387 164 939406.758 28.490 + 21 93 72 165 Hf x -51635.513 27.945 8042.8728 0.1694 B- -5787.6410 31.0668 164 944567.000 30.000 + 19 92 73 165 Ta -45847.872 13.573 8003.0547 0.0823 B- -6986.5555 29.1133 164 950780.287 14.571 + 17 91 74 165 W -38861.316 25.756 7955.9704 0.1561 B- -8201.9627 34.9116 164 958280.663 27.649 + 15 90 75 165 Re +a -30659.353 23.593 7901.5201 0.1430 B- -8913# 202# 164 967085.831 25.328 + 13 89 76 165 Os -a -21747# 200# 7843# 1# B- -10151# 255# 164 976654# 215# + 11 88 77 165 Ir IT -11595# 158# 7776# 1# B- -11277# 430# 164 987552# 170# + 9 87 78 165 Pt -a -318# 400# 7703# 2# B- * 164 999658# 429# +0 42 104 62 166 Sm x -40450# 400# 8023# 2# B- 6299# 412# 165 956575# 429# + 40 103 63 166 Eu + -46749# 100# 8056# 1# B- 7622# 100# 165 949813# 107# + 38 102 64 166 Gd x -54370.926 1.584 8097.2260 0.0095 B- 3437.8515 2.1558 165 941630.413 1.700 + 36 101 65 166 Tb -57808.778 1.463 8113.2230 0.0088 B- 4775.6930 1.6690 165 937939.727 1.570 + 34 100 66 166 Dy -n -62584.471 0.804 8137.2793 0.0048 B- 485.8684 0.8502 165 932812.810 0.862 + 32 99 67 166 Ho -63070.339 0.786 8135.4933 0.0047 B- 1853.8057 0.7792 165 932291.209 0.844 + 30 98 68 166 Er -64924.145 0.334 8141.9479 0.0020 B- -3037.6667 11.5470 165 930301.067 0.358 + 28 97 69 166 Tm - -61886.478 11.552 8118.9357 0.0696 B- -292.7714 13.5069 165 933562.136 12.401 + 26 96 70 166 Yb +nn -61593.706 7.001 8112.4591 0.0422 B- -5572.7197 30.6189 165 933876.439 7.515 + 24 95 71 166 Lu x -56020.987 29.808 8074.1756 0.1796 B- -2161.9978 40.8585 165 939859.000 32.000 + 22 94 72 166 Hf x -53858.989 27.945 8056.4386 0.1683 B- -7761.2089 39.5199 165 942180.000 30.000 + 20 93 73 166 Ta x -46097.780 27.945 8004.9714 0.1683 B- -4210.3092 29.5036 165 950512.000 30.000 + 18 92 74 166 W -41887.471 9.463 7974.8951 0.0570 B- -10050.1358 88.7072 165 955031.952 10.159 + 16 91 75 166 Re -a -31837.335 88.242 7909.6392 0.5316 B- -6405.8090 88.3046 165 965821.216 94.731 + 14 90 76 166 Os -25431.526 17.966 7866.3371 0.1082 B- -12126# 201# 165 972698.135 19.287 + 12 89 77 166 Ir -p -13306# 201# 7789# 1# B- -8523# 361# 165 985716# 215# + 10 88 78 166 Pt -a -4783# 300# 7733# 2# B- * 165 994866# 322# +0 43 105 62 167 Sm x -35330# 500# 7992# 3# B- 8440# 640# 166 962072# 537# + 41 104 63 167 Eu x -43770# 400# 8038# 2# B- 7006# 400# 166 953011# 429# + 39 103 64 167 Gd -50775.732 5.213 8075.5428 0.0312 B- 5107.3505 5.5584 166 945490.012 5.596 + 37 102 65 167 Tb -55883.082 1.929 8101.4410 0.0116 B- 4028.3686 4.4459 166 940007.046 2.071 + 35 101 66 167 Dy x -59911.451 4.005 8120.8782 0.0240 B- 2368.0076 6.5549 166 935682.415 4.300 + 33 100 67 167 Ho p2n -62279.459 5.189 8130.3732 0.0311 B- 1009.7971 5.1890 166 933140.254 5.570 + 31 99 68 167 Er -63289.256 0.286 8131.7352 0.0017 B- -746.1392 1.2633 166 932056.192 0.306 + 29 98 69 167 Tm -62543.117 1.258 8122.5826 0.0075 B- -1953.2162 3.7968 166 932857.206 1.350 + 27 97 70 167 Yb -60589.900 3.960 8106.2020 0.0237 B- -3063.6190 37.4696 166 934954.069 4.251 + 25 96 71 167 Lu x -57526.281 37.260 8083.1722 0.2231 B- -4058.5198 46.5747 166 938243.000 40.000 + 23 95 72 167 Hf x -53467.761 27.945 8054.1850 0.1673 B- -5116.6971 39.5199 166 942600.000 30.000 + 21 94 73 167 Ta x -48351.064 27.945 8018.8614 0.1673 B- -6257.8523 33.6262 166 948093.000 30.000 + 19 93 74 167 W -42093.212 18.703 7976.7045 0.1120 B- -7259# 44# 166 954811.080 20.078 + 17 92 75 167 Re +a -34834# 40# 7929# 0# B- -8335# 90# 166 962604# 43# + 15 91 76 167 Os -a -26498.860 80.892 7873.9557 0.4844 B- -9426.4121 82.9464 166 971552.304 86.841 + 13 90 77 167 Ir -17072.448 18.346 7812.8254 0.1099 B- -10319# 307# 166 981671.973 19.694 + 11 89 78 167 Pt -a -6753# 306# 7746# 2# B- * 166 992750# 329# +0 44 106 62 168 Sm x -31640# 300# 7971# 2# B- 7610# 500# 167 966033# 322# + 42 105 63 168 Eu x -39250# 400# 8012# 2# B- 8899# 500# 167 957863# 429# + 40 104 64 168 Gd x -48150# 300# 8060# 2# B- 4631# 300# 167 948309# 322# + 38 103 65 168 Tb x -52781.181 4.192 8082.7980 0.0250 B- 5777.2167 140.0696 167 943337.074 4.500 + 36 102 66 168 Dy +pp -58558.398 140.007 8112.5293 0.8334 B- 1500.8333 143.1849 167 937134.977 150.303 + 34 101 67 168 Ho + -60059.231 30.001 8116.8061 0.1786 B- 2930.0000 30.0000 167 935523.766 32.207 + 32 100 68 168 Er -62989.231 0.262 8129.5897 0.0016 B- -1676.8526 1.6858 167 932378.282 0.280 + 30 99 69 168 Tm -61312.379 1.677 8114.9516 0.0100 B- 267.4880 1.6782 167 934178.457 1.800 + 28 98 70 168 Yb -61579.867 0.093 8111.8870 0.0006 B- -4507.0351 37.9735 167 933891.297 0.100 + 26 97 71 168 Lu -57072.832 37.973 8080.4026 0.2260 B- -1712.2740 47.1476 167 938729.798 40.766 + 24 96 72 168 Hf x -55360.557 27.945 8065.5536 0.1663 B- -6966.6444 39.5199 167 940568.000 30.000 + 22 95 73 168 Ta x -48393.913 27.945 8019.4287 0.1663 B- -3500.9828 30.9307 167 948047.000 30.000 + 20 94 74 168 W -44892.930 13.259 7993.9327 0.0789 B- -9098.0411 33.5515 167 951805.459 14.233 + 18 93 75 168 Re -a -35794.889 30.821 7935.1208 0.1835 B- -5799.8944 32.3727 167 961572.607 33.087 + 16 92 76 168 Os -29994.995 9.903 7895.9408 0.0589 B- -11328.7644 56.0975 167 967799.050 10.631 + 14 91 77 168 Ir -a -18666.230 55.216 7823.8509 0.3287 B- -7656.1526 140.3258 167 979960.978 59.277 + 12 90 78 168 Pt -a -11010.078 149.934 7773.6217 0.8925 B- -13540# 427# 167 988180.196 160.960 + 10 89 79 168 Au x 2530# 400# 7688# 2# B- * 168 002716# 429# +0 43 106 63 169 Eu x -35660# 500# 7991# 3# B- 8230# 640# 168 961717# 537# + 41 105 64 169 Gd x -43890# 400# 8035# 2# B- 6590# 500# 168 952882# 429# + 39 104 65 169 Tb x -50480# 300# 8069# 2# B- 5116# 425# 168 945807# 322# + 37 103 66 169 Dy + -55596.010 300.669 8094.7566 1.7791 B- 3200.0000 300.0000 168 940315.231 322.781 + 35 102 67 169 Ho +p -58796.010 20.048 8109.0622 0.1186 B- 2125.1534 20.0483 168 936879.890 21.522 + 33 101 68 169 Er -n -60921.163 0.304 8117.0078 0.0018 B- 353.4910 0.7729 168 934598.444 0.326 + 31 100 69 169 Tm -61274.654 0.738 8114.4702 0.0044 B- -899.1270 0.7563 168 934218.956 0.792 + 29 99 70 169 Yb -n -60375.527 0.178 8104.5206 0.0011 B- -2293.0000 3.0000 168 935184.208 0.191 + 27 98 71 169 Lu - -58082.527 3.005 8086.3233 0.0178 B- -3365.6321 28.1060 168 937645.845 3.226 + 25 97 72 169 Hf x -54716.895 27.945 8061.7791 0.1654 B- -4426.4600 39.5199 168 941259.000 30.000 + 23 96 73 169 Ta x -50290.435 27.945 8030.9577 0.1654 B- -5372.5686 31.9246 168 946011.000 30.000 + 21 95 74 169 W -44917.866 15.436 7994.5381 0.0913 B- -6508.6195 19.1703 168 951778.689 16.571 + 19 94 75 169 Re +a -38409.247 11.369 7951.3963 0.0673 B- -7686.2626 28.3218 168 958765.979 12.204 + 17 93 76 169 Os -a -30722.984 25.940 7901.2862 0.1535 B- -8629.5684 34.8557 168 967017.521 27.847 + 15 92 77 169 Ir +a -22093.416 23.307 7845.5944 0.1379 B- -9629# 202# 168 976281.743 25.020 + 13 91 78 169 Pt -a -12464# 200# 7784# 1# B- -10676# 359# 168 986619# 215# + 11 90 79 169 Au x -1788# 298# 7716# 2# B- * 168 998080# 320# +0 44 107 63 170 Eu x -30860# 500# 7963# 3# B- 9989# 707# 169 966870# 537# + 42 106 64 170 Gd x -40850# 500# 8017# 3# B- 5860# 583# 169 956146# 537# + 40 105 65 170 Tb x -46710# 300# 8047# 2# B- 7000# 361# 169 949855# 322# + 38 104 66 170 Dy x -53710# 200# 8084# 1# B- 2528# 206# 169 942340# 215# + 36 103 67 170 Ho + -56237.514 50.019 8093.7902 0.2942 B- 3870.0000 50.0000 169 939626.548 53.697 + 34 102 68 170 Er -60107.514 1.387 8111.9529 0.0082 B- -312.1997 1.7852 169 935471.933 1.488 + 32 101 69 170 Tm -59795.314 0.732 8105.5144 0.0043 B- 968.6148 0.7319 169 935807.093 0.785 + 30 100 70 170 Yb -60763.929 0.010 8106.6101 0.0003 B- -3457.6950 16.8430 169 934767.242 0.011 + 28 99 71 170 Lu - -57306.234 16.843 8081.6686 0.0991 B- -1052.3734 32.6282 169 938479.230 18.081 + 26 98 72 170 Hf x -56253.860 27.945 8070.8762 0.1644 B- -6116.1903 39.5199 169 939609.000 30.000 + 24 97 73 170 Ta x -50137.670 27.945 8030.2965 0.1644 B- -2846.8656 30.9035 169 946175.000 30.000 + 22 96 74 170 W -47290.804 13.195 8008.9482 0.0776 B- -8386.8083 17.4557 169 949231.235 14.165 + 20 95 75 170 Re -38903.996 11.427 7955.0120 0.0672 B- -4978.3046 15.0274 169 958234.844 12.267 + 18 94 76 170 Os -33925.692 9.759 7921.1258 0.0574 B- -10743# 102# 169 963579.273 10.476 + 16 93 77 170 Ir -a -23182# 101# 7853# 1# B- -6883# 102# 169 975113# 109# + 14 92 78 170 Pt -16299.202 18.246 7808.2365 0.1073 B- -12596# 202# 169 982502.087 19.588 + 12 91 79 170 Au -p -3703# 201# 7730# 1# B- -9119# 362# 169 996024# 216# + 10 90 80 170 Hg -a 5415# 302# 7671# 2# B- * 170 005814# 324# +0 43 107 64 171 Gd x -36210# 500# 7990# 3# B- 7560# 640# 170 961127# 537# + 41 106 65 171 Tb x -43770# 400# 8030# 2# B- 6240# 447# 170 953011# 429# + 39 105 66 171 Dy x -50010# 200# 8062# 1# B- 4508# 633# 170 946312# 215# + 37 104 67 171 Ho + -54517.822 600.002 8083.6021 3.5088 B- 3200.0000 600.0000 170 941472.713 644.128 + 35 103 68 171 Er -57717.822 1.408 8097.7404 0.0082 B- 1492.4490 1.0788 170 938037.372 1.511 + 33 102 69 171 Tm -59210.271 0.972 8101.8931 0.0057 B- 96.5468 0.9715 170 936435.162 1.043 + 31 101 70 171 Yb -59306.818 0.013 8097.8826 0.0003 B- -1478.3526 1.8621 170 936331.515 0.013 + 29 100 71 171 Lu -57828.465 1.862 8084.6621 0.0109 B- -2397.1144 28.9363 170 937918.591 1.999 + 27 99 72 171 Hf x -55431.351 28.876 8066.0687 0.1689 B- -3711.0725 40.1840 170 940492.000 31.000 + 25 98 73 171 Ta x -51720.279 27.945 8039.7914 0.1634 B- -4634.1832 39.5199 170 944476.000 30.000 + 23 97 74 171 W x -47086.095 27.945 8008.1158 0.1634 B- -5835.8106 39.5199 170 949451.000 30.000 + 21 96 75 171 Re x -41250.285 27.945 7969.4131 0.1634 B- -6953.0469 33.3748 170 955716.000 30.000 + 19 95 76 171 Os -34297.238 18.247 7924.1769 0.1067 B- -7885.2079 42.5749 170 963180.402 19.589 + 17 94 77 171 Ir -a -26412.030 38.466 7873.4895 0.2249 B- -8945.4613 89.6251 170 971645.520 41.295 + 15 93 78 171 Pt -a -17466.569 80.951 7816.6017 0.4734 B- -9904.2655 83.5586 170 981248.868 86.904 + 13 92 79 171 Au -p -7562.303 20.713 7754.1069 0.1211 B- -10901# 307# 170 991881.533 22.236 + 11 91 80 171 Hg -a 3339# 307# 7686# 2# B- * 171 003585# 329# +0 44 108 64 172 Gd x -32970# 300# 7972# 2# B- 6720# 583# 171 964605# 322# + 42 107 65 172 Tb x -39690# 500# 8006# 3# B- 8070# 583# 171 957391# 537# + 40 106 66 172 Dy x -47760# 300# 8049# 2# B- 3724# 358# 171 948728# 322# + 38 105 67 172 Ho x -51484# 196# 8066# 1# B- 4999# 196# 171 944730# 210# + 36 104 68 172 Er -56482.578 3.962 8090.4052 0.0230 B- 890.9756 4.5418 171 939363.461 4.253 + 34 103 69 172 Tm -57373.554 5.481 8091.0367 0.0319 B- 1881.9024 5.4814 171 938406.959 5.884 + 32 102 70 172 Yb -59255.456 0.014 8097.4295 0.0003 B- -2519.3805 2.3360 171 936386.654 0.014 + 30 101 71 172 Lu -56736.076 2.336 8078.2334 0.0136 B- -333.8443 24.5396 171 939091.320 2.507 + 28 100 72 172 Hf x -56402.232 24.428 8071.7439 0.1420 B- -5072.2490 37.1167 171 939449.716 26.224 + 26 99 73 172 Ta x -51329.983 27.945 8037.7056 0.1625 B- -2232.7914 39.5199 171 944895.000 30.000 + 24 98 74 172 W x -49097.191 27.945 8020.1757 0.1625 B- -7530.3525 45.2323 171 947292.000 30.000 + 22 97 75 172 Re -41566.839 35.568 7971.8460 0.2068 B- -4323.1979 37.7890 171 955376.165 38.183 + 20 96 76 172 Os -37243.641 12.766 7942.1626 0.0742 B- -9864.2673 34.8263 171 960017.309 13.704 + 18 95 77 172 Ir -a -27379.373 32.402 7880.2637 0.1884 B- -6272.7035 34.0232 171 970607.035 34.785 + 16 94 78 172 Pt -21106.670 10.376 7839.2460 0.0603 B- -11788.6592 57.1082 171 977341.059 11.139 + 14 93 79 172 Au -a -9318.011 56.158 7766.1587 0.3265 B- -8256.6495 140.8350 171 989996.704 60.287 + 12 92 80 172 Hg -a -1061.361 150.062 7713.6064 0.8725 B- * 171 998860.581 161.098 +0 43 108 65 173 Tb x -36510# 500# 7988# 3# B- 7230# 640# 172 960805# 537# + 41 107 66 173 Dy x -43740# 400# 8026# 2# B- 5610# 499# 172 953043# 429# + 39 106 67 173 Ho x -49351# 298# 8054# 2# B- 4304# 357# 172 947020# 320# + 37 105 68 173 Er x -53654# 196# 8074# 1# B- 2602# 196# 172 942400# 210# + 35 104 69 173 Tm p2n -56256.067 4.400 8084.4633 0.0254 B- 1295.1669 4.4000 172 939606.630 4.723 + 33 103 70 173 Yb -57551.234 0.011 8087.4276 0.0003 B- -670.2201 1.5674 172 938216.211 0.012 + 31 102 71 173 Lu -56881.014 1.567 8079.0312 0.0091 B- -1469.2244 27.9887 172 938935.722 1.682 + 29 101 72 173 Hf x -55411.790 27.945 8066.0164 0.1615 B- -3015.2464 39.5199 172 940513.000 30.000 + 27 100 73 173 Ta x -52396.543 27.945 8044.0650 0.1615 B- -3669.1553 39.5199 172 943750.000 30.000 + 25 99 74 173 W x -48727.388 27.945 8018.3337 0.1615 B- -5173.5182 39.5199 172 947689.000 30.000 + 23 98 75 173 Re x -43553.870 27.945 7983.9068 0.1615 B- -6115.6196 31.6968 172 953243.000 30.000 + 21 97 76 173 Os -37438.250 14.959 7944.0341 0.0865 B- -7169.7944 18.2998 172 959808.387 16.059 + 19 96 77 173 Ir -30268.456 10.542 7898.0680 0.0609 B- -8331.6974 64.3014 172 967505.477 11.316 + 17 95 78 173 Pt -a -21936.758 63.431 7845.3856 0.3667 B- -9104.7415 67.3903 172 976449.922 68.096 + 15 94 79 173 Au +a -12832.017 22.783 7788.2348 0.1317 B- -10171# 202# 172 986224.263 24.458 + 13 93 80 173 Hg -a -2661# 201# 7725# 1# B- * 172 997143# 215# +0 44 109 65 174 Tb x -31970# 500# 7963# 3# B- 9160# 707# 173 965679# 537# + 42 108 66 174 Dy x -41130# 500# 8011# 3# B- 4739# 583# 173 955845# 537# + 40 107 67 174 Ho x -45870# 300# 8034# 2# B- 6080# 423# 173 950757# 322# + 38 106 68 174 Er x -51949# 298# 8064# 2# B- 1915# 301# 173 944230# 320# + 36 105 69 174 Tm + -53864.521 44.721 8070.6432 0.2570 B- 3080.0000 44.7214 173 942174.061 48.010 + 34 104 70 174 Yb -56944.521 0.011 8083.8481 0.0003 B- -1374.2287 1.5675 173 938867.545 0.011 + 32 103 71 174 Lu -55570.292 1.567 8071.4540 0.0090 B- 274.2911 2.1686 173 940342.840 1.682 + 30 102 72 174 Hf -55844.583 2.259 8068.5341 0.0130 B- -4103.8117 28.0360 173 940048.377 2.425 + 28 101 73 174 Ta x -51740.771 27.945 8040.4528 0.1606 B- -1513.6779 39.5199 173 944454.000 30.000 + 26 100 74 174 W x -50227.093 27.945 8027.2572 0.1606 B- -6553.9925 39.5199 173 946079.000 30.000 + 24 99 75 174 Re x -43673.101 27.945 7985.0944 0.1606 B- -3677.7177 29.7667 173 953115.000 30.000 + 22 98 76 174 Os -39995.383 10.254 7959.4618 0.0589 B- -9209.4466 15.2008 173 957063.192 11.008 + 20 97 77 174 Ir +a -30785.937 11.221 7902.0377 0.0645 B- -5468.3293 15.2578 173 966949.939 12.046 + 18 96 78 174 Pt -a -25317.608 10.338 7866.1143 0.0594 B- -11259# 102# 173 972820.431 11.098 + 16 95 79 174 Au -a -14058# 102# 7797# 1# B- -7417# 102# 173 984908# 109# + 14 94 80 174 Hg -a -6641.017 19.211 7749.7851 0.1104 B- * 173 992870.575 20.623 +0 43 109 66 175 Dy x -36730# 500# 7986# 3# B- 6570# 640# 174 960569# 537# + 41 108 67 175 Ho x -43300# 400# 8019# 2# B- 5352# 566# 174 953516# 429# + 39 107 68 175 Er x -48652# 401# 8045# 2# B- 3659# 404# 174 947770# 430# + 37 106 69 175 Tm + -52310.556 50.000 8061.7673 0.2857 B- 2385.0000 50.0000 174 943842.310 53.677 + 35 105 70 175 Yb -54695.556 0.071 8070.9253 0.0005 B- 470.1219 1.2068 174 941281.907 0.076 + 33 104 71 175 Lu -55165.678 1.207 8069.1412 0.0069 B- -683.9154 1.9516 174 940777.211 1.295 + 31 103 72 175 Hf -54481.763 2.283 8060.7625 0.0130 B- -2073.1103 28.0379 174 941511.424 2.450 + 29 102 73 175 Ta x -52408.653 27.945 8044.4456 0.1597 B- -2775.8524 39.5199 174 943737.000 30.000 + 27 101 74 175 W x -49632.800 27.945 8024.1130 0.1597 B- -4344.4885 39.5199 174 946717.000 30.000 + 25 100 75 175 Re x -45288.312 27.945 7994.8168 0.1597 B- -5182.9513 30.3243 174 951381.000 30.000 + 23 99 76 175 Os -40105.360 11.775 7960.7294 0.0673 B- -6710.8496 17.0887 174 956945.126 12.640 + 21 98 77 175 Ir -33394.511 12.384 7917.9112 0.0708 B- -7685.8265 22.3572 174 964149.519 13.295 + 19 97 78 175 Pt -25708.684 18.614 7869.5216 0.1064 B- -8304.9980 42.8203 174 972400.593 19.982 + 17 96 79 175 Au -a -17403.686 38.563 7817.5939 0.2204 B- -9434.2436 89.7876 174 981316.375 41.399 + 15 95 80 175 Hg -a -7969.443 81.085 7759.2134 0.4633 B- * 174 991444.451 87.047 +0 44 110 66 176 Dy x -33610# 500# 7969# 3# B- 5780# 707# 175 963918# 537# + 42 109 67 176 Ho x -39390# 500# 7997# 3# B- 7241# 641# 175 957713# 537# + 40 108 68 176 Er x -46631# 401# 8034# 2# B- 2741# 413# 175 949940# 430# + 38 107 69 176 Tm + -49371.322 100.000 8045.1214 0.5682 B- 4120.0000 100.0000 175 946997.707 107.354 + 36 106 70 176 Yb -53491.322 0.014 8064.0853 0.0003 B- -108.9895 1.2124 175 942574.706 0.015 + 34 105 71 176 Lu -53382.333 1.212 8059.0209 0.0069 B- 1194.0947 0.8744 175 942691.711 1.301 + 32 104 72 176 Hf -54576.428 1.482 8061.3604 0.0084 B- -3211.0484 30.7750 175 941409.797 1.591 + 30 103 73 176 Ta x -51365.379 30.739 8038.6706 0.1747 B- -723.7709 41.5430 175 944857.000 33.000 + 28 102 74 176 W x -50641.608 27.945 8030.1131 0.1588 B- -5578.7182 39.5199 175 945634.000 30.000 + 26 101 75 176 Re x -45062.890 27.945 7993.9707 0.1588 B- -2931.7058 30.0134 175 951623.000 30.000 + 24 100 76 176 Os -42131.184 10.949 7972.8681 0.0622 B- -8249.2618 13.6110 175 954770.315 11.754 + 22 99 77 176 Ir -33881.923 8.085 7921.5522 0.0459 B- -4948.0041 15.0657 175 963626.261 8.679 + 20 98 78 176 Pt -28933.918 12.712 7888.9934 0.0722 B- -10412.9516 35.5363 175 968938.162 13.647 + 18 97 79 176 Au -a -18520.967 33.185 7825.3837 0.1885 B- -6736.3283 34.9978 175 980116.925 35.625 + 16 96 80 176 Hg -11784.639 11.118 7782.6640 0.0632 B- -12369.3668 83.7993 175 987348.670 11.936 + 14 95 81 176 Tl -p 584.728 83.058 7707.9383 0.4719 B- * 176 000627.731 89.166 +0 43 110 67 177 Ho x -36280# 500# 7980# 3# B- 6578# 709# 176 961052# 537# + 41 109 68 177 Er x -42858# 503# 8013# 3# B- 4711# 541# 176 953990# 540# + 39 108 69 177 Tm x -47570# 200# 8035# 1# B- 3417# 200# 176 948932# 215# + 37 107 70 177 Yb -n -50986.404 0.220 8049.9741 0.0013 B- 1397.4983 1.2406 176 945263.846 0.236 + 35 106 71 177 Lu -52383.903 1.221 8053.4495 0.0069 B- 496.8425 0.7921 176 943763.570 1.310 + 33 105 72 177 Hf -52880.745 1.410 8051.8365 0.0080 B- -1166.0000 3.0000 176 943230.187 1.514 + 31 104 73 177 Ta - -51714.745 3.315 8040.8289 0.0187 B- -2013.0144 28.1408 176 944481.940 3.558 + 29 103 74 177 W x -49701.731 27.945 8025.0359 0.1579 B- -3432.5558 39.5199 176 946643.000 30.000 + 27 102 75 177 Re x -46269.175 27.945 8001.2229 0.1579 B- -4312.7271 31.5349 176 950328.000 30.000 + 25 101 76 177 Os +a -41956.448 14.613 7972.4371 0.0826 B- -5909.0234 24.5763 176 954957.902 15.687 + 23 100 77 177 Ir x -36047.425 19.760 7934.6328 0.1116 B- -6676.9880 24.8010 176 961301.500 21.213 + 21 99 78 177 Pt -29370.437 14.988 7892.4896 0.0847 B- -7824.7003 17.9991 176 968469.541 16.090 + 19 98 79 177 Au -21545.736 9.968 7843.8623 0.0563 B- -8769.9135 85.3061 176 976869.701 10.700 + 17 97 80 177 Hg -a -12775.823 84.722 7789.8947 0.4787 B- -9435.7198 87.4322 176 986284.590 90.952 + 15 96 81 177 Tl IT -3340.103 21.628 7732.1655 0.1222 B- * 176 996414.252 23.218 +0 44 111 67 178 Ho x -32130# 500# 7957# 3# B- 8130# 778# 177 965507# 537# + 42 110 68 178 Er x -40260# 596# 7999# 3# B- 3980# 667# 177 956779# 640# + 40 109 69 178 Tm x -44240# 300# 8017# 2# B- 5437# 300# 177 952506# 322# + 38 108 70 178 Yb -49677.139 6.588 8042.7386 0.0370 B- 660.7415 6.9617 177 946669.400 7.072 + 36 107 71 178 Lu -50337.881 2.251 8042.0554 0.0127 B- 2097.4851 2.0569 177 945960.065 2.416 + 34 106 72 178 Hf -52435.366 1.415 8049.4438 0.0080 B- -1837# 52# 177 943708.322 1.519 + 32 105 73 178 Ta IT -50598# 52# 8035# 0# B- -191# 50# 177 945680# 56# + 30 104 74 178 W - -50407.066 15.199 8029.2584 0.0854 B- -4753.6082 31.8106 177 945885.791 16.316 + 28 103 75 178 Re x -45653.457 27.945 7998.1576 0.1570 B- -2109.2143 31.0925 177 950989.000 30.000 + 26 102 76 178 Os -43544.243 13.632 7981.9128 0.0766 B- -7289.9295 23.2390 177 953253.334 14.634 + 24 101 77 178 Ir -36254.314 18.821 7936.5630 0.1057 B- -4256.8282 21.3752 177 961079.395 20.204 + 22 100 78 178 Pt -31997.486 10.133 7908.2530 0.0569 B- -9694.4567 14.4108 177 965649.288 10.878 + 20 99 79 178 Au x -22303.029 10.246 7849.3946 0.0576 B- -5987.6832 14.8566 177 976056.714 11.000 + 18 98 80 178 Hg -a -16315.346 10.758 7811.3607 0.0604 B- -11702# 103# 177 982484.756 11.548 + 16 97 81 178 Tl -a -4613# 102# 7741# 1# B- -8187# 103# 177 995047# 110# + 14 96 82 178 Pb -a 3573.371 23.184 7690.8359 0.1302 B- * 178 003836.171 24.889 +0 43 111 68 179 Er x -36080# 500# 7976# 3# B- 5821# 640# 178 961267# 537# + 41 110 69 179 Tm x -41900# 400# 8004# 2# B- 4739# 447# 178 955018# 429# + 39 109 70 179 Yb x -46640# 200# 8026# 1# B- 2419# 200# 178 949930# 215# + 37 108 71 179 Lu -49059.013 5.150 8035.0744 0.0288 B- 1404.0231 5.0672 178 947332.985 5.528 + 35 107 72 179 Hf -50463.036 1.416 8038.5474 0.0079 B- -105.5801 0.4088 178 945825.705 1.520 + 33 106 73 179 Ta -50357.456 1.466 8033.5869 0.0082 B- -1062.2093 14.5197 178 945939.050 1.574 + 31 105 74 179 W -49295.247 14.573 8023.2821 0.0814 B- -2710.9347 26.8021 178 947079.378 15.644 + 29 104 75 179 Re -46584.312 24.639 8003.7666 0.1376 B- -3564.1747 29.1116 178 949989.686 26.450 + 27 103 76 179 Os -43020.137 15.505 7979.4844 0.0866 B- -4938.4182 18.3271 178 953815.985 16.645 + 25 102 77 179 Ir -38081.719 9.771 7947.5248 0.0546 B- -5813.5920 12.6133 178 959117.594 10.489 + 23 101 78 179 Pt -32268.127 7.977 7910.6759 0.0446 B- -7279.5556 14.1567 178 965358.742 8.563 + 21 100 79 179 Au -24988.572 11.696 7865.6374 0.0653 B- -8055.6480 30.4559 178 973173.666 12.555 + 19 99 80 179 Hg -16932.924 28.121 7816.2631 0.1571 B- -8663.2918 47.7998 178 981821.759 30.188 + 17 98 81 179 Tl -a -8269.632 38.653 7763.4942 0.2159 B- -10321.2401 89.9571 178 991122.185 41.495 + 15 97 82 179 Pb -a 2051.608 81.229 7701.4630 0.4538 B- * 179 002202.492 87.203 +0 44 112 68 180 Er x -33180# 500# 7960# 3# B- 4990# 640# 179 964380# 537# + 42 111 69 180 Tm x -38170# 400# 7983# 2# B- 6550# 500# 179 959023# 429# + 40 110 70 180 Yb x -44720# 300# 8016# 2# B- 1956# 308# 179 951991# 322# + 38 109 71 180 Lu + -46676.476 70.725 8022.0394 0.3929 B- 3103.0000 70.7107 179 949890.744 75.926 + 36 108 72 180 Hf -49779.476 1.421 8034.9319 0.0079 B- -845.8453 2.3472 179 946559.537 1.525 + 34 107 73 180 Ta +n -48933.631 2.068 8025.8864 0.0115 B- 702.6122 2.3590 179 947467.589 2.219 + 32 106 74 180 W -49636.243 1.439 8025.4434 0.0080 B- -3798.8793 21.4404 179 946713.304 1.545 + 30 105 75 180 Re x -45837.364 21.392 7999.9922 0.1188 B- -1481.1659 26.5482 179 950791.568 22.965 + 28 104 76 180 Os -44356.198 15.722 7987.4171 0.0873 B- -6378.6679 26.8021 179 952381.665 16.878 + 26 103 77 180 Ir x -37977.530 21.706 7947.6337 0.1206 B- -3547.6546 23.9205 179 959229.446 23.302 + 24 102 78 180 Pt -34429.875 10.051 7923.5781 0.0558 B- -8804.2290 11.1207 179 963038.010 10.790 + 22 101 79 180 Au -25625.646 4.759 7870.3194 0.0264 B- -5375.1330 13.5105 179 972489.738 5.108 + 20 100 80 180 Hg -20250.513 12.645 7836.1111 0.0702 B- -10860.0750 71.0509 179 978260.180 13.574 + 18 99 81 180 Tl -a -9390.438 69.917 7771.4310 0.3884 B- -7449.3696 71.0069 179 989918.950 75.058 + 16 98 82 180 Pb -a -1941.069 12.395 7725.6993 0.0689 B- * 179 997916.177 13.306 +0 43 112 69 181 Tm x -35440# 500# 7969# 3# B- 5649# 582# 180 961954# 537# + 41 111 70 181 Yb x -41088# 298# 7996# 2# B- 3709# 324# 180 955890# 320# + 39 110 71 181 Lu x -44797.414 125.752 8011.9301 0.6948 B- 2605.5435 125.7598 180 951908.000 135.000 + 37 109 72 181 Hf -n -47402.958 1.423 8022.0030 0.0079 B- 1036.1061 1.9298 180 949110.834 1.527 + 35 108 73 181 Ta -48439.064 1.576 8023.4050 0.0087 B- -205.1193 1.9495 180 947998.528 1.692 + 33 107 74 181 W -n -48233.945 1.448 8017.9494 0.0080 B- -1716.5331 12.6289 180 948218.733 1.554 + 31 106 75 181 Re 4n -46517.412 12.549 8004.1434 0.0693 B- -2967.4438 28.2755 180 950061.507 13.471 + 29 105 76 181 Os -43549.968 25.338 7983.4263 0.1400 B- -4086.9327 25.8756 180 953247.188 27.201 + 27 104 77 181 Ir +a -39463.035 5.245 7956.5242 0.0290 B- -5081.5379 14.6597 180 957634.691 5.631 + 25 103 78 181 Pt -34381.497 13.689 7924.1271 0.0756 B- -6510.3575 24.2164 180 963089.946 14.695 + 23 102 79 181 Au -a -27871.140 19.976 7883.8359 0.1104 B- -7210.0126 25.2123 180 970079.102 21.445 + 21 101 80 181 Hg -20661.127 15.382 7839.6792 0.0850 B- -7862.3780 17.8730 180 977819.368 16.513 + 19 100 81 181 Tl -12798.749 9.102 7791.9183 0.0503 B- -9688.1182 85.5227 180 986259.978 9.771 + 17 99 82 181 Pb -a -3110.631 85.037 7734.0704 0.4698 B- * 180 996660.600 91.290 +0 44 113 69 182 Tm x -31490# 500# 7948# 3# B- 7410# 640# 181 966194# 537# + 42 112 70 182 Yb x -38900# 400# 7984# 2# B- 2870# 447# 181 958239# 429# + 40 111 71 182 Lu x -41770# 200# 7996# 1# B- 4280# 200# 181 955158# 215# + 38 110 72 182 Hf -nn -46049.636 6.166 8014.8381 0.0339 B- 381.0486 6.3027 181 950563.684 6.619 + 36 109 73 182 Ta -46430.685 1.578 8012.6332 0.0087 B- 1815.4592 1.5276 181 950154.612 1.693 + 34 108 74 182 W -48246.144 0.745 8018.3096 0.0041 B- -2800.0000 101.9804 181 948205.636 0.799 + 32 107 75 182 Re IT -45446.144 101.983 7998.6264 0.5603 B- -837.0348 104.2757 181 951211.560 109.483 + 30 106 76 182 Os -44609.109 21.745 7989.7287 0.1195 B- -5557.4266 30.2074 181 952110.154 23.344 + 28 105 77 182 Ir -39051.682 20.967 7954.8948 0.1152 B- -2883.2620 24.7202 181 958076.296 22.509 + 26 104 78 182 Pt -36168.420 13.095 7934.7541 0.0719 B- -7864.4447 22.8812 181 961171.605 14.057 + 24 103 79 182 Au -28303.976 18.764 7887.2442 0.1031 B- -4727.0905 21.1645 181 969614.433 20.143 + 22 102 80 182 Hg -23576.885 9.790 7856.9726 0.0538 B- -10249.6721 15.4687 181 974689.173 10.510 + 20 101 81 182 Tl -a -13327.213 11.976 7796.3571 0.0658 B- -6502.6567 17.0151 181 985692.649 12.856 + 18 100 82 182 Pb -a -6824.556 12.086 7756.3296 0.0664 B- * 181 992673.537 12.975 +0 43 113 70 183 Yb x -35000# 400# 7963# 2# B- 4716# 408# 182 962426# 429# + 41 112 71 183 Lu x -39716.114 80.108 7984.8125 0.4378 B- 3567.4325 85.5564 182 957363.000 86.000 + 39 111 72 183 Hf + -43283.547 30.042 8000.0315 0.1642 B- 2010.0000 30.0000 182 953533.203 32.251 + 37 110 73 183 Ta -n -45293.547 1.590 8006.7400 0.0087 B- 1072.1161 1.5405 182 951375.380 1.707 + 35 109 74 183 W -46365.663 0.743 8008.3234 0.0041 B- -556.0000 8.0000 182 950224.416 0.798 + 33 108 75 183 Re - -45809.663 8.034 8001.0101 0.0439 B- -2145.9028 50.4129 182 950821.306 8.625 + 31 107 76 183 Os -43663.760 49.769 7985.0087 0.2720 B- -3461.6215 52.8061 182 953125.028 53.428 + 29 106 77 183 Ir -40202.138 24.672 7961.8176 0.1348 B- -4428.9417 28.4743 182 956841.231 26.486 + 27 105 78 183 Pt -35773.197 14.216 7933.3406 0.0777 B- -5581.7092 17.0554 182 961595.895 15.261 + 25 104 79 183 Au -30191.488 9.423 7898.5644 0.0515 B- -6386.8322 11.7891 182 967588.106 10.116 + 23 103 80 183 Hg -23804.655 7.084 7859.3885 0.0387 B- -7217.3941 11.7158 182 974444.652 7.604 + 21 102 81 183 Tl -16587.261 9.331 7815.6741 0.0510 B- -9007.2534 30.4442 182 982192.843 10.017 + 19 101 82 183 Pb -a -7580.008 28.979 7762.1790 0.1584 B- * 182 991862.527 31.110 +0 44 114 70 184 Yb x -32600# 503# 7951# 3# B- 3700# 541# 183 965002# 540# + 42 113 71 184 Lu x -36300# 200# 7967# 1# B- 5199# 204# 183 961030# 215# + 40 112 72 184 Hf + -41499.453 39.706 7990.7228 0.2158 B- 1340.0000 30.0000 183 955448.507 42.625 + 38 111 73 184 Ta + -42839.453 26.010 7993.7535 0.1414 B- 2866.0000 26.0000 183 954009.958 27.923 + 36 110 74 184 W -45705.453 0.738 8005.0777 0.0040 B- -1485.6333 4.1971 183 950933.180 0.792 + 34 109 75 184 Re -44219.819 4.276 7992.7517 0.0232 B- 32.7460 4.1387 183 952528.073 4.590 + 32 108 76 184 Os -44252.565 0.829 7988.6778 0.0045 B- -4641.7101 27.9571 183 952492.919 0.890 + 30 107 77 184 Ir x -39610.855 27.945 7959.1992 0.1519 B- -2278.3688 31.5957 183 957476.000 30.000 + 28 106 78 184 Pt -37332.486 14.744 7942.5649 0.0801 B- -7013.7724 26.7122 183 959921.929 15.828 + 26 105 79 184 Au -a -30318.714 22.275 7900.1947 0.1211 B- -3973.9269 24.2296 183 967451.523 23.912 + 24 104 80 184 Hg -26344.787 9.535 7874.3454 0.0518 B- -9461.4321 13.8254 183 971717.709 10.235 + 22 103 81 184 Tl -16883.355 10.012 7818.6727 0.0544 B- -5831.7688 16.2517 183 981874.973 10.747 + 20 102 82 184 Pb -11051.586 12.802 7782.7264 0.0696 B- -12306# 123# 183 988135.634 13.743 + 18 101 83 184 Bi -a 1254# 122# 7712# 1# B- * 184 001347# 131# +0 45 115 70 185 Yb x -28480# 500# 7929# 3# B- 5480# 583# 184 969425# 537# + 43 114 71 185 Lu x -33960# 300# 7955# 2# B- 4359# 307# 184 963542# 322# + 41 113 72 185 Hf x -38319.804 64.273 7973.9711 0.3474 B- 3074.5667 65.8147 184 958862.000 69.000 + 39 112 73 185 Ta + -41394.371 14.161 7986.3615 0.0765 B- 1993.5000 14.1421 184 955561.317 15.202 + 37 111 74 185 W -43387.871 0.739 7992.9083 0.0040 B- 431.1764 0.6616 184 953421.206 0.793 + 35 110 75 185 Re -43819.047 0.820 7991.0101 0.0044 B- -1013.1393 0.4190 184 952958.320 0.879 + 33 109 76 185 Os -42805.908 0.832 7981.3047 0.0045 B- -2470.3505 27.9572 184 954045.969 0.893 + 31 108 77 185 Ir x -40335.558 27.945 7963.7226 0.1511 B- -3647.4137 38.0554 184 956698.000 30.000 + 29 107 78 185 Pt -36688.144 25.832 7939.7779 0.1396 B- -4829.9942 25.9635 184 960613.659 27.731 + 27 106 79 185 Au x -31858.150 2.608 7909.4410 0.0141 B- -5674.4989 13.8859 184 965798.871 2.800 + 25 105 80 185 Hg -26183.651 13.639 7874.5391 0.0737 B- -6425.9062 24.7674 184 971890.696 14.641 + 23 104 81 185 Tl IT -19757.745 20.674 7835.5756 0.1118 B- -8216.5333 26.2493 184 978789.189 22.194 + 21 103 82 185 Pb -a -11541.211 16.175 7786.9330 0.0874 B- -9305# 83# 184 987610.000 17.364 + 19 102 83 185 Bi IT -2236# 81# 7732# 0# B- * 184 997600# 87# +0 44 115 71 186 Lu x -30320# 400# 7936# 2# B- 6104# 403# 185 967450# 429# + 42 114 72 186 Hf x -36424.214 51.232 7964.3032 0.2754 B- 2183.3883 78.9063 185 960897.000 55.000 + 40 113 73 186 Ta + -38607.602 60.012 7971.8357 0.3226 B- 3901.0000 60.0000 185 958553.036 64.425 + 38 112 74 186 W -42508.602 1.213 7988.6026 0.0065 B- -581.2819 1.2386 185 954365.140 1.302 + 36 111 75 186 Re -41927.320 0.820 7981.2713 0.0044 B- 1072.7114 0.8337 185 954989.172 0.880 + 34 110 76 186 Os -43000.032 0.761 7982.8324 0.0041 B- -3827.6813 16.5430 185 953837.569 0.816 + 32 109 77 186 Ir x -39172.350 16.526 7958.0473 0.0888 B- -1307.9030 27.3122 185 957946.754 17.740 + 30 108 78 186 Pt -37864.447 21.745 7946.8094 0.1169 B- -6149.5913 30.2074 185 959350.845 23.344 + 28 107 79 186 Au -31714.856 20.967 7909.5409 0.1127 B- -3175.7972 23.9866 185 965952.703 22.509 + 26 106 80 186 Hg -28539.059 11.650 7888.2605 0.0626 B- -8656.1190 23.7974 185 969362.061 12.507 + 24 105 81 186 Tl -19882.940 20.751 7837.5161 0.1116 B- -5202.0427 23.4877 185 978654.787 22.276 + 22 104 82 186 Pb -a -14680.897 11.004 7805.3420 0.0592 B- -11535.3999 20.2118 185 984239.409 11.813 + 20 103 83 186 Bi -a -3145.497 16.954 7739.1175 0.0911 B- -7247.0279 24.9305 185 996623.169 18.200 + 18 102 84 186 Po -a 4101.531 18.278 7695.9488 0.0983 B- * 186 004403.174 19.622 +0 45 116 71 187 Lu x -27770# 400# 7923# 2# B- 5230# 447# 186 970188# 429# + 43 115 72 187 Hf x -33000# 200# 7947# 1# B- 3896# 208# 186 964573# 215# + 41 114 73 187 Ta x -36895.550 55.890 7963.2123 0.2989 B- 3008.4937 55.9028 186 960391.000 60.000 + 39 113 74 187 W -39904.044 1.213 7975.1168 0.0065 B- 1312.5048 1.1219 186 957161.249 1.302 + 37 112 75 187 Re -41216.548 0.737 7977.9519 0.0039 B- 2.4667 0.0016 186 955752.217 0.791 + 35 111 76 187 Os -41219.015 0.737 7973.7814 0.0039 B- -1669.6385 27.9545 186 955749.569 0.791 + 33 110 77 187 Ir x -39549.377 27.945 7960.6692 0.1494 B- -2864.0151 36.8802 186 957542.000 30.000 + 31 109 78 187 Pt -36685.361 24.067 7941.1699 0.1287 B- -3656.5811 27.4478 186 960616.646 25.837 + 29 108 79 187 Au -33028.780 22.499 7917.4323 0.1203 B- -4910.2713 25.9171 186 964542.147 24.153 + 27 107 80 187 Hg -28118.509 12.864 7886.9905 0.0688 B- -5673.9170 15.1746 186 969813.540 13.810 + 25 106 81 187 Tl -22444.592 8.048 7852.4650 0.0430 B- -7457.6370 9.5248 186 975904.740 8.640 + 23 105 82 187 Pb -14986.955 5.094 7808.4010 0.0272 B- -8603.6798 11.2268 186 983910.842 5.468 + 21 104 83 187 Bi -a -6383.275 10.005 7758.2083 0.0535 B- -9207.0832 34.1302 186 993147.272 10.740 + 19 103 84 187 Po -a 2823.808 32.631 7704.7889 0.1745 B- * 187 003031.482 35.030 +0 46 117 71 188 Lu x -23820# 400# 7903# 2# B- 7009# 500# 187 974428# 429# + 44 116 72 188 Hf x -30830# 300# 7936# 2# B- 3080# 361# 187 966903# 322# + 42 115 73 188 Ta x -33910# 200# 7948# 1# B- 4758# 200# 187 963596# 215# + 40 114 74 188 W + -38667.880 3.089 7969.0532 0.0164 B- 349.0000 3.0000 187 958488.325 3.316 + 38 113 75 188 Re -n -39016.880 0.738 7966.7481 0.0039 B- 2120.4209 0.1520 187 958113.658 0.792 + 36 112 76 188 Os -41137.301 0.734 7973.8656 0.0039 B- -2792.3457 9.4164 187 955837.292 0.788 + 34 111 77 188 Ir -38344.955 9.423 7954.8512 0.0501 B- -523.9860 8.6863 187 958834.999 10.116 + 32 110 78 188 Pt -37820.970 5.305 7947.9027 0.0282 B- -5449.6549 5.9528 187 959397.521 5.694 + 30 109 79 188 Au x -32371.315 2.701 7914.7537 0.0144 B- -2172.9634 7.3046 187 965247.966 2.900 + 28 108 80 188 Hg -30198.351 6.787 7899.0340 0.0361 B- -7861.9485 30.6643 187 967580.738 7.285 + 26 107 81 188 Tl x -22336.403 29.904 7853.0537 0.1591 B- -4525.3784 31.5712 187 976020.886 32.103 + 24 106 82 188 Pb -a -17811.024 10.124 7824.8211 0.0539 B- -10616.2241 15.0824 187 980879.079 10.868 + 22 105 83 188 Bi -a -7194.800 11.179 7764.1904 0.0595 B- -6650.4226 22.8861 187 992276.064 12.001 + 20 104 84 188 Po -a -544.378 19.970 7724.6544 0.1062 B- * 187 999415.586 21.438 +0 45 117 72 189 Hf x -27150# 300# 7917# 2# B- 4809# 361# 188 970853# 322# + 43 116 73 189 Ta x -31960# 200# 7938# 1# B- 3850# 283# 188 965690# 215# + 41 115 74 189 W + -35809# 200# 7954# 1# B- 2170# 200# 188 961557# 215# + 39 114 75 189 Re +p -37979.097 8.191 7961.8105 0.0433 B- 1007.7049 8.1671 188 959227.764 8.793 + 37 113 76 189 Os -38986.802 0.666 7963.0029 0.0035 B- -537.1494 12.5630 188 958145.949 0.715 + 35 112 77 189 Ir -38449.652 12.576 7956.0214 0.0665 B- -1980.2470 13.6363 188 958722.602 13.500 + 33 111 78 189 Pt -36469.405 10.090 7941.4045 0.0534 B- -2887.4471 22.4737 188 960848.485 10.832 + 31 110 79 189 Au x -33581.958 20.081 7921.9876 0.1063 B- -3955.5800 37.4009 188 963948.286 21.558 + 29 109 80 189 Hg -29626.378 31.553 7896.9192 0.1669 B- -5010.2727 32.6434 188 968194.776 33.873 + 27 108 81 189 Tl -24616.105 8.368 7866.2704 0.0443 B- -6772.0862 16.3636 188 973573.525 8.983 + 25 107 82 189 Pb -17844.019 14.062 7826.2999 0.0744 B- -7779.3555 25.1498 188 980843.658 15.096 + 23 106 83 189 Bi -a -10064.664 20.851 7780.9999 0.1103 B- -8642.6682 30.3542 188 989195.139 22.384 + 21 105 84 189 Po -a -1421.996 22.059 7731.1321 0.1167 B- * 188 998473.425 23.681 +0 46 118 72 190 Hf x -24800# 400# 7905# 2# B- 3920# 447# 189 973376# 429# + 44 117 73 190 Ta x -28720# 200# 7922# 1# B- 5649# 203# 189 969168# 215# + 42 116 74 190 W -34368.832 35.391 7947.5031 0.1863 B- 1214.1824 35.5545 189 963103.542 37.993 + 40 115 75 190 Re -35583.015 4.870 7949.7759 0.0256 B- 3124.8105 4.7864 189 961800.064 5.227 + 38 114 76 190 Os -38707.825 0.650 7962.1047 0.0034 B- -1954.2108 1.2131 189 958445.442 0.697 + 36 113 77 190 Ir +n -36753.614 1.370 7947.7017 0.0072 B- 552.8893 1.2822 189 960543.374 1.470 + 34 112 78 190 Pt -37306.504 0.657 7946.4941 0.0035 B- -4472.9637 3.5086 189 959949.823 0.705 + 32 111 79 190 Au x -32833.540 3.447 7918.8345 0.0181 B- -1462.9150 16.2760 189 964751.746 3.700 + 30 110 80 190 Hg -31370.625 15.907 7907.0174 0.0837 B- -7004.3892 17.4819 189 966322.250 17.076 + 28 109 81 190 Tl +a -24366.236 7.252 7866.0345 0.0382 B- -3949.6288 14.4634 189 973841.771 7.784 + 26 108 82 190 Pb -a -20416.607 12.514 7841.1294 0.0659 B- -9820.7014 24.4226 189 978081.872 13.434 + 24 107 83 190 Bi -a -10595.906 20.973 7785.3239 0.1104 B- -6033.1975 24.7615 189 988624.828 22.515 + 22 106 84 190 Po -a -4562.708 13.163 7749.4526 0.0693 B- * 189 995101.731 14.131 +0 45 118 73 191 Ta x -26520# 300# 7911# 2# B- 4657# 303# 190 971530# 322# + 43 117 74 191 W x -31176.176 41.917 7931.4359 0.2195 B- 3174.2318 43.1556 190 966531.000 45.000 + 41 116 75 191 Re +p -34350.408 10.264 7943.9588 0.0537 B- 2044.8311 10.2443 190 963123.322 11.019 + 39 115 76 191 Os -36395.239 0.659 7950.5687 0.0035 B- 313.5873 1.1410 190 960928.105 0.707 + 37 114 77 191 Ir -36708.826 1.310 7948.1144 0.0069 B- -1010.4903 3.6360 190 960591.455 1.406 + 35 113 78 191 Pt -35698.336 4.127 7938.7279 0.0216 B- -1900.4257 6.4260 190 961676.261 4.430 + 33 112 79 191 Au -33797.910 4.926 7924.6819 0.0258 B- -3206.0616 22.7103 190 963716.452 5.288 + 31 111 80 191 Hg -30591.849 22.280 7903.8002 0.1167 B- -4308.8981 23.4609 190 967158.301 23.918 + 29 110 81 191 Tl +a -26282.951 7.349 7877.1445 0.0385 B- -5991.7073 9.8864 190 971784.093 7.889 + 27 109 82 191 Pb -20291.243 6.613 7841.6782 0.0346 B- -7051.8922 9.9895 190 978216.455 7.099 + 25 108 83 191 Bi -13239.351 7.487 7800.6613 0.0392 B- -8170.6205 10.3201 190 985786.972 8.037 + 23 107 84 191 Po -5068.731 7.103 7753.7871 0.0372 B- -8932.6440 17.5997 190 994558.494 7.624 + 21 106 85 191 At -a 3863.913 16.103 7702.9233 0.0843 B- * 191 004148.081 17.287 +0 46 119 73 192 Ta x -23100# 400# 7894# 2# B- 6520# 447# 191 975201# 429# + 44 118 74 192 W x -29620# 200# 7924# 1# B- 1969# 212# 191 968202# 215# + 42 117 75 192 Re x -31588.828 70.794 7930.2389 0.3687 B- 4293.4750 70.8314 191 966088.000 76.000 + 40 116 76 192 Os -35882.303 2.314 7948.5260 0.0121 B- -1046.6722 2.3962 191 961478.765 2.484 + 38 115 77 192 Ir -34835.631 1.314 7938.9999 0.0068 B- 1452.8946 2.2739 191 962602.414 1.410 + 36 114 78 192 Pt -36288.525 2.570 7942.4923 0.0134 B- -3516.3415 15.6174 191 961042.667 2.758 + 34 113 79 192 Au - -32772.184 15.827 7920.1033 0.0824 B- -760.7028 22.1777 191 964817.615 16.991 + 32 112 80 192 Hg x -32011.481 15.537 7912.0666 0.0809 B- -6139.2324 35.2767 191 965634.263 16.679 + 30 111 81 192 Tl x -25872.249 31.671 7876.0167 0.1650 B- -3320.4029 32.1843 191 972225.000 34.000 + 28 110 82 192 Pb -22551.846 5.726 7854.6482 0.0298 B- -9017.3089 30.6518 191 975789.598 6.147 + 26 109 83 192 Bi -a -13534.537 30.112 7803.6084 0.1568 B- -5468.0534 31.9348 191 985470.077 32.326 + 24 108 84 192 Po -a -8066.483 10.634 7771.0542 0.0554 B- -10992.2252 29.8328 191 991340.274 11.416 + 22 107 85 192 At -a 2925.742 27.873 7709.7283 0.1452 B- * 192 003140.912 29.922 +0 47 120 73 193 Ta x -20810# 400# 7883# 2# B- 5380# 447# 192 977660# 429# + 45 119 74 193 W x -26190# 200# 7907# 1# B- 4042# 204# 192 971884# 215# + 43 118 75 193 Re x -30231.641 39.123 7923.9378 0.2027 B- 3162.7597 39.1915 192 967545.000 42.000 + 41 117 76 193 Os -33394.401 2.320 7936.2716 0.0120 B- 1141.9038 2.4000 192 964149.637 2.490 + 39 116 77 193 Ir -34536.305 1.327 7938.1346 0.0069 B- -56.6276 0.2997 192 962923.753 1.425 + 37 115 78 193 Pt -34479.677 1.359 7933.7875 0.0070 B- -1074.8477 8.7676 192 962984.546 1.458 + 35 114 79 193 Au -33404.829 8.674 7924.1648 0.0449 B- -2342.6641 14.3702 192 964138.442 9.311 + 33 113 80 193 Hg -31062.165 15.505 7907.9730 0.0803 B- -3584.9466 16.8938 192 966653.395 16.645 + 31 112 81 193 Tl x -27477.218 6.707 7885.3445 0.0348 B- -5247.9637 12.2808 192 970501.994 7.200 + 29 111 82 193 Pb -22229.255 10.288 7854.0994 0.0533 B- -6344.6913 12.7761 192 976135.914 11.044 + 27 110 83 193 Bi -15884.563 7.576 7817.1718 0.0393 B- -7559.2614 16.3874 192 982947.220 8.132 + 25 109 84 193 Po -a -8325.302 14.531 7773.9510 0.0753 B- -8257.9789 26.0594 192 991062.421 15.599 + 23 108 85 193 At -a -67.323 21.632 7727.1099 0.1121 B- -9110.2435 33.1444 192 999927.725 23.222 + 21 107 86 193 Rn -a 9042.920 25.112 7675.8530 0.1301 B- * 193 009707.973 26.958 +0 48 121 73 194 Ta x -17130# 500# 7865# 3# B- 7280# 583# 193 981610# 537# + 46 120 74 194 W x -24410# 300# 7899# 2# B- 2850# 361# 193 973795# 322# + 44 119 75 194 Re x -27260# 200# 7909# 1# B- 5175# 200# 193 970735# 215# + 42 118 76 194 Os + -32435.176 2.403 7932.0232 0.0124 B- 96.6000 2.0000 193 965179.407 2.579 + 40 117 77 194 Ir -n -32531.776 1.332 7928.4885 0.0069 B- 2228.3252 1.2569 193 965075.703 1.429 + 38 116 78 194 Pt -34760.101 0.496 7935.9420 0.0026 B- -2548.1518 2.1174 193 962683.498 0.532 + 36 115 79 194 Au +3n -32211.950 2.118 7918.7744 0.0109 B- -27.9978 3.5809 193 965419.051 2.273 + 34 114 80 194 Hg x -32183.952 2.888 7914.5974 0.0149 B- -5246.4542 14.2677 193 965449.108 3.100 + 32 113 81 194 Tl x -26937.498 13.972 7883.5211 0.0720 B- -2729.6315 22.3433 193 971081.408 15.000 + 30 112 82 194 Pb -24207.866 17.435 7865.4181 0.0899 B- -8184.8462 18.2094 193 974011.788 18.717 + 28 111 83 194 Bi +a -16023.020 5.252 7819.1955 0.0271 B- -5018.4029 13.9386 193 982798.581 5.638 + 26 110 84 194 Po -a -11004.617 12.911 7789.2947 0.0666 B- -10288.1273 26.8153 193 988186.058 13.860 + 24 109 85 194 At -a -716.490 23.502 7732.2304 0.1211 B- -6441.1134 28.8079 193 999230.816 25.230 + 22 108 86 194 Rn -a 5724.624 16.659 7694.9961 0.0859 B- * 194 006145.636 17.884 +0 47 121 74 195 W x -20740# 300# 7881# 2# B- 4820# 424# 194 977735# 322# + 45 120 75 195 Re x -25560# 300# 7901# 2# B- 3951# 305# 194 972560# 322# + 43 119 76 195 Os x -29511.596 55.890 7917.7449 0.2866 B- 2180.7220 55.9055 194 968318.000 60.000 + 41 118 77 195 Ir -n -31692.318 1.333 7924.9160 0.0068 B- 1101.5601 1.2637 194 965976.898 1.431 + 39 117 78 195 Pt -32793.878 0.503 7926.5530 0.0026 B- -226.8175 0.9998 194 964794.325 0.540 + 37 116 79 195 Au -32567.061 1.119 7921.3778 0.0057 B- -1553.7190 23.1562 194 965037.823 1.201 + 35 115 80 195 Hg -31013.342 23.142 7909.3980 0.1187 B- -2858.0499 25.6707 194 966705.809 24.843 + 33 114 81 195 Tl -28155.292 11.126 7890.7293 0.0571 B- -4417.2524 12.2333 194 969774.052 11.944 + 31 113 82 195 Pb -23738.039 5.088 7864.0647 0.0261 B- -5712.4729 7.3370 194 974516.167 5.461 + 29 112 83 195 Bi -18025.567 5.287 7830.7579 0.0271 B- -6908.9121 8.0284 194 980648.759 5.675 + 27 111 84 195 Po -11116.655 6.042 7791.3155 0.0310 B- -7646.3554 11.3199 194 988065.781 6.486 + 25 110 85 195 At -a -3470.299 9.573 7748.0914 0.0491 B- -8520.5842 52.5650 194 996274.480 10.276 + 23 109 86 195 Rn -a 5050.285 51.686 7700.3841 0.2651 B- * 195 005421.703 55.487 +0 48 122 74 196 W x -18740# 400# 7872# 2# B- 3620# 500# 195 979882# 429# + 46 121 75 196 Re x -22360# 300# 7886# 2# B- 5918# 303# 195 975996# 322# + 44 120 76 196 Os +pp -28277.123 40.055 7912.2301 0.2044 B- 1158.3989 55.4951 195 969643.261 43.000 + 42 119 77 196 Ir + -29435.522 38.414 7914.1487 0.1960 B- 3209.0164 38.4111 195 968399.669 41.239 + 40 118 78 196 Pt -32644.538 0.510 7926.5297 0.0026 B- -1505.8204 2.9605 195 964954.648 0.547 + 38 117 79 196 Au -31138.718 2.962 7914.8553 0.0151 B- 687.2263 3.1176 195 966571.213 3.179 + 36 116 80 196 Hg -31825.944 2.946 7914.3700 0.0150 B- -4329.3455 12.4627 195 965833.445 3.163 + 34 115 81 196 Tl x -27496.598 12.109 7888.2900 0.0618 B- -2148.3639 14.3556 195 970481.189 13.000 + 32 114 82 196 Pb -25348.234 7.710 7873.3374 0.0393 B- -7339.2020 25.6160 195 972787.552 8.277 + 30 113 83 196 Bi x -18009.032 24.428 7831.9009 0.1246 B- -4540.3012 25.0142 195 980666.509 26.224 + 28 112 84 196 Po -13468.731 5.383 7804.7445 0.0275 B- -9555.5564 30.7105 195 985540.722 5.778 + 26 111 85 196 At -a -3913.175 30.235 7752.0001 0.1543 B- -5888.3439 33.3417 195 995799.034 32.458 + 24 110 86 196 Rn -a 1975.169 14.054 7717.9660 0.0717 B- * 196 002120.431 15.087 +0 49 123 74 197 W x -14870# 400# 7853# 2# B- 5480# 500# 196 984036# 429# + 47 122 75 197 Re x -20350# 300# 7877# 2# B- 4729# 361# 196 978153# 322# + 45 121 76 197 Os x -25080# 200# 7897# 1# B- 3185# 201# 196 973076# 215# + 43 120 77 197 Ir +p -28264.123 20.110 7909.0003 0.1021 B- 2155.6519 20.1061 196 969657.217 21.588 + 41 119 78 197 Pt -30419.775 0.536 7915.9714 0.0027 B- 719.9769 0.5022 196 967343.030 0.575 + 39 118 79 197 Au -31139.751 0.542 7915.6548 0.0028 B- -599.5206 3.2022 196 966570.103 0.581 + 37 117 80 197 Hg -30540.231 3.207 7908.6402 0.0163 B- -2186.0092 13.9478 196 967213.715 3.442 + 35 116 81 197 Tl +a -28354.222 13.575 7893.5725 0.0689 B- -3608.8367 14.3969 196 969560.492 14.573 + 33 115 82 197 Pb -24745.385 4.804 7871.2822 0.0244 B- -5058.1894 9.6190 196 973434.737 5.157 + 31 114 83 197 Bi +a -19687.196 8.333 7841.6348 0.0423 B- -6294.1172 12.9103 196 978864.927 8.946 + 29 113 84 197 Po -13393.078 9.861 7805.7136 0.0501 B- -7037.8235 12.6871 196 985621.939 10.585 + 27 112 85 197 At -6355.255 7.983 7766.0174 0.0405 B- -7865.6231 18.0538 196 993177.353 8.570 + 25 111 86 197 Rn -a 1510.368 16.193 7722.1190 0.0822 B- -8743.5996 58.7110 197 001621.446 17.383 + 23 110 87 197 Fr -a 10253.968 56.434 7673.7640 0.2865 B- * 197 011008.086 60.584 +0 48 123 75 198 Re x -16990# 400# 7861# 2# B- 6610# 447# 197 981760# 429# + 46 122 76 198 Os x -23600# 200# 7890# 1# B- 2110# 283# 197 974664# 215# + 44 121 77 198 Ir x -25710# 200# 7897# 1# B- 4194# 200# 197 972399# 215# + 42 120 78 198 Pt -29904.018 2.100 7914.1512 0.0106 B- -323.2251 2.0595 197 967896.718 2.254 + 40 119 79 198 Au -29580.793 0.540 7908.5675 0.0027 B- 1373.5226 0.4905 197 968243.714 0.579 + 38 118 80 198 Hg -30954.315 0.458 7911.5532 0.0023 B- -3425.5625 7.5590 197 966769.177 0.491 + 36 117 81 198 Tl x -27528.753 7.545 7890.3011 0.0381 B- -1461.3103 11.5537 197 970446.669 8.100 + 34 116 82 198 Pb -26067.443 8.750 7878.9695 0.0442 B- -6693.5916 28.9259 197 972015.450 9.393 + 32 115 83 198 Bi -19373.851 27.571 7841.2123 0.1392 B- -3900.5727 32.6152 197 979201.316 29.598 + 30 114 84 198 Po -15473.278 17.424 7817.5611 0.0880 B- -8764.5316 18.1013 197 983388.753 18.705 + 28 113 85 198 At -6708.747 4.904 7769.3446 0.0248 B- -5478.4271 14.2879 197 992797.864 5.265 + 26 112 86 198 Rn -a -1230.320 13.420 7737.7245 0.0678 B- -10808.0177 33.8991 197 998679.197 14.406 + 24 111 87 198 Fr -a 9577.698 31.130 7679.1873 0.1572 B- * 198 010282.081 33.419 +0 49 124 75 199 Re x -14730# 400# 7850# 2# B- 5541# 447# 198 984187# 429# + 47 123 76 199 Os x -20270# 200# 7874# 1# B- 4128# 204# 198 978239# 215# + 45 122 77 199 Ir p-2n -24398.534 41.054 7891.2066 0.2063 B- 2990.1656 41.0030 198 973807.097 44.073 + 43 121 78 199 Pt -n -27388.700 2.159 7902.3011 0.0109 B- 1705.0525 2.1201 198 970597.022 2.317 + 41 120 79 199 Au -29093.752 0.542 7906.9379 0.0027 B- 452.3142 0.6126 198 968766.573 0.581 + 39 119 80 199 Hg -29546.066 0.526 7905.2794 0.0027 B- -1486.6695 27.9498 198 968280.994 0.564 + 37 118 81 199 Tl x -28059.397 27.945 7893.8773 0.1404 B- -2827.6624 28.7653 198 969877.000 30.000 + 35 117 82 199 Pb +a -25231.734 6.821 7875.7366 0.0343 B- -4434.1181 12.6179 198 972912.620 7.322 + 33 116 83 199 Bi -20797.616 10.615 7849.5232 0.0533 B- -5558.7875 11.9224 198 977672.841 11.395 + 31 115 84 199 Po -a -15238.829 5.429 7817.6582 0.0273 B- -6415.4515 7.6464 198 983640.445 5.828 + 29 114 85 199 At -8823.377 5.384 7781.4883 0.0271 B- -7263.5308 9.0686 198 990527.715 5.780 + 27 113 86 199 Rn -a -1559.846 7.297 7741.0568 0.0367 B- -8331.2349 15.5446 198 998325.436 7.833 + 25 112 87 199 Fr -a 6771.388 13.726 7695.2599 0.0690 B- * 199 007269.384 14.734 +0 48 124 76 200 Os x -18550# 300# 7867# 1# B- 3020# 358# 199 980086# 322# + 46 123 77 200 Ir x -21570# 196# 7878# 1# B- 5030# 197# 199 976844# 210# + 44 122 78 200 Pt -nn -26599.178 20.110 7899.1986 0.1006 B- 640.9158 33.4386 199 971444.609 21.588 + 42 121 79 200 Au -27240.094 26.717 7898.4915 0.1336 B- 2263.1737 26.7188 199 970756.558 28.681 + 40 120 80 200 Hg -29503.267 0.530 7905.8956 0.0027 B- -2456.0403 5.7346 199 968326.941 0.568 + 38 119 81 200 Tl - -27047.227 5.759 7889.7037 0.0288 B- -796.3695 11.5360 199 970963.608 6.182 + 36 118 82 200 Pb -26250.858 10.008 7881.8101 0.0500 B- -5880.2841 24.8094 199 971818.546 10.744 + 34 117 83 200 Bi +a -20370.574 22.701 7848.4969 0.1135 B- -3428.8901 23.9327 199 978131.290 24.370 + 32 116 84 200 Po -16941.683 7.579 7827.4407 0.0379 B- -7953.7897 25.6119 199 981812.355 8.136 + 30 115 85 200 At -a -8987.894 24.465 7783.7601 0.1223 B- -4987.4394 25.1411 199 990351.099 26.264 + 28 114 86 200 Rn -a -4000.454 5.792 7754.9111 0.0290 B- -10134.0327 31.0688 199 995705.335 6.217 + 26 113 87 200 Fr -a 6133.578 30.524 7700.3292 0.1526 B- * 200 006584.666 32.769 +0 49 125 76 201 Os x -14840# 300# 7849# 1# B- 5000# 361# 200 984069# 322# + 47 124 77 201 Ir x -19840# 200# 7870# 1# B- 3901# 206# 200 978701# 215# + 45 123 78 201 Pt + -23740.705 50.103 7885.8337 0.2493 B- 2660.0000 50.0000 200 974513.305 53.788 + 43 122 79 201 Au -26400.705 3.218 7895.1752 0.0160 B- 1261.8237 3.1471 200 971657.678 3.455 + 41 121 80 201 Hg -27662.529 0.712 7897.5607 0.0036 B- -481.7508 14.1815 200 970303.054 0.763 + 39 120 81 201 Tl -27180.778 14.185 7891.2717 0.0706 B- -1909.7458 18.5299 200 970820.235 15.228 + 37 119 82 201 Pb -25271.033 13.747 7877.8782 0.0684 B- -3842.0269 18.3637 200 972870.431 14.758 + 35 118 83 201 Bi +a -21429.006 12.177 7854.8713 0.0606 B- -4907.8397 13.1377 200 976995.017 13.072 + 33 117 84 201 Po -16521.166 4.942 7826.5619 0.0246 B- -5731.7247 9.5606 200 982263.799 5.305 + 31 116 85 201 At +a -10789.441 8.184 7794.1536 0.0407 B- -6682.0288 13.0163 200 988417.058 8.786 + 29 115 86 201 Rn -a -4107.413 10.121 7757.0174 0.0504 B- -7695.9856 13.5972 200 995590.511 10.865 + 27 114 87 201 Fr -a 3588.573 9.080 7714.8367 0.0452 B- -8348.2439 22.2391 201 003852.491 9.747 + 25 113 88 201 Ra -a 11936.817 20.301 7669.4108 0.1010 B- * 201 012814.699 21.794 +0 50 126 76 202 Os x -12530# 400# 7839# 2# B- 4110# 500# 201 986548# 429# + 48 125 77 202 Ir x -16640# 300# 7855# 1# B- 6052# 301# 201 982136# 322# + 46 124 78 202 Pt x -22692.128 25.150 7881.5609 0.1245 B- 1660.8540 34.2759 201 975639.000 27.000 + 44 123 79 202 Au x -24352.982 23.287 7885.9100 0.1153 B- 2992.3278 23.2980 201 973856.000 25.000 + 42 122 80 202 Hg -27345.310 0.705 7896.8505 0.0035 B- -1364.8906 1.8348 201 970643.604 0.757 + 40 121 81 202 Tl -25980.419 1.838 7886.2206 0.0091 B- -39.8110 4.1863 201 972108.874 1.972 + 38 120 82 202 Pb -25940.608 3.796 7882.1505 0.0188 B- -5189.7539 14.5070 201 972151.613 4.075 + 36 119 83 202 Bi -20750.854 14.002 7852.5857 0.0693 B- -2809.2850 16.4660 201 977723.042 15.032 + 34 118 84 202 Po -17941.569 8.670 7834.8053 0.0429 B- -7346.4628 28.9311 201 980738.934 9.307 + 32 117 85 202 At -10595.106 27.601 7794.5637 0.1366 B- -4320.5458 32.6924 201 988625.686 29.631 + 30 116 86 202 Rn -a -6274.561 17.520 7769.3018 0.0867 B- -9376.0984 18.5296 201 993263.982 18.808 + 28 115 87 202 Fr -a 3101.538 6.033 7719.0125 0.0299 B- -5973.3620 16.1841 202 003329.637 6.476 + 26 114 88 202 Ra -a 9074.900 15.018 7685.5684 0.0743 B- * 202 009742.305 16.122 +0 51 127 76 203 Os x -7270# 400# 7814# 2# B- 7100# 565# 202 992195# 429# + 49 126 77 203 Ir x -14370# 400# 7845# 2# B- 5140# 447# 202 984573# 429# + 47 125 78 203 Pt x -19510# 200# 7867# 1# B- 3633# 200# 202 979055# 215# + 45 124 79 203 Au -23143.444 3.083 7880.8650 0.0152 B- 2125.7592 3.4514 202 975154.492 3.309 + 43 123 80 203 Hg -25269.203 1.630 7887.4828 0.0080 B- 492.1062 1.2247 202 972872.396 1.750 + 41 122 81 203 Tl -25761.309 1.171 7886.0530 0.0058 B- -974.8265 6.4609 202 972344.098 1.257 + 39 121 82 203 Pb -24786.483 6.554 7877.3970 0.0323 B- -3261.5896 14.3559 202 973390.617 7.036 + 37 120 83 203 Bi +a -21524.893 12.778 7857.4762 0.0629 B- -4214.0744 13.5942 202 976892.077 13.717 + 35 119 84 203 Po -17310.819 4.640 7832.8632 0.0229 B- -5148.2116 11.5921 202 981416.072 4.981 + 33 118 85 203 At -12162.607 10.623 7803.6487 0.0523 B- -5978.5623 12.1098 202 986942.904 11.404 + 31 117 86 203 Rn -a -6184.045 5.815 7770.3437 0.0286 B- -7060.4572 8.5231 202 993361.155 6.242 + 29 116 87 203 Fr 876.412 6.232 7731.7092 0.0307 B- -7724.9182 11.5191 203 000940.867 6.689 + 27 115 88 203 Ra -a 8601.331 9.688 7689.8015 0.0477 B- * 203 009233.907 10.400 +0 50 127 77 204 Ir x -9570# 400# 7823# 2# B- 8050# 447# 203 989726# 429# + 48 126 78 204 Pt x -17620# 200# 7859# 1# B- 2770# 283# 203 981084# 215# + 46 125 79 204 Au + -20390# 200# 7868# 1# B- 4300# 200# 203 978110# 215# + 44 124 80 204 Hg -24690.148 0.498 7885.5455 0.0025 B- -344.0781 1.1876 203 973494.037 0.534 + 42 123 81 204 Tl -24346.070 1.154 7880.0238 0.0057 B- 763.7453 0.1768 203 973863.420 1.238 + 40 122 82 204 Pb -25109.815 1.147 7879.9326 0.0056 B- -4463.8883 9.2480 203 973043.506 1.231 + 38 121 83 204 Bi +a -20645.927 9.180 7854.2157 0.0450 B- -2304.8814 13.6253 203 977835.687 9.854 + 36 120 84 204 Po -18341.045 10.071 7839.0823 0.0494 B- -6465.7939 24.8047 203 980310.078 10.811 + 34 119 85 204 At -11875.252 22.668 7803.5522 0.1111 B- -3905.1360 23.8592 203 987251.393 24.335 + 32 118 86 204 Rn -7970.115 7.444 7780.5743 0.0365 B- -8577.4239 25.6840 203 991443.729 7.991 + 30 117 87 204 Fr -a 607.308 24.581 7734.6931 0.1205 B- -5453.7889 26.1514 204 000651.972 26.389 + 28 116 88 204 Ra -a 6061.097 8.924 7704.1238 0.0437 B- * 204 006506.855 9.580 +0 51 128 77 205 Ir x -5600# 500# 7805# 2# B- 7220# 583# 204 993988# 537# + 49 127 78 205 Pt x -12820# 300# 7836# 1# B- 5750# 361# 204 986237# 322# + 47 126 79 205 Au x -18570# 200# 7860# 1# B- 3717# 200# 204 980064# 215# + 45 125 80 205 Hg -22287.719 3.655 7874.7325 0.0178 B- 1533.0836 3.7238 204 976073.151 3.923 + 43 124 81 205 Tl -23820.802 1.239 7878.3946 0.0060 B- -50.6402 0.5033 204 974427.318 1.330 + 41 123 82 205 Pb -23770.162 1.145 7874.3313 0.0056 B- -2704.5927 4.8196 204 974481.682 1.228 + 39 122 83 205 Bi -21065.569 4.808 7857.3218 0.0235 B- -3544.1710 11.1458 204 977385.182 5.161 + 37 121 84 205 Po -17521.398 10.059 7836.2168 0.0491 B- -4536.8793 15.6996 204 981190.006 10.798 + 35 120 85 205 At +a -12984.519 12.055 7810.2694 0.0588 B- -5274.7547 13.0777 204 986060.546 12.941 + 33 119 86 205 Rn -7709.764 5.080 7780.7226 0.0248 B- -6399.9479 9.3288 204 991723.228 5.453 + 31 118 87 205 Fr x -1309.816 7.824 7745.6870 0.0382 B- -7113.6693 24.0784 204 998593.854 8.399 + 29 117 88 205 Ra -a 5803.853 22.772 7707.1698 0.1111 B- -8302.8357 63.5402 205 006230.692 24.446 + 27 116 89 205 Ac -a 14106.689 59.320 7662.8519 0.2894 B- * 205 015144.152 63.682 +0 50 128 78 206 Pt x -9240# 300# 7820# 1# B- 4950# 424# 205 990080# 322# + 48 127 79 206 Au x -14190# 300# 7840# 1# B- 6755# 301# 205 984766# 322# + 46 126 80 206 Hg +a -20945.728 20.441 7869.1723 0.0992 B- 1307.5659 20.4100 205 977513.837 21.943 + 44 125 81 206 Tl -22253.293 1.286 7871.7219 0.0062 B- 1532.2128 0.6117 205 976110.108 1.380 + 42 124 82 206 Pb -23785.506 1.144 7875.3620 0.0056 B- -3757.3057 7.5461 205 974465.210 1.228 + 40 123 83 206 Bi - -20028.201 7.632 7853.3249 0.0371 B- -1839.5323 8.6005 205 978498.843 8.193 + 38 122 84 206 Po -a -18188.668 4.012 7840.5973 0.0195 B- -5749.2803 14.1099 205 980473.662 4.306 + 36 121 85 206 At -12439.388 13.529 7808.8904 0.0657 B- -3306.4697 16.0227 205 986645.768 14.523 + 34 120 86 206 Rn -9132.918 8.591 7789.0417 0.0417 B- -7886.0592 29.1075 205 990195.409 9.223 + 32 119 87 206 Fr -1246.859 27.811 7746.9621 0.1350 B- -4812.4721 33.1318 205 998661.441 29.856 + 30 118 88 206 Ra -a 3565.613 18.008 7719.8028 0.0874 B- -9919.1406 67.5328 206 003827.842 19.332 + 28 117 89 206 Ac -a 13484.754 65.088 7667.8538 0.3160 B- * 206 014476.477 69.874 +0 51 129 78 207 Pt x -4140# 400# 7797# 2# B- 6501# 500# 206 995556# 429# + 49 128 79 207 Au x -10640# 300# 7824# 1# B- 5847# 301# 206 988577# 322# + 47 127 80 207 Hg x -16487.446 29.808 7848.6112 0.1440 B- 4546.9906 30.3000 206 982300.000 32.000 + 45 126 81 207 Tl -21034.436 5.439 7866.7979 0.0263 B- 1417.5323 5.4024 206 977418.605 5.839 + 43 125 82 207 Pb -22451.968 1.147 7869.8664 0.0055 B- -2397.4140 2.1175 206 975896.821 1.231 + 41 124 83 207 Bi -20054.554 2.397 7854.5053 0.0116 B- -2908.8541 6.6140 206 978470.551 2.573 + 39 123 84 207 Po -17145.700 6.659 7836.6734 0.0322 B- -3918.2186 14.0754 206 981593.334 7.148 + 37 122 85 207 At +a -13227.482 12.406 7813.9653 0.0599 B- -4592.7400 13.2815 206 985799.715 13.318 + 35 121 86 207 Rn -8634.742 4.742 7787.9987 0.0229 B- -5785.7211 18.1857 206 990730.224 5.090 + 33 120 87 207 Fr -2849.021 17.557 7756.2689 0.0848 B- -6363.0084 60.8726 206 996941.450 18.847 + 31 119 88 207 Ra -a 3513.988 58.286 7721.7503 0.2816 B- -7632.2404 81.0004 207 003772.420 62.572 + 29 118 89 207 Ac -a 11146.228 56.248 7681.1001 0.2717 B- * 207 011965.967 60.384 +0 52 130 78 208 Pt x -500# 400# 7780# 2# B- 5410# 500# 207 999463# 429# + 50 129 79 208 Au x -5910# 300# 7803# 1# B- 7355# 302# 207 993655# 322# + 48 128 80 208 Hg x -13265.408 30.739 7834.1914 0.1478 B- 3484.7131 30.7951 207 985759.000 33.000 + 46 127 81 208 Tl +a -16750.121 1.854 7847.1835 0.0089 B- 4998.3984 1.6693 207 982018.006 1.989 + 44 126 82 208 Pb -21748.519 1.148 7867.4530 0.0055 B- -2878.3680 2.0127 207 976652.005 1.232 + 42 125 83 208 Bi +n -18870.151 2.305 7849.8534 0.0111 B- -1400.9438 2.3787 207 979742.060 2.474 + 40 124 84 208 Po -17469.207 1.672 7839.3568 0.0080 B- -4999.3061 9.0736 207 981246.035 1.795 + 38 123 85 208 At +a -12469.901 8.921 7811.5604 0.0429 B- -2814.5118 13.5215 207 986613.011 9.577 + 36 122 86 208 Rn -9655.389 10.163 7794.2678 0.0489 B- -6990.4614 15.4656 207 989634.513 10.910 + 34 121 87 208 Fr -2664.928 11.657 7756.8985 0.0560 B- -4392.8615 14.7413 207 997139.082 12.514 + 32 120 88 208 Ra -a 1727.934 9.023 7732.0177 0.0434 B- -9032.9208 65.1111 208 001855.012 9.686 + 30 119 89 208 Ac -a 10760.854 64.483 7684.8289 0.3100 B- -5927.1868 71.9264 208 011552.251 69.225 + 28 118 90 208 Th -a 16688.041 31.865 7652.5716 0.1532 B- * 208 017915.348 34.208 +0 51 130 79 209 Au x -2230# 400# 7786# 2# B- 6380# 427# 208 997606# 429# + 49 129 80 209 Hg x -8610# 150# 7813# 1# B- 5035# 150# 208 990757# 161# + 47 128 81 209 Tl +a -13644.793 6.110 7833.3979 0.0292 B- 3969.7809 6.2115 208 985351.713 6.559 + 45 127 82 209 Pb -17614.574 1.747 7848.6488 0.0084 B- 644.0152 1.1462 208 981089.978 1.875 + 43 126 83 209 Bi -18258.589 1.365 7847.9869 0.0065 B- -1892.5741 1.5635 208 980398.599 1.465 + 41 125 84 209 Po -a -16366.015 1.778 7835.1882 0.0085 B- -3482.2417 4.9599 208 982430.361 1.909 + 39 124 85 209 At -12883.773 4.745 7814.7835 0.0227 B- -3942.7237 11.0298 208 986168.701 5.094 + 37 123 86 209 Rn -8941.049 9.960 7792.1755 0.0477 B- -5158.9051 15.2153 208 990401.389 10.692 + 35 122 87 209 Fr -3782.144 11.503 7763.7485 0.0550 B- -5640.3845 12.8549 208 995939.701 12.349 + 33 121 88 209 Ra -a 1858.240 5.747 7733.0177 0.0275 B- -6986.6464 56.1409 209 001994.902 6.169 + 31 120 89 209 Ac -a 8844.887 55.846 7695.8455 0.2672 B- -7550# 117# 209 009495.375 59.953 + 29 119 90 209 Th IT 16395# 103# 7656# 0# B- * 209 017601# 111# +0 52 131 79 210 Au x 2680# 400# 7764# 2# B- 7980# 447# 210 002877# 429# + 50 130 80 210 Hg x -5300# 200# 7799# 1# B- 3947# 201# 209 994310# 215# + 48 129 81 210 Tl +a -9246.996 11.603 7813.5890 0.0553 B- 5481.4334 11.5610 209 990072.942 12.456 + 46 128 82 210 Pb -14728.429 1.448 7835.9656 0.0069 B- 63.4758 0.4992 209 984188.381 1.554 + 44 127 83 210 Bi -14791.905 1.364 7832.5424 0.0065 B- 1161.1549 0.7662 209 984120.237 1.463 + 42 126 84 210 Po -15953.060 1.146 7834.3462 0.0055 B- -3980.9605 7.6101 209 982873.686 1.230 + 40 125 85 210 At -a -11972.099 7.695 7811.6638 0.0366 B- -2367.3352 8.9225 209 987147.423 8.261 + 38 124 86 210 Rn -a -9604.764 4.557 7796.6653 0.0217 B- -6261.2558 14.1720 209 989688.862 4.892 + 36 123 87 210 Fr -3343.508 13.420 7763.1243 0.0639 B- -3786.3467 16.2633 209 996410.596 14.407 + 34 122 88 210 Ra -a 442.839 9.193 7741.3687 0.0438 B- -8321.2403 62.8832 210 000475.406 9.868 + 32 121 89 210 Ac 8764.079 62.208 7698.0182 0.2962 B- -5295.4420 65.0180 210 009408.625 66.782 + 30 120 90 210 Th -a 14059.521 18.909 7669.0764 0.0900 B- * 210 015093.515 20.299 +0 51 131 80 211 Hg x -390# 200# 7777# 1# B- 5688# 205# 210 999581# 215# + 49 130 81 211 Tl x -6077.999 41.917 7799.7915 0.1987 B- 4415.0129 41.9781 210 993475.000 45.000 + 47 129 82 211 Pb -10493.012 2.260 7817.0079 0.0107 B- 1366.1041 5.4713 210 988735.288 2.426 + 45 128 83 211 Bi -11859.116 5.442 7819.7745 0.0258 B- 573.3763 5.4297 210 987268.715 5.842 + 43 127 84 211 Po -a -12432.492 1.255 7818.7842 0.0060 B- -785.3012 2.5385 210 986653.171 1.347 + 41 126 85 211 At -a -11647.191 2.729 7811.3545 0.0129 B- -2891.8615 6.8937 210 987496.226 2.929 + 39 125 86 211 Rn -a -8755.330 6.813 7793.9412 0.0323 B- -4615.0152 13.7862 210 990600.767 7.314 + 37 124 87 211 Fr -4140.314 11.991 7768.3613 0.0568 B- -4972.1844 12.9786 210 995555.189 12.872 + 35 123 88 211 Ra 831.870 4.966 7741.0887 0.0235 B- -6311.6152 53.9818 211 000893.049 5.331 + 33 122 89 211 Ac 7143.485 53.753 7707.4680 0.2548 B- -6732.9111 101.4758 211 007668.846 57.706 + 31 121 90 211 Th -a 13876.396 86.070 7671.8506 0.4079 B- -8175.8296 110.6091 211 014896.923 92.399 + 29 120 91 211 Pa -a 22052.226 69.472 7629.3948 0.3293 B- * 211 023674.036 74.581 +0 52 132 80 212 Hg x 3020# 300# 7762# 1# B- 4571# 361# 212 003242# 322# + 50 131 81 212 Tl +a -1551# 200# 7780# 1# B- 5998# 200# 211 998335# 215# + 48 130 82 212 Pb -7548.929 1.840 7804.3203 0.0087 B- 569.0133 1.8246 211 991895.891 1.975 + 46 129 83 212 Bi -8117.943 1.853 7803.3140 0.0087 B- 2251.4656 1.6671 211 991285.030 1.989 + 44 128 84 212 Po -10369.408 1.153 7810.2438 0.0054 B- -1741.2596 2.1066 211 988867.982 1.237 + 42 127 85 212 At -a -8628.149 2.385 7798.3400 0.0113 B- 31.0705 3.5927 211 990737.301 2.559 + 40 126 86 212 Rn -a -8659.219 3.110 7794.7963 0.0147 B- -5143.2210 9.3064 211 990703.946 3.338 + 38 125 87 212 Fr -3515.998 8.775 7766.8455 0.0414 B- -3317.2355 13.4939 211 996225.420 9.419 + 36 124 88 212 Ra -198.763 10.254 7747.5078 0.0484 B- -7498.3626 24.1666 211 999786.619 11.007 + 34 123 89 212 Ac 7299.600 21.883 7708.4479 0.1032 B- -4811.2864 24.1055 212 007836.442 23.492 + 32 122 90 212 Th -a 12110.886 10.109 7682.0628 0.0477 B- -9485.6366 88.1858 212 013001.570 10.852 + 30 121 91 212 Pa -a 21596.523 87.604 7633.6289 0.4132 B- * 212 023184.819 94.047 +0 53 133 80 213 Hg x 8200# 300# 7739# 1# B- 6416# 301# 213 008803# 322# + 51 132 81 213 Tl x 1783.811 27.013 7765.4311 0.1268 B- 4987.4088 27.8941 213 001915.000 29.000 + 49 131 82 213 Pb +a -3203.598 6.954 7785.1732 0.0326 B- 2028.0730 8.3708 212 996560.796 7.465 + 47 130 83 213 Bi -5231.671 5.082 7791.0217 0.0239 B- 1421.8481 5.4898 212 994383.570 5.455 + 45 129 84 213 Po -6653.519 3.053 7794.0240 0.0143 B- -73.9972 5.4646 212 992857.154 3.277 + 43 128 85 213 At -a -6579.522 4.898 7790.0036 0.0230 B- -883.5727 5.7243 212 992936.593 5.258 + 41 127 86 213 Rn -a -5695.949 3.370 7782.1824 0.0158 B- -2141.7493 5.6996 212 993885.147 3.618 + 39 126 87 213 Fr -3554.199 4.707 7768.4543 0.0221 B- -3899.7568 10.8862 212 996184.410 5.053 + 37 125 88 213 Ra 345.557 9.818 7746.4726 0.0461 B- -5795.4721 15.2463 213 000370.971 10.540 + 35 124 89 213 Ac 6141.029 11.665 7715.5908 0.0548 B- -5979.0781 14.8635 213 006592.665 12.522 + 33 123 90 213 Th -a 12120.108 9.217 7683.8470 0.0433 B- -7534.0866 57.9078 213 013011.470 9.895 + 31 122 91 213 Pa -a 19654.194 57.170 7644.8027 0.2684 B- * 213 021099.644 61.374 +0 54 134 80 214 Hg x 11770# 400# 7724# 2# B- 5306# 445# 214 012636# 429# + 52 133 81 214 Tl x 6465# 196# 7745# 1# B- 6648# 196# 214 006940# 210# + 50 132 82 214 Pb -183.019 1.969 7772.3955 0.0092 B- 1017.7611 11.2559 213 999803.521 2.114 + 48 131 83 214 Bi -1200.780 11.209 7773.4955 0.0524 B- 3269.1925 11.1649 213 998710.909 12.033 + 46 130 84 214 Po -4469.972 1.449 7785.1163 0.0068 B- -1090.8208 3.7750 213 995201.287 1.556 + 44 129 85 214 At -3379.151 3.982 7776.3632 0.0186 B- 940.5125 9.8827 213 996372.331 4.274 + 42 128 86 214 Rn -a -4319.664 9.187 7777.1023 0.0429 B- -3361.3369 12.4238 213 995362.650 9.862 + 40 127 87 214 Fr -a -958.327 8.519 7757.7393 0.0398 B- -1051.0675 9.9879 213 998971.193 9.145 + 38 126 88 214 Ra -a 92.740 5.250 7749.1719 0.0245 B- -6340.5313 14.5317 214 000099.560 5.636 + 36 125 89 214 Ac 6433.272 13.551 7715.8874 0.0633 B- -4261.6599 17.2389 214 006906.400 14.547 + 34 124 90 214 Th -a 10694.932 10.661 7692.3173 0.0498 B- -8764.9630 81.9051 214 011481.480 11.445 + 32 123 91 214 Pa -a 19459.895 81.208 7647.7037 0.3795 B- * 214 020891.055 87.180 +0 55 135 80 215 Hg x 17110# 400# 7701# 2# B- 7079# 500# 215 018368# 429# + 53 134 81 215 Tl x 10030# 300# 7730# 1# B- 5688# 305# 215 010768# 322# + 51 133 82 215 Pb +a 4342.245 52.685 7752.7381 0.2450 B- 2712.9729 52.9848 215 004661.591 56.560 + 49 132 83 215 Bi 1629.272 5.624 7761.7177 0.0262 B- 2171.0426 5.5297 215 001749.095 6.037 + 47 131 84 215 Po -541.771 2.120 7768.1768 0.0099 B- 714.8128 6.6491 214 999418.385 2.276 + 45 130 85 215 At -a -1256.583 6.629 7767.8627 0.0308 B- -87.5935 8.9062 214 998651.002 7.116 + 43 129 86 215 Rn -a -1168.990 6.090 7763.8164 0.0283 B- -1487.1274 9.1890 214 998745.037 6.538 + 41 128 87 215 Fr -a 318.137 7.066 7753.2607 0.0329 B- -2213.8573 9.7691 215 000341.534 7.585 + 39 127 88 215 Ra -a 2531.995 7.201 7739.3249 0.0335 B- -3498.5554 14.3395 215 002718.208 7.730 + 37 126 89 215 Ac -a 6030.550 12.406 7719.4137 0.0577 B- -4890.8833 13.9296 215 006474.061 13.318 + 35 125 90 215 Th -a 10921.434 6.335 7693.0266 0.0295 B- -6883.1037 82.6932 215 011724.640 6.800 + 33 124 91 215 Pa -a 17804.537 82.450 7657.3733 0.3835 B- -7084.7747 132.8246 215 019113.955 88.513 + 31 123 92 215 U -a 24889.312 104.136 7620.7821 0.4844 B- * 215 026719.774 111.794 +0 56 136 80 216 Hg x 20920# 400# 7685# 2# B- 6050# 500# 216 022459# 429# + 54 135 81 216 Tl x 14870# 300# 7709# 1# B- 7361# 361# 216 015964# 322# + 52 134 82 216 Pb x 7510# 200# 7740# 1# B- 1636# 201# 216 008062# 215# + 50 133 83 216 Bi x 5873.988 11.178 7743.4996 0.0518 B- 4091.6520 11.3243 216 006305.985 12.000 + 48 132 84 216 Po 1782.336 1.815 7758.8205 0.0084 B- -474.3423 3.5713 216 001913.416 1.948 + 46 131 85 216 At -a 2256.678 3.575 7753.0024 0.0166 B- 2003.3657 6.6383 216 002422.643 3.837 + 44 130 86 216 Rn -a 253.312 5.768 7758.6553 0.0267 B- -2717.7096 6.9366 216 000271.942 6.192 + 42 129 87 216 Fr -a 2971.022 4.174 7742.4513 0.0193 B- -320.4441 8.8904 216 003189.523 4.480 + 40 128 88 216 Ra -a 3291.466 8.004 7737.3458 0.0371 B- -4858.2701 12.2147 216 003533.534 8.592 + 38 127 89 216 Ac 8149.736 9.230 7711.2319 0.0427 B- -2148.8006 14.4375 216 008749.101 9.908 + 36 126 90 216 Th -a 10298.537 11.104 7697.6617 0.0514 B- -7525.2616 27.0327 216 011055.933 11.920 + 34 125 91 216 Pa -a 17823.799 24.647 7659.2006 0.1141 B- -5242.6308 37.3721 216 019134.633 26.459 + 32 124 92 216 U -a 23066.429 28.093 7631.3072 0.1301 B- * 216 024762.829 30.158 +0 55 136 81 217 Tl x 18660# 400# 7693# 2# B- 6399# 500# 217 020032# 429# + 53 135 82 217 Pb x 12260# 300# 7719# 1# B- 3530# 300# 217 013162# 322# + 51 134 83 217 Bi x 8729.963 17.698 7731.8491 0.0816 B- 2846.5103 18.8695 217 009372.000 19.000 + 49 133 84 217 Po +a 5883.452 6.544 7741.3614 0.0302 B- 1488.8543 7.9791 217 006316.145 7.025 + 47 132 85 217 At 4394.598 5.001 7744.6172 0.0230 B- 736.0320 6.1505 217 004717.794 5.368 + 45 131 86 217 Rn -a 3658.566 4.198 7744.4037 0.0193 B- -656.0967 7.5383 217 003927.632 4.506 + 43 130 87 217 Fr -a 4314.663 6.531 7737.7750 0.0301 B- -1574.8729 9.4723 217 004631.980 7.011 + 41 129 88 217 Ra -a 5889.536 7.047 7726.9122 0.0325 B- -2812.7853 13.2129 217 006322.676 7.564 + 39 128 89 217 Ac -a 8702.321 11.223 7710.3448 0.0517 B- -3503.4590 15.4454 217 009342.325 12.048 + 37 127 90 217 Th -a 12205.780 10.614 7690.5945 0.0489 B- -4848.9680 16.3966 217 013103.443 11.394 + 35 126 91 217 Pa -a 17054.748 12.498 7664.6438 0.0576 B- -5916# 81# 217 018309.024 13.417 + 33 125 92 217 U -a 22971# 81# 7634# 0# B- * 217 024660# 86# +0 56 137 81 218 Tl x 23710# 400# 7672# 2# B- 8081# 500# 218 025454# 429# + 54 136 82 218 Pb x 15630# 300# 7705# 1# B- 2414# 301# 218 016779# 322# + 52 135 83 218 Bi x 13216.038 27.013 7712.8280 0.1239 B- 4859.3866 27.0849 218 014188.000 29.000 + 50 134 84 218 Po 8356.652 1.967 7731.5300 0.0090 B- 256.4334 11.5490 218 008971.234 2.112 + 48 133 85 218 At -a 8100.218 11.503 7729.1175 0.0528 B- 2882.8048 11.6054 218 008695.941 12.349 + 46 132 86 218 Rn 5217.413 2.316 7738.7527 0.0106 B- -1842.0267 4.4418 218 005601.123 2.486 + 44 131 87 218 Fr -a 7059.440 4.235 7726.7143 0.0194 B- 413.8838 10.5603 218 007578.620 4.546 + 42 130 88 218 Ra -a 6645.556 9.807 7725.0241 0.0450 B- -4205.2887 58.4224 218 007134.297 10.528 + 40 129 89 218 Ac -a 10850.845 57.616 7702.1450 0.2643 B- -1515.9019 58.5648 218 011648.860 61.853 + 38 128 90 218 Th -a 12366.747 10.516 7691.6026 0.0482 B- -6282.8212 20.7132 218 013276.248 11.289 + 36 127 91 218 Pa -a 18649.568 17.846 7659.1935 0.0819 B- -3245.0869 22.5042 218 020021.133 19.158 + 34 126 92 218 U -a 21894.655 13.714 7640.7191 0.0629 B- * 218 023504.877 14.722 +0 55 137 82 219 Pb x 20620# 400# 7684# 2# B- 4300# 447# 219 022136# 429# + 53 136 83 219 Bi x 16320# 200# 7700# 1# B- 3638# 201# 219 017520# 215# + 51 135 84 219 Po x 12681.361 15.835 7713.3340 0.0723 B- 2285.3395 16.1628 219 013614.000 17.000 + 49 134 85 219 At 10396.021 3.237 7720.1970 0.0148 B- 1566.6838 2.9473 219 011160.587 3.474 + 47 133 86 219 Rn 8829.337 2.100 7723.7784 0.0096 B- 212.3984 6.8938 219 009478.683 2.254 + 45 132 87 219 Fr -a 8616.939 6.874 7721.1759 0.0314 B- -776.9137 9.5906 219 009250.664 7.380 + 43 131 88 219 Ra -a 9393.853 6.814 7714.0560 0.0311 B- -2175.7005 51.9016 219 010084.715 7.315 + 41 130 89 219 Ac -a 11569.553 51.477 7700.5489 0.2351 B- -2893.2268 76.3627 219 012420.425 55.263 + 39 129 90 219 Th -a 14462.780 56.460 7683.7655 0.2578 B- -4120.4434 89.7010 219 015526.432 60.611 + 37 128 91 219 Pa -a 18583.223 69.705 7661.3783 0.3183 B- -4712.7298 70.9693 219 019949.909 74.831 + 35 127 92 219 U -a 23295.953 13.338 7636.2867 0.0609 B- -6140.9976 92.9309 219 025009.233 14.319 + 33 126 93 219 Np -a 29436.951 91.969 7604.6732 0.4199 B- * 219 031601.865 98.732 +0 56 138 82 220 Pb x 24130# 400# 7670# 2# B- 3171# 500# 220 025905# 429# + 54 137 83 220 Bi x 20960# 300# 7681# 1# B- 5696# 300# 220 022501# 322# + 52 136 84 220 Po x 15263.462 17.698 7703.2244 0.0804 B- 887.7139 22.5491 220 016386.000 19.000 + 50 135 85 220 At x 14375.748 13.972 7703.7033 0.0635 B- 3763.7550 14.0896 220 015433.000 15.000 + 48 134 86 220 Rn 10611.994 1.814 7717.2552 0.0082 B- -870.3384 4.0256 220 011392.443 1.947 + 46 133 87 220 Fr -a 11482.332 4.028 7709.7430 0.0183 B- 1210.2406 8.4809 220 012326.789 4.324 + 44 132 88 220 Ra -a 10272.091 7.595 7711.6879 0.0345 B- -3471.6640 9.6266 220 011027.542 8.153 + 42 131 89 220 Ac -a 13743.755 6.129 7692.3515 0.0279 B- -945.7825 14.9144 220 014754.527 6.579 + 40 130 90 220 Th -a 14689.538 13.687 7684.4964 0.0622 B- -5588.8595 20.0508 220 015769.866 14.693 + 38 129 91 220 Pa -a 20278.397 14.655 7655.5364 0.0666 B- -2735# 102# 220 021769.753 15.732 + 36 128 92 220 U -a 23013# 101# 7640# 0# B- -7462# 105# 220 024706# 108# + 34 127 93 220 Np -a 30475.022 30.718 7602.0758 0.1396 B- * 220 032716.280 32.977 +0 55 138 83 221 Bi x 24200# 300# 7668# 1# B- 4426# 301# 221 025980# 322# + 53 137 84 221 Po x 19773.757 19.561 7684.4814 0.0885 B- 2991.0276 24.0390 221 021228.000 21.000 + 51 136 85 221 At x 16782.729 13.972 7694.4754 0.0632 B- 2311.3750 15.0957 221 018017.000 15.000 + 49 135 86 221 Rn +a 14471.354 5.714 7701.3941 0.0259 B- 1194.1032 7.2312 221 015535.637 6.134 + 47 134 87 221 Fr 13277.251 4.886 7703.2572 0.0221 B- 313.3741 6.3858 221 014253.714 5.245 + 45 133 88 221 Ra -a 12963.877 4.630 7701.1352 0.0210 B- -1567.1715 57.0591 221 013917.293 4.970 + 43 132 89 221 Ac -a 14531.048 56.901 7690.5039 0.2575 B- -2408.8773 57.4376 221 015599.721 61.086 + 41 131 90 221 Th -a 16939.926 7.994 7676.0640 0.0362 B- -3435.0112 59.9069 221 018185.757 8.582 + 39 130 91 221 Pa -a 20374.937 59.380 7656.9809 0.2687 B- -4145.0590 93.4311 221 021873.393 63.746 + 37 129 92 221 U -a 24519.996 72.135 7634.6849 0.3264 B- -5390# 213# 221 026323.297 77.440 + 35 128 93 221 Np x 29910# 200# 7607# 1# B- -6019# 361# 221 032110# 215# + 33 127 94 221 Pu x 35930# 300# 7576# 1# B- * 221 038572# 322# +0 56 139 83 222 Bi x 28950# 300# 7648# 1# B- 6464# 303# 222 031079# 322# + 54 138 84 222 Po x 22486.268 40.054 7674.0054 0.1804 B- 1533.2393 43.0709 222 024140.000 43.000 + 52 137 85 222 At x 20953.028 15.835 7677.3878 0.0713 B- 4581.0714 15.9542 222 022494.000 17.000 + 50 136 86 222 Rn 16371.957 1.944 7694.4991 0.0088 B- -6.1461 7.7013 222 017576.017 2.086 + 48 135 87 222 Fr x 16378.103 7.452 7690.9474 0.0336 B- 2057.8980 8.6816 222 017582.615 8.000 + 46 134 88 222 Ra 14320.205 4.454 7696.6931 0.0201 B- -2301.5922 6.2737 222 015373.371 4.781 + 44 133 89 222 Ac -a 16621.797 4.699 7682.8015 0.0212 B- -581.2415 11.1289 222 017844.232 5.044 + 42 132 90 222 Th -a 17203.039 10.216 7676.6592 0.0460 B- -4861.3220 87.1915 222 018468.220 10.966 + 40 131 91 222 Pa -a 22064.361 86.606 7651.2373 0.3901 B- -2208.4729 101.0129 222 023687.064 92.975 + 38 130 92 222 U -a 24272.834 51.994 7637.7651 0.2342 B- -7001.8072 64.4300 222 026057.957 55.817 + 36 129 93 222 Np -a 31274.641 38.051 7602.7013 0.1714 B- -3785# 302# 222 033574.706 40.849 + 34 128 94 222 Pu x 35060# 300# 7582# 1# B- * 222 037638# 322# +0 57 140 83 223 Bi x 32240# 400# 7636# 2# B- 5161# 445# 223 034611# 429# + 55 139 84 223 Po x 27079# 196# 7655# 1# B- 3651# 196# 223 029070# 210# + 53 138 85 223 At x 23428.008 13.972 7668.0557 0.0627 B- 3038.2698 16.0129 223 025151.000 15.000 + 51 137 86 223 Rn 20389.738 7.822 7678.1720 0.0351 B- 2007.4091 8.0568 223 021889.283 8.397 + 49 136 87 223 Fr 18382.329 1.931 7683.6655 0.0087 B- 1149.0844 0.8476 223 019734.241 2.073 + 47 135 88 223 Ra 17233.245 2.090 7685.3101 0.0094 B- -591.8099 6.9657 223 018500.648 2.243 + 45 134 89 223 Ac -a 17825.055 6.947 7679.1479 0.0312 B- -1560.3471 10.4712 223 019135.982 7.457 + 43 133 90 223 Th -a 19385.402 7.943 7668.6426 0.0356 B- -2952.2124 76.0305 223 020811.083 8.527 + 41 132 91 223 Pa -a 22337.614 75.632 7651.8957 0.3392 B- -3707.6637 95.9225 223 023980.414 81.193 + 39 131 92 223 U -a 26045.278 59.054 7631.7611 0.2648 B- -4613.3046 101.7520 223 027960.754 63.396 + 37 130 93 223 Np -a 30658.583 82.863 7607.5654 0.3716 B- -5462# 311# 223 032913.340 88.956 + 35 129 94 223 Pu x 36121# 300# 7580# 1# B- -6579# 424# 223 038777# 322# + 33 128 95 223 Am x 42700# 300# 7547# 1# B- * 223 045840# 322# +0 58 141 83 224 Bi x 37070# 400# 7616# 2# B- 7159# 445# 224 039796# 429# + 56 140 84 224 Po x 29910# 196# 7644# 1# B- 2199# 197# 224 032110# 210# + 54 139 85 224 At x 27711.018 22.356 7650.7354 0.0998 B- 5265.9197 24.4153 224 029749.000 24.000 + 52 138 86 224 Rn 22445.098 9.814 7670.7514 0.0438 B- 696.4840 14.8750 224 024095.803 10.536 + 50 137 87 224 Fr x 21748.614 11.178 7670.3680 0.0499 B- 2922.7819 11.3237 224 023348.096 12.000 + 48 136 88 224 Ra 18825.832 1.811 7679.9236 0.0081 B- -1408.3152 4.0869 224 020210.361 1.944 + 46 135 89 224 Ac -a 20234.148 4.089 7670.1438 0.0183 B- 238.5672 10.3428 224 021722.249 4.389 + 44 134 90 224 Th -a 19995.581 9.604 7667.7162 0.0429 B- -3866.7705 12.1339 224 021466.137 10.310 + 42 133 91 224 Pa -a 23862.351 7.587 7646.9612 0.0339 B- -1880.3393 16.9711 224 025617.286 8.145 + 40 132 92 224 U -a 25742.690 15.261 7635.0742 0.0681 B- -6289.5572 32.7036 224 027635.913 16.383 + 38 131 93 224 Np 32032.248 28.925 7603.5032 0.1291 B- -3248# 301# 224 034388.030 31.052 + 36 130 94 224 Pu x 35280# 300# 7586# 1# B- -7980# 500# 224 037875# 322# + 34 129 95 224 Am x 43260# 400# 7546# 2# B- * 224 046442# 429# +0 57 141 84 225 Po x 34580# 300# 7626# 1# B- 4280# 424# 225 037123# 322# + 55 140 85 225 At x 30300# 300# 7641# 1# B- 3765# 300# 225 032528# 322# + 53 139 86 225 Rn 26534.143 11.140 7654.3581 0.0495 B- 2713.5412 16.3492 225 028485.572 11.958 + 51 138 87 225 Fr 23820.602 11.967 7662.9412 0.0532 B- 1827.5584 12.1574 225 025572.466 12.847 + 49 137 88 225 Ra 21993.044 2.596 7667.5866 0.0115 B- 355.7386 5.0067 225 023610.502 2.786 + 47 136 89 225 Ac 21637.305 4.758 7665.6906 0.0211 B- -672.8878 6.6576 225 023228.601 5.107 + 45 135 90 225 Th -a 22310.193 5.093 7659.2229 0.0226 B- -2046.4473 82.0038 225 023950.975 5.467 + 43 134 91 225 Pa -a 24356.640 81.867 7646.6504 0.3639 B- -3015.3610 82.4514 225 026147.927 87.887 + 41 133 92 225 U -a 27372.001 9.934 7629.7717 0.0442 B- -4246.0969 92.1491 225 029385.050 10.664 + 39 132 93 225 Np -a 31618.098 91.618 7607.4231 0.4072 B- -4682# 314# 225 033943.422 98.355 + 37 131 94 225 Pu x 36300# 300# 7583# 1# B- -6090# 500# 225 038970# 322# + 35 130 95 225 Am x 42390# 400# 7553# 2# B- * 225 045508# 429# +0 58 142 84 226 Po x 37549# 401# 7614# 2# B- 2889# 500# 226 040310# 430# + 56 141 85 226 At x 34660# 300# 7624# 1# B- 5913# 300# 226 037209# 322# + 54 140 86 226 Rn 28747.194 10.477 7646.4108 0.0464 B- 1226.6542 12.1895 226 030861.380 11.247 + 52 139 87 226 Fr 27520.539 6.230 7648.3768 0.0276 B- 3852.9638 6.5215 226 029544.512 6.688 + 50 138 88 226 Ra 23667.576 1.927 7661.9636 0.0085 B- -641.6252 3.2730 226 025408.186 2.068 + 48 137 89 226 Ac 24309.201 3.100 7655.6628 0.0137 B- 1111.5517 4.5626 226 026096.999 3.327 + 46 136 90 226 Th 23197.649 4.481 7657.1195 0.0198 B- -2835.9504 11.9702 226 024903.699 4.810 + 44 135 91 226 Pa -a 26033.600 11.213 7641.1093 0.0496 B- -1295.1978 15.6747 226 027948.217 12.037 + 42 134 92 226 U -a 27328.797 11.071 7631.9166 0.0490 B- -5488.0792 102.6485 226 029338.669 11.884 + 40 133 93 226 Np -a 32816.877 102.063 7604.1714 0.4516 B- -2813# 225# 226 035230.364 109.568 + 38 132 94 226 Pu x 35630# 200# 7588# 1# B- -7340# 361# 226 038250# 215# + 36 131 95 226 Am x 42970# 300# 7552# 1# B- * 226 046130# 322# +0 59 143 84 227 Po x 42281# 401# 7596# 2# B- 4850# 500# 227 045390# 430# + 57 142 85 227 At x 37430# 300# 7613# 1# B- 4544# 300# 227 040183# 322# + 55 141 86 227 Rn 32885.835 14.091 7630.0508 0.0621 B- 3203.3894 15.2755 227 035304.393 15.127 + 53 140 87 227 Fr 29682.445 5.898 7640.7162 0.0260 B- 2504.9813 6.2112 227 031865.413 6.332 + 51 139 88 227 Ra -n 27177.464 1.946 7648.3048 0.0086 B- 1327.9489 2.2622 227 029176.205 2.089 + 49 138 89 227 Ac 25849.515 1.926 7650.7084 0.0085 B- 44.7559 0.8297 227 027750.594 2.068 + 47 137 90 227 Th 25804.759 2.088 7647.4591 0.0092 B- -1025.6117 7.2815 227 027702.546 2.241 + 45 136 91 227 Pa -a 26830.371 7.263 7639.4945 0.0320 B- -2214.6629 11.1118 227 028803.586 7.797 + 43 135 92 227 U -a 29045.034 8.510 7626.2918 0.0375 B- -3533.9848 77.4417 227 031181.124 9.136 + 41 134 93 227 Np -a 32579.018 76.989 7607.2771 0.3392 B- -4191# 126# 227 034975.012 82.651 + 39 133 94 227 Pu x 36770# 100# 7585# 0# B- -5410# 224# 227 039474# 107# + 37 132 95 227 Am x 42180# 200# 7558# 1# B- * 227 045282# 215# +0 58 143 85 228 At x 41880# 400# 7596# 2# B- 6637# 400# 228 044960# 429# + 56 142 86 228 Rn 35243.466 17.677 7621.6457 0.0775 B- 1859.2451 18.9157 228 037835.415 18.977 + 54 141 87 228 Fr 33384.221 6.732 7626.3689 0.0295 B- 4444.0270 7.0210 228 035839.433 7.226 + 52 140 88 228 Ra +a 28940.194 1.995 7642.4289 0.0088 B- 45.5402 0.6344 228 031068.574 2.141 + 50 139 89 228 Ac - 28894.654 2.093 7639.1973 0.0092 B- 2123.7545 2.6446 228 031019.685 2.247 + 48 138 90 228 Th 26770.899 1.806 7645.0807 0.0079 B- -2152.6993 4.3399 228 028739.741 1.938 + 46 137 91 228 Pa -a 28923.599 4.340 7632.2076 0.0190 B- -296.4020 14.0858 228 031050.758 4.659 + 44 136 92 228 U -a 29220.001 13.474 7627.4763 0.0591 B- -4605# 101# 228 031368.959 14.465 + 42 135 93 228 Np -a 33825# 100# 7604# 0# B- -2283# 103# 228 036313# 108# + 40 134 94 228 Pu -a 36107.809 23.352 7590.4039 0.1024 B- -6742# 202# 228 038763.325 25.069 + 38 133 95 228 Am x 42850# 200# 7557# 1# B- * 228 046001# 215# +0 59 144 85 229 At x 44890# 400# 7585# 2# B- 5527# 400# 229 048191# 429# + 57 143 86 229 Rn x 39362.400 13.041 7605.6227 0.0569 B- 3694.1465 13.9670 229 042257.272 14.000 + 55 142 87 229 Fr 35668.253 5.001 7618.3380 0.0218 B- 3106.2907 16.2305 229 038291.443 5.368 + 53 141 88 229 Ra x 32561.963 15.441 7628.4862 0.0674 B- 1872.0266 19.6229 229 034956.703 16.576 + 51 140 89 229 Ac x 30689.936 12.109 7633.2446 0.0529 B- 1104.4191 12.3458 229 032947.000 13.000 + 49 139 90 229 Th 29585.517 2.404 7634.6510 0.0105 B- -311.3310 3.7152 229 031761.357 2.581 + 47 138 91 229 Pa 29896.848 3.280 7629.8752 0.0143 B- -1313.7716 6.6554 229 032095.585 3.521 + 45 137 92 229 U -a 31210.620 5.938 7620.7218 0.0259 B- -2590.7577 101.3342 229 033505.976 6.374 + 43 136 93 229 Np -a 33801.378 101.177 7605.9921 0.4418 B- -3593.5462 117.9433 229 036287.269 108.618 + 41 135 94 229 Pu -a 37394.924 60.633 7586.8834 0.2648 B- -4785.4899 122.4147 229 040145.099 65.092 + 39 134 95 229 Am -a 42180.414 106.348 7562.5697 0.4644 B- * 229 045282.534 114.169 +0 58 144 86 230 Rn x 42170# 200# 7595# 1# B- 2683# 200# 230 045271# 215# + 56 143 87 230 Fr 39486.769 6.541 7603.7052 0.0284 B- 4970.4627 12.1984 230 042390.787 7.022 + 54 142 88 230 Ra x 34516.306 10.296 7621.9144 0.0448 B- 677.9196 18.8884 230 037054.776 11.053 + 52 141 89 230 Ac x 33838.386 15.835 7621.4604 0.0689 B- 2975.8745 15.8815 230 036327.000 17.000 + 50 140 90 230 Th 30862.512 1.209 7630.9974 0.0053 B- -1311.0313 2.8334 230 033132.267 1.297 + 48 139 91 230 Pa 32173.543 3.038 7621.8958 0.0132 B- 558.5262 4.5919 230 034539.717 3.261 + 46 138 92 230 U -a 31615.017 4.509 7620.9227 0.0196 B- -3621.5986 55.1683 230 033940.114 4.841 + 44 137 93 230 Np -a 35236.615 55.007 7601.7751 0.2392 B- -1695.5543 56.8505 230 037828.060 59.051 + 42 136 94 230 Pu -a 36932.170 14.451 7591.0016 0.0628 B- -5940# 144# 230 039648.313 15.514 + 40 135 95 230 Am -a 42872# 143# 7562# 1# B- * 230 046025# 153# +0 59 145 86 231 Rn x 46550# 300# 7579# 1# B- 4469# 300# 231 049973# 322# + 57 144 87 231 Fr x 42080.575 7.731 7594.5009 0.0335 B- 3864.0868 13.7495 231 045175.353 8.300 + 55 143 88 231 Ra 38216.488 11.370 7607.8418 0.0492 B- 2453.6351 17.3014 231 041027.085 12.206 + 53 142 89 231 Ac x 35762.853 13.041 7615.0768 0.0565 B- 1947.0425 13.0976 231 038393.000 14.000 + 51 141 90 231 Th 33815.811 1.217 7620.1188 0.0053 B- 391.4727 1.4598 231 036302.764 1.306 + 49 140 91 231 Pa 33424.338 1.771 7618.4267 0.0077 B- -381.6138 2.0325 231 035882.500 1.901 + 47 139 92 231 U -a 33805.952 2.670 7613.3879 0.0116 B- -1817.7347 51.1839 231 036292.180 2.866 + 45 138 93 231 Np -a 35623.686 51.154 7602.1321 0.2214 B- -2684.8905 55.6931 231 038243.598 54.916 + 43 137 94 231 Pu -a 38308.577 22.061 7587.1224 0.0955 B- -4101# 301# 231 041125.946 23.683 + 41 136 95 231 Am x 42410# 300# 7566# 1# B- -4860# 424# 231 045529# 322# + 39 135 96 231 Cm x 47270# 300# 7542# 1# B- * 231 050746# 322# +0 58 145 87 232 Fr x 46072.834 13.972 7579.3481 0.0602 B- 5575.8791 16.7023 232 049461.219 15.000 + 56 144 88 232 Ra 40496.955 9.151 7600.0099 0.0394 B- 1342.5322 15.9313 232 043475.267 9.823 + 54 143 89 232 Ac x 39154.423 13.041 7602.4245 0.0562 B- 3707.7131 13.1181 232 042034.000 14.000 + 52 142 90 232 Th 35446.710 1.421 7615.0338 0.0061 B- -499.8388 7.7338 232 038053.606 1.525 + 50 141 91 232 Pa + 35946.549 7.645 7609.5072 0.0330 B- 1337.1034 7.4278 232 038590.205 8.206 + 48 140 92 232 U 34609.445 1.808 7611.8984 0.0078 B- -2750# 100# 232 037154.765 1.941 + 46 139 93 232 Np - 37359# 100# 7597# 0# B- -1001# 101# 232 040107# 107# + 44 138 94 232 Pu -a 38360.915 16.885 7588.9839 0.0728 B- -5059# 300# 232 041182.133 18.126 + 42 137 95 232 Am x 43420# 300# 7564# 1# B- -2913# 361# 232 046613# 322# + 40 136 96 232 Cm -a 46333# 201# 7548# 1# B- * 232 049740# 216# +0 59 146 87 233 Fr x 48920.052 19.561 7569.2398 0.0840 B- 4585.9906 21.3694 233 052517.833 21.000 + 57 145 88 233 Ra 44334.062 8.603 7585.5644 0.0369 B- 3026.0244 15.6228 233 047594.570 9.235 + 55 144 89 233 Ac x 41308.037 13.041 7595.1939 0.0560 B- 2576.3950 13.1184 233 044346.000 14.000 + 53 143 90 233 Th 38731.642 1.424 7602.8937 0.0061 B- 1242.2320 1.1224 233 041580.126 1.528 + 51 142 91 233 Pa 37489.410 1.336 7604.8675 0.0057 B- 570.2993 1.9750 233 040246.535 1.433 + 49 141 92 233 U 36919.111 2.254 7603.9574 0.0097 B- -1029.4197 51.0050 233 039634.294 2.420 + 47 140 93 233 Np -a 37948.531 50.981 7596.1816 0.2188 B- -2103.3047 74.3811 233 040739.421 54.729 + 45 139 94 233 Pu -a 40051.836 54.178 7583.7968 0.2325 B- -3233# 126# 233 042997.411 58.162 + 43 138 95 233 Am -a 43285# 114# 7567# 0# B- -4008# 140# 233 046468# 123# + 41 137 96 233 Cm -a 47293.340 81.095 7546.0020 0.3480 B- -5478# 247# 233 050771.485 87.059 + 39 136 97 233 Bk -a 52771# 233# 7519# 1# B- * 233 056652# 250# +0 58 146 88 234 Ra x 46930.629 8.383 7576.5439 0.0358 B- 2089.4348 16.2945 234 050382.100 9.000 + 56 145 89 234 Ac x 44841.195 13.972 7582.1297 0.0597 B- 4228.2364 14.2103 234 048139.000 15.000 + 54 144 90 234 Th +a 40612.958 2.589 7596.8557 0.0111 B- 274.0882 3.1716 234 043599.801 2.779 + 52 143 91 234 Pa IT 40338.870 4.094 7594.6837 0.0175 B- 2193.9105 3.9998 234 043305.555 4.395 + 50 142 92 234 U 38144.959 1.129 7600.7160 0.0048 B- -1809.8462 8.3205 234 040950.296 1.212 + 48 141 93 234 Np - 39954.806 8.397 7589.6382 0.0359 B- -395.1807 10.7522 234 042893.245 9.014 + 46 140 94 234 Pu -a 40349.986 6.798 7584.6061 0.0291 B- -4112# 160# 234 043317.489 7.298 + 44 139 95 234 Am -a 44462# 160# 7564# 1# B- -2261# 161# 234 047731# 172# + 42 138 96 234 Cm -a 46722.411 17.078 7550.6868 0.0730 B- -6673# 154# 234 050158.568 18.333 + 40 137 97 234 Bk -a 53395# 153# 7519# 1# B- * 234 057322# 164# +0 59 147 88 235 Ra x 51130# 300# 7561# 1# B- 3773# 300# 235 054890# 322# + 57 146 89 235 Ac x 47357.160 13.972 7573.5051 0.0595 B- 3339.4064 19.1127 235 050840.000 15.000 + 55 145 90 235 Th x 44017.754 13.041 7584.3862 0.0555 B- 1728.8531 19.1127 235 047255.000 14.000 + 53 144 91 235 Pa x 42288.901 13.972 7588.4139 0.0595 B- 1370.1184 14.0169 235 045399.000 15.000 + 51 143 92 235 U 40918.782 1.116 7590.9151 0.0048 B- -124.2619 0.8524 235 043928.117 1.198 + 49 142 93 235 Np 41043.044 1.388 7587.0571 0.0059 B- -1139.3021 20.4992 235 044061.518 1.490 + 47 141 94 235 Pu -a 42182.346 20.521 7578.8799 0.0873 B- -2442.2558 56.5932 235 045284.609 22.030 + 45 140 95 235 Am -a 44624.602 52.780 7565.1582 0.2246 B- -3389# 115# 235 047906.478 56.661 + 43 139 96 235 Cm -a 48013# 102# 7547# 0# B- -4757# 413# 235 051545# 110# + 41 138 97 235 Bk x 52770# 401# 7524# 2# B- * 235 056651# 430# +0 58 147 89 236 Ac x 51220.998 38.191 7559.2423 0.1618 B- 4965.7951 40.6669 236 054988.000 41.000 + 56 146 90 236 Th x 46255.203 13.972 7576.9688 0.0592 B- 921.2477 19.7600 236 049657.000 15.000 + 54 145 91 236 Pa x 45333.955 13.972 7577.5573 0.0592 B- 2889.3730 14.0166 236 048668.000 15.000 + 52 144 92 236 U 42444.582 1.112 7586.4854 0.0047 B- -933.5116 50.4152 236 045566.130 1.193 + 50 143 93 236 Np IT 43378.094 50.421 7579.2148 0.2136 B- 476.5854 50.3887 236 046568.296 54.129 + 48 142 94 236 Pu 42901.508 1.810 7577.9192 0.0077 B- -3139# 119# 236 046056.661 1.942 + 46 141 95 236 Am -a 46041# 119# 7561# 1# B- -1812# 120# 236 049427# 127# + 44 140 96 236 Cm -a 47852.820 17.635 7550.3090 0.0747 B- -5689# 361# 236 051372.112 18.931 + 42 139 97 236 Bk -a 53542# 361# 7523# 2# B- * 236 057479# 387# +0 59 148 89 237 Ac x 54020# 400# 7550# 2# B- 4065# 400# 237 057993# 429# + 57 147 90 237 Th x 49955.097 15.835 7563.4433 0.0668 B- 2427.4736 20.5140 237 053629.000 17.000 + 55 146 91 237 Pa x 47527.624 13.041 7570.3847 0.0550 B- 2137.4905 13.0962 237 051023.000 14.000 + 53 145 92 237 U 45390.133 1.202 7576.1026 0.0051 B- 518.5338 0.5200 237 048728.309 1.290 + 51 144 93 237 Np 44871.599 1.120 7574.9895 0.0047 B- -220.0630 1.2944 237 048171.640 1.201 + 49 143 94 237 Pu 45091.662 1.697 7570.7599 0.0072 B- -1478# 59# 237 048407.888 1.821 + 47 142 95 237 Am -a 46570# 59# 7561# 0# B- -2677# 95# 237 049995# 64# + 45 141 96 237 Cm -a 49247.151 74.399 7546.6241 0.3139 B- -3963# 242# 237 052868.988 79.870 + 43 140 97 237 Bk -a 53210# 230# 7527# 1# B- -4728# 250# 237 057123# 247# + 41 139 98 237 Cf -a 57938.255 97.347 7503.3507 0.4107 B- * 237 062199.272 104.506 +0 58 148 90 238 Th +a 52525# 283# 7555# 1# B- 1631# 284# 238 056388# 304# + 56 147 91 238 Pa x 50894.043 15.835 7558.3449 0.0665 B- 3586.3111 15.9056 238 054637.000 17.000 + 54 146 92 238 U 47307.732 1.492 7570.1262 0.0063 B- -146.8652 1.2006 238 050786.936 1.601 + 52 145 93 238 Np -n 47454.597 1.137 7566.2220 0.0048 B- 1291.4491 0.4573 238 050944.603 1.220 + 50 144 94 238 Pu 46163.148 1.138 7568.3611 0.0048 B- -2258.2731 58.9005 238 049558.175 1.221 + 48 143 95 238 Am -a 48421.421 58.911 7555.5853 0.2475 B- -1023.7818 60.1587 238 051982.531 63.243 + 46 142 96 238 Cm -a 49445.203 12.234 7547.9966 0.0514 B- -4771# 256# 238 053081.606 13.133 + 44 141 97 238 Bk -a 54216# 256# 7525# 1# B- -3061# 393# 238 058204# 275# + 42 140 98 238 Cf x 57278# 298# 7509# 1# B- * 238 061490# 320# +0 59 149 90 239 Th x 56500# 400# 7540# 2# B- 3162# 445# 239 060655# 429# + 57 148 91 239 Pa x 53337# 196# 7550# 1# B- 2765# 196# 239 057260# 210# + 55 147 92 239 U -n 50572.668 1.502 7558.5624 0.0063 B- 1261.6634 1.4935 239 054291.989 1.612 + 53 146 93 239 Np 49311.005 1.310 7560.5680 0.0055 B- 722.7849 0.9304 239 052937.538 1.406 + 51 145 94 239 Pu 48588.220 1.112 7560.3187 0.0047 B- -802.1402 1.6635 239 052161.596 1.194 + 49 144 95 239 Am -a 49390.360 1.982 7553.6891 0.0083 B- -1756.6021 150.0740 239 053022.729 2.127 + 47 143 96 239 Cm -a 51146.962 150.070 7543.0659 0.6279 B- -3103# 256# 239 054908.519 161.107 + 45 142 97 239 Bk -a 54250# 207# 7527# 1# B- -3952# 239# 239 058239# 222# + 43 141 98 239 Cf -a 58202# 120# 7507# 1# B- -5429# 323# 239 062482# 129# + 41 140 99 239 Es x 63630# 300# 7481# 1# B- * 239 068310# 322# +0 58 149 91 240 Pa x 57010# 200# 7537# 1# B- 4295# 200# 240 061203# 215# + 56 148 92 240 U 52715.497 2.553 7551.7705 0.0106 B- 399.2685 17.0830 240 056592.411 2.740 + 54 147 93 240 Np 52316.229 17.032 7550.1743 0.0710 B- 2190.9095 17.0151 240 056163.778 18.284 + 52 146 94 240 Pu 50125.319 1.105 7556.0433 0.0046 B- -1384.7902 13.7882 240 053811.740 1.186 + 50 145 95 240 Am +n 51510.110 13.832 7547.0136 0.0576 B- -214.1127 13.8967 240 055298.374 14.849 + 48 144 96 240 Cm 51724.222 1.905 7542.8617 0.0079 B- -3940# 150# 240 055528.233 2.045 + 46 143 97 240 Bk - 55664# 150# 7523# 1# B- -2324# 151# 240 059758# 161# + 44 142 98 240 Cf -a 57988.719 18.034 7510.2400 0.0751 B- -6237# 366# 240 062253.447 19.360 + 42 141 99 240 Es -a 64225# 366# 7481# 2# B- * 240 068949# 393# +0 59 150 91 241 Pa x 59740# 300# 7528# 1# B- 3543# 358# 241 064134# 322# + 57 149 92 241 U x 56197# 196# 7539# 1# B- 1882# 220# 241 060330# 210# + 55 148 93 241 Np + 54315.115 100.006 7544.0426 0.4150 B- 1360.0000 100.0000 241 058309.671 107.360 + 53 147 94 241 Pu 52955.115 1.105 7546.4395 0.0046 B- 20.7799 0.1658 241 056849.651 1.186 + 51 146 95 241 Am 52934.335 1.113 7543.2795 0.0046 B- -767.4346 1.1685 241 056827.343 1.195 + 49 145 96 241 Cm 53701.770 1.607 7536.8488 0.0067 B- -2279# 165# 241 057651.218 1.725 + 47 144 97 241 Bk +a 55981# 165# 7524# 1# B- -3346# 235# 241 060098# 178# + 45 143 98 241 Cf -a 59327# 167# 7507# 1# B- -4567# 285# 241 063690# 180# + 43 142 99 241 Es -a 63893# 231# 7485# 1# B- -5327# 379# 241 068592# 248# + 41 141 100 241 Fm x 69220# 300# 7459# 1# B- * 241 074311# 322# +0 58 150 92 242 U +a 58620# 201# 7532# 1# B- 1203# 283# 242 062931# 215# + 56 149 93 242 Np + 57416.876 200.004 7533.4042 0.8265 B- 2700.0000 200.0000 242 061639.548 214.712 + 54 148 94 242 Pu 54716.876 1.245 7541.3284 0.0052 B- -751.1373 0.7080 242 058740.979 1.336 + 52 147 95 242 Am -n 55468.014 1.118 7534.9917 0.0046 B- 664.3145 0.4143 242 059547.358 1.199 + 50 146 96 242 Cm 54803.699 1.141 7534.5040 0.0047 B- -2948# 135# 242 058834.187 1.224 + 48 145 97 242 Bk IT 57752# 135# 7519# 1# B- -1635# 135# 242 061999# 144# + 46 144 98 242 Cf -a 59386.982 12.892 7509.0991 0.0533 B- -5414# 257# 242 063754.544 13.840 + 44 143 99 242 Es -a 64801# 257# 7483# 1# B- -3598# 476# 242 069567# 276# + 42 142 100 242 Fm x 68400# 401# 7465# 2# B- * 242 073430# 430# +0 59 151 92 243 U x 62480# 300# 7518# 1# B- 2674# 302# 243 067075# 322# + 57 150 93 243 Np IT 59806# 32# 7526# 0# B- 2051# 32# 243 064204# 34# + 55 149 94 243 Pu 57754.561 2.542 7531.0087 0.0105 B- 579.5559 2.6216 243 062002.068 2.728 + 53 148 95 243 Am 57175.005 1.388 7530.1742 0.0057 B- -6.9302 1.5692 243 061379.889 1.490 + 51 147 96 243 Cm -a 57181.936 1.496 7526.9261 0.0062 B- -1507.6936 4.5065 243 061387.329 1.605 + 49 146 97 243 Bk -a 58689.629 4.524 7517.5021 0.0186 B- -2300# 181# 243 063005.905 4.856 + 47 145 98 243 Cf -a 60990# 181# 7505# 1# B- -3757# 275# 243 065475# 194# + 45 144 99 243 Es -a 64747# 207# 7486# 1# B- -4569# 245# 243 069508# 222# + 43 143 100 243 Fm -a 69316# 130# 7464# 1# B- * 243 074414# 140# +0 58 151 93 244 Np x 63240# 100# 7514# 0# B- 3434# 100# 244 067891# 107# + 56 150 94 244 Pu 59806.021 2.346 7524.8154 0.0096 B- -73.1143 2.6856 244 064204.401 2.518 + 54 149 95 244 Am + 59879.135 1.491 7521.3095 0.0061 B- 1427.3000 1.0000 244 064282.892 1.600 + 52 148 96 244 Cm -a 58451.835 1.106 7523.9527 0.0045 B- -2261.9902 14.3567 244 062750.622 1.187 + 50 147 97 244 Bk -a 60713.825 14.399 7511.4759 0.0590 B- -764.2709 14.5724 244 065178.969 15.457 + 48 146 98 244 Cf 61478.096 2.617 7505.1373 0.0107 B- -4547# 181# 244 065999.447 2.809 + 46 145 99 244 Es -a 66026# 181# 7483# 1# B- -2938# 271# 244 070881# 195# + 44 144 100 244 Fm -a 68964# 201# 7468# 1# B- -6634# 425# 244 074036# 216# + 42 143 101 244 Md -a 75597# 374# 7438# 2# B- * 244 081157# 402# +0 59 152 93 245 Np x 65850# 200# 7506# 1# B- 2672# 201# 245 070693# 215# + 57 151 94 245 Pu -n 63178.173 13.620 7513.2822 0.0556 B- 1277.7559 13.7334 245 067824.554 14.621 + 55 150 95 245 Am +a 61900.417 1.886 7515.3043 0.0077 B- 895.8929 1.5491 245 066452.827 2.024 + 53 149 96 245 Cm 61004.524 1.149 7515.7677 0.0047 B- -809.2519 1.4964 245 065491.047 1.233 + 51 148 97 245 Bk -a 61813.776 1.792 7509.2714 0.0073 B- -1571.3755 2.5861 245 066359.814 1.923 + 49 147 98 245 Cf 63385.151 2.428 7499.6644 0.0099 B- -2930# 165# 245 068046.755 2.606 + 47 146 99 245 Es IT 66315# 165# 7485# 1# B- -3877# 256# 245 071192# 178# + 45 145 100 245 Fm -a 70192# 195# 7465# 1# B- -5133# 325# 245 075354# 210# + 43 144 101 245 Md -a 75325# 260# 7441# 1# B- * 245 080864# 279# +0 58 152 94 246 Pu 65394.772 14.985 7506.5401 0.0609 B- 401# 14# 246 070204.172 16.087 + 56 151 95 246 Am IT 64994# 18# 7505# 0# B- 2377# 18# 246 069774# 19# + 54 150 96 246 Cm 62616.912 1.525 7511.4716 0.0062 B- -1350.0000 60.0000 246 067222.016 1.637 + 52 149 97 246 Bk - 63966.912 60.019 7502.8035 0.2440 B- -123.3159 60.0198 246 068671.300 64.433 + 50 148 98 246 Cf 64090.228 1.514 7499.1220 0.0062 B- -3728.5741 89.9373 246 068803.685 1.625 + 48 147 99 246 Es 67818.802 89.925 7480.7849 0.3655 B- -2372.3848 90.9577 246 072806.474 96.538 + 46 146 100 246 Fm -a 70191.187 13.670 7467.9608 0.0556 B- -5924# 260# 246 075353.334 14.675 + 44 145 101 246 Md -a 76115# 260# 7441# 1# B- * 246 081713# 279# +0 59 153 94 247 Pu x 69210# 200# 7493# 1# B- 2057# 224# 247 074300# 215# + 57 152 95 247 Am + 67153# 100# 7499# 0# B- 1620# 100# 247 072092# 107# + 55 151 96 247 Cm 65533.105 3.797 7501.9318 0.0154 B- 43.5841 6.3245 247 070352.678 4.076 + 53 150 97 247 Bk -a 65489.521 5.189 7498.9408 0.0210 B- -619.8711 15.2376 247 070305.889 5.570 + 51 149 98 247 Cf +a 66109.392 14.327 7493.2638 0.0580 B- -2469.0006 24.1495 247 070971.348 15.380 + 49 148 99 247 Es +a 68578.393 19.441 7480.1005 0.0787 B- -3094# 182# 247 073621.929 20.870 + 47 147 100 247 Fm +a 71672# 181# 7464# 1# B- -4263# 275# 247 076944# 194# + 45 146 101 247 Md -a 75936# 207# 7444# 1# B- * 247 081520# 223# +0 58 153 95 248 Am + 70563# 200# 7487# 1# B- 3170# 200# 248 075752# 215# + 56 152 96 248 Cm 67392.748 2.358 7496.7291 0.0095 B- -738.3049 50.0026 248 072349.086 2.531 + 54 151 97 248 Bk +a 68131.053 50.058 7490.5975 0.2018 B- 893.1015 50.3143 248 073141.689 53.739 + 52 150 98 248 Cf -a 67237.951 5.121 7491.0440 0.0207 B- -3061# 53# 248 072182.905 5.497 + 50 149 99 248 Es -a 70299# 52# 7476# 0# B- -1599# 53# 248 075469# 56# + 48 148 100 248 Fm 71897.793 8.497 7465.9451 0.0343 B- -5050# 184# 248 077185.451 9.122 + 46 147 101 248 Md -a 76948# 184# 7442# 1# B- -3741# 290# 248 082607# 198# + 44 146 102 248 No -a 80689# 224# 7424# 1# B- * 248 086623# 241# +0 59 154 95 249 Am x 73104# 298# 7479# 1# B- 2353# 298# 249 078480# 320# + 57 153 96 249 Cm -n 70750.696 2.371 7485.5510 0.0095 B- 904.3630 2.5934 249 075953.992 2.545 + 55 152 97 249 Bk + 69846.333 1.248 7486.0410 0.0050 B- 123.6000 0.4000 249 074983.118 1.339 + 53 151 98 249 Cf 69722.733 1.182 7483.3954 0.0048 B- -1452# 30# 249 074850.428 1.269 + 51 150 99 249 Es -a 71175# 30# 7474# 0# B- -2344# 31# 249 076409# 32# + 49 149 100 249 Fm 73519.143 6.212 7461.8649 0.0249 B- -3661.8091 164.5418 249 078926.042 6.668 + 47 148 101 249 Md 77180.952 164.425 7444.0169 0.6603 B- -4606# 324# 249 082857.155 176.516 + 45 147 102 249 No -a 81787# 279# 7422# 1# B- * 249 087802# 300# +0 58 154 96 250 Cm -nn 72989.588 10.274 7478.9385 0.0411 B- 37.5820 10.6414 250 078357.541 11.029 + 56 153 97 250 Bk +a 72952.006 2.898 7475.9594 0.0116 B- 1781.6696 2.4561 250 078317.195 3.110 + 54 152 98 250 Cf -a 71170.336 1.538 7479.9567 0.0062 B- -2055# 100# 250 076404.494 1.650 + 52 151 99 250 Es - 73225# 100# 7469# 0# B- -847# 100# 250 078611# 107# + 50 150 100 250 Fm 74072.193 7.888 7462.0905 0.0316 B- -4326.9476 91.2615 250 079519.765 8.468 + 48 149 101 250 Md 78399.140 90.920 7441.6533 0.3637 B- -3167# 220# 250 084164.934 97.606 + 46 148 102 250 No -a 81566# 200# 7426# 1# B- * 250 087565# 215# +0 59 155 96 251 Cm + 76647.981 22.698 7466.7233 0.0904 B- 1420.0000 20.0000 251 082284.988 24.367 + 57 154 97 251 Bk + 75227.981 10.734 7469.2637 0.0428 B- 1093.0000 10.0000 251 080760.555 11.523 + 55 153 98 251 Cf -a 74134.981 3.901 7470.5014 0.0155 B- -376.5660 6.4677 251 079587.171 4.187 + 53 152 99 251 Es -a 74511.547 5.288 7465.8842 0.0211 B- -1447.2610 15.2387 251 079991.431 5.676 + 51 151 100 251 Fm 75958.808 14.292 7457.0013 0.0569 B- -3007.9406 23.7108 251 081545.130 15.342 + 49 150 101 251 Md +a 78966.749 18.919 7441.9005 0.0754 B- -3882# 182# 251 084774.287 20.310 + 47 149 102 251 No IT 82849# 181# 7423# 1# B- -4981# 270# 251 088942# 194# + 45 148 103 251 Lr x 87830# 200# 7400# 1# B- * 251 094289# 215# +0 60 156 96 252 Cm x 79056# 298# 7460# 1# B- 521# 359# 252 084870# 320# + 58 155 97 252 Bk + 78535# 200# 7459# 1# B- 2500# 200# 252 084310# 215# + 56 154 98 252 Cf -a 76034.610 2.358 7465.3474 0.0094 B- -1260.0000 50.0000 252 081626.507 2.531 + 54 153 99 252 Es - 77294.610 50.056 7457.2428 0.1986 B- 477.9998 50.3220 252 082979.173 53.736 + 52 152 100 252 Fm -a 76816.611 5.221 7456.0351 0.0207 B- -3650.5075 91.4356 252 082466.019 5.604 + 50 151 101 252 Md x 80467.118 91.286 7438.4444 0.3622 B- -2404.2523 91.7581 252 086385.000 98.000 + 48 150 102 252 No 82871.370 9.292 7425.7992 0.0369 B- -5666# 185# 252 088966.070 9.975 + 46 149 103 252 Lr -a 88537# 185# 7400# 1# B- * 252 095048# 198# +0 59 156 97 253 Bk -a 80929# 359# 7451# 1# B- 1627# 359# 253 086880# 385# + 57 155 98 253 Cf -a 79301.562 4.257 7454.8297 0.0168 B- 291.0753 4.3850 253 085133.723 4.570 + 55 154 99 253 Es -a 79010.486 1.249 7452.8879 0.0049 B- -335.0623 1.0782 253 084821.241 1.341 + 53 153 100 253 Fm -a 79345.549 1.549 7448.4712 0.0061 B- -1827# 31# 253 085180.945 1.662 + 51 152 101 253 Md -a 81173# 31# 7438# 0# B- -3186# 32# 253 087143# 34# + 49 151 102 253 No 84358.696 6.912 7422.4719 0.0273 B- -4164.7752 164.6791 253 090562.780 7.420 + 47 150 103 253 Lr 88523.471 164.534 7402.9180 0.6503 B- -5118# 442# 253 095033.850 176.634 + 45 149 104 253 Rf -a 93642# 410# 7380# 2# B- * 253 100528# 440# +0 60 157 97 254 Bk x 84393# 298# 7440# 1# B- 3052# 298# 254 090600# 320# + 58 156 98 254 Cf -a 81341.395 11.462 7449.2259 0.0451 B- -652.7561 11.8014 254 087323.575 12.304 + 56 155 99 254 Es -a 81994.151 2.936 7443.5759 0.0116 B- 1091.6300 2.2858 254 088024.337 3.152 + 54 154 100 254 Fm -a 80902.521 1.843 7444.7936 0.0073 B- -2550# 100# 254 086852.424 1.978 + 52 153 101 254 Md - 83453# 100# 7432# 0# B- -1271# 100# 254 089590# 107# + 50 152 102 254 No 84723.312 9.658 7423.5909 0.0380 B- -4922.5753 91.8208 254 090954.211 10.367 + 48 151 103 254 Lr -a 89645.887 91.312 7401.1306 0.3595 B- -3555# 298# 254 096238.813 98.026 + 46 150 104 254 Rf -a 93201# 283# 7384# 1# B- * 254 100055# 304# +0 59 157 98 255 Cf + 84809# 200# 7438# 1# B- 720# 200# 255 091046# 215# + 57 156 99 255 Es -a 84089.237 10.817 7437.8216 0.0424 B- 288.7717 10.1024 255 090273.504 11.612 + 55 155 100 255 Fm -a 83800.465 3.934 7435.8860 0.0154 B- -1041.6037 6.7172 255 089963.495 4.223 + 53 154 101 255 Md -a 84842.069 5.567 7428.7333 0.0218 B- -1969.8648 15.1096 255 091081.702 5.976 + 51 153 102 255 No 86811.934 14.047 7417.9403 0.0551 B- -3135.3716 22.5952 255 093196.439 15.079 + 49 152 103 255 Lr x 89947.305 17.698 7402.5767 0.0694 B- -4382# 182# 255 096562.399 19.000 + 47 151 104 255 Rf -a 94329# 181# 7382# 1# B- -5265# 336# 255 101267# 194# + 45 150 105 255 Db -a 99595# 283# 7359# 1# B- * 255 106919# 304# +0 60 158 98 256 Cf -a 87041# 314# 7432# 1# B- -144# 330# 256 093442# 338# + 58 157 99 256 Es + 87185# 100# 7428# 0# B- 1700# 100# 256 093597# 107# + 56 156 100 256 Fm -a 85484.796 3.020 7431.7888 0.0118 B- -1971# 124# 256 091771.699 3.241 + 54 155 101 256 Md IT 87456# 124# 7421# 0# B- -367# 124# 256 093888# 133# + 52 154 102 256 No -a 87823.046 7.548 7416.5429 0.0295 B- -3923.5573 83.2459 256 094281.912 8.103 + 50 153 103 256 Lr x 91746.603 82.903 7398.1605 0.3238 B- -2475.3893 84.8025 256 098494.024 89.000 + 48 152 104 256 Rf -a 94221.992 17.848 7385.4349 0.0697 B- -6076# 188# 256 101151.464 19.160 + 46 151 105 256 Db -a 100298# 187# 7359# 1# B- * 256 107674# 201# +0 59 158 99 257 Es -a 89403# 411# 7422# 2# B- 813# 411# 257 095979# 441# + 57 157 100 257 Fm -a 88590.137 4.350 7422.1942 0.0169 B- -402.3347 4.5748 257 095105.419 4.669 + 55 156 101 257 Md -a 88992.472 1.569 7417.5845 0.0061 B- -1254.5923 6.1695 257 095537.343 1.683 + 53 155 102 257 No -a 90247.064 6.197 7409.6587 0.0241 B- -2418# 45# 257 096884.203 6.652 + 51 154 103 257 Lr -a 92665# 44# 7397# 0# B- -3201# 45# 257 099480# 47# + 49 153 104 257 Rf -a 95866.389 10.817 7381.7053 0.0421 B- -4287.8969 164.9888 257 102916.796 11.612 + 47 152 105 257 Db 100154.285 164.634 7361.9767 0.6406 B- * 257 107520.042 176.741 +0 60 159 99 258 Es x 92702# 401# 7412# 2# B- 2276# 448# 258 099520# 430# + 58 158 100 258 Fm -a 90426# 200# 7418# 1# B- -1264# 200# 258 097077# 215# + 56 157 101 258 Md -a 91690.350 3.474 7409.6615 0.0135 B- 213# 100# 258 098433.634 3.729 + 54 156 102 258 No -a 91477# 100# 7407# 0# B- -3304# 143# 258 098205# 107# + 52 155 103 258 Lr -a 94782# 102# 7392# 0# B- -1562# 103# 258 101753# 109# + 50 154 104 258 Rf -a 96344.338 16.104 7382.5257 0.0624 B- -5163.3651 93.2584 258 103429.895 17.288 + 48 153 105 258 Db -a 101507.703 91.857 7359.4803 0.3560 B- -3788# 423# 258 108972.995 98.613 + 46 152 106 258 Sg -a 105296# 413# 7342# 2# B- * 258 113040# 443# +0 59 159 100 259 Fm -a 93704# 283# 7407# 1# B- 140# 300# 259 100596# 304# + 57 158 101 259 Md -a 93564# 101# 7405# 0# B- -515# 101# 259 100445# 108# + 55 157 102 259 No -a 94079.381 6.362 7399.9714 0.0246 B- -1771# 71# 259 100998.364 6.829 + 53 156 103 259 Lr -a 95851# 71# 7390# 0# B- -2516# 101# 259 102900# 76# + 51 155 104 259 Rf -a 98367# 72# 7377# 0# B- -3624# 92# 259 105601# 78# + 49 154 105 259 Db -a 101991.021 56.685 7360.3626 0.2189 B- -4528# 190# 259 109491.859 60.854 + 47 153 106 259 Sg -a 106519# 181# 7340# 1# B- * 259 114353# 194# +0 60 160 100 260 Fm -a 95766# 435# 7402# 2# B- -784# 537# 260 102809# 467# + 58 159 101 260 Md -a 96550# 316# 7396# 1# B- 940# 374# 260 103650# 339# + 56 158 102 260 No -a 95610# 200# 7397# 1# B- -2667# 236# 260 102641# 215# + 54 157 103 260 Lr -a 98277# 125# 7383# 0# B- -871# 236# 260 105504# 134# + 52 156 104 260 Rf -a 99148# 200# 7377# 1# B- -4525# 221# 260 106440# 215# + 50 155 105 260 Db -a 103673# 93# 7357# 0# B- -2875# 95# 260 111297# 100# + 48 154 106 260 Sg -a 106547.495 20.536 7342.5632 0.0790 B- -6576# 197# 260 114383.435 22.045 + 46 153 107 260 Bh -a 113123# 196# 7314# 1# B- * 260 121443# 211# +0 59 160 101 261 Md -a 98578# 509# 7391# 2# B- 123# 547# 261 105828# 546# + 57 159 102 261 No -a 98455# 200# 7388# 1# B- -1102# 283# 261 105696# 215# + 55 158 103 261 Lr -a 99557# 200# 7381# 1# B- -1761# 211# 261 106879# 215# + 53 157 104 261 Rf -a 101318.233 65.663 7371.3858 0.2516 B- -2990# 128# 261 108769.591 70.492 + 51 156 105 261 Db -a 104308# 110# 7357# 0# B- -3697# 112# 261 111979# 118# + 49 155 106 261 Sg -a 108005.004 18.494 7339.7710 0.0709 B- -5074.4052 180.7519 261 115948.135 19.853 + 47 154 107 261 Bh -a 113079.410 179.803 7317.3313 0.6889 B- * 261 121395.733 193.026 +0 60 161 101 262 Md -a 101667# 448# 7382# 2# B- 1566# 575# 262 109144# 481# + 58 160 102 262 No -a 100101# 361# 7385# 1# B- -2004# 412# 262 107463# 387# + 56 159 103 262 Lr -a 102105# 200# 7374# 1# B- -287# 300# 262 109615# 215# + 54 158 104 262 Rf -a 102392# 224# 7370# 1# B- -3861# 265# 262 109923# 240# + 52 157 105 262 Db -a 106253# 143# 7352# 1# B- -2116# 145# 262 114067# 154# + 50 156 106 262 Sg -a 108369.072 22.167 7341.1736 0.0846 B- -5883.0463 95.6774 262 116338.978 23.797 + 48 155 107 262 Bh -a 114252.119 93.074 7315.7331 0.3552 B- * 262 122654.688 99.919 +0 59 161 102 263 No -a 103129# 490# 7376# 2# B- -540# 539# 263 110714# 526# + 57 160 103 263 Lr -a 103669# 224# 7371# 1# B- -1087# 271# 263 111293# 240# + 55 159 104 263 Rf -a 104757# 153# 7364# 1# B- -2353# 227# 263 112461# 164# + 53 158 105 263 Db -a 107110# 168# 7352# 1# B- -3085# 193# 263 114987# 180# + 51 157 106 263 Sg -a 110195# 95# 7337# 0# B- -4301# 320# 263 118299# 101# + 49 156 107 263 Bh -a 114496# 305# 7318# 1# B- -5182# 363# 263 122916# 328# + 47 155 108 263 Hs -a 119678# 197# 7295# 1# B- * 263 128479# 212# +0 60 162 102 264 No -a 105011# 591# 7371# 2# B- -1364# 734# 264 112734# 634# + 58 161 103 264 Lr -a 106375# 436# 7363# 2# B- 300# 566# 264 114198# 468# + 56 160 104 264 Rf -a 106075# 361# 7361# 1# B- -3187# 431# 264 113876# 387# + 54 159 105 264 Db -a 109262# 236# 7346# 1# B- -1521# 368# 264 117297# 253# + 52 158 106 264 Sg -a 110783# 283# 7338# 1# B- -5175# 334# 264 118930# 304# + 50 157 107 264 Bh -a 115958# 177# 7315# 1# B- -3605# 180# 264 124486# 190# + 48 156 108 264 Hs -a 119563.165 28.881 7298.3762 0.1094 B- * 264 128356.330 31.005 +0 59 162 103 265 Lr -a 108233# 547# 7359# 2# B- -457# 655# 265 116193# 587# + 57 161 104 265 Rf -a 108690# 361# 7354# 1# B- -1692# 424# 265 116683# 387# + 55 160 105 265 Db -a 110382# 224# 7345# 1# B- -2412# 263# 265 118500# 240# + 53 159 106 265 Sg -a 112794# 139# 7333# 1# B- -3601# 277# 265 121089# 149# + 51 158 107 265 Bh -a 116395# 239# 7316# 1# B- -4505# 240# 265 124955# 257# + 49 157 108 265 Hs -a 120900.245 23.958 7296.2474 0.0904 B- -5724# 439# 265 129791.744 25.719 + 47 156 109 265 Mt -a 126624# 439# 7272# 2# B- * 265 135937# 471# +0 60 163 103 266 Lr -a 111662# 539# 7349# 2# B- 1526# 679# 266 119874# 579# + 58 162 104 266 Rf -a 110136# 412# 7351# 2# B- -2604# 500# 266 118236# 443# + 56 161 105 266 Db -a 112740# 283# 7339# 1# B- -877# 374# 266 121032# 304# + 54 160 106 266 Sg -a 113617# 245# 7332# 1# B- -4487# 294# 266 121973# 263# + 52 159 107 266 Bh -a 118104# 163# 7313# 1# B- -3036# 165# 266 126790# 175# + 50 158 108 266 Hs -a 121139.675 27.106 7298.2611 0.1019 B- -6533.0066 100.2087 266 130048.783 29.099 + 48 157 109 266 Mt -a 127672.681 96.473 7270.7598 0.3627 B- * 266 137062.253 103.568 +0 59 163 104 267 Rf -a 113444# 575# 7342# 2# B- -570# 686# 267 121787# 617# + 57 162 105 267 Db -a 114014# 374# 7337# 1# B- -1792# 457# 267 122399# 402# + 55 161 106 267 Sg -a 115806# 261# 7327# 1# B- -2958# 371# 267 124323# 281# + 53 160 107 267 Bh -a 118765# 263# 7313# 1# B- -3893# 279# 267 127499# 282# + 51 159 108 267 Hs -a 122658# 95# 7295# 0# B- -5133# 512# 267 131678# 102# + 49 158 109 267 Mt -a 127791# 503# 7273# 2# B- -6089# 543# 267 137189# 540# + 47 157 110 267 Ds -a 133880# 204# 7248# 1# B- * 267 143726# 219# +0 60 164 104 268 Rf -a 115476# 662# 7337# 2# B- -1584# 848# 268 123968# 711# + 58 163 105 268 Db -a 117060# 529# 7328# 2# B- 260# 707# 268 125669# 568# + 56 162 106 268 Sg -a 116800# 469# 7326# 2# B- -3907# 605# 268 125389# 504# + 54 161 107 268 Bh -a 120707# 382# 7309# 1# B- -2261# 486# 268 129584# 410# + 52 160 108 268 Hs -a 122968# 300# 7297# 1# B- -6183# 380# 268 132011# 322# + 50 159 109 268 Mt -a 129151# 233# 7271# 1# B- -4497# 381# 268 138649# 250# + 48 158 110 268 Ds -a 133648# 301# 7252# 1# B- * 268 143477# 324# +0 59 164 105 269 Db -a 119148# 624# 7323# 2# B- -544# 724# 269 127911# 669# + 57 163 106 269 Sg -a 119692# 368# 7318# 1# B- -1785# 525# 269 128495# 395# + 55 162 107 269 Bh -a 121477# 374# 7309# 1# B- -3016# 396# 269 130411# 402# + 53 161 108 269 Hs -a 124493# 131# 7294# 0# B- -4807# 338# 269 133649# 141# + 51 160 109 269 Mt -a 129300# 312# 7274# 1# B- -5535# 313# 269 138809# 335# + 49 159 110 269 Ds -a 134834.671 31.403 7250.1551 0.1167 B- * 269 144750.965 33.712 +0 60 165 105 270 Db -a 122397# 575# 7314# 2# B- 966# 735# 270 131399# 617# + 58 164 106 270 Sg -a 121431# 458# 7314# 2# B- -2799# 547# 270 130362# 492# + 56 163 107 270 Bh -a 124230# 299# 7301# 1# B- -882# 388# 270 133366# 320# + 54 162 108 270 Hs -a 125112# 248# 7295# 1# B- -5597# 313# 270 134313# 266# + 52 161 109 270 Mt -a 130709# 191# 7271# 1# B- -3973# 195# 270 140322# 205# + 50 160 110 270 Ds -a 134681.584 39.275 7253.7634 0.1455 B- * 270 144586.620 42.163 +0 59 165 106 271 Sg -a 124617# 591# 7305# 2# B- -1242# 705# 271 133782# 634# + 57 164 107 271 Bh -a 125859# 384# 7298# 1# B- -1832# 473# 271 135115# 412# + 55 163 108 271 Hs -a 127691# 276# 7288# 1# B- -3409# 430# 271 137082# 296# + 53 162 109 271 Mt -a 131100# 330# 7273# 1# B- -4853# 344# 271 140741# 354# + 51 161 110 271 Ds -a 135952# 97# 7252# 0# B- * 271 145951# 104# +0 60 166 106 272 Sg -a 126520# 692# 7301# 3# B- -2267# 873# 272 135825# 743# + 58 165 107 272 Bh -a 128787# 532# 7290# 2# B- -217# 737# 272 138259# 571# + 56 164 108 272 Hs -a 129004# 510# 7286# 2# B- -4477# 704# 272 138492# 547# + 54 163 109 272 Mt -a 133481# 485# 7267# 2# B- -2601# 645# 272 143298# 521# + 52 162 110 272 Ds -a 136083# 424# 7255# 2# B- -6690# 484# 272 146091# 456# + 50 161 111 272 Rg -a 142773# 233# 7227# 1# B- * 272 153273# 251# +0 61 167 106 273 Sg x 129920# 400# 7292# 1# B- -763# 767# 273 139475# 429# + 59 166 107 273 Bh -a 130683# 655# 7286# 2# B- -1084# 754# 273 140294# 703# + 57 165 108 273 Hs -a 131767# 374# 7279# 1# B- -3015# 565# 273 141458# 401# + 55 164 109 273 Mt -a 134782# 424# 7265# 2# B- -3503# 447# 273 144695# 455# + 53 163 110 273 Ds -a 138285# 142# 7250# 1# B- -4600# 424# 273 148455# 152# + 51 162 111 273 Rg -a 142885# 400# 7230# 1# B- * 273 153393# 429# +0 60 167 107 274 Bh -a 133762# 578# 7278# 2# B- 356# 744# 274 143599# 620# + 58 166 108 274 Hs -a 133406# 469# 7276# 2# B- -3843# 602# 274 143217# 504# + 56 165 109 274 Mt -a 137249# 377# 7259# 1# B- -1948# 542# 274 147343# 404# + 54 164 110 274 Ds -a 139197# 389# 7249# 1# B- -5415# 442# 274 149434# 418# + 52 163 111 274 Rg -a 144612# 209# 7227# 1# B- * 274 155247# 225# +0 61 168 107 275 Bh x 135780# 600# 7273# 2# B- -712# 844# 275 145766# 644# + 59 167 108 275 Hs -a 136492# 593# 7268# 2# B- -2275# 709# 275 146530# 637# + 57 166 109 275 Mt -a 138767# 387# 7257# 1# B- -2899# 516# 275 148972# 416# + 55 165 110 275 Ds -a 141666# 340# 7243# 1# B- -3729# 561# 275 152085# 366# + 53 164 111 275 Rg -a 145395# 446# 7227# 2# B- * 275 156088# 479# +0 62 169 107 276 Bh x 138950# 600# 7265# 2# B- 765# 937# 276 149169# 644# + 60 168 108 276 Hs -a 138185# 720# 7265# 3# B- -3127# 895# 276 148348# 773# + 58 167 109 276 Mt -a 141312# 532# 7250# 2# B- -1227# 764# 276 151705# 571# + 56 166 110 276 Ds -a 142539# 548# 7243# 2# B- -4847# 834# 276 153022# 588# + 54 165 111 276 Rg -a 147386# 629# 7223# 2# B- -2974# 804# 276 158226# 675# + 52 164 112 276 Cn x 150360# 500# 7209# 2# B- * 276 161418# 537# +0 63 170 107 277 Bh x 141100# 600# 7260# 2# B- -275# 748# 277 151477# 644# + 61 169 108 277 Hs -a 141375# 447# 7256# 2# B- -1633# 799# 277 151772# 480# + 59 168 109 277 Mt -a 143008# 662# 7247# 2# B- -2084# 770# 277 153525# 711# + 57 167 110 277 Ds -a 145092# 392# 7237# 1# B- -3315# 611# 277 155763# 421# + 55 166 111 277 Rg -a 148407# 469# 7222# 2# B- -3925# 493# 277 159322# 504# + 53 165 112 277 Cn -a 152332# 153# 7205# 1# B- * 277 163535# 165# +0 64 171 107 278 Bh x 144370# 400# 7251# 1# B- 1150# 500# 278 154988# 429# + 62 170 108 278 Hs x 143220# 300# 7252# 1# B- -2547# 652# 278 153753# 322# + 60 169 109 278 Mt -a 145767# 579# 7240# 2# B- -484# 771# 278 156487# 621# + 58 168 110 278 Ds -a 146251# 510# 7236# 2# B- -4270# 641# 278 157007# 548# + 56 167 111 278 Rg -a 150521# 389# 7218# 1# B- -2321# 585# 278 161590# 417# + 54 166 112 278 Cn -a 152842# 438# 7206# 2# B- -6188# 491# 278 164083# 470# + 52 165 113 278 Nh -a 159030# 224# 7181# 1# B- * 278 170725# 240# +0 63 171 108 279 Hs x 146500# 600# 7243# 2# B- -1085# 900# 279 157274# 644# + 61 170 109 279 Mt -a 147585# 671# 7237# 2# B- -1439# 903# 279 158439# 720# + 59 169 110 279 Ds -a 149024# 605# 7229# 2# B- -2697# 737# 279 159984# 649# + 57 168 111 279 Rg -a 151721# 422# 7216# 2# B- -3299# 578# 279 162880# 453# + 55 167 112 279 Cn -a 155021# 395# 7202# 1# B- -4439# 718# 279 166422# 424# + 53 166 113 279 Nh x 159460# 600# 7183# 2# B- * 279 171187# 644# +0 64 172 108 280 Hs x 148420# 600# 7239# 2# B- -2090# 848# 280 159335# 644# + 62 171 109 280 Mt x 150510# 600# 7229# 2# B- 190# 958# 280 161579# 644# + 60 170 110 280 Ds -a 150320# 748# 7227# 3# B- -3566# 918# 280 161375# 803# + 58 169 111 280 Rg -a 153886# 532# 7212# 2# B- -1768# 789# 280 165204# 571# + 56 168 112 280 Cn -a 155654# 583# 7202# 2# B- -5585# 707# 280 167102# 626# + 54 167 113 280 Nh x 161240# 400# 7180# 1# B- * 280 173098# 429# +0 63 172 109 281 Mt x 152400# 600# 7225# 2# B- -873# 776# 281 163608# 644# + 61 171 110 281 Ds -a 153273# 493# 7220# 2# B- -2060# 918# 281 164545# 529# + 59 170 111 281 Rg -a 155333# 774# 7209# 3# B- -2614# 870# 281 166757# 831# + 57 169 112 281 Cn -a 157947# 397# 7197# 1# B- -3863# 498# 281 169563# 427# + 55 168 113 281 Nh x 161810# 300# 7181# 1# B- * 281 173710# 322# +0 64 173 109 282 Mt -a 155455# 447# 7218# 2# B- 665# 538# 282 166888# 480# + 62 172 110 282 Ds x 154790# 300# 7217# 1# B- -2952# 660# 282 166174# 322# + 60 171 111 282 Rg -a 157742# 588# 7204# 2# B- -1084# 804# 282 169343# 631# + 58 170 112 282 Cn -a 158826# 548# 7197# 2# B- -4903# 678# 282 170507# 588# + 56 169 113 282 Nh -a 163729# 400# 7177# 1# B- * 282 175770# 430# +0 63 173 110 283 Ds x 157830# 500# 7210# 2# B- -1550# 843# 283 169437# 537# + 61 172 111 283 Rg -a 159380# 678# 7201# 2# B- -1957# 916# 283 171101# 728# + 59 171 112 283 Cn -a 161337# 615# 7192# 2# B- -3226# 754# 283 173202# 660# + 57 170 113 283 Nh -a 164563# 437# 7177# 2# B- * 283 176666# 469# +0 64 174 110 284 Ds x 159460# 500# 7207# 2# B- -2510# 707# 284 171187# 537# + 62 173 111 284 Rg x 161970# 500# 7195# 2# B- -445# 912# 284 173882# 537# + 60 172 112 284 Cn -a 162415# 762# 7191# 3# B- -4176# 931# 284 174360# 819# + 58 171 113 284 Nh -a 166591# 533# 7173# 2# B- -2188# 845# 284 178843# 573# + 56 170 114 284 Fl -a 168779# 656# 7163# 2# B- * 284 181192# 704# +0 63 174 111 285 Rg x 163730# 600# 7192# 2# B- -1357# 785# 285 175771# 644# + 61 173 112 285 Cn -a 165086# 507# 7185# 2# B- -2682# 926# 285 177227# 544# + 59 172 113 285 Nh -a 167768# 775# 7172# 3# B- -3164# 874# 285 180106# 832# + 57 171 114 285 Fl -a 170932# 404# 7159# 1# B- * 285 183503# 433# +0 64 175 111 286 Rg -a 166510# 458# 7185# 2# B- 61# 836# 286 178756# 492# + 62 174 112 286 Cn x 166450# 700# 7183# 2# B- -3507# 915# 286 178691# 751# + 60 173 113 286 Nh -a 169957# 590# 7168# 2# B- -1649# 806# 286 182456# 634# + 58 172 114 286 Fl -a 171606# 549# 7159# 2# B- * 286 184226# 590# +0 63 175 112 287 Cn x 169370# 700# 7176# 2# B- -2085# 995# 287 181826# 751# + 61 174 113 287 Nh -a 171455# 707# 7166# 2# B- -2474# 939# 287 184064# 759# + 59 173 114 287 Fl -a 173929# 617# 7155# 2# B- -3819# 759# 287 186720# 663# + 57 172 115 287 Mc -a 177748# 443# 7139# 2# B- * 287 190820# 475# +0 64 176 112 288 Cn x 170930# 700# 7174# 2# B- -3039# 989# 288 183501# 751# + 62 175 113 288 Nh x 173970# 700# 7160# 2# B- -947# 1035# 288 186764# 751# + 60 174 114 288 Fl -a 174917# 763# 7154# 3# B- -4749# 932# 288 187781# 819# + 58 173 115 288 Mc -a 179666# 536# 7135# 2# B- * 288 192879# 575# +0 63 176 113 289 Nh x 175550# 500# 7158# 2# B- -1915# 715# 289 188461# 537# + 61 175 114 289 Fl -a 177465# 511# 7149# 2# B- -3217# 929# 289 190517# 548# + 59 174 115 289 Mc -a 180683# 776# 7135# 3# B- -3774# 925# 289 193971# 834# + 57 173 116 289 Lv -a 184457# 503# 7119# 2# B- * 289 198023# 540# +0 64 177 113 290 Nh -a 178315# 469# 7152# 2# B- -416# 843# 290 191429# 503# + 62 176 114 290 Fl -a 178731# 700# 7147# 2# B- -4061# 917# 290 191875# 752# + 60 175 115 290 Mc -a 182792# 592# 7131# 2# B- -2236# 809# 290 196235# 635# + 58 174 116 290 Lv -a 185028# 552# 7120# 2# B- * 290 198635# 593# +0 63 177 114 291 Fl x 181500# 700# 7141# 2# B- -2680# 1015# 291 194848# 751# + 61 176 115 291 Mc -a 184180# 735# 7129# 3# B- -3064# 964# 291 197725# 789# + 59 175 116 291 Lv -a 187244# 623# 7116# 2# B- -4409# 863# 291 201014# 669# + 57 174 117 291 Ts -a 191653# 597# 7098# 2# B- * 291 205748# 640# +0 62 177 115 292 Mc x 186600# 700# 7124# 2# B- -1533# 1035# 292 200323# 751# + 60 176 116 292 Lv -a 188133# 763# 7116# 3# B- -5488# 1014# 292 201969# 819# + 58 175 117 292 Ts -a 193621# 669# 7095# 2# B- * 292 207861# 718# +0 61 177 116 293 Lv -a 190568# 515# 7111# 2# B- -3860# 933# 293 204583# 553# + 59 176 117 293 Ts -a 194428# 778# 7095# 3# B- -4374# 1053# 293 208727# 835# + 57 175 118 293 Og -a 198802# 709# 7078# 2# B- * 293 213423# 761# +0 60 177 117 294 Ts -a 196397# 593# 7092# 2# B- -2923# 811# 294 210840# 637# + 58 176 118 294 Og -a 199320# 553# 7079# 2# B- * 294 213979# 594# +0 59 177 118 295 Og -a 201369# 655# 7076# 2# B- * 295 216178# 703# From 2f95966b0a5e2fd71abfbe8b27b296beeb9e80f8 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 13:49:56 +0000 Subject: [PATCH 14/98] Made the decorator in neutronics.py follow the open-closed principle for ease of maintenace; added tests. --- process/neutronics.py | 284 ++++++++++++++++++++-------------- process/neutronics_data.py | 14 +- tests/unit/test_neutronics.py | 85 +++++++--- 3 files changed, 239 insertions(+), 144 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index d6262e87f5..003d3f52f3 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -4,38 +4,46 @@ """ import functools +import inspect import numpy as np -from neutronics_data import MaterialMacroInfo from numpy import typing as npt from scipy.special import expm1 from process.exceptions import ProcessValidationError +from process.neutronics_data import MaterialMacroInfo -def groupwise(func): - """Rename the current func as groupwise_func, and over-write the current method - as one that sums up all group-wise func. +def summarize_values(func): """ - method_name = func.__name__ - groupwise_name = f"groupwise_{method_name}" + Keep groupwise_func unchanged, but create a new method under a similar name + (but with the prefix "groupwise_" removed) which outputs the sum of every + groupwise value. + """ + summary_method_name = func.__name__[10:] + # confirm this is a groupwise method + func_params = inspect.signature(func).parameters + if not (func.__name__.startswith("groupwise_") and "n" in func_params): + raise ValueError( + "The decorated method is designed to turn groupwise methods into " + "summed flux/reaction/current methods." + ) @functools.wraps(func) def wrapper(self, *args, **kwargs): - groupwise_func = getattr(self, groupwise_name) - return np.array( - [ - groupwise_func(n, *args, **kwargs) - for n in range(1, self.n_groups + 1) - ], + groupwise_func = getattr(self, func.__name__) + return np.sum( + [groupwise_func(n, *args, **kwargs) for n in range(self.n_groups)], + axis=0, ) def wrapper_setattr(cls): - """Save the decorated (groupwise) function under a different name after it has - been created, then overwrite the current method with the np.sum implementation. """ - setattr(cls, groupwise_name, func) - setattr(cls, method_name, wrapper) + Attach the method that outputs the summed values of all of the + groupwise values to the same parent class. + """ + setattr(cls, func.__name__, func) + setattr(cls, summary_method_name, wrapper) return cls # Instead of returning a function, we return a descriptor that registers itself later @@ -133,7 +141,7 @@ def __init__( x_fw: thickness of the first wall [m]. It will be converted and stored in [cm]. x_bz: - thickness of the blanket [m]. It will be converted and stored in [cm]. + thickness of the blanket + first-wall [m]. It will be converted and stored in [cm]. fw_mat: first wall material information bz_mat: @@ -141,10 +149,10 @@ def __init__( Attributes ---------- - x_fw: + x_fw_cm: thickness of the first wall, converted from [m] into [cm]. - x_bz: - thickness of the blanket, converted from [m] into [cm]. + x_bz_cm: + thickness of the blanket + first-wall, converted from [m] into [cm]. n_groups: number of groups in the group structure group_structure: @@ -155,14 +163,16 @@ def __init__( raise ValueError( f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." ) - self.x_fw = x_fw * 100 - self.x_bz = x_bz * 100 + self.x_fw_cm = x_fw * 100 + self.x_bz_cm = x_bz * 100 self.fw_mat = fw_mat self.bz_mat = bz_mat self.n_groups = self.fw_mat.n_groups self.group_structure = self.fw_mat.group_structure - if not np.isclose( - self.fw_mat.group_structure, self.bz_mat.group_structure + if not np.allclose( + self.fw_mat.group_structure, + self.bz_mat.group_structure, + atol=0, ): raise ProcessValidationError( "The first-wall material info and breeding zone material info" @@ -182,24 +192,24 @@ def solve_lowest_group(self) -> None: Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], self.l_bz_2[0], and self.integration_constants[0]. """ - i = 0 - if i in self.integration_constants: + n = 0 + if n in self.integration_constants: return # skip if it has already been solved. - self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( - self.fw_mat.sigma_t[i], - self.fw_mat.sigma_s[i, i], + self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( + self.fw_mat.sigma_t[n], + self.fw_mat.sigma_s[n, n], self.fw_mat.avg_atomic_mass, ) - self.l_bz_2[i], d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[i], - self.bz_mat.sigma_s[i, i], + self.l_bz_2[n], d_bz = get_diffusion_coefficient_and_length( + self.bz_mat.sigma_t[n], + self.bz_mat.sigma_s[n, n], self.bz_mat.avg_atomic_mass, ) - l_fw = np.sqrt(abs(self.l_fw_2[i])) - l_bz = np.sqrt(abs(self.l_bz_2[i])) - x_fw, x_bz = self.x_fw, self.x_bz - self.extended_boundary[i] = x_bz + extrapolation_length(d_bz) - if self.l_fw_2[i] > 0: + l_fw = np.sqrt(abs(self.l_fw_2[n])) + l_bz = np.sqrt(abs(self.l_bz_2[n])) + x_fw, x_bz = self.x_fw_cm, self.x_bz_cm + self.extended_boundary[n] = x_bz + extrapolation_length(d_bz) + if self.l_fw_2[n] > 0: sinh_fw = np.sinh(x_fw / l_fw) cosh_fw = np.cosh(x_fw / l_fw) tanh_fw = np.tanh(x_fw / l_fw) @@ -207,14 +217,14 @@ def solve_lowest_group(self) -> None: sinh_fw = np.sin(x_fw / l_fw) cosh_fw = np.cos(x_fw / l_fw) tanh_fw = np.tan(x_fw / l_fw) - if self.l_bz_2[i] > 0: - sinh_bz = np.sinh((self.extended_boundary[i] - x_fw) / l_bz) - cosh_bz = np.cosh((self.extended_boundary[i] - x_fw) / l_bz) - tanh_bz = np.tanh((self.extended_boundary[i] - x_fw) / l_bz) + if self.l_bz_2[n] > 0: + sinh_bz = np.sinh((self.extended_boundary[n] - x_fw) / l_bz) + cosh_bz = np.cosh((self.extended_boundary[n] - x_fw) / l_bz) + tanh_bz = np.tanh((self.extended_boundary[n] - x_fw) / l_bz) else: - sinh_bz = np.sin((self.extended_boundary[i] - x_fw) / l_bz) - cosh_bz = np.cos((self.extended_boundary[i] - x_fw) / l_bz) - tanh_bz = np.tan((self.extended_boundary[i] - x_fw) / l_bz) + sinh_bz = np.sin((self.extended_boundary[n] - x_fw) / l_bz) + cosh_bz = np.cos((self.extended_boundary[n] - x_fw) / l_bz) + tanh_bz = np.tan((self.extended_boundary[n] - x_fw) / l_bz) c2 = ( self.flux @@ -232,64 +242,64 @@ def solve_lowest_group(self) -> None: * (1 - tanh_fw) / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) ) - c3 = c3_c4_common_factor * np.exp(self.extended_boundary[i] / l_bz) - c4 = -c3_c4_common_factor * np.exp(-self.extended_boundary[i] / l_bz) - self.integration_constants[i] = [c1, c2, c3, c4] + c3 = c3_c4_common_factor * np.exp(self.extended_boundary[n] / l_bz) + c4 = -c3_c4_common_factor * np.exp(-self.extended_boundary[n] / l_bz) + self.integration_constants[n] = [c1, c2, c3, c4] def solve_group_n(self, n: int) -> None: """ - Solve the n-th group of neutron's diffusion equation. + Solve the n-th group of neutron's diffusion equation, where n<=n_groups-1. Store the solved constants in self.extended_boundary[n-1], self.l_fw_2[n-1], self.l_bz_2[n-1], and self.integration_constants[n-1]. Parameters ---------- n: - The index of the neutron group whose constants are being solved. - allowed range: [1, self.n_groups] - This gets translated to the index i=n-1 used for the dictionaries of - constants attached to self. + The index of the neutron group whose constants are being solved. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. """ - if n not in range(1, self.n_groups): + if n not in range(self.n_groups): raise ValueError( f"n must be a positive integer between 1 and {self.n_groups}!" ) - if n == 1: + if n == 0: return self.solve_lowest_group() - for k in range(n - 1): + for k in range(n): if k not in self.integration_constants: self.solve_group_n(k) - i = n - 1 - if i in self.integration_constants: + if n in self.integration_constants: return None # skip if it has already been solved. - self.l_fw_2[i], d_fw = get_diffusion_coefficient_and_length( - self.fw_mat.sigma_t[i], - self.fw_mat.sigma_s[i, i], + self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( + self.fw_mat.sigma_t[n], + self.fw_mat.sigma_s[n, n], self.fw_mat.avg_atomic_mass, ) - self.l_bz_2[i], d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[i], - self.bz_mat.sigma_s[i, i], + self.l_bz_2[n], d_bz = get_diffusion_coefficient_and_length( + self.bz_mat.sigma_t[n], + self.bz_mat.sigma_s[n, n], self.bz_mat.avg_atomic_mass, ) - l_fw = np.sqrt(abs(self.l_fw_2[i])) - l_bz = np.sqrt(abs(self.l_bz_2[i])) + l_fw = np.sqrt(abs(self.l_fw_2[n])) + l_bz = np.sqrt(abs(self.l_bz_2[n])) c1 = ... c2 = ... c3 = ... c4 = ... - self.extended_boundary[i] = self.x_bz + extrapolation_length(d_bz) - self.integration_constants[i] = [c1, c2, c3, c4] + self.extended_boundary[n] = self.x_bz_cm + extrapolation_length(d_bz) + self.integration_constants[n] = [c1, c2, c3, c4] return None - @groupwise - def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: + @summarize_values + def groupwise_neutron_flux_fw( + self, n: int, x: float | npt.NDArray + ) -> npt.NDArray: """Neutron flux of the n-th group at the first wall, at location x [m]. Parameters ---------- n: - The index of the neutron group whose flux is being evaluated. + The index of the neutron group whose flux is being evaluated. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. x: The position where the neutron flux has to be evaluated. Note that this function does not enforce a check for x=inside the first-wall, @@ -302,20 +312,22 @@ def neutron_flux_fw(self, n: int, x: float | npt.NDArray) -> npt.NDArray: flux: Neutron flux at x meter from the first wall. """ - i = n - 1 - c1, c2 = self.integration_constants[i][:2] - l_fw = np.sqrt(abs(self.l_fw_2[i])) + c1, c2 = self.integration_constants[n][:2] + l_fw = np.sqrt(abs(self.l_fw_2[n])) x_l_fw = abs(x) / l_fw return c1 * np.exp(x_l_fw) + c2 * np.exp(-x_l_fw) - @groupwise - def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: + @summarize_values + def groupwise_neutron_flux_bz( + self, n: int, x: float | npt.NDArray + ) -> npt.NDArray: """Neutron flux of the n-th groupat the blanket, at location x [m]. Parameters ---------- n: - The index of the neutron group whose flux is being evaluated. + The index of the neutron group whose flux is being evaluated. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. x: The position where the neutron flux has to be evaluated. [m] Note that this function does not enforce a check for x=inside the blanket, @@ -328,22 +340,24 @@ def neutron_flux_bz(self, n: int, x: float | npt.NDArray) -> npt.NDArray: flux: Neutron flux at x meter from the first wall. """ - i = n - 1 - c3, c4 = self.integration_constants[i][2:] - l_bz = np.sqrt(abs(self.l_bz_2[i])) + c3, c4 = self.integration_constants[n][2:] + l_bz = np.sqrt(abs(self.l_bz_2[n])) x_l_bz = abs(x) / l_bz return c3 * np.exp(x_l_bz) + c4 * np.exp(-x_l_bz) - @groupwise - def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: + @summarize_values + def groupwise_neutron_flux_at( + self, n: int, x: float | npt.NDArray + ) -> npt.NDArray: """ Neutron flux anywhere within the valid range of x, - i.e. from -self.x_bz to self.x_bz. + i.e. from -self.x_bz_cm to self.x_bz_cm. Parameters ---------- n: - Neutron group number + Neutron group index. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. x: The depth where we want the neutron flux (m). Valid only between x= -extended boundary to +-extended boundary of that group @@ -356,8 +370,8 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] x = np.asarray(x) - in_fw = abs(x) <= self.x_fw - in_bz = np.logical_and(self.x_fw < abs(x), abs(x) <= self.x_bz) + in_fw = abs(x) <= self.x_fw_cm + in_bz = np.logical_and(self.x_fw_cm < abs(x), abs(x) <= self.x_bz_cm) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated up to " @@ -370,98 +384,128 @@ def neutron_flux_at(self, n: int, x: float | npt.NDArray) -> npt.NDArray: return out_flux # scalar values (one or two such floats per neutron group.) - @groupwise - def reaction_rate_fw(self, n: int, reaction_type: str) -> float: + @summarize_values + def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: """Calculate the reaction rate in the first wall. Parameters ---------- n: - The index of the neutron group that needs to be solved. + The index of the neutron group that needs to be solved. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: Two options: "total" or "non-scattering". """ self.solve_group_n(n) - i = n - 1 - l_fw = np.sqrt(abs(self.l_fw_2[i])) - c1, c2, c3, c4 = self.integration_constants[i] + l_fw = np.sqrt(abs(self.l_fw_2[n])) + c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "non-scattering": - sigma = self.fw_mat.sigma_t[i] - self.fw_mat.sigma_s[i, i] + sigma = self.fw_mat.sigma_t[n] - self.fw_mat.sigma_s[n, n] elif reaction_type == "total": - sigma = self.fw_mat.sigma_t[i] + sigma = self.fw_mat.sigma_t[n] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) return sigma * ( - c1 * expm1(self.x_fw / l_fw) - c2 * expm1(-self.x_fw / l_fw) + c1 * expm1(self.x_fw_cm / l_fw) - c2 * expm1(-self.x_fw_cm / l_fw) ) - @groupwise - def reaction_rate_bz(self, n: int, reaction_type: str) -> float: + @summarize_values + def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: """Calculate the reaction rate in the blanket. Parameters ---------- n: - The index of the neutron group that needs to be solved. + The index of the neutron group that needs to be solved. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: Two options: "total" or "non-scattering". """ self.solve_group_n(n) - i = n - 1 - l_bz = np.sqrt(abs(self.l_bz_2[i])) - c1, c2, c3, c4 = self.integration_constants[i] + l_bz = np.sqrt(abs(self.l_bz_2[n])) + c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "non-scattering": - sigma = self.bz_mat.sigma_t[i] - self.bz_mat.sigma_s[i, i] + sigma = self.bz_mat.sigma_t[n] - self.bz_mat.sigma_s[n, n] elif reaction_type == "total": - sigma = self.bz_mat.sigma_t[i] + sigma = self.bz_mat.sigma_t[n] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) # thicknesses in terms of bz path lengths - bz_thick = (self.x_bz - self.x_fw) / l_bz - fw_thick = self.x_fw / l_bz + bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz + fw_thick = self.x_fw_cm / l_bz return sigma * ( c3 * np.exp(fw_thick) * expm1(bz_thick) - c4 * np.exp(-fw_thick) * expm1(-bz_thick) ) - @groupwise - def flux_fw2bz(self, n: int) -> float: + @summarize_values + def groupwise_current_fw2bz(self, n: int) -> float: + """ + Net current from the first wall to breeding zone. + Parameters + ---------- + n: + The index of the neutron group that we want the current for. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + + Returns + ------- + : + current in cm^-2 + """ self.solve_group_n(n) - i = n - 1 - c1, c2, c3, c4 = self.integration_constants[i] + c1, c2, c3, c4 = self.integration_constants[n] l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[i], - self.bz_mat.sigma_s[i, i], + self.bz_mat.sigma_t[n], + self.bz_mat.sigma_s[n, n], self.bz_mat.avg_atomic_mass, ) l_bz = np.sqrt(abs(l_bz_2)) return ( -d_bz / l_bz - * (c3 * np.exp(self.x_fw / l_bz) - c4 * np.exp(-self.x_fw / l_bz)) + * ( + c3 * np.exp(self.x_fw_cm / l_bz) + - c4 * np.exp(-self.x_fw_cm / l_bz) + ) ) # equivalent definition below: (should yield the same answer) - # self.flux_fw2bz[i] = - d_fw / l_fw * (c1 * np.exp(x_fw/l_fw) - c2 * np.exp(-x_fw/l_fw)) + # return - d_fw / l_fw * (c1 * np.exp(x_fw/l_fw) - c2 * np.exp(-x_fw/l_fw)) + + @summarize_values + def groupwise_current_escaped(self, n: int) -> float: + """ + Neutron current escaped from the breeding zone to outside the reactor. + Parameters + ---------- + n: + The index of the neutron group that we want the current for. n <= n_groups - 1. + Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. - @groupwise - def flux_escaped(self, n: int) -> float: + Returns + ------- + : + current in cm^-2 + """ self.solve_group_n(n) - i = n - 1 - c1, c2, c3, c4 = self.integration_constants[i] + c1, c2, c3, c4 = self.integration_constants[n] l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[i], - self.bz_mat.sigma_s[i, i], + self.bz_mat.sigma_t[n], + self.bz_mat.sigma_s[n, n], self.bz_mat.avg_atomic_mass, ) l_bz = np.sqrt(abs(l_bz_2)) - self.flux_escaped[i] = ( + return ( -d_bz / l_bz - * (c3 * np.exp(self.x_bz / l_bz) - c4 * np.exp(-self.x_bz / l_bz)) + * ( + c3 * np.exp(self.x_bz_cm / l_bz) + - c4 * np.exp(-self.x_bz_cm / l_bz) + ) ) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index a7c29f05f1..5f16c72d28 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -200,7 +200,13 @@ class MaterialMacroInfo: def __post_init__(self): """Validation to confirm the shape is correct.""" - if len(self.sigma_t) != self.n_groups: + # force into float or numpy arrays. + self.sigma_t = np.array(self.sigma_t, dtype=float) + self.sigma_s = np.array(self.sigma_s, dtype=float) + self.group_structure = np.array(self.group_structure, dtype=float) + self.avg_atomic_mass = float(self.avg_atomic_mass) + + if np.shape(self.sigma_t) != (self.n_groups,): raise ProcessValidationError( f"total group-wise cross-sections should have {self.n_groups} " "groups as specified by the group_structure." @@ -210,7 +216,11 @@ def __post_init__(self): "Group-wise scattering cross-sections be a square matrix of " f"shape n*n, where n= number of groups = {self.n_groups}." ) - self.avg_atomic_mass = float(self.avg_atomic_mass) # force into float + if (self.sigma_s.sum(axis=1) > self.sigma_t).any(): + raise ProcessValidationError( + "Each group's scattering cross-section should be smaller than " + "or equal to its total cross-section." + ) @property def n_groups(self): diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 8f41310411..082d9d30c7 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -1,25 +1,66 @@ import pytest +from process.exceptions import ProcessValidationError +from process.neutronics import NeutronFluxProfile +from process.neutronics_data import MaterialMacroInfo + + +def test_scattering_larger_than_total(): + with pytest.raises(ProcessValidationError): + MaterialMacroInfo( + [1.0], + [[2.0]], + [1.0, 2.0], + 1, + ) + + +def test_group_structure_too_short(): + with pytest.raises(ProcessValidationError): + MaterialMacroInfo( + [1.0], + [[1.0]], + [0.0], + 0.1, + ) + + +def test_has_local_fluxes(): + """Test that the groupwise decorator has worked on the local fluxes methods.""" + assert hasattr(NeutronFluxProfile, "neutron_flux_at") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_at") + assert hasattr(NeutronFluxProfile, "neutron_flux_fw") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_fw") + assert hasattr(NeutronFluxProfile, "neutron_flux_bz") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_bz") + + +def test_has_boundary_current(): + """Test that the groupwise decorator has worked on the boundary fluxes methods.""" + assert hasattr(NeutronFluxProfile, "groupwise_current_fw2bz") + assert hasattr(NeutronFluxProfile, "current_fw2bz") + assert hasattr(NeutronFluxProfile, "groupwise_current_escaped") + assert hasattr(NeutronFluxProfile, "current_escaped") + + +def test_has_reactions(): + """Test that the groupwise decorator has worked on the reactions methods.""" + assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_fw") + assert hasattr(NeutronFluxProfile, "reaction_rate_fw") + assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_bz") + assert hasattr(NeutronFluxProfile, "reaction_rate_bz") + + +fw_material = MaterialMacroInfo( + [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 1.0 +) +bz_material = MaterialMacroInfo( + [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 2.0 +) profile = NeutronFluxProfile( - 1.0, #flux - "dummy-FW-mat", - 0.01, #1cm - "dummy-BZ-mat", - 0.11, #10cm thick blanket - n_groups=2, - ) -def test_has_fluxes(): - assert hasattr(profile, "neutron_flux_at") - assert hasattr(profile, "groupwise_neutron_flux_at") - assert hasattr(profile, "neutron_flux_fw") - assert hasattr(profile, "groupwise_neutron_flux_fw") - assert hasattr(profile, "neutron_flux_bz") - assert hasattr(profile, "groupwise_neutron_flux_bz") - -def test_reactions(): - assert hasattr(profile, "groupwise_reaction_rate_fw") - assert hasattr(profile, "reaction_rate_fw") - assert hasattr(profile, "groupwise_reaction_rate_bz") - assert hasattr(profile, "reaction_rate_bz") - assert hasattr(profile, "flux_fw2bz") - assert hasattr(profile, "flux_escaped") \ No newline at end of file + 1.0, # flux + 0.01, # 1cm + 0.11, # 10cm thick blanket + fw_material, + bz_material, +) From 3336c233c10555e64d79bdcd29de05ed774af083 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 14:52:12 +0000 Subject: [PATCH 15/98] made the four attributes: integration_constants, l_fw_2, l_bz_2, extended_boundary, to be self-populating dictionaries (populated by solve_group_n). --- process/neutronics.py | 71 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 003d3f52f3..72fc2fb8aa 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -5,6 +5,7 @@ import functools import inspect +from collections.abc import Callable import numpy as np from numpy import typing as npt @@ -120,6 +121,55 @@ def extrapolation_length(diffusion_coefficient: float) -> float: return 0.7104 * 3 * diffusion_coefficient +class AutoPopulatingDict: + """ + Class that behaves like a dictionary, but if the required key does not + exist in the dictionary, it will call the populating_method to populate + that specific key. + """ + + def __init__(self, populating_method: Callable[[int], None]): + """ + Attributes + ---------- + _dict: + A dictionary indexed by integers, so that we can populate its + values out of sequence. + populating_method: + The method to be called if the requested index n is currently + unpopulated in the dictionary. This method should populate the + dictionary. + """ + self._dict = {} + self._attempting_to_access = [] + self.populating_method = populating_method + + def __getitem__(self, i: int): + """Check if index i is in the dictionary or not. If not, populate it.""" + if i in self._attempting_to_access: + raise RecursionError( + f"retrieving the value of [{i}] requires the value of [{i}]" + ) + if i not in self._dict: + self._attempting_to_access.append(i) + self.populating_method(i) + if i not in self._dict: + raise RuntimeError( + f"{self.populating_method}({i}) failed to populate key {i} " + "in the dictionary!" + ) + self._attempting_to_access.remove(i) + return self._dict[i] + + def __contains__(self, i: int): + """Check if key 'i' is in the dictionary or not.""" + return i in self._dict + + def __setitem__(self, i: int, value: float): + """Check if dict i is in the index or not.""" + self._dict[i] = value + + class NeutronFluxProfile: """Neutron flux in the first wall or the blanket.""" @@ -179,12 +229,11 @@ def __init__( "must have the same group structure!" ) - # macroscopic cross-sections Sigma saved here. - # Dictionaries indexed by integers, so that we can create these values - # out of sequence. - self.integration_constants = {} - self.l_fw_2, self.l_bz_2 = {}, {} # diffusion lengths squared - self.extended_boundary = {} + self.integration_constants = AutoPopulatingDict(self.solve_group_n) + # diffusion lengths squared + self.l_fw_2 = AutoPopulatingDict(self.solve_group_n) + self.l_bz_2 = AutoPopulatingDict(self.solve_group_n) + self.extended_boundary = AutoPopulatingDict(self.solve_group_n) def solve_lowest_group(self) -> None: """ @@ -374,8 +423,8 @@ def groupwise_neutron_flux_at( in_bz = np.logical_and(self.x_fw_cm < abs(x), abs(x) <= self.x_bz_cm) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( - f"for neutron group {n}, neutron flux can only be calculated up to " - f"{self.extended_boundary[n]} cm, which {x * 100} cm violates!" + f"for neutron group {n}, neutron flux can only be calculated " + f"up to {self.x_bz_cm} cm, which {x * 100} cm violates!" ) out_flux = np.zeros_like(x) @@ -383,7 +432,7 @@ def groupwise_neutron_flux_at( out_flux[in_bz] = self.groupwise_neutron_flux_bz(n, x[in_bz]) return out_flux - # scalar values (one or two such floats per neutron group.) + # scalar values (one such float per neutron group.) @summarize_values def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: """Calculate the reaction rate in the first wall. @@ -397,7 +446,6 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: Two options: "total" or "non-scattering". """ - self.solve_group_n(n) l_fw = np.sqrt(abs(self.l_fw_2[n])) c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "non-scattering": @@ -425,7 +473,6 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: Two options: "total" or "non-scattering". """ - self.solve_group_n(n) l_bz = np.sqrt(abs(self.l_bz_2[n])) c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "non-scattering": @@ -459,7 +506,6 @@ def groupwise_current_fw2bz(self, n: int) -> float: : current in cm^-2 """ - self.solve_group_n(n) c1, c2, c3, c4 = self.integration_constants[n] l_bz_2, d_bz = get_diffusion_coefficient_and_length( self.bz_mat.sigma_t[n], @@ -493,7 +539,6 @@ def groupwise_current_escaped(self, n: int) -> float: : current in cm^-2 """ - self.solve_group_n(n) c1, c2, c3, c4 = self.integration_constants[n] l_bz_2, d_bz = get_diffusion_coefficient_and_length( self.bz_mat.sigma_t[n], From 1506730eb39cb178dd0fed27e51a4e6f905bffff Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 15:44:26 +0000 Subject: [PATCH 16/98] Some quality-of-life things - _attempting_to_access attribute is made into a set, allowing index i to be discarded from it at every opportunity without having to check for membership. --- process/neutronics.py | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 72fc2fb8aa..390c4e217a 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -128,7 +128,7 @@ class AutoPopulatingDict: that specific key. """ - def __init__(self, populating_method: Callable[[int], None]): + def __init__(self, populating_method: Callable[[int], None], name: str): """ Attributes ---------- @@ -141,24 +141,26 @@ def __init__(self, populating_method: Callable[[int], None]): dictionary. """ self._dict = {} - self._attempting_to_access = [] + self._name = name + self._attempting_to_access = set() self.populating_method = populating_method def __getitem__(self, i: int): """Check if index i is in the dictionary or not. If not, populate it.""" if i in self._attempting_to_access: raise RecursionError( - f"retrieving the value of [{i}] requires the value of [{i}]" + f"retrieving the value of {self._name}[{i}] requires the " + f"value of {self._name}[{i}]." ) if i not in self._dict: - self._attempting_to_access.append(i) + self._attempting_to_access.add(i) self.populating_method(i) if i not in self._dict: raise RuntimeError( f"{self.populating_method}({i}) failed to populate key {i} " "in the dictionary!" ) - self._attempting_to_access.remove(i) + self._attempting_to_access.discard(i) return self._dict[i] def __contains__(self, i: int): @@ -167,6 +169,7 @@ def __contains__(self, i: int): def __setitem__(self, i: int, value: float): """Check if dict i is in the index or not.""" + self._attempting_to_access.discard(i) self._dict[i] = value @@ -229,11 +232,15 @@ def __init__( "must have the same group structure!" ) - self.integration_constants = AutoPopulatingDict(self.solve_group_n) + self.integration_constants = AutoPopulatingDict( + self.solve_group_n, "integration_constants" + ) # diffusion lengths squared - self.l_fw_2 = AutoPopulatingDict(self.solve_group_n) - self.l_bz_2 = AutoPopulatingDict(self.solve_group_n) - self.extended_boundary = AutoPopulatingDict(self.solve_group_n) + self.l_fw_2 = AutoPopulatingDict(self.solve_group_n, "l_fw_2") + self.l_bz_2 = AutoPopulatingDict(self.solve_group_n, "l_bz_2") + self.extended_boundary = AutoPopulatingDict( + self.solve_group_n, "extended_boundary" + ) def solve_lowest_group(self) -> None: """ @@ -309,7 +316,7 @@ def solve_group_n(self, n: int) -> None: """ if n not in range(self.n_groups): raise ValueError( - f"n must be a positive integer between 1 and {self.n_groups}!" + f"n must be a positive integer between 0 and {self.n_groups}!" ) if n == 0: return self.solve_lowest_group() @@ -408,7 +415,7 @@ def groupwise_neutron_flux_at( Neutron group index. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. x: - The depth where we want the neutron flux (m). + The depth where we want the neutron flux [m]. Valid only between x= -extended boundary to +-extended boundary of that group Raises @@ -418,13 +425,15 @@ def groupwise_neutron_flux_at( """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.asarray(x) + x = np.asarray(x) * 100 in_fw = abs(x) <= self.x_fw_cm - in_bz = np.logical_and(self.x_fw_cm < abs(x), abs(x) <= self.x_bz_cm) + in_bz = np.logical_and( + self.x_fw_cm < abs(x), abs(x) <= self.extended_boundary[n] + ) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated " - f"up to {self.x_bz_cm} cm, which {x * 100} cm violates!" + f"up to {self.extended_boundary[n]} cm, which {x * 100} cm violates!" ) out_flux = np.zeros_like(x) @@ -492,7 +501,7 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: ) @summarize_values - def groupwise_current_fw2bz(self, n: int) -> float: + def groupwise_neutron_current_fw2bz(self, n: int) -> float: """ Net current from the first wall to breeding zone. Parameters @@ -525,7 +534,7 @@ def groupwise_current_fw2bz(self, n: int) -> float: # return - d_fw / l_fw * (c1 * np.exp(x_fw/l_fw) - c2 * np.exp(-x_fw/l_fw)) @summarize_values - def groupwise_current_escaped(self, n: int) -> float: + def groupwise_neutron_current_escaped(self, n: int) -> float: """ Neutron current escaped from the breeding zone to outside the reactor. Parameters From faed908d451c6c15a2ae717638b1f2f2999dd002 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 15:48:15 +0000 Subject: [PATCH 17/98] Keeping test updated. --- tests/unit/test_neutronics.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 082d9d30c7..b1f113965e 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -37,10 +37,10 @@ def test_has_local_fluxes(): def test_has_boundary_current(): """Test that the groupwise decorator has worked on the boundary fluxes methods.""" - assert hasattr(NeutronFluxProfile, "groupwise_current_fw2bz") - assert hasattr(NeutronFluxProfile, "current_fw2bz") - assert hasattr(NeutronFluxProfile, "groupwise_current_escaped") - assert hasattr(NeutronFluxProfile, "current_escaped") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_fw2bz") + assert hasattr(NeutronFluxProfile, "neutron_current_fw2bz") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_escaped") + assert hasattr(NeutronFluxProfile, "neutron_current_escaped") def test_has_reactions(): @@ -51,11 +51,19 @@ def test_has_reactions(): assert hasattr(NeutronFluxProfile, "reaction_rate_bz") +# 2 groups +# fw_material = MaterialMacroInfo( +# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 1.0 +# ) +# bz_material = MaterialMacroInfo( +# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 2.0 +# ) +# 1 group fw_material = MaterialMacroInfo( - [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 1.0 + [1.0], [[0.5]], [0, 100], 1.0 ) bz_material = MaterialMacroInfo( - [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 2.0 + [1.0], [[0.5]], [0, 100], 2.0 ) profile = NeutronFluxProfile( 1.0, # flux From 1c9093d9590aed7abd1c17d6d1b2402e763be61b Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 16:13:03 +0000 Subject: [PATCH 18/98] Corrected the ordering of the group structure to ensure that the first bin = highest energy/lowest lethargy. --- process/neutronics_data.py | 8 ++++++++ tests/unit/test_neutronics.py | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 5f16c72d28..1a9d3db150 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -206,6 +206,14 @@ def __post_init__(self): self.group_structure = np.array(self.group_structure, dtype=float) self.avg_atomic_mass = float(self.avg_atomic_mass) + if np.diff(self.group_structure)>=0: + raise ValueError( + "The group structure must be defined beginning from the highest energy " + "bin (i.e. lowest lethargy bin) edge, descending to the lowest energy. " + "Similarly the cross-section must be arranged with the highest energy " + "group first, and the lowest energy group last." + ) + if np.shape(self.sigma_t) != (self.n_groups,): raise ProcessValidationError( f"total group-wise cross-sections should have {self.n_groups} " diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index b1f113965e..f5f997a409 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -53,17 +53,17 @@ def test_has_reactions(): # 2 groups # fw_material = MaterialMacroInfo( -# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 1.0 + # [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 1.0 # ) # bz_material = MaterialMacroInfo( -# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [0, 100, 1000], 2.0 + # [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 2.0 # ) # 1 group fw_material = MaterialMacroInfo( - [1.0], [[0.5]], [0, 100], 1.0 + [1.0], [[0.5]], [100, 0], 1.0 ) bz_material = MaterialMacroInfo( - [1.0], [[0.5]], [0, 100], 2.0 + [1.0], [[0.5]], [100, 0], 2.0 ) profile = NeutronFluxProfile( 1.0, # flux From e21a2d62ec252981a1cef549c7befb118a3b70ef Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 16:14:00 +0000 Subject: [PATCH 19/98] to cm fix. --- process/neutronics.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 390c4e217a..c4074458ea 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -370,7 +370,7 @@ def groupwise_neutron_flux_fw( """ c1, c2 = self.integration_constants[n][:2] l_fw = np.sqrt(abs(self.l_fw_2[n])) - x_l_fw = abs(x) / l_fw + x_l_fw = abs(x * 100) / l_fw return c1 * np.exp(x_l_fw) + c2 * np.exp(-x_l_fw) @summarize_values @@ -398,7 +398,7 @@ def groupwise_neutron_flux_bz( """ c3, c4 = self.integration_constants[n][2:] l_bz = np.sqrt(abs(self.l_bz_2[n])) - x_l_bz = abs(x) / l_bz + x_l_bz = abs(x * 100) / l_bz return c3 * np.exp(x_l_bz) + c4 * np.exp(-x_l_bz) @summarize_values @@ -425,10 +425,11 @@ def groupwise_neutron_flux_at( """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.asarray(x) * 100 - in_fw = abs(x) <= self.x_fw_cm + x = np.asarray(x) + in_fw = abs(x * 100) <= self.x_fw_cm in_bz = np.logical_and( - self.x_fw_cm < abs(x), abs(x) <= self.extended_boundary[n] + self.x_fw_cm < abs(x * 100), + abs(x * 100) <= self.extended_boundary[n], ) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( From 4aba6ef018c52e15f1d299a9ad21c753294f1740 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 16:14:13 +0000 Subject: [PATCH 20/98] ruff fix --- process/neutronics_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 1a9d3db150..b7113bfb67 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -206,7 +206,7 @@ def __post_init__(self): self.group_structure = np.array(self.group_structure, dtype=float) self.avg_atomic_mass = float(self.avg_atomic_mass) - if np.diff(self.group_structure)>=0: + if np.diff(self.group_structure) >= 0: raise ValueError( "The group structure must be defined beginning from the highest energy " "bin (i.e. lowest lethargy bin) edge, descending to the lowest energy. " From 0e1c8cfb2e94afd620e6aeab1441c60ecc20f953 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 30 Oct 2025 16:27:29 +0000 Subject: [PATCH 21/98] Quality of life things: (clarify non-scattering into 'exclude elastic-scattering'. --- process/neutronics.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index c4074458ea..4a750a8124 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -453,12 +453,12 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: - Two options: "total" or "non-scattering". + Two options: "total" or "exclude elastic-scattering". """ l_fw = np.sqrt(abs(self.l_fw_2[n])) c1, c2, c3, c4 = self.integration_constants[n] - if reaction_type == "non-scattering": + if reaction_type == "exclude elastic-scattering": sigma = self.fw_mat.sigma_t[n] - self.fw_mat.sigma_s[n, n] elif reaction_type == "total": sigma = self.fw_mat.sigma_t[n] @@ -480,12 +480,12 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: - Two options: "total" or "non-scattering". + Two options: "total" or "exclude elastic-scattering". """ l_bz = np.sqrt(abs(self.l_bz_2[n])) c1, c2, c3, c4 = self.integration_constants[n] - if reaction_type == "non-scattering": + if reaction_type == "exclude elastic-scattering": sigma = self.bz_mat.sigma_t[n] - self.bz_mat.sigma_s[n, n] elif reaction_type == "total": sigma = self.bz_mat.sigma_t[n] From 61c8cf056c753edfe4d0da0ae87bc9bd4567f1f1 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 31 Oct 2025 14:47:35 +0000 Subject: [PATCH 22/98] Allowed source macroscopic cross-section matrix to be larger than the total macroscopic cross-section (due to breeding) --- process/neutronics_data.py | 34 +++++++++++++++++++++++----------- tests/unit/test_neutronics.py | 10 ---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index b7113bfb67..2293294d60 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -191,16 +191,33 @@ def __call__(self, x): @dataclass class MaterialMacroInfo: - """Material information""" + """ + Material information. - sigma_t: npt.NDArray[np.float64] # Sigma_total, 1D array of len = n - sigma_s: npt.NDArray # Sigma_scattering from group i to j, 2D array of n*n - group_structure: npt.NDArray # energy bin edges, 1D array of len = n+1 - avg_atomic_mass: float # average atomic mass (weighted by fraction) + Parameters + ---------- + sigma_t: + total macroscopic cross-section, 1D array of len = n. + sigma_s: + Source matrix, 2D array of shape (n, n). Includes a sum of the + scattering matrix and multiplying matrix. Scattering matrix is the + macroscopic scattering cross-section from group i to j, and the + multiplying matrix is the macroscopic cross-section for production of + group j neutrons due to group i neutrons. + group_structure: + energy bin edges, 1D array of len = n+1 + avg_atomic_mass: + average atomic mass (weighted by fraction) + """ + + sigma_t: npt.NDArray[np.float64] + sigma_s: npt.NDArray + group_structure: npt.NDArray + avg_atomic_mass: float def __post_init__(self): """Validation to confirm the shape is correct.""" - # force into float or numpy arrays. + # force into float or numpy arrays of floats. self.sigma_t = np.array(self.sigma_t, dtype=float) self.sigma_s = np.array(self.sigma_s, dtype=float) self.group_structure = np.array(self.group_structure, dtype=float) @@ -224,11 +241,6 @@ def __post_init__(self): "Group-wise scattering cross-sections be a square matrix of " f"shape n*n, where n= number of groups = {self.n_groups}." ) - if (self.sigma_s.sum(axis=1) > self.sigma_t).any(): - raise ProcessValidationError( - "Each group's scattering cross-section should be smaller than " - "or equal to its total cross-section." - ) @property def n_groups(self): diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index f5f997a409..124a957a8c 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -5,16 +5,6 @@ from process.neutronics_data import MaterialMacroInfo -def test_scattering_larger_than_total(): - with pytest.raises(ProcessValidationError): - MaterialMacroInfo( - [1.0], - [[2.0]], - [1.0, 2.0], - 1, - ) - - def test_group_structure_too_short(): with pytest.raises(ProcessValidationError): MaterialMacroInfo( From eef85fa110188fbfbce32366fd23121c7762ad67 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 31 Oct 2025 18:15:09 +0000 Subject: [PATCH 23/98] Added a property 'downscatter_only' which helps quickly determine if the transport problem is solvable without iterations. --- process/neutronics_data.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 2293294d60..93a5372b18 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -200,10 +200,15 @@ class MaterialMacroInfo: total macroscopic cross-section, 1D array of len = n. sigma_s: Source matrix, 2D array of shape (n, n). Includes a sum of the - scattering matrix and multiplying matrix. Scattering matrix is the + scattering matrix and n2n matrix. Scattering matrix is the macroscopic scattering cross-section from group i to j, and the - multiplying matrix is the macroscopic cross-section for production of - group j neutrons due to group i neutrons. + n2n matrix is the macroscopic cross-section for production of + group j neutrons due to group i neutrons. It should be + mostly-upper-triangular, i.e. the lower triangle must have small values + compared to the average macroscopic cross-section value of the matrix. + + e.g. [0,3] would be the cross-section for proudction of group 4 neutrons + due to reactions (scattering and n2n) caused by group 1 neutrons. group_structure: energy bin edges, 1D array of len = n+1 avg_atomic_mass: @@ -249,6 +254,24 @@ def n_groups(self): self._n_groups = len(self.group_structure) - 1 return self._n_groups + @property + def downscatter_only(self): + """ + Checks if the source matrix suggests that neutrons from each group can + only cause neutrons to be born in higher-lethargy (lower energy) groups. + + If True, the transport equation can be solved acyclically, from low + to high lethargy groups in a single-pass. + + If False, and the transport equation will need to be solved iteratively, + as neutron fluxes in higher-lethargy groups in turn affects the neutron + flux in lower-lethargy groups. + """ + return ~self.contains_upscatter + + @property + def contains_upscatter(self): + return np.tril(self.sigma_s, k=-1).any() def get_material_nuclear_data( material: str, group_structure: list[float] From 1179f5e17c9157db4d4bd725e6b7604ecb3fef14 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 31 Oct 2025 18:48:02 +0000 Subject: [PATCH 24/98] Clean up to make four separate dictionaries: micro_total_xs, micro_scattering_xs, micro_n2n_xs, micro_fiss_xs, to make the code more readable. --- process/neutronics_data.py | 258 ++++++++++++++++++++++++------------- 1 file changed, 167 insertions(+), 91 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 93a5372b18..fe23a0915a 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -43,10 +43,11 @@ def get_avg_atomic_mass(composition: dict[str, float]) -> float: ) -material_density_data_bank = ... -material_composition_data_bank = ... +material_density_data_bank = {"stainless steel": {"Fe": 6.0}} +material_composition_data_bank = {"stainless steel": {"Fe60": 1.0}} xs_data_bank = ... breeding_xs_data_bank = ... +fission_xs_data_bank = ... def calculate_average_macro_xs( @@ -68,9 +69,15 @@ def calculate_average_macro_xs( A dictionary of each species, and their microscopic cross-sections, given in [barns]. Given in the format {'species': float(microscopic cross-section)}. + Possible to have some missing values here. density: Density of the medium, given in [g/cm^3] + Returns + ------- + : + macroscopic cross-section of the material. + Notes ----- .. math:: @@ -80,29 +87,30 @@ def calculate_average_macro_xs( total_fraction = sum(composition.values()) weighted_micro_xs, weighted_atomic_mass = [], [] - if composition.keys() != micro_xs.keys(): + if extra_species:=set(micro_xs.keys()).difference(set(composition.keys())): raise KeyError( - "The two dictionaries 'composition' and 'micro_xs' must have matching keys." + f"micro_xs contains species not specified by the composition: {extra_species}" ) for species, fraction in composition.items(): - normalized_fraction = fraction / total_fraction - weighted_atomic_mass.append( - normalized_fraction * extract_atomic_mass(species) - ) - weighted_micro_xs.append(normalized_fraction * micro_xs[species]) + if species in micro_xs: + frac = fraction / total_fraction + + weighted_atomic_mass.append(frac * extract_atomic_mass(species)) + weighted_micro_xs.append(frac * micro_xs[species]) + avg_sigma = np.sum(weighted_micro_xs, axis=0) avg_mass_amu = sum(weighted_atomic_mass) - return ( - (BARNS_CM2 * N_A) / avg_mass_amu * avg_sigma * density - ) # N_A/A * rho * sigma + + # N_A/A * rho * sigma + return N_A / avg_mass_amu * density * (avg_sigma * BARNS_CM2) def discretize_xs( - continuous_xs, group_structure: list[float] + continuous_xs, group_structure: npt.NDArray[np.float64] ) -> npt.NDArray[np.float64]: """ Discretise a continuous cross-section function into a group structure of n discrete - flaots. + floats. This is done by taking the average xs per bin. (assuming constant-lethargy within bin.) Parameters ---------- @@ -116,12 +124,107 @@ def discretize_xs( ------- : microscopic cross-section values discretized according to the group structure. + 1D array. + """ + lethargy = np.log10(group_structure) + lower_leth, upper_leth = lethargy[:-1], lethargy[1:] + leth_spacing = np.diff(lethargy) + continuous_xs_lethargy_input = lambda e: continuous_xs(10**-e) + + return integrate(continuous_xs_lethargy_input, lower_leth, upper_leth)/leth_spacing + +def discretize_scattering_xs( + continuous_xs, group_structure: npt.NDArray[np.float64], atomic_mass: float +) -> npt.NDArray: + """ + Discretize a scattering macroscopic cross-section from a continuous + function into a numpy array of len==len(group_structure)-1. + + Parameters + ---------- + continuous_xs: + continuous microscopic scattering cross-section function to be discretized. + group_structure: + group structure of neutron energies, the n+1 energy bin boundaries for the n + neutron groups, in descending energies. + + Returns + ------- + : + microscopic scattering cross-section values discretized according to the + group structure. 2D array, where element [i,j] is proportional to the + probability of scattering neutrons from bin i to bin j. + """ + return ( + discretize_xs(continuous_xs, group_structure) * + scattering_weight_matrix(group_structure, atomic_mass).T + ).T + +def discretize_n2n_xs( + continuous_xs, group_structure: npt.NDArray[np.float64], q_value: float +) -> npt.NDArray: + """ + Discretize a n2n reaction macroscopic cross-section from a continuous + function into a numpy array of len==len(group_structure)-1. + + Parameters + ---------- + continuous_xs: + continuous cross-section function to be discretized. + group_structure: + group structure of neutron energies, the n+1 energy bin boundaries for the n + neutron groups, in descending energies. + + Returns + ------- + : + microscopic n2n reaction cross-section values discretized according to the + group structure. 2D array, where element [i,j] is proportional to the + probability of n2n neutrons being born into bin j due to a reaction + caused by a neutron in bin i. """ - return group_structure, continuous_xs + return ( + discretize_xs(continuous_xs, group_structure) * 2 * + n2n_weight_matrix(group_structure, atomic_mass).T + ).T + +def discretize_fission_xs( + continuous_xs, group_structure: npt.NDArray[np.float64], + fission_spectrum_continuous, num_neutrons: float, +) -> npt.NDArray: + """ + Discretize a fission macroscopic cross-section from a continuous + function into a numpy array of len==len(group_structure)-1. + + Parameters + ---------- + continuous_xs: + continuous cross-section function to be discretized. + group_structure: + group structure of neutron energies, the n+1 energy bin boundaries for the n + neutron groups, in descending energies. + fission_spectrum_continuous: + The neutron spectrum formed by the fission neutrons (e.g. the Watt spectrum) + as a continuous, integrable function. + Returns + ------- + : + microscopic fission cross-section values discretized according to the + group structure. 2D array, where element [i,j] is proportional to the + probability of a fission neutron being born into bin j due to a reaction + caused by a neutron in bin i. + """ + fiss_spec = integrate(fission_spectrum_continuous, group_structure) + + scaled_fission_spectrum = fiss_spec/fiss_spec.sum() * num_neutrons + return np.outer( + discretize_xs(continuous_xs, group_structure), + scaled_fission_spectrum, + ) def scattering_weight_matrix( - group_structure: list[float], atomic_mass: float + group_structure: npt.NDArray[np.float64], atomic_mass: float ) -> npt.NDArray: """ Parameters @@ -134,59 +237,38 @@ def scattering_weight_matrix( Returns ------- : - A lower triangular matrix, where the i-th row contains the normalized weights for + An upper triangular matrix, where the i-th row contains the normalized weights for scattering down from the i-th bin to the j-th bin. The main-diagonal contains the self-scattering cross-section. e.g. [2,1] would be the fraction of elastic scattering reactions that causes neutrons from group 3 to scatter into group 2. - The upper triangle must be all zeros. + The lower triangle must be all zeros. np.sum(axis=1) == np.ones(len(group_structure)-1). """ return atomic_mass, group_structure -def expand_macro_neutron_multiplication_xs_into_matrix( - discrete_n2n_xs: npt.NDArray[np.float64], - group_structure: list[float], - q_value: float, +def n2n_weight_matrix( + group_structure: npt.NDArray[np.float64], q_value: float ) -> npt.NDArray: - """Instead of only having the macroscopic cross-section values for the (n,2n) - reaction for each group, calculate the macroscopic cross-section of neutron in the - [i]-th bin producing a neutron in the [j]-bin, recorded as the [i,j] element in the - matrix. - + """ Parameters ---------- - discrete_n2n_xs: - The group-wise macroscopic cross-section for the n2n reaction. - A 1D numpy array, with len==number of neutron groups. group_structure: - The n+1 energy bin boundaries for the n neutron groups, in descending energies. + the n+1 energy bin boundaries for the n neutron groups, in descending energies, + in eV. q_value: - The difference in q-value. + the q-value of the reaction in eV. Returns ------- : - A macroscopic neutron multiplication cross-section matrix, such that each row - should sum to = 2 * discrete_n2n_xs (since two neutrons should be produced per - neutron consumed in the (n,2n) reaction). - - Notes - ----- - This is a three body problem. TODO: further investigation is needed to figure out - how to distribute the two outputted neutron's energies! + A macroscopic cross-section matrix, where the j-th column of the i-th row + expresses the probability of one of the n2n neutrons trigged by a i-th + bin neutron ends up in the j-th bin. + np.sum(axis=1) == np.ones(len(group_structure)-1). """ - - -class ZeroContinuousFunc: - """A dummy class that returns 0 whenever called.""" - - def __call__(self, x): - """Return 0 for al cases.""" - if np.isscalar(x): - return 0.0 - return np.zeros_like(x) + return @dataclass @@ -210,7 +292,7 @@ class MaterialMacroInfo: e.g. [0,3] would be the cross-section for proudction of group 4 neutrons due to reactions (scattering and n2n) caused by group 1 neutrons. group_structure: - energy bin edges, 1D array of len = n+1 + energy bin edges, 1D array of len = n+1, in eV. avg_atomic_mass: average atomic mass (weighted by fraction) """ @@ -225,7 +307,7 @@ def __post_init__(self): # force into float or numpy arrays of floats. self.sigma_t = np.array(self.sigma_t, dtype=float) self.sigma_s = np.array(self.sigma_s, dtype=float) - self.group_structure = np.array(self.group_structure, dtype=float) + self.group_structure = np.clip(self.group_structure, 1E-9, np.inf) self.avg_atomic_mass = float(self.avg_atomic_mass) if np.diff(self.group_structure) >= 0: @@ -274,7 +356,7 @@ def contains_upscatter(self): return np.tril(self.sigma_s, k=-1).any() def get_material_nuclear_data( - material: str, group_structure: list[float] + material: str, group_structure: npt.NDArray[np.float64] ) -> MaterialMacroInfo: """ The constants that is directly used. @@ -288,14 +370,10 @@ def get_material_nuclear_data( Returns ------- - discrete_macro_total_xs: - All group-wise total cross-sections, given in ascending order. - macroscopic scattering cross-section matrix: - A lower-triangular matrix of total scattering cross-sections, - e.g. [2,1] would be the scattering cross-section from neutron group 3 to group 2. - The upper triangle MUST be zeros. - avg_atomic_mass: - average atomic mass, used for further calcuations + : + MaterialMacroInfo encapsulating the total macroscopic cross-section, + source (i.e. scattering + n2n) macroscopic cross-section, group structure + (same as the input group structure) and average atomic mass number. Notes ----- @@ -307,26 +385,32 @@ def get_material_nuclear_data( composition = material_composition_data_bank[material] avg_atomic_mass = get_avg_atomic_mass(composition) - # dicts of {"isotope": npt.NDArray[np.float64] 1D arrays} - micro_total_xs = {} - micro_scattering_xs = {} - micro_n2n_xs = {} + # dicts of {"isotope": npt.NDArray[np.float64] 1D/2D arrays} + micro_total_xs, micro_scattering_xs, micro_n2n_xs = {}, {}, {} + for species in composition: - total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[ - species - ] - n2n_xs_continuous = breeding_xs_data_bank.get( - species, ZeroContinuousFunc - ) + total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[species] + micro_total_xs[species] = discretize_xs( total_xs_continuous, group_structure ) - micro_scattering_xs[species] = discretize_xs( - elastic_scattering_xs_continuous, group_structure - ) - micro_n2n_xs[species] = discretize_xs( - n2n_xs_continuous, group_structure + micro_scattering_xs[species] = discretize_scattering_xs( + elastic_scattering_xs_continuous, + group_structure, + extract_atomic_mass(species), + ) + if species in breeding_xs_data_bank: + n2n_xs_continuous, q_value = breeding_xs_data_bank[species] + micro_n2n_xs[species] = discretize_n2n_xs( + n2n_xs_continuous, group_structure, q_value, + ) + if species in fission_xs_data_bank: + fission_xs_continuous, fission_spectrum_continuous, num_neutrons_per_fission = fission_xs_data_bank[species] + micro_fiss_xs[species] = discretize_fission_xs( + fission_xs_continuous, group_structure, + fission_spectrum_continuous, num_neutrons_per_fission, + ) discrete_macro_total_xs = calculate_average_macro_xs( composition, micro_total_xs, density @@ -334,21 +418,13 @@ def get_material_nuclear_data( discrete_macro_scattering_xs = calculate_average_macro_xs( composition, micro_scattering_xs, density ) - source_matrix = ( - scattering_weight_matrix(group_structure, avg_atomic_mass).T - * discrete_macro_scattering_xs - ).T - n2n_susceptible_species = ... - for ( - modified_composition_file, - modified_density, - q_value, - ) in n2n_susceptible_species: - source_matrix += expand_macro_neutron_multiplication_xs_into_matrix( - calculate_average_macro_xs(composition, micro_n2n_xs, density), - group_structure, - q_value, - ) + discrete_macro_n2n_xs = calculate_average_macro_xs( + composition, micro_n2n_xs, density + ) + discrete_macro_fission_xs = calculate_average_macro_xs( + composition, micro_fiss_xs, density + ) + source_matrix = discrete_macro_scattering_xs + discrete_macro_n2n_xs + discrete_macro_fission_xs return MaterialMacroInfo( discrete_macro_total_xs, From 5e3b631c85028e3fdb9a9fa427d0e93f2b1c7dbe Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 31 Oct 2025 18:55:49 +0000 Subject: [PATCH 25/98] Ruff fixes. --- process/neutronics.py | 10 ++++++ process/neutronics_data.py | 71 +++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 4a750a8124..03f2490c8a 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -457,6 +457,11 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: """ l_fw = np.sqrt(abs(self.l_fw_2[n])) + if n > 0: + raise NotImplementedError( + "We have not done the integration for " + "higher energy groups' fluxes yet." + ) c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "exclude elastic-scattering": sigma = self.fw_mat.sigma_t[n] - self.fw_mat.sigma_s[n, n] @@ -484,6 +489,11 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: """ l_bz = np.sqrt(abs(self.l_bz_2[n])) + if n > 0: + raise NotImplementedError( + "We have not done the integration for " + "higher energy groups' fluxes yet." + ) c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "exclude elastic-scattering": sigma = self.bz_mat.sigma_t[n] - self.bz_mat.sigma_s[n, n] diff --git a/process/neutronics_data.py b/process/neutronics_data.py index fe23a0915a..cb6540d714 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -87,7 +87,9 @@ def calculate_average_macro_xs( total_fraction = sum(composition.values()) weighted_micro_xs, weighted_atomic_mass = [], [] - if extra_species:=set(micro_xs.keys()).difference(set(composition.keys())): + if extra_species := set(micro_xs.keys()).difference( + set(composition.keys()) + ): raise KeyError( f"micro_xs contains species not specified by the composition: {extra_species}" ) @@ -126,12 +128,18 @@ def discretize_xs( microscopic cross-section values discretized according to the group structure. 1D array. """ - lethargy = np.log10(group_structure) + lethargy = -np.log(group_structure) lower_leth, upper_leth = lethargy[:-1], lethargy[1:] leth_spacing = np.diff(lethargy) - continuous_xs_lethargy_input = lambda e: continuous_xs(10**-e) - return integrate(continuous_xs_lethargy_input, lower_leth, upper_leth)/leth_spacing + def continuous_xs_lethargy_input(lethargy): + return continuous_xs(np.exp(-lethargy)) + + return ( + integrate(continuous_xs_lethargy_input, lower_leth, upper_leth) + / leth_spacing + ) + def discretize_scattering_xs( continuous_xs, group_structure: npt.NDArray[np.float64], atomic_mass: float @@ -156,10 +164,11 @@ def discretize_scattering_xs( probability of scattering neutrons from bin i to bin j. """ return ( - discretize_xs(continuous_xs, group_structure) * - scattering_weight_matrix(group_structure, atomic_mass).T + discretize_xs(continuous_xs, group_structure) + * scattering_weight_matrix(group_structure, atomic_mass).T ).T + def discretize_n2n_xs( continuous_xs, group_structure: npt.NDArray[np.float64], q_value: float ) -> npt.NDArray: @@ -184,13 +193,17 @@ def discretize_n2n_xs( caused by a neutron in bin i. """ return ( - discretize_xs(continuous_xs, group_structure) * 2 * - n2n_weight_matrix(group_structure, atomic_mass).T + discretize_xs(continuous_xs, group_structure) + * 2 + * n2n_weight_matrix(group_structure, q_value).T ).T + def discretize_fission_xs( - continuous_xs, group_structure: npt.NDArray[np.float64], - fission_spectrum_continuous, num_neutrons: float, + continuous_xs, + group_structure: npt.NDArray[np.float64], + fission_spectrum_continuous, + num_neutrons: float, ) -> npt.NDArray: """ Discretize a fission macroscopic cross-section from a continuous @@ -217,12 +230,13 @@ def discretize_fission_xs( """ fiss_spec = integrate(fission_spectrum_continuous, group_structure) - scaled_fission_spectrum = fiss_spec/fiss_spec.sum() * num_neutrons + scaled_fission_spectrum = fiss_spec / fiss_spec.sum() * num_neutrons return np.outer( discretize_xs(continuous_xs, group_structure), scaled_fission_spectrum, ) + def scattering_weight_matrix( group_structure: npt.NDArray[np.float64], atomic_mass: float ) -> npt.NDArray: @@ -307,7 +321,7 @@ def __post_init__(self): # force into float or numpy arrays of floats. self.sigma_t = np.array(self.sigma_t, dtype=float) self.sigma_s = np.array(self.sigma_s, dtype=float) - self.group_structure = np.clip(self.group_structure, 1E-9, np.inf) + self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) self.avg_atomic_mass = float(self.avg_atomic_mass) if np.diff(self.group_structure) >= 0: @@ -355,6 +369,7 @@ def downscatter_only(self): def contains_upscatter(self): return np.tril(self.sigma_s, k=-1).any() + def get_material_nuclear_data( material: str, group_structure: npt.NDArray[np.float64] ) -> MaterialMacroInfo: @@ -386,10 +401,15 @@ def get_material_nuclear_data( avg_atomic_mass = get_avg_atomic_mass(composition) # dicts of {"isotope": npt.NDArray[np.float64] 1D/2D arrays} - micro_total_xs, micro_scattering_xs, micro_n2n_xs = {}, {}, {} + micro_total_xs = {} + micro_scattering_xs = {} + micro_n2n_xs = {} + micro_fiss_xs = {} for species in composition: - total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[species] + total_xs_continuous, elastic_scattering_xs_continuous = xs_data_bank[ + species + ] micro_total_xs[species] = discretize_xs( total_xs_continuous, group_structure @@ -398,18 +418,25 @@ def get_material_nuclear_data( elastic_scattering_xs_continuous, group_structure, extract_atomic_mass(species), - ) if species in breeding_xs_data_bank: n2n_xs_continuous, q_value = breeding_xs_data_bank[species] micro_n2n_xs[species] = discretize_n2n_xs( - n2n_xs_continuous, group_structure, q_value, + n2n_xs_continuous, + group_structure, + q_value, ) if species in fission_xs_data_bank: - fission_xs_continuous, fission_spectrum_continuous, num_neutrons_per_fission = fission_xs_data_bank[species] + ( + fission_xs_continuous, + fission_spectrum_continuous, + num_neutrons_per_fission, + ) = fission_xs_data_bank[species] micro_fiss_xs[species] = discretize_fission_xs( - fission_xs_continuous, group_structure, - fission_spectrum_continuous, num_neutrons_per_fission, + fission_xs_continuous, + group_structure, + fission_spectrum_continuous, + num_neutrons_per_fission, ) discrete_macro_total_xs = calculate_average_macro_xs( @@ -424,7 +451,11 @@ def get_material_nuclear_data( discrete_macro_fission_xs = calculate_average_macro_xs( composition, micro_fiss_xs, density ) - source_matrix = discrete_macro_scattering_xs + discrete_macro_n2n_xs + discrete_macro_fission_xs + source_matrix = ( + discrete_macro_scattering_xs + + discrete_macro_n2n_xs + + discrete_macro_fission_xs + ) return MaterialMacroInfo( discrete_macro_total_xs, From 461ba6f6b41f7e90f7dbb6ada1dc3bb5b1818bc0 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 5 Nov 2025 16:23:19 +0000 Subject: [PATCH 26/98] Created the scattering matrix, and tested it. Next on the to-do list: n2n matrix. --- process/neutronics_data.py | 140 ++++++++++++++++++++++++++++- tests/unit/test_neutronics_data.py | 27 ++++++ 2 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test_neutronics_data.py diff --git a/process/neutronics_data.py b/process/neutronics_data.py index cb6540d714..a5ff5824ed 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from itertools import islice +from itertools import islice, pairwise from pathlib import Path import numpy as np @@ -237,6 +237,10 @@ def discretize_fission_xs( ) +def _get_alpha(atomic_mass: float): + return ((atomic_mass - 1) / (atomic_mass + 1)) ** 2 + + def scattering_weight_matrix( group_structure: npt.NDArray[np.float64], atomic_mass: float ) -> npt.NDArray: @@ -259,7 +263,133 @@ def scattering_weight_matrix( The lower triangle must be all zeros. np.sum(axis=1) == np.ones(len(group_structure)-1). """ - return atomic_mass, group_structure + + alpha = _get_alpha(atomic_mass) + n_groups = len(group_structure) - 1 + matrix = np.zeros([n_groups, n_groups], dtype=float) + for i, in_group in enumerate(pairwise(group_structure)): + for g, out_group in enumerate(pairwise(group_structure)): + if i == g: + for energy_limits, case_descr in _split_into_energy_limits( + alpha, in_group + ): + matrix[i, g] += _convolved_scattering_fraction( + energy_limits, alpha, in_group, out_group, case_descr + ) + elif i < g: + for energy_limits, case_descr in _split_into_energy_limits( + alpha, in_group, out_group + ): + matrix[i, g] += _convolved_scattering_fraction( + energy_limits, alpha, in_group, out_group, case_descr + ) + return matrix + + +def _split_into_energy_limits( + alpha, + in_group: tuple[float, float], + out_group: tuple[float, float] | None = None, +): + """ + Spit out a list of integration limits to be used by _convolved_scattering_fraction. + + Parameters + ---------- + alpha: + Parameters + in_group: + Descending energy bounds of the input group. Scattering neutrons are + generated from this energy group. (e_i1, e_i) + out_group: + Descending energy bounds of the output group. Scattering neutrons are + born into this energy group. (e_g1, e_g) + + Returns + ------- + : + list of 2-tuples, each two tuple contains the following items: + energy_limits: + A tuple of two floats in descending order, describing the integration + limits. + case_descr: + A string to describe which case it belongs to. + """ + e_i1, e_i = in_group + max_min_scattered_energy = alpha * e_i1 + min_min_scattered_energy = alpha * e_i + + if not out_group: + # min_min_scattered_energy < e_i < max_min_scattered_energy < e_i1 + if (alpha > 0) and (e_i < max_min_scattered_energy): + mid_e = min(e_i / alpha, e_i1) + return [ + ((e_i1, mid_e), "self, complete"), + ((mid_e, e_i), "self, upper-half"), + ] + # min_min_scattered_energy < max_min_scattered_energy < e_i < e_i1 + return [((e_i1, e_i), "self, upper-half")] + e_g1, e_g = out_group + if alpha == 0: + # min_min_scattered_energy < max_min_scattered_energy < e_g < e_g1 + return [((e_i1, e_i), "down, middle")] + + top_e = min(e_g1 / alpha, e_i1) + mid_e = min(e_g / alpha, e_i1) + + # e_g < e_g1 < min_min_scattered_energy < max_min_scattered_energy + if e_g1 <= min_min_scattered_energy: + return [] + + # e_g < min_min_scattered_energy < e_g1 < max_min_scattered_energy + # e_g < min_min_scattered_energy < max_min_scattered_energy < e_g1 + if e_g <= min_min_scattered_energy: + return [((top_e, e_i), "down, upper-half")] + + # min_min_scattered_energy < e_g < e_g1 < max_min_scattered_energy + # min_min_scattered_energy < e_g < max_min_scattered_energy < e_g1 + if e_g < max_min_scattered_energy: + return [ + ((top_e, mid_e), "down, upper-half"), + ((mid_e, e_i), "down, middle"), + ] + + # min_min_scattered_energy < max_min_scattered_energy < e_g < e_g1 + return [((top_e, e_i), "down, middle")] + + +def _convolved_scattering_fraction( + energy_limits: tuple[float, float], + alpha: float, + in_group: tuple[float, float], + out_group: tuple[float, float], + case_description: str, +): + r""" + The fraction of neutron flux from bin i that would get scattered into bin g + is calculated as $M_{ig} = \int_{E_{min}}^{E_{max}} flux_i(E) dist(E) dE$, + where $flux_i=$ normalized flux (we assume the neutron flux in bin i has + constant in per-unit-lethargy space), i.e. follows a 1/E distribution. + Hence after intergration, frac is always accompanied by a factor of + $1/(ln(E_{i-1}) - ln(E_i))$. + """ + e_max, e_min = energy_limits + e_i1, e_i = in_group + e_g1, e_g = out_group + + _const = 1 / (np.log(e_i1) - np.log(e_i)) + _am1i = 1 / (1 - alpha) + _diff_log_e = np.log(e_max) - np.log(e_min) + _diff_inv_e = 1 / e_min - 1 / e_max + match case_description: + case "self, complete": + return _const * _diff_log_e + case "self, upper-half": + return _const * _am1i * (_diff_log_e - e_g * _diff_inv_e) + case "down, upper-half": + return _const * _am1i * -(alpha * _diff_log_e - e_g1 * _diff_inv_e) + case "down, middle": + return _const * _am1i * (e_g1 - e_g) * _diff_inv_e def n2n_weight_matrix( @@ -282,7 +412,9 @@ def n2n_weight_matrix( bin neutron ends up in the j-th bin. np.sum(axis=1) == np.ones(len(group_structure)-1). """ - return + # Assume that the two neutrons would share the resulting energy evenly, i.e. + # a flat line. + return q_value, group_structure @dataclass @@ -324,7 +456,7 @@ def __post_init__(self): self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) self.avg_atomic_mass = float(self.avg_atomic_mass) - if np.diff(self.group_structure) >= 0: + if np.diff(self.group_structure) > 0: raise ValueError( "The group structure must be defined beginning from the highest energy " "bin (i.e. lowest lethargy bin) edge, descending to the lowest energy. " diff --git a/tests/unit/test_neutronics_data.py b/tests/unit/test_neutronics_data.py new file mode 100644 index 0000000000..0d6b33dd54 --- /dev/null +++ b/tests/unit/test_neutronics_data.py @@ -0,0 +1,27 @@ +import pytest +import numpy as np +from numpy import typing as npt + +from process.neutronics_data import scattering_weight_matrix, _convolved_scattering_fraction + +np.random.seed(1) +@pytest.mark.parametrize("group_structure, atomic_mass", + [ + (np.cumsum(100**abs(np.random.randn(5)))[::-1], np.random.rand()*200), + (np.cumsum(100**abs(np.random.randn(10)))[::-1], np.random.rand()*239), + (np.cumsum(100**abs(np.random.randn(20)))[::-1], np.random.rand()*150), + (np.cumsum(100**abs(np.random.randn(30)))[::-1], 1), + (np.cumsum(100**abs(np.random.randn(40)))[::-1], 2), + ] +) +def test_scattering_matrix(group_structure: npt.NDArray[np.float64], atomic_mass: float): + """ + Check that even randomly generated scattering matrix are normalized + and non-negative. + """ + scattering_matrix = scattering_weight_matrix(group_structure, atomic_mass) + row_sum = scattering_matrix.sum(axis=1) + assert np.logical_or(np.isclose(row_sum, 1, rtol=0), row_sum<1).all(), ( + "Every row must be unitary or less." + ) + assert (scattering_matrix>=0).all(), "Must be all non-negative." From a20702660a96ad812fb3ada571c3f36f47b876fd Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 04:22:56 +0000 Subject: [PATCH 27/98] Added the n2n_matrix the feature, and added tests. --- process/neutronics_data.py | 23 ++++++-- tests/unit/test_neutronics_data.py | 88 ++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index a5ff5824ed..be927c3633 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -194,7 +194,6 @@ def discretize_n2n_xs( """ return ( discretize_xs(continuous_xs, group_structure) - * 2 * n2n_weight_matrix(group_structure, q_value).T ).T @@ -410,11 +409,27 @@ def n2n_weight_matrix( A macroscopic cross-section matrix, where the j-th column of the i-th row expresses the probability of one of the n2n neutrons trigged by a i-th bin neutron ends up in the j-th bin. - np.sum(axis=1) == np.ones(len(group_structure)-1). + np.sum(axis=1) <= np.ones(len(group_structure)-1) * 2, i.e. the + probability distribution in each row (i.e. i-th bin) is normalized to + 2, i.e. the number of neutrons. """ # Assume that the two neutrons would share the resulting energy evenly, i.e. - # a flat line. - return q_value, group_structure + # each take half of the neutron + # To make things even simpler, we'll assume the neutron flux is + shift_e = -q_value / 2 + + e_i1, e_i = group_structure[:-1], group_structure[1:] + weight = 1 / (np.log(e_i1) - np.log(e_i)) + + n_groups = len(group_structure) - 1 + e_g1 = np.broadcast_to(e_i1, [n_groups, n_groups]) + e_g = np.broadcast_to(e_i, [n_groups, n_groups]) + + e_min = np.clip((e_g + shift_e).T, e_i, e_i1).T + e_max = np.clip((e_g1 + shift_e).T, e_min.T, e_i1).T + + matrix = np.log(e_max) - np.log(e_min) + return (weight * matrix.T).T @dataclass diff --git a/tests/unit/test_neutronics_data.py b/tests/unit/test_neutronics_data.py index 0d6b33dd54..866ced4078 100644 --- a/tests/unit/test_neutronics_data.py +++ b/tests/unit/test_neutronics_data.py @@ -1,27 +1,91 @@ -import pytest import numpy as np +import pytest from numpy import typing as npt -from process.neutronics_data import scattering_weight_matrix, _convolved_scattering_fraction +from process.neutronics_data import n2n_weight_matrix, scattering_weight_matrix np.random.seed(1) -@pytest.mark.parametrize("group_structure, atomic_mass", + + +@pytest.mark.parametrize( + "group_structure, atomic_mass", [ - (np.cumsum(100**abs(np.random.randn(5)))[::-1], np.random.rand()*200), - (np.cumsum(100**abs(np.random.randn(10)))[::-1], np.random.rand()*239), - (np.cumsum(100**abs(np.random.randn(20)))[::-1], np.random.rand()*150), - (np.cumsum(100**abs(np.random.randn(30)))[::-1], 1), - (np.cumsum(100**abs(np.random.randn(40)))[::-1], 2), - ] + ( + np.cumsum(100 ** abs(np.random.randn(5)))[::-1], + np.random.rand() * 200, + ), + ( + np.cumsum(100 ** abs(np.random.randn(10)))[::-1], + np.random.rand() * 239, + ), + ( + np.cumsum(100 ** abs(np.random.randn(20)))[::-1], + np.random.rand() * 150, + ), + (np.cumsum(100 ** abs(np.random.randn(30)))[::-1], 1), + (np.cumsum(100 ** abs(np.random.randn(40)))[::-1], 2), + ], ) -def test_scattering_matrix(group_structure: npt.NDArray[np.float64], atomic_mass: float): +def test_scattering_matrix( + group_structure: npt.NDArray[np.float64], atomic_mass: float +): """ Check that even randomly generated scattering matrix are normalized and non-negative. """ scattering_matrix = scattering_weight_matrix(group_structure, atomic_mass) row_sum = scattering_matrix.sum(axis=1) - assert np.logical_or(np.isclose(row_sum, 1, rtol=0), row_sum<1).all(), ( + assert np.logical_or(np.isclose(row_sum, 1, rtol=0), row_sum < 1).all(), ( "Every row must be unitary or less." ) - assert (scattering_matrix>=0).all(), "Must be all non-negative." + assert (scattering_matrix >= 0).all(), "Must be all non-negative." + + +def test_n2n_matrix_neg1(): + fibo_gs = np.array([8, 5, 3, 2, 1]) + n2n_matrix = n2n_weight_matrix(fibo_gs, -1) + row_sum = n2n_matrix.sum(axis=1) + assert np.isclose( + row_sum, [1, 1, 1, np.log(2 / 1.5) / np.log(2 / 1)], rtol=0 + ).all(), "Expected bin 4 to be partially out-of-bounds" + assert (n2n_matrix >= 0).all(), "Must be all non-negative." + + +def test_n2n_matrix_neg2(): + fibo_gs = np.array([8, 5, 3, 2, 1]) + n2n_matrix = n2n_weight_matrix(fibo_gs, -2) + row_sum = n2n_matrix.sum(axis=1) + assert np.isclose(row_sum, [1, 1, 1, 0], rtol=0).all(), ( + "Expected bin 4 to be out-of-bounds" + ) + assert (n2n_matrix >= 0).all(), "Must be all non-negative." + + +def test_n2n_matrix_neg3(): + fibo_gs = np.array([8, 5, 3, 2, 1]) + n2n_matrix = n2n_weight_matrix(fibo_gs, -3) + row_sum = n2n_matrix.sum(axis=1) + assert np.isclose( + row_sum, [1, 1, np.log(3 / 2.5) / np.log(3 / 2), 0], rtol=0 + ).all(), "Expected bin 3 to be partially out-of-bounds" + assert (n2n_matrix >= 0).all(), "Must be all non-negative." + + +def test_n2n_matrix_pos3(): + fibo_gs = np.array([8, 5, 3, 2, 1]) + n2n_matrix = n2n_weight_matrix(fibo_gs, 3) + row_sum = n2n_matrix.sum(axis=1) + assert np.isclose( + row_sum, [np.log(6.5 / 5) / np.log(8 / 5), 1, 1, 1], rtol=0 + ).all(), "Expected bin 1 to be partially out-of-bounds" + assert (n2n_matrix >= 0).all(), "Must be all non-negative." + + +def test_n2n_matrix_pos6(): + fibo_gs = np.array([8, 5, 3, 2, 1]) + n2n_matrix = n2n_weight_matrix(fibo_gs, 6) + row_sum = n2n_matrix.sum(axis=1) + assert np.isclose(row_sum, [0, 1, 1, 1], rtol=0).all(), ( + "Expected bin 1 to be completely out-of-bounds" + ) + assert (n2n_matrix >= 0).all(), "Must be all non-negative." From aca4b386515d45abf7b3cb27a3999b0408eb63ac Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 04:28:37 +0000 Subject: [PATCH 28/98] Cleaned a bit up where the hypothetical 'integrate' function is used, to prep for its import --- process/neutronics_data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index be927c3633..e42214a608 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -227,7 +227,8 @@ def discretize_fission_xs( probability of a fission neutron being born into bin j due to a reaction caused by a neutron in bin i. """ - fiss_spec = integrate(fission_spectrum_continuous, group_structure) + e_max, e_min = group_structure[:-1], group_structure[1:] + fiss_spec = integrate(fission_spectrum_continuous, e_max, e_min) scaled_fission_spectrum = fiss_spec / fiss_spec.sum() * num_neutrons return np.outer( From 4c1373d395f6423bc784a4abf8dff51e4bada951 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 17:42:07 +0000 Subject: [PATCH 29/98] Used numpy testing in appropriate places --- tests/unit/test_neutronics_data.py | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tests/unit/test_neutronics_data.py b/tests/unit/test_neutronics_data.py index 866ced4078..86d72ccdaa 100644 --- a/tests/unit/test_neutronics_data.py +++ b/tests/unit/test_neutronics_data.py @@ -45,9 +45,11 @@ def test_n2n_matrix_neg1(): fibo_gs = np.array([8, 5, 3, 2, 1]) n2n_matrix = n2n_weight_matrix(fibo_gs, -1) row_sum = n2n_matrix.sum(axis=1) - assert np.isclose( - row_sum, [1, 1, 1, np.log(2 / 1.5) / np.log(2 / 1)], rtol=0 - ).all(), "Expected bin 4 to be partially out-of-bounds" + np.testing.assert_allclose( + row_sum, + [1, 1, 1, np.log(2 / 1.5) / np.log(2 / 1)], + err_msg="Expected bin 4 to be partially out-of-bounds", + ) assert (n2n_matrix >= 0).all(), "Must be all non-negative." @@ -55,8 +57,8 @@ def test_n2n_matrix_neg2(): fibo_gs = np.array([8, 5, 3, 2, 1]) n2n_matrix = n2n_weight_matrix(fibo_gs, -2) row_sum = n2n_matrix.sum(axis=1) - assert np.isclose(row_sum, [1, 1, 1, 0], rtol=0).all(), ( - "Expected bin 4 to be out-of-bounds" + np.testing.assert_allclose( + row_sum, [1, 1, 1, 0], err_msg="Expected bin 4 to be out-of-bounds" ) assert (n2n_matrix >= 0).all(), "Must be all non-negative." @@ -65,9 +67,11 @@ def test_n2n_matrix_neg3(): fibo_gs = np.array([8, 5, 3, 2, 1]) n2n_matrix = n2n_weight_matrix(fibo_gs, -3) row_sum = n2n_matrix.sum(axis=1) - assert np.isclose( - row_sum, [1, 1, np.log(3 / 2.5) / np.log(3 / 2), 0], rtol=0 - ).all(), "Expected bin 3 to be partially out-of-bounds" + np.testing.assert_allclose( + row_sum, + [1, 1, np.log(3 / 2.5) / np.log(3 / 2), 0], + err_msg="Expected bin 3 to be partially out-of-bounds", + ) assert (n2n_matrix >= 0).all(), "Must be all non-negative." @@ -75,9 +79,11 @@ def test_n2n_matrix_pos3(): fibo_gs = np.array([8, 5, 3, 2, 1]) n2n_matrix = n2n_weight_matrix(fibo_gs, 3) row_sum = n2n_matrix.sum(axis=1) - assert np.isclose( - row_sum, [np.log(6.5 / 5) / np.log(8 / 5), 1, 1, 1], rtol=0 - ).all(), "Expected bin 1 to be partially out-of-bounds" + np.testing.assert_allclose( + row_sum, + [np.log(6.5 / 5) / np.log(8 / 5), 1, 1, 1], + err_msg="Expected bin 1 to be partially out-of-bounds", + ) assert (n2n_matrix >= 0).all(), "Must be all non-negative." @@ -85,7 +91,9 @@ def test_n2n_matrix_pos6(): fibo_gs = np.array([8, 5, 3, 2, 1]) n2n_matrix = n2n_weight_matrix(fibo_gs, 6) row_sum = n2n_matrix.sum(axis=1) - assert np.isclose(row_sum, [0, 1, 1, 1], rtol=0).all(), ( - "Expected bin 1 to be completely out-of-bounds" + np.testing.assert_allclose( + row_sum, + [0, 1, 1, 1], + err_msg="Expected bin 1 to be completely out-of-bounds", ) assert (n2n_matrix >= 0).all(), "Must be all non-negative." From 6643fbe17ee4e10e68bc6d9835ad51ddebf86ead Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 17:46:22 +0000 Subject: [PATCH 30/98] Ruff fix: numpy.random --- tests/unit/test_neutronics_data.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/unit/test_neutronics_data.py b/tests/unit/test_neutronics_data.py index 86d72ccdaa..7f76fe2137 100644 --- a/tests/unit/test_neutronics_data.py +++ b/tests/unit/test_neutronics_data.py @@ -4,26 +4,17 @@ from process.neutronics_data import n2n_weight_matrix, scattering_weight_matrix -np.random.seed(1) +rng = np.random.default_rng(1) @pytest.mark.parametrize( "group_structure, atomic_mass", [ - ( - np.cumsum(100 ** abs(np.random.randn(5)))[::-1], - np.random.rand() * 200, - ), - ( - np.cumsum(100 ** abs(np.random.randn(10)))[::-1], - np.random.rand() * 239, - ), - ( - np.cumsum(100 ** abs(np.random.randn(20)))[::-1], - np.random.rand() * 150, - ), - (np.cumsum(100 ** abs(np.random.randn(30)))[::-1], 1), - (np.cumsum(100 ** abs(np.random.randn(40)))[::-1], 2), + (np.cumsum(100 ** abs(rng.normal(5)))[::-1], rng.random() * 200), + (np.cumsum(100 ** abs(rng.normal(10)))[::-1], rng.random() * 239), + (np.cumsum(100 ** abs(rng.normal(20)))[::-1], rng.random() * 150), + (np.cumsum(100 ** abs(rng.normal(30)))[::-1], 1), + (np.cumsum(100 ** abs(rng.normal(40)))[::-1], 2), ], ) def test_scattering_matrix( From fa95610aa17980ef70a6a839687a657b96341f08 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 18:29:31 +0000 Subject: [PATCH 31/98] Docstring improvements --- process/neutronics.py | 5 +++-- process/neutronics_data.py | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 03f2490c8a..b8bac89249 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -311,8 +311,9 @@ def solve_group_n(self, n: int) -> None: Parameters ---------- n: - The index of the neutron group whose constants are being solved. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + The index of the neutron group whose constants are being solved. + The allowed range of values = [0, self.n_groups-1]. Therefore, + n=0 shows the reaction rate for group 1, n=1 for group 2, etc. """ if n not in range(self.n_groups): raise ValueError( diff --git a/process/neutronics_data.py b/process/neutronics_data.py index e42214a608..f26ec75119 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -465,14 +465,17 @@ class MaterialMacroInfo: avg_atomic_mass: float def __post_init__(self): - """Validation to confirm the shape is correct.""" + """ + Validation of group_structure, sigma_s and sigma_t to confirm their + shapes are correct. + """ # force into float or numpy arrays of floats. self.sigma_t = np.array(self.sigma_t, dtype=float) self.sigma_s = np.array(self.sigma_s, dtype=float) self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) self.avg_atomic_mass = float(self.avg_atomic_mass) - if np.diff(self.group_structure) > 0: + if (np.diff(self.group_structure) > 0).any(): raise ValueError( "The group structure must be defined beginning from the highest energy " "bin (i.e. lowest lethargy bin) edge, descending to the lowest energy. " @@ -493,7 +496,10 @@ def __post_init__(self): @property def n_groups(self): - """Store this attribute upon first retrieval.""" + """ + Number of groups in the group structure. + Store this attribute upon first retrieval. + """ if not hasattr(self, "_n_groups"): self._n_groups = len(self.group_structure) - 1 return self._n_groups From 971e0aa8cc9efb21cb55b35c08807ddede4254e9 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 18:30:15 +0000 Subject: [PATCH 32/98] Added plotting function. --- process/neutronics.py | 53 +++++++++++++++++++++++++++++++++++ tests/unit/test_neutronics.py | 38 +++++++++++++++++++------ 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index b8bac89249..9c05f18fdb 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -8,6 +8,7 @@ from collections.abc import Callable import numpy as np +from matplotlib import pyplot as plt from numpy import typing as npt from scipy.special import expm1 @@ -172,6 +173,9 @@ def __setitem__(self, i: int, value: float): self._attempting_to_access.discard(i) self._dict[i] = value + def values(self): + return self._dict.values() + class NeutronFluxProfile: """Neutron flux in the first wall or the blanket.""" @@ -575,3 +579,52 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: - c4 * np.exp(-self.x_bz_cm / l_bz) ) ) + + def plot( + self, + ax: plt.Axes | None = None, + n_points: int = 100, + symmetric: bool = True, + plot_groups: bool = False, + ): + """ + Make a rough plot of the neutron flux. + + Parameters + ---------- + ax: + A plt.Axes object to plot on. + n_points: + number of points to be used for plotting. + symmetric: + Whether to plot from -x to x (symmetric), or from 0 to x (right side only.) + plot_groups: + Whether to plot each individual group's neutron flux. + If True, a legend will be added to help label the groups. + """ + self.solve_group_n(self.n_groups - 1) + x_range = _generate_x_range( + min(self.extended_boundary.values()) / 100, n_points, symmetric + ) + flux = self.neutron_flux_at(x_range) + ax = ax or plt.axes() + ax.plot(x_range, flux, label="total") + + if plot_groups: + for n in range(self.n_groups): + x_range = _generate_x_range( + self.extended_boundary[n], n_points, symmetric + ) + flux = self.groupwise_neutron_flux_at(x_range) + ax.plot(x_range, flux, label=f"group {n}") + ax.legend() + ax.set_title("Neutron flux profile") + return ax + + +def _generate_x_range(x_max, n_points, symmetric: bool): + """Helper function for finding the range of x-values to be plotted.""" + + if symmetric: + return np.linspace(-x_max, x_max, n_points * 2 - 1) + return np.linspace(0, x_max, n_points) diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 124a957a8c..a3dbaa4e7f 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -43,18 +43,14 @@ def test_has_reactions(): # 2 groups # fw_material = MaterialMacroInfo( - # [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 1.0 +# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 1.0 # ) # bz_material = MaterialMacroInfo( - # [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 2.0 +# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 2.0 # ) # 1 group -fw_material = MaterialMacroInfo( - [1.0], [[0.5]], [100, 0], 1.0 -) -bz_material = MaterialMacroInfo( - [1.0], [[0.5]], [100, 0], 2.0 -) +fw_material = MaterialMacroInfo([1.0], [[0.5]], [100, 0], 1.0) +bz_material = MaterialMacroInfo([1.0], [[0.5]], [100, 0], 2.0) profile = NeutronFluxProfile( 1.0, # flux 0.01, # 1cm @@ -62,3 +58,29 @@ def test_has_reactions(): fw_material, bz_material, ) + + +def test_against_desmos_number(): + dummy = [100, 1] # dummy group structure + # translate from mean-free-path lengths (mfp) to macroscopic cross-sections + # [cm] + mfp_fw_s = 118 * 0.01 + mfp_fw_t = 16.65 * 0.01 + sigma_fw_t = 1 / mfp_fw_t # [1/cm] + sigma_fw_s = 1 / mfp_fw_s # [1/cm] + a_fw = 52 + fw_material = MaterialMacroInfo([sigma_fw_t], [[sigma_fw_s]], dummy, a_fw) + + mfp_bz_s = 97 * 0.01 + mfp_bz_t = 35.8 * 0.01 + sigma_bz_s = 1 / mfp_bz_s # [1/cm] + sigma_bz_t = 1 / mfp_bz_t # [1/cm] + a_bz = 71 + bz_material = MaterialMacroInfo([sigma_bz_t], [[sigma_bz_s]], dummy, a_bz) + + x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 + incoming_flux = 41 + neutron_profile = NeutronFluxProfile( + incoming_flux, x_fw, x_bz, fw_material, bz_material + ) + neutron_profile.plot() From 86e9518b4a8e6029a95e2242e5c914119c92824e Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 19:31:21 +0000 Subject: [PATCH 33/98] further improved the plotting. --- process/neutronics.py | 118 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 104 insertions(+), 14 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 9c05f18fdb..7d3c3f4adc 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -585,7 +585,7 @@ def plot( ax: plt.Axes | None = None, n_points: int = 100, symmetric: bool = True, - plot_groups: bool = False, + plot_groups: bool = True, ): """ Make a rough plot of the neutron flux. @@ -603,28 +603,118 @@ def plot( If True, a legend will be added to help label the groups. """ self.solve_group_n(self.n_groups - 1) - x_range = _generate_x_range( - min(self.extended_boundary.values()) / 100, n_points, symmetric - ) - flux = self.neutron_flux_at(x_range) ax = ax or plt.axes() - ax.plot(x_range, flux, label="total") + + x_bz_left, x_fw, x_bz_right = _generate_x_range( + min(self.extended_boundary.values()), n_points, + symmetric, self.x_fw_cm + ) + ax.plot( + x_bz_left, self.neutron_flux_bz(x_bz_left), + label="total (BZ)", color="black", ls=(0, (3, 1, 1, 1)) + ) + ax.plot( + x_fw, self.neutron_flux_fw(x_fw), + label="total (FW)", color="black", ls="solid" + ) + ax.plot( + x_bz_right, self.neutron_flux_bz(x_bz_right), + color="black", ls=(0, (3, 1, 1, 1)) + ) if plot_groups: for n in range(self.n_groups): - x_range = _generate_x_range( - self.extended_boundary[n], n_points, symmetric + x_bz_left, x_fw, x_bz_right = _generate_x_range( + self.extended_boundary[n], n_points, + symmetric, self.x_fw_cm + ) + ax.plot( + x_bz_left, self.neutron_flux_bz(x_bz_left), + label=f"group {n+1} (BZ)", color=f"C{n}", ls=(0, (3, 1, 1, 1)) + ) + ax.plot( + x_fw, self.neutron_flux_fw(x_fw), + label=f"group {n+1} (FW)", color=f"C{n}", ls="solid" + ) + ax.plot( + x_bz_right, self.neutron_flux_bz(x_bz_right), + color=f"C{n}", ls=(0, (3, 1, 1, 1)) ) - flux = self.groupwise_neutron_flux_at(x_range) - ax.plot(x_range, flux, label=f"group {n}") ax.legend() ax.set_title("Neutron flux profile") return ax -def _generate_x_range(x_max, n_points, symmetric: bool): - """Helper function for finding the range of x-values to be plotted.""" +def _generate_x_range( + x_max_cm: float, + approx_n_points: int, + symmetric: bool, + fw_bz_split_point_cm: float|None=None +): + """Helper function for finding the range of x-values to be plotted. + + Parameters + ---------- + x_max_cm: + absolute value of the maximum x that we want to plot. + This is typically obtained by min(extended_boundary), or + extended_boundary[n] [cm] + symmetric: + Whether we want to plot the negative side of the x-axis as well, forming + a symmetric plot. + approx_n_points: + number of points to be plotted. + fw_bz_split_point_cm: + FW and BZ region splits at this distance. If provided, we generate separate + x ranges for the FW and BZ. [cm] + + Returns + ------- + if (fw_bz_split_point_cm, symmetric) = (float value, True): + x_range_bz_left: + The array of x-values to be used for plotting the left (negative) + side of bz. [m] + x_range_fw: + The array of x-values to be used for plotting both the left and + right sides of fw. [m] + x_range_bz_right: + The array of x-values to be used for plotting the right (positive) + side of bz. [m] + elif (fw_bz_split_point_cm, symmetric) = (float value, False): + x_range_fw: + The array of x-values to be used for plotting the right (positive) + side of fw [m] + x_range_bz: + The array of x-values to be used for plotting the right (positive) + side of bz [m] + elif (fw_bz_split_point_cm, symmetric) = (None, True): + x_range: + The array of x-values to be used for plotting both sides of the + neutron flux. [m] + else (fw_bz_split_point_cm, symmetric) = (None, False): + x_range: + The array of x-values to be used for plotting the right (positive) + side neutron flux. [m] + """ + + x_max = x_max_cm/100 + if fw_bz_split_point_cm is not None: + x_range = np.linspace(0, x_max_cm, approx_n_points) + n_points_fw = (x_range=fw_bz_split_point_cm).sum() + 1 + + split_point = fw_bz_split_point_cm/100 + if symmetric: + return ( + np.linspace(-x_max, -split_point, n_points_bz), + np.linspace(-split_point, split_point, n_points_fw * 2 - 1), + np.linspace(split_point, x_max, n_points_bz), + ) + return ( + np.linspace(0, split_point, n_points_fw), + np.linspace(split_point, x_max, n_points_bz), + ) if symmetric: - return np.linspace(-x_max, x_max, n_points * 2 - 1) - return np.linspace(0, x_max, n_points) + return np.linspace(-x_max, x_max, approx_n_points * 2 - 1) + return np.linspace(0, x_max, approx_n_points) From 44ca361899d45e0a6b14a5c6a8f0ee50a9a4c5c2 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 19:37:36 +0000 Subject: [PATCH 34/98] Formatting fix --- process/neutronics.py | 64 +++++++++++++++++++++++------------ tests/unit/test_neutronics.py | 19 ----------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 7d3c3f4adc..4b87c8e810 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -606,39 +606,59 @@ def plot( ax = ax or plt.axes() x_bz_left, x_fw, x_bz_right = _generate_x_range( - min(self.extended_boundary.values()), n_points, - symmetric, self.x_fw_cm + min(self.extended_boundary.values()), + n_points, + symmetric, + self.x_fw_cm, ) ax.plot( - x_bz_left, self.neutron_flux_bz(x_bz_left), - label="total (BZ)", color="black", ls=(0, (3, 1, 1, 1)) + x_bz_left, + self.neutron_flux_bz(x_bz_left), + label="total (BZ)", + color="black", + ls=(0, (3, 1, 1, 1)), ) ax.plot( - x_fw, self.neutron_flux_fw(x_fw), - label="total (FW)", color="black", ls="solid" + x_fw, + self.neutron_flux_fw(x_fw), + label="total (FW)", + color="black", + ls="solid", ) ax.plot( - x_bz_right, self.neutron_flux_bz(x_bz_right), - color="black", ls=(0, (3, 1, 1, 1)) + x_bz_right, + self.neutron_flux_bz(x_bz_right), + color="black", + ls=(0, (3, 1, 1, 1)), ) if plot_groups: for n in range(self.n_groups): x_bz_left, x_fw, x_bz_right = _generate_x_range( - self.extended_boundary[n], n_points, - symmetric, self.x_fw_cm + self.extended_boundary[n], + n_points, + symmetric, + self.x_fw_cm, ) ax.plot( - x_bz_left, self.neutron_flux_bz(x_bz_left), - label=f"group {n+1} (BZ)", color=f"C{n}", ls=(0, (3, 1, 1, 1)) + x_bz_left, + self.neutron_flux_bz(x_bz_left), + label=f"group {n + 1} (BZ)", + color=f"C{n}", + ls=(0, (3, 1, 1, 1)), ) ax.plot( - x_fw, self.neutron_flux_fw(x_fw), - label=f"group {n+1} (FW)", color=f"C{n}", ls="solid" + x_fw, + self.neutron_flux_fw(x_fw), + label=f"group {n + 1} (FW)", + color=f"C{n}", + ls="solid", ) ax.plot( - x_bz_right, self.neutron_flux_bz(x_bz_right), - color=f"C{n}", ls=(0, (3, 1, 1, 1)) + x_bz_right, + self.neutron_flux_bz(x_bz_right), + color=f"C{n}", + ls=(0, (3, 1, 1, 1)), ) ax.legend() ax.set_title("Neutron flux profile") @@ -649,7 +669,7 @@ def _generate_x_range( x_max_cm: float, approx_n_points: int, symmetric: bool, - fw_bz_split_point_cm: float|None=None + fw_bz_split_point_cm: float | None = None, ): """Helper function for finding the range of x-values to be plotted. @@ -678,7 +698,7 @@ def _generate_x_range( The array of x-values to be used for plotting both the left and right sides of fw. [m] x_range_bz_right: - The array of x-values to be used for plotting the right (positive) + The array of x-values to be used for plotting the right (positive) side of bz. [m] elif (fw_bz_split_point_cm, symmetric) = (float value, False): x_range_fw: @@ -697,13 +717,13 @@ def _generate_x_range( side neutron flux. [m] """ - x_max = x_max_cm/100 + x_max = x_max_cm / 100 if fw_bz_split_point_cm is not None: x_range = np.linspace(0, x_max_cm, approx_n_points) - n_points_fw = (x_range=fw_bz_split_point_cm).sum() + 1 + n_points_fw = (x_range < fw_bz_split_point_cm).sum() + 1 + n_points_bz = (x_range >= fw_bz_split_point_cm).sum() + 1 - split_point = fw_bz_split_point_cm/100 + split_point = fw_bz_split_point_cm / 100 if symmetric: return ( np.linspace(-x_max, -split_point, n_points_bz), diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index a3dbaa4e7f..09c4238353 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -41,25 +41,6 @@ def test_has_reactions(): assert hasattr(NeutronFluxProfile, "reaction_rate_bz") -# 2 groups -# fw_material = MaterialMacroInfo( -# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 1.0 -# ) -# bz_material = MaterialMacroInfo( -# [1.0, 0.5], [[0.5, 0.1], [0, 0.1]], [1000, 100, 0], 2.0 -# ) -# 1 group -fw_material = MaterialMacroInfo([1.0], [[0.5]], [100, 0], 1.0) -bz_material = MaterialMacroInfo([1.0], [[0.5]], [100, 0], 2.0) -profile = NeutronFluxProfile( - 1.0, # flux - 0.01, # 1cm - 0.11, # 10cm thick blanket - fw_material, - bz_material, -) - - def test_against_desmos_number(): dummy = [100, 1] # dummy group structure # translate from mean-free-path lengths (mfp) to macroscopic cross-sections From e50e851eafd764c965ce4dadbf13dbd6dd88fa3b Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 6 Nov 2025 19:49:54 +0000 Subject: [PATCH 35/98] extended_boundary renamed to extended_boundary_cm --- process/neutronics.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 4b87c8e810..ff146f1d99 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -242,14 +242,14 @@ def __init__( # diffusion lengths squared self.l_fw_2 = AutoPopulatingDict(self.solve_group_n, "l_fw_2") self.l_bz_2 = AutoPopulatingDict(self.solve_group_n, "l_bz_2") - self.extended_boundary = AutoPopulatingDict( - self.solve_group_n, "extended_boundary" + self.extended_boundary_cm = AutoPopulatingDict( + self.solve_group_n, "extended_boundary_cm" ) def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. - Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], + Store the solved constants in self.extended_boundary_cm[0], self.l_fw_2[0], self.l_bz_2[0], and self.integration_constants[0]. """ n = 0 @@ -268,7 +268,7 @@ def solve_lowest_group(self) -> None: l_fw = np.sqrt(abs(self.l_fw_2[n])) l_bz = np.sqrt(abs(self.l_bz_2[n])) x_fw, x_bz = self.x_fw_cm, self.x_bz_cm - self.extended_boundary[n] = x_bz + extrapolation_length(d_bz) + self.extended_boundary_cm[n] = x_bz + extrapolation_length(d_bz) if self.l_fw_2[n] > 0: sinh_fw = np.sinh(x_fw / l_fw) cosh_fw = np.cosh(x_fw / l_fw) @@ -278,13 +278,13 @@ def solve_lowest_group(self) -> None: cosh_fw = np.cos(x_fw / l_fw) tanh_fw = np.tan(x_fw / l_fw) if self.l_bz_2[n] > 0: - sinh_bz = np.sinh((self.extended_boundary[n] - x_fw) / l_bz) - cosh_bz = np.cosh((self.extended_boundary[n] - x_fw) / l_bz) - tanh_bz = np.tanh((self.extended_boundary[n] - x_fw) / l_bz) + sinh_bz = np.sinh((self.extended_boundary_cm[n] - x_fw) / l_bz) + cosh_bz = np.cosh((self.extended_boundary_cm[n] - x_fw) / l_bz) + tanh_bz = np.tanh((self.extended_boundary_cm[n] - x_fw) / l_bz) else: - sinh_bz = np.sin((self.extended_boundary[n] - x_fw) / l_bz) - cosh_bz = np.cos((self.extended_boundary[n] - x_fw) / l_bz) - tanh_bz = np.tan((self.extended_boundary[n] - x_fw) / l_bz) + sinh_bz = np.sin((self.extended_boundary_cm[n] - x_fw) / l_bz) + cosh_bz = np.cos((self.extended_boundary_cm[n] - x_fw) / l_bz) + tanh_bz = np.tan((self.extended_boundary_cm[n] - x_fw) / l_bz) c2 = ( self.flux @@ -302,14 +302,14 @@ def solve_lowest_group(self) -> None: * (1 - tanh_fw) / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) ) - c3 = c3_c4_common_factor * np.exp(self.extended_boundary[n] / l_bz) - c4 = -c3_c4_common_factor * np.exp(-self.extended_boundary[n] / l_bz) + c3 = c3_c4_common_factor * np.exp(self.extended_boundary_cm[n] / l_bz) + c4 = -c3_c4_common_factor * np.exp(-self.extended_boundary_cm[n] / l_bz) self.integration_constants[n] = [c1, c2, c3, c4] def solve_group_n(self, n: int) -> None: """ Solve the n-th group of neutron's diffusion equation, where n<=n_groups-1. - Store the solved constants in self.extended_boundary[n-1], self.l_fw_2[n-1], + Store the solved constants in self.extended_boundary_cm[n-1], self.l_fw_2[n-1], self.l_bz_2[n-1], and self.integration_constants[n-1]. Parameters @@ -346,7 +346,7 @@ def solve_group_n(self, n: int) -> None: c2 = ... c3 = ... c4 = ... - self.extended_boundary[n] = self.x_bz_cm + extrapolation_length(d_bz) + self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length(d_bz) self.integration_constants[n] = [c1, c2, c3, c4] return None @@ -434,12 +434,12 @@ def groupwise_neutron_flux_at( in_fw = abs(x * 100) <= self.x_fw_cm in_bz = np.logical_and( self.x_fw_cm < abs(x * 100), - abs(x * 100) <= self.extended_boundary[n], + abs(x * 100) <= self.extended_boundary_cm[n], ) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated " - f"up to {self.extended_boundary[n]} cm, which {x * 100} cm violates!" + f"up to {self.extended_boundary_cm[n]} cm, which {x * 100} cm violates!" ) out_flux = np.zeros_like(x) @@ -606,7 +606,7 @@ def plot( ax = ax or plt.axes() x_bz_left, x_fw, x_bz_right = _generate_x_range( - min(self.extended_boundary.values()), + min(self.extended_boundary_cm.values()), n_points, symmetric, self.x_fw_cm, @@ -635,7 +635,7 @@ def plot( if plot_groups: for n in range(self.n_groups): x_bz_left, x_fw, x_bz_right = _generate_x_range( - self.extended_boundary[n], + self.extended_boundary_cm[n], n_points, symmetric, self.x_fw_cm, @@ -677,8 +677,8 @@ def _generate_x_range( ---------- x_max_cm: absolute value of the maximum x that we want to plot. - This is typically obtained by min(extended_boundary), or - extended_boundary[n] [cm] + This is typically obtained by min(extended_boundary_cm), or + extended_boundary_cm[n] [cm] symmetric: Whether we want to plot the negative side of the x-axis as well, forming a symmetric plot. From f304ca038387e00db914d620be9188fd98ab5cd7 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 7 Nov 2025 11:06:18 +0000 Subject: [PATCH 36/98] Added regression test, and fixed all the little details to make the regression test work. --- process/neutronics.py | 82 ++++++++++++++++++----------- process/neutronics_data.py | 2 + tests/regression/test_neutronics.py | 45 ++++++++++++++++ tests/unit/test_neutronics.py | 26 --------- 4 files changed, 99 insertions(+), 56 deletions(-) create mode 100644 tests/regression/test_neutronics.py diff --git a/process/neutronics.py b/process/neutronics.py index ff146f1d99..cd857e37e3 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -65,7 +65,7 @@ def __set_name__(self, owner, name): def get_diffusion_coefficient_and_length( - total_xs: float, scattering_xs: float, avg_atomic_mass: float + total_xs_cm: float, scattering_xs_cm: float, avg_atomic_mass: float ) -> tuple[float, float]: r""" Calculate the diffusion coefficient for a given scattering and total macro-scopic @@ -73,12 +73,12 @@ def get_diffusion_coefficient_and_length( Parameters ---------- - total_xs: + total_xs_cm: macroscopic total cross-section `\sigma_{total}`, i.e. any reaction between nuclei and neutrons, that either changes the neutron's path or remove it from that energy group. Unit: cm^-1 - scattering_xs: + scattering_xs_cm: macroscopic total cross-section `\sigma_{scatter}`, i.e. number of reactions per unit distance travelled by the neutron that leads to it being scattered (without getting absorbed). @@ -101,10 +101,10 @@ def get_diffusion_coefficient_and_length( unit: [cm] """ - transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs + transport_xs = total_xs_cm - 2 / (3 * avg_atomic_mass) * scattering_xs_cm diffusion_coef = 1 / 3 / transport_xs - diffusion_len_2 = diffusion_coef / (total_xs - scattering_xs) - return diffusion_coef, diffusion_len_2 + diffusion_len_2 = diffusion_coef / (total_xs_cm - scattering_xs_cm) + return diffusion_len_2, diffusion_coef def extrapolation_length(diffusion_coefficient: float) -> float: @@ -176,6 +176,8 @@ def __setitem__(self, i: int, value: float): def values(self): return self._dict.values() + def __repr__(self): + return f"AutoPopulatingDict{self._dict}" class NeutronFluxProfile: """Neutron flux in the first wall or the blanket.""" @@ -210,10 +212,28 @@ def __init__( thickness of the first wall, converted from [m] into [cm]. x_bz_cm: thickness of the blanket + first-wall, converted from [m] into [cm]. + fw_mat: + first wall material information + bz_mat: + blanket material information n_groups: number of groups in the group structure group_structure: energy bin edges, 1D array of len = n_groups+1 + + integration_constants: + Integration constants that determine the flux shape (and therefore + reaction rates and neutron current) of each group. A set of four + constants, two for fw and two for bz; each with unit: [cm^-2 s^-1] + l_fw_2: + square of the characteristic diffusion length as given by Reactor Analysis, + Duderstadt and Hamilton, applied to the fw. + l_bz_2: + square of the characteristic diffusion length as given by Reactor Analysis, + Duderstadt and Hamilton, applied to the bz. + extended_boundary_cm: + extended boundary (outside the bz) for each group, stored in cm. + This value should be larger than x_bz for each of them. """ self.flux = flux # flux incident on the first wall. if not (0 < x_fw < x_bz): @@ -251,18 +271,19 @@ def solve_lowest_group(self) -> None: Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. Store the solved constants in self.extended_boundary_cm[0], self.l_fw_2[0], self.l_bz_2[0], and self.integration_constants[0]. + integration_constants have units of [cm^-2 s^-1]. """ n = 0 if n in self.integration_constants: return # skip if it has already been solved. self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( - self.fw_mat.sigma_t[n], - self.fw_mat.sigma_s[n, n], + self.fw_mat.sigma_t_cm[n], + self.fw_mat.sigma_s_cm[n, n], self.fw_mat.avg_atomic_mass, ) self.l_bz_2[n], d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[n], - self.bz_mat.sigma_s[n, n], + self.bz_mat.sigma_t_cm[n], + self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, ) l_fw = np.sqrt(abs(self.l_fw_2[n])) @@ -302,8 +323,8 @@ def solve_lowest_group(self) -> None: * (1 - tanh_fw) / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) ) - c3 = c3_c4_common_factor * np.exp(self.extended_boundary_cm[n] / l_bz) - c4 = -c3_c4_common_factor * np.exp(-self.extended_boundary_cm[n] / l_bz) + c3 = -c3_c4_common_factor * np.exp(-self.extended_boundary_cm[n] / l_bz) + c4 = c3_c4_common_factor * np.exp(self.extended_boundary_cm[n] / l_bz) self.integration_constants[n] = [c1, c2, c3, c4] def solve_group_n(self, n: int) -> None: @@ -331,13 +352,13 @@ def solve_group_n(self, n: int) -> None: if n in self.integration_constants: return None # skip if it has already been solved. self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( - self.fw_mat.sigma_t[n], - self.fw_mat.sigma_s[n, n], + self.fw_mat.sigma_t_cm[n], + self.fw_mat.sigma_s_cm[n, n], self.fw_mat.avg_atomic_mass, ) self.l_bz_2[n], d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[n], - self.bz_mat.sigma_s[n, n], + self.bz_mat.sigma_t_cm[n], + self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, ) l_fw = np.sqrt(abs(self.l_fw_2[n])) @@ -354,7 +375,8 @@ def solve_group_n(self, n: int) -> None: def groupwise_neutron_flux_fw( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: - """Neutron flux of the n-th group at the first wall, at location x [m]. + """ + Neutron flux[cm^-2 s^-1] of the n-th group at the first wall, at location x [m]. Parameters ---------- @@ -382,7 +404,7 @@ def groupwise_neutron_flux_fw( def groupwise_neutron_flux_bz( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: - """Neutron flux of the n-th groupat the blanket, at location x [m]. + """Neutron flux[cm^-2 s^-1] of the n-th groupat the blanket, at location x [m]. Parameters ---------- @@ -411,7 +433,7 @@ def groupwise_neutron_flux_at( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron flux anywhere within the valid range of x, + Neutron flux [cm^-2 s^-1] anywhere within the valid range of x, i.e. from -self.x_bz_cm to self.x_bz_cm. Parameters @@ -450,7 +472,7 @@ def groupwise_neutron_flux_at( # scalar values (one such float per neutron group.) @summarize_values def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: - """Calculate the reaction rate in the first wall. + """Calculate the reaction rate [s^-1] in the first wall. Parameters ---------- @@ -468,10 +490,10 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: "higher energy groups' fluxes yet." ) c1, c2, c3, c4 = self.integration_constants[n] - if reaction_type == "exclude elastic-scattering": - sigma = self.fw_mat.sigma_t[n] - self.fw_mat.sigma_s[n, n] + if reaction_type == "heating": + sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n, n] elif reaction_type == "total": - sigma = self.fw_mat.sigma_t[n] + sigma = self.fw_mat.sigma_t_cm[n] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" @@ -500,10 +522,10 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: "higher energy groups' fluxes yet." ) c1, c2, c3, c4 = self.integration_constants[n] - if reaction_type == "exclude elastic-scattering": - sigma = self.bz_mat.sigma_t[n] - self.bz_mat.sigma_s[n, n] + if reaction_type == "heating": + sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n, n] elif reaction_type == "total": - sigma = self.bz_mat.sigma_t[n] + sigma = self.bz_mat.sigma_t_cm[n] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" @@ -533,8 +555,8 @@ def groupwise_neutron_current_fw2bz(self, n: int) -> float: """ c1, c2, c3, c4 = self.integration_constants[n] l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[n], - self.bz_mat.sigma_s[n, n], + self.bz_mat.sigma_t_cm[n], + self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, ) l_bz = np.sqrt(abs(l_bz_2)) @@ -566,8 +588,8 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: """ c1, c2, c3, c4 = self.integration_constants[n] l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t[n], - self.bz_mat.sigma_s[n, n], + self.bz_mat.sigma_t_cm[n], + self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, ) l_bz = np.sqrt(abs(l_bz_2)) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index f26ec75119..3a99cd1d18 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -493,6 +493,8 @@ def __post_init__(self): "Group-wise scattering cross-sections be a square matrix of " f"shape n*n, where n= number of groups = {self.n_groups}." ) + self.sigma_t_cm = self.sigma_t/100 + self.sigma_s_cm = self.sigma_s/100 @property def n_groups(self): diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py new file mode 100644 index 0000000000..12ab1d5bcc --- /dev/null +++ b/tests/regression/test_neutronics.py @@ -0,0 +1,45 @@ +import pytest + +from process.neutronics import NeutronFluxProfile +from process.neutronics_data import MaterialMacroInfo + +def test_against_desmos_number(): + """ + Regression test against Desmos snapshot: + https://www.desmos.com/calculator/18xojespuo + """ + dummy = [100, 1] # dummy group structure + # translate from mean-free-path lengths (mfp) to macroscopic cross-sections + # [m] + mfp_fw_s = 118 * 0.01 + mfp_fw_t = 16.65 * 0.01 + sigma_fw_t = 1 / mfp_fw_t # [1/m] + sigma_fw_s = 1 / mfp_fw_s # [1/m] + a_fw = 52 + fw_material = MaterialMacroInfo([sigma_fw_t], [[sigma_fw_s]], dummy, a_fw) + + mfp_bz_s = 97 * 0.01 + mfp_bz_t = 35.8 * 0.01 + sigma_bz_s = 1 / mfp_bz_s # [1/m] + sigma_bz_t = 1 / mfp_bz_t # [1/m] + a_bz = 71 + bz_material = MaterialMacroInfo([sigma_bz_t], [[sigma_bz_s]], dummy, a_bz) + + x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 + incoming_flux = 41 + neutron_profile = NeutronFluxProfile( + incoming_flux, x_fw, x_bz, fw_material, bz_material + ) + + c1, c2, c3, c4 = neutron_profile.integration_constants + assert np.isclose(c1, 78.5454445887), "Integration constant c1." + assert np.isclose(c2, 1.98923249017), "Integration constant c2." + assert np.isclose(c3, -0.0126020377605), "Integration constant c3." + assert np.isclose(c4, 60.6997676395), "Integration constant c4." + + assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), 48.72444) + assert np.isclose(neutron_profile.neutron_flux_bz(x_fw), 48.72444) + assert np.isclose(neutron_profile.neutron_flux_at(x_fw), 48.72444) + + assert np.isclose(neutron_profile.neutron_current_fw2bz(), 22.3980214162) + assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) \ No newline at end of file diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 09c4238353..1825e8852e 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -39,29 +39,3 @@ def test_has_reactions(): assert hasattr(NeutronFluxProfile, "reaction_rate_fw") assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_bz") assert hasattr(NeutronFluxProfile, "reaction_rate_bz") - - -def test_against_desmos_number(): - dummy = [100, 1] # dummy group structure - # translate from mean-free-path lengths (mfp) to macroscopic cross-sections - # [cm] - mfp_fw_s = 118 * 0.01 - mfp_fw_t = 16.65 * 0.01 - sigma_fw_t = 1 / mfp_fw_t # [1/cm] - sigma_fw_s = 1 / mfp_fw_s # [1/cm] - a_fw = 52 - fw_material = MaterialMacroInfo([sigma_fw_t], [[sigma_fw_s]], dummy, a_fw) - - mfp_bz_s = 97 * 0.01 - mfp_bz_t = 35.8 * 0.01 - sigma_bz_s = 1 / mfp_bz_s # [1/cm] - sigma_bz_t = 1 / mfp_bz_t # [1/cm] - a_bz = 71 - bz_material = MaterialMacroInfo([sigma_bz_t], [[sigma_bz_s]], dummy, a_bz) - - x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 - incoming_flux = 41 - neutron_profile = NeutronFluxProfile( - incoming_flux, x_fw, x_bz, fw_material, bz_material - ) - neutron_profile.plot() From abc1f1d2159d1d222e2e9e97853c76b226bdccba Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 7 Nov 2025 11:14:37 +0000 Subject: [PATCH 37/98] regression test fix. --- tests/regression/test_neutronics.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 12ab1d5bcc..7fd83dfd91 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -1,4 +1,5 @@ import pytest +import numpy as np from process.neutronics import NeutronFluxProfile from process.neutronics_data import MaterialMacroInfo @@ -31,9 +32,9 @@ def test_against_desmos_number(): incoming_flux, x_fw, x_bz, fw_material, bz_material ) - c1, c2, c3, c4 = neutron_profile.integration_constants - assert np.isclose(c1, 78.5454445887), "Integration constant c1." - assert np.isclose(c2, 1.98923249017), "Integration constant c2." + c1, c2, c3, c4 = neutron_profile.integration_constants[0] + assert np.isclose(c1, 1.98923249017), "Integration constant c1." + assert np.isclose(c2, 78.5454445887), "Integration constant c2." assert np.isclose(c3, -0.0126020377605), "Integration constant c3." assert np.isclose(c4, 60.6997676395), "Integration constant c4." From 85553a6112121ea8286e3bb9b8e683ad8838ff04 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 7 Nov 2025 13:18:18 +0000 Subject: [PATCH 38/98] Regression test added - conservation in total number of neutrons (they've either achieved 'removal' by reaction or escaped as neutron current. --- process/neutronics.py | 26 ++++++++++++++------------ tests/regression/test_neutronics.py | 8 +++++++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index cd857e37e3..0eba1e27a5 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -480,7 +480,7 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: - Two options: "total" or "exclude elastic-scattering". + string of either {"total","removal"}. """ l_fw = np.sqrt(abs(self.l_fw_2[n])) @@ -490,15 +490,15 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: "higher energy groups' fluxes yet." ) c1, c2, c3, c4 = self.integration_constants[n] - if reaction_type == "heating": - sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n, n] + if reaction_type == "removal": + sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum() elif reaction_type == "total": sigma = self.fw_mat.sigma_t_cm[n] else: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) - return sigma * ( + return sigma * l_fw * ( c1 * expm1(self.x_fw_cm / l_fw) - c2 * expm1(-self.x_fw_cm / l_fw) ) @@ -512,7 +512,7 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: - Two options: "total" or "exclude elastic-scattering". + string of either {"total","removal"}. """ l_bz = np.sqrt(abs(self.l_bz_2[n])) @@ -522,8 +522,8 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: "higher energy groups' fluxes yet." ) c1, c2, c3, c4 = self.integration_constants[n] - if reaction_type == "heating": - sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n, n] + if reaction_type == "removal": + sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum() elif reaction_type == "total": sigma = self.bz_mat.sigma_t_cm[n] else: @@ -533,9 +533,9 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: # thicknesses in terms of bz path lengths bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz fw_thick = self.x_fw_cm / l_bz - return sigma * ( - c3 * np.exp(fw_thick) * expm1(bz_thick) - - c4 * np.exp(-fw_thick) * expm1(-bz_thick) + return sigma * l_bz * ( + c3 * expm1(bz_thick) * np.exp(fw_thick) + - c4 * expm1(-bz_thick) * np.exp(-fw_thick) ) @summarize_values @@ -636,7 +636,6 @@ def plot( ax.plot( x_bz_left, self.neutron_flux_bz(x_bz_left), - label="total (BZ)", color="black", ls=(0, (3, 1, 1, 1)), ) @@ -651,6 +650,7 @@ def plot( x_bz_right, self.neutron_flux_bz(x_bz_right), color="black", + label="total (BZ)", ls=(0, (3, 1, 1, 1)), ) @@ -665,7 +665,6 @@ def plot( ax.plot( x_bz_left, self.neutron_flux_bz(x_bz_left), - label=f"group {n + 1} (BZ)", color=f"C{n}", ls=(0, (3, 1, 1, 1)), ) @@ -679,11 +678,14 @@ def plot( ax.plot( x_bz_right, self.neutron_flux_bz(x_bz_right), + label=f"group {n + 1} (BZ)", color=f"C{n}", ls=(0, (3, 1, 1, 1)), ) ax.legend() ax.set_title("Neutron flux profile") + ax.set_xlabel("Distance from the plasma-fw interface [m]") + ax.set_ylabel("Neutron flux [cm^-2 s^-1]") return ax diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 7fd83dfd91..8e69b3ba6c 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -43,4 +43,10 @@ def test_against_desmos_number(): assert np.isclose(neutron_profile.neutron_flux_at(x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_current_fw2bz(), 22.3980214162) - assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) \ No newline at end of file + assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) + + assert np.isclose(neutron_profile.flux, + neutron_profile.neutron_current_escaped() + + neutron_profile.reaction_rate_fw("removal") + + neutron_profile.reaction_rate_bz("removal") + ) \ No newline at end of file From 9d06fbc2d014ad0f892ae1beea6fb106dfd18ba5 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 00:25:48 +0000 Subject: [PATCH 39/98] Added an IntegrationConstants class, which contains a validation method to make sure it's the right length. --- process/neutronics.py | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 0eba1e27a5..fbb64815c1 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -5,6 +5,8 @@ import functools import inspect +from dataclasses import dataclass, asdict +from typing import Iterable from collections.abc import Callable import numpy as np @@ -12,7 +14,7 @@ from numpy import typing as npt from scipy.special import expm1 -from process.exceptions import ProcessValidationError +from process.exceptions import ProcessValidationError, ProcessValueError from process.neutronics_data import MaterialMacroInfo @@ -121,6 +123,34 @@ def extrapolation_length(diffusion_coefficient: float) -> float: """ return 0.7104 * 3 * diffusion_coefficient +@dataclass +class IntegrationConstants: + """ + Inside each material, there are two new exponentials per group, i.e. + group n=0 has exp(x/L[0]) and exp(-x/L[0]), + group n=1 has exp(x/L[0]), exp(-x/L[0]), exp(x/L[1]) and exp(-x/L[1]), + etc. + To get the neutron flux, each exponential has to be scaled by an integration + constant. E.g. + group n=0: fw: fw_pos[0][0] * exp(x/L[0]) + fw_neg[0][0] * exp(-x/L[0]) + group n=1: fw: fw_pos[1][0] * exp(x/L[0]) + fw_pos[1][1] * exp(x/L[1]) + + fw_neg[1][0] * exp(-x/L[0]) + fw_neg[1][1] * exp(-x/L[1]) + + """ + fw_pos: Iterable[float] + fw_neg: Iterable[float] + bz_pos: Iterable[float] + bz_neg: Iterable[float] + + def validate(self, n): + """Validate that all fields has the correct length.""" + for const_name, const_value in asdict(self): + if len(const_value)!=(n+1): + raise ProcessValueError( + f"Expected {const_name} to have len=={n+1}, " + f"got {len(const_value)} instead." + ) + class AutoPopulatingDict: """ @@ -170,8 +200,10 @@ def __contains__(self, i: int): def __setitem__(self, i: int, value: float): """Check if dict i is in the index or not.""" - self._attempting_to_access.discard(i) + if hasattr(value, "validate"): + value.validate(i) self._dict[i] = value + self._attempting_to_access.discard(i) def values(self): return self._dict.values() From b82b077d76b4c7d4e96cda09f43668455383ca90 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 00:26:43 +0000 Subject: [PATCH 40/98] Made return None more explicit in some places. --- process/neutronics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index fbb64815c1..59712a8443 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -307,7 +307,7 @@ def solve_lowest_group(self) -> None: """ n = 0 if n in self.integration_constants: - return # skip if it has already been solved. + return None # skip if it has already been solved. self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], @@ -378,6 +378,7 @@ def solve_group_n(self, n: int) -> None: ) if n == 0: return self.solve_lowest_group() + # ensure all lower groups are solved. for k in range(n): if k not in self.integration_constants: self.solve_group_n(k) @@ -401,7 +402,6 @@ def solve_group_n(self, n: int) -> None: c4 = ... self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length(d_bz) self.integration_constants[n] = [c1, c2, c3, c4] - return None @summarize_values def groupwise_neutron_flux_fw( From 5bd6608efe9d3b6c4db40e467034c5446549339a Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 00:42:06 +0000 Subject: [PATCH 41/98] self.integration_constants conversion step 1 of 3: groupwise_neutron_flux conversion. --- process/neutronics.py | 45 ++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 59712a8443..78c157a514 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -142,10 +142,10 @@ class IntegrationConstants: bz_pos: Iterable[float] bz_neg: Iterable[float] - def validate(self, n): + def validate_length(self, expected_length: int): """Validate that all fields has the correct length.""" for const_name, const_value in asdict(self): - if len(const_value)!=(n+1): + if len(const_value)!=expected_length: raise ProcessValueError( f"Expected {const_name} to have len=={n+1}, " f"got {len(const_value)} instead." @@ -200,8 +200,8 @@ def __contains__(self, i: int): def __setitem__(self, i: int, value: float): """Check if dict i is in the index or not.""" - if hasattr(value, "validate"): - value.validate(i) + if hasattr(value, "validate_length"): + value.validate_length(i+1) self._dict[i] = value self._attempting_to_access.discard(i) @@ -357,7 +357,10 @@ def solve_lowest_group(self) -> None: ) c3 = -c3_c4_common_factor * np.exp(-self.extended_boundary_cm[n] / l_bz) c4 = c3_c4_common_factor * np.exp(self.extended_boundary_cm[n] / l_bz) - self.integration_constants[n] = [c1, c2, c3, c4] + + self.integration_constants[n] = IntegrationConstants( + [c1], [c2], [c3], [c4] + ) def solve_group_n(self, n: int) -> None: """ @@ -427,10 +430,18 @@ def groupwise_neutron_flux_fw( flux: Neutron flux at x meter from the first wall. """ - c1, c2 = self.integration_constants[n][:2] - l_fw = np.sqrt(abs(self.l_fw_2[n])) - x_l_fw = abs(x * 100) / l_fw - return c1 * np.exp(x_l_fw) + c2 * np.exp(-x_l_fw) + x_cm = abs(x * 100) + + exponentials = [] + for i in range(n+1): + l_fw = np.sqrt(abs(self.l_fw_2[i])) + exponentials.append( + self.integration_constants[n].fw_pos[i] * exp(x_cm/l_fw) + ) + exponentials.append( + self.integration_constants[n].fw_neg[i] * exp(-x_cm/l_fw) + ) + return np.sum(exponential, axis=0) @summarize_values def groupwise_neutron_flux_bz( @@ -455,10 +466,18 @@ def groupwise_neutron_flux_bz( flux: Neutron flux at x meter from the first wall. """ - c3, c4 = self.integration_constants[n][2:] - l_bz = np.sqrt(abs(self.l_bz_2[n])) - x_l_bz = abs(x * 100) / l_bz - return c3 * np.exp(x_l_bz) + c4 * np.exp(-x_l_bz) + x_cm = abs(x * 100) + + exponentials = [] + for i in range(n+1): + l_bz = np.sqrt(abs(self.l_bz_2[i])) + exponentials.append( + self.integration_constants[n].bz_pos[i] * exp(x_cm/l_bz) + ) + exponentials.append( + self.integration_constants[n].bz_neg[i] * exp(-x_cm/l_bz) + ) + return np.sum(exponential, axis=0) @summarize_values def groupwise_neutron_flux_at( From 489976c15ab503a3bf8b3aed35aafe175ee6f4d7 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 00:54:42 +0000 Subject: [PATCH 42/98] Added d_fw and d_bz diffusion constants as attributes of NeutronFluxProfile. --- process/neutronics.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 78c157a514..b72c777a36 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -259,10 +259,14 @@ def __init__( constants, two for fw and two for bz; each with unit: [cm^-2 s^-1] l_fw_2: square of the characteristic diffusion length as given by Reactor Analysis, - Duderstadt and Hamilton, applied to the fw. + Duderstadt and Hamilton, applied to the fw. unit: [cm] l_bz_2: square of the characteristic diffusion length as given by Reactor Analysis, - Duderstadt and Hamilton, applied to the bz. + Duderstadt and Hamilton, applied to the bz. unit: [cm] + d_fw_cm: + diffusion constants in the fw. unit: [cm] + d_bz_cm: + diffusion constants in the bz. unit: [cm] extended_boundary_cm: extended boundary (outside the bz) for each group, stored in cm. This value should be larger than x_bz for each of them. @@ -294,6 +298,8 @@ def __init__( # diffusion lengths squared self.l_fw_2 = AutoPopulatingDict(self.solve_group_n, "l_fw_2") self.l_bz_2 = AutoPopulatingDict(self.solve_group_n, "l_bz_2") + self.d_fw_cm = AutoPopulatingDict(self.solve_group_n, "d_fw_cm") + self.d_bz_cm = AutoPopulatingDict(self.solve_group_n, "d_bz_cm") self.extended_boundary_cm = AutoPopulatingDict( self.solve_group_n, "extended_boundary_cm" ) @@ -308,12 +314,12 @@ def solve_lowest_group(self) -> None: n = 0 if n in self.integration_constants: return None # skip if it has already been solved. - self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( + self.l_fw_2[n], self.d_fw_cm[n] = get_diffusion_coefficient_and_length( self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], self.fw_mat.avg_atomic_mass, ) - self.l_bz_2[n], d_bz = get_diffusion_coefficient_and_length( + self.l_bz_2[n], self.d_bz_cm[n] = get_diffusion_coefficient_and_length( self.bz_mat.sigma_t_cm[n], self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, @@ -321,6 +327,8 @@ def solve_lowest_group(self) -> None: l_fw = np.sqrt(abs(self.l_fw_2[n])) l_bz = np.sqrt(abs(self.l_bz_2[n])) x_fw, x_bz = self.x_fw_cm, self.x_bz_cm + d_fw = self.d_fw_cm[n] + d_bz = self.d_bz_cm[n] self.extended_boundary_cm[n] = x_bz + extrapolation_length(d_bz) if self.l_fw_2[n] > 0: sinh_fw = np.sinh(x_fw / l_fw) @@ -387,12 +395,12 @@ def solve_group_n(self, n: int) -> None: self.solve_group_n(k) if n in self.integration_constants: return None # skip if it has already been solved. - self.l_fw_2[n], d_fw = get_diffusion_coefficient_and_length( + self.l_fw_2[n], self.d_fw_cm[n] = get_diffusion_coefficient_and_length( self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], self.fw_mat.avg_atomic_mass, ) - self.l_bz_2[n], d_bz = get_diffusion_coefficient_and_length( + self.l_bz_2[n], self.d_bz_cm[n] = get_diffusion_coefficient_and_length( self.bz_mat.sigma_t_cm[n], self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, @@ -403,7 +411,7 @@ def solve_group_n(self, n: int) -> None: c2 = ... c3 = ... c4 = ... - self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length(d_bz) + self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length(self.d_bz_cm[n]) self.integration_constants[n] = [c1, c2, c3, c4] @summarize_values @@ -605,14 +613,9 @@ def groupwise_neutron_current_fw2bz(self, n: int) -> float: current in cm^-2 """ c1, c2, c3, c4 = self.integration_constants[n] - l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t_cm[n], - self.bz_mat.sigma_s_cm[n, n], - self.bz_mat.avg_atomic_mass, - ) - l_bz = np.sqrt(abs(l_bz_2)) + l_bz = np.sqrt(abs(self.l_bz_2[n])) return ( - -d_bz + -self.d_bz_cm[n] / l_bz * ( c3 * np.exp(self.x_fw_cm / l_bz) @@ -638,14 +641,9 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: current in cm^-2 """ c1, c2, c3, c4 = self.integration_constants[n] - l_bz_2, d_bz = get_diffusion_coefficient_and_length( - self.bz_mat.sigma_t_cm[n], - self.bz_mat.sigma_s_cm[n, n], - self.bz_mat.avg_atomic_mass, - ) - l_bz = np.sqrt(abs(l_bz_2)) + l_bz = np.sqrt(abs(self.l_bz_2[n])) return ( - -d_bz + -self.d_bz_cm[n] / l_bz * ( c3 * np.exp(self.x_bz_cm / l_bz) From b5de87374023b7a806052fce3aa7ce8ef7e814f8 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 00:55:48 +0000 Subject: [PATCH 43/98] Fixed the ordering of the two arguments outputted by get_diffusion_coefficient_and_length --- process/neutronics.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index b72c777a36..1a3eaec191 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -106,7 +106,7 @@ def get_diffusion_coefficient_and_length( transport_xs = total_xs_cm - 2 / (3 * avg_atomic_mass) * scattering_xs_cm diffusion_coef = 1 / 3 / transport_xs diffusion_len_2 = diffusion_coef / (total_xs_cm - scattering_xs_cm) - return diffusion_len_2, diffusion_coef + return diffusion_coef, diffusion_len_2 def extrapolation_length(diffusion_coefficient: float) -> float: @@ -314,12 +314,12 @@ def solve_lowest_group(self) -> None: n = 0 if n in self.integration_constants: return None # skip if it has already been solved. - self.l_fw_2[n], self.d_fw_cm[n] = get_diffusion_coefficient_and_length( + self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], self.fw_mat.avg_atomic_mass, ) - self.l_bz_2[n], self.d_bz_cm[n] = get_diffusion_coefficient_and_length( + self.d_bz_cm[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( self.bz_mat.sigma_t_cm[n], self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, @@ -395,12 +395,12 @@ def solve_group_n(self, n: int) -> None: self.solve_group_n(k) if n in self.integration_constants: return None # skip if it has already been solved. - self.l_fw_2[n], self.d_fw_cm[n] = get_diffusion_coefficient_and_length( + self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], self.fw_mat.avg_atomic_mass, ) - self.l_bz_2[n], self.d_bz_cm[n] = get_diffusion_coefficient_and_length( + self.d_bz_cm[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( self.bz_mat.sigma_t_cm[n], self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, From 943bdeb8c148332eb74b459075e8c658bc1c20d0 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 02:52:03 +0000 Subject: [PATCH 44/98] self.integration_constants conversion step 2 of 3: solve_group_n conversion. --- process/neutronics.py | 112 ++++++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 26 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 1a3eaec191..67e38c6b0f 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -5,9 +5,8 @@ import functools import inspect -from dataclasses import dataclass, asdict -from typing import Iterable -from collections.abc import Callable +from collections.abc import Callable, Iterable +from dataclasses import asdict, dataclass import numpy as np from matplotlib import pyplot as plt @@ -123,6 +122,7 @@ def extrapolation_length(diffusion_coefficient: float) -> float: """ return 0.7104 * 3 * diffusion_coefficient + @dataclass class IntegrationConstants: """ @@ -137,6 +137,7 @@ class IntegrationConstants: + fw_neg[1][0] * exp(-x/L[0]) + fw_neg[1][1] * exp(-x/L[1]) """ + fw_pos: Iterable[float] fw_neg: Iterable[float] bz_pos: Iterable[float] @@ -144,10 +145,10 @@ class IntegrationConstants: def validate_length(self, expected_length: int): """Validate that all fields has the correct length.""" - for const_name, const_value in asdict(self): - if len(const_value)!=expected_length: + for const_name, const_value in asdict(self).items(): + if len(const_value) != expected_length: raise ProcessValueError( - f"Expected {const_name} to have len=={n+1}, " + f"Expected {const_name} to have len=={expected_length}, " f"got {len(const_value)} instead." ) @@ -201,7 +202,7 @@ def __contains__(self, i: int): def __setitem__(self, i: int, value: float): """Check if dict i is in the index or not.""" if hasattr(value, "validate_length"): - value.validate_length(i+1) + value.validate_length(i + 1) self._dict[i] = value self._attempting_to_access.discard(i) @@ -211,6 +212,7 @@ def values(self): def __repr__(self): return f"AutoPopulatingDict{self._dict}" + class NeutronFluxProfile: """Neutron flux in the first wall or the blanket.""" @@ -313,7 +315,7 @@ def solve_lowest_group(self) -> None: """ n = 0 if n in self.integration_constants: - return None # skip if it has already been solved. + return # skip if it has already been solved. self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], @@ -363,12 +365,15 @@ def solve_lowest_group(self) -> None: * (1 - tanh_fw) / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) ) - c3 = -c3_c4_common_factor * np.exp(-self.extended_boundary_cm[n] / l_bz) + c3 = -c3_c4_common_factor * np.exp( + -self.extended_boundary_cm[n] / l_bz + ) c4 = c3_c4_common_factor * np.exp(self.extended_boundary_cm[n] / l_bz) self.integration_constants[n] = IntegrationConstants( [c1], [c2], [c3], [c4] ) + return def solve_group_n(self, n: int) -> None: """ @@ -405,14 +410,60 @@ def solve_group_n(self, n: int) -> None: self.bz_mat.sigma_s_cm[n, n], self.bz_mat.avg_atomic_mass, ) - l_fw = np.sqrt(abs(self.l_fw_2[n])) - l_bz = np.sqrt(abs(self.l_bz_2[n])) + self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length( + self.d_bz_cm[n] + ) + + # Setting up aliases for shorter code + l_fw_2, l_bz_2 = self.l_fw_2[n], self.l_bz_2[n] + d_fw, d_bz = self.d_fw_cm[n], self.d_bz_cm[n] + ic = self.integration_constants + fw_sigma_s, bz_sigma_s = self.fw_mat.sigma_s, self.bz_mat.sigma_s + + _ic_n = IntegrationConstants([], [], [], []) + for g in range(n): + if np.isclose(diff_fw := self.l_fw_2[g] - l_fw_2, 0): + raise ProcessValueError( + f"Singularity encountered when calculating group {n}'s " + "flux in fw, specifically the scale factor for the exponential " + f"used to cancel out the group {g}'s neutron fluxes." + ) + if np.isclose(diff_bz := self.l_bz_2[g] - l_bz_2, 0): + raise ProcessValueError( + f"Singularity encountered when calculating group {n}'s " + "flux in bz, specifically the scale factor for the exponential " + f"used to cancel out the group {g}'s neutron fluxes." + ) + scale_factor_fw = (l_fw_2 * self.l_fw_2[g]) / d_fw / diff_fw + scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz + _ic_n.fw_pos.append( + sum(fw_sigma_s[i, n] * ic[i].fw_pos[g] for i in range(g, n)) + * scale_factor_fw + ) + _ic_n.fw_neg.append( + sum(fw_sigma_s[i, n] * ic[i].fw_neg[g] for i in range(g, n)) + * scale_factor_fw + ) + _ic_n.bz_pos.append( + sum(bz_sigma_s[i, n] * ic[i].bz_pos[g] for i in range(g, n)) + * scale_factor_bz + ) + _ic_n.bz_neg.append( + sum(bz_sigma_s[i, n] * ic[i].bz_neg[g] for i in range(g, n)) + * scale_factor_bz + ) + l_fw = np.sqrt(abs(l_fw_2)) + l_bz = np.sqrt(abs(l_bz_2)) c1 = ... c2 = ... c3 = ... c4 = ... - self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length(self.d_bz_cm[n]) - self.integration_constants[n] = [c1, c2, c3, c4] + _ic_n.fw_pos.append(c1) + _ic_n.fw_neg.append(c2) + _ic_n.bz_pos.append(c3) + _ic_n.bz_neg.append(c4) + self.integration_constants[n] = _ic_n + return None @summarize_values def groupwise_neutron_flux_fw( @@ -441,15 +492,15 @@ def groupwise_neutron_flux_fw( x_cm = abs(x * 100) exponentials = [] - for i in range(n+1): + for i in range(n + 1): l_fw = np.sqrt(abs(self.l_fw_2[i])) exponentials.append( - self.integration_constants[n].fw_pos[i] * exp(x_cm/l_fw) + self.integration_constants[n].fw_pos[i] * np.exp(x_cm / l_fw) ) exponentials.append( - self.integration_constants[n].fw_neg[i] * exp(-x_cm/l_fw) + self.integration_constants[n].fw_neg[i] * np.exp(-x_cm / l_fw) ) - return np.sum(exponential, axis=0) + return np.sum(exponentials, axis=0) @summarize_values def groupwise_neutron_flux_bz( @@ -477,15 +528,15 @@ def groupwise_neutron_flux_bz( x_cm = abs(x * 100) exponentials = [] - for i in range(n+1): + for i in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[i])) exponentials.append( - self.integration_constants[n].bz_pos[i] * exp(x_cm/l_bz) + self.integration_constants[n].bz_pos[i] * np.exp(x_cm / l_bz) ) exponentials.append( - self.integration_constants[n].bz_neg[i] * exp(-x_cm/l_bz) + self.integration_constants[n].bz_neg[i] * np.exp(-x_cm / l_bz) ) - return np.sum(exponential, axis=0) + return np.sum(exponentials, axis=0) @summarize_values def groupwise_neutron_flux_at( @@ -557,8 +608,13 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) - return sigma * l_fw * ( - c1 * expm1(self.x_fw_cm / l_fw) - c2 * expm1(-self.x_fw_cm / l_fw) + return ( + sigma + * l_fw + * ( + c1 * expm1(self.x_fw_cm / l_fw) + - c2 * expm1(-self.x_fw_cm / l_fw) + ) ) @summarize_values @@ -592,9 +648,13 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: # thicknesses in terms of bz path lengths bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz fw_thick = self.x_fw_cm / l_bz - return sigma * l_bz * ( - c3 * expm1(bz_thick) * np.exp(fw_thick) - - c4 * expm1(-bz_thick) * np.exp(-fw_thick) + return ( + sigma + * l_bz + * ( + c3 * expm1(bz_thick) * np.exp(fw_thick) + - c4 * expm1(-bz_thick) * np.exp(-fw_thick) + ) ) @summarize_values From 868d07c4ab32d5454a5620fe9092a279988dd4b4 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 04:25:44 +0000 Subject: [PATCH 45/98] self.integration_constants conversion step 3 of 3: neutron current and reaction rate conversion. Conversion is now complete. --- process/neutronics.py | 118 +++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 67e38c6b0f..1265ba642f 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -492,13 +492,13 @@ def groupwise_neutron_flux_fw( x_cm = abs(x * 100) exponentials = [] - for i in range(n + 1): - l_fw = np.sqrt(abs(self.l_fw_2[i])) + for g in range(n + 1): + l_fw = np.sqrt(abs(self.l_fw_2[g])) exponentials.append( - self.integration_constants[n].fw_pos[i] * np.exp(x_cm / l_fw) + self.integration_constants[n].fw_pos[g] * np.exp(x_cm / l_fw) ) exponentials.append( - self.integration_constants[n].fw_neg[i] * np.exp(-x_cm / l_fw) + self.integration_constants[n].fw_neg[g] * np.exp(-x_cm / l_fw) ) return np.sum(exponentials, axis=0) @@ -528,13 +528,13 @@ def groupwise_neutron_flux_bz( x_cm = abs(x * 100) exponentials = [] - for i in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[i])) + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) exponentials.append( - self.integration_constants[n].bz_pos[i] * np.exp(x_cm / l_bz) + self.integration_constants[n].bz_pos[g] * np.exp(x_cm / l_bz) ) exponentials.append( - self.integration_constants[n].bz_neg[i] * np.exp(-x_cm / l_bz) + self.integration_constants[n].bz_neg[g] * np.exp(-x_cm / l_bz) ) return np.sum(exponentials, axis=0) @@ -593,13 +593,6 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: string of either {"total","removal"}. """ - l_fw = np.sqrt(abs(self.l_fw_2[n])) - if n > 0: - raise NotImplementedError( - "We have not done the integration for " - "higher energy groups' fluxes yet." - ) - c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "removal": sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum() elif reaction_type == "total": @@ -608,14 +601,17 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) - return ( - sigma - * l_fw - * ( - c1 * expm1(self.x_fw_cm / l_fw) - - c2 * expm1(-self.x_fw_cm / l_fw) + + integrals = [] + for g in range(n + 1): + l_fw = np.sqrt(abs(self.l_fw_2[g])) + integrals.append( + l_fw * self.integration_constants[n].fw_pos[g] * expm1(self.x_fw_cm / l_fw) ) - ) + integrals.append( + - l_fw * self.integration_constants[n].fw_neg[g] * expm1(-self.x_fw_cm / l_fw) + ) + return sigma * np.sum(integrals, axis=0) @summarize_values def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: @@ -630,13 +626,6 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: string of either {"total","removal"}. """ - l_bz = np.sqrt(abs(self.l_bz_2[n])) - if n > 0: - raise NotImplementedError( - "We have not done the integration for " - "higher energy groups' fluxes yet." - ) - c1, c2, c3, c4 = self.integration_constants[n] if reaction_type == "removal": sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum() elif reaction_type == "total": @@ -646,16 +635,21 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: f"Not yet implemented the reaction type {reaction_type}" ) # thicknesses in terms of bz path lengths - bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz - fw_thick = self.x_fw_cm / l_bz - return ( - sigma - * l_bz - * ( - c3 * expm1(bz_thick) * np.exp(fw_thick) - - c4 * expm1(-bz_thick) * np.exp(-fw_thick) + + integrals = [] + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz + fw_thick = self.x_fw_cm / l_bz + integrals.append( + l_bz * self.integration_constants[n].bz_pos[g] + * expm1(bz_thick) * np.exp(fw_thick) ) - ) + integrals.append( + - l_bz * self.integration_constants[n].bz_neg[g] + * expm1(-bz_thick) * np.exp(-fw_thick) + ) + return sigma * np.sum(integrals, axis=0) @summarize_values def groupwise_neutron_current_fw2bz(self, n: int) -> float: @@ -672,18 +666,27 @@ def groupwise_neutron_current_fw2bz(self, n: int) -> float: : current in cm^-2 """ - c1, c2, c3, c4 = self.integration_constants[n] - l_bz = np.sqrt(abs(self.l_bz_2[n])) - return ( - -self.d_bz_cm[n] - / l_bz - * ( - c3 * np.exp(self.x_fw_cm / l_bz) - - c4 * np.exp(-self.x_fw_cm / l_bz) + differentials = [] + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + differentials.append( + 1/ l_bz * self.integration_constants[n].bz_pos[g] * np.exp(self.x_fw_cm / l_bz) ) - ) - # equivalent definition below: (should yield the same answer) - # return - d_fw / l_fw * (c1 * np.exp(x_fw/l_fw) - c2 * np.exp(-x_fw/l_fw)) + differentials.append( + - 1/l_bz * self.integration_constants[n].bz_neg[g] * np.exp(-self.x_fw_cm / l_bz) + ) + return - self.d_bz_cm[n] * np.sum(differentials, axis=0) + + # # equivalent definition below: (should yield the same answer) + # for g in range(n + 1): + # l_fw = np.sqrt(abs(self.l_fw_2[g])) + # differentials.append( + # 1/ l_fw * self.integration_constants[n].fw_pos[g] * np.exp(self.x_fw_cm / l_fw) + # ) + # differentials.append( + # - 1/l_fw * self.integration_constants[n].fw_neg[g] * np.exp(-self.x_fw_cm / l_fw) + # ) + # return - self.d_fw_cm[n] * np.sum(differentials, axis=0) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -700,16 +703,15 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: : current in cm^-2 """ - c1, c2, c3, c4 = self.integration_constants[n] - l_bz = np.sqrt(abs(self.l_bz_2[n])) - return ( - -self.d_bz_cm[n] - / l_bz - * ( - c3 * np.exp(self.x_bz_cm / l_bz) - - c4 * np.exp(-self.x_bz_cm / l_bz) + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + differentials.append( + 1/ l_bz * self.integration_constants[n].bz_pos[g] * np.exp(self.x_bz_cm / l_bz) ) - ) + differentials.append( + - 1/l_bz * self.integration_constants[n].bz_neg[g] * np.exp(-self.x_bz_cm / l_bz) + ) + return - self.d_bz_cm[n] * np.sum(differentials, axis=0) def plot( self, From aa3525d05c5611b3155eb09d9e4600d2719f3377 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 04:32:32 +0000 Subject: [PATCH 46/98] Fixed regression test --- process/neutronics.py | 1 + tests/regression/test_neutronics.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 1265ba642f..3e5252a9e2 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -703,6 +703,7 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: : current in cm^-2 """ + differentials = [] for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) differentials.append( diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 8e69b3ba6c..5fd6e9b1ab 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -32,11 +32,11 @@ def test_against_desmos_number(): incoming_flux, x_fw, x_bz, fw_material, bz_material ) - c1, c2, c3, c4 = neutron_profile.integration_constants[0] - assert np.isclose(c1, 1.98923249017), "Integration constant c1." - assert np.isclose(c2, 78.5454445887), "Integration constant c2." - assert np.isclose(c3, -0.0126020377605), "Integration constant c3." - assert np.isclose(c4, 60.6997676395), "Integration constant c4." + const = neutron_profile.integration_constants[0] # alias to fit line width + assert np.isclose(const.fw_pos, 1.98923249017), "c1" + assert np.isclose(const.fw_neg, 78.5454445887), "c2" + assert np.isclose(const.bz_pos, -0.0126020377605), "c3" + assert np.isclose(const.bz_neg, 60.6997676395), "c4" assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_bz(x_fw), 48.72444) @@ -49,4 +49,6 @@ def test_against_desmos_number(): neutron_profile.neutron_current_escaped() + neutron_profile.reaction_rate_fw("removal") + neutron_profile.reaction_rate_bz("removal") - ) \ No newline at end of file + ) +def test_one_group_with_fission(): + """Expecting a cosine-shape (dome shape!) of neutron flux profile""" From 0b85ff3af095d2ce0477859c7d6c4837108994fd Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 9 Nov 2025 06:36:06 +0000 Subject: [PATCH 47/98] Wrote up the solver for higher order groups, not tested yet. --- process/neutronics.py | 293 ++++++++++++++++++++++++++++++------------ 1 file changed, 210 insertions(+), 83 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 3e5252a9e2..38ea8a21fb 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -12,6 +12,7 @@ from matplotlib import pyplot as plt from numpy import typing as npt from scipy.special import expm1 +from scipy import optimize from process.exceptions import ProcessValidationError, ProcessValueError from process.neutronics_data import MaterialMacroInfo @@ -398,6 +399,10 @@ def solve_group_n(self, n: int) -> None: for k in range(n): if k not in self.integration_constants: self.solve_group_n(k) + if self.fw_mat.contains_upscatter or self.bz_mat.contains_upscatter: + raise NotImplementedError( + "Will implement solve_group_n in a loop later..." + ) if n in self.integration_constants: return None # skip if it has already been solved. self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( @@ -452,16 +457,48 @@ def solve_group_n(self, n: int) -> None: sum(bz_sigma_s[i, n] * ic[i].bz_neg[g] for i in range(g, n)) * scale_factor_bz ) - l_fw = np.sqrt(abs(l_fw_2)) - l_bz = np.sqrt(abs(l_bz_2)) - c1 = ... - c2 = ... - c3 = ... - c4 = ... + + c1, c2, c3, c4 = 0.0, 0.0, 0.0, 0.0 _ic_n.fw_pos.append(c1) _ic_n.fw_neg.append(c2) _ic_n.bz_pos.append(c3) _ic_n.bz_neg.append(c4) + + def set_constants(input_vector: Iterable[float]): + c1, c2, c3, c4 = input_vector + _ic_n.fw_pos[n] = c1 + _ic_n.fw_neg[n] = c2 + _ic_n.bz_pos[n] = c3 + _ic_n.bz_neg[n] = c4 + + def evaluate_fit(): + flux_continuity = _groupwise_neutron_flux_fw(_ic_n, self, n, self.x_fw_cm) - _groupwise_neutron_flux_bz(_ic_n, self, n, self.x_fw_cm) + flux_at_boundary = _groupwise_neutron_flux_bz(_ic_n, self, n, self.extended_boundary_cm[n]) + current_continuity = _groupwise_neutron_current_fw2bz(_ic_n, self, n, True) - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) + influx_fw, influx_bz = 0.0, 0.0 + for g in range(n): + influx_fw += self.fw_mat.sigma_s_cm[g,n] * _groupwise_integrated_flux_fw(self.integration_constants[g], self, g) + influx_bz += self.bz_mat.sigma_s_cm[g,n] * _groupwise_integrated_flux_bz(self.integration_constants[g], self, g) + removal_fw = (self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum()) * _groupwise_neutron_flux_fw(_ic_n, self, n) + removal_bz = (self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum()) * _groupwise_neutron_flux_bz(_ic_n, self, n) + neutron_conservation = influx_fw + influx_bz - removal_fw - removal_bz - _groupwise_neutron_current_escaped(_ic_n, self, n) + # in fact, we can separate the last condition (neutron conservation) + # into two regions: fw and bz + # which gives: + # conservation_fw = influx_fw - removal_fw - _groupwise_neutron_current_fw2bz(_ic_n, self, n, True) + # conservation_bz = influx_bz - removal_bz - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) - _groupwise_neutron_current_escaped(_ic_n, self, n) + return np.array([ + flux_continuity, + flux_at_boundary, + current_continuity, + neutron_conservation, + ]) + + def objective(four_integration_constants_vector): + set_constants(four_integration_constants_vector) + return evaluate_fit() + + optimize.root(set_constants, x0=[c1,c2,c3,c4]) self.integration_constants[n] = _ic_n return None @@ -491,16 +528,9 @@ def groupwise_neutron_flux_fw( """ x_cm = abs(x * 100) - exponentials = [] - for g in range(n + 1): - l_fw = np.sqrt(abs(self.l_fw_2[g])) - exponentials.append( - self.integration_constants[n].fw_pos[g] * np.exp(x_cm / l_fw) - ) - exponentials.append( - self.integration_constants[n].fw_neg[g] * np.exp(-x_cm / l_fw) - ) - return np.sum(exponentials, axis=0) + return _groupwise_neutron_flux_fw( + self.integration_constants[n], self, n, x_cm, + ) @summarize_values def groupwise_neutron_flux_bz( @@ -527,16 +557,9 @@ def groupwise_neutron_flux_bz( """ x_cm = abs(x * 100) - exponentials = [] - for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - exponentials.append( - self.integration_constants[n].bz_pos[g] * np.exp(x_cm / l_bz) - ) - exponentials.append( - self.integration_constants[n].bz_neg[g] * np.exp(-x_cm / l_bz) - ) - return np.sum(exponentials, axis=0) + return _groupwise_neutron_flux_bz( + self.integration_constants[n], self, n, x_cm, + ) @summarize_values def groupwise_neutron_flux_at( @@ -601,17 +624,9 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) - - integrals = [] - for g in range(n + 1): - l_fw = np.sqrt(abs(self.l_fw_2[g])) - integrals.append( - l_fw * self.integration_constants[n].fw_pos[g] * expm1(self.x_fw_cm / l_fw) - ) - integrals.append( - - l_fw * self.integration_constants[n].fw_neg[g] * expm1(-self.x_fw_cm / l_fw) - ) - return sigma * np.sum(integrals, axis=0) + return sigma * _groupwise_integrated_flux_fw( + self.integration_constants[n], self, n, + ) @summarize_values def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: @@ -634,22 +649,11 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: raise NotImplementedError( f"Not yet implemented the reaction type {reaction_type}" ) - # thicknesses in terms of bz path lengths - integrals = [] - for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz - fw_thick = self.x_fw_cm / l_bz - integrals.append( - l_bz * self.integration_constants[n].bz_pos[g] - * expm1(bz_thick) * np.exp(fw_thick) - ) - integrals.append( - - l_bz * self.integration_constants[n].bz_neg[g] - * expm1(-bz_thick) * np.exp(-fw_thick) - ) - return sigma * np.sum(integrals, axis=0) + return sigma * _groupwise_integrated_flux_bz( + self.integration_constants[n], self, n, + ) + @summarize_values def groupwise_neutron_current_fw2bz(self, n: int) -> float: @@ -666,27 +670,9 @@ def groupwise_neutron_current_fw2bz(self, n: int) -> float: : current in cm^-2 """ - differentials = [] - for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - differentials.append( - 1/ l_bz * self.integration_constants[n].bz_pos[g] * np.exp(self.x_fw_cm / l_bz) - ) - differentials.append( - - 1/l_bz * self.integration_constants[n].bz_neg[g] * np.exp(-self.x_fw_cm / l_bz) - ) - return - self.d_bz_cm[n] * np.sum(differentials, axis=0) - - # # equivalent definition below: (should yield the same answer) - # for g in range(n + 1): - # l_fw = np.sqrt(abs(self.l_fw_2[g])) - # differentials.append( - # 1/ l_fw * self.integration_constants[n].fw_pos[g] * np.exp(self.x_fw_cm / l_fw) - # ) - # differentials.append( - # - 1/l_fw * self.integration_constants[n].fw_neg[g] * np.exp(-self.x_fw_cm / l_fw) - # ) - # return - self.d_fw_cm[n] * np.sum(differentials, axis=0) + return _groupwise_neutron_current_fw2bz( + self.integration_constants[n], self, n, False + ) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -703,16 +689,10 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: : current in cm^-2 """ - differentials = [] - for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - differentials.append( - 1/ l_bz * self.integration_constants[n].bz_pos[g] * np.exp(self.x_bz_cm / l_bz) - ) - differentials.append( - - 1/l_bz * self.integration_constants[n].bz_neg[g] * np.exp(-self.x_bz_cm / l_bz) - ) - return - self.d_bz_cm[n] * np.sum(differentials, axis=0) + return _groupwise_neutron_current_escaped( + self.integration_constants[n], self, n, + ) + def plot( self, @@ -800,6 +780,153 @@ def plot( ax.set_ylabel("Neutron flux [cm^-2 s^-1]") return ax +def _groupwise_neutron_flux_fw( + int_const: IntegrationConstants, + self: NeutronFluxProfile, n: int, x_cm: float | npt.NDArray, +) -> npt.NDArray: + """ + Calculate groupwise_neutron_flux_fw for NeutronFluxProfile, but + in such a way that doesn't trigger the re-calculation of integration_constants + (which would've led to RecursionError if called within solve_group_n). + """ + exponentials = [] + for g in range(n + 1): + l_fw = np.sqrt(abs(self.l_fw_2[g])) + exponentials.append( + int_const.fw_pos[g] * np.exp(x_cm / l_fw) + ) + exponentials.append( + int_const.fw_neg[g] * np.exp(-x_cm / l_fw) + ) + return np.sum(exponentials, axis=0) + +def _groupwise_neutron_flux_bz( + int_const: IntegrationConstants, + self: NeutronFluxProfile, n: int, x_cm: float | npt.NDArray, +) -> npt.NDArray: + """ + Calculate groupwise_neutron_flux_bz for NeutronFluxProfile, but + in such a way that doesn't trigger the re-calculation of integration_constants + (which would've led to RecursionError if called within solve_group_n). + """ + exponentials = [] + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + exponentials.append( + int_const.bz_pos[g] * np.exp(x_cm / l_bz) + ) + exponentials.append( + int_const.bz_neg[g] * np.exp(-x_cm / l_bz) + ) + return np.sum(exponentials, axis=0) + +def _groupwise_integrated_flux_fw( + int_const: IntegrationConstants, + self: NeutronFluxProfile, n: int +) -> float: + """ + Help calculate groupwise_reaction_rate_fw for NeutronFluxProfile, but + in such a way that doesn't trigger the re-calculation of integration_constants + (which would've led to RecursionError if called within solve_group_n). + """ + + integrals = [] + for g in range(n + 1): + l_fw = np.sqrt(abs(self.l_fw_2[g])) + integrals.append( + l_fw * int_const.fw_pos[g] * expm1(self.x_fw_cm / l_fw) + ) + integrals.append( + - l_fw * int_const.fw_neg[g] * expm1(-self.x_fw_cm / l_fw) + ) + return np.sum(integrals, axis=0) + +def _groupwise_integrated_flux_bz( + int_const: IntegrationConstants, + self: NeutronFluxProfile, n: int +) -> float: + """ + Help calculate groupwise_reaction_rate_bz for NeutronFluxProfile, but + in such a way that doesn't trigger the re-calculation of integration_constants + (which would've led to RecursionError if called within solve_group_n). + """ + + integrals = [] + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz + fw_thick = self.x_fw_cm / l_bz + integrals.append( + l_bz * int_const.bz_pos[g] + * expm1(bz_thick) * np.exp(fw_thick) + ) + integrals.append( + - l_bz * int_const.bz_neg[g] + * expm1(-bz_thick) * np.exp(-fw_thick) + ) + return np.sum(integrals, axis=0) + + +def _groupwise_neutron_current_fw2bz( + int_const: IntegrationConstants, self: NeutronFluxProfile, n: int, + alt_implementation: bool=False +) -> float: + """ + Calculate groupwise_neutron_current_fw2bz for NeutronFluxProfile, but + in such a way that doesn't trigger the re-calculation of integration_constants + (which would've led to RecursionError if called within solve_group_n). + + Returns + ------- + : + current in cm^-2 + """ + differentials = [] + if alt_implementation: + for g in range(n + 1): + l_fw = np.sqrt(abs(self.l_fw_2[g])) + differentials.append( + 1/ l_fw * int_const.fw_pos[g] * np.exp(self.x_fw_cm / l_fw) + ) + differentials.append( + - 1/l_fw * int_const.fw_neg[g] * np.exp(-self.x_fw_cm / l_fw) + ) + return - self.d_fw_cm[n] * np.sum(differentials, axis=0) + + # equivalent definition below: (should yield the same answer once converged) + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + differentials.append( + 1/ l_bz * int_const.bz_pos[g] * np.exp(self.x_fw_cm / l_bz) + ) + differentials.append( + - 1/l_bz * int_const.bz_neg[g] * np.exp(-self.x_fw_cm / l_bz) + ) + return - self.d_bz_cm[n] * np.sum(differentials, axis=0) + +def _groupwise_neutron_current_escaped( + int_const: IntegrationConstants, self: NeutronFluxProfile, n: int, +) -> float: + """ + Calculate groupwise_neutron_current_escaped for NeutronFluxProfile, but + in such a way that doesn't trigger the re-calculation of integration_constants + (which would've led to RecursionError if called within solve_group_n). + + Returns + ------- + : + current in cm^-2 + """ + differentials = [] + for g in range(n + 1): + l_bz = np.sqrt(abs(self.l_bz_2[g])) + differentials.append( + 1/ l_bz * int_const.bz_pos[g] * np.exp(self.x_bz_cm / l_bz) + ) + differentials.append( + - 1/l_bz * int_const.bz_neg[g] * np.exp(-self.x_bz_cm / l_bz) + ) + return - self.d_bz_cm[n] * np.sum(differentials, axis=0) def _generate_x_range( x_max_cm: float, From 5640fbabef838b544dd7a0af12d14e83e20b5c7e Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 11 Nov 2025 14:36:15 +0000 Subject: [PATCH 48/98] Handled events of same-characteristic-lengths more gracefully. --- process/neutronics.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 38ea8a21fb..0eb820b7c3 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -427,20 +427,18 @@ def solve_group_n(self, n: int) -> None: _ic_n = IntegrationConstants([], [], [], []) for g in range(n): + # if the characteristic length of group [g] coincides with the + # characteristic length of group [n], then that particular + # exponential would be indistinguishable from group [n]'s + # exponential anyways, therefore we can set the coefficient to 0. if np.isclose(diff_fw := self.l_fw_2[g] - l_fw_2, 0): - raise ProcessValueError( - f"Singularity encountered when calculating group {n}'s " - "flux in fw, specifically the scale factor for the exponential " - f"used to cancel out the group {g}'s neutron fluxes." - ) + scale_factor_fw = 0.0 + else: + scale_factor_fw = (l_fw_2 * self.l_fw_2[g]) / d_fw / diff_fw if np.isclose(diff_bz := self.l_bz_2[g] - l_bz_2, 0): - raise ProcessValueError( - f"Singularity encountered when calculating group {n}'s " - "flux in bz, specifically the scale factor for the exponential " - f"used to cancel out the group {g}'s neutron fluxes." - ) - scale_factor_fw = (l_fw_2 * self.l_fw_2[g]) / d_fw / diff_fw - scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz + scale_factor_bz = 0.0 + else: + scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz _ic_n.fw_pos.append( sum(fw_sigma_s[i, n] * ic[i].fw_pos[g] for i in range(g, n)) * scale_factor_fw From ec61dec10d51b5490d30f66afd6bc4f22e87ec25 Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 11 Nov 2025 17:52:06 +0000 Subject: [PATCH 49/98] Added validation to warn when there's elastic upscatter, or error when there's too much scattering cross-section, or warn when group structure bin edges reaching 0. --- process/neutronics_data.py | 35 ++++++++++++++++++------- tests/unit/test_neutronics.py | 49 +++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 3a99cd1d18..3daad19bcd 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -1,3 +1,4 @@ +import warnings from dataclasses import dataclass from itertools import islice, pairwise from pathlib import Path @@ -470,19 +471,26 @@ def __post_init__(self): shapes are correct. """ # force into float or numpy arrays of floats. + self.group_structure = np.array(self.group_structure, dtype=float) + self.avg_atomic_mass = float(self.avg_atomic_mass) self.sigma_t = np.array(self.sigma_t, dtype=float) self.sigma_s = np.array(self.sigma_s, dtype=float) - self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) - self.avg_atomic_mass = float(self.avg_atomic_mass) - - if (np.diff(self.group_structure) > 0).any(): + if self.sigma_in: + self.sigma_in = np.array(self.sigma_in, dtype=float) + else: + self.sigma_in = np.zeros_like(self.sigma_s) + + if (self.group_structure<=0).any(): + warnings.warn("Zero energy (inf. lethargy) not allowed.") + self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) + if (np.diff(self.group_structure) >= 0).any(): raise ValueError( - "The group structure must be defined beginning from the highest energy " - "bin (i.e. lowest lethargy bin) edge, descending to the lowest energy. " - "Similarly the cross-section must be arranged with the highest energy " - "group first, and the lowest energy group last." + "The group structure must be defined descendingly, from the " + "highest energy bin (i.e. lowest lethargy bin) edge to the " + "lowest energy bin edge, which can't be zero (infinite " + "lethargy). Similarly the cross-section must be arranged " + "according to these bin edges." ) - if np.shape(self.sigma_t) != (self.n_groups,): raise ProcessValidationError( f"total group-wise cross-sections should have {self.n_groups} " @@ -493,6 +501,15 @@ def __post_init__(self): "Group-wise scattering cross-sections be a square matrix of " f"shape n*n, where n= number of groups = {self.n_groups}." ) + if (self.sigma_s.sum(axis=1) > self.sigma_t).any(): + raise ProcessValidationError( + "Total cross-section should include the scattering cross-section." + ) + if np.tril(self.sigma_s, k=-1).any(): + warnings.warn( + "Elastic up-scattering seems unlikely in this model! " + "Check if the group structure is chosen correctly?", + ) self.sigma_t_cm = self.sigma_t/100 self.sigma_s_cm = self.sigma_s/100 diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 1825e8852e..878c80cc69 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -1,19 +1,53 @@ import pytest -from process.exceptions import ProcessValidationError +from process.exceptions import ProcessValidationError, ProcessValueError from process.neutronics import NeutronFluxProfile from process.neutronics_data import MaterialMacroInfo +def test_group_structure_0_energy(): + with pytest.warns(): + MaterialMacroInfo( + [1.0, 0.0], + 0.1, + [1.0], + [[1.0]], + ) + def test_group_structure_too_short(): with pytest.raises(ProcessValidationError): MaterialMacroInfo( + [1.0], + 0.1, [1.0], [[1.0]], - [0.0], + ) + +def test_sigma_s_incorrect_shape(): + with pytest.raises(ProcessValidationError): + MaterialMacroInfo( + [1000, 10, 1.0], 0.1, + [1.0, 2.0], + [1.0, 1.0], ) +def test_sigma_s_too_large(): + with pytest.raises(ProcessValidationError): + MaterialMacroInfo( + [1000, 10, 1.0], + 0.1, + [1.0, 2.0], + [[1.0, 1.0], [1.0, 1.0]], + ) +def test_warn_up_elastic_scatter(): + with pytest.warns(): + MaterialMacroInfo( + [1000, 10, 1.0], + 0.1, + [1.0, 2.0], + [[0.5, 0.5], [1.0, 1.0]], + ) def test_has_local_fluxes(): """Test that the groupwise decorator has worked on the local fluxes methods.""" @@ -39,3 +73,14 @@ def test_has_reactions(): assert hasattr(NeutronFluxProfile, "reaction_rate_fw") assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_bz") assert hasattr(NeutronFluxProfile, "reaction_rate_bz") + +def test_three_group(): + # no negative flux + dummy = [10000, 1000, 100, 1] + # fw_mat = MaterialMacroInfo() + bz_mat = MaterialMacroInfo + # same L_1 and L_3 shoudl yield integration_constants[2].fw_pos[0] and + # integration_constants[2].fw_neg[0] = 0.0 + +def test_two_group(): + """""" \ No newline at end of file From bf51d7b5a0f259e0fb48c934e89af61c28b5e35f Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 11 Nov 2025 17:54:18 +0000 Subject: [PATCH 50/98] ruff fixes. --- tests/unit/test_neutronics.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 878c80cc69..8ebefa95c0 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -1,6 +1,6 @@ import pytest -from process.exceptions import ProcessValidationError, ProcessValueError +from process.exceptions import ProcessValidationError from process.neutronics import NeutronFluxProfile from process.neutronics_data import MaterialMacroInfo @@ -14,6 +14,7 @@ def test_group_structure_0_energy(): [[1.0]], ) + def test_group_structure_too_short(): with pytest.raises(ProcessValidationError): MaterialMacroInfo( @@ -23,6 +24,7 @@ def test_group_structure_too_short(): [[1.0]], ) + def test_sigma_s_incorrect_shape(): with pytest.raises(ProcessValidationError): MaterialMacroInfo( @@ -32,6 +34,7 @@ def test_sigma_s_incorrect_shape(): [1.0, 1.0], ) + def test_sigma_s_too_large(): with pytest.raises(ProcessValidationError): MaterialMacroInfo( @@ -40,6 +43,8 @@ def test_sigma_s_too_large(): [1.0, 2.0], [[1.0, 1.0], [1.0, 1.0]], ) + + def test_warn_up_elastic_scatter(): with pytest.warns(): MaterialMacroInfo( @@ -49,6 +54,7 @@ def test_warn_up_elastic_scatter(): [[0.5, 0.5], [1.0, 1.0]], ) + def test_has_local_fluxes(): """Test that the groupwise decorator has worked on the local fluxes methods.""" assert hasattr(NeutronFluxProfile, "neutron_flux_at") @@ -74,6 +80,7 @@ def test_has_reactions(): assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_bz") assert hasattr(NeutronFluxProfile, "reaction_rate_bz") + def test_three_group(): # no negative flux dummy = [10000, 1000, 100, 1] @@ -82,5 +89,6 @@ def test_three_group(): # same L_1 and L_3 shoudl yield integration_constants[2].fw_pos[0] and # integration_constants[2].fw_neg[0] = 0.0 + def test_two_group(): - """""" \ No newline at end of file + """""" From d48f5f67a4c0edeb9480f59960e7aa020fbc551a Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 11 Nov 2025 17:55:31 +0000 Subject: [PATCH 51/98] Separated the in_source matrix from the scattering matrix in MaterialMacroInfo. --- process/neutronics.py | 188 +++++++++++++++++++++++-------------- process/neutronics_data.py | 47 +++++----- 2 files changed, 141 insertions(+), 94 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 0eb820b7c3..3d51ba2b16 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -11,8 +11,8 @@ import numpy as np from matplotlib import pyplot as plt from numpy import typing as npt -from scipy.special import expm1 from scipy import optimize +from scipy.special import expm1 from process.exceptions import ProcessValidationError, ProcessValueError from process.neutronics_data import MaterialMacroInfo @@ -67,7 +67,10 @@ def __set_name__(self, owner, name): def get_diffusion_coefficient_and_length( - total_xs_cm: float, scattering_xs_cm: float, avg_atomic_mass: float + avg_atomic_mass: float, + total_xs_cm: float, + scattering_xs_cm: float, + in_source_xs_cm: float, ) -> tuple[float, float]: r""" Calculate the diffusion coefficient for a given scattering and total macro-scopic @@ -105,7 +108,9 @@ def get_diffusion_coefficient_and_length( transport_xs = total_xs_cm - 2 / (3 * avg_atomic_mass) * scattering_xs_cm diffusion_coef = 1 / 3 / transport_xs - diffusion_len_2 = diffusion_coef / (total_xs_cm - scattering_xs_cm) + diffusion_len_2 = diffusion_coef / ( + total_xs_cm - scattering_xs_cm - in_source_xs_cm + ) return diffusion_coef, diffusion_len_2 @@ -318,14 +323,16 @@ def solve_lowest_group(self) -> None: if n in self.integration_constants: return # skip if it has already been solved. self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( + self.fw_mat.avg_atomic_mass, self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], - self.fw_mat.avg_atomic_mass, + self.fw_mat.sigma_in_cm[n, n], ) self.d_bz_cm[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( + self.bz_mat.avg_atomic_mass, self.bz_mat.sigma_t_cm[n], self.bz_mat.sigma_s_cm[n, n], - self.bz_mat.avg_atomic_mass, + self.bz_mat.sigma_in_cm[n, n], ) l_fw = np.sqrt(abs(self.l_fw_2[n])) l_bz = np.sqrt(abs(self.l_bz_2[n])) @@ -399,21 +406,23 @@ def solve_group_n(self, n: int) -> None: for k in range(n): if k not in self.integration_constants: self.solve_group_n(k) - if self.fw_mat.contains_upscatter or self.bz_mat.contains_upscatter: + if not (self.fw_mat.downscatter_only and self.bz_mat.downscatter_only): raise NotImplementedError( "Will implement solve_group_n in a loop later..." ) if n in self.integration_constants: return None # skip if it has already been solved. self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( + self.fw_mat.avg_atomic_mass, self.fw_mat.sigma_t_cm[n], self.fw_mat.sigma_s_cm[n, n], - self.fw_mat.avg_atomic_mass, + self.fw_mat.sigma_in_cm[n, n], ) self.d_bz_cm[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( + self.bz_mat.avg_atomic_mass, self.bz_mat.sigma_t_cm[n], self.bz_mat.sigma_s_cm[n, n], - self.bz_mat.avg_atomic_mass, + self.bz_mat.sigma_in_cm[n, n], ) self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length( self.d_bz_cm[n] @@ -423,7 +432,8 @@ def solve_group_n(self, n: int) -> None: l_fw_2, l_bz_2 = self.l_fw_2[n], self.l_bz_2[n] d_fw, d_bz = self.d_fw_cm[n], self.d_bz_cm[n] ic = self.integration_constants - fw_sigma_s, bz_sigma_s = self.fw_mat.sigma_s, self.bz_mat.sigma_s + src_fw = self.fw_mat.sigma_s_cm + self.fw_mat.sigma_in_cm + src_bz = self.bz_mat.sigma_s_cm + self.bz_mat.sigma_in_cm _ic_n = IntegrationConstants([], [], [], []) for g in range(n): @@ -440,19 +450,19 @@ def solve_group_n(self, n: int) -> None: else: scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz _ic_n.fw_pos.append( - sum(fw_sigma_s[i, n] * ic[i].fw_pos[g] for i in range(g, n)) + sum(src_fw[i, n] * ic[i].fw_pos[g] for i in range(g, n)) * scale_factor_fw ) _ic_n.fw_neg.append( - sum(fw_sigma_s[i, n] * ic[i].fw_neg[g] for i in range(g, n)) + sum(src_fw[i, n] * ic[i].fw_neg[g] for i in range(g, n)) * scale_factor_fw ) _ic_n.bz_pos.append( - sum(bz_sigma_s[i, n] * ic[i].bz_pos[g] for i in range(g, n)) + sum(src_bz[i, n] * ic[i].bz_pos[g] for i in range(g, n)) * scale_factor_bz ) _ic_n.bz_neg.append( - sum(bz_sigma_s[i, n] * ic[i].bz_neg[g] for i in range(g, n)) + sum(src_bz[i, n] * ic[i].bz_neg[g] for i in range(g, n)) * scale_factor_bz ) @@ -470,16 +480,40 @@ def set_constants(input_vector: Iterable[float]): _ic_n.bz_neg[n] = c4 def evaluate_fit(): - flux_continuity = _groupwise_neutron_flux_fw(_ic_n, self, n, self.x_fw_cm) - _groupwise_neutron_flux_bz(_ic_n, self, n, self.x_fw_cm) - flux_at_boundary = _groupwise_neutron_flux_bz(_ic_n, self, n, self.extended_boundary_cm[n]) - current_continuity = _groupwise_neutron_current_fw2bz(_ic_n, self, n, True) - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) + flux_continuity = _groupwise_neutron_flux_fw( + _ic_n, self, n, self.x_fw_cm + ) - _groupwise_neutron_flux_bz(_ic_n, self, n, self.x_fw_cm) + flux_at_boundary = _groupwise_neutron_flux_bz( + _ic_n, self, n, self.extended_boundary_cm[n] + ) + current_continuity = _groupwise_neutron_current_fw2bz( + _ic_n, self, n, True + ) - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) influx_fw, influx_bz = 0.0, 0.0 for g in range(n): - influx_fw += self.fw_mat.sigma_s_cm[g,n] * _groupwise_integrated_flux_fw(self.integration_constants[g], self, g) - influx_bz += self.bz_mat.sigma_s_cm[g,n] * _groupwise_integrated_flux_bz(self.integration_constants[g], self, g) - removal_fw = (self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum()) * _groupwise_neutron_flux_fw(_ic_n, self, n) - removal_bz = (self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum()) * _groupwise_neutron_flux_bz(_ic_n, self, n) - neutron_conservation = influx_fw + influx_bz - removal_fw - removal_bz - _groupwise_neutron_current_escaped(_ic_n, self, n) + influx_fw += self.fw_mat.sigma_s_cm[ + g, n + ] * _groupwise_integrated_flux_fw( + self.integration_constants[g], self, g + ) + influx_bz += self.bz_mat.sigma_s_cm[ + g, n + ] * _groupwise_integrated_flux_bz( + self.integration_constants[g], self, g + ) + removal_fw = ( + self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum() + ) * _groupwise_neutron_flux_fw(_ic_n, self, n) + removal_bz = ( + self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum() + ) * _groupwise_neutron_flux_bz(_ic_n, self, n) + neutron_conservation = ( + influx_fw + + influx_bz + - removal_fw + - removal_bz + - _groupwise_neutron_current_escaped(_ic_n, self, n) + ) # in fact, we can separate the last condition (neutron conservation) # into two regions: fw and bz # which gives: @@ -496,7 +530,7 @@ def objective(four_integration_constants_vector): set_constants(four_integration_constants_vector) return evaluate_fit() - optimize.root(set_constants, x0=[c1,c2,c3,c4]) + optimize.root(set_constants, x0=[c1, c2, c3, c4]) self.integration_constants[n] = _ic_n return None @@ -527,7 +561,10 @@ def groupwise_neutron_flux_fw( x_cm = abs(x * 100) return _groupwise_neutron_flux_fw( - self.integration_constants[n], self, n, x_cm, + self.integration_constants[n], + self, + n, + x_cm, ) @summarize_values @@ -556,7 +593,10 @@ def groupwise_neutron_flux_bz( x_cm = abs(x * 100) return _groupwise_neutron_flux_bz( - self.integration_constants[n], self, n, x_cm, + self.integration_constants[n], + self, + n, + x_cm, ) @summarize_values @@ -623,7 +663,9 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: f"Not yet implemented the reaction type {reaction_type}" ) return sigma * _groupwise_integrated_flux_fw( - self.integration_constants[n], self, n, + self.integration_constants[n], + self, + n, ) @summarize_values @@ -649,9 +691,10 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: ) return sigma * _groupwise_integrated_flux_bz( - self.integration_constants[n], self, n, + self.integration_constants[n], + self, + n, ) - @summarize_values def groupwise_neutron_current_fw2bz(self, n: int) -> float: @@ -688,10 +731,11 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: current in cm^-2 """ return _groupwise_neutron_current_escaped( - self.integration_constants[n], self, n, + self.integration_constants[n], + self, + n, ) - def plot( self, ax: plt.Axes | None = None, @@ -778,52 +822,50 @@ def plot( ax.set_ylabel("Neutron flux [cm^-2 s^-1]") return ax + def _groupwise_neutron_flux_fw( int_const: IntegrationConstants, - self: NeutronFluxProfile, n: int, x_cm: float | npt.NDArray, + self: NeutronFluxProfile, + n: int, + x_cm: float | npt.NDArray, ) -> npt.NDArray: """ - Calculate groupwise_neutron_flux_fw for NeutronFluxProfile, but + Calculate groupwise_neutron_flux_fw for NeutronFluxProfile, but in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). """ exponentials = [] for g in range(n + 1): l_fw = np.sqrt(abs(self.l_fw_2[g])) - exponentials.append( - int_const.fw_pos[g] * np.exp(x_cm / l_fw) - ) - exponentials.append( - int_const.fw_neg[g] * np.exp(-x_cm / l_fw) - ) + exponentials.append(int_const.fw_pos[g] * np.exp(x_cm / l_fw)) + exponentials.append(int_const.fw_neg[g] * np.exp(-x_cm / l_fw)) return np.sum(exponentials, axis=0) + def _groupwise_neutron_flux_bz( int_const: IntegrationConstants, - self: NeutronFluxProfile, n: int, x_cm: float | npt.NDArray, + self: NeutronFluxProfile, + n: int, + x_cm: float | npt.NDArray, ) -> npt.NDArray: """ - Calculate groupwise_neutron_flux_bz for NeutronFluxProfile, but + Calculate groupwise_neutron_flux_bz for NeutronFluxProfile, but in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). """ exponentials = [] for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) - exponentials.append( - int_const.bz_pos[g] * np.exp(x_cm / l_bz) - ) - exponentials.append( - int_const.bz_neg[g] * np.exp(-x_cm / l_bz) - ) + exponentials.append(int_const.bz_pos[g] * np.exp(x_cm / l_bz)) + exponentials.append(int_const.bz_neg[g] * np.exp(-x_cm / l_bz)) return np.sum(exponentials, axis=0) + def _groupwise_integrated_flux_fw( - int_const: IntegrationConstants, - self: NeutronFluxProfile, n: int + int_const: IntegrationConstants, self: NeutronFluxProfile, n: int ) -> float: """ - Help calculate groupwise_reaction_rate_fw for NeutronFluxProfile, but + Help calculate groupwise_reaction_rate_fw for NeutronFluxProfile, but in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). """ @@ -835,42 +877,42 @@ def _groupwise_integrated_flux_fw( l_fw * int_const.fw_pos[g] * expm1(self.x_fw_cm / l_fw) ) integrals.append( - - l_fw * int_const.fw_neg[g] * expm1(-self.x_fw_cm / l_fw) + -l_fw * int_const.fw_neg[g] * expm1(-self.x_fw_cm / l_fw) ) return np.sum(integrals, axis=0) + def _groupwise_integrated_flux_bz( - int_const: IntegrationConstants, - self: NeutronFluxProfile, n: int + int_const: IntegrationConstants, self: NeutronFluxProfile, n: int ) -> float: """ - Help calculate groupwise_reaction_rate_bz for NeutronFluxProfile, but + Help calculate groupwise_reaction_rate_bz for NeutronFluxProfile, but in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). """ - + integrals = [] for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz fw_thick = self.x_fw_cm / l_bz integrals.append( - l_bz * int_const.bz_pos[g] - * expm1(bz_thick) * np.exp(fw_thick) + l_bz * int_const.bz_pos[g] * expm1(bz_thick) * np.exp(fw_thick) ) integrals.append( - - l_bz * int_const.bz_neg[g] - * expm1(-bz_thick) * np.exp(-fw_thick) + -l_bz * int_const.bz_neg[g] * expm1(-bz_thick) * np.exp(-fw_thick) ) return np.sum(integrals, axis=0) def _groupwise_neutron_current_fw2bz( - int_const: IntegrationConstants, self: NeutronFluxProfile, n: int, - alt_implementation: bool=False + int_const: IntegrationConstants, + self: NeutronFluxProfile, + n: int, + alt_implementation: bool = False, ) -> float: """ - Calculate groupwise_neutron_current_fw2bz for NeutronFluxProfile, but + Calculate groupwise_neutron_current_fw2bz for NeutronFluxProfile, but in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). @@ -884,29 +926,32 @@ def _groupwise_neutron_current_fw2bz( for g in range(n + 1): l_fw = np.sqrt(abs(self.l_fw_2[g])) differentials.append( - 1/ l_fw * int_const.fw_pos[g] * np.exp(self.x_fw_cm / l_fw) + 1 / l_fw * int_const.fw_pos[g] * np.exp(self.x_fw_cm / l_fw) ) differentials.append( - - 1/l_fw * int_const.fw_neg[g] * np.exp(-self.x_fw_cm / l_fw) + -1 / l_fw * int_const.fw_neg[g] * np.exp(-self.x_fw_cm / l_fw) ) - return - self.d_fw_cm[n] * np.sum(differentials, axis=0) + return -self.d_fw_cm[n] * np.sum(differentials, axis=0) # equivalent definition below: (should yield the same answer once converged) for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) differentials.append( - 1/ l_bz * int_const.bz_pos[g] * np.exp(self.x_fw_cm / l_bz) + 1 / l_bz * int_const.bz_pos[g] * np.exp(self.x_fw_cm / l_bz) ) differentials.append( - - 1/l_bz * int_const.bz_neg[g] * np.exp(-self.x_fw_cm / l_bz) + -1 / l_bz * int_const.bz_neg[g] * np.exp(-self.x_fw_cm / l_bz) ) - return - self.d_bz_cm[n] * np.sum(differentials, axis=0) + return -self.d_bz_cm[n] * np.sum(differentials, axis=0) + def _groupwise_neutron_current_escaped( - int_const: IntegrationConstants, self: NeutronFluxProfile, n: int, + int_const: IntegrationConstants, + self: NeutronFluxProfile, + n: int, ) -> float: """ - Calculate groupwise_neutron_current_escaped for NeutronFluxProfile, but + Calculate groupwise_neutron_current_escaped for NeutronFluxProfile, but in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). @@ -919,12 +964,13 @@ def _groupwise_neutron_current_escaped( for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) differentials.append( - 1/ l_bz * int_const.bz_pos[g] * np.exp(self.x_bz_cm / l_bz) + 1 / l_bz * int_const.bz_pos[g] * np.exp(self.x_bz_cm / l_bz) ) differentials.append( - - 1/l_bz * int_const.bz_neg[g] * np.exp(-self.x_bz_cm / l_bz) + -1 / l_bz * int_const.bz_neg[g] * np.exp(-self.x_bz_cm / l_bz) ) - return - self.d_bz_cm[n] * np.sum(differentials, axis=0) + return -self.d_bz_cm[n] * np.sum(differentials, axis=0) + def _generate_x_range( x_max_cm: float, diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 3daad19bcd..cec79b5db2 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -460,10 +460,11 @@ class MaterialMacroInfo: average atomic mass (weighted by fraction) """ - sigma_t: npt.NDArray[np.float64] - sigma_s: npt.NDArray group_structure: npt.NDArray avg_atomic_mass: float + sigma_t: npt.NDArray[np.float64] + sigma_s: npt.NDArray + sigma_in: npt.NDArray | None = None def __post_init__(self): """ @@ -480,7 +481,7 @@ def __post_init__(self): else: self.sigma_in = np.zeros_like(self.sigma_s) - if (self.group_structure<=0).any(): + if (self.group_structure <= 0).any(): warnings.warn("Zero energy (inf. lethargy) not allowed.") self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) if (np.diff(self.group_structure) >= 0).any(): @@ -510,8 +511,9 @@ def __post_init__(self): "Elastic up-scattering seems unlikely in this model! " "Check if the group structure is chosen correctly?", ) - self.sigma_t_cm = self.sigma_t/100 - self.sigma_s_cm = self.sigma_s/100 + self.sigma_t_cm = self.sigma_t / 100 + self.sigma_s_cm = self.sigma_s / 100 + self.sigma_in_cm = self.sigma_in / 100 @property def n_groups(self): @@ -536,11 +538,10 @@ def downscatter_only(self): as neutron fluxes in higher-lethargy groups in turn affects the neutron flux in lower-lethargy groups. """ - return ~self.contains_upscatter - - @property - def contains_upscatter(self): - return np.tril(self.sigma_s, k=-1).any() + return ~( + np.tril(self.sigma_s, k=-1).any() + or np.tril(self.sigma_in, k=-1).any() + ) def get_material_nuclear_data( @@ -572,6 +573,7 @@ def get_material_nuclear_data( density = material_density_data_bank[material] composition = material_composition_data_bank[material] avg_atomic_mass = get_avg_atomic_mass(composition) + n_groups = len(group_structure) - 1 # dicts of {"isotope": npt.NDArray[np.float64] 1D/2D arrays} micro_total_xs = {} @@ -618,21 +620,20 @@ def get_material_nuclear_data( discrete_macro_scattering_xs = calculate_average_macro_xs( composition, micro_scattering_xs, density ) - discrete_macro_n2n_xs = calculate_average_macro_xs( - composition, micro_n2n_xs, density - ) - discrete_macro_fission_xs = calculate_average_macro_xs( - composition, micro_fiss_xs, density - ) - source_matrix = ( - discrete_macro_scattering_xs - + discrete_macro_n2n_xs - + discrete_macro_fission_xs - ) + source_matrix = np.zeros([n_groups, n_groups], dtype=float) + if micro_n2n_xs: + source_matrix += calculate_average_macro_xs( + composition, micro_n2n_xs, density + ) + if micro_fiss_xs: + source_matrix += calculate_average_macro_xs( + composition, micro_fiss_xs, density + ) return MaterialMacroInfo( - discrete_macro_total_xs, - source_matrix, group_structure, avg_atomic_mass, + discrete_macro_total_xs, + discrete_macro_scattering_xs, + source_matrix, ) From f6f018bffd7267e4447bc34f42b148d930b6bb4e Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 02:37:04 +0000 Subject: [PATCH 52/98] Turned the base functions from exp(x),exp(-x) to cosh(x),sinh(x); such that when the characteristic length goes imaginary, the function simply becomes cos(x),sin(x). --- process/neutronics.py | 170 +++++++++++++++------------- tests/regression/test_neutronics.py | 59 ++++++++-- 2 files changed, 138 insertions(+), 91 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 3d51ba2b16..6ea343bfaf 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -132,22 +132,22 @@ def extrapolation_length(diffusion_coefficient: float) -> float: @dataclass class IntegrationConstants: """ - Inside each material, there are two new exponentials per group, i.e. - group n=0 has exp(x/L[0]) and exp(-x/L[0]), - group n=1 has exp(x/L[0]), exp(-x/L[0]), exp(x/L[1]) and exp(-x/L[1]), + Inside each material, there are two new hyperbolic trig funcs per group, i.e. + group n=0 has cosh(x/L[0]) and sinh(x/L[0]), + group n=1 has cosh(x/L[0]), sinh(x/L[0]), cosh(x/L[1]) and sinh(x/L[1]), etc. - To get the neutron flux, each exponential has to be scaled by an integration + To get the neutron flux, each trig func has to be scaled by an integration constant. E.g. - group n=0: fw: fw_pos[0][0] * exp(x/L[0]) + fw_neg[0][0] * exp(-x/L[0]) - group n=1: fw: fw_pos[1][0] * exp(x/L[0]) + fw_pos[1][1] * exp(x/L[1]) - + fw_neg[1][0] * exp(-x/L[0]) + fw_neg[1][1] * exp(-x/L[1]) + group n=0: fw: fw_c[0][0] * cosh(x/L[0]) + fw_s[0][0] * sinh(x/L[0]) + group n=1: fw: fw_c[1][0] * cosh(x/L[0]) + fw_c[1][1] * cosh(x/L[1]) + + fw_s[1][0] * sinh(x/L[0]) + fw_s[1][1] * sinh(x/L[1]) """ - fw_pos: Iterable[float] - fw_neg: Iterable[float] - bz_pos: Iterable[float] - bz_neg: Iterable[float] + fw_c: Iterable[float] + fw_s: Iterable[float] + bz_c: Iterable[float] + bz_s: Iterable[float] def validate_length(self, expected_length: int): """Validate that all fields has the correct length.""" @@ -341,45 +341,47 @@ def solve_lowest_group(self) -> None: d_bz = self.d_bz_cm[n] self.extended_boundary_cm[n] = x_bz + extrapolation_length(d_bz) if self.l_fw_2[n] > 0: - sinh_fw = np.sinh(x_fw / l_fw) - cosh_fw = np.cosh(x_fw / l_fw) - tanh_fw = np.tanh(x_fw / l_fw) + s_fw = np.sinh(x_fw / l_fw) + c_fw = np.cosh(x_fw / l_fw) + t_fw = np.tanh(x_fw / l_fw) else: - sinh_fw = np.sin(x_fw / l_fw) - cosh_fw = np.cos(x_fw / l_fw) - tanh_fw = np.tan(x_fw / l_fw) + s_fw = np.sin(x_fw / l_fw) + c_fw = np.cos(x_fw / l_fw) + t_fw = np.tan(x_fw / l_fw) if self.l_bz_2[n] > 0: - sinh_bz = np.sinh((self.extended_boundary_cm[n] - x_fw) / l_bz) - cosh_bz = np.cosh((self.extended_boundary_cm[n] - x_fw) / l_bz) - tanh_bz = np.tanh((self.extended_boundary_cm[n] - x_fw) / l_bz) + c_bz = np.cosh(self.extended_boundary_cm[n] / l_bz) + s_bz = np.sinh(self.extended_boundary_cm[n] / l_bz) + c_bz_mod = np.cosh((self.extended_boundary_cm[n] - x_fw) / l_bz) + s_bz_mod = np.sinh((self.extended_boundary_cm[n] - x_fw) / l_bz) + t_bz_mod = np.tanh((self.extended_boundary_cm[n] - x_fw) / l_bz) else: - sinh_bz = np.sin((self.extended_boundary_cm[n] - x_fw) / l_bz) - cosh_bz = np.cos((self.extended_boundary_cm[n] - x_fw) / l_bz) - tanh_bz = np.tan((self.extended_boundary_cm[n] - x_fw) / l_bz) + c_bz = np.cos(self.extended_boundary_cm[n] / l_bz) + s_bz = np.sin(self.extended_boundary_cm[n] / l_bz) + c_bz_mod = np.cos((self.extended_boundary_cm[n] - x_fw) / l_bz) + s_bz_mod = np.sin((self.extended_boundary_cm[n] - x_fw) / l_bz) + t_bz_mod = np.tan((self.extended_boundary_cm[n] - x_fw) / l_bz) + + c5 = - self.flux * ( + l_fw / d_fw + - np.exp(x_fw / l_fw) * ( + (l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod + )/( + c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz) + ) + ) + c6 = - self.flux * l_fw / d_fw - c2 = ( + c7_c8_common_factor = ( self.flux * np.exp(x_fw / l_fw) - / 2 - * ((l_fw / d_fw) + (l_bz / d_bz) * tanh_bz) - / (cosh_fw + sinh_fw * tanh_bz * (d_fw / l_fw) * (l_bz / d_bz)) + * (1 - t_fw) + / ((d_bz / l_bz) * c_bz_mod + (d_fw / l_fw) * t_fw * s_bz_mod) ) - c1 = c2 - l_fw / d_fw * self.flux - - c3_c4_common_factor = ( - self.flux - * np.exp(x_fw / l_fw) - / 2 - * (1 - tanh_fw) - / ((d_bz / l_bz) * cosh_bz + (d_fw / l_fw) * tanh_fw * sinh_bz) - ) - c3 = -c3_c4_common_factor * np.exp( - -self.extended_boundary_cm[n] / l_bz - ) - c4 = c3_c4_common_factor * np.exp(self.extended_boundary_cm[n] / l_bz) + c7 = c7_c8_common_factor * s_bz + c8 = -c7_c8_common_factor * c_bz self.integration_constants[n] = IntegrationConstants( - [c1], [c2], [c3], [c4] + [c5], [c6], [c7], [c8] ) return @@ -439,8 +441,8 @@ def solve_group_n(self, n: int) -> None: for g in range(n): # if the characteristic length of group [g] coincides with the # characteristic length of group [n], then that particular - # exponential would be indistinguishable from group [n]'s - # exponential anyways, therefore we can set the coefficient to 0. + # cosh/sinh would be indistinguishable from group [n]'s + # cosh/sinh anyways, therefore we can set the coefficient to 0. if np.isclose(diff_fw := self.l_fw_2[g] - l_fw_2, 0): scale_factor_fw = 0.0 else: @@ -449,35 +451,35 @@ def solve_group_n(self, n: int) -> None: scale_factor_bz = 0.0 else: scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz - _ic_n.fw_pos.append( - sum(src_fw[i, n] * ic[i].fw_pos[g] for i in range(g, n)) + _ic_n.fw_c.append( + sum(src_fw[i, n] * ic[i].fw_c[g] for i in range(g, n)) * scale_factor_fw ) - _ic_n.fw_neg.append( - sum(src_fw[i, n] * ic[i].fw_neg[g] for i in range(g, n)) + _ic_n.fw_s.append( + sum(src_fw[i, n] * ic[i].fw_s[g] for i in range(g, n)) * scale_factor_fw ) - _ic_n.bz_pos.append( - sum(src_bz[i, n] * ic[i].bz_pos[g] for i in range(g, n)) + _ic_n.bz_c.append( + sum(src_bz[i, n] * ic[i].bz_c[g] for i in range(g, n)) * scale_factor_bz ) - _ic_n.bz_neg.append( - sum(src_bz[i, n] * ic[i].bz_neg[g] for i in range(g, n)) + _ic_n.bz_s.append( + sum(src_bz[i, n] * ic[i].bz_s[g] for i in range(g, n)) * scale_factor_bz ) c1, c2, c3, c4 = 0.0, 0.0, 0.0, 0.0 - _ic_n.fw_pos.append(c1) - _ic_n.fw_neg.append(c2) - _ic_n.bz_pos.append(c3) - _ic_n.bz_neg.append(c4) + _ic_n.fw_c.append(c1) + _ic_n.fw_s.append(c2) + _ic_n.bz_c.append(c3) + _ic_n.bz_s.append(c4) def set_constants(input_vector: Iterable[float]): c1, c2, c3, c4 = input_vector - _ic_n.fw_pos[n] = c1 - _ic_n.fw_neg[n] = c2 - _ic_n.bz_pos[n] = c3 - _ic_n.bz_neg[n] = c4 + _ic_n.fw_c[n] = c1 + _ic_n.fw_s[n] = c2 + _ic_n.bz_c[n] = c3 + _ic_n.bz_s[n] = c4 def evaluate_fit(): flux_continuity = _groupwise_neutron_flux_fw( @@ -834,12 +836,17 @@ def _groupwise_neutron_flux_fw( in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). """ - exponentials = [] + trig_funcs = [] for g in range(n + 1): - l_fw = np.sqrt(abs(self.l_fw_2[g])) - exponentials.append(int_const.fw_pos[g] * np.exp(x_cm / l_fw)) - exponentials.append(int_const.fw_neg[g] * np.exp(-x_cm / l_fw)) - return np.sum(exponentials, axis=0) + l_fw_2 = self.l_fw_2[g] + if l_fw_2>0: + c, s = np.cosh, np.sinh + else: + c, s = np.cos, np.sin + l_fw = np.sqrt(abs(l_fw_2)) + trig_funcs.append(int_const.fw_c[g] * c(x_cm / l_fw)) + trig_funcs.append(int_const.fw_s[g] * s(x_cm / l_fw)) + return np.sum(trig_funcs, axis=0) def _groupwise_neutron_flux_bz( @@ -853,12 +860,17 @@ def _groupwise_neutron_flux_bz( in such a way that doesn't trigger the re-calculation of integration_constants (which would've led to RecursionError if called within solve_group_n). """ - exponentials = [] + trig_funcs = [] for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - exponentials.append(int_const.bz_pos[g] * np.exp(x_cm / l_bz)) - exponentials.append(int_const.bz_neg[g] * np.exp(-x_cm / l_bz)) - return np.sum(exponentials, axis=0) + l_bz_2 = self.l_bz_2[g] + if l_bz_2>0: + c, s = np.cosh, np.sinh + else: + c, s = np.cos, np.sin + l_bz = np.sqrt(abs(l_bz_2)) + trig_funcs.append(int_const.bz_c[g] * c(x_cm / l_bz)) + trig_funcs.append(int_const.bz_s[g] * s(x_cm / l_bz)) + return np.sum(trig_funcs, axis=0) def _groupwise_integrated_flux_fw( @@ -874,10 +886,10 @@ def _groupwise_integrated_flux_fw( for g in range(n + 1): l_fw = np.sqrt(abs(self.l_fw_2[g])) integrals.append( - l_fw * int_const.fw_pos[g] * expm1(self.x_fw_cm / l_fw) + l_fw * int_const.fw_c[g] * expm1(self.x_fw_cm / l_fw) ) integrals.append( - -l_fw * int_const.fw_neg[g] * expm1(-self.x_fw_cm / l_fw) + -l_fw * int_const.fw_s[g] * expm1(-self.x_fw_cm / l_fw) ) return np.sum(integrals, axis=0) @@ -897,10 +909,10 @@ def _groupwise_integrated_flux_bz( bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz fw_thick = self.x_fw_cm / l_bz integrals.append( - l_bz * int_const.bz_pos[g] * expm1(bz_thick) * np.exp(fw_thick) + l_bz * int_const.bz_c[g] * expm1(bz_thick) * np.exp(fw_thick) ) integrals.append( - -l_bz * int_const.bz_neg[g] * expm1(-bz_thick) * np.exp(-fw_thick) + -l_bz * int_const.bz_s[g] * expm1(-bz_thick) * np.exp(-fw_thick) ) return np.sum(integrals, axis=0) @@ -926,10 +938,10 @@ def _groupwise_neutron_current_fw2bz( for g in range(n + 1): l_fw = np.sqrt(abs(self.l_fw_2[g])) differentials.append( - 1 / l_fw * int_const.fw_pos[g] * np.exp(self.x_fw_cm / l_fw) + 1 / l_fw * int_const.fw_c[g] * np.exp(self.x_fw_cm / l_fw) ) differentials.append( - -1 / l_fw * int_const.fw_neg[g] * np.exp(-self.x_fw_cm / l_fw) + -1 / l_fw * int_const.fw_s[g] * np.exp(-self.x_fw_cm / l_fw) ) return -self.d_fw_cm[n] * np.sum(differentials, axis=0) @@ -937,10 +949,10 @@ def _groupwise_neutron_current_fw2bz( for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) differentials.append( - 1 / l_bz * int_const.bz_pos[g] * np.exp(self.x_fw_cm / l_bz) + 1 / l_bz * int_const.bz_c[g] * np.exp(self.x_fw_cm / l_bz) ) differentials.append( - -1 / l_bz * int_const.bz_neg[g] * np.exp(-self.x_fw_cm / l_bz) + -1 / l_bz * int_const.bz_s[g] * np.exp(-self.x_fw_cm / l_bz) ) return -self.d_bz_cm[n] * np.sum(differentials, axis=0) @@ -964,10 +976,10 @@ def _groupwise_neutron_current_escaped( for g in range(n + 1): l_bz = np.sqrt(abs(self.l_bz_2[g])) differentials.append( - 1 / l_bz * int_const.bz_pos[g] * np.exp(self.x_bz_cm / l_bz) + 1 / l_bz * int_const.bz_c[g] * np.exp(self.x_bz_cm / l_bz) ) differentials.append( - -1 / l_bz * int_const.bz_neg[g] * np.exp(-self.x_bz_cm / l_bz) + -1 / l_bz * int_const.bz_s[g] * np.exp(-self.x_bz_cm / l_bz) ) return -self.d_bz_cm[n] * np.sum(differentials, axis=0) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 5fd6e9b1ab..72524d1b1c 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -11,20 +11,19 @@ def test_against_desmos_number(): """ dummy = [100, 1] # dummy group structure # translate from mean-free-path lengths (mfp) to macroscopic cross-sections - # [m] - mfp_fw_s = 118 * 0.01 - mfp_fw_t = 16.65 * 0.01 + mfp_fw_s = 118 * 0.01 # [m] + mfp_fw_t = 16.65 * 0.01 # [m] sigma_fw_t = 1 / mfp_fw_t # [1/m] sigma_fw_s = 1 / mfp_fw_s # [1/m] a_fw = 52 - fw_material = MaterialMacroInfo([sigma_fw_t], [[sigma_fw_s]], dummy, a_fw) + fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]]) - mfp_bz_s = 97 * 0.01 - mfp_bz_t = 35.8 * 0.01 + mfp_bz_s = 97 * 0.01 # [m] + mfp_bz_t = 35.8 * 0.01 # [m] sigma_bz_s = 1 / mfp_bz_s # [1/m] sigma_bz_t = 1 / mfp_bz_t # [1/m] a_bz = 71 - bz_material = MaterialMacroInfo([sigma_bz_t], [[sigma_bz_s]], dummy, a_bz) + bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]]) x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 @@ -33,10 +32,10 @@ def test_against_desmos_number(): ) const = neutron_profile.integration_constants[0] # alias to fit line width - assert np.isclose(const.fw_pos, 1.98923249017), "c1" - assert np.isclose(const.fw_neg, 78.5454445887), "c2" - assert np.isclose(const.bz_pos, -0.0126020377605), "c3" - assert np.isclose(const.bz_neg, 60.6997676395), "c4" + assert np.isclose(const.fw_c, 80.5346770788), "c5" + assert np.isclose(const.fw_s, -76.5562120985), "c6" + assert np.isclose(const.bz_c, 60.6871656017), "c7" + assert np.isclose(const.bz_s, -60.7123696772), "c8" assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_bz(x_fw), 48.72444) @@ -51,4 +50,40 @@ def test_against_desmos_number(): + neutron_profile.reaction_rate_bz("removal") ) def test_one_group_with_fission(): - """Expecting a cosine-shape (dome shape!) of neutron flux profile""" + """ + Regression test against Desmos snapshot with fission involved: + https://www.desmos.com/calculator/cd830add9c + Expecting a cosine-shape (dome shape!) of neutron flux profile. + """ + dummy = [100, 1] + mfp_fw_s = 118 * 0.01 # [m] + mfp_fw_t = 16.65 * 0.01 # [m] + sigma_fw_t = 1 / mfp_fw_t # [1/m] + sigma_fw_s = 1 / mfp_fw_s # [1/m] + a_fw = 52 + fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]]) + + mfp_bz_s = 97 * 0.01 # [m] + mfp_bz_t = 35.8 * 0.01 # [m] + sigma_bz_s = 1 / mfp_bz_s # [1/m] + sigma_bz_t = 1 / mfp_bz_t # [1/m] + a_bz = 71 + + g = 1.2 + nu_sigma_bz_f = g * (sigma_bz_t - sigma_bz_s) + bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], [[nu_sigma_bz_f]]) + + x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 + incoming_flux = 41 + neutron_profile = NeutronFluxProfile( + incoming_flux, x_fw, x_bz, fw_material, bz_material + ) + assert np.isclose(neutron_profile.l_bz_2[0], -58.2869567709**2) + neutron_profile.plot() + import matplotlib.pyplot as plt + plt.show() + assert np.isclose(neutron_profile.neutron_flux_at(18.96382/100), 164.81245) + +def test_two_groups(): + """4""" + From 0b49790f5fa3d4795f53d871cc26ea0f0ba9db9c Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 03:08:34 +0000 Subject: [PATCH 53/98] Conversion from exponential basis to ((cosh/sinh)/(cos/sin)) bases complete. --- process/neutronics.py | 135 ++++++++++++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 43 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 6ea343bfaf..a68708341d 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -12,7 +12,6 @@ from matplotlib import pyplot as plt from numpy import typing as npt from scipy import optimize -from scipy.special import expm1 from process.exceptions import ProcessValidationError, ProcessValueError from process.neutronics_data import MaterialMacroInfo @@ -838,12 +837,12 @@ def _groupwise_neutron_flux_fw( """ trig_funcs = [] for g in range(n + 1): - l_fw_2 = self.l_fw_2[g] - if l_fw_2>0: + if self.l_fw_2[g]>0: c, s = np.cosh, np.sinh + l_fw = np.sqrt(self.l_fw_2[g]) else: c, s = np.cos, np.sin - l_fw = np.sqrt(abs(l_fw_2)) + l_fw = np.sqrt(-self.l_fw_2[g]) trig_funcs.append(int_const.fw_c[g] * c(x_cm / l_fw)) trig_funcs.append(int_const.fw_s[g] * s(x_cm / l_fw)) return np.sum(trig_funcs, axis=0) @@ -862,12 +861,12 @@ def _groupwise_neutron_flux_bz( """ trig_funcs = [] for g in range(n + 1): - l_bz_2 = self.l_bz_2[g] - if l_bz_2>0: + if self.l_bz_2[g]>0: c, s = np.cosh, np.sinh + l_bz = np.sqrt(self.l_bz_2[g]) else: c, s = np.cos, np.sin - l_bz = np.sqrt(abs(l_bz_2)) + l_bz = np.sqrt(-self.l_bz_2[g]) trig_funcs.append(int_const.bz_c[g] * c(x_cm / l_bz)) trig_funcs.append(int_const.bz_s[g] * s(x_cm / l_bz)) return np.sum(trig_funcs, axis=0) @@ -884,13 +883,23 @@ def _groupwise_integrated_flux_fw( integrals = [] for g in range(n + 1): - l_fw = np.sqrt(abs(self.l_fw_2[g])) - integrals.append( - l_fw * int_const.fw_c[g] * expm1(self.x_fw_cm / l_fw) - ) - integrals.append( - -l_fw * int_const.fw_s[g] * expm1(-self.x_fw_cm / l_fw) - ) + if self.l_fw_2[g]>0: + l_fw = np.sqrt(self.l_fw_2[g]) + integrals.append( + l_fw * int_const.fw_c[g] * np.sinh(self.x_fw_cm / l_fw) + ) + integrals.append( + l_fw * int_const.fw_s[g] * (np.cosh(self.x_fw_cm / l_fw) - 1) + ) + else: + l_fw = np.sqrt(-self.l_fw_2[g]) + integrals.append( + l_fw * int_const.fw_c[g] * np.sin(self.x_fw_cm / l_fw) + ) + integrals.append( + l_fw * int_const.fw_s[g] * (1 - np.cos(self.x_fw_cm / l_fw)) + ) + return np.sum(integrals, axis=0) @@ -905,15 +914,26 @@ def _groupwise_integrated_flux_bz( integrals = [] for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - bz_thick = (self.x_bz_cm - self.x_fw_cm) / l_bz - fw_thick = self.x_fw_cm / l_bz - integrals.append( - l_bz * int_const.bz_c[g] * expm1(bz_thick) * np.exp(fw_thick) - ) - integrals.append( - -l_bz * int_const.bz_s[g] * expm1(-bz_thick) * np.exp(-fw_thick) - ) + if self.l_bz_2[g]>0: + l_bz = np.sqrt(self.l_bz_2[g]) + integrals.append( + l_bz * int_const.bz_c[g] * + (np.sinh(self.x_bz_cm / l_bz) - np.sinh(self.x_fw_cm / l_bz)) + ) + integrals.append( + l_bz * int_const.bz_s[g] * + (np.cosh(self.x_bz_cm / l_bz) - np.cosh(self.x_fw_cm / l_bz)) + ) + else: + l_bz = np.sqrt(-self.l_bz_2[g]) + integrals.append( + l_bz * int_const.bz_c[g] * + (np.sin(self.x_bz_cm / l_bz) - np.sin(self.x_fw_cm / l_bz)) + ) + integrals.append( + -l_bz * int_const.bz_s[g] * + (np.cos(self.x_bz_cm / l_bz) - np.cos(self.x_fw_cm / l_bz)) + ) return np.sum(integrals, axis=0) @@ -936,24 +956,44 @@ def _groupwise_neutron_current_fw2bz( differentials = [] if alt_implementation: for g in range(n + 1): - l_fw = np.sqrt(abs(self.l_fw_2[g])) + if self.l_fw_2[g]>0: + l_fw = np.sqrt(self.l_fw_2[g]) + differentials.append( + int_const.fw_c[g] / l_fw * np.sinh(self.x_fw_cm / l_fw) + ) + differentials.append( + int_const.fw_s[g] / l_fw * np.cosh(self.x_fw_cm / l_fw) + ) + else: + l_fw = np.sqrt(-self.l_fw_2[g]) + differentials.append( + - int_const.fw_c[g] / l_fw * np.sin(self.x_fw_cm / l_fw) + ) + differentials.append( + int_const.fw_s[g] / l_fw * np.cos(self.x_fw_cm / l_fw) + ) + + return -self.d_fw_cm[n] * np.sum(differentials, axis=0) + + # equivalent definition below: (should yield the same answer once converged) + for g in range(n + 1): + if self.l_bz_2[g]>0: + l_bz = np.sqrt(self.l_bz_2[g]) differentials.append( - 1 / l_fw * int_const.fw_c[g] * np.exp(self.x_fw_cm / l_fw) + int_const.bz_c[g] / l_bz * np.sinh(self.x_fw_cm / l_bz) ) differentials.append( - -1 / l_fw * int_const.fw_s[g] * np.exp(-self.x_fw_cm / l_fw) + int_const.bz_s[g] / l_bz * np.cosh(self.x_fw_cm / l_bz) + ) + else: + l_bz = np.sqrt(-self.l_bz_2[g]) + differentials.append( + - int_const.bz_c[g] / l_bz * np.sin(self.x_fw_cm / l_bz) + ) + differentials.append( + int_const.bz_s[g] / l_bz * np.cos(self.x_fw_cm / l_bz) ) - return -self.d_fw_cm[n] * np.sum(differentials, axis=0) - # equivalent definition below: (should yield the same answer once converged) - for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - differentials.append( - 1 / l_bz * int_const.bz_c[g] * np.exp(self.x_fw_cm / l_bz) - ) - differentials.append( - -1 / l_bz * int_const.bz_s[g] * np.exp(-self.x_fw_cm / l_bz) - ) return -self.d_bz_cm[n] * np.sum(differentials, axis=0) @@ -974,13 +1014,22 @@ def _groupwise_neutron_current_escaped( """ differentials = [] for g in range(n + 1): - l_bz = np.sqrt(abs(self.l_bz_2[g])) - differentials.append( - 1 / l_bz * int_const.bz_c[g] * np.exp(self.x_bz_cm / l_bz) - ) - differentials.append( - -1 / l_bz * int_const.bz_s[g] * np.exp(-self.x_bz_cm / l_bz) - ) + if self.l_bz_2[g]>0: + l_bz = np.sqrt(self.l_bz_2[g]) + differentials.append( + int_const.bz_c[g] / l_bz * np.sinh(self.x_bz_cm / l_bz) + ) + differentials.append( + int_const.bz_s[g] / l_bz * np.cosh(self.x_bz_cm / l_bz) + ) + else: + l_bz = np.sqrt(-self.l_bz_2[g]) + differentials.append( + - int_const.bz_c[g] / l_bz * np.sin(self.x_bz_cm / l_bz) + ) + differentials.append( + int_const.bz_s[g] / l_bz * np.cos(self.x_bz_cm / l_bz) + ) return -self.d_bz_cm[n] * np.sum(differentials, axis=0) From 42ea1dfd024b5a9e066fc10975a797b1e9eeb34e Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 04:03:15 +0000 Subject: [PATCH 54/98] Fixed where the abs() are placed for taking the absolute value of x --- process/neutronics.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index a68708341d..c50cb4a75e 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -559,7 +559,7 @@ def groupwise_neutron_flux_fw( flux: Neutron flux at x meter from the first wall. """ - x_cm = abs(x * 100) + x_cm = x * 100 return _groupwise_neutron_flux_fw( self.integration_constants[n], @@ -591,7 +591,7 @@ def groupwise_neutron_flux_bz( flux: Neutron flux at x meter from the first wall. """ - x_cm = abs(x * 100) + x_cm = x * 100 return _groupwise_neutron_flux_bz( self.integration_constants[n], @@ -843,8 +843,8 @@ def _groupwise_neutron_flux_fw( else: c, s = np.cos, np.sin l_fw = np.sqrt(-self.l_fw_2[g]) - trig_funcs.append(int_const.fw_c[g] * c(x_cm / l_fw)) - trig_funcs.append(int_const.fw_s[g] * s(x_cm / l_fw)) + trig_funcs.append(int_const.fw_c[g] * c(abs(x_cm) / l_fw)) + trig_funcs.append(int_const.fw_s[g] * s(abs(x_cm) / l_fw)) return np.sum(trig_funcs, axis=0) @@ -867,8 +867,8 @@ def _groupwise_neutron_flux_bz( else: c, s = np.cos, np.sin l_bz = np.sqrt(-self.l_bz_2[g]) - trig_funcs.append(int_const.bz_c[g] * c(x_cm / l_bz)) - trig_funcs.append(int_const.bz_s[g] * s(x_cm / l_bz)) + trig_funcs.append(int_const.bz_c[g] * c(abs(x_cm) / l_bz)) + trig_funcs.append(int_const.bz_s[g] * s(abs(x_cm) / l_bz)) return np.sum(trig_funcs, axis=0) From b68db420e7f5f43428f2adf1de7346bdf7456f97 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 04:04:18 +0000 Subject: [PATCH 55/98] renamed the integration constants' working names to something a little more meaningful. --- process/neutronics.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index c50cb4a75e..c8f20cc473 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -360,27 +360,27 @@ def solve_lowest_group(self) -> None: s_bz_mod = np.sin((self.extended_boundary_cm[n] - x_fw) / l_bz) t_bz_mod = np.tan((self.extended_boundary_cm[n] - x_fw) / l_bz) - c5 = - self.flux * ( + fw_c_factor = - self.flux * ( l_fw / d_fw - np.exp(x_fw / l_fw) * ( - (l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod - )/( - c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz) - ) + (l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod + )/( + c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz) ) - c6 = - self.flux * l_fw / d_fw + ) + fw_s_factor = - self.flux * l_fw / d_fw - c7_c8_common_factor = ( + bz_common_factor = ( self.flux * np.exp(x_fw / l_fw) * (1 - t_fw) / ((d_bz / l_bz) * c_bz_mod + (d_fw / l_fw) * t_fw * s_bz_mod) ) - c7 = c7_c8_common_factor * s_bz - c8 = -c7_c8_common_factor * c_bz + bz_c_factor = bz_common_factor * s_bz + bz_s_factor = -bz_common_factor * c_bz self.integration_constants[n] = IntegrationConstants( - [c5], [c6], [c7], [c8] + [fw_c_factor], [fw_s_factor], [bz_c_factor], [bz_s_factor] ) return From d8d5b9821c525881ead1462ed9df60db713c1987 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 19:21:40 +0000 Subject: [PATCH 56/98] One more regression test for now. --- tests/regression/test_neutronics.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 72524d1b1c..14a05e5c08 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -4,7 +4,7 @@ from process.neutronics import NeutronFluxProfile from process.neutronics_data import MaterialMacroInfo -def test_against_desmos_number(): +def test_one_group(): """ Regression test against Desmos snapshot: https://www.desmos.com/calculator/18xojespuo @@ -79,11 +79,11 @@ def test_one_group_with_fission(): incoming_flux, x_fw, x_bz, fw_material, bz_material ) assert np.isclose(neutron_profile.l_bz_2[0], -58.2869567709**2) - neutron_profile.plot() - import matplotlib.pyplot as plt - plt.show() - assert np.isclose(neutron_profile.neutron_flux_at(18.96382/100), 164.81245) + assert np.isclose(neutron_profile.neutron_flux_at(18.96382/100), 164.81245), "Maximum flux in BZ" + assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), neutron_profile.neutron_flux_bz(x_fw)), "Flux continuity assurance" def test_two_groups(): - """4""" - + """ + Same group n=0 values as test_one_group. Second group can have a massive removal cross-section + """ + From 3627fad22142876cbe1c9c194815f4e565505e1e Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 19:22:21 +0000 Subject: [PATCH 57/98] Beginning removal of the _groupwise functions (because they don't need to be separated out like that) --- process/neutronics.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index c8f20cc473..c8c200f1ca 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -432,7 +432,6 @@ def solve_group_n(self, n: int) -> None: # Setting up aliases for shorter code l_fw_2, l_bz_2 = self.l_fw_2[n], self.l_bz_2[n] d_fw, d_bz = self.d_fw_cm[n], self.d_bz_cm[n] - ic = self.integration_constants src_fw = self.fw_mat.sigma_s_cm + self.fw_mat.sigma_in_cm src_bz = self.bz_mat.sigma_s_cm + self.bz_mat.sigma_in_cm @@ -451,19 +450,19 @@ def solve_group_n(self, n: int) -> None: else: scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz _ic_n.fw_c.append( - sum(src_fw[i, n] * ic[i].fw_c[g] for i in range(g, n)) + sum(src_fw[i, n] * self.integration_constants[i].fw_c[g] for i in range(g, n)) * scale_factor_fw ) _ic_n.fw_s.append( - sum(src_fw[i, n] * ic[i].fw_s[g] for i in range(g, n)) + sum(src_fw[i, n] * self.integration_constants[i].fw_s[g] for i in range(g, n)) * scale_factor_fw ) _ic_n.bz_c.append( - sum(src_bz[i, n] * ic[i].bz_c[g] for i in range(g, n)) + sum(src_bz[i, n] * self.integration_constants[i].bz_c[g] for i in range(g, n)) * scale_factor_bz ) _ic_n.bz_s.append( - sum(src_bz[i, n] * ic[i].bz_s[g] for i in range(g, n)) + sum(src_bz[i, n] * self.integration_constants[i].bz_s[g] for i in range(g, n)) * scale_factor_bz ) @@ -474,11 +473,10 @@ def solve_group_n(self, n: int) -> None: _ic_n.bz_s.append(c4) def set_constants(input_vector: Iterable[float]): - c1, c2, c3, c4 = input_vector - _ic_n.fw_c[n] = c1 - _ic_n.fw_s[n] = c2 - _ic_n.bz_c[n] = c3 - _ic_n.bz_s[n] = c4 + _ic_n.fw_c[n] = input_vector[0] + _ic_n.fw_s[n] = input_vector[1] + _ic_n.bz_c[n] = input_vector[2] + _ic_n.bz_s[n] = input_vector[3] def evaluate_fit(): flux_continuity = _groupwise_neutron_flux_fw( From 958192e146f430c20fe5094e49fa759fc2b467f2 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 20:14:55 +0000 Subject: [PATCH 58/98] Minor change to the solve_n_group method to prep it for future (iterative) solver. --- process/neutronics.py | 137 +++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 75 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index c8c200f1ca..fb9609cff0 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -413,6 +413,10 @@ def solve_group_n(self, n: int) -> None: ) if n in self.integration_constants: return None # skip if it has already been solved. + else: + # Parameter to be changed later, to allow solving non-down-scatter + # only systems by iterating. + first_iteration = True self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.avg_atomic_mass, self.fw_mat.sigma_t_cm[n], @@ -435,7 +439,7 @@ def solve_group_n(self, n: int) -> None: src_fw = self.fw_mat.sigma_s_cm + self.fw_mat.sigma_in_cm src_bz = self.bz_mat.sigma_s_cm + self.bz_mat.sigma_in_cm - _ic_n = IntegrationConstants([], [], [], []) + self.integration_constants[n] = IntegrationConstants([], [], [], []) for g in range(n): # if the characteristic length of group [g] coincides with the # characteristic length of group [n], then that particular @@ -449,69 +453,64 @@ def solve_group_n(self, n: int) -> None: scale_factor_bz = 0.0 else: scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz - _ic_n.fw_c.append( + self.integration_constants[n].fw_c.append( sum(src_fw[i, n] * self.integration_constants[i].fw_c[g] for i in range(g, n)) * scale_factor_fw ) - _ic_n.fw_s.append( + self.integration_constants[n].fw_s.append( sum(src_fw[i, n] * self.integration_constants[i].fw_s[g] for i in range(g, n)) * scale_factor_fw ) - _ic_n.bz_c.append( + self.integration_constants[n].bz_c.append( sum(src_bz[i, n] * self.integration_constants[i].bz_c[g] for i in range(g, n)) * scale_factor_bz ) - _ic_n.bz_s.append( + self.integration_constants[n].bz_s.append( sum(src_bz[i, n] * self.integration_constants[i].bz_s[g] for i in range(g, n)) * scale_factor_bz ) - c1, c2, c3, c4 = 0.0, 0.0, 0.0, 0.0 - _ic_n.fw_c.append(c1) - _ic_n.fw_s.append(c2) - _ic_n.bz_c.append(c3) - _ic_n.bz_s.append(c4) + fw_c_factor_guess = 0.0 + fw_s_factor_guess = 0.0 + bz_c_factor_guess = 0.0 + bz_s_factor_guess = 0.0 + self.integration_constants[n].fw_c.append(fw_c_factor_guess) + self.integration_constants[n].fw_s.append(fw_s_factor_guess) + self.integration_constants[n].bz_c.append(bz_c_factor_guess) + self.integration_constants[n].bz_s.append(bz_s_factor_guess) - def set_constants(input_vector: Iterable[float]): + def _set_constants(input_vector: Iterable[float]): _ic_n.fw_c[n] = input_vector[0] _ic_n.fw_s[n] = input_vector[1] _ic_n.bz_c[n] = input_vector[2] _ic_n.bz_s[n] = input_vector[3] - def evaluate_fit(): - flux_continuity = _groupwise_neutron_flux_fw( - _ic_n, self, n, self.x_fw_cm - ) - _groupwise_neutron_flux_bz(_ic_n, self, n, self.x_fw_cm) - flux_at_boundary = _groupwise_neutron_flux_bz( - _ic_n, self, n, self.extended_boundary_cm[n] - ) + def _evaluate_fit(): + flux_continuity = self.groupwise_neutron_flux_fw(n, self.x_fw_cm) - self.groupwise_neutron_flux_bz(n, self.x_fw_cm) + flux_at_boundary = self.groupwise_neutron_flux_bz(n, self.extended_boundary_cm[n]) current_continuity = _groupwise_neutron_current_fw2bz( _ic_n, self, n, True ) - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) influx_fw, influx_bz = 0.0, 0.0 - for g in range(n): - influx_fw += self.fw_mat.sigma_s_cm[ - g, n - ] * _groupwise_integrated_flux_fw( - self.integration_constants[g], self, g - ) - influx_bz += self.bz_mat.sigma_s_cm[ - g, n - ] * _groupwise_integrated_flux_bz( - self.integration_constants[g], self, g - ) - removal_fw = ( - self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum() - ) * _groupwise_neutron_flux_fw(_ic_n, self, n) - removal_bz = ( - self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum() - ) * _groupwise_neutron_flux_bz(_ic_n, self, n) - neutron_conservation = ( + for g in range(self.n_groups): + if g>n and not first_iteration: + if not self.fw_mat.downscatter_only: + influx_fw += (self.fw_mat.sigma_s_cm[g, n] + self.fw_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_fw(g) + if not self.bz_mat.downscatter_only: + influx_bz += (self.bz_mat.sigma_s_cm[g, n] + self.bz_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_bz(g) + elif g<=n: + influx_fw += (self.fw_mat.sigma_s_cm[g, n] + self.fw_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_fw(g) + influx_bz += (self.bz_mat.sigma_s_cm[g, n] + self.bz_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_bz(g) + removal_fw = self.fw_mat.sigma_t_cm[n] * self.groupwise_integrated_flux_fw(n) + removal_bz = self.bz_mat.sigma_t_cm[n] * self.groupwise_integrated_flux_bz(n) + # conservation_fw = influx_fw - removal_fw - current_fw2bz + # conservation_bz = current_fw2bz + influx_bz - removal_bz - escaped_bz + total_neutron_conservation = ( influx_fw + influx_bz - removal_fw - removal_bz - - _groupwise_neutron_current_escaped(_ic_n, self, n) + - self.groupwise_neutron_current_escaped(_ic_n, self, n) ) # in fact, we can separate the last condition (neutron conservation) # into two regions: fw and bz @@ -522,15 +521,20 @@ def evaluate_fit(): flux_continuity, flux_at_boundary, current_continuity, - neutron_conservation, + total_neutron_conservation, ]) def objective(four_integration_constants_vector): - set_constants(four_integration_constants_vector) - return evaluate_fit() - - optimize.root(set_constants, x0=[c1, c2, c3, c4]) - self.integration_constants[n] = _ic_n + _set_constants(four_integration_constants_vector) + return _evaluate_fit() + + results = optimize.root(objective, x0=[ + fw_c_factor_guess, + fw_s_factor_guess, + bz_c_factor_guess, + bz_s_factor_guess, + ]) + _set_constants(results.res) return None @summarize_values @@ -559,12 +563,17 @@ def groupwise_neutron_flux_fw( """ x_cm = x * 100 - return _groupwise_neutron_flux_fw( - self.integration_constants[n], - self, - n, - x_cm, - ) + trig_funcs = [] + for g in range(n + 1): + if self.l_fw_2[g]>0: + c, s = np.cosh, np.sinh + l_fw = np.sqrt(self.l_fw_2[g]) + else: + c, s = np.cos, np.sin + l_fw = np.sqrt(-self.l_fw_2[g]) + trig_funcs.append(self.integration_constants.fw_c[g] * c(abs(x_cm) / l_fw)) + trig_funcs.append(self.integration_constants.fw_s[g] * s(abs(x_cm) / l_fw)) + return np.sum(trig_funcs, axis=0) @summarize_values def groupwise_neutron_flux_bz( @@ -650,11 +659,11 @@ def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: - string of either {"total","removal"}. + string of either {"total", "removal"}. """ if reaction_type == "removal": - sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n].sum() + sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n, n] elif reaction_type == "total": sigma = self.fw_mat.sigma_t_cm[n] else: @@ -677,11 +686,11 @@ def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. reaction_type: - string of either {"total","removal"}. + string of either {"total", "removal"}. """ if reaction_type == "removal": - sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n].sum() + sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n, n] elif reaction_type == "total": sigma = self.bz_mat.sigma_t_cm[n] else: @@ -822,28 +831,6 @@ def plot( return ax -def _groupwise_neutron_flux_fw( - int_const: IntegrationConstants, - self: NeutronFluxProfile, - n: int, - x_cm: float | npt.NDArray, -) -> npt.NDArray: - """ - Calculate groupwise_neutron_flux_fw for NeutronFluxProfile, but - in such a way that doesn't trigger the re-calculation of integration_constants - (which would've led to RecursionError if called within solve_group_n). - """ - trig_funcs = [] - for g in range(n + 1): - if self.l_fw_2[g]>0: - c, s = np.cosh, np.sinh - l_fw = np.sqrt(self.l_fw_2[g]) - else: - c, s = np.cos, np.sin - l_fw = np.sqrt(-self.l_fw_2[g]) - trig_funcs.append(int_const.fw_c[g] * c(abs(x_cm) / l_fw)) - trig_funcs.append(int_const.fw_s[g] * s(abs(x_cm) / l_fw)) - return np.sum(trig_funcs, axis=0) def _groupwise_neutron_flux_bz( From c5323e7d6cd7ea93808399d5b4a2e1aebc3505e7 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 12 Nov 2025 20:50:50 +0000 Subject: [PATCH 59/98] Completed removal of the _groupwise functions. --- process/neutronics.py | 420 +++++++++++----------------- process/neutronics_data.py | 1 + tests/regression/test_neutronics.py | 10 +- tests/unit/test_neutronics.py | 10 +- 4 files changed, 177 insertions(+), 264 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index fb9609cff0..d4956ae39b 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -486,11 +486,9 @@ def _set_constants(input_vector: Iterable[float]): _ic_n.bz_s[n] = input_vector[3] def _evaluate_fit(): - flux_continuity = self.groupwise_neutron_flux_fw(n, self.x_fw_cm) - self.groupwise_neutron_flux_bz(n, self.x_fw_cm) + flux_continuity = self.groupwise_neutron_flux_fw(n, self.x_fw_cm/100) - self.groupwise_neutron_flux_bz(n, self.x_fw_cm/100) flux_at_boundary = self.groupwise_neutron_flux_bz(n, self.extended_boundary_cm[n]) - current_continuity = _groupwise_neutron_current_fw2bz( - _ic_n, self, n, True - ) - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) + current_continuity = self.groupwise_neutron_current_fw(n, self.x_fw_cm/100) - self.groupwise_neutron_current_bz(n, self.x_fw_cm/100) influx_fw, influx_bz = 0.0, 0.0 for g in range(self.n_groups): if g>n and not first_iteration: @@ -502,7 +500,7 @@ def _evaluate_fit(): influx_fw += (self.fw_mat.sigma_s_cm[g, n] + self.fw_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_fw(g) influx_bz += (self.bz_mat.sigma_s_cm[g, n] + self.bz_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_bz(g) removal_fw = self.fw_mat.sigma_t_cm[n] * self.groupwise_integrated_flux_fw(n) - removal_bz = self.bz_mat.sigma_t_cm[n] * self.groupwise_integrated_flux_bz(n) + removal_bz = self.bz_mat.szsigma_t_cm[n] * self.groupwise_integrated_flux_bz(n) # conservation_fw = influx_fw - removal_fw - current_fw2bz # conservation_bz = current_fw2bz + influx_bz - removal_bz - escaped_bz total_neutron_conservation = ( @@ -512,11 +510,6 @@ def _evaluate_fit(): - removal_bz - self.groupwise_neutron_current_escaped(_ic_n, self, n) ) - # in fact, we can separate the last condition (neutron conservation) - # into two regions: fw and bz - # which gives: - # conservation_fw = influx_fw - removal_fw - _groupwise_neutron_current_fw2bz(_ic_n, self, n, True) - # conservation_bz = influx_bz - removal_bz - _groupwise_neutron_current_fw2bz(_ic_n, self, n, False) - _groupwise_neutron_current_escaped(_ic_n, self, n) return np.array([ flux_continuity, flux_at_boundary, @@ -548,7 +541,7 @@ def groupwise_neutron_flux_fw( ---------- n: The index of the neutron group whose flux is being evaluated. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. x: The position where the neutron flux has to be evaluated. Note that this function does not enforce a check for x=inside the first-wall, @@ -571,8 +564,8 @@ def groupwise_neutron_flux_fw( else: c, s = np.cos, np.sin l_fw = np.sqrt(-self.l_fw_2[g]) - trig_funcs.append(self.integration_constants.fw_c[g] * c(abs(x_cm) / l_fw)) - trig_funcs.append(self.integration_constants.fw_s[g] * s(abs(x_cm) / l_fw)) + trig_funcs.append(self.integration_constants[n].fw_c[g] * c(abs(x_cm) / l_fw)) + trig_funcs.append(self.integration_constants[n].fw_s[g] * s(abs(x_cm) / l_fw)) return np.sum(trig_funcs, axis=0) @summarize_values @@ -585,7 +578,7 @@ def groupwise_neutron_flux_bz( ---------- n: The index of the neutron group whose flux is being evaluated. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. x: The position where the neutron flux has to be evaluated. [m] Note that this function does not enforce a check for x=inside the blanket, @@ -600,12 +593,17 @@ def groupwise_neutron_flux_bz( """ x_cm = x * 100 - return _groupwise_neutron_flux_bz( - self.integration_constants[n], - self, - n, - x_cm, - ) + trig_funcs = [] + for g in range(n + 1): + if self.l_bz_2[g]>0: + c, s = np.cosh, np.sinh + l_bz = np.sqrt(self.l_bz_2[g]) + else: + c, s = np.cos, np.sin + l_bz = np.sqrt(-self.l_bz_2[g]) + trig_funcs.append(self.integration_constants[n].bz_c[g] * c(abs(x_cm) / l_bz)) + trig_funcs.append(self.integration_constants[n].bz_s[g] * s(abs(x_cm) / l_bz)) + return np.sum(trig_funcs, axis=0) @summarize_values def groupwise_neutron_flux_at( @@ -613,13 +611,13 @@ def groupwise_neutron_flux_at( ) -> npt.NDArray: """ Neutron flux [cm^-2 s^-1] anywhere within the valid range of x, - i.e. from -self.x_bz_cm to self.x_bz_cm. + i.e. [-self.extended_boundary_cm[n], self.extended_boundary_cm[n]]. Parameters ---------- n: Neutron group index. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. x: The depth where we want the neutron flux [m]. Valid only between x= -extended boundary to +-extended boundary of that group @@ -650,59 +648,164 @@ def groupwise_neutron_flux_at( # scalar values (one such float per neutron group.) @summarize_values - def groupwise_reaction_rate_fw(self, n: int, reaction_type: str) -> float: - """Calculate the reaction rate [s^-1] in the first wall. + def groupwise_integrated_flux_fw(self, n: int) -> float: + """ + Calculate the integrated flux[cm s^-1], which can be mulitplied to any + macroscopic cross-section [cm^-1] to get the reaction rate [s^-1] in + the first wall. Parameters ---------- n: The index of the neutron group that needs to be solved. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. - reaction_type: - string of either {"total", "removal"}. - + Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. """ - if reaction_type == "removal": - sigma = self.fw_mat.sigma_t_cm[n] - self.fw_mat.sigma_s_cm[n, n] - elif reaction_type == "total": - sigma = self.fw_mat.sigma_t_cm[n] - else: - raise NotImplementedError( - f"Not yet implemented the reaction type {reaction_type}" - ) - return sigma * _groupwise_integrated_flux_fw( - self.integration_constants[n], - self, - n, - ) + integrals = [] + for g in range(n + 1): + if self.l_fw_2[g]>0: + l_fw = np.sqrt(self.l_fw_2[g]) + integrals.append( + l_fw * self.integration_constants[n].fw_c[g] * np.sinh(self.x_fw_cm / l_fw) + ) + integrals.append( + l_fw * self.integration_constants[n].fw_s[g] * (np.cosh(self.x_fw_cm / l_fw) - 1) + ) + else: + l_fw = np.sqrt(-self.l_fw_2[g]) + integrals.append( + l_fw * self.integration_constants[n].fw_c[g] * np.sin(self.x_fw_cm / l_fw) + ) + integrals.append( + l_fw * self.integration_constants[n].fw_s[g] * (1 - np.cos(self.x_fw_cm / l_fw)) + ) + + return np.sum(integrals, axis=0) @summarize_values - def groupwise_reaction_rate_bz(self, n: int, reaction_type: str) -> float: - """Calculate the reaction rate in the blanket. + def groupwise_integrated_flux_bz(self, n: int) -> float: + """ + Calculate the integrated flux[cm s^-1], which can be mulitplied to any + macroscopic cross-section [cm^-1] to get the reaction rate [s^-1] in + the blanket. Parameters ---------- n: The index of the neutron group that needs to be solved. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. - reaction_type: - string of either {"total", "removal"}. + Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. + """ + integrals = [] + for g in range(n + 1): + if self.l_bz_2[g]>0: + l_bz = np.sqrt(self.l_bz_2[g]) + integrals.append( + l_bz * self.integration_constants[n].bz_c[g] * + (np.sinh(self.x_bz_cm / l_bz) - np.sinh(self.x_fw_cm / l_bz)) + ) + integrals.append( + l_bz * self.integration_constants[n].bz_s[g] * + (np.cosh(self.x_bz_cm / l_bz) - np.cosh(self.x_fw_cm / l_bz)) + ) + else: + l_bz = np.sqrt(-self.l_bz_2[g]) + integrals.append( + l_bz * self.integration_constants[n].bz_c[g] * + (np.sin(self.x_bz_cm / l_bz) - np.sin(self.x_fw_cm / l_bz)) + ) + integrals.append( + -l_bz * self.integration_constants[n].bz_s[g] * + (np.cos(self.x_bz_cm / l_bz) - np.cos(self.x_fw_cm / l_bz)) + ) + return np.sum(integrals, axis=0) + + @summarize_values + def groupwise_neutron_current_fw(self, n: int, x: float | npt.NDArray) -> float: + """Get the neutron current (in the outward direction) in the fw""" + x_cm = x * 100 + differentials = [] + for g in range(n + 1): + if self.l_fw_2[g]>0: + l_fw = np.sqrt(self.l_fw_2[g]) + differentials.append( + self.integration_constants[n].fw_c[g] / l_fw * np.sinh(x_cm / l_fw) + ) + differentials.append( + self.integration_constants[n].fw_s[g] / l_fw * np.cosh(x_cm / l_fw) + ) + else: + l_fw = np.sqrt(-self.l_fw_2[g]) + differentials.append( + - self.integration_constants[n].fw_c[g] / l_fw * np.sin(x_cm / l_fw) + ) + differentials.append( + self.integration_constants[n].fw_s[g] / l_fw * np.cos(x_cm / l_fw) + ) + return -self.d_fw_cm[n] * np.sum(differentials, axis=0) + + @summarize_values + def groupwise_neutron_current_bz(self, n: int, x: float | npt.NDArray) -> float: + """Get the neutron current (in the outward direction) in the bz.""" + x_cm = x * 100 + differentials = [] + for g in range(n + 1): + if self.l_bz_2[g]>0: + l_bz = np.sqrt(self.l_bz_2[g]) + differentials.append( + self.integration_constants[n].bz_c[g] / l_bz * np.sinh(x_cm / l_bz) + ) + differentials.append( + self.integration_constants[n].bz_s[g] / l_bz * np.cosh(x_cm / l_bz) + ) + else: + l_bz = np.sqrt(-self.l_bz_2[g]) + differentials.append( + - self.integration_constants[n].bz_c[g] / l_bz * np.sin(x_cm / l_bz) + ) + differentials.append( + self.integration_constants[n].bz_s[g] / l_bz * np.cos(x_cm / l_bz) + ) + return -self.d_bz_cm[n] * np.sum(differentials, axis=0) + @summarize_values + def groupwise_neutron_current_at( + self, n: int, x: float | npt.NDArray + ) -> npt.NDArray: """ - if reaction_type == "removal": - sigma = self.bz_mat.sigma_t_cm[n] - self.bz_mat.sigma_s_cm[n, n] - elif reaction_type == "total": - sigma = self.bz_mat.sigma_t_cm[n] - else: - raise NotImplementedError( - f"Not yet implemented the reaction type {reaction_type}" - ) + Neutron current [cm^-2 s^-1] anywhere within the valid range of x, + i.e. from -self.x_bz_cm to self.x_bz_cm. + + Parameters + ---------- + n: + Neutron group index. n <= n_groups - 1. + Therefore n=0 shows the neutron current for group 1, n=1 for group 2, etc. + x: + The depth where we want the neutron flux [m]. + Valid only between x= -extended boundary to +-extended boundary of that group - return sigma * _groupwise_integrated_flux_bz( - self.integration_constants[n], - self, - n, + Raises + ------ + ValueError + The inputted x + """ + if np.isscalar(x): + return self.groupwise_neutron_flux_at(n, [x])[0] + x = np.asarray(x) + in_fw = abs(x * 100) <= self.x_fw_cm + in_bz = np.logical_and( + self.x_fw_cm < abs(x * 100), + abs(x * 100) <= self.x_bz_cm, ) + if (~np.logical_or(in_fw, in_bz)).any(): + raise ValueError( + f"for neutron group {n}, neutron flux can only be calculated " + f"up to {self.x_bz_cm} cm, which {x * 100} cm violates!" + ) + + out_current = np.zeros_like(x) + out_current[in_fw] = self.groupwise_neutron_current_fw(n, x[in_fw]) + out_current[in_bz] = self.groupwise_neutron_current_bz(n, x[in_bz]) + return out_current @summarize_values def groupwise_neutron_current_fw2bz(self, n: int) -> float: @@ -712,16 +815,14 @@ def groupwise_neutron_current_fw2bz(self, n: int) -> float: ---------- n: The index of the neutron group that we want the current for. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + Therefore n=0 shows the neutron current for group 1, n=1 for group 2, etc. Returns ------- : current in cm^-2 """ - return _groupwise_neutron_current_fw2bz( - self.integration_constants[n], self, n, False - ) + return self.groupwise_neutron_current_bz(n, self.x_fw_cm/100) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -731,18 +832,14 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: ---------- n: The index of the neutron group that we want the current for. n <= n_groups - 1. - Therefore n=0 shows the reaction rate for group 1, n=1 for group 2, etc. + Therefore n=0 shows the neutron current for group 1, n=1 for group 2, etc. Returns ------- : current in cm^-2 """ - return _groupwise_neutron_current_escaped( - self.integration_constants[n], - self, - n, - ) + return self.groupwise_neutron_current_bz(n, self.x_bz_cm/100) def plot( self, @@ -831,193 +928,6 @@ def plot( return ax - - -def _groupwise_neutron_flux_bz( - int_const: IntegrationConstants, - self: NeutronFluxProfile, - n: int, - x_cm: float | npt.NDArray, -) -> npt.NDArray: - """ - Calculate groupwise_neutron_flux_bz for NeutronFluxProfile, but - in such a way that doesn't trigger the re-calculation of integration_constants - (which would've led to RecursionError if called within solve_group_n). - """ - trig_funcs = [] - for g in range(n + 1): - if self.l_bz_2[g]>0: - c, s = np.cosh, np.sinh - l_bz = np.sqrt(self.l_bz_2[g]) - else: - c, s = np.cos, np.sin - l_bz = np.sqrt(-self.l_bz_2[g]) - trig_funcs.append(int_const.bz_c[g] * c(abs(x_cm) / l_bz)) - trig_funcs.append(int_const.bz_s[g] * s(abs(x_cm) / l_bz)) - return np.sum(trig_funcs, axis=0) - - -def _groupwise_integrated_flux_fw( - int_const: IntegrationConstants, self: NeutronFluxProfile, n: int -) -> float: - """ - Help calculate groupwise_reaction_rate_fw for NeutronFluxProfile, but - in such a way that doesn't trigger the re-calculation of integration_constants - (which would've led to RecursionError if called within solve_group_n). - """ - - integrals = [] - for g in range(n + 1): - if self.l_fw_2[g]>0: - l_fw = np.sqrt(self.l_fw_2[g]) - integrals.append( - l_fw * int_const.fw_c[g] * np.sinh(self.x_fw_cm / l_fw) - ) - integrals.append( - l_fw * int_const.fw_s[g] * (np.cosh(self.x_fw_cm / l_fw) - 1) - ) - else: - l_fw = np.sqrt(-self.l_fw_2[g]) - integrals.append( - l_fw * int_const.fw_c[g] * np.sin(self.x_fw_cm / l_fw) - ) - integrals.append( - l_fw * int_const.fw_s[g] * (1 - np.cos(self.x_fw_cm / l_fw)) - ) - - return np.sum(integrals, axis=0) - - -def _groupwise_integrated_flux_bz( - int_const: IntegrationConstants, self: NeutronFluxProfile, n: int -) -> float: - """ - Help calculate groupwise_reaction_rate_bz for NeutronFluxProfile, but - in such a way that doesn't trigger the re-calculation of integration_constants - (which would've led to RecursionError if called within solve_group_n). - """ - - integrals = [] - for g in range(n + 1): - if self.l_bz_2[g]>0: - l_bz = np.sqrt(self.l_bz_2[g]) - integrals.append( - l_bz * int_const.bz_c[g] * - (np.sinh(self.x_bz_cm / l_bz) - np.sinh(self.x_fw_cm / l_bz)) - ) - integrals.append( - l_bz * int_const.bz_s[g] * - (np.cosh(self.x_bz_cm / l_bz) - np.cosh(self.x_fw_cm / l_bz)) - ) - else: - l_bz = np.sqrt(-self.l_bz_2[g]) - integrals.append( - l_bz * int_const.bz_c[g] * - (np.sin(self.x_bz_cm / l_bz) - np.sin(self.x_fw_cm / l_bz)) - ) - integrals.append( - -l_bz * int_const.bz_s[g] * - (np.cos(self.x_bz_cm / l_bz) - np.cos(self.x_fw_cm / l_bz)) - ) - return np.sum(integrals, axis=0) - - -def _groupwise_neutron_current_fw2bz( - int_const: IntegrationConstants, - self: NeutronFluxProfile, - n: int, - alt_implementation: bool = False, -) -> float: - """ - Calculate groupwise_neutron_current_fw2bz for NeutronFluxProfile, but - in such a way that doesn't trigger the re-calculation of integration_constants - (which would've led to RecursionError if called within solve_group_n). - - Returns - ------- - : - current in cm^-2 - """ - differentials = [] - if alt_implementation: - for g in range(n + 1): - if self.l_fw_2[g]>0: - l_fw = np.sqrt(self.l_fw_2[g]) - differentials.append( - int_const.fw_c[g] / l_fw * np.sinh(self.x_fw_cm / l_fw) - ) - differentials.append( - int_const.fw_s[g] / l_fw * np.cosh(self.x_fw_cm / l_fw) - ) - else: - l_fw = np.sqrt(-self.l_fw_2[g]) - differentials.append( - - int_const.fw_c[g] / l_fw * np.sin(self.x_fw_cm / l_fw) - ) - differentials.append( - int_const.fw_s[g] / l_fw * np.cos(self.x_fw_cm / l_fw) - ) - - return -self.d_fw_cm[n] * np.sum(differentials, axis=0) - - # equivalent definition below: (should yield the same answer once converged) - for g in range(n + 1): - if self.l_bz_2[g]>0: - l_bz = np.sqrt(self.l_bz_2[g]) - differentials.append( - int_const.bz_c[g] / l_bz * np.sinh(self.x_fw_cm / l_bz) - ) - differentials.append( - int_const.bz_s[g] / l_bz * np.cosh(self.x_fw_cm / l_bz) - ) - else: - l_bz = np.sqrt(-self.l_bz_2[g]) - differentials.append( - - int_const.bz_c[g] / l_bz * np.sin(self.x_fw_cm / l_bz) - ) - differentials.append( - int_const.bz_s[g] / l_bz * np.cos(self.x_fw_cm / l_bz) - ) - - return -self.d_bz_cm[n] * np.sum(differentials, axis=0) - - -def _groupwise_neutron_current_escaped( - int_const: IntegrationConstants, - self: NeutronFluxProfile, - n: int, -) -> float: - """ - Calculate groupwise_neutron_current_escaped for NeutronFluxProfile, but - in such a way that doesn't trigger the re-calculation of integration_constants - (which would've led to RecursionError if called within solve_group_n). - - Returns - ------- - : - current in cm^-2 - """ - differentials = [] - for g in range(n + 1): - if self.l_bz_2[g]>0: - l_bz = np.sqrt(self.l_bz_2[g]) - differentials.append( - int_const.bz_c[g] / l_bz * np.sinh(self.x_bz_cm / l_bz) - ) - differentials.append( - int_const.bz_s[g] / l_bz * np.cosh(self.x_bz_cm / l_bz) - ) - else: - l_bz = np.sqrt(-self.l_bz_2[g]) - differentials.append( - - int_const.bz_c[g] / l_bz * np.sin(self.x_bz_cm / l_bz) - ) - differentials.append( - int_const.bz_s[g] / l_bz * np.cos(self.x_bz_cm / l_bz) - ) - return -self.d_bz_cm[n] * np.sum(differentials, axis=0) - - def _generate_x_range( x_max_cm: float, approx_n_points: int, diff --git a/process/neutronics_data.py b/process/neutronics_data.py index cec79b5db2..46a412cf6f 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -465,6 +465,7 @@ class MaterialMacroInfo: sigma_t: npt.NDArray[np.float64] sigma_s: npt.NDArray sigma_in: npt.NDArray | None = None + name: str = "" def __post_init__(self): """ diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 14a05e5c08..a028d97b0b 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -16,14 +16,14 @@ def test_one_group(): sigma_fw_t = 1 / mfp_fw_t # [1/m] sigma_fw_s = 1 / mfp_fw_s # [1/m] a_fw = 52 - fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]]) + fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]], name="fw") mfp_bz_s = 97 * 0.01 # [m] mfp_bz_t = 35.8 * 0.01 # [m] sigma_bz_s = 1 / mfp_bz_s # [1/m] sigma_bz_t = 1 / mfp_bz_t # [1/m] a_bz = 71 - bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]]) + bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], name="bz") x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 @@ -61,7 +61,7 @@ def test_one_group_with_fission(): sigma_fw_t = 1 / mfp_fw_t # [1/m] sigma_fw_s = 1 / mfp_fw_s # [1/m] a_fw = 52 - fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]]) + fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]], name="fw") mfp_bz_s = 97 * 0.01 # [m] mfp_bz_t = 35.8 * 0.01 # [m] @@ -71,7 +71,7 @@ def test_one_group_with_fission(): g = 1.2 nu_sigma_bz_f = g * (sigma_bz_t - sigma_bz_s) - bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], [[nu_sigma_bz_f]]) + bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], [[nu_sigma_bz_f]], name="bz") x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 @@ -86,4 +86,4 @@ def test_two_groups(): """ Same group n=0 values as test_one_group. Second group can have a massive removal cross-section """ - + diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 8ebefa95c0..b99d434e9a 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -82,13 +82,15 @@ def test_has_reactions(): def test_three_group(): - # no negative flux + # 1. No negative flux dummy = [10000, 1000, 100, 1] # fw_mat = MaterialMacroInfo() bz_mat = MaterialMacroInfo - # same L_1 and L_3 shoudl yield integration_constants[2].fw_pos[0] and - # integration_constants[2].fw_neg[0] = 0.0 + # 2. same L_1 and L_3 shoudl yield integration_constants[2].fw_c[0] and + # integration_constants[2].fw_s[0] = 0.0 + # self.l_fw_2 == self.l_fw_2[n] case. + # def test_two_group(): - """""" + """Ensure continuity at interface for both groups.""" From 15b527c1b25fc95d9e01aec233f84f74ba749330 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 20 Nov 2025 13:46:25 +0000 Subject: [PATCH 60/98] Completed one-group fission regression test. --- tests/regression/test_neutronics.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index a028d97b0b..0224b825cf 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -44,11 +44,14 @@ def test_one_group(): assert np.isclose(neutron_profile.neutron_current_fw2bz(), 22.3980214162) assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) + fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] + bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] assert np.isclose(neutron_profile.flux, neutron_profile.neutron_current_escaped() - + neutron_profile.reaction_rate_fw("removal") - + neutron_profile.reaction_rate_bz("removal") - ) + + fw_removal/100 * neutron_profile.integrated_flux_fw() + + bz_removal/100 * neutron_profile.integrated_flux_bz() + ), "Conservation of neutrons" + def test_one_group_with_fission(): """ Regression test against Desmos snapshot with fission involved: @@ -79,8 +82,20 @@ def test_one_group_with_fission(): incoming_flux, x_fw, x_bz, fw_material, bz_material ) assert np.isclose(neutron_profile.l_bz_2[0], -58.2869567709**2) + assert np.isclose(neutron_profile.neutron_flux_at(-4.79675/100), 159.9434), "Minimum flux in FW" + assert np.isclose(neutron_profile.neutron_flux_at(4.79675/100), 159.9434), "Minimum flux in FW" assert np.isclose(neutron_profile.neutron_flux_at(18.96382/100), 164.81245), "Maximum flux in BZ" + assert np.isclose(neutron_profile.neutron_flux_at(-18.96382/100), 164.81245), "Maximum flux in BZ" assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), neutron_profile.neutron_flux_bz(x_fw)), "Flux continuity assurance" + assert np.isclose(neutron_profile.neutron_current_fw2bz(), -7.6275782637960745), "Negative current because BZ (breeding) is backflowing into the FW" + assert np.isclose(neutron_profile.neutron_current_escaped(), 30.665951670177186), "positive escaped current." + fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] + bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] + assert np.isclose(neutron_profile.flux, + neutron_profile.neutron_current_escaped() + + fw_removal/100 * neutron_profile.integrated_flux_fw() + + bz_removal/100 * neutron_profile.integrated_flux_bz() + ), "Conservation of neutrons" def test_two_groups(): """ From 3d4f8c0f14940d8b3e49e78cdd7645fe46037782 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 20 Nov 2025 14:32:35 +0000 Subject: [PATCH 61/98] Updated the docs for MaterialMacroInfo parameters. --- process/neutronics_data.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 46a412cf6f..f406e01d90 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -444,16 +444,22 @@ class MaterialMacroInfo: sigma_t: total macroscopic cross-section, 1D array of len = n. sigma_s: - Source matrix, 2D array of shape (n, n). Includes a sum of the - scattering matrix and n2n matrix. Scattering matrix is the - macroscopic scattering cross-section from group i to j, and the - n2n matrix is the macroscopic cross-section for production of - group j neutrons due to group i neutrons. It should be - mostly-upper-triangular, i.e. the lower triangle must have small values + Macroscopic scattering cross-section from group i to j, forming a 2D + array of shape (n, n). It should be mostly-upper-triangular, i.e. the + lower triangle (excluding the main diagonal) must have small values compared to the average macroscopic cross-section value of the matrix. - - e.g. [0,3] would be the cross-section for proudction of group 4 neutrons - due to reactions (scattering and n2n) caused by group 1 neutrons. + Neutrons fluxes are assumed to be isotropic before and after scattering. + + e.g. [0,3] would be the cross-section for group 4 neutrons scattered-in + from group 1 neutrons. + sigma_in: + In-source matrix: for now, it includes a sum of the matrix of (n,2n) + reactions and fission reactions. Same logic as the scattering matrix, + i.e. probability of group j neutrons produced (presumed to be + isotropic) per unit flux of group i neutrons. + + e.g. [0,3] would be the cross-section for the proudction of group 4 + neutrons due to n,2n and fission reactions caused by group 1 neutrons. group_structure: energy bin edges, 1D array of len = n+1, in eV. avg_atomic_mass: From e38dc0e42dfd501bf3aad5a0fc6af3b927ccdebb Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 20 Nov 2025 15:48:48 +0000 Subject: [PATCH 62/98] Converted from cgs to metric --- process/neutronics.py | 303 ++++++++++++++++++------------------- process/neutronics_data.py | 15 +- 2 files changed, 151 insertions(+), 167 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index d4956ae39b..6229e80fcd 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -67,9 +67,9 @@ def __set_name__(self, owner, name): def get_diffusion_coefficient_and_length( avg_atomic_mass: float, - total_xs_cm: float, - scattering_xs_cm: float, - in_source_xs_cm: float, + total_xs: float, + scattering_xs: float, + in_source_xs: float, ) -> tuple[float, float]: r""" Calculate the diffusion coefficient for a given scattering and total macro-scopic @@ -77,16 +77,16 @@ def get_diffusion_coefficient_and_length( Parameters ---------- - total_xs_cm: + total_xs: macroscopic total cross-section `\sigma_{total}`, i.e. any reaction between nuclei and neutrons, that either changes the neutron's path or remove it from that energy group. - Unit: cm^-1 - scattering_xs_cm: + Unit: m^-1 + scattering_xs: macroscopic total cross-section `\sigma_{scatter}`, i.e. number of reactions per unit distance travelled by the neutron that leads to it being scattered (without getting absorbed). - Unit: cm^-1 + Unit: m^-1 avg_atomic_mass: Average atomic mass in [amu]. This can be approximated by the atomic number 'A' of the medium that the neutron passes through. The effect of the more-anisotropic @@ -98,18 +98,16 @@ def get_diffusion_coefficient_and_length( ------- diffusion_coef: The diffusion coefficient as given by Reactor Analysis, Duderstadt and Hamilton. - unit: [cm] + unit: [m] diffusion_len_2: The square of the characteristic diffusion length as given by Reactor Analysis, Duderstadt and Hamilton. - unit: [cm] + unit: [m^2] """ - transport_xs = total_xs_cm - 2 / (3 * avg_atomic_mass) * scattering_xs_cm + transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs diffusion_coef = 1 / 3 / transport_xs - diffusion_len_2 = diffusion_coef / ( - total_xs_cm - scattering_xs_cm - in_source_xs_cm - ) + diffusion_len_2 = diffusion_coef / (total_xs - scattering_xs - in_source_xs) return diffusion_coef, diffusion_len_2 @@ -235,11 +233,11 @@ def __init__( ---------- flux: Nuetron flux directly emitted by the plasma, incident on the first wall. - unit: cm^-2 s^-1 + unit: m^-2 s^-1 x_fw: - thickness of the first wall [m]. It will be converted and stored in [cm]. + thickness of the first wall [m]. x_bz: - thickness of the blanket + first-wall [m]. It will be converted and stored in [cm]. + thickness of the blanket + first-wall [m]. fw_mat: first wall material information bz_mat: @@ -247,10 +245,6 @@ def __init__( Attributes ---------- - x_fw_cm: - thickness of the first wall, converted from [m] into [cm]. - x_bz_cm: - thickness of the blanket + first-wall, converted from [m] into [cm]. fw_mat: first wall material information bz_mat: @@ -263,19 +257,19 @@ def __init__( integration_constants: Integration constants that determine the flux shape (and therefore reaction rates and neutron current) of each group. A set of four - constants, two for fw and two for bz; each with unit: [cm^-2 s^-1] + constants, two for fw and two for bz; each with unit: [m^-2 s^-1] l_fw_2: square of the characteristic diffusion length as given by Reactor Analysis, - Duderstadt and Hamilton, applied to the fw. unit: [cm] + Duderstadt and Hamilton, applied to the fw. unit: [m^2] l_bz_2: square of the characteristic diffusion length as given by Reactor Analysis, - Duderstadt and Hamilton, applied to the bz. unit: [cm] - d_fw_cm: - diffusion constants in the fw. unit: [cm] - d_bz_cm: - diffusion constants in the bz. unit: [cm] - extended_boundary_cm: - extended boundary (outside the bz) for each group, stored in cm. + Duderstadt and Hamilton, applied to the bz. unit: [m^2] + d_fw: + diffusion constants in the fw. unit: [m] + d_bz: + diffusion constants in the bz. unit: [m] + extended_boundary: + extended boundary (outside the bz) for each group. This value should be larger than x_bz for each of them. """ self.flux = flux # flux incident on the first wall. @@ -283,8 +277,7 @@ def __init__( raise ValueError( f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." ) - self.x_fw_cm = x_fw * 100 - self.x_bz_cm = x_bz * 100 + self.x_fw, self.x_bz = x_fw, x_bz self.fw_mat = fw_mat self.bz_mat = bz_mat self.n_groups = self.fw_mat.n_groups @@ -305,40 +298,40 @@ def __init__( # diffusion lengths squared self.l_fw_2 = AutoPopulatingDict(self.solve_group_n, "l_fw_2") self.l_bz_2 = AutoPopulatingDict(self.solve_group_n, "l_bz_2") - self.d_fw_cm = AutoPopulatingDict(self.solve_group_n, "d_fw_cm") - self.d_bz_cm = AutoPopulatingDict(self.solve_group_n, "d_bz_cm") - self.extended_boundary_cm = AutoPopulatingDict( - self.solve_group_n, "extended_boundary_cm" + self.d_fw = AutoPopulatingDict(self.solve_group_n, "d_fw") + self.d_bz = AutoPopulatingDict(self.solve_group_n, "d_bz") + self.extended_boundary = AutoPopulatingDict( + self.solve_group_n, "extended_boundary" ) def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. - Store the solved constants in self.extended_boundary_cm[0], self.l_fw_2[0], + Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], self.l_bz_2[0], and self.integration_constants[0]. - integration_constants have units of [cm^-2 s^-1]. + integration_constants have units of [m^-2 s^-1]. """ n = 0 if n in self.integration_constants: return # skip if it has already been solved. - self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( + self.d_fw[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.avg_atomic_mass, - self.fw_mat.sigma_t_cm[n], - self.fw_mat.sigma_s_cm[n, n], - self.fw_mat.sigma_in_cm[n, n], + self.fw_mat.sigma_t[n], + self.fw_mat.sigma_s[n, n], + self.fw_mat.sigma_in[n, n], ) - self.d_bz_cm[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( + self.d_bz[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( self.bz_mat.avg_atomic_mass, - self.bz_mat.sigma_t_cm[n], - self.bz_mat.sigma_s_cm[n, n], - self.bz_mat.sigma_in_cm[n, n], + self.bz_mat.sigma_t[n], + self.bz_mat.sigma_s[n, n], + self.bz_mat.sigma_in[n, n], ) l_fw = np.sqrt(abs(self.l_fw_2[n])) l_bz = np.sqrt(abs(self.l_bz_2[n])) - x_fw, x_bz = self.x_fw_cm, self.x_bz_cm - d_fw = self.d_fw_cm[n] - d_bz = self.d_bz_cm[n] - self.extended_boundary_cm[n] = x_bz + extrapolation_length(d_bz) + x_fw, x_bz = self.x_fw, self.x_bz + d_fw = self.d_fw[n] + d_bz = self.d_bz[n] + self.extended_boundary[n] = x_bz + extrapolation_length(d_bz) if self.l_fw_2[n] > 0: s_fw = np.sinh(x_fw / l_fw) c_fw = np.cosh(x_fw / l_fw) @@ -348,17 +341,17 @@ def solve_lowest_group(self) -> None: c_fw = np.cos(x_fw / l_fw) t_fw = np.tan(x_fw / l_fw) if self.l_bz_2[n] > 0: - c_bz = np.cosh(self.extended_boundary_cm[n] / l_bz) - s_bz = np.sinh(self.extended_boundary_cm[n] / l_bz) - c_bz_mod = np.cosh((self.extended_boundary_cm[n] - x_fw) / l_bz) - s_bz_mod = np.sinh((self.extended_boundary_cm[n] - x_fw) / l_bz) - t_bz_mod = np.tanh((self.extended_boundary_cm[n] - x_fw) / l_bz) + c_bz = np.cosh(self.extended_boundary[n] / l_bz) + s_bz = np.sinh(self.extended_boundary[n] / l_bz) + c_bz_mod = np.cosh((self.extended_boundary[n] - x_fw) / l_bz) + s_bz_mod = np.sinh((self.extended_boundary[n] - x_fw) / l_bz) + t_bz_mod = np.tanh((self.extended_boundary[n] - x_fw) / l_bz) else: - c_bz = np.cos(self.extended_boundary_cm[n] / l_bz) - s_bz = np.sin(self.extended_boundary_cm[n] / l_bz) - c_bz_mod = np.cos((self.extended_boundary_cm[n] - x_fw) / l_bz) - s_bz_mod = np.sin((self.extended_boundary_cm[n] - x_fw) / l_bz) - t_bz_mod = np.tan((self.extended_boundary_cm[n] - x_fw) / l_bz) + c_bz = np.cos(self.extended_boundary[n] / l_bz) + s_bz = np.sin(self.extended_boundary[n] / l_bz) + c_bz_mod = np.cos((self.extended_boundary[n] - x_fw) / l_bz) + s_bz_mod = np.sin((self.extended_boundary[n] - x_fw) / l_bz) + t_bz_mod = np.tan((self.extended_boundary[n] - x_fw) / l_bz) fw_c_factor = - self.flux * ( l_fw / d_fw @@ -387,7 +380,7 @@ def solve_lowest_group(self) -> None: def solve_group_n(self, n: int) -> None: """ Solve the n-th group of neutron's diffusion equation, where n<=n_groups-1. - Store the solved constants in self.extended_boundary_cm[n-1], self.l_fw_2[n-1], + Store the solved constants in self.extended_boundary[n-1], self.l_fw_2[n-1], self.l_bz_2[n-1], and self.integration_constants[n-1]. Parameters @@ -417,27 +410,27 @@ def solve_group_n(self, n: int) -> None: # Parameter to be changed later, to allow solving non-down-scatter # only systems by iterating. first_iteration = True - self.d_fw_cm[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( + self.d_fw[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.avg_atomic_mass, - self.fw_mat.sigma_t_cm[n], - self.fw_mat.sigma_s_cm[n, n], - self.fw_mat.sigma_in_cm[n, n], + self.fw_mat.sigma_t[n], + self.fw_mat.sigma_s[n, n], + self.fw_mat.sigma_in[n, n], ) - self.d_bz_cm[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( + self.d_bz[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( self.bz_mat.avg_atomic_mass, - self.bz_mat.sigma_t_cm[n], - self.bz_mat.sigma_s_cm[n, n], - self.bz_mat.sigma_in_cm[n, n], + self.bz_mat.sigma_t[n], + self.bz_mat.sigma_s[n, n], + self.bz_mat.sigma_in[n, n], ) - self.extended_boundary_cm[n] = self.x_bz_cm + extrapolation_length( - self.d_bz_cm[n] + self.extended_boundary[n] = self.x_bz + extrapolation_length( + self.d_bz[n] ) # Setting up aliases for shorter code l_fw_2, l_bz_2 = self.l_fw_2[n], self.l_bz_2[n] - d_fw, d_bz = self.d_fw_cm[n], self.d_bz_cm[n] - src_fw = self.fw_mat.sigma_s_cm + self.fw_mat.sigma_in_cm - src_bz = self.bz_mat.sigma_s_cm + self.bz_mat.sigma_in_cm + d_fw, d_bz = self.d_fw[n], self.d_bz[n] + src_fw = self.fw_mat.sigma_s + self.fw_mat.sigma_in + src_bz = self.bz_mat.sigma_s + self.bz_mat.sigma_in self.integration_constants[n] = IntegrationConstants([], [], [], []) for g in range(n): @@ -486,21 +479,21 @@ def _set_constants(input_vector: Iterable[float]): _ic_n.bz_s[n] = input_vector[3] def _evaluate_fit(): - flux_continuity = self.groupwise_neutron_flux_fw(n, self.x_fw_cm/100) - self.groupwise_neutron_flux_bz(n, self.x_fw_cm/100) - flux_at_boundary = self.groupwise_neutron_flux_bz(n, self.extended_boundary_cm[n]) - current_continuity = self.groupwise_neutron_current_fw(n, self.x_fw_cm/100) - self.groupwise_neutron_current_bz(n, self.x_fw_cm/100) + flux_continuity = self.groupwise_neutron_flux_fw(n, self.x_fw) - self.groupwise_neutron_flux_bz(n, self.x_fw) + flux_at_boundary = self.groupwise_neutron_flux_bz(n, self.extended_boundary[n]) + current_continuity = self.groupwise_neutron_current_fw(n, self.x_fw) - self.groupwise_neutron_current_bz(n, self.x_fw) influx_fw, influx_bz = 0.0, 0.0 for g in range(self.n_groups): if g>n and not first_iteration: if not self.fw_mat.downscatter_only: - influx_fw += (self.fw_mat.sigma_s_cm[g, n] + self.fw_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_fw(g) + influx_fw += (self.fw_mat.sigma_s[g, n] + self.fw_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_fw(g) if not self.bz_mat.downscatter_only: - influx_bz += (self.bz_mat.sigma_s_cm[g, n] + self.bz_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_bz(g) + influx_bz += (self.bz_mat.sigma_s[g, n] + self.bz_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_bz(g) elif g<=n: - influx_fw += (self.fw_mat.sigma_s_cm[g, n] + self.fw_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_fw(g) - influx_bz += (self.bz_mat.sigma_s_cm[g, n] + self.bz_mat.sigma_in_cm[g, n]) * self.groupwise_integrated_flux_bz(g) - removal_fw = self.fw_mat.sigma_t_cm[n] * self.groupwise_integrated_flux_fw(n) - removal_bz = self.bz_mat.szsigma_t_cm[n] * self.groupwise_integrated_flux_bz(n) + influx_fw += (self.fw_mat.sigma_s[g, n] + self.fw_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_fw(g) + influx_bz += (self.bz_mat.sigma_s[g, n] + self.bz_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_bz(g) + removal_fw = self.fw_mat.sigma_t[n] * self.groupwise_integrated_flux_fw(n) + removal_bz = self.bz_mat.sigma_t[n] * self.groupwise_integrated_flux_bz(n) # conservation_fw = influx_fw - removal_fw - current_fw2bz # conservation_bz = current_fw2bz + influx_bz - removal_bz - escaped_bz total_neutron_conservation = ( @@ -535,7 +528,7 @@ def groupwise_neutron_flux_fw( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron flux[cm^-2 s^-1] of the n-th group at the first wall, at location x [m]. + Neutron flux[m^-2 s^-1] of the n-th group at the first wall, at location x [m]. Parameters ---------- @@ -554,8 +547,6 @@ def groupwise_neutron_flux_fw( flux: Neutron flux at x meter from the first wall. """ - x_cm = x * 100 - trig_funcs = [] for g in range(n + 1): if self.l_fw_2[g]>0: @@ -564,15 +555,15 @@ def groupwise_neutron_flux_fw( else: c, s = np.cos, np.sin l_fw = np.sqrt(-self.l_fw_2[g]) - trig_funcs.append(self.integration_constants[n].fw_c[g] * c(abs(x_cm) / l_fw)) - trig_funcs.append(self.integration_constants[n].fw_s[g] * s(abs(x_cm) / l_fw)) + trig_funcs.append(self.integration_constants[n].fw_c[g] * c(abs(x) / l_fw)) + trig_funcs.append(self.integration_constants[n].fw_s[g] * s(abs(x) / l_fw)) return np.sum(trig_funcs, axis=0) @summarize_values def groupwise_neutron_flux_bz( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: - """Neutron flux[cm^-2 s^-1] of the n-th groupat the blanket, at location x [m]. + """Neutron flux[m^-2 s^-1] of the n-th groupat the blanket, at location x [m]. Parameters ---------- @@ -591,8 +582,6 @@ def groupwise_neutron_flux_bz( flux: Neutron flux at x meter from the first wall. """ - x_cm = x * 100 - trig_funcs = [] for g in range(n + 1): if self.l_bz_2[g]>0: @@ -601,8 +590,8 @@ def groupwise_neutron_flux_bz( else: c, s = np.cos, np.sin l_bz = np.sqrt(-self.l_bz_2[g]) - trig_funcs.append(self.integration_constants[n].bz_c[g] * c(abs(x_cm) / l_bz)) - trig_funcs.append(self.integration_constants[n].bz_s[g] * s(abs(x_cm) / l_bz)) + trig_funcs.append(self.integration_constants[n].bz_c[g] * c(abs(x) / l_bz)) + trig_funcs.append(self.integration_constants[n].bz_s[g] * s(abs(x) / l_bz)) return np.sum(trig_funcs, axis=0) @summarize_values @@ -610,8 +599,8 @@ def groupwise_neutron_flux_at( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron flux [cm^-2 s^-1] anywhere within the valid range of x, - i.e. [-self.extended_boundary_cm[n], self.extended_boundary_cm[n]]. + Neutron flux [m^-2 s^-1] anywhere within the valid range of x, + i.e. [-self.extended_boundary[n], self.extended_boundary[n]]. Parameters ---------- @@ -630,15 +619,15 @@ def groupwise_neutron_flux_at( if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] x = np.asarray(x) - in_fw = abs(x * 100) <= self.x_fw_cm + in_fw = abs(x) <= self.x_fw in_bz = np.logical_and( - self.x_fw_cm < abs(x * 100), - abs(x * 100) <= self.extended_boundary_cm[n], + self.x_fw < abs(x), + abs(x) <= self.extended_boundary[n], ) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated " - f"up to {self.extended_boundary_cm[n]} cm, which {x * 100} cm violates!" + f"up to {self.extended_boundary[n]} m, which {x} m violates!" ) out_flux = np.zeros_like(x) @@ -650,8 +639,8 @@ def groupwise_neutron_flux_at( @summarize_values def groupwise_integrated_flux_fw(self, n: int) -> float: """ - Calculate the integrated flux[cm s^-1], which can be mulitplied to any - macroscopic cross-section [cm^-1] to get the reaction rate [s^-1] in + Calculate the integrated flux[m^-1 s^-1], which can be mulitplied to any + macroscopic cross-section [m^-1] to get the reaction rate [s^-1] in the first wall. Parameters @@ -665,18 +654,18 @@ def groupwise_integrated_flux_fw(self, n: int) -> float: if self.l_fw_2[g]>0: l_fw = np.sqrt(self.l_fw_2[g]) integrals.append( - l_fw * self.integration_constants[n].fw_c[g] * np.sinh(self.x_fw_cm / l_fw) + l_fw * self.integration_constants[n].fw_c[g] * np.sinh(self.x_fw / l_fw) ) integrals.append( - l_fw * self.integration_constants[n].fw_s[g] * (np.cosh(self.x_fw_cm / l_fw) - 1) + l_fw * self.integration_constants[n].fw_s[g] * (np.cosh(self.x_fw / l_fw) - 1) ) else: l_fw = np.sqrt(-self.l_fw_2[g]) integrals.append( - l_fw * self.integration_constants[n].fw_c[g] * np.sin(self.x_fw_cm / l_fw) + l_fw * self.integration_constants[n].fw_c[g] * np.sin(self.x_fw / l_fw) ) integrals.append( - l_fw * self.integration_constants[n].fw_s[g] * (1 - np.cos(self.x_fw_cm / l_fw)) + l_fw * self.integration_constants[n].fw_s[g] * (1 - np.cos(self.x_fw / l_fw)) ) return np.sum(integrals, axis=0) @@ -684,8 +673,8 @@ def groupwise_integrated_flux_fw(self, n: int) -> float: @summarize_values def groupwise_integrated_flux_bz(self, n: int) -> float: """ - Calculate the integrated flux[cm s^-1], which can be mulitplied to any - macroscopic cross-section [cm^-1] to get the reaction rate [s^-1] in + Calculate the integrated flux[m^-1 s^-1], which can be mulitplied to any + macroscopic cross-section [m^-1] to get the reaction rate [s^-1] in the blanket. Parameters @@ -700,79 +689,77 @@ def groupwise_integrated_flux_bz(self, n: int) -> float: l_bz = np.sqrt(self.l_bz_2[g]) integrals.append( l_bz * self.integration_constants[n].bz_c[g] * - (np.sinh(self.x_bz_cm / l_bz) - np.sinh(self.x_fw_cm / l_bz)) + (np.sinh(self.x_bz / l_bz) - np.sinh(self.x_fw / l_bz)) ) integrals.append( l_bz * self.integration_constants[n].bz_s[g] * - (np.cosh(self.x_bz_cm / l_bz) - np.cosh(self.x_fw_cm / l_bz)) + (np.cosh(self.x_bz / l_bz) - np.cosh(self.x_fw / l_bz)) ) else: l_bz = np.sqrt(-self.l_bz_2[g]) integrals.append( l_bz * self.integration_constants[n].bz_c[g] * - (np.sin(self.x_bz_cm / l_bz) - np.sin(self.x_fw_cm / l_bz)) + (np.sin(self.x_bz / l_bz) - np.sin(self.x_fw / l_bz)) ) integrals.append( -l_bz * self.integration_constants[n].bz_s[g] * - (np.cos(self.x_bz_cm / l_bz) - np.cos(self.x_fw_cm / l_bz)) + (np.cos(self.x_bz / l_bz) - np.cos(self.x_fw / l_bz)) ) return np.sum(integrals, axis=0) @summarize_values def groupwise_neutron_current_fw(self, n: int, x: float | npt.NDArray) -> float: """Get the neutron current (in the outward direction) in the fw""" - x_cm = x * 100 differentials = [] for g in range(n + 1): if self.l_fw_2[g]>0: l_fw = np.sqrt(self.l_fw_2[g]) differentials.append( - self.integration_constants[n].fw_c[g] / l_fw * np.sinh(x_cm / l_fw) + self.integration_constants[n].fw_c[g] / l_fw * np.sinh(x / l_fw) ) differentials.append( - self.integration_constants[n].fw_s[g] / l_fw * np.cosh(x_cm / l_fw) + self.integration_constants[n].fw_s[g] / l_fw * np.cosh(x / l_fw) ) else: l_fw = np.sqrt(-self.l_fw_2[g]) differentials.append( - - self.integration_constants[n].fw_c[g] / l_fw * np.sin(x_cm / l_fw) + - self.integration_constants[n].fw_c[g] / l_fw * np.sin(x / l_fw) ) differentials.append( - self.integration_constants[n].fw_s[g] / l_fw * np.cos(x_cm / l_fw) + self.integration_constants[n].fw_s[g] / l_fw * np.cos(x / l_fw) ) - return -self.d_fw_cm[n] * np.sum(differentials, axis=0) + return -self.d_fw[n] * np.sum(differentials, axis=0) @summarize_values def groupwise_neutron_current_bz(self, n: int, x: float | npt.NDArray) -> float: """Get the neutron current (in the outward direction) in the bz.""" - x_cm = x * 100 differentials = [] for g in range(n + 1): if self.l_bz_2[g]>0: l_bz = np.sqrt(self.l_bz_2[g]) differentials.append( - self.integration_constants[n].bz_c[g] / l_bz * np.sinh(x_cm / l_bz) + self.integration_constants[n].bz_c[g] / l_bz * np.sinh(x / l_bz) ) differentials.append( - self.integration_constants[n].bz_s[g] / l_bz * np.cosh(x_cm / l_bz) + self.integration_constants[n].bz_s[g] / l_bz * np.cosh(x / l_bz) ) else: l_bz = np.sqrt(-self.l_bz_2[g]) differentials.append( - - self.integration_constants[n].bz_c[g] / l_bz * np.sin(x_cm / l_bz) + - self.integration_constants[n].bz_c[g] / l_bz * np.sin(x / l_bz) ) differentials.append( - self.integration_constants[n].bz_s[g] / l_bz * np.cos(x_cm / l_bz) + self.integration_constants[n].bz_s[g] / l_bz * np.cos(x / l_bz) ) - return -self.d_bz_cm[n] * np.sum(differentials, axis=0) + return -self.d_bz[n] * np.sum(differentials, axis=0) @summarize_values def groupwise_neutron_current_at( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron current [cm^-2 s^-1] anywhere within the valid range of x, - i.e. from -self.x_bz_cm to self.x_bz_cm. + Neutron current [m^-2 s^-1] anywhere within the valid range of x, + i.e. from -self.x_bz to self.x_bz. Parameters ---------- @@ -791,15 +778,15 @@ def groupwise_neutron_current_at( if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] x = np.asarray(x) - in_fw = abs(x * 100) <= self.x_fw_cm + in_fw = abs(x) <= self.x_fw in_bz = np.logical_and( - self.x_fw_cm < abs(x * 100), - abs(x * 100) <= self.x_bz_cm, + self.x_fw < abs(x), + abs(x) <= self.x_bz, ) if (~np.logical_or(in_fw, in_bz)).any(): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated " - f"up to {self.x_bz_cm} cm, which {x * 100} cm violates!" + f"up to {self.x_bz} m, which {x} m violates!" ) out_current = np.zeros_like(x) @@ -820,9 +807,9 @@ def groupwise_neutron_current_fw2bz(self, n: int) -> float: Returns ------- : - current in cm^-2 + current in m^-2 """ - return self.groupwise_neutron_current_bz(n, self.x_fw_cm/100) + return self.groupwise_neutron_current_bz(n, self.x_fw) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -837,9 +824,9 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: Returns ------- : - current in cm^-2 + current in m^-2 """ - return self.groupwise_neutron_current_bz(n, self.x_bz_cm/100) + return self.groupwise_neutron_current_bz(n, self.x_bz) def plot( self, @@ -867,10 +854,10 @@ def plot( ax = ax or plt.axes() x_bz_left, x_fw, x_bz_right = _generate_x_range( - min(self.extended_boundary_cm.values()), + min(self.extended_boundary.values()), n_points, symmetric, - self.x_fw_cm, + self.x_fw, ) ax.plot( x_bz_left, @@ -896,10 +883,10 @@ def plot( if plot_groups: for n in range(self.n_groups): x_bz_left, x_fw, x_bz_right = _generate_x_range( - self.extended_boundary_cm[n], + self.extended_boundary[n], n_points, symmetric, - self.x_fw_cm, + self.x_fw, ) ax.plot( x_bz_left, @@ -924,36 +911,36 @@ def plot( ax.legend() ax.set_title("Neutron flux profile") ax.set_xlabel("Distance from the plasma-fw interface [m]") - ax.set_ylabel("Neutron flux [cm^-2 s^-1]") + ax.set_ylabel("Neutron flux [m^-2 s^-1]") return ax def _generate_x_range( - x_max_cm: float, + x_max: float, approx_n_points: int, symmetric: bool, - fw_bz_split_point_cm: float | None = None, + fw_bz_split_point: float | None = None, ): """Helper function for finding the range of x-values to be plotted. Parameters ---------- - x_max_cm: + x_max: absolute value of the maximum x that we want to plot. - This is typically obtained by min(extended_boundary_cm), or - extended_boundary_cm[n] [cm] + This is typically obtained by min(extended_boundary), or + extended_boundary[n] [m] symmetric: Whether we want to plot the negative side of the x-axis as well, forming a symmetric plot. approx_n_points: number of points to be plotted. - fw_bz_split_point_cm: + fw_bz_split_point: FW and BZ region splits at this distance. If provided, we generate separate - x ranges for the FW and BZ. [cm] + x ranges for the FW and BZ. [m] Returns ------- - if (fw_bz_split_point_cm, symmetric) = (float value, True): + if (fw_bz_split_point, symmetric) = (float value, True): x_range_bz_left: The array of x-values to be used for plotting the left (negative) side of bz. [m] @@ -963,39 +950,37 @@ def _generate_x_range( x_range_bz_right: The array of x-values to be used for plotting the right (positive) side of bz. [m] - elif (fw_bz_split_point_cm, symmetric) = (float value, False): + elif (fw_bz_split_point, symmetric) = (float value, False): x_range_fw: The array of x-values to be used for plotting the right (positive) side of fw [m] x_range_bz: The array of x-values to be used for plotting the right (positive) side of bz [m] - elif (fw_bz_split_point_cm, symmetric) = (None, True): + elif (fw_bz_split_point, symmetric) = (None, True): x_range: The array of x-values to be used for plotting both sides of the neutron flux. [m] - else (fw_bz_split_point_cm, symmetric) = (None, False): + else (fw_bz_split_point, symmetric) = (None, False): x_range: The array of x-values to be used for plotting the right (positive) side neutron flux. [m] """ - x_max = x_max_cm / 100 - if fw_bz_split_point_cm is not None: - x_range = np.linspace(0, x_max_cm, approx_n_points) - n_points_fw = (x_range < fw_bz_split_point_cm).sum() + 1 - n_points_bz = (x_range >= fw_bz_split_point_cm).sum() + 1 + if fw_bz_split_point is not None: + x_range = np.linspace(0, x_max, approx_n_points) + n_points_fw = (x_range < fw_bz_split_point).sum() + 1 + n_points_bz = (x_range >= fw_bz_split_point).sum() + 1 - split_point = fw_bz_split_point_cm / 100 if symmetric: return ( - np.linspace(-x_max, -split_point, n_points_bz), - np.linspace(-split_point, split_point, n_points_fw * 2 - 1), - np.linspace(split_point, x_max, n_points_bz), + np.linspace(-x_max, -fw_bz_split_point, n_points_bz), + np.linspace(-fw_bz_split_point, fw_bz_split_point, n_points_fw * 2 - 1), + np.linspace(fw_bz_split_point, x_max, n_points_bz), ) return ( - np.linspace(0, split_point, n_points_fw), - np.linspace(split_point, x_max, n_points_bz), + np.linspace(0, fw_bz_split_point, n_points_fw), + np.linspace(fw_bz_split_point, x_max, n_points_bz), ) if symmetric: diff --git a/process/neutronics_data.py b/process/neutronics_data.py index f406e01d90..dd9e9d99a4 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -9,7 +9,8 @@ from process.exceptions import ProcessValidationError -BARNS_CM2 = 1e-24 +BARNS_TO_CM2 = 1e-24 +BARNS_TO_M2 = 1e-28 N_A = Avogadro N2N_Q_VALUE = ... _ATOMIC_MASS = {} @@ -72,12 +73,12 @@ def calculate_average_macro_xs( Given in the format {'species': float(microscopic cross-section)}. Possible to have some missing values here. density: - Density of the medium, given in [g/cm^3] + Density of the medium, given in [kg/m^3] Returns ------- : - macroscopic cross-section of the material. + macroscopic cross-section of the material. [m] Notes ----- @@ -105,7 +106,8 @@ def calculate_average_macro_xs( avg_mass_amu = sum(weighted_atomic_mass) # N_A/A * rho * sigma - return N_A / avg_mass_amu * density * (avg_sigma * BARNS_CM2) + + return N_A / (avg_mass_amu/1000) * density * (avg_sigma * BARNS_TO_M2) def discretize_xs( @@ -518,9 +520,6 @@ def __post_init__(self): "Elastic up-scattering seems unlikely in this model! " "Check if the group structure is chosen correctly?", ) - self.sigma_t_cm = self.sigma_t / 100 - self.sigma_s_cm = self.sigma_s / 100 - self.sigma_in_cm = self.sigma_in / 100 @property def n_groups(self): @@ -577,7 +576,7 @@ def get_material_nuclear_data( cross-section :math:`\\Sigma_{s}` is the i-th element on the main diagonal of the macroscopic scattering cross-section matrix. """ - density = material_density_data_bank[material] + density = material_density_data_bank[material] # [kg/m^3] composition = material_composition_data_bank[material] avg_atomic_mass = get_avg_atomic_mass(composition) n_groups = len(group_structure) - 1 From d5081e37395ff4a7935fac4af160565f520152bf Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 20 Nov 2025 15:51:03 +0000 Subject: [PATCH 63/98] Updated regression test to use cgs. --- tests/regression/test_neutronics.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 0224b825cf..90d20d4d1a 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -32,10 +32,10 @@ def test_one_group(): ) const = neutron_profile.integration_constants[0] # alias to fit line width - assert np.isclose(const.fw_c, 80.5346770788), "c5" - assert np.isclose(const.fw_s, -76.5562120985), "c6" - assert np.isclose(const.bz_c, 60.6871656017), "c7" - assert np.isclose(const.bz_s, -60.7123696772), "c8" + assert np.isclose(const.fw_c[0], 80.5346770788), "c5" + assert np.isclose(const.fw_s[0], -76.5562120985), "c6" + assert np.isclose(const.bz_c[0], 60.6871656017), "c7" + assert np.isclose(const.bz_s[0], -60.7123696772), "c8" assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_bz(x_fw), 48.72444) @@ -48,10 +48,10 @@ def test_one_group(): bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] assert np.isclose(neutron_profile.flux, neutron_profile.neutron_current_escaped() - + fw_removal/100 * neutron_profile.integrated_flux_fw() - + bz_removal/100 * neutron_profile.integrated_flux_bz() + + fw_removal * neutron_profile.integrated_flux_fw() + + bz_removal * neutron_profile.integrated_flux_bz() ), "Conservation of neutrons" - + def test_one_group_with_fission(): """ Regression test against Desmos snapshot with fission involved: @@ -81,7 +81,7 @@ def test_one_group_with_fission(): neutron_profile = NeutronFluxProfile( incoming_flux, x_fw, x_bz, fw_material, bz_material ) - assert np.isclose(neutron_profile.l_bz_2[0], -58.2869567709**2) + assert np.isclose(neutron_profile.l_bz_2[0], -(58.2869567709/100)**2) assert np.isclose(neutron_profile.neutron_flux_at(-4.79675/100), 159.9434), "Minimum flux in FW" assert np.isclose(neutron_profile.neutron_flux_at(4.79675/100), 159.9434), "Minimum flux in FW" assert np.isclose(neutron_profile.neutron_flux_at(18.96382/100), 164.81245), "Maximum flux in BZ" @@ -93,8 +93,8 @@ def test_one_group_with_fission(): bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] assert np.isclose(neutron_profile.flux, neutron_profile.neutron_current_escaped() - + fw_removal/100 * neutron_profile.integrated_flux_fw() - + bz_removal/100 * neutron_profile.integrated_flux_bz() + + fw_removal * neutron_profile.integrated_flux_fw() + + bz_removal * neutron_profile.integrated_flux_bz() ), "Conservation of neutrons" def test_two_groups(): From 0748180b40c5287ee5cbb3a487d4f0b67f5aadc0 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 20 Nov 2025 15:56:53 +0000 Subject: [PATCH 64/98] Updated unit-test for checking the number of methods present. --- tests/unit/test_neutronics.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index b99d434e9a..48f4c9ff83 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -75,10 +75,10 @@ def test_has_boundary_current(): def test_has_reactions(): """Test that the groupwise decorator has worked on the reactions methods.""" - assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_fw") - assert hasattr(NeutronFluxProfile, "reaction_rate_fw") - assert hasattr(NeutronFluxProfile, "groupwise_reaction_rate_bz") - assert hasattr(NeutronFluxProfile, "reaction_rate_bz") + assert hasattr(NeutronFluxProfile, "groupwise_integrated_flux_fw") + assert hasattr(NeutronFluxProfile, "integrated_flux_fw") + assert hasattr(NeutronFluxProfile, "groupwise_integrated_flux_bz") + assert hasattr(NeutronFluxProfile, "integrated_flux_bz") def test_three_group(): @@ -89,7 +89,7 @@ def test_three_group(): # 2. same L_1 and L_3 shoudl yield integration_constants[2].fw_c[0] and # integration_constants[2].fw_s[0] = 0.0 # self.l_fw_2 == self.l_fw_2[n] case. - # + # def test_two_group(): From 2ae85f848c3876fd471edfaf1a37f25dbc0d1b93 Mon Sep 17 00:00:00 2001 From: ocean Date: Thu, 20 Nov 2025 15:57:08 +0000 Subject: [PATCH 65/98] Pre-commit ruff fix --- process/neutronics.py | 220 +++++++++++++++++++--------- process/neutronics_data.py | 2 +- tests/regression/test_neutronics.py | 66 ++++++--- 3 files changed, 195 insertions(+), 93 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 6229e80fcd..4b606fa851 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -107,7 +107,9 @@ def get_diffusion_coefficient_and_length( transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs diffusion_coef = 1 / 3 / transport_xs - diffusion_len_2 = diffusion_coef / (total_xs - scattering_xs - in_source_xs) + diffusion_len_2 = diffusion_coef / ( + total_xs - scattering_xs - in_source_xs + ) return diffusion_coef, diffusion_len_2 @@ -353,15 +355,13 @@ def solve_lowest_group(self) -> None: s_bz_mod = np.sin((self.extended_boundary[n] - x_fw) / l_bz) t_bz_mod = np.tan((self.extended_boundary[n] - x_fw) / l_bz) - fw_c_factor = - self.flux * ( - l_fw / d_fw - - np.exp(x_fw / l_fw) * ( - (l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod - )/( - c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz) - ) + fw_c_factor = -self.flux * ( + l_fw / d_fw + - np.exp(x_fw / l_fw) + * ((l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod) + / (c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz)) ) - fw_s_factor = - self.flux * l_fw / d_fw + fw_s_factor = -self.flux * l_fw / d_fw bz_common_factor = ( self.flux @@ -406,10 +406,9 @@ def solve_group_n(self, n: int) -> None: ) if n in self.integration_constants: return None # skip if it has already been solved. - else: - # Parameter to be changed later, to allow solving non-down-scatter - # only systems by iterating. - first_iteration = True + # Parameter to be changed later, to allow solving non-down-scatter + # only systems by iterating. + first_iteration = True self.d_fw[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.avg_atomic_mass, self.fw_mat.sigma_t[n], @@ -447,19 +446,31 @@ def solve_group_n(self, n: int) -> None: else: scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz self.integration_constants[n].fw_c.append( - sum(src_fw[i, n] * self.integration_constants[i].fw_c[g] for i in range(g, n)) + sum( + src_fw[i, n] * self.integration_constants[i].fw_c[g] + for i in range(g, n) + ) * scale_factor_fw ) self.integration_constants[n].fw_s.append( - sum(src_fw[i, n] * self.integration_constants[i].fw_s[g] for i in range(g, n)) + sum( + src_fw[i, n] * self.integration_constants[i].fw_s[g] + for i in range(g, n) + ) * scale_factor_fw ) self.integration_constants[n].bz_c.append( - sum(src_bz[i, n] * self.integration_constants[i].bz_c[g] for i in range(g, n)) + sum( + src_bz[i, n] * self.integration_constants[i].bz_c[g] + for i in range(g, n) + ) * scale_factor_bz ) self.integration_constants[n].bz_s.append( - sum(src_bz[i, n] * self.integration_constants[i].bz_s[g] for i in range(g, n)) + sum( + src_bz[i, n] * self.integration_constants[i].bz_s[g] + for i in range(g, n) + ) * scale_factor_bz ) @@ -473,27 +484,47 @@ def solve_group_n(self, n: int) -> None: self.integration_constants[n].bz_s.append(bz_s_factor_guess) def _set_constants(input_vector: Iterable[float]): - _ic_n.fw_c[n] = input_vector[0] - _ic_n.fw_s[n] = input_vector[1] - _ic_n.bz_c[n] = input_vector[2] - _ic_n.bz_s[n] = input_vector[3] + self.integration_constants[n].fw_c[n] = input_vector[0] + self.integration_constants[n].fw_s[n] = input_vector[1] + self.integration_constants[n].bz_c[n] = input_vector[2] + self.integration_constants[n].bz_s[n] = input_vector[3] def _evaluate_fit(): - flux_continuity = self.groupwise_neutron_flux_fw(n, self.x_fw) - self.groupwise_neutron_flux_bz(n, self.x_fw) - flux_at_boundary = self.groupwise_neutron_flux_bz(n, self.extended_boundary[n]) - current_continuity = self.groupwise_neutron_current_fw(n, self.x_fw) - self.groupwise_neutron_current_bz(n, self.x_fw) + flux_continuity = self.groupwise_neutron_flux_fw( + n, self.x_fw + ) - self.groupwise_neutron_flux_bz(n, self.x_fw) + flux_at_boundary = self.groupwise_neutron_flux_bz( + n, self.extended_boundary[n] + ) + current_continuity = self.groupwise_neutron_current_fw( + n, self.x_fw + ) - self.groupwise_neutron_current_bz(n, self.x_fw) influx_fw, influx_bz = 0.0, 0.0 for g in range(self.n_groups): - if g>n and not first_iteration: + if g > n and not first_iteration: if not self.fw_mat.downscatter_only: - influx_fw += (self.fw_mat.sigma_s[g, n] + self.fw_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_fw(g) + influx_fw += ( + self.fw_mat.sigma_s[g, n] + + self.fw_mat.sigma_in[g, n] + ) * self.groupwise_integrated_flux_fw(g) if not self.bz_mat.downscatter_only: - influx_bz += (self.bz_mat.sigma_s[g, n] + self.bz_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_bz(g) - elif g<=n: - influx_fw += (self.fw_mat.sigma_s[g, n] + self.fw_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_fw(g) - influx_bz += (self.bz_mat.sigma_s[g, n] + self.bz_mat.sigma_in[g, n]) * self.groupwise_integrated_flux_bz(g) - removal_fw = self.fw_mat.sigma_t[n] * self.groupwise_integrated_flux_fw(n) - removal_bz = self.bz_mat.sigma_t[n] * self.groupwise_integrated_flux_bz(n) + influx_bz += ( + self.bz_mat.sigma_s[g, n] + + self.bz_mat.sigma_in[g, n] + ) * self.groupwise_integrated_flux_bz(g) + elif g <= n: + influx_fw += ( + self.fw_mat.sigma_s[g, n] + self.fw_mat.sigma_in[g, n] + ) * self.groupwise_integrated_flux_fw(g) + influx_bz += ( + self.bz_mat.sigma_s[g, n] + self.bz_mat.sigma_in[g, n] + ) * self.groupwise_integrated_flux_bz(g) + removal_fw = self.fw_mat.sigma_t[ + n + ] * self.groupwise_integrated_flux_fw(n) + removal_bz = self.bz_mat.sigma_t[ + n + ] * self.groupwise_integrated_flux_bz(n) # conservation_fw = influx_fw - removal_fw - current_fw2bz # conservation_bz = current_fw2bz + influx_bz - removal_bz - escaped_bz total_neutron_conservation = ( @@ -501,7 +532,7 @@ def _evaluate_fit(): + influx_bz - removal_fw - removal_bz - - self.groupwise_neutron_current_escaped(_ic_n, self, n) + - self.groupwise_neutron_current_escaped(n) ) return np.array([ flux_continuity, @@ -514,12 +545,15 @@ def objective(four_integration_constants_vector): _set_constants(four_integration_constants_vector) return _evaluate_fit() - results = optimize.root(objective, x0=[ - fw_c_factor_guess, - fw_s_factor_guess, - bz_c_factor_guess, - bz_s_factor_guess, - ]) + results = optimize.root( + objective, + x0=[ + fw_c_factor_guess, + fw_s_factor_guess, + bz_c_factor_guess, + bz_s_factor_guess, + ], + ) _set_constants(results.res) return None @@ -549,14 +583,18 @@ def groupwise_neutron_flux_fw( """ trig_funcs = [] for g in range(n + 1): - if self.l_fw_2[g]>0: + if self.l_fw_2[g] > 0: c, s = np.cosh, np.sinh l_fw = np.sqrt(self.l_fw_2[g]) else: c, s = np.cos, np.sin l_fw = np.sqrt(-self.l_fw_2[g]) - trig_funcs.append(self.integration_constants[n].fw_c[g] * c(abs(x) / l_fw)) - trig_funcs.append(self.integration_constants[n].fw_s[g] * s(abs(x) / l_fw)) + trig_funcs.append( + self.integration_constants[n].fw_c[g] * c(abs(x) / l_fw) + ) + trig_funcs.append( + self.integration_constants[n].fw_s[g] * s(abs(x) / l_fw) + ) return np.sum(trig_funcs, axis=0) @summarize_values @@ -584,14 +622,18 @@ def groupwise_neutron_flux_bz( """ trig_funcs = [] for g in range(n + 1): - if self.l_bz_2[g]>0: + if self.l_bz_2[g] > 0: c, s = np.cosh, np.sinh l_bz = np.sqrt(self.l_bz_2[g]) else: c, s = np.cos, np.sin l_bz = np.sqrt(-self.l_bz_2[g]) - trig_funcs.append(self.integration_constants[n].bz_c[g] * c(abs(x) / l_bz)) - trig_funcs.append(self.integration_constants[n].bz_s[g] * s(abs(x) / l_bz)) + trig_funcs.append( + self.integration_constants[n].bz_c[g] * c(abs(x) / l_bz) + ) + trig_funcs.append( + self.integration_constants[n].bz_s[g] * s(abs(x) / l_bz) + ) return np.sum(trig_funcs, axis=0) @summarize_values @@ -651,21 +693,29 @@ def groupwise_integrated_flux_fw(self, n: int) -> float: """ integrals = [] for g in range(n + 1): - if self.l_fw_2[g]>0: + if self.l_fw_2[g] > 0: l_fw = np.sqrt(self.l_fw_2[g]) integrals.append( - l_fw * self.integration_constants[n].fw_c[g] * np.sinh(self.x_fw / l_fw) + l_fw + * self.integration_constants[n].fw_c[g] + * np.sinh(self.x_fw / l_fw) ) integrals.append( - l_fw * self.integration_constants[n].fw_s[g] * (np.cosh(self.x_fw / l_fw) - 1) + l_fw + * self.integration_constants[n].fw_s[g] + * (np.cosh(self.x_fw / l_fw) - 1) ) else: l_fw = np.sqrt(-self.l_fw_2[g]) integrals.append( - l_fw * self.integration_constants[n].fw_c[g] * np.sin(self.x_fw / l_fw) + l_fw + * self.integration_constants[n].fw_c[g] + * np.sin(self.x_fw / l_fw) ) integrals.append( - l_fw * self.integration_constants[n].fw_s[g] * (1 - np.cos(self.x_fw / l_fw)) + l_fw + * self.integration_constants[n].fw_s[g] + * (1 - np.cos(self.x_fw / l_fw)) ) return np.sum(integrals, axis=0) @@ -685,71 +735,95 @@ def groupwise_integrated_flux_bz(self, n: int) -> float: """ integrals = [] for g in range(n + 1): - if self.l_bz_2[g]>0: + if self.l_bz_2[g] > 0: l_bz = np.sqrt(self.l_bz_2[g]) integrals.append( - l_bz * self.integration_constants[n].bz_c[g] * - (np.sinh(self.x_bz / l_bz) - np.sinh(self.x_fw / l_bz)) + l_bz + * self.integration_constants[n].bz_c[g] + * (np.sinh(self.x_bz / l_bz) - np.sinh(self.x_fw / l_bz)) ) integrals.append( - l_bz * self.integration_constants[n].bz_s[g] * - (np.cosh(self.x_bz / l_bz) - np.cosh(self.x_fw / l_bz)) + l_bz + * self.integration_constants[n].bz_s[g] + * (np.cosh(self.x_bz / l_bz) - np.cosh(self.x_fw / l_bz)) ) else: l_bz = np.sqrt(-self.l_bz_2[g]) integrals.append( - l_bz * self.integration_constants[n].bz_c[g] * - (np.sin(self.x_bz / l_bz) - np.sin(self.x_fw / l_bz)) + l_bz + * self.integration_constants[n].bz_c[g] + * (np.sin(self.x_bz / l_bz) - np.sin(self.x_fw / l_bz)) ) integrals.append( - -l_bz * self.integration_constants[n].bz_s[g] * - (np.cos(self.x_bz / l_bz) - np.cos(self.x_fw / l_bz)) + -l_bz + * self.integration_constants[n].bz_s[g] + * (np.cos(self.x_bz / l_bz) - np.cos(self.x_fw / l_bz)) ) return np.sum(integrals, axis=0) @summarize_values - def groupwise_neutron_current_fw(self, n: int, x: float | npt.NDArray) -> float: + def groupwise_neutron_current_fw( + self, n: int, x: float | npt.NDArray + ) -> float: """Get the neutron current (in the outward direction) in the fw""" differentials = [] for g in range(n + 1): - if self.l_fw_2[g]>0: + if self.l_fw_2[g] > 0: l_fw = np.sqrt(self.l_fw_2[g]) differentials.append( - self.integration_constants[n].fw_c[g] / l_fw * np.sinh(x / l_fw) + self.integration_constants[n].fw_c[g] + / l_fw + * np.sinh(x / l_fw) ) differentials.append( - self.integration_constants[n].fw_s[g] / l_fw * np.cosh(x / l_fw) + self.integration_constants[n].fw_s[g] + / l_fw + * np.cosh(x / l_fw) ) else: l_fw = np.sqrt(-self.l_fw_2[g]) differentials.append( - - self.integration_constants[n].fw_c[g] / l_fw * np.sin(x / l_fw) + -self.integration_constants[n].fw_c[g] + / l_fw + * np.sin(x / l_fw) ) differentials.append( - self.integration_constants[n].fw_s[g] / l_fw * np.cos(x / l_fw) + self.integration_constants[n].fw_s[g] + / l_fw + * np.cos(x / l_fw) ) return -self.d_fw[n] * np.sum(differentials, axis=0) @summarize_values - def groupwise_neutron_current_bz(self, n: int, x: float | npt.NDArray) -> float: + def groupwise_neutron_current_bz( + self, n: int, x: float | npt.NDArray + ) -> float: """Get the neutron current (in the outward direction) in the bz.""" differentials = [] for g in range(n + 1): - if self.l_bz_2[g]>0: + if self.l_bz_2[g] > 0: l_bz = np.sqrt(self.l_bz_2[g]) differentials.append( - self.integration_constants[n].bz_c[g] / l_bz * np.sinh(x / l_bz) + self.integration_constants[n].bz_c[g] + / l_bz + * np.sinh(x / l_bz) ) differentials.append( - self.integration_constants[n].bz_s[g] / l_bz * np.cosh(x / l_bz) + self.integration_constants[n].bz_s[g] + / l_bz + * np.cosh(x / l_bz) ) else: l_bz = np.sqrt(-self.l_bz_2[g]) differentials.append( - - self.integration_constants[n].bz_c[g] / l_bz * np.sin(x / l_bz) + -self.integration_constants[n].bz_c[g] + / l_bz + * np.sin(x / l_bz) ) differentials.append( - self.integration_constants[n].bz_s[g] / l_bz * np.cos(x / l_bz) + self.integration_constants[n].bz_s[g] + / l_bz + * np.cos(x / l_bz) ) return -self.d_bz[n] * np.sum(differentials, axis=0) @@ -975,7 +1049,9 @@ def _generate_x_range( if symmetric: return ( np.linspace(-x_max, -fw_bz_split_point, n_points_bz), - np.linspace(-fw_bz_split_point, fw_bz_split_point, n_points_fw * 2 - 1), + np.linspace( + -fw_bz_split_point, fw_bz_split_point, n_points_fw * 2 - 1 + ), np.linspace(fw_bz_split_point, x_max, n_points_bz), ) return ( diff --git a/process/neutronics_data.py b/process/neutronics_data.py index dd9e9d99a4..aabc97b60b 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -107,7 +107,7 @@ def calculate_average_macro_xs( # N_A/A * rho * sigma - return N_A / (avg_mass_amu/1000) * density * (avg_sigma * BARNS_TO_M2) + return N_A / (avg_mass_amu / 1000) * density * (avg_sigma * BARNS_TO_M2) def discretize_xs( diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 90d20d4d1a..4550b0aca2 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -1,9 +1,9 @@ -import pytest import numpy as np from process.neutronics import NeutronFluxProfile from process.neutronics_data import MaterialMacroInfo + def test_one_group(): """ Regression test against Desmos snapshot: @@ -16,21 +16,25 @@ def test_one_group(): sigma_fw_t = 1 / mfp_fw_t # [1/m] sigma_fw_s = 1 / mfp_fw_s # [1/m] a_fw = 52 - fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]], name="fw") + fw_material = MaterialMacroInfo( + dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]], name="fw" + ) mfp_bz_s = 97 * 0.01 # [m] mfp_bz_t = 35.8 * 0.01 # [m] sigma_bz_s = 1 / mfp_bz_s # [1/m] sigma_bz_t = 1 / mfp_bz_t # [1/m] a_bz = 71 - bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], name="bz") + bz_material = MaterialMacroInfo( + dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], name="bz" + ) x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 neutron_profile = NeutronFluxProfile( incoming_flux, x_fw, x_bz, fw_material, bz_material ) - + const = neutron_profile.integration_constants[0] # alias to fit line width assert np.isclose(const.fw_c[0], 80.5346770788), "c5" assert np.isclose(const.fw_s[0], -76.5562120985), "c6" @@ -46,12 +50,14 @@ def test_one_group(): fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] - assert np.isclose(neutron_profile.flux, + assert np.isclose( + neutron_profile.flux, neutron_profile.neutron_current_escaped() + fw_removal * neutron_profile.integrated_flux_fw() - + bz_removal * neutron_profile.integrated_flux_bz() + + bz_removal * neutron_profile.integrated_flux_bz(), ), "Conservation of neutrons" + def test_one_group_with_fission(): """ Regression test against Desmos snapshot with fission involved: @@ -64,7 +70,9 @@ def test_one_group_with_fission(): sigma_fw_t = 1 / mfp_fw_t # [1/m] sigma_fw_s = 1 / mfp_fw_s # [1/m] a_fw = 52 - fw_material = MaterialMacroInfo(dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]], name="fw") + fw_material = MaterialMacroInfo( + dummy, a_fw, [sigma_fw_t], [[sigma_fw_s]], name="fw" + ) mfp_bz_s = 97 * 0.01 # [m] mfp_bz_t = 35.8 * 0.01 # [m] @@ -74,31 +82,49 @@ def test_one_group_with_fission(): g = 1.2 nu_sigma_bz_f = g * (sigma_bz_t - sigma_bz_s) - bz_material = MaterialMacroInfo(dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], [[nu_sigma_bz_f]], name="bz") + bz_material = MaterialMacroInfo( + dummy, a_bz, [sigma_bz_t], [[sigma_bz_s]], [[nu_sigma_bz_f]], name="bz" + ) x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 neutron_profile = NeutronFluxProfile( incoming_flux, x_fw, x_bz, fw_material, bz_material ) - assert np.isclose(neutron_profile.l_bz_2[0], -(58.2869567709/100)**2) - assert np.isclose(neutron_profile.neutron_flux_at(-4.79675/100), 159.9434), "Minimum flux in FW" - assert np.isclose(neutron_profile.neutron_flux_at(4.79675/100), 159.9434), "Minimum flux in FW" - assert np.isclose(neutron_profile.neutron_flux_at(18.96382/100), 164.81245), "Maximum flux in BZ" - assert np.isclose(neutron_profile.neutron_flux_at(-18.96382/100), 164.81245), "Maximum flux in BZ" - assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), neutron_profile.neutron_flux_bz(x_fw)), "Flux continuity assurance" - assert np.isclose(neutron_profile.neutron_current_fw2bz(), -7.6275782637960745), "Negative current because BZ (breeding) is backflowing into the FW" - assert np.isclose(neutron_profile.neutron_current_escaped(), 30.665951670177186), "positive escaped current." + assert np.isclose(neutron_profile.l_bz_2[0], -((58.2869567709 / 100) ** 2)) + assert np.isclose( + neutron_profile.neutron_flux_at(-4.79675 / 100), 159.9434 + ), "Minimum flux in FW" + assert np.isclose( + neutron_profile.neutron_flux_at(4.79675 / 100), 159.9434 + ), "Minimum flux in FW" + assert np.isclose( + neutron_profile.neutron_flux_at(18.96382 / 100), 164.81245 + ), "Maximum flux in BZ" + assert np.isclose( + neutron_profile.neutron_flux_at(-18.96382 / 100), 164.81245 + ), "Maximum flux in BZ" + assert np.isclose( + neutron_profile.neutron_flux_fw(x_fw), + neutron_profile.neutron_flux_bz(x_fw), + ), "Flux continuity assurance" + assert np.isclose( + neutron_profile.neutron_current_fw2bz(), -7.6275782637960745 + ), "Negative current because BZ (breeding) is backflowing into the FW" + assert np.isclose( + neutron_profile.neutron_current_escaped(), 30.665951670177186 + ), "positive escaped current." fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] - assert np.isclose(neutron_profile.flux, + assert np.isclose( + neutron_profile.flux, neutron_profile.neutron_current_escaped() + fw_removal * neutron_profile.integrated_flux_fw() - + bz_removal * neutron_profile.integrated_flux_bz() + + bz_removal * neutron_profile.integrated_flux_bz(), ), "Conservation of neutrons" + def test_two_groups(): """ - Same group n=0 values as test_one_group. Second group can have a massive removal cross-section + Same group n=0 values as test_one_group. Second group can have a massive removal cross-section """ - From 5450d0bf7a188f90670e5c79e679d7e6e3414e5c Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 09:56:02 +0000 Subject: [PATCH 66/98] Renamed the integration_constants to coefficients (because they're no longer obtained by integration) --- process/neutronics.py | 123 ++++++++++++++-------------- tests/regression/test_neutronics.py | 2 +- tests/unit/test_neutronics.py | 4 +- 3 files changed, 65 insertions(+), 64 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 4b606fa851..b2c443e6e9 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -129,14 +129,14 @@ def extrapolation_length(diffusion_coefficient: float) -> float: @dataclass -class IntegrationConstants: +class Coefficients: """ Inside each material, there are two new hyperbolic trig funcs per group, i.e. group n=0 has cosh(x/L[0]) and sinh(x/L[0]), group n=1 has cosh(x/L[0]), sinh(x/L[0]), cosh(x/L[1]) and sinh(x/L[1]), etc. - To get the neutron flux, each trig func has to be scaled by an integration - constant. E.g. + To get the neutron flux, each trig func has to be scaled by a coeffient. + E.g. group n=0: fw: fw_c[0][0] * cosh(x/L[0]) + fw_s[0][0] * sinh(x/L[0]) group n=1: fw: fw_c[1][0] * cosh(x/L[0]) + fw_c[1][1] * cosh(x/L[1]) + fw_s[1][0] * sinh(x/L[0]) + fw_s[1][1] * sinh(x/L[1]) @@ -148,13 +148,14 @@ class IntegrationConstants: bz_c: Iterable[float] bz_s: Iterable[float] - def validate_length(self, expected_length: int): + def validate_length(self, exp_len: int, parent_name: str): """Validate that all fields has the correct length.""" for const_name, const_value in asdict(self).items(): - if len(const_value) != expected_length: + if len(const_value) != exp_len: raise ProcessValueError( - f"Expected {const_name} to have len=={expected_length}, " - f"got {len(const_value)} instead." + f"{parent_name}'s [{exp_len-1}]-th item is expected to " + "have .{const_name} of length={exp_len}, but instead got " + f"{const_value}." ) @@ -178,7 +179,7 @@ def __init__(self, populating_method: Callable[[int], None], name: str): dictionary. """ self._dict = {} - self._name = name + self.name = name self._attempting_to_access = set() self.populating_method = populating_method @@ -186,8 +187,8 @@ def __getitem__(self, i: int): """Check if index i is in the dictionary or not. If not, populate it.""" if i in self._attempting_to_access: raise RecursionError( - f"retrieving the value of {self._name}[{i}] requires the " - f"value of {self._name}[{i}]." + f"retrieving the value of {self.name}[{i}] requires the " + f"value of {self.name}[{i}]." ) if i not in self._dict: self._attempting_to_access.add(i) @@ -207,7 +208,7 @@ def __contains__(self, i: int): def __setitem__(self, i: int, value: float): """Check if dict i is in the index or not.""" if hasattr(value, "validate_length"): - value.validate_length(i + 1) + value.validate_length(i + 1, parent_name=self.name) self._dict[i] = value self._attempting_to_access.discard(i) @@ -256,8 +257,8 @@ def __init__( group_structure: energy bin edges, 1D array of len = n_groups+1 - integration_constants: - Integration constants that determine the flux shape (and therefore + coefficients: + Coefficients that determine the flux shape (and therefore reaction rates and neutron current) of each group. A set of four constants, two for fw and two for bz; each with unit: [m^-2 s^-1] l_fw_2: @@ -294,8 +295,8 @@ def __init__( "must have the same group structure!" ) - self.integration_constants = AutoPopulatingDict( - self.solve_group_n, "integration_constants" + self.coefficients = AutoPopulatingDict( + self.solve_group_n, "coefficients" ) # diffusion lengths squared self.l_fw_2 = AutoPopulatingDict(self.solve_group_n, "l_fw_2") @@ -310,11 +311,11 @@ def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], - self.l_bz_2[0], and self.integration_constants[0]. - integration_constants have units of [m^-2 s^-1]. + self.l_bz_2[0], and self.coefficients[0]. + coefficients have units of [m^-2 s^-1]. """ n = 0 - if n in self.integration_constants: + if n in self.coefficients: return # skip if it has already been solved. self.d_fw[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( self.fw_mat.avg_atomic_mass, @@ -372,7 +373,7 @@ def solve_lowest_group(self) -> None: bz_c_factor = bz_common_factor * s_bz bz_s_factor = -bz_common_factor * c_bz - self.integration_constants[n] = IntegrationConstants( + self.coefficients[n] = Coefficients( [fw_c_factor], [fw_s_factor], [bz_c_factor], [bz_s_factor] ) return @@ -381,7 +382,7 @@ def solve_group_n(self, n: int) -> None: """ Solve the n-th group of neutron's diffusion equation, where n<=n_groups-1. Store the solved constants in self.extended_boundary[n-1], self.l_fw_2[n-1], - self.l_bz_2[n-1], and self.integration_constants[n-1]. + self.l_bz_2[n-1], and self.coefficients[n-1]. Parameters ---------- @@ -398,13 +399,13 @@ def solve_group_n(self, n: int) -> None: return self.solve_lowest_group() # ensure all lower groups are solved. for k in range(n): - if k not in self.integration_constants: + if k not in self.coefficients: self.solve_group_n(k) if not (self.fw_mat.downscatter_only and self.bz_mat.downscatter_only): raise NotImplementedError( "Will implement solve_group_n in a loop later..." ) - if n in self.integration_constants: + if n in self.coefficients: return None # skip if it has already been solved. # Parameter to be changed later, to allow solving non-down-scatter # only systems by iterating. @@ -431,7 +432,7 @@ def solve_group_n(self, n: int) -> None: src_fw = self.fw_mat.sigma_s + self.fw_mat.sigma_in src_bz = self.bz_mat.sigma_s + self.bz_mat.sigma_in - self.integration_constants[n] = IntegrationConstants([], [], [], []) + self.coefficients[n] = Coefficients([], [], [], []) for g in range(n): # if the characteristic length of group [g] coincides with the # characteristic length of group [n], then that particular @@ -445,30 +446,30 @@ def solve_group_n(self, n: int) -> None: scale_factor_bz = 0.0 else: scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz - self.integration_constants[n].fw_c.append( + self.coefficients[n].fw_c.append( sum( - src_fw[i, n] * self.integration_constants[i].fw_c[g] + src_fw[i, n] * self.coefficients[i].fw_c[g] for i in range(g, n) ) * scale_factor_fw ) - self.integration_constants[n].fw_s.append( + self.coefficients[n].fw_s.append( sum( - src_fw[i, n] * self.integration_constants[i].fw_s[g] + src_fw[i, n] * self.coefficients[i].fw_s[g] for i in range(g, n) ) * scale_factor_fw ) - self.integration_constants[n].bz_c.append( + self.coefficients[n].bz_c.append( sum( - src_bz[i, n] * self.integration_constants[i].bz_c[g] + src_bz[i, n] * self.coefficients[i].bz_c[g] for i in range(g, n) ) * scale_factor_bz ) - self.integration_constants[n].bz_s.append( + self.coefficients[n].bz_s.append( sum( - src_bz[i, n] * self.integration_constants[i].bz_s[g] + src_bz[i, n] * self.coefficients[i].bz_s[g] for i in range(g, n) ) * scale_factor_bz @@ -478,16 +479,16 @@ def solve_group_n(self, n: int) -> None: fw_s_factor_guess = 0.0 bz_c_factor_guess = 0.0 bz_s_factor_guess = 0.0 - self.integration_constants[n].fw_c.append(fw_c_factor_guess) - self.integration_constants[n].fw_s.append(fw_s_factor_guess) - self.integration_constants[n].bz_c.append(bz_c_factor_guess) - self.integration_constants[n].bz_s.append(bz_s_factor_guess) + self.coefficients[n].fw_c.append(fw_c_factor_guess) + self.coefficients[n].fw_s.append(fw_s_factor_guess) + self.coefficients[n].bz_c.append(bz_c_factor_guess) + self.coefficients[n].bz_s.append(bz_s_factor_guess) def _set_constants(input_vector: Iterable[float]): - self.integration_constants[n].fw_c[n] = input_vector[0] - self.integration_constants[n].fw_s[n] = input_vector[1] - self.integration_constants[n].bz_c[n] = input_vector[2] - self.integration_constants[n].bz_s[n] = input_vector[3] + self.coefficients[n].fw_c[n] = input_vector[0] + self.coefficients[n].fw_s[n] = input_vector[1] + self.coefficients[n].bz_c[n] = input_vector[2] + self.coefficients[n].bz_s[n] = input_vector[3] def _evaluate_fit(): flux_continuity = self.groupwise_neutron_flux_fw( @@ -541,8 +542,8 @@ def _evaluate_fit(): total_neutron_conservation, ]) - def objective(four_integration_constants_vector): - _set_constants(four_integration_constants_vector) + def objective(four_coefficients_vector): + _set_constants(four_coefficients_vector) return _evaluate_fit() results = optimize.root( @@ -590,10 +591,10 @@ def groupwise_neutron_flux_fw( c, s = np.cos, np.sin l_fw = np.sqrt(-self.l_fw_2[g]) trig_funcs.append( - self.integration_constants[n].fw_c[g] * c(abs(x) / l_fw) + self.coefficients[n].fw_c[g] * c(abs(x) / l_fw) ) trig_funcs.append( - self.integration_constants[n].fw_s[g] * s(abs(x) / l_fw) + self.coefficients[n].fw_s[g] * s(abs(x) / l_fw) ) return np.sum(trig_funcs, axis=0) @@ -629,10 +630,10 @@ def groupwise_neutron_flux_bz( c, s = np.cos, np.sin l_bz = np.sqrt(-self.l_bz_2[g]) trig_funcs.append( - self.integration_constants[n].bz_c[g] * c(abs(x) / l_bz) + self.coefficients[n].bz_c[g] * c(abs(x) / l_bz) ) trig_funcs.append( - self.integration_constants[n].bz_s[g] * s(abs(x) / l_bz) + self.coefficients[n].bz_s[g] * s(abs(x) / l_bz) ) return np.sum(trig_funcs, axis=0) @@ -697,24 +698,24 @@ def groupwise_integrated_flux_fw(self, n: int) -> float: l_fw = np.sqrt(self.l_fw_2[g]) integrals.append( l_fw - * self.integration_constants[n].fw_c[g] + * self.coefficients[n].fw_c[g] * np.sinh(self.x_fw / l_fw) ) integrals.append( l_fw - * self.integration_constants[n].fw_s[g] + * self.coefficients[n].fw_s[g] * (np.cosh(self.x_fw / l_fw) - 1) ) else: l_fw = np.sqrt(-self.l_fw_2[g]) integrals.append( l_fw - * self.integration_constants[n].fw_c[g] + * self.coefficients[n].fw_c[g] * np.sin(self.x_fw / l_fw) ) integrals.append( l_fw - * self.integration_constants[n].fw_s[g] + * self.coefficients[n].fw_s[g] * (1 - np.cos(self.x_fw / l_fw)) ) @@ -739,24 +740,24 @@ def groupwise_integrated_flux_bz(self, n: int) -> float: l_bz = np.sqrt(self.l_bz_2[g]) integrals.append( l_bz - * self.integration_constants[n].bz_c[g] + * self.coefficients[n].bz_c[g] * (np.sinh(self.x_bz / l_bz) - np.sinh(self.x_fw / l_bz)) ) integrals.append( l_bz - * self.integration_constants[n].bz_s[g] + * self.coefficients[n].bz_s[g] * (np.cosh(self.x_bz / l_bz) - np.cosh(self.x_fw / l_bz)) ) else: l_bz = np.sqrt(-self.l_bz_2[g]) integrals.append( l_bz - * self.integration_constants[n].bz_c[g] + * self.coefficients[n].bz_c[g] * (np.sin(self.x_bz / l_bz) - np.sin(self.x_fw / l_bz)) ) integrals.append( -l_bz - * self.integration_constants[n].bz_s[g] + * self.coefficients[n].bz_s[g] * (np.cos(self.x_bz / l_bz) - np.cos(self.x_fw / l_bz)) ) return np.sum(integrals, axis=0) @@ -771,24 +772,24 @@ def groupwise_neutron_current_fw( if self.l_fw_2[g] > 0: l_fw = np.sqrt(self.l_fw_2[g]) differentials.append( - self.integration_constants[n].fw_c[g] + self.coefficients[n].fw_c[g] / l_fw * np.sinh(x / l_fw) ) differentials.append( - self.integration_constants[n].fw_s[g] + self.coefficients[n].fw_s[g] / l_fw * np.cosh(x / l_fw) ) else: l_fw = np.sqrt(-self.l_fw_2[g]) differentials.append( - -self.integration_constants[n].fw_c[g] + -self.coefficients[n].fw_c[g] / l_fw * np.sin(x / l_fw) ) differentials.append( - self.integration_constants[n].fw_s[g] + self.coefficients[n].fw_s[g] / l_fw * np.cos(x / l_fw) ) @@ -804,24 +805,24 @@ def groupwise_neutron_current_bz( if self.l_bz_2[g] > 0: l_bz = np.sqrt(self.l_bz_2[g]) differentials.append( - self.integration_constants[n].bz_c[g] + self.coefficients[n].bz_c[g] / l_bz * np.sinh(x / l_bz) ) differentials.append( - self.integration_constants[n].bz_s[g] + self.coefficients[n].bz_s[g] / l_bz * np.cosh(x / l_bz) ) else: l_bz = np.sqrt(-self.l_bz_2[g]) differentials.append( - -self.integration_constants[n].bz_c[g] + -self.coefficients[n].bz_c[g] / l_bz * np.sin(x / l_bz) ) differentials.append( - self.integration_constants[n].bz_s[g] + self.coefficients[n].bz_s[g] / l_bz * np.cos(x / l_bz) ) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 4550b0aca2..ba13b2deee 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -35,7 +35,7 @@ def test_one_group(): incoming_flux, x_fw, x_bz, fw_material, bz_material ) - const = neutron_profile.integration_constants[0] # alias to fit line width + const = neutron_profile.coefficients[0] # alias to fit line width assert np.isclose(const.fw_c[0], 80.5346770788), "c5" assert np.isclose(const.fw_s[0], -76.5562120985), "c6" assert np.isclose(const.bz_c[0], 60.6871656017), "c7" diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 48f4c9ff83..6c4cbf14d0 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -86,8 +86,8 @@ def test_three_group(): dummy = [10000, 1000, 100, 1] # fw_mat = MaterialMacroInfo() bz_mat = MaterialMacroInfo - # 2. same L_1 and L_3 shoudl yield integration_constants[2].fw_c[0] and - # integration_constants[2].fw_s[0] = 0.0 + # 2. same L_1 and L_3 shoudl yield coefficients[2].fw_c[0] and + # coefficients[2].fw_s[0] = 0.0 # self.l_fw_2 == self.l_fw_2[n] case. # From 8a63ad158e09433676f3a2c4f676f53754de5245 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 10:46:49 +0000 Subject: [PATCH 67/98] Removed unused constant --- process/neutronics_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/process/neutronics_data.py b/process/neutronics_data.py index aabc97b60b..80fd4daf1b 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -9,7 +9,6 @@ from process.exceptions import ProcessValidationError -BARNS_TO_CM2 = 1e-24 BARNS_TO_M2 = 1e-28 N_A = Avogadro N2N_Q_VALUE = ... From a97ba1715189cdee393339915a621abc72ecec95 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 16:54:45 +0000 Subject: [PATCH 68/98] Majority of the conversion from 2-layer model to the infinite-layer model is complete. --- process/neutronics.py | 758 +++++++++++++++++------------------------- 1 file changed, 313 insertions(+), 445 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index b2c443e6e9..dc27fd795a 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -5,6 +5,7 @@ import functools import inspect +from itertools import pairwise from collections.abc import Callable, Iterable from dataclasses import asdict, dataclass @@ -96,7 +97,7 @@ def get_diffusion_coefficient_and_length( Returns ------- - diffusion_coef: + diffusion_const: The diffusion coefficient as given by Reactor Analysis, Duderstadt and Hamilton. unit: [m] diffusion_len_2: @@ -106,14 +107,14 @@ def get_diffusion_coefficient_and_length( """ transport_xs = total_xs - 2 / (3 * avg_atomic_mass) * scattering_xs - diffusion_coef = 1 / 3 / transport_xs - diffusion_len_2 = diffusion_coef / ( + diffusion_const = 1 / 3 / transport_xs + diffusion_len_2 = diffusion_const / ( total_xs - scattering_xs - in_source_xs ) - return diffusion_coef, diffusion_len_2 + return diffusion_const, diffusion_len_2 -def extrapolation_length(diffusion_coefficient: float) -> float: +def extrapolation_length(diffusion_constficient: float) -> float: """Get the extrapolation length of the final medium :math:`\\delta`. Notes @@ -125,7 +126,7 @@ def extrapolation_length(diffusion_coefficient: float) -> float: THis yields a very close approximation. All of this equation is provided by Duderstadt and Hamilton. """ - return 0.7104 * 3 * diffusion_coefficient + return 0.7104 * 3 * diffusion_constficient @dataclass @@ -143,10 +144,8 @@ class Coefficients: """ - fw_c: Iterable[float] - fw_s: Iterable[float] - bz_c: Iterable[float] - bz_s: Iterable[float] + c: Iterable[float] + s: Iterable[float] def validate_length(self, exp_len: int, parent_name: str): """Validate that all fields has the correct length.""" @@ -216,7 +215,7 @@ def values(self): return self._dict.values() def __repr__(self): - return f"AutoPopulatingDict{self._dict}" + return f"AutoPopulatingDict({self.name}):{self._dict}" class NeutronFluxProfile: @@ -225,10 +224,8 @@ class NeutronFluxProfile: def __init__( self, flux: float, - x_fw: float, - x_bz: float, - fw_mat: MaterialMacroInfo, - bz_mat: MaterialMacroInfo, + interface_x: npt.NDArray[np.float64], + materials: Iterable[MaterialMacroInfo], ): """Initialize a particular FW-BZ geometry and neutron flux. @@ -237,72 +234,86 @@ def __init__( flux: Nuetron flux directly emitted by the plasma, incident on the first wall. unit: m^-2 s^-1 - x_fw: - thickness of the first wall [m]. - x_bz: - thickness of the blanket + first-wall [m]. - fw_mat: - first wall material information - bz_mat: - blanket material information + interface_x: + The x-coordinates of every interface between layers. For n_layers, + there will be n_layers - 1 interfaces between layers, plus the + interface between the final layer and the void into which neutrons + are lost. + E.g. interface_x[0] is the thickness of the first wall, + interface_x[1] is the thickness of the first wall + breeding zone, + etc. + materials: + Every layer's material information. Attributes ---------- - fw_mat: - first wall material information - bz_mat: - blanket material information + n_layers: + Number of layers n_groups: - number of groups in the group structure + Number of groups in the group structure group_structure: - energy bin edges, 1D array of len = n_groups+1 + Energy bin edges, 1D array of len = n_groups+1 coefficients: - Coefficients that determine the flux shape (and therefore - reaction rates and neutron current) of each group. A set of four - constants, two for fw and two for bz; each with unit: [m^-2 s^-1] - l_fw_2: - square of the characteristic diffusion length as given by Reactor Analysis, - Duderstadt and Hamilton, applied to the fw. unit: [m^2] - l_bz_2: - square of the characteristic diffusion length as given by Reactor Analysis, - Duderstadt and Hamilton, applied to the bz. unit: [m^2] - d_fw: - diffusion constants in the fw. unit: [m] - d_bz: - diffusion constants in the bz. unit: [m] + Coefficients that determine the flux shape (and therefore reaction + rates, neutron current, etc.) of each group. Each coefficient has + unit: [m^-2 s^-1] + l2: + Square of the characteristic diffusion length of each layer as + given by Reactor Analysis, Duderstadt and Hamilton. unit: [m^2] + diffusion_const: + Diffusion coefficient of each layer. unit: [m] extended_boundary: - extended boundary (outside the bz) for each group. - This value should be larger than x_bz for each of them. + Extended boundary for each group. These values should be larger + than interface_x[-1]. """ - self.flux = flux # flux incident on the first wall. - if not (0 < x_fw < x_bz): + # flux incident on the first wall at the highest energy. + self.flux = flux + + # layers + self.interface_x = np.array(interface_x).ravel() + if not (np.diff(self.interface_x)>0).all(): raise ValueError( - f"Cannot construct a first-wall+blanket module where{x_fw=}, {x_bz=}." + f"Model cannot have non-positive layer thicknesses." ) - self.x_fw, self.x_bz = x_fw, x_bz - self.fw_mat = fw_mat - self.bz_mat = bz_mat - self.n_groups = self.fw_mat.n_groups - self.group_structure = self.fw_mat.group_structure - if not np.allclose( - self.fw_mat.group_structure, - self.bz_mat.group_structure, - atol=0, - ): + self.interface_x.flag.writeable = False + self.materials = tuple(materials) + if len(self.interface_x) != len(self.materials): raise ProcessValidationError( - "The first-wall material info and breeding zone material info" - "must have the same group structure!" + "The number of layers specified by self.materials must match " + "the number of x-positions specified by interface_x." ) - - self.coefficients = AutoPopulatingDict( - self.solve_group_n, "coefficients" - ) + self.n_layers = len(self.materials) + + # groups + fw_mat = self.materials[0] + for mat in self.materials[1:]: + if not np.allclose( + fw_mat.group_structure, mat.group_structure, atol=0, + ): + raise ProcessValidationError( + "All material info must have the same group structure!" + ) + self.n_groups = fw_mat.n_groups + self.group_structure = fw_mat.group_structure + + trig_coefs, l2, d_coef = [], [], [] + for num_layer, mat in enumerate(self.materials): + c_name = f"Coefficients for layer {num_layer}" + l_name = f"characteristic diffusion length for layer {num_layer}" + d_name = f"Diffusion coefficient D for layer {num_layer}" + if mat.name: + c_name += f":{mat.name}" + l_name += f":{mat.name}" + d_name += f":{mat.name}" + trig_coefs.append(AutoPopulatingDict(self.solve_group_n, c_name)) + l2.append(AutoPopulatingDict(self.solve_group_n, l_name)) + d_coef.append(AutoPopulatingDict(self.solve_group_n, d_name)) + + self.coefficients = tuple(trig_coefs) + self.l2 = tuple(l2) + self.diffusion_const = tuple(d_coef) # diffusion lengths squared - self.l_fw_2 = AutoPopulatingDict(self.solve_group_n, "l_fw_2") - self.l_bz_2 = AutoPopulatingDict(self.solve_group_n, "l_bz_2") - self.d_fw = AutoPopulatingDict(self.solve_group_n, "d_fw") - self.d_bz = AutoPopulatingDict(self.solve_group_n, "d_bz") self.extended_boundary = AutoPopulatingDict( self.solve_group_n, "extended_boundary" ) @@ -310,79 +321,76 @@ def __init__( def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. - Store the solved constants in self.extended_boundary[0], self.l_fw_2[0], - self.l_bz_2[0], and self.coefficients[0]. - coefficients have units of [m^-2 s^-1]. + Store the solved constants in self.extended_boundary[0], self.l2[*][0], + and self.coefficients[*][0]. + self.coefficients each have units of [m^-2 s^-1]. """ n = 0 - if n in self.coefficients: + if all(n in layer_coefs for layer_coefs in self.coefficients): return # skip if it has already been solved. - self.d_fw[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( - self.fw_mat.avg_atomic_mass, - self.fw_mat.sigma_t[n], - self.fw_mat.sigma_s[n, n], - self.fw_mat.sigma_in[n, n], - ) - self.d_bz[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( - self.bz_mat.avg_atomic_mass, - self.bz_mat.sigma_t[n], - self.bz_mat.sigma_s[n, n], - self.bz_mat.sigma_in[n, n], - ) - l_fw = np.sqrt(abs(self.l_fw_2[n])) - l_bz = np.sqrt(abs(self.l_bz_2[n])) - x_fw, x_bz = self.x_fw, self.x_bz - d_fw = self.d_fw[n] - d_bz = self.d_bz[n] - self.extended_boundary[n] = x_bz + extrapolation_length(d_bz) - if self.l_fw_2[n] > 0: - s_fw = np.sinh(x_fw / l_fw) - c_fw = np.cosh(x_fw / l_fw) - t_fw = np.tanh(x_fw / l_fw) - else: - s_fw = np.sin(x_fw / l_fw) - c_fw = np.cos(x_fw / l_fw) - t_fw = np.tan(x_fw / l_fw) - if self.l_bz_2[n] > 0: - c_bz = np.cosh(self.extended_boundary[n] / l_bz) - s_bz = np.sinh(self.extended_boundary[n] / l_bz) - c_bz_mod = np.cosh((self.extended_boundary[n] - x_fw) / l_bz) - s_bz_mod = np.sinh((self.extended_boundary[n] - x_fw) / l_bz) - t_bz_mod = np.tanh((self.extended_boundary[n] - x_fw) / l_bz) - else: - c_bz = np.cos(self.extended_boundary[n] / l_bz) - s_bz = np.sin(self.extended_boundary[n] / l_bz) - c_bz_mod = np.cos((self.extended_boundary[n] - x_fw) / l_bz) - s_bz_mod = np.sin((self.extended_boundary[n] - x_fw) / l_bz) - t_bz_mod = np.tan((self.extended_boundary[n] - x_fw) / l_bz) - - fw_c_factor = -self.flux * ( - l_fw / d_fw - - np.exp(x_fw / l_fw) - * ((l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod) - / (c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz)) + for num_layer, mat in enumerate(self.materials): + self.diffusion_const[num_layer][n], self.l2[num_layer][n] = get_diffusion_coefficient_and_length( + mat.avg_atomic_mass, + mat.sigma_t[n], + mat.sigma_s[n, n], + mat.sigma_in[n, n], + ) + self.extended_boundary[n] = self.interface_x[-1] + extrapolation_length( + self.diffusion_const[-1][n] ) - fw_s_factor = -self.flux * l_fw / d_fw + if self.n_layers == 2: + l_fw, l_bz = np.sqrt(abs(self.l2[0][n])), np.sqrt(abs(self.l2[1][n])) + x_fw, = self.interface_x[:-1] + d_fw, d_bz = self.diffusion_const[0][n], self.diffusion_const[1][n] + if self.l2[0][n] > 0: + s_fw = np.sinh(x_fw / l_fw) + c_fw = np.cosh(x_fw / l_fw) + t_fw = np.tanh(x_fw / l_fw) + else: + s_fw = np.sin(x_fw / l_fw) + c_fw = np.cos(x_fw / l_fw) + t_fw = np.tan(x_fw / l_fw) + if self.l2[1][n] > 0: + c_bz = np.cosh(self.extended_boundary[n] / l_bz) + s_bz = np.sinh(self.extended_boundary[n] / l_bz) + c_bz_mod = np.cosh((self.extended_boundary[n] - x_fw) / l_bz) + s_bz_mod = np.sinh((self.extended_boundary[n] - x_fw) / l_bz) + t_bz_mod = np.tanh((self.extended_boundary[n] - x_fw) / l_bz) + else: + c_bz = np.cos(self.extended_boundary[n] / l_bz) + s_bz = np.sin(self.extended_boundary[n] / l_bz) + c_bz_mod = np.cos((self.extended_boundary[n] - x_fw) / l_bz) + s_bz_mod = np.sin((self.extended_boundary[n] - x_fw) / l_bz) + t_bz_mod = np.tan((self.extended_boundary[n] - x_fw) / l_bz) + + fw_c_factor = -self.flux * ( + l_fw / d_fw + - np.exp(x_fw / l_fw) + * ((l_fw / d_fw) + (l_bz / d_bz) * t_bz_mod) + / (c_fw + s_fw * t_bz_mod * (d_fw / l_fw) * (l_bz / d_bz)) + ) + fw_s_factor = -self.flux * l_fw / d_fw - bz_common_factor = ( - self.flux - * np.exp(x_fw / l_fw) - * (1 - t_fw) - / ((d_bz / l_bz) * c_bz_mod + (d_fw / l_fw) * t_fw * s_bz_mod) - ) - bz_c_factor = bz_common_factor * s_bz - bz_s_factor = -bz_common_factor * c_bz + bz_common_factor = ( + self.flux + * np.exp(x_fw / l_fw) + * (1 - t_fw) + / ((d_bz / l_bz) * c_bz_mod + (d_fw / l_fw) * t_fw * s_bz_mod) + ) + bz_c_factor = bz_common_factor * s_bz + bz_s_factor = -bz_common_factor * c_bz - self.coefficients[n] = Coefficients( - [fw_c_factor], [fw_s_factor], [bz_c_factor], [bz_s_factor] - ) + self.coefficients[0][n] = Coefficients([fw_c_factor], [fw_s_factor]) + self.coefficients[1][n] = Coefficients([bz_c_factor], [bz_s_factor]) + else: + raise NotImplementedError("Only implemented 2 groups so far.") return def solve_group_n(self, n: int) -> None: """ - Solve the n-th group of neutron's diffusion equation, where n<=n_groups-1. - Store the solved constants in self.extended_boundary[n-1], self.l_fw_2[n-1], - self.l_bz_2[n-1], and self.coefficients[n-1]. + Solve the n-th group of neutron's diffusion equation, where n <= + n_groups-1. Store the solved constants in self.extended_boundary[n-1], + self.l2[*][n-1], and self.coefficients[*][n-1]. Parameters ---------- @@ -399,183 +407,132 @@ def solve_group_n(self, n: int) -> None: return self.solve_lowest_group() # ensure all lower groups are solved. for k in range(n): - if k not in self.coefficients: + if not all(k in layer_coefs for layer_coefs in self.coefficients): self.solve_group_n(k) - if not (self.fw_mat.downscatter_only and self.bz_mat.downscatter_only): + if not all(mat.downscatter_only for mat in self.materials): raise NotImplementedError( "Will implement solve_group_n in a loop later..." ) - if n in self.coefficients: + if all(n in layer_coefs for layer_coefs in self.coefficients): return None # skip if it has already been solved. # Parameter to be changed later, to allow solving non-down-scatter # only systems by iterating. first_iteration = True - self.d_fw[n], self.l_fw_2[n] = get_diffusion_coefficient_and_length( - self.fw_mat.avg_atomic_mass, - self.fw_mat.sigma_t[n], - self.fw_mat.sigma_s[n, n], - self.fw_mat.sigma_in[n, n], - ) - self.d_bz[n], self.l_bz_2[n] = get_diffusion_coefficient_and_length( - self.bz_mat.avg_atomic_mass, - self.bz_mat.sigma_t[n], - self.bz_mat.sigma_s[n, n], - self.bz_mat.sigma_in[n, n], - ) - self.extended_boundary[n] = self.x_bz + extrapolation_length( - self.d_bz[n] + for num_layer, mat in enumerate(self.materials): + self.diffusion_const[num_layer][n], self.l2[num_layer][n] = get_diffusion_coefficient_and_length( + mat.avg_atomic_mass, + mat.sigma_t[n], + mat.sigma_s[n, n], + mat.sigma_in[n, n], + ) + self.extended_boundary[n] = self.interface_x[-1] + extrapolation_length( + self.diffusion_const[-1][n] ) - # Setting up aliases for shorter code - l_fw_2, l_bz_2 = self.l_fw_2[n], self.l_bz_2[n] - d_fw, d_bz = self.d_fw[n], self.d_bz[n] - src_fw = self.fw_mat.sigma_s + self.fw_mat.sigma_in - src_bz = self.bz_mat.sigma_s + self.bz_mat.sigma_in - - self.coefficients[n] = Coefficients([], [], [], []) - for g in range(n): - # if the characteristic length of group [g] coincides with the - # characteristic length of group [n], then that particular - # cosh/sinh would be indistinguishable from group [n]'s - # cosh/sinh anyways, therefore we can set the coefficient to 0. - if np.isclose(diff_fw := self.l_fw_2[g] - l_fw_2, 0): - scale_factor_fw = 0.0 - else: - scale_factor_fw = (l_fw_2 * self.l_fw_2[g]) / d_fw / diff_fw - if np.isclose(diff_bz := self.l_bz_2[g] - l_bz_2, 0): - scale_factor_bz = 0.0 - else: - scale_factor_bz = (l_bz_2 * self.l_bz_2[g]) / d_bz / diff_bz - self.coefficients[n].fw_c.append( - sum( - src_fw[i, n] * self.coefficients[i].fw_c[g] - for i in range(g, n) - ) - * scale_factor_fw - ) - self.coefficients[n].fw_s.append( - sum( - src_fw[i, n] * self.coefficients[i].fw_s[g] - for i in range(g, n) - ) - * scale_factor_fw - ) - self.coefficients[n].bz_c.append( - sum( - src_bz[i, n] * self.coefficients[i].bz_c[g] - for i in range(g, n) + + for num_layer in range(self.n_layers): + # Setting up aliases for shorter code + _coefs = Coefficients([], []) + mat = self.materials[num_layer] + src_matrix = mat.sigma_s + mat.sigma_in + diffusion_const_n = self.diffusion_const[num_layer][n] + for g in range(n): + # if the characteristic length of group [g] coincides with the + # characteristic length of group [n], then that particular + # cosh/sinh would be indistinguishable from group [n]'s + # cosh/sinh anyways, therefore we can set the coefficient to 0. + scale_factor = 0.0 + l2n, l2g = self.l2[num_layer][n], self.l2[num_layer][g] + if not np.isclose(l2_diff:=(l2g - l2n), 0): + scale_factor = (l2n * l2g) / diffusion_const_n / l2_diff + _coefs.c.append( + sum( + src_matrix[i, n] * self.coefficients[num_layer][i].c[g] + for i in range(g, n) + ) + * scale_factor ) - * scale_factor_bz - ) - self.coefficients[n].bz_s.append( - sum( - src_bz[i, n] * self.coefficients[i].bz_s[g] - for i in range(g, n) + _coefs.s.append( + sum( + src_matrix[i, n] * self.coefficients[num_layer][i].s[g] + for i in range(g, n) + ) + * scale_factor ) - * scale_factor_bz - ) - fw_c_factor_guess = 0.0 - fw_s_factor_guess = 0.0 - bz_c_factor_guess = 0.0 - bz_s_factor_guess = 0.0 - self.coefficients[n].fw_c.append(fw_c_factor_guess) - self.coefficients[n].fw_s.append(fw_s_factor_guess) - self.coefficients[n].bz_c.append(bz_c_factor_guess) - self.coefficients[n].bz_s.append(bz_s_factor_guess) - - def _set_constants(input_vector: Iterable[float]): - self.coefficients[n].fw_c[n] = input_vector[0] - self.coefficients[n].fw_s[n] = input_vector[1] - self.coefficients[n].bz_c[n] = input_vector[2] - self.coefficients[n].bz_s[n] = input_vector[3] + c_factor_guess = 0.0 + s_factor_guess = 0.0 + _coefs.c.append(c_factor_guess) + _coefs.s.append(s_factor_guess) + self.coefficients[num_layer][n] = _coefs + + + def _set_coefficients(input_vector: Iterable[float]): + for num_layer in range(self.n_layers): + i = num_layer * 2 + self.coefficients[num_layer][n].c[n] = input_vector[i] + self.coefficients[num_layer][n].s[n] = input_vector[i+1] def _evaluate_fit(): - flux_continuity = self.groupwise_neutron_flux_fw( - n, self.x_fw - ) - self.groupwise_neutron_flux_bz(n, self.x_fw) - flux_at_boundary = self.groupwise_neutron_flux_bz( - n, self.extended_boundary[n] + # zero flux condition + flux_at_boundary = self.groupwise_neutron_flux_in_layer( + n, self.n_layers - 1, self.extended_boundary[n] ) - current_continuity = self.groupwise_neutron_current_fw( - n, self.x_fw - ) - self.groupwise_neutron_current_bz(n, self.x_fw) - influx_fw, influx_bz = 0.0, 0.0 + # conservation condition + influx, removal = 0.0, 0.0 for g in range(self.n_groups): if g > n and not first_iteration: - if not self.fw_mat.downscatter_only: - influx_fw += ( - self.fw_mat.sigma_s[g, n] - + self.fw_mat.sigma_in[g, n] - ) * self.groupwise_integrated_flux_fw(g) - if not self.bz_mat.downscatter_only: - influx_bz += ( - self.bz_mat.sigma_s[g, n] - + self.bz_mat.sigma_in[g, n] - ) * self.groupwise_integrated_flux_bz(g) + for num_layer, mat in self.materials: + if not mat.downscatter_only: + influx += (mat.sigma_s[g, n] + mat.sigma_in[g, n]) * self.groupwise_integrated_flux_in_layer(g, num_layer) elif g <= n: - influx_fw += ( - self.fw_mat.sigma_s[g, n] + self.fw_mat.sigma_in[g, n] - ) * self.groupwise_integrated_flux_fw(g) - influx_bz += ( - self.bz_mat.sigma_s[g, n] + self.bz_mat.sigma_in[g, n] - ) * self.groupwise_integrated_flux_bz(g) - removal_fw = self.fw_mat.sigma_t[ - n - ] * self.groupwise_integrated_flux_fw(n) - removal_bz = self.bz_mat.sigma_t[ - n - ] * self.groupwise_integrated_flux_bz(n) + for num_layer, mat in self.materials: + influx += (mat.sigma_s[g, n] + mat.sigma_in[g, n]) * self.groupwise_integrated_flux_in_layer(g, num_layer) + for num_layer, mat in self.materials: + removal += mat.sigma_t[n] * self.groupwise_integrated_flux_in_layer(n, num_layer) # conservation_fw = influx_fw - removal_fw - current_fw2bz # conservation_bz = current_fw2bz + influx_bz - removal_bz - escaped_bz - total_neutron_conservation = ( - influx_fw - + influx_bz - - removal_fw - - removal_bz - - self.groupwise_neutron_current_escaped(n) - ) - return np.array([ - flux_continuity, - flux_at_boundary, - current_continuity, - total_neutron_conservation, - ]) - - def objective(four_coefficients_vector): - _set_constants(four_coefficients_vector) + total_neutron_conservation = influx - removal - self.groupwise_neutron_current_escaped(n) + + conditions = [flux_at_boundary, total_neutron_conservation] + + # enforce continuity conditions + for num_layer in range(self.n_layers - 1): + x = self.interface_x[num_layer] + flux_continuity = self.groupwise_neutron_flux_in_layer(n, num_layer, x) - self.groupwise_neutron_flux_in_layer(n, num_layer + 1, x) + current_continuity = self.groupwise_neutron_current_in_layer(n, num_layer, x) - self.groupwise_neutron_current_in_layer(n, num_layer + 1, x) + conditions.append(flux_continuity) + conditions.append(current_continuity) + # TODO: there may be one more condition that I should impose: the slope at x=0 should be 0. + return np.array(conditions) + + def objective(coefficients_vector): + _set_coefficients(coefficients_vector) return _evaluate_fit() - results = optimize.root( - objective, - x0=[ - fw_c_factor_guess, - fw_s_factor_guess, - bz_c_factor_guess, - bz_s_factor_guess, - ], - ) - _set_constants(results.res) + x0 = np.flatten([[layer_coefs[n].c[n], layer_coefs[n].s[n]] for layer_coefs in self.coefficients]) + results = optimize.root(objective, x0=x0) + _set_coefficients(results.res) return None @summarize_values - def groupwise_neutron_flux_fw( - self, n: int, x: float | npt.NDArray + def groupwise_neutron_flux_in_layer( + self, n: int, num_layer: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron flux[m^-2 s^-1] of the n-th group at the first wall, at location x [m]. + Neutron flux[m^-2 s^-1] of the n-th group int h specified layer, + at location x [m]. Parameters ---------- n: - The index of the neutron group whose flux is being evaluated. n <= n_groups - 1. + The index of the neutron group whose flux is being evaluated. + n <= n_groups - 1. Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. + num_layer: + The index of the layer that we want to get the neutron flux for. x: The position where the neutron flux has to be evaluated. - Note that this function does not enforce a check for x=inside the first-wall, - thus if x is outside the first-wall, an extrapolated first-wall flux value up - to that point will be given, this flux is still guaranteed to be non-singular - i.e. finite, but not guaranteed to be positive. Returns ------- @@ -584,58 +541,16 @@ def groupwise_neutron_flux_fw( """ trig_funcs = [] for g in range(n + 1): - if self.l_fw_2[g] > 0: + if self.l2[num_layer][g] > 0: c, s = np.cosh, np.sinh - l_fw = np.sqrt(self.l_fw_2[g]) + l = np.sqrt(self.l2[num_layer][g]) else: c, s = np.cos, np.sin - l_fw = np.sqrt(-self.l_fw_2[g]) - trig_funcs.append( - self.coefficients[n].fw_c[g] * c(abs(x) / l_fw) - ) - trig_funcs.append( - self.coefficients[n].fw_s[g] * s(abs(x) / l_fw) - ) + l = np.sqrt(-self.l2[num_layer][g]) + trig_funcs.append(self.coefficients[num_layer][n].c[g] * c(abs(x) / l)) + trig_funcs.append(self.coefficients[num_layer][n].s[g] * s(abs(x) / l)) return np.sum(trig_funcs, axis=0) - @summarize_values - def groupwise_neutron_flux_bz( - self, n: int, x: float | npt.NDArray - ) -> npt.NDArray: - """Neutron flux[m^-2 s^-1] of the n-th groupat the blanket, at location x [m]. - - Parameters - ---------- - n: - The index of the neutron group whose flux is being evaluated. n <= n_groups - 1. - Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. - x: - The position where the neutron flux has to be evaluated. [m] - Note that this function does not enforce a check for x=inside the blanket, - thus if x is outside the blanket, an extrapolated blanket flux value up to - that point will be given, this flux is still guaranteed to be non-singular - i.e. finite, but not guaranteed to be positive. - - Returns - ------- - flux: - Neutron flux at x meter from the first wall. - """ - trig_funcs = [] - for g in range(n + 1): - if self.l_bz_2[g] > 0: - c, s = np.cosh, np.sinh - l_bz = np.sqrt(self.l_bz_2[g]) - else: - c, s = np.cos, np.sin - l_bz = np.sqrt(-self.l_bz_2[g]) - trig_funcs.append( - self.coefficients[n].bz_c[g] * c(abs(x) / l_bz) - ) - trig_funcs.append( - self.coefficients[n].bz_s[g] * s(abs(x) / l_bz) - ) - return np.sum(trig_funcs, axis=0) @summarize_values def groupwise_neutron_flux_at( @@ -662,171 +577,120 @@ def groupwise_neutron_flux_at( if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] x = np.asarray(x) - in_fw = abs(x) <= self.x_fw - in_bz = np.logical_and( - self.x_fw < abs(x), - abs(x) <= self.extended_boundary[n], - ) - if (~np.logical_or(in_fw, in_bz)).any(): + if not all(-self.extended_boundary[n]<=x<=self.extended_boundary[n]): raise ValueError( f"for neutron group {n}, neutron flux can only be calculated " f"up to {self.extended_boundary[n]} m, which {x} m violates!" ) out_flux = np.zeros_like(x) - out_flux[in_fw] = self.groupwise_neutron_flux_fw(n, x[in_fw]) - out_flux[in_bz] = self.groupwise_neutron_flux_bz(n, x[in_bz]) + abs_x = abs(x) + extended_interface_x = [0, *self.interface_x] + extended_interface_x[-1] = np.nextafter(self.extended_boundary[n], np.inf) + for num_layer, (lower_x, upper_x) in enumerate(pairwise(extended_interface_x)): + in_layer = lower_x <= abs_x < upper_x + if in_layer.any(): + out_flux[in_layer] = self.groupwise_neutron_flux_in_layer( + n, num_layer, x[in_layer] + ) return out_flux # scalar values (one such float per neutron group.) @summarize_values - def groupwise_integrated_flux_fw(self, n: int) -> float: + def groupwise_integrated_flux_in_layer( + self, n: int, num_layer: int + ) -> float: """ Calculate the integrated flux[m^-1 s^-1], which can be mulitplied to any macroscopic cross-section [m^-1] to get the reaction rate [s^-1] in - the first wall. + any layer specified. Parameters ---------- n: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. + num_layer: + The index of the layer that we want to get the neutron flux for. """ integrals = [] + # set integration limits + x_start = self.interface_x[num_layer-1] + if num_layer==0: + x_start = 0.0 + x_end = self.interface_x[num_layer] + for g in range(n + 1): - if self.l_fw_2[g] > 0: - l_fw = np.sqrt(self.l_fw_2[g]) + l2g = self.l2[num_layer][g] + if l2g > 0: + l = np.sqrt(l2g) integrals.append( - l_fw - * self.coefficients[n].fw_c[g] - * np.sinh(self.x_fw / l_fw) + l * self.coefficients[num_layer][n].c[g] + * (np.sinh(x_end / l) - np.sinh(x_start / l)) ) integrals.append( - l_fw - * self.coefficients[n].fw_s[g] - * (np.cosh(self.x_fw / l_fw) - 1) + l * self.coefficients[num_layer][n].s[g] + * (np.cosh(x_end / l) - np.cosh(x_start / l)) ) else: - l_fw = np.sqrt(-self.l_fw_2[g]) + l = np.sqrt(-l2g) integrals.append( - l_fw - * self.coefficients[n].fw_c[g] - * np.sin(self.x_fw / l_fw) + l * self.coefficients[num_layer][n].c[g] + * (np.sin(x_end / l) - np.sin(x_start / l)) ) integrals.append( - l_fw - * self.coefficients[n].fw_s[g] - * (1 - np.cos(self.x_fw / l_fw)) + -l * self.coefficients[num_layer][n].s[g] + * (np.cos(x_end / l) - np.cos(x_start / l)) ) - return np.sum(integrals, axis=0) + @summarize_values - def groupwise_integrated_flux_bz(self, n: int) -> float: + def groupwise_neutron_current_in_layer( + self, n: int, num_layer: int, x: float | npt.NDArray + ) -> float: """ - Calculate the integrated flux[m^-1 s^-1], which can be mulitplied to any - macroscopic cross-section [m^-1] to get the reaction rate [s^-1] in - the blanket. + Get the neutron current (right=positive, left=negative) in any layer. Parameters ---------- n: The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. + num_layer: + The index of the layer that we want to get the neutron flux for. + x: + The depth where we want the neutron flux [m]. + Valid only between x= -extended boundary to +-extended boundary of that group """ - integrals = [] - for g in range(n + 1): - if self.l_bz_2[g] > 0: - l_bz = np.sqrt(self.l_bz_2[g]) - integrals.append( - l_bz - * self.coefficients[n].bz_c[g] - * (np.sinh(self.x_bz / l_bz) - np.sinh(self.x_fw / l_bz)) - ) - integrals.append( - l_bz - * self.coefficients[n].bz_s[g] - * (np.cosh(self.x_bz / l_bz) - np.cosh(self.x_fw / l_bz)) - ) - else: - l_bz = np.sqrt(-self.l_bz_2[g]) - integrals.append( - l_bz - * self.coefficients[n].bz_c[g] - * (np.sin(self.x_bz / l_bz) - np.sin(self.x_fw / l_bz)) - ) - integrals.append( - -l_bz - * self.coefficients[n].bz_s[g] - * (np.cos(self.x_bz / l_bz) - np.cos(self.x_fw / l_bz)) - ) - return np.sum(integrals, axis=0) - - @summarize_values - def groupwise_neutron_current_fw( - self, n: int, x: float | npt.NDArray - ) -> float: - """Get the neutron current (in the outward direction) in the fw""" - differentials = [] - for g in range(n + 1): - if self.l_fw_2[g] > 0: - l_fw = np.sqrt(self.l_fw_2[g]) - differentials.append( - self.coefficients[n].fw_c[g] - / l_fw - * np.sinh(x / l_fw) - ) - differentials.append( - self.coefficients[n].fw_s[g] - / l_fw - * np.cosh(x / l_fw) - ) - else: - l_fw = np.sqrt(-self.l_fw_2[g]) - differentials.append( - -self.coefficients[n].fw_c[g] - / l_fw - * np.sin(x / l_fw) - ) - differentials.append( - self.coefficients[n].fw_s[g] - / l_fw - * np.cos(x / l_fw) - ) - return -self.d_fw[n] * np.sum(differentials, axis=0) - - @summarize_values - def groupwise_neutron_current_bz( - self, n: int, x: float | npt.NDArray - ) -> float: - """Get the neutron current (in the outward direction) in the bz.""" differentials = [] for g in range(n + 1): - if self.l_bz_2[g] > 0: - l_bz = np.sqrt(self.l_bz_2[g]) + l2g = self.l2[num_layer][g] + if l2g > 0: + l = np.sqrt(l2g) differentials.append( - self.coefficients[n].bz_c[g] - / l_bz - * np.sinh(x / l_bz) + self.coefficients[num_layer][n].c[g] + / l + * np.sinh(abs(x) / l) ) differentials.append( - self.coefficients[n].bz_s[g] - / l_bz - * np.cosh(x / l_bz) + self.coefficients[num_layer][n].s[g] + / l + * np.cosh(abs(x) / l) ) else: - l_bz = np.sqrt(-self.l_bz_2[g]) + l = np.sqrt(-l2g) differentials.append( - -self.coefficients[n].bz_c[g] - / l_bz - * np.sin(x / l_bz) + -self.coefficients[num_layer][n].c[g] + / l + * np.sin(abs(x) / l) ) differentials.append( - self.coefficients[n].bz_s[g] - / l_bz - * np.cos(x / l_bz) + self.coefficients[num_layer][n].s[g] + / l + * np.cos(abs(x) / l) ) - return -self.d_bz[n] * np.sum(differentials, axis=0) + return -self.diffusion_const[num_layer][n] * np.sum(differentials, axis=0) * np.sign(x) @summarize_values def groupwise_neutron_current_at( @@ -853,21 +717,23 @@ def groupwise_neutron_current_at( if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] x = np.asarray(x) - in_fw = abs(x) <= self.x_fw - in_bz = np.logical_and( - self.x_fw < abs(x), - abs(x) <= self.x_bz, - ) - if (~np.logical_or(in_fw, in_bz)).any(): + if not all(-self.extended_boundary[n]<=x<=self.extended_boundary[n]): raise ValueError( - f"for neutron group {n}, neutron flux can only be calculated " - f"up to {self.x_bz} m, which {x} m violates!" + f"for neutron group {n}, neutron current can only be calculated" + f" up to {self.extended_boundary[n]} m, which {x} m violates!" ) - out_current = np.zeros_like(x) - out_current[in_fw] = self.groupwise_neutron_current_fw(n, x[in_fw]) - out_current[in_bz] = self.groupwise_neutron_current_bz(n, x[in_bz]) - return out_current + current = np.zeros_like(x) + abs_x = abs(x) + extended_interface_x = [0, *self.interface_x] + extended_interface_x[-1] = np.nextafter(self.extended_boundary[n], np.inf) + for num_layer, (lower_x, upper_x) in enumerate(pairwise(extended_interface_x)): + in_layer = lower_x <= abs_x < upper_x + if in_layer.any(): + current[in_layer] = self.groupwise_neutron_current_in_layer( + n, num_layer, x[in_layer] + ) + return current @summarize_values def groupwise_neutron_current_fw2bz(self, n: int) -> float: @@ -903,12 +769,13 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: """ return self.groupwise_neutron_current_bz(n, self.x_bz) - def plot( + def plot_flux( self, ax: plt.Axes | None = None, n_points: int = 100, symmetric: bool = True, plot_groups: bool = True, + quantity: str = "flux", ): """ Make a rough plot of the neutron flux. @@ -924,6 +791,8 @@ def plot( plot_groups: Whether to plot each individual group's neutron flux. If True, a legend will be added to help label the groups. + quantity: + Options of plotting which quantity: {"flux", "current"}. """ self.solve_group_n(self.n_groups - 1) ax = ax or plt.axes() @@ -989,7 +858,6 @@ def plot( ax.set_ylabel("Neutron flux [m^-2 s^-1]") return ax - def _generate_x_range( x_max: float, approx_n_points: int, From fa6d26667f542bc8bd5daf2920ff58b95801f653 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 17:06:03 +0000 Subject: [PATCH 69/98] Neutron flux and current are defined such that they're assumed to be unperturbed once the neutrons exit the final layer. I.e. the neutron flux and current at infinity == the neutron flux and current at the interface between the final layer and the void. --- process/neutronics.py | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index dc27fd795a..9ce5d6fafb 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -557,8 +557,8 @@ def groupwise_neutron_flux_at( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron flux [m^-2 s^-1] anywhere within the valid range of x, - i.e. [-self.extended_boundary[n], self.extended_boundary[n]]. + Neutron flux [m^-2 s^-1] anywhere. Neutron flux is assumed to be + unperturbed once it leaves the final layer. Parameters ---------- @@ -576,18 +576,13 @@ def groupwise_neutron_flux_at( """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.asarray(x) - if not all(-self.extended_boundary[n]<=x<=self.extended_boundary[n]): - raise ValueError( - f"for neutron group {n}, neutron flux can only be calculated " - f"up to {self.extended_boundary[n]} m, which {x} m violates!" - ) + x = np.clip(np.asarray(x), -self.interface_x[-1], self.interface_x[-1]) out_flux = np.zeros_like(x) abs_x = abs(x) - extended_interface_x = [0, *self.interface_x] - extended_interface_x[-1] = np.nextafter(self.extended_boundary[n], np.inf) - for num_layer, (lower_x, upper_x) in enumerate(pairwise(extended_interface_x)): + x_cutoffs = [0, *self.interface_x] + x_cutoffs[-1] = np.nextafter(x_cutoffs[-1], np.inf) + for num_layer, (lower_x, upper_x) in enumerate(pairwise(x_cutoffs)): in_layer = lower_x <= abs_x < upper_x if in_layer.any(): out_flux[in_layer] = self.groupwise_neutron_flux_in_layer( @@ -697,8 +692,8 @@ def groupwise_neutron_current_at( self, n: int, x: float | npt.NDArray ) -> npt.NDArray: """ - Neutron current [m^-2 s^-1] anywhere within the valid range of x, - i.e. from -self.x_bz to self.x_bz. + Neutron current [m^-2 s^-1]. Neutron current is assumed to be + unperturbed once it leaves the final layer. Parameters ---------- @@ -716,18 +711,13 @@ def groupwise_neutron_current_at( """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.asarray(x) - if not all(-self.extended_boundary[n]<=x<=self.extended_boundary[n]): - raise ValueError( - f"for neutron group {n}, neutron current can only be calculated" - f" up to {self.extended_boundary[n]} m, which {x} m violates!" - ) + x = np.clip(np.asarray(x), -self.interface_x[-1], self.interface_x[-1]) current = np.zeros_like(x) abs_x = abs(x) - extended_interface_x = [0, *self.interface_x] - extended_interface_x[-1] = np.nextafter(self.extended_boundary[n], np.inf) - for num_layer, (lower_x, upper_x) in enumerate(pairwise(extended_interface_x)): + x_cutoffs = [0, *self.interface_x] + x_cutoffs[-1] = np.nextafter(x_cutoffs[-1], np.inf) + for num_layer, (lower_x, upper_x) in enumerate(pairwise(x_cutoffs)): in_layer = lower_x <= abs_x < upper_x if in_layer.any(): current[in_layer] = self.groupwise_neutron_current_in_layer( @@ -798,7 +788,7 @@ def plot_flux( ax = ax or plt.axes() x_bz_left, x_fw, x_bz_right = _generate_x_range( - min(self.extended_boundary.values()), + max(self.extended_boundary.values()), n_points, symmetric, self.x_fw, @@ -870,8 +860,6 @@ def _generate_x_range( ---------- x_max: absolute value of the maximum x that we want to plot. - This is typically obtained by min(extended_boundary), or - extended_boundary[n] [m] symmetric: Whether we want to plot the negative side of the x-axis as well, forming a symmetric plot. From 715b379ec41dcfc4cea2c2177f34a2080b6b4fe9 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 18:08:57 +0000 Subject: [PATCH 70/98] Updated docstring on Coefficients (now gives the correct use case) and populated the docstring of NeutronFluxProfile. --- process/neutronics.py | 119 ++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 51 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 9ce5d6fafb..ad2a1e4067 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -137,10 +137,15 @@ class Coefficients: group n=1 has cosh(x/L[0]), sinh(x/L[0]), cosh(x/L[1]) and sinh(x/L[1]), etc. To get the neutron flux, each trig func has to be scaled by a coeffient. - E.g. - group n=0: fw: fw_c[0][0] * cosh(x/L[0]) + fw_s[0][0] * sinh(x/L[0]) - group n=1: fw: fw_c[1][0] * cosh(x/L[0]) + fw_c[1][1] * cosh(x/L[1]) - + fw_s[1][0] * sinh(x/L[0]) + fw_s[1][1] * sinh(x/L[1]) + E.g. Let's say for the first wall, which is num_layer=0, + group n=0: NeutronFluxProfile.coefficients[0][0] = Coefficients(...) + fw_grp0 = NeutronFluxProfile.coefficients[0][0] + flux = fw_grp0.c[0] * cosh(x/L[0]) + fw_grp0.s[0] * sinh(x/L[0]) + + group n=1: NeutronFluxProfile.coefficients[0][1] = Coefficients(...) + fw_grp1 = NeutronFluxProfile.coefficients[0][1] + flux = fw_grp1.c[0] * cosh(x/L[0]) + fw_grp1.c[1] * cosh(x/L[1]) + + fw_grp1.s[0] * sinh(x/L[0]) + fw_grp1.s[1] * sinh(x/L[1]) """ @@ -219,12 +224,18 @@ def __repr__(self): class NeutronFluxProfile: - """Neutron flux in the first wall or the blanket.""" + """ + Calculate the neutron flux, neutron current, and neutron heating in the + mirrored infinite-slab model, where each layer extend infinitely in y- and + z-directions, but has finite width in the x-direction. Each layer's + thickness is defined along the positive x-axis starting at 0, and then + reflected along x=0 to fill out the negative x-axis. + """ def __init__( self, flux: float, - interface_x: npt.NDArray[np.float64], + layer_x: npt.NDArray[np.float64], materials: Iterable[MaterialMacroInfo], ): """Initialize a particular FW-BZ geometry and neutron flux. @@ -234,19 +245,24 @@ def __init__( flux: Nuetron flux directly emitted by the plasma, incident on the first wall. unit: m^-2 s^-1 - interface_x: - The x-coordinates of every interface between layers. For n_layers, - there will be n_layers - 1 interfaces between layers, plus the - interface between the final layer and the void into which neutrons - are lost. - E.g. interface_x[0] is the thickness of the first wall, - interface_x[1] is the thickness of the first wall + breeding zone, + layer_x: + The x-coordinates of the right side of every layers. By definition, + the plasma is situated at x=0, so all values in layer_x must be >0. + E.g. layer_x[0] is the thickness of the first wall, + layer_x[1] is the thickness of the first wall + breeding zone, etc. materials: Every layer's material information. Attributes ---------- + interface_x: + The x-coordinates of every plasma-layer interfaces/ layer-layer + interface/ layer-void interface. For n_layers, + there will be the interface between the first layer and the plasma, + plus (n_layers - 1) interfaces between layers, plus the interface + between the final layer and the void into which neutrons are lost. + E.g. interface_x[0] = 0.0 = the plasma-fw interface. n_layers: Number of layers n_groups: @@ -265,23 +281,27 @@ def __init__( Diffusion coefficient of each layer. unit: [m] extended_boundary: Extended boundary for each group. These values should be larger - than interface_x[-1]. + than layer_x[-1]. """ # flux incident on the first wall at the highest energy. self.flux = flux # layers - self.interface_x = np.array(interface_x).ravel() - if not (np.diff(self.interface_x)>0).all(): + self.layer_x = np.array(layer_x).ravel() + if not (np.diff(self.layer_x)>0).all(): raise ValueError( f"Model cannot have non-positive layer thicknesses." ) + + self.layer_x.flag.writeable = False + self.interface_x = np.array([0.0, *self.layer_x]) self.interface_x.flag.writeable = False + self.materials = tuple(materials) - if len(self.interface_x) != len(self.materials): + if len(self.layer_x) != len(self.materials): raise ProcessValidationError( "The number of layers specified by self.materials must match " - "the number of x-positions specified by interface_x." + "the number of x-positions specified by layer_x." ) self.n_layers = len(self.materials) @@ -335,12 +355,12 @@ def solve_lowest_group(self) -> None: mat.sigma_s[n, n], mat.sigma_in[n, n], ) - self.extended_boundary[n] = self.interface_x[-1] + extrapolation_length( + self.extended_boundary[n] = self.layer_x[-1] + extrapolation_length( self.diffusion_const[-1][n] ) if self.n_layers == 2: l_fw, l_bz = np.sqrt(abs(self.l2[0][n])), np.sqrt(abs(self.l2[1][n])) - x_fw, = self.interface_x[:-1] + x_fw, = self.layer_x[:-1] d_fw, d_bz = self.diffusion_const[0][n], self.diffusion_const[1][n] if self.l2[0][n] > 0: s_fw = np.sinh(x_fw / l_fw) @@ -425,7 +445,7 @@ def solve_group_n(self, n: int) -> None: mat.sigma_s[n, n], mat.sigma_in[n, n], ) - self.extended_boundary[n] = self.interface_x[-1] + extrapolation_length( + self.extended_boundary[n] = self.layer_x[-1] + extrapolation_length( self.diffusion_const[-1][n] ) @@ -498,7 +518,7 @@ def _evaluate_fit(): # enforce continuity conditions for num_layer in range(self.n_layers - 1): - x = self.interface_x[num_layer] + x = self.layer_x[num_layer] flux_continuity = self.groupwise_neutron_flux_in_layer(n, num_layer, x) - self.groupwise_neutron_flux_in_layer(n, num_layer + 1, x) current_continuity = self.groupwise_neutron_current_in_layer(n, num_layer, x) - self.groupwise_neutron_current_in_layer(n, num_layer + 1, x) conditions.append(flux_continuity) @@ -566,24 +586,19 @@ def groupwise_neutron_flux_at( Neutron group index. n <= n_groups - 1. Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. x: - The depth where we want the neutron flux [m]. - Valid only between x= -extended boundary to +-extended boundary of that group - - Raises - ------ - ValueError - The inputted x + The depth where we want the neutron flux [m]. Out-of-bounds x would + be clipped back to bound. """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.clip(np.asarray(x), -self.interface_x[-1], self.interface_x[-1]) + x = np.clip(np.asarray(x), -self.layer_x[-1], self.layer_x[-1]) out_flux = np.zeros_like(x) abs_x = abs(x) - x_cutoffs = [0, *self.interface_x] - x_cutoffs[-1] = np.nextafter(x_cutoffs[-1], np.inf) - for num_layer, (lower_x, upper_x) in enumerate(pairwise(x_cutoffs)): + for num_layer, (xmin, xmax) in enumerate(pairwise(self.interface_x)): in_layer = lower_x <= abs_x < upper_x + if num_layer==(self.n_layers-1): + in_layer = lower_x <= abs_x <= upper_x if in_layer.any(): out_flux[in_layer] = self.groupwise_neutron_flux_in_layer( n, num_layer, x[in_layer] @@ -610,10 +625,10 @@ def groupwise_integrated_flux_in_layer( """ integrals = [] # set integration limits - x_start = self.interface_x[num_layer-1] + x_start = self.layer_x[num_layer-1] if num_layer==0: x_start = 0.0 - x_end = self.interface_x[num_layer] + x_end = self.layer_x[num_layer] for g in range(n + 1): l2g = self.l2[num_layer][g] @@ -656,7 +671,6 @@ def groupwise_neutron_current_in_layer( The index of the layer that we want to get the neutron flux for. x: The depth where we want the neutron flux [m]. - Valid only between x= -extended boundary to +-extended boundary of that group """ differentials = [] for g in range(n + 1): @@ -701,24 +715,19 @@ def groupwise_neutron_current_at( Neutron group index. n <= n_groups - 1. Therefore n=0 shows the neutron current for group 1, n=1 for group 2, etc. x: - The depth where we want the neutron flux [m]. - Valid only between x= -extended boundary to +-extended boundary of that group - - Raises - ------ - ValueError - The inputted x + The depth where we want the neutron current [m]. Out-of-bounds x + would be clipped back to bound. """ if np.isscalar(x): return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.clip(np.asarray(x), -self.interface_x[-1], self.interface_x[-1]) + x = np.clip(np.asarray(x), -self.layer_x[-1], self.layer_x[-1]) current = np.zeros_like(x) abs_x = abs(x) - x_cutoffs = [0, *self.interface_x] - x_cutoffs[-1] = np.nextafter(x_cutoffs[-1], np.inf) - for num_layer, (lower_x, upper_x) in enumerate(pairwise(x_cutoffs)): + for num_layer, (xmin, xmax) in enumerate(pairwise(self.interface_x)): in_layer = lower_x <= abs_x < upper_x + if num_layer==(self.n_layers-1): + in_layer = lower_x <= abs_x <= upper_x if in_layer.any(): current[in_layer] = self.groupwise_neutron_current_in_layer( n, num_layer, x[in_layer] @@ -726,21 +735,29 @@ def groupwise_neutron_current_at( return current @summarize_values - def groupwise_neutron_current_fw2bz(self, n: int) -> float: + def groupwise_neutron_current_through_interface(self, n: int, n_interface: int, calculate_by_inner_layer : bool=True) -> float: """ - Net current from the first wall to breeding zone. + Net current from left to right on the positive side of the model, at + the specified interface number. + Parameters ---------- n: The index of the neutron group that we want the current for. n <= n_groups - 1. Therefore n=0 shows the neutron current for group 1, n=1 for group 2, etc. + n_interface: + The index of the interface that we want the net neutron current + through for. Returns ------- : current in m^-2 """ - return self.groupwise_neutron_current_bz(n, self.x_fw) + if calculate_by_inner_layer: + return self.groupwise_neutron_current_in_layer(n, n_interface, self.interface_x[n_interface]) + else: + return self.groupwise_neutron_current_in_layer(n, n_interface, self.interface_x[n_interface]) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -757,7 +774,7 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: : current in m^-2 """ - return self.groupwise_neutron_current_bz(n, self.x_bz) + return self.groupwise_neutron_current_through_interface(n, self.n_layers, True) def plot_flux( self, From 57e83d50e0db08a895a0b5faeb6039710a21c832 Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 18:29:47 +0000 Subject: [PATCH 71/98] Fixed the various off-by-one errors deliberately introduced a couple of commits ago (because I was in a hurry) in groupwise_neutron_current_through_interface --- process/neutronics.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index ad2a1e4067..468f36cf04 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -735,7 +735,7 @@ def groupwise_neutron_current_at( return current @summarize_values - def groupwise_neutron_current_through_interface(self, n: int, n_interface: int, calculate_by_inner_layer : bool=True) -> float: + def groupwise_neutron_current_through_interface(self, n: int, n_interface: int, default_to_inner_layer : bool=True) -> float: """ Net current from left to right on the positive side of the model, at the specified interface number. @@ -748,16 +748,27 @@ def groupwise_neutron_current_through_interface(self, n: int, n_interface: int, n_interface: The index of the interface that we want the net neutron current through for. + E.g. for n_interface=0, that would be getting the current at the + plasma-fw interface. For n_interface=n_layers, that would be + getting the neutron current leaking from the final layer into the void. Returns ------- : current in m^-2 """ - if calculate_by_inner_layer: - return self.groupwise_neutron_current_in_layer(n, n_interface, self.interface_x[n_interface]) + x = self.interface_x[n_interface] + + if default_to_inner_layer: + if n_interface==0: + return self.groupwise_neutron_current_in_layer(n, 0, x) + return self.groupwise_neutron_current_in_layer(n, n_interface-1, x) else: - return self.groupwise_neutron_current_in_layer(n, n_interface, self.interface_x[n_interface]) + if n_interface==self.n_layers: + return self.groupwise_neutron_current_in_layer( + n, self.n_layers-1, x + ) + return self.groupwise_neutron_current_in_layer(n, n_interface, x) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -774,9 +785,9 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: : current in m^-2 """ - return self.groupwise_neutron_current_through_interface(n, self.n_layers, True) + return self.groupwise_neutron_current_through_interface(n, self.n_layers) - def plot_flux( + def plot( self, ax: plt.Axes | None = None, n_points: int = 100, From 202efba124fc3f0e62ca93a2cf16e86e67057b0c Mon Sep 17 00:00:00 2001 From: ocean Date: Fri, 21 Nov 2025 19:04:15 +0000 Subject: [PATCH 72/98] Completed conversion from 2-layer model to infinite-layer model. Cleanup successful: unit test and regression test (1-group regression test case only) passed. Only the plotting function remains to be fixed for this conversion to infinite-layer model. --- process/neutronics.py | 20 +++++++++------- tests/regression/test_neutronics.py | 36 ++++++++++++++--------------- tests/unit/test_neutronics.py | 25 ++++++++++---------- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 468f36cf04..fb28749c27 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -293,9 +293,9 @@ def __init__( f"Model cannot have non-positive layer thicknesses." ) - self.layer_x.flag.writeable = False + self.layer_x.flags.writeable = False self.interface_x = np.array([0.0, *self.layer_x]) - self.interface_x.flag.writeable = False + self.interface_x.flags.writeable = False self.materials = tuple(materials) if len(self.layer_x) != len(self.materials): @@ -596,9 +596,9 @@ def groupwise_neutron_flux_at( out_flux = np.zeros_like(x) abs_x = abs(x) for num_layer, (xmin, xmax) in enumerate(pairwise(self.interface_x)): - in_layer = lower_x <= abs_x < upper_x + in_layer = xmin <= abs_x < xmax if num_layer==(self.n_layers-1): - in_layer = lower_x <= abs_x <= upper_x + in_layer = xmin <= abs_x <= xmax if in_layer.any(): out_flux[in_layer] = self.groupwise_neutron_flux_in_layer( n, num_layer, x[in_layer] @@ -725,9 +725,9 @@ def groupwise_neutron_current_at( current = np.zeros_like(x) abs_x = abs(x) for num_layer, (xmin, xmax) in enumerate(pairwise(self.interface_x)): - in_layer = lower_x <= abs_x < upper_x + in_layer = xmin <= abs_x < xmax if num_layer==(self.n_layers-1): - in_layer = lower_x <= abs_x <= upper_x + in_layer = xmin <= abs_x <= xmax if in_layer.any(): current[in_layer] = self.groupwise_neutron_current_in_layer( n, num_layer, x[in_layer] @@ -735,7 +735,9 @@ def groupwise_neutron_current_at( return current @summarize_values - def groupwise_neutron_current_through_interface(self, n: int, n_interface: int, default_to_inner_layer : bool=True) -> float: + def groupwise_neutron_current_through_interface( + self, n: int, n_interface: int, default_to_inner_layer : bool=True + ) -> float: """ Net current from left to right on the positive side of the model, at the specified interface number. @@ -785,7 +787,9 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: : current in m^-2 """ - return self.groupwise_neutron_current_through_interface(n, self.n_layers) + return self.groupwise_neutron_current_through_interface( + n, self.n_layers + ) def plot( self, diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index ba13b2deee..d29d38ab94 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -32,20 +32,20 @@ def test_one_group(): x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 neutron_profile = NeutronFluxProfile( - incoming_flux, x_fw, x_bz, fw_material, bz_material + incoming_flux, [x_fw, x_bz], [fw_material, bz_material] ) - const = neutron_profile.coefficients[0] # alias to fit line width - assert np.isclose(const.fw_c[0], 80.5346770788), "c5" - assert np.isclose(const.fw_s[0], -76.5562120985), "c6" - assert np.isclose(const.bz_c[0], 60.6871656017), "c7" - assert np.isclose(const.bz_s[0], -60.7123696772), "c8" + const = neutron_profile.coefficients # alias to fit line width + assert np.isclose(const[0][0].c[0], 80.5346770788), "c5" + assert np.isclose(const[0][0].s[0], -76.5562120985), "c6" + assert np.isclose(const[1][0].c[0], 60.6871656017), "c7" + assert np.isclose(const[1][0].s[0], -60.7123696772), "c8" - assert np.isclose(neutron_profile.neutron_flux_fw(x_fw), 48.72444) - assert np.isclose(neutron_profile.neutron_flux_bz(x_fw), 48.72444) + assert np.isclose(neutron_profile.neutron_flux_in_layer(0, x_fw), 48.72444) + assert np.isclose(neutron_profile.neutron_flux_in_layer(1, x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_at(x_fw), 48.72444) - assert np.isclose(neutron_profile.neutron_current_fw2bz(), 22.3980214162) + assert np.isclose(neutron_profile.neutron_current_through_interface(1), 22.3980214162) assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] @@ -53,8 +53,8 @@ def test_one_group(): assert np.isclose( neutron_profile.flux, neutron_profile.neutron_current_escaped() - + fw_removal * neutron_profile.integrated_flux_fw() - + bz_removal * neutron_profile.integrated_flux_bz(), + + fw_removal * neutron_profile.integrated_flux_in_layer(0) + + bz_removal * neutron_profile.integrated_flux_in_layer(1), ), "Conservation of neutrons" @@ -89,9 +89,9 @@ def test_one_group_with_fission(): x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 neutron_profile = NeutronFluxProfile( - incoming_flux, x_fw, x_bz, fw_material, bz_material + incoming_flux, [x_fw, x_bz], [fw_material, bz_material], ) - assert np.isclose(neutron_profile.l_bz_2[0], -((58.2869567709 / 100) ** 2)) + assert np.isclose(neutron_profile.l2[1][0], -((58.2869567709 / 100) ** 2)) assert np.isclose( neutron_profile.neutron_flux_at(-4.79675 / 100), 159.9434 ), "Minimum flux in FW" @@ -105,11 +105,11 @@ def test_one_group_with_fission(): neutron_profile.neutron_flux_at(-18.96382 / 100), 164.81245 ), "Maximum flux in BZ" assert np.isclose( - neutron_profile.neutron_flux_fw(x_fw), - neutron_profile.neutron_flux_bz(x_fw), + neutron_profile.neutron_flux_in_layer(0, x_fw), + neutron_profile.neutron_flux_in_layer(1, x_fw), ), "Flux continuity assurance" assert np.isclose( - neutron_profile.neutron_current_fw2bz(), -7.6275782637960745 + neutron_profile.neutron_current_through_interface(1), -7.6275782637960745 ), "Negative current because BZ (breeding) is backflowing into the FW" assert np.isclose( neutron_profile.neutron_current_escaped(), 30.665951670177186 @@ -119,8 +119,8 @@ def test_one_group_with_fission(): assert np.isclose( neutron_profile.flux, neutron_profile.neutron_current_escaped() - + fw_removal * neutron_profile.integrated_flux_fw() - + bz_removal * neutron_profile.integrated_flux_bz(), + + fw_removal * neutron_profile.integrated_flux_in_layer(0) + + bz_removal * neutron_profile.integrated_flux_in_layer(1), ), "Conservation of neutrons" diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 6c4cbf14d0..76e01c1923 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -59,36 +59,35 @@ def test_has_local_fluxes(): """Test that the groupwise decorator has worked on the local fluxes methods.""" assert hasattr(NeutronFluxProfile, "neutron_flux_at") assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_at") - assert hasattr(NeutronFluxProfile, "neutron_flux_fw") - assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_fw") - assert hasattr(NeutronFluxProfile, "neutron_flux_bz") - assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_bz") + assert hasattr(NeutronFluxProfile, "neutron_flux_in_layer") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_flux_in_layer") def test_has_boundary_current(): """Test that the groupwise decorator has worked on the boundary fluxes methods.""" - assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_fw2bz") - assert hasattr(NeutronFluxProfile, "neutron_current_fw2bz") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_through_interface") + assert hasattr(NeutronFluxProfile, "neutron_current_through_interface") assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_escaped") assert hasattr(NeutronFluxProfile, "neutron_current_escaped") def test_has_reactions(): """Test that the groupwise decorator has worked on the reactions methods.""" - assert hasattr(NeutronFluxProfile, "groupwise_integrated_flux_fw") - assert hasattr(NeutronFluxProfile, "integrated_flux_fw") - assert hasattr(NeutronFluxProfile, "groupwise_integrated_flux_bz") - assert hasattr(NeutronFluxProfile, "integrated_flux_bz") + assert hasattr(NeutronFluxProfile, "groupwise_integrated_flux_in_layer") + assert hasattr(NeutronFluxProfile, "integrated_flux_in_layer") +def test_has_plot(): + assert hasattr(NeutronFluxProfile, "plot") + def test_three_group(): # 1. No negative flux dummy = [10000, 1000, 100, 1] # fw_mat = MaterialMacroInfo() bz_mat = MaterialMacroInfo - # 2. same L_1 and L_3 shoudl yield coefficients[2].fw_c[0] and - # coefficients[2].fw_s[0] = 0.0 - # self.l_fw_2 == self.l_fw_2[n] case. + # 2. same L_1 and L_3 shoudl yield coefficients[0][2].c[0] and + # coefficients[0][2].s[0] = 0.0 + # self.l2[0][n] == self.l2[1][n] case. # From 85371d22139e01ef27c9b447a5d93e3d32c3ae56 Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 22 Nov 2025 01:35:12 +0000 Subject: [PATCH 73/98] Added new class LayerSpecificGroupwiseConstants to encapsulate the behaviour of (NeutronFluxProfile.coefficients, NeutronFluxProfile.l2, NeutronFluxProfile.diffusion_const) --- process/neutronics.py | 203 +++++++++++++++++++--------- tests/regression/test_neutronics.py | 10 +- tests/unit/test_neutronics.py | 19 ++- 3 files changed, 165 insertions(+), 67 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index fb28749c27..15570ad6a7 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -136,14 +136,14 @@ class Coefficients: group n=0 has cosh(x/L[0]) and sinh(x/L[0]), group n=1 has cosh(x/L[0]), sinh(x/L[0]), cosh(x/L[1]) and sinh(x/L[1]), etc. - To get the neutron flux, each trig func has to be scaled by a coeffient. + To get the neutron flux, each trig func has to be scaled by a coefficient. E.g. Let's say for the first wall, which is num_layer=0, - group n=0: NeutronFluxProfile.coefficients[0][0] = Coefficients(...) - fw_grp0 = NeutronFluxProfile.coefficients[0][0] + group n=0: NeutronFluxProfile.coefficients[0, 0] = Coefficients(...) + fw_grp0 = NeutronFluxProfile.coefficients[0, 0] flux = fw_grp0.c[0] * cosh(x/L[0]) + fw_grp0.s[0] * sinh(x/L[0]) - group n=1: NeutronFluxProfile.coefficients[0][1] = Coefficients(...) - fw_grp1 = NeutronFluxProfile.coefficients[0][1] + group n=1: NeutronFluxProfile.coefficients[0, 1] = Coefficients(...) + fw_grp1 = NeutronFluxProfile.coefficients[0, 1] flux = fw_grp1.c[0] * cosh(x/L[0]) + fw_grp1.c[1] * cosh(x/L[1]) + fw_grp1.s[0] * sinh(x/L[0]) + fw_grp1.s[1] * sinh(x/L[1]) @@ -222,6 +222,93 @@ def values(self): def __repr__(self): return f"AutoPopulatingDict({self.name}):{self._dict}" +class LayerSpecificGroupwiseConstants: + """An object containing multiple AutoPopulatingDict""" + def __init__(self, populating_method: Callable[[int], None], layer_names: list[str], quantity_description: str): + """ + Create an object that contains as many AutoPopulatingDict as there are + items in layer_names. + + Parameters + ---------- + populating_method: + The method to be called if the requested index n in any one of the + AutoPopulatingDict is currently unpopulated. This method should + populate that dictionary. + layer_names: + A list of strings, each of which is the descriptive name for that + layer. While the actual content in each string could be empty, + the length of this list MUST be equal to the total number + of dictionaries required. + quantity_description: + A name to be given to this specific instance of the class, to help + label what quantity is being stored. + """ + self._name = quantity_description + layer_dicts = [] + for num_layer, _layer_name in enumerate(layer_names): + name = f"{self._name} for layer {num_layer}" + if _layer_name: + name += f":{_layer_name}" + layer_dicts.append(AutoPopulatingDict(populating_method, name)) + self._dicts = tuple(layer_dicts) + self.n_layers = len(self._dicts) + + def __iter__(self): + return self._dicts.__iter__() + + def __len__(self) -> int: + return len(self._dicts) + + def __setitem__(self, index: int | tuple[int, int], value): + """ + Act as if this is a 2D array, where the first-axis is the layer and the + second axis is the group. support slice of the thing, + """ + if isinstance(index, tuple) and len(index)>=2: + if len(index)>2: + raise IndexError("2D array indexed with more than 2 indices!") + layer_index, group_index = index + self._dicts[layer_index][group_index] = value + else: + super().__setitem__(index, value) + + def __getitem__(self, index: int | tuple[int, int]): + """ + Act as if this is a 2D array, where the first-axis is the layer and the + second axis is the group. Handle slices as well. + """ + if isinstance(index, tuple) and len(index)>=2: + if len(index)>2: + raise IndexError("2D array indexed with more than 2 indices!") + layer_index, group_index = index + if isinstance(layer_index, slice): + return tuple( + [_dict[group_index] for _dict in self._dicts[layer_index]] + ) + return self._dicts[layer_index][group_index] + return self._dicts[index] + + def has_populated(self, n: int) -> bool: + """ + Check if group n's constants are populated for every layer's dict. + + Parameter + --------- + n: + group number to check the population status of every layer's dict. + + + Returns + ------- + : + Whether group n's constants are poplated across all dictionaries + stored by the current instance. + """ + return all(n in layer_dict for layer_dict in self._dicts) + + def __repr__(self): + return f"A tuple of {self.n_layers} layers of {self._name}" class NeutronFluxProfile: """ @@ -317,23 +404,17 @@ def __init__( self.n_groups = fw_mat.n_groups self.group_structure = fw_mat.group_structure - trig_coefs, l2, d_coef = [], [], [] - for num_layer, mat in enumerate(self.materials): - c_name = f"Coefficients for layer {num_layer}" - l_name = f"characteristic diffusion length for layer {num_layer}" - d_name = f"Diffusion coefficient D for layer {num_layer}" - if mat.name: - c_name += f":{mat.name}" - l_name += f":{mat.name}" - d_name += f":{mat.name}" - trig_coefs.append(AutoPopulatingDict(self.solve_group_n, c_name)) - l2.append(AutoPopulatingDict(self.solve_group_n, l_name)) - d_coef.append(AutoPopulatingDict(self.solve_group_n, d_name)) - - self.coefficients = tuple(trig_coefs) - self.l2 = tuple(l2) - self.diffusion_const = tuple(d_coef) - # diffusion lengths squared + mat_name_list = [mat.name for mat in self.materials] + self.coefficients = LayerSpecificGroupwiseConstants( + self.solve_group_n, mat_name_list, "Coefficients" + ) + self.l2 = LayerSpecificGroupwiseConstants( + self.solve_group_n, mat_name_list, + "Characteristic diffusion length squared" + ) + self.diffusion_const = LayerSpecificGroupwiseConstants( + self.solve_group_n, mat_name_list, "Diffusion coefficient D" + ) self.extended_boundary = AutoPopulatingDict( self.solve_group_n, "extended_boundary" ) @@ -341,28 +422,28 @@ def __init__( def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. - Store the solved constants in self.extended_boundary[0], self.l2[*][0], - and self.coefficients[*][0]. + Store the solved constants in self.extended_boundary[0], self.l2[:, 0], + and self.coefficients[:, 0]. self.coefficients each have units of [m^-2 s^-1]. """ n = 0 - if all(n in layer_coefs for layer_coefs in self.coefficients): + if self.coefficients.has_populated(n): return # skip if it has already been solved. for num_layer, mat in enumerate(self.materials): - self.diffusion_const[num_layer][n], self.l2[num_layer][n] = get_diffusion_coefficient_and_length( + self.diffusion_const[num_layer, n], self.l2[num_layer, n] = get_diffusion_coefficient_and_length( mat.avg_atomic_mass, mat.sigma_t[n], mat.sigma_s[n, n], mat.sigma_in[n, n], ) self.extended_boundary[n] = self.layer_x[-1] + extrapolation_length( - self.diffusion_const[-1][n] + self.diffusion_const[-1, n] ) if self.n_layers == 2: - l_fw, l_bz = np.sqrt(abs(self.l2[0][n])), np.sqrt(abs(self.l2[1][n])) + l_fw, l_bz = np.sqrt(abs(self.l2[0, n])), np.sqrt(abs(self.l2[1, n])) x_fw, = self.layer_x[:-1] - d_fw, d_bz = self.diffusion_const[0][n], self.diffusion_const[1][n] - if self.l2[0][n] > 0: + d_fw, d_bz = self.diffusion_const[0, n], self.diffusion_const[1, n] + if self.l2[0, n] > 0: s_fw = np.sinh(x_fw / l_fw) c_fw = np.cosh(x_fw / l_fw) t_fw = np.tanh(x_fw / l_fw) @@ -370,7 +451,7 @@ def solve_lowest_group(self) -> None: s_fw = np.sin(x_fw / l_fw) c_fw = np.cos(x_fw / l_fw) t_fw = np.tan(x_fw / l_fw) - if self.l2[1][n] > 0: + if self.l2[1, n] > 0: c_bz = np.cosh(self.extended_boundary[n] / l_bz) s_bz = np.sinh(self.extended_boundary[n] / l_bz) c_bz_mod = np.cosh((self.extended_boundary[n] - x_fw) / l_bz) @@ -400,8 +481,8 @@ def solve_lowest_group(self) -> None: bz_c_factor = bz_common_factor * s_bz bz_s_factor = -bz_common_factor * c_bz - self.coefficients[0][n] = Coefficients([fw_c_factor], [fw_s_factor]) - self.coefficients[1][n] = Coefficients([bz_c_factor], [bz_s_factor]) + self.coefficients[0, n] = Coefficients([fw_c_factor], [fw_s_factor]) + self.coefficients[1, n] = Coefficients([bz_c_factor], [bz_s_factor]) else: raise NotImplementedError("Only implemented 2 groups so far.") return @@ -410,7 +491,7 @@ def solve_group_n(self, n: int) -> None: """ Solve the n-th group of neutron's diffusion equation, where n <= n_groups-1. Store the solved constants in self.extended_boundary[n-1], - self.l2[*][n-1], and self.coefficients[*][n-1]. + self.l2[:, n-1], and self.coefficients[:, n-1]. Parameters ---------- @@ -427,26 +508,26 @@ def solve_group_n(self, n: int) -> None: return self.solve_lowest_group() # ensure all lower groups are solved. for k in range(n): - if not all(k in layer_coefs for layer_coefs in self.coefficients): + if not self.coefficients.has_populated(k): self.solve_group_n(k) if not all(mat.downscatter_only for mat in self.materials): raise NotImplementedError( "Will implement solve_group_n in a loop later..." ) - if all(n in layer_coefs for layer_coefs in self.coefficients): + if self.coefficients.has_populated(n): return None # skip if it has already been solved. # Parameter to be changed later, to allow solving non-down-scatter # only systems by iterating. first_iteration = True for num_layer, mat in enumerate(self.materials): - self.diffusion_const[num_layer][n], self.l2[num_layer][n] = get_diffusion_coefficient_and_length( + self.diffusion_const[num_layer, n], self.l2[num_layer, n] = get_diffusion_coefficient_and_length( mat.avg_atomic_mass, mat.sigma_t[n], mat.sigma_s[n, n], mat.sigma_in[n, n], ) self.extended_boundary[n] = self.layer_x[-1] + extrapolation_length( - self.diffusion_const[-1][n] + self.diffusion_const[-1, n] ) @@ -455,26 +536,26 @@ def solve_group_n(self, n: int) -> None: _coefs = Coefficients([], []) mat = self.materials[num_layer] src_matrix = mat.sigma_s + mat.sigma_in - diffusion_const_n = self.diffusion_const[num_layer][n] + diffusion_const_n = self.diffusion_const[num_layer, n] for g in range(n): # if the characteristic length of group [g] coincides with the # characteristic length of group [n], then that particular # cosh/sinh would be indistinguishable from group [n]'s # cosh/sinh anyways, therefore we can set the coefficient to 0. scale_factor = 0.0 - l2n, l2g = self.l2[num_layer][n], self.l2[num_layer][g] + l2n, l2g = self.l2[num_layer, n], self.l2[num_layer, g] if not np.isclose(l2_diff:=(l2g - l2n), 0): scale_factor = (l2n * l2g) / diffusion_const_n / l2_diff _coefs.c.append( sum( - src_matrix[i, n] * self.coefficients[num_layer][i].c[g] + src_matrix[i, n] * self.coefficients[num_layer, i].c[g] for i in range(g, n) ) * scale_factor ) _coefs.s.append( sum( - src_matrix[i, n] * self.coefficients[num_layer][i].s[g] + src_matrix[i, n] * self.coefficients[num_layer, i].s[g] for i in range(g, n) ) * scale_factor @@ -484,14 +565,14 @@ def solve_group_n(self, n: int) -> None: s_factor_guess = 0.0 _coefs.c.append(c_factor_guess) _coefs.s.append(s_factor_guess) - self.coefficients[num_layer][n] = _coefs + self.coefficients[num_layer, n] = _coefs def _set_coefficients(input_vector: Iterable[float]): for num_layer in range(self.n_layers): i = num_layer * 2 - self.coefficients[num_layer][n].c[n] = input_vector[i] - self.coefficients[num_layer][n].s[n] = input_vector[i+1] + self.coefficients[num_layer, n].c[n] = input_vector[i] + self.coefficients[num_layer, n].s[n] = input_vector[i+1] def _evaluate_fit(): # zero flux condition @@ -561,14 +642,14 @@ def groupwise_neutron_flux_in_layer( """ trig_funcs = [] for g in range(n + 1): - if self.l2[num_layer][g] > 0: + if self.l2[num_layer, g] > 0: c, s = np.cosh, np.sinh - l = np.sqrt(self.l2[num_layer][g]) + l = np.sqrt(self.l2[num_layer, g]) else: c, s = np.cos, np.sin - l = np.sqrt(-self.l2[num_layer][g]) - trig_funcs.append(self.coefficients[num_layer][n].c[g] * c(abs(x) / l)) - trig_funcs.append(self.coefficients[num_layer][n].s[g] * s(abs(x) / l)) + l = np.sqrt(-self.l2[num_layer, g]) + trig_funcs.append(self.coefficients[num_layer, n].c[g] * c(abs(x) / l)) + trig_funcs.append(self.coefficients[num_layer, n].s[g] * s(abs(x) / l)) return np.sum(trig_funcs, axis=0) @@ -631,25 +712,25 @@ def groupwise_integrated_flux_in_layer( x_end = self.layer_x[num_layer] for g in range(n + 1): - l2g = self.l2[num_layer][g] + l2g = self.l2[num_layer, g] if l2g > 0: l = np.sqrt(l2g) integrals.append( - l * self.coefficients[num_layer][n].c[g] + l * self.coefficients[num_layer, n].c[g] * (np.sinh(x_end / l) - np.sinh(x_start / l)) ) integrals.append( - l * self.coefficients[num_layer][n].s[g] + l * self.coefficients[num_layer, n].s[g] * (np.cosh(x_end / l) - np.cosh(x_start / l)) ) else: l = np.sqrt(-l2g) integrals.append( - l * self.coefficients[num_layer][n].c[g] + l * self.coefficients[num_layer, n].c[g] * (np.sin(x_end / l) - np.sin(x_start / l)) ) integrals.append( - -l * self.coefficients[num_layer][n].s[g] + -l * self.coefficients[num_layer, n].s[g] * (np.cos(x_end / l) - np.cos(x_start / l)) ) return np.sum(integrals, axis=0) @@ -674,32 +755,32 @@ def groupwise_neutron_current_in_layer( """ differentials = [] for g in range(n + 1): - l2g = self.l2[num_layer][g] + l2g = self.l2[num_layer, g] if l2g > 0: l = np.sqrt(l2g) differentials.append( - self.coefficients[num_layer][n].c[g] + self.coefficients[num_layer, n].c[g] / l * np.sinh(abs(x) / l) ) differentials.append( - self.coefficients[num_layer][n].s[g] + self.coefficients[num_layer, n].s[g] / l * np.cosh(abs(x) / l) ) else: l = np.sqrt(-l2g) differentials.append( - -self.coefficients[num_layer][n].c[g] + -self.coefficients[num_layer, n].c[g] / l * np.sin(abs(x) / l) ) differentials.append( - self.coefficients[num_layer][n].s[g] + self.coefficients[num_layer, n].s[g] / l * np.cos(abs(x) / l) ) - return -self.diffusion_const[num_layer][n] * np.sum(differentials, axis=0) * np.sign(x) + return -self.diffusion_const[num_layer, n] * np.sum(differentials, axis=0) * np.sign(x) @summarize_values def groupwise_neutron_current_at( diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index d29d38ab94..eb376ed42b 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -36,10 +36,10 @@ def test_one_group(): ) const = neutron_profile.coefficients # alias to fit line width - assert np.isclose(const[0][0].c[0], 80.5346770788), "c5" - assert np.isclose(const[0][0].s[0], -76.5562120985), "c6" - assert np.isclose(const[1][0].c[0], 60.6871656017), "c7" - assert np.isclose(const[1][0].s[0], -60.7123696772), "c8" + assert np.isclose(const[0, 0].c[0], 80.5346770788), "c5" + assert np.isclose(const[0, 0].s[0], -76.5562120985), "c6" + assert np.isclose(const[1, 0].c[0], 60.6871656017), "c7" + assert np.isclose(const[1, 0].s[0], -60.7123696772), "c8" assert np.isclose(neutron_profile.neutron_flux_in_layer(0, x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_in_layer(1, x_fw), 48.72444) @@ -91,7 +91,7 @@ def test_one_group_with_fission(): neutron_profile = NeutronFluxProfile( incoming_flux, [x_fw, x_bz], [fw_material, bz_material], ) - assert np.isclose(neutron_profile.l2[1][0], -((58.2869567709 / 100) ** 2)) + assert np.isclose(neutron_profile.l2[1, 0], -((58.2869567709 / 100) ** 2)) assert np.isclose( neutron_profile.neutron_flux_at(-4.79675 / 100), 159.9434 ), "Minimum flux in FW" diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 76e01c1923..ba6bad999e 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -1,7 +1,7 @@ import pytest from process.exceptions import ProcessValidationError -from process.neutronics import NeutronFluxProfile +from process.neutronics import NeutronFluxProfile, LayerSpecificGroupwiseConstants, AutoPopulatingDict from process.neutronics_data import MaterialMacroInfo @@ -54,6 +54,23 @@ def test_warn_up_elastic_scatter(): [[0.5, 0.5], [1.0, 1.0]], ) +def test_throw_index_error(): + layer_specific_const = LayerSpecificGroupwiseConstants( + lambda x: x, ["", ""], ["Dummy constants"] + ) + with pytest.raises(IndexError): + layer_specific_const[0, 0, 0] + with pytest.raises(IndexError): + layer_specific_const[0, 0, 0] = 1 + +def test_iter_and_len(): + layer_specific_const = LayerSpecificGroupwiseConstants( + lambda x: x, ["", ""], ["Dummy constants"] + ) + assert len(layer_specific_const) == 2 + as_list = list(layer_specific_const) + assert len(as_list) == 2 + assert isinstance(as_list[0], AutoPopulatingDict) def test_has_local_fluxes(): """Test that the groupwise decorator has worked on the local fluxes methods.""" From 7ec56891d314961653e73155726e62357f94c0ef Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 22 Nov 2025 17:26:16 +0000 Subject: [PATCH 74/98] Starting to fix plotting. Still need to verify that the layers' boundaries (i.e. interfaces) are properly drawn. Will need to make heating calculation method. --- process/neutronics.py | 249 +++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 126 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 15570ad6a7..c0e70875ec 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -30,7 +30,7 @@ def summarize_values(func): if not (func.__name__.startswith("groupwise_") and "n" in func_params): raise ValueError( "The decorated method is designed to turn groupwise methods into " - "summed flux/reaction/current methods." + "flux/integrated flux/current methods." ) @functools.wraps(func) @@ -310,6 +310,14 @@ def has_populated(self, n: int) -> bool: def __repr__(self): return f"A tuple of {self.n_layers} layers of {self._name}" +UNIT_LOOKUP = { + "integrated_flux": "m^-1 s^-1", + "reaction_rate": "m^-2 s^-1", + "flux": "m^-2 s^-1", + "current": "m^-2 s^-1", + "heating": "W m^-3", +} + class NeutronFluxProfile: """ Calculate the neutron flux, neutron current, and neutron heating in the @@ -780,7 +788,14 @@ def groupwise_neutron_current_in_layer( / l * np.cos(abs(x) / l) ) - return -self.diffusion_const[num_layer, n] * np.sum(differentials, axis=0) * np.sign(x) + def special_sign(x_values): + """Forces 0 to be +ve and -0.0 to be -ve.""" + signs = np.sign(x_values) + are_zeros = x_values==0 + neg_zeros = [str(z).startswith("-") for z in x_values[are_zeros]] + signs[are_zeros] = np.array(neg_zeros, dtype=float) * -2 + 1 + return signs + return -self.diffusion_const[num_layer, n] * np.sum(differentials, axis=0) * special_sign(x) @summarize_values def groupwise_neutron_current_at( @@ -817,7 +832,7 @@ def groupwise_neutron_current_at( @summarize_values def groupwise_neutron_current_through_interface( - self, n: int, n_interface: int, default_to_inner_layer : bool=True + self, n: int, n_interface: int, *, default_to_inner_layer : bool=True ) -> float: """ Net current from left to right on the positive side of the model, at @@ -872,163 +887,145 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: n, self.n_layers ) + @classmethod + def get_output_unit(cls, method) -> str | None: + """ + Check a method's outputted quantity's unit + Parameters + ---------- + method: + A method whose name we shall be inspecting and comparing against + UNIT_LOOKUP. + Returns + ------- + : + If a match is found, return the unit as a string. Otherwise, return + None. + """ + for quantity, unit in UNIT_LOOKUP.items(): + if quantity in method.__name__: + return unit + def plot( self, + quantity: str = "flux", ax: plt.Axes | None = None, - n_points: int = 100, - symmetric: bool = True, + *, plot_groups: bool = True, - quantity: str = "flux", + symmetric: bool = True, + n_points: int = 100, ): """ Make a rough plot of the neutron flux. Parameters ---------- + quantity: + Options of plotting which quantity: {"flux", "current", "heating"}. ax: A plt.Axes object to plot on. n_points: - number of points to be used for plotting. + Number of points to be used for plotting. symmetric: - Whether to plot from -x to x (symmetric), or from 0 to x (right side only.) + Whether to plot from -x to x (symmetric), or from 0 to x + (right side only.) plot_groups: Whether to plot each individual group's neutron flux. If True, a legend will be added to help label the groups. - quantity: - Options of plotting which quantity: {"flux", "current"}. """ - self.solve_group_n(self.n_groups - 1) ax = ax or plt.axes() + method_name = f"neutron_{quantity}_in_layer" + total_function = getattr(self, method_name) + unit = self.get_output_unit(total_function) + ylabel = f"{quantity}({unit})" - x_bz_left, x_fw, x_bz_right = _generate_x_range( + if plot_groups: + groupwise_function = getattr(self, f"groupwise_{method_name}") + x_ranges = _generate_x_range( + self.interface_x.copy(), max(self.extended_boundary.values()), - n_points, - symmetric, - self.x_fw, - ) - ax.plot( - x_bz_left, - self.neutron_flux_bz(x_bz_left), - color="black", - ls=(0, (3, 1, 1, 1)), + min_total_num_points=n_points, + symmetric=symmetric ) - ax.plot( - x_fw, - self.neutron_flux_fw(x_fw), - label="total (FW)", - color="black", - ls="solid", - ) - ax.plot( - x_bz_right, - self.neutron_flux_bz(x_bz_right), - color="black", - label="total (BZ)", - ls=(0, (3, 1, 1, 1)), - ) - - if plot_groups: - for n in range(self.n_groups): - x_bz_left, x_fw, x_bz_right = _generate_x_range( - self.extended_boundary[n], - n_points, - symmetric, - self.x_fw, - ) - ax.plot( - x_bz_left, - self.neutron_flux_bz(x_bz_left), - color=f"C{n}", - ls=(0, (3, 1, 1, 1)), - ) - ax.plot( - x_fw, - self.neutron_flux_fw(x_fw), - label=f"group {n + 1} (FW)", - color=f"C{n}", - ls="solid", - ) - ax.plot( - x_bz_right, - self.neutron_flux_bz(x_bz_right), - label=f"group {n + 1} (BZ)", - color=f"C{n}", - ls=(0, (3, 1, 1, 1)), - ) + for num_layer in range(self.n_layers): + if symmetric: + neg_x = next(x_ranges) + ax.plot(neg_x, total_function(num_layer, neg_x), color="black") + pos_x = next(x_ranges) + plot_dict = {"label": "total"} if num_layer==0 else {} + ax.plot( + pos_x, total_function(num_layer, pos_x), + color="black", **plot_dict, + ) + if plot_groups: + for n in range(self.n_groups): + if symmetric: + ax.plot( + neg_x, groupwise_function(n, num_layer, neg_x), + color=f"C{n}" + ) + plot_dict = {"label": f"group {n}"} if num_layer==0 else {} + ax.plot( + pos_x, groupwise_function(n, num_layer, pos_x), + color=f"C{n}", **plot_dict, + ) ax.legend() - ax.set_title("Neutron flux profile") + ax.set_title(f"Neutron {quantity} profile") ax.set_xlabel("Distance from the plasma-fw interface [m]") - ax.set_ylabel("Neutron flux [m^-2 s^-1]") + ax.set_ylabel(ylabel) + + # plotting the interfaces for ease of comprehension. + ylims = ax.get_ylims() + for (xmin, xmax), mat in zip(pairwise(self.interface_x), self.materials): + ax.plot([xmin, xmin], ylims, color="black", ls="--") + ax.text([np.mean([xmin, xmax]), 0], mat.name) + ax.text([-np.mean([xmin, xmax]), 0], mat.name) + ax.plot([xmax, xmax], ylims, color="black", ls="--") return ax def _generate_x_range( - x_max: float, - approx_n_points: int, + interface_x: npt.NDArray[np.float64], + extended_boundary: float | None, + *, + min_total_num_points: int, symmetric: bool, - fw_bz_split_point: float | None = None, ): - """Helper function for finding the range of x-values to be plotted. + """Helper generator for finding the range of x-values to be plotted. Parameters ---------- - x_max: - absolute value of the maximum x that we want to plot. + interface_x: + The x-coordinates of each interface. It should be all-positive, and + ascending only. + extended_boundary: + extended boundary + min_total_num_points: + Approximate number of points to be plotted. Increase this number to increase the resolution symmetric: - Whether we want to plot the negative side of the x-axis as well, forming - a symmetric plot. - approx_n_points: - number of points to be plotted. - fw_bz_split_point: - FW and BZ region splits at this distance. If provided, we generate separate - x ranges for the FW and BZ. [m] + Whether to return two copies (one negative, one positive) of x-ranges + per layer. - Returns + Yields ------- - if (fw_bz_split_point, symmetric) = (float value, True): - x_range_bz_left: - The array of x-values to be used for plotting the left (negative) - side of bz. [m] - x_range_fw: - The array of x-values to be used for plotting both the left and - right sides of fw. [m] - x_range_bz_right: - The array of x-values to be used for plotting the right (positive) - side of bz. [m] - elif (fw_bz_split_point, symmetric) = (float value, False): - x_range_fw: - The array of x-values to be used for plotting the right (positive) - side of fw [m] - x_range_bz: - The array of x-values to be used for plotting the right (positive) - side of bz [m] - elif (fw_bz_split_point, symmetric) = (None, True): - x_range: - The array of x-values to be used for plotting both sides of the - neutron flux. [m] - else (fw_bz_split_point, symmetric) = (None, False): - x_range: - The array of x-values to be used for plotting the right (positive) - side neutron flux. [m] + : + A generator of x-coordinates used for plotting, each of which falls + within the limit of the xmin and xmax of that layer, forming a total + of a minimum of min_total_num_points. + If symmetric=True, then the number of numpy arrays in the list + = 2*n_layers, where out_x_range[0] and out_x_range[1] are for the + negative and positive sides of the first layer respectively; + out_x_range[2] and out_x_range[3] are for the negative and positive + sides of the second layer respectively. + Otherwise, the number of numpy arrays in the list = n_layers. """ - - if fw_bz_split_point is not None: - x_range = np.linspace(0, x_max, approx_n_points) - n_points_fw = (x_range < fw_bz_split_point).sum() + 1 - n_points_bz = (x_range >= fw_bz_split_point).sum() + 1 - + full_x_range = np.linspace( + interface_x.min(), interface_x.max(), min_total_num_points + ) + for num_layer, (xmin, xmax) in enumerate(pairwise(interface_x)): + num_points = np.logical_and(xmin Date: Sat, 22 Nov 2025 17:27:25 +0000 Subject: [PATCH 75/98] Slight name change --- tests/regression/test_neutronics.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index eb376ed42b..68cdb09351 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -35,11 +35,11 @@ def test_one_group(): incoming_flux, [x_fw, x_bz], [fw_material, bz_material] ) - const = neutron_profile.coefficients # alias to fit line width - assert np.isclose(const[0, 0].c[0], 80.5346770788), "c5" - assert np.isclose(const[0, 0].s[0], -76.5562120985), "c6" - assert np.isclose(const[1, 0].c[0], 60.6871656017), "c7" - assert np.isclose(const[1, 0].s[0], -60.7123696772), "c8" + layer_group_coefs = neutron_profile.coefficients + assert np.isclose(layer_group_coefs[0, 0].c[0], 80.5346770788), "c5" + assert np.isclose(layer_group_coefs[0, 0].s[0], -76.5562120985), "c6" + assert np.isclose(layer_group_coefs[1, 0].c[0], 60.6871656017), "c7" + assert np.isclose(layer_group_coefs[1, 0].s[0], -60.7123696772), "c8" assert np.isclose(neutron_profile.neutron_flux_in_layer(0, x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_in_layer(1, x_fw), 48.72444) From f16d433f4ed6b958f519820fcfbd8390fd3d52bd Mon Sep 17 00:00:00 2001 From: ocean Date: Sat, 22 Nov 2025 18:42:49 +0000 Subject: [PATCH 76/98] Finished updating the plotting function, so at the moment it works for both flux and current, but not for heating yet. --- process/neutronics.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index c0e70875ec..6b578f5cb3 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -975,14 +975,21 @@ def plot( ax.set_ylabel(ylabel) # plotting the interfaces for ease of comprehension. - ylims = ax.get_ylims() + ylims = ax.get_ylim() for (xmin, xmax), mat in zip(pairwise(self.interface_x), self.materials): - ax.plot([xmin, xmin], ylims, color="black", ls="--") - ax.text([np.mean([xmin, xmax]), 0], mat.name) - ax.text([-np.mean([xmin, xmax]), 0], mat.name) - ax.plot([xmax, xmax], ylims, color="black", ls="--") + _plot_vertical_dotted_line(ax, xmin, ylims, symmetric=symmetric) + ax.text(np.mean([xmin, xmax]), 0, mat.name, ha="center", va="center") + if symmetric: + ax.text(-np.mean([xmin, xmax]), 0, mat.name, ha="center", va="center") + _plot_vertical_dotted_line(ax, xmax, ylims, symmetric=symmetric) return ax +def _plot_vertical_dotted_line(ax, x, ylims, *, symmetric: bool=True): + if symmetric: + ax.plot([-x, -x], ylims, color="black", ls="--") + ax.plot([x, x], ylims, color="black", ls="--") + return None + def _generate_x_range( interface_x: npt.NDArray[np.float64], extended_boundary: float | None, From e3de8ecaddbb214009d0b3a5ffd86d830579ce78 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 03:01:08 +0000 Subject: [PATCH 77/98] Simplified the sign extraction function --- process/neutronics.py | 15 +++++++-------- tests/unit/test_neutronics.py | 7 ++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 6b578f5cb3..53ae06065a 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -788,14 +788,8 @@ def groupwise_neutron_current_in_layer( / l * np.cos(abs(x) / l) ) - def special_sign(x_values): - """Forces 0 to be +ve and -0.0 to be -ve.""" - signs = np.sign(x_values) - are_zeros = x_values==0 - neg_zeros = [str(z).startswith("-") for z in x_values[are_zeros]] - signs[are_zeros] = np.array(neg_zeros, dtype=float) * -2 + 1 - return signs - return -self.diffusion_const[num_layer, n] * np.sum(differentials, axis=0) * special_sign(x) + + return -self.diffusion_const[num_layer, n] * np.sum(differentials, axis=0) * _get_sign_of(x) @summarize_values def groupwise_neutron_current_at( @@ -984,6 +978,11 @@ def plot( _plot_vertical_dotted_line(ax, xmax, ylims, symmetric=symmetric) return ax +def _get_sign_of(x_values): + """Forces 0 to be +ve and -0.0 to be -ve.""" + negatives = np.signbit(x_values) + return np.array(negatives, dtype=float) * -2 + 1 + def _plot_vertical_dotted_line(ax, x, ylims, *, symmetric: bool=True): if symmetric: ax.plot([-x, -x], ylims, color="black", ls="--") diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index ba6bad999e..dda6605475 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -1,7 +1,8 @@ import pytest +import numpy as np from process.exceptions import ProcessValidationError -from process.neutronics import NeutronFluxProfile, LayerSpecificGroupwiseConstants, AutoPopulatingDict +from process.neutronics import NeutronFluxProfile, LayerSpecificGroupwiseConstants, AutoPopulatingDict, _get_sign_of from process.neutronics_data import MaterialMacroInfo @@ -97,6 +98,10 @@ def test_has_reactions(): def test_has_plot(): assert hasattr(NeutronFluxProfile, "plot") +def test_get_sign_func(): + signs = _get_sign_of(np.array([-np.inf, -2, -1, -0.0, 0.0, 1.0, 2.0, np.inf])) + np.testing.assert_equal(signs, [-1, -1, -1, -1, 1, 1, 1, 1]) + def test_three_group(): # 1. No negative flux dummy = [10000, 1000, 100, 1] From 9b498f8e3fffe0d7b2be08f564bbdaa287bfb130 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 04:58:38 +0000 Subject: [PATCH 78/98] Implemented an attribute to record the neutron energy; and changed units from eV to Joule --- process/neutronics.py | 208 +++++++++++++++++++++++++++---------- process/neutronics_data.py | 6 +- 2 files changed, 155 insertions(+), 59 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 53ae06065a..7f37c1e9c0 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -332,14 +332,18 @@ def __init__( flux: float, layer_x: npt.NDArray[np.float64], materials: Iterable[MaterialMacroInfo], + init_neutron_energy: float = DT_NEUTRON_E, ): """Initialize a particular FW-BZ geometry and neutron flux. Parameters ---------- flux: - Nuetron flux directly emitted by the plasma, incident on the first wall. - unit: m^-2 s^-1 + Neutron flux directly emitted by the plasma, incident on the first + wall. unit: m^-2 s^-1 + init_neutron_energy: + Neutron's initial energy when it first exit the plasma, before any + downscattering or reactions. unit: J. layer_x: The x-coordinates of the right side of every layers. By definition, the plasma is situated at x=0, so all values in layer_x must be >0. @@ -364,6 +368,8 @@ def __init__( Number of groups in the group structure group_structure: Energy bin edges, 1D array of len = n_groups+1 + energy: + The mean neutron energy of each group. coefficients: Coefficients that determine the flux shape (and therefore reaction @@ -380,6 +386,7 @@ def __init__( """ # flux incident on the first wall at the highest energy. self.flux = flux + self.init_neutron_energy = init_neutron_energy # layers self.layer_x = np.array(layer_x).ravel() @@ -411,6 +418,9 @@ def __init__( ) self.n_groups = fw_mat.n_groups self.group_structure = fw_mat.group_structure + self.group_energy = self._calculate_mean_energy( + self.group_structure, self.init_neutron_energy + ) mat_name_list = [mat.name for mat in self.materials] self.coefficients = LayerSpecificGroupwiseConstants( @@ -427,6 +437,55 @@ def __init__( self.solve_group_n, "extended_boundary" ) + @staticmethod + def _calculate_mean_energy( + group_structure: npt.NDArray[np.float64], init_neutron_e: float, + ) -> npt.NDArray[np.float64]: + """ + Calculate the mean energy of each neutron group in Joule. + When implementing this method, we can choose either a weighted mean or + an unweighted mean. The weighted mean (where neutron flux is assumed + constant w.r.t. neutorn lethargy within the bin) is more accurate, but + may end up being incorrect if the bins in the group structure are too + wide, as it heavily biases towards lower energy. In contrast, the + simple unweighted mean does not have such problem, but is inconsistent + with the rest of the program's assumption (const. flux w.r.t. lethargy), + therefore the former is chosen. + + Parameters + ---------- + group_structure: + The neutron energy bin's edges, in descending order, with len= + n_groups + 1. + init_neutron_e: + The neutrons entering from the plasma to the FW is assumed to be + monoenergetic, with this energy. + + Returns + ------- + mean_neutron_e: + Mean energy of neutrons. The bin containing init_neutron_e + (likely the highest energy bin, i.e. bin[0]) is assumed to be + dominated by the unscattered neutrons entering from the plasma, + therefore it is + """ + high, low = group_structure[:-1], group_structure[1:] + weighted_mean = (high - low)/(np.log(high)- np.log(low)) + # unweighted_mean = np.mean([high, low], axis=0) + first_bin = np.logical_and(high>init_neutron_e, init_neutron_e>=low) + if first_bin.sum()<1: + raise ValueError( + "The energy of neutrons incident from the plasma is not " + "captured by the group structure!" + ) + elif first_bin.sum()>1: + raise ValueError( + "The energy of neutrons incident from the plasma is NOT captured by the group " + "structure!" + ) + weighted_mean[first_bin] = init_neutron_e + return weighted_mean + def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. @@ -627,7 +686,7 @@ def objective(coefficients_vector): @summarize_values def groupwise_neutron_flux_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray - ) -> npt.NDArray: + ) -> float | npt.NDArray: """ Neutron flux[m^-2 s^-1] of the n-th group int h specified layer, at location x [m]. @@ -661,10 +720,19 @@ def groupwise_neutron_flux_in_layer( return np.sum(trig_funcs, axis=0) + @summarize_values + def groupwise_neutron_heating_in_layer( + self, n: int, num_layer: int, x: float | npt.NDArray + ) -> float | npt.NDArray: + return ( + self.groupwise_linear_heating_density_in_layer(n, num_layer) + * self.groupwise_neutron_flux_in_layer(n, num_layer, x) + ) + @summarize_values def groupwise_neutron_flux_at( self, n: int, x: float | npt.NDArray - ) -> npt.NDArray: + ) -> float | npt.NDArray: """ Neutron flux [m^-2 s^-1] anywhere. Neutron flux is assumed to be unperturbed once it leaves the final layer. @@ -694,60 +762,10 @@ def groupwise_neutron_flux_at( ) return out_flux - # scalar values (one such float per neutron group.) - @summarize_values - def groupwise_integrated_flux_in_layer( - self, n: int, num_layer: int - ) -> float: - """ - Calculate the integrated flux[m^-1 s^-1], which can be mulitplied to any - macroscopic cross-section [m^-1] to get the reaction rate [s^-1] in - any layer specified. - - Parameters - ---------- - n: - The index of the neutron group that needs to be solved. n <= n_groups - 1. - Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. - num_layer: - The index of the layer that we want to get the neutron flux for. - """ - integrals = [] - # set integration limits - x_start = self.layer_x[num_layer-1] - if num_layer==0: - x_start = 0.0 - x_end = self.layer_x[num_layer] - - for g in range(n + 1): - l2g = self.l2[num_layer, g] - if l2g > 0: - l = np.sqrt(l2g) - integrals.append( - l * self.coefficients[num_layer, n].c[g] - * (np.sinh(x_end / l) - np.sinh(x_start / l)) - ) - integrals.append( - l * self.coefficients[num_layer, n].s[g] - * (np.cosh(x_end / l) - np.cosh(x_start / l)) - ) - else: - l = np.sqrt(-l2g) - integrals.append( - l * self.coefficients[num_layer, n].c[g] - * (np.sin(x_end / l) - np.sin(x_start / l)) - ) - integrals.append( - -l * self.coefficients[num_layer, n].s[g] - * (np.cos(x_end / l) - np.cos(x_start / l)) - ) - return np.sum(integrals, axis=0) - - @summarize_values def groupwise_neutron_current_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray - ) -> float: + ) -> float | npt.NDArray: """ Get the neutron current (right=positive, left=negative) in any layer. @@ -794,7 +812,7 @@ def groupwise_neutron_current_in_layer( @summarize_values def groupwise_neutron_current_at( self, n: int, x: float | npt.NDArray - ) -> npt.NDArray: + ) -> float | npt.NDArray: """ Neutron current [m^-2 s^-1]. Neutron current is assumed to be unperturbed once it leaves the final layer. @@ -881,6 +899,84 @@ def groupwise_neutron_current_escaped(self, n: int) -> float: n, self.n_layers ) + # scalar values (one such float per neutron group, and per layer.) + @summarize_values + def groupwise_integrated_flux_in_layer( + self, n: int, num_layer: int + ) -> float: + """ + Calculate the integrated flux[m^-1 s^-1], which can be mulitplied to any + macroscopic cross-section [m^-1] to get the reaction rate [s^-1] in + any layer specified. + + Parameters + ---------- + n: + The index of the neutron group that needs to be solved. n <= n_groups - 1. + Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. + num_layer: + The index of the layer that we want to get the neutron flux for. + """ + integrals = [] + # set integration limits + x_start = self.layer_x[num_layer-1] + if num_layer==0: + x_start = 0.0 + x_end = self.layer_x[num_layer] + + for g in range(n + 1): + l2g = self.l2[num_layer, g] + if l2g > 0: + l = np.sqrt(l2g) + integrals.append( + l * self.coefficients[num_layer, n].c[g] + * (np.sinh(x_end / l) - np.sinh(x_start / l)) + ) + integrals.append( + l * self.coefficients[num_layer, n].s[g] + * (np.cosh(x_end / l) - np.cosh(x_start / l)) + ) + else: + l = np.sqrt(-l2g) + integrals.append( + l * self.coefficients[num_layer, n].c[g] + * (np.sin(x_end / l) - np.sin(x_start / l)) + ) + integrals.append( + -l * self.coefficients[num_layer, n].s[g] + * (np.cos(x_end / l) - np.cos(x_start / l)) + ) + return np.sum(integrals, axis=0) + + @summarize_values + def groupwise_integrated_heating_in_layer( + self, n: int, num_layer: int, + ) -> float: + """ + How much neutron heating is + """ + return ( + self.groupwise_linear_heating_density_in_layer(n, num_layer) + * self.groupwise_integrated_flux_in_layer(n, num_layer) + ) + + def groupwise_linear_heating_density_in_layer( + self, n: int, num_layer: int, + ) -> float: + """ + All reactions that does not lead to scattering are assumed to have + the full energy of the neutron deposited into the material. + Obviously this contradicts the assumption of neutrons retaining some of + its energy in the n,2n reaction, but we hope this is a small enough + error that we can overlook it. + """ + mat = self.materials[num_layer] + non_scatter_xs = mat.sigma_t[n] - mat.sigma_s[n,:].sum() + lost_energy = ( + (self.group_energy[n] - self.group_energy) * mat.sigma_s[n,:] + ).sum() + return self.group_energy[n] * non_scatter_xs + lost_energy + @classmethod def get_output_unit(cls, method) -> str | None: """ diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 80fd4daf1b..9675724418 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -402,9 +402,9 @@ def n2n_weight_matrix( ---------- group_structure: the n+1 energy bin boundaries for the n neutron groups, in descending energies, - in eV. + in J. q_value: - the q-value of the reaction in eV. + the q-value of the reaction in J. Returns ------- @@ -462,7 +462,7 @@ class MaterialMacroInfo: e.g. [0,3] would be the cross-section for the proudction of group 4 neutrons due to n,2n and fission reactions caused by group 1 neutrons. group_structure: - energy bin edges, 1D array of len = n+1, in eV. + energy bin edges, 1D array of len = n+1, in [J]. avg_atomic_mass: average atomic mass (weighted by fraction) """ From 2345a2a52f463996bb91806d1d4e6df2a59e13fc Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 05:05:14 +0000 Subject: [PATCH 79/98] Updated documentation and test --- process/neutronics.py | 4 +++- process/neutronics_data.py | 1 + tests/unit/test_neutronics.py | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/process/neutronics.py b/process/neutronics.py index 7f37c1e9c0..ee830bbfc2 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -15,7 +15,7 @@ from scipy import optimize from process.exceptions import ProcessValidationError, ProcessValueError -from process.neutronics_data import MaterialMacroInfo +from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E def summarize_values(func): @@ -960,6 +960,8 @@ def groupwise_integrated_heating_in_layer( * self.groupwise_integrated_flux_in_layer(n, num_layer) ) + # Do NOT add a summarize_values decorator, as you can't add cross-sections + # from different groups together without first multiplying by flux to get reaction rate. def groupwise_linear_heating_density_in_layer( self, n: int, num_layer: int, ) -> float: diff --git a/process/neutronics_data.py b/process/neutronics_data.py index 9675724418..eff5bf2183 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -13,6 +13,7 @@ N_A = Avogadro N2N_Q_VALUE = ... _ATOMIC_MASS = {} +DT_NEUTRON_E = 14.06 * 1.602E-19 def extract_atomic_mass(isotope: str) -> float: diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index dda6605475..52d44dd580 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -93,6 +93,8 @@ def test_has_reactions(): """Test that the groupwise decorator has worked on the reactions methods.""" assert hasattr(NeutronFluxProfile, "groupwise_integrated_flux_in_layer") assert hasattr(NeutronFluxProfile, "integrated_flux_in_layer") + assert hasattr(NeutronFluxProfile, "groupwise_integrated_heating_in_layer") + assert hasattr(NeutronFluxProfile, "integrated_heating_in_layer") def test_has_plot(): From 8888d1119a3619b9b8728e73b963b000c50b8a97 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 12:13:25 +0000 Subject: [PATCH 80/98] Slight fixes to docstring, and fix to regression test dummy energies so they're still valid under the new units (J, instead of eV) --- process/neutronics.py | 10 +++++++++- process/neutronics_data.py | 5 +++-- tests/regression/test_neutronics.py | 8 +++++--- tests/unit/test_neutronics.py | 6 +++++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index ee830bbfc2..50164b25ae 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -1025,6 +1025,7 @@ def plot( Whether to plot each individual group's neutron flux. If True, a legend will be added to help label the groups. """ + self.solve_group_n(self.n_groups - 1) ax = ax or plt.axes() method_name = f"neutron_{quantity}_in_layer" total_function = getattr(self, method_name) @@ -1077,7 +1078,14 @@ def plot( return ax def _get_sign_of(x_values): - """Forces 0 to be +ve and -0.0 to be -ve.""" + """ + Get sign of any real number, but also forces 0.0 to be +ve and -0.0 to be -ve. + The neutron current for the first group (in a non-breeding/weakly breeding + scenario) is strongest at x=0, but have different signs when limit x-> 0^+ + and limit x-> 0^-. This function allows the input x to behave like 0^+ when + it's =0.0 and like 0^- when it's =-0.0, giving the correct neutron current + at those locations, rather than setting the neutron current to zer0. + """ negatives = np.signbit(x_values) return np.array(negatives, dtype=float) * -2 + 1 diff --git a/process/neutronics_data.py b/process/neutronics_data.py index eff5bf2183..63ea13522d 100644 --- a/process/neutronics_data.py +++ b/process/neutronics_data.py @@ -13,7 +13,8 @@ N_A = Avogadro N2N_Q_VALUE = ... _ATOMIC_MASS = {} -DT_NEUTRON_E = 14.06 * 1.602E-19 +EV_TO_J = 1.602E-19 +DT_NEUTRON_E = 14.06 * EV_TO_J def extract_atomic_mass(isotope: str) -> float: @@ -492,7 +493,7 @@ def __post_init__(self): if (self.group_structure <= 0).any(): warnings.warn("Zero energy (inf. lethargy) not allowed.") - self.group_structure = np.clip(self.group_structure, 1e-9, np.inf) + self.group_structure = np.clip(self.group_structure, 1e-9 * EV_TO_J, np.inf) if (np.diff(self.group_structure) >= 0).any(): raise ValueError( "The group structure must be defined descendingly, from the " diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 68cdb09351..543ac2d743 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -1,15 +1,17 @@ import numpy as np from process.neutronics import NeutronFluxProfile -from process.neutronics_data import MaterialMacroInfo +from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E, EV_TO_J +max_E = DT_NEUTRON_E * 1.01 +min_E = 1E-9 * EV_TO_J def test_one_group(): """ Regression test against Desmos snapshot: https://www.desmos.com/calculator/18xojespuo """ - dummy = [100, 1] # dummy group structure + dummy = [max_E, min_E] # dummy group structure # translate from mean-free-path lengths (mfp) to macroscopic cross-sections mfp_fw_s = 118 * 0.01 # [m] mfp_fw_t = 16.65 * 0.01 # [m] @@ -64,7 +66,7 @@ def test_one_group_with_fission(): https://www.desmos.com/calculator/cd830add9c Expecting a cosine-shape (dome shape!) of neutron flux profile. """ - dummy = [100, 1] + dummy = [max_E, min_E] mfp_fw_s = 118 * 0.01 # [m] mfp_fw_t = 16.65 * 0.01 # [m] sigma_fw_t = 1 / mfp_fw_t # [1/m] diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 52d44dd580..7bb9dc00a8 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -83,7 +83,11 @@ def test_has_local_fluxes(): def test_has_boundary_current(): """Test that the groupwise decorator has worked on the boundary fluxes methods.""" - assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_through_interface") + assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_in_layer") + assert hasattr(NeutronFluxProfile, "neutron_current_in_layer") + assert hasattr( + NeutronFluxProfile, "groupwise_neutron_current_through_interface" + ) assert hasattr(NeutronFluxProfile, "neutron_current_through_interface") assert hasattr(NeutronFluxProfile, "groupwise_neutron_current_escaped") assert hasattr(NeutronFluxProfile, "neutron_current_escaped") From 0e7d4775bf39127868574888fe660eb654677b9b Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 12:38:41 +0000 Subject: [PATCH 81/98] Docstring update for heating methods --- process/neutronics.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/process/neutronics.py b/process/neutronics.py index 50164b25ae..de814d6b99 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -724,6 +724,16 @@ def groupwise_neutron_flux_in_layer( def groupwise_neutron_heating_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray ) -> float | npt.NDArray: + """ + Calculate volumetric heating (unit: [W m^-3]) in the specified group + and layer. + + We do not recommend manually integrating this curve by sampling points + in [self.interface_x[n], self.interface_x[n+1]] to get the total amount + of heating across this entire layer, per unit area. Instead, use + groupwise_integrated_heating_in_layer/ integrated_heating_in_layer, + which is faster and more accurate. + """ return ( self.groupwise_linear_heating_density_in_layer(n, num_layer) * self.groupwise_neutron_flux_in_layer(n, num_layer, x) @@ -953,7 +963,10 @@ def groupwise_integrated_heating_in_layer( self, n: int, num_layer: int, ) -> float: """ - How much neutron heating is + The total amount of heat produced (per unit area) due to neutron + heating across the entire num_layer-th layer. unit: [W m^-2]. It should + yield the same result as integrating the curve neutron_heating_in_layer + from self.interface_x[n] to self.interface_x[n+1]. """ return ( self.groupwise_linear_heating_density_in_layer(n, num_layer) From 1ffe7110878aa4d4a4df9e6a7f8c277e227080bf Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 13:14:45 +0000 Subject: [PATCH 82/98] Added test to ensure integration of the heating term is done correctly. --- tests/regression/test_neutronics.py | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index 543ac2d743..fb732989dc 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -2,6 +2,8 @@ from process.neutronics import NeutronFluxProfile from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E, EV_TO_J +from scipy.integrate import trapezoid +from matplotlib import pyplot as plt max_E = DT_NEUTRON_E * 1.01 min_E = 1E-9 * EV_TO_J @@ -50,6 +52,7 @@ def test_one_group(): assert np.isclose(neutron_profile.neutron_current_through_interface(1), 22.3980214162) assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) + fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] assert np.isclose( @@ -59,6 +62,23 @@ def test_one_group(): + bz_removal * neutron_profile.integrated_flux_in_layer(1), ), "Conservation of neutrons" + x_fw = np.linspace(*neutron_profile.interface_x[0:2], 100000) + manually_integrated_heating_fw = trapezoid( + neutron_profile.neutron_heating_in_layer(0, x_fw), x_fw, + ) + x_bz = np.linspace(*neutron_profile.interface_x[1:3], 100000) + manually_integrated_heating_bz = trapezoid( + neutron_profile.neutron_heating_in_layer(1, x_bz), x_bz, + ) + assert np.isclose( + neutron_profile.integrated_heating_in_layer(0), + manually_integrated_heating_fw, atol=0, rtol=1E-8, + ), "Correctly integrated heating in FW" + assert np.isclose( + neutron_profile.integrated_heating_in_layer(1), + manually_integrated_heating_bz, atol=0, rtol=1E-8, + ), "Correctly integrated heating in BZ" + def test_one_group_with_fission(): """ @@ -118,12 +138,29 @@ def test_one_group_with_fission(): ), "positive escaped current." fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] + assert np.isclose( neutron_profile.flux, neutron_profile.neutron_current_escaped() + fw_removal * neutron_profile.integrated_flux_in_layer(0) + bz_removal * neutron_profile.integrated_flux_in_layer(1), ), "Conservation of neutrons" + x_fw = np.linspace(*neutron_profile.interface_x[0:2], 100000) + manually_integrated_heating_fw = trapezoid( + neutron_profile.neutron_heating_in_layer(0, x_fw), x_fw, + ) + x_bz = np.linspace(*neutron_profile.interface_x[1:3], 100000) + manually_integrated_heating_bz = trapezoid( + neutron_profile.neutron_heating_in_layer(1, x_bz), x_bz, + ) + assert np.isclose( + neutron_profile.integrated_heating_in_layer(0), + manually_integrated_heating_fw, atol=0, rtol=1E-8, + ), "Correctly integrated heating in FW" + assert np.isclose( + neutron_profile.integrated_heating_in_layer(1), + manually_integrated_heating_bz, atol=0, rtol=1E-8, + ), "Correctly integrated heating in BZ" def test_two_groups(): From 7ec2666f19d715995992e1384e5c17229e336c44 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 13:15:20 +0000 Subject: [PATCH 83/98] tested units output as well. --- process/neutronics.py | 5 ++++- tests/unit/test_neutronics.py | 30 ++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index de814d6b99..2668771159 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -312,6 +312,8 @@ def __repr__(self): UNIT_LOOKUP = { "integrated_flux": "m^-1 s^-1", + "integrated_heating": "W m^-2", + "linear_heating_density": "J m^-1", "reaction_rate": "m^-2 s^-1", "flux": "m^-2 s^-1", "current": "m^-2 s^-1", @@ -979,6 +981,7 @@ def groupwise_linear_heating_density_in_layer( self, n: int, num_layer: int, ) -> float: """ + unit: [J m^-1] All reactions that does not lead to scattering are assumed to have the full energy of the neutron deposited into the material. Obviously this contradicts the assumption of neutrons retaining some of @@ -993,7 +996,7 @@ def groupwise_linear_heating_density_in_layer( return self.group_energy[n] * non_scatter_xs + lost_energy @classmethod - def get_output_unit(cls, method) -> str | None: + def get_output_unit(cls, method: Callable) -> str | None: """ Check a method's outputted quantity's unit Parameters diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index 7bb9dc00a8..d145747e8f 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -3,7 +3,10 @@ import numpy as np from process.exceptions import ProcessValidationError from process.neutronics import NeutronFluxProfile, LayerSpecificGroupwiseConstants, AutoPopulatingDict, _get_sign_of -from process.neutronics_data import MaterialMacroInfo +from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E, EV_TO_J + +max_E = DT_NEUTRON_E * 1.01 +min_E = 1E-9 * EV_TO_J def test_group_structure_0_energy(): @@ -104,13 +107,36 @@ def test_has_reactions(): def test_has_plot(): assert hasattr(NeutronFluxProfile, "plot") +def test_units(): + nfp = NeutronFluxProfile + assert nfp.get_output_unit(nfp.groupwise_integrated_flux_in_layer)=="m^-1 s^-1" + assert nfp.get_output_unit(nfp.groupwise_integrated_heating_in_layer)=="W m^-2" + assert nfp.get_output_unit(nfp.groupwise_linear_heating_density_in_layer)=="J m^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_current_at)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_current_escaped)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_current_in_layer)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_current_through_interface)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_flux_at)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_flux_in_layer)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.groupwise_neutron_heating_in_layer)=="W m^-3" + + assert nfp.get_output_unit(nfp.integrated_flux_in_layer)=="m^-1 s^-1" + assert nfp.get_output_unit(nfp.integrated_heating_in_layer)=="W m^-2" + assert nfp.get_output_unit(nfp.neutron_current_at)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_current_escaped)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_current_in_layer)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_current_through_interface)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_flux_at)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_flux_in_layer)=="m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_heating_in_layer)=="W m^-3" + def test_get_sign_func(): signs = _get_sign_of(np.array([-np.inf, -2, -1, -0.0, 0.0, 1.0, 2.0, np.inf])) np.testing.assert_equal(signs, [-1, -1, -1, -1, 1, 1, 1, 1]) def test_three_group(): # 1. No negative flux - dummy = [10000, 1000, 100, 1] + dummy = np.geomspace(max_E, min_E, 4) # fw_mat = MaterialMacroInfo() bz_mat = MaterialMacroInfo # 2. same L_1 and L_3 shoudl yield coefficients[0][2].c[0] and From 4fb85191641e4ca1cb25bdf64f3d640d2188fe80 Mon Sep 17 00:00:00 2001 From: ocean Date: Sun, 23 Nov 2025 23:41:13 +0000 Subject: [PATCH 84/98] Fixed the plot such that all discontinuity are minimized, and those discontinuity present are all justified (i.e. have physical meaning). This in turn updated the behaviour of some methods, and notably two new methods are added to calculate the heating in a per-layer fashion. Docstring updates as well. --- process/neutronics.py | 163 ++++++++++++++++++++++++++-------- tests/unit/test_neutronics.py | 9 +- 2 files changed, 135 insertions(+), 37 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 2668771159..3597f5b7fa 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -314,7 +314,6 @@ def __repr__(self): "integrated_flux": "m^-1 s^-1", "integrated_heating": "W m^-2", "linear_heating_density": "J m^-1", - "reaction_rate": "m^-2 s^-1", "flux": "m^-2 s^-1", "current": "m^-2 s^-1", "heating": "W m^-3", @@ -685,12 +684,27 @@ def objective(coefficients_vector): _set_coefficients(results.res) return None + def _check_if_in_layer( + self, x: npt.NDArray[np.float64], num_layer: int + ) -> npt.NDArray[bool]: + if num_layer==(self.n_layers-1): + return np.logical_and( + self.interface_x[num_layer]<=abs(x), + abs(x)<=self.interface_x[num_layer+1] + ) + elif num_layer==self.n_layers: + return abs(x)>self.interface_x[-1] + return np.logical_and( + self.interface_x[num_layer]<=abs(x), + abs(x)<=self.interface_x[num_layer+1] + ) + @summarize_values def groupwise_neutron_flux_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray ) -> float | npt.NDArray: """ - Neutron flux[m^-2 s^-1] of the n-th group int h specified layer, + Neutron flux[m^-2 s^-1] of the n-th group in the specified layer, at location x [m]. Parameters @@ -709,6 +723,10 @@ def groupwise_neutron_flux_in_layer( flux: Neutron flux at x meter from the first wall. """ + if num_layer==self.n_layers: + return self.groupwise_neutron_flux_in_layer( + n, self.n_layers-1, np.sign(x) * self.layer_x[-1] + ) trig_funcs = [] for g in range(n + 1): if self.l2[num_layer, g] > 0: @@ -722,6 +740,39 @@ def groupwise_neutron_flux_in_layer( return np.sum(trig_funcs, axis=0) + @summarize_values + def groupwise_neutron_flux_at( + self, n: int, x: float | npt.NDArray + ) -> float | npt.NDArray: + """ + Neutron flux [m^-2 s^-1] anywhere. Neutron flux is assumed to be + unperturbed once it leaves the final layer. + + Parameters + ---------- + n: + Neutron group index. n <= n_groups - 1. + Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. + x: + The depth where we want the neutron flux [m]. Neutron flux at + infinity is assumed to be the same as the neutron flux at the + nearest layer-void interface. This is achieved by clipping all out- + of-bounds x back to the the nearest interface_x. + """ + if np.isscalar(x): + return self.groupwise_neutron_flux_at(n, [x])[0] + x = np.asarray(x) + + out_flux = np.zeros_like(x) + abs_x = abs(x) + for num_layer in range(self.n_layers + 1): + in_layer = self._check_if_in_layer(x, num_layer) + if in_layer.any(): + out_flux[in_layer] = self.groupwise_neutron_flux_in_layer( + n, num_layer, x[in_layer] + ) + return out_flux + @summarize_values def groupwise_neutron_heating_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray @@ -735,6 +786,22 @@ def groupwise_neutron_heating_in_layer( of heating across this entire layer, per unit area. Instead, use groupwise_integrated_heating_in_layer/ integrated_heating_in_layer, which is faster and more accurate. + + Parameters + ---------- + n: + Neutron group index. n <= n_groups - 1. + Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. + num_layer: + The index of the layer that we want to get the neutron heating for. + x: + The depth where we want the neutron heating [m]. + + Returns + ------- + : + The neutron heating in that specific layer at position x, due to + group n's neutrons. """ return ( self.groupwise_linear_heating_density_in_layer(n, num_layer) @@ -742,37 +809,41 @@ def groupwise_neutron_heating_in_layer( ) @summarize_values - def groupwise_neutron_flux_at( + def groupwise_neutron_heating_at( self, n: int, x: float | npt.NDArray ) -> float | npt.NDArray: """ - Neutron flux [m^-2 s^-1] anywhere. Neutron flux is assumed to be - unperturbed once it leaves the final layer. + Neutron heating [W m^-3] of the n-th group in the specified layer, + at location x [m]. Parameters ---------- n: - Neutron group index. n <= n_groups - 1. - Therefore n=0 shows the flux for group 1, n=1 for group 2, etc. + The index of the neutron group whose heating is being evaluated. + n <= n_groups - 1. + Therefore n=0 shows the heating for group 1, n=1 for group 2, etc. + num_layer: + The index of the layer that we want to get the neutron heating for. x: - The depth where we want the neutron flux [m]. Out-of-bounds x would - be clipped back to bound. + The position where the neutron heating has to be evaluated. + + Returns + ------- + heating: + Volumetric neutron heating due to group n's neutrons at x. """ if np.isscalar(x): - return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.clip(np.asarray(x), -self.layer_x[-1], self.layer_x[-1]) + return groupwise_neutron_heating_at(n, num_layer, [x])[0] - out_flux = np.zeros_like(x) + out_heat = np.zeros_like(x) abs_x = abs(x) - for num_layer, (xmin, xmax) in enumerate(pairwise(self.interface_x)): - in_layer = xmin <= abs_x < xmax - if num_layer==(self.n_layers-1): - in_layer = xmin <= abs_x <= xmax + for num_layer in range(self.n_layers + 1): + in_layer = self._check_if_in_layer(x, num_layer) if in_layer.any(): - out_flux[in_layer] = self.groupwise_neutron_flux_in_layer( + out_heat[in_layer] = self.groupwise_neutron_heating_in_layer( n, num_layer, x[in_layer] ) - return out_flux + return out_heat @summarize_values def groupwise_neutron_current_in_layer( @@ -787,10 +858,14 @@ def groupwise_neutron_current_in_layer( The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. num_layer: - The index of the layer that we want to get the neutron flux for. + The index of the layer that we want to get the neutron current for. x: - The depth where we want the neutron flux [m]. + The depth where we want the neutron current [m]. """ + if num_layer==self.n_layers: + return self.groupwise_neutron_current_in_layer( + n, self.n_layers-1, np.sign(x) * self.layer_x[-1] + ) differentials = [] for g in range(n + 1): l2g = self.l2[num_layer, g] @@ -835,19 +910,19 @@ def groupwise_neutron_current_at( Neutron group index. n <= n_groups - 1. Therefore n=0 shows the neutron current for group 1, n=1 for group 2, etc. x: - The depth where we want the neutron current [m]. Out-of-bounds x - would be clipped back to bound. + The depth where we want the neutron current [m]. Neutron current at + infinity is assumed to be the same as the neutron flux at the + nearest layer-void interface; this is achieved by clipping all out- + of-bounds x back to the the nearest interface_x. """ if np.isscalar(x): - return self.groupwise_neutron_flux_at(n, [x])[0] - x = np.clip(np.asarray(x), -self.layer_x[-1], self.layer_x[-1]) + return self.groupwise_neutron_current_at(n, [x])[0] + x = np.asarray(x) current = np.zeros_like(x) abs_x = abs(x) - for num_layer, (xmin, xmax) in enumerate(pairwise(self.interface_x)): - in_layer = xmin <= abs_x < xmax - if num_layer==(self.n_layers-1): - in_layer = xmin <= abs_x <= xmax + for num_layer in range(self.n_layers + 1): + in_layer = self._check_if_in_layer(x, num_layer) if in_layer.any(): current[in_layer] = self.groupwise_neutron_current_in_layer( n, num_layer, x[in_layer] @@ -927,8 +1002,10 @@ def groupwise_integrated_flux_in_layer( The index of the neutron group that needs to be solved. n <= n_groups - 1. Therefore n=0 shows the integrated flux for group 1, n=1 for group 2, etc. num_layer: - The index of the layer that we want to get the neutron flux for. + The index of the layer that we want to get the integrated flux for. """ + if num_layer==self.n_layers: + return np.nan integrals = [] # set integration limits x_start = self.layer_x[num_layer-1] @@ -970,6 +1047,8 @@ def groupwise_integrated_heating_in_layer( yield the same result as integrating the curve neutron_heating_in_layer from self.interface_x[n] to self.interface_x[n+1]. """ + if num_layer==self.n_layers: + return 0.0 return ( self.groupwise_linear_heating_density_in_layer(n, num_layer) * self.groupwise_integrated_flux_in_layer(n, num_layer) @@ -988,6 +1067,8 @@ def groupwise_linear_heating_density_in_layer( its energy in the n,2n reaction, but we hope this is a small enough error that we can overlook it. """ + if num_layer==self.n_layers: + return 0.0 mat = self.materials[num_layer] non_scatter_xs = mat.sigma_t[n] - mat.sigma_s[n,:].sum() lost_energy = ( @@ -1021,6 +1102,7 @@ def plot( *, plot_groups: bool = True, symmetric: bool = True, + extend_plot_beyond_boundary: bool=True, n_points: int = 100, ): """ @@ -1052,11 +1134,11 @@ def plot( groupwise_function = getattr(self, f"groupwise_{method_name}") x_ranges = _generate_x_range( self.interface_x.copy(), - max(self.extended_boundary.values()), + max(self.extended_boundary.values()) if extend_plot_beyond_boundary else None, min_total_num_points=n_points, symmetric=symmetric ) - for num_layer in range(self.n_layers): + for num_layer in range(self.n_layers + bool(extend_plot_beyond_boundary)): if symmetric: neg_x = next(x_ranges) ax.plot(neg_x, total_function(num_layer, neg_x), color="black") @@ -1113,10 +1195,10 @@ def _plot_vertical_dotted_line(ax, x, ylims, *, symmetric: bool=True): def _generate_x_range( interface_x: npt.NDArray[np.float64], - extended_boundary: float | None, + extension_to_be_plotted: float | None=None, *, - min_total_num_points: int, - symmetric: bool, + min_total_num_points: int=100, + symmetric: bool=True, ): """Helper generator for finding the range of x-values to be plotted. @@ -1152,8 +1234,17 @@ def _generate_x_range( for num_layer, (xmin, xmax) in enumerate(pairwise(interface_x)): num_points = np.logical_and(xmin Date: Mon, 24 Nov 2025 02:31:16 +0000 Subject: [PATCH 85/98] Does not allow higher energy bins than the incident neutron energy to exist without first re-writing solve_lowest_group --- process/neutronics.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 3597f5b7fa..1f6f9c6d08 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -473,7 +473,7 @@ def _calculate_mean_energy( high, low = group_structure[:-1], group_structure[1:] weighted_mean = (high - low)/(np.log(high)- np.log(low)) # unweighted_mean = np.mean([high, low], axis=0) - first_bin = np.logical_and(high>init_neutron_e, init_neutron_e>=low) + first_bin = np.logical_and(low<=init_neutron_e, init_neutron_e1: raise ValueError( - "The energy of neutrons incident from the plasma is NOT captured by the group " - "structure!" + "The energy of neutrons incident from the plasma is captured " + "multiple times, by more than one bin in the group structure!" + ) + if not first_bin[0]: + raise NotImplementedError( + "If init_neutron_e does not sit inside the lowest lethargy " + "group, then solve_lowest_group would have to be re-written." ) weighted_mean[first_bin] = init_neutron_e return weighted_mean From 919d743871bf6411d99f66d8288e81b28857d8ad Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 24 Nov 2025 02:40:15 +0000 Subject: [PATCH 86/98] Further modification to include a new attribute incident_neutron_group while keeping _calculate_mean_energy_and_incident_bin as a staticmethod. --- process/neutronics.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 1f6f9c6d08..9cb4014835 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -369,8 +369,11 @@ def __init__( Number of groups in the group structure group_structure: Energy bin edges, 1D array of len = n_groups+1 - energy: - The mean neutron energy of each group. + group_energy: + The average neutron energy of each group. + incident_neutron_group: + The group index (n) of the neutron group that contains the incident + (monoenergetic) plasma neutron's energy. coefficients: Coefficients that determine the flux shape (and therefore reaction @@ -419,8 +422,10 @@ def __init__( ) self.n_groups = fw_mat.n_groups self.group_structure = fw_mat.group_structure - self.group_energy = self._calculate_mean_energy( - self.group_structure, self.init_neutron_energy + self.group_energy, self.incident_neutron_group = ( + self._calculate_mean_energy_and_incident_bin( + self.group_structure, self.init_neutron_energy + ) ) mat_name_list = [mat.name for mat in self.materials] @@ -439,11 +444,11 @@ def __init__( ) @staticmethod - def _calculate_mean_energy( + def _calculate_mean_energy_and_incident_bin( group_structure: npt.NDArray[np.float64], init_neutron_e: float, ) -> npt.NDArray[np.float64]: """ - Calculate the mean energy of each neutron group in Joule. + Calculate the average energy of each neutron group in Joule. When implementing this method, we can choose either a weighted mean or an unweighted mean. The weighted mean (where neutron flux is assumed constant w.r.t. neutorn lethargy within the bin) is more accurate, but @@ -464,7 +469,7 @@ def _calculate_mean_energy( Returns ------- - mean_neutron_e: + avg_neutron_e: Mean energy of neutrons. The bin containing init_neutron_e (likely the highest energy bin, i.e. bin[0]) is assumed to be dominated by the unscattered neutrons entering from the plasma, @@ -474,6 +479,7 @@ def _calculate_mean_energy( weighted_mean = (high - low)/(np.log(high)- np.log(low)) # unweighted_mean = np.mean([high, low], axis=0) first_bin = np.logical_and(low<=init_neutron_e, init_neutron_e None: """ From 1e625429c8861500e91b4dfd3a1a34ca8478f09d Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 24 Nov 2025 02:45:16 +0000 Subject: [PATCH 87/98] Removed conservation of neutrons condition entirely. --- process/neutronics.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 9cb4014835..392c1753b8 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -658,31 +658,16 @@ def _evaluate_fit(): flux_at_boundary = self.groupwise_neutron_flux_in_layer( n, self.n_layers - 1, self.extended_boundary[n] ) - # conservation condition - influx, removal = 0.0, 0.0 - for g in range(self.n_groups): - if g > n and not first_iteration: - for num_layer, mat in self.materials: - if not mat.downscatter_only: - influx += (mat.sigma_s[g, n] + mat.sigma_in[g, n]) * self.groupwise_integrated_flux_in_layer(g, num_layer) - elif g <= n: - for num_layer, mat in self.materials: - influx += (mat.sigma_s[g, n] + mat.sigma_in[g, n]) * self.groupwise_integrated_flux_in_layer(g, num_layer) - for num_layer, mat in self.materials: - removal += mat.sigma_t[n] * self.groupwise_integrated_flux_in_layer(n, num_layer) - # conservation_fw = influx_fw - removal_fw - current_fw2bz - # conservation_bz = current_fw2bz + influx_bz - removal_bz - escaped_bz - total_neutron_conservation = influx - removal - self.groupwise_neutron_current_escaped(n) - - conditions = [flux_at_boundary, total_neutron_conservation] + + conditions = [flux_at_boundary] # enforce continuity conditions for num_layer in range(self.n_layers - 1): x = self.layer_x[num_layer] flux_continuity = self.groupwise_neutron_flux_in_layer(n, num_layer, x) - self.groupwise_neutron_flux_in_layer(n, num_layer + 1, x) current_continuity = self.groupwise_neutron_current_in_layer(n, num_layer, x) - self.groupwise_neutron_current_in_layer(n, num_layer + 1, x) - conditions.append(flux_continuity) - conditions.append(current_continuity) + conditions.append(flux_continuity) + conditions.append(current_continuity) # TODO: there may be one more condition that I should impose: the slope at x=0 should be 0. return np.array(conditions) From 7b355ab584483c0e089b6ae642ad24e53923b0df Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 24 Nov 2025 10:41:15 +0000 Subject: [PATCH 88/98] Fix the list of conditions so it's no longer singular --- process/neutronics.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 392c1753b8..92ea108d54 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -654,21 +654,35 @@ def _set_coefficients(input_vector: Iterable[float]): self.coefficients[num_layer, n].s[n] = input_vector[i+1] def _evaluate_fit(): - # zero flux condition - flux_at_boundary = self.groupwise_neutron_flux_in_layer( - n, self.n_layers - 1, self.extended_boundary[n] + # Enforce zero net current flowing out of the plasma. + no_net_current_at_zero = self.groupwise_neutron_current_in_layer( + n, 0, 0.0 ) + conditions = [no_net_current_at_zero] - conditions = [flux_at_boundary] - - # enforce continuity conditions + # Enforce continuity conditions. for num_layer in range(self.n_layers - 1): x = self.layer_x[num_layer] - flux_continuity = self.groupwise_neutron_flux_in_layer(n, num_layer, x) - self.groupwise_neutron_flux_in_layer(n, num_layer + 1, x) - current_continuity = self.groupwise_neutron_current_in_layer(n, num_layer, x) - self.groupwise_neutron_current_in_layer(n, num_layer + 1, x) + flux_continuity = ( + self.groupwise_neutron_flux_in_layer(n, num_layer, x) + - self.groupwise_neutron_flux_in_layer( + n, num_layer + 1, x + ) + ) + current_continuity = ( + self.groupwise_neutron_current_in_layer(n, num_layer, x) + - self.groupwise_neutron_current_in_layer( + n, num_layer + 1, x + ) + ) conditions.append(flux_continuity) conditions.append(current_continuity) - # TODO: there may be one more condition that I should impose: the slope at x=0 should be 0. + + # Enforce zero flux at extended boundary + flux_at_extended_boundary = self.groupwise_neutron_flux_in_layer( + n, self.n_layers - 1, self.extended_boundary[n] + ) + conditions.append(flux_at_extended_boundary) return np.array(conditions) def objective(coefficients_vector): From b9bf9f848da3f14d4c3bca014f2daffb32c9ed1a Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 24 Nov 2025 10:53:00 +0000 Subject: [PATCH 89/98] Bug fixes prompted by ruff --- process/neutronics.py | 343 ++++++++++++++++++++++--------------- process/neutronics_data.py | 8 +- 2 files changed, 210 insertions(+), 141 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 92ea108d54..ce16ebb87a 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -5,9 +5,9 @@ import functools import inspect -from itertools import pairwise from collections.abc import Callable, Iterable from dataclasses import asdict, dataclass +from itertools import pairwise import numpy as np from matplotlib import pyplot as plt @@ -15,7 +15,7 @@ from scipy import optimize from process.exceptions import ProcessValidationError, ProcessValueError -from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E +from process.neutronics_data import DT_NEUTRON_E, MaterialMacroInfo def summarize_values(func): @@ -141,7 +141,7 @@ class Coefficients: group n=0: NeutronFluxProfile.coefficients[0, 0] = Coefficients(...) fw_grp0 = NeutronFluxProfile.coefficients[0, 0] flux = fw_grp0.c[0] * cosh(x/L[0]) + fw_grp0.s[0] * sinh(x/L[0]) - + group n=1: NeutronFluxProfile.coefficients[0, 1] = Coefficients(...) fw_grp1 = NeutronFluxProfile.coefficients[0, 1] flux = fw_grp1.c[0] * cosh(x/L[0]) + fw_grp1.c[1] * cosh(x/L[1]) @@ -157,8 +157,8 @@ def validate_length(self, exp_len: int, parent_name: str): for const_name, const_value in asdict(self).items(): if len(const_value) != exp_len: raise ProcessValueError( - f"{parent_name}'s [{exp_len-1}]-th item is expected to " - "have .{const_name} of length={exp_len}, but instead got " + f"{parent_name}'s [{exp_len - 1}]-th item is expected to " + f"have .{const_name} of length={exp_len}, but instead got " f"{const_value}." ) @@ -222,9 +222,16 @@ def values(self): def __repr__(self): return f"AutoPopulatingDict({self.name}):{self._dict}" + class LayerSpecificGroupwiseConstants: """An object containing multiple AutoPopulatingDict""" - def __init__(self, populating_method: Callable[[int], None], layer_names: list[str], quantity_description: str): + + def __init__( + self, + populating_method: Callable[[int], None], + layer_names: list[str], + quantity_description: str, + ): """ Create an object that contains as many AutoPopulatingDict as there are items in layer_names. @@ -259,14 +266,14 @@ def __iter__(self): def __len__(self) -> int: return len(self._dicts) - + def __setitem__(self, index: int | tuple[int, int], value): """ Act as if this is a 2D array, where the first-axis is the layer and the - second axis is the group. support slice of the thing, + second axis is the group. support slice of the thing, """ - if isinstance(index, tuple) and len(index)>=2: - if len(index)>2: + if isinstance(index, tuple) and len(index) >= 2: + if len(index) > 2: raise IndexError("2D array indexed with more than 2 indices!") layer_index, group_index = index self._dicts[layer_index][group_index] = value @@ -278,14 +285,14 @@ def __getitem__(self, index: int | tuple[int, int]): Act as if this is a 2D array, where the first-axis is the layer and the second axis is the group. Handle slices as well. """ - if isinstance(index, tuple) and len(index)>=2: - if len(index)>2: + if isinstance(index, tuple) and len(index) >= 2: + if len(index) > 2: raise IndexError("2D array indexed with more than 2 indices!") layer_index, group_index = index if isinstance(layer_index, slice): - return tuple( - [_dict[group_index] for _dict in self._dicts[layer_index]] - ) + return tuple([ + _dict[group_index] for _dict in self._dicts[layer_index] + ]) return self._dicts[layer_index][group_index] return self._dicts[index] @@ -310,6 +317,7 @@ def has_populated(self, n: int) -> bool: def __repr__(self): return f"A tuple of {self.n_layers} layers of {self._name}" + UNIT_LOOKUP = { "integrated_flux": "m^-1 s^-1", "integrated_heating": "W m^-2", @@ -319,6 +327,7 @@ def __repr__(self): "heating": "W m^-3", } + class NeutronFluxProfile: """ Calculate the neutron flux, neutron current, and neutron heating in the @@ -394,9 +403,9 @@ def __init__( # layers self.layer_x = np.array(layer_x).ravel() - if not (np.diff(self.layer_x)>0).all(): + if not (np.diff(self.layer_x) > 0).all(): raise ValueError( - f"Model cannot have non-positive layer thicknesses." + "Model cannot have non-positive layer thicknesses." ) self.layer_x.flags.writeable = False @@ -415,7 +424,9 @@ def __init__( fw_mat = self.materials[0] for mat in self.materials[1:]: if not np.allclose( - fw_mat.group_structure, mat.group_structure, atol=0, + fw_mat.group_structure, + mat.group_structure, + atol=0, ): raise ProcessValidationError( "All material info must have the same group structure!" @@ -433,8 +444,9 @@ def __init__( self.solve_group_n, mat_name_list, "Coefficients" ) self.l2 = LayerSpecificGroupwiseConstants( - self.solve_group_n, mat_name_list, - "Characteristic diffusion length squared" + self.solve_group_n, + mat_name_list, + "Characteristic diffusion length squared", ) self.diffusion_const = LayerSpecificGroupwiseConstants( self.solve_group_n, mat_name_list, "Diffusion coefficient D" @@ -445,7 +457,8 @@ def __init__( @staticmethod def _calculate_mean_energy_and_incident_bin( - group_structure: npt.NDArray[np.float64], init_neutron_e: float, + group_structure: npt.NDArray[np.float64], + init_neutron_e: float, ) -> npt.NDArray[np.float64]: """ Calculate the average energy of each neutron group in Joule. @@ -473,24 +486,26 @@ def _calculate_mean_energy_and_incident_bin( Mean energy of neutrons. The bin containing init_neutron_e (likely the highest energy bin, i.e. bin[0]) is assumed to be dominated by the unscattered neutrons entering from the plasma, - therefore it is + therefore it is """ high, low = group_structure[:-1], group_structure[1:] - weighted_mean = (high - low)/(np.log(high)- np.log(low)) + weighted_mean = (high - low) / (np.log(high) - np.log(low)) # unweighted_mean = np.mean([high, low], axis=0) - first_bin = np.logical_and(low<=init_neutron_e, init_neutron_e1: + if first_bin.sum() > 1: raise ValueError( "The energy of neutrons incident from the plasma is captured " "multiple times, by more than one bin in the group structure!" ) - if incident_neutron_group!=0: + if incident_neutron_group != 0: raise NotImplementedError( "If init_neutron_e does not sit inside the lowest lethargy " "group, then solve_lowest_group would have to be re-written." @@ -509,18 +524,23 @@ def solve_lowest_group(self) -> None: if self.coefficients.has_populated(n): return # skip if it has already been solved. for num_layer, mat in enumerate(self.materials): - self.diffusion_const[num_layer, n], self.l2[num_layer, n] = get_diffusion_coefficient_and_length( - mat.avg_atomic_mass, - mat.sigma_t[n], - mat.sigma_s[n, n], - mat.sigma_in[n, n], + self.diffusion_const[num_layer, n], self.l2[num_layer, n] = ( + get_diffusion_coefficient_and_length( + mat.avg_atomic_mass, + mat.sigma_t[n], + mat.sigma_s[n, n], + mat.sigma_in[n, n], + ) ) self.extended_boundary[n] = self.layer_x[-1] + extrapolation_length( self.diffusion_const[-1, n] ) if self.n_layers == 2: - l_fw, l_bz = np.sqrt(abs(self.l2[0, n])), np.sqrt(abs(self.l2[1, n])) - x_fw, = self.layer_x[:-1] + l_fw, l_bz = ( + np.sqrt(abs(self.l2[0, n])), + np.sqrt(abs(self.l2[1, n])), + ) + (x_fw,) = self.layer_x[:-1] d_fw, d_bz = self.diffusion_const[0, n], self.diffusion_const[1, n] if self.l2[0, n] > 0: s_fw = np.sinh(x_fw / l_fw) @@ -560,8 +580,12 @@ def solve_lowest_group(self) -> None: bz_c_factor = bz_common_factor * s_bz bz_s_factor = -bz_common_factor * c_bz - self.coefficients[0, n] = Coefficients([fw_c_factor], [fw_s_factor]) - self.coefficients[1, n] = Coefficients([bz_c_factor], [bz_s_factor]) + self.coefficients[0, n] = Coefficients( + [fw_c_factor], [fw_s_factor] + ) + self.coefficients[1, n] = Coefficients( + [bz_c_factor], [bz_s_factor] + ) else: raise NotImplementedError("Only implemented 2 groups so far.") return @@ -599,17 +623,18 @@ def solve_group_n(self, n: int) -> None: # only systems by iterating. first_iteration = True for num_layer, mat in enumerate(self.materials): - self.diffusion_const[num_layer, n], self.l2[num_layer, n] = get_diffusion_coefficient_and_length( - mat.avg_atomic_mass, - mat.sigma_t[n], - mat.sigma_s[n, n], - mat.sigma_in[n, n], + self.diffusion_const[num_layer, n], self.l2[num_layer, n] = ( + get_diffusion_coefficient_and_length( + mat.avg_atomic_mass, + mat.sigma_t[n], + mat.sigma_s[n, n], + mat.sigma_in[n, n], + ) ) self.extended_boundary[n] = self.layer_x[-1] + extrapolation_length( self.diffusion_const[-1, n] ) - for num_layer in range(self.n_layers): # Setting up aliases for shorter code _coefs = Coefficients([], []) @@ -623,7 +648,7 @@ def solve_group_n(self, n: int) -> None: # cosh/sinh anyways, therefore we can set the coefficient to 0. scale_factor = 0.0 l2n, l2g = self.l2[num_layer, n], self.l2[num_layer, g] - if not np.isclose(l2_diff:=(l2g - l2n), 0): + if not np.isclose(l2_diff := (l2g - l2n), 0): scale_factor = (l2n * l2g) / diffusion_const_n / l2_diff _coefs.c.append( sum( @@ -646,12 +671,11 @@ def solve_group_n(self, n: int) -> None: _coefs.s.append(s_factor_guess) self.coefficients[num_layer, n] = _coefs - def _set_coefficients(input_vector: Iterable[float]): for num_layer in range(self.n_layers): i = num_layer * 2 self.coefficients[num_layer, n].c[n] = input_vector[i] - self.coefficients[num_layer, n].s[n] = input_vector[i+1] + self.coefficients[num_layer, n].s[n] = input_vector[i + 1] def _evaluate_fit(): # Enforce zero net current flowing out of the plasma. @@ -663,17 +687,13 @@ def _evaluate_fit(): # Enforce continuity conditions. for num_layer in range(self.n_layers - 1): x = self.layer_x[num_layer] - flux_continuity = ( - self.groupwise_neutron_flux_in_layer(n, num_layer, x) - - self.groupwise_neutron_flux_in_layer( - n, num_layer + 1, x - ) - ) - current_continuity = ( - self.groupwise_neutron_current_in_layer(n, num_layer, x) - - self.groupwise_neutron_current_in_layer( - n, num_layer + 1, x - ) + flux_continuity = self.groupwise_neutron_flux_in_layer( + n, num_layer, x + ) - self.groupwise_neutron_flux_in_layer(n, num_layer + 1, x) + current_continuity = self.groupwise_neutron_current_in_layer( + n, num_layer, x + ) - self.groupwise_neutron_current_in_layer( + n, num_layer + 1, x ) conditions.append(flux_continuity) conditions.append(current_continuity) @@ -689,7 +709,10 @@ def objective(coefficients_vector): _set_coefficients(coefficients_vector) return _evaluate_fit() - x0 = np.flatten([[layer_coefs[n].c[n], layer_coefs[n].s[n]] for layer_coefs in self.coefficients]) + x0 = np.flatten([ + [layer_coefs[n].c[n], layer_coefs[n].s[n]] + for layer_coefs in self.coefficients + ]) results = optimize.root(objective, x0=x0) _set_coefficients(results.res) return None @@ -697,16 +720,17 @@ def objective(coefficients_vector): def _check_if_in_layer( self, x: npt.NDArray[np.float64], num_layer: int ) -> npt.NDArray[bool]: - if num_layer==(self.n_layers-1): + abs_x = abs(x) + if num_layer == (self.n_layers - 1): return np.logical_and( - self.interface_x[num_layer]<=abs(x), - abs(x)<=self.interface_x[num_layer+1] + self.interface_x[num_layer] <= abs_x, + abs_x <= self.interface_x[num_layer + 1], ) - elif num_layer==self.n_layers: - return abs(x)>self.interface_x[-1] + if num_layer == self.n_layers: + return abs_x > self.interface_x[-1] return np.logical_and( - self.interface_x[num_layer]<=abs(x), - abs(x)<=self.interface_x[num_layer+1] + self.interface_x[num_layer] <= abs_x, + abs_x <= self.interface_x[num_layer + 1], ) @summarize_values @@ -733,11 +757,12 @@ def groupwise_neutron_flux_in_layer( flux: Neutron flux at x meter from the first wall. """ - if num_layer==self.n_layers: + if num_layer == self.n_layers: return self.groupwise_neutron_flux_in_layer( - n, self.n_layers-1, np.sign(x) * self.layer_x[-1] + n, self.n_layers - 1, np.sign(x) * self.layer_x[-1] ) trig_funcs = [] + abs_x = abs(x) for g in range(n + 1): if self.l2[num_layer, g] > 0: c, s = np.cosh, np.sinh @@ -745,11 +770,14 @@ def groupwise_neutron_flux_in_layer( else: c, s = np.cos, np.sin l = np.sqrt(-self.l2[num_layer, g]) - trig_funcs.append(self.coefficients[num_layer, n].c[g] * c(abs(x) / l)) - trig_funcs.append(self.coefficients[num_layer, n].s[g] * s(abs(x) / l)) + trig_funcs.append( + self.coefficients[num_layer, n].c[g] * c(abs_x / l) + ) + trig_funcs.append( + self.coefficients[num_layer, n].s[g] * s(abs_x / l) + ) return np.sum(trig_funcs, axis=0) - @summarize_values def groupwise_neutron_flux_at( self, n: int, x: float | npt.NDArray @@ -774,7 +802,6 @@ def groupwise_neutron_flux_at( x = np.asarray(x) out_flux = np.zeros_like(x) - abs_x = abs(x) for num_layer in range(self.n_layers + 1): in_layer = self._check_if_in_layer(x, num_layer) if in_layer.any(): @@ -805,18 +832,17 @@ def groupwise_neutron_heating_in_layer( num_layer: The index of the layer that we want to get the neutron heating for. x: - The depth where we want the neutron heating [m]. - + The depth where we want the neutron heating [m]. + Returns ------- : The neutron heating in that specific layer at position x, due to group n's neutrons. """ - return ( - self.groupwise_linear_heating_density_in_layer(n, num_layer) - * self.groupwise_neutron_flux_in_layer(n, num_layer, x) - ) + return self.groupwise_linear_heating_density_in_layer( + n, num_layer + ) * self.groupwise_neutron_flux_in_layer(n, num_layer, x) @summarize_values def groupwise_neutron_heating_at( @@ -843,10 +869,9 @@ def groupwise_neutron_heating_at( Volumetric neutron heating due to group n's neutrons at x. """ if np.isscalar(x): - return groupwise_neutron_heating_at(n, num_layer, [x])[0] + return self.groupwise_neutron_heating_at(n, [x])[0] out_heat = np.zeros_like(x) - abs_x = abs(x) for num_layer in range(self.n_layers + 1): in_layer = self._check_if_in_layer(x, num_layer) if in_layer.any(): @@ -872,11 +897,12 @@ def groupwise_neutron_current_in_layer( x: The depth where we want the neutron current [m]. """ - if num_layer==self.n_layers: + if num_layer == self.n_layers: return self.groupwise_neutron_current_in_layer( - n, self.n_layers-1, np.sign(x) * self.layer_x[-1] + n, self.n_layers - 1, np.sign(x) * self.layer_x[-1] ) differentials = [] + abs_x = abs(x) for g in range(n + 1): l2g = self.l2[num_layer, g] if l2g > 0: @@ -884,27 +910,31 @@ def groupwise_neutron_current_in_layer( differentials.append( self.coefficients[num_layer, n].c[g] / l - * np.sinh(abs(x) / l) + * np.sinh(abs_x / l) ) differentials.append( self.coefficients[num_layer, n].s[g] / l - * np.cosh(abs(x) / l) + * np.cosh(abs_x / l) ) else: l = np.sqrt(-l2g) differentials.append( -self.coefficients[num_layer, n].c[g] / l - * np.sin(abs(x) / l) + * np.sin(abs_x / l) ) differentials.append( self.coefficients[num_layer, n].s[g] / l - * np.cos(abs(x) / l) + * np.cos(abs_x / l) ) - - return -self.diffusion_const[num_layer, n] * np.sum(differentials, axis=0) * _get_sign_of(x) + + return ( + -self.diffusion_const[num_layer, n] + * np.sum(differentials, axis=0) + * _get_sign_of(x) + ) @summarize_values def groupwise_neutron_current_at( @@ -930,7 +960,6 @@ def groupwise_neutron_current_at( x = np.asarray(x) current = np.zeros_like(x) - abs_x = abs(x) for num_layer in range(self.n_layers + 1): in_layer = self._check_if_in_layer(x, num_layer) if in_layer.any(): @@ -941,7 +970,7 @@ def groupwise_neutron_current_at( @summarize_values def groupwise_neutron_current_through_interface( - self, n: int, n_interface: int, *, default_to_inner_layer : bool=True + self, n: int, n_interface: int, *, default_to_inner_layer: bool = True ) -> float: """ Net current from left to right on the positive side of the model, at @@ -967,15 +996,16 @@ def groupwise_neutron_current_through_interface( x = self.interface_x[n_interface] if default_to_inner_layer: - if n_interface==0: + if n_interface == 0: return self.groupwise_neutron_current_in_layer(n, 0, x) - return self.groupwise_neutron_current_in_layer(n, n_interface-1, x) - else: - if n_interface==self.n_layers: - return self.groupwise_neutron_current_in_layer( - n, self.n_layers-1, x - ) - return self.groupwise_neutron_current_in_layer(n, n_interface, x) + return self.groupwise_neutron_current_in_layer( + n, n_interface - 1, x + ) + if n_interface == self.n_layers: + return self.groupwise_neutron_current_in_layer( + n, self.n_layers - 1, x + ) + return self.groupwise_neutron_current_in_layer(n, n_interface, x) @summarize_values def groupwise_neutron_current_escaped(self, n: int) -> float: @@ -1014,12 +1044,12 @@ def groupwise_integrated_flux_in_layer( num_layer: The index of the layer that we want to get the integrated flux for. """ - if num_layer==self.n_layers: + if num_layer == self.n_layers: return np.nan integrals = [] # set integration limits - x_start = self.layer_x[num_layer-1] - if num_layer==0: + x_start = self.layer_x[num_layer - 1] + if num_layer == 0: x_start = 0.0 x_end = self.layer_x[num_layer] @@ -1028,28 +1058,34 @@ def groupwise_integrated_flux_in_layer( if l2g > 0: l = np.sqrt(l2g) integrals.append( - l * self.coefficients[num_layer, n].c[g] + l + * self.coefficients[num_layer, n].c[g] * (np.sinh(x_end / l) - np.sinh(x_start / l)) ) integrals.append( - l * self.coefficients[num_layer, n].s[g] + l + * self.coefficients[num_layer, n].s[g] * (np.cosh(x_end / l) - np.cosh(x_start / l)) ) else: l = np.sqrt(-l2g) integrals.append( - l * self.coefficients[num_layer, n].c[g] + l + * self.coefficients[num_layer, n].c[g] * (np.sin(x_end / l) - np.sin(x_start / l)) ) integrals.append( - -l * self.coefficients[num_layer, n].s[g] + -l + * self.coefficients[num_layer, n].s[g] * (np.cos(x_end / l) - np.cos(x_start / l)) ) return np.sum(integrals, axis=0) @summarize_values def groupwise_integrated_heating_in_layer( - self, n: int, num_layer: int, + self, + n: int, + num_layer: int, ) -> float: """ The total amount of heat produced (per unit area) due to neutron @@ -1057,17 +1093,18 @@ def groupwise_integrated_heating_in_layer( yield the same result as integrating the curve neutron_heating_in_layer from self.interface_x[n] to self.interface_x[n+1]. """ - if num_layer==self.n_layers: + if num_layer == self.n_layers: return 0.0 - return ( - self.groupwise_linear_heating_density_in_layer(n, num_layer) - * self.groupwise_integrated_flux_in_layer(n, num_layer) - ) + return self.groupwise_linear_heating_density_in_layer( + n, num_layer + ) * self.groupwise_integrated_flux_in_layer(n, num_layer) # Do NOT add a summarize_values decorator, as you can't add cross-sections # from different groups together without first multiplying by flux to get reaction rate. def groupwise_linear_heating_density_in_layer( - self, n: int, num_layer: int, + self, + n: int, + num_layer: int, ) -> float: """ unit: [J m^-1] @@ -1077,12 +1114,12 @@ def groupwise_linear_heating_density_in_layer( its energy in the n,2n reaction, but we hope this is a small enough error that we can overlook it. """ - if num_layer==self.n_layers: + if num_layer == self.n_layers: return 0.0 mat = self.materials[num_layer] - non_scatter_xs = mat.sigma_t[n] - mat.sigma_s[n,:].sum() + non_scatter_xs = mat.sigma_t[n] - mat.sigma_s[n, :].sum() lost_energy = ( - (self.group_energy[n] - self.group_energy) * mat.sigma_s[n,:] + (self.group_energy[n] - self.group_energy) * mat.sigma_s[n, :] ).sum() return self.group_energy[n] * non_scatter_xs + lost_energy @@ -1104,6 +1141,7 @@ def get_output_unit(cls, method: Callable) -> str | None: for quantity, unit in UNIT_LOOKUP.items(): if quantity in method.__name__: return unit + return None def plot( self, @@ -1112,7 +1150,7 @@ def plot( *, plot_groups: bool = True, symmetric: bool = True, - extend_plot_beyond_boundary: bool=True, + extend_plot_beyond_boundary: bool = True, n_points: int = 100, ): """ @@ -1144,47 +1182,69 @@ def plot( groupwise_function = getattr(self, f"groupwise_{method_name}") x_ranges = _generate_x_range( self.interface_x.copy(), - max(self.extended_boundary.values()) if extend_plot_beyond_boundary else None, + max(self.extended_boundary.values()) + if extend_plot_beyond_boundary + else None, min_total_num_points=n_points, - symmetric=symmetric + symmetric=symmetric, ) - for num_layer in range(self.n_layers + bool(extend_plot_beyond_boundary)): + for num_layer in range( + self.n_layers + bool(extend_plot_beyond_boundary) + ): if symmetric: neg_x = next(x_ranges) ax.plot(neg_x, total_function(num_layer, neg_x), color="black") pos_x = next(x_ranges) - plot_dict = {"label": "total"} if num_layer==0 else {} + plot_dict = {"label": "total"} if num_layer == 0 else {} ax.plot( - pos_x, total_function(num_layer, pos_x), - color="black", **plot_dict, + pos_x, + total_function(num_layer, pos_x), + color="black", + **plot_dict, ) if plot_groups: for n in range(self.n_groups): if symmetric: ax.plot( - neg_x, groupwise_function(n, num_layer, neg_x), - color=f"C{n}" + neg_x, + groupwise_function(n, num_layer, neg_x), + color=f"C{n}", ) - plot_dict = {"label": f"group {n}"} if num_layer==0 else {} + plot_dict = ( + {"label": f"group {n}"} if num_layer == 0 else {} + ) ax.plot( - pos_x, groupwise_function(n, num_layer, pos_x), - color=f"C{n}", **plot_dict, + pos_x, + groupwise_function(n, num_layer, pos_x), + color=f"C{n}", + **plot_dict, ) ax.legend() ax.set_title(f"Neutron {quantity} profile") ax.set_xlabel("Distance from the plasma-fw interface [m]") ax.set_ylabel(ylabel) - + # plotting the interfaces for ease of comprehension. ylims = ax.get_ylim() - for (xmin, xmax), mat in zip(pairwise(self.interface_x), self.materials): + for (xmin, xmax), mat in zip( + pairwise(self.interface_x), self.materials, strict=False + ): _plot_vertical_dotted_line(ax, xmin, ylims, symmetric=symmetric) - ax.text(np.mean([xmin, xmax]), 0, mat.name, ha="center", va="center") + ax.text( + np.mean([xmin, xmax]), 0, mat.name, ha="center", va="center" + ) if symmetric: - ax.text(-np.mean([xmin, xmax]), 0, mat.name, ha="center", va="center") + ax.text( + -np.mean([xmin, xmax]), + 0, + mat.name, + ha="center", + va="center", + ) _plot_vertical_dotted_line(ax, xmax, ylims, symmetric=symmetric) return ax + def _get_sign_of(x_values): """ Get sign of any real number, but also forces 0.0 to be +ve and -0.0 to be -ve. @@ -1197,18 +1257,20 @@ def _get_sign_of(x_values): negatives = np.signbit(x_values) return np.array(negatives, dtype=float) * -2 + 1 -def _plot_vertical_dotted_line(ax, x, ylims, *, symmetric: bool=True): + +def _plot_vertical_dotted_line(ax, x, ylims, *, symmetric: bool = True): if symmetric: ax.plot([-x, -x], ylims, color="black", ls="--") ax.plot([x, x], ylims, color="black", ls="--") - return None + return + def _generate_x_range( interface_x: npt.NDArray[np.float64], - extension_to_be_plotted: float | None=None, + extension_to_be_plotted: float | None = None, *, - min_total_num_points: int=100, - symmetric: bool=True, + min_total_num_points: int = 100, + symmetric: bool = True, ): """Helper generator for finding the range of x-values to be plotted. @@ -1241,20 +1303,25 @@ def _generate_x_range( full_x_range = np.linspace( interface_x.min(), interface_x.max(), min_total_num_points ) - for num_layer, (xmin, xmax) in enumerate(pairwise(interface_x)): - num_points = np.logical_and(xmin float: @@ -493,7 +493,9 @@ def __post_init__(self): if (self.group_structure <= 0).any(): warnings.warn("Zero energy (inf. lethargy) not allowed.") - self.group_structure = np.clip(self.group_structure, 1e-9 * EV_TO_J, np.inf) + self.group_structure = np.clip( + self.group_structure, 1e-9 * EV_TO_J, np.inf + ) if (np.diff(self.group_structure) >= 0).any(): raise ValueError( "The group structure must be defined descendingly, from the " From 82d259f7c8405c6f4184318d478b83dd05ef50a9 Mon Sep 17 00:00:00 2001 From: ocean Date: Mon, 24 Nov 2025 10:55:29 +0000 Subject: [PATCH 90/98] Ruff fixes for tests too --- tests/regression/test_neutronics.py | 54 +++++++++----- tests/unit/test_neutronics.py | 105 ++++++++++++++++++---------- 2 files changed, 104 insertions(+), 55 deletions(-) diff --git a/tests/regression/test_neutronics.py b/tests/regression/test_neutronics.py index fb732989dc..435edddab6 100644 --- a/tests/regression/test_neutronics.py +++ b/tests/regression/test_neutronics.py @@ -1,19 +1,19 @@ import numpy as np +from scipy.integrate import trapezoid from process.neutronics import NeutronFluxProfile -from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E, EV_TO_J -from scipy.integrate import trapezoid -from matplotlib import pyplot as plt +from process.neutronics_data import DT_NEUTRON_E, EV_TO_J, MaterialMacroInfo + +MAX_E = DT_NEUTRON_E * 1.01 +MIN_E = 1e-9 * EV_TO_J -max_E = DT_NEUTRON_E * 1.01 -min_E = 1E-9 * EV_TO_J def test_one_group(): """ Regression test against Desmos snapshot: https://www.desmos.com/calculator/18xojespuo """ - dummy = [max_E, min_E] # dummy group structure + dummy = [MAX_E, MIN_E] # dummy group structure # translate from mean-free-path lengths (mfp) to macroscopic cross-sections mfp_fw_s = 118 * 0.01 # [m] mfp_fw_t = 16.65 * 0.01 # [m] @@ -49,10 +49,11 @@ def test_one_group(): assert np.isclose(neutron_profile.neutron_flux_in_layer(1, x_fw), 48.72444) assert np.isclose(neutron_profile.neutron_flux_at(x_fw), 48.72444) - assert np.isclose(neutron_profile.neutron_current_through_interface(1), 22.3980214162) + assert np.isclose( + neutron_profile.neutron_current_through_interface(1), 22.3980214162 + ) assert np.isclose(neutron_profile.neutron_current_escaped(), 1.22047369356) - fw_removal = sigma_fw_t - sigma_fw_s - fw_material.sigma_in[0, 0] bz_removal = sigma_bz_t - sigma_bz_s - bz_material.sigma_in[0, 0] assert np.isclose( @@ -64,19 +65,25 @@ def test_one_group(): x_fw = np.linspace(*neutron_profile.interface_x[0:2], 100000) manually_integrated_heating_fw = trapezoid( - neutron_profile.neutron_heating_in_layer(0, x_fw), x_fw, + neutron_profile.neutron_heating_in_layer(0, x_fw), + x_fw, ) x_bz = np.linspace(*neutron_profile.interface_x[1:3], 100000) manually_integrated_heating_bz = trapezoid( - neutron_profile.neutron_heating_in_layer(1, x_bz), x_bz, + neutron_profile.neutron_heating_in_layer(1, x_bz), + x_bz, ) assert np.isclose( neutron_profile.integrated_heating_in_layer(0), - manually_integrated_heating_fw, atol=0, rtol=1E-8, + manually_integrated_heating_fw, + atol=0, + rtol=1e-8, ), "Correctly integrated heating in FW" assert np.isclose( neutron_profile.integrated_heating_in_layer(1), - manually_integrated_heating_bz, atol=0, rtol=1E-8, + manually_integrated_heating_bz, + atol=0, + rtol=1e-8, ), "Correctly integrated heating in BZ" @@ -86,7 +93,7 @@ def test_one_group_with_fission(): https://www.desmos.com/calculator/cd830add9c Expecting a cosine-shape (dome shape!) of neutron flux profile. """ - dummy = [max_E, min_E] + dummy = [MAX_E, MIN_E] mfp_fw_s = 118 * 0.01 # [m] mfp_fw_t = 16.65 * 0.01 # [m] sigma_fw_t = 1 / mfp_fw_t # [1/m] @@ -111,7 +118,9 @@ def test_one_group_with_fission(): x_fw, x_bz = 5.72 * 0.01, 85 * 0.01 incoming_flux = 41 neutron_profile = NeutronFluxProfile( - incoming_flux, [x_fw, x_bz], [fw_material, bz_material], + incoming_flux, + [x_fw, x_bz], + [fw_material, bz_material], ) assert np.isclose(neutron_profile.l2[1, 0], -((58.2869567709 / 100) ** 2)) assert np.isclose( @@ -131,7 +140,8 @@ def test_one_group_with_fission(): neutron_profile.neutron_flux_in_layer(1, x_fw), ), "Flux continuity assurance" assert np.isclose( - neutron_profile.neutron_current_through_interface(1), -7.6275782637960745 + neutron_profile.neutron_current_through_interface(1), + -7.6275782637960745, ), "Negative current because BZ (breeding) is backflowing into the FW" assert np.isclose( neutron_profile.neutron_current_escaped(), 30.665951670177186 @@ -147,19 +157,25 @@ def test_one_group_with_fission(): ), "Conservation of neutrons" x_fw = np.linspace(*neutron_profile.interface_x[0:2], 100000) manually_integrated_heating_fw = trapezoid( - neutron_profile.neutron_heating_in_layer(0, x_fw), x_fw, + neutron_profile.neutron_heating_in_layer(0, x_fw), + x_fw, ) x_bz = np.linspace(*neutron_profile.interface_x[1:3], 100000) manually_integrated_heating_bz = trapezoid( - neutron_profile.neutron_heating_in_layer(1, x_bz), x_bz, + neutron_profile.neutron_heating_in_layer(1, x_bz), + x_bz, ) assert np.isclose( neutron_profile.integrated_heating_in_layer(0), - manually_integrated_heating_fw, atol=0, rtol=1E-8, + manually_integrated_heating_fw, + atol=0, + rtol=1e-8, ), "Correctly integrated heating in FW" assert np.isclose( neutron_profile.integrated_heating_in_layer(1), - manually_integrated_heating_bz, atol=0, rtol=1E-8, + manually_integrated_heating_bz, + atol=0, + rtol=1e-8, ), "Correctly integrated heating in BZ" diff --git a/tests/unit/test_neutronics.py b/tests/unit/test_neutronics.py index babc740276..68144094d4 100644 --- a/tests/unit/test_neutronics.py +++ b/tests/unit/test_neutronics.py @@ -1,12 +1,17 @@ +import numpy as np import pytest -import numpy as np from process.exceptions import ProcessValidationError -from process.neutronics import NeutronFluxProfile, LayerSpecificGroupwiseConstants, AutoPopulatingDict, _get_sign_of -from process.neutronics_data import MaterialMacroInfo, DT_NEUTRON_E, EV_TO_J +from process.neutronics import ( + AutoPopulatingDict, + LayerSpecificGroupwiseConstants, + NeutronFluxProfile, + _get_sign_of, +) +from process.neutronics_data import DT_NEUTRON_E, EV_TO_J, MaterialMacroInfo -max_E = DT_NEUTRON_E * 1.01 -min_E = 1E-9 * EV_TO_J +MAX_E = DT_NEUTRON_E * 1.01 +MIN_E = 1e-9 * EV_TO_J def test_group_structure_0_energy(): @@ -58,6 +63,7 @@ def test_warn_up_elastic_scatter(): [[0.5, 0.5], [1.0, 1.0]], ) + def test_throw_index_error(): layer_specific_const = LayerSpecificGroupwiseConstants( lambda x: x, ["", ""], ["Dummy constants"] @@ -67,6 +73,7 @@ def test_throw_index_error(): with pytest.raises(IndexError): layer_specific_const[0, 0, 0] = 1 + def test_iter_and_len(): layer_specific_const = LayerSpecificGroupwiseConstants( lambda x: x, ["", ""], ["Dummy constants"] @@ -76,6 +83,7 @@ def test_iter_and_len(): assert len(as_list) == 2 assert isinstance(as_list[0], AutoPopulatingDict) + def test_has_local_fluxes(): """Test that the groupwise decorator has worked on the local fluxes methods.""" assert hasattr(NeutronFluxProfile, "neutron_flux_at") @@ -103,53 +111,78 @@ def test_has_reaction_rates(): assert hasattr(NeutronFluxProfile, "groupwise_integrated_heating_in_layer") assert hasattr(NeutronFluxProfile, "integrated_heating_in_layer") + def test_has_volumetric_heating(): assert hasattr(NeutronFluxProfile, "groupwise_neutron_heating_in_layer") assert hasattr(NeutronFluxProfile, "neutron_heating_in_layer") assert hasattr(NeutronFluxProfile, "groupwise_neutron_heating_at") assert hasattr(NeutronFluxProfile, "neutron_heating_at") + def test_has_plot(): assert hasattr(NeutronFluxProfile, "plot") + def test_units(): nfp = NeutronFluxProfile - assert nfp.get_output_unit(nfp.groupwise_integrated_flux_in_layer)=="m^-1 s^-1" - assert nfp.get_output_unit(nfp.groupwise_integrated_heating_in_layer)=="W m^-2" - assert nfp.get_output_unit(nfp.groupwise_linear_heating_density_in_layer)=="J m^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_current_at)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_current_escaped)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_current_in_layer)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_current_through_interface)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_flux_at)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_flux_in_layer)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.groupwise_neutron_heating_in_layer)=="W m^-3" - assert nfp.get_output_unit(nfp.groupwise_neutron_heating_at)=="W m^-3" - - assert nfp.get_output_unit(nfp.integrated_flux_in_layer)=="m^-1 s^-1" - assert nfp.get_output_unit(nfp.integrated_heating_in_layer)=="W m^-2" - assert nfp.get_output_unit(nfp.neutron_current_at)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.neutron_current_escaped)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.neutron_current_in_layer)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.neutron_current_through_interface)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.neutron_flux_at)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.neutron_flux_in_layer)=="m^-2 s^-1" - assert nfp.get_output_unit(nfp.neutron_heating_in_layer)=="W m^-3" - assert nfp.get_output_unit(nfp.neutron_heating_at)=="W m^-3" + assert ( + nfp.get_output_unit(nfp.groupwise_integrated_flux_in_layer) + == "m^-1 s^-1" + ) + assert ( + nfp.get_output_unit(nfp.groupwise_integrated_heating_in_layer) + == "W m^-2" + ) + assert ( + nfp.get_output_unit(nfp.groupwise_linear_heating_density_in_layer) + == "J m^-1" + ) + assert nfp.get_output_unit(nfp.groupwise_neutron_current_at) == "m^-2 s^-1" + assert ( + nfp.get_output_unit(nfp.groupwise_neutron_current_escaped) + == "m^-2 s^-1" + ) + assert ( + nfp.get_output_unit(nfp.groupwise_neutron_current_in_layer) + == "m^-2 s^-1" + ) + assert ( + nfp.get_output_unit(nfp.groupwise_neutron_current_through_interface) + == "m^-2 s^-1" + ) + assert nfp.get_output_unit(nfp.groupwise_neutron_flux_at) == "m^-2 s^-1" + assert ( + nfp.get_output_unit(nfp.groupwise_neutron_flux_in_layer) == "m^-2 s^-1" + ) + assert ( + nfp.get_output_unit(nfp.groupwise_neutron_heating_in_layer) == "W m^-3" + ) + assert nfp.get_output_unit(nfp.groupwise_neutron_heating_at) == "W m^-3" + + assert nfp.get_output_unit(nfp.integrated_flux_in_layer) == "m^-1 s^-1" + assert nfp.get_output_unit(nfp.integrated_heating_in_layer) == "W m^-2" + assert nfp.get_output_unit(nfp.neutron_current_at) == "m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_current_escaped) == "m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_current_in_layer) == "m^-2 s^-1" + assert ( + nfp.get_output_unit(nfp.neutron_current_through_interface) + == "m^-2 s^-1" + ) + assert nfp.get_output_unit(nfp.neutron_flux_at) == "m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_flux_in_layer) == "m^-2 s^-1" + assert nfp.get_output_unit(nfp.neutron_heating_in_layer) == "W m^-3" + assert nfp.get_output_unit(nfp.neutron_heating_at) == "W m^-3" + def test_get_sign_func(): - signs = _get_sign_of(np.array([-np.inf, -2, -1, -0.0, 0.0, 1.0, 2.0, np.inf])) + signs = _get_sign_of( + np.array([-np.inf, -2, -1, -0.0, 0.0, 1.0, 2.0, np.inf]) + ) np.testing.assert_equal(signs, [-1, -1, -1, -1, 1, 1, 1, 1]) + def test_three_group(): - # 1. No negative flux - dummy = np.geomspace(max_E, min_E, 4) - # fw_mat = MaterialMacroInfo() - bz_mat = MaterialMacroInfo - # 2. same L_1 and L_3 shoudl yield coefficients[0][2].c[0] and - # coefficients[0][2].s[0] = 0.0 - # self.l2[0][n] == self.l2[1][n] case. - # + """Can use degenerate cross-sections values between groups?""" def test_two_group(): From 115b29fb67e7f183a2b7edd0e7f4ff90309d7f1d Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 25 Nov 2025 01:14:34 +0000 Subject: [PATCH 91/98] Fixed plotting zorder --- process/neutronics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index ce16ebb87a..a28dd9031f 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -1260,8 +1260,8 @@ def _get_sign_of(x_values): def _plot_vertical_dotted_line(ax, x, ylims, *, symmetric: bool = True): if symmetric: - ax.plot([-x, -x], ylims, color="black", ls="--") - ax.plot([x, x], ylims, color="black", ls="--") + ax.plot([-x, -x], ylims, color="black", ls="--", zorder=-1) + ax.plot([x, x], ylims, color="black", ls="--", zorder=-1) return From 16e879997e5a25dc3477e0056137370f7da41a07 Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 25 Nov 2025 01:17:25 +0000 Subject: [PATCH 92/98] Prepared for the case that allows for contains_upscatter=True, where each NeutronFluxProfile.coefficient[:, n] will contain self.n_groups coefficients rather than n coefficients. --- process/neutronics.py | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index a28dd9031f..f14a94e1c9 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -396,6 +396,12 @@ def __init__( extended_boundary: Extended boundary for each group. These values should be larger than layer_x[-1]. + num_iteration: + How many times the method has been called to solve all of the + neutron groups collectively. + downscatter_only: + A boolean to denote if all materials here only allow for + downscattering. """ # flux incident on the first wall at the highest energy. self.flux = flux @@ -454,6 +460,10 @@ def __init__( self.extended_boundary = AutoPopulatingDict( self.solve_group_n, "extended_boundary" ) + self.num_iteration = 0 + self.contains_upscatter = any( + not mat.downscatter_only for mat in self.materials + ) @staticmethod def _calculate_mean_energy_and_incident_bin( @@ -613,15 +623,16 @@ def solve_group_n(self, n: int) -> None: for k in range(n): if not self.coefficients.has_populated(k): self.solve_group_n(k) - if not all(mat.downscatter_only for mat in self.materials): + if self.contains_upscatter: raise NotImplementedError( - "Will implement solve_group_n in a loop later..." + "Will implement solve_group_n in a loop later.\n" + "Current implementation will trigger a ProcessValueError via " + "coefficients[:, :].validate_length if allowed to continue." ) if self.coefficients.has_populated(n): return None # skip if it has already been solved. # Parameter to be changed later, to allow solving non-down-scatter # only systems by iterating. - first_iteration = True for num_layer, mat in enumerate(self.materials): self.diffusion_const[num_layer, n], self.l2[num_layer, n] = ( get_diffusion_coefficient_and_length( @@ -635,40 +646,49 @@ def solve_group_n(self, n: int) -> None: self.diffusion_const[-1, n] ) + include_upscatter = self.contains_upscatter and self.num_iteration!=0 for num_layer in range(self.n_layers): # Setting up aliases for shorter code _coefs = Coefficients([], []) mat = self.materials[num_layer] src_matrix = mat.sigma_s + mat.sigma_in diffusion_const_n = self.diffusion_const[num_layer, n] - for g in range(n): + in_scatter_max_group = self.n_groups if include_upscatter else n+1 + for g in range(in_scatter_max_group): # if the characteristic length of group [g] coincides with the # characteristic length of group [n], then that particular # cosh/sinh would be indistinguishable from group [n]'s # cosh/sinh anyways, therefore we can set the coefficient to 0. + if g==n: + c_factor_guess = 0.0 + s_factor_guess = 0.0 + _coefs.c.append(c_factor_guess) + _coefs.s.append(s_factor_guess) + continue scale_factor = 0.0 l2n, l2g = self.l2[num_layer, n], self.l2[num_layer, g] if not np.isclose(l2_diff := (l2g - l2n), 0): scale_factor = (l2n * l2g) / diffusion_const_n / l2_diff + in_scatter_min_group = 0 if include_upscatter else g _coefs.c.append( sum( src_matrix[i, n] * self.coefficients[num_layer, i].c[g] - for i in range(g, n) + for i in range( + in_scatter_min_group, in_scatter_max_group + ) if i!=n ) * scale_factor ) _coefs.s.append( sum( src_matrix[i, n] * self.coefficients[num_layer, i].s[g] - for i in range(g, n) + for i in range( + in_scatter_min_group, in_scatter_max_group + ) if i!=n ) * scale_factor ) - c_factor_guess = 0.0 - s_factor_guess = 0.0 - _coefs.c.append(c_factor_guess) - _coefs.s.append(s_factor_guess) self.coefficients[num_layer, n] = _coefs def _set_coefficients(input_vector: Iterable[float]): @@ -715,6 +735,7 @@ def objective(coefficients_vector): ]) results = optimize.root(objective, x0=x0) _set_coefficients(results.res) + self.num_iteration += 1 return None def _check_if_in_layer( From 6a8f20a0335d02940668ae141ac14a375e5f195d Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 25 Nov 2025 01:24:25 +0000 Subject: [PATCH 93/98] Slightly tidied up the code that calculates the non-central cosh/sinh's coefficients (i.e. coefficients used to cancel the flux shapes contributed by other groups). --- process/neutronics.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index f14a94e1c9..241aafb6af 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -665,10 +665,13 @@ def solve_group_n(self, n: int) -> None: _coefs.c.append(c_factor_guess) _coefs.s.append(s_factor_guess) continue - scale_factor = 0.0 l2n, l2g = self.l2[num_layer, n], self.l2[num_layer, g] - if not np.isclose(l2_diff := (l2g - l2n), 0): - scale_factor = (l2n * l2g) / diffusion_const_n / l2_diff + l2_diff = l2g - l2n + if np.isclose(l2_diff, 0): + _coefs.c.append(0.0) + _coefs.s.append(0.0) + continue + scale_factor = (l2n * l2g) / diffusion_const_n / l2_diff in_scatter_min_group = 0 if include_upscatter else g _coefs.c.append( sum( From 367cb4e940c3ec2f49cb044ad639880b6bdce829 Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 25 Nov 2025 02:37:59 +0000 Subject: [PATCH 94/98] Added placeholder list for summing up all of the skipped coefficients. --- process/neutronics.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 241aafb6af..eb3aad8e82 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -653,6 +653,7 @@ def solve_group_n(self, n: int) -> None: mat = self.materials[num_layer] src_matrix = mat.sigma_s + mat.sigma_in diffusion_const_n = self.diffusion_const[num_layer, n] + skipped_c_coefs, skipped_s_coefs = [], [] in_scatter_max_group = self.n_groups if include_upscatter else n+1 for g in range(in_scatter_max_group): # if the characteristic length of group [g] coincides with the @@ -660,14 +661,14 @@ def solve_group_n(self, n: int) -> None: # cosh/sinh would be indistinguishable from group [n]'s # cosh/sinh anyways, therefore we can set the coefficient to 0. if g==n: - c_factor_guess = 0.0 - s_factor_guess = 0.0 - _coefs.c.append(c_factor_guess) - _coefs.s.append(s_factor_guess) + _coefs.c.append(0.0) + _coefs.s.append(0.0) continue l2n, l2g = self.l2[num_layer, n], self.l2[num_layer, g] l2_diff = l2g - l2n if np.isclose(l2_diff, 0): + skipped_c_coefs.append(...) + skipped_s_coefs.append(...) _coefs.c.append(0.0) _coefs.s.append(0.0) continue @@ -691,6 +692,8 @@ def solve_group_n(self, n: int) -> None: ) * scale_factor ) + _coefs[num_layer, n].c[n] = sum(skipped_c_coefs) + _coefs[num_layer, n].s[n] = sum(skipped_s_coefs) self.coefficients[num_layer, n] = _coefs From 311d63f3685db4d07760284fc87c96259ae17eb2 Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 16 Dec 2025 11:03:57 +0000 Subject: [PATCH 95/98] slightly modified validate_length to allow for second+ passes to have coefficient length = total number of groups rather than the current group number. --- process/neutronics.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/process/neutronics.py b/process/neutronics.py index eb3aad8e82..05b5601e13 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -209,10 +209,14 @@ def __contains__(self, i: int): """Check if key 'i' is in the dictionary or not.""" return i in self._dict + def __len__(self): + """Return the number of items in the """ + return len(self._dict) + def __setitem__(self, i: int, value: float): """Check if dict i is in the index or not.""" if hasattr(value, "validate_length"): - value.validate_length(i + 1, parent_name=self.name) + value.validate_length(len(self) + 1, parent_name=self.name) self._dict[i] = value self._attempting_to_access.discard(i) From 84e443e014797845f8333b287987d09eb3f07da1 Mon Sep 17 00:00:00 2001 From: ocean Date: Tue, 16 Dec 2025 17:47:11 +0000 Subject: [PATCH 96/98] Put the cosh-sinh/cos-sin switching logic into dedicated methods, so the programmer won't have to write them out explicitly every time. --- process/neutronics.py | 126 +++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 05b5601e13..a489fa4e0f 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -527,6 +527,55 @@ def _calculate_mean_energy_and_incident_bin( weighted_mean[first_bin] = init_neutron_e return weighted_mean, incident_neutron_group + def _groupwise_cs_values_in_layer( + self, n: int, num_layer: int, x: float | npt.NDArray + ) -> tuple[float, float] | tuple[npt.NDArray, npt.NDArray]: + """ + Calculate the num_layer-th layer n-th basis function at the specified + x position(s). + """ + abs_x = abs(x) + if self.l2[num_layer, n] > 0: + l = np.sqrt(self.l2[num_layer, n]) + c, s = np.cosh, np.sinh + else: + l = np.sqrt(-self.l2[num_layer, n]) + c, s = np.cos, np.sin + return c(abs_x / l), s(abs_x / l) + + def _groupwise_cs_differential_in_layer( + self, n: int, num_layer: int, x: float | npt.NDArray + ) -> tuple[float, float] | tuple[npt.NDArray, npt.NDArray]: + """ + Differentiate the num_layer-th layer n-th basis function, and evaluate + it at position(s) x. + """ + abs_x = abs(x) + if self.l2[num_layer, n] > 0: + l = np.sqrt(self.l2[num_layer, n]) + return np.sinh(abs_x / l) / l, np.cosh(abs_x / l) / l + l = np.sqrt(-self.l2[num_layer, n]) + return -np.sin(abs_x / l) / l, np.cos(abs_x / l) / l + + def _groupwise_cs_definite_integral_in_layer( + self, n: int, num_layer: int, x_lower: float | npt.NDArray, x_upper + ) -> tuple[float, float] | tuple[npt.NDArray, npt.NDArray]: + """ + Integrate the num_layer-th layer n-th basis function + from x_lower to x_upper. + """ + if self.l2[num_layer, n] > 0: + l = np.sqrt(self.l2[num_layer, n]) + return ( + l * (np.sinh(x_upper / l) - np.sinh(x_lower / l)), + l * (np.cosh(x_upper / l) - np.cosh(x_lower / l)) + ) + l = np.sqrt(-self.l2[num_layer, n]) + return ( + l * (np.sin(x_upper / l) - np.sin(x_lower / l)), + l * (np.cos(x_lower / l) - np.cos(x_upper / l)) # reverse sign + ) + def solve_lowest_group(self) -> None: """ Solve the highest-energy (lowest-lethargy)-group's neutron diffusion equation. @@ -793,20 +842,10 @@ def groupwise_neutron_flux_in_layer( n, self.n_layers - 1, np.sign(x) * self.layer_x[-1] ) trig_funcs = [] - abs_x = abs(x) for g in range(n + 1): - if self.l2[num_layer, g] > 0: - c, s = np.cosh, np.sinh - l = np.sqrt(self.l2[num_layer, g]) - else: - c, s = np.cos, np.sin - l = np.sqrt(-self.l2[num_layer, g]) - trig_funcs.append( - self.coefficients[num_layer, n].c[g] * c(abs_x / l) - ) - trig_funcs.append( - self.coefficients[num_layer, n].s[g] * s(abs_x / l) - ) + c_val, s_val = self._groupwise_cs_values_in_layer(g, num_layer, x) + trig_funcs.append(self.coefficients[num_layer, n].c[g] * c_val) + trig_funcs.append(self.coefficients[num_layer, n].s[g] * s_val) return np.sum(trig_funcs, axis=0) @summarize_values @@ -933,33 +972,12 @@ def groupwise_neutron_current_in_layer( n, self.n_layers - 1, np.sign(x) * self.layer_x[-1] ) differentials = [] - abs_x = abs(x) for g in range(n + 1): - l2g = self.l2[num_layer, g] - if l2g > 0: - l = np.sqrt(l2g) - differentials.append( - self.coefficients[num_layer, n].c[g] - / l - * np.sinh(abs_x / l) - ) - differentials.append( - self.coefficients[num_layer, n].s[g] - / l - * np.cosh(abs_x / l) - ) - else: - l = np.sqrt(-l2g) - differentials.append( - -self.coefficients[num_layer, n].c[g] - / l - * np.sin(abs_x / l) - ) - differentials.append( - self.coefficients[num_layer, n].s[g] - / l - * np.cos(abs_x / l) - ) + c_diff, s_diff = self._groupwise_cs_differential_in_layer( + g, num_layer, x + ) + differentials.append(self.coefficients[num_layer, n].c[g] * c_diff) + differentials.append(self.coefficients[num_layer, n].s[g] * s_diff) return ( -self.diffusion_const[num_layer, n] @@ -1085,31 +1103,11 @@ def groupwise_integrated_flux_in_layer( x_end = self.layer_x[num_layer] for g in range(n + 1): - l2g = self.l2[num_layer, g] - if l2g > 0: - l = np.sqrt(l2g) - integrals.append( - l - * self.coefficients[num_layer, n].c[g] - * (np.sinh(x_end / l) - np.sinh(x_start / l)) - ) - integrals.append( - l - * self.coefficients[num_layer, n].s[g] - * (np.cosh(x_end / l) - np.cosh(x_start / l)) - ) - else: - l = np.sqrt(-l2g) - integrals.append( - l - * self.coefficients[num_layer, n].c[g] - * (np.sin(x_end / l) - np.sin(x_start / l)) - ) - integrals.append( - -l - * self.coefficients[num_layer, n].s[g] - * (np.cos(x_end / l) - np.cos(x_start / l)) - ) + c_int, s_int = self._groupwise_cs_definite_integral_in_layer( + g, num_layer, x_start, x_end + ) + integrals.append(self.coefficients[num_layer, n].c[g] * c_int) + integrals.append(self.coefficients[num_layer, n].s[g] * s_int) return np.sum(integrals, axis=0) @summarize_values From 055109c7ca555d2a4238477403987de2e0a9237c Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 17 Dec 2025 16:22:57 +0000 Subject: [PATCH 97/98] Added feature to count the number of coefficient pairs. --- process/neutronics.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/process/neutronics.py b/process/neutronics.py index a489fa4e0f..24e0c403eb 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -152,6 +152,22 @@ class Coefficients: c: Iterable[float] s: Iterable[float] + @property + def num_coef_pairs(self) -> int: + """ + The length of .c and .s, which should be the same. + Raises + ------ + ValueError: + If .c and .s do not match in length, then we have a problem. + """ + if len(self.c)!=len(self.s): + raise ValueError( + "Mismatched lengths between " + f"c ({len(self.c)}) and s ({len(self.s)})" + ) + return len(self.c) + def validate_length(self, exp_len: int, parent_name: str): """Validate that all fields has the correct length.""" for const_name, const_value in asdict(self).items(): From 73734e35590c7b3c8dd0ef541faedd9a689ec3e5 Mon Sep 17 00:00:00 2001 From: ocean Date: Wed, 17 Dec 2025 17:11:09 +0000 Subject: [PATCH 98/98] THe problem of deducing the next layer's coefficient given the previous layer can be written as an affine transformation in linear algebra (y = Ax+b). The method _get_propagation_matrix_and_offset_vec returns A and b. num_coef_pairs is no longer needed so is deleted. --- process/neutronics.py | 91 ++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/process/neutronics.py b/process/neutronics.py index 24e0c403eb..f80d038110 100644 --- a/process/neutronics.py +++ b/process/neutronics.py @@ -152,22 +152,6 @@ class Coefficients: c: Iterable[float] s: Iterable[float] - @property - def num_coef_pairs(self) -> int: - """ - The length of .c and .s, which should be the same. - Raises - ------ - ValueError: - If .c and .s do not match in length, then we have a problem. - """ - if len(self.c)!=len(self.s): - raise ValueError( - "Mismatched lengths between " - f"c ({len(self.c)}) and s ({len(self.s)})" - ) - return len(self.c) - def validate_length(self, exp_len: int, parent_name: str): """Validate that all fields has the correct length.""" for const_name, const_value in asdict(self).items(): @@ -545,7 +529,7 @@ def _calculate_mean_energy_and_incident_bin( def _groupwise_cs_values_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray - ) -> tuple[float, float] | tuple[npt.NDArray, npt.NDArray]: + ) -> npt.NDArray: """ Calculate the num_layer-th layer n-th basis function at the specified x position(s). @@ -557,7 +541,7 @@ def _groupwise_cs_values_in_layer( else: l = np.sqrt(-self.l2[num_layer, n]) c, s = np.cos, np.sin - return c(abs_x / l), s(abs_x / l) + return np.array([c(abs_x / l), s(abs_x / l)]) def _groupwise_cs_differential_in_layer( self, n: int, num_layer: int, x: float | npt.NDArray @@ -569,9 +553,9 @@ def _groupwise_cs_differential_in_layer( abs_x = abs(x) if self.l2[num_layer, n] > 0: l = np.sqrt(self.l2[num_layer, n]) - return np.sinh(abs_x / l) / l, np.cosh(abs_x / l) / l + return np.array([np.sinh(abs_x / l) / l, np.cosh(abs_x / l) / l]) l = np.sqrt(-self.l2[num_layer, n]) - return -np.sin(abs_x / l) / l, np.cos(abs_x / l) / l + return np.array([-np.sin(abs_x / l) / l, np.cos(abs_x / l) / l]) def _groupwise_cs_definite_integral_in_layer( self, n: int, num_layer: int, x_lower: float | npt.NDArray, x_upper @@ -582,15 +566,15 @@ def _groupwise_cs_definite_integral_in_layer( """ if self.l2[num_layer, n] > 0: l = np.sqrt(self.l2[num_layer, n]) - return ( + return np.array([ l * (np.sinh(x_upper / l) - np.sinh(x_lower / l)), l * (np.cosh(x_upper / l) - np.cosh(x_lower / l)) - ) + ]) l = np.sqrt(-self.l2[num_layer, n]) - return ( + return np.array([ l * (np.sin(x_upper / l) - np.sin(x_lower / l)), l * (np.cos(x_lower / l) - np.cos(x_upper / l)) # reverse sign - ) + ]) def solve_lowest_group(self) -> None: """ @@ -666,9 +650,62 @@ def solve_lowest_group(self) -> None: [bz_c_factor], [bz_s_factor] ) else: - raise NotImplementedError("Only implemented 2 groups so far.") + return NotImplemented return + def _get_propagation_matrix_and_offset_vec(n: int, num_layer: int): + """ + Infer this layer's main basis functions' coefficients (.c[n] and .s[n]) + using using the previous layer's basis functions. + """ + x_j = self.interface_x[num_layer] + coefs_in = np.array(astuple(self.coefficients[num_layer - 1, n])).T + coefs_jn = np.array(astuple(self.coefficients[num_layer, n])).T + d_in = self.diffusion_const[num_layer-1, n] + d_jn = self.diffusion_const[num_layer, n] + l_in = self.l2[num_layer-1, n] + l_jn = self.l2[num_layer, n] + + diff_residual_flux = (sum( + cs_coef_pair @ self._groupwise_cs_values_in_layer( + g, num_layer - 1, x_j + ) + for g, cs_coef_pair in enumerate(coefs_in) if g!=n + ) - sum( + cs_coef_pair @ self._groupwise_cs_values_in_layer( + g, num_layer, x_j + ) + for g, cs_coef_pair in enumerate(coefs_jn) if g!=n + ) + ) + diff_residual_current = l_jn * ( + - d_in/d_jn * sum( + cs_coef_pair @ self._groupwise_cs_differential_in_layer( + g, num_layer - 1, x_j + ) + for g, cs_coef_pair in enumerate(coefs_in) if g!=n + ) + + sum( + cs_coef_pair @ self._groupwise_cs_differential_in_layer( + g, num_layer, x_j + ) + for g, cs_coef_pair in enumerate(coefs_jn) if g!=n + ) + ) + shift_vector = np.array([diff_residual_flux, diff_residual_current]) + + transformation_matrix = np.array([ + self._groupwise_cs_values_in_layer(n, num_layer - 1, x_j), + -l_jn / d_jn * d_in / l_in * ( + self._groupwise_cs_differential_in_layer(n, num_layer - 1, x_j) + ), + ]) + A = np.array([ + self._groupwise_cs_values_in_layer(n, num_layer, x_j), + -self._groupwise_cs_differential_in_layer(n, num_layer, x_j), + ]) + return A @ transformation_matrix, A @ shift_vector + def solve_group_n(self, n: int) -> None: """ Solve the n-th group of neutron's diffusion equation, where n <= @@ -761,8 +798,8 @@ def solve_group_n(self, n: int) -> None: ) * scale_factor ) - _coefs[num_layer, n].c[n] = sum(skipped_c_coefs) - _coefs[num_layer, n].s[n] = sum(skipped_s_coefs) + _coefs[num_layer, n].c[n] = ... - sum(skipped_c_coefs) + _coefs[num_layer, n].s[n] = ... - sum(skipped_s_coefs) self.coefficients[num_layer, n] = _coefs