From 2e984c52923214ab7394e94fb63edded3d834b1b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Dec 2025 10:42:56 +0000 Subject: [PATCH 1/4] Add VacuumVessel class and integrate into Caller model --- process/caller.py | 2 ++ process/main.py | 3 ++- process/vacuum.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/process/caller.py b/process/caller.py index 0a93243a15..3f5b0a0eff 100644 --- a/process/caller.py +++ b/process/caller.py @@ -276,6 +276,8 @@ def _call_models_once(self, xc: np.ndarray) -> None: # First wall model self.models.fw.run() + self.models.vacuum_vessel.run() + # Blanket model """Blanket switch values No. | model diff --git a/process/main.py b/process/main.py index e16b7f2109..a0727742e9 100644 --- a/process/main.py +++ b/process/main.py @@ -106,7 +106,7 @@ from process.structure import Structure from process.superconducting_tf_coil import SuperconductingTFCoil from process.tf_coil import TFCoil -from process.vacuum import Vacuum +from process.vacuum import Vacuum, VacuumVessel from process.water_use import WaterUse os.environ["PYTHON_PROCESS_ROOT"] = os.path.join(os.path.dirname(__file__)) @@ -660,6 +660,7 @@ def __init__(self): self.availability = Availability() self.buildings = Buildings() self.vacuum = Vacuum() + self.vacuum_vessel = VacuumVessel() self.water_use = WaterUse() self.pulse = Pulse() self.ife = IFE(availability=self.availability, costs=self.costs) diff --git a/process/vacuum.py b/process/vacuum.py index 7f71c0ec46..576893cfc4 100644 --- a/process/vacuum.py +++ b/process/vacuum.py @@ -5,6 +5,7 @@ from process import constants from process import process_output as po +from process.data_structure import blanket_library as blanket_library from process.data_structure import build_variables as buv from process.data_structure import physics_variables as pv from process.data_structure import tfcoil_variables as tfv @@ -683,3 +684,60 @@ def vacuum( ) return pumpn, nduct, dlscalc, mvdsh, dimax + + +class VacuumVessel: + """Class containing vacuum vessel routines""" + + def __init__(self) -> None: + pass + + def run(self) -> None: + blanket_library.dz_vv_half = self.calculate_vessel_half_height( + z_tf_inside_half=buv.z_tf_inside_half, + dz_shld_vv_gap=buv.dz_shld_vv_gap, + dz_vv_lower=buv.dz_vv_lower, + n_divertors=pv.n_divertors, + dz_blkt_upper=buv.dz_blkt_upper, + dz_shld_upper=buv.dz_shld_upper, + z_plasma_xpoint_upper=buv.z_plasma_xpoint_upper, + dr_fw_plasma_gap_inboard=buv.dr_fw_plasma_gap_inboard, + dr_fw_plasma_gap_outboard=buv.dr_fw_plasma_gap_outboard, + dr_fw_inboard=buv.dr_fw_inboard, + dr_fw_outboard=buv.dr_fw_outboard, + ) + + def calculate_vessel_half_height( + self, + z_tf_inside_half: float, + dz_shld_vv_gap: float, + dz_vv_lower: float, + n_divertors: int, + dz_blkt_upper: float, + dz_shld_upper: 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, + ) -> float: + """Calculate vacuum vessel internal half-height (m)""" + + z_bottom = z_tf_inside_half - dz_shld_vv_gap - dz_vv_lower + + # Calculate component internal upper half-height (m) + # If a double null machine then symmetric + if n_divertors == 2: + z_top = z_bottom + else: + z_top = z_plasma_xpoint_upper + 0.5 * ( + dr_fw_plasma_gap_inboard + + dr_fw_plasma_gap_outboard + + dr_fw_inboard + + dr_fw_outboard + + dz_blkt_upper + + dz_shld_upper + ) + + # Average of top and bottom (m) + return 0.5 * (z_top + z_bottom) From 5bc94eae2a45c78fa45348eb6bb3356499fcd0d3 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Dec 2025 11:01:36 +0000 Subject: [PATCH 2/4] Add calculate_dshaped_vessel_volumes method to VacuumVessel class --- process/vacuum.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/process/vacuum.py b/process/vacuum.py index 576893cfc4..59378f5a31 100644 --- a/process/vacuum.py +++ b/process/vacuum.py @@ -5,8 +5,10 @@ from process import constants from process import process_output as po +from process.blanket_library import dshellvol from process.data_structure import blanket_library as blanket_library from process.data_structure import build_variables as buv +from process.data_structure import fwbs_variables as fwbs_variables from process.data_structure import physics_variables as pv from process.data_structure import tfcoil_variables as tfv from process.data_structure import times_variables as tv @@ -707,6 +709,20 @@ def run(self) -> None: dr_fw_outboard=buv.dr_fw_outboard, ) + ( + blanket_library.vol_vv_inboard, + blanket_library.vol_vv_outboard, + fwbs_variables.vol_vv, + ) = self.calculate_dshaped_vessel_volumes( + rsldi=buv.rsldi, + rsldo=buv.rsldo, + dz_vv_half=blanket_library.dz_vv_half, + dr_vv_inboard=buv.dr_vv_inboard, + dr_vv_outboard=buv.dr_vv_outboard, + dz_vv_upper=buv.dz_vv_upper, + dz_vv_lower=buv.dz_vv_lower, + ) + def calculate_vessel_half_height( self, z_tf_inside_half: float, @@ -741,3 +757,33 @@ def calculate_vessel_half_height( # Average of top and bottom (m) return 0.5 * (z_top + z_bottom) + + def calculate_dshaped_vessel_volumes( + self, + rsldi: float, + rsldo: float, + dz_vv_half: float, + dr_vv_inboard: float, + dr_vv_outboard: float, + dz_vv_upper: float, + dz_vv_lower: float, + ) -> None: + """Calculate volumes of D-shaped vacuum vessel segments""" + + r_1 = rsldi + r_2 = rsldo - r_1 + + ( + vol_vv_inboard, + vol_vv_outboard, + vol_vv, + ) = dshellvol( + rmajor=r_1, + rminor=r_2, + zminor=dz_vv_half, + drin=dr_vv_inboard, + drout=dr_vv_outboard, + dz=(dz_vv_upper + dz_vv_lower) / 2, + ) + + return vol_vv_inboard, vol_vv_outboard, vol_vv From ae2897c78f24cd048eb6d10f3ae5ccc26dbb2a2f Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Dec 2025 11:14:48 +0000 Subject: [PATCH 3/4] Add calculate_elliptical_vessel_volumes method to VacuumVessel class --- process/vacuum.py | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/process/vacuum.py b/process/vacuum.py index 59378f5a31..e0a6600c25 100644 --- a/process/vacuum.py +++ b/process/vacuum.py @@ -5,7 +5,7 @@ from process import constants from process import process_output as po -from process.blanket_library import dshellvol +from process.blanket_library import dshellvol, eshellvol from process.data_structure import blanket_library as blanket_library from process.data_structure import build_variables as buv from process.data_structure import fwbs_variables as fwbs_variables @@ -767,7 +767,7 @@ def calculate_dshaped_vessel_volumes( dr_vv_outboard: float, dz_vv_upper: float, dz_vv_lower: float, - ) -> None: + ) -> tuple[float, float, float]: """Calculate volumes of D-shaped vacuum vessel segments""" r_1 = rsldi @@ -787,3 +787,40 @@ def calculate_dshaped_vessel_volumes( ) return vol_vv_inboard, vol_vv_outboard, vol_vv + + def calculate_elliptical_vessel_volumes( + self, + rmajor: float, + rminor: float, + triang: float, + rsldi: float, + rsldo: float, + dz_vv_half: float, + dr_vv_inboard: float, + dr_vv_outboard: float, + dz_vv_upper: float, + dz_vv_lower: float, + ) -> tuple[float, float, float]: + # Major radius to centre of inboard and outboard ellipses (m) + # (coincident in radius with top of plasma) + r_1 = rmajor - rminor * triang + + # Calculate distance between r1 and outer edge of inboard ... + # ... section (m) + r_2 = r_1 - rsldi + r_3 = rsldo - r_1 + + ( + vol_vv_inboard, + vol_vv_outboard, + vol_vv, + ) = eshellvol( + r_1, + r_2, + r_3, + dz_vv_half, + dr_vv_inboard, + dr_vv_outboard, + (dz_vv_upper + dz_vv_lower) / 2, + ) + return vol_vv_inboard, vol_vv_outboard, vol_vv From 7869c1ae5d2e6a3b9567ac8676bef26a6f4331a3 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 7 Jan 2026 15:00:24 +0000 Subject: [PATCH 4/4] :fire: Remove now redundant vacuum calcs from blanket library --- process/blanket_library.py | 51 ++-------------------------------- process/caller.py | 4 +-- process/hcpb.py | 8 +++--- process/vacuum.py | 56 ++++++++++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 68 deletions(-) diff --git a/process/blanket_library.py b/process/blanket_library.py index d873190686..4dfe5dd5f2 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -57,25 +57,17 @@ def component_volumes(self): blanket_library.dz_blkt_half = self.component_half_height(icomponent=0) # Shield blanket_library.dz_shld_half = self.component_half_height(icomponent=1) - # Vacuum Vessel - blanket_library.dz_vv_half = self.component_half_height(icomponent=2) # D-shaped blanket and shield if physics_variables.itart == 1 or fwbs_variables.i_fw_blkt_vv_shape == 1: - for icomponent in range(3): + for icomponent in range(2): self.dshaped_component(icomponent) # Elliptical blanket and shield else: - for icomponent in range(3): + for icomponent in range(2): self.elliptical_component(icomponent) - # This will fail the hts_REBCO and 2D_scan regression tests, - # the number of VMCON iterations (nviter) is different. - # Seems to be because in the blanket calculations (icomponent=0): - # r2 = 1.3836567143743970 rather than old value of r2 = 1.3836567143743972, - # r3 = 3.7009701431231936 rather than r3 = 3.7009701431231923. - # Apply coverage factors to volumes and surface areas self.apply_coverage_factors() @@ -109,7 +101,7 @@ def component_half_height(self, icomponent: int): - build_variables.dz_vv_lower ) else: - raise ProcessValueError(f"{icomponent=} is invalid, it must be either 0,1,2") + raise ProcessValueError(f"{icomponent=} is invalid, it must be either 0,1") # Calculate component internal upper half-height (m) # If a double null machine then symmetric @@ -126,11 +118,6 @@ def component_half_height(self, icomponent: int): # Shield if icomponent == 1: htop = htop + build_variables.dz_blkt_upper - # Vacuum Vessel - if icomponent == 2: - htop = ( - htop + build_variables.dz_blkt_upper + build_variables.dz_shld_upper - ) # Average of top and bottom (m) return 0.5 * (htop + hbot) @@ -209,19 +196,6 @@ def dshaped_component(self, icomponent: int): build_variables.dr_shld_outboard, build_variables.dz_shld_upper, ) - elif icomponent == 2: - ( - blanket_library.vol_vv_inboard, - blanket_library.vol_vv_outboard, - fwbs_variables.vol_vv, - ) = dshellvol( - r1, - r2, - blanket_library.dz_vv_half, - build_variables.dr_vv_inboard, - build_variables.dr_vv_outboard, - (build_variables.dz_vv_upper + build_variables.dz_vv_lower) / 2, - ) def elliptical_component(self, icomponent: int): """Calculate component surface area and volume using elliptical scheme @@ -299,20 +273,6 @@ def elliptical_component(self, icomponent: int): build_variables.dr_shld_outboard, build_variables.dz_shld_upper, ) - if icomponent == 2: - ( - blanket_library.vol_vv_inboard, - blanket_library.vol_vv_outboard, - fwbs_variables.vol_vv, - ) = eshellvol( - r1, - r2, - r3, - blanket_library.dz_vv_half, - build_variables.dr_vv_inboard, - build_variables.dr_vv_outboard, - (build_variables.dz_vv_upper + build_variables.dz_vv_lower) / 2, - ) def apply_coverage_factors(self): """Apply coverage factors to volumes @@ -383,11 +343,6 @@ def apply_coverage_factors(self): blanket_library.vol_shld_inboard + blanket_library.vol_shld_outboard ) - # Apply vacuum vessel coverage factor - # moved from dshaped_* and elliptical_* to keep coverage factor - # changes in the same location. - fwbs_variables.vol_vv = fwbs_variables.fvoldw * fwbs_variables.vol_vv - 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/caller.py b/process/caller.py index 3f5b0a0eff..8cd74fefc8 100644 --- a/process/caller.py +++ b/process/caller.py @@ -276,8 +276,6 @@ def _call_models_once(self, xc: np.ndarray) -> None: # First wall model self.models.fw.run() - self.models.vacuum_vessel.run() - # Blanket model """Blanket switch values No. | model @@ -298,6 +296,8 @@ def _call_models_once(self, xc: np.ndarray) -> None: # DCLL model self.models.dcll.run(output=False) + self.models.vacuum_vessel.run() + self.models.divertor.run(output=False) self.models.cryostat.run() diff --git a/process/hcpb.py b/process/hcpb.py index 7c8d29c312..7dc310a6d7 100644 --- a/process/hcpb.py +++ b/process/hcpb.py @@ -474,10 +474,10 @@ def nuclear_heating_magnets(self, output: bool): if build_variables.dr_vv_outboard > d_vv_all: d_vv_all = build_variables.dr_vv_outboard - if d_vv_all > 1.0e-6: - ccfe_hcpb_module.vv_density = fwbs_variables.m_vv / fwbs_variables.vol_vv - else: - ccfe_hcpb_module.vv_density = 0.0 + # if d_vv_all > 1.0e-6: + # ccfe_hcpb_module.vv_density = fwbs_variables.m_vv / fwbs_variables.vol_vv + # else: + # ccfe_hcpb_module.vv_density = 0.0 # Calculation of average blanket/shield thickness [m] if physics_variables.itart == 1: diff --git a/process/vacuum.py b/process/vacuum.py index e0a6600c25..a198ba8faf 100644 --- a/process/vacuum.py +++ b/process/vacuum.py @@ -8,7 +8,9 @@ from process.blanket_library import dshellvol, eshellvol from process.data_structure import blanket_library as blanket_library from process.data_structure import build_variables as buv +from process.data_structure import ccfe_hcpb_module as ccfe_hcpb_module from process.data_structure import fwbs_variables as fwbs_variables +from process.data_structure import physics_variables as physics_variables from process.data_structure import physics_variables as pv from process.data_structure import tfcoil_variables as tfv from process.data_structure import times_variables as tv @@ -708,20 +710,45 @@ def run(self) -> None: dr_fw_inboard=buv.dr_fw_inboard, dr_fw_outboard=buv.dr_fw_outboard, ) - - ( - blanket_library.vol_vv_inboard, - blanket_library.vol_vv_outboard, - fwbs_variables.vol_vv, - ) = self.calculate_dshaped_vessel_volumes( - rsldi=buv.rsldi, - rsldo=buv.rsldo, - dz_vv_half=blanket_library.dz_vv_half, - dr_vv_inboard=buv.dr_vv_inboard, - dr_vv_outboard=buv.dr_vv_outboard, - dz_vv_upper=buv.dz_vv_upper, - dz_vv_lower=buv.dz_vv_lower, - ) + # D-shaped blanket and shield + if physics_variables.itart == 1 or fwbs_variables.i_fw_blkt_vv_shape == 1: + ( + blanket_library.vol_vv_inboard, + blanket_library.vol_vv_outboard, + fwbs_variables.vol_vv, + ) = self.calculate_dshaped_vessel_volumes( + rsldi=buv.rsldi, + rsldo=buv.rsldo, + dz_vv_half=blanket_library.dz_vv_half, + dr_vv_inboard=buv.dr_vv_inboard, + dr_vv_outboard=buv.dr_vv_outboard, + dz_vv_upper=buv.dz_vv_upper, + dz_vv_lower=buv.dz_vv_lower, + ) + else: + ( + blanket_library.vol_vv_inboard, + blanket_library.vol_vv_outboard, + fwbs_variables.vol_vv, + ) = self.calculate_elliptical_vessel_volumes( + rmajor=pv.rmajor, + rminor=pv.rminor, + triang=pv.triang, + rsldi=buv.rsldi, + rsldo=buv.rsldo, + dz_vv_half=blanket_library.dz_vv_half, + dr_vv_inboard=buv.dr_vv_inboard, + dr_vv_outboard=buv.dr_vv_outboard, + dz_vv_upper=buv.dz_vv_upper, + dz_vv_lower=buv.dz_vv_lower, + ) + + # Apply vacuum vessel coverage factor + # moved from dshaped_* and elliptical_* to keep coverage factor + # changes in the same location. + fwbs_variables.vol_vv = fwbs_variables.fvoldw * fwbs_variables.vol_vv + + ccfe_hcpb_module.vv_density = fwbs_variables.m_vv / fwbs_variables.vol_vv def calculate_vessel_half_height( self, @@ -754,6 +781,7 @@ def calculate_vessel_half_height( + dz_blkt_upper + dz_shld_upper ) + z_top = z_top + dz_blkt_upper + dz_shld_upper # Average of top and bottom (m) return 0.5 * (z_top + z_bottom)