Plates and Channels, an MTR Love Story

In the following example, we will construct a channel and a fuel plate based on IRR-1 (MAMAG) reactor specifications.

[1]:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rc

rc("font", family="serif", size=15)
rc("savefig", dpi=600)
rc("figure", figsize=(8, 6))
rc("mathtext", fontset="dejavuserif")
rc("lines", linewidth=3)

from functools import partial

from stream.calculations import ChannelAndContacts, Fuel
from stream.calculations.heat_diffusion import Solid
from stream.composition import symmetric_plate_steady_state
from stream.composition.mtr_geometry import symmetric_plate, x_boundaries
from stream.physical_models.heat_transfer_coefficient import (
    regime_dependent_q_scb,
    spl_htc,
    wall_heat_transfer_coeff,
)
from stream.physical_models.pressure_drop import (
    friction_factor,
    pressure_diff,
    rectangular_laminar_correction,
)
from stream.pipe_geometry import EffectivePipe
from stream.substances import light_water
from stream.units import cm, mm
from stream.utilities import cosine_shape

Entering data for fuel plate modeling

We need to specify the discretization, dimensions and properties of the plate - both fuel and cladding:

[2]:
z_N, fuel_N, clad_N = 25, 8, 3
meat_height = 60.4 * cm
meat_width = 63 * mm
meat_depth = 0.51 * mm
clad_depth = 0.38 * mm
clad = Solid(density=2700, specific_heat=900, conductivity=250)  # numbers are approximate
fuel = Solid(density=3500, specific_heat=750, conductivity=100)  # numbers are approximate

Creating a model of the fuel plate

We set the power distribution along the plate to be cosine-shaped in the xz plane, and fixed throughout the depth of the plate and its width (along the x-axis and y-axis):

[3]:
shape = np.array((z_N, fuel_N + 2 * clad_N))
meat = np.zeros(shape, dtype=bool)
meat[:, clad_N:-clad_N] = True

materials = np.empty(shape, dtype=object)
materials[meat] = fuel
materials[~meat] = clad
material = Solid.from_array(materials)

power_shape_in_rod = cosine_shape(np.linspace(0, meat_height, z_N + 1))
dx_meat = np.diff(x_boundaries(clad_N, fuel_N, clad_depth, meat_depth))[clad_N:-clad_N]
area_fraction = dx_meat / meat_depth
plate_power_shape = np.outer(power_shape_in_rod, area_fraction)

Defining the fuel plate using the defined values and inputs

[4]:
F = Fuel(
    z_boundaries=np.linspace(0, meat_height, z_N + 1),
    x_boundaries=x_boundaries(clad_N=clad_N, fuel_N=fuel_N, clad_w=clad_depth, meat_w=meat_depth),
    material=material,
    y_length=meat_width,
    meat_indices=meat,
    power_shape=plate_power_shape,
    name="Fuel",
)

Creating a model of the channel

we enter inputs defining the dimensions of the channel (between two already-defined plates, coupled with periodic boundary conditions), and properties of the flow in the channel:

[5]:
channel_width = 66.6 * mm
channel_depth = 2.1 * mm

re_bounds = laminar_re_max, turbulent_re_min = 2500, 4000
a_dp = channel_depth / channel_width
k_R = rectangular_laminar_correction(a_dp)

comp_friction = friction_factor("regime_dependent", re_bounds=re_bounds, k_R=k_R)

pressure_diff_func = partial(pressure_diff, f=comp_friction)

comp_h_spl = spl_htc("regime_dependent", re_bounds=re_bounds, a_dp=a_dp, Lh=meat_height)
comp_scb = partial(regime_dependent_q_scb, re_bounds=re_bounds)
htc = partial(wall_heat_transfer_coeff, h_spl=comp_h_spl, q_scb=comp_scb)

Defining the channel using the defined values and inputs

Notice that for our coupled construction (which we will create in a moment), the z_N discretization of both fuel and channel must be the same.

[6]:
C = ChannelAndContacts(
    z_boundaries=np.linspace(0, meat_height, z_N + 1),
    fluid=light_water,
    pipe=EffectivePipe.rectangular(
        length=meat_height,
        edge1=channel_depth,
        edge2=channel_width,
        heated_edge=meat_width,
    ),
    h_wall_func=htc,
    pressure_func=pressure_diff_func,
    name="Channel",
)

Coupling Fuel and Channel

Assuming symmetry, we will construct the fuel and channel as if they envelope each other simultaneously from both sides:

[7]:
sys = symmetric_plate(C, F)
from stream.analysis.report import report

report(sys.to_aggregator())

Contains 476 Equations, 2 Nodes, 2 Edges.

Calculation

Type

Equation No.

Unset

Set Externally

Missing

Fuel

Fuel

0 - 400

power, T_top, T_bottom, h_top, h_bottom

power

Channel

ChannelAndContacts

400 - 476

Tin, Tin_minus, mdot, p_abs, mdot2

Tin, mdot, p_abs

The missing parameters must be provided, as shown below.

Let us define some approximate parameters of IRR-1:

[8]:
total_power = 5e6
FA_flow = 17.5  # in m3/h, in one fuel assembly
core_rods = 24  # a typical number
plates_per_rod = 23
plates_in_core = plates_per_rod * core_rods

Now, we can run any simulation we want with this coupled system, or compose it into a larger system. Let’s say we only wish to know the steady state of this system given some obvious parameters. Easily enough, there’s already a function for that in STREAM, which employs symmetric_plate internally:

[9]:
state = symmetric_plate_steady_state(
    C,
    F,
    mdot=FA_flow
    * (1000 / 3600)
    / plates_per_rod,  # Coolant mass flow. A positive value indicates downward flow [KgPerS]
    p_abs=1.67e5,  # Absolute pressure at the top of the channel [Pascal]
    power=total_power / plates_in_core,  # Total power generated by the fuel plate, averaged for the entire core [Watt]
    Tin=35.0,  # Inlet coolant temperature [Celsius]
)

Here we will draw the temperature distribution along the channel (z-axis) of the coolant, the cladding and the fuel:

[10]:
plt.figure()
plt.plot(C.centers, state[C.name]["T_cool"], label="Coolant")
plt.plot(C.centers, state[F.name]["T_wall_right"])
plt.plot(C.centers, state[F.name]["T_wall_left"], label="Wall")
plt.plot(
    C.centers,
    state[F.name]["T"].reshape(F.shape)[:, clad_N + int((fuel_N - 1) / 2)],
    label="Fuel Center",
)
plt.xlabel("Distance from top [m]")
plt.ylabel(r"Temperature [$\degree$C]")
plt.legend()
plt.grid()
plt.show()
_images/SampleFuelPlateAndChannel_20_0.png

And here we will draw a color map of the temperature distribution of the fuel along the channel:

[11]:
plt.figure(figsize=(8, 6))
ax = plt.imshow(state[F.name]["T"].reshape(F.shape), cmap="jet")
plt.colorbar(ax, label="Fuel Temp. [C]")
plt.xticks([])
plt.yticks([])
plt.show()
_images/SampleFuelPlateAndChannel_22_0.png