From faf50ea3046cd618e1f04b7ed8e2e55497b111d4 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 10:44:26 +0100 Subject: [PATCH 01/19] Restrict TF coil turn calculations to cable superconductors only --- process/models/tfcoil/superconducting.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index a36fff7c1c..2baf89d0cd 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -17,6 +17,7 @@ N_CROCO_STRANDS_TURN, SuperconductorMaterial, SuperconductorModel, + SuperconductorShape, calculate_croco_cable_geometry, ) from process.models.tfcoil import quench @@ -2775,6 +2776,17 @@ def tf_cable_in_conduit_superconductor_properties( (i.e., the copper in the superconducting strands and any additional copper, such as REBCO tape support). """ + if ( + SuperconductorModel(i_tf_superconductor).sc_shape + != SuperconductorShape.CABLE + ): + raise ProcessValueError( + "Cannot calculate cable in conduit superconductor properties for " + "non-cable superconductors. Change `i_tf_sc_mat` to a cable " + "superconductor or use a different TF coil class for non-cable " + "superconductors." + ) + # Guard against negative conductor fraction f_a_tf_turn_cable_space_conductor # Kludge to allow solver to continue and hopefully be constrained away # from this point @@ -2969,14 +2981,6 @@ def tf_cable_in_conduit_superconductor_properties( # ================================================================= - # "REBCO" 2nd generation HTS superconductor in CrCo strand - elif i_tf_superconductor == SuperconductorModel.CROCO_REBCO: - raise ProcessValueError( - "sctfcoil.supercon has been called but data.tfcoil.i_tf_sc_mat=6" - ) - - # ================================================================= - # Durham Ginzburg-Landau Nb-Ti parameterisation elif i_tf_superconductor == SuperconductorModel.DURHAM_NBTI: bc20m = data.tfcoil.b_crit_upper_nbti # [T] From 98dede91d78dcbe840e55711daf052275dea97c0 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 11:19:54 +0100 Subject: [PATCH 02/19] Initialize conductor parameters in SuperconductingTFData with default values --- .../superconducting_tf_coil_variables.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/process/data_structure/superconducting_tf_coil_variables.py b/process/data_structure/superconducting_tf_coil_variables.py index 9603342fbb..e3e40ce716 100644 --- a/process/data_structure/superconducting_tf_coil_variables.py +++ b/process/data_structure/superconducting_tf_coil_variables.py @@ -254,22 +254,22 @@ class SuperconductingTFData: # conductor - a_tf_turn_croco_cable_space_copper: float = None - conductor_copper_fraction: float = None - a_tf_turn_croco_copper_bar: float = None + a_tf_turn_croco_cable_space_copper: float = 0.0 + conductor_copper_fraction: float = 0.0 + a_tf_turn_croco_copper_bar: float = 0.0 """Area of the central copper strand in the CroCo TF turn [m²]""" - a_tf_turn_croco_hastelloy: float = None - conductor_hastelloy_fraction: float = None - conductor_helium_area: float = None - conductor_helium_fraction: float = None - conductor_solder_area: float = None - conductor_solder_fraction: float = None - conductor_jacket_area: float = None - conductor_jacket_fraction: float = None - conductor_rebco_area: float = None - conductor_rebco_fraction: float = None - conductor_critical_current: float = None - conductor_area: float = None + a_tf_turn_croco_hastelloy: float = 0.0 + conductor_hastelloy_fraction: float = 0.0 + conductor_helium_area: float = 0.0 + conductor_helium_fraction: float = 0.0 + conductor_solder_area: float = 0.0 + conductor_solder_fraction: float = 0.0 + conductor_jacket_area: float = 0.0 + conductor_jacket_fraction: float = 0.0 + conductor_rebco_area: float = 0.0 + conductor_rebco_fraction: float = 0.0 + conductor_critical_current: float = 0.0 + conductor_area: float = 0.0 """Area of cable space inside jacket""" t1: float = 0.0 From 4ef27f2301f3eee50c1c5b050db9202be2d8867a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 11:33:29 +0100 Subject: [PATCH 03/19] Refactor CROCOSuperconductingTFCoil to streamline superconductor property calculations and remove deprecated models --- process/models/tfcoil/superconducting.py | 320 +++++++++++++---------- 1 file changed, 185 insertions(+), 135 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 2baf89d0cd..142a5400cd 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -3009,86 +3009,6 @@ def tf_cable_in_conduit_superconductor_properties( # ================================================================= - # Durham Ginzburg-Landau critical surface model for REBCO - elif i_tf_superconductor == SuperconductorModel.DURHAM_REBCO: - bc20m = 430 # [T] - tc0m = 185 # [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_coolant_peak_field, - b_conductor=b_tf_inboard_peak, - strain=strain, - b_c20max=bc20m, - t_c0=tc0m, - ) - # Scale for the copper area fraction of the cable - j_cables_critical = j_superconductor_critical * ( - 1.0e0 - f_a_tf_turn_cable_copper - ) - - # Critical current in turn all turn cables - c_turn_cables_critical = j_cables_critical * a_tf_turn_cable_space_effective - - # 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 - 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)" - ) - - # ================================================================= - - # Hazelton experimental data + Zhai conceptual model for REBCO - elif i_tf_superconductor == SuperconductorModel.HAZELTON_ZHAI_REBCO: - bc20m = 138 # [T] - tc0m = 92 # [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_coolant_peak_field, - b_conductor=b_tf_inboard_peak, - b_c20max=bc20m, - t_c0=tc0m, - dr_hts_tape=data.superconducting_tfcoil.dr_tf_hts_tape, - dx_hts_tape_rebco=data.superconducting_tfcoil.dx_tf_hts_tape_rebco, - dx_hts_tape_total=data.superconducting_tfcoil.dx_tf_hts_tape_total, - ) - # Scale for the copper area fraction of the cable - j_cables_critical = j_superconductor_critical * ( - 1.0e0 - f_a_tf_turn_cable_copper - ) - - # Critical current in turn all turn cables - c_turn_cables_critical = j_cables_critical * a_tf_turn_cable_space_effective - - # Strand critical current calulation for costing in $ / kAm - # = superconducting filaments jc * (1 -strand copper fraction) - data.tfcoil.j_crit_str_tf = j_superconductor_critical * ( - 1.0e0 - f_a_tf_turn_cable_copper - ) - else: raise ProcessValueError( "Illegal value for i_tf_sc_mat", i_tf_superconductor=i_tf_superconductor @@ -3976,44 +3896,43 @@ def run(self, output: bool = False): * self.data.tfcoil.n_tf_coil_turns ) - if ( - SuperconductorModel(self.data.tfcoil.i_tf_sc_mat) - == SuperconductorModel.CROCO_REBCO - ): - superconductor_critical_properties = self.tf_croco_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, - ) + superconductor_critical_properties: TFSuperconductorLimits = self.tf_croco_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, + a_tf_turn_cable_space_effective=self.data.superconducting_tfcoil.a_tf_turn_cable_space_effective, + 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, + ) - self.data.tfcoil.j_tf_wp_critical = ( - superconductor_critical_properties.j_tf_wp_critical - ) - d_sc_tf.j_tf_superconductor_critical = ( - superconductor_critical_properties.j_superconductor_critical - ) - d_sc_tf.f_c_tf_turn_operating_critical = ( - superconductor_critical_properties.f_c_tf_turn_operating_critical - ) - d_sc_tf.j_tf_superconductor = ( - superconductor_critical_properties.j_superconductor - ) - d_sc_tf.j_tf_coil_turn = superconductor_critical_properties.j_tf_coil_turn + 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 - ) + self.data.superconducting_tfcoil.b_tf_superconductor_critical_zero_temp_strain = superconductor_critical_properties.bc20m + self.data.superconducting_tfcoil.temp_tf_superconductor_critical_zero_field_strain = superconductor_critical_properties.tc0m + self.data.superconducting_tfcoil.c_tf_turn_cables_critical = ( + superconductor_critical_properties.c_turn_cables_critical + ) - self.data.tfcoil.v_tf_coil_dump_quench_kv = ( - self.croco_voltage() / 1.0e3 - ) # TFC Quench voltage in kV + self.data.tfcoil.v_tf_coil_dump_quench_kv = ( + self.croco_voltage() / 1.0e3 + ) # TFC Quench voltage in kV # Negative areas or fractions error reporting if ( @@ -4383,33 +4302,160 @@ def tf_croco_superconductor_properties( b_tf_inboard_peak: float, cur_tf_turn: float, temp_tf_peak: float, + a_tf_turn_cable_space_effective: float, + i_tf_superconductor: int, + dr_tf_hts_tape: float, + dx_tf_hts_tape_rebco: float, + dx_tf_hts_tape_total: float, ) -> TFSuperconductorLimits: """TF superconducting CroCo conductor using REBCO 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 : - He temperature at peak field point (K) + Coil temperature at peak field point (K) + a_tf_turn_cable_space_effective : + Effective cross-sectional area of the TF turn cable space (m²) + 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) + + Returns + ------- + TFSuperconductorLimits + A dataclass containing the calculated superconducting properties of the TF coil, including: + - j_tf_wp_critical: Critical current density in the TF winding pack (A/m²). + - j_superconductor_critical: Critical current density in the superconductor (A/m²). + - f_c_tf_turn_operating_critical: Ratio of operating current to critical current for the TF turn (dimensionless). + - j_tf_superconductor: Current density in the superconductor at operating conditions (A/m²). + - j_tf_coil_turn: Current density in the TF coil turn at operating conditions (A/m²). + - bc20m: Critical magnetic field at 20 K and zero strain (T). + - tc0m: Critical temperature at zero magnetic field and zero strain (K). + - c_turn_cables_critical: Critical current in the TF turn cables (A). """ - # Find critical current density in superconducting cable, j_crit_cable - j_crit_sc, _, bc20m, tc0m = superconductors.jcrit_rebco( - temp_conductor=temp_tf_peak, b_conductor=b_tf_inboard_peak - ) + 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." + ) - d_sc_tf = self.data.superconducting_tfcoil + if self.data.tfcoil.i_str_wp == 0: + strain = self.data.tfcoil.str_tf_con_res + else: + strain = self.data.tfcoil.str_wp + + f_a_tf_turn_tape_superconductor = dx_tf_hts_tape_rebco / dx_tf_hts_tape_total + + # ================================================================= + + if i_tf_superconductor == SuperconductorModel.CROCO_REBCO: + # 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 + ) + + # ================================================================= + + # Durham Ginzburg-Landau critical surface model for REBCO + elif i_tf_superconductor == SuperconductorModel.DURHAM_REBCO: + bc20m = 430 # [T] + tc0m = 185 # [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, + ) + # Scale for the copper area fraction of the cable + j_tape_critical = j_superconductor_critical * f_a_tf_turn_tape_superconductor + + # Critical current in turn all turn cables + c_turn_cables_critical = j_tape_critical * a_tf_turn_cable_space_effective + + # 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)" + ) - d_sc_tf.cur_tf_turn_croco_strand_critical = j_crit_sc * d_sc_tf.a_tf_croco_strand + # ================================================================= + + # Hazelton experimental data + Zhai conceptual model for REBCO + elif i_tf_superconductor == SuperconductorModel.HAZELTON_ZHAI_REBCO: + bc20m = 138 # [T] + tc0m = 92 # [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, + ) + # Scale for the copper area fraction of the cable + j_tape_critical = j_superconductor_critical * f_a_tf_turn_tape_superconductor + + # Critical current in turn all turn cables + c_turn_cables_critical = j_tape_critical * a_tf_turn_cable_space_effective + + # Strand critical current calulation for costing in $ / kAm + # = superconducting filaments jc * (1 -strand copper fraction) + self.data.tfcoil.j_crit_str_tf = ( + j_superconductor_critical * f_a_tf_turn_tape_superconductor + ) + + # ================================================================= + + cur_tf_turn_croco_strand_critical = ( + j_superconductor_critical + * self.data.superconducting_tfcoil.a_tf_croco_strand + ) # Conductor properties - d_sc_tf.conductor_critical_current = ( - d_sc_tf.cur_tf_turn_croco_strand_critical * N_CROCO_STRANDS_TURN + self.data.superconducting_tfcoil.conductor_critical_current = ( + cur_tf_turn_croco_strand_critical * N_CROCO_STRANDS_TURN ) d_sc_tf.tf_coppera_m2 = cur_tf_turn / d_sc_tf.a_tf_turn_croco_cable_space_copper @@ -4419,18 +4465,22 @@ def tf_croco_superconductor_properties( # 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_critical / a_tf_turn + # Ratio of operating / critical current - iooic = cur_tf_turn / cur_critical + f_c_tf_turn_operating_critical = cur_tf_turn / cur_critical + # Operating current density - jwdgop = cur_tf_turn / a_tf_turn + 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 - jsc = iooic * j_crit_sc + j_superconductor = f_c_tf_turn_operating_critical * j_superconductor_critical # Temperature margin - current_sharing_t = superconductors.current_sharing_rebco(b_tf_inboard_peak, jsc) + 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 @@ -4438,13 +4488,13 @@ def tf_croco_superconductor_properties( return TFSuperconductorLimits( j_tf_wp_critical=j_tf_wp_critical, - j_superconductor_critical=j_crit_sc, - f_c_tf_turn_operating_critical=iooic, - j_superconductor=jsc, - j_tf_coil_turn=jwdgop, + 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=d_sc_tf.cur_tf_turn_croco_strand_critical, + c_turn_cables_critical=cur_tf_turn_croco_strand_critical, ) @staticmethod From eaeb36e6cf04cc6ba054c6dcd2e513a8098c7e6b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 12:03:20 +0100 Subject: [PATCH 04/19] Refactor CROCOSuperconductingTFCoil to optimize critical current calculations and improve code clarity --- process/models/tfcoil/superconducting.py | 42 +++++++++--------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 142a5400cd..5b337f52c4 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -4390,22 +4390,6 @@ def tf_croco_superconductor_properties( b_c20max=bc20m, t_c0=tc0m, ) - # Scale for the copper area fraction of the cable - j_tape_critical = j_superconductor_critical * f_a_tf_turn_tape_superconductor - - # Critical current in turn all turn cables - c_turn_cables_critical = j_tape_critical * a_tf_turn_cable_space_effective - - # 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)" - ) # ================================================================= @@ -4434,19 +4418,25 @@ def tf_croco_superconductor_properties( dx_hts_tape_rebco=dx_tf_hts_tape_rebco, dx_hts_tape_total=dx_tf_hts_tape_total, ) - # Scale for the copper area fraction of the cable - j_tape_critical = j_superconductor_critical * f_a_tf_turn_tape_superconductor - # Critical current in turn all turn cables - c_turn_cables_critical = j_tape_critical * a_tf_turn_cable_space_effective + # ================================================================= - # Strand critical current calulation for costing in $ / kAm - # = superconducting filaments jc * (1 -strand copper fraction) - self.data.tfcoil.j_crit_str_tf = ( - j_superconductor_critical * f_a_tf_turn_tape_superconductor - ) + # Scale for the copper area fraction of the cable + j_tape_critical = j_superconductor_critical * f_a_tf_turn_tape_superconductor - # ================================================================= + # Critical current in turn all turn cables + c_turn_cables_critical = j_tape_critical * a_tf_turn_cable_space_effective + + # 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)" + ) cur_tf_turn_croco_strand_critical = ( j_superconductor_critical From e68f8b290499281155852c8c541f61b8cd3b218b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 13:42:41 +0100 Subject: [PATCH 05/19] Enhance TF coil plots by adding critical current density and field information --- process/core/io/plot/summary.py | 4 ++++ process/models/superconductors.py | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 536c671b65..8d64d0c538 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -7519,6 +7519,8 @@ def _pack_strands_rectangular_with_obstacles( 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" @@ -7797,6 +7799,8 @@ def plot_tf_croco_turn(axis: plt.Axes, fig, mfile: MFile, scan: int): 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" diff --git a/process/models/superconductors.py b/process/models/superconductors.py index 2db882efad..fed746e3bc 100644 --- a/process/models/superconductors.py +++ b/process/models/superconductors.py @@ -814,34 +814,34 @@ def hijc_rebco( # finding A(T); constants based on a Newton polynomial fit to pubished data a_t = a_0 + (u * temp_conductor**2) + (v * temp_conductor) - # Critical current density (A/m2) + # Critical current # In the original formula bcrit must be > bmax to prevent NaNs. # However, negative jcrit is permissible (I think). # So when bcrit < bmax, I reverse the sign of the bracket, # giving a negative but real value of jcrit. if b_critical > b_conductor: - j_critical = ( + cur_critical = ( (a_t / b_conductor) * b_critical**b * (b_conductor / b_critical) ** p * (1 - b_conductor / b_critical) ** q ) else: - j_critical = ( + cur_critical = ( (a_t / b_conductor) * b_critical**b * (b_conductor / b_critical) ** p * (b_conductor / b_critical - 1) ** q ) - # Jc times HTS area: default area is width 4mm times HTS layer thickness 1 um, + # Critical current times HTS area: default area is width 4mm times HTS layer thickness 1 um, # divided by the tape area to provide engineering Jc per tape,! # A scaling factor of 0.4 used to be applied below to assume the difference # between tape stacks and CORC cable layouts. j_critical = ( - j_critical + cur_critical * (dr_hts_tape * dx_hts_tape_rebco) / (dr_hts_tape * dx_hts_tape_total) ) From df8fe19c261f6ed5d74b39585d5c999276b0fccf Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 14:03:23 +0100 Subject: [PATCH 06/19] Add output for peak inboard toroidal field with ripple in SuperconductingTFCoil --- process/models/tfcoil/superconducting.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 5b337f52c4..1fdb5a4ae2 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -865,6 +865,13 @@ def output_tf_superconductor_info(self): "(tftmp)", self.data.tfcoil.tftmp, ) + po.ovarre( + self.outfile, + "Peak inboard toroidal field including ripple (T)", + "(b_tf_inboard_peak_with_ripple)", + self.data.tfcoil.b_tf_inboard_peak_with_ripple, + ) + po.oblnkl(self.outfile) po.ovarre( self.outfile, "Total cooling area fraction inside cable space", From da2dba4155b1bb545f89e06b855e4acc0a396c6a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 16:04:10 +0100 Subject: [PATCH 07/19] Add copper area calculations and update related attributes in CROCOSuperconductingTFCoil --- .../superconducting_tf_coil_variables.py | 11 +++- process/models/tfcoil/superconducting.py | 65 +++++++++---------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/process/data_structure/superconducting_tf_coil_variables.py b/process/data_structure/superconducting_tf_coil_variables.py index e3e40ce716..4a23f8e78b 100644 --- a/process/data_structure/superconducting_tf_coil_variables.py +++ b/process/data_structure/superconducting_tf_coil_variables.py @@ -255,9 +255,18 @@ class SuperconductingTFData: # conductor a_tf_turn_croco_cable_space_copper: float = 0.0 - conductor_copper_fraction: float = 0.0 + """Area of the copper in the CroCo cable space of the TF turn (includes tapes, + outer tube and central copper) (m²)""" + + a_tf_turn_copper_total: float = 0.0 + """Area of all copper in the TF turn (m²)""" + + f_a_tf_turn_copper: float = 0.0 + """Fraction of the TF turn area that is copper (m²)""" + a_tf_turn_croco_copper_bar: float = 0.0 """Area of the central copper strand in the CroCo TF turn [m²]""" + a_tf_turn_croco_hastelloy: float = 0.0 conductor_hastelloy_fraction: float = 0.0 conductor_helium_area: float = 0.0 diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 1fdb5a4ae2..b591a646d4 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -3864,8 +3864,25 @@ def run(self, output: bool = False): d_sc_tf.a_tf_croco_strand_copper_total * N_CROCO_STRANDS_TURN + d_sc_tf.a_tf_turn_croco_copper_bar ) - d_sc_tf.conductor_copper_fraction = ( - d_sc_tf.a_tf_turn_croco_cable_space_copper / d_sc_tf.conductor_area + + self.data.superconducting_tfcoil.a_tf_turn_copper_total = ( + self.data.superconducting_tfcoil.a_tf_turn_croco_cable_space_copper + ) + + self.data.superconducting_tfcoil.f_a_tf_turn_copper = ( + self.data.superconducting_tfcoil.a_tf_turn_croco_cable_space_copper + / self.data.tfcoil.a_tf_turn + ) + + self.data.superconducting_tfcoil.f_a_tf_turn_cable_space_cooling = ( + self.data.tfcoil.a_tf_turn_cable_space_no_void + - ( + ( + N_CROCO_STRANDS_TURN + * self.data.superconducting_tfcoil.a_tf_croco_strand + ) + - self.data.superconducting_tfcoil.a_tf_turn_croco_copper_bar + ) ) # Helium area is set by the user. @@ -3913,6 +3930,7 @@ def run(self, output: bool = False): 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, + a_tf_croco_strand=self.data.superconducting_tfcoil.a_tf_croco_strand, ) self.data.tfcoil.j_tf_wp_critical = ( @@ -4314,6 +4332,7 @@ def tf_croco_superconductor_properties( dr_tf_hts_tape: float, dx_tf_hts_tape_rebco: float, dx_tf_hts_tape_total: float, + a_tf_croco_strand: float, ) -> TFSuperconductorLimits: """TF superconducting CroCo conductor using REBCO tape @@ -4445,10 +4464,7 @@ def tf_croco_superconductor_properties( "Field on superconductor > 14 T (outside of interpolation range)" ) - cur_tf_turn_croco_strand_critical = ( - j_superconductor_critical - * self.data.superconducting_tfcoil.a_tf_croco_strand - ) + cur_tf_turn_croco_strand_critical = j_superconductor_critical * a_tf_croco_strand # Conductor properties self.data.superconducting_tfcoil.conductor_critical_current = ( @@ -4684,27 +4700,6 @@ def output_croco_info(self) -> None: d_sc_tf.a_tf_croco_strand_solder, "OP ", ) - po.ovarre( - self.outfile, - "Total: area of CroCo strand (m²) ", - "(a_tf_croco_strand)", - d_sc_tf.a_tf_croco_strand, - "OP ", - ) - if ( - abs( - d_sc_tf.a_tf_croco_strand - - ( - d_sc_tf.a_tf_croco_strand_rebco - + d_sc_tf.a_tf_croco_strand_copper_total - + d_sc_tf.a_tf_croco_strand_hastelloy - + d_sc_tf.a_tf_croco_strand_solder - ) - ) - > 1e-6 - ): - po.ocmmnt(self.outfile, "ERROR: Areas in CroCo strand do not add up") - logger.error("Areas in CroCo strand do not add up - see OUT.DAT") po.oblnkl(self.outfile) po.ocmmnt(self.outfile, "Cable information") @@ -4737,8 +4732,8 @@ def output_croco_info(self) -> None: po.ovarre( self.outfile, "Area of conductor (m²)", - "(area)", - d_sc_tf.conductor_area, + "(conductor_area)", + self.data.superconducting_tfcoil.conductor_area, "OP ", ) po.ovarre( @@ -4751,22 +4746,22 @@ def output_croco_info(self) -> None: po.ovarre( self.outfile, "Area of central copper bar (m²)", - "(copper_bar_area)", - d_sc_tf.a_tf_turn_croco_copper_bar, + "(a_tf_turn_croco_copper_bar)", + self.data.superconducting_tfcoil.a_tf_turn_croco_copper_bar, "OP ", ) po.ovarre( self.outfile, "Total copper area of conductor, total (m²)", - "(a_tf_croco_strand_copper_total)", - d_sc_tf.a_tf_turn_croco_cable_space_copper, + "(a_tf_turn_croco_cable_space_copper)", + self.data.superconducting_tfcoil.a_tf_turn_croco_cable_space_copper, "OP ", ) po.ovarre( self.outfile, "Hastelloy area of conductor (m²)", - "(a_tf_croco_strand_hastelloy)", - d_sc_tf.a_tf_turn_croco_hastelloy, + "(a_tf_turn_croco_hastelloy)", + self.data.superconducting_tfcoil.a_tf_turn_croco_hastelloy, "OP ", ) po.ovarre( From 9930d5054a061f217213268a4d1f27f14d2d2b29 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 16:15:25 +0100 Subject: [PATCH 08/19] Refactor CROCOSuperconductingTFCoil to remove unused helium area calculations and add fraction of superconducting material area --- .../superconducting_tf_coil_variables.py | 10 ++++----- process/models/tfcoil/superconducting.py | 21 ++++--------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/process/data_structure/superconducting_tf_coil_variables.py b/process/data_structure/superconducting_tf_coil_variables.py index 4a23f8e78b..db11bbfe77 100644 --- a/process/data_structure/superconducting_tf_coil_variables.py +++ b/process/data_structure/superconducting_tf_coil_variables.py @@ -246,14 +246,9 @@ class SuperconductingTFData: a_tf_croco_strand: float = 0.0 """Total area of a CroCo strand (m²)""" - # croco_strand - - tf_croco_strand_area: float = 0.0 cur_tf_turn_croco_strand_critical: float = 0.0 """Critical current in the TF turn CroCo strand (A)""" - # conductor - a_tf_turn_croco_cable_space_copper: float = 0.0 """Area of the copper in the CroCo cable space of the TF turn (includes tapes, outer tube and central copper) (m²)""" @@ -267,7 +262,12 @@ class SuperconductingTFData: a_tf_turn_croco_copper_bar: float = 0.0 """Area of the central copper strand in the CroCo TF turn [m²]""" + f_a_tf_turn_superconductor: float = 0.0 + """Fraction of the TF turn area that is superconducting material [m²]""" + 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²)""" + conductor_hastelloy_fraction: float = 0.0 conductor_helium_area: float = 0.0 conductor_helium_fraction: float = 0.0 diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index b591a646d4..986bcf1867 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -3883,14 +3883,7 @@ def run(self, output: bool = False): ) - self.data.superconducting_tfcoil.a_tf_turn_croco_copper_bar ) - ) - - # Helium area is set by the user. - # conductor_helium_area = cable_helium_fraction * self.data.tfcoil.a_tf_turn_cable_space_no_void # noqa: E501 - d_sc_tf.conductor_helium_area = np.pi / 2.0 * d_sc_tf.dia_tf_turn_croco_cable**2 - d_sc_tf.conductor_helium_fraction = ( - d_sc_tf.conductor_helium_area / d_sc_tf.conductor_area - ) + ) / self.data.tfcoil.a_tf_turn_cable_space_no_void d_sc_tf.a_tf_turn_croco_hastelloy = ( d_sc_tf.a_tf_croco_strand_hastelloy * N_CROCO_STRANDS_TURN @@ -3909,8 +3902,9 @@ def run(self, output: bool = False): d_sc_tf.conductor_rebco_area = ( d_sc_tf.a_tf_croco_strand_rebco * N_CROCO_STRANDS_TURN ) - d_sc_tf.conductor_rebco_fraction = ( - d_sc_tf.conductor_rebco_area / d_sc_tf.conductor_area + self.data.superconducting_tfcoil.f_a_tf_turn_superconductor = ( + self.data.superconducting_tfcoil.conductor_rebco_area + / self.data.superconducting_tfcoil.conductor_area ) # Cross-sectional area per turn @@ -4778,13 +4772,6 @@ def output_croco_info(self) -> None: d_sc_tf.conductor_jacket_area, "OP ", ) - po.ovarre( - self.outfile, - "Helium area of conductor (m²)", - "(helium_area)", - d_sc_tf.conductor_helium_area, - "OP ", - ) po.ovarre( self.outfile, From 750a0d2195c04d34d51f39d2070cb93b367af87c Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 16:36:42 +0100 Subject: [PATCH 09/19] Refactor CROCOSuperconductingTFCoil to update conductor area calculations and remove unused void area logic --- process/models/tfcoil/superconducting.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 986bcf1867..4291c9afc6 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -3751,15 +3751,6 @@ def run(self, output: bool = False): # No central channel in CroCo conductor, self.data.tfcoil.a_tf_wp_coolant_channels = 0.0 - # Total conductor cross-sectional area, taking account of void area - # and central helium channel [m²] - self.data.tfcoil.a_tf_wp_conductor = ( - self.data.tfcoil.a_tf_turn_cable_space_no_void - * self.data.tfcoil.n_tf_coil_turns - * (1.0e0 - self.data.tfcoil.f_a_tf_turn_cable_space_extra_void) - - self.data.tfcoil.a_tf_wp_coolant_channels - ) - # Void area in conductor for He, not including central channel [m²] self.data.tfcoil.a_tf_wp_extra_void = ( self.data.tfcoil.a_tf_turn_cable_space_no_void @@ -3865,6 +3856,12 @@ def run(self, output: bool = False): + d_sc_tf.a_tf_turn_croco_copper_bar ) + # Total conductor cross-sectional area, taking account of void area + # and central helium channel [m²] + self.data.tfcoil.a_tf_wp_conductor = ( + N_CROCO_STRANDS_TURN * self.data.superconducting_tfcoil.a_tf_croco_strand + ) * self.data.tfcoil.n_tf_coil_turns + self.data.superconducting_tfcoil.a_tf_turn_copper_total = ( self.data.superconducting_tfcoil.a_tf_turn_croco_cable_space_copper ) From b21a1344453ff60bf6374348d0954b4fab1b1d87 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 16:46:28 +0100 Subject: [PATCH 10/19] Refactor TF coil variables to rename conductor width to conduit full average and update related calculations --- process/core/io/obsolete_vars.py | 2 +- process/data_structure/tfcoil_variables.py | 4 +- process/models/tfcoil/superconducting.py | 138 ++++++++++++++------- tests/unit/models/tfcoil/test_sctfcoil.py | 20 +-- 4 files changed, 106 insertions(+), 58 deletions(-) diff --git a/process/core/io/obsolete_vars.py b/process/core/io/obsolete_vars.py index 82aa8ed33f..dd0a276d99 100644 --- a/process/core/io/obsolete_vars.py +++ b/process/core/io/obsolete_vars.py @@ -49,7 +49,7 @@ "thkwp": "dr_tf_wp_with_insulation", "leni": "dx_tf_turn_cable_space_average", "leno": "t_turn", - "conductor_width": "t_conductor", + "conductor_width": "dx_tf_turn_conduit_full_average", "deltf": "dr_tf_shld_gap", "ddwi": "dr_vv_outboard", "pnuccp": "pnuc_cp", diff --git a/process/data_structure/tfcoil_variables.py b/process/data_structure/tfcoil_variables.py index c01a16cbb1..dc7e6f7f92 100644 --- a/process/data_structure/tfcoil_variables.py +++ b/process/data_structure/tfcoil_variables.py @@ -95,8 +95,8 @@ class TFData: tfc_sidewall_is_fraction: bool = False """logical switch to make dx_tf_side_case_min a fraction of TF coil thickness (`casths_fraction`)""" - t_conductor: float = 0.0 - """Conductor (cable + steel conduit) area averaged dimension [m]""" + dx_tf_turn_conduit_full_average: float = 0.0 + """Average full width of the conduit surrounding the TF turn cable space [m]""" dx_tf_turn_general: float = 0.0 """TF coil turn edge length including turn insulation [m] diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 4291c9afc6..8004e378de 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -585,14 +585,14 @@ def output_general_superconducting_tf_info(self) -> None: ) po.ovarre( self.outfile, - "Width of conductor (square) (m)", - "(t_conductor)", - self.data.tfcoil.t_conductor, + "Width of conduit surrounding cable space (square) (m)", + "(dx_tf_turn_conduit_full_average)", + self.data.tfcoil.dx_tf_turn_conduit_full_average, "OP ", ) po.ovarre( self.outfile, - "Width of space inside conductor (m)", + "Width of cable space inside conduit (m)", "(dx_tf_turn_cable_space_average)", d_sc_tf.dx_tf_turn_cable_space_average, "OP ", @@ -2186,7 +2186,7 @@ class CICCAveragedTurnGeometry: dx_tf_turn_general: float dr_tf_turn: float dx_tf_turn: float - t_conductor: float + dx_tf_turn_conduit_full_average: float radius_tf_turn_cable_space_corners: float dx_tf_turn_cable_space_average: float a_tf_turn_cable_space_effective: float @@ -2207,7 +2207,7 @@ class CICCIntegerTurnGeometry: n_tf_coil_turns: int t_conductor_radial: float t_conductor_toroidal: float - t_conductor: float + dx_tf_turn_conduit_full_average: float dr_tf_turn_cable_space: float dx_tf_turn_cable_space: float dx_tf_turn_cable_space_average: float @@ -2257,10 +2257,12 @@ def run(self, output: bool = False): self.data.tfcoil.dx_tf_turn_general = avg_turn_geometry.dx_tf_turn_general self.data.tfcoil.c_tf_turn = avg_turn_geometry.c_tf_turn self.data.tfcoil.dx_tf_turn_general = avg_turn_geometry.dx_tf_turn_general - d_sc_tf.dr_tf_turn = avg_turn_geometry.dr_tf_turn - d_sc_tf.dx_tf_turn = avg_turn_geometry.dx_tf_turn - self.data.tfcoil.t_conductor = avg_turn_geometry.t_conductor - d_sc_tf.radius_tf_turn_cable_space_corners = ( + self.data.superconducting_tfcoil.dr_tf_turn = avg_turn_geometry.dr_tf_turn + self.data.superconducting_tfcoil.dx_tf_turn = avg_turn_geometry.dx_tf_turn + self.data.tfcoil.dx_tf_turn_conduit_full_average = ( + avg_turn_geometry.dx_tf_turn_conduit_full_average + ) + self.data.superconducting_tfcoil.radius_tf_turn_cable_space_corners = ( avg_turn_geometry.radius_tf_turn_cable_space_corners ) d_sc_tf.dx_tf_turn_cable_space_average = ( @@ -2302,12 +2304,22 @@ def run(self, output: bool = False): ) self.data.tfcoil.c_tf_turn = int_turn_geometry.c_tf_turn self.data.tfcoil.n_tf_coil_turns = int_turn_geometry.n_tf_coil_turns - d_sc_tf.t_conductor_radial = int_turn_geometry.t_conductor_radial - d_sc_tf.t_conductor_toroidal = int_turn_geometry.t_conductor_toroidal - self.data.tfcoil.t_conductor = int_turn_geometry.t_conductor - d_sc_tf.dr_tf_turn_cable_space = int_turn_geometry.dr_tf_turn_cable_space - d_sc_tf.dx_tf_turn_cable_space = int_turn_geometry.dx_tf_turn_cable_space - d_sc_tf.dx_tf_turn_cable_space_average = ( + self.data.superconducting_tfcoil.t_conductor_radial = ( + int_turn_geometry.t_conductor_radial + ) + self.data.superconducting_tfcoil.t_conductor_toroidal = ( + int_turn_geometry.t_conductor_toroidal + ) + self.data.tfcoil.dx_tf_turn_conduit_full_average = ( + int_turn_geometry.dx_tf_turn_conduit_full_average + ) + self.data.superconducting_tfcoil.dr_tf_turn_cable_space = ( + int_turn_geometry.dr_tf_turn_cable_space + ) + self.data.superconducting_tfcoil.dx_tf_turn_cable_space = ( + int_turn_geometry.dx_tf_turn_cable_space + ) + self.data.superconducting_tfcoil.dx_tf_turn_cable_space_average = ( int_turn_geometry.dx_tf_turn_cable_space_average ) @@ -3243,7 +3255,7 @@ def tf_cable_in_conduit_averaged_turn_geometry( # See derivation in the following document # k:\power plant physics and technology\process\hts\hts coil module # for process.docx - t_conductor = ( + dx_tf_turn_conduit_full_average = ( -layer_ins + np.sqrt(layer_ins**2 + 4.0e00 * a_tf_turn) ) / 2 - 2.0e0 * dx_tf_turn_insulation @@ -3251,13 +3263,15 @@ def tf_cable_in_conduit_averaged_turn_geometry( n_tf_coil_turns = a_tf_wp_no_insulation / a_tf_turn # Area of inter-turn insulation: single turn [m2] - a_tf_turn_insulation = a_tf_turn - t_conductor**2 + a_tf_turn_insulation = a_tf_turn - dx_tf_turn_conduit_full_average**2 # Radius of rounded corners of cable space inside conduit [m] radius_tf_turn_cable_space_corners = dx_tf_turn_steel * 0.75e0 # Dimension of square cable space inside conduit [m] - dx_tf_turn_cable_space_average = t_conductor - 2.0e0 * dx_tf_turn_steel + dx_tf_turn_cable_space_average = ( + dx_tf_turn_conduit_full_average - 2.0e0 * dx_tf_turn_steel + ) # Cross-sectional area of cable space per turn # taking account of rounded inside corners [m2] @@ -3283,7 +3297,7 @@ def tf_cable_in_conduit_averaged_turn_geometry( ) if a_tf_turn_cable_space_no_void <= 0.0e0: - if t_conductor < 0.0e0: + if dx_tf_turn_conduit_full_average < 0.0e0: logger.error( "Negative cable space dimension. %s %s", a_tf_turn_cable_space_no_void, @@ -3300,7 +3314,9 @@ def tf_cable_in_conduit_averaged_turn_geometry( a_tf_turn_cable_space_no_void = dx_tf_turn_cable_space_average**2 # Cross-sectional area of conduit jacket per turn [m2] - a_tf_turn_steel = t_conductor**2 - a_tf_turn_cable_space_no_void + a_tf_turn_steel = ( + dx_tf_turn_conduit_full_average**2 - a_tf_turn_cable_space_no_void + ) return CICCAveragedTurnGeometry( a_tf_turn_cable_space_no_void=a_tf_turn_cable_space_no_void, @@ -3311,7 +3327,7 @@ def tf_cable_in_conduit_averaged_turn_geometry( dx_tf_turn_general=dx_tf_turn_general, dr_tf_turn=dr_tf_turn, dx_tf_turn=dx_tf_turn, - t_conductor=t_conductor, + dx_tf_turn_conduit_full_average=dx_tf_turn_conduit_full_average, radius_tf_turn_cable_space_corners=radius_tf_turn_cable_space_corners, dx_tf_turn_cable_space_average=dx_tf_turn_cable_space_average, a_tf_turn_cable_space_effective=a_tf_turn_cable_space_effective, @@ -3404,7 +3420,9 @@ def tf_cable_in_conduit_integer_turn_geometry( # Radial and toroidal dimension of conductor [m] t_conductor_radial = dr_tf_turn - 2.0e0 * dx_tf_turn_insulation t_conductor_toroidal = dx_tf_turn - 2.0e0 * dx_tf_turn_insulation - t_conductor = np.sqrt(t_conductor_radial * t_conductor_toroidal) + dx_tf_turn_conduit_full_average = np.sqrt( + t_conductor_radial * t_conductor_toroidal + ) # Dimension of square cable space inside conduit [m] dr_tf_turn_cable_space = t_conductor_radial - 2.0e0 * dx_tf_turn_steel @@ -3480,7 +3498,7 @@ def tf_cable_in_conduit_integer_turn_geometry( n_tf_coil_turns=n_tf_coil_turns, t_conductor_radial=t_conductor_radial, t_conductor_toroidal=t_conductor_toroidal, - t_conductor=t_conductor, + dx_tf_turn_conduit_full_average=dx_tf_turn_conduit_full_average, dr_tf_turn_cable_space=dr_tf_turn_cable_space, dx_tf_turn_cable_space=dx_tf_turn_cable_space, dx_tf_turn_cable_space_average=dx_tf_turn_cable_space_average, @@ -3675,7 +3693,7 @@ class CROCOAveragedTurnGeometry: dx_tf_turn_general: float dr_tf_turn: float dx_tf_turn: float - t_conductor: float + dx_tf_turn_conduit_full_average: float dx_tf_turn_cable_space_average: float @@ -3733,10 +3751,12 @@ def run(self, output: bool = False): self.data.tfcoil.dx_tf_turn_general = avg_turn_geometry.dx_tf_turn_general self.data.tfcoil.c_tf_turn = avg_turn_geometry.c_tf_turn self.data.tfcoil.dx_tf_turn_general = avg_turn_geometry.dx_tf_turn_general - d_sc_tf.dr_tf_turn = avg_turn_geometry.dr_tf_turn - d_sc_tf.dx_tf_turn = avg_turn_geometry.dx_tf_turn - self.data.tfcoil.t_conductor = avg_turn_geometry.t_conductor - d_sc_tf.dx_tf_turn_cable_space_average = ( + self.data.superconducting_tfcoil.dr_tf_turn = avg_turn_geometry.dr_tf_turn + self.data.superconducting_tfcoil.dx_tf_turn = avg_turn_geometry.dx_tf_turn + self.data.tfcoil.dx_tf_turn_conduit_full_average = ( + avg_turn_geometry.dx_tf_turn_conduit_full_average + ) + self.data.superconducting_tfcoil.dx_tf_turn_cable_space_average = ( avg_turn_geometry.dx_tf_turn_cable_space_average ) @@ -3793,8 +3813,8 @@ def run(self, output: bool = False): / self.data.tfcoil.a_tf_inboard_total ) - croco_cable_space_geometry = self.tf_turn_croco_cable_space_properties( - t_conductor=self.data.tfcoil.t_conductor, + croco_cable_space_geometry: CroCoCableSpaceGeometry = self.tf_turn_croco_cable_space_properties( + dx_tf_turn_conduit_full_average=self.data.tfcoil.dx_tf_turn_conduit_full_average, dx_tf_turn_steel=self.data.tfcoil.dx_tf_turn_steel, ) @@ -4283,7 +4303,7 @@ def tf_croco_averaged_turn_geometry( dr_tf_turn = dx_tf_turn_general dx_tf_turn = dx_tf_turn_general - t_conductor = ( + dx_tf_turn_conduit_full_average = ( -layer_ins + np.sqrt(layer_ins**2 + 4.0e00 * a_tf_turn) ) / 2 - 2.0e0 * dx_tf_turn_insulation @@ -4291,13 +4311,21 @@ def tf_croco_averaged_turn_geometry( n_tf_coil_turns = a_tf_wp_no_insulation / a_tf_turn # Area of inter-turn insulation: single turn [m²] - a_tf_turn_insulation = a_tf_turn - t_conductor**2 + a_tf_turn_insulation = a_tf_turn - dx_tf_turn_conduit_full_average**2 + + a_tf_turn_cable_space_no_void = copy.copy( + self.data.tfcoil.a_tf_turn_cable_space_no_void + ) # Diameter of circular cable space inside conduit [m] - dx_tf_turn_cable_space_average = t_conductor - 2.0e0 * dx_tf_turn_steel + dx_tf_turn_cable_space_average = ( + dx_tf_turn_conduit_full_average - 2.0e0 * dx_tf_turn_steel + ) # Cross-sectional area of conduit jacket per turn [m²] - a_tf_turn_steel = t_conductor**2 - self.data.tfcoil.a_tf_turn_cable_space_no_void + a_tf_turn_steel = ( + dx_tf_turn_conduit_full_average**2 - a_tf_turn_cable_space_no_void + ) return CROCOAveragedTurnGeometry( a_tf_turn_cable_space_no_void=self.data.tfcoil.a_tf_turn_cable_space_no_void, @@ -4308,7 +4336,7 @@ def tf_croco_averaged_turn_geometry( dx_tf_turn_general=dx_tf_turn_general, dr_tf_turn=dr_tf_turn, dx_tf_turn=dx_tf_turn, - t_conductor=t_conductor, + dx_tf_turn_conduit_full_average=dx_tf_turn_conduit_full_average, dx_tf_turn_cable_space_average=dx_tf_turn_cable_space_average, ) @@ -4503,25 +4531,43 @@ def tf_croco_superconductor_properties( @staticmethod def tf_turn_croco_cable_space_properties( - t_conductor: float, dx_tf_turn_steel: float + dx_tf_turn_conduit_full_average: float, dx_tf_turn_steel: float ) -> CroCoCableSpaceGeometry: """Calculate the properties of the cable space in the TF turn for a CroCo conductor. Parameters ---------- - t_conductor : float + dx_tf_turn_conduit_full_average : float Thickness of the conductor in the TF turn (in meters). dx_tf_turn_steel : float Thickness of the steel layer in the TF turn (in meters). Returns ------- - : - CroCo cable space geometry + + CroCoCableSpaceGeometry + A dataclass containing the calculated properties of the cable space in + the TF turn, including: + - dia_tf_turn_croco_cable: Diameter of the circular cable space in the TF + turn (in meters). + - a_tf_turn_cable_space_no_void: Area of the cable space in the TF turn + without voids (in square meters). + - a_tf_turn_cable_space_effective: Effective area of the cable space in + the TF turn after accounting for cooling channels and voids + (in square meters). + - a_tf_turn_steel: Area of the steel in the TF turn (in square meters). + - conductor_area: Total area of the conductor in the TF turn + (in square meters). + - conductor_jacket_area: Area of the conductor jacket in the TF turn + (in square meters). + - conductor_jacket_fraction: Fraction of the conductor area that is the + jacket (dimensionless). + + """ - dia_tf_turn_croco_cable = t_conductor / 3.0e0 - dx_tf_turn_steel * ( - 2.0e0 / 3.0e0 + dia_tf_turn_croco_cable = ( + dx_tf_turn_conduit_full_average / 3.0e0 - dx_tf_turn_steel * (2.0e0 / 3.0e0) ) # Area of the full cable circle in the turn @@ -4534,7 +4580,9 @@ def tf_turn_croco_cable_space_properties( a_tf_turn_cable_space_no_void - 0.25e0 * np.pi * dia_tf_turn_croco_cable**2 ) - conductor_area = t_conductor**2 # does this not assume it's a sqaure??? + conductor_area = ( + dx_tf_turn_conduit_full_average**2 + ) # does this not assume it's a sqaure??? conductor_jacket_area = conductor_area - a_tf_turn_cable_space_no_void a_tf_turn_steel = conductor_jacket_area @@ -4716,8 +4764,8 @@ def output_croco_info(self) -> None: po.ovarre( self.outfile, "Width of square conductor (cable + steel jacket) (m)", - "(t_conductor)", - self.data.tfcoil.t_conductor, + "(dx_tf_turn_conduit_full_average)", + self.data.tfcoil.dx_tf_turn_conduit_full_average, "OP ", ) po.ovarre( diff --git a/tests/unit/models/tfcoil/test_sctfcoil.py b/tests/unit/models/tfcoil/test_sctfcoil.py index 015caeaa2d..48845d6209 100644 --- a/tests/unit/models/tfcoil/test_sctfcoil.py +++ b/tests/unit/models/tfcoil/test_sctfcoil.py @@ -984,7 +984,7 @@ class TfIntegerTurnGeomParam(NamedTuple): dx_tf_wp_insertion_gap: Any = None - t_conductor: Any = None + dx_tf_turn_conduit_full_average: Any = None dx_tf_turn_general: Any = None @@ -1050,7 +1050,7 @@ class TfIntegerTurnGeomParam(NamedTuple): dr_tf_wp_with_insulation=0.54261087836601019, dx_tf_wp_insulation=0.0080000000000000019, dx_tf_wp_insertion_gap=0.01, - t_conductor=0, + dx_tf_turn_conduit_full_average=0, dx_tf_turn_general=0, c_tf_coil=14805350.287500001, dx_tf_wp_toroidal_min=1.299782604942499, @@ -1084,7 +1084,7 @@ class TfIntegerTurnGeomParam(NamedTuple): dr_tf_wp_with_insulation=0.54261087836601019, dx_tf_wp_insulation=0.0080000000000000019, dx_tf_wp_insertion_gap=0.01, - t_conductor=0.052553108427885735, + dx_tf_turn_conduit_full_average=0.052553108427885735, dx_tf_turn_general=0.056579413904423038, c_tf_coil=14805350.287500001, dx_tf_wp_toroidal_min=1.299782604942499, @@ -1149,7 +1149,7 @@ def test_tf_cable_in_conduit_integer_turn_geometry( 0.75 * tfintegerturngeomparam.dx_tf_turn_steel ) - assert integer_turn_geometry.t_conductor == pytest.approx( + assert integer_turn_geometry.dx_tf_turn_conduit_full_average == pytest.approx( tfintegerturngeomparam.expected_t_conductor ) @@ -1209,7 +1209,7 @@ def test_tf_cable_in_conduit_integer_turn_geometry( class TfAveragedTurnGeomParam(NamedTuple): layer_ins: Any = None - t_conductor: Any = None + dx_tf_turn_conduit_full_average: Any = None dx_tf_turn_general: Any = None @@ -1259,7 +1259,7 @@ class TfAveragedTurnGeomParam(NamedTuple): [ TfAveragedTurnGeomParam( layer_ins=0, - t_conductor=0, + dx_tf_turn_conduit_full_average=0, dx_tf_turn_general=0, i_dx_tf_turn_general_input=False, c_tf_turn=65000, @@ -1284,7 +1284,7 @@ class TfAveragedTurnGeomParam(NamedTuple): ), TfAveragedTurnGeomParam( layer_ins=0, - t_conductor=0.047932469413859431, + dx_tf_turn_conduit_full_average=0.047932469413859431, dx_tf_turn_general=0.049532469413859428, i_dx_tf_turn_general_input=False, c_tf_turn=65000, @@ -1309,7 +1309,7 @@ class TfAveragedTurnGeomParam(NamedTuple): ), TfAveragedTurnGeomParam( layer_ins=0, - t_conductor=5.712e-02, + dx_tf_turn_conduit_full_average=5.712e-02, dx_tf_turn_general=0.05872, i_dx_tf_turn_general_input=True, c_tf_turn=0, @@ -1334,7 +1334,7 @@ class TfAveragedTurnGeomParam(NamedTuple): ), TfAveragedTurnGeomParam( layer_ins=0, - t_conductor=0.058296, + dx_tf_turn_conduit_full_average=0.058296, dx_tf_turn_general=0, i_dx_tf_turn_general_input=False, c_tf_turn=0, @@ -1391,7 +1391,7 @@ def test_tf_cable_in_conduit_averaged_turn_geometry( ) # Existing checks - assert avg_turn_geometry.t_conductor == pytest.approx( + assert avg_turn_geometry.dx_tf_turn_conduit_full_average == pytest.approx( tfaveragedturngeomparam.expected_t_conductor ) assert avg_turn_geometry.dx_tf_turn_general == pytest.approx( From 2c92fc9d8f10a25faaf8fe186b644d98832a7d43 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 16:50:02 +0100 Subject: [PATCH 11/19] Refactor SuperconductingTFData and related tests to rename conductor dimensions for clarity --- .../superconducting_tf_coil_variables.py | 8 ++-- process/models/tfcoil/superconducting.py | 39 ++++++++++--------- tests/unit/models/tfcoil/test_sctfcoil.py | 16 ++++---- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/process/data_structure/superconducting_tf_coil_variables.py b/process/data_structure/superconducting_tf_coil_variables.py index db11bbfe77..fd54025729 100644 --- a/process/data_structure/superconducting_tf_coil_variables.py +++ b/process/data_structure/superconducting_tf_coil_variables.py @@ -113,11 +113,11 @@ class SuperconductingTFData: tan_theta_coil: float = 0.0 """Tan half toroidal angular extent of a single TF coil inboard leg""" - t_conductor_radial: float = 0.0 - """Conductor area radial and toroidal dimension (integer turn only) [m]""" + dr_tf_turn_conduit_full: float = 0.0 + """Radial thickness of the full conduit around the cable space (integer turn only) [m]""" - t_conductor_toroidal: float = 0.0 - """Conductor area radial and toroidal dimension (integer turn only) [m]""" + dx_tf_turn_conduit_full_toroidal: float = 0.0 + """Toroidal thickness of the full conduit around the cable space (integer turn only) [m]""" dr_tf_turn_cable_space: float = 0.0 """Cable area radial and toroidal dimension (integer turn only) [m]""" diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 8004e378de..192162a69f 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -546,15 +546,15 @@ def output_general_superconducting_tf_info(self) -> None: po.ovarre( self.outfile, "Radial width of conductor (m)", - "(t_conductor_radial)", - d_sc_tf.t_conductor_radial, + "(dr_tf_turn_conduit_full)", + self.data.superconducting_tfcoil.dr_tf_turn_conduit_full, "OP ", ) po.ovarre( self.outfile, "Toroidal width of conductor (m)", - "(t_conductor_toroidal)", - d_sc_tf.t_conductor_toroidal, + "(dx_tf_turn_conduit_full_toroidal)", + self.data.superconducting_tfcoil.dx_tf_turn_conduit_full_toroidal, "OP ", ) po.ovarre( @@ -2205,8 +2205,8 @@ class CICCIntegerTurnGeometry: a_tf_turn_insulation: float c_tf_turn: float n_tf_coil_turns: int - t_conductor_radial: float - t_conductor_toroidal: float + dr_tf_turn_conduit_full: float + dx_tf_turn_conduit_full_toroidal: float dx_tf_turn_conduit_full_average: float dr_tf_turn_cable_space: float dx_tf_turn_cable_space: float @@ -2304,11 +2304,11 @@ def run(self, output: bool = False): ) self.data.tfcoil.c_tf_turn = int_turn_geometry.c_tf_turn self.data.tfcoil.n_tf_coil_turns = int_turn_geometry.n_tf_coil_turns - self.data.superconducting_tfcoil.t_conductor_radial = ( - int_turn_geometry.t_conductor_radial + self.data.superconducting_tfcoil.dr_tf_turn_conduit_full = ( + int_turn_geometry.dr_tf_turn_conduit_full ) - self.data.superconducting_tfcoil.t_conductor_toroidal = ( - int_turn_geometry.t_conductor_toroidal + self.data.superconducting_tfcoil.dx_tf_turn_conduit_full_toroidal = ( + int_turn_geometry.dx_tf_turn_conduit_full_toroidal ) self.data.tfcoil.dx_tf_turn_conduit_full_average = ( int_turn_geometry.dx_tf_turn_conduit_full_average @@ -3418,15 +3418,17 @@ def tf_cable_in_conduit_integer_turn_geometry( c_tf_turn = c_tf_coil / n_tf_coil_turns # Radial and toroidal dimension of conductor [m] - t_conductor_radial = dr_tf_turn - 2.0e0 * dx_tf_turn_insulation - t_conductor_toroidal = dx_tf_turn - 2.0e0 * dx_tf_turn_insulation + dr_tf_turn_conduit_full = dr_tf_turn - 2.0e0 * dx_tf_turn_insulation + dx_tf_turn_conduit_full_toroidal = dx_tf_turn - 2.0e0 * dx_tf_turn_insulation dx_tf_turn_conduit_full_average = np.sqrt( - t_conductor_radial * t_conductor_toroidal + dr_tf_turn_conduit_full * dx_tf_turn_conduit_full_toroidal ) # Dimension of square cable space inside conduit [m] - dr_tf_turn_cable_space = t_conductor_radial - 2.0e0 * dx_tf_turn_steel - dx_tf_turn_cable_space = t_conductor_toroidal - 2.0e0 * dx_tf_turn_steel + dr_tf_turn_cable_space = dr_tf_turn_conduit_full - 2.0e0 * dx_tf_turn_steel + dx_tf_turn_cable_space = ( + dx_tf_turn_conduit_full_toroidal - 2.0e0 * dx_tf_turn_steel + ) dx_tf_turn_cable_space_average = np.sqrt( dr_tf_turn_cable_space * dx_tf_turn_cable_space ) @@ -3480,7 +3482,8 @@ def tf_cable_in_conduit_integer_turn_geometry( # Cross-sectional area of conduit jacket per turn [m²] a_tf_turn_steel = ( - t_conductor_radial * t_conductor_toroidal - a_tf_turn_cable_space_no_void + dr_tf_turn_conduit_full * dx_tf_turn_conduit_full_toroidal + - a_tf_turn_cable_space_no_void ) # Area of inter-turn insulation: single turn [m²] @@ -3496,8 +3499,8 @@ def tf_cable_in_conduit_integer_turn_geometry( a_tf_turn_insulation=a_tf_turn_insulation, c_tf_turn=c_tf_turn, n_tf_coil_turns=n_tf_coil_turns, - t_conductor_radial=t_conductor_radial, - t_conductor_toroidal=t_conductor_toroidal, + dr_tf_turn_conduit_full=dr_tf_turn_conduit_full, + dx_tf_turn_conduit_full_toroidal=dx_tf_turn_conduit_full_toroidal, dx_tf_turn_conduit_full_average=dx_tf_turn_conduit_full_average, dr_tf_turn_cable_space=dr_tf_turn_cable_space, dx_tf_turn_cable_space=dx_tf_turn_cable_space, diff --git a/tests/unit/models/tfcoil/test_sctfcoil.py b/tests/unit/models/tfcoil/test_sctfcoil.py index 48845d6209..9bf50af294 100644 --- a/tests/unit/models/tfcoil/test_sctfcoil.py +++ b/tests/unit/models/tfcoil/test_sctfcoil.py @@ -992,9 +992,9 @@ class TfIntegerTurnGeomParam(NamedTuple): dx_tf_wp_toroidal_min: Any = None - t_conductor_radial: Any = None + dr_tf_turn_conduit_full: Any = None - t_conductor_toroidal: Any = None + dx_tf_turn_conduit_full_toroidal: Any = None dr_tf_turn_cable_space: Any = None @@ -1054,8 +1054,8 @@ class TfIntegerTurnGeomParam(NamedTuple): dx_tf_turn_general=0, c_tf_coil=14805350.287500001, dx_tf_wp_toroidal_min=1.299782604942499, - t_conductor_radial=0, - t_conductor_toroidal=0, + dr_tf_turn_conduit_full=0, + dx_tf_turn_conduit_full_toroidal=0, dr_tf_turn_cable_space=0, dx_tf_turn_cable_space=0, dr_tf_turn=0, @@ -1088,8 +1088,8 @@ class TfIntegerTurnGeomParam(NamedTuple): dx_tf_turn_general=0.056579413904423038, c_tf_coil=14805350.287500001, dx_tf_wp_toroidal_min=1.299782604942499, - t_conductor_radial=0.046661087836601015, - t_conductor_toroidal=0.059189130247124938, + dr_tf_turn_conduit_full=0.046661087836601015, + dx_tf_turn_conduit_full_toroidal=0.059189130247124938, dr_tf_turn_cable_space=0.030661087836601014, dx_tf_turn_cable_space=0.043189130247124938, dr_tf_turn=0.050661087836601018, @@ -1157,11 +1157,11 @@ def test_tf_cable_in_conduit_integer_turn_geometry( tfintegerturngeomparam.expected_dx_tf_turn_general ) - assert integer_turn_geometry.t_conductor_radial == pytest.approx( + assert integer_turn_geometry.dr_tf_turn_conduit_full == pytest.approx( tfintegerturngeomparam.expected_t_conductor_radial ) - assert integer_turn_geometry.t_conductor_toroidal == pytest.approx( + assert integer_turn_geometry.dx_tf_turn_conduit_full_toroidal == pytest.approx( tfintegerturngeomparam.expected_t_conductor_toroidal ) From 06d9730a6ff46b6b8f377f16c24d13431a232be6 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 12 Jun 2026 17:10:18 +0100 Subject: [PATCH 12/19] Refactor TFData and SuperconductingTFCoil to clarify mass calculations and improve variable naming --- process/data_structure/tfcoil_variables.py | 5 ++- process/models/tfcoil/superconducting.py | 49 +++++----------------- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/process/data_structure/tfcoil_variables.py b/process/data_structure/tfcoil_variables.py index dc7e6f7f92..68e7118ce3 100644 --- a/process/data_structure/tfcoil_variables.py +++ b/process/data_structure/tfcoil_variables.py @@ -757,7 +757,10 @@ class TFData: """mass of ground-wall insulation layer per coil (kg/coil)""" m_tf_coils_total: float = 0.0 - """total mass of the TF coils (kg)""" + """Total mass of all TF coils (kg)""" + + m_tf_coil: float = 0.0 + """Total mass of one TF coil (kg)""" dx_tf_wp_primary_toroidal: float = 0.0 """width of first step of winding pack (m)""" diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 192162a69f..af1936ccce 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -684,8 +684,8 @@ def output_general_superconducting_tf_info(self) -> None: po.ovarre( self.outfile, "Mass of each TF coil (kg)", - "(m_tf_coils_total/n_tf_coils)", - self.data.tfcoil.m_tf_coils_total / self.data.tfcoil.n_tf_coils, + "(m_tf_coil)", + self.data.tfcoil.m_tf_coil, "OP ", ) po.ovarre( @@ -1977,11 +1977,16 @@ def superconducting_tf_coil_areas_and_masses(self): # --------------------------------- # Total TF coil mass [kg] (all coils) - self.data.tfcoil.m_tf_coils_total = ( + 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 - ) * self.data.tfcoil.n_tf_coils + ) + + # 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 + ) # If spherical tokamak, distribute between centrepost and outboard legs # (in this case, total TF coil length = inboard `cplen` + @@ -3613,48 +3618,16 @@ def output_cable_in_conduit_cable_info(self) -> None: po.ovarre( self.outfile, - "Copper fraction of conductor", + "Copper area fraction of cable conductor", "(f_a_tf_turn_cable_copper)", self.data.tfcoil.f_a_tf_turn_cable_copper, ) po.ovarre( self.outfile, - "Superconductor fraction of conductor", + "Superconductor area fraction of cable conductor", "(1-f_a_tf_turn_cable_copper)", 1 - self.data.tfcoil.f_a_tf_turn_cable_copper, ) - ap = ( - self.data.tfcoil.a_tf_wp_conductor - + self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_steel - + self.data.tfcoil.a_tf_coil_wp_turn_insulation - + self.data.tfcoil.a_tf_wp_extra_void - + self.data.tfcoil.a_tf_wp_coolant_channels - ) - po.ovarre( - self.outfile, - "Check total area fractions in winding pack = 1", - "", - ( - self.data.tfcoil.a_tf_wp_conductor - + self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_steel - + self.data.tfcoil.a_tf_coil_wp_turn_insulation - + self.data.tfcoil.a_tf_wp_extra_void - + self.data.tfcoil.a_tf_wp_coolant_channels - ) - / ap, - ) - po.ovarre( - self.outfile, - "minimum TF conductor temperature margin (K)", - "(temp_tf_superconductor_margin_min)", - self.data.tfcoil.temp_tf_superconductor_margin_min, - ) - po.ovarre( - self.outfile, - "TF conductor temperature margin (K)", - "(temp_tf_superconductor_margin)", - self.data.tfcoil.temp_tf_superconductor_margin, - ) po.ovarre( self.outfile, From f66e32381f8af36073e11bb41a2bc376a64cda8c Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 15 Jun 2026 13:21:08 +0100 Subject: [PATCH 13/19] Update tests for ST to use croco turn type for tapes --- process/models/tfcoil/superconducting.py | 10 ---------- .../input_files/spherical_tokamak_eval.IN.DAT | 1 + tests/regression/input_files/st_regression.IN.DAT | 5 ++++- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index af1936ccce..4c9b622026 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -3912,7 +3912,6 @@ def run(self, output: bool = False): 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, - a_tf_turn_cable_space_effective=self.data.superconducting_tfcoil.a_tf_turn_cable_space_effective, 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, @@ -4322,7 +4321,6 @@ def tf_croco_superconductor_properties( b_tf_inboard_peak: float, cur_tf_turn: float, temp_tf_peak: float, - a_tf_turn_cable_space_effective: float, i_tf_superconductor: int, dr_tf_hts_tape: float, dx_tf_hts_tape_rebco: float, @@ -4379,8 +4377,6 @@ def tf_croco_superconductor_properties( else: strain = self.data.tfcoil.str_wp - f_a_tf_turn_tape_superconductor = dx_tf_hts_tape_rebco / dx_tf_hts_tape_total - # ================================================================= if i_tf_superconductor == SuperconductorModel.CROCO_REBCO: @@ -4442,12 +4438,6 @@ def tf_croco_superconductor_properties( # ================================================================= - # Scale for the copper area fraction of the cable - j_tape_critical = j_superconductor_critical * f_a_tf_turn_tape_superconductor - - # Critical current in turn all turn cables - c_turn_cables_critical = j_tape_critical * a_tf_turn_cable_space_effective - # 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 diff --git a/tests/regression/input_files/spherical_tokamak_eval.IN.DAT b/tests/regression/input_files/spherical_tokamak_eval.IN.DAT index 7ea0b50584..2b2153567b 100644 --- a/tests/regression/input_files/spherical_tokamak_eval.IN.DAT +++ b/tests/regression/input_files/spherical_tokamak_eval.IN.DAT @@ -69,6 +69,7 @@ gapomin = 0.0 * minimum gap between outboard vacuum vessel and TF coil (m) (`it iohcl = 0 * Switch for existence of central solenoid; i_cs_precomp = 0 * Switch for existence of central solenoid pre-compression structure; i_tf_inside_cs = 0 * Switch for placing the TF coil inside the CS +i_tf_turn_type = 2 * CroCo Turn geometry for HTS Tapes dr_cs = 0.20016400484967947 * Central solenoid thickness (m) (`iteration variable 16`) i_r_cp_top = 2 * Switch selecting the he parametrization of the outer radius of the top of the CP part of the TF coil dr_fw_plasma_gap_inboard = 0.1 * Gap between plasma and first wall; inboard side (m) (if `i_plasma_wall_gap=1`) diff --git a/tests/regression/input_files/st_regression.IN.DAT b/tests/regression/input_files/st_regression.IN.DAT index 165335d9b8..08693c90b3 100644 --- a/tests/regression/input_files/st_regression.IN.DAT +++ b/tests/regression/input_files/st_regression.IN.DAT @@ -789,7 +789,10 @@ p_plasma_separatrix_rmajor_max_mw = 40.0 n_tf_coils = 12 * DESCRIPTION: Number of TF Coils -* JUSTIFICATION: +* JUSTIFICATION: + +i_tf_turn_type = 2 +* CroCo Turn geometry for HTS Tapes i_tf_shape = 2 * DESCRIPTION: Switch for TF coil toroidal shape (2: Picture frame coils) From 11d7ba3313f0a18c4870ee17461405179f4fed4a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 15 Jun 2026 13:34:03 +0100 Subject: [PATCH 14/19] Add strain calculation and superconductor temperature margin logic in CROCOSuperconductingTFCoil --- process/models/tfcoil/superconducting.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 4c9b622026..ab930dcc6a 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -3941,6 +3941,23 @@ def run(self, output: bool = False): 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, + ) + self.data.tfcoil.v_tf_coil_dump_quench_kv = ( self.croco_voltage() / 1.0e3 ) # TFC Quench voltage in kV From 59951018da14c9e300ead4007b478a2b7950d94e Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 15 Jun 2026 14:17:14 +0100 Subject: [PATCH 15/19] Add mapping for obsolete variable 't_conductor' to 'dx_tf_turn_conduit_full_average' --- process/core/io/obsolete_vars.py | 1 + 1 file changed, 1 insertion(+) diff --git a/process/core/io/obsolete_vars.py b/process/core/io/obsolete_vars.py index dd0a276d99..41357155d1 100644 --- a/process/core/io/obsolete_vars.py +++ b/process/core/io/obsolete_vars.py @@ -472,6 +472,7 @@ "alstroh": "stress_cs_steel_max", "i_cs_stress": None, "f_nd_alpha_electron": "f_nd_alpha_thermal_electron", + "t_conductor": "dx_tf_turn_conduit_full_average", } OBS_VARS_HELP = { From 9b56839343a9e49fdd33b8ff2677d187a332bb5c Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 15 Jun 2026 14:21:52 +0100 Subject: [PATCH 16/19] Remove outdated comments regarding critical current density in CICCSuperconductingTFCoil class --- process/models/tfcoil/superconducting.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index ab930dcc6a..d9ca1d8fe6 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -2792,13 +2792,6 @@ def tf_cable_in_conduit_superconductor_properties( and also the protection information (for a quench). Not used for the CroCo conductor. - The critical current density for a superconductor - (``j_superconductor_critical``) is for the superconducting strands/tape, - not including copper. The critical current density for - a cable (``j_crit_cable``) accounts for both the fraction of the cable taken - up by helium coolant channels, and the cable conductor copper fraction - (i.e., the copper in the superconducting strands and any additional copper, - such as REBCO tape support). """ if ( SuperconductorModel(i_tf_superconductor).sc_shape From 78c66d81f896869f094a098eb5d894b13069f8aa Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 15 Jun 2026 18:31:36 +0100 Subject: [PATCH 17/19] Refactor code structure for improved readability and maintainability --- process/core/input.py | 4 +- .../superconducting_tf_coil_variables.py | 19 +- process/models/tfcoil/superconducting.py | 217 +++++------------- 3 files changed, 67 insertions(+), 173 deletions(-) diff --git a/process/core/input.py b/process/core/input.py index 946132889e..06cae7568e 100644 --- a/process/core/input.py +++ b/process/core/input.py @@ -297,7 +297,9 @@ def bounds(self) -> tuple[NumberType | None, NumberType | None]: "crane_arm_h": InputVariable("buildings", float, range=(1.0, 100.0)), "crane_clrnc_h": InputVariable("buildings", float, range=(0.0, 10.0)), "crane_clrnc_v": InputVariable("buildings", float, range=(0.0, 10.0)), - "dx_tf_croco_strand_copper": InputVariable("rebco", float, range=(0.001, 0.1)), + "dx_tf_croco_strand_copper": InputVariable( + "superconducting_tfcoil", float, range=(0.001, 0.1) + ), "cryomag_h": InputVariable("buildings", float, range=(1.0, 100.0)), "cryomag_l": InputVariable("buildings", float, range=(10.0, 1000.0)), "cryomag_w": InputVariable("buildings", float, range=(10.0, 1000.0)), diff --git a/process/data_structure/superconducting_tf_coil_variables.py b/process/data_structure/superconducting_tf_coil_variables.py index fd54025729..0ff662dd5a 100644 --- a/process/data_structure/superconducting_tf_coil_variables.py +++ b/process/data_structure/superconducting_tf_coil_variables.py @@ -254,33 +254,20 @@ class SuperconductingTFData: outer tube and central copper) (m²)""" a_tf_turn_copper_total: float = 0.0 - """Area of all copper in the TF turn (m²)""" + """Area of all copper in the TF turn [m²]""" f_a_tf_turn_copper: float = 0.0 - """Fraction of the TF turn area that is copper (m²)""" + """Fraction of the TF turn area that is copper""" a_tf_turn_croco_copper_bar: float = 0.0 """Area of the central copper strand in the CroCo TF turn [m²]""" f_a_tf_turn_superconductor: float = 0.0 - """Fraction of the TF turn area that is superconducting material [m²]""" + """Fraction of the TF turn area that is superconducting material""" 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²)""" - conductor_hastelloy_fraction: float = 0.0 - conductor_helium_area: float = 0.0 - conductor_helium_fraction: float = 0.0 - conductor_solder_area: float = 0.0 - conductor_solder_fraction: float = 0.0 - conductor_jacket_area: float = 0.0 - conductor_jacket_fraction: float = 0.0 - conductor_rebco_area: float = 0.0 - conductor_rebco_fraction: float = 0.0 - conductor_critical_current: float = 0.0 - conductor_area: float = 0.0 - """Area of cable space inside jacket""" - t1: float = 0.0 time2: float = 0.0 diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index d9ca1d8fe6..0118212220 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -80,7 +80,7 @@ def full_name(self): return self.name.title().replace("_", " ") -@dataclass +@dataclass(slots=True) class TFWPGeometry: """Data class for storing the geometry of the TF coil winding pack and ground insulation. @@ -99,7 +99,7 @@ class TFWPGeometry: a_tf_wp_ground_insulation: float -@dataclass +@dataclass(slots=True) class TFSuperconductorLimits: j_tf_wp_critical: float j_superconductor_critical: float @@ -616,12 +616,33 @@ def output_general_superconducting_tf_info(self) -> None: "(dx_tf_turn_insulation)", self.data.tfcoil.dx_tf_turn_insulation, ) + po.oblnkl(self.outfile) po.ovarre( self.outfile, "TF coil turn area (m²)", "(a_tf_turn)", self.data.tfcoil.a_tf_turn, ) + po.ovarre( + self.outfile, + "Total area of available cable space [m²]", + "(a_tf_turn_cable_space_no_void)", + self.data.tfcoil.a_tf_turn_cable_space_no_void, + "OP ", + ) + po.ovarre( + self.outfile, + "True area of turn cable space usable by conductor [m²]", + "(a_tf_turn_cable_space_effective)", + self.data.superconducting_tfcoil.a_tf_turn_cable_space_effective, + ) + + po.ovarre( + self.outfile, + "Extra coolant area fraction in turn cable space", + "(f_a_tf_turn_cable_space_extra_void)", + self.data.tfcoil.f_a_tf_turn_cable_space_extra_void, + ) po.oblnkl(self.outfile) po.ocmmnt(self.outfile, "----------------------------") @@ -2179,9 +2200,9 @@ def run_and_output_stress(self) -> None: self.data.tfcoil.sig_tf_wp = 0.0e0 -@dataclass -class CICCAveragedTurnGeometry: - """Averaged turn geometry for a CICC conductor with LTS cables.""" +@dataclass(slots=True) +class TFGeneralTurnGeometry: + """General turn geometry info needed for all TF turn types.""" a_tf_turn_cable_space_no_void: float a_tf_turn_steel: float @@ -2192,30 +2213,29 @@ class CICCAveragedTurnGeometry: dr_tf_turn: float dx_tf_turn: float dx_tf_turn_conduit_full_average: float - radius_tf_turn_cable_space_corners: float dx_tf_turn_cable_space_average: float + + +@dataclass(slots=True) +class CICCAveragedTurnGeometry(TFGeneralTurnGeometry): + """Averaged turn geometry for a CICC conductor with LTS cables.""" + + radius_tf_turn_cable_space_corners: float a_tf_turn_cable_space_effective: float f_a_tf_turn_cable_space_cooling: float -@dataclass -class CICCIntegerTurnGeometry: +@dataclass(slots=True) +class CICCIntegerTurnGeometry(TFGeneralTurnGeometry): """Integer turn geometry for a CICC conductor with LTS cables.""" radius_tf_turn_cable_space_corners: float - dr_tf_turn: float - dx_tf_turn: float - a_tf_turn_cable_space_no_void: float - a_tf_turn_steel: float - a_tf_turn_insulation: float - c_tf_turn: float - n_tf_coil_turns: int dr_tf_turn_conduit_full: float dx_tf_turn_conduit_full_toroidal: float - dx_tf_turn_conduit_full_average: float dr_tf_turn_cable_space: float dx_tf_turn_cable_space: float - dx_tf_turn_cable_space_average: float + a_tf_turn_cable_space_effective: float + f_a_tf_turn_cable_space_cooling: float class CICCSuperconductingTFCoil(SuperconductingTFCoil): @@ -3545,26 +3565,8 @@ def output_cable_in_conduit_cable_info(self) -> None: "(len_tf_superconductor_total)", d_sc_tf.len_tf_superconductor_total, ) - po.ocmmnt(self.outfile, "Fractions by area") - po.ovarre( - self.outfile, - "internal area of the cable space", - "(a_tf_turn_cable_space_no_void)", - self.data.tfcoil.a_tf_turn_cable_space_no_void, - ) - po.ovarre( - self.outfile, - "True area of turn cable space with gaps and channels removed", - "(a_tf_turn_cable_space_effective)", - d_sc_tf.a_tf_turn_cable_space_effective, - ) + po.oblnkl(self.outfile) - po.ovarre( - self.outfile, - "Coolant fraction in conductor excluding central channel", - "(f_a_tf_turn_cable_space_extra_void)", - self.data.tfcoil.f_a_tf_turn_cable_space_extra_void, - ) po.ovarre( self.outfile, "Area of steel in turn", @@ -3652,29 +3654,20 @@ def output_cable_in_conduit_cable_info(self) -> None: ) -@dataclass -class CROCOAveragedTurnGeometry: - a_tf_turn_cable_space_no_void: float - a_tf_turn_steel: float - a_tf_turn_insulation: float - n_tf_coil_turns: int - c_tf_turn: float - dx_tf_turn_general: float - dr_tf_turn: float - dx_tf_turn: float - dx_tf_turn_conduit_full_average: float - dx_tf_turn_cable_space_average: float +@dataclass(slots=True) +class CROCOAveragedTurnGeometry(TFGeneralTurnGeometry): + """Data class for the averaged turn geometry of a CroCo conductor.""" -@dataclass +@dataclass(slots=True) class CroCoCableSpaceGeometry: + """Data class for the geometry of the cable space in a CroCo conductor.""" + dia_tf_turn_croco_cable: float a_tf_turn_cable_space_no_void: float a_tf_turn_cable_space_effective: float a_tf_turn_steel: float - conductor_area: float - conductor_jacket_area: float - conductor_jacket_fraction: float + f_a_tf_turn_cable_space_cooling: float class CROCOSuperconductingTFCoil(SuperconductingTFCoil): @@ -3740,6 +3733,8 @@ def run(self, output: bool = False): # No central channel in CroCo conductor, self.data.tfcoil.a_tf_wp_coolant_channels = 0.0 + self.data.tfcoil.f_a_tf_turn_cable_space_extra_void = 0.0 + # Void area in conductor for He, not including central channel [m²] self.data.tfcoil.a_tf_wp_extra_void = ( self.data.tfcoil.a_tf_turn_cable_space_no_void @@ -3797,10 +3792,8 @@ def run(self, output: bool = False): croco_cable_space_geometry.a_tf_turn_cable_space_effective ) self.data.tfcoil.a_tf_turn_steel = croco_cable_space_geometry.a_tf_turn_steel - d_sc_tf.conductor_area = croco_cable_space_geometry.conductor_area - d_sc_tf.conductor_jacket_area = croco_cable_space_geometry.conductor_jacket_area - d_sc_tf.conductor_jacket_fraction = ( - croco_cable_space_geometry.conductor_jacket_fraction + self.data.superconducting_tfcoil.f_a_tf_turn_cable_space_cooling = ( + croco_cable_space_geometry.f_a_tf_turn_cable_space_cooling ) croco_cable_geometry = calculate_croco_cable_geometry( @@ -3874,24 +3867,6 @@ def run(self, output: bool = False): d_sc_tf.a_tf_turn_croco_hastelloy = ( d_sc_tf.a_tf_croco_strand_hastelloy * N_CROCO_STRANDS_TURN ) - d_sc_tf.conductor_hastelloy_fraction = ( - d_sc_tf.a_tf_turn_croco_hastelloy / d_sc_tf.conductor_area - ) - - d_sc_tf.conductor_solder_area = ( - d_sc_tf.a_tf_croco_strand_solder * N_CROCO_STRANDS_TURN - ) - d_sc_tf.conductor_solder_fraction = ( - d_sc_tf.conductor_solder_area / d_sc_tf.conductor_area - ) - - d_sc_tf.conductor_rebco_area = ( - d_sc_tf.a_tf_croco_strand_rebco * N_CROCO_STRANDS_TURN - ) - self.data.superconducting_tfcoil.f_a_tf_turn_superconductor = ( - self.data.superconducting_tfcoil.conductor_rebco_area - / self.data.superconducting_tfcoil.conductor_area - ) # Cross-sectional area per turn self.data.tfcoil.a_tf_turn = self.data.tfcoil.c_tf_total / ( @@ -4462,20 +4437,14 @@ def tf_croco_superconductor_properties( cur_tf_turn_croco_strand_critical = j_superconductor_critical * a_tf_croco_strand # Conductor properties - self.data.superconducting_tfcoil.conductor_critical_current = ( - cur_tf_turn_croco_strand_critical * N_CROCO_STRANDS_TURN - ) - - d_sc_tf.tf_coppera_m2 = cur_tf_turn / d_sc_tf.a_tf_turn_croco_cable_space_copper - - cur_critical = d_sc_tf.conductor_critical_current + cur_tf_turn_critical = cur_tf_turn_croco_strand_critical * N_CROCO_STRANDS_TURN # 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_critical / a_tf_turn + j_tf_wp_critical = cur_tf_turn_critical / a_tf_turn # Ratio of operating / critical current - f_c_tf_turn_operating_critical = cur_tf_turn / cur_critical + f_c_tf_turn_operating_critical = cur_tf_turn / cur_tf_turn_critical # Operating current density j_tf_coil_turn = cur_tf_turn / a_tf_turn @@ -4521,26 +4490,7 @@ def tf_turn_croco_cable_space_properties( Returns ------- - CroCoCableSpaceGeometry - A dataclass containing the calculated properties of the cable space in - the TF turn, including: - - dia_tf_turn_croco_cable: Diameter of the circular cable space in the TF - turn (in meters). - - a_tf_turn_cable_space_no_void: Area of the cable space in the TF turn - without voids (in square meters). - - a_tf_turn_cable_space_effective: Effective area of the cable space in - the TF turn after accounting for cooling channels and voids - (in square meters). - - a_tf_turn_steel: Area of the steel in the TF turn (in square meters). - - conductor_area: Total area of the conductor in the TF turn - (in square meters). - - conductor_jacket_area: Area of the conductor jacket in the TF turn - (in square meters). - - conductor_jacket_fraction: Fraction of the conductor area that is the - jacket (dimensionless). - - """ dia_tf_turn_croco_cable = ( dx_tf_turn_conduit_full_average / 3.0e0 - dx_tf_turn_steel * (2.0e0 / 3.0e0) @@ -4551,28 +4501,25 @@ def tf_turn_croco_cable_space_properties( 9.0e0 / 4.0e0 * np.pi * dia_tf_turn_croco_cable**2 ) - # Area of the full cable spac circle minus the central copper strand + # Just the area of the CroCo strands in the turn (i.e. not including voids) a_tf_turn_cable_space_effective = ( - a_tf_turn_cable_space_no_void - 0.25e0 * np.pi * dia_tf_turn_croco_cable**2 + N_CROCO_STRANDS_TURN * np.pi * (dia_tf_turn_croco_cable / 2.0e0) ** 2 ) - conductor_area = ( - dx_tf_turn_conduit_full_average**2 - ) # does this not assume it's a sqaure??? - - conductor_jacket_area = conductor_area - a_tf_turn_cable_space_no_void - a_tf_turn_steel = conductor_jacket_area + a_tf_turn_steel = ( + dx_tf_turn_conduit_full_average**2 - a_tf_turn_cable_space_no_void + ) - conductor_jacket_fraction = conductor_jacket_area / conductor_area + f_a_tf_turn_cable_space_cooling = a_tf_turn_cable_space_no_void - ( + (N_CROCO_STRANDS_TURN + 1) * np.pi * (dia_tf_turn_croco_cable / 2.0e0) ** 2 + ) return CroCoCableSpaceGeometry( dia_tf_turn_croco_cable=dia_tf_turn_croco_cable, a_tf_turn_cable_space_no_void=a_tf_turn_cable_space_no_void, a_tf_turn_cable_space_effective=a_tf_turn_cable_space_effective, a_tf_turn_steel=a_tf_turn_steel, - conductor_area=conductor_area, - conductor_jacket_area=conductor_jacket_area, - conductor_jacket_fraction=conductor_jacket_fraction, + f_a_tf_turn_cable_space_cooling=f_a_tf_turn_cable_space_cooling, ) def croco_voltage(self) -> float: @@ -4724,13 +4671,6 @@ def output_croco_info(self) -> None: "", N_CROCO_STRANDS_TURN, ) - po.ovarre( - self.outfile, - "Total area of circular cable space (m²)", - "(a_tf_turn_cable_space_no_void)", - self.data.tfcoil.a_tf_turn_cable_space_no_void, - "OP ", - ) po.oblnkl(self.outfile) po.ocmmnt( @@ -4744,20 +4684,6 @@ def output_croco_info(self) -> None: self.data.tfcoil.dx_tf_turn_conduit_full_average, "OP ", ) - po.ovarre( - self.outfile, - "Area of conductor (m²)", - "(conductor_area)", - self.data.superconducting_tfcoil.conductor_area, - "OP ", - ) - po.ovarre( - self.outfile, - "REBCO area of conductor (m²)", - "(a_tf_croco_strand_rebco)", - d_sc_tf.conductor_rebco_area, - "OP ", - ) po.ovarre( self.outfile, "Area of central copper bar (m²)", @@ -4779,20 +4705,6 @@ def output_croco_info(self) -> None: self.data.superconducting_tfcoil.a_tf_turn_croco_hastelloy, "OP ", ) - po.ovarre( - self.outfile, - "Solder area of conductor (m²)", - "(a_tf_croco_strand_solder)", - d_sc_tf.conductor_solder_area, - "OP ", - ) - po.ovarre( - self.outfile, - "Jacket area of conductor (m²)", - "(jacket_area)", - d_sc_tf.conductor_jacket_area, - "OP ", - ) po.ovarre( self.outfile, @@ -4801,13 +4713,6 @@ def output_croco_info(self) -> None: d_sc_tf.cur_tf_turn_croco_strand_critical, "OP ", ) - po.ovarre( - self.outfile, - "Critical current of conductor (A) ", - "(conductor_critical_current)", - d_sc_tf.conductor_critical_current, - "OP ", - ) @staticmethod From 384e874e1850a0403a5c85d65d9d23557bd9d291 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Tue, 16 Jun 2026 10:30:48 +0100 Subject: [PATCH 18/19] Enhance CICC and CroCo TF coil area calculations and add new data structure for area fractions --- process/models/tfcoil/superconducting.py | 459 ++++++++++++++-------- tests/unit/models/tfcoil/test_sctfcoil.py | 2 +- 2 files changed, 298 insertions(+), 163 deletions(-) diff --git a/process/models/tfcoil/superconducting.py b/process/models/tfcoil/superconducting.py index 0118212220..783b405143 100644 --- a/process/models/tfcoil/superconducting.py +++ b/process/models/tfcoil/superconducting.py @@ -460,9 +460,48 @@ def output_general_superconducting_tf_info(self) -> None: # WP material fraction po.osubhd(self.outfile, "TF winding pack (WP) material area/fractions:") + + po.ovarre( + self.outfile, + "Area of all turn insulation in WP [m²]", + "(a_tf_coil_wp_turn_insulation)", + self.data.tfcoil.a_tf_coil_wp_turn_insulation, + ) + po.ovarre( + self.outfile, + "Total insulation area in TF coil (turn and WP) [m²]", + "(a_tf_coil_inboard_insulation)", + self.data.superconducting_tfcoil.a_tf_coil_inboard_insulation, + ) + po.ovarre( + self.outfile, + "Total steel area in inboard TF coil (turn and case) [m²]", + "(a_tf_coil_inboard_steel)", + self.data.superconducting_tfcoil.a_tf_coil_inboard_steel, + ) + po.ovarre( + self.outfile, + "Total conductor area in WP [m²]", + "(a_tf_wp_conductor)", + self.data.tfcoil.a_tf_wp_conductor, + ) + po.ovarre( + self.outfile, + "Total additional void area in WP [m²]", + "(a_tf_wp_extra_void)", + self.data.tfcoil.a_tf_wp_extra_void, + ) + + po.ovarre( + self.outfile, + "Area of all coolant channels in WP [m²]", + "(a_tf_wp_coolant_channels)", + self.data.tfcoil.a_tf_wp_coolant_channels, + ) + po.ovarre( self.outfile, - "Steel WP cross-section (total) (m²)", + "Steel WP cross-section (total) [m²]", "(a_tf_wp_steel*n_tf_coils)", self.data.tfcoil.a_tf_wp_steel * self.data.tfcoil.n_tf_coils, ) @@ -503,9 +542,9 @@ def output_general_superconducting_tf_info(self) -> None: self.data.tfcoil.i_tf_turns_integer, ) if self.data.tfcoil.i_tf_turns_integer == 0: - po.ocmmnt(self.outfile, " Non-integer number of turns") + po.ocmmnt(self.outfile, "-> Non-integer number of turns") else: - po.ocmmnt(self.outfile, " Integer number of turns") + po.ocmmnt(self.outfile, "-> Integer number of turns") po.ovarre( self.outfile, @@ -619,7 +658,7 @@ def output_general_superconducting_tf_info(self) -> None: po.oblnkl(self.outfile) po.ovarre( self.outfile, - "TF coil turn area (m²)", + "TF coil turn area [m²]", "(a_tf_turn)", self.data.tfcoil.a_tf_turn, ) @@ -636,6 +675,12 @@ def output_general_superconducting_tf_info(self) -> None: "(a_tf_turn_cable_space_effective)", self.data.superconducting_tfcoil.a_tf_turn_cable_space_effective, ) + po.ovarre( + self.outfile, + "Area of steel in turn [m²]", + "(a_tf_turn_steel)", + self.data.tfcoil.a_tf_turn_steel, + ) po.ovarre( self.outfile, @@ -2216,6 +2261,21 @@ class TFGeneralTurnGeometry: dx_tf_turn_cable_space_average: float +@dataclass(slots=True) +class SuperconTFAreasFractions: + """Superconducting TF coil winding pack areas and fractions.""" + + a_tf_wp_coolant_channels: float + a_tf_wp_conductor: float + a_tf_wp_extra_void: float + a_tf_coil_wp_turn_insulation: float + a_tf_wp_steel: float + a_tf_coil_inboard_steel: float + f_a_tf_coil_inboard_steel: float + a_tf_coil_inboard_insulation: float + f_a_tf_coil_inboard_insulation: float + + @dataclass(slots=True) class CICCAveragedTurnGeometry(TFGeneralTurnGeometry): """Averaged turn geometry for a CICC conductor with LTS cables.""" @@ -2347,6 +2407,13 @@ def run(self, output: bool = False): self.data.superconducting_tfcoil.dx_tf_turn_cable_space_average = ( int_turn_geometry.dx_tf_turn_cable_space_average ) + self.data.superconducting_tfcoil.a_tf_turn_cable_space_effective = ( + int_turn_geometry.a_tf_turn_cable_space_effective + ) + self.data.superconducting_tfcoil.f_a_tf_turn_cable_space_cooling = ( + int_turn_geometry.f_a_tf_turn_cable_space_cooling + ) + self.data.tfcoil.dx_tf_turn_general = int_turn_geometry.dx_tf_turn_general # Calculate number of cables in turn if CICC conductor # --------------------------------------------------- @@ -2368,65 +2435,39 @@ def run(self, output: bool = False): n_tf_turn_superconducting_cables=d_sc_tf.n_tf_turn_superconducting_cables, ) - # Areas and fractions - # ------------------- - # Central helium channel down the conductor core [m2] - self.data.tfcoil.a_tf_wp_coolant_channels = ( - 0.25e0 - * self.data.tfcoil.n_tf_coil_turns - * np.pi - * self.data.tfcoil.dia_tf_turn_coolant_channel**2 - ) - - # Total conductor cross-sectional area, taking account of void area - # and central helium channel [m2] - self.data.tfcoil.a_tf_wp_conductor = ( - self.data.tfcoil.a_tf_turn_cable_space_no_void - * self.data.tfcoil.n_tf_coil_turns - * (1.0e0 - self.data.tfcoil.f_a_tf_turn_cable_space_extra_void) - - self.data.tfcoil.a_tf_wp_coolant_channels + inboard_areas_fractions = self.tf_cicc_inboard_areas_and_fractions( + n_tf_coil_turns=self.data.tfcoil.n_tf_coil_turns, + dia_tf_turn_coolant_channel=self.data.tfcoil.dia_tf_turn_coolant_channel, + a_tf_turn_cable_space_no_void=self.data.tfcoil.a_tf_turn_cable_space_no_void, + f_a_tf_turn_cable_space_extra_void=self.data.tfcoil.f_a_tf_turn_cable_space_extra_void, + 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=self.data.superconducting_tfcoil.a_tf_wp_ground_insulation, ) - # Void area in conductor for He, not including central channel [m2] - self.data.tfcoil.a_tf_wp_extra_void = ( - self.data.tfcoil.a_tf_turn_cable_space_no_void - * self.data.tfcoil.n_tf_coil_turns - * self.data.tfcoil.f_a_tf_turn_cable_space_extra_void + self.data.tfcoil.a_tf_wp_coolant_channels = ( + inboard_areas_fractions.a_tf_wp_coolant_channels ) - - # Area of inter-turn insulation: total [m2] + 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 = ( - self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_insulation - ) - - # Area of steel structure in winding pack [m2] - self.data.tfcoil.a_tf_wp_steel = ( - self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_steel + inboard_areas_fractions.a_tf_coil_wp_turn_insulation ) - - # Inboard coil steel area [m2] - d_sc_tf.a_tf_coil_inboard_steel = ( - self.data.tfcoil.a_tf_coil_inboard_case + self.data.tfcoil.a_tf_wp_steel + self.data.tfcoil.a_tf_wp_steel = inboard_areas_fractions.a_tf_wp_steel + self.data.superconducting_tfcoil.a_tf_coil_inboard_steel = ( + inboard_areas_fractions.a_tf_coil_inboard_steel ) - - # Inboard coil steel fraction [-] - d_sc_tf.f_a_tf_coil_inboard_steel = ( - self.data.tfcoil.n_tf_coils - * d_sc_tf.a_tf_coil_inboard_steel - / self.data.tfcoil.a_tf_inboard_total + self.data.superconducting_tfcoil.f_a_tf_coil_inboard_steel = ( + inboard_areas_fractions.f_a_tf_coil_inboard_steel ) - - # Inboard coil insulation cross-section [m2] - d_sc_tf.a_tf_coil_inboard_insulation = ( - self.data.tfcoil.a_tf_coil_wp_turn_insulation - + d_sc_tf.a_tf_wp_ground_insulation + self.data.superconducting_tfcoil.a_tf_coil_inboard_insulation = ( + inboard_areas_fractions.a_tf_coil_inboard_insulation ) - - # Inboard coil insulation fraction [-] - d_sc_tf.f_a_tf_coil_inboard_insulation = ( - self.data.tfcoil.n_tf_coils - * d_sc_tf.a_tf_coil_inboard_insulation - / self.data.tfcoil.a_tf_inboard_total + self.data.superconducting_tfcoil.f_a_tf_coil_inboard_insulation = ( + inboard_areas_fractions.f_a_tf_coil_inboard_insulation ) # Negative areas or fractions error reporting @@ -3427,7 +3468,7 @@ def tf_cable_in_conduit_integer_turn_geometry( ) # Average turn dimension [m] - data.tfcoil.dx_tf_turn_general = np.sqrt(dr_tf_turn * dx_tf_turn) + dx_tf_turn_general = np.sqrt(dr_tf_turn * dx_tf_turn) # Number of TF turns n_tf_coil_turns = np.double(n_tf_wp_layers * n_tf_wp_pancakes) @@ -3459,7 +3500,7 @@ def tf_cable_in_conduit_integer_turn_geometry( # Calculate the true effective cable space by taking away the cooling # channel and the extra void fraction - data.superconducting_tfcoil.a_tf_turn_cable_space_effective = ( + a_tf_turn_cable_space_effective = ( a_tf_turn_cable_space_no_void - # Coolant channel area @@ -3475,9 +3516,8 @@ def tf_cable_in_conduit_integer_turn_geometry( ) ) - data.superconducting_tfcoil.f_a_tf_turn_cable_space_cooling = 1 - ( - data.superconducting_tfcoil.a_tf_turn_cable_space_effective - / a_tf_turn_cable_space_no_void + f_a_tf_turn_cable_space_cooling = 1 - ( + a_tf_turn_cable_space_effective / a_tf_turn_cable_space_no_void ) if a_tf_turn_cable_space_no_void <= 0.0e0: @@ -3523,10 +3563,86 @@ def tf_cable_in_conduit_integer_turn_geometry( dr_tf_turn_cable_space=dr_tf_turn_cable_space, dx_tf_turn_cable_space=dx_tf_turn_cable_space, dx_tf_turn_cable_space_average=dx_tf_turn_cable_space_average, + a_tf_turn_cable_space_effective=a_tf_turn_cable_space_effective, + f_a_tf_turn_cable_space_cooling=f_a_tf_turn_cable_space_cooling, + dx_tf_turn_general=dx_tf_turn_general, ) # ------------- + @staticmethod + def tf_cicc_inboard_areas_and_fractions( + n_tf_coil_turns: int, + dia_tf_turn_coolant_channel: float, + a_tf_turn_cable_space_no_void: float, + f_a_tf_turn_cable_space_extra_void: float, + a_tf_turn_insulation: float, + a_tf_turn_steel: float, + n_tf_coils: int, + a_tf_inboard_total: float, + a_tf_coil_inboard_case: 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_cable_space_no_void + * n_tf_coil_turns + * (1.0e0 - f_a_tf_turn_cable_space_extra_void) + - a_tf_wp_coolant_channels + ) + + # Void area in conductor for He, not including central channel [m2] + a_tf_wp_extra_void = ( + a_tf_turn_cable_space_no_void + * n_tf_coil_turns + * f_a_tf_turn_cable_space_extra_void + ) + + # Area of inter-turn insulation: total [m2] + a_tf_coil_wp_turn_insulation = n_tf_coil_turns * a_tf_turn_insulation + + # 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 output_cable_in_conduit_cable_info(self) -> None: """ Outputs the calculated cable in condutit cable space geometry information @@ -3567,50 +3683,6 @@ def output_cable_in_conduit_cable_info(self) -> None: ) po.oblnkl(self.outfile) - po.ovarre( - self.outfile, - "Area of steel in turn", - "(a_tf_turn_steel)", - self.data.tfcoil.a_tf_turn_steel, - ) - po.ovarre( - self.outfile, - "Area of all turn insulation in WP", - "(a_tf_coil_wp_turn_insulation)", - self.data.tfcoil.a_tf_coil_wp_turn_insulation, - ) - po.ovarre( - self.outfile, - "Total insulation area in TF coil (turn and WP)", - "(a_tf_coil_inboard_insulation)", - d_sc_tf.a_tf_coil_inboard_insulation, - ) - po.ovarre( - self.outfile, - "Total steel area in inboard TF coil (turn and case)", - "(a_tf_coil_inboard_steel)", - d_sc_tf.a_tf_coil_inboard_steel, - ) - po.ovarre( - self.outfile, - "Total conductor area in WP", - "(a_tf_wp_conductor)", - self.data.tfcoil.a_tf_wp_conductor, - ) - po.ovarre( - self.outfile, - "Total additional void area in WP", - "(a_tf_wp_extra_void)", - self.data.tfcoil.a_tf_wp_extra_void, - ) - - po.ovarre( - self.outfile, - "Area of all coolant channels in WP", - "(a_tf_wp_coolant_channels)", - self.data.tfcoil.a_tf_wp_coolant_channels, - ) - po.ovarre( self.outfile, "Copper area fraction of cable conductor", @@ -3624,6 +3696,8 @@ def output_cable_in_conduit_cable_info(self) -> None: 1 - self.data.tfcoil.f_a_tf_turn_cable_copper, ) + po.oblnkl(self.outfile) + po.ovarre( self.outfile, "Elastic properties behavior", @@ -3727,56 +3801,6 @@ def run(self, output: bool = False): "Integer turn geometry not implemented for CroCo conductor." ) - # Areas and fractions - # ------------------- - # Central helium channel down the conductor core [m²] - # No central channel in CroCo conductor, - self.data.tfcoil.a_tf_wp_coolant_channels = 0.0 - - self.data.tfcoil.f_a_tf_turn_cable_space_extra_void = 0.0 - - # Void area in conductor for He, not including central channel [m²] - self.data.tfcoil.a_tf_wp_extra_void = ( - self.data.tfcoil.a_tf_turn_cable_space_no_void - * self.data.tfcoil.n_tf_coil_turns - * self.data.tfcoil.f_a_tf_turn_cable_space_extra_void - ) - - # Area of inter-turn insulation: total [m²] - self.data.tfcoil.a_tf_coil_wp_turn_insulation = ( - self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_insulation - ) - - # Area of steel structure in winding pack [m²] - self.data.tfcoil.a_tf_wp_steel = ( - self.data.tfcoil.n_tf_coil_turns * self.data.tfcoil.a_tf_turn_steel - ) - - # Inboard coil steel area [m²] - d_sc_tf.a_tf_coil_inboard_steel = ( - self.data.tfcoil.a_tf_coil_inboard_case + self.data.tfcoil.a_tf_wp_steel - ) - - # Inboard coil steel fraction [-] - d_sc_tf.f_a_tf_coil_inboard_steel = ( - self.data.tfcoil.n_tf_coils - * d_sc_tf.a_tf_coil_inboard_steel - / self.data.tfcoil.a_tf_inboard_total - ) - - # Inboard coil insulation cross-section [m²] - d_sc_tf.a_tf_coil_inboard_insulation = ( - self.data.tfcoil.a_tf_coil_wp_turn_insulation - + d_sc_tf.a_tf_wp_ground_insulation - ) - - # Inboard coil insulation fraction [-] - d_sc_tf.f_a_tf_coil_inboard_insulation = ( - self.data.tfcoil.n_tf_coils - * d_sc_tf.a_tf_coil_inboard_insulation - / self.data.tfcoil.a_tf_inboard_total - ) - croco_cable_space_geometry: CroCoCableSpaceGeometry = self.tf_turn_croco_cable_space_properties( dx_tf_turn_conduit_full_average=self.data.tfcoil.dx_tf_turn_conduit_full_average, dx_tf_turn_steel=self.data.tfcoil.dx_tf_turn_steel, @@ -3825,11 +3849,57 @@ def run(self, output: bool = False): croco_cable_geometry.dx_croco_strand_tape_stack ) - d_sc_tf.a_tf_croco_strand_copper_total = d_sc_tf.a_tf_croco_strand_copper_total - d_sc_tf.a_tf_croco_strand_hastelloy = d_sc_tf.a_tf_croco_strand_hastelloy - d_sc_tf.a_tf_croco_strand_solder = d_sc_tf.a_tf_croco_strand_solder - d_sc_tf.a_tf_croco_strand_rebco = d_sc_tf.a_tf_croco_strand_rebco - d_sc_tf.a_tf_croco_strand = d_sc_tf.a_tf_croco_strand + self.data.superconducting_tfcoil.a_tf_croco_strand_copper_total = ( + self.data.superconducting_tfcoil.a_tf_croco_strand_copper_total + ) + self.data.superconducting_tfcoil.a_tf_croco_strand_hastelloy = ( + self.data.superconducting_tfcoil.a_tf_croco_strand_hastelloy + ) + self.data.superconducting_tfcoil.a_tf_croco_strand_solder = ( + self.data.superconducting_tfcoil.a_tf_croco_strand_solder + ) + self.data.superconducting_tfcoil.a_tf_croco_strand_rebco = ( + self.data.superconducting_tfcoil.a_tf_croco_strand_rebco + ) + self.data.superconducting_tfcoil.a_tf_croco_strand = ( + self.data.superconducting_tfcoil.a_tf_croco_strand + ) + + self.data.tfcoil.f_a_tf_turn_cable_space_extra_void = 0.0 + + inbaord_areas_fractions = self.tf_croco_inboard_areas_and_fractions( + a_tf_turn_cable_space_no_void=self.data.tfcoil.a_tf_turn_cable_space_no_void, + n_tf_coil_turns=self.data.tfcoil.n_tf_coil_turns, + f_a_tf_turn_cable_space_extra_void=self.data.tfcoil.f_a_tf_turn_cable_space_extra_void, + a_tf_turn_insulation=self.data.tfcoil.a_tf_turn_insulation, + a_tf_turn_steel=self.data.tfcoil.a_tf_turn_steel, + a_tf_coil_inboard_case=self.data.tfcoil.a_tf_coil_inboard_case, + n_tf_coils=self.data.tfcoil.n_tf_coils, + a_tf_inboard_total=self.data.tfcoil.a_tf_inboard_total, + a_tf_wp_ground_insulation=self.data.superconducting_tfcoil.a_tf_wp_ground_insulation, + a_tf_croco_strand=self.data.superconducting_tfcoil.a_tf_croco_strand, + ) + self.data.tfcoil.a_tf_wp_coolant_channels = ( + inbaord_areas_fractions.a_tf_wp_coolant_channels + ) + self.data.tfcoil.a_tf_wp_conductor = inbaord_areas_fractions.a_tf_wp_conductor + self.data.tfcoil.a_tf_wp_extra_void = inbaord_areas_fractions.a_tf_wp_extra_void + self.data.tfcoil.a_tf_coil_wp_turn_insulation = ( + inbaord_areas_fractions.a_tf_coil_wp_turn_insulation + ) + self.data.tfcoil.a_tf_wp_steel = inbaord_areas_fractions.a_tf_wp_steel + self.data.superconducting_tfcoil.a_tf_coil_inboard_steel = ( + inbaord_areas_fractions.a_tf_coil_inboard_steel + ) + self.data.superconducting_tfcoil.f_a_tf_coil_inboard_steel = ( + inbaord_areas_fractions.f_a_tf_coil_inboard_steel + ) + self.data.superconducting_tfcoil.a_tf_coil_inboard_insulation = ( + inbaord_areas_fractions.a_tf_coil_inboard_insulation + ) + self.data.superconducting_tfcoil.f_a_tf_coil_inboard_insulation = ( + inbaord_areas_fractions.f_a_tf_coil_inboard_insulation + ) # Area of core = area of strand d_sc_tf.a_tf_turn_croco_copper_bar = d_sc_tf.a_tf_croco_strand @@ -3905,9 +3975,9 @@ def run(self, output: bool = False): self.data.superconducting_tfcoil.b_tf_superconductor_critical_zero_temp_strain = superconductor_critical_properties.bc20m self.data.superconducting_tfcoil.temp_tf_superconductor_critical_zero_field_strain = superconductor_critical_properties.tc0m - self.data.superconducting_tfcoil.c_tf_turn_cables_critical = ( - superconductor_critical_properties.c_turn_cables_critical - ) + self.data.superconducting_tfcoil.cur_tf_turn_croco_strand_critical = ( + self.data.superconducting_tfcoil.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 @@ -4522,6 +4592,71 @@ def tf_turn_croco_cable_space_properties( f_a_tf_turn_cable_space_cooling=f_a_tf_turn_cable_space_cooling, ) + @staticmethod + def tf_croco_inboard_areas_and_fractions( + a_tf_turn_cable_space_no_void: float, + n_tf_coil_turns: int, + f_a_tf_turn_cable_space_extra_void: 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, + a_tf_croco_strand: float, + ) -> SuperconTFAreasFractions: + + # Areas and fractions + # ------------------- + # Central helium channel down the conductor core [m²] + # No central channel in CroCo conductor, + a_tf_wp_coolant_channels = 0.0 + + a_tf_wp_conductor = n_tf_coil_turns * a_tf_croco_strand * N_CROCO_STRANDS_TURN + + # Void area in conductor for He, not including central channel [m²] + a_tf_wp_extra_void = ( + a_tf_turn_cable_space_no_void + * n_tf_coil_turns + * f_a_tf_turn_cable_space_extra_void + ) + + # Area of inter-turn insulation: total [m²] + a_tf_coil_wp_turn_insulation = n_tf_coil_turns * a_tf_turn_insulation + + # Area of steel structure in winding pack [m²] + a_tf_wp_steel = n_tf_coil_turns * a_tf_turn_steel + + # Inboard coil steel area [m²] + 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 [m²] + 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 croco_voltage(self) -> float: d_sc_tf = self.data.superconducting_tfcoil diff --git a/tests/unit/models/tfcoil/test_sctfcoil.py b/tests/unit/models/tfcoil/test_sctfcoil.py index 9bf50af294..e043edf411 100644 --- a/tests/unit/models/tfcoil/test_sctfcoil.py +++ b/tests/unit/models/tfcoil/test_sctfcoil.py @@ -1153,7 +1153,7 @@ def test_tf_cable_in_conduit_integer_turn_geometry( tfintegerturngeomparam.expected_t_conductor ) - assert cicc_sctfcoil.data.tfcoil.dx_tf_turn_general == pytest.approx( + assert integer_turn_geometry.dx_tf_turn_general == pytest.approx( tfintegerturngeomparam.expected_dx_tf_turn_general ) From 8722c11b09ff2983c477e127ef8db006bfeeb39a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 22 Jun 2026 10:53:14 +0100 Subject: [PATCH 19/19] Update test values to try and align with previous solution --- process/core/input.py | 14 -------------- .../input_files/spherical_tokamak_eval.IN.DAT | 4 ++++ tests/regression/input_files/st_regression.IN.DAT | 6 ++++++ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/process/core/input.py b/process/core/input.py index 06cae7568e..9e1418b6c7 100644 --- a/process/core/input.py +++ b/process/core/input.py @@ -710,20 +710,6 @@ def bounds(self) -> tuple[NumberType | None, NumberType | None]: "superconducting_tfcoil", float, range=(1e-08, 0.0001), - additional_actions=lambda _n, rt, _i, _c: ( - rt <= 1e-6 - or logger.warning( - ( - "the relationship between REBCO layer thickness " - "and current density is not linear." - "REBCO layer thicknesses > 1um should be considered " - "an aggressive extrapolation of" - "current HTS technology and any results " - "must be considered speculative." - ), - stacklevel=1, - ) - ), ), "redun_vacp": InputVariable("costs", float, range=(0.0, 100.0)), "residual_sig_hoop": InputVariable("cs_fatigue", float, range=(0.0, 1000000000.0)), diff --git a/tests/regression/input_files/spherical_tokamak_eval.IN.DAT b/tests/regression/input_files/spherical_tokamak_eval.IN.DAT index 2b2153567b..eb671f21b4 100644 --- a/tests/regression/input_files/spherical_tokamak_eval.IN.DAT +++ b/tests/regression/input_files/spherical_tokamak_eval.IN.DAT @@ -70,6 +70,10 @@ iohcl = 0 * Switch for existence of central solenoid; i_cs_precomp = 0 * Switch for existence of central solenoid pre-compression structure; i_tf_inside_cs = 0 * Switch for placing the TF coil inside the CS i_tf_turn_type = 2 * CroCo Turn geometry for HTS Tapes +dx_tf_hts_tape_rebco = 1.0e-6 +dx_tf_croco_strand_copper = 2.0e-3 +dx_tf_hts_tape_copper = 2.0e-4 +dx_tf_hts_tape_hastelloy = 1e-5 dr_cs = 0.20016400484967947 * Central solenoid thickness (m) (`iteration variable 16`) i_r_cp_top = 2 * Switch selecting the he parametrization of the outer radius of the top of the CP part of the TF coil dr_fw_plasma_gap_inboard = 0.1 * Gap between plasma and first wall; inboard side (m) (if `i_plasma_wall_gap=1`) diff --git a/tests/regression/input_files/st_regression.IN.DAT b/tests/regression/input_files/st_regression.IN.DAT index 08693c90b3..bc085b4ce8 100644 --- a/tests/regression/input_files/st_regression.IN.DAT +++ b/tests/regression/input_files/st_regression.IN.DAT @@ -784,6 +784,12 @@ p_plasma_separatrix_rmajor_max_mw = 40.0 *-------------------------------- *TF Coil* --------------------------------------------------------------------------------------------------------------------------------------------------------------* *‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾* +dx_tf_hts_tape_rebco = 1.0e-6 +dx_tf_croco_strand_copper = 2.0e-3 +dx_tf_hts_tape_copper = 2.0e-4 +dx_tf_hts_tape_hastelloy = 1e-5 + + *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ General settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾