Beispiel #1
0
def test_xcylinder():
    y, z, r = 3, 5, 2
    s = openmc.XCylinder(y0=y, z0=z, r=r)
    assert s.y0 == y
    assert s.z0 == z
    assert s.r == r

    # Check bounding box
    ll, ur = (+s).bounding_box
    assert np.all(np.isinf(ll))
    assert np.all(np.isinf(ur))
    ll, ur = (-s).bounding_box
    assert ll == pytest.approx((-np.inf, y - r, z - r))
    assert ur == pytest.approx((np.inf, y + r, z + r))

    # evaluate method
    assert s.evaluate((0, y, z)) == pytest.approx(-r**2)

    # translate method
    st = s.translate((1.0, 1.0, 1.0))
    assert st.y0 == s.y0 + 1
    assert st.z0 == s.z0 + 1
    assert st.r == s.r

    # rotate method
    sr = s.rotate((90, 90, 90))
    R = np.array([[0, 0, 1], [0, 1, 0], [-1, 0, 0]])
    assert sr._origin == pytest.approx(R @ s._origin)
    assert sr._axis == pytest.approx(R @ s._axis)
    # test passing in rotation matrix
    sr2 = s.rotate(R)
    assert sr2._get_base_coeffs() == pytest.approx(sr._get_base_coeffs())

    # Make sure repr works
    repr(s)
def test_xcylinder():
    y, z, r = 3, 5, 2
    s = openmc.XCylinder(y0=y, z0=z, r=r)
    assert s.y0 == y
    assert s.z0 == z
    assert s.r == r

    # Check bounding box
    ll, ur = (+s).bounding_box
    assert np.all(np.isinf(ll))
    assert np.all(np.isinf(ur))
    ll, ur = (-s).bounding_box
    assert ll == pytest.approx((-np.inf, y-r, z-r))
    assert ur == pytest.approx((np.inf, y+r, z+r))

    # evaluate method
    assert s.evaluate((0, y, z)) == pytest.approx(-r**2)

    # translate method
    st = s.translate((1.0, 1.0, 1.0))
    assert st.y0 == s.y0 + 1
    assert st.z0 == s.z0 + 1
    assert st.r == s.r

    # Make sure repr works
    repr(s)
Beispiel #3
0
def test_failure(pin_mats, good_radii):
    """Check for various failure modes"""
    good_surfaces = [openmc.ZCylinder(r=r) for r in good_radii]
    # Bad material type
    with pytest.raises(TypeError):
        pin(good_surfaces, [mat.name for mat in pin_mats])

    # Incorrect lengths
    with pytest.raises(ValueError, match="length"):
        pin(good_surfaces[:len(pin_mats) - 2], pin_mats)

    # Non-positive radii
    rad = [openmc.ZCylinder(r=-0.1)] + good_surfaces[1:]
    with pytest.raises(ValueError, match="index 0"):
        pin(rad, pin_mats)

    # Non-increasing radii
    surfs = tuple(reversed(good_surfaces))
    with pytest.raises(ValueError, match="index 1"):
        pin(surfs, pin_mats)

    # Bad orientation
    surfs = [openmc.XCylinder(r=good_surfaces[0].r)] + good_surfaces[1:]
    with pytest.raises(TypeError, match="surfaces"):
        pin(surfs, pin_mats)

    # Passing cells argument
    with pytest.raises(SyntaxError, match="Cells"):
        pin(surfs, pin_mats, cells=[])
def centers_x_cylinder():
    cylinder = openmc.XCylinder(r=1, y0=1, z0=2)
    min_x = openmc.XPlane(0)
    max_x = openmc.XPlane(1)
    region = +min_x & -max_x & -cylinder
    return openmc.model.pack_spheres(radius=_RADIUS,
                                     region=region,
                                     pf=_PACKING_FRACTION,
                                     initial_pf=0.2)
Beispiel #5
0
 def __init__(self, center_base, height, radius, axis='z', **kwargs):
     cx, cy, cz = center_base
     check_greater_than('cylinder height', height, 0.0)
     check_greater_than('cylinder radius', radius, 0.0)
     check_value('cylinder axis', axis, ('x', 'y', 'z'))
     if axis == 'x':
         self.cyl = openmc.XCylinder(y0=cy, z0=cz, r=radius, **kwargs)
         self.bottom = openmc.XPlane(x0=cx, **kwargs)
         self.top = openmc.XPlane(x0=cx + height, **kwargs)
     elif axis == 'y':
         self.cyl = openmc.YCylinder(x0=cx, z0=cz, r=radius, **kwargs)
         self.bottom = openmc.YPlane(y0=cy, **kwargs)
         self.top = openmc.YPlane(y0=cy + height, **kwargs)
     elif axis == 'z':
         self.cyl = openmc.ZCylinder(x0=cx, y0=cy, r=radius, **kwargs)
         self.bottom = openmc.ZPlane(z0=cz, **kwargs)
         self.top = openmc.ZPlane(z0=cz + height, **kwargs)
Beispiel #6
0
def get_openmc_surface(opencg_surface):
    """Return an OpenMC surface corresponding to an OpenCG surface.

    Parameters
    ----------
    opencg_surface : opencg.Surface
        OpenCG surface

    Returns
    -------
    openmc_surface : openmc.surface.Surface
        Equivalent OpenMC surface

    """

    if not isinstance(opencg_surface, opencg.Surface):
        msg = 'Unable to create an OpenMC Surface from "{0}" which ' \
              'is not an OpenCG Surface'.format(opencg_surface)
        raise ValueError(msg)

    global openmc_surface
    surface_id = opencg_surface._id

    # If this Surface was already created, use it
    if surface_id in OPENMC_SURFACES:
        return OPENMC_SURFACES[surface_id]

    # Create an OpenMC Surface to represent this OpenCG Surface
    name = opencg_surface._name

    # Correct for OpenMC's syntax for Surfaces dividing Cells
    boundary = opencg_surface._boundary_type
    if boundary == 'interface':
        boundary = 'transmission'

    if opencg_surface._type == 'plane':
        A = opencg_surface._coeffs['A']
        B = opencg_surface._coeffs['B']
        C = opencg_surface._coeffs['C']
        D = opencg_surface._coeffs['D']
        openmc_surface = openmc.Plane(surface_id, boundary, A, B, C, D, name)

    elif opencg_surface._type == 'x-plane':
        x0 = opencg_surface._coeffs['x0']
        openmc_surface = openmc.XPlane(surface_id, boundary, x0, name)

    elif opencg_surface._type == 'y-plane':
        y0 = opencg_surface._coeffs['y0']
        openmc_surface = openmc.YPlane(surface_id, boundary, y0, name)

    elif opencg_surface._type == 'z-plane':
        z0 = opencg_surface._coeffs['z0']
        openmc_surface = openmc.ZPlane(surface_id, boundary, z0, name)

    elif opencg_surface._type == 'x-cylinder':
        y0 = opencg_surface._coeffs['y0']
        z0 = opencg_surface._coeffs['z0']
        R = opencg_surface._coeffs['R']
        openmc_surface = openmc.XCylinder(surface_id, boundary, y0, z0, R,
                                          name)

    elif opencg_surface._type == 'y-cylinder':
        x0 = opencg_surface._coeffs['x0']
        z0 = opencg_surface._coeffs['z0']
        R = opencg_surface._coeffs['R']
        openmc_surface = openmc.YCylinder(surface_id, boundary, x0, z0, R,
                                          name)

    elif opencg_surface._type == 'z-cylinder':
        x0 = opencg_surface._coeffs['x0']
        y0 = opencg_surface._coeffs['y0']
        R = opencg_surface._coeffs['R']
        openmc_surface = openmc.ZCylinder(surface_id, boundary, x0, y0, R,
                                          name)

    else:
        msg = 'Unable to create an OpenMC Surface from an OpenCG ' \
              'Surface of type "{0}" since it is not a compatible ' \
              'Surface type in OpenMC'.format(opencg_surface._type)
        raise ValueError(msg)

    # Add the OpenMC Surface to the global collection of all OpenMC Surfaces
    OPENMC_SURFACES[surface_id] = openmc_surface

    # Add the OpenCG Surface to the global collection of all OpenCG Surfaces
    OPENCG_SURFACES[surface_id] = opencg_surface

    return openmc_surface
Beispiel #7
0
    def _read_surfaces(self):
        self.n_surfaces = self._f['geometry/n_surfaces'].value

        # Initialize dictionary for each Surface
        # Keys     - Surface keys
        # Values   - Surfacee objects
        self.surfaces = {}

        for key in self._f['geometry/surfaces'].keys():
            if key == 'n_surfaces':
                continue

            surface_id = int(key.lstrip('surface '))
            index = self._f['geometry/surfaces'][key]['index'].value
            name = self._f['geometry/surfaces'][key]['name'].value.decode()
            surf_type = self._f['geometry/surfaces'][key]['type'].value.decode(
            )
            bc = self._f['geometry/surfaces'][key][
                'boundary_condition'].value.decode()
            coeffs = self._f['geometry/surfaces'][key]['coefficients'][...]

            # Create the Surface based on its type
            if surf_type == 'x-plane':
                x0 = coeffs[0]
                surface = openmc.XPlane(surface_id, bc, x0, name)

            elif surf_type == 'y-plane':
                y0 = coeffs[0]
                surface = openmc.YPlane(surface_id, bc, y0, name)

            elif surf_type == 'z-plane':
                z0 = coeffs[0]
                surface = openmc.ZPlane(surface_id, bc, z0, name)

            elif surf_type == 'plane':
                A = coeffs[0]
                B = coeffs[1]
                C = coeffs[2]
                D = coeffs[3]
                surface = openmc.Plane(surface_id, bc, A, B, C, D, name)

            elif surf_type == 'x-cylinder':
                y0 = coeffs[0]
                z0 = coeffs[1]
                R = coeffs[2]
                surface = openmc.XCylinder(surface_id, bc, y0, z0, R, name)

            elif surf_type == 'y-cylinder':
                x0 = coeffs[0]
                z0 = coeffs[1]
                R = coeffs[2]
                surface = openmc.YCylinder(surface_id, bc, x0, z0, R, name)

            elif surf_type == 'z-cylinder':
                x0 = coeffs[0]
                y0 = coeffs[1]
                R = coeffs[2]
                surface = openmc.ZCylinder(surface_id, bc, x0, y0, R, name)

            elif surf_type == 'sphere':
                x0 = coeffs[0]
                y0 = coeffs[1]
                z0 = coeffs[2]
                R = coeffs[3]
                surface = openmc.Sphere(surface_id, bc, x0, y0, z0, R, name)

            elif surf_type in ['x-cone', 'y-cone', 'z-cone']:
                x0 = coeffs[0]
                y0 = coeffs[1]
                z0 = coeffs[2]
                R2 = coeffs[3]

                if surf_type == 'x-cone':
                    surface = openmc.XCone(surface_id, bc, x0, y0, z0, R2,
                                           name)
                if surf_type == 'y-cone':
                    surface = openmc.YCone(surface_id, bc, x0, y0, z0, R2,
                                           name)
                if surf_type == 'z-cone':
                    surface = openmc.ZCone(surface_id, bc, x0, y0, z0, R2,
                                           name)

            elif surf_type == 'quadric':
                a, b, c, d, e, f, g, h, j, k = coeffs
                surface = openmc.Quadric(surface_id, bc, a, b, c, d, e, f, g,
                                         h, j, k, name)

            # Add Surface to global dictionary of all Surfaces
            self.surfaces[index] = surface
def get_openmc_surface(opencg_surface):
    """Return an OpenMC surface corresponding to an OpenCG surface.

    Parameters
    ----------
    opencg_surface : opencg.Surface
        OpenCG surface

    Returns
    -------
    openmc_surface : openmc.surface.Surface
        Equivalent OpenMC surface

    """

    cv.check_type('opencg_surface', opencg_surface, opencg.Surface)

    surface_id = opencg_surface.id

    # If this Surface was already created, use it
    if surface_id in OPENMC_SURFACES:
        return OPENMC_SURFACES[surface_id]

    # Create an OpenMC Surface to represent this OpenCG Surface
    name = opencg_surface.name

    # Correct for OpenMC's syntax for Surfaces dividing Cells
    boundary = opencg_surface.boundary_type
    if boundary == 'interface':
        boundary = 'transmission'

    if opencg_surface.type == 'plane':
        A = opencg_surface.a
        B = opencg_surface.b
        C = opencg_surface.c
        D = opencg_surface.d
        openmc_surface = openmc.Plane(surface_id, boundary, A, B, C, D, name)

    elif opencg_surface.type == 'x-plane':
        x0 = opencg_surface.x0
        openmc_surface = openmc.XPlane(surface_id, boundary, x0, name)

    elif opencg_surface.type == 'y-plane':
        y0 = opencg_surface.y0
        openmc_surface = openmc.YPlane(surface_id, boundary, y0, name)

    elif opencg_surface.type == 'z-plane':
        z0 = opencg_surface.z0
        openmc_surface = openmc.ZPlane(surface_id, boundary, z0, name)

    elif opencg_surface.type == 'x-cylinder':
        y0 = opencg_surface.y0
        z0 = opencg_surface.z0
        R = opencg_surface.r
        openmc_surface = openmc.XCylinder(surface_id, boundary, y0, z0, R,
                                          name)

    elif opencg_surface.type == 'y-cylinder':
        x0 = opencg_surface.x0
        z0 = opencg_surface.z0
        R = opencg_surface.r
        openmc_surface = openmc.YCylinder(surface_id, boundary, x0, z0, R,
                                          name)

    elif opencg_surface.type == 'z-cylinder':
        x0 = opencg_surface.x0
        y0 = opencg_surface.y0
        R = opencg_surface.r
        openmc_surface = openmc.ZCylinder(surface_id, boundary, x0, y0, R,
                                          name)

    else:
        msg = 'Unable to create an OpenMC Surface from an OpenCG ' \
              'Surface of type "{0}" since it is not a compatible ' \
              'Surface type in OpenMC'.format(opencg_surface.type)
        raise ValueError(msg)

    # Add the OpenMC Surface to the global collection of all OpenMC Surfaces
    OPENMC_SURFACES[surface_id] = openmc_surface

    # Add the OpenCG Surface to the global collection of all OpenCG Surfaces
    OPENCG_SURFACES[surface_id] = opencg_surface

    return openmc_surface
Beispiel #9
0
    def _make_openmc_input(self):
        """Generate the OpenMC input XML

        """
        # Define material
        mat = openmc.Material()
        for nuclide, fraction in self.nuclides:
            mat.add_nuclide(nuclide, fraction)
        mat.set_density('g/cm3', self.density)
        materials = openmc.Materials([mat])
        if self.xsdir is not None:
            xs_path = (self.openmc_dir / 'cross_sections.xml').resolve()
            materials.cross_sections = str(xs_path)
        materials.export_to_xml(self.openmc_dir / 'materials.xml')

        # Instantiate surfaces
        cyl = openmc.XCylinder(boundary_type='vacuum', r=1.e-6)
        px1 = openmc.XPlane(boundary_type='vacuum', x0=-1.)
        px2 = openmc.XPlane(boundary_type='transmission', x0=1.)
        px3 = openmc.XPlane(boundary_type='vacuum', x0=1.e9)

        # Instantiate cells
        inner_cyl_left = openmc.Cell()
        inner_cyl_right = openmc.Cell()
        outer_cyl = openmc.Cell()

        # Set cells regions and materials
        inner_cyl_left.region = -cyl & +px1 & -px2
        inner_cyl_right.region = -cyl & +px2 & -px3
        outer_cyl.region = ~(-cyl & +px1 & -px3)
        inner_cyl_right.fill = mat

        # Create root universe and export to XML
        geometry = openmc.Geometry(
            [inner_cyl_left, inner_cyl_right, outer_cyl])
        geometry.export_to_xml(self.openmc_dir / 'geometry.xml')

        # Define source
        source = openmc.Source()
        source.space = openmc.stats.Point((0, 0, 0))
        source.angle = openmc.stats.Monodirectional()
        source.energy = openmc.stats.Discrete([self.energy], [1.])
        source.particle = 'neutron'

        # Settings
        settings = openmc.Settings()
        if self._temperature is not None:
            settings.temperature = {'default': self._temperature}
        settings.source = source
        settings.particles = self.particles // self._batches
        settings.run_mode = 'fixed source'
        settings.batches = self._batches
        settings.photon_transport = True
        settings.electron_treatment = self.electron_treatment
        settings.cutoff = {'energy_photon': self._cutoff_energy}
        settings.export_to_xml(self.openmc_dir / 'settings.xml')

        # Define filters
        surface_filter = openmc.SurfaceFilter(cyl)
        particle_filter = openmc.ParticleFilter('photon')
        energy_bins = np.logspace(np.log10(self._cutoff_energy),
                                  np.log10(self.max_energy), self._bins + 1)
        energy_filter = openmc.EnergyFilter(energy_bins)

        # Create tallies and export to XML
        tally = openmc.Tally(name='tally')
        tally.filters = [surface_filter, energy_filter, particle_filter]
        tally.scores = ['current']
        tallies = openmc.Tallies([tally])
        tallies.export_to_xml(self.openmc_dir / 'tallies.xml')
Beispiel #10
0
    def _build_openmc(self):
        """Generate the OpenMC input XML

        """
        # Directory from which openmc is run
        os.makedirs('openmc', exist_ok=True)

        # Define material
        mat = openmc.Material()
        for nuclide, fraction in self.nuclides:
            mat.add_nuclide(nuclide, fraction)
        mat.set_density('g/cm3', self.density)
        materials = openmc.Materials([mat])
        materials.export_to_xml(os.path.join('openmc', 'materials.xml'))

        # Instantiate surfaces
        cyl = openmc.XCylinder(boundary_type='vacuum', R=1.e-6)
        px1 = openmc.XPlane(boundary_type='vacuum', x0=-1.)
        px2 = openmc.XPlane(boundary_type='transmission', x0=1.)
        px3 = openmc.XPlane(boundary_type='vacuum', x0=1.e9)

        # Instantiate cells
        inner_cyl_left = openmc.Cell()
        inner_cyl_right = openmc.Cell()
        outer_cyl = openmc.Cell()

        # Set cells regions and materials
        inner_cyl_left.region = -cyl & +px1 & -px2
        inner_cyl_right.region = -cyl & +px2 & -px3
        outer_cyl.region = ~(-cyl & +px1 & -px3)
        inner_cyl_right.fill = mat

        # Create root universe and export to XML
        geometry = openmc.Geometry(
            [inner_cyl_left, inner_cyl_right, outer_cyl])
        geometry.export_to_xml(os.path.join('openmc', 'geometry.xml'))

        # Define source
        source = openmc.Source()
        source.space = openmc.stats.Point((0, 0, 0))
        source.angle = openmc.stats.Monodirectional()
        source.energy = openmc.stats.Discrete([self.energy], [1.])
        source.particle = 'neutron'

        # Settings
        settings = openmc.Settings()
        settings.source = source
        settings.particles = self.particles
        settings.run_mode = 'fixed source'
        settings.batches = 1
        settings.photon_transport = True
        settings.electron_treatment = self.electron_treatment
        settings.cutoff = {'energy_photon': 1000.}
        settings.export_to_xml(os.path.join('openmc', 'settings.xml'))

        # Define filters
        surface_filter = openmc.SurfaceFilter(cyl)
        particle_filter = openmc.ParticleFilter('photon')
        energy_bins = np.logspace(3, np.log10(2 * self.energy), 500)
        energy_filter = openmc.EnergyFilter(energy_bins)

        # Create tallies and export to XML
        tally = openmc.Tally(name='photon current')
        tally.filters = [surface_filter, energy_filter, particle_filter]
        tally.scores = ['current']
        tallies = openmc.Tallies([tally])
        tallies.export_to_xml(os.path.join('openmc', 'tallies.xml'))
Beispiel #11
0
    def _build_inputs(self):
        mat = openmc.Material()
        mat.set_density('g/cm3', 2.6989)
        mat.add_nuclide('Al27', 1.0)
        materials = openmc.Materials([mat])
        materials.export_to_xml()

        cyl = openmc.XCylinder(r=1.0, boundary_type='vacuum')
        x_plane_left = openmc.XPlane(-1.0, 'vacuum')
        x_plane_center = openmc.XPlane(1.0)
        x_plane_right = openmc.XPlane(1.0e9, 'vacuum')

        inner_cyl_left = openmc.Cell()
        inner_cyl_right = openmc.Cell()
        outer_cyl = openmc.Cell()

        inner_cyl_left.region = -cyl & +x_plane_left & -x_plane_center
        inner_cyl_right.region = -cyl & +x_plane_center & -x_plane_right
        outer_cyl.region = ~(-cyl & +x_plane_left & -x_plane_right)
        inner_cyl_right.fill = mat
        geometry = openmc.Geometry(
            [inner_cyl_left, inner_cyl_right, outer_cyl])
        geometry.export_to_xml()

        source = openmc.Source()
        source.space = openmc.stats.Point((0, 0, 0))
        source.angle = openmc.stats.Monodirectional()
        source.energy = openmc.stats.Discrete([14.0e6], [1.0])
        source.particle = 'neutron'

        settings = openmc.Settings()
        settings.particles = 10000
        settings.run_mode = 'fixed source'
        settings.batches = 1
        settings.photon_transport = True
        settings.electron_treatment = 'ttb'
        settings.cutoff = {'energy_photon': 1000.0}
        settings.source = source
        settings.export_to_xml()

        surface_filter = openmc.SurfaceFilter(cyl)
        particle_filter = openmc.ParticleFilter('photon')
        current_tally = openmc.Tally()
        current_tally.filters = [surface_filter, particle_filter]
        current_tally.scores = ['current']
        tally_tracklength = openmc.Tally()
        tally_tracklength.filters = [particle_filter]
        tally_tracklength.scores = ['total', 'heating']
        tally_tracklength.nuclides = ['Al27', 'total']
        tally_tracklength.estimator = 'tracklength'
        tally_collision = openmc.Tally()
        tally_collision.filters = [particle_filter]
        tally_collision.scores = ['total', 'heating']
        tally_collision.nuclides = ['Al27', 'total']
        tally_collision.estimator = 'collision'
        tally_analog = openmc.Tally()
        tally_analog.filters = [particle_filter]
        tally_analog.scores = ['total', 'heating']
        tally_analog.nuclides = ['Al27', 'total']
        tally_analog.estimator = 'analog'
        tallies = openmc.Tallies(
            [current_tally, tally_tracklength, tally_collision, tally_analog])
        tallies.export_to_xml()
Beispiel #12
0
def model():
    model = openmc.model.Model()
    mat = openmc.Material()
    mat.set_density('g/cm3', 2.6989)
    mat.add_nuclide('Al27', 1.0)
    model.materials.append(mat)

    cyl = openmc.XCylinder(r=1.0, boundary_type='vacuum')
    x_plane_left = openmc.XPlane(-1.0, boundary_type='vacuum')
    x_plane_center = openmc.XPlane(1.0)
    x_plane_right = openmc.XPlane(1.0e9, boundary_type='vacuum')

    inner_cyl_left = openmc.Cell()
    inner_cyl_right = openmc.Cell()
    outer_cyl = openmc.Cell()

    inner_cyl_left.region = -cyl & +x_plane_left & -x_plane_center
    inner_cyl_right.region = -cyl & +x_plane_center & -x_plane_right
    outer_cyl.region = ~(-cyl & +x_plane_left & -x_plane_right)
    inner_cyl_right.fill = mat
    model.geometry = openmc.Geometry(
        [inner_cyl_left, inner_cyl_right, outer_cyl])

    source = openmc.Source()
    source.space = openmc.stats.Point((0, 0, 0))
    source.angle = openmc.stats.Monodirectional()
    source.energy = openmc.stats.Discrete([14.0e6], [1.0])
    source.particle = 'neutron'

    model.settings.particles = 10000
    model.settings.run_mode = 'fixed source'
    model.settings.batches = 1
    model.settings.photon_transport = True
    model.settings.electron_treatment = 'ttb'
    model.settings.cutoff = {'energy_photon': 1000.0}
    model.settings.source = source

    surface_filter = openmc.SurfaceFilter(cyl)
    particle_filter = openmc.ParticleFilter(
        ['neutron', 'photon', 'electron', 'positron'])
    current_tally = openmc.Tally()
    current_tally.filters = [surface_filter, particle_filter]
    current_tally.scores = ['current']
    tally_tracklength = openmc.Tally()
    tally_tracklength.filters = [particle_filter]
    tally_tracklength.scores = ['total', '(n,gamma)'
                                ]  # heating doesn't work with tracklength
    tally_tracklength.nuclides = ['Al27', 'total']
    tally_tracklength.estimator = 'tracklength'
    tally_collision = openmc.Tally()
    tally_collision.filters = [particle_filter]
    tally_collision.scores = ['total', 'heating', '(n,gamma)']
    tally_collision.nuclides = ['Al27', 'total']
    tally_collision.estimator = 'collision'
    tally_analog = openmc.Tally()
    tally_analog.filters = [particle_filter]
    tally_analog.scores = ['total', 'heating', '(n,gamma)']
    tally_analog.nuclides = ['Al27', 'total']
    tally_analog.estimator = 'analog'
    model.tallies.extend(
        [current_tally, tally_tracklength, tally_collision, tally_analog])

    return model