Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions documentation/proc-pages/eng-models/plant-availability.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ It is assumed that the vacuum system can be maintained in parallel with blanket

If `iavail = 3`, the availability model for Spherical Tokamaks (ST) is implemented.

!!! Warning "Warning"
Currently, this model only uses the centrepost to calculate the availability of an ST plant. Other systems/components will be added in the future.

This model takes the user-specified time to replace a centrepost `tmain` and the centrepost lifetime `cplife` (calculated, see below) and calculates the number of maintenance cycles

$$ t_{\text{main}} + t_{\text{CP,life}} = t_{\text{maint cycle}}. $$
Expand All @@ -50,7 +47,7 @@ $$ n_{\text{CP}} = \lceil n_{\text{cycles}} \rceil. $$

The planned unavailability is then what percent of a maintenance cycle is taken up by the user-specified maintenance time

$$ U_{\text{planned}} = t_{\text{main}} / t_{\text{maint cycle}} $$
$$ U_{\text{planned,CP}} = t_{\text{main}} / t_{\text{maint cycle}} $$

and the total operational time is given by

Expand All @@ -60,7 +57,9 @@ The total availability of the plant is then given by

$$ A_{\text{tot}} = 1 - (U_{\text{planned}} + U_{\text{unplanned}} + U_{\text{planned}}U_{\text{unplanned}}) $$

where $U_{unplanned}$ is unplanned unavailability which is provided by the user i.e. how often do you expect the centrepost to break over its lifetime. The cross term takes account of overlap between planned and unplanned unavailability.
where $U_{\text{unplanned}}$ is unplanned unavailability. The cross term takes account of overlap between planned and unplanned unavailability.

This model uses the unplanned unavailability calculations implemented in `iavail = 2` (see above). This includes the magnets, divertor, first wall and blanket, balance of plant, heating and current drive, and vacuum systems. The centrepost unplanned unavailability $U_{\text{unplanned,CP}}$ is provided by the user i.e. how often do you expect the centrepost to break over its lifetime. These unplanned unavailabilities are then added to $U_{\text{unplanned,CP}}$ to give $U_{\text{unplanned}}$.

Finally, the capcity factor is given by

Expand Down
46 changes: 42 additions & 4 deletions process/availability.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,16 +1004,54 @@ def avail_st(self, output: bool):
# Operational time (years)
cv.t_operation = cv.tlife * (1.0e0 - u_planned)

if output:
po.oheadr(self.outfile, "Plant Availability")

# Un-planned unavailability

# Magnets
u_unplanned_magnets = self.calc_u_unplanned_magnets(output)

# Divertor
u_unplanned_div = self.calc_u_unplanned_divertor(output)

# First wall and blanket
u_unplanned_fwbs = self.calc_u_unplanned_fwbs(output)

# Balance of plant
u_unplanned_bop = self.calc_u_unplanned_bop(output)

# Heating and current drive
u_unplanned_hcd = self.calc_u_unplanned_hcd()

# Vacuum systems

# Number of redundant pumps
cv.redun_vac = math.floor(vacv.vpumpn * cv.redun_vacp / 100.0 + 0.5e0)

u_unplanned_vacuum = self.calc_u_unplanned_vacuum(output)

# Total unplanned unavailability
u_unplanned = min(
1.0e0,
u_unplanned_magnets
+ u_unplanned_div
+ u_unplanned_fwbs
+ u_unplanned_bop
+ u_unplanned_hcd
+ u_unplanned_vacuum
+ cv.u_unplanned_cp,
)

# Total availability
cv.cfactr = max(
1.0e0 - (u_planned + cv.u_unplanned + u_planned * cv.u_unplanned), 0.0e0
1.0e0 - (u_planned + u_unplanned + u_planned * u_unplanned), 0.0e0
)

# Capacity factor
cv.cpfact = cv.cfactr * (tv.tburn / tv.tcycle)

if output:
po.oheadr(self.outfile, "Plant Availability")
if tfv.i_tf_sup == 1:
po.ovarre(
self.outfile,
Expand Down Expand Up @@ -1085,8 +1123,8 @@ def avail_st(self, output: bool):
self.outfile,
"Total unplanned unavailability",
"(u_unplanned)",
cv.u_unplanned,
"IP ",
u_unplanned,
"OP ",
)
po.ovarre(
self.outfile,
Expand Down
3 changes: 2 additions & 1 deletion source/fortran/cost_variables.f90
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ module cost_variables
real(dp) :: tmain
!! Maintenance time for replacing CP (years) (iavail = 3)

real(dp) :: u_unplanned
real(dp) :: u_unplanned_cp
!! User-input CP unplanned unavailability (iavail = 3)

real(dp), parameter :: ucad = 180.0D0
Expand Down Expand Up @@ -752,6 +752,7 @@ subroutine init_cost_variables
ucwindpf = 465.0D0
ucwindtf = 480.0D0
ucwst = (/0.0D0, 3.94D0, 5.91D0, 7.88D0/)
u_unplanned_cp = 0.0
i_cp_lifetime = 0
cplife_input = 2.0D0

Expand Down
6 changes: 3 additions & 3 deletions source/fortran/input.f90
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ subroutine parse_input_file(in_file,out_file,show_changes)
ucblli, ucpfcb, tlife, ipnet, fcdfuel, ucbus, ucpfb, uchts, &
maintenance_fwbs, fwbs_prob_fail, uclh, ucblss, ucblvd, ucsc, ucturb, &
ucpens, cland, ucwindpf, i_cp_lifetime, cplife_input, &
startupratio, tmain, u_unplanned
startupratio, tmain, u_unplanned_cp
use current_drive_variables, only: pinjfixmw, etaech, pinjalw, etanbi, &
ftritbm, gamma_ecrh, pheat, beamwd, enbeam, pheatfix, bscfmax, &
forbitloss, nbshield, tbeamin, feffcd, iefrf, iefrffix, irfcd, cboot, &
Expand Down Expand Up @@ -2406,8 +2406,8 @@ subroutine parse_input_file(in_file,out_file,show_changes)
case ('tmain')
call parse_real_variable('tmain', tmain, 0.0D0, 100.0D0, &
'Maintenance time for replacing CP (years) (iavail = 3)')
case ('u_unplanned')
call parse_real_variable('u_unplanned', u_unplanned, 0.0D0, 1.0D0, &
case ('u_unplanned_cp')
call parse_real_variable('u_unplanned_cp', u_unplanned_cp, 0.0D0, 1.0D0, &
'User-input CP unplanned unavailability (iavail = 3)')

! Unit cost settings
Expand Down
11 changes: 8 additions & 3 deletions tests/unit/test_availability.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,18 +486,23 @@ def test_avail_st(monkeypatch, availability):
:param availability: fixture containing an initialised `Availability` object
:type availability: tests.unit.test_availability.availability (functional fixture)
"""
# Initialise fortran variables to keep test isolated from others
fortran.init_module.init_all_module_vars()

monkeypatch.setattr(cv, "tmain", 1.0)
monkeypatch.setattr(cv, "tlife", 30.0)
monkeypatch.setattr(cv, "u_unplanned", 0.1)
monkeypatch.setattr(cv, "u_unplanned_cp", 0.05)
monkeypatch.setattr(tv, "tburn", 5.0)
monkeypatch.setattr(tv, "tcycle", 10.0)

availability.avail_st(output=False)

assert pytest.approx(cv.t_operation) == 29.03225806
assert pytest.approx(cv.cfactr) == 0.86451613
assert pytest.approx(cv.cpfact) == 0.43225806
assert pytest.approx(cv.cfactr) == 0.82579737
assert pytest.approx(cv.cpfact) == 0.41289868

# Initialise fortran variables again to reset for other tests
fortran.init_module.init_all_module_vars()


@pytest.mark.parametrize("i_tf_sup, exp", ((1, 6.337618), (0, 4)))
Expand Down