From 713fd706277f02cb3172da8e878519682119eb7a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 09:17:40 +0100 Subject: [PATCH 1/8] Create engineering method files --- process/models/engineering/__init__.py | 0 process/models/engineering/materials.py | 41 +++++++++++++++++++++++++ process/models/engineering/pumping.py | 0 3 files changed, 41 insertions(+) create mode 100644 process/models/engineering/__init__.py create mode 100644 process/models/engineering/materials.py create mode 100644 process/models/engineering/pumping.py diff --git a/process/models/engineering/__init__.py b/process/models/engineering/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/process/models/engineering/materials.py b/process/models/engineering/materials.py new file mode 100644 index 0000000000..dc9eb340eb --- /dev/null +++ b/process/models/engineering/materials.py @@ -0,0 +1,41 @@ +import logging + +from process.data_structure import ( + fwbs_variables, +) + +logger = logging.getLogger(__name__) + + +def eurofer97_thermal_conductivity(temp: float) -> float: + """Calculates the thermal conductivity of the first wall material (Eurofer97). + + Parameters + ---------- + temp: + Property temperature in Kelvin (K). + + Returns + ------- + : + Thermal conductivity of Eurofer97 in W/m/K. + + Notes + ----- + Valid up to about 800 K + + References + ---------- + - A. A. Tavassoli et al., “Materials design data for reduced activation martensitic steel type EUROFER,” + Journal of Nuclear Materials, vol. 329-333, pp. 257-262, Aug. 2004, + doi: https://doi.org/10.1016/j.jnucmat.2004.04.020. + + - Tavassoli, F. "Fusion Demo Interim Structural Design Criteria (DISDC)/Appendix A Material Design Limit Data/A3. S18E Eurofer Steel." + CEA, EFDA_TASK_TW4-TTMS-005-D01 (2004) + """ + # temp in Kelvin + return ( + (5.4308 + 0.13565 * temp - 0.00023862 * temp**2 + 1.3393e-7 * temp**3) + * fwbs_variables.fw_th_conductivity + / 28.34 + ) diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py new file mode 100644 index 0000000000..e69de29bb2 From c6cdc0d79cc01ddbd7d0111c1bcb4c64d5a62a27 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 09:28:43 +0100 Subject: [PATCH 2/8] Refactor first wall thermal conductivity calculation and add unit tests for Eurofer97 material Co-authored-by: Copilot --- process/models/fw.py | 36 ++----------------- .../unit/models/engineering/test_materials.py | 10 ++++++ tests/unit/models/test_fw.py | 6 ---- 3 files changed, 12 insertions(+), 40 deletions(-) create mode 100644 tests/unit/models/engineering/test_materials.py diff --git a/process/models/fw.py b/process/models/fw.py index 59dadcb9e9..4dc0c2e538 100644 --- a/process/models/fw.py +++ b/process/models/fw.py @@ -22,6 +22,7 @@ eshellarea, ) from process.models.build import FwBlktVVShape +from process.models.engineering.materials import eurofer97_thermal_conductivity logger = logging.getLogger(__name__) @@ -457,7 +458,7 @@ def fw_temp( ) # Thermal conductivity of first wall material (W/m.K) - tkfw = self.fw_thermal_conductivity(temp_k) + tkfw = eurofer97_thermal_conductivity(temp=temp_k) # Heat transfer coefficient (W m^-2 K^-1) hcoeff = self.heat_transfer( @@ -646,39 +647,6 @@ def fw_temp( mflow_fw_coolant, ) - def fw_thermal_conductivity(self, temp: float) -> float: - """Calculates the thermal conductivity of the first wall material (Eurofer97). - - Parameters - ---------- - temp: - Property temperature in Kelvin (K). - - Returns - ------- - : - Thermal conductivity of Eurofer97 in W/m/K. - - Notes - ----- - Valid up to about 800 K - - References - ---------- - - A. A. Tavassoli et al., “Materials design data for reduced activation martensitic steel type EUROFER,” - Journal of Nuclear Materials, vol. 329-333, pp. 257-262, Aug. 2004, - doi: https://doi.org/10.1016/j.jnucmat.2004.04.020. - - - Tavassoli, F. "Fusion Demo Interim Structural Design Criteria (DISDC)/Appendix A Material Design Limit Data/A3. S18E Eurofer Steel." - CEA, EFDA_TASK_TW4-TTMS-005-D01 (2004) - """ - # temp in Kelvin - return ( - (5.4308 + 0.13565 * temp - 0.00023862 * temp**2 + 1.3393e-7 * temp**3) - * fwbs_variables.fw_th_conductivity - / 28.34 - ) - def heat_transfer( self, mflux_coolant: float, diff --git a/tests/unit/models/engineering/test_materials.py b/tests/unit/models/engineering/test_materials.py new file mode 100644 index 0000000000..e56867059f --- /dev/null +++ b/tests/unit/models/engineering/test_materials.py @@ -0,0 +1,10 @@ +import pytest + +from process.data_structure import fwbs_variables +from process.models.engineering.materials import eurofer97_thermal_conductivity + + +def test_eurofer97_thermal_conductivity(monkeypatch): + monkeypatch.setattr(fwbs_variables, "fw_th_conductivity", 28.9) + + assert eurofer97_thermal_conductivity(1900.0) == pytest.approx(326.70406785462256) diff --git a/tests/unit/models/test_fw.py b/tests/unit/models/test_fw.py index db4c1be64d..b222a54447 100644 --- a/tests/unit/models/test_fw.py +++ b/tests/unit/models/test_fw.py @@ -182,9 +182,3 @@ def test_heat_transfer(fw): thermcond_coolant=0.3211653052986152, roughness_fw_channel=6e-8, ) == pytest.approx(1929.2042015869506) - - -def test_fw_thermal_conductivity(monkeypatch, fw): - monkeypatch.setattr(fwbs_variables, "fw_th_conductivity", 28.9) - - assert fw.fw_thermal_conductivity(1900.0) == pytest.approx(326.70406785462256) From a398d4d650c789504e792bbe2fae820db89466ce Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 09:35:02 +0100 Subject: [PATCH 3/8] Add darcy_friction_haaland function and update first wall model to use it Co-authored-by: Copilot --- process/models/blankets/blanket_library.py | 9 ++-- process/models/engineering/pumping.py | 40 +++++++++++++++++ process/models/fw.py | 45 +++---------------- tests/unit/models/engineering/test_pumping.py | 9 ++++ tests/unit/models/test_fw.py | 6 --- 5 files changed, 59 insertions(+), 50 deletions(-) create mode 100644 tests/unit/models/engineering/test_pumping.py diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index 3f1cf646c9..aa41b46c3a 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -20,6 +20,7 @@ primary_pumping_variables, ) from process.models.build import FwBlktVVShape +from process.models.engineering.pumping import darcy_friction_haaland logger = logging.getLogger(__name__) @@ -3016,10 +3017,10 @@ def coolant_friction_pressure_drop( # Use dh which allows us to do fluid calculations for non-cicular tubes # (dh is estimate appropriate for fully developed flow). - darcy_friction_factor = self.fw.darcy_friction_haaland( - reynolds_number, - fwbs_variables.roughness_fw_channel, - fwbs_variables.radius_fw_channel, + darcy_friction_factor = darcy_friction_haaland( + reynolds=reynolds_number, + roughness_channel=fwbs_variables.roughness_fw_channel, + radius_channel=fwbs_variables.radius_fw_channel, ) # Pressure drop coefficient diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index e69de29bb2..81657a43f4 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -0,0 +1,40 @@ +import logging + +import numpy as np + +logger = logging.getLogger(__name__) + + +def darcy_friction_haaland( + reynolds: float, roughness_channel: float, radius_channel: float +) -> float: + """Calculate Darcy friction factor using the Haaland equation. + + Parameters + ---------- + reynolds: + Reynolds number. + roughness_channel: + Roughness of the first wall coolant channel (m). + radius_channel: + Radius of the first wall coolant channel (m). + + Returns + ------- + : + Darcy friction factor. + + Notes + ----- + The Haaland equation is an approximation to the implicit Colebrook-White equation. + It is used to calculate the Darcy friction factor for turbulent flow in pipes. + + References + ---------- + - https://en.wikipedia.org/wiki/Darcy_friction_factor_formulae#Haaland_equation + """ + # Bracketed term in Haaland equation + bracket = (roughness_channel / radius_channel / 3.7) ** 1.11 + 6.9 / reynolds + + # Calculate Darcy friction factor + return (1.8 * np.log10(bracket)) ** (-2) diff --git a/process/models/fw.py b/process/models/fw.py index 4dc0c2e538..d8ac25fe32 100644 --- a/process/models/fw.py +++ b/process/models/fw.py @@ -23,6 +23,7 @@ ) from process.models.build import FwBlktVVShape from process.models.engineering.materials import eurofer97_thermal_conductivity +from process.models.engineering.pumping import darcy_friction_haaland logger = logging.getLogger(__name__) @@ -704,10 +705,10 @@ def heat_transfer( pr = heatcap_coolant * visc_coolant / thermcond_coolant # Calculate Darcy friction factor, using Haaland equation - f = self.darcy_friction_haaland( - reynolds, - roughness_fw_channel, - radius_channel, + f = darcy_friction_haaland( + reynolds=reynolds, + roughness_channel=roughness_fw_channel, + radius_channel=radius_channel, ) # Calculate the Nusselt number @@ -735,42 +736,6 @@ def heat_transfer( return heat_transfer_coefficient - def darcy_friction_haaland( - self, reynolds: float, roughness_fw_channel: float, radius_fw_channel: float - ) -> float: - """Calculate Darcy friction factor using the Haaland equation. - - Parameters - ---------- - reynolds - Reynolds number. - roughness_fw_channel - Roughness of the first wall coolant channel (m). - radius_fw_channel - Radius of the first wall coolant channel (m). - - Returns - ------- - : - Darcy friction factor. - - Notes - ----- - The Haaland equation is an approximation to the implicit Colebrook-White equation. - It is used to calculate the Darcy friction factor for turbulent flow in pipes. - - References - ---------- - - https://en.wikipedia.org/wiki/Darcy_friction_factor_formulae#Haaland_equation - """ - # Bracketed term in Haaland equation - bracket = ( - roughness_fw_channel / radius_fw_channel / 3.7 - ) ** 1.11 + 6.9 / reynolds - - # Calculate Darcy friction factor - return (1.8 * np.log10(bracket)) ** (-2) - @staticmethod def calculate_total_fw_channels( a_fw_inboard: float, diff --git a/tests/unit/models/engineering/test_pumping.py b/tests/unit/models/engineering/test_pumping.py new file mode 100644 index 0000000000..01643d046c --- /dev/null +++ b/tests/unit/models/engineering/test_pumping.py @@ -0,0 +1,9 @@ +import pytest + +from process.models.engineering.pumping import darcy_friction_haaland + + +def test_darcy_friction_haaland(): + assert darcy_friction_haaland( + reynolds=5500, roughness_channel=1e-6, radius_channel=0.1 + ) == pytest.approx(0.0366668931278784) diff --git a/tests/unit/models/test_fw.py b/tests/unit/models/test_fw.py index b222a54447..8836c28225 100644 --- a/tests/unit/models/test_fw.py +++ b/tests/unit/models/test_fw.py @@ -166,12 +166,6 @@ def test_fw_temp(fwtempparam, monkeypatch, fw): assert massrate == pytest.approx(fwtempparam.expected_massrate, rel=1e-4) -def test_darcy_friction_haaland(fw): - assert fw.darcy_friction_haaland(5500, 1e-6, 0.1) == pytest.approx( - 0.0366668931278784 - ) - - def test_heat_transfer(fw): assert fw.heat_transfer( mflux_coolant=112.19853108876258, From 22695913e62f66733cd3b846cca41b733041dcd8 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 09:42:14 +0100 Subject: [PATCH 4/8] Implement Gnielinski heat transfer coefficient calculation and update FirstWall model to use it Co-authored-by: Copilot --- process/models/engineering/pumping.py | 88 ++++++++++++++ process/models/fw.py | 108 ++---------------- tests/unit/models/engineering/test_pumping.py | 17 ++- tests/unit/models/test_fw.py | 12 -- 4 files changed, 115 insertions(+), 110 deletions(-) diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index 81657a43f4..eb49c70ea3 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -38,3 +38,91 @@ def darcy_friction_haaland( # Calculate Darcy friction factor return (1.8 * np.log10(bracket)) ** (-2) + + +def gnielinski_heat_transfer_coefficient( + mflux_coolant: float, + den_coolant: float, + radius_channel: float, + heatcap_coolant: float, + visc_coolant: float, + thermcond_coolant: float, + roughness_fw_channel: float, +) -> float: + """Calculate heat transfer coefficient using Gnielinski correlation. + + Parameters + ---------- + mflux_coolant: + Coolant mass flux in a single channel (kg/m²/s). + den_coolant: + Coolant density (average of inlet and outlet) (kg/m³). + radius_channel: + Coolant pipe radius (m). + heatcap_coolant: + Coolant specific heat capacity (average of inlet and outlet) (J/kg/K). + visc_coolant: + Coolant viscosity (average of inlet and outlet) (Pa.s). + thermcond_coolant: + Thermal conductivity of coolant (average of inlet and outlet) (W/m.K). + roughness_fw_channel: + Roughness of the first wall coolant channel (m). + + Returns + ------- + : + Heat transfer coefficient (W/m²K). + + Notes + ----- + Gnielinski correlation. Ignore the distinction between wall and + bulk temperatures. Valid for: 3000 < Re < 5e6, 0.5 < Pr < 2000 + + References + ---------- + - https://en.wikipedia.org/wiki/Nusselt_number#Gnielinski_correlation + + """ + # Calculate pipe diameter (m) + diameter = 2 * radius_channel + + # Calculate flow velocity (m/s) + velocity = mflux_coolant / den_coolant + + # Calculate Reynolds number + reynolds = den_coolant * velocity * diameter / visc_coolant + + # Calculate Prandtl number + pr = heatcap_coolant * visc_coolant / thermcond_coolant + + # Calculate Darcy friction factor, using Haaland equation + f = darcy_friction_haaland( + reynolds=reynolds, + roughness_channel=roughness_fw_channel, + radius_channel=radius_channel, + ) + + # Calculate the Nusselt number + nusselt = ( + (f / 8.0) + * (reynolds - 1000.0) + * pr + / (1 + 12.7 * np.sqrt(f / 8.0) * (pr ** (2 / 3) - 1.0)) + ) + + # Calculate the heat transfer coefficient (W/m^2K) + heat_transfer_coefficient = nusselt * thermcond_coolant / (2.0 * radius_channel) + + # Check that Reynolds number is in valid range for the Gnielinski correlation + if (reynolds <= 3000.0) or (reynolds > 5.0e6): + logger.error("Reynolds number out of range : [3e3-5000e3]. %s", reynolds) + + # Check that Prandtl number is in valid range for the Gnielinski correlation + if (pr < 0.5) or (pr > 2000.0): + logger.error("Prandtl number out of range : [0.5-2000]. %s", pr) + + # Check that the Darcy friction factor is in valid range for the Gnielinski correlation + if f <= 0.0: + logger.error("Negative Darcy friction factor (f). %s", f) + + return heat_transfer_coefficient diff --git a/process/models/fw.py b/process/models/fw.py index d8ac25fe32..493fac7329 100644 --- a/process/models/fw.py +++ b/process/models/fw.py @@ -23,7 +23,9 @@ ) from process.models.build import FwBlktVVShape from process.models.engineering.materials import eurofer97_thermal_conductivity -from process.models.engineering.pumping import darcy_friction_haaland +from process.models.engineering.pumping import ( + gnielinski_heat_transfer_coefficient, +) logger = logging.getLogger(__name__) @@ -462,14 +464,14 @@ def fw_temp( tkfw = eurofer97_thermal_conductivity(temp=temp_k) # Heat transfer coefficient (W m^-2 K^-1) - hcoeff = self.heat_transfer( - mflux_fw_coolant, - outlet_coolant_properties.density, - radius_fw_channel, - outlet_coolant_properties.specific_heat_const_p, - outlet_coolant_properties.viscosity, - outlet_coolant_properties.thermal_conductivity, - fwbs_variables.roughness_fw_channel, + hcoeff = gnielinski_heat_transfer_coefficient( + mflux_coolant=mflux_fw_coolant, + den_coolant=outlet_coolant_properties.density, + radius_channel=radius_fw_channel, + heatcap_coolant=outlet_coolant_properties.specific_heat_const_p, + visc_coolant=outlet_coolant_properties.viscosity, + thermcond_coolant=outlet_coolant_properties.thermal_conductivity, + roughness_fw_channel=fwbs_variables.roughness_fw_channel, ) # Temperature drops between first-wall surface and bulk coolant ! @@ -648,94 +650,6 @@ def fw_temp( mflow_fw_coolant, ) - def heat_transfer( - self, - mflux_coolant: float, - den_coolant: float, - radius_channel: float, - heatcap_coolant: float, - visc_coolant: float, - thermcond_coolant: float, - roughness_fw_channel: float, - ) -> float: - """Calculate heat transfer coefficient using Gnielinski correlation. - - Parameters - ---------- - mflux_coolant: - Coolant mass flux in a single channel (kg/m^2/s). - den_coolant: - Coolant density (average of inlet and outlet) (kg/m^3). - radius_channel: - Coolant pipe radius (m). - heatcap_coolant: - Coolant specific heat capacity (average of inlet and outlet) (J/kg/K). - visc_coolant: - Coolant viscosity (average of inlet and outlet) (Pa.s). - thermcond_coolant: - Thermal conductivity of coolant (average of inlet and outlet) (W/m.K). - roughness_fw_channel: - Roughness of the first wall coolant channel (m). - - Returns - ------- - : - Heat transfer coefficient (W/m^2K). - - Notes - ----- - Gnielinski correlation. Ignore the distinction between wall and - bulk temperatures. Valid for: 3000 < Re < 5e6, 0.5 < Pr < 2000 - - References - ---------- - - https://en.wikipedia.org/wiki/Nusselt_number#Gnielinski_correlation - - """ - # Calculate pipe diameter (m) - diameter = 2 * radius_channel - - # Calculate flow velocity (m/s) - velocity = mflux_coolant / den_coolant - - # Calculate Reynolds number - reynolds = den_coolant * velocity * diameter / visc_coolant - - # Calculate Prandtl number - pr = heatcap_coolant * visc_coolant / thermcond_coolant - - # Calculate Darcy friction factor, using Haaland equation - f = darcy_friction_haaland( - reynolds=reynolds, - roughness_channel=roughness_fw_channel, - radius_channel=radius_channel, - ) - - # Calculate the Nusselt number - nusselt = ( - (f / 8.0) - * (reynolds - 1000.0) - * pr - / (1 + 12.7 * np.sqrt(f / 8.0) * (pr ** (2 / 3) - 1.0)) - ) - - # Calculate the heat transfer coefficient (W/m^2K) - heat_transfer_coefficient = nusselt * thermcond_coolant / (2.0 * radius_channel) - - # Check that Reynolds number is in valid range for the Gnielinski correlation - if (reynolds <= 3000.0) or (reynolds > 5.0e6): - logger.error("Reynolds number out of range : [3e3-5000e3]. %s", reynolds) - - # Check that Prandtl number is in valid range for the Gnielinski correlation - if (pr < 0.5) or (pr > 2000.0): - logger.error("Prandtl number out of range : [0.5-2000]. %s", pr) - - # Check that the Darcy friction factor is in valid range for the Gnielinski correlation - if f <= 0.0: - logger.error("Negative Darcy friction factor (f). %s", f) - - return heat_transfer_coefficient - @staticmethod def calculate_total_fw_channels( a_fw_inboard: float, diff --git a/tests/unit/models/engineering/test_pumping.py b/tests/unit/models/engineering/test_pumping.py index 01643d046c..2e1e296943 100644 --- a/tests/unit/models/engineering/test_pumping.py +++ b/tests/unit/models/engineering/test_pumping.py @@ -1,9 +1,24 @@ import pytest -from process.models.engineering.pumping import darcy_friction_haaland +from process.models.engineering.pumping import ( + darcy_friction_haaland, + gnielinski_heat_transfer_coefficient, +) def test_darcy_friction_haaland(): assert darcy_friction_haaland( reynolds=5500, roughness_channel=1e-6, radius_channel=0.1 ) == pytest.approx(0.0366668931278784) + + +def test_gnielinski_heat_transfer_coefficient(): + assert gnielinski_heat_transfer_coefficient( + mflux_coolant=112.19853108876258, + den_coolant=8.8673250601290707, + radius_channel=0.0060000000000000001, + heatcap_coolant=5184.9330299967578, + visc_coolant=4.0416219836935569e-05, + thermcond_coolant=0.3211653052986152, + roughness_fw_channel=6e-8, + ) == pytest.approx(1929.2042015869506) diff --git a/tests/unit/models/test_fw.py b/tests/unit/models/test_fw.py index 8836c28225..dc7867b2fc 100644 --- a/tests/unit/models/test_fw.py +++ b/tests/unit/models/test_fw.py @@ -164,15 +164,3 @@ def test_fw_temp(fwtempparam, monkeypatch, fw): assert rhofmean == pytest.approx(fwtempparam.expected_rhofmean, rel=1e-4) assert massrate == pytest.approx(fwtempparam.expected_massrate, rel=1e-4) - - -def test_heat_transfer(fw): - assert fw.heat_transfer( - mflux_coolant=112.19853108876258, - den_coolant=8.8673250601290707, - radius_channel=0.0060000000000000001, - heatcap_coolant=5184.9330299967578, - visc_coolant=4.0416219836935569e-05, - thermcond_coolant=0.3211653052986152, - roughness_fw_channel=6e-8, - ) == pytest.approx(1929.2042015869506) From 8f169bf1ba158988279b37280b505df0ed402071 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 09:53:41 +0100 Subject: [PATCH 5/8] Add pumping and materials methods documentation and update navigation Co-authored-by: Copilot --- documentation/source/eng-models/fw-blanket.md | 2 +- .../source/eng-models/generic_methods/materials.md | 1 + .../source/eng-models/generic_methods/pumping.md | 9 +++++++++ mkdocs.yml | 3 +++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 documentation/source/eng-models/generic_methods/materials.md create mode 100644 documentation/source/eng-models/generic_methods/pumping.md diff --git a/documentation/source/eng-models/fw-blanket.md b/documentation/source/eng-models/fw-blanket.md index d1ca05bcaa..c5952c980b 100644 --- a/documentation/source/eng-models/fw-blanket.md +++ b/documentation/source/eng-models/fw-blanket.md @@ -213,7 +213,7 @@ where $\texttt{tkfw}$ is the thermal conductivity of the first wall material and were $c_{\text{p}}$ is the coolant heat capacity and $k$ is the coolant thermal conductivity. -3. **Calculate the Darcy friction factor using the [`darcy_friction_haaland()`](#fw-coolant-friction--darcy_friction_haaland) method:** +3. **Calculate the Darcy friction factor using the [`darcy_friction_haaland()`](../eng-models/generic_methods/pumping.md#pumping-coolant-friction--darcy_friction_haaland) method:** $$ f = \texttt{darcy_friction_haaland()} diff --git a/documentation/source/eng-models/generic_methods/materials.md b/documentation/source/eng-models/generic_methods/materials.md new file mode 100644 index 0000000000..0a1bf9cb6c --- /dev/null +++ b/documentation/source/eng-models/generic_methods/materials.md @@ -0,0 +1 @@ +# Materials Methods \ No newline at end of file diff --git a/documentation/source/eng-models/generic_methods/pumping.md b/documentation/source/eng-models/generic_methods/pumping.md new file mode 100644 index 0000000000..eb2bea0689 --- /dev/null +++ b/documentation/source/eng-models/generic_methods/pumping.md @@ -0,0 +1,9 @@ +# Pumping Methods + +## Pumping coolant friction | `darcy_friction_haaland()` + + The pressure drop is based on the Darcy fraction factor, using the [Haaland equation](https://en.wikipedia.org/wiki/Darcy_friction_factor_formulae#Haaland_equation), an approximation to the implicit Colebrook–White equation. + +$$ +\frac{1}{\sqrt{f}} = -1.8 \log{\left[ \left(\frac{\epsilon / D}{3.7}\right)^{1.11} \frac{6.9}{\text{Re}} \right]} +$$ \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 74ba107a8e..ef45e2a15c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -118,6 +118,9 @@ nav: - Plant Availability: eng-models/plant-availability.md - Power Requirements: eng-models/power-requirements.md - Vacuum Vessel: eng-models/vacuum-vessel.md + - Generic Engineering Methods: + - Pumping: eng-models/pumping.md + - Materials: eng-models/materials.md - Unique Models: - Water Use: unique-models/water_use.md - Power Plant Building Sizes: unique-models/buildings_sizes.md From 408fbc3a9db13ca84408e53497d304dfdb3dff0a Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 10:10:04 +0100 Subject: [PATCH 6/8] Update documentation for coolant pumping and heat transfer methods Co-authored-by: Copilot --- .../source/eng-models/blanket_overview.md | 2 +- documentation/source/eng-models/fw-blanket.md | 81 +------------------ .../eng-models/generic_methods/materials.md | 18 ++++- .../eng-models/generic_methods/pumping.md | 47 ++++++++++- mkdocs.yml | 4 +- 5 files changed, 69 insertions(+), 83 deletions(-) diff --git a/documentation/source/eng-models/blanket_overview.md b/documentation/source/eng-models/blanket_overview.md index 71ea951c26..66a84b15f7 100644 --- a/documentation/source/eng-models/blanket_overview.md +++ b/documentation/source/eng-models/blanket_overview.md @@ -44,7 +44,7 @@ $$ here $L$ is the characteristic length which we set to be the pipe diameter and $\mu$ is the coolant dynamic viscosity. -Using the Reynolds number we calculate the Darcy friction factor using the Haaland approximation calculated by `darcy_friction_haaland()`. +Using the Reynolds number we calculate the Darcy friction factor using the Haaland approximation calculated by [`darcy_friction_haaland()`](../eng-models/generic_methods/pumping.md#pumping-coolant-friction--darcy_friction_haaland). For the radius of the pipe bend we assume it to be 3 times the radius of the coolant channel. diff --git a/documentation/source/eng-models/fw-blanket.md b/documentation/source/eng-models/fw-blanket.md index c5952c980b..a1cdf2aa22 100644 --- a/documentation/source/eng-models/fw-blanket.md +++ b/documentation/source/eng-models/fw-blanket.md @@ -137,9 +137,9 @@ This function is used to calculate the first wall heating, it assumes the same c \mathtt{temp_k} = \frac{T_{\text{outlet}} + T_{\text{FW,peak}}}{2} $$ -8. Calculate the FW thermal conductivity at $\mathtt{temp_k}$ using the [`fw_thermal_conductivity()`](#fw-thermal-conductivity--fw_thermal_conductivity) function. +8. Calculate the FW thermal conductivity at $\mathtt{temp_k}$ using the [`eurofer97_thermal_conductivity()`](../eng-models/generic_methods/materials.md#eurofer97-thermal-conductivity--eurofer97_thermal_conductivity) function. -9. Determine the heat transfer coefficient using the [`heat_transfer()`](#fw-heat-transfer--heat_transfer) function. +9. Determine the heat transfer coefficient using the [`gnielinski_heat_transfer_coefficient()`](../eng-models/generic_methods/pumping.md#gnielinski-heat-transfer--gnielinski_heat_transfer_coefficient) function. 10. Compute the worst-case load. @@ -193,78 +193,8 @@ $$ where $\texttt{tkfw}$ is the thermal conductivity of the first wall material and $\texttt{onedload}$ is the heat load per unit length. -------------- - -### FW heat transfer | `heat_transfer()` - -1. **Calculate the Reynolds number:** - - $$ - \mathrm{Re} = \frac{\rho v \left(2r_{\text{channel}}\right)}{\mu} - $$ - - where $\rho$ is the coolant density and $\mu$ is the coolant viscosity. - -2. **Calculate the Prandtl number:** - - $$ - \mathrm{Pr} = \frac{c_{\text{p}}\mu}{k} - $$ - - were $c_{\text{p}}$ is the coolant heat capacity and $k$ is the coolant thermal conductivity. - -3. **Calculate the Darcy friction factor using the [`darcy_friction_haaland()`](../eng-models/generic_methods/pumping.md#pumping-coolant-friction--darcy_friction_haaland) method:** - - $$ - f = \texttt{darcy_friction_haaland()} - $$ - -4. **Calculate the Nusselt number using the [Gnielinski correlation](https://en.wikipedia.org/wiki/Nusselt_number#Gnielinski_correlation):** - - $$ - \mathrm{Nu_D} = \frac{\left(f/8\right)\left(\mathrm{Re}-1000\right)\mathrm{Pr}}{1+12.7\left(f/8\right)^{0.5}\left(\mathrm{Pr}^{2/3}-1\right)} - $$ - - The relation is valid for: - - $$ - 0.5 \le \mathrm{Pr} \le 2000 \\ - 3000 \le \mathrm{Re} \le 5 \times 10^6 - $$ - -5. **Calculate the heat transfer coefficient with the Nusselt number:** - - $$ - h = \frac{\mathrm{Nu_D}k}{2r_{\text{channel}}} - $$ - - -------------- -### FW coolant friction | `darcy_friction_haaland()` - - The pressure drop is based on the Darcy fraction factor, using the [Haaland equation](https://en.wikipedia.org/wiki/Darcy_friction_factor_formulae#Haaland_equation), an approximation to the implicit Colebrook–White equation. - -$$ -\frac{1}{\sqrt{f}} = -1.8 \log{\left[ \left(\frac{\epsilon / D}{3.7}\right)^{1.11} \frac{6.9}{\text{Re}} \right]} -$$ - ------------- - -### FW thermal conductivity | `fw_thermal_conductivity()` - -The thermal conductivity of the first wall is assumed to be that of Eurofer97 using the relation below[^1] [^2]: - -$$ -K_{\text{Eurofer97}} = 5.4308 + 0.13565T - 0.00023862T^2 + 1.3393 \times 10^{-7} T^3 -$$ - -!!! warning Thermal conductivity validity bounds - - The sources for the stated thermal conductivity relation above state that the relation is only valid up to 800K [^1] [^2]. - -------------- - ### Model Switches @@ -323,9 +253,4 @@ There are three model options, chosen by the user to match their selected blanke | Variable | Units | Itvar. | Usage | Default | Description | | :----------------------: | :-------: | ------ | ----------- | ------- | ------------------------------------------------------------------- | -| `bz_channel_conduct_liq` | A V-1 m-1 | 72 | ifci = 0, 2 | 8.33D5 | Liquid metal coolant/breeder thin conductor or FCI wall conductance | - - -[^1]: A. A. Tavassoli et al., “Materials design data for reduced activation martensitic steel type EUROFER,” Journal of Nuclear Materials, vol. 329–333, pp. 257–262, Aug. 2004, doi: https://doi.org/10.1016/j.jnucmat.2004.04.020. - -[^2]: Tavassoli, F. "Fusion Demo Interim Structural Design Criteria (DISDC)/Appendix A Material Design Limit Data/A3. S18E Eurofer Steel." CEA, EFDA_TASK_TW4-TTMS-005-D01 (2004). \ No newline at end of file +| `bz_channel_conduct_liq` | A V-1 m-1 | 72 | ifci = 0, 2 | 8.33D5 | Liquid metal coolant/breeder thin conductor or FCI wall conductance | \ No newline at end of file diff --git a/documentation/source/eng-models/generic_methods/materials.md b/documentation/source/eng-models/generic_methods/materials.md index 0a1bf9cb6c..bdf14d9768 100644 --- a/documentation/source/eng-models/generic_methods/materials.md +++ b/documentation/source/eng-models/generic_methods/materials.md @@ -1 +1,17 @@ -# Materials Methods \ No newline at end of file +# Materials Methods + +## Eurofer97 thermal conductivity | `eurofer97_thermal_conductivity()` + +The thermal conductivity of the first wall is assumed to be that of Eurofer97 using the relation below[^1] [^2]: + +$$ +K_{\text{Eurofer97}} = 5.4308 + 0.13565T - 0.00023862T^2 + 1.3393 \times 10^{-7} T^3 +$$ + +!!! warning Thermal conductivity validity bounds + + The sources for the stated thermal conductivity relation above state that the relation is only valid up to 800K [^1] [^2]. + +[^1]: A. A. Tavassoli et al., “Materials design data for reduced activation martensitic steel type EUROFER,” Journal of Nuclear Materials, vol. 329–333, pp. 257–262, Aug. 2004, doi: https://doi.org/10.1016/j.jnucmat.2004.04.020. + +[^2]: Tavassoli, F. "Fusion Demo Interim Structural Design Criteria (DISDC)/Appendix A Material Design Limit Data/A3. S18E Eurofer Steel." CEA, EFDA_TASK_TW4-TTMS-005-D01 (2004). \ No newline at end of file diff --git a/documentation/source/eng-models/generic_methods/pumping.md b/documentation/source/eng-models/generic_methods/pumping.md index eb2bea0689..a502facd91 100644 --- a/documentation/source/eng-models/generic_methods/pumping.md +++ b/documentation/source/eng-models/generic_methods/pumping.md @@ -6,4 +6,49 @@ $$ \frac{1}{\sqrt{f}} = -1.8 \log{\left[ \left(\frac{\epsilon / D}{3.7}\right)^{1.11} \frac{6.9}{\text{Re}} \right]} -$$ \ No newline at end of file +$$ + +------------------- + +## Gnielinski heat transfer | `gnielinski_heat_transfer_coefficient()` + +1. **Calculate the Reynolds number:** + + $$ + \mathrm{Re} = \frac{\rho v \left(2r_{\text{channel}}\right)}{\mu} + $$ + + where $\rho$ is the coolant density and $\mu$ is the coolant viscosity. + +2. **Calculate the Prandtl number:** + + $$ + \mathrm{Pr} = \frac{c_{\text{p}}\mu}{k} + $$ + + were $c_{\text{p}}$ is the coolant heat capacity and $k$ is the coolant thermal conductivity. + +3. **Calculate the Darcy friction factor using the [`darcy_friction_haaland()`](../eng-models/generic_methods/pumping.md#pumping-coolant-friction--darcy_friction_haaland) method:** + + $$ + f = \texttt{darcy_friction_haaland()} + $$ + +4. **Calculate the Nusselt number using the [Gnielinski correlation](https://en.wikipedia.org/wiki/Nusselt_number#Gnielinski_correlation):** + + $$ + \mathrm{Nu_D} = \frac{\left(f/8\right)\left(\mathrm{Re}-1000\right)\mathrm{Pr}}{1+12.7\left(f/8\right)^{0.5}\left(\mathrm{Pr}^{2/3}-1\right)} + $$ + + The relation is valid for: + + $$ + 0.5 \le \mathrm{Pr} \le 2000 \\ + 3000 \le \mathrm{Re} \le 5 \times 10^6 + $$ + +5. **Calculate the heat transfer coefficient with the Nusselt number:** + + $$ + h = \frac{\mathrm{Nu_D}k}{2r_{\text{channel}}} + $$ \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index ef45e2a15c..42595c58bf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -119,8 +119,8 @@ nav: - Power Requirements: eng-models/power-requirements.md - Vacuum Vessel: eng-models/vacuum-vessel.md - Generic Engineering Methods: - - Pumping: eng-models/pumping.md - - Materials: eng-models/materials.md + - Pumping: eng-models/generic_methods/pumping.md + - Materials: eng-models/generic_methods/materials.md - Unique Models: - Water Use: unique-models/water_use.md - Power Plant Building Sizes: unique-models/buildings_sizes.md From 28b795a3fceff9c6187feff185b8b30b184a616d Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 10:26:21 +0100 Subject: [PATCH 7/8] Add calculate_reynolds_number function and update related models and tests Co-authored-by: Copilot --- .../eng-models/generic_methods/pumping.md | 10 +++++ process/models/blankets/blanket_library.py | 12 +++++- process/models/engineering/pumping.py | 42 +++++++++++++++++-- tests/unit/models/engineering/test_pumping.py | 11 +++++ 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/documentation/source/eng-models/generic_methods/pumping.md b/documentation/source/eng-models/generic_methods/pumping.md index a502facd91..befc6de670 100644 --- a/documentation/source/eng-models/generic_methods/pumping.md +++ b/documentation/source/eng-models/generic_methods/pumping.md @@ -10,6 +10,16 @@ $$ ------------------- +## Reynolds number | `calculate_reynolds_number()` + +$$ +\mathrm{Re} = \frac{\rho v \left(2r_{\text{channel}}\right)}{\mu} +$$ + +where $\rho$ is the coolant density and $\mu$ is the coolant viscosity. + +------------------- + ## Gnielinski heat transfer | `gnielinski_heat_transfer_coefficient()` 1. **Calculate the Reynolds number:** diff --git a/process/models/blankets/blanket_library.py b/process/models/blankets/blanket_library.py index aa41b46c3a..47b7a754b6 100644 --- a/process/models/blankets/blanket_library.py +++ b/process/models/blankets/blanket_library.py @@ -20,7 +20,10 @@ primary_pumping_variables, ) from process.models.build import FwBlktVVShape -from process.models.engineering.pumping import darcy_friction_haaland +from process.models.engineering.pumping import ( + calculate_reynolds_number, + darcy_friction_haaland, +) logger = logging.getLogger(__name__) @@ -3010,7 +3013,12 @@ def coolant_friction_pressure_drop( dia_pipe = self.pipe_hydraulic_diameter(i_ps) # Reynolds number - reynolds_number = den_coolant * vel_coolant * dia_pipe / visc_coolant + reynolds_number = calculate_reynolds_number( + den_coolant=den_coolant, + vel_coolant=vel_coolant, + radius_channel=dia_pipe / 2, + visc_coolant=visc_coolant, + ) # Calculate Darcy friction factor # N.B. friction function Uses Haaland approx. which assumes a filled circular pipe. diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index eb49c70ea3..1e5b816f26 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -86,11 +86,13 @@ def gnielinski_heat_transfer_coefficient( # Calculate pipe diameter (m) diameter = 2 * radius_channel - # Calculate flow velocity (m/s) - velocity = mflux_coolant / den_coolant - # Calculate Reynolds number - reynolds = den_coolant * velocity * diameter / visc_coolant + reynolds = calculate_reynolds_number( + mflux_coolant=mflux_coolant, + den_coolant=den_coolant, + radius_channel=diameter / 2, + visc_coolant=visc_coolant, + ) # Calculate Prandtl number pr = heatcap_coolant * visc_coolant / thermcond_coolant @@ -126,3 +128,35 @@ def gnielinski_heat_transfer_coefficient( logger.error("Negative Darcy friction factor (f). %s", f) return heat_transfer_coefficient + + +def calculate_reynolds_number( + mflux_coolant: float, den_coolant: float, radius_channel: float, visc_coolant: float +) -> float: + """Calculate Reynolds number for flow in a pipe. + + Parameters + ---------- + mflux_coolant: + Coolant mass flux in a single channel (kg/m²/s). + den_coolant: + Coolant density (average of inlet and outlet) (kg/m³). + radius_channel: + Coolant pipe radius (m). + visc_coolant: + Coolant viscosity (average of inlet and outlet) (Pa.s). + + Returns + ------- + : + Reynolds number. + + """ + # Calculate pipe diameter (m) + diameter = 2 * radius_channel + + # Calculate flow velocity (m/s) + velocity = mflux_coolant / den_coolant + + # Calculate Reynolds number + return den_coolant * velocity * diameter / visc_coolant diff --git a/tests/unit/models/engineering/test_pumping.py b/tests/unit/models/engineering/test_pumping.py index 2e1e296943..781ea6ce5b 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_reynolds_number, darcy_friction_haaland, gnielinski_heat_transfer_coefficient, ) @@ -22,3 +23,13 @@ def test_gnielinski_heat_transfer_coefficient(): thermcond_coolant=0.3211653052986152, roughness_fw_channel=6e-8, ) == pytest.approx(1929.2042015869506) + + +def test_calculate_reynolds_number(): + + assert calculate_reynolds_number( + mflux_coolant=112.19853108876258, + den_coolant=8.8673250601290707, + radius_channel=0.0060000000000000001, + visc_coolant=4.0416219836935569e-05, + ) == pytest.approx(33312.92185407996) From bc0c38e0ee2c5987b638d4f2dc9c3cdcea4a5581 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Apr 2026 10:45:04 +0100 Subject: [PATCH 8/8] Refactor gnielinski_heat_transfer_coefficient and calculate_reynolds_number to use flow velocity directly Co-authored-by: Copilot --- process/models/engineering/pumping.py | 16 ++++++++-------- tests/unit/models/engineering/test_pumping.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/process/models/engineering/pumping.py b/process/models/engineering/pumping.py index 1e5b816f26..7d2683f477 100644 --- a/process/models/engineering/pumping.py +++ b/process/models/engineering/pumping.py @@ -86,10 +86,13 @@ def gnielinski_heat_transfer_coefficient( # Calculate pipe diameter (m) diameter = 2 * radius_channel + # Calculate flow velocity (m/s) + vel_coolant = mflux_coolant / den_coolant + # Calculate Reynolds number reynolds = calculate_reynolds_number( - mflux_coolant=mflux_coolant, den_coolant=den_coolant, + vel_coolant=vel_coolant, radius_channel=diameter / 2, visc_coolant=visc_coolant, ) @@ -131,16 +134,16 @@ def gnielinski_heat_transfer_coefficient( def calculate_reynolds_number( - mflux_coolant: float, den_coolant: float, radius_channel: float, visc_coolant: float + den_coolant: float, vel_coolant: float, radius_channel: float, visc_coolant: float ) -> float: """Calculate Reynolds number for flow in a pipe. Parameters ---------- - mflux_coolant: - Coolant mass flux in a single channel (kg/m²/s). den_coolant: Coolant density (average of inlet and outlet) (kg/m³). + vel_coolant: + Coolant velocity in a single channel (m/s). radius_channel: Coolant pipe radius (m). visc_coolant: @@ -155,8 +158,5 @@ def calculate_reynolds_number( # Calculate pipe diameter (m) diameter = 2 * radius_channel - # Calculate flow velocity (m/s) - velocity = mflux_coolant / den_coolant - # Calculate Reynolds number - return den_coolant * velocity * diameter / visc_coolant + return den_coolant * vel_coolant * diameter / visc_coolant diff --git a/tests/unit/models/engineering/test_pumping.py b/tests/unit/models/engineering/test_pumping.py index 781ea6ce5b..71953b5217 100644 --- a/tests/unit/models/engineering/test_pumping.py +++ b/tests/unit/models/engineering/test_pumping.py @@ -28,8 +28,8 @@ def test_gnielinski_heat_transfer_coefficient(): def test_calculate_reynolds_number(): assert calculate_reynolds_number( - mflux_coolant=112.19853108876258, den_coolant=8.8673250601290707, + vel_coolant=12.649110769896881, radius_channel=0.0060000000000000001, visc_coolant=4.0416219836935569e-05, - ) == pytest.approx(33312.92185407996) + ) == pytest.approx(33302.602975971815)