From c81112d700cccb3fd67a6006baf2312cc9d92d12 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 13:59:27 +0000 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=94=84=20Rename=20`component=5Fhalf?= =?UTF-8?q?=5Fheight`=20method=20to=20`calculate=5Fblkt=5Fhalf=5Fheight`?= =?UTF-8?q?=20for=20clarity=20and=20update=20references=20in=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- process/blanket_library.py | 4 ++-- tests/unit/test_blanket_library.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index aa447c98f..76991f7f9 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -54,7 +54,7 @@ def component_volumes(self): # Calculate half-height # Blanket - blanket_library.dz_blkt_half = self.component_half_height(icomponent=0) + blanket_library.dz_blkt_half = self.calculate_blkt_half_height(icomponent=0) # D-shaped blanket and shield if physics_variables.itart == 1 or fwbs_variables.i_fw_blkt_vv_shape == 1: @@ -67,7 +67,7 @@ def component_volumes(self): # Apply coverage factors to volumes and surface areas self.apply_coverage_factors() - def component_half_height(self, icomponent: int): + def calculate_blkt_half_height(self, icomponent: int): """Calculate the blanket, shield or vacuum vessel half-height Based on blanket_half_height, shield_half_height, vv_half_height original author: J. Morris, CCFE, Culham Science Centre diff --git a/tests/unit/test_blanket_library.py b/tests/unit/test_blanket_library.py index 24eb8a252..cb5a6c07b 100644 --- a/tests/unit/test_blanket_library.py +++ b/tests/unit/test_blanket_library.py @@ -422,7 +422,7 @@ class ComponentHalfHeightParam(NamedTuple): ), ), ) -def test_component_half_height( +def test_calculate_blkt_half_height( componenthalfheightparam, monkeypatch, blanket_library_fixture ): """ @@ -494,7 +494,7 @@ def test_component_half_height( divertor_variables, "dz_divertor", componenthalfheightparam.dz_divertor ) - half_height = blanket_library_fixture.component_half_height( + half_height = blanket_library_fixture.calculate_blkt_half_height( componenthalfheightparam.icomponent ) From 6aabb99792adc4c39a40ec31221a62981f4e091b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 14:16:22 +0000 Subject: [PATCH 02/10] Refactor `calculate_blkt_half_height` method to accept parameters directly instead of using an `icomponent` switch; update corresponding tests for consistency. --- process/blanket_library.py | 85 ++++++++++++++++++++++-------- tests/unit/test_blanket_library.py | 85 +++++------------------------- 2 files changed, 76 insertions(+), 94 deletions(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index 76991f7f9..a11cbefbd 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -49,12 +49,21 @@ def component_volumes(self): author: J. Morris, CCFE, Culham Science Centre Calculate the blanket, shield, vacuum vessel and cryostat volumes """ - # N.B. icomponent is a switch used to specify selected component: blanket=0, sheild=1, vacuum vessel=2 - # Replaced seperate subroutines for blnkt, shld and vv with fuction/subroutine with icomponent switch. # Calculate half-height # Blanket - blanket_library.dz_blkt_half = self.calculate_blkt_half_height(icomponent=0) + blanket_library.dz_blkt_half = self.calculate_blkt_half_height( + z_plasma_xpoint_lower=build_variables.z_plasma_xpoint_lower, + dz_xpoint_divertor=build_variables.dz_xpoint_divertor, + dz_divertor=divertor_variables.dz_divertor, + z_plasma_xpoint_upper=build_variables.z_plasma_xpoint_upper, + dr_fw_plasma_gap_inboard=build_variables.dr_fw_plasma_gap_inboard, + dr_fw_plasma_gap_outboard=build_variables.dr_fw_plasma_gap_outboard, + dr_fw_inboard=build_variables.dr_fw_inboard, + dr_fw_outboard=build_variables.dr_fw_outboard, + dz_blkt_upper=build_variables.dz_blkt_upper, + n_divertors=divertor_variables.n_divertors, + ) # D-shaped blanket and shield if physics_variables.itart == 1 or fwbs_variables.i_fw_blkt_vv_shape == 1: @@ -67,37 +76,67 @@ def component_volumes(self): # Apply coverage factors to volumes and surface areas self.apply_coverage_factors() - def calculate_blkt_half_height(self, icomponent: int): - """Calculate the blanket, shield or vacuum vessel half-height - Based on blanket_half_height, shield_half_height, vv_half_height - original author: J. Morris, CCFE, Culham Science Centre - author: G. Graham, CCFE, Culham Science Centre + @staticmethod + def calculate_blkt_half_height( + z_plasma_xpoint_lower: float, + dz_xpoint_divertor: float, + dz_divertor: float, + z_plasma_xpoint_upper: float, + dr_fw_plasma_gap_inboard: float, + dr_fw_plasma_gap_outboard: float, + dr_fw_inboard: float, + dr_fw_outboard: float, + dz_blkt_upper: float, + n_divertors: int, + ) -> float: + """ + Calculate the blanket half-height based on plasma and component geometry. + + :param z_plasma_xpoint_lower: Lower vertical position of the plasma x-point (m) + :type z_plasma_xpoint_lower: float + :param dz_xpoint_divertor: Vertical distance from x-point to divertor (m) + :type dz_xpoint_divertor: float + :param dz_divertor: Vertical thickness of the divertor (m) + :type dz_divertor: float + :param z_plasma_xpoint_upper: Upper vertical position of the plasma x-point (m) + :type z_plasma_xpoint_upper: float + :param dr_fw_plasma_gap_inboard: Radial gap between first wall and plasma on inboard side (m) + :type dr_fw_plasma_gap_inboard: float + :param dr_fw_plasma_gap_outboard: Radial gap between first wall and plasma on outboard side (m) + :type dr_fw_plasma_gap_outboard: float + :param dr_fw_inboard: Radial thickness of the first wall on inboard side (m) + :type dr_fw_inboard: float + :param dr_fw_outboard: Radial thickness of the first wall on outboard side (m) + :type dr_fw_outboard: float + :param dz_blkt_upper: Vertical thickness of the upper blanket (m) + :type dz_blkt_upper: float + :param n_divertors: Number of divertors (1 for single null, 2 for double null) + :type n_divertors: int + + :return: Calculated blanket half-height (m) + :rtype: float """ # Calculate component internal lower half-height (m) # Blanket - if icomponent == 0: - hbot = ( - build_variables.z_plasma_xpoint_lower - + build_variables.dz_xpoint_divertor - + divertor_variables.dz_divertor - - build_variables.dz_blkt_upper - ) + z_bottom = ( + z_plasma_xpoint_lower + dz_xpoint_divertor + dz_divertor - dz_blkt_upper + ) # Calculate component internal upper half-height (m) # If a double null machine then symmetric - if divertor_variables.n_divertors == 2: - htop = hbot + if n_divertors == 2: + z_top = z_bottom else: # Blanket - htop = build_variables.z_plasma_xpoint_upper + 0.5 * ( - build_variables.dr_fw_plasma_gap_inboard - + build_variables.dr_fw_plasma_gap_outboard - + build_variables.dr_fw_inboard - + build_variables.dr_fw_outboard + z_top = z_plasma_xpoint_upper + 0.5 * ( + dr_fw_plasma_gap_inboard + + dr_fw_plasma_gap_outboard + + dr_fw_inboard + + dr_fw_outboard ) # Average of top and bottom (m) - return 0.5 * (htop + hbot) + return 0.5 * (z_top + z_bottom) def dshaped_component(self): """Calculate component surface area and volume using dshaped scheme diff --git a/tests/unit/test_blanket_library.py b/tests/unit/test_blanket_library.py index cb5a6c07b..cab860a56 100644 --- a/tests/unit/test_blanket_library.py +++ b/tests/unit/test_blanket_library.py @@ -392,7 +392,6 @@ class ComponentHalfHeightParam(NamedTuple): z_plasma_xpoint_upper: Any = None n_divertors: Any = None dz_divertor: Any = None - icomponent: Any = None expected_icomponent: Any = None expected_half_height: Any = None @@ -416,86 +415,30 @@ class ComponentHalfHeightParam(NamedTuple): z_plasma_xpoint_upper=4.93333333333333333, n_divertors=1, dz_divertor=0.62000000000000011, - icomponent=0, - expected_icomponent=0, expected_half_height=5.9532752487304119, ), ), ) -def test_calculate_blkt_half_height( - componenthalfheightparam, monkeypatch, blanket_library_fixture -): +def test_calculate_blkt_half_height(componenthalfheightparam, blanket_library_fixture): """ - Automatically generated Regression Unit Test for component_half_height. + Regression Unit Test for component_half_height. - This test was generated using data from tests/regression/input_files/large_tokamak.IN.DAT. + This test was generated using data from large_tokamak.IN.DAT. - :param componenthalfheightparam: the data used to mock and assert in this test. + :param componenthalfheightparam: the data used in this test. :type componenthalfheightparam: componenthalfheightparam - - :param monkeypatch: pytest fixture used to mock module/class variables - :type monkeypatch: _pytest.monkeypatch.monkeypatch """ - monkeypatch.setattr( - build_variables, "z_tf_inside_half", componenthalfheightparam.z_tf_inside_half - ) - monkeypatch.setattr( - build_variables, - "dz_xpoint_divertor", - componenthalfheightparam.dz_xpoint_divertor, - ) - monkeypatch.setattr( - build_variables, - "dz_shld_vv_gap", - componenthalfheightparam.dz_shld_vv_gap, - ) - monkeypatch.setattr( - build_variables, "dz_blkt_upper", componenthalfheightparam.dz_blkt_upper - ) - monkeypatch.setattr( - build_variables, "dz_shld_upper", componenthalfheightparam.dz_shld_upper - ) - monkeypatch.setattr( - build_variables, - "dr_fw_plasma_gap_inboard", - componenthalfheightparam.dr_fw_plasma_gap_inboard, - ) - monkeypatch.setattr( - build_variables, - "dr_fw_plasma_gap_outboard", - componenthalfheightparam.dr_fw_plasma_gap_outboard, - ) - monkeypatch.setattr( - build_variables, "dr_fw_inboard", componenthalfheightparam.dr_fw_inboard - ) - monkeypatch.setattr( - build_variables, "dr_fw_outboard", componenthalfheightparam.dr_fw_outboard - ) - monkeypatch.setattr( - build_variables, "dz_vv_lower", componenthalfheightparam.dz_vv_lower - ) - monkeypatch.setattr( - build_variables, "dz_vv_upper", componenthalfheightparam.dz_vv_upper - ) - monkeypatch.setattr( - build_variables, - "z_plasma_xpoint_lower", - componenthalfheightparam.z_plasma_xpoint_lower, - ) - monkeypatch.setattr( - build_variables, - "z_plasma_xpoint_upper", - componenthalfheightparam.z_plasma_xpoint_upper, - ) - monkeypatch.setattr( - divertor_variables, "n_divertors", componenthalfheightparam.n_divertors - ) - monkeypatch.setattr( - divertor_variables, "dz_divertor", componenthalfheightparam.dz_divertor - ) - half_height = blanket_library_fixture.calculate_blkt_half_height( - componenthalfheightparam.icomponent + z_plasma_xpoint_lower=componenthalfheightparam.z_plasma_xpoint_lower, + dz_xpoint_divertor=componenthalfheightparam.dz_xpoint_divertor, + dz_divertor=componenthalfheightparam.dz_divertor, + z_plasma_xpoint_upper=componenthalfheightparam.z_plasma_xpoint_upper, + dr_fw_plasma_gap_inboard=componenthalfheightparam.dr_fw_plasma_gap_inboard, + dr_fw_plasma_gap_outboard=componenthalfheightparam.dr_fw_plasma_gap_outboard, + dr_fw_inboard=componenthalfheightparam.dr_fw_inboard, + dr_fw_outboard=componenthalfheightparam.dr_fw_outboard, + dz_blkt_upper=componenthalfheightparam.dz_blkt_upper, + n_divertors=componenthalfheightparam.n_divertors, ) assert half_height == pytest.approx(componenthalfheightparam.expected_half_height) From c313d91d66437dca5634eeab23f31d6006c83ee2 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 14:52:31 +0000 Subject: [PATCH 03/10] Add methods to calculate D-shaped blanket areas and volumes --- process/blanket_library.py | 169 ++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index a11cbefbd..874eb651a 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -67,7 +67,39 @@ def component_volumes(self): # D-shaped blanket and shield if physics_variables.itart == 1 or fwbs_variables.i_fw_blkt_vv_shape == 1: - self.dshaped_component() + ( + build_variables.a_blkt_inboard_surface, + build_variables.a_blkt_outboard_surface, + build_variables.a_blkt_total_surface, + ) = self.calculate_dshaped_blkt_areas( + r_shld_inboard_inner=build_variables.r_shld_inboard_inner, + dr_shld_inboard=build_variables.dr_shld_inboard, + dr_blkt_inboard=build_variables.dr_blkt_inboard, + dr_fw_inboard=build_variables.dr_fw_inboard, + dr_fw_plasma_gap_inboard=build_variables.dr_fw_plasma_gap_inboard, + rminor=physics_variables.rminor, + dr_fw_plasma_gap_outboard=build_variables.dr_fw_plasma_gap_outboard, + dr_fw_outboard=build_variables.dr_fw_outboard, + dz_blkt_half=blanket_library.dz_blkt_half, + ) + + ( + fwbs_variables.vol_blkt_inboard, + fwbs_variables.vol_blkt_outboard, + fwbs_variables.vol_blkt_total, + ) = self.calculate_dshaped_blkt_volumes( + r_shld_inboard_inner=build_variables.r_shld_inboard_inner, + dr_shld_inboard=build_variables.dr_shld_inboard, + dr_blkt_inboard=build_variables.dr_blkt_inboard, + dr_fw_inboard=build_variables.dr_fw_inboard, + dr_fw_plasma_gap_inboard=build_variables.dr_fw_plasma_gap_inboard, + rminor=physics_variables.rminor, + dr_fw_plasma_gap_outboard=build_variables.dr_fw_plasma_gap_outboard, + dr_fw_outboard=build_variables.dr_fw_outboard, + dz_blkt_half=blanket_library.dz_blkt_half, + dr_blkt_outboard=build_variables.dr_blkt_outboard, + dz_blkt_upper=build_variables.dz_blkt_upper, + ) # Elliptical blanket and shield else: @@ -182,6 +214,141 @@ def dshaped_component(self): build_variables.dz_blkt_upper, ) + @staticmethod + def calculate_dshaped_blkt_areas( + r_shld_inboard_inner: float, + dr_shld_inboard: float, + dr_blkt_inboard: float, + dr_fw_inboard: float, + dr_fw_plasma_gap_inboard: float, + rminor: float, + dr_fw_plasma_gap_outboard: float, + dr_fw_outboard: float, + dz_blkt_half: float, + ) -> tuple[float, float, float]: + """ + Calculate D-shaped blanket surface areas. + + :param r_shld_inboard_inner: Inner radius of inboard shield (m) + :type r_shld_inboard_inner: float + :param dr_shld_inboard: Thickness of inboard shield (m) + :type dr_shld_inboard: float + :param dr_blkt_inboard: Thickness of inboard blanket (m) + :type dr_blkt_inboard: float + :param dr_fw_inboard: Thickness of inboard first wall (m) + :type dr_fw_inboard: float + :param dr_fw_plasma_gap_inboard: Radial gap between inboard first wall and plasma (m) + :type dr_fw_plasma_gap_inboard: float + :param rminor: Minor radius of the plasma (m) + :type rminor: float + :param dr_fw_plasma_gap_outboard: Radial gap between outboard first wall and plasma (m) + :type dr_fw_plasma_gap_outboard: float + :param dr_fw_outboard: Thickness of outboard first wall (m) + :type dr_fw_outboard: float + :param dz_blkt_half: Half-height of the blanket (m) + :type dz_blkt_half: float + + :return: Tuple containing inboard blanket surface area (m²), outboard blanket surface area (m²), and total blanket surface area (m²) + """ + # Calculate major radius to outer edge of inboard ... + # ... section (m) + r1 = r_shld_inboard_inner + + # ... blanket (m) + + r1 = r1 + dr_shld_inboard + dr_blkt_inboard + # Horizontal distance between inside edges (m) + # i.e. outer radius of inboard part to inner radius of outboard part + + r2 = ( + dr_fw_inboard + + dr_fw_plasma_gap_inboard + + 2.0 * rminor + + dr_fw_plasma_gap_outboard + + dr_fw_outboard + ) + + ( + a_blkt_inboard_surface, + a_blkt_outboard_surface, + a_blkt_total_surface, + ) = dshellarea(rmajor=r1, rminor=r2, zminor=dz_blkt_half) + + return a_blkt_inboard_surface, a_blkt_outboard_surface, a_blkt_total_surface + + @staticmethod + def calculate_dshaped_blkt_volumes( + r_shld_inboard_inner: float, + dr_shld_inboard: float, + dr_blkt_inboard: float, + dr_fw_inboard: float, + dr_fw_plasma_gap_inboard: float, + rminor: float, + dr_fw_plasma_gap_outboard: float, + dr_fw_outboard: float, + dz_blkt_half: float, + dr_blkt_outboard: float, + dz_blkt_upper: float, + ) -> tuple[float, float, float]: + """ + Calculate D-shaped blanket volumes. + + :param r_shld_inboard_inner: Inner radius of inboard shield (m) + :type r_shld_inboard_inner: float + :param dr_shld_inboard: Thickness of inboard shield (m) + :type dr_shld_inboard: float + :param dr_blkt_inboard: Thickness of inboard blanket (m) + :type dr_blkt_inboard: float + :param dr_fw_inboard: Thickness of inboard first wall (m) + :type dr_fw_inboard: float + :param dr_fw_plasma_gap_inboard: Radial gap between inboard first wall and plasma (m) + :type dr_fw_plasma_gap_inboard: float + :param rminor: Minor radius of the plasma (m) + :type rminor: float + :param dr_fw_plasma_gap_outboard: Radial gap between outboard first wall and plasma (m) + :type dr_fw_plasma_gap_outboard: float + :param dr_fw_outboard: Thickness of outboard first wall (m) + :type dr_fw_outboard: float + :param dz_blkt_half: Half-height of the blanket (m) + :type dz_blkt_half: float + :param dr_blkt_outboard: Thickness of outboard blanket (m) + :type dr_blkt_outboard: float + :param dz_blkt_upper: Upper vertical thickness of the blanket (m) + :type dz_blkt_upper: float + + :return: Tuple containing inboard blanket volume (m³), outboard blanket volume (m³), and total blanket volume (m³) + """ + # Calculate major radius to outer edge of inboard ... + # ... section (m) + r1 = r_shld_inboard_inner + + r1 = r1 + dr_shld_inboard + dr_blkt_inboard + # Horizontal distance between inside edges (m) + # i.e. outer radius of inboard part to inner radius of outboard part + + r2 = ( + dr_fw_inboard + + dr_fw_plasma_gap_inboard + + 2.0 * rminor + + dr_fw_plasma_gap_outboard + + dr_fw_outboard + ) + + ( + vol_blkt_inboard, + vol_blkt_outboard, + vol_blkt_total, + ) = dshellvol( + rmajor=r1, + rminor=r2, + zminor=dz_blkt_half, + drin=dr_blkt_inboard, + drout=dr_blkt_outboard, + dz=dz_blkt_upper, + ) + + return vol_blkt_inboard, vol_blkt_outboard, vol_blkt_total + def elliptical_component(self): """Calculate component surface area and volume using elliptical scheme Based on elliptical_blanket, elliptical_shield, elliptical_vv From d14a1d4179160807324ee175e4b1367e7429abba Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 15:13:47 +0000 Subject: [PATCH 04/10] Add methods to calculate elliptical blanket areas and volumes --- process/blanket_library.py | 176 ++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index 874eb651a..ffe43cc7b 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -103,7 +103,40 @@ def component_volumes(self): # Elliptical blanket and shield else: - self.elliptical_component() + ( + build_variables.a_blkt_inboard_surface, + build_variables.a_blkt_outboard_surface, + build_variables.a_blkt_total_surface, + ) = self.calculate_elliptical_blkt_areas( + rmajor=physics_variables.rmajor, + rminor=physics_variables.rminor, + triang=physics_variables.triang, + r_shld_inboard_inner=build_variables.r_shld_inboard_inner, + dr_shld_inboard=build_variables.dr_shld_inboard, + dr_blkt_inboard=build_variables.dr_blkt_inboard, + r_shld_outboard_outer=build_variables.r_shld_outboard_outer, + dr_shld_outboard=build_variables.dr_shld_outboard, + dr_blkt_outboard=build_variables.dr_blkt_outboard, + dz_blkt_half=blanket_library.dz_blkt_half, + ) + + ( + fwbs_variables.vol_blkt_inboard, + fwbs_variables.vol_blkt_outboard, + fwbs_variables.vol_blkt_total, + ) = self.calculate_elliptical_blkt_volumes( + rmajor=physics_variables.rmajor, + rminor=physics_variables.rminor, + triang=physics_variables.triang, + r_shld_inboard_inner=build_variables.r_shld_inboard_inner, + dr_shld_inboard=build_variables.dr_shld_inboard, + dr_blkt_inboard=build_variables.dr_blkt_inboard, + r_shld_outboard_outer=build_variables.r_shld_outboard_outer, + dr_shld_outboard=build_variables.dr_shld_outboard, + dr_blkt_outboard=build_variables.dr_blkt_outboard, + dz_blkt_half=blanket_library.dz_blkt_half, + dz_blkt_upper=build_variables.dz_blkt_upper, + ) # Apply coverage factors to volumes and surface areas self.apply_coverage_factors() @@ -349,6 +382,147 @@ def calculate_dshaped_blkt_volumes( return vol_blkt_inboard, vol_blkt_outboard, vol_blkt_total + @staticmethod + def calculate_elliptical_blkt_areas( + rmajor: float, + rminor: float, + triang: float, + r_shld_inboard_inner: float, + dr_shld_inboard: float, + dr_blkt_inboard: float, + r_shld_outboard_outer: float, + dr_shld_outboard: float, + dr_blkt_outboard: float, + dz_blkt_half: float, + ) -> tuple[float, float, float]: + """Calculate elliptical blanket surface areas. + + :param rmajor: Major radius of the plasma (m) + :type rmajor: float + :param rminor: Minor radius of the plasma (m) + :type rminor: float + :param triang: Triangularity of the plasma + :type triang: float + :param r_shld_inboard_inner: Inner radius of inboard shield (m) + :type r_shld_inboard_inner: float + :param dr_shld_inboard: Thickness of inboard shield (m) + :type dr_shld_inboard: float + :param dr_blkt_inboard: Thickness of inboard blanket (m) + :type dr_blkt_inboard: float + :param r_shld_outboard_outer: Outer radius of outboard shield (m) + :type r_shld_outboard_outer: float + :param dr_shld_outboard: Thickness of outboard shield (m) + :type dr_shld_outboard: float + :param dr_blkt_outboard: Thickness of outboard blanket (m) + :type dr_blkt_outboard: float + :param dz_blkt_half: Half-height of the blanket (m) + :type dz_blkt_half: float + + :return: Tuple containing inboard blanket surface area (m²), outboard blanket surface area (m²), and total blanket surface area (m²) + + """ + # Major radius to centre of inboard and outboard ellipses (m) + # (coincident in radius with top of plasma) + r1 = rmajor - rminor * triang + + # Calculate distance between r1 and outer edge of inboard ... + # ... section (m) + r2 = r1 - r_shld_inboard_inner + + r2 = r2 - dr_shld_inboard - dr_blkt_inboard + + # Calculate distance between r1 and inner edge of outboard ... + # ... section (m) + r3 = r_shld_outboard_outer - r1 + + r3 = r3 - dr_shld_outboard - dr_blkt_outboard + + # Calculate surface area, assuming 100% coverage + + ( + a_blkt_inboard_surface, + a_blkt_outboard_surface, + a_blkt_total_surface, + ) = eshellarea(r1, r2, r3, dz_blkt_half) + + return a_blkt_inboard_surface, a_blkt_outboard_surface, a_blkt_total_surface + + @staticmethod + def calculate_elliptical_blkt_volumes( + rmajor: float, + rminor: float, + triang: float, + r_shld_inboard_inner: float, + dr_shld_inboard: float, + dr_blkt_inboard: float, + r_shld_outboard_outer: float, + dr_shld_outboard: float, + dr_blkt_outboard: float, + dz_blkt_half: float, + dz_blkt_upper: float, + ) -> tuple[float, float, float]: + """Calculate elliptical blanket volumes. + + :param rmajor: Major radius of the plasma (m) + :type rmajor: float + :param rminor: Minor radius of the plasma (m) + :type rminor: float + :param triang: Triangularity of the plasma + :type triang: float + :param r_shld_inboard_inner: Inner radius of inboard shield (m) + :type r_shld_inboard_inner: float + :param dr_shld_inboard: Thickness of inboard shield (m) + :type dr_shld_inboard: float + :param dr_blkt_inboard: Thickness of inboard blanket (m) + :type dr_blkt_inboard: float + :param r_shld_outboard_outer: Outer radius of outboard shield (m) + :type r_shld_outboard_outer: float + :param dr_shld_outboard: Thickness of outboard shield (m) + :type dr_shld_outboard: float + :param dr_blkt_outboard: Thickness of outboard blanket (m) + :type dr_blkt_outboard: float + :param dz_blkt_half: Half-height of the blanket (m) + :type dz_blkt_half: float + :param dz_blkt_upper: Upper vertical thickness of the blanket (m) + :type dz_blkt_upper: float + + :return: Tuple containing inboard blanket volume (m³), outboard blanket volume (m³), and total blanket volume (m³) + + """ + # Major radius to centre of inboard and outboard ellipses (m) + # (coincident in radius with top of plasma) + r1 = rmajor - rminor * triang + + # Calculate distance between r1 and outer edge of inboard ... + # ... section (m) + r2 = r1 - r_shld_inboard_inner + + r2 = r2 - dr_shld_inboard - dr_blkt_inboard + + # Calculate distance between r1 and inner edge of outboard ... + # ... section (m) + r3 = r_shld_outboard_outer - r1 + + r3 = r3 - dr_shld_outboard - dr_blkt_outboard + + # Calculate surface area, assuming 100% coverage + + ( + vol_blkt_inboard, + vol_blkt_outboard, + vol_blkt_total, + ) = eshellvol( + rshell=r1, + rmini=r2, + rmino=r3, + zminor=dz_blkt_half, + drin=dr_blkt_inboard, + drout=dr_blkt_outboard, + dz=dz_blkt_upper, + ) + + return vol_blkt_inboard, vol_blkt_outboard, vol_blkt_total + def elliptical_component(self): """Calculate component surface area and volume using elliptical scheme Based on elliptical_blanket, elliptical_shield, elliptical_vv From aeab797b173f4998ac94e4e925494a4e8a82b474 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 16:11:31 +0000 Subject: [PATCH 05/10] Add `plot_blkt_structure` function to visualize blanket and first wall cross-section --- process/io/plot_proc.py | 115 ++++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 40 deletions(-) diff --git a/process/io/plot_proc.py b/process/io/plot_proc.py index 95a6f80ad..6f8828ac7 100644 --- a/process/io/plot_proc.py +++ b/process/io/plot_proc.py @@ -12743,6 +12743,80 @@ def plot_inequality_constraint_equations(axis: plt.Axes, m_file: mf.MFile, scan: axis.set_xticklabels([]) +def plot_blkt_structure( + ax: plt.Axes, + m_file: mf.MFile, + scan: int, + radial_build: dict[str, float], + colour_scheme: Literal[1, 2], +): + """Plot the BLKT structure on the given axis.""" + + rmajor = m_file.get("rmajor", scan=scan) + + plot_blanket(ax, m_file, scan, radial_build, colour_scheme) + plot_firstwall(ax, m_file, scan, radial_build, colour_scheme) + ax.set_xlabel("Radial position [m]") + ax.set_ylabel("Vertical position [m]") + ax.set_title("Blanket and First Wall Poloidal Cross-Section") + ax.minorticks_on() + ax.grid(which="minor", linestyle=":", linewidth=0.5, alpha=0.5) + # Plot major radius line (vertical dashed line at rmajor) + ax.axvline( + m_file.get("rminor", scan=scan), + color="black", + linestyle="--", + linewidth=1.5, + label="Major Radius $R_0$", + ) + # Plot a horizontal line at dz_blkt_half (blanket half height) + dz_blkt_half = m_file.get("dz_blkt_half", scan=scan) + ax.axhline( + dz_blkt_half, + color="purple", + linestyle="--", + linewidth=1.5, + label="Blanket Half Height", + ) + ax.axhline( + -dz_blkt_half, + color="purple", + linestyle="--", + linewidth=1.5, + label="Blanket Half Height", + ) + + ax.annotate( + "", + xy=(rmajor, dz_blkt_half), + xytext=(rmajor, -dz_blkt_half), + arrowprops={"arrowstyle": "<->", "color": "black"}, + ) + + # Add a label for the internal coil width + ax.text( + rmajor, + 0.0, + f"{2 * dz_blkt_half:.3f} m", + fontsize=7, + color="black", + rotation=270, + verticalalignment="center", + horizontalalignment="center", + bbox={"boxstyle": "round", "facecolor": "pink", "alpha": 1.0}, + zorder=101, # Ensure label is on top of all plots + ) + + # Plot midplane line (horizontal dashed line at Z=0) + ax.axhline( + 0.0, + color="black", + linestyle="--", + linewidth=1.5, + label="Midplane", + ) + + def main_plot( figs: list[Axes], m_file: mf.MFile, @@ -13012,46 +13086,7 @@ def main_plot( plot_blkt_pipe_bends(figs[27], m_file, scan) ax_blanket = figs[27].add_subplot(122, aspect="equal") - plot_blanket(ax_blanket, m_file, scan, radial_build, colour_scheme) - plot_firstwall(ax_blanket, m_file, scan, radial_build, colour_scheme) - ax_blanket.set_xlabel("Radial position [m]") - ax_blanket.set_ylabel("Vertical position [m]") - ax_blanket.set_title("Blanket and First Wall Poloidal Cross-Section") - ax_blanket.minorticks_on() - ax_blanket.grid(which="minor", linestyle=":", linewidth=0.5, alpha=0.5) - # Plot major radius line (vertical dashed line at rmajor) - ax_blanket.axvline( - m_file.get("rminor", scan=scan), - color="black", - linestyle="--", - linewidth=1.5, - label="Major Radius $R_0$", - ) - # Plot a horizontal line at dz_blkt_half (blanket half height) - dz_blkt_half = m_file.get("dz_blkt_half", scan=scan) - ax_blanket.axhline( - dz_blkt_half, - color="purple", - linestyle="--", - linewidth=1.5, - label="Blanket Half Height", - ) - ax_blanket.axhline( - -dz_blkt_half, - color="purple", - linestyle="--", - linewidth=1.5, - label="Blanket Half Height", - ) - - # Plot midplane line (horizontal dashed line at Z=0) - ax_blanket.axhline( - 0.0, - color="black", - linestyle="--", - linewidth=1.5, - label="Midplane", - ) + plot_blkt_structure(ax_blanket, m_file, scan, radial_build, colour_scheme) plot_main_power_flow( figs[28].add_subplot(111, aspect="equal"), m_file, scan, figs[28] From 4e2cb3c30290a2375bb11f95694d9ea4cf5c0899 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 16:24:43 +0000 Subject: [PATCH 06/10] Refactor blanket area and volume calculations to include full coverage variables for D-shaped and elliptical shapes --- process/blanket_library.py | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index ffe43cc7b..943db2aa0 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -68,9 +68,9 @@ def component_volumes(self): # D-shaped blanket and shield if physics_variables.itart == 1 or fwbs_variables.i_fw_blkt_vv_shape == 1: ( - build_variables.a_blkt_inboard_surface, - build_variables.a_blkt_outboard_surface, - build_variables.a_blkt_total_surface, + build_variables.a_blkt_inboard_surface_full_coverage, + build_variables.a_blkt_outboard_surface_full_coverage, + build_variables.a_blkt_total_surface_full_coverage, ) = self.calculate_dshaped_blkt_areas( r_shld_inboard_inner=build_variables.r_shld_inboard_inner, dr_shld_inboard=build_variables.dr_shld_inboard, @@ -84,9 +84,9 @@ def component_volumes(self): ) ( - fwbs_variables.vol_blkt_inboard, - fwbs_variables.vol_blkt_outboard, - fwbs_variables.vol_blkt_total, + fwbs_variables.vol_blkt_inboard_full_coverage, + fwbs_variables.vol_blkt_outboard_full_coverage, + fwbs_variables.vol_blkt_total_full_coverage, ) = self.calculate_dshaped_blkt_volumes( r_shld_inboard_inner=build_variables.r_shld_inboard_inner, dr_shld_inboard=build_variables.dr_shld_inboard, @@ -104,9 +104,9 @@ def component_volumes(self): # Elliptical blanket and shield else: ( - build_variables.a_blkt_inboard_surface, - build_variables.a_blkt_outboard_surface, - build_variables.a_blkt_total_surface, + build_variables.a_blkt_inboard_surface_full_coverage, + build_variables.a_blkt_outboard_surface_full_coverage, + build_variables.a_blkt_total_surface_full_coverage, ) = self.calculate_elliptical_blkt_areas( rmajor=physics_variables.rmajor, rminor=physics_variables.rminor, @@ -121,9 +121,9 @@ def component_volumes(self): ) ( - fwbs_variables.vol_blkt_inboard, - fwbs_variables.vol_blkt_outboard, - fwbs_variables.vol_blkt_total, + fwbs_variables.vol_blkt_inboard_full_coverage, + fwbs_variables.vol_blkt_outboard_full_coverage, + fwbs_variables.vol_blkt_total_full_coverage, ) = self.calculate_elliptical_blkt_volumes( rmajor=physics_variables.rmajor, rminor=physics_variables.rminor, @@ -581,42 +581,43 @@ def apply_coverage_factors(self): if divertor_variables.n_divertors == 2: # double null configuration build_variables.a_blkt_outboard_surface = ( - build_variables.a_blkt_total_surface + build_variables.a_blkt_total_surface_full_coverage * ( 1.0 - 2.0 * fwbs_variables.f_ster_div_single - fwbs_variables.f_a_fw_outboard_hcd ) - - build_variables.a_blkt_inboard_surface + - build_variables.a_blkt_inboard_surface_full_coverage ) else: # single null configuration build_variables.a_blkt_outboard_surface = ( - build_variables.a_blkt_total_surface + build_variables.a_blkt_total_surface_full_coverage * ( 1.0 - fwbs_variables.f_ster_div_single - fwbs_variables.f_a_fw_outboard_hcd ) - - build_variables.a_blkt_inboard_surface + - build_variables.a_blkt_inboard_surface_full_coverage ) build_variables.a_blkt_total_surface = ( - build_variables.a_blkt_inboard_surface + build_variables.a_blkt_inboard_surface_full_coverage + build_variables.a_blkt_outboard_surface ) fwbs_variables.vol_blkt_outboard = ( - fwbs_variables.vol_blkt_total + fwbs_variables.vol_blkt_total_full_coverage * ( 1.0 - fwbs_variables.f_ster_div_single - fwbs_variables.f_a_fw_outboard_hcd ) - - fwbs_variables.vol_blkt_inboard + - fwbs_variables.vol_blkt_inboard_full_coverage ) fwbs_variables.vol_blkt_total = ( - fwbs_variables.vol_blkt_inboard + fwbs_variables.vol_blkt_outboard + fwbs_variables.vol_blkt_inboard_full_coverage + + fwbs_variables.vol_blkt_outboard ) def primary_coolant_properties(self, output: bool): From 75ebe9d9a03f871cb8db46b55af7bbaf802bcb1a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 17:05:39 +0000 Subject: [PATCH 07/10] Add output function for blanket volumes and areas in blanket_library; integrate into DCLL and CCFE_HCPB classes --- process/blanket_library.py | 83 ++++++++++++++++++++++++++++++++++++++ process/dcll.py | 2 + process/hcpb.py | 3 ++ 3 files changed, 88 insertions(+) diff --git a/process/blanket_library.py b/process/blanket_library.py index 943db2aa0..53508101c 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -615,11 +615,94 @@ def apply_coverage_factors(self): ) - fwbs_variables.vol_blkt_inboard_full_coverage ) + fwbs_variables.vol_blkt_inboard = fwbs_variables.vol_blkt_inboard_full_coverage + fwbs_variables.vol_blkt_total = ( fwbs_variables.vol_blkt_inboard_full_coverage + fwbs_variables.vol_blkt_outboard ) + def output_blkt_volumes_and_areas(self): + """Outputs blanket volumes and areas to the output file""" + + po.oheadr(self.outfile, "Blanket Volumes and Surface Areas") + + po.ovarst( + self.outfile, + "Inboard Blanket Volume with gaps and holes (m3)", + "(vol_blkt_inboard)", + fwbs_variables.vol_blkt_inboard, + ) + po.ovarst( + self.outfile, + "Outboard Blanket Volume with gaps and holes (m3)", + "(vol_blkt_outboard)", + fwbs_variables.vol_blkt_outboard, + ) + po.ovarst( + self.outfile, + "Total Blanket Volume with gaps and holes (m3)", + "(vol_blkt_total)", + fwbs_variables.vol_blkt_total, + ) + + po.ovarst( + self.outfile, + "Inboard Blanket Volume if toridally continuous (m3)", + "(vol_blkt_inboard_full_coverage)", + fwbs_variables.vol_blkt_inboard_full_coverage, + ) + po.ovarst( + self.outfile, + "Outboard Blanket Volume if toridally continuous (m3)", + "(vol_blkt_outboard_full_coverage)", + fwbs_variables.vol_blkt_outboard_full_coverage, + ) + po.ovarst( + self.outfile, + "Total Blanket Volume if toridally continuous (m3)", + "(vol_blkt_total_full_coverage)", + fwbs_variables.vol_blkt_total_full_coverage, + ) + + po.ovarst( + self.outfile, + "Inboard Blanket Surface Area with gaps and holes (m2)", + "(a_blkt_inboard_surface)", + build_variables.a_blkt_inboard_surface, + ) + po.ovarst( + self.outfile, + "Outboard Blanket Surface Area with gaps and holes (m2)", + "(a_blkt_outboard_surface)", + build_variables.a_blkt_outboard_surface, + ) + po.ovarst( + self.outfile, + "Total Blanket Surface Area with gaps and holes (m2)", + "(a_blkt_total_surface)", + build_variables.a_blkt_total_surface, + ) + + po.ovarst( + self.outfile, + "Inboard blanket surface area if toridally continuous (m2)", + "(a_blkt_inboard_surface_full_coverage)", + build_variables.a_blkt_inboard_surface_full_coverage, + ) + po.ovarst( + self.outfile, + "Outboard blanket surface area if toridally continuous (m2)", + "(a_blkt_outboard_surface_full_coverage)", + build_variables.a_blkt_outboard_surface_full_coverage, + ) + po.ovarst( + self.outfile, + "Total blanket surface area if toridally continuous (m2)", + "(a_blkt_total_surface_full_coverage)", + build_variables.a_blkt_total_surface_full_coverage, + ) + def primary_coolant_properties(self, output: bool): """Calculates the fluid properties of the Primary Coolant in the FW and BZ. Uses middle value of input and output temperatures of coolant. diff --git a/process/dcll.py b/process/dcll.py index 2b368ac7f..c96637a66 100644 --- a/process/dcll.py +++ b/process/dcll.py @@ -912,6 +912,8 @@ def write_output(self): # Component Volumes po.osubhd(self.outfile, "Component Volumes :") + self.output_blkt_volumes_and_areas() + po.ovarrf( self.outfile, "First Wall Armour Volume (m3)", diff --git a/process/hcpb.py b/process/hcpb.py index 288beb7a5..32868cfe1 100644 --- a/process/hcpb.py +++ b/process/hcpb.py @@ -1221,6 +1221,9 @@ def st_centrepost_nuclear_heating(self, pneut, sh_width): def write_output(self): po.oheadr(self.outfile, "First wall and blanket : CCFE HCPB model") + + self.output_blkt_volumes_and_areas() + po.osubhd(self.outfile, "Blanket Composition by volume :") po.ovarrf( From 29ffdf0fd4c6f3e4668258bcb500a86efdda07e9 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 17:29:53 +0000 Subject: [PATCH 08/10] Add surface area and volume calculations for blanket with full coverage; update plotting functions to display these metrics --- process/blanket_library.py | 4 +++ process/io/plot_proc.py | 59 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index 53508101c..e8b6a50d8 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -617,6 +617,10 @@ def apply_coverage_factors(self): ) fwbs_variables.vol_blkt_inboard = fwbs_variables.vol_blkt_inboard_full_coverage + build_variables.a_blkt_inboard_surface = ( + build_variables.a_blkt_inboard_surface_full_coverage + ) + fwbs_variables.vol_blkt_total = ( fwbs_variables.vol_blkt_inboard_full_coverage + fwbs_variables.vol_blkt_outboard diff --git a/process/io/plot_proc.py b/process/io/plot_proc.py index 6f8828ac7..406f1b44b 100644 --- a/process/io/plot_proc.py +++ b/process/io/plot_proc.py @@ -10596,8 +10596,8 @@ def plot_tf_stress(axis: plt.Axes, mfile: mf.MFile): def plot_blkt_pipe_bends(fig, m_file, scan: int): """Plot the blanket pipe bends on the given axis, with axes in mm.""" - ax_90 = fig.add_subplot(331) - ax_180 = fig.add_subplot(334) + ax_90 = fig.add_subplot(341) + ax_180 = fig.add_subplot(342) # Get pipe radius from m_file, fallback to 0.1 m r = m_file.get("radius_blkt_channel", scan=scan) @@ -12745,6 +12745,7 @@ def plot_inequality_constraint_equations(axis: plt.Axes, m_file: mf.MFile, scan: def plot_blkt_structure( ax: plt.Axes, + fig: plt.Figure, m_file: mf.MFile, scan: int, radial_build: dict[str, float], @@ -12816,6 +12817,58 @@ def plot_blkt_structure( label="Midplane", ) + textstr_blkt_areas = ( + f"$\\mathbf{{Blanket \\ Areas:}}$\n\n" + f"Inboard blanket, with holes and gaps: {m_file.get('a_blkt_inboard_surface', scan=scan):,.3f} $\\text{{m}}^2$ \n" + f"Outboard blanket, with holes and gaps: {m_file.get('a_blkt_outboard_surface', scan=scan):,.3f} $\\text{{m}}^2$ \n" + f"Total blanket, with holes and gaps: {m_file.get('a_blkt_total_surface', scan=scan):,.3f} $\\text{{m}}^2$ \n\n" + f"Inboard blanket, full coverage: {m_file.get('a_blkt_inboard_surface_full_coverage', scan=scan):,.3f} $\\text{{m}}^2$ \n" + f"Outboard blanket, full coverage: {m_file.get('a_blkt_outboard_surface_full_coverage', scan=scan):,.3f} $\\text{{m}}^2$ \n" + f"Total blanket, full coverage: {m_file.get('a_blkt_total_surface_full_coverage', scan=scan):,.3f} $\\text{{m}}^2$ " + ) + + ax.text( + 0.05, + 0.3, + textstr_blkt_areas, + fontsize=9, + verticalalignment="bottom", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "wheat", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + textstr_blkt_volumes = ( + f"$\\mathbf{{Blanket \\ Volumes:}}$\n\n" + f"Inboard blanket, with holes and gaps: {m_file.get('vol_blkt_inboard', scan=scan):,.3f} $\\text{{m}}^3$ \n" + f"Outboard blanket, with holes and gaps: {m_file.get('vol_blkt_outboard', scan=scan):,.3f} $\\text{{m}}^3$ \n" + f"Total blanket, with holes and gaps: {m_file.get('vol_blkt_total', scan=scan):,.3f} $\\text{{m}}^3$ \n\n" + f"Inboard blanket, full coverage: {m_file.get('vol_blkt_inboard_full_coverage', scan=scan):,.3f} $\\text{{m}}^3$ \n" + f"Outboard blanket, full coverage: {m_file.get('vol_blkt_outboard_full_coverage', scan=scan):,.3f} $\\text{{m}}^3$ \n" + f"Total blanket, full coverage: {m_file.get('vol_blkt_total_full_coverage', scan=scan):,.3f} $\\text{{m}}^3$ " + ) + + ax.text( + 0.05, + 0.05, + textstr_blkt_volumes, + fontsize=9, + verticalalignment="bottom", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "wheat", + "alpha": 1.0, + "linewidth": 2, + }, + ) + def main_plot( figs: list[Axes], @@ -13086,7 +13139,7 @@ def main_plot( plot_blkt_pipe_bends(figs[27], m_file, scan) ax_blanket = figs[27].add_subplot(122, aspect="equal") - plot_blkt_structure(ax_blanket, m_file, scan, radial_build, colour_scheme) + plot_blkt_structure(ax_blanket, figs[27], m_file, scan, radial_build, colour_scheme) plot_main_power_flow( figs[28].add_subplot(111, aspect="equal"), m_file, scan, figs[28] From 530e56cb3c91293f5cf8a52e18be37dd09ef0f85 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 17:54:35 +0000 Subject: [PATCH 09/10] Add blanket arc radius variables to fwbs_variables module --- process/data_structure/fwbs_variables.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/process/data_structure/fwbs_variables.py b/process/data_structure/fwbs_variables.py index 5decc9c3d..818eef440 100644 --- a/process/data_structure/fwbs_variables.py +++ b/process/data_structure/fwbs_variables.py @@ -373,6 +373,14 @@ dr_fw_wall: float = None """wall thickness of first wall coolant channels [m]""" +r_blkt_arc_1: float = None +"""First blanket arc radius [m]""" + +r_blkt_arc_2: float = None +"""Second blanket arc radius [m]""" + +r_blkt_arc_3: float = None +"""Third blanket arc radius [m]""" radius_fw_channel: float = None """radius of first wall cooling channels [m]""" @@ -989,6 +997,9 @@ def init_fwbs_variables(): i_blkt_coolant_type, \ i_fw_coolant_type, \ dr_fw_wall, \ + r_blkt_arc_1, \ + r_blkt_arc_2, \ + r_blkt_arc_3, \ radius_fw_channel, \ dx_fw_module, \ temp_fw_coolant_in, \ @@ -1184,6 +1195,9 @@ def init_fwbs_variables(): i_blkt_coolant_type = 1 i_fw_coolant_type = "helium" dr_fw_wall = 0.003 + r_blkt_arc_1 = 0.0 + r_blkt_arc_2 = 0.0 + r_blkt_arc_3 = 0.0 radius_fw_channel = 0.006 dx_fw_module = 0.02 temp_fw_coolant_in = 573.0 From f5c63a2e98e67a3b2ded1d1a4d12da6bce8416d5 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 30 Jan 2026 19:15:25 +0000 Subject: [PATCH 10/10] Add blanket arc radius calculations and update plotting to visualize arc points --- process/blanket_library.py | 38 +++++++++++++++++++++++++++++++++++--- process/io/plot_proc.py | 15 +++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index e8b6a50d8..a4442251a 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -107,6 +107,9 @@ def component_volumes(self): build_variables.a_blkt_inboard_surface_full_coverage, build_variables.a_blkt_outboard_surface_full_coverage, build_variables.a_blkt_total_surface_full_coverage, + fwbs_variables.r_blkt_arc_1, + fwbs_variables.r_blkt_arc_2, + fwbs_variables.r_blkt_arc_3, ) = self.calculate_elliptical_blkt_areas( rmajor=physics_variables.rmajor, rminor=physics_variables.rminor, @@ -394,7 +397,7 @@ def calculate_elliptical_blkt_areas( dr_shld_outboard: float, dr_blkt_outboard: float, dz_blkt_half: float, - ) -> tuple[float, float, float]: + ) -> tuple[float, float, float, float, float, float]: """Calculate elliptical blanket surface areas. :param rmajor: Major radius of the plasma (m) @@ -418,7 +421,8 @@ def calculate_elliptical_blkt_areas( :param dz_blkt_half: Half-height of the blanket (m) :type dz_blkt_half: float - :return: Tuple containing inboard blanket surface area (m²), outboard blanket surface area (m²), and total blanket surface area (m²) + :return: Tuple containing inboard blanket surface area (m²), outboard blanket surface area (m²), and total blanket surface area (m²), + and three blanket arc radii (m) """ # Major radius to centre of inboard and outboard ellipses (m) @@ -445,7 +449,14 @@ def calculate_elliptical_blkt_areas( a_blkt_total_surface, ) = eshellarea(r1, r2, r3, dz_blkt_half) - return a_blkt_inboard_surface, a_blkt_outboard_surface, a_blkt_total_surface + return ( + a_blkt_inboard_surface, + a_blkt_outboard_surface, + a_blkt_total_surface, + r1, + r2, + r3, + ) @staticmethod def calculate_elliptical_blkt_volumes( @@ -707,6 +718,27 @@ def output_blkt_volumes_and_areas(self): build_variables.a_blkt_total_surface_full_coverage, ) + po.oblnkl(self.outfile) + + po.ovarst( + self.outfile, + "First radial blanket arc point (m)", + "(r_blkt_arc_1)", + fwbs_variables.r_blkt_arc_1, + ) + po.ovarst( + self.outfile, + "Second radial blanket arc point (m)", + "(r_blkt_arc_2)", + fwbs_variables.r_blkt_arc_2, + ) + po.ovarst( + self.outfile, + "Third radial blanket arc point (m)", + "(r_blkt_arc_3)", + fwbs_variables.r_blkt_arc_3, + ) + def primary_coolant_properties(self, output: bool): """Calculates the fluid properties of the Primary Coolant in the FW and BZ. Uses middle value of input and output temperatures of coolant. diff --git a/process/io/plot_proc.py b/process/io/plot_proc.py index 406f1b44b..dfb282f0d 100644 --- a/process/io/plot_proc.py +++ b/process/io/plot_proc.py @@ -12817,6 +12817,21 @@ def plot_blkt_structure( label="Midplane", ) + # Plot the points as black dots, number them, and connect them with lines + xs = [m_file.get(f"r_blkt_arc_{i}", scan=scan) for i in range(1, 4)] + for i, (x,) in enumerate(zip(xs, strict=False), 1): + ax.plot(x, 0.0, "ko", markersize=8) + ax.text( + x, + 0.0, + str(i), + color="red", + fontsize=5, + ha="center", + va="center", + fontweight="bold", + ) + textstr_blkt_areas = ( f"$\\mathbf{{Blanket \\ Areas:}}$\n\n" f"Inboard blanket, with holes and gaps: {m_file.get('a_blkt_inboard_surface', scan=scan):,.3f} $\\text{{m}}^2$ \n"