Difference between revisions of "SMR startup simulation (outdated)"

From Kraken Wiki
Jump to: navigation, search
(Overview)
(Evaluating HFP ARO critical boron)
Line 30: Line 30:
  
 
== Evaluating HFP ARO critical boron ==
 
== Evaluating HFP ARO critical boron ==
 +
 +
 +
<div class="toccolours mw-collapsible mw-collapsed" style="width:60em;">
 +
'''Cerberus input for HPF ARO boron iteration'''
 +
<div class="mw-collapsible-content">
 +
from os import environ
 +
from pathlib import Path
 +
 +
import numpy as np
 +
 +
import cerberus as cb
 +
from cerberus.solvers import CodeInput
 +
from cerberus.solvers import Solver
 +
from cerberus.interpolation import Interpolator
 +
from numpy.core.fromnumeric import size
 +
 +
# Verbosity for terminal output of Cerberus
 +
 +
cb.LOG.set_verbosity(1)
 +
 +
# Create and start solvers
 +
 +
solver_defs = [["SCF", environ["SCFWRAP_EXE_PATH"], [], ["./Inputs/scf/input.txt"]],
 +
                ["ANTS", environ["ANTS_EXE_PATH"], ["--cerberus","--port"], ["./Inputs/Ants8g.inp"]]]
 +
 +
solvers = {}
 +
 +
port_number = 2211
 +
 +
for name, solver_path, params, inputs in solver_defs:
 +
 +
    # Create input
 +
 +
    solver_input = CodeInput(name, inputs)
 +
 +
    # Create solver
 +
 +
    solver = Solver(name, solver_path, params)
 +
    solver.input = solver_input
 +
    solver.initialize(port_number)
 +
 +
    # Add to solver dict
 +
 +
    solvers[name] = solver
 +
 +
    port_number += 1
 +
 +
# Alias variables for solvers
 +
 +
scf = solvers["SCF"]
 +
ants = solvers["ANTS"]
 +
 +
# Get SCF fields needed for coupled calculation
 +
 +
scf_cool_temperature = scf.get_transferrable("scf_of_cool_temperature_chan")
 +
scf_cool_density = scf.get_transferrable("scf_of_cool_density_chan")
 +
scf_fuel_temperature = scf.get_transferrable("scf_of_fuel_temperature_vol_ave")
 +
scf_power = scf.get_transferrable("scf_if_fuel_power")
 +
 +
# Initialize SCF power field (50 MW divided uniformly over SCF cells)
 +
 +
scf_power.value_vec = 50e6/scf_power.n_values*np.ones(scf_power.n_values)
 +
 +
# Get Ants fields needed for coupled calculation
 +
 +
ants_cool_temperature = ants.get_transferrable("Ants_if_coolant_temperature")
 +
ants_cool_density = ants.get_transferrable("Ants_if_coolant_density")
 +
ants_fuel_temperature = ants.get_transferrable("Ants_if_fuel_temperature")
 +
ants_power = ants.get_transferrable("Ants_of_supernode_power")
 +
ants_boron = ants.get_transferrable("Ants_ov_boron")
 +
 +
# Create interpolators that handle data transfer between SCF and Ants
 +
 +
interp_ct = Interpolator.from_file(scf_cool_temperature,
 +
                                    ants_cool_temperature,
 +
                                    "./Inputs/scf_to_ants.txt")
 +
interp_cd = Interpolator.from_file(scf_cool_density,
 +
                                    ants_cool_density,
 +
                                    "./Inputs/scf_to_ants.txt")
 +
interp_ft = Interpolator.from_file(scf_fuel_temperature,
 +
                                    ants_fuel_temperature,
 +
                                    "./Inputs/scf_to_ants.txt")
 +
interp_p = Interpolator.from_file(ants_power,
 +
                                  scf_power,
 +
                                  "./Inputs/ants_to_scf.txt")
 +
 +
 +
################################################################################
 +
################################################################################
 +
 +
# --- Coupled solution
 +
 +
max_iter = 50
 +
for i in range(max_iter):
 +
    # --- TH solution and communication
 +
 +
    scf_power.communicate()
 +
    scf_power.write_simple(suffix_in=f"{i+1}")
 +
 +
    scf.solve()
 +
 +
    scf_cool_density.communicate()
 +
    scf_cool_temperature.communicate()
 +
    scf_fuel_temperature.communicate()
 +
 +
    # --- Transfers from SCF to Ants fields
 +
 +
    interp_ct.interpolate()
 +
    interp_cd.interpolate()
 +
    interp_ft.interpolate()
 +
 +
    # --- Neutronics solution and communication
 +
 +
    ants_cool_density.communicate()
 +
    ants_cool_temperature.communicate()
 +
    ants_fuel_temperature.communicate()
 +
 +
    ants.solve()
 +
 +
    ants_power.communicate()
 +
    ants_boron.communicate()
 +
 +
    # --- Transfers from Ants to SCF
 +
 +
    interp_p.interpolate()
 +
 +
    print(f"Finished iteration {i+1}, boron is {ants_boron.value_vec[0]}")
 +
 +
# Choose field/value names to save
 +
 +
to_save = ["Ants_ov_keff", "Ants_ov_boron"]
 +
 +
# Output path. Create folder if necessary
 +
 +
output_path = Path(f"./output")
 +
output_path.mkdir(exist_ok=True)
 +
for name in to_save:
 +
    tra = ants.get_transferrable(name)
 +
    tra.communicate()
 +
    tra.write_simple(suffix_in="final", folder_path=output_path)
 +
 +
</div>
 +
</div>
  
 
== Evaluating HZP fixed boron critical control rod position ==
 
== Evaluating HZP fixed boron critical control rod position ==

Revision as of 10:47, 31 August 2021

Overview

In order to test and demonstrate the time dependent calculation capabilities of the Kraken framework in a reasonably realistic context, a time dependent simulation was conducted of the initial rise to power of a small modular reactor (SMR) core. The simulation used the Ants nodal neutronics code to resolve the evolution of neutronics and the xenon fission poison chain in the system and the SUBCHANFLOW thermal hydraulics code to solve the coolant flow and heat transfer in fuel rods.

The modelled SMR is the same 37 assembly Er-UO2 fuelled core that has been previously used for the demonstration of the depletion capabilities of Kraken:

Horizontal geometry plot of a Serpent model for the Er-UO2 SMR core. Vertical geometry plot of a Serpent model for the Er-UO2 SMR core.

The transient starts from critical hot zero power (HZP) conditions (actually from 1 % power level) with all control rod banks at approximately 50 % insertion. The boron concentration in the coolant corresponds to the critical boron at all rods out (ARO) hot full power (HFP) conditions. The control rods are withdrawn from the core in a stepwise manner over 38 hours to allow for the accumulation of xenon in the core:

Control rod withdraw schedule used for the SMR startup.

To reformulate the simulation setup:

  • Evaluate (in a time-independent simulation) critical boron at hot full power all rods out conditions with convergence in
    • Neutronics
    • Thermal hydraulics
    • Fuel temperature
    • Xenon
  • Using that critical boron, evaluate (in a time-independent simulation) critical control rod position at 1 % power level with convergence in
    • Neutronics
    • Thermal hydraulics
    • Fuel temperature
    • Xenon
  • Save initial conditions from the 1 % power level time-independent calculation.
  • Start a time dependent simulation from 1 % power level and slowly withdraw the control rods fully from the core.

If the time-independent and time-dependent calculation methodologies produce equivalent steady state solutions and have been correctly implemented, the simulation should (in the end) end up in the same state as the time-independent HFP ARO calculation.

Evaluating HFP ARO critical boron

Cerberus input for HPF ARO boron iteration

from os import environ
from pathlib import Path

import numpy as np

import cerberus as cb
from cerberus.solvers import CodeInput
from cerberus.solvers import Solver
from cerberus.interpolation import Interpolator
from numpy.core.fromnumeric import size

# Verbosity for terminal output of Cerberus

cb.LOG.set_verbosity(1)

# Create and start solvers

solver_defs = [["SCF", environ["SCFWRAP_EXE_PATH"], [], ["./Inputs/scf/input.txt"]],
               ["ANTS", environ["ANTS_EXE_PATH"], ["--cerberus","--port"], ["./Inputs/Ants8g.inp"]]]

solvers = {}

port_number = 2211

for name, solver_path, params, inputs in solver_defs:

    # Create input

    solver_input = CodeInput(name, inputs)

    # Create solver

    solver = Solver(name, solver_path, params)
    solver.input = solver_input
    solver.initialize(port_number)

    # Add to solver dict

    solvers[name] = solver

    port_number += 1

# Alias variables for solvers

scf = solvers["SCF"]
ants = solvers["ANTS"]

# Get SCF fields needed for coupled calculation

scf_cool_temperature = scf.get_transferrable("scf_of_cool_temperature_chan")
scf_cool_density = scf.get_transferrable("scf_of_cool_density_chan")
scf_fuel_temperature = scf.get_transferrable("scf_of_fuel_temperature_vol_ave")
scf_power = scf.get_transferrable("scf_if_fuel_power")

# Initialize SCF power field (50 MW divided uniformly over SCF cells)

scf_power.value_vec = 50e6/scf_power.n_values*np.ones(scf_power.n_values)

# Get Ants fields needed for coupled calculation

ants_cool_temperature = ants.get_transferrable("Ants_if_coolant_temperature")
ants_cool_density = ants.get_transferrable("Ants_if_coolant_density")
ants_fuel_temperature = ants.get_transferrable("Ants_if_fuel_temperature")
ants_power = ants.get_transferrable("Ants_of_supernode_power")
ants_boron = ants.get_transferrable("Ants_ov_boron")

# Create interpolators that handle data transfer between SCF and Ants

interp_ct = Interpolator.from_file(scf_cool_temperature,
                                   ants_cool_temperature,
                                   "./Inputs/scf_to_ants.txt")
interp_cd = Interpolator.from_file(scf_cool_density,
                                   ants_cool_density,
                                   "./Inputs/scf_to_ants.txt")
interp_ft = Interpolator.from_file(scf_fuel_temperature,
                                   ants_fuel_temperature,
                                   "./Inputs/scf_to_ants.txt")
interp_p = Interpolator.from_file(ants_power,
                                  scf_power,
                                  "./Inputs/ants_to_scf.txt")


################################################################################
################################################################################

# --- Coupled solution

max_iter = 50
for i in range(max_iter):
    # --- TH solution and communication

    scf_power.communicate()
    scf_power.write_simple(suffix_in=f"{i+1}")

    scf.solve()

    scf_cool_density.communicate()
    scf_cool_temperature.communicate()
    scf_fuel_temperature.communicate()

    # --- Transfers from SCF to Ants fields

    interp_ct.interpolate()
    interp_cd.interpolate()
    interp_ft.interpolate()

    # --- Neutronics solution and communication

    ants_cool_density.communicate()
    ants_cool_temperature.communicate()
    ants_fuel_temperature.communicate()

    ants.solve()

    ants_power.communicate()
    ants_boron.communicate()

    # --- Transfers from Ants to SCF

    interp_p.interpolate()

    print(f"Finished iteration {i+1}, boron is {ants_boron.value_vec[0]}")

# Choose field/value names to save

to_save = ["Ants_ov_keff", "Ants_ov_boron"]

# Output path. Create folder if necessary

output_path = Path(f"./output")
output_path.mkdir(exist_ok=True)
for name in to_save:
    tra = ants.get_transferrable(name)
    tra.communicate()
    tra.write_simple(suffix_in="final", folder_path=output_path)

Evaluating HZP fixed boron critical control rod position

Saving initial conditions for the transient

Time dependent simulation