From 943935ca2d61191330170e3e7592dadd18bf0664 Mon Sep 17 00:00:00 2001 From: Jack Foster Date: Thu, 23 May 2024 09:01:00 +0100 Subject: [PATCH 1/3] Added other system's availability calcs to avail_st --- process/availability.py | 44 ++++++++++++++++++++++++++++--- source/fortran/cost_variables.f90 | 3 ++- source/fortran/input.f90 | 6 ++--- tests/unit/test_availability.py | 11 +++++--- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/process/availability.py b/process/availability.py index 78e5ceefb1..bb3b0891dd 100644 --- a/process/availability.py +++ b/process/availability.py @@ -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, @@ -1085,7 +1123,7 @@ def avail_st(self, output: bool): self.outfile, "Total unplanned unavailability", "(u_unplanned)", - cv.u_unplanned, + u_unplanned, "IP ", ) po.ovarre( diff --git a/source/fortran/cost_variables.f90 b/source/fortran/cost_variables.f90 index f677f61b9b..5877b36329 100644 --- a/source/fortran/cost_variables.f90 +++ b/source/fortran/cost_variables.f90 @@ -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 @@ -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 diff --git a/source/fortran/input.f90 b/source/fortran/input.f90 index a9385813f3..d40ebaeacb 100644 --- a/source/fortran/input.f90 +++ b/source/fortran/input.f90 @@ -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, & @@ -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 diff --git a/tests/unit/test_availability.py b/tests/unit/test_availability.py index 9ed0f97c9e..117c293ee4 100644 --- a/tests/unit/test_availability.py +++ b/tests/unit/test_availability.py @@ -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))) From f31b36d86c438f39859bbc855e08f7e04f6063f1 Mon Sep 17 00:00:00 2001 From: Jack Foster Date: Wed, 5 Jun 2024 15:27:54 +0100 Subject: [PATCH 2/3] Updated availability docs --- .../proc-pages/eng-models/plant-availability.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/documentation/proc-pages/eng-models/plant-availability.md b/documentation/proc-pages/eng-models/plant-availability.md index c07da428d3..a16d6a79f0 100644 --- a/documentation/proc-pages/eng-models/plant-availability.md +++ b/documentation/proc-pages/eng-models/plant-availability.md @@ -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}}. $$ @@ -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 @@ -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_{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 From 2303b22372aa7c2765fb39e54ed20165e2fef91a Mon Sep 17 00:00:00 2001 From: Jack Foster Date: Wed, 5 Jun 2024 16:02:09 +0100 Subject: [PATCH 3/3] Minor changes --- documentation/proc-pages/eng-models/plant-availability.md | 2 +- process/availability.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/proc-pages/eng-models/plant-availability.md b/documentation/proc-pages/eng-models/plant-availability.md index a16d6a79f0..b23f6044ab 100644 --- a/documentation/proc-pages/eng-models/plant-availability.md +++ b/documentation/proc-pages/eng-models/plant-availability.md @@ -57,7 +57,7 @@ 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. 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}}$. diff --git a/process/availability.py b/process/availability.py index bb3b0891dd..8cb39e9113 100644 --- a/process/availability.py +++ b/process/availability.py @@ -1124,7 +1124,7 @@ def avail_st(self, output: bool): "Total unplanned unavailability", "(u_unplanned)", u_unplanned, - "IP ", + "OP ", ) po.ovarre( self.outfile,