diff --git a/process/core/caller.py b/process/core/caller.py index b2283e1516..5d9a326f38 100644 --- a/process/core/caller.py +++ b/process/core/caller.py @@ -306,6 +306,8 @@ def _call_models_once(self, xc: np.ndarray): self.models.cicc_sctfcoil.run() case SuperconductingTFTurnType.CROSS_CONDUCTOR: self.models.croco_sctfcoil.run() + case SuperconductingTFTurnType.STEP_STACKED_TAPE: + self.models.step_sctfcoil.run() case TFConductorModel.HELIUM_COOLED_ALUMINIUM: self.models.aluminium_tf_coil.run() diff --git a/process/core/input.py b/process/core/input.py index 31b6c6f6cd..b911b00511 100644 --- a/process/core/input.py +++ b/process/core/input.py @@ -1070,7 +1070,7 @@ def bounds(self) -> tuple[NumberType | None, NumberType | None]: "lsa": InputVariable("costs", int, range=(1, 4)), "m_res": InputVariable("stellarator", int, range=(1, 10)), "n_tf_wp_layers": InputVariable("tfcoil", int, range=(1, 100)), - "i_tf_turn_type": InputVariable("superconducting_tfcoil", int, choices=[1, 2]), + "i_tf_turn_type": InputVariable("superconducting_tfcoil", int, choices=[1, 2, 3]), "n_liq_recirc": InputVariable("fwbs", int, range=(1, 50)), "n_tf_wp_pancakes": InputVariable("tfcoil", int, range=(1, 100)), "n_rad_per_layer": InputVariable("tfcoil", int, range=(1, 500)), diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 6d1379d3d5..b2057d2a00 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -102,7 +102,10 @@ _build_cumulative_quench_integral, calculate_quench_protection_current_density, ) -from process.models.tfcoil.superconducting import SuperconductingTFTurnType +from process.models.tfcoil.superconducting import ( + SuperconductingTFTurnType, + SuperconductingTFWPShapeType, +) @dataclass @@ -6207,10 +6210,13 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): # ================================================================ # Plot the rectangular WP - if i_tf_wp_geom == 0: + if ( + SuperconductingTFWPShapeType(i_tf_wp_geom) + == SuperconductingTFWPShapeType.RECTANGULAR + ): if TFWPIntegerTurnType(i_tf_turns_integer) == TFWPIntegerTurnType.INTEGER: long_turns = round(turn_layers) - short_turns = round(turn_pancakes) + n_turns_toroidal = round(turn_pancakes) else: wp_side_ratio = ( dr_tf_wp_with_insulation @@ -6222,7 +6228,7 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): side_unit = n_tf_coil_turns / wp_side_ratio root_turns = round(np.sqrt(side_unit), 1) long_turns = round(root_turns * wp_side_ratio) - short_turns = round(root_turns) + n_turns_toroidal = round(root_turns) # Plots the surrounding insualtion axis.add_patch( @@ -6255,94 +6261,26 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): color="blue", ) ) - # Dvides the WP up into the turn segments - for i in range(1, long_turns): + # Divides the WP up into the turn segments + wp_inner_margin = dx_tf_wp_insulation + dx_tf_wp_insertion_gap + wp_r_min = r_tf_wp_inboard_inner + wp_inner_margin + wp_r_max = wp_r_min + dr_tf_wp_with_insulation - 2 * wp_inner_margin + wp_t_min = -0.5 * dx_tf_wp_primary_toroidal + wp_inner_margin + wp_t_max = -wp_t_min + + for r_line in np.linspace(wp_r_min, wp_r_max, long_turns + 1)[1:-1]: axis.plot( - [ - ( - r_tf_wp_inboard_inner - + dx_tf_wp_insulation - + dx_tf_wp_insertion_gap - ) - + i - * ( - ( - dr_tf_wp_with_insulation - - dx_tf_wp_insulation - - dx_tf_wp_insertion_gap - ) - / long_turns - ), - ( - r_tf_wp_inboard_inner - + dx_tf_wp_insulation - + dx_tf_wp_insertion_gap - ) - + i - * ( - ( - dr_tf_wp_with_insulation - - dx_tf_wp_insulation - - dx_tf_wp_insertion_gap - ) - / long_turns - ), - ], - [ - -0.5 * dx_tf_wp_primary_toroidal - + (dx_tf_wp_insulation + dx_tf_wp_insertion_gap), - 0.5 * dx_tf_wp_primary_toroidal - - (dx_tf_wp_insulation + dx_tf_wp_insertion_gap), - ], + [r_line, r_line], + [wp_t_min, wp_t_max], color="white", linewidth="0.25", linestyle="dashed", ) - for i in range(1, short_turns): + for t_line in np.linspace(wp_t_min, wp_t_max, n_turns_toroidal + 1)[1:-1]: axis.plot( - [ - ( - r_tf_wp_inboard_inner - + dx_tf_wp_insulation - + dx_tf_wp_insertion_gap - ), - ( - r_tf_wp_inboard_outer - - dx_tf_wp_insulation - - dx_tf_wp_insertion_gap - ), - ], - [ - ( - -0.5 * dx_tf_wp_primary_toroidal - + dx_tf_wp_insulation - + dx_tf_wp_insertion_gap - ) - + ( - i - * ( - dx_tf_wp_primary_toroidal - - dx_tf_wp_insulation - - dx_tf_wp_insertion_gap - ) - / short_turns - ), - ( - -0.5 * dx_tf_wp_primary_toroidal - + dx_tf_wp_insulation - + dx_tf_wp_insertion_gap - ) - + ( - i - * ( - dx_tf_wp_primary_toroidal - - dx_tf_wp_insulation - - dx_tf_wp_insertion_gap - ) - / short_turns - ), - ], + [wp_r_min, wp_r_max], + [t_line, t_line], color="white", linewidth="0.25", linestyle="dashed", @@ -6351,7 +6289,10 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): # ================================================================ # Plot the double rectangle winding pack - if i_tf_wp_geom == 1: + if ( + SuperconductingTFWPShapeType(i_tf_wp_geom) + == SuperconductingTFWPShapeType.DOUBLE_RECTANGULAR + ): # Inner WP insulation axis.add_patch( Rectangle( @@ -6417,7 +6358,10 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): # ================================================================ # Trapezium WP - if i_tf_wp_geom == 2: + if ( + SuperconductingTFWPShapeType(i_tf_wp_geom) + == SuperconductingTFWPShapeType.TRAPEZOIDAL + ): # WP insulation x = [ r_tf_wp_inboard_inner, @@ -6595,7 +6539,7 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): f"Max $\\Delta r$: {mfile.get('dx_tf_side_case_peak', scan=scan):.3f} m" ) axis.text( - 0.55, + 0.525, 0.975, textstr_casing, fontsize=9, @@ -6619,7 +6563,7 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): f"$\\Delta r$: {mfile.get('dx_tf_wp_insertion_gap', scan=scan):.4f} m" ) axis.text( - 0.55, + 0.525, 0.575, textstr_wp_insulation, fontsize=9, @@ -6655,7 +6599,7 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): ) axis.text( - 0.775, + 0.75, 0.95, textstr_wp, fontsize=9, @@ -6681,10 +6625,10 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): f"Total area of steel in coil: {mfile.get('a_tf_coil_inboard_steel', scan=scan):.4f} $\\mathrm{{m}}^2$\n" f"Total area fraction of steel: {mfile.get('f_a_tf_coil_inboard_steel', scan=scan):.4f}\n" f"Total area fraction of insulation: {mfile.get('f_a_tf_coil_inboard_insulation', scan=scan):.4f}\n" - f"$A$, all insulation in coil: {mfile.get('a_tf_coil_inboard_insulation', scan=scan):.4f} $\\mathrm{{m}}^2$\n" + f"$A$, all insulation in coil: {mfile.get('a_tf_coil_inboard_insulation', scan=scan):.4f} $\\mathrm{{m}}^2$" ) axis.text( - 0.775, + 0.75, 0.58, textstr_general_info, fontsize=9, @@ -6706,7 +6650,7 @@ def plot_superconducting_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): axis.set_title("Top-down view of inboard TF coil at midplane") axis.set_xlabel("Radial distance [m]") axis.set_ylabel("Toroidal distance [m]") - axis.legend(loc="upper left") + axis.legend(loc="lower center", bbox_to_anchor=(0.5, -0.4)) def plot_resistive_tf_wp(axis: plt.Axes, mfile: MFile, scan: int, fig): @@ -13321,6 +13265,242 @@ def plot_tf_corc_cable_summary_box(axis, fig, mfile: MFile, scan: int): ) +def plot_tf_step_vertical_tape_turn( + axis: plt.Axes, + fig: plt.Figure, + mfile: MFile, + scan: int, + dr_tf_turn: float, + dx_tf_turn: float, + dia_tf_turn_coolant_channel: float, + dx_tf_turn_insulation: float, + dr_tf_turn_tape_stack: float, + dx_tf_turn_tape_stack: float, + x_tf_turn_coolant_channel_centre: float, + dr_tf_turn_stabiliser: float, +) -> None: + """ + Plots TF coil STEP styled vertical tape turn structure. + """ + axis.add_patch( + Rectangle( + [0, 0], + dr_tf_turn, + dx_tf_turn, + facecolor="red", + edgecolor="black", + ), + ) + # Plot the steel conduit + axis.add_patch( + Rectangle( + [dx_tf_turn_insulation, dx_tf_turn_insulation], + (dr_tf_turn - 2 * dx_tf_turn_insulation), + (dx_tf_turn - 2 * dx_tf_turn_insulation), + facecolor="#b87333", + edgecolor="#8B4000", + ), + ) + + # Plot the coolant channel + axis.add_patch( + Circle( + [(dr_tf_turn / 2), x_tf_turn_coolant_channel_centre], + dia_tf_turn_coolant_channel / 2, + facecolor="white", + edgecolor="black", + ), + ) + + # Outline of the space available for the tape stack + axis.add_patch( + Rectangle( + [(dr_tf_turn_stabiliser * 0.1 + dx_tf_turn_insulation), (dx_tf_turn * 0.5)], + (dr_tf_turn_tape_stack), + (dx_tf_turn_tape_stack), + facecolor="none", + edgecolor="black", + linewidth=1, + ), + ) + + # Tapes are packed from the bottom of the stack at the pitch used by the model + # to count them. Layer thicknesses are scaled so each tape sums to that pitch. + dx_hts_tape_total = mfile.get("dx_tf_hts_tape_total", scan=scan) + dx_hts_tape_rebco = mfile.get("dx_tf_hts_tape_rebco", scan=scan) + dx_hts_tape_copper = mfile.get("dx_tf_hts_tape_copper", scan=scan) + dx_hts_tape_hastelloy = mfile.get("dx_tf_hts_tape_hastelloy", scan=scan) + tape_scale = dx_hts_tape_total / ( + dx_hts_tape_rebco + dx_hts_tape_copper + dx_hts_tape_hastelloy + ) + dr_hts_tape = mfile.get("dr_tf_hts_tape", scan=scan) + + for i in range(int(mfile.get("n_tf_turn_superconducting_strands", scan=scan))): + plot_hts_tape_geometry( + axis=axis, + r_left=(dr_tf_turn / 2) - (dr_hts_tape / 2), + z_bottom=(dx_tf_turn * 0.5) + i * dx_hts_tape_total, + dr_hts_tape=dr_hts_tape, + dx_hts_tape_rebco=dx_hts_tape_rebco * tape_scale, + dx_hts_tape_copper=dx_hts_tape_copper * tape_scale, + dx_hts_tape_hastelloy=dx_hts_tape_hastelloy * tape_scale, + show_legend=False, + ) + + axis.set_xlim(-dr_tf_turn * 0.05, dr_tf_turn * 1.05) + axis.set_ylim(-dx_tf_turn * 0.05, dx_tf_turn * 1.05) + + axis.minorticks_on() + axis.set_title("WP Turn Structure") + axis.set_xlabel("r [m]") + axis.set_ylabel("x [m]") + + # Add info about the steel casing surrounding the WP + textstr_turn_insulation = f"$\\mathbf{{Turn \\ Insulation:}}$\n\n$\\Delta r:${mfile.get('t_tf_superconductor_quench', scan=scan):.3e} m" + + axis.text( + 0.5, + 0.9, + textstr_turn_insulation, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "red", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + textstr_turn = ( + f"$\\mathbf{{Turn:}}$\n\n" + f"$\\Delta r$: {mfile.get('dr_tf_turn', scan=scan):.3e} m\n" + f"$\\Delta x$: {mfile.get('dx_tf_turn', scan=scan):.3e} m" + ) + + axis.text( + 0.65, + 0.9, + textstr_turn, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "wheat", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + textstr_turn_strand_space = ( + f"$\\mathbf{{Strand \\ Space:}}$\n\n" + f"$\\Delta r:$ {mfile.get('dr_tf_turn_tape_stack', scan=scan):.3e} m\n" + f"$\\Delta x:$ {mfile.get('dx_tf_turn_tape_stack', scan=scan):.3e} m\n" + f"Tape stack space area: {mfile.get('a_tf_turn_tape_stack', scan=scan):.3e} m$^2$\n" + f"Strands per turn: {mfile.get('n_tf_turn_superconducting_strands', scan=scan)}" + ) + + axis.text( + 0.525, + 0.7, + textstr_turn_strand_space, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "royalblue", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + textstr_stabiliser = ( + f"$\\mathbf{{Stabiliser:}}$\n\n" + f"$\\Delta r$: {mfile.get('dr_tf_turn_stabiliser', scan=scan):.3e} m\n" + f"$\\Delta x$: {mfile.get('dx_tf_turn_stabiliser', scan=scan):.3e} m\n" + f"Stabiliser area: {mfile.get('a_tf_turn_stabiliser', scan=scan):.3e} m$^2$" + ) + + axis.text( + 0.575, + 0.55, + textstr_stabiliser, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "#b87333", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + # Add info about the steel casing surrounding the WP + textstr_turn_cooling = ( + f"$\\mathbf{{Cooling:}}$\n\n" + f"$\\varnothing$: {mfile.get('dia_tf_turn_coolant_channel', scan=scan):.3e} m\n" + f"Total area of all coolant channels: {mfile.get('a_tf_wp_coolant_channels', scan=scan):.4f} m$^2$" + ) + + axis.text( + 0.5, + 0.8, + textstr_turn_cooling, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "white", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + textstr_superconductor = ( + f"$\\mathbf{{Superconductor:}}$\n \n" + f"Superconductor used: {SuperconductorModel(mfile.get('i_tf_sc_mat', scan=scan)).full_name}\n" + f"Critical field at zero \ntemperature and strain: {mfile.get('b_tf_superconductor_critical_zero_temp_strain', scan=scan):.4f} T\n" + f"Critical temperature at \nzero field and strain: {mfile.get('temp_tf_superconductor_critical_zero_field_strain', scan=scan):.4f} K\n" + f"Temperature at conductor: {mfile.get('tftmp', scan=scan):.4f} K\n" + f"Field at conductor: {mfile.get('b_tf_inboard_peak_with_ripple', scan=scan):.4f} T\n" + f"Superconductor critical current density at \noperating conditions: {mfile.get('j_tf_superconductor_critical', scan=scan):.2e} A/m$^2$\n" + f"$I_{{\\text{{TF,turn critical}}}}$: {mfile.get('c_turn_cables_critical', scan=scan):,.2f} A\n" + f"$I_{{\\text{{TF,turn}}}}$: {mfile.get('c_tf_turn', scan=scan):,.2f} A\n" + f"Critcal current ratio: {mfile.get('f_c_tf_turn_operating_critical', scan=scan):,.4f}\n" + f"Superconductor temperature \nmargin: {mfile.get('temp_tf_superconductor_margin', scan=scan):,.4f} K\n" + f"\n$\\mathbf{{Quench:}}$\n \n" + f"Quench dump time: {mfile.get('t_tf_superconductor_quench', scan=scan):.4e} s\n" + f"Quench detection time: {mfile.get('t_tf_quench_detection', scan=scan):.4e} s\n" + f"User input max temperature \nduring quench: {mfile.get('temp_tf_conductor_quench_max', scan=scan):.2f} K\n" + f"Required maxium WP current \ndensity for heat protection:\n{mfile.get('j_tf_wp_quench_heat_max', scan=scan):.2e} A/m$^2$\n" + ) + axis.text( + 0.75, + 0.9, + textstr_superconductor, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "#6dd3f7", # light blue for superconductors + "alpha": 1.0, + "linewidth": 2, + }, + ) + + def reaction_plot_grid( rminor, rmajor, @@ -17195,14 +17375,13 @@ def _add_page(name: str | None = None): # Can only plot WP and turn structure if superconducting coil at the moment if m_file.get("i_tf_sup", scan=scan) == TFConductorModel.SUPERCONDUCTING: # TF coil with WP - ax19 = _add_page("tf_wp").add_subplot(221, aspect="equal") - ax19.set_position([ - 0.025, - 0.45, - 0.5, - 0.5, - ]) # Half height, a bit wider, top left - plot_superconducting_tf_wp(ax19, m_file, scan, pages["tf_wp"]) + + plot_superconducting_tf_wp( + _add_page("tf_wp").add_subplot(221, aspect="equal"), + m_file, + scan, + pages["tf_wp"], + ) _add_page("cable") if ( @@ -17220,6 +17399,28 @@ def _add_page(name: str | None = None): ax20 = pages["cable"].add_subplot(325, aspect="equal") ax20.set_position([0.025, 0.5, 0.4, 0.4]) plot_tf_cable_in_conduit_turn(ax20, pages["cable"], m_file, scan) + elif ( + m_file.get("i_tf_turn_type", scan=scan) + == SuperconductingTFTurnType.STEP_STACKED_TAPE + ): + plot_tf_step_vertical_tape_turn( + axis=pages["cable"].add_subplot(221, aspect="equal"), + fig=pages["cable"], + mfile=m_file, + scan=scan, + dr_tf_turn=m_file.get("dr_tf_turn", scan=scan), + dx_tf_turn=m_file.get("dx_tf_turn", scan=scan), + dia_tf_turn_coolant_channel=m_file.get( + "dia_tf_turn_coolant_channel", scan=scan + ), + dx_tf_turn_insulation=m_file.get("dx_tf_turn_insulation", scan=scan), + dr_tf_turn_tape_stack=m_file.get("dr_tf_turn_tape_stack", scan=scan), + dx_tf_turn_tape_stack=m_file.get("dx_tf_turn_tape_stack", scan=scan), + x_tf_turn_coolant_channel_centre=m_file.get( + "x_tf_turn_coolant_channel_centre", scan=scan + ), + dr_tf_turn_stabiliser=m_file.get("dr_tf_turn_stabiliser", scan=scan), + ) if ( m_file.get("i_tf_turn_type", scan=scan) @@ -17248,18 +17449,7 @@ def _add_page(name: str | None = None): show_legend=True, ) plot_tf_corc_cable_summary_box(plot_205, pages["cable"], m_file, scan) - ax_hts_tape = pages["cable"].add_subplot(339) - ax_hts_tape.set_position([0.75, 0.1, 0.2, 0.2]) - plot_hts_tape_geometry( - axis=ax_hts_tape, - r_left=0.0, - z_bottom=0.0, - dr_hts_tape=m_file.get("dr_tf_hts_tape", scan=scan), - dx_hts_tape_rebco=m_file.get("dx_tf_hts_tape_rebco", scan=scan), - dx_hts_tape_copper=m_file.get("dx_tf_hts_tape_copper", scan=scan), - dx_hts_tape_hastelloy=m_file.get("dx_tf_hts_tape_hastelloy", scan=scan), - show_legend=True, - ) + elif ( m_file.get("i_tf_turn_type", scan=scan) == SuperconductingTFTurnType.CABLE_IN_CONDUIT @@ -17287,6 +17477,23 @@ def _add_page(name: str | None = None): axes_1=_add_page("quench_time_evo").add_subplot(211), axes_2=pages["quench_time_evo"].add_subplot(212), ) + if ( + m_file.get("i_tf_turn_type", scan=scan) + == SuperconductingTFTurnType.STEP_STACKED_TAPE + or SuperconductingTFTurnType.CROSS_CONDUCTOR + ): + ax_hts_tape = pages["cable"].add_subplot(339) + ax_hts_tape.set_position([0.75, 0.1, 0.2, 0.2]) + plot_hts_tape_geometry( + axis=ax_hts_tape, + r_left=0.0, + z_bottom=0.0, + dr_hts_tape=m_file.get("dr_tf_hts_tape", scan=scan), + dx_hts_tape_rebco=m_file.get("dx_tf_hts_tape_rebco", scan=scan), + dx_hts_tape_copper=m_file.get("dx_tf_hts_tape_copper", scan=scan), + dx_hts_tape_hastelloy=m_file.get("dx_tf_hts_tape_hastelloy", scan=scan), + show_legend=True, + ) else: ax19 = _add_page("tf_wp").add_subplot(211, aspect="equal") ax19.set_position([0.06, 0.55, 0.675, 0.4]) @@ -17298,7 +17505,7 @@ def _add_page(name: str | None = None): plot_plasma_outboard_toroidal_ripple_map(_add_page(), m_file, scan) - plot_tf_stress(_add_page().subplots(nrows=3, ncols=1, sharex=True).flatten(), m_file) + # plot_tf_stress(_add_page().subplots(nrows=3, ncols=1, sharex=True).flatten(), m_file) plot_pf_dimensions( axis=_add_page("pf_dimensions").add_subplot(121, aspect="equal"), diff --git a/process/data_structure/superconducting_tf_coil_variables.py b/process/data_structure/superconducting_tf_coil_variables.py index 34faf78cf8..13b8b3f47d 100644 --- a/process/data_structure/superconducting_tf_coil_variables.py +++ b/process/data_structure/superconducting_tf_coil_variables.py @@ -275,6 +275,30 @@ class SuperconductingTFData: a_tf_turn_croco_hastelloy: float = 0.0 """Area of the Hastelloy in the CroCo cable space of the TF turn (includes tapes and outer tube) (m²)""" + dx_tf_turn_tape_stack: float = 0.0 + """Thickness of the tape stack in the TF turn [m]""" + + dr_tf_turn_tape_stack: float = 0.0 + """Radial thickness of the tape stack in the TF turn [m]""" + + a_tf_turn_tape_stack: float = 0.0 + """Cross-sectional area of the tape stack in the TF turn [m²]""" + + x_tf_turn_coolant_channel_centre: float = 0.0 + """Vertical centre position of the coolant channel in the TF turn [m]""" + + dr_tf_turn_stabiliser: float = 0.0 + """Radial thickness of the stabiliser in the TF turn [m]""" + + dx_tf_turn_stabiliser: float = 0.0 + """Toroidal thickness of the stabiliser in the TF turn [m]""" + + a_tf_turn_stabiliser: float = 0.0 + """Cross-sectional area of the stabiliser in the TF turn [m²]""" + + n_tf_turn_superconducting_strands: int = 0.0 + """Number of superconducting strands in the TF turn""" + t1: float = 0.0 time2: float = 0.0 diff --git a/process/main.py b/process/main.py index d99959837f..7fec801f15 100644 --- a/process/main.py +++ b/process/main.py @@ -124,6 +124,7 @@ from process.models.tfcoil.superconducting import ( CICCSuperconductingTFCoil, CROCOSuperconductingTFCoil, + STEPSuperconductingTFCoil, SuperconductingTFCoil, SuperconductingTFTurnType, ) @@ -657,6 +658,7 @@ def __init__(self, data: DataStructure): self.sctfcoil = SuperconductingTFCoil() self.cicc_sctfcoil = CICCSuperconductingTFCoil() self.croco_sctfcoil = CROCOSuperconductingTFCoil() + self.step_sctfcoil = STEPSuperconductingTFCoil() self.tfcoil = TFCoil() self.resistive_tf_coil = ResistiveTFCoil() self.copper_tf_coil = CopperTFCoil() @@ -809,6 +811,7 @@ def models(self) -> tuple[Model, ...]: self.copper_tf_coil, self.cicc_sctfcoil, self.croco_sctfcoil, + self.step_sctfcoil, self.tfcoil, self.build, self.shield, diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 9bcc29b344..385adef161 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -35,6 +35,7 @@ class SuperconductingTFTurnType(IntEnum): CABLE_IN_CONDUIT = (1, "CICC", "Cable-in-Conduit Conductor") CROSS_CONDUCTOR = (2, "CroCo", "Cross Conductor") + STEP_STACKED_TAPE = (3, "STEP", "STEP Stacked Tape") def __new__(cls, value: int, abbreviation: str, full_name: str): """Create a new SuperconductingTFTurnType enum member @@ -144,6 +145,24 @@ class TFSuperconductorLimits: """Critical current in the TF turn cables (A).""" +@dataclass(slots=True) +class SuperconTFAreasAndMasses: + """Superconducting TF coil winding pack areas and masses.""" + + m_tf_coil_wp_insulation: float + cplen: float + m_tf_coil_case: float + m_tf_coil_superconductor: float + m_tf_coil_copper: float + m_tf_wp_steel_conduit: float + m_tf_coil_wp_turn_insulation: float + m_tf_coil_conductor: float + m_tf_coil: float + m_tf_coils_total: float + whtcp: float + whttflgs: float + + class SuperconductingTFCoil(TFCoil): """Class for superconducting TF coil model, inheriting from the base TFCoil class. @@ -1529,6 +1548,9 @@ def peak_b_tf_inboard_with_ripple( a[2] = -0.85031e0 a[3] = 0.89808e0 case _: + self.data.superconducting_tfcoil.f_b_tf_inboard_peak_ripple_symmetric = ( + 1.09e0 + ) return 1.09e0 * b_tf_inboard_peak_symmetric # Maximum winding pack width before adjacent packs touch @@ -1985,7 +2007,7 @@ def tf_wp_currents(data: DataStructure): ), ) - def superconducting_tf_coil_areas_and_masses(self): + def superconducting_tf_coil_areas_and_masses(self) -> SuperconTFAreasAndMasses: """Calculate areas and masses of superconducting TF coil components.""" # Mass of case [kg] # *** @@ -1994,7 +2016,7 @@ def superconducting_tf_coil_areas_and_masses(self): # (assumed to be same density/material as turn insulation) d_sc_tf = self.data.superconducting_tfcoil - self.data.tfcoil.m_tf_coil_wp_insulation = ( + m_tf_coil_wp_insulation = ( self.data.tfcoil.len_tf_coil * (d_sc_tf.a_tf_wp_with_insulation - d_sc_tf.a_tf_wp_no_insulation) * self.data.tfcoil.den_tf_wp_turn_insulation @@ -2002,7 +2024,7 @@ def superconducting_tf_coil_areas_and_masses(self): # The length of the vertical section is that of the first (inboard) segment # = height of TF coil inner edge + (2 * coil thickness) - self.data.tfcoil.cplen = (2.0e0 * self.data.build.z_tf_inside_half) + ( + cplen = (2.0e0 * self.data.build.z_tf_inside_half) + ( 2.0e0 * self.data.build.dr_tf_inboard ) @@ -2011,22 +2033,22 @@ def superconducting_tf_coil_areas_and_masses(self): if self.data.physics.itart == 1: # self.data.tfcoil.len_tf_coil does not include inboard leg # ('centrepost') length in TART - self.data.tfcoil.m_tf_coil_case = ( + m_tf_coil_case = ( 2.2e0 * self.data.tfcoil.den_tf_coil_case * ( - self.data.tfcoil.cplen * self.data.tfcoil.a_tf_coil_inboard_case + cplen * self.data.tfcoil.a_tf_coil_inboard_case + self.data.tfcoil.len_tf_coil * self.data.tfcoil.a_tf_coil_outboard_case ) ) else: - self.data.tfcoil.m_tf_coil_case = ( + m_tf_coil_case = ( 2.2e0 * self.data.tfcoil.den_tf_coil_case * ( - self.data.tfcoil.cplen * self.data.tfcoil.a_tf_coil_inboard_case - + (self.data.tfcoil.len_tf_coil - self.data.tfcoil.cplen) + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + (self.data.tfcoil.len_tf_coil - cplen) * self.data.tfcoil.a_tf_coil_outboard_case ) ) @@ -2038,7 +2060,7 @@ def superconducting_tf_coil_areas_and_masses(self): # Superconductor mass [kg] # Includes space allowance for central helium channel, area # self.data.tfcoil.a_tf_wp_coolant_channels - self.data.tfcoil.m_tf_coil_superconductor = ( + m_tf_coil_superconductor = ( self.data.tfcoil.len_tf_coil * self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_cable_space_no_void @@ -2048,7 +2070,7 @@ def superconducting_tf_coil_areas_and_masses(self): ) * self.data.tfcoil.dcond[self.data.tfcoil.i_tf_sc_mat - 1] # Copper mass [kg] - self.data.tfcoil.m_tf_coil_copper = ( + m_tf_coil_copper = ( self.data.tfcoil.len_tf_coil * self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_cable_space_no_void @@ -2056,10 +2078,10 @@ def superconducting_tf_coil_areas_and_masses(self): * self.data.tfcoil.f_a_tf_turn_cable_copper - self.data.tfcoil.len_tf_coil * self.data.tfcoil.a_tf_wp_coolant_channels ) * constants.DEN_COPPER - self.data.tfcoil.m_tf_coil_copper = max(0.0e0, self.data.tfcoil.m_tf_coil_copper) + m_tf_coil_copper = max(0.0e0, m_tf_coil_copper) # Steel conduit (sheath) mass [kg] - self.data.tfcoil.m_tf_wp_steel_conduit = ( + m_tf_wp_steel_conduit = ( self.data.tfcoil.len_tf_coil * self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_steel @@ -2069,44 +2091,52 @@ def superconducting_tf_coil_areas_and_masses(self): # Conduit insulation mass [kg] # (self.data.tfcoil.a_tf_coil_wp_turn_insulation already contains # self.data.tfcoil.n_tf_coil_turns) - self.data.tfcoil.m_tf_coil_wp_turn_insulation = ( + m_tf_coil_wp_turn_insulation = ( self.data.tfcoil.len_tf_coil * self.data.tfcoil.a_tf_coil_wp_turn_insulation * self.data.tfcoil.den_tf_wp_turn_insulation ) # Total conductor mass [kg] - self.data.tfcoil.m_tf_coil_conductor = ( - self.data.tfcoil.m_tf_coil_superconductor - + self.data.tfcoil.m_tf_coil_copper - + self.data.tfcoil.m_tf_wp_steel_conduit - + self.data.tfcoil.m_tf_coil_wp_turn_insulation + m_tf_coil_conductor = ( + m_tf_coil_superconductor + + m_tf_coil_copper + + m_tf_wp_steel_conduit + + m_tf_coil_wp_turn_insulation ) # --------------------------------- # Total TF coil mass [kg] (all coils) - self.data.tfcoil.m_tf_coil = ( - self.data.tfcoil.m_tf_coil_case - + self.data.tfcoil.m_tf_coil_conductor - + self.data.tfcoil.m_tf_coil_wp_insulation - ) + m_tf_coil = m_tf_coil_case + m_tf_coil_conductor + m_tf_coil_wp_insulation # Total TF coil mass [kg] (all coils) - self.data.tfcoil.m_tf_coils_total = ( - self.data.tfcoil.m_tf_coil * self.data.tfcoil.n_tf_coils - ) + m_tf_coils_total = m_tf_coil * self.data.tfcoil.n_tf_coils # If spherical tokamak, distribute between centrepost and outboard legs # (in this case, total TF coil length = inboard `cplen` + # outboard `len_tf_coil`) if self.data.physics.itart == 1: tfleng_sph = self.data.tfcoil.cplen + self.data.tfcoil.len_tf_coil - self.data.tfcoil.whtcp = self.data.tfcoil.m_tf_coils_total * ( - self.data.tfcoil.cplen / tfleng_sph - ) - self.data.tfcoil.whttflgs = self.data.tfcoil.m_tf_coils_total * ( - self.data.tfcoil.len_tf_coil / tfleng_sph - ) + whtcp = m_tf_coils_total * (self.data.tfcoil.cplen / tfleng_sph) + whttflgs = m_tf_coils_total * (self.data.tfcoil.len_tf_coil / tfleng_sph) + else: + whtcp = 0.0 + whttflgs = 0.0 + + return SuperconTFAreasAndMasses( + m_tf_coil_wp_insulation=m_tf_coil_wp_insulation, + cplen=cplen, + m_tf_coil_case=m_tf_coil_case, + m_tf_coil_superconductor=m_tf_coil_superconductor, + m_tf_coil_copper=m_tf_coil_copper, + m_tf_wp_steel_conduit=m_tf_wp_steel_conduit, + m_tf_coil_conductor=m_tf_coil_conductor, + m_tf_coil_wp_turn_insulation=m_tf_coil_wp_turn_insulation, + m_tf_coil=m_tf_coil, + m_tf_coils_total=m_tf_coils_total, + whtcp=whtcp, + whttflgs=whttflgs, + ) def run_and_output_stress(self) -> None: """ @@ -2513,7 +2543,25 @@ def run(self, output: bool = False): # Calculate TF coil areas and masses self.generic_tf_coil_area_and_masses() - self.superconducting_tf_coil_areas_and_masses() + tf_areas_masses = self.tf_cicc_areas_and_masses() + self.data.tfcoil.m_tf_coil_wp_insulation = ( + tf_areas_masses.m_tf_coil_wp_insulation + ) + self.data.tfcoil.cplen = tf_areas_masses.cplen + self.data.tfcoil.m_tf_coil_case = tf_areas_masses.m_tf_coil_case + self.data.tfcoil.m_tf_coil_superconductor = ( + tf_areas_masses.m_tf_coil_superconductor + ) + self.data.tfcoil.m_tf_coil_copper = tf_areas_masses.m_tf_coil_copper + self.data.tfcoil.m_tf_wp_steel_conduit = tf_areas_masses.m_tf_wp_steel_conduit + self.data.tfcoil.m_tf_coil_wp_turn_insulation = ( + tf_areas_masses.m_tf_coil_wp_turn_insulation + ) + self.data.tfcoil.m_tf_coil = tf_areas_masses.m_tf_coil + self.data.tfcoil.m_tf_coil_conductor = tf_areas_masses.m_tf_coil_conductor + self.data.tfcoil.m_tf_coils_total = tf_areas_masses.m_tf_coils_total + self.data.tfcoil.whtcp = tf_areas_masses.whtcp + self.data.tfcoil.whttflgs = tf_areas_masses.whttflgs # Do stress calculations (writes the stress output) if output: @@ -3666,6 +3714,134 @@ def tf_cicc_inboard_areas_and_fractions( f_a_tf_coil_inboard_insulation=f_a_tf_coil_inboard_insulation, ) + def tf_cicc_areas_and_masses(self) -> SuperconTFAreasAndMasses: + """Calculate areas and masses of superconducting TF coil components.""" + # Mass of ground-wall insulation [kg] + # (assumed to be same density/material as turn insulation) + d_sc_tf = self.data.superconducting_tfcoil + + m_tf_coil_wp_insulation = ( + self.data.tfcoil.len_tf_coil + * (d_sc_tf.a_tf_wp_with_insulation - d_sc_tf.a_tf_wp_no_insulation) + * self.data.tfcoil.den_tf_wp_turn_insulation + ) + + # The length of the vertical section is that of the first (inboard) segment + # = height of TF coil inner edge + (2 * coil thickness) + cplen = (2.0e0 * self.data.build.z_tf_inside_half) + ( + 2.0e0 * self.data.build.dr_tf_inboard + ) + + # The 2.2 factor is used as a scaling factor to fit + # to the ITER-FDR value of 450 tonnes; see CCFE note T&M/PKNIGHT/PROCESS/026 + if self.data.physics.itart == 1: + # self.data.tfcoil.len_tf_coil does not include inboard leg + # ('centrepost') length in TART + m_tf_coil_case = ( + 2.2e0 + * self.data.tfcoil.den_tf_coil_case + * ( + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.a_tf_coil_outboard_case + ) + ) + else: + m_tf_coil_case = ( + 2.2e0 + * self.data.tfcoil.den_tf_coil_case + * ( + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + (self.data.tfcoil.len_tf_coil - cplen) + * self.data.tfcoil.a_tf_coil_outboard_case + ) + ) + + # *** + + # Masses of conductor constituents + # --------------------------------- + # Superconductor mass [kg] + # Includes space allowance for central helium channel, area + # self.data.tfcoil.a_tf_wp_coolant_channels + m_tf_coil_superconductor = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * self.data.tfcoil.a_tf_turn_cable_space_no_void + * (1.0e0 - self.data.tfcoil.f_a_tf_turn_cable_space_extra_void) + * (1.0e0 - self.data.tfcoil.f_a_tf_turn_cable_copper) + - self.data.tfcoil.len_tf_coil * self.data.tfcoil.a_tf_wp_coolant_channels + ) * self.data.tfcoil.dcond[self.data.tfcoil.i_tf_sc_mat - 1] + + # Copper mass [kg] + m_tf_coil_copper = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * self.data.tfcoil.a_tf_turn_cable_space_no_void + * (1.0e0 - self.data.tfcoil.f_a_tf_turn_cable_space_extra_void) + * self.data.tfcoil.f_a_tf_turn_cable_copper + - self.data.tfcoil.len_tf_coil * self.data.tfcoil.a_tf_wp_coolant_channels + ) * constants.DEN_COPPER + m_tf_coil_copper = max(0.0e0, m_tf_coil_copper) + + # Steel conduit (sheath) mass [kg] + m_tf_wp_steel_conduit = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * self.data.tfcoil.a_tf_turn_steel + * self.data.fwbs.den_steel + ) + + # Conduit insulation mass [kg] + # (self.data.tfcoil.a_tf_coil_wp_turn_insulation already contains + # self.data.tfcoil.n_tf_coil_turns) + m_tf_coil_wp_turn_insulation = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.a_tf_coil_wp_turn_insulation + * self.data.tfcoil.den_tf_wp_turn_insulation + ) + + # Total conductor mass [kg] + m_tf_coil_conductor = ( + m_tf_coil_superconductor + + m_tf_coil_copper + + m_tf_wp_steel_conduit + + m_tf_coil_wp_turn_insulation + ) + # --------------------------------- + + # Total TF coil mass [kg] (all coils) + m_tf_coil = m_tf_coil_case + m_tf_coil_conductor + m_tf_coil_wp_insulation + + # Total TF coil mass [kg] (all coils) + m_tf_coils_total = m_tf_coil * self.data.tfcoil.n_tf_coils + + # If spherical tokamak, distribute between centrepost and outboard legs + # (in this case, total TF coil length = inboard `cplen` + + # outboard `len_tf_coil`) + if self.data.physics.itart == 1: + tfleng_sph = self.data.tfcoil.cplen + self.data.tfcoil.len_tf_coil + whtcp = m_tf_coils_total * (self.data.tfcoil.cplen / tfleng_sph) + whttflgs = m_tf_coils_total * (self.data.tfcoil.len_tf_coil / tfleng_sph) + else: + whtcp = 0.0 + whttflgs = 0.0 + + return SuperconTFAreasAndMasses( + m_tf_coil_wp_insulation=m_tf_coil_wp_insulation, + cplen=cplen, + m_tf_coil_case=m_tf_coil_case, + m_tf_coil_superconductor=m_tf_coil_superconductor, + m_tf_coil_copper=m_tf_coil_copper, + m_tf_wp_steel_conduit=m_tf_wp_steel_conduit, + m_tf_coil_conductor=m_tf_coil_conductor, + m_tf_coil_wp_turn_insulation=m_tf_coil_wp_turn_insulation, + m_tf_coil=m_tf_coil, + m_tf_coils_total=m_tf_coils_total, + whtcp=whtcp, + whttflgs=whttflgs, + ) + def output_cable_in_conduit_cable_info(self) -> None: """ Outputs the calculated cable in conduit cable space geometry information @@ -4042,7 +4218,25 @@ def run(self, output: bool = False): # Calculate TF coil areas and masses self.generic_tf_coil_area_and_masses() - self.superconducting_tf_coil_areas_and_masses() + tf_areas_masses = self.tf_croco_areas_and_masses() + self.data.tfcoil.m_tf_coil_wp_insulation = ( + tf_areas_masses.m_tf_coil_wp_insulation + ) + self.data.tfcoil.cplen = tf_areas_masses.cplen + self.data.tfcoil.m_tf_coil_case = tf_areas_masses.m_tf_coil_case + self.data.tfcoil.m_tf_coil_superconductor = ( + tf_areas_masses.m_tf_coil_superconductor + ) + self.data.tfcoil.m_tf_coil_copper = tf_areas_masses.m_tf_coil_copper + self.data.tfcoil.m_tf_wp_steel_conduit = tf_areas_masses.m_tf_wp_steel_conduit + self.data.tfcoil.m_tf_coil_wp_turn_insulation = ( + tf_areas_masses.m_tf_coil_wp_turn_insulation + ) + self.data.tfcoil.m_tf_coil_conductor = tf_areas_masses.m_tf_coil_conductor + self.data.tfcoil.m_tf_coil = tf_areas_masses.m_tf_coil + self.data.tfcoil.m_tf_coils_total = tf_areas_masses.m_tf_coils_total + self.data.tfcoil.whtcp = tf_areas_masses.whtcp + self.data.tfcoil.whttflgs = tf_areas_masses.whttflgs # Do stress calculations (writes the stress output) if output: @@ -4660,6 +4854,127 @@ def tf_croco_inboard_areas_and_fractions( f_a_tf_coil_inboard_insulation=f_a_tf_coil_inboard_insulation, ) + def tf_croco_areas_and_masses(self) -> SuperconTFAreasAndMasses: + """Calculate areas and masses of superconducting TF coil components.""" + # Mass of ground-wall insulation [kg] + # (assumed to be same density/material as turn insulation) + d_sc_tf = self.data.superconducting_tfcoil + + m_tf_coil_wp_insulation = ( + self.data.tfcoil.len_tf_coil + * (d_sc_tf.a_tf_wp_with_insulation - d_sc_tf.a_tf_wp_no_insulation) + * self.data.tfcoil.den_tf_wp_turn_insulation + ) + + # The length of the vertical section is that of the first (inboard) segment + # = height of TF coil inner edge + (2 * coil thickness) + cplen = (2.0e0 * self.data.build.z_tf_inside_half) + ( + 2.0e0 * self.data.build.dr_tf_inboard + ) + + # The 2.2 factor is used as a scaling factor to fit + # to the ITER-FDR value of 450 tonnes; see CCFE note T&M/PKNIGHT/PROCESS/026 + if self.data.physics.itart == 1: + # self.data.tfcoil.len_tf_coil does not include inboard leg + # ('centrepost') length in TART + m_tf_coil_case = ( + 2.2e0 + * self.data.tfcoil.den_tf_coil_case + * ( + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.a_tf_coil_outboard_case + ) + ) + else: + m_tf_coil_case = ( + 2.2e0 + * self.data.tfcoil.den_tf_coil_case + * ( + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + (self.data.tfcoil.len_tf_coil - cplen) + * self.data.tfcoil.a_tf_coil_outboard_case + ) + ) + + # Masses of conductor constituents + # --------------------------------- + # Superconductor mass [kg] + m_tf_coil_superconductor = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * d_sc_tf.a_tf_croco_strand_rebco + * N_CROCO_STRANDS_TURN + ) * self.data.tfcoil.dcond[self.data.tfcoil.i_tf_sc_mat - 1] + + # Copper mass [kg] + # Copper around the tape stacks in each strand plus the copper in the tapes + # and the central core of the cable space [kg] + m_tf_coil_copper = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * ( + d_sc_tf.a_tf_croco_strand_copper_total * N_CROCO_STRANDS_TURN + + d_sc_tf.a_tf_croco_strand + ) + ) * constants.DEN_COPPER + + # Steel conduit (sheath) mass [kg] + m_tf_wp_steel_conduit = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * self.data.tfcoil.a_tf_turn_steel + * self.data.fwbs.den_steel + ) + + # Conduit insulation mass [kg] + m_tf_coil_wp_turn_insulation = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.a_tf_coil_wp_turn_insulation + * self.data.tfcoil.den_tf_wp_turn_insulation + ) + + # Total conductor mass [kg] + m_tf_coil_conductor = ( + m_tf_coil_superconductor + + m_tf_coil_copper + + m_tf_wp_steel_conduit + + m_tf_coil_wp_turn_insulation + ) + # --------------------------------- + + # Total TF coil mass [kg] (all coils) + m_tf_coil = m_tf_coil_case + m_tf_coil_conductor + m_tf_coil_wp_insulation + + # Total TF coil mass [kg] (all coils) + m_tf_coils_total = m_tf_coil * self.data.tfcoil.n_tf_coils + + # If spherical tokamak, distribute between centrepost and outboard legs + # (in this case, total TF coil length = inboard `cplen` + + # outboard `len_tf_coil`) + if self.data.physics.itart == 1: + tfleng_sph = self.data.tfcoil.cplen + self.data.tfcoil.len_tf_coil + whtcp = m_tf_coils_total * (self.data.tfcoil.cplen / tfleng_sph) + whttflgs = m_tf_coils_total * (self.data.tfcoil.len_tf_coil / tfleng_sph) + else: + whtcp = 0.0 + whttflgs = 0.0 + + return SuperconTFAreasAndMasses( + m_tf_coil_wp_insulation=m_tf_coil_wp_insulation, + cplen=cplen, + m_tf_coil_case=m_tf_coil_case, + m_tf_coil_superconductor=m_tf_coil_superconductor, + m_tf_coil_copper=m_tf_coil_copper, + m_tf_wp_steel_conduit=m_tf_wp_steel_conduit, + m_tf_coil_conductor=m_tf_coil_conductor, + m_tf_coil_wp_turn_insulation=m_tf_coil_wp_turn_insulation, + m_tf_coil=m_tf_coil, + m_tf_coils_total=m_tf_coils_total, + whtcp=whtcp, + whttflgs=whttflgs, + ) + def croco_voltage(self) -> float: """Calculates CROCO voltage""" d_sc_tf = self.data.superconducting_tfcoil @@ -4855,6 +5170,1217 @@ def output_croco_info(self) -> None: ) +@dataclass(slots=True) +class STEPIntegerTurnGeometry(TFGeneralTurnGeometry): + """Geometry of a STEP integer turn in the superconducting TF coil.""" + + dr_tf_turn_stabiliser: float + dx_tf_turn_stabiliser: float + x_tf_turn_coolant_channel_centre: float + dr_tf_turn_tape_stack: float + dx_tf_turn_tape_stack: float + a_tf_turn_tape_stack: float + a_tf_turn_stabiliser: float + dia_tf_turn_coolant_channel: float + dr_tf_turn_conduit_full: float + dx_tf_turn_conduit_full_toroidal: float + + +class STEPSuperconductingTFCoil(SuperconductingTFCoil): + """STEP Vertically Stacked Tapes Superconducting TF Coil class. + + + Raises + ------ + ProcessValueError + + References + ---------- + [1] E. Nasr, S. C. Wimbush, P. Noonan, P. Harris, R. Gowland, and A. Petrov, + “The magnetic cage,” Philosophical Transactions of the Royal Society + A Mathematical Physical and Engineering Sciences, + vol. 382, no. 2280, Aug. 2024, doi: https://doi.org/10.1098/rsta.2023.0407. + + """ + + def run(self, output: bool = False): + """Run the superconducting TF coil model for a STEP vertically stacked tapes + conductor with HTS tape. + + Parameters + ---------- + output : bool + If True, print the results of the calculations. + + """ + self.run_base_superconducting_tf() + + d_sc_tf = self.data.superconducting_tfcoil + + match TFWPIntegerTurnType(self.data.tfcoil.i_tf_turns_integer): + # Setting the WP turn geometry / areas + case TFWPIntegerTurnType.INTEGER: + integer_turn_geometry: STEPIntegerTurnGeometry = self.tf_step_vertical_tape_integer_turn_geometry( + dr_tf_wp_with_insulation=self.data.tfcoil.dr_tf_wp_with_insulation, + dx_tf_wp_insulation=self.data.tfcoil.dx_tf_wp_insulation, + dx_tf_wp_insertion_gap=self.data.tfcoil.dx_tf_wp_insertion_gap, + n_tf_wp_layers=self.data.tfcoil.n_tf_wp_layers, + dx_tf_wp_toroidal_min=self.data.superconducting_tfcoil.dx_tf_wp_toroidal_min, + n_tf_wp_pancakes=self.data.tfcoil.n_tf_wp_pancakes, + c_tf_coil=self.data.superconducting_tfcoil.c_tf_coil, + dx_tf_turn_insulation=self.data.tfcoil.dx_tf_turn_insulation, + ) + + d_sc_tf.dr_tf_turn = integer_turn_geometry.dr_tf_turn + d_sc_tf.dx_tf_turn = integer_turn_geometry.dx_tf_turn + self.data.tfcoil.c_tf_turn = integer_turn_geometry.c_tf_turn + self.data.tfcoil.n_tf_coil_turns = integer_turn_geometry.n_tf_coil_turns + d_sc_tf.dr_tf_turn_stabiliser = ( + integer_turn_geometry.dr_tf_turn_stabiliser + ) + d_sc_tf.dx_tf_turn_stabiliser = ( + integer_turn_geometry.dx_tf_turn_stabiliser + ) + d_sc_tf.x_tf_turn_coolant_channel_centre = ( + integer_turn_geometry.x_tf_turn_coolant_channel_centre + ) + d_sc_tf.dr_tf_turn_tape_stack = ( + integer_turn_geometry.dr_tf_turn_tape_stack + ) + d_sc_tf.dx_tf_turn_tape_stack = ( + integer_turn_geometry.dx_tf_turn_tape_stack + ) + d_sc_tf.a_tf_turn_tape_stack = integer_turn_geometry.a_tf_turn_tape_stack + self.data.tfcoil.a_tf_turn_insulation = ( + integer_turn_geometry.a_tf_turn_insulation + ) + d_sc_tf.a_tf_turn_stabiliser = integer_turn_geometry.a_tf_turn_stabiliser + + d_sc_tf.dr_tf_hts_tape = ( + self.data.superconducting_tfcoil.dr_tf_turn_tape_stack + ) + self.data.tfcoil.dia_tf_turn_coolant_channel = ( + integer_turn_geometry.dia_tf_turn_coolant_channel + ) + self.data.tfcoil.a_tf_turn_cable_space_no_void = ( + integer_turn_geometry.a_tf_turn_cable_space_no_void + ) + + self.data.tfcoil.a_tf_turn_steel = integer_turn_geometry.a_tf_turn_steel + + self.data.tfcoil.dx_tf_turn_general = ( + integer_turn_geometry.dx_tf_turn_general + ) + + self.data.tfcoil.dx_tf_turn_conduit_full_average = ( + integer_turn_geometry.dx_tf_turn_conduit_full_average + ) + + d_sc_tf.dx_tf_turn_cable_space_average = ( + integer_turn_geometry.dx_tf_turn_cable_space_average + ) + + d_sc_tf.dr_tf_turn_cable_space = ( + integer_turn_geometry.dr_tf_turn_tape_stack + ) + d_sc_tf.dx_tf_turn_cable_space = ( + integer_turn_geometry.dx_tf_turn_tape_stack + ) + d_sc_tf.a_tf_turn_cable_space_effective = ( + integer_turn_geometry.a_tf_turn_tape_stack + ) + + d_sc_tf.dr_tf_turn_conduit_full = ( + integer_turn_geometry.dr_tf_turn_conduit_full + ) + d_sc_tf.dx_tf_turn_conduit_full_toroidal = ( + integer_turn_geometry.dx_tf_turn_conduit_full_toroidal + ) + + self.data.tfcoil.dx_tf_turn_steel = 0.0 + + case TFWPIntegerTurnType.NON_INTEGER: + raise ProcessValueError( + "Non integer turn geometry not implemented for STEP conductor." + ) + + # Cross-sectional area per turn + self.data.tfcoil.a_tf_turn = self.data.tfcoil.c_tf_total / ( + self.data.tfcoil.j_tf_wp + * self.data.tfcoil.n_tf_coils + * self.data.tfcoil.n_tf_coil_turns + ) + + self.data.superconducting_tfcoil.n_tf_turn_superconducting_strands = ( + self.calculate_stacked_tape_strand_count( + dr_tape_stack=self.data.superconducting_tfcoil.dx_tf_turn_tape_stack, + dr_hts_tape=self.data.superconducting_tfcoil.dx_tf_hts_tape_total, + ) + ) + + ( + d_sc_tf.len_tf_coil_superconductor, + d_sc_tf.len_tf_superconductor_total, + ) = self.calculate_tf_step_superconductor_length( + n_tf_coils=self.data.tfcoil.n_tf_coils, + n_tf_coil_turns=self.data.tfcoil.n_tf_coil_turns, + len_tf_coil=self.data.tfcoil.len_tf_coil, + n_tf_turn_superconducting_strands=d_sc_tf.n_tf_turn_superconducting_strands, + ) + + self.data.tfcoil.f_a_tf_turn_cable_space_extra_void = 0.0 + + inboard_areas_fractions = self.tf_step_inboard_areas_and_fractions( + dia_tf_turn_coolant_channel=self.data.tfcoil.dia_tf_turn_coolant_channel, + n_tf_coil_turns=self.data.tfcoil.n_tf_coil_turns, + a_tf_turn_tape_stack=d_sc_tf.a_tf_turn_tape_stack, + a_tf_turn_insulation=self.data.tfcoil.a_tf_turn_insulation, + a_tf_turn_steel=self.data.tfcoil.a_tf_turn_steel, + n_tf_coils=self.data.tfcoil.n_tf_coils, + a_tf_inboard_total=self.data.tfcoil.a_tf_inboard_total, + a_tf_coil_inboard_case=self.data.tfcoil.a_tf_coil_inboard_case, + a_tf_wp_ground_insulation=d_sc_tf.a_tf_wp_ground_insulation, + ) + + self.data.tfcoil.a_tf_wp_coolant_channels = ( + inboard_areas_fractions.a_tf_wp_coolant_channels + ) + self.data.tfcoil.a_tf_wp_conductor = inboard_areas_fractions.a_tf_wp_conductor + self.data.tfcoil.a_tf_wp_extra_void = inboard_areas_fractions.a_tf_wp_extra_void + self.data.tfcoil.a_tf_coil_wp_turn_insulation = ( + inboard_areas_fractions.a_tf_coil_wp_turn_insulation + ) + self.data.tfcoil.a_tf_wp_steel = inboard_areas_fractions.a_tf_wp_steel + d_sc_tf.a_tf_coil_inboard_steel = inboard_areas_fractions.a_tf_coil_inboard_steel + d_sc_tf.f_a_tf_coil_inboard_steel = ( + inboard_areas_fractions.f_a_tf_coil_inboard_steel + ) + d_sc_tf.a_tf_coil_inboard_insulation = ( + inboard_areas_fractions.a_tf_coil_inboard_insulation + ) + d_sc_tf.f_a_tf_coil_inboard_insulation = ( + inboard_areas_fractions.f_a_tf_coil_inboard_insulation + ) + + superconductor_critical_properties = self.tf_step_superconductor_properties( + a_tf_turn=self.data.tfcoil.a_tf_turn, + b_tf_inboard_peak=self.data.tfcoil.b_tf_inboard_peak_with_ripple, + cur_tf_turn=self.data.tfcoil.c_tf_turn, + temp_tf_peak=self.data.tfcoil.tftmp, + i_tf_superconductor=self.data.tfcoil.i_tf_sc_mat, + dr_tf_hts_tape=self.data.superconducting_tfcoil.dr_tf_hts_tape, + dx_tf_hts_tape_rebco=self.data.superconducting_tfcoil.dx_tf_hts_tape_rebco, + dx_tf_hts_tape_total=self.data.superconducting_tfcoil.dx_tf_hts_tape_total, + n_tf_turn_superconducting_strands=self.data.superconducting_tfcoil.n_tf_turn_superconducting_strands, + ) + + self.data.tfcoil.j_tf_wp_critical = ( + superconductor_critical_properties.j_tf_wp_critical + ) + self.data.superconducting_tfcoil.j_tf_superconductor_critical = ( + superconductor_critical_properties.j_superconductor_critical + ) + self.data.superconducting_tfcoil.f_c_tf_turn_operating_critical = ( + superconductor_critical_properties.f_c_tf_turn_operating_critical + ) + self.data.superconducting_tfcoil.j_tf_superconductor = ( + superconductor_critical_properties.j_superconductor + ) + self.data.superconducting_tfcoil.j_tf_coil_turn = ( + superconductor_critical_properties.j_tf_coil_turn + ) + + d_sc_tf.b_tf_superconductor_critical_zero_temp_strain = ( + superconductor_critical_properties.bc20m + ) + d_sc_tf.temp_tf_superconductor_critical_zero_field_strain = ( + superconductor_critical_properties.tc0m + ) + d_sc_tf.c_tf_turn_cables_critical = ( + superconductor_critical_properties.c_turn_cables_critical + ) + + if self.data.tfcoil.i_str_wp == 0: + strain = self.data.tfcoil.str_tf_con_res + else: + strain = self.data.tfcoil.str_wp + + self.data.tfcoil.temp_tf_superconductor_margin = self.calculate_superconductor_temperature_margin( + i_tf_superconductor=self.data.tfcoil.i_tf_sc_mat, + j_superconductor=self.data.superconducting_tfcoil.j_tf_superconductor, + b_tf_inboard_peak=self.data.tfcoil.b_tf_inboard_peak_with_ripple, + strain=strain, + bc20m=self.data.superconducting_tfcoil.b_tf_superconductor_critical_zero_temp_strain, + tc0m=self.data.superconducting_tfcoil.temp_tf_superconductor_critical_zero_field_strain, + c0=1.0e10, + temp_tf_coolant_peak_field=self.data.tfcoil.tftmp, + data=self.data, + ) + + # TFC Quench voltage in kV + + # Negative areas or fractions error reporting + if ( + self.data.tfcoil.a_tf_wp_conductor <= 0.0e0 + or self.data.tfcoil.a_tf_wp_extra_void <= 0.0e0 + or self.data.tfcoil.a_tf_coil_wp_turn_insulation <= 0.0e0 + or self.data.tfcoil.a_tf_wp_steel <= 0.0e0 + or self.data.superconducting_tfcoil.a_tf_coil_inboard_steel <= 0.0e0 + or self.data.superconducting_tfcoil.f_a_tf_coil_inboard_steel <= 0.0e0 + or self.data.superconducting_tfcoil.a_tf_coil_inboard_insulation <= 0.0e0 + or self.data.superconducting_tfcoil.f_a_tf_coil_inboard_insulation <= 0.0e0 + ): + logger.error( + "One of the areas or fractions is negative in the internal SC TF " + "coil geometry " + f"{self.data.tfcoil.a_tf_wp_conductor=} " + f"{self.data.tfcoil.a_tf_wp_extra_void=} " + f"{self.data.tfcoil.a_tf_coil_wp_turn_insulation=} " + f"{self.data.tfcoil.a_tf_wp_steel=} " + f"{self.data.superconducting_tfcoil.a_tf_coil_inboard_steel=} " + f"{self.data.superconducting_tfcoil.f_a_tf_coil_inboard_steel=} " + f"{self.data.superconducting_tfcoil.a_tf_coil_inboard_insulation=} " + f"{self.data.superconducting_tfcoil.f_a_tf_coil_inboard_insulation=}" + ) + + # Calculate TF coil areas and masses + self.generic_tf_coil_area_and_masses() + + tf_areas_masses = self.tf_step_areas_and_masses() + self.data.tfcoil.m_tf_coil_wp_insulation = ( + tf_areas_masses.m_tf_coil_wp_insulation + ) + self.data.tfcoil.cplen = tf_areas_masses.cplen + self.data.tfcoil.m_tf_coil_case = tf_areas_masses.m_tf_coil_case + self.data.tfcoil.m_tf_coil_superconductor = ( + tf_areas_masses.m_tf_coil_superconductor + ) + self.data.tfcoil.m_tf_coil_copper = tf_areas_masses.m_tf_coil_copper + self.data.tfcoil.m_tf_wp_steel_conduit = tf_areas_masses.m_tf_wp_steel_conduit + self.data.tfcoil.m_tf_coil_wp_turn_insulation = ( + tf_areas_masses.m_tf_coil_wp_turn_insulation + ) + self.data.tfcoil.m_tf_coil_conductor = tf_areas_masses.m_tf_coil_conductor + self.data.tfcoil.m_tf_coil = tf_areas_masses.m_tf_coil + self.data.tfcoil.m_tf_coils_total = tf_areas_masses.m_tf_coils_total + self.data.tfcoil.whtcp = tf_areas_masses.whtcp + self.data.tfcoil.whttflgs = tf_areas_masses.whttflgs + # # Do stress calculations (writes the stress output) + # if output: + # self.data.tfcoil.n_rad_per_layer = 500 + + # try: + # ( + # sig_tf_r_max, + # sig_tf_t_max, + # sig_tf_z_max, + # sig_tf_vmises_max, + # s_shear_tf_peak, + # deflect, + # eyoung_axial, + # eyoung_trans, + # eyoung_wp_axial, + # eyoung_wp_trans, + # poisson_wp_trans, + # radial_array, + # s_shear_cea_tf_cond, + # poisson_wp_axial, + # sig_tf_r, + # sig_tf_smeared_r, + # sig_tf_smeared_t, + # sig_tf_smeared_z, + # sig_tf_t, + # s_shear_tf, + # sig_tf_vmises, + # sig_tf_z, + # str_tf_r, + # str_tf_t, + # str_tf_z, + # n_radial_array, + # n_tf_bucking, + # self.data.tfcoil.sig_tf_wp, + # sig_tf_case, + # sig_tf_cs_bucked, + # str_wp, + # casestr, + # insstrain, + # sig_tf_wp_av_z, + # ) = self.stresscl( + # int(self.data.tfcoil.n_tf_stress_layers), + # int(self.data.tfcoil.n_rad_per_layer), + # int(self.data.tfcoil.n_tf_wp_stress_layers), + # int(self.data.tfcoil.i_tf_bucking), + # float(self.data.build.r_tf_inboard_in), + # self.data.build.dr_bore, + # self.data.build.z_tf_inside_half, + # self.data.pf_coil.f_z_cs_tf_internal, + # self.data.build.dr_cs, + # self.data.build.i_tf_inside_cs, + # self.data.build.dr_tf_inboard, + # self.data.build.dr_cs_tf_gap, + # self.data.pf_coil.i_pf_conductor, + # self.data.pf_coil.j_cs_flat_top_end, + # self.data.pf_coil.j_cs_pulse_start, + # self.data.pf_coil.c_pf_coil_turn_peak_input, + # self.data.pf_coil.n_pf_coils_in_group, + # self.data.pf_coil.f_dr_dz_cs_turn, + # self.data.pf_coil.radius_cs_turn_corners, + # self.data.pf_coil.f_a_cs_turn_steel, + # self.data.tfcoil.eyoung_steel, + # self.data.tfcoil.poisson_steel, + # self.data.tfcoil.eyoung_cond_axial, + # self.data.tfcoil.poisson_cond_axial, + # self.data.tfcoil.eyoung_cond_trans, + # self.data.tfcoil.poisson_cond_trans, + # self.data.tfcoil.eyoung_ins, + # self.data.tfcoil.poisson_ins, + # self.data.tfcoil.dx_tf_turn_insulation, + # self.data.tfcoil.eyoung_copper, + # self.data.tfcoil.poisson_copper, + # self.data.tfcoil.i_tf_sup, + # self.data.tfcoil.eyoung_res_tf_buck, + # self.data.superconducting_tfcoil.r_tf_wp_inboard_inner, + # self.data.superconducting_tfcoil.tan_theta_coil, + # self.data.superconducting_tfcoil.rad_tf_coil_inboard_toroidal_half, + # self.data.superconducting_tfcoil.r_tf_wp_inboard_outer, + # self.data.superconducting_tfcoil.a_tf_coil_inboard_steel, + # self.data.superconducting_tfcoil.a_tf_plasma_case, + # self.data.superconducting_tfcoil.a_tf_coil_nose_case, + # self.data.tfcoil.dx_tf_wp_insertion_gap, + # self.data.tfcoil.dx_tf_wp_insulation, + # self.data.tfcoil.n_tf_coil_turns, + # int(self.data.tfcoil.i_tf_turns_integer), + # self.data.superconducting_tfcoil.dx_tf_turn_cable_space_average, + # self.data.superconducting_tfcoil.dr_tf_turn_cable_space, + # self.data.tfcoil.dia_tf_turn_coolant_channel, + # self.data.tfcoil.f_a_tf_turn_cable_copper, + # self.data.tfcoil.dx_tf_turn_steel, + # self.data.superconducting_tfcoil.dx_tf_side_case_average, + # self.data.superconducting_tfcoil.dx_tf_wp_toroidal_average, + # self.data.superconducting_tfcoil.a_tf_coil_inboard_insulation, + # self.data.tfcoil.a_tf_wp_steel, + # self.data.tfcoil.a_tf_wp_conductor, + # self.data.superconducting_tfcoil.a_tf_wp_with_insulation, + # self.data.tfcoil.eyoung_al, + # self.data.tfcoil.poisson_al, + # self.data.tfcoil.fcoolcp, + # self.data.tfcoil.n_tf_graded_layers, + # self.data.tfcoil.c_tf_total, + # self.data.tfcoil.dr_tf_plasma_case, + # self.data.tfcoil.i_tf_stress_model, + # self.data.superconducting_tfcoil.vforce_inboard_tot, + # self.data.tfcoil.i_tf_tresca, + # self.data.tfcoil.a_tf_coil_inboard_case, + # self.data.tfcoil.vforce, + # self.data.tfcoil.a_tf_turn_steel, + # ) + + # self.data.tfcoil.sig_tf_case = ( + # self.data.tfcoil.sig_tf_case + # if self.data.tfcoil.sig_tf_case is None + # else sig_tf_case + # ) + + # self.data.tfcoil.sig_tf_cs_bucked = ( + # self.data.tfcoil.sig_tf_cs_bucked + # if self.data.tfcoil.sig_tf_cs_bucked is None + # else sig_tf_cs_bucked + # ) + + # self.data.tfcoil.str_wp = ( + # self.data.tfcoil.str_wp if self.data.tfcoil.str_wp is None else str_wp + # ) + + # self.data.tfcoil.casestr = ( + # self.data.tfcoil.casestr if self.data.tfcoil.casestr is None else casestr + # ) + + # self.data.tfcoil.insstrain = ( + # self.data.tfcoil.insstrain + # if self.data.tfcoil.insstrain is None + # else insstrain + # ) + # if output: + # self.out_stress( + # sig_tf_r_max, + # sig_tf_t_max, + # sig_tf_z_max, + # sig_tf_vmises_max, + # s_shear_tf_peak, + # deflect, + # eyoung_axial, + # eyoung_trans, + # eyoung_wp_axial, + # eyoung_wp_trans, + # poisson_wp_trans, + # radial_array, + # s_shear_cea_tf_cond, + # poisson_wp_axial, + # sig_tf_r, + # sig_tf_smeared_r, + # sig_tf_smeared_t, + # sig_tf_smeared_z, + # sig_tf_t, + # s_shear_tf, + # sig_tf_vmises, + # sig_tf_z, + # str_tf_r, + # str_tf_t, + # str_tf_z, + # n_radial_array, + # n_tf_bucking, + # sig_tf_wp_av_z, + # ) + # except ValueError as e: + # if e.args[1] == 245 and e.args[2] == 0: + # logger.warning( + # "Invalid stress model (r_tf_inboard = 0), stress constraint " + # "switched off" + # ) + # self.data.tfcoil.sig_tf_case = 0.0e0 + # self.data.tfcoil.sig_tf_wp = 0.0e0 + + self.vv_stress_on_quench() + + if output: + self.output_general_tf_info() + + def output(self) -> None: + """Output the results of the superconducting TF coil model for a STEP vertically + stacked tapes conductor. + """ + self.output_general_tf_info() + self.output_general_superconducting_tf_info() + self.output_step_turn_info() + self.output_tf_superconductor_info() + # self.run_and_output_stress() + + @staticmethod + def tf_step_vertical_tape_integer_turn_geometry( + dr_tf_wp_with_insulation: float, + dx_tf_wp_insulation: float, + dx_tf_wp_insertion_gap: float, + n_tf_wp_layers: int, + dx_tf_wp_toroidal_min: float, + n_tf_wp_pancakes: int, + c_tf_coil: float, + dx_tf_turn_insulation: float, + ) -> STEPIntegerTurnGeometry: + """ + Calculate the integer-turn geometry for TF coil turns using a vertical + stacked tape (HTS-style) conductor. + + Parameters + ---------- + dr_tf_wp_with_insulation: + Radial thickness of the winding pack including insulation [m]. + dx_tf_wp_insulation: + Thickness of winding-pack insulation [m]. + dx_tf_wp_insertion_gap: + Insertion gap thickness inside the winding pack [m]. + n_tf_wp_layers: + Number of radial layers (turn rows). + dx_tf_wp_toroidal_min: + Minimum toroidal thickness of the winding pack [m]. + n_tf_wp_pancakes: + Number of toroidal pancakes per radial layer. + c_tf_coil: + Total TF coil current [A]. + dx_tf_turn_insulation: + Thickness of the turn (intra-turn) insulation [m]. + + Returns + ------- + : + STEPIntegerTurnGeometry + + Notes + ----- + - Assumes rectangular turns and places the coolant channel near the + bottom of the conductor with a small clearance from the tape stack. + - Basic consistency checks are emitted via logger.error() if + calculated dimensions are non-positive or if the coolant channel + conflicts with the conductor geometry. + + References + ---------- + [1] E. Nasr, S. C. Wimbush, P. Noonan, P. Harris, R. Gowland, and A. Petrov, + “The magnetic cage,” Philosophical Transactions of the Royal Society + A Mathematical Physical and Engineering Sciences, + vol. 382, no. 2280, Aug. 2024, doi: https://doi.org/10.1098/rsta.2023.0407. + ‌ + """ + # Radial turn dimension [m] + dr_tf_turn = ( + dr_tf_wp_with_insulation + - 2.0e0 * (dx_tf_wp_insulation + dx_tf_wp_insertion_gap) + ) / n_tf_wp_layers + + if dr_tf_turn <= (2.0e0 * dx_tf_turn_insulation): + logger.error( + "Negative cable space dimension; reduce conduit thicknesses or raise " + "c_tf_turn. " + f"{dr_tf_turn=} {dx_tf_turn_insulation=}" + ) + + # Toroidal turn dimension [m] + dx_tf_turn = ( + dx_tf_wp_toroidal_min + - 2.0e0 * (dx_tf_wp_insulation + dx_tf_wp_insertion_gap) + ) / n_tf_wp_pancakes + + if dx_tf_turn <= (2.0e0 * dx_tf_turn_insulation): + logger.error( + "Negative cable space dimension; reduce conduit thicknesses or raise " + "c_tf_turn. " + f"{dx_tf_turn=} {dx_tf_turn_insulation=}" + ) + + dx_tf_turn_general = dx_tf_turn + + # Number of TF turns + n_tf_coil_turns = np.double(n_tf_wp_layers * n_tf_wp_pancakes) + + # Current per turn [A/turn] + c_tf_turn = c_tf_coil / n_tf_coil_turns + + # Radial and toroidal dimension of conduit/stabiliser region containing tape + # stack and cooling pipe [m] + dr_tf_turn_stabiliser = dr_tf_turn - 2.0e0 * dx_tf_turn_insulation + dx_tf_turn_stabiliser = dx_tf_turn - 2.0e0 * dx_tf_turn_insulation + + dr_tf_turn_conduit_full = dr_tf_turn_stabiliser + dx_tf_turn_conduit_full_toroidal = dx_tf_turn_stabiliser + + dx_tf_turn_conduit_full_average = dx_tf_turn_stabiliser + + dia_tf_turn_coolant_channel = min( + 0.3 * dx_tf_turn_stabiliser, 0.8 * dr_tf_turn_stabiliser + ) + + # Place coolant channel at bottom of turn with a gap equal to 10% of conductor + # height + x_tf_turn_coolant_channel_centre = ( + dx_tf_turn_insulation + + (0.15 * dx_tf_turn_stabiliser) + + (dia_tf_turn_coolant_channel / 2) + ) + + # Check to make sure coolant channel leaves some gap to the tape stack + if x_tf_turn_coolant_channel_centre > (dx_tf_turn_stabiliser / 2) - ( + 0.1 * dx_tf_turn_stabiliser + ) - (dia_tf_turn_coolant_channel / 2): + logger.error( + "Coolant channel too big for turn conductor dimension; reduce coolant " + "channel diameter or increase turn dimensions." + f"{x_tf_turn_coolant_channel_centre=} {dx_tf_turn_stabiliser=}" + ) + + # Width of the tape stack allows for 10% of copper stabiliser on each side + dr_tf_turn_tape_stack = dr_tf_turn_stabiliser * 0.8 + + # Bottom of tape stack starts at the centre of the turn and allows for 10% of + # conductor height above + dx_tf_turn_tape_stack = (dx_tf_turn / 2) - ( + dx_tf_turn_insulation + (0.1 * dx_tf_turn_stabiliser) + ) + + dx_tf_turn_cable_space_average = dx_tf_turn_tape_stack + + # Cross-sectional area of tape stack per turn [m²] + a_tf_turn_tape_stack = dr_tf_turn_tape_stack * dx_tf_turn_tape_stack + + # The tape stack is perfectly packed with no voids + a_tf_turn_cable_space_no_void = a_tf_turn_tape_stack + + # Area of steel conduit per turn [m²] (none in STEP design) + a_tf_turn_steel = 0.0 + + # Area of inter-turn insulation: single turn [m²] + a_tf_turn_insulation = (dr_tf_turn * dx_tf_turn) - ( + dr_tf_turn_stabiliser * dx_tf_turn_stabiliser + ) + + # Area of stabiliser region per turn [m²] + a_tf_turn_stabiliser = ( + dr_tf_turn_stabiliser * dx_tf_turn_stabiliser + - a_tf_turn_tape_stack + - (np.pi / 4.0e0) * dia_tf_turn_coolant_channel * dia_tf_turn_coolant_channel + ) + + return STEPIntegerTurnGeometry( + dr_tf_turn=dr_tf_turn, + dx_tf_turn=dx_tf_turn, + c_tf_turn=c_tf_turn, + n_tf_coil_turns=n_tf_coil_turns, + dr_tf_turn_stabiliser=dr_tf_turn_stabiliser, + dx_tf_turn_stabiliser=dx_tf_turn_stabiliser, + x_tf_turn_coolant_channel_centre=x_tf_turn_coolant_channel_centre, + dr_tf_turn_tape_stack=dr_tf_turn_tape_stack, + dx_tf_turn_tape_stack=dx_tf_turn_tape_stack, + a_tf_turn_tape_stack=a_tf_turn_tape_stack, + a_tf_turn_insulation=a_tf_turn_insulation, + a_tf_turn_stabiliser=a_tf_turn_stabiliser, + dia_tf_turn_coolant_channel=dia_tf_turn_coolant_channel, + a_tf_turn_cable_space_no_void=a_tf_turn_cable_space_no_void, + a_tf_turn_steel=a_tf_turn_steel, + dx_tf_turn_cable_space_average=dx_tf_turn_cable_space_average, + dx_tf_turn_conduit_full_average=dx_tf_turn_conduit_full_average, + dx_tf_turn_general=dx_tf_turn_general, + dr_tf_turn_conduit_full=dr_tf_turn_conduit_full, + dx_tf_turn_conduit_full_toroidal=dx_tf_turn_conduit_full_toroidal, + ) + + @staticmethod + def tf_step_inboard_areas_and_fractions( + dia_tf_turn_coolant_channel: float, + n_tf_coil_turns: int, + a_tf_turn_tape_stack: float, + a_tf_turn_insulation: float, + a_tf_turn_steel: float, + a_tf_coil_inboard_case: float, + n_tf_coils: int, + a_tf_inboard_total: float, + a_tf_wp_ground_insulation: float, + ) -> SuperconTFAreasFractions: + + # Areas and fractions + # ------------------- + # Central helium channel down the conductor core [m2] + a_tf_wp_coolant_channels = ( + 0.25e0 * n_tf_coil_turns * np.pi * dia_tf_turn_coolant_channel**2 + ) + + # Total conductor cross-sectional area, taking account of void area + # and central helium channel [m2] + a_tf_wp_conductor = a_tf_turn_tape_stack * n_tf_coil_turns + + # Void area in conductor for He, not including central channel [m2] + a_tf_wp_extra_void = 0.0 + + # Area of inter-turn insulation: total [m2] + a_tf_coil_wp_turn_insulation = n_tf_coil_turns * a_tf_turn_insulation + + a_tf_turn_steel = 0.0 + + # Area of steel structure in winding pack [m2] + a_tf_wp_steel = n_tf_coil_turns * a_tf_turn_steel + + # Inboard coil steel area [m2] + a_tf_coil_inboard_steel = a_tf_coil_inboard_case + a_tf_wp_steel + + # Inboard coil steel fraction [-] + f_a_tf_coil_inboard_steel = ( + n_tf_coils * a_tf_coil_inboard_steel / a_tf_inboard_total + ) + + # Inboard coil insulation cross-section [m2] + a_tf_coil_inboard_insulation = ( + a_tf_coil_wp_turn_insulation + a_tf_wp_ground_insulation + ) + + # Inboard coil insulation fraction [-] + f_a_tf_coil_inboard_insulation = ( + n_tf_coils * a_tf_coil_inboard_insulation / a_tf_inboard_total + ) + + return SuperconTFAreasFractions( + a_tf_wp_coolant_channels=a_tf_wp_coolant_channels, + a_tf_wp_conductor=a_tf_wp_conductor, + a_tf_wp_extra_void=a_tf_wp_extra_void, + a_tf_coil_wp_turn_insulation=a_tf_coil_wp_turn_insulation, + a_tf_wp_steel=a_tf_wp_steel, + a_tf_coil_inboard_steel=a_tf_coil_inboard_steel, + f_a_tf_coil_inboard_steel=f_a_tf_coil_inboard_steel, + a_tf_coil_inboard_insulation=a_tf_coil_inboard_insulation, + f_a_tf_coil_inboard_insulation=f_a_tf_coil_inboard_insulation, + ) + + def tf_step_superconductor_properties( + self, + a_tf_turn: float, + b_tf_inboard_peak: float, + cur_tf_turn: float, + temp_tf_peak: float, + i_tf_superconductor: int, + dr_tf_hts_tape: float, + dx_tf_hts_tape_rebco: float, + dx_tf_hts_tape_total: float, + n_tf_turn_superconducting_strands: int, + ) -> TFSuperconductorLimits: + """TF superconducting STEP turn using HTS tape + + Parameters + ---------- + a_tf_turn : + Cross-sectional area of the TF turn [m²] + b_tf_inboard_peak : + Peak field at conductor [T] + cur_tf_turn : + Operating current per turn [A] + temp_tf_peak : + Coil temperature at peak field point [K] + i_tf_superconductor : + Integer identifier for the superconductor material model to use. + dr_tf_hts_tape : + Thickness of the HTS tape [m] + dx_tf_hts_tape_rebco : + Width of the REBCO layer in the HTS tape [m] + dx_tf_hts_tape_total : + Total width of the HTS tape [m] + n_tf_turn_superconducting_strands : + Number of HTS tapes stacked in the turn + + Returns + ------- + : + TFSuperconductorLimits + + """ + if SuperconductorModel(i_tf_superconductor).sc_shape != SuperconductorShape.TAPE: + raise ProcessValueError( + "Cannot calculate tape superconductor properties for " + "non-tape superconductors. Change `i_tf_sc_mat` to a tape " + "superconductor or use a different TF coil class for non-tape " + "superconductors." + ) + + if self.data.tfcoil.i_str_wp == 0: + strain = self.data.tfcoil.str_tf_con_res + else: + strain = self.data.tfcoil.str_wp + + match SuperconductorModel(i_tf_superconductor): + # ================================================================= + + case SuperconductorModel.CROCO_REBCO: + b_c20_max = ( + SuperconductorModel.CROCO_REBCO.b_crit_zero_field_strain + ) # [T] + t_c0 = SuperconductorModel.CROCO_REBCO.temp_crit_zero_field_strain # [K] + # Find critical current density in superconducting cable, j_crit_cable + j_superconductor_critical, _, bc20m, tc0m = superconductors.jcrit_rebco( + temp_conductor=temp_tf_peak, + b_conductor=b_tf_inboard_peak, + temp_c0_max=t_c0, + b_c20_max=b_c20_max, + ) + + # ================================================================= + + # Durham Ginzburg-Landau critical surface model for REBCO + case SuperconductorModel.DURHAM_REBCO: + bc20m = SuperconductorModel.DURHAM_REBCO.b_crit_zero_field_strain # [T] + tc0m = ( + SuperconductorModel.DURHAM_REBCO.temp_crit_zero_field_strain + ) # [K] + + # If strain limit achieved, throw a warning and use the lower strain + if abs(strain) > 0.7e-2: + logger.error( + f"TF strain={strain} was outside the region of applicability. " + f"Used lower strain." + ) + strain = np.sign(strain) * 0.7e-2 + + j_superconductor_critical, _, _ = superconductors.gl_rebco( + temp_conductor=temp_tf_peak, + b_conductor=b_tf_inboard_peak, + strain=strain, + b_c20max=bc20m, + t_c0=tc0m, + ) + + # ================================================================= + + # Hazelton experimental data + Zhai conceptual model for REBCO + case SuperconductorModel.HAZELTON_ZHAI_REBCO: + bc20m = ( + SuperconductorModel.HAZELTON_ZHAI_REBCO.b_crit_zero_field_strain + ) # [T] + tc0m = ( + SuperconductorModel.HAZELTON_ZHAI_REBCO.temp_crit_zero_field_strain + ) # [K] + + # If strain limit achieved, throw a warning and use the lower strain + if abs(strain) > 0.7e-2: + logger.error( + f"TF strain={strain} was outside the region of applicability. " + f"Used lower strain." + ) + strain = np.sign(strain) * 0.7e-2 + + # 'high current density' as per parameterisation described in Wolf, + # and based on Hazelton experimental data and Zhai conceptual model; + # see subroutine for full references + j_superconductor_critical, _, _ = superconductors.hijc_rebco( + temp_conductor=temp_tf_peak, + b_conductor=b_tf_inboard_peak, + b_c20max=bc20m, + t_c0=tc0m, + dr_hts_tape=dr_tf_hts_tape, + dx_hts_tape_rebco=dx_tf_hts_tape_rebco, + dx_hts_tape_total=dx_tf_hts_tape_total, + ) + + # ================================================================= + + # ================================================================= + + # Strand critical current calulation for costing in $ / kAm + # Already includes buffer and support layers so no need to include + # f_a_tf_turn_cable_copper here + self.data.tfcoil.j_crit_str_tf = j_superconductor_critical + + # REBCO measurements from 2 T to 14 T, extrapolating outside this + if (b_tf_inboard_peak) >= 14.0: + logger.error( + "Field on superconductor > 14 T (outside of interpolation range)" + ) + + a_tf_strand = dr_tf_hts_tape * dx_tf_hts_tape_total + + cur_tf_turn_strand_critical = ( + j_superconductor_critical * a_tf_strand * n_tf_turn_superconducting_strands + ) + + # Critical current density in winding pack + # a_tf_turn : Area per turn (i.e. entire jacketed conductor with insulation) (m2) + j_tf_wp_critical = cur_tf_turn_strand_critical / a_tf_turn + + # Ratio of operating / critical current + f_c_tf_turn_operating_critical = cur_tf_turn / cur_tf_turn_strand_critical + + # Operating current density + j_tf_coil_turn = cur_tf_turn / a_tf_turn + + # Actual current density in superconductor, + # which should be equal to jcrit(thelium+tmarg) + # when we have found the desired value of tmarg + j_superconductor = f_c_tf_turn_operating_critical * j_superconductor_critical + + # Temperature margin + current_sharing_t = superconductors.current_sharing_rebco( + b_tf_inboard_peak, j_superconductor + ) + tmarg = current_sharing_t - temp_tf_peak + self.data.tfcoil.temp_margin = ( + tmarg # Only used in the availabilty routine - see comment to Issue #526 + ) + + return TFSuperconductorLimits( + j_tf_wp_critical=j_tf_wp_critical, + j_superconductor_critical=j_superconductor_critical, + f_c_tf_turn_operating_critical=f_c_tf_turn_operating_critical, + j_superconductor=j_superconductor, + j_tf_coil_turn=j_tf_coil_turn, + bc20m=bc20m, + tc0m=tc0m, + c_turn_cables_critical=cur_tf_turn_strand_critical, + ) + + @staticmethod + def calculate_stacked_tape_strand_count( + dr_tape_stack: float, + dr_hts_tape: float, + ) -> int: + """ + Calculate how many HTS tapes can be placed in a vertical stacked tape conductor. + The function returns the maximum whole number of tapes that fit within the + available radial tape stack width by taking the floor of the ratio + dr_tape_stack / dr_hts_tape. + + Parameters + ---------- + dr_tape_stack : float + Available radial width for the tape stack (m). Must be >= 0. + dr_hts_tape : float + Width of a single HTS tape (m). Must be > 0. + + Returns + ------- + int + Maximum number of tapes that fit. + + Raises + ------ + ValueError + If dr_hts_tape <= 0 or dr_tape_stack < 0. + """ + if dr_hts_tape <= 0: + raise ValueError("dr_hts_tape must be greater than 0") + if dr_tape_stack < 0: + raise ValueError("dr_tape_stack must be non-negative") + + # Use floor to get the maximum whole number of tapes that fit + return int(np.floor(dr_tape_stack / dr_hts_tape)) + + def tf_step_areas_and_masses(self) -> SuperconTFAreasAndMasses: + """Calculate areas and masses of superconducting TF coil components.""" + # Mass of ground-wall insulation [kg] + # (assumed to be same density/material as turn insulation) + d_sc_tf = self.data.superconducting_tfcoil + + m_tf_coil_wp_insulation = ( + self.data.tfcoil.len_tf_coil + * (d_sc_tf.a_tf_wp_with_insulation - d_sc_tf.a_tf_wp_no_insulation) + * self.data.tfcoil.den_tf_wp_turn_insulation + ) + + # The length of the vertical section is that of the first (inboard) segment + # = height of TF coil inner edge + (2 * coil thickness) + cplen = (2.0e0 * self.data.build.z_tf_inside_half) + ( + 2.0e0 * self.data.build.dr_tf_inboard + ) + + # The 2.2 factor is used as a scaling factor to fit + # to the ITER-FDR value of 450 tonnes; see CCFE note T&M/PKNIGHT/PROCESS/026 + if self.data.physics.itart == 1: + # self.data.tfcoil.len_tf_coil does not include inboard leg + # ('centrepost') length in TART + m_tf_coil_case = ( + 2.2e0 + * self.data.tfcoil.den_tf_coil_case + * ( + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.a_tf_coil_outboard_case + ) + ) + else: + m_tf_coil_case = ( + 2.2e0 + * self.data.tfcoil.den_tf_coil_case + * ( + cplen * self.data.tfcoil.a_tf_coil_inboard_case + + (self.data.tfcoil.len_tf_coil - cplen) + * self.data.tfcoil.a_tf_coil_outboard_case + ) + ) + + # Masses of conductor constituents + # --------------------------------- + # Superconductor mass [kg] + m_tf_coil_superconductor = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * d_sc_tf.dx_tf_hts_tape_rebco + * d_sc_tf.dr_tf_hts_tape + * d_sc_tf.n_tf_turn_superconducting_strands + ) * self.data.tfcoil.dcond[self.data.tfcoil.i_tf_sc_mat - 1] + + # Copper mass [kg] + # Copper around the tape stacks and the surrounding stabiliser [kg] + m_tf_coil_copper = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.n_tf_coil_turns + * ( + d_sc_tf.a_tf_turn_stabiliser + + ( + d_sc_tf.dx_tf_hts_tape_copper + * d_sc_tf.dr_tf_hts_tape + * d_sc_tf.n_tf_turn_superconducting_strands + ) + ) + ) * constants.DEN_COPPER + + # Steel conduit (sheath) mass [kg] + # No steel conduit in the STEP design it is all copper stabiliser + m_tf_wp_steel_conduit = 0.0 + + # Conduit insulation mass [kg] + m_tf_coil_wp_turn_insulation = ( + self.data.tfcoil.len_tf_coil + * self.data.tfcoil.a_tf_coil_wp_turn_insulation + * self.data.tfcoil.den_tf_wp_turn_insulation + ) + + # Total conductor mass [kg] + m_tf_coil_conductor = ( + m_tf_coil_superconductor + + m_tf_coil_copper + + m_tf_wp_steel_conduit + + m_tf_coil_wp_turn_insulation + ) + # --------------------------------- + + # Total TF coil mass [kg] (all coils) + m_tf_coil = m_tf_coil_case + m_tf_coil_conductor + m_tf_coil_wp_insulation + + # Total TF coil mass [kg] (all coils) + m_tf_coils_total = m_tf_coil * self.data.tfcoil.n_tf_coils + + # If spherical tokamak, distribute between centrepost and outboard legs + # (in this case, total TF coil length = inboard `cplen` + + # outboard `len_tf_coil`) + if self.data.physics.itart == 1: + tfleng_sph = self.data.tfcoil.cplen + self.data.tfcoil.len_tf_coil + whtcp = m_tf_coils_total * (self.data.tfcoil.cplen / tfleng_sph) + whttflgs = m_tf_coils_total * (self.data.tfcoil.len_tf_coil / tfleng_sph) + else: + whtcp = 0.0 + whttflgs = 0.0 + + return SuperconTFAreasAndMasses( + m_tf_coil_wp_insulation=m_tf_coil_wp_insulation, + cplen=cplen, + m_tf_coil_case=m_tf_coil_case, + m_tf_coil_superconductor=m_tf_coil_superconductor, + m_tf_coil_copper=m_tf_coil_copper, + m_tf_wp_steel_conduit=m_tf_wp_steel_conduit, + m_tf_coil_conductor=m_tf_coil_conductor, + m_tf_coil_wp_turn_insulation=m_tf_coil_wp_turn_insulation, + m_tf_coil=m_tf_coil, + m_tf_coils_total=m_tf_coils_total, + whtcp=whtcp, + whttflgs=whttflgs, + ) + + @staticmethod + def calculate_tf_step_superconductor_length( + n_tf_coils: int, + n_tf_coil_turns: int, + len_tf_coil: float, + n_tf_turn_superconducting_strands: int, + ) -> float: + """Calculates the total length of superconducting material required for the + TF coils. + + Parameters + ---------- + n_tf_coils: int : + n_tf_coils: Number of TF coils. + n_tf_coil_turns: int : + n_tf_coil_turns: Total number of turns in the TF coil winding pack. + len_tf_coil: + len_tf_coil: Length of a single TF coil (in meters). + n_tf_turn_superconducting_strands: int : + n_tf_turn_superconducting_strands: Number of superconducting tapes/strands + per turn in the TF coil. + + Returns + ------- + tuple[float, float] + Tuple containing: + - Length of superconductor in one TF coil (in meters). + - Total length of superconductor in all TF coils (in meters). + """ + # Length of superconductor in one TF coil + len_tf_coil_superconductor = ( + n_tf_coil_turns * len_tf_coil * n_tf_turn_superconducting_strands + ) + + # Total length of superconductor in all TF coils + len_tf_superconductor_total = len_tf_coil_superconductor * n_tf_coils + + return len_tf_coil_superconductor, len_tf_superconductor_total + + def output_step_turn_info(self) -> None: + """Output the STEP conductor geometry and properties.""" + po.oheadr(self.outfile, "TF STEP Cable Space Information") + + po.ovarre( + self.outfile, + "Thickness of REBCO layer in tape (m)", + "(dx_tf_hts_tape_rebco)", + self.data.superconducting_tfcoil.dx_tf_hts_tape_rebco, + ) + po.ovarre( + self.outfile, + "Thickness of copper layer in tape (m)", + "(dx_tf_hts_tape_copper)", + self.data.superconducting_tfcoil.dx_tf_hts_tape_copper, + ) + po.ovarre( + self.outfile, + "Thickness of Hastelloy layer in tape (m) ", + "(dx_tf_hts_tape_hastelloy)", + self.data.superconducting_tfcoil.dx_tf_hts_tape_hastelloy, + ) + po.ovarre( + self.outfile, + "Thickness of each HTS tape ", + "(dx_tf_hts_tape_total)", + self.data.superconducting_tfcoil.dx_tf_hts_tape_total, + "OP ", + ) + po.ovarre( + self.outfile, + "Mean width of tape (m)", + "(dr_tf_hts_tape)", + self.data.superconducting_tfcoil.dr_tf_hts_tape, + "OP ", + ) + po.oblnkl(self.outfile) + + po.ovarre( + self.outfile, + "Diameter of central helium channel in cable", + "(dia_tf_turn_coolant_channel)", + self.data.tfcoil.dia_tf_turn_coolant_channel, + ) + po.ovarre( + self.outfile, + "Number of superconducting strands per turn", + "(n_tf_turn_superconducting_strands)", + self.data.superconducting_tfcoil.n_tf_turn_superconducting_strands, + ) + po.ovarre( + self.outfile, + "Length of superconductor in TF coil (m)", + "(len_tf_coil_superconductor)", + self.data.superconducting_tfcoil.len_tf_coil_superconductor, + ) + po.ovarre( + self.outfile, + "Total length of superconductor in all TF coils (m)", + "(len_tf_superconductor_total)", + self.data.superconducting_tfcoil.len_tf_superconductor_total, + ) + po.ovarre( + self.outfile, + "Radial width of tape stack in TF turn (m)", + "(dr_tf_turn_tape_stack)", + self.data.superconducting_tfcoil.dr_tf_turn_tape_stack, + ) + po.ovarre( + self.outfile, + "Vertical width of tape stack in TF turn (m)", + "(dx_tf_turn_tape_stack)", + self.data.superconducting_tfcoil.dx_tf_turn_tape_stack, + ) + po.ovarre( + self.outfile, + "Area of tape stack in TF turn (m)", + "(a_tf_turn_tape_stack)", + self.data.superconducting_tfcoil.a_tf_turn_tape_stack, + ) + po.ovarre( + self.outfile, + "Vertical position of coolant channel centre in TF turn (m)", + "(x_tf_turn_coolant_channel_centre)", + self.data.superconducting_tfcoil.x_tf_turn_coolant_channel_centre, + ) + po.ovarre( + self.outfile, + "Radial width of stabiliser in TF turn (m)", + "(dr_tf_turn_stabiliser)", + self.data.superconducting_tfcoil.dr_tf_turn_stabiliser, + ) + po.ovarre( + self.outfile, + "Toroidal width of stabiliser in TF turn (m)", + "(dx_tf_turn_stabiliser)", + self.data.superconducting_tfcoil.dx_tf_turn_stabiliser, + ) + po.ovarre( + self.outfile, + "Area of stabiliser in TF turn (m)", + "(a_tf_turn_stabiliser)", + self.data.superconducting_tfcoil.a_tf_turn_stabiliser, + ) + + @staticmethod def lambda_term(tau: float, omega: float) -> float: """The lambda function used inegral in inductance calcuation found