diff --git a/process/blanket_library.py b/process/blanket_library.py index aa447c98f..a4442251a 100644 --- a/process/blanket_library.py +++ b/process/blanket_library.py @@ -49,55 +49,162 @@ 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.component_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: - self.dshaped_component() + ( + 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, + 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_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, + 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: - self.elliptical_component() + ( + 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, + 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_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, + 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() - def component_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 @@ -143,6 +250,290 @@ 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 + + @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, 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²), + and three blanket arc radii (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, + r1, + r2, + r3, + ) + + @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 @@ -201,42 +592,151 @@ 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_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 + fwbs_variables.vol_blkt_outboard + 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, + ) + + 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): 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 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( diff --git a/process/io/plot_proc.py b/process/io/plot_proc.py index 95a6f80ad..dfb282f0d 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) @@ -12743,6 +12743,148 @@ def plot_inequality_constraint_equations(axis: plt.Axes, m_file: mf.MFile, scan: axis.set_xticklabels([]) +def plot_blkt_structure( + ax: plt.Axes, + fig: plt.Figure, + 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", + ) + + # 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" + 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], m_file: mf.MFile, @@ -13012,46 +13154,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, 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] diff --git a/tests/unit/test_blanket_library.py b/tests/unit/test_blanket_library.py index 24eb8a252..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_component_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.component_half_height( - componenthalfheightparam.icomponent + half_height = blanket_library_fixture.calculate_blkt_half_height( + 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)