def _get_destruction(self, nuc, decay=True): """Computes the destruction rate of the nuclide. Parameters ---------- nuc : int Name of the nuclide in question decay : bool True if the decay constant should be added to the returned value. False if only destruction from neutron reactions should be considered. Returns ------- d : float Destruction rate of the nuclide. """ xscache = self.xscache sig_a = sigma_a(nuc, xs_cache=xscache) d = utils.from_barns(sig_a[0], 'cm2') * xscache['phi_g'][0] if decay and not np.isnan(data.decay_const(nuc)): d += data.decay_const(nuc) return d
def _traversal(self, nuc, A, out, depth=0): """Nuclide transmutation traversal method. This method will traverse the reaction tree recursively, using a DFS algorithm. On termination, the method will return all number densities after a given time that are a result of the starting nuclide. Parameters ---------- nuc : int ID of the active nuclide for the traversal. A : NumPy 2-dimensional array Current state of the coupled equation matrix. out : dict A dictionary containing the final recorded number densities for each nuclide. Keys are nuclide names in integer id form. Values are number densities for the coupled nuclide in float format. This is modified in place. depth : int Current depth of traversal (root at 0). Should never be provided by user. """ t = self.t tol = self.tol phi = self.xscache['phi_g'][0] temp = self.temp xscache = self.xscache if self.log is not None: self._log_tree(depth, nuc, 1.0) prod = {} # decay info lam = data.decay_const(nuc) decay_branches = {} if lam == 0 else self._decay_branches(nuc) for decay_child, branch_ratio in decay_branches.items(): prod[decay_child] = lam * branch_ratio # reaction daughters for rx in self.rxs: try: child = rxname.child(nuc, rx) except RuntimeError: continue child_xs = xscache[nuc, rx, temp][0] rr = utils.from_barns(child_xs, 'cm2') * phi # reaction rate prod[child] = rr + prod.get(child, 0.0) # Cycle production dictionary for child in prod: # Grow matrix d = self._get_destruction(child) B = self._grow_matrix(A, prod[child], d) # Create initial density vector n = B.shape[0] N0 = np.zeros((n, 1), dtype=float) N0[0] = 1.0 # Compute matrix exponential and dot with density vector eB = linalg.expm(B * t) N_final = np.dot(eB, N0) # <-- DENSE #N_final = eB.dot(N0) # <-- SPARSE if self.log is not None: self._log_tree(depth + 1, child, N_final[-1]) # Check against tolerance and continue traversal if N_final[-1] > tol: self._traversal(child, B, out, depth=depth + 1) # On recursion exit or truncation, write data from this nuclide outval = N_final[-1, 0] + out.get(child, 0.0) if 0.0 < outval: out[child] = outval
def test_from_barns(): assert_equal(3E-3, utils.from_barns(3, 'KB'))
def _traversal(self, nuc, A, out, depth=0): """Nuclide transmutation traversal method. This method will traverse the reaction tree recursively, using a DFS algorithm. On termination, the method will return all number densities after a given time that are a result of the starting nuclide. Parameters ---------- nuc : int ID of the active nuclide for the traversal. A : NumPy 2-dimensional array Current state of the coupled equation matrix. out : dict A dictionary containing the final recorded number densities for each nuclide. Keys are nuclide names in integer id form. Values are number densities for the coupled nuclide in float format. This is modified in place. depth : int Current depth of traversal (root at 0). Should never be provided by user. """ t = self.t tol = self.tol phi = self.xscache['phi_g'][0] temp = self.temp xscache = self.xscache if self.log is not None: self._log_tree(depth, nuc, 1.0) prod = {} # decay info lam = data.decay_const(nuc) decay_branches = {} if lam == 0 else self._decay_branches(nuc) for decay_child, branch_ratio in decay_branches.items(): prod[decay_child] = lam * branch_ratio # reaction daughters for rx in self.rxs: try: child = rxname.child(nuc, rx) except RuntimeError: continue child_xs = xscache[nuc, rx, temp][0] rr = utils.from_barns(child_xs, 'cm2') * phi # reaction rate prod[child] = rr + prod.get(child, 0.0) # Cycle production dictionary for child in prod: # Grow matrix d = self._get_destruction(child) B = self._grow_matrix(A, prod[child], d) # Create initial density vector n = B.shape[0] N0 = np.zeros((n, 1), dtype=float) N0[0] = 1.0 # Compute matrix exponential and dot with density vector eB = linalg.expm(B * t) N_final = np.dot(eB, N0) # <-- DENSE #N_final = eB.dot(N0) # <-- SPARSE if self.log is not None: self._log_tree(depth+1, child, N_final[-1]) # Check against tolerance and continue traversal if N_final[-1] > tol: self._traversal(child, B, out, depth=depth+1) # On recursion exit or truncation, write data from this nuclide outval = N_final[-1,0] + out.get(child, 0.0) if 0.0 < outval: out[child] = outval
def test_from_barns(): assert_equal(3e-3, utils.from_barns(3, "KB"))