Source code for scarabee.reseau.guide_tube

from .._scarabee import (
    NDLibrary,
    Material,
    CrossSection,
    PinCellType,
    SimplePinCell,
    PinCell,
    MOCDriver,
    DepletionChain,
)
from .burnable_poison_rod import BurnablePoisonRod
import numpy as np
from typing import Optional, List
import copy


[docs]class GuideTube: """ Represents an empty guide tube for a PWR. Parameters ---------- clad : Material Material which describes the cladding composition, density, and temperature. inner_radius : float Inner radius of the guide tube. outer_radius : float Outer radius of the guide tube. fill : BurnablePoisonRod, optional Optional burnable poison rod which can be placed inside the guide tube. Default value is None. Attributes ---------- clad : Material Material which describes the cladding composition, density, and temperature. inner_radius : float Inner radius of the guide tube. outer_radius : float Outer radius of the guide tube. fill : BurnablePoisonRod, optional Optional burnable poison rod which can be placed inside the guide tube. clad_dancoff_corrections : list of float Dancoff corrections to be used when self-shielding the cladding at each depletion time step. empty : bool True if fill is None and False otherwise. """
[docs] def __init__( self, clad: Material, inner_radius: float, outer_radius: float, fill: Optional[BurnablePoisonRod] = None, ): if inner_radius >= outer_radius: raise ValueError("Inner radius must be > outer radius.") self._clad = copy.deepcopy(clad) self._inner_radius = inner_radius self._outer_radius = outer_radius self._fill = copy.deepcopy(fill) # Make sure the control rod of poison rod would actually fit inside the # guide tube. Do this by checking the radii. if self.fill is not None: if isinstance(self.fill, BurnablePoisonRod): if self.fill.outer_clad_radius >= self.inner_radius: raise ValueError( "The burnable poison rod is too large for the guide tube." ) else: raise TypeError("Unknown fill object placed in guide tube.") # ====================================================================== # DANCOFF CORRECTION CALCULATION DATA # ---------------------------------------------------------------------- # Initialize empty list of Dancoff corrections for the cladding self._clad_dancoff_corrections: List[float] = [] # Initialize empty variables for Dancoff correction calculations. # These are all kept private. self._clad_dancoff_xs: CrossSection = CrossSection( np.array([self.clad.potential_xs]), np.array([self.clad.potential_xs]), np.array([[0.0]]), "Clad", ) self._clad_isolated_dancoff_fsr_ids = [] self._clad_isolated_dancoff_fsr_inds = [] self._mod_isolated_dancoff_fsr_ids = [] self._mod_isolated_dancoff_fsr_inds = [] self._clad_full_dancoff_fsr_ids = [] self._clad_full_dancoff_fsr_inds = [] self._mod_full_dancoff_fsr_ids = [] self._mod_full_dancoff_fsr_inds = [] # ====================================================================== # TRANSPORT CALCULATION DATA # ---------------------------------------------------------------------- self._clad_fsr_ids: List[int] = [] self._mod_fsr_ids: List[int] = [] self._clad_fsr_inds: List[int] = [] self._mod_fsr_inds: List[int] = [] # Holds the CrossSection object used for the real transport calc. self._clad_xs: Optional[CrossSection] = None
@property def clad(self) -> Material: return self._clad @property def inner_radius(self) -> float: return self._inner_radius @property def outer_radius(self) -> float: return self._outer_radius @property def fill(self) -> Optional[BurnablePoisonRod]: return self._fill @property def empty(self) -> bool: return self.fill is None @property def clad_dancoff_corrections(self) -> List[float]: return self._clad_dancoff_corrections def _check_dx_dy(self, dx, dy, pintype): if pintype == PinCellType.Full: if dx < 2.0 * self.outer_radius: raise ValueError( "The fuel pin cell x width must be > the diameter of the cladding." ) if dy < 2.0 * self.outer_radius: raise ValueError( "The fuel pin cell y width must be > the diameter of the cladding." ) elif pintype in [PinCellType.XN, PinCellType.XP]: if dx < self.outer_radius: raise ValueError( "The fuel pin cell x width must be > the radius of the cladding." ) if dy < 2.0 * self.outer_radius: raise ValueError( "The fuel pin cell y width must be > the diameter of the cladding." ) elif pintype in [PinCellType.YN, PinCellType.YP]: if dy < self.outer_radius: raise ValueError( "The fuel pin cell y width must be > the radius of the cladding." ) if dx < 2.0 * self.outer_radius: raise ValueError( "The fuel pin cell x width must be > the diameter of the cladding." ) else: if dx < self.outer_radius: raise ValueError( "The fuel pin cell x width must be > the radius of the cladding." ) if dy < self.outer_radius: raise ValueError( "The fuel pin cell y width must be > the radius of the cladding." )
[docs] def load_nuclides(self, ndl: NDLibrary) -> None: """ Loads all the nuclides for all current materials into the data library. Parameters ---------- ndl : NDLibrary Nuclear data library which should load the nuclides. """ self.clad.load_nuclides(ndl)
# ========================================================================== # Dancoff Correction Related Methods
[docs] def set_xs_for_fuel_dancoff_calculation(self) -> None: """ Sets the 1-group cross sections to calculate the fuel Dancoff corrections. """ self._clad_dancoff_xs.set( CrossSection( np.array([self.clad.potential_xs]), np.array([self.clad.potential_xs]), np.array([[0.0]]), "Clad", ) ) if isinstance(self.fill, BurnablePoisonRod): self.fill.set_xs_for_dancoff_calculation()
[docs] def set_xs_for_clad_dancoff_calculation(self, ndl: NDLibrary) -> None: """ Sets the 1-group cross sections to calculate the clad Dancoff corrections. Parameters ---------- ndl : NDLibrary Nuclear data library for obtaining potential scattering cross sections. """ self._clad_dancoff_xs.set( CrossSection( np.array([1.0e5]), np.array([1.0e5]), np.array([[0.0]]), "Clad", ) ) if isinstance(self.fill, BurnablePoisonRod): self.fill.set_xs_for_dancoff_calculation()
[docs] def make_dancoff_moc_cell( self, moderator_xs: CrossSection, dx: float, dy: float, pintype: PinCellType, isolated: bool, ) -> SimplePinCell: """ Makes a simplified cell suitable for performing Dancoff correction calculations. The flat source region IDs are stored locally in the GuideTube object. Parameters ---------- moderator_xs : CrossSection One group cross sections for the moderator. Total should equal absorption (i.e. no scattering) and should be equal to the macroscopic potential cross section. dx : float Width of the cell along x. dy : float Width of the cell along y. pintype : PinCellType How the cell should be split (along x, y, or only a quadrant). isolated : bool If True, the FSR IDs are stored for the isolated pin. Otherwise, they are stored for the full pin. Returns ------- SimplifiedPinCell Pin cell object for MOC Dancoff correction calculation. """ self._check_dx_dy(dx, dy, pintype) # First we create list of radii and materials radii = [] xs = [] if isinstance(self.fill, BurnablePoisonRod): radii, xs = self.fill._make_dancoff_moc_cell(moderator_xs) FILL_OFFSET = len(radii) # This is either all the moderator inside the guide tube, or it is the # ring of moderator inside the guide tube, but outside the fill object. radii.append(self.inner_radius) xs.append(moderator_xs) radii.append(self.outer_radius) xs.append(self._clad_dancoff_xs) xs.append(moderator_xs) # Make the simple pin cell. cell = SimplePinCell(radii, xs, dx, dy, pintype) # Get the FSR IDs for the regions of interest cell_fsr_ids = cell.get_all_fsr_ids() if isolated: self._clad_isolated_dancoff_fsr_ids.append(cell_fsr_ids[FILL_OFFSET + 1]) self._mod_isolated_dancoff_fsr_ids = [ cell_fsr_ids[FILL_OFFSET + 0], cell_fsr_ids[FILL_OFFSET + 2], ] # Must set FSR IDs by hand for the fill if isinstance(self.fill, BurnablePoisonRod): if self.fill.center is not None: self._mod_isolated_dancoff_fsr_ids.append(cell_fsr_ids[0]) else: self.fill._center_isolated_dancoff_fsr_ids.append(cell_fsr_ids[0]) self.fill._clad_isolated_dancoff_fsr_ids = [ cell_fsr_ids[1], cell_fsr_ids[5], ] self.fill._gap_isolated_dancoff_fsr_ids = [ cell_fsr_ids[2], cell_fsr_ids[4], ] self.fill._poison_isolated_dancoff_fsr_ids = [cell_fsr_ids[3]] else: self._clad_full_dancoff_fsr_ids.append(cell_fsr_ids[FILL_OFFSET + 1]) self._mod_full_dancoff_fsr_ids = [ cell_fsr_ids[FILL_OFFSET + 0], cell_fsr_ids[FILL_OFFSET + 2], ] # Must set FSR IDs by hand for the fill if isinstance(self.fill, BurnablePoisonRod): if self.fill.center is not None: self._mod_full_dancoff_fsr_ids.append(cell_fsr_ids[0]) else: self.fill._center_full_dancoff_fsr_ids.append(cell_fsr_ids[0]) self.fill._clad_full_dancoff_fsr_ids = [ cell_fsr_ids[1], cell_fsr_ids[5], ] self.fill._gap_full_dancoff_fsr_ids = [cell_fsr_ids[2], cell_fsr_ids[4]] self.fill._poison_full_dancoff_fsr_ids = [cell_fsr_ids[3]] return cell
[docs] def populate_dancoff_fsr_indexes( self, isomoc: MOCDriver, fullmoc: MOCDriver ) -> None: """ Obtains the flat source region indexes for all of the flat source regions used in the Dancoff correction calculations. Parameters ---------- isomoc : MOCDriver MOC simulation for the isolated pin. fullmoc : MOCDriver MOC simulation for the full geometry. """ self._clad_isolated_dancoff_fsr_inds = [] self._mod_isolated_dancoff_fsr_inds = [] self._clad_full_dancoff_fsr_inds = [] self._mod_full_dancoff_fsr_inds = [] for id in self._clad_isolated_dancoff_fsr_ids: self._clad_isolated_dancoff_fsr_inds.append(isomoc.get_fsr_indx(id, 0)) for id in self._mod_isolated_dancoff_fsr_ids: self._mod_isolated_dancoff_fsr_inds.append(isomoc.get_fsr_indx(id, 0)) for id in self._clad_full_dancoff_fsr_ids: self._clad_full_dancoff_fsr_inds.append(fullmoc.get_fsr_indx(id, 0)) for id in self._mod_full_dancoff_fsr_ids: self._mod_full_dancoff_fsr_inds.append(fullmoc.get_fsr_indx(id, 0)) if isinstance(self.fill, BurnablePoisonRod): self.fill.populate_dancoff_fsr_indexes(isomoc, fullmoc)
[docs] def set_isolated_dancoff_fuel_sources( self, isomoc: MOCDriver, moderator: Material ) -> None: """ Initializes the fixed sources for the isolated MOC calculation required in computing Dancoff corrections. Sources are set for a fuel Dancoff correction calculation. Parameters ---------- isomoc : MOCDriver MOC simulation for the isolated geometry. moderator : Material Material definition for the moderator, used to obtain the potential scattering cross section. """ # Clad sources should all be potential_xs pot_xs = self.clad.potential_xs for ind in self._clad_isolated_dancoff_fsr_inds: isomoc.set_extern_src(ind, 0, pot_xs) # Moderator sources should all be potential_xs pot_xs = moderator.potential_xs for ind in self._mod_isolated_dancoff_fsr_inds: isomoc.set_extern_src(ind, 0, pot_xs) if isinstance(self.fill, BurnablePoisonRod): self.fill.set_isolated_dancoff_fuel_sources(isomoc, moderator)
[docs] def set_isolated_dancoff_clad_sources( self, isomoc: MOCDriver, moderator: Material, ndl: NDLibrary ) -> None: """ Initializes the fixed sources for the isolated MOC calculation required in computing Dancoff corrections. Sources are set for a clad Dancoff correction calculation. Parameters ---------- isomoc : MOCDriver MOC simulation for the isolated geometry. moderator : Material Material definition for the moderator, used to obtain the potential scattering cross section. ndl : NDLibrary Nuclear data library for obtaining potential scattering cross sections. """ # Clad sources should all be zero ! for ind in self._clad_isolated_dancoff_fsr_inds: isomoc.set_extern_src(ind, 0, 0.0) # Moderator sources should all be potential_xs pot_xs = moderator.potential_xs for ind in self._mod_isolated_dancoff_fsr_inds: isomoc.set_extern_src(ind, 0, pot_xs) if isinstance(self.fill, BurnablePoisonRod): self.fill.set_isolated_dancoff_clad_sources(isomoc, moderator, ndl)
[docs] def set_full_dancoff_fuel_sources( self, fullmoc: MOCDriver, moderator: Material ) -> None: """ Initializes the fixed sources for the full MOC calculation required in computing Dancoff corrections. Sources are set for a fuel Dancoff correction calculation. Parameters ---------- fullmoc : MOCDriver MOC simulation for the full geometry. moderator : Material Material definition for the moderator, used to obtain the potential scattering cross section. """ # Clad sources should all be potential_xs pot_xs = self.clad.potential_xs for ind in self._clad_full_dancoff_fsr_inds: fullmoc.set_extern_src(ind, 0, pot_xs) # Moderator sources should all be potential_xs pot_xs = moderator.potential_xs for ind in self._mod_full_dancoff_fsr_inds: fullmoc.set_extern_src(ind, 0, pot_xs) if isinstance(self.fill, BurnablePoisonRod): self.fill.set_full_dancoff_fuel_sources(fullmoc, moderator)
[docs] def set_full_dancoff_clad_sources( self, fullmoc: MOCDriver, moderator: Material, ndl: NDLibrary ) -> None: """ Initializes the fixed sources for the full MOC calculation required in computing Dancoff corrections. Sources are set for a clad Dancoff correction calculation. Parameters ---------- isomoc : MOCDriver MOC simulation for the isolated geometry. moderator : Material Material definition for the moderator, used to obtain the potential scattering cross section. ndl : NDLibrary Nuclear data library for obtaining potential scattering cross sections. """ # Clad sources should all be zero ! for ind in self._clad_full_dancoff_fsr_inds: fullmoc.set_extern_src(ind, 0, 0.0) # Moderator sources should all be potential_xs pot_xs = moderator.potential_xs for ind in self._mod_full_dancoff_fsr_inds: fullmoc.set_extern_src(ind, 0, pot_xs) if isinstance(self.fill, BurnablePoisonRod): self.fill.set_full_dancoff_clad_sources(fullmoc, moderator, ndl)
[docs] def compute_clad_dancoff_correction( self, isomoc: MOCDriver, fullmoc: MOCDriver ) -> float: """ Computes the Dancoff correction for the cladding region. Parameters ---------- isomoc : MOCDriver MOC simulation for the isolated geometry (previously solved). fullmoc : MOCDriver MOC simulation for the full geometry (previously solved). Returns ------- float Dancoff correction for the cladding region. """ iso_flux = isomoc.homogenize_flux_spectrum( self._clad_isolated_dancoff_fsr_inds )[0] full_flux = fullmoc.homogenize_flux_spectrum(self._clad_full_dancoff_fsr_inds)[ 0 ] C = (iso_flux - full_flux) / iso_flux D = 1.0 - C return D
[docs] def append_clad_dancoff_correction(self, C) -> None: """ Saves new Dancoff correction for the cladding that will be used for all subsequent cross section updates. Parameters ---------- C : float New Dancoff correction. """ if C < 0.0 or C > 1.0: raise ValueError( f"Dancoff correction must be in range [0, 1]. Was provided {C}." ) self._clad_dancoff_corrections.append(C)
# ========================================================================== # Transport Calculation Related Methods
[docs] def set_clad_xs_for_depletion_step(self, t: int, ndl: NDLibrary) -> None: """ Constructs the CrossSection object for the cladding of the guide tube at the specified depletion step. The depletion step only changes the Dancoff correction, not the cladding composition. Parameters ---------- t : int Index for the depletion step. ndl : NDLibrary Nuclear data library to use for cross sections. """ # Compute escape xs Ee = 1.0 / (2.0 * (self.outer_radius - self.inner_radius)) # Get / set the xs if self._clad_xs is None: self._clad_xs = self.clad.roman_xs( self._clad_dancoff_corrections[t], Ee, ndl ) else: self._clad_xs.set( self.clad.roman_xs(self._clad_dancoff_corrections[t], Ee, ndl) ) if self._clad_xs.name == "": self._clad_xs.name = "Clad"
[docs] def set_fill_xs_for_depletion_step(self, t: int, ndl: NDLibrary) -> None: """ Constructs the CrossSection objects for the fill of the guide tube at the specified depletion step. The depletion step changes the poison composition, if filled with a burnable poison rod. Parameters ---------- t : int Index for the depletion step. ndl : NDLibrary Nuclear data library to use for cross sections. """ if self.empty: return if isinstance(self.fill, BurnablePoisonRod): self.fill.set_center_xs(ndl) self.fill.set_gap_xs(ndl) self.fill.set_clad_xs(ndl) self.fill.set_poison_xs_for_depletion_step(t, ndl)
[docs] def make_moc_cell( self, moderator_xs: CrossSection, dx: float, dy: float, pintype: PinCellType ) -> PinCell: """ Constructs the pin cell object used in for the global MOC simulation. Parameters ---------- moderator_xs : CrossSection Cross sections to use for the moderator surrounding the fuel pin. dx : float Width of the cell along x. dy : float Width of the cell along y. pintype : PinCellType How the pin cell should be split (along x, y, or only a quadrant). """ if self._clad_xs is None: raise RuntimeError("Clad cross section has not yet been built.") self._check_dx_dy(dx, dy, pintype) # Initialize empty lists radii = [] xss = [] FILL_OFFSET = 0 NUM_MOD_RINGS = 3 if self.empty: # For an empty guide tube, we use 3 rings of water # Create list of inner moderator radii V = np.pi * self.inner_radius * self.inner_radius Vr = V / 3.0 for ri in range(3): Rin = 0.0 if ri > 0: Rin = radii[-1] Rout = np.sqrt((Vr + np.pi * Rin * Rin) / np.pi) if Rout > self.inner_radius: Rout = self.inner_radius radii.append(Rout) # Initialize the cross section lists with the inner moderator xs xss += len(radii) * [moderator_xs] elif isinstance(self.fill, BurnablePoisonRod): radii, xss = self.fill._make_moc_cell(moderator_xs) FILL_OFFSET = len(radii) # Add the layer of moderator outside the poison rod radii.append(self.inner_radius) xss.append(moderator_xs) NUM_MOD_RINGS = 1 else: # Should never get here due to check in constructor, but in any case raise TypeError("Unknown fill object placed in guide tube.") # Add cladding radii.append(self.outer_radius) xss.append(self._clad_xs) # Add another ring of moderator if possible if ( pintype == PinCellType.Full and min(dx, dy) > 2.0 * self.outer_radius and 0.5 * min(dx, dy) - self.outer_radius >= 0.1 ): radii.append(0.5 * min(dx, dy)) xss.append(moderator_xs) elif ( pintype in [PinCellType.XN, PinCellType.XP] and dx > self.outer_radius and dy > 2.0 * self.outer_radius and min(dx, 0.5 * dy) - self.outer_radius >= 0.1 ): radii.append(min(dx, 0.5 * dy)) xss.append(moderator_xs) elif ( pintype in [PinCellType.YN, PinCellType.YP] and dy > self.outer_radius and dx > 2.0 * self.outer_radius and min(0.5 * dx, dy) - self.outer_radius >= 0.1 ): radii.append(min(0.5 * dx, dy)) xss.append(moderator_xs) elif ( pintype in [PinCellType.I, PinCellType.II, PinCellType.III, PinCellType.IV] and dx > self.outer_radius and dy > self.outer_radius and min(dx, dy) - self.outer_radius >= 0.1 ): radii.append(min(dx, dy)) xss.append(moderator_xs) # Add moderator to the end of materials xss.append(moderator_xs) cell = PinCell(radii, xss, dx, dy, pintype) # Get the FSR IDs for the regions of interest cell_fsr_ids = cell.get_all_fsr_ids() # Number of angular divisions NA = 8 if pintype in [PinCellType.XN, PinCellType.XP, PinCellType.YN, PinCellType.YP]: NA = 4 elif pintype in [ PinCellType.I, PinCellType.II, PinCellType.III, PinCellType.IV, ]: NA = 2 # Get all the FSR ids for the poison rod if isinstance(self.fill, BurnablePoisonRod): if self.fill.center is not None: self.fill._center_fsr_ids += cell_fsr_ids[0:NA] self.fill._clad_fsr_ids += cell_fsr_ids[NA : 2 * NA] self.fill._gap_fsr_ids += cell_fsr_ids[2 * NA : 3 * NA] self.fill._poison_fsr_ids += cell_fsr_ids[3 * NA : 4 * NA] self.fill._gap_fsr_ids += cell_fsr_ids[4 * NA : 5 * NA] self.fill._clad_fsr_ids += cell_fsr_ids[5 * NA : 6 * NA] I = 0 # Starting index for cell_fsr_inds # Go through all rings of moderator and get FSR IDs for a in range(NUM_MOD_RINGS * NA): self._mod_fsr_ids.append(cell_fsr_ids[FILL_OFFSET * NA + I]) I += 1 # If we have a poision rod with a water center, add those FSR IDs to the moderator list if isinstance(self.fill, BurnablePoisonRod): if self.fill.center is None: self._mod_fsr_ids += cell_fsr_ids[0:NA] # Get FSR IDs for the cladding for a in range(NA): self._clad_fsr_ids.append(cell_fsr_ids[FILL_OFFSET * NA + I]) I += 1 # Everything outside the clad should be moderator self._mod_fsr_ids = list(cell_fsr_ids[FILL_OFFSET * NA + I :]) return cell
[docs] def populate_fsr_indexes(self, moc: MOCDriver) -> None: """ Obtains the flat source region indexes for all of the flat source regions used in the full MOC calculations. Parameters ---------- moc : MOCDriver MOC simulation for the full calculations. """ self._clad_fsr_inds: List[int] = [] self._mod_fsr_inds: List[int] = [] for id in self._clad_fsr_ids: self._clad_fsr_inds.append(moc.get_fsr_indx(id, 0)) for id in self._mod_fsr_ids: self._mod_fsr_inds.append(moc.get_fsr_indx(id, 0)) if isinstance(self.fill, BurnablePoisonRod): self.fill.populate_fsr_indexes(moc)
[docs] def obtain_flux_spectra(self, moc: MOCDriver) -> None: """ If the guide tube contains a burnable poison rod, the average flux spectrum in the poison is obtained from the MOC simulation. Parameters ---------- moc : MOCDriver MOC simulation for the full calculations. """ if not self.empty and isinstance(self.fill, BurnablePoisonRod): self.fill.obtain_flux_spectra(moc)
[docs] def normalize_flux_spectrum(self, f) -> None: """ If the guide tube contains a burnable poison rod, it applies a multiplicative factor to the flux spectra for the poison. This permits normalizing the flux to a known assembly power. Parameters ---------- f : float Normalization factor. """ if not self.empty and isinstance(self.fill, BurnablePoisonRod): self.fill.normalize_flux_spectrum(f)
[docs] def predict_depletion( self, chain: DepletionChain, ndl: NDLibrary, dt: float, dtm1: Optional[float] = None, ) -> None: """ Performs the predictor in the integration of the Bateman equation. If the argument for the previous time step is not provided, CE/LI will be used. Otherwise, CE/LI is used on the first depletion step, and LE/QI is used for all subsequent time steps. The predicted material compositions are appended to the materials lists. Parameters ---------- chain : DepletionChain Depletion chain to use for radioactive decay and transmutation. ndl : NDLibrary Nuclear data library. dt : float Durration of the time step in seconds. dtm1 : float, optional Durration of the previous time step in seconds. Default is None. """ if dt <= 0: raise ValueError("Predictor time step must be > 0.") if not self.empty and isinstance(self.fill, BurnablePoisonRod): self.fill.predict_depletion(chain, ndl, dt, dtm1)
[docs] def correct_depletion( self, chain: DepletionChain, ndl: NDLibrary, dt: float, dtm1: Optional[float] = None, ) -> None: """ Performs the corrector in the integration of the Bateman equation. If the argument for the previous time step is not provided, CE/LI will be used. Otherwise, CE/LI is used on the first depletion step, and LE/QI is used for all subsequent time steps. The corrected material compositions replace the ones where were appended in the corrector step. Parameters ---------- chain : DepletionChain Depletion chain to use for radioactive decay and transmutation. ndl : NDLibrary Nuclear data library. dt : float Durration of the time step in seconds. dtm1 : float, optional Durration of the previous time step in seconds. Default is None. """ if dt <= 0: raise ValueError("Corrector time step must be > 0.") # Nothing to do here yet, as guide tube "fills" with burnable # absorber pins is not yet supported. In the future, those will # need to be depleted ! if not self.empty and isinstance(self.fill, BurnablePoisonRod): self.fill.correct_depletion(chain, ndl, dt, dtm1)