From 4fe9d1f711a9982e2c501948b748bd0c8add3ae1 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 4 Dec 2025 13:36:51 +0000 Subject: [PATCH 1/4] Add incident power calculation methods for divertor --- process/divertor.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/process/divertor.py b/process/divertor.py index 29f89a6d9a..1e12f0a81d 100644 --- a/process/divertor.py +++ b/process/divertor.py @@ -6,6 +6,7 @@ from process import process_output as po from process.data_structure import build_variables as bv from process.data_structure import divertor_variables as dv +from process.data_structure import fwbs_variables as fwbs from process.data_structure import physics_variables as pv from process.data_structure import tfcoil_variables as tfv from process.exceptions import ProcessValueError @@ -34,6 +35,19 @@ def run(self, output: bool) -> None: :param output: indicate whether output should be written to the output file, or not :type output: boolean """ + + fwbs.p_div_nuclear_heat_total_mw = self.set_incident_neutron_power( + p_plasma_neutron_mw=pv.p_plasma_neutron_mw, + f_ster_div_single=fwbs.f_ster_div_single, + n_divertors=pv.n_divertors, + ) + + fwbs.p_div_rad_total_mw = self.set_incident_radiation_power( + p_plasma_rad_mw=pv.p_plasma_rad_mw, + f_ster_div_single=fwbs.f_ster_div_single, + n_divertors=pv.n_divertors, + ) + if dv.i_div_heat_load == 0 and output: po.ovarre( self.outfile, @@ -362,3 +376,31 @@ def divwade( dv.pflux_div_heat_load_mw, ) return dv.pflux_div_heat_load_mw + + def set_incident_radiation_power( + self, + p_plasma_rad_mw: float, + f_ster_div_single: float, + n_divertors: int, + ) -> float: + """Set incident radiation on divertor box""" + + return p_plasma_rad_mw * f_ster_div_single * n_divertors + + def set_incident_neutron_power( + self, + p_plasma_neutron_mw: float, + f_ster_div_single: float, + n_divertors: int, + ) -> float: + """Set incident neutron power on divertor box""" + + return p_plasma_neutron_mw * f_ster_div_single * n_divertors + + +class LowerDivertor(Divertor): + """Module containing lower divertor routines""" + + +class UpperDivertor(Divertor): + """Module containing upper divertor routines""" From 15244d1ee97ea19d02258e3ba0b79a3d7a4ba408 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Dec 2025 09:48:53 +0000 Subject: [PATCH 2/4] Remove now redundant divertor assignment in HCPB and DCLL --- process/dcll.py | 25 --------------- process/hcpb.py | 56 ---------------------------------- tests/unit/test_ccfe_hcpb.py | 59 ++---------------------------------- tests/unit/test_dcll.py | 20 ++---------- 4 files changed, 4 insertions(+), 156 deletions(-) diff --git a/process/dcll.py b/process/dcll.py index 0d14496888..e1a255dadb 100644 --- a/process/dcll.py +++ b/process/dcll.py @@ -172,31 +172,6 @@ def dcll_neutronics_and_power(self, output: bool): * covf ) - # Divertor - - if physics_variables.n_divertors == 2: - # Double null configuration - # Nuclear heating in the divertor (MW), neutron power times f_ster_div_single - fwbs_variables.p_div_nuclear_heat_total_mw = ( - physics_variables.p_neutron_total_mw - * 2 - * fwbs_variables.f_ster_div_single - ) - # Radiation power incident on divertor (MW) - fwbs_variables.p_div_rad_total_mw = ( - physics_variables.p_plasma_rad_mw * 2 * fwbs_variables.f_ster_div_single - ) - else: - # Single null configuration - # Nuclear heating in the divertor (MW), neutron power times f_ster_div_single - fwbs_variables.p_div_nuclear_heat_total_mw = ( - physics_variables.p_neutron_total_mw * fwbs_variables.f_ster_div_single - ) - # Radiation power incident on divertor (MW) - fwbs_variables.p_div_rad_total_mw = ( - physics_variables.p_plasma_rad_mw * fwbs_variables.f_ster_div_single - ) - # HCD Apperatus # No nuclear heating of the H & CD diff --git a/process/hcpb.py b/process/hcpb.py index 94d5424853..7c8d29c312 100644 --- a/process/hcpb.py +++ b/process/hcpb.py @@ -150,12 +150,6 @@ def run(self, output: bool): p_fusion_total_mw=physics_variables.p_fusion_total_mw, ) - fwbs_variables.p_div_nuclear_heat_total_mw = self.nuclear_heating_divertor( - n_divertors=physics_variables.n_divertors, - p_neutron_total_mw=physics_variables.p_neutron_total_mw, - f_ster_div_single=fwbs_variables.f_ster_div_single, - ) - # Normalisation of the nuclear heating # The nuclear heating are noramalized assuming no energy multiplication # in the divertor and the centrepost @@ -733,61 +727,11 @@ def nuclear_heating_shield( return p_shld_nuclear_heat_mw, exp_shield1, exp_shield2, shld_u_nuc_heating - def nuclear_heating_divertor( - self, - n_divertors: int, - p_neutron_total_mw: float, - f_ster_div_single: float, - ) -> float: - """ - Calculate the nuclear heating in the divertor for the CCFE HCPB model. - - This method computes the total nuclear heating deposited in the divertor, - based on the number of divertors, the total neutron power, and the solid angle - fraction taken by a single divertor. - - :param n_divertors: Number of divertors (1 for single null, 2 for double null configuration). - :type n_divertors: int - :param p_neutron_total_mw: Total neutron power generated by the plasma (MW). - :type p_neutron_total_mw: float - :param f_ster_div_single: Solid angle fraction taken by a single divertor (dimensionless). - :type f_ster_div_single: float - - :returns: Total nuclear heating in the divertor (MW). - :rtype: float - - The calculation multiplies the neutron power by the solid angle fraction for a single divertor, - and doubles the result if there are two divertors (double null configuration). - """ - - # Nuclear heating in the divertor just the neutron power times f_ster_div_single - if n_divertors == 2: - # Double null configuration - p_div_nuclear_heat_total_mw = p_neutron_total_mw * 2 * f_ster_div_single - else: - # single null configuration - p_div_nuclear_heat_total_mw = p_neutron_total_mw * f_ster_div_single - - return p_div_nuclear_heat_total_mw - def powerflow_calc(self, output: bool): """Calculations for powerflow author: J. Morris, CCFE, Culham Science Centre Calculations for powerflow """ - # Radiation power incident on divertor (MW) - if physics_variables.n_divertors == 2: - # Double null configuration - fwbs_variables.p_div_rad_total_mw = ( - physics_variables.p_plasma_rad_mw - * 2.0 - * fwbs_variables.f_ster_div_single - ) - else: - # single null configuration - fwbs_variables.p_div_rad_total_mw = ( - physics_variables.p_plasma_rad_mw * fwbs_variables.f_ster_div_single - ) # Radiation power incident on HCD apparatus (MW) fwbs_variables.p_fw_hcd_rad_total_mw = ( diff --git a/tests/unit/test_ccfe_hcpb.py b/tests/unit/test_ccfe_hcpb.py index d45e467467..50cc429bce 100644 --- a/tests/unit/test_ccfe_hcpb.py +++ b/tests/unit/test_ccfe_hcpb.py @@ -659,55 +659,6 @@ def test_nuclear_heating_shield(nuclearheatingshieldparam, ccfe_hcpb): assert exp_shield2 == pytest.approx(nuclearheatingshieldparam.expected_exp_shield2) -class NuclearHeatingDivertorParam(NamedTuple): - f_ster_div_single: Any = None - - n_divertors: Any = None - - p_neutron_total_mw: Any = None - - expected_p_div_nuclear_heat_total_mw: Any = None - - -@pytest.mark.parametrize( - "nuclearheatingdivertorparam", - ( - NuclearHeatingDivertorParam( - f_ster_div_single=0.115, - n_divertors=1, - p_neutron_total_mw=1986.0623241661431, - expected_p_div_nuclear_heat_total_mw=228.39716727910647, - ), - NuclearHeatingDivertorParam( - f_ster_div_single=0.115, - n_divertors=2, - p_neutron_total_mw=1985.4423932312809, - expected_p_div_nuclear_heat_total_mw=456.6517504431946, - ), - ), -) -def test_nuclear_heating_divertor(nuclearheatingdivertorparam, ccfe_hcpb): - """ - Automatically generated Regression Unit Test for nuclear_heating_divertor. - - This test was generated using data from tracking/baseline_2018/baseline_2018_IN.DAT. - - :param nuclearheatingdivertorparam: the data used to mock and assert in this test. - :type nuclearheatingdivertorparam: nuclearheatingdivertorparam - - """ - - p_div_nuclear_heat_total_mw = ccfe_hcpb.nuclear_heating_divertor( - n_divertors=nuclearheatingdivertorparam.n_divertors, - p_neutron_total_mw=nuclearheatingdivertorparam.p_neutron_total_mw, - f_ster_div_single=nuclearheatingdivertorparam.f_ster_div_single, - ) - - assert p_div_nuclear_heat_total_mw == pytest.approx( - nuclearheatingdivertorparam.expected_p_div_nuclear_heat_total_mw - ) - - class PowerflowCalcParam(NamedTuple): a_fw_outboard: Any = None @@ -808,7 +759,6 @@ class PowerflowCalcParam(NamedTuple): a_fw_total=1601.1595634509963, p_beam_orbit_loss_mw=0, f_ster_div_single=0.115, - p_div_rad_total_mw=0, p_fw_hcd_rad_total_mw=0, f_a_fw_outboard_hcd=0, p_fw_rad_total_mw=0, @@ -816,6 +766,7 @@ class PowerflowCalcParam(NamedTuple): temp_blkt_coolant_out=823, pres_blkt_coolant=15500000, i_p_coolant_pumping=3, + p_div_rad_total_mw=33.056596978820579, p_fw_nuclear_heat_total_mw=276.80690153753221, p_blkt_nuclear_heat_total_mw=1504.9215740808861, p_div_nuclear_heat_total_mw=182.71773382328519, @@ -842,7 +793,6 @@ class PowerflowCalcParam(NamedTuple): t_in_bb=573.13, t_out_bb=773.13, p_fw_blkt_coolant_pump_mw=0, - expected_p_div_rad_total_mw=33.056596978820579, expected_p_fw_rad_total_mw=254.39207240222791, expected_psurffwi=97.271629070225231, expected_psurffwo=176.95628839065773, @@ -855,10 +805,10 @@ class PowerflowCalcParam(NamedTuple): a_fw_total=1891.2865102700493, p_beam_orbit_loss_mw=0, f_ster_div_single=0.115, - p_div_rad_total_mw=33.056596978820579, p_fw_hcd_rad_total_mw=0, f_a_fw_outboard_hcd=0, p_fw_rad_total_mw=254.39207240222791, + p_div_rad_total_mw=33.056596978820579, i_blkt_coolant_type=1, temp_blkt_coolant_out=823, pres_blkt_coolant=15500000, @@ -889,7 +839,6 @@ class PowerflowCalcParam(NamedTuple): t_in_bb=573.13, t_out_bb=773.13, p_fw_blkt_coolant_pump_mw=202.00455086503842, - expected_p_div_rad_total_mw=33.056596978820579, expected_p_fw_rad_total_mw=254.39207240222791, expected_psurffwi=97.271629070225259, expected_psurffwo=176.95009681558912, @@ -1090,10 +1039,6 @@ def test_powerflow_calc(powerflowcalcparam, monkeypatch, ccfe_hcpb): ccfe_hcpb.powerflow_calc(False) - assert fwbs_variables.p_div_rad_total_mw == pytest.approx( - powerflowcalcparam.expected_p_div_rad_total_mw - ) - assert fwbs_variables.p_fw_rad_total_mw == pytest.approx( powerflowcalcparam.expected_p_fw_rad_total_mw ) diff --git a/tests/unit/test_dcll.py b/tests/unit/test_dcll.py index cbf2ec6c3a..a1a33e8b87 100644 --- a/tests/unit/test_dcll.py +++ b/tests/unit/test_dcll.py @@ -72,10 +72,6 @@ class DcllNeutronicsAndPowerParam(NamedTuple): p_fw_alpha_mw: Any = None - expected_p_div_rad_total_mw: Any = None - - expected_p_div_nuclear_heat_total_mw: Any = None - expected_p_fw_rad_total_mw: Any = None expected_p_fw_nuclear_heat_total_mw: Any = None @@ -93,8 +89,8 @@ class DcllNeutronicsAndPowerParam(NamedTuple): a_fw_total=1601.1595634509963, p_beam_orbit_loss_mw=0, f_ster_div_single=0.115, - p_div_rad_total_mw=0, - p_div_nuclear_heat_total_mw=0, + p_div_rad_total_mw=33.056596978820579, + p_div_nuclear_heat_total_mw=182.58994516305046, f_a_fw_outboard_hcd=0, p_fw_hcd_rad_total_mw=0, p_fw_hcd_nuclear_heat_mw=0, @@ -113,8 +109,6 @@ class DcllNeutronicsAndPowerParam(NamedTuple): p_neutron_total_mw=1587.7386535917431, p_plasma_rad_mw=287.44866938104849, p_fw_alpha_mw=19.835845058655043, - expected_p_div_rad_total_mw=33.056596978820579, - expected_p_div_nuclear_heat_total_mw=182.58994516305046, expected_p_fw_rad_total_mw=254.39207240222791, expected_p_fw_nuclear_heat_total_mw=196.72081918001697, expected_p_blkt_nuclear_heat_total_mw=1533.4949914565693, @@ -145,8 +139,6 @@ class DcllNeutronicsAndPowerParam(NamedTuple): p_neutron_total_mw=1587.2430556964196, p_plasma_rad_mw=287.44866938104849, p_fw_alpha_mw=19.829653483586444, - expected_p_div_rad_total_mw=33.056596978820579, - expected_p_div_nuclear_heat_total_mw=182.53295140508826, expected_p_fw_rad_total_mw=254.39207240222791, expected_p_fw_nuclear_heat_total_mw=196.65941460078642, expected_p_blkt_nuclear_heat_total_mw=1533.0163252173013, @@ -301,14 +293,6 @@ def test_dcll_neutronics_and_power(dcllneutronicsandpowerparam, monkeypatch, dcl dcll.dcll_neutronics_and_power(False) - assert fwbs_variables.p_div_rad_total_mw == pytest.approx( - dcllneutronicsandpowerparam.expected_p_div_rad_total_mw - ) - - assert fwbs_variables.p_div_nuclear_heat_total_mw == pytest.approx( - dcllneutronicsandpowerparam.expected_p_div_nuclear_heat_total_mw - ) - assert fwbs_variables.p_fw_rad_total_mw == pytest.approx( dcllneutronicsandpowerparam.expected_p_fw_rad_total_mw ) From d010aedaf7a35b9fa4ca1af4f01dcd49c20cfd11 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Dec 2025 10:08:50 +0000 Subject: [PATCH 3/4] Add tests for incident radiation and neutron power in Divertor class --- tests/unit/test_divertor.py | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/unit/test_divertor.py b/tests/unit/test_divertor.py index 9b351e992f..6fed8e5e91 100644 --- a/tests/unit/test_divertor.py +++ b/tests/unit/test_divertor.py @@ -102,3 +102,43 @@ def test_divwade(self, monkeypatch, divertor): ) assert pflux_div_heat_load_mw == pytest.approx(expected_pflux_div_heat_load_mw) + + +@pytest.mark.parametrize( + "p_plasma_rad_mw, f_ster_div_single, n_divertors, expected", + [ + (10.0, 0.5, 2, 10.0), + (0.0, 1.0, 1, 0.0), + (5.5, 0.2, 3, 3.3), + (100.0, 0.0, 5, 0.0), + (7.0, 0.25, 4, 7.0), + ], +) +def test_set_incident_radiation_power( + p_plasma_rad_mw, f_ster_div_single, n_divertors, expected +): + divertor = Divertor() + result = divertor.set_incident_radiation_power( + p_plasma_rad_mw, f_ster_div_single, n_divertors + ) + assert result == pytest.approx(expected) + + +@pytest.mark.parametrize( + "p_plasma_neutron_mw, f_ster_div_single, n_divertors, expected", + [ + (20.0, 0.5, 2, 20.0), + (0.0, 1.0, 1, 0.0), + (8.0, 0.25, 4, 8.0), + (50.0, 0.0, 3, 0.0), + (12.5, 0.4, 2, 10.0), + ], +) +def test_set_incident_neutron_power( + p_plasma_neutron_mw, f_ster_div_single, n_divertors, expected +): + divertor = Divertor() + result = divertor.set_incident_neutron_power( + p_plasma_neutron_mw, f_ster_div_single, n_divertors + ) + assert result == pytest.approx(expected) From 426bc228cd76eabce9af73e82c9f961b814f1531 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 17 Dec 2025 14:37:28 +0000 Subject: [PATCH 4/4] Requested changes --- process/divertor.py | 34 ++++++++++++++++++++++++++++------ tests/unit/test_divertor.py | 10 ++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/process/divertor.py b/process/divertor.py index 1e12f0a81d..738afae3ff 100644 --- a/process/divertor.py +++ b/process/divertor.py @@ -36,13 +36,13 @@ def run(self, output: bool) -> None: :type output: boolean """ - fwbs.p_div_nuclear_heat_total_mw = self.set_incident_neutron_power( + fwbs.p_div_nuclear_heat_total_mw = self.incident_neutron_power( p_plasma_neutron_mw=pv.p_plasma_neutron_mw, f_ster_div_single=fwbs.f_ster_div_single, n_divertors=pv.n_divertors, ) - fwbs.p_div_rad_total_mw = self.set_incident_radiation_power( + fwbs.p_div_rad_total_mw = self.incident_radiation_power( p_plasma_rad_mw=pv.p_plasma_rad_mw, f_ster_div_single=fwbs.f_ster_div_single, n_divertors=pv.n_divertors, @@ -377,23 +377,45 @@ def divwade( ) return dv.pflux_div_heat_load_mw - def set_incident_radiation_power( + def incident_radiation_power( self, p_plasma_rad_mw: float, f_ster_div_single: float, n_divertors: int, ) -> float: - """Set incident radiation on divertor box""" + """ + Calculates the total incident radiation power on the divertor box. + + :param p_plasma_rad_mw: Total plasma radiated power in megawatts (MW). + :type p_plasma_rad_mw: float + :param f_ster_div_single: Fraction of the solid angle subtended by a single divertor. + :type f_ster_div_single: float + :param n_divertors: Number of divertors. + :type n_divertors: int + :returns: Total incident radiation power on the divertor box in megawatts (MW). + :rtype: float + """ return p_plasma_rad_mw * f_ster_div_single * n_divertors - def set_incident_neutron_power( + def incident_neutron_power( self, p_plasma_neutron_mw: float, f_ster_div_single: float, n_divertors: int, ) -> float: - """Set incident neutron power on divertor box""" + """ + Calculates the total incident neutron power on the divertor box. + + :param p_plasma_neutron_mw: Total plasma neutron power in megawatts (MW). + :type p_plasma_neutron_mw: float + :param f_ster_div_single: Fraction of the solid angle subtended by a single divertor. + :type f_ster_div_single: float + :param n_divertors: Number of divertors. + :type n_divertors: int + :returns: Total incident radiation power on the divertor box in megawatts (MW). + :rtype: float + """ return p_plasma_neutron_mw * f_ster_div_single * n_divertors diff --git a/tests/unit/test_divertor.py b/tests/unit/test_divertor.py index 6fed8e5e91..1e8c905d0e 100644 --- a/tests/unit/test_divertor.py +++ b/tests/unit/test_divertor.py @@ -115,10 +115,9 @@ def test_divwade(self, monkeypatch, divertor): ], ) def test_set_incident_radiation_power( - p_plasma_rad_mw, f_ster_div_single, n_divertors, expected + divertor, p_plasma_rad_mw, f_ster_div_single, n_divertors, expected ): - divertor = Divertor() - result = divertor.set_incident_radiation_power( + result = divertor.incident_radiation_power( p_plasma_rad_mw, f_ster_div_single, n_divertors ) assert result == pytest.approx(expected) @@ -135,10 +134,9 @@ def test_set_incident_radiation_power( ], ) def test_set_incident_neutron_power( - p_plasma_neutron_mw, f_ster_div_single, n_divertors, expected + divertor, p_plasma_neutron_mw, f_ster_div_single, n_divertors, expected ): - divertor = Divertor() - result = divertor.set_incident_neutron_power( + result = divertor.incident_neutron_power( p_plasma_neutron_mw, f_ster_div_single, n_divertors ) assert result == pytest.approx(expected)