From 02bf8de1424372f99c87a5d892f5ae7f4781880b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 4 Jun 2026 10:27:09 +0100 Subject: [PATCH 01/18] Move elbow coeffieicnt calc from blanket to pumping --- .../source/eng-models/blanket_overview.md | 22 ------ .../eng-models/generic_methods/pumping.md | 28 +++++++- process/models/blankets/blanket_library.py | 69 +------------------ process/models/engineering/pumping.py | 66 ++++++++++++++++++ .../models/blankets/test_blanket_library.py | 21 ------ tests/unit/models/engineering/test_pumping.py | 14 ++++ 6 files changed, 110 insertions(+), 110 deletions(-) diff --git a/documentation/source/eng-models/blanket_overview.md b/documentation/source/eng-models/blanket_overview.md index 66a84b15f7..fa0de10aa6 100644 --- a/documentation/source/eng-models/blanket_overview.md +++ b/documentation/source/eng-models/blanket_overview.md @@ -78,27 +78,5 @@ $$ ------------------- -### Pipe bend elbow coefficient | `elbow_coeff()` -This function calculates the elbow bend coefficients for pressure drop calculations. - -$$ -a = 1.0 \quad \text{if} \ \theta = 90^{\circ} \\ -a = 0.9 \times \sin{\left(\frac{\theta \pi}{180^{\circ}}\right)} \quad \text{if} \ \theta < 70^{\circ} \\ -a = 0.7 + 0.35 \times \sin{\left(\frac{\theta}{90^{\circ}} \times \frac{\pi}{180^{\circ}}\right)} \quad \text{if} \ \theta > 90^{\circ} \\ -$$ - -where $\theta$ is the angle of the pipe bend. - -$$ -b = \frac{0.21}{\sqrt{\frac{R_{\text{elbow}}}{D_{\text{pipe}}}}}\quad \text{if} \ \frac{R_{\text{elbow}}}{D_{\text{pipe}}} \ge 1 \\ -b = \frac{0.21}{\left(\frac{R_{\text{elbow}}}{D_{\text{pipe}}}\right)^{2.5}}\quad \text{if} \ \frac{R_{\text{elbow}}}{D_{\text{pipe}}} \le 1 \\ -\text{else} \quad b =0.21 -$$ - -The elbow coefficient is given by: - -$$ -ab + \left( f_{\text{D}} \times \frac{R_{\text{elbow}}}{D_{\text{pipe}}}\right) \times \theta \times \left(\frac{\pi}{180^{\circ}}\right) -$$ diff --git a/documentation/source/eng-models/generic_methods/pumping.md b/documentation/source/eng-models/generic_methods/pumping.md index a4822ba00b..7bd3a1dc4e 100644 --- a/documentation/source/eng-models/generic_methods/pumping.md +++ b/documentation/source/eng-models/generic_methods/pumping.md @@ -61,4 +61,30 @@ where $\rho$ is the coolant density and $\mu$ is the coolant viscosity. $$ h = \frac{\mathrm{Nu_D}k}{2r_{\text{channel}}} - $$ \ No newline at end of file + $$ + +------------------------- + +## Pipe bend elbow coefficient | `elbow_coeff()` + +This function calculates the elbow bend coefficients for pressure drop calculations. + +$$ +a = 1.0 \quad \text{if} \ \theta = 90^{\circ} \\ +a = 0.9 \times \sin{\left(\frac{\theta \pi}{180^{\circ}}\right)} \quad \text{if} \ \theta < 70^{\circ} \\ +a = 0.7 + 0.35 \times \sin{\left(\frac{\theta}{90^{\circ}} \times \frac{\pi}{180^{\circ}}\right)} \quad \text{if} \ \theta > 90^{\circ} \\ +$$ + +where $\theta$ is the angle of the pipe bend. + +$$ +b = \frac{0.21}{\sqrt{\frac{R_{\text{elbow}}}{D_{\text{pipe}}}}}\quad \text{if} \ \frac{R_{\text{elbow}}}{D_{\text{pipe}}} \ge 1 \\ +b = \frac{0.21}{\left(\frac{R_{\text{elbow}}}{D_{\text{pipe}}}\right)^{2.5}}\quad \text{if} \ \frac{R_{\text{elbow}}}{D_{\text{pipe}}} \le 1 \\ +\text{else} \quad b =0.21 +$$ + +The elbow coefficient is given by: + +$$ +ab + \left( f_{\text{D}} \times \frac{R_{\text{elbow}}}{D_{\text{pipe}}}\right) \times \theta \times \left(\frac{\pi}{180^{\circ}}\right) +$$ \ No newline at end of file diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index db1c458f0c..24457261f8 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -24,6 +24,7 @@ CoolantType, calculate_reynolds_number, darcy_friction_haaland, + elbow_coeff, ) from process.models.power import PumpingPowerModelTypes @@ -3171,7 +3172,7 @@ def coolant_friction_pressure_drop( f_straight = darcy_friction_factor * len_pipe / dia_pipe # 90 degree elbow pressure drop coefficient - f_elbow_90 = self.elbow_coeff( + f_elbow_90 = elbow_coeff( radius_pipe_elbow=radius_pipe_90_deg_bend, deg_pipe_elbow=90.0, darcy_friction=darcy_friction_factor, @@ -3179,7 +3180,7 @@ def coolant_friction_pressure_drop( ) # 180 degree elbow pressure drop coefficient - f_elbow_180 = self.elbow_coeff( + f_elbow_180 = elbow_coeff( radius_pipe_elbow=radius_pipe_180_deg_bend, deg_pipe_elbow=180.0, darcy_friction=darcy_friction_factor, @@ -3290,70 +3291,6 @@ def pipe_hydraulic_diameter(self, i_channel_shape): f"i_channel_shape ={i_channel_shape} is an invalid option." ) - @staticmethod - def elbow_coeff( - radius_pipe_elbow: float, - deg_pipe_elbow: float, - darcy_friction: float, - dia_pipe: float, - ) -> float: - """Calculates elbow bend coefficients for pressure drop calculations. - - Parameters - ---------- - radius_pipe_elbow : float - Pipe elbow radius (m) - deg_pipe_elbow : float - Pipe elbow angle (degrees) - darcy_friction : float - Darcy friction factor - dia_pipe : float - Pipe diameter (m) - - Returns - ------- - float - Elbow coefficient for pressure drop calculation - - References - ---------- - - [Ide1969] Idel'Cik, I. E. (1969), Memento des pertes de charge, - Collection de la Direction des Etudes et Recherches d'Electricité de France. - """ - if deg_pipe_elbow == 90: - a = 1.0 - elif deg_pipe_elbow < 70: - a = 0.9 * np.sin(deg_pipe_elbow * np.pi / 180.0) - elif deg_pipe_elbow > 100: - a = 0.7 + (0.35 * np.sin((deg_pipe_elbow / 90.0) * (np.pi / 180.0))) - else: - raise ProcessValueError( - "No formula for 70 <= elbow angle(deg) <= 100, only 90 deg option available in this range." - ) - - r_ratio = radius_pipe_elbow / dia_pipe - - if r_ratio > 1: - b = 0.21 / r_ratio**0.5 - elif r_ratio < 1: - b = 0.21 / r_ratio**2.5 - else: - b = 0.21 - - # Singularity - ximt = a * b - - # Friction - xift = ( - (np.pi / 180.0) - * darcy_friction - * (radius_pipe_elbow / dia_pipe) - * deg_pipe_elbow - ) - - # Elbow Coefficient - return ximt + xift - def coolant_pumping_power( self, output: bool, diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index ae7f2f6131..9f2f1acbe3 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -40,6 +40,8 @@ def full_name(self): return self._full_name_ +from process.core.exceptions import ProcessValueError + logger = logging.getLogger(__name__) @@ -199,3 +201,67 @@ def calculate_reynolds_number( # Calculate Reynolds number return den_coolant * vel_coolant * diameter / visc_coolant + + +def elbow_coeff( + radius_pipe_elbow: float, + deg_pipe_elbow: float, + darcy_friction: float, + dia_pipe: float, +) -> float: + """Calculates elbow bend coefficients for pressure drop calculations. + + Parameters + ---------- + radius_pipe_elbow : float + Pipe elbow radius (m) + deg_pipe_elbow : float + Pipe elbow angle (degrees) + darcy_friction : float + Darcy friction factor + dia_pipe : float + Pipe diameter (m) + + Returns + ------- + float + Elbow coefficient for pressure drop calculation + + References + ---------- + [1] Idel'Cik, I. E. (1969), Memento des pertes de charge, + Collection de la Direction des Etudes et Recherches d'Electricité de France. + """ + if deg_pipe_elbow == 90: + a = 1.0 + elif deg_pipe_elbow < 70: + a = 0.9 * np.sin(deg_pipe_elbow * np.pi / 180.0) + elif deg_pipe_elbow > 100: + a = 0.7 + (0.35 * np.sin((deg_pipe_elbow / 90.0) * (np.pi / 180.0))) + else: + raise ProcessValueError( + "No formula for 70 <= elbow angle(deg) <= 100, only 90 deg option available in this range." + ) + + r_ratio = radius_pipe_elbow / dia_pipe + + if r_ratio > 1: + b = 0.21 / r_ratio**0.5 + elif r_ratio < 1: + b = 0.21 / r_ratio**2.5 + else: + b = 0.21 + + # Singularity + ximt = a * b + + # Friction + xift = ( + (np.pi / 180.0) + * darcy_friction + * (radius_pipe_elbow / dia_pipe) + * deg_pipe_elbow + ) + + # Elbow Coefficient + return ximt + xift diff --git a/tests/unit/models/blankets/test_blanket_library.py b/tests/unit/models/blankets/test_blanket_library.py index acfdf502f0..f6741bd992 100644 --- a/tests/unit/models/blankets/test_blanket_library.py +++ b/tests/unit/models/blankets/test_blanket_library.py @@ -1606,27 +1606,6 @@ def test_hydraulic_diameter(monkeypatch, blanket_library): assert blanket_library.pipe_hydraulic_diameter(2) == pytest.approx(1.0) -def test_elbow_coeff(blanket_library): - """ - Test for elbow_coeff function. - """ - # input = r_elbow, ang_elbow, lambda, dh - assert blanket_library.elbow_coeff(1, 0, 1, 1) == pytest.approx(0.0, rel=1e-3) - assert blanket_library.elbow_coeff(1, 90, 1, 1) == pytest.approx( - 1.7807963267948965, rel=1e-3 - ) - assert blanket_library.elbow_coeff(1, 180, 1, 1) == pytest.approx( - 3.291157766597427, rel=1e-3 - ) - assert blanket_library.elbow_coeff(1, 90, 1, 0.1) == pytest.approx( - 15.774371098812502, rel=1e-3 - ) - assert blanket_library.elbow_coeff(0.1, 90, 1, 1) == pytest.approx(66.57, rel=1e-3) - assert blanket_library.elbow_coeff(1, 90, 0.1, 1) == pytest.approx( - 0.3670796326794896, rel=1e-3 - ) - - def test_flow_velocity(monkeypatch, blanket_library): """ Test for flow_velocity function. diff --git a/tests/unit/models/engineering/test_pumping.py b/tests/unit/models/engineering/test_pumping.py index 6b1898bb1a..5e85511dda 100644 --- a/tests/unit/models/engineering/test_pumping.py +++ b/tests/unit/models/engineering/test_pumping.py @@ -3,6 +3,7 @@ from process.models.engineering.pumping import ( calculate_reynolds_number, darcy_friction_haaland, + elbow_coeff, gnielinski_heat_transfer_coefficient, ) @@ -33,3 +34,16 @@ def test_calculate_reynolds_number(): radius_channel=0.0060000000000000001, visc_coolant=4.0416219836935569e-05, ) == pytest.approx(33302.602975971815) + + +def test_elbow_coeff(): + """ + Test for elbow_coeff function. + """ + # input = r_elbow, ang_elbow, lambda, dh + assert elbow_coeff(1, 0, 1, 1) == pytest.approx(0.0, rel=1e-3) + assert elbow_coeff(1, 90, 1, 1) == pytest.approx(1.7807963267948965, rel=1e-3) + assert elbow_coeff(1, 180, 1, 1) == pytest.approx(3.291157766597427, rel=1e-3) + assert elbow_coeff(1, 90, 1, 0.1) == pytest.approx(15.774371098812502, rel=1e-3) + assert elbow_coeff(0.1, 90, 1, 1) == pytest.approx(66.57, rel=1e-3) + assert elbow_coeff(1, 90, 0.1, 1) == pytest.approx(0.3670796326794896, rel=1e-3) From c4833bd1fe6db212019000128850a8fd57bd60d6 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 4 Jun 2026 10:40:41 +0100 Subject: [PATCH 02/18] Add coolant properties to BlanketData class --- process/data_structure/blanket_variables.py | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/process/data_structure/blanket_variables.py b/process/data_structure/blanket_variables.py index 2849473727..0abd7c0fe2 100644 --- a/process/data_structure/blanket_variables.py +++ b/process/data_structure/blanket_variables.py @@ -206,5 +206,35 @@ class BlanketData: f_deg_blkt_inboard_poloidal_plasma: float = 0.0 """Fraction of inboard blanket poloidal angle subtended by plasma (degrees)""" + reynolds_blkt_inboard_coolant: float = 0.0 + """Inboard blanket coolant Reynolds number""" + + reynolds_blkt_outboard_coolant: float = 0.0 + """Outboard blanket coolant Reynolds number""" + + darcy_frict_blkt_inboard_coolant: float = 0.0 + """Inboard blanket coolant Darcy friction factor""" + + darcy_frict_blkt_outboard_coolant: float = 0.0 + """Outboard blanket coolant Darcy friction factor""" + + f_elbow_blkt_inboard_90_bend: float = 0.0 + """Inboard blanket coolant 90 degree bend loss coefficient""" + + f_elbow_blkt_outboard_90_bend: float = 0.0 + """Outboard blanket coolant 90 degree bend loss coefficient""" + + f_elbow_blkt_inboard_180_bend: float = 0.0 + """Inboard blanket coolant 180 degree bend loss coefficient""" + + f_elbow_blkt_outboard_180_bend: float = 0.0 + """Outboard blanket coolant 180 degree bend loss coefficient""" + + len_blkt_inboard_coolant_channel_straight_total: float = 0.0 + """Total length of inboard blanket coolant channel straight sections (m)""" + + len_blkt_outboard_coolant_channel_straight_total: float = 0.0 + """Total length of outboard blanket coolant channel straight sections (m)""" + CREATE_DICTS_FROM_DATACLASS = BlanketData From 21d96feee69b549644754ffe1d4f58f3fa04a44b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 4 Jun 2026 16:21:28 +0100 Subject: [PATCH 03/18] Add coolant friction loss parameters and output functions for blanket models --- process/core/output.py | 2 + process/data_structure/blanket_variables.py | 42 ++ process/models/blankets/blanket_library.py | 475 ++++++++++++------ process/models/engineering/pumping.py | 33 ++ .../models/blankets/test_blanket_library.py | 1 - 5 files changed, 402 insertions(+), 151 deletions(-) diff --git a/process/core/output.py b/process/core/output.py index 1368eaae7f..5ec99588d3 100644 --- a/process/core/output.py +++ b/process/core/output.py @@ -127,6 +127,8 @@ def write(models, data, _outfile): # DCLL model models.dcll.output() + models.blanket_library.output_blkt_pumping_variables() + # FISPACT and LOCA model (not used)- removed # Power model diff --git a/process/data_structure/blanket_variables.py b/process/data_structure/blanket_variables.py index 0abd7c0fe2..c7ea5d74b8 100644 --- a/process/data_structure/blanket_variables.py +++ b/process/data_structure/blanket_variables.py @@ -230,6 +230,48 @@ class BlanketData: f_elbow_blkt_outboard_180_bend: float = 0.0 """Outboard blanket coolant 180 degree bend loss coefficient""" + f_straight_blkt_inboard_coolant: float = 0.0 + """Inboard blanket coolant straight length loss coefficient""" + + f_straight_blkt_outboard_coolant: float = 0.0 + """Outboard blanket coolant straight length loss coefficient""" + + dpres_blkt_inboard_coolant_channel_straight_total: float = 0.0 + """Total pressure drop in inboard blanket coolant channel straight sections (Pa)""" + + dpres_blkt_outboard_coolant_channel_straight_total: float = 0.0 + """Total pressure drop in outboard blanket coolant channel straight sections (Pa)""" + + dpres_blkt_inboard_coolant_channel_90_bends_total: float = 0.0 + """Total pressure drop in inboard blanket coolant channel 90 degree bends (Pa)""" + + dpres_blkt_outboard_coolant_channel_90_bends_total: float = 0.0 + """Total pressure drop in outboard blanket coolant channel 90 degree bends (Pa)""" + + dpres_blkt_inboard_coolant_channel_180_bends_total: float = 0.0 + """Total pressure drop in inboard blanket coolant channel 180 degree bends (Pa)""" + + dpres_blkt_outboard_coolant_channel_180_bends_total: float = 0.0 + """Total pressure drop in outboard blanket coolant channel 180 degree bends (Pa)""" + + dpres_blkt_inboard_coolant_channel_90_bend: float = 0.0 + """Pressure drop in inboard blanket coolant channel 90 degree bend (Pa)""" + + dpres_blkt_outboard_coolant_channel_90_bend: float = 0.0 + """Pressure drop in outboard blanket coolant channel 90 degree bend (Pa)""" + + dpres_blkt_inboard_coolant_channel_180_bend: float = 0.0 + """Pressure drop in inboard blanket coolant channel 180 degree bend (Pa)""" + + dpres_blkt_outboard_coolant_channel_180_bend: float = 0.0 + """Pressure drop in outboard blanket coolant channel 180 degree bend (Pa)""" + + dpres_blkt_inboard_bends_total: float = 0.0 + """Total pressure drop in inboard blanket coolant channel bends (Pa)""" + + dpres_blkt_outboard_bends_total: float = 0.0 + """Total pressure drop in outboard blanket coolant channel bends (Pa)""" + len_blkt_inboard_coolant_channel_straight_total: float = 0.0 """Total length of inboard blanket coolant channel straight sections (m)""" diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 24457261f8..2dd4b56d55 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -22,6 +22,7 @@ ) from process.models.engineering.pumping import ( CoolantType, + CoolantFrictionLossParameters, calculate_reynolds_number, darcy_friction_haaland, elbow_coeff, @@ -1393,7 +1394,7 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): b_bz_liq=self.data.fwbs.b_bz_liq, ) - dpres_fw_inboard_coolant = self.total_pressure_drop( + dpres_fw_inboard_coolant, fw_inboard_friction_params = self.total_pressure_drop( output, icoolpump=1, vel_coolant=vel_fw_inboard_coolant, @@ -1408,19 +1409,21 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): label="Inboard first wall", ) - dpres_fw_outboard_coolant = self.total_pressure_drop( - output, - icoolpump=1, - vel_coolant=vel_fw_outboard_coolant, - len_pipe=self.data.fwbs.len_fw_channel, - n_pipe_90_deg_bends=N_FW_PIPE_90_DEG_BENDS, - n_pipe_180_deg_bends=N_FW_PIPE_180_DEG_BENDS, - den_coolant=self.data.fwbs.den_fw_coolant, - visc_coolant_dynamic=self.data.fwbs.visc_fw_coolant, - coolant_electrical_conductivity=0.0e0, - pol_channel_length=pollengo, - nopolchan=npoltoto, - label="Outboard first wall", + dpres_fw_outboard_coolant, fw_outboard_friction_params = ( + self.total_pressure_drop( + output, + icoolpump=1, + vel_coolant=vel_fw_outboard_coolant, + len_pipe=self.data.fwbs.len_fw_channel, + n_pipe_90_deg_bends=N_FW_PIPE_90_DEG_BENDS, + n_pipe_180_deg_bends=N_FW_PIPE_180_DEG_BENDS, + den_coolant=self.data.fwbs.den_fw_coolant, + visc_coolant_dynamic=self.data.fwbs.visc_fw_coolant, + coolant_electrical_conductivity=0.0e0, + pol_channel_length=pollengo, + nopolchan=npoltoto, + label="Outboard first wall", + ) ) # BB Presure Drops ############### @@ -1441,43 +1444,85 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): npoltoti = self.data.fwbs.nopol * npblkti_liq npoltoto = self.data.fwbs.nopol * npblkto_liq - dpres_blkt_outboard_coolant = self.total_pressure_drop( - output, - icoolpump=1, - vel_coolant=self.data.blanket.vel_blkt_outboard_coolant, - len_pipe=self.data.blanket.len_blkt_outboard_channel_total, - n_pipe_90_deg_bends=N_BLKT_PIPE_90_DEG_BENDS, - n_pipe_180_deg_bends=N_BLKT_PIPE_180_DEG_BENDS, - den_coolant=self.data.fwbs.den_blkt_coolant, - visc_coolant_dynamic=self.data.fwbs.visc_blkt_coolant, - coolant_electrical_conductivity=0.0e0, - pol_channel_length=pollengo, - nopolchan=npoltoto, - label="Outboard blanket", - ) - - if ( - self.data.build.i_blkt_inboard - == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT - ): - dpres_blkt_inboard_coolant = self.total_pressure_drop( + dpres_blkt_outboard_coolant, blkt_outboard_friction_params = ( + self.total_pressure_drop( output, icoolpump=1, - vel_coolant=self.data.blanket.vel_blkt_inboard_coolant, - len_pipe=self.data.blanket.len_blkt_inboard_channel_total, + vel_coolant=self.data.blanket.vel_blkt_outboard_coolant, + len_pipe=self.data.blanket.len_blkt_outboard_channel_total, n_pipe_90_deg_bends=N_BLKT_PIPE_90_DEG_BENDS, n_pipe_180_deg_bends=N_BLKT_PIPE_180_DEG_BENDS, den_coolant=self.data.fwbs.den_blkt_coolant, visc_coolant_dynamic=self.data.fwbs.visc_blkt_coolant, coolant_electrical_conductivity=0.0e0, - pol_channel_length=pollengi, - nopolchan=npoltoti, - label="Inboard blanket", + pol_channel_length=pollengo, + nopolchan=npoltoto, + label="Outboard blanket", + ) + ) + + self.data.blanket.dpres_blkt_outboard_coolant_channel_straight_total = ( + blkt_outboard_friction_params.dpres_straight + ) + self.data.blanket.dpres_blkt_outboard_coolant_channel_90_bend = ( + blkt_outboard_friction_params.dpres_90 + ) + self.data.blanket.dpres_blkt_outboard_coolant_channel_90_bends_total = ( + blkt_outboard_friction_params.dpres_90_total + ) + self.data.blanket.dpres_blkt_outboard_coolant_channel_180_bend = ( + blkt_outboard_friction_params.dpres_180 + ) + self.data.blanket.dpres_blkt_outboard_coolant_channel_180_bends_total = ( + blkt_outboard_friction_params.dpres_180_total + ) + self.data.blanket.dpres_blkt_outboard_bends_total = ( + blkt_outboard_friction_params.dpres_bends_total + ) + + self.data.blanket.reynolds_blkt_outboard_coolant = ( + blkt_outboard_friction_params.reynolds_number + ) + self.data.blanket.darcy_frict_blkt_outboard_coolant = ( + blkt_outboard_friction_params.darcy_friction_factor + ) + self.data.blanket.f_straight_blkt_outboard_coolant = ( + blkt_outboard_friction_params.f_straight + ) + self.data.blanket.len_blkt_outboard_coolant_channel_straight_total = ( + blkt_outboard_friction_params.len_straight + ) + self.data.blanket.f_elbow_blkt_outboard_90_bend = ( + blkt_outboard_friction_params.f_elbow_90 + ) + self.data.blanket.f_elbow_blkt_outboard_180_bend = ( + blkt_outboard_friction_params.f_elbow_180 + ) + + if ( + self.data.build.i_blkt_inboard + == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT + ): + dpres_blkt_inboard_coolant, blkt_inboard_friction_params = ( + self.total_pressure_drop( + output, + icoolpump=1, + vel_coolant=self.data.blanket.vel_blkt_inboard_coolant, + len_pipe=self.data.blanket.len_blkt_inboard_channel_total, + n_pipe_90_deg_bends=N_BLKT_PIPE_90_DEG_BENDS, + n_pipe_180_deg_bends=N_BLKT_PIPE_180_DEG_BENDS, + den_coolant=self.data.fwbs.den_blkt_coolant, + visc_coolant_dynamic=self.data.fwbs.visc_blkt_coolant, + coolant_electrical_conductivity=0.0e0, + pol_channel_length=pollengi, + nopolchan=npoltoti, + label="Inboard blanket", + ) ) # If the blanket has a liquid metal breeder... if self.data.fwbs.i_blkt_dual_coolant > 0: - deltap_blo_liq = self.total_pressure_drop( + deltap_blo_liq, _ = self.total_pressure_drop( output, icoolpump=2, vel_coolant=velblkto_liq, @@ -1495,7 +1540,7 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): self.data.build.i_blkt_inboard == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): - deltap_bli_liq = self.total_pressure_drop( + deltap_bli_liq, _ = self.total_pressure_drop( output, icoolpump=2, vel_coolant=velblkti_liq, @@ -2412,6 +2457,7 @@ def thermo_hydraulic_model(self, output: bool): deltap = self.thermo_hydraulic_model_pressure_drop_calculations( output=output ) + print(deltap) deltap_fwi = deltap[0] deltap_fwo = deltap[1] deltap_blo = deltap[2] @@ -2841,7 +2887,7 @@ def total_pressure_drop( pol_channel_length: float, nopolchan: int, label: str, - ) -> float: + ) -> tuple[float, CoolantFrictionLossParameters]: """Calculate the total pressure drop (Pa) for coolant flow in the first wall (FW) and breeding blanket (BZ). This includes frictional losses and, for liquid breeder coolants, magnetohydrodynamic (MHD) losses. @@ -2875,8 +2921,8 @@ def total_pressure_drop( Returns ------- - float - Total pressure drop (Pa). + tuple + Total pressure drop (Pa) and friction loss parameters. """ radius_pipe_90_deg_bend, radius_pipe_180_deg_bend = calculate_pipe_bend_radius( i_ps=icoolpump, @@ -2885,19 +2931,20 @@ def total_pressure_drop( ) # Friction - for all coolants - dpres_friction = self.coolant_friction_pressure_drop( - i_ps=icoolpump, - radius_pipe_90_deg_bend=radius_pipe_90_deg_bend, - radius_pipe_180_deg_bend=radius_pipe_180_deg_bend, - n_pipe_90_deg_bends=n_pipe_90_deg_bends, - n_pipe_180_deg_bends=n_pipe_180_deg_bends, - len_pipe=len_pipe, - den_coolant=den_coolant, - visc_coolant=visc_coolant_dynamic, - vel_coolant=vel_coolant, - label=label, - output=output, + friction_params: CoolantFrictionLossParameters = ( + self.coolant_friction_pressure_drop( + i_ps=icoolpump, + radius_pipe_90_deg_bend=radius_pipe_90_deg_bend, + radius_pipe_180_deg_bend=radius_pipe_180_deg_bend, + n_pipe_90_deg_bends=n_pipe_90_deg_bends, + n_pipe_180_deg_bends=n_pipe_180_deg_bends, + len_pipe=len_pipe, + den_coolant=den_coolant, + visc_coolant=visc_coolant_dynamic, + vel_coolant=vel_coolant, + ) ) + dpres_friction = friction_params.dpres_total if icoolpump == 2: dpres_mhd = self.liquid_breeder_mhd_pressure_drop( @@ -2915,22 +2962,7 @@ def total_pressure_drop( # Total pressure drop (Pa) dpres_total = dpres_friction + dpres_mhd - if output: - po.osubhd(self.outfile, f"Total pressure drop for {label}") - - po.ocmmnt(self.outfile, "Friction drops plus MHD drops if applicaple") - po.ovarre( - self.outfile, "Total pressure drop (Pa)", "(deltap)", dpres_total, "OP " - ) - po.ovarre( - self.outfile, - "Coolant flow velocity (m/s)", - "(flow_velocity, formerly vv)", - vel_coolant, - "OP ", - ) - - return dpres_total + return dpres_total, friction_params def liquid_breeder_mhd_pressure_drop( self, @@ -3097,9 +3129,7 @@ def coolant_friction_pressure_drop( den_coolant: float, visc_coolant: float, vel_coolant: float, - label: str, - output: bool = False, - ): + ) -> CoolantFrictionLossParameters: """Pressure drops are calculated for a pipe with a number of 90 and 180 degree bends. The pressure drop due to frictional forces along the total straight length of the pipe is calculated, then the pressure @@ -3126,12 +3156,23 @@ def coolant_friction_pressure_drop( coolant viscosity (Pa s) vel_coolant : coolant flow velocity (m/s) - label : - component name - output : - boolean of whether to write data to output file - :Notes: + Returns + ------- + : + CoolantFrictionLossParameters dataclass containing: + - Total pressure drop due to friction (Pa) + - Pressure drop due to straight sections (Pa) + - Pressure drop due to 90 degree bends (Pa) + - Pressure drop due to 180 degree bends (Pa) + - Reynolds number + - Darcy friction factor + - Pressure drop coefficient for straight sections + - Pressure drop coefficient for 90 degree bends + - Pressure drop coefficient for 180 degree bends + + Notes + ----- Darcy-Weisbach Equation (straight pipe): ΔP = λ * L/D * (p 〈v〉²) / 2 @@ -3191,78 +3232,31 @@ def coolant_friction_pressure_drop( dpres_straight = f_straight * 0.5 * den_coolant * vel_coolant**2 # Pressure drop due to 90 and 180 degree bends - dpres_90 = n_pipe_90_deg_bends * f_elbow_90 * 0.5 * den_coolant * vel_coolant**2 - dpres_180 = ( - n_pipe_180_deg_bends * f_elbow_180 * 0.5 * den_coolant * vel_coolant**2 - ) - - # Total pressure drop (Pa) - dpres_total = dpres_straight + dpres_90 + dpres_180 - - if output: - po.osubhd(self.outfile, f"Pressure drop (friction) for {label}") - po.ovarre(self.outfile, "Reynolds number", "(reyn)", reynolds_number, "OP ") - po.ovarre( - self.outfile, - "Darcy friction factor", - "(lambda)", - darcy_friction_factor, - "OP ", - ) - po.ovarre( - self.outfile, - "Pressure drop (Pa)", - "(pressure_drop)", - dpres_total, - "OP ", - ) - po.ocmmnt(self.outfile, "This is the sum of the following:") - po.ovarre( - self.outfile, - " Straight sections (Pa)", - "(pdropstraight)", - dpres_straight, - "OP ", - ) - po.ovarre( - self.outfile, - " 90 degree bends (Pa)", - "(pdrop90)", - dpres_90, - "OP ", - ) - po.ovarre( - self.outfile, - " 180 degree bends (Pa)", - "(pdrop180)", - dpres_180, - "OP ", - ) + dpres_90 = f_elbow_90 * 0.5 * den_coolant * vel_coolant**2 + dpres_90_total = n_pipe_90_deg_bends * dpres_90 + dpres_180 = f_elbow_180 * 0.5 * den_coolant * vel_coolant**2 + dpres_180_total = n_pipe_180_deg_bends * dpres_180 - # TN: always write verbose stuff, it has no harm - po.ovarre( - self.outfile, - "Straight section pressure drop coefficient", - "(kstrght)", - f_straight, - "OP ", - ) - po.ovarre( - self.outfile, - "90 degree elbow coefficient", - "(kelbwn)", - f_elbow_90, - "OP ", - ) - po.ovarre( - self.outfile, - "180 degree elbow coefficient coefficient", - "(kelbwt)", - f_elbow_180, - "OP ", - ) + dpres_bends_total = dpres_90_total + dpres_180_total - return dpres_total + # Total pressure drop (Pa) + dpres_total = dpres_straight + dpres_bends_total + + return CoolantFrictionLossParameters( + dpres_total=dpres_total, + dpres_straight=dpres_straight, + dpres_90=dpres_90, + dpres_90_total=dpres_90_total, + dpres_180=dpres_180, + dpres_180_total=dpres_180_total, + dpres_bends_total=dpres_bends_total, + reynolds_number=reynolds_number, + darcy_friction_factor=darcy_friction_factor, + f_straight=f_straight, + len_straight=len_pipe, + f_elbow_90=f_elbow_90, + f_elbow_180=f_elbow_180, + ) def pipe_hydraulic_diameter(self, i_channel_shape): """Caculate the hydraulic diameter (m) for a given coolant pipe size/shape. @@ -3462,6 +3456,187 @@ def coolant_pumping_power( return pumppower + def output_blkt_pumping_variables(self): + + po.oheadr(self.outfile, "Blanket pumping variables") + + po.osubhd(self.outfile, "Inboard Blanket") + + po.ovarre( + self.outfile, + "Inboard blanket coolant channel length (radial direction) (m)", + "(len_blkt_inboard_coolant_channel_radial)", + self.data.blanket.len_blkt_inboard_coolant_channel_radial, + "OP ", + ) + po.ovarre( + self.outfile, + "Inboard blanket coolant channel length (toroidal direction) (m)", + "(len_blkt_inboard_segment_toroidal)", + self.data.blanket.len_blkt_inboard_segment_toroidal, + "OP ", + ) + po.ovarre( + self.outfile, + "Number of inboard blanket coolant sections in the radial direction", + "(n_blkt_inboard_module_coolant_sections_radial)", + self.data.fwbs.n_blkt_inboard_module_coolant_sections_radial, + "OP ", + ) + po.ovarre( + self.outfile, + "Number of inboard blanket coolant sections in the poloidal direction", + "(n_blkt_inboard_module_coolant_sections_poloidal)", + self.data.fwbs.n_blkt_inboard_module_coolant_sections_poloidal, + "OP ", + ) + po.ovarre( + self.outfile, + "Total length of inboard blanket coolant channel straight sections (m)", + "(len_blkt_inboard_channel_total)", + self.data.blanket.len_blkt_inboard_channel_total, + "OP ", + ) + + po.osubhd(self.outfile, "Outboard Blanket") + + po.ovarre( + self.outfile, + "Outboard blanket coolant channel length (radial direction) (m)", + "(len_blkt_outboard_coolant_channel_radial)", + self.data.blanket.len_blkt_outboard_coolant_channel_radial, + "OP ", + ) + po.ovarre( + self.outfile, + "Outboard blanket coolant channel length (toroidal direction) (m)", + "(len_blkt_outboard_segment_toroidal)", + self.data.blanket.len_blkt_outboard_segment_toroidal, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Number of outboard blanket coolant sections in the radial direction", + "(n_blkt_outboard_module_coolant_sections_radial)", + self.data.fwbs.n_blkt_outboard_module_coolant_sections_radial, + "OP ", + ) + po.ovarre( + self.outfile, + "Number of outboard blanket coolant sections in the poloidal direction", + "(n_blkt_outboard_module_coolant_sections_poloidal)", + self.data.fwbs.n_blkt_outboard_module_coolant_sections_poloidal, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Total length of outboard blanket coolant channel straight sections (m)", + "(len_blkt_outboard_channel_total)", + self.data.blanket.len_blkt_outboard_channel_total, + "OP ", + ) + po.oblnkl(self.outfile) + po.ocmmnt(self.outfile, "----------------------------") + + po.ovarre( + self.outfile, + "Pressure drop for straight sections of outboard blanket (Pa)", + "(dpres_blkt_outboard_coolant_channel_straight_total)", + self.data.blanket.dpres_blkt_outboard_coolant_channel_straight_total, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Pressure drop for 90° bends of outboard blanket (Pa)", + "(dpres_blkt_outboard_coolant_channel_90_bend)", + self.data.blanket.dpres_blkt_outboard_coolant_channel_90_bend, + "OP ", + ) + po.ovarre( + self.outfile, + "Total pressure drop for 90° bends of outboard blanket (Pa)", + "(dpres_blkt_outboard_coolant_channel_90_bends_total)", + self.data.blanket.dpres_blkt_outboard_coolant_channel_90_bends_total, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Pressure drop for 180° bends of outboard blanket (Pa)", + "(dpres_blkt_outboard_coolant_channel_180_bend)", + self.data.blanket.dpres_blkt_outboard_coolant_channel_180_bend, + "OP ", + ) + po.ovarre( + self.outfile, + "Total pressure drop for 180° bends of outboard blanket (Pa)", + "(dpres_blkt_outboard_coolant_channel_180_bends_total)", + self.data.blanket.dpres_blkt_outboard_coolant_channel_180_bends_total, + "OP ", + ) + + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Total pressure drop for all bends (Pa)", + "(dpres_blkt_outboard_bends_total)", + self.data.blanket.dpres_blkt_outboard_bends_total, + "OP ", + ) + + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Reynolds number of outboard blanket coolant", + "(reynolds_blkt_outboard_coolant)", + self.data.blanket.reynolds_blkt_outboard_coolant, + "OP ", + ) + + po.ovarre( + self.outfile, + "Darcy friction factor of outboard blanket coolant", + "(darcy_frict_blkt_outboard_coolant)", + self.data.blanket.darcy_frict_blkt_outboard_coolant, + "OP ", + ) + po.oblnkl(self.outfile) + + po.ovarre( + self.outfile, + "Pressure drop coefficient for straight sections of outboard blanket", + "(f_straight_blkt_outboard_coolant)", + self.data.blanket.f_straight_blkt_outboard_coolant, + "OP ", + ) + + po.ovarre( + self.outfile, + "Total length of straight sections of outboard blanket coolant channels (m)", + "(len_blkt_outboard_coolant_channel_straight_total)", + self.data.blanket.len_blkt_outboard_coolant_channel_straight_total, + "OP ", + ) + + po.ovarre( + self.outfile, + "Pressure drop coefficient for 90° bends in outboard blanket", + "(f_elbow_blkt_outboard_90_bend)", + self.data.blanket.f_elbow_blkt_outboard_90_bend, + "OP ", + ) + + po.ovarre( + self.outfile, + "Pressure drop coefficient for 180° bends in outboard blanket", + "(f_elbow_blkt_outboard_180_bend)", + self.data.blanket.f_elbow_blkt_outboard_180_bend, + "OP ", + ) + class OutboardBlanket(BlanketLibrary): def calculate_basic_geometry(self): diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index 9f2f1acbe3..f2bac5cfd2 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -3,6 +3,7 @@ import logging from enum import IntEnum from types import DynamicClassAttribute +from dataclasses import dataclass import numpy as np @@ -45,6 +46,38 @@ def full_name(self): logger = logging.getLogger(__name__) +@dataclass +class CoolantFrictionLossParameters: + """Parameters for calculating coolant friction losses.""" + + dpres_total: float + """Total pressure drop across the coolant channel (Pa)""" + dpres_straight: float + """Pressure drop due to straight length of the coolant channel (Pa)""" + dpres_90: float + """Pressure drop due to 90 degree bends in the coolant channel (Pa)""" + dpres_90_total: float + """Total pressure drop due to 90 degree bends in the coolant channel (Pa)""" + dpres_180: float + """Pressure drop due to 180 degree bends in the coolant channel (Pa)""" + dpres_180_total: float + """Total pressure drop due to 180 degree bends in the coolant channel (Pa)""" + dpres_bends_total: float + """Total pressure drop due to bends in the coolant channel (Pa)""" + reynolds_number: float + """Reynolds number of the coolant flow in the channel""" + darcy_friction_factor: float + """Darcy friction factor for the coolant flow in the channel""" + f_straight: float + """Friction factor for straight length of the coolant channel""" + len_straight: float + """Length of straight sections of the coolant channel (m)""" + f_elbow_90: float + """Friction factor for 90 degree bends in the coolant channel""" + f_elbow_180: float + """Friction factor for 180 degree bends in the coolant channel""" + + def darcy_friction_haaland( reynolds: float, roughness_channel: float, radius_channel: float ) -> float: diff --git a/tests/unit/models/blankets/test_blanket_library.py b/tests/unit/models/blankets/test_blanket_library.py index f6741bd992..bb02e62c55 100644 --- a/tests/unit/models/blankets/test_blanket_library.py +++ b/tests/unit/models/blankets/test_blanket_library.py @@ -1118,7 +1118,6 @@ def test_pressure_drop(pressuredropparam, monkeypatch, blanket_library): den_coolant=pressuredropparam.den, visc_coolant=pressuredropparam.vsc, vel_coolant=pressuredropparam.vv, - label=pressuredropparam.label, ) assert pressure_drop_out == pytest.approx( From 7deab95d34e1eec30dba5b260c9228c5a527ee42 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 4 Jun 2026 16:40:38 +0100 Subject: [PATCH 04/18] Add function to plot blanket coolant channel structure and update main plot --- process/core/io/plot/summary.py | 238 ++++++++++++++++++++- process/models/blankets/blanket_library.py | 1 - process/models/blankets/hcpb.py | 47 ++++ 3 files changed, 284 insertions(+), 2 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 399a2e9928..b7a3b7221e 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -15301,6 +15301,239 @@ def plot_cs_radial_stress_profile( axis.legend(loc="best") +def plot_blanket_coolant_channel_structure(self, m_file: MFile, scan: int): + """Plot a schematic of the blanket coolant channel routing.""" + len_blkt_outboard_coolant_channel_radial = float( + m_file.get("len_blkt_outboard_coolant_channel_radial", scan=scan) + ) + len_blkt_outboard_segment_toroidal = float( + m_file.get("len_blkt_outboard_segment_toroidal", scan=scan) + ) + n_blkt_outboard_module_coolant_sections_radial = max( + 1, + int( + round( + m_file.get("n_blkt_outboard_module_coolant_sections_radial", scan=scan) + ) + ), + ) + n_blkt_outboard_module_coolant_sections_poloidal = max( + 1, + int( + round( + m_file.get("n_blkt_outboard_module_coolant_sections_poloidal", scan=scan) + ) + ), + ) + elbow_radius_180 = max( + float(m_file.get("radius_blkt_channel_180_bend", scan=scan)), 1e-6 + ) + r = max(float(m_file.get("radius_blkt_channel", scan=scan)), 1e-6) + elbow_radius_90 = max( + float(m_file.get("radius_blkt_channel_90_bend", scan=scan)), 1e-6 + ) + + axis = self if isinstance(self, Axes) else getattr(self, "ax", None) + figure = axis.figure if isinstance(axis, Axes) else None + + if not isinstance(axis, Axes): + figure, axis = plt.subplots(figsize=(10, 6)) + + def _plot_straight( + x0: float, + y0: float, + x1: float, + y1: float, + *, + label: str | None = None, + alpha: float = 1.0, + ): + axis.plot( + [x0, x1], + [y0, y1], + color="tab:blue", + linewidth=2.5, + solid_capstyle="round", + alpha=alpha, + label=label, + ) + + def _plot_bend( + centre_x: float, + centre_y: float, + radius: float, + theta_start: float, + theta_end: float, + *, + label: str | None = None, + alpha: float = 1.0, + ): + theta = np.linspace(theta_start, theta_end, 80) + axis.plot( + centre_x + radius * np.cos(theta), + centre_y + radius * np.sin(theta), + color="tab:orange", + linewidth=2.5, + solid_capstyle="round", + alpha=alpha, + label=label, + ) + + lane_pitch = 2.0 * elbow_radius_180 + poloidal_section_length = max(4.0 * r, 1.5 * elbow_radius_90) + + show_radial_label = True + show_poloidal_label = True + show_90_label = True + + inlet_x = 0.0 + x_left = elbow_radius_90 + x_right = elbow_radius_90 + len_blkt_outboard_coolant_channel_radial + y_lower = 0.0 + y_upper = y_lower + lane_pitch + y_inlet_lower = y_lower - elbow_radius_90 - poloidal_section_length + y_outlet_upper = y_upper + elbow_radius_90 + poloidal_section_length + + _plot_straight( + inlet_x, + y_inlet_lower, + inlet_x, + y_lower - elbow_radius_90, + label="Straight poloidal section" if show_poloidal_label else None, + ) + show_poloidal_label = False + + _plot_bend( + elbow_radius_90, + y_lower - elbow_radius_90, + elbow_radius_90, + np.pi, + np.pi / 2.0, + label="90° bend" if show_90_label else None, + ) + show_90_label = False + + _plot_straight( + x_left, + y_lower, + x_right, + y_lower, + label="Straight radial section" if show_radial_label else None, + ) + show_radial_label = False + + _plot_bend( + x_right, + y_lower + elbow_radius_180, + elbow_radius_180, + -np.pi / 2.0, + np.pi / 2.0, + label="180° bend", + ) + + _plot_straight( + x_right, + y_upper, + x_left, + y_upper, + label="Straight radial section" if show_radial_label else None, + ) + + _plot_bend( + x_left, + y_upper + elbow_radius_90, + elbow_radius_90, + 3.0 * np.pi / 2.0, + np.pi, + label="90° bend" if show_90_label else None, + ) + + _plot_straight( + inlet_x, + y_upper + elbow_radius_90, + inlet_x, + y_outlet_upper, + label="Straight poloidal section" if show_poloidal_label else None, + ) + + total_180_bends = 1 + total_90_bends = 2 + total_poloidal_sections = 2 + length_per_90_bend = 0.5 * np.pi * elbow_radius_90 + length_per_180_bend = np.pi * elbow_radius_180 + length_per_poloidal_section = poloidal_section_length + total_radial_channel_length = ( + n_blkt_outboard_module_coolant_sections_radial + * len_blkt_outboard_coolant_channel_radial + ) + total_poloidal_length = total_poloidal_sections * length_per_poloidal_section + total_bend_length = ( + total_90_bends * length_per_90_bend + total_180_bends * length_per_180_bend + ) + total_channel_length = ( + total_radial_channel_length + total_poloidal_length + total_bend_length + ) + info = textwrap.dedent( + f""" + Representative continuous channel loop + Straight radial sections: {n_blkt_outboard_module_coolant_sections_radial} + Straight radial length per channel: {total_radial_channel_length:.2f} m + Straight poloidal sections per loop: {total_poloidal_sections} + Straight poloidal length: {length_per_poloidal_section:.2f} m each + 90° bends per channel: {total_90_bends} + 90° bend length: {length_per_90_bend:.2f} m each + 180° bends per channel: {total_180_bends} + 180° bend length: {length_per_180_bend:.2f} m each + Total poloidal length per channel: {total_poloidal_length:.2f} m + Total bend length per channel: {total_bend_length:.2f} m + Approx. total channel length: {total_channel_length:.2f} m + Poloidal sections per module: {n_blkt_outboard_module_coolant_sections_poloidal} + Toroidal span per segment: {len_blkt_outboard_segment_toroidal:.2f} m + Channel radius: {r:.3f} m + """ + ).strip() + + axis.text( + 1.02, + 0.98, + info, + transform=axis.transAxes, + va="top", + ha="left", + fontsize=8, + bbox={"boxstyle": "round", "facecolor": "white", "alpha": 0.9}, + ) + + axis.text( + 0.02, + 0.02, + "Continuous loop schematic with a single 180° return bend", + transform=axis.transAxes, + fontsize=8, + color="dimgray", + ) + + axis.set_title("Blanket coolant channel structure") + axis.set_xlabel("Radial direction [m]") + axis.set_ylabel("Channel layout [schematic m]") + axis.set_aspect("equal", adjustable="box") + axis.grid(True, alpha=0.25) + axis.minorticks_on() + axis.legend(fontsize=8, loc="upper right") + + x_margin = len_blkt_outboard_coolant_channel_radial * 0.1 + 2.0 * elbow_radius_90 + axis.set_xlim(-x_margin, x_right + x_margin) + axis.set_ylim( + y_inlet_lower - r, + y_outlet_upper + r, + ) + + if figure is not None: + figure.tight_layout() + + return axis + + def main_plot( figs: list[Axes], m_file: MFile, @@ -15713,6 +15946,9 @@ def main_plot( ax24.set_position([0.08, 0.35, 0.84, 0.57]) plot_system_power_profiles_over_time(ax24, m_file, scan, figs[36]) + plot_blanket_coolant_channel_structure(figs[37].add_subplot(111), m_file, scan) + + def create_thickness_builds(m_file, scan: int): # Build the dictionaries of radial and vertical build values and cumulative values @@ -15817,7 +16053,7 @@ def add_page_footer( # create main plot # Increase range when adding new page - pages = [plt.figure(figsize=(12, 9), dpi=80) for i in range(37)] + pages = [plt.figure(figsize=(12, 9), dpi=80) for i in range(38)] # run main_plot mfile_obj = MFile(mfile) if mfile != "" else MFile("MFILE.DAT") diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 2dd4b56d55..22aadff8ef 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -2457,7 +2457,6 @@ def thermo_hydraulic_model(self, output: bool): deltap = self.thermo_hydraulic_model_pressure_drop_calculations( output=output ) - print(deltap) deltap_fwi = deltap[0] deltap_fwo = deltap[1] deltap_blo = deltap[2] diff --git a/process/models/blankets/hcpb.py b/process/models/blankets/hcpb.py index 4187fe05cb..e35dad9148 100644 --- a/process/models/blankets/hcpb.py +++ b/process/models/blankets/hcpb.py @@ -847,6 +847,53 @@ def powerflow_calc(self, output: bool): + self.data.fwbs.p_div_rad_total_mw ) ) + if output: + po.ovarre( + self.outfile, + "Mechanical pumping power for FW and blanket cooling loop including heat exchanger (MW)", + "(p_fw_blkt_coolant_pump_mw)", + self.data.primary_pumping.p_fw_blkt_coolant_pump_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Pumping power for FW and Blanket multiplier factor", + "(f_p_fw_blkt_pump)", + self.data.primary_pumping.f_p_fw_blkt_pump, + "IP ", + ) + po.ovarre( + self.outfile, + "Mechanical pumping power for divertor (MW)", + "(p_div_coolant_pump_mw)", + self.data.heat_transport.p_div_coolant_pump_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Mechanical pumping power for shield and vacuum vessel (MW)", + "(p_shld_coolant_pump_mw)", + self.data.heat_transport.p_shld_coolant_pump_mw, + "OP ", + ) + po.ovarre( + self.outfile, + "Radius of blanket cooling channels (m)", + "(radius_blkt_channel)", + self.data.fwbs.radius_blkt_channel, + ) + po.ovarre( + self.outfile, + "Radius of 90 degree coolant channel bend (m)", + "(radius_blkt_channel_90_bend)", + self.data.fwbs.radius_blkt_channel_90_bend, + ) + po.ovarre( + self.outfile, + "Radius of 180 degree coolant channel bend (m)", + "(radius_blkt_channel_180_bend)", + self.data.fwbs.radius_blkt_channel_180_bend, + ) elif i_p_coolant_pumping == PumpingPowerModelTypes.MECHANICAL_WITH_PRESSURE_DROP: # Issue #503 From 777783a4c85d95b3b437bb0292b008fb30f77cff Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Jun 2026 10:58:10 +0100 Subject: [PATCH 05/18] Refactor pressure drop assertions in blanket tests for clarity and consistency --- .../unit/models/blankets/test_blanket_library.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/unit/models/blankets/test_blanket_library.py b/tests/unit/models/blankets/test_blanket_library.py index bb02e62c55..770e50f17a 100644 --- a/tests/unit/models/blankets/test_blanket_library.py +++ b/tests/unit/models/blankets/test_blanket_library.py @@ -301,10 +301,8 @@ def test_deltap_tot_inboard_first_wall(monkeypatch, blanket_library): "label": "Inboard first wall", } - assert ( - pytest.approx(blanket_library.total_pressure_drop(False, **data)) - == 5884.982168510442 - ) + dpres_total, _ = blanket_library.total_pressure_drop(False, **data) + assert dpres_total == pytest.approx(5884.982168510442) def test_deltap_tot_outboard_blanket_breeder_liquid(monkeypatch, blanket_library): @@ -332,10 +330,8 @@ def test_deltap_tot_outboard_blanket_breeder_liquid(monkeypatch, blanket_library "label": "Outboard blanket breeder liquid", } - assert ( - pytest.approx(blanket_library.total_pressure_drop(False, **data)) - == 56.95922064419226 - ) + dpres_total, _ = blanket_library.total_pressure_drop(False, **data) + assert dpres_total == pytest.approx(56.95922064419226) def test_pumppower_primary_helium(monkeypatch, blanket_library): @@ -1108,7 +1104,7 @@ def test_pressure_drop(pressuredropparam, monkeypatch, blanket_library): pressuredropparam.roughness_fw_channel, ) - pressure_drop_out = blanket_library.coolant_friction_pressure_drop( + pressure_params = blanket_library.coolant_friction_pressure_drop( i_ps=pressuredropparam.i_ps, radius_pipe_90_deg_bend=pressuredropparam.radius_pipe_90_deg_bend, radius_pipe_180_deg_bend=pressuredropparam.radius_pipe_180_deg_bend, @@ -1120,7 +1116,7 @@ def test_pressure_drop(pressuredropparam, monkeypatch, blanket_library): vel_coolant=pressuredropparam.vv, ) - assert pressure_drop_out == pytest.approx( + assert pressure_params.dpres_total == pytest.approx( pressuredropparam.expected_pressure_drop_out ) From ce16e534feaf003425c760f623251aa31dc96e59 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Jun 2026 14:30:55 +0100 Subject: [PATCH 06/18] Add function to plot outboard blanket coolant properties along the poloidal direction --- process/core/io/plot/summary.py | 100 ++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index b7a3b7221e..a42c3d4d56 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -7,11 +7,14 @@ from pathlib import Path from typing import Any, Literal +import CoolProp import matplotlib as mpl import matplotlib.backends.backend_pdf as bpdf import matplotlib.image as mpimg import matplotlib.pyplot as plt import numpy as np +from CoolProp.CoolProp import PropsSI +from CoolProp.Plots import PropertyPlot from matplotlib import patches from matplotlib.axes import Axes from matplotlib.patches import Circle, Rectangle @@ -15534,6 +15537,102 @@ def _plot_bend( return axis +def plot_outboard_blanket_coolant_properties(fig: plt.Figure, m_file: MFile, scan: int): + """Plots the properties of the outboard blanket coolant along the poloidal direction.""" + temp_blkt_coolant_in = float(m_file.get("temp_blkt_coolant_in", scan=scan)) + temp_blkt_coolant_out = float(m_file.get("temp_blkt_coolant_out", scan=scan)) + pres_blkt_coolant = float(m_file.get("pres_blkt_coolant", scan=scan)) + dens_blkt_coolant_in = PropsSI( + "Dmass", "T", temp_blkt_coolant_in, "P", pres_blkt_coolant, "Helium" + ) + dens_blkt_coolant_out = PropsSI( + "Dmass", "T", temp_blkt_coolant_out, "P", pres_blkt_coolant, "Helium" + ) + + fig.clear() + axes = fig.subplots(2, 2) + + axis = axes[0, 0] + + plot = PropertyPlot("Helium", "PH", axis=axis, unit_system="SI") + + # #axis.set_xscale('log') + axis.set_ylim(((pres_blkt_coolant) * 0.9), (pres_blkt_coolant) * 1.5) + # plot.set_axis_limits([None, None, (pres_blkt_coolant/1e3)*0.9, (pres_blkt_coolant/1e3)*1.1]) + + plot.calc_isolines(CoolProp.iT) # Temperature + plot.calc_isolines(CoolProp.iSmass) # Entropy + plot.calc_isolines(CoolProp.iDmass) # Density + # plot.axis.relim() + # plot.axis.autoscale_view() + plot.draw() + + axis.set_title("Pressure-enthalpy plot") + + axis = axes[0, 1] + plot = PropertyPlot("Helium", "TD", axis=axis, unit_system="SI") + + density_min = min(dens_blkt_coolant_in, dens_blkt_coolant_out) + density_max = max(dens_blkt_coolant_in, dens_blkt_coolant_out) + temperature_min = min(temp_blkt_coolant_in, temp_blkt_coolant_out) + temperature_max = max(temp_blkt_coolant_in, temp_blkt_coolant_out) + + density_margin = max((density_max - density_min) * 0.2, max(density_max, 1.0) * 0.05) + temperature_margin = max( + (temperature_max - temperature_min) * 0.2, + max(temperature_max, 1.0) * 0.05, + ) + + axis.set_xlim(density_min - density_margin, density_max + density_margin) + axis.set_ylim( + temperature_min - temperature_margin, temperature_max + temperature_margin + ) + + plot.calc_isolines(CoolProp.iP) # Pressure + plot.calc_isolines(CoolProp.iHmass) # Enthalpy + plot.draw() + + axis.plot( + [dens_blkt_coolant_in, dens_blkt_coolant_out], + [temp_blkt_coolant_in, temp_blkt_coolant_out], + color="C3", + marker="o", + linewidth=1.5, + label="Coolant path", + ) + axis.legend(fontsize=8, loc="best") + axis.set_title("Temperature-density plot") + + axis = axes[1, 0] + plot = PropertyPlot("Helium", "PD", axis=axis, unit_system="SI") + + pressure_margin = max(pres_blkt_coolant * 0.1, 1.0) + + axis.set_xlim(density_min - density_margin, density_max + density_margin) + axis.set_ylim( + pres_blkt_coolant - pressure_margin, pres_blkt_coolant + pressure_margin + ) + + plot.calc_isolines(CoolProp.iT) # Temperature + plot.calc_isolines(CoolProp.iHmass) # Enthalpy + plot.draw() + + axis.plot( + [dens_blkt_coolant_in, dens_blkt_coolant_out], + [pres_blkt_coolant, pres_blkt_coolant], + color="C3", + marker="o", + linewidth=1.5, + label="Coolant path", + ) + axis.legend(fontsize=8, loc="best") + axis.set_title("Pressure-density plot") + + axes[1, 1].axis("off") + + fig.tight_layout() + + def main_plot( figs: list[Axes], m_file: MFile, @@ -15948,6 +16047,7 @@ def main_plot( plot_blanket_coolant_channel_structure(figs[37].add_subplot(111), m_file, scan) + plot_outboard_blanket_coolant_properties(figs[37], m_file, scan) def create_thickness_builds(m_file, scan: int): From 5854071208c24dfe04a6114865cc29385031767f Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Jun 2026 17:17:45 +0100 Subject: [PATCH 07/18] Tidy some variable names to match style guide --- process/models/blankets/blanket_library.py | 85 +++++++++++++--------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 22aadff8ef..e1adb39e14 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -2263,26 +2263,26 @@ def thermo_hydraulic_model(self, output: bool): self.data.build.i_blkt_inboard == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): - fwoutleti = (f_nuc_fwi * self.data.fwbs.temp_blkt_coolant_out) + ( - 1 - f_nuc_fwi - ) * self.data.fwbs.temp_fw_coolant_in - inlet_tempi = fwoutleti + temp_fw_coolant_out = ( + f_nuc_fwi * self.data.fwbs.temp_blkt_coolant_out + ) + (1 - f_nuc_fwi) * self.data.fwbs.temp_fw_coolant_in + temp_blkt_coolant_in = temp_fw_coolant_out else: - fwoutleti = self.data.fwbs.temp_fw_coolant_out + temp_fw_coolant_out = self.data.fwbs.temp_fw_coolant_out - fwoutleto = (f_nuc_fwo * self.data.fwbs.temp_blkt_coolant_out) + ( + temp_fw_coolant_out = (f_nuc_fwo * self.data.fwbs.temp_blkt_coolant_out) + ( 1 - f_nuc_fwo ) * self.data.fwbs.temp_fw_coolant_in - inlet_tempo = fwoutleto + temp_blkt_coolant_in = temp_fw_coolant_out elif ( self.data.fwbs.i_fw_blkt_shared_coolant == FWBlktCoolantLoopTypes.SEPARATE_LOOPS ): - fwoutleti = self.data.fwbs.temp_fw_coolant_out - inlet_tempi = self.data.fwbs.temp_blkt_coolant_in - fwoutleto = self.data.fwbs.temp_fw_coolant_out - inlet_tempo = self.data.fwbs.temp_blkt_coolant_in + temp_fw_coolant_out = self.data.fwbs.temp_fw_coolant_out + temp_blkt_coolant_in = self.data.fwbs.temp_blkt_coolant_in + temp_fw_coolant_out = self.data.fwbs.temp_fw_coolant_out + temp_blkt_coolant_in = self.data.fwbs.temp_blkt_coolant_in # Maximum FW temperature. (27/11/2015) Issue #348 # First wall flow is just along the first wall, with no allowance for radial @@ -2327,13 +2327,19 @@ def thermo_hydraulic_model(self, output: bool): self.data.blanket.mflow_fw_inboard_coolant_total = ( 1.0e6 * (self.data.blanket.p_fw_inboard_nuclear_heat_mw + self.data.fwbs.psurffwi) - / (self.data.fwbs.cp_fw * (fwoutleti - self.data.fwbs.temp_fw_coolant_in)) + / ( + self.data.fwbs.cp_fw + * (temp_fw_coolant_out - self.data.fwbs.temp_fw_coolant_in) + ) ) # Total mass flow rate to remove outboard FW power (kg/s) self.data.blanket.mflow_fw_outboard_coolant_total = ( 1.0e6 * (self.data.blanket.p_fw_outboard_nuclear_heat_mw + self.data.fwbs.psurffwo) - / (self.data.fwbs.cp_fw * (fwoutleto - self.data.fwbs.temp_fw_coolant_in)) + / ( + self.data.fwbs.cp_fw + * (temp_fw_coolant_out - self.data.fwbs.temp_fw_coolant_in) + ) ) # If the blanket is dual-coolant... @@ -2344,7 +2350,7 @@ def thermo_hydraulic_model(self, output: bool): * (pnucblkto_struct) / ( self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - inlet_tempo) + * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) ) ) self.data.blanket.mfblkto_liq = ( @@ -2367,7 +2373,7 @@ def thermo_hydraulic_model(self, output: bool): * (pnucblkti_struct) / ( self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - inlet_tempi) + * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) ) ) self.data.blanket.mfblkti_liq = ( @@ -2390,7 +2396,7 @@ def thermo_hydraulic_model(self, output: bool): * (self.data.blanket.p_blkt_nuclear_heat_outboard_mw) / ( self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - inlet_tempo) + * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) ) ) @@ -2412,7 +2418,7 @@ def thermo_hydraulic_model(self, output: bool): * (self.data.blanket.p_blkt_nuclear_heat_inboard_mw) / ( self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - inlet_tempi) + * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) ) ) # Mass flow rate for inboard breeder flow (kg/s) @@ -2428,7 +2434,7 @@ def thermo_hydraulic_model(self, output: bool): * (self.data.blanket.p_blkt_nuclear_heat_outboard_mw) / ( self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - inlet_tempo) + * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) ) ) @@ -2443,7 +2449,7 @@ def thermo_hydraulic_model(self, output: bool): * (self.data.blanket.p_blkt_nuclear_heat_inboard_mw) / ( self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - inlet_tempi) + * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) ) ) @@ -2457,15 +2463,15 @@ def thermo_hydraulic_model(self, output: bool): deltap = self.thermo_hydraulic_model_pressure_drop_calculations( output=output ) - deltap_fwi = deltap[0] - deltap_fwo = deltap[1] - deltap_blo = deltap[2] + dpres_fw_inboard_coolant = deltap[0] + dpres_fw_outboard_coolant = deltap[1] + dpres_blkt_outboard_coolant = deltap[2] if self.data.fwbs.i_blkt_dual_coolant > 0: if ( self.data.build.i_blkt_inboard == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): - deltap_bli = deltap[3] + dpres_blkt_inboard_coolant = deltap[3] deltap_blo_liq = deltap[4] deltap_bli_liq = deltap[5] else: @@ -2474,7 +2480,7 @@ def thermo_hydraulic_model(self, output: bool): self.data.build.i_blkt_inboard == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): - deltap_bli = deltap[3] + dpres_blkt_inboard_coolant = deltap[3] # Pumping Power # If FW and BB have the same coolant... @@ -2485,12 +2491,21 @@ def thermo_hydraulic_model(self, output: bool): self.data.build.i_blkt_inboard == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): - deltap_fw_blkt = deltap_fwi + deltap_bli + deltap_fwo + deltap_blo + deltap_fw_blkt = ( + dpres_fw_inboard_coolant + + dpres_blkt_inboard_coolant + + dpres_fw_outboard_coolant + + dpres_blkt_outboard_coolant + ) if ( self.data.build.i_blkt_inboard == InboardBlanketConfiguration.NO_INBOARD_BLANKET ): - deltap_fw_blkt = deltap_fwi + deltap_fwo + deltap_blo + deltap_fw_blkt = ( + dpres_fw_inboard_coolant + + dpres_fw_outboard_coolant + + dpres_blkt_outboard_coolant + ) elif ( i_p_coolant_pumping == PumpingPowerModelTypes.MECHANICAL_WITH_PRESSURE_DROP @@ -2525,25 +2540,29 @@ def thermo_hydraulic_model(self, output: bool): ): if i_p_coolant_pumping == PumpingPowerModelTypes.MECHANICAL: # Total pressure drop in the first wall (Pa) - deltap_fw = deltap_fwi + deltap_fwo + dpres_fw_coolant_total = ( + dpres_fw_inboard_coolant + dpres_fw_outboard_coolant + ) # Total pressure drop in the blanket (Pa) if ( self.data.build.i_blkt_inboard == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): - deltap_blkt = deltap_bli + deltap_blo + dpres_blkt_coolant_total = ( + dpres_blkt_inboard_coolant + dpres_blkt_outboard_coolant + ) if ( self.data.build.i_blkt_inboard == InboardBlanketConfiguration.NO_INBOARD_BLANKET ): - deltap_blkt = deltap_blo + dpres_blkt_coolant_total = dpres_blkt_outboard_coolant elif ( i_p_coolant_pumping == PumpingPowerModelTypes.MECHANICAL_WITH_PRESSURE_DROP ): - deltap_fw = self.data.primary_pumping.dp_fw - deltap_blkt = self.data.primary_pumping.dp_blkt + dpres_fw_coolant_total = self.data.primary_pumping.dp_fw + dpres_blkt_coolant_total = self.data.primary_pumping.dp_blkt # Total coolant mass flow rate in the first wall (kg/s) self.data.blanket.mflow_fw_coolant_total = ( @@ -2563,7 +2582,7 @@ def thermo_hydraulic_model(self, output: bool): temp_coolant_pump_outlet=self.data.fwbs.temp_fw_coolant_in, temp_coolant_pump_inlet=self.data.fwbs.temp_fw_coolant_out, pres_coolant_pump_inlet=self.data.fwbs.pres_fw_coolant, - dpres_coolant=deltap_fw, + dpres_coolant=dpres_fw_coolant_total, mflow_coolant_total=self.data.blanket.mflow_fw_coolant_total, i_coolant_type=self.data.fwbs.i_fw_coolant_type, den_coolant=self.data.fwbs.den_fw_coolant, @@ -2577,7 +2596,7 @@ def thermo_hydraulic_model(self, output: bool): temp_coolant_pump_outlet=self.data.fwbs.temp_blkt_coolant_in, temp_coolant_pump_inlet=self.data.fwbs.temp_blkt_coolant_out, pres_coolant_pump_inlet=self.data.fwbs.pres_blkt_coolant, - dpres_coolant=deltap_blkt, + dpres_coolant=dpres_blkt_coolant_total, mflow_coolant_total=self.data.blanket.mflow_blkt_coolant_total, i_coolant_type=(self.data.fwbs.i_blkt_coolant_type), den_coolant=self.data.fwbs.den_blkt_coolant, From 7ba0551883eeac48ee9db009e101830237a5c418 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Jun 2026 18:04:26 +0100 Subject: [PATCH 08/18] Create mass flow required function and implement --- .../eng-models/generic_methods/pumping.md | 30 ++++- process/models/blankets/blanket_library.py | 124 ++++++++++-------- process/models/engineering/pumping.py | 34 +++++ tests/unit/models/engineering/test_pumping.py | 29 ++++ 4 files changed, 159 insertions(+), 58 deletions(-) diff --git a/documentation/source/eng-models/generic_methods/pumping.md b/documentation/source/eng-models/generic_methods/pumping.md index 7bd3a1dc4e..7047b42199 100644 --- a/documentation/source/eng-models/generic_methods/pumping.md +++ b/documentation/source/eng-models/generic_methods/pumping.md @@ -87,4 +87,32 @@ The elbow coefficient is given by: $$ ab + \left( f_{\text{D}} \times \frac{R_{\text{elbow}}}{D_{\text{pipe}}}\right) \times \theta \times \left(\frac{\pi}{180^{\circ}}\right) -$$ \ No newline at end of file +$$ + +-------------- + +## Required mass flow rate | `calculate_required_mass_flow_rate()` + +The required mass flow rate of a coolant is given simply by the fundamental heat transfer equation: + +$$ +\dot{m} = \frac{P}{c_{\text{p}}(T)\times \Delta T} +$$ + +where $\dot{m}$ is the required mass flow rate in, $P$ is the heating power to be removed, $c_{\text{p}}$ is the coolant specific heat capacity for constant pressure and $\Delta T$ is the temperature change in the coolant. + +!!! note "Variation specific heat capacity" + + The heat capacity itself is a function of temperature. Therefore it is common to use the heat capacity value at the simple average between the initial and final temperature. + This however assumes a linear relationship. Ideally the equation should be solves as: + + $$ + \dot{m} = \frac{P}{\int_{T_{\text{in}}}^{T_{\text{in}}}c_{\text{p}}(T) dT} + $$ + + +!!! info "Choice of specific heat capacity" + + For pumping, the specific heat capacity for constant pressure $(c_{\text{p}})$ is used as cooling loops are open-flow systems where the fluid moves continuously through pipes, heat exchangers, and pumps. As the coolant heats up, it expands freely along the loop. Because it is free to expand, the local pressure remains relatively constant while the volume changes. + + You would only use the specific heat capacity for constant volume $(c_{\text{v}})$ if the coolant was completely sealed inside a rigid, unyielding container with zero flow, where heating it would cause the pressure to spike but the volume to stay exactly the same. \ No newline at end of file diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index e1adb39e14..e9f791ccb6 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -23,6 +23,7 @@ from process.models.engineering.pumping import ( CoolantType, CoolantFrictionLossParameters, + calculate_required_mass_flow_rate, calculate_reynolds_number, darcy_friction_haaland, elbow_coeff, @@ -2325,20 +2326,29 @@ def thermo_hydraulic_model(self, output: bool): # Total mass flow rate to remove inboard FW power (kg/s) self.data.blanket.mflow_fw_inboard_coolant_total = ( - 1.0e6 - * (self.data.blanket.p_fw_inboard_nuclear_heat_mw + self.data.fwbs.psurffwi) - / ( - self.data.fwbs.cp_fw - * (temp_fw_coolant_out - self.data.fwbs.temp_fw_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 + * ( + self.data.blanket.p_fw_inboard_nuclear_heat_mw + + self.data.fwbs.psurffwi + ), + heatcap_coolant=self.data.fwbs.cp_fw, + temp_in_coolant=temp_fw_coolant_out, + temp_out_coolant=self.data.fwbs.temp_fw_coolant_in, ) ) + # Total mass flow rate to remove outboard FW power (kg/s) self.data.blanket.mflow_fw_outboard_coolant_total = ( - 1.0e6 - * (self.data.blanket.p_fw_outboard_nuclear_heat_mw + self.data.fwbs.psurffwo) - / ( - self.data.fwbs.cp_fw - * (temp_fw_coolant_out - self.data.fwbs.temp_fw_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 + * ( + self.data.blanket.p_fw_outboard_nuclear_heat_mw + + self.data.fwbs.psurffwo + ), + heatcap_coolant=self.data.fwbs.cp_fw, + temp_in_coolant=temp_fw_coolant_out, + temp_out_coolant=self.data.fwbs.temp_fw_coolant_in, ) ) @@ -2346,20 +2356,19 @@ def thermo_hydraulic_model(self, output: bool): if self.data.fwbs.i_blkt_dual_coolant == 2: # Mass flow rates for outboard blanket coolants (kg/s) self.data.blanket.mflow_blkt_outboard_coolant = ( - 1.0e6 - * (pnucblkto_struct) - / ( - self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 * pnucblkto_struct, + heatcap_coolant=self.data.fwbs.cp_bl, + temp_in_coolant=temp_blkt_coolant_in, + temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) ) - self.data.blanket.mfblkto_liq = ( - 1.0e6 - * (pnucblkto_liq) - / ( - self.data.fwbs.specific_heat_liq - * (self.data.fwbs.outlet_temp_liq - self.data.fwbs.inlet_temp_liq) - ) + + self.data.blanket.mfblkto_liq = calculate_required_mass_flow_rate( + p_heat_total=1.0e6 * pnucblkto_liq, + heatcap_coolant=self.data.fwbs.specific_heat_liq, + temp_in_coolant=self.data.fwbs.inlet_temp_liq, + temp_out_coolant=self.data.fwbs.outlet_temp_liq, ) # If there is an IB blanket... @@ -2369,34 +2378,31 @@ def thermo_hydraulic_model(self, output: bool): ): # Mass flow rates for inboard blanket coolants (kg/s) self.data.blanket.mflow_blkt_inboard_coolant = ( - 1.0e6 - * (pnucblkti_struct) - / ( - self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 * pnucblkti_struct, + heatcap_coolant=self.data.fwbs.cp_bl, + temp_in_coolant=temp_blkt_coolant_in, + temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) ) - self.data.blanket.mfblkti_liq = ( - 1.0e6 - * (pnucblkti_liq) - / ( - self.data.fwbs.specific_heat_liq - * ( - self.data.fwbs.outlet_temp_liq - - self.data.fwbs.inlet_temp_liq - ) - ) + + self.data.blanket.mfblkti_liq = calculate_required_mass_flow_rate( + p_heat_total=1.0e6 * pnucblkti_liq, + heatcap_coolant=self.data.fwbs.specific_heat_liq, + temp_in_coolant=self.data.fwbs.inlet_temp_liq, + temp_out_coolant=self.data.fwbs.outlet_temp_liq, ) # If the blanket is single-coolant with liquid metal breeder... elif self.data.fwbs.i_blkt_dual_coolant == 1: # Mass flow rate for outboard blanket coolant (kg/s) self.data.blanket.mflow_blkt_outboard_coolant = ( - 1.0e6 - * (self.data.blanket.p_blkt_nuclear_heat_outboard_mw) - / ( - self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 + * self.data.blanket.p_blkt_nuclear_heat_outboard_mw, + heatcap_coolant=self.data.fwbs.cp_bl, + temp_in_coolant=temp_blkt_coolant_in, + temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) ) @@ -2414,13 +2420,15 @@ def thermo_hydraulic_model(self, output: bool): ): # Mass flow rate for inboard blanket coolant (kg/s) self.data.blanket.mflow_blkt_inboard_coolant = ( - 1.0e6 - * (self.data.blanket.p_blkt_nuclear_heat_inboard_mw) - / ( - self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 + * self.data.blanket.p_blkt_nuclear_heat_inboard_mw, + heatcap_coolant=self.data.fwbs.cp_bl, + temp_in_coolant=temp_blkt_coolant_in, + temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) ) + # Mass flow rate for inboard breeder flow (kg/s) self.data.fwbs.mfblkti_liq = ( self.data.fwbs.n_liq_recirc * self.data.fwbs.wht_liq_ib @@ -2430,11 +2438,12 @@ def thermo_hydraulic_model(self, output: bool): else: # Mass flow rate for inboard blanket coolant (kg/s) self.data.blanket.mflow_blkt_outboard_coolant = ( - 1.0e6 - * (self.data.blanket.p_blkt_nuclear_heat_outboard_mw) - / ( - self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 + * self.data.blanket.p_blkt_nuclear_heat_outboard_mw, + heatcap_coolant=self.data.fwbs.cp_bl, + temp_in_coolant=temp_blkt_coolant_in, + temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) ) @@ -2445,11 +2454,12 @@ def thermo_hydraulic_model(self, output: bool): == InboardBlanketConfiguration.INBOARD_BLANKET_PRESENT ): self.data.blanket.mflow_blkt_inboard_coolant = ( - 1.0e6 - * (self.data.blanket.p_blkt_nuclear_heat_inboard_mw) - / ( - self.data.fwbs.cp_bl - * (self.data.fwbs.temp_blkt_coolant_out - temp_blkt_coolant_in) + calculate_required_mass_flow_rate( + p_heat_total=1.0e6 + * self.data.blanket.p_blkt_nuclear_heat_inboard_mw, + heatcap_coolant=self.data.fwbs.cp_bl, + temp_in_coolant=temp_blkt_coolant_in, + temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) ) diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index f2bac5cfd2..222dc02aca 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -298,3 +298,37 @@ def elbow_coeff( # Elbow Coefficient return ximt + xift + + +def calculate_required_mass_flow_rate( + p_heat_total: float, + heatcap_coolant: float, + temp_in_coolant: float, + temp_out_coolant: float, +) -> float: + """Calculate the required mass flow rate of coolant to remove the specified heat + load, due to the fundamental energy balance formula. + + Parameters + ---------- + p_heat_total: + Total heat load to be removed (W). + heatcap_coolant: + Specific heat capacity of the coolant (J/kg/K). + temp_in_coolant: + Inlet temperature of the coolant (K). + temp_out_coolant: + Outlet temperature of the coolant (K). + + Returns + ------- + float + Required mass flow rate of the coolant (kg/s). + + Notes + ----- + The heat capacity is assumed to be constant over the temperature range of the + coolant. + + """ + return p_heat_total / (heatcap_coolant * (temp_out_coolant - temp_in_coolant)) diff --git a/tests/unit/models/engineering/test_pumping.py b/tests/unit/models/engineering/test_pumping.py index 5e85511dda..bc5fbee253 100644 --- a/tests/unit/models/engineering/test_pumping.py +++ b/tests/unit/models/engineering/test_pumping.py @@ -1,6 +1,7 @@ import pytest from process.models.engineering.pumping import ( + calculate_required_mass_flow_rate, calculate_reynolds_number, darcy_friction_haaland, elbow_coeff, @@ -47,3 +48,31 @@ def test_elbow_coeff(): assert elbow_coeff(1, 90, 1, 0.1) == pytest.approx(15.774371098812502, rel=1e-3) assert elbow_coeff(0.1, 90, 1, 1) == pytest.approx(66.57, rel=1e-3) assert elbow_coeff(1, 90, 0.1, 1) == pytest.approx(0.3670796326794896, rel=1e-3) + + +def test_calculate_required_mass_flow_rate(): + assert calculate_required_mass_flow_rate( + p_heat_total=1000.0, + heatcap_coolant=100.0, + temp_in_coolant=300.0, + temp_out_coolant=310.0, + ) == pytest.approx(1.0) + + +def test_calculate_required_mass_flow_rate_with_realistic_values(): + assert calculate_required_mass_flow_rate( + p_heat_total=50000.0, + heatcap_coolant=4180.0, + temp_in_coolant=293.15, + temp_out_coolant=313.15, + ) == pytest.approx(0.5980861244019139) + + +def test_calculate_required_mass_flow_rate_zero_temperature_rise(): + with pytest.raises(ZeroDivisionError): + calculate_required_mass_flow_rate( + p_heat_total=1000.0, + heatcap_coolant=4180.0, + temp_in_coolant=300.0, + temp_out_coolant=300.0, + ) From 84e6fc5694152651c2dd6a4f3b00cb7082fd60af Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Jun 2026 18:22:28 +0100 Subject: [PATCH 09/18] =?UTF-8?q?=F0=9F=94=84=20Rename=20FW=20and=20Blkt?= =?UTF-8?q?=20heat=20capacity=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- documentation/source/development/standards.md | 8 ++++ process/data_structure/fwbs_variables.py | 16 +++---- process/models/blankets/blanket_library.py | 48 ++++++++++++------- .../models/blankets/test_blanket_library.py | 48 +++++++++++-------- 4 files changed, 76 insertions(+), 44 deletions(-) diff --git a/documentation/source/development/standards.md b/documentation/source/development/standards.md index a265e36c32..82202ae93a 100644 --- a/documentation/source/development/standards.md +++ b/documentation/source/development/standards.md @@ -259,6 +259,14 @@ This should be used for units of $\text{kg} \cdot \text{m}^{-2}\text{s}^{-1}$ --------------------- +##### Specific Heat Capacities + +- Specific heat capacities for materials $[\text{J/kg/K}]$ should start with the `heatcap_` prefix +- Specific heat capacities at constant volume should start with the `heatcap_vol_` pefix +- Specific heat capacities at constant pressure should start with the `heatcap_pres_` pefix + +--------------------- + ##### Pressures - Pressures should start with the `pres_` prefix diff --git a/process/data_structure/fwbs_variables.py b/process/data_structure/fwbs_variables.py index 860161499e..645a9df8aa 100644 --- a/process/data_structure/fwbs_variables.py +++ b/process/data_structure/fwbs_variables.py @@ -638,17 +638,17 @@ class FWBSData: visc_blkt_coolant: float = 0.0 """Viscosity of the blanket primary coolant""" - cp_fw: float = 0.0 - """Spesific heat for FW and blanket primary coolant(s)""" + heatcap_pres_fw_coolant_average: float = 0.0 + """FW coolant average specific heat capacity at constant pressure [J/kg/K]""" - cv_fw: float = 0.0 - """Spesific heat for FW and blanket primary coolant(s)""" + heatcap_vol_fw_coolant_average: float = 0.0 + """FW coolant average specific heat capacity at constant volume [J/kg/K]""" - cp_bl: float = 0.0 - """Spesific heat for FW and blanket primary coolant(s)""" + heatcap_pres_blkt_coolant_average: float = 0.0 + """Blanket coolant average specific heat capacity at constant pressure [J/kg/K]""" - cv_bl: float = 0.0 - """Spesific heat for FW and blanket primary coolant(s)""" + heatcap_vol_blkt_coolant_average: float = 0.0 + """Blanket coolant average specific heat capacity at constant volume [J/kg/K]""" f_nuc_pow_bz_struct: float = 0.34 """For a dual-coolant blanket, fraction of BZ power cooled by primary coolant""" diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index e9f791ccb6..abc9561384 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -722,14 +722,22 @@ def primary_coolant_properties(self, output: bool): pressure=self.data.fwbs.pres_fw_coolant, ) self.data.fwbs.den_fw_coolant = fw_bb_fluid_properties.density - self.data.fwbs.cp_fw = fw_bb_fluid_properties.specific_heat_const_p - self.data.fwbs.cv_fw = fw_bb_fluid_properties.specific_heat_const_v + self.data.fwbs.heatcap_pres_fw_coolant_average = ( + fw_bb_fluid_properties.specific_heat_const_p + ) + self.data.fwbs.heatcap_vol_fw_coolant_average = ( + fw_bb_fluid_properties.specific_heat_const_v + ) self.data.fwbs.visc_fw_coolant = fw_bb_fluid_properties.viscosity self.data.fwbs.den_blkt_coolant = self.data.fwbs.den_fw_coolant self.data.fwbs.visc_blkt_coolant = self.data.fwbs.visc_fw_coolant - self.data.fwbs.cp_bl = self.data.fwbs.cp_fw - self.data.fwbs.cv_bl = self.data.fwbs.cv_fw + self.data.fwbs.heatcap_pres_blkt_coolant_average = ( + self.data.fwbs.heatcap_pres_fw_coolant_average + ) + self.data.fwbs.heatcap_vol_blkt_coolant_average = ( + self.data.fwbs.heatcap_vol_fw_coolant_average + ) # If FW and BB have different coolants... else: @@ -743,8 +751,12 @@ def primary_coolant_properties(self, output: bool): pressure=self.data.fwbs.pres_fw_coolant, ) self.data.fwbs.den_fw_coolant = fw_fluid_properties.density - self.data.fwbs.cp_fw = fw_fluid_properties.specific_heat_const_p - self.data.fwbs.cv_fw = fw_fluid_properties.specific_heat_const_v + self.data.fwbs.heatcap_pres_fw_coolant_average = ( + fw_fluid_properties.specific_heat_const_p + ) + self.data.fwbs.heatcap_vol_fw_coolant_average = ( + fw_fluid_properties.specific_heat_const_v + ) self.data.fwbs.visc_fw_coolant = fw_fluid_properties.viscosity # BB @@ -758,8 +770,12 @@ def primary_coolant_properties(self, output: bool): pressure=self.data.fwbs.pres_blkt_coolant, ) self.data.fwbs.den_blkt_coolant = bb_fluid_properties.density - self.data.fwbs.cp_bl = bb_fluid_properties.specific_heat_const_p - self.data.fwbs.cv_bl = bb_fluid_properties.specific_heat_const_v + self.data.fwbs.heatcap_pres_blkt_coolant_average = ( + bb_fluid_properties.specific_heat_const_p + ) + self.data.fwbs.heatcap_vol_blkt_coolant_average = ( + bb_fluid_properties.specific_heat_const_v + ) self.data.fwbs.visc_blkt_coolant = bb_fluid_properties.viscosity if ( @@ -2332,7 +2348,7 @@ def thermo_hydraulic_model(self, output: bool): self.data.blanket.p_fw_inboard_nuclear_heat_mw + self.data.fwbs.psurffwi ), - heatcap_coolant=self.data.fwbs.cp_fw, + heatcap_coolant=self.data.fwbs.heatcap_pres_fw_coolant_average, temp_in_coolant=temp_fw_coolant_out, temp_out_coolant=self.data.fwbs.temp_fw_coolant_in, ) @@ -2346,7 +2362,7 @@ def thermo_hydraulic_model(self, output: bool): self.data.blanket.p_fw_outboard_nuclear_heat_mw + self.data.fwbs.psurffwo ), - heatcap_coolant=self.data.fwbs.cp_fw, + heatcap_coolant=self.data.fwbs.heatcap_pres_fw_coolant_average, temp_in_coolant=temp_fw_coolant_out, temp_out_coolant=self.data.fwbs.temp_fw_coolant_in, ) @@ -2358,7 +2374,7 @@ def thermo_hydraulic_model(self, output: bool): self.data.blanket.mflow_blkt_outboard_coolant = ( calculate_required_mass_flow_rate( p_heat_total=1.0e6 * pnucblkto_struct, - heatcap_coolant=self.data.fwbs.cp_bl, + heatcap_coolant=self.data.fwbs.heatcap_pres_blkt_coolant_average, temp_in_coolant=temp_blkt_coolant_in, temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) @@ -2380,7 +2396,7 @@ def thermo_hydraulic_model(self, output: bool): self.data.blanket.mflow_blkt_inboard_coolant = ( calculate_required_mass_flow_rate( p_heat_total=1.0e6 * pnucblkti_struct, - heatcap_coolant=self.data.fwbs.cp_bl, + heatcap_coolant=self.data.fwbs.heatcap_pres_blkt_coolant_average, temp_in_coolant=temp_blkt_coolant_in, temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) @@ -2400,7 +2416,7 @@ def thermo_hydraulic_model(self, output: bool): calculate_required_mass_flow_rate( p_heat_total=1.0e6 * self.data.blanket.p_blkt_nuclear_heat_outboard_mw, - heatcap_coolant=self.data.fwbs.cp_bl, + heatcap_coolant=self.data.fwbs.heatcap_pres_blkt_coolant_average, temp_in_coolant=temp_blkt_coolant_in, temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) @@ -2423,7 +2439,7 @@ def thermo_hydraulic_model(self, output: bool): calculate_required_mass_flow_rate( p_heat_total=1.0e6 * self.data.blanket.p_blkt_nuclear_heat_inboard_mw, - heatcap_coolant=self.data.fwbs.cp_bl, + heatcap_coolant=self.data.fwbs.heatcap_pres_blkt_coolant_average, temp_in_coolant=temp_blkt_coolant_in, temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) @@ -2441,7 +2457,7 @@ def thermo_hydraulic_model(self, output: bool): calculate_required_mass_flow_rate( p_heat_total=1.0e6 * self.data.blanket.p_blkt_nuclear_heat_outboard_mw, - heatcap_coolant=self.data.fwbs.cp_bl, + heatcap_coolant=self.data.fwbs.heatcap_pres_blkt_coolant_average, temp_in_coolant=temp_blkt_coolant_in, temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) @@ -2457,7 +2473,7 @@ def thermo_hydraulic_model(self, output: bool): calculate_required_mass_flow_rate( p_heat_total=1.0e6 * self.data.blanket.p_blkt_nuclear_heat_inboard_mw, - heatcap_coolant=self.data.fwbs.cp_bl, + heatcap_coolant=self.data.fwbs.heatcap_pres_blkt_coolant_average, temp_in_coolant=temp_blkt_coolant_in, temp_out_coolant=self.data.fwbs.temp_blkt_coolant_out, ) diff --git a/tests/unit/models/blankets/test_blanket_library.py b/tests/unit/models/blankets/test_blanket_library.py index 770e50f17a..5366e6984b 100644 --- a/tests/unit/models/blankets/test_blanket_library.py +++ b/tests/unit/models/blankets/test_blanket_library.py @@ -29,9 +29,9 @@ class PrimaryCoolantPropertiesParam(NamedTuple): den_fw_coolant: Any = None - cp_fw: Any = None + heatcap_pres_fw_coolant_average: Any = None - cv_fw: Any = None + heatcap_vol_fw_coolant_average: Any = None i_blkt_coolant_type: Any = None @@ -47,9 +47,9 @@ class PrimaryCoolantPropertiesParam(NamedTuple): visc_blkt_coolant: Any = None - cp_bl: Any = None + heatcap_pres_blkt_coolant_average: Any = None - cv_bl: Any = None + heatcap_vol_blkt_coolant_average: Any = None visc_fw_coolant: Any = None @@ -81,8 +81,8 @@ class PrimaryCoolantPropertiesParam(NamedTuple): temp_fw_coolant_out=773, pres_fw_coolant=8000000, den_fw_coolant=0, - cp_fw=0, - cv_fw=0, + heatcap_pres_fw_coolant_average=0, + heatcap_vol_fw_coolant_average=0, i_blkt_coolant_type=CoolantType.HELIUM, temp_blkt_coolant_in=573, temp_blkt_coolant_out=773, @@ -90,8 +90,8 @@ class PrimaryCoolantPropertiesParam(NamedTuple): den_blkt_coolant=0, i_blkt_dual_coolant=2, visc_blkt_coolant=0, - cp_bl=0, - cv_bl=0, + heatcap_pres_blkt_coolant_average=0, + heatcap_vol_blkt_coolant_average=0, visc_fw_coolant=0, i_fw_blkt_shared_coolant=0, expected_den_fw_coolant=5.6389735407435868, @@ -109,8 +109,8 @@ class PrimaryCoolantPropertiesParam(NamedTuple): temp_fw_coolant_out=773, pres_fw_coolant=8000000, den_fw_coolant=5.6389735407435868, - cp_fw=5188.5588430173211, - cv_fw=3123.5687263525392, + heatcap_pres_fw_coolant_average=5188.5588430173211, + heatcap_vol_fw_coolant_average=3123.5687263525392, i_blkt_coolant_type=CoolantType.HELIUM, temp_blkt_coolant_in=573, temp_blkt_coolant_out=773, @@ -118,8 +118,8 @@ class PrimaryCoolantPropertiesParam(NamedTuple): den_blkt_coolant=5.6389735407435868, i_blkt_dual_coolant=2, visc_blkt_coolant=3.5036293160410249e-05, - cp_bl=5188.5588430173211, - cv_bl=3123.5687263525392, + heatcap_pres_blkt_coolant_average=5188.5588430173211, + heatcap_vol_blkt_coolant_average=3123.5687263525392, visc_fw_coolant=3.5036293160410249e-05, i_fw_blkt_shared_coolant=0, expected_den_fw_coolant=5.6389735407435868, @@ -179,11 +179,15 @@ def test_primary_coolant_properties( ) monkeypatch.setattr( - blanket_library.data.fwbs, "cp_fw", primarycoolantpropertiesparam.cp_fw + blanket_library.data.fwbs, + "heatcap_pres_fw_coolant_average", + primarycoolantpropertiesparam.heatcap_pres_fw_coolant_average, ) monkeypatch.setattr( - blanket_library.data.fwbs, "cv_fw", primarycoolantpropertiesparam.cv_fw + blanket_library.data.fwbs, + "heatcap_vol_fw_coolant_average", + primarycoolantpropertiesparam.heatcap_vol_fw_coolant_average, ) monkeypatch.setattr( @@ -229,11 +233,15 @@ def test_primary_coolant_properties( ) monkeypatch.setattr( - blanket_library.data.fwbs, "cp_bl", primarycoolantpropertiesparam.cp_bl + blanket_library.data.fwbs, + "heatcap_pres_blkt_coolant_average", + primarycoolantpropertiesparam.heatcap_pres_blkt_coolant_average, ) monkeypatch.setattr( - blanket_library.data.fwbs, "cv_bl", primarycoolantpropertiesparam.cv_bl + blanket_library.data.fwbs, + "heatcap_vol_blkt_coolant_average", + primarycoolantpropertiesparam.heatcap_vol_blkt_coolant_average, ) monkeypatch.setattr( @@ -254,11 +262,11 @@ def test_primary_coolant_properties( primarycoolantpropertiesparam.expected_den_fw_coolant, rel=1e-4 ) - assert blanket_library.data.fwbs.cp_fw == pytest.approx( + assert blanket_library.data.fwbs.heatcap_pres_fw_coolant_average == pytest.approx( primarycoolantpropertiesparam.expected_cp_fw, rel=1e-4 ) - assert blanket_library.data.fwbs.cv_fw == pytest.approx( + assert blanket_library.data.fwbs.heatcap_vol_fw_coolant_average == pytest.approx( primarycoolantpropertiesparam.expected_cv_fw, rel=1e-4 ) @@ -270,11 +278,11 @@ def test_primary_coolant_properties( primarycoolantpropertiesparam.expected_visc_blkt_coolant, rel=1e-4 ) - assert blanket_library.data.fwbs.cp_bl == pytest.approx( + assert blanket_library.data.fwbs.heatcap_pres_blkt_coolant_average == pytest.approx( primarycoolantpropertiesparam.expected_cp_bl, rel=1e-4 ) - assert blanket_library.data.fwbs.cv_bl == pytest.approx( + assert blanket_library.data.fwbs.heatcap_vol_blkt_coolant_average == pytest.approx( primarycoolantpropertiesparam.expected_cv_bl, rel=1e-4 ) From 8cf9faa5d6c24d74bb2d7e3c8b2d192e2a8a145b Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 5 Jun 2026 23:13:55 +0100 Subject: [PATCH 10/18] Add output for outboard blanket piping --- process/core/io/plot/summary.py | 51 +++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index a42c3d4d56..8098e0818d 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -15632,6 +15632,41 @@ def plot_outboard_blanket_coolant_properties(fig: plt.Figure, m_file: MFile, sca fig.tight_layout() +def plot_blanket_coolant_channel_structure_and_properties(fig: plt.Figure, m_file: MFile, scan: int): + """Combined plot of blanket coolant channel structure and properties.""" + + # Add info about the Winding Pack + textstr_outboard_blkt = ( + f"$\\mathbf{{Outboard \\ blanket:}}$\n \n" + f"Radial coolant channel length: {m_file.get('len_blkt_outboard_coolant_channel_radial', scan=scan):.4f}\n" + f"Toroidal coolant channel length: {m_file.get('len_blkt_outboard_coolant_channel_toroidal', scan=scan):.4f}\n" + f"Number of radial channels: {m_file.get('n_blkt_outboard_coolant_channels_radial', scan=scan)}\n" + f"Number of poloidal channels: {m_file.get('n_blkt_outboard_coolant_channels_poloidal', scan=scan)}\n" + f"Stored energy of all coils: {m_file.get('e_tf_magnetic_stored_total_gj', scan=scan):.4f} GJ\n" + f"Stored energy of a single coil: {m_file.get('e_tf_coil_magnetic_stored', scan=scan) / 1e9:.2f} GJ\n" + f"Total area of steel in coil: {m_file.get('a_tf_coil_inboard_steel', scan=scan):.4f} $\\mathrm{{m}}^2$\n" + f"Total area fraction of steel: {m_file.get('f_a_tf_coil_inboard_steel', scan=scan):.4f}\n" + f"Total area fraction of insulation: {m_file.get('f_a_tf_coil_inboard_insulation', scan=scan):.4f}\n" + f"$A$, all insulation in coil: {m_file.get('a_tf_coil_inboard_insulation', scan=scan):.4f} $\\mathrm{{m}}^2$\n" + ) + + fig.text( + 0.775, + 0.58, + textstr_outboard_blkt, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "wheat", + "alpha": 1.0, + "linewidth": 2, + }, + ) + + def main_plot( figs: list[Axes], @@ -16032,22 +16067,26 @@ def main_plot( plot_first_wall_poloidal_cross_section(figs[33].add_subplot(122), m_file, scan) plot_fw_90_deg_pipe_bend(figs[33].add_subplot(337), m_file, scan) - plot_blkt_pipe_bends(figs[34], m_file, scan) + ax_blanket = figs[34].add_subplot(122, aspect="equal") plot_blkt_structure(ax_blanket, figs[34], m_file, scan, radial_build, colour_scheme) + + plot_blkt_pipe_bends(figs[35], m_file, scan) + plot_blanket_coolant_channel_structure(figs[35].add_subplot(111), m_file, scan) + plot_blanket_coolant_channel_structure_and_properties(figs[35], m_file, scan) plot_main_power_flow( - figs[35].add_subplot(111, aspect="equal"), m_file, scan, figs[35] + figs[36].add_subplot(111, aspect="equal"), m_file, scan, figs[36] ) - ax24 = figs[36].add_subplot(111) + ax24 = figs[37].add_subplot(111) # set_position([left, bottom, width, height]) -> height ~ 0.66 => ~2/3 of page height ax24.set_position([0.08, 0.35, 0.84, 0.57]) - plot_system_power_profiles_over_time(ax24, m_file, scan, figs[36]) + plot_system_power_profiles_over_time(ax24, m_file, scan, figs[37]) - plot_blanket_coolant_channel_structure(figs[37].add_subplot(111), m_file, scan) + - plot_outboard_blanket_coolant_properties(figs[37], m_file, scan) + # plot_outboard_blanket_coolant_properties(figs[37], m_file, scan) def create_thickness_builds(m_file, scan: int): From 11f03f9a486aad32aded478ce1ad08148f946eae Mon Sep 17 00:00:00 2001 From: mn3981 Date: Sat, 6 Jun 2026 00:12:24 +0100 Subject: [PATCH 11/18] Add output table for outboard blanket --- process/core/io/plot/summary.py | 50 ++++++++++++---------- process/data_structure/fwbs_variables.py | 2 +- process/models/blankets/blanket_library.py | 8 ++-- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 8098e0818d..18fe4ebe51 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -15632,27 +15632,37 @@ def plot_outboard_blanket_coolant_properties(fig: plt.Figure, m_file: MFile, sca fig.tight_layout() -def plot_blanket_coolant_channel_structure_and_properties(fig: plt.Figure, m_file: MFile, scan: int): + +def plot_blanket_coolant_channel_structure_and_properties( + fig: plt.Figure, m_file: MFile, scan: int +): """Combined plot of blanket coolant channel structure and properties.""" - # Add info about the Winding Pack textstr_outboard_blkt = ( f"$\\mathbf{{Outboard \\ blanket:}}$\n \n" - f"Radial coolant channel length: {m_file.get('len_blkt_outboard_coolant_channel_radial', scan=scan):.4f}\n" - f"Toroidal coolant channel length: {m_file.get('len_blkt_outboard_coolant_channel_toroidal', scan=scan):.4f}\n" - f"Number of radial channels: {m_file.get('n_blkt_outboard_coolant_channels_radial', scan=scan)}\n" - f"Number of poloidal channels: {m_file.get('n_blkt_outboard_coolant_channels_poloidal', scan=scan)}\n" - f"Stored energy of all coils: {m_file.get('e_tf_magnetic_stored_total_gj', scan=scan):.4f} GJ\n" - f"Stored energy of a single coil: {m_file.get('e_tf_coil_magnetic_stored', scan=scan) / 1e9:.2f} GJ\n" - f"Total area of steel in coil: {m_file.get('a_tf_coil_inboard_steel', scan=scan):.4f} $\\mathrm{{m}}^2$\n" - f"Total area fraction of steel: {m_file.get('f_a_tf_coil_inboard_steel', scan=scan):.4f}\n" - f"Total area fraction of insulation: {m_file.get('f_a_tf_coil_inboard_insulation', scan=scan):.4f}\n" - f"$A$, all insulation in coil: {m_file.get('a_tf_coil_inboard_insulation', scan=scan):.4f} $\\mathrm{{m}}^2$\n" - ) - + f"Radius of blanket channel: {m_file.get('radius_blkt_channel', scan=scan):.4f} m\n" + f"Channel roughness ($\\epsilon$): {m_file.get('roughness_fw_channel', scan=scan):.4e} m\n\n" + f"Radial coolant channel length: {m_file.get('len_blkt_outboard_coolant_channel_radial', scan=scan):.4f} m\n" + f"Toroidal coolant channel length: {m_file.get('len_blkt_inboard_segment_toroidal', scan=scan):.4f} m\n" + f"Number of radial channels: {m_file.get('n_blkt_inboard_module_coolant_sections_radial', scan=scan)}\n" + f"Number of poloidal channels: {m_file.get('n_blkt_inboard_module_coolant_sections_poloidal', scan=scan)}\n" + f"Total length of coolant channel straight sections: {m_file.get('len_blkt_inboard_channel_total', scan=scan):.4f} m\n\n" + f"Pressure drop for straight sections: {m_file.get('dpres_blkt_outboard_coolant_channel_straight_total', scan=scan):.2e} Pa\n" + f"Pressure drop for 90° bends: {m_file.get('dpres_blkt_outboard_coolant_channel_90_bend', scan=scan):.2e} Pa\n" + f"Total pressure drop for 90° bends: {m_file.get('dpres_blkt_outboard_coolant_channel_90_bends_total', scan=scan):.2e} Pa\n" + f"Pressure drop for 180° bends: {m_file.get('dpres_blkt_outboard_coolant_channel_180_bend', scan=scan):.2e} Pa\n" + f"Total pressure drop for 180° bends: {m_file.get('dpres_blkt_outboard_coolant_channel_180_bends_total', scan=scan):.2e} Pa\n" + f"Total pressure drop for all bends: {m_file.get('dpres_blkt_outboard_bends_total', scan=scan):.2e} Pa\n\n" + f"Reynolds number ($Re$): {m_file.get('reynolds_blkt_outboard_coolant', scan=scan):.4f}\n" + f"Darcy Friction factor ($f$): {m_file.get('darcy_frict_blkt_outboard_coolant', scan=scan):.4f}\n\n" + f"Friction drop coefficient for straight sections: {m_file.get('f_straight_blkt_outboard_coolant', scan=scan):.4f}\n" + f"Friction drop coefficient for 90° bends: {m_file.get('f_elbow_blkt_outboard_90_bend', scan=scan):.4f}\n" + f"Friction drop coefficient for 180° bends: {m_file.get('f_elbow_blkt_outboard_180_bend', scan=scan):.4f}\n" + ) + fig.text( - 0.775, - 0.58, + 0.5, + 0.65, textstr_outboard_blkt, fontsize=9, verticalalignment="top", @@ -15665,8 +15675,7 @@ def plot_blanket_coolant_channel_structure_and_properties(fig: plt.Figure, m_fil "linewidth": 2, }, ) - - + def main_plot( figs: list[Axes], @@ -16067,10 +16076,9 @@ def main_plot( plot_first_wall_poloidal_cross_section(figs[33].add_subplot(122), m_file, scan) plot_fw_90_deg_pipe_bend(figs[33].add_subplot(337), m_file, scan) - ax_blanket = figs[34].add_subplot(122, aspect="equal") plot_blkt_structure(ax_blanket, figs[34], m_file, scan, radial_build, colour_scheme) - + plot_blkt_pipe_bends(figs[35], m_file, scan) plot_blanket_coolant_channel_structure(figs[35].add_subplot(111), m_file, scan) plot_blanket_coolant_channel_structure_and_properties(figs[35], m_file, scan) @@ -16084,8 +16092,6 @@ def main_plot( ax24.set_position([0.08, 0.35, 0.84, 0.57]) plot_system_power_profiles_over_time(ax24, m_file, scan, figs[37]) - - # plot_outboard_blanket_coolant_properties(figs[37], m_file, scan) diff --git a/process/data_structure/fwbs_variables.py b/process/data_structure/fwbs_variables.py index 645a9df8aa..5e8e76e7c3 100644 --- a/process/data_structure/fwbs_variables.py +++ b/process/data_structure/fwbs_variables.py @@ -313,7 +313,7 @@ class FWBSData: """peak first wall temperature [K]""" roughness_fw_channel: float = 1.0e-6 - """first wall channel roughness epsilon [m]""" + """First wall channel roughness (ε) [m]""" len_fw_channel: float = 4.0 """Length of a single first wall channel (all in parallel) [m] diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index abc9561384..ca71af2ff0 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -2349,8 +2349,8 @@ def thermo_hydraulic_model(self, output: bool): + self.data.fwbs.psurffwi ), heatcap_coolant=self.data.fwbs.heatcap_pres_fw_coolant_average, - temp_in_coolant=temp_fw_coolant_out, - temp_out_coolant=self.data.fwbs.temp_fw_coolant_in, + temp_in_coolant=self.data.fwbs.temp_fw_coolant_in, + temp_out_coolant=temp_fw_coolant_out, ) ) @@ -2363,8 +2363,8 @@ def thermo_hydraulic_model(self, output: bool): + self.data.fwbs.psurffwo ), heatcap_coolant=self.data.fwbs.heatcap_pres_fw_coolant_average, - temp_in_coolant=temp_fw_coolant_out, - temp_out_coolant=self.data.fwbs.temp_fw_coolant_in, + temp_in_coolant=self.data.fwbs.temp_fw_coolant_in, + temp_out_coolant=temp_fw_coolant_out, ) ) From 20608a0880174e2beadc096b1c6c59dadda625f8 Mon Sep 17 00:00:00 2001 From: chris-ashe Date: Sun, 7 Jun 2026 17:00:36 +0100 Subject: [PATCH 12/18] Refactor coolant friction loss parameters and update related tests --- process/models/blankets/blanket_library.py | 33 +++-- .../models/blankets/test_blanket_library.py | 121 +++++++++--------- 2 files changed, 81 insertions(+), 73 deletions(-) diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index ca71af2ff0..666bf7dc56 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -2986,6 +2986,8 @@ def total_pressure_drop( den_coolant=den_coolant, visc_coolant=visc_coolant_dynamic, vel_coolant=vel_coolant, + roughness_channel=self.data.fwbs.roughness_fw_channel, + radius_channel=self.data.fwbs.radius_fw_channel, ) ) dpres_friction = friction_params.dpres_total @@ -3173,6 +3175,8 @@ def coolant_friction_pressure_drop( den_coolant: float, visc_coolant: float, vel_coolant: float, + roughness_channel: float, + radius_channel: float, ) -> CoolantFrictionLossParameters: """Pressure drops are calculated for a pipe with a number of 90 and 180 degree bends. The pressure drop due to frictional forces along @@ -3185,26 +3189,30 @@ def coolant_friction_pressure_drop( i_ps : switch for primary or secondary coolant radius_pipe_90_deg_bend : - radius of 90 degree bend in pipe (m) + radius of 90 degree bend in pipe [m] radius_pipe_180_deg_bend : - radius of 180 degree bend in pipe (m) + radius of 180 degree bend in pipe [m] n_pipe_90_deg_bends : number of 90 degree bends in the pipe n_pipe_180_deg_bends : number of 180 degree bends in the pipe len_pipe : - total flow length along pipe (m) + total flow length along pipe [m] den_coolant : - coolant density (kg/m³) + coolant density [kg/m³] visc_coolant : - coolant viscosity (Pa s) + coolant viscosity [Pa s] vel_coolant : - coolant flow velocity (m/s) + coolant flow velocity [m/s] + roughness_channel : + roughness of the channel wall (ε) [m] + radius_channel : + radius of the channel [m] Returns ------- : - CoolantFrictionLossParameters dataclass containing: + `CoolantFrictionLossParameters` dataclass containing: - Total pressure drop due to friction (Pa) - Pressure drop due to straight sections (Pa) - Pressure drop due to 90 degree bends (Pa) @@ -3230,7 +3238,7 @@ def coolant_friction_pressure_drop( N.B. Darcy friction factor is estimated from the Haaland approximation. """ # Calculate hydraulic dimater for round or retancular pipe (m) - dia_pipe = self.pipe_hydraulic_diameter(i_ps) + dia_pipe = self.pipe_hydraulic_diameter(i_channel_shape=i_ps) # Reynolds number reynolds_number = calculate_reynolds_number( @@ -3241,14 +3249,15 @@ def coolant_friction_pressure_drop( ) # Calculate Darcy friction factor - # N.B. friction function Uses Haaland approx. which assumes a filled circular pipe. - # Use dh which allows us to do fluid calculations for non-cicular tubes + # N.B. friction function Uses Haaland approx. which assumes a filled + # circular pipe. + # Use dh which allows us to do fluid calculations for non-circular tubes # (dh is estimate appropriate for fully developed flow). darcy_friction_factor = darcy_friction_haaland( reynolds=reynolds_number, - roughness_channel=self.data.fwbs.roughness_fw_channel, - radius_channel=self.data.fwbs.radius_fw_channel, + roughness_channel=roughness_channel, + radius_channel=radius_channel, ) # Pressure drop coefficient diff --git a/tests/unit/models/blankets/test_blanket_library.py b/tests/unit/models/blankets/test_blanket_library.py index 5366e6984b..cb75ec58ac 100644 --- a/tests/unit/models/blankets/test_blanket_library.py +++ b/tests/unit/models/blankets/test_blanket_library.py @@ -1,4 +1,4 @@ -from typing import Any, NamedTuple +from typing import TYPE_CHECKING, Any, NamedTuple import numpy as np import pytest @@ -7,6 +7,9 @@ from process.models.blankets.blanket_library import InboardBlanket from process.models.engineering.pumping import CoolantType +if TYPE_CHECKING: + from process.models.engineering.pumping import CoolantFrictionLossParameters + @pytest.fixture def blanket_library(process_models): @@ -1022,110 +1025,106 @@ def test_liquid_breeder_properties( ) -class PressureDropParam(NamedTuple): - radius_fw_channel: Any = None +class CoolantFrictionLossParam(NamedTuple): + radius_channel: Any = None radius_pipe_90_deg_bend: Any = None radius_pipe_180_deg_bend: Any = None a_bz_liq: Any = None b_bz_liq: Any = None - roughness_fw_channel: Any = None - ip: Any = None + roughness_channel: Any = None i_ps: Any = None - num_90: Any = None - num_180: Any = None - l_pipe: Any = None - den: Any = None - vsc: Any = None - vv: Any = None + n_pipe_90_deg_bends: Any = None + n_pipe_180_deg_bends: Any = None + len_pipe: Any = None + den_coolant: Any = None + visc_coolant: Any = None + vel_coolant: Any = None label: Any = None expected_pressure_drop_out: Any = None @pytest.mark.parametrize( - "pressuredropparam", + "coolantfrictionlossparam", [ - PressureDropParam( - radius_fw_channel=0.0060000000000000001, + CoolantFrictionLossParam( + radius_channel=0.0060000000000000001, radius_pipe_90_deg_bend=0.018, radius_pipe_180_deg_bend=0.09, a_bz_liq=0.20000000000000001, b_bz_liq=0.20000000000000001, - roughness_fw_channel=9.9999999999999995e-07, - ip=0, + roughness_channel=9.9999999999999995e-07, i_ps=1, - num_90=2, - num_180=0, - l_pipe=4, - den=10.405276820718059, - vsc=3.604452999475736e-05, - vv=32.753134225223164, + n_pipe_90_deg_bends=2, + n_pipe_180_deg_bends=0, + len_pipe=4, + den_coolant=10.405276820718059, + visc_coolant=3.604452999475736e-05, + vel_coolant=32.753134225223164, label="Inboard first wall", expected_pressure_drop_out=36213.58989742931, ), - PressureDropParam( - radius_fw_channel=1.0, + CoolantFrictionLossParam( + radius_channel=1.0, radius_pipe_90_deg_bend=1.0, radius_pipe_180_deg_bend=1.0, a_bz_liq=1.0, b_bz_liq=1.0, - roughness_fw_channel=1e-6, - ip=0, + roughness_channel=1e-6, i_ps=2, - num_90=1.0, - num_180=1.0, - l_pipe=1.0, - den=1.0, - vsc=1.0, - vv=1.0, + n_pipe_90_deg_bends=1.0, + n_pipe_180_deg_bends=1.0, + len_pipe=1.0, + den_coolant=1.0, + visc_coolant=1.0, + vel_coolant=1.0, label="label", expected_pressure_drop_out=1.4325633520224854, ), ], ) -def test_pressure_drop(pressuredropparam, monkeypatch, blanket_library): +def test_coolant_friction_loss(coolantfrictionlossparam, monkeypatch, blanket_library): """ - Automatically generated Regression Unit Test for pressure_drop. + Automatically generated Regression Unit Test for coolant_friction_loss. This test was generated using data from blanket_files/large_tokamak_primary_pumping2.IN.DAT. - :param pressuredropparam: the data used to mock and assert in this test. - :type pressuredropparam: pressuredropparam + Parameters + ---------- + coolantfrictionlossparam : CoolantFrictionLossParam + the data used to mock and assert in this test. + monkeypatch : _pytest.monkeypatch.monkeypatch + pytest fixture used to mock module/class variables + blanket_library : BlanketLibrary + the blanket library instance used in this test. - :param monkeypatch: pytest fixture used to mock module/class variables - :type monkeypatch: _pytest.monkeypatch.monkeypatch """ + monkeypatch.setattr( - blanket_library.data.fwbs, - "radius_fw_channel", - pressuredropparam.radius_fw_channel, - ) - monkeypatch.setattr( - blanket_library.data.fwbs, "a_bz_liq", pressuredropparam.a_bz_liq - ) - monkeypatch.setattr( - blanket_library.data.fwbs, "b_bz_liq", pressuredropparam.b_bz_liq + blanket_library.data.fwbs, "a_bz_liq", coolantfrictionlossparam.a_bz_liq ) monkeypatch.setattr( - blanket_library.data.fwbs, - "roughness_fw_channel", - pressuredropparam.roughness_fw_channel, + blanket_library.data.fwbs, "b_bz_liq", coolantfrictionlossparam.b_bz_liq ) - pressure_params = blanket_library.coolant_friction_pressure_drop( - i_ps=pressuredropparam.i_ps, - radius_pipe_90_deg_bend=pressuredropparam.radius_pipe_90_deg_bend, - radius_pipe_180_deg_bend=pressuredropparam.radius_pipe_180_deg_bend, - n_pipe_90_deg_bends=pressuredropparam.num_90, - n_pipe_180_deg_bends=pressuredropparam.num_180, - len_pipe=pressuredropparam.l_pipe, - den_coolant=pressuredropparam.den, - visc_coolant=pressuredropparam.vsc, - vel_coolant=pressuredropparam.vv, + pressure_params: CoolantFrictionLossParameters = ( + blanket_library.coolant_friction_pressure_drop( + i_ps=coolantfrictionlossparam.i_ps, + radius_pipe_90_deg_bend=(coolantfrictionlossparam.radius_pipe_90_deg_bend), + radius_pipe_180_deg_bend=(coolantfrictionlossparam.radius_pipe_180_deg_bend), + n_pipe_90_deg_bends=coolantfrictionlossparam.n_pipe_90_deg_bends, + n_pipe_180_deg_bends=coolantfrictionlossparam.n_pipe_180_deg_bends, + len_pipe=coolantfrictionlossparam.len_pipe, + den_coolant=coolantfrictionlossparam.den_coolant, + visc_coolant=coolantfrictionlossparam.visc_coolant, + vel_coolant=coolantfrictionlossparam.vel_coolant, + roughness_channel=coolantfrictionlossparam.roughness_channel, + radius_channel=coolantfrictionlossparam.radius_channel, + ) ) assert pressure_params.dpres_total == pytest.approx( - pressuredropparam.expected_pressure_drop_out + coolantfrictionlossparam.expected_pressure_drop_out ) From 55760477ede8facd5c6830d736e5e63060ad90e1 Mon Sep 17 00:00:00 2001 From: chris-ashe Date: Sun, 7 Jun 2026 19:30:26 +0100 Subject: [PATCH 13/18] Enhance inboard blanket coolant channel output and pressure drop calculations --- process/core/io/plot/summary.py | 47 ++++++- process/models/blankets/blanket_library.py | 151 ++++++++++++++++++++- 2 files changed, 188 insertions(+), 10 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 18fe4ebe51..1e9c1e9d3b 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -15643,10 +15643,10 @@ def plot_blanket_coolant_channel_structure_and_properties( f"Radius of blanket channel: {m_file.get('radius_blkt_channel', scan=scan):.4f} m\n" f"Channel roughness ($\\epsilon$): {m_file.get('roughness_fw_channel', scan=scan):.4e} m\n\n" f"Radial coolant channel length: {m_file.get('len_blkt_outboard_coolant_channel_radial', scan=scan):.4f} m\n" - f"Toroidal coolant channel length: {m_file.get('len_blkt_inboard_segment_toroidal', scan=scan):.4f} m\n" - f"Number of radial channels: {m_file.get('n_blkt_inboard_module_coolant_sections_radial', scan=scan)}\n" - f"Number of poloidal channels: {m_file.get('n_blkt_inboard_module_coolant_sections_poloidal', scan=scan)}\n" - f"Total length of coolant channel straight sections: {m_file.get('len_blkt_inboard_channel_total', scan=scan):.4f} m\n\n" + f"Poloidal coolant channel length: {m_file.get('len_blkt_outboard_segment_poloidal', scan=scan):.4f} m\n" + f"Number of radial channels: {m_file.get('n_blkt_outboard_module_coolant_sections_radial', scan=scan)}\n" + f"Number of poloidal channels: {m_file.get('n_blkt_outboard_module_coolant_sections_poloidal', scan=scan)}\n" + f"Total length of coolant channel straight sections: {m_file.get('len_blkt_outboard_channel_total', scan=scan):.4f} m\n\n" f"Pressure drop for straight sections: {m_file.get('dpres_blkt_outboard_coolant_channel_straight_total', scan=scan):.2e} Pa\n" f"Pressure drop for 90° bends: {m_file.get('dpres_blkt_outboard_coolant_channel_90_bend', scan=scan):.2e} Pa\n" f"Total pressure drop for 90° bends: {m_file.get('dpres_blkt_outboard_coolant_channel_90_bends_total', scan=scan):.2e} Pa\n" @@ -15676,6 +15676,45 @@ def plot_blanket_coolant_channel_structure_and_properties( }, ) + # Add info about the Winding Pack + textstr_inboard_blkt = ( + f"$\\mathbf{{Inboard \\ blanket:}}$\n \n" + f"Radius of blanket channel: {m_file.get('radius_blkt_channel', scan=scan):.4f} m\n" + f"Channel roughness ($\\epsilon$): {m_file.get('roughness_fw_channel', scan=scan):.4e} m\n\n" + f"Radial coolant channel length: {m_file.get('len_blkt_inboard_coolant_channel_radial', scan=scan):.4f} m\n" + f"Poloidal coolant channel length: {m_file.get('len_blkt_inboard_segment_poloidal', scan=scan):.4f} m\n" + f"Number of radial channels: {m_file.get('n_blkt_inboard_module_coolant_sections_radial', scan=scan)}\n" + f"Number of poloidal channels: {m_file.get('n_blkt_inboard_module_coolant_sections_poloidal', scan=scan)}\n" + f"Total length of coolant channel straight sections: {m_file.get('len_blkt_inboard_channel_total', scan=scan):.4f} m\n\n" + f"Pressure drop for straight sections: {m_file.get('dpres_blkt_inboard_coolant_channel_straight_total', scan=scan):.2e} Pa\n" + f"Pressure drop for 90° bends: {m_file.get('dpres_blkt_inboard_coolant_channel_90_bend', scan=scan):.2e} Pa\n" + f"Total pressure drop for 90° bends: {m_file.get('dpres_blkt_inboard_coolant_channel_90_bends_total', scan=scan):.2e} Pa\n" + f"Pressure drop for 180° bends: {m_file.get('dpres_blkt_inboard_coolant_channel_180_bend', scan=scan):.2e} Pa\n" + f"Total pressure drop for 180° bends: {m_file.get('dpres_blkt_inboard_coolant_channel_180_bends_total', scan=scan):.2e} Pa\n" + f"Total pressure drop for all bends: {m_file.get('dpres_blkt_inboard_bends_total', scan=scan):.2e} Pa\n\n" + f"Reynolds number ($Re$): {m_file.get('reynolds_blkt_inboard_coolant', scan=scan):.4f}\n" + f"Darcy Friction factor ($f$): {m_file.get('darcy_frict_blkt_inboard_coolant', scan=scan):.4f}\n\n" + f"Friction drop coefficient for straight sections: {m_file.get('f_straight_blkt_inboard_coolant', scan=scan):.4f}\n" + f"Friction drop coefficient for 90° bends: {m_file.get('f_elbow_blkt_inboard_90_bend', scan=scan):.4f}\n" + f"Friction drop coefficient for 180° bends: {m_file.get('f_elbow_blkt_inboard_180_bend', scan=scan):.4f}\n" + ) + + fig.text( + 0.2, + 0.65, + textstr_inboard_blkt, + fontsize=9, + verticalalignment="top", + horizontalalignment="left", + transform=fig.transFigure, + bbox={ + "boxstyle": "round", + "facecolor": "wheat", + "alpha": 1.0, + "linewidth": 2, + }, + ) + def main_plot( figs: list[Axes], diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 666bf7dc56..524fb743db 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -1537,6 +1537,44 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): ) ) + self.data.blanket.dpres_blkt_inboard_coolant_channel_straight_total = ( + blkt_inboard_friction_params.dpres_straight + ) + self.data.blanket.dpres_blkt_inboard_coolant_channel_90_bend = ( + blkt_inboard_friction_params.dpres_90 + ) + self.data.blanket.dpres_blkt_inboard_coolant_channel_90_bends_total = ( + blkt_inboard_friction_params.dpres_90_total + ) + self.data.blanket.dpres_blkt_inboard_coolant_channel_180_bend = ( + blkt_inboard_friction_params.dpres_180 + ) + self.data.blanket.dpres_blkt_inboard_coolant_channel_180_bends_total = ( + blkt_inboard_friction_params.dpres_180_total + ) + self.data.blanket.dpres_blkt_inboard_bends_total = ( + blkt_inboard_friction_params.dpres_bends_total + ) + + self.data.blanket.reynolds_blkt_inboard_coolant = ( + blkt_inboard_friction_params.reynolds_number + ) + self.data.blanket.darcy_frict_blkt_inboard_coolant = ( + blkt_inboard_friction_params.darcy_friction_factor + ) + self.data.blanket.f_straight_blkt_inboard_coolant = ( + blkt_inboard_friction_params.f_straight + ) + self.data.blanket.len_blkt_inboard_coolant_channel_straight_total = ( + blkt_inboard_friction_params.len_straight + ) + self.data.blanket.f_elbow_blkt_inboard_90_bend = ( + blkt_inboard_friction_params.f_elbow_90 + ) + self.data.blanket.f_elbow_blkt_inboard_180_bend = ( + blkt_inboard_friction_params.f_elbow_180 + ) + # If the blanket has a liquid metal breeder... if self.data.fwbs.i_blkt_dual_coolant > 0: deltap_blo_liq, _ = self.total_pressure_drop( @@ -3524,11 +3562,12 @@ def output_blkt_pumping_variables(self): ) po.ovarre( self.outfile, - "Inboard blanket coolant channel length (toroidal direction) (m)", - "(len_blkt_inboard_segment_toroidal)", - self.data.blanket.len_blkt_inboard_segment_toroidal, + "Inboard blanket coolant channel length (poloidal direction) (m)", + "(len_blkt_inboard_segment_poloidal)", + self.data.blanket.len_blkt_inboard_segment_poloidal, "OP ", ) + po.oblnkl(self.outfile) po.ovarre( self.outfile, "Number of inboard blanket coolant sections in the radial direction", @@ -3543,6 +3582,7 @@ def output_blkt_pumping_variables(self): self.data.fwbs.n_blkt_inboard_module_coolant_sections_poloidal, "OP ", ) + po.oblnkl(self.outfile) po.ovarre( self.outfile, "Total length of inboard blanket coolant channel straight sections (m)", @@ -3550,6 +3590,105 @@ def output_blkt_pumping_variables(self): self.data.blanket.len_blkt_inboard_channel_total, "OP ", ) + po.oblnkl(self.outfile) + po.ocmmnt(self.outfile, "----------------------------") + + po.ovarre( + self.outfile, + "Pressure drop for straight sections of inboard blanket (Pa)", + "(dpres_blkt_inboard_coolant_channel_straight_total)", + self.data.blanket.dpres_blkt_inboard_coolant_channel_straight_total, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Pressure drop for 90° bends of inboard blanket (Pa)", + "(dpres_blkt_inboard_coolant_channel_90_bend)", + self.data.blanket.dpres_blkt_inboard_coolant_channel_90_bend, + "OP ", + ) + po.ovarre( + self.outfile, + "Total pressure drop for 90° bends of inboard blanket (Pa)", + "(dpres_blkt_inboard_coolant_channel_90_bends_total)", + self.data.blanket.dpres_blkt_inboard_coolant_channel_90_bends_total, + "OP ", + ) + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Pressure drop for 180° bends of inboard blanket (Pa)", + "(dpres_blkt_inboard_coolant_channel_180_bend)", + self.data.blanket.dpres_blkt_inboard_coolant_channel_180_bend, + "OP ", + ) + po.ovarre( + self.outfile, + "Total pressure drop for 180° bends of inboard blanket (Pa)", + "(dpres_blkt_inboard_coolant_channel_180_bends_total)", + self.data.blanket.dpres_blkt_inboard_coolant_channel_180_bends_total, + "OP ", + ) + + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Total pressure drop for all bends (Pa)", + "(dpres_blkt_inboard_bends_total)", + self.data.blanket.dpres_blkt_inboard_bends_total, + "OP ", + ) + + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Reynolds number of inboard blanket coolant", + "(reynolds_blkt_inboard_coolant)", + self.data.blanket.reynolds_blkt_inboard_coolant, + "OP ", + ) + + po.ovarre( + self.outfile, + "Darcy friction factor of inboard blanket coolant", + "(darcy_frict_blkt_inboard_coolant)", + self.data.blanket.darcy_frict_blkt_inboard_coolant, + "OP ", + ) + po.oblnkl(self.outfile) + + po.ovarre( + self.outfile, + "Pressure drop coefficient for straight sections of inboard blanket", + "(f_straight_blkt_inboard_coolant)", + self.data.blanket.f_straight_blkt_inboard_coolant, + "OP ", + ) + + po.ovarre( + self.outfile, + "Total length of straight sections of inboard blanket coolant channels (m)", + "(len_blkt_inboard_coolant_channel_straight_total)", + self.data.blanket.len_blkt_inboard_coolant_channel_straight_total, + "OP ", + ) + + po.ovarre( + self.outfile, + "Pressure drop coefficient for 90° bends in inboard blanket", + "(f_elbow_blkt_inboard_90_bend)", + self.data.blanket.f_elbow_blkt_inboard_90_bend, + "OP ", + ) + + po.ovarre( + self.outfile, + "Pressure drop coefficient for 180° bends in inboard blanket", + "(f_elbow_blkt_inboard_180_bend)", + self.data.blanket.f_elbow_blkt_inboard_180_bend, + "OP ", + ) po.osubhd(self.outfile, "Outboard Blanket") @@ -3562,9 +3701,9 @@ def output_blkt_pumping_variables(self): ) po.ovarre( self.outfile, - "Outboard blanket coolant channel length (toroidal direction) (m)", - "(len_blkt_outboard_segment_toroidal)", - self.data.blanket.len_blkt_outboard_segment_toroidal, + "Outboard blanket coolant channel length (poloidal direction) (m)", + "(len_blkt_outboard_segment_poloidal)", + self.data.blanket.len_blkt_outboard_segment_poloidal, "OP ", ) po.oblnkl(self.outfile) From 8f270d030bc568d00e375909fb00b510b8eb1642 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 8 Jun 2026 10:28:12 +0100 Subject: [PATCH 14/18] Move FW number of bends to FW file --- process/models/blankets/blanket_library.py | 7 +------ process/models/fw.py | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 524fb743db..a978b54a9f 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -28,6 +28,7 @@ darcy_friction_haaland, elbow_coeff, ) +from process.models.fw import N_FW_PIPE_90_DEG_BENDS, N_FW_PIPE_180_DEG_BENDS from process.models.power import PumpingPowerModelTypes logger = logging.getLogger(__name__) @@ -1116,12 +1117,6 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): # Coolant channel bends - # Number of angle turns in FW and blanket flow channels, n.b. these are the - # same for CCFE HCPB and KIT DCLL. FW is also be the same for DCLL MMS ans SMS. - - N_FW_PIPE_90_DEG_BENDS = 2 - N_FW_PIPE_180_DEG_BENDS = 0 - # N.B. This is for BZ only, does not include MF/BSS. if self.data.fwbs.i_blkt_dual_coolant in {1, 2}: N_BLKT_PIPE_90_DEG_BENDS = 4 diff --git a/process/models/fw.py b/process/models/fw.py index 9f847fcf5f..6134f58e2a 100644 --- a/process/models/fw.py +++ b/process/models/fw.py @@ -22,6 +22,12 @@ logger = logging.getLogger(__name__) +N_FW_PIPE_90_DEG_BENDS = 2 +"Number of 90 degree bends in first wall coolant channels." +N_FW_PIPE_180_DEG_BENDS = 0 +"Number of 180 degree bends in first wall coolant channels." + + class FirstWall(Model): def __init__(self): self.outfile = constants.NOUT From 9c68452a9d9656bd502e11e5b7351d1e1ed37871 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 8 Jun 2026 10:54:17 +0100 Subject: [PATCH 15/18] Remove pipe plotting --- process/core/io/plot/summary.py | 1 - 1 file changed, 1 deletion(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 1e9c1e9d3b..800b6f54b7 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -16119,7 +16119,6 @@ def main_plot( plot_blkt_structure(ax_blanket, figs[34], m_file, scan, radial_build, colour_scheme) plot_blkt_pipe_bends(figs[35], m_file, scan) - plot_blanket_coolant_channel_structure(figs[35].add_subplot(111), m_file, scan) plot_blanket_coolant_channel_structure_and_properties(figs[35], m_file, scan) plot_main_power_flow( From 95a820fff0d0e8b966ff4f8613a9057a0a10de31 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Mon, 8 Jun 2026 11:14:21 +0100 Subject: [PATCH 16/18] Update summary positions of tables --- process/core/io/plot/summary.py | 8 +++--- process/models/blankets/blanket_library.py | 30 ++++++++++------------ 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 800b6f54b7..7a14082b64 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -15662,7 +15662,7 @@ def plot_blanket_coolant_channel_structure_and_properties( fig.text( 0.5, - 0.65, + 0.5, textstr_outboard_blkt, fontsize=9, verticalalignment="top", @@ -15700,8 +15700,8 @@ def plot_blanket_coolant_channel_structure_and_properties( ) fig.text( - 0.2, - 0.65, + 0.1, + 0.5, textstr_inboard_blkt, fontsize=9, verticalalignment="top", @@ -16130,8 +16130,6 @@ def main_plot( ax24.set_position([0.08, 0.35, 0.84, 0.57]) plot_system_power_profiles_over_time(ax24, m_file, scan, figs[37]) - # plot_outboard_blanket_coolant_properties(figs[37], m_file, scan) - def create_thickness_builds(m_file, scan: int): # Build the dictionaries of radial and vertical build values and cumulative values diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index a978b54a9f..1dce72158c 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -1406,7 +1406,7 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): b_bz_liq=self.data.fwbs.b_bz_liq, ) - dpres_fw_inboard_coolant, fw_inboard_friction_params = self.total_pressure_drop( + dpres_fw_inboard_coolant, _ = self.total_pressure_drop( output, icoolpump=1, vel_coolant=vel_fw_inboard_coolant, @@ -1421,21 +1421,19 @@ def thermo_hydraulic_model_pressure_drop_calculations(self, output: bool): label="Inboard first wall", ) - dpres_fw_outboard_coolant, fw_outboard_friction_params = ( - self.total_pressure_drop( - output, - icoolpump=1, - vel_coolant=vel_fw_outboard_coolant, - len_pipe=self.data.fwbs.len_fw_channel, - n_pipe_90_deg_bends=N_FW_PIPE_90_DEG_BENDS, - n_pipe_180_deg_bends=N_FW_PIPE_180_DEG_BENDS, - den_coolant=self.data.fwbs.den_fw_coolant, - visc_coolant_dynamic=self.data.fwbs.visc_fw_coolant, - coolant_electrical_conductivity=0.0e0, - pol_channel_length=pollengo, - nopolchan=npoltoto, - label="Outboard first wall", - ) + dpres_fw_outboard_coolant, _ = self.total_pressure_drop( + output, + icoolpump=1, + vel_coolant=vel_fw_outboard_coolant, + len_pipe=self.data.fwbs.len_fw_channel, + n_pipe_90_deg_bends=N_FW_PIPE_90_DEG_BENDS, + n_pipe_180_deg_bends=N_FW_PIPE_180_DEG_BENDS, + den_coolant=self.data.fwbs.den_fw_coolant, + visc_coolant_dynamic=self.data.fwbs.visc_fw_coolant, + coolant_electrical_conductivity=0.0e0, + pol_channel_length=pollengo, + nopolchan=npoltoto, + label="Outboard first wall", ) # BB Presure Drops ############### From 3b043bbcbf66d20d4c3fb7fdf4d9d02e1604f1c0 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 11 Jun 2026 15:23:04 +0100 Subject: [PATCH 17/18] Post rebase fixes --- process/models/blankets/blanket_library.py | 2 +- process/models/engineering/pumping.py | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 1dce72158c..1e50fc6239 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -21,8 +21,8 @@ eshellvol, ) from process.models.engineering.pumping import ( - CoolantType, CoolantFrictionLossParameters, + CoolantType, calculate_required_mass_flow_rate, calculate_reynolds_number, darcy_friction_haaland, diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index 222dc02aca..19c00b242f 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -1,12 +1,16 @@ """Engineering models for pumping system analysis.""" import logging +from dataclasses import dataclass from enum import IntEnum from types import DynamicClassAttribute -from dataclasses import dataclass import numpy as np +from process.core.exceptions import ProcessValueError + +logger = logging.getLogger(__name__) + class CoolantType(IntEnum): """Enum for coolant types.""" @@ -41,11 +45,6 @@ def full_name(self): return self._full_name_ -from process.core.exceptions import ProcessValueError - -logger = logging.getLogger(__name__) - - @dataclass class CoolantFrictionLossParameters: """Parameters for calculating coolant friction losses.""" From 96202a1ae6a218f4fb06e927d87f494bd9a14bfc Mon Sep 17 00:00:00 2001 From: mn3981 Date: Tue, 23 Jun 2026 16:48:11 +0100 Subject: [PATCH 18/18] Remove unused CoolProp imports and related plotting functions for outboard blanket coolant properties --- process/core/io/plot/summary.py | 111 +------------------------------- 1 file changed, 2 insertions(+), 109 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 7a14082b64..e3dd4b3f44 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -7,14 +7,11 @@ from pathlib import Path from typing import Any, Literal -import CoolProp import matplotlib as mpl import matplotlib.backends.backend_pdf as bpdf import matplotlib.image as mpimg import matplotlib.pyplot as plt import numpy as np -from CoolProp.CoolProp import PropsSI -from CoolProp.Plots import PropertyPlot from matplotlib import patches from matplotlib.axes import Axes from matplotlib.patches import Circle, Rectangle @@ -15314,19 +15311,11 @@ def plot_blanket_coolant_channel_structure(self, m_file: MFile, scan: int): ) n_blkt_outboard_module_coolant_sections_radial = max( 1, - int( - round( - m_file.get("n_blkt_outboard_module_coolant_sections_radial", scan=scan) - ) - ), + round(m_file.get("n_blkt_outboard_module_coolant_sections_radial", scan=scan)), ) n_blkt_outboard_module_coolant_sections_poloidal = max( 1, - int( - round( - m_file.get("n_blkt_outboard_module_coolant_sections_poloidal", scan=scan) - ) - ), + round(m_file.get("n_blkt_outboard_module_coolant_sections_poloidal", scan=scan)), ) elbow_radius_180 = max( float(m_file.get("radius_blkt_channel_180_bend", scan=scan)), 1e-6 @@ -15537,102 +15526,6 @@ def _plot_bend( return axis -def plot_outboard_blanket_coolant_properties(fig: plt.Figure, m_file: MFile, scan: int): - """Plots the properties of the outboard blanket coolant along the poloidal direction.""" - temp_blkt_coolant_in = float(m_file.get("temp_blkt_coolant_in", scan=scan)) - temp_blkt_coolant_out = float(m_file.get("temp_blkt_coolant_out", scan=scan)) - pres_blkt_coolant = float(m_file.get("pres_blkt_coolant", scan=scan)) - dens_blkt_coolant_in = PropsSI( - "Dmass", "T", temp_blkt_coolant_in, "P", pres_blkt_coolant, "Helium" - ) - dens_blkt_coolant_out = PropsSI( - "Dmass", "T", temp_blkt_coolant_out, "P", pres_blkt_coolant, "Helium" - ) - - fig.clear() - axes = fig.subplots(2, 2) - - axis = axes[0, 0] - - plot = PropertyPlot("Helium", "PH", axis=axis, unit_system="SI") - - # #axis.set_xscale('log') - axis.set_ylim(((pres_blkt_coolant) * 0.9), (pres_blkt_coolant) * 1.5) - # plot.set_axis_limits([None, None, (pres_blkt_coolant/1e3)*0.9, (pres_blkt_coolant/1e3)*1.1]) - - plot.calc_isolines(CoolProp.iT) # Temperature - plot.calc_isolines(CoolProp.iSmass) # Entropy - plot.calc_isolines(CoolProp.iDmass) # Density - # plot.axis.relim() - # plot.axis.autoscale_view() - plot.draw() - - axis.set_title("Pressure-enthalpy plot") - - axis = axes[0, 1] - plot = PropertyPlot("Helium", "TD", axis=axis, unit_system="SI") - - density_min = min(dens_blkt_coolant_in, dens_blkt_coolant_out) - density_max = max(dens_blkt_coolant_in, dens_blkt_coolant_out) - temperature_min = min(temp_blkt_coolant_in, temp_blkt_coolant_out) - temperature_max = max(temp_blkt_coolant_in, temp_blkt_coolant_out) - - density_margin = max((density_max - density_min) * 0.2, max(density_max, 1.0) * 0.05) - temperature_margin = max( - (temperature_max - temperature_min) * 0.2, - max(temperature_max, 1.0) * 0.05, - ) - - axis.set_xlim(density_min - density_margin, density_max + density_margin) - axis.set_ylim( - temperature_min - temperature_margin, temperature_max + temperature_margin - ) - - plot.calc_isolines(CoolProp.iP) # Pressure - plot.calc_isolines(CoolProp.iHmass) # Enthalpy - plot.draw() - - axis.plot( - [dens_blkt_coolant_in, dens_blkt_coolant_out], - [temp_blkt_coolant_in, temp_blkt_coolant_out], - color="C3", - marker="o", - linewidth=1.5, - label="Coolant path", - ) - axis.legend(fontsize=8, loc="best") - axis.set_title("Temperature-density plot") - - axis = axes[1, 0] - plot = PropertyPlot("Helium", "PD", axis=axis, unit_system="SI") - - pressure_margin = max(pres_blkt_coolant * 0.1, 1.0) - - axis.set_xlim(density_min - density_margin, density_max + density_margin) - axis.set_ylim( - pres_blkt_coolant - pressure_margin, pres_blkt_coolant + pressure_margin - ) - - plot.calc_isolines(CoolProp.iT) # Temperature - plot.calc_isolines(CoolProp.iHmass) # Enthalpy - plot.draw() - - axis.plot( - [dens_blkt_coolant_in, dens_blkt_coolant_out], - [pres_blkt_coolant, pres_blkt_coolant], - color="C3", - marker="o", - linewidth=1.5, - label="Coolant path", - ) - axis.legend(fontsize=8, loc="best") - axis.set_title("Pressure-density plot") - - axes[1, 1].axis("off") - - fig.tight_layout() - - def plot_blanket_coolant_channel_structure_and_properties( fig: plt.Figure, m_file: MFile, scan: int ):