From 211b9862fc9ff12aea998aea15700b1b47b441e6 Mon Sep 17 00:00:00 2001 From: Anders Andreasen <58475535+andr1976@users.noreply.github.com> Date: Wed, 3 Dec 2025 23:16:32 +0100 Subject: [PATCH 1/5] misc --- src/hyddown/examples/LPG.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hyddown/examples/LPG.yml b/src/hyddown/examples/LPG.yml index 813814d..76d594f 100644 --- a/src/hyddown/examples/LPG.yml +++ b/src/hyddown/examples/LPG.yml @@ -5,7 +5,7 @@ vessel: heat_capacity: 500 density: 7700 thickness: 0.01185 - liquid_level: 0.4668 + liquid_level: 1.15 #0.4668 initial: temperature: 298.15 pressure: 550000 @@ -17,7 +17,7 @@ calculation: valve: flow: "discharge" type: "psv" - diameter: 0.040 + diameter: 0.05 discharge_coef: 0.975 set_pressure: 1430000 blowdown: 0.20 From c3181b620b322f98670fe0d23adf95d5346bd637 Mon Sep 17 00:00:00 2001 From: Anders Andreasen <58475535+andr1976@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:31:01 +0100 Subject: [PATCH 2/5] Fixed performance regression for multicomponent gas mixtures --- src/hyddown/hdclass.py | 5 +++-- src/hyddown/test_all.py | 10 +++++----- validation/CO2_tank_BDV.yml | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hyddown/hdclass.py b/src/hyddown/hdclass.py index 1014ac0..7390c15 100644 --- a/src/hyddown/hdclass.py +++ b/src/hyddown/hdclass.py @@ -229,7 +229,8 @@ def initialize(self): self.surf_area_inner = self.inner_vol.A self.fluid = CP.AbstractState("HEOS", self.comp) - # self.fluid.specify_phase(CP.iphase_gas) + if "&" in self.comp: + self.fluid.specify_phase(CP.iphase_gas) self.fluid.set_mole_fractions(self.molefracs) self.transport_fluid = CP.AbstractState("HEOS", self.compSRK) @@ -241,7 +242,7 @@ def initialize(self): self.transport_fluid_wet.set_mole_fractions(self.molefracs) self.vent_fluid = CP.AbstractState("HEOS", self.comp) - # self.vent_fluid.specify_phase(CP.iphase_gas) + self.vent_fluid.specify_phase(CP.iphase_gas) self.vent_fluid.set_mole_fractions(self.molefracs) if "liquid_level" in self.input["vessel"]: diff --git a/src/hyddown/test_all.py b/src/hyddown/test_all.py index 4a871c9..e57f8b0 100644 --- a/src/hyddown/test_all.py +++ b/src/hyddown/test_all.py @@ -323,12 +323,12 @@ def test_sim_filling(): hdown.run() -# def test_multicomponent(): -# from hyddown import HydDown +def test_multicomponent(): + from hyddown import HydDown -# input = get_example_input("ng.yml") -# hdown = HydDown(input) -# hdown.run() + input = get_example_input("ng.yml") + hdown = HydDown(input) + hdown.run() def test_sim_stefan_boltzmann(): diff --git a/validation/CO2_tank_BDV.yml b/validation/CO2_tank_BDV.yml index 75cb5ef..6fb7ede 100644 --- a/validation/CO2_tank_BDV.yml +++ b/validation/CO2_tank_BDV.yml @@ -21,12 +21,12 @@ initial: fluid: "CO2" calculation: type: "energybalance" - time_step: 1 - end_time: 4000 + time_step: 10 + end_time: 80000 valve: flow: "discharge" type: "orifice" - diameter : 0.070 + diameter : 0.020 #diameter : 0.013 discharge_coef: 0.975 back_pressure: 101300. From c0b842af64f12b16d5b431090d9de99689b4cdcf Mon Sep 17 00:00:00 2001 From: Anders Andreasen <58475535+andr1976@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:18:51 +0100 Subject: [PATCH 3/5] 1-D heat transfer for two-phase calcs --- src/hyddown/hdclass.py | 127 ++++++++++++++++++++++++++++++++---- validation/CO2_tank_BDV.yml | 24 +++---- 2 files changed, 125 insertions(+), 26 deletions(-) diff --git a/src/hyddown/hdclass.py b/src/hyddown/hdclass.py index 7390c15..6758c69 100644 --- a/src/hyddown/hdclass.py +++ b/src/hyddown/hdclass.py @@ -288,6 +288,7 @@ def initialize(self): self.T_outer_wall = np.zeros(data_len) self.T_outer_wall_wetted = np.zeros(data_len) self.T_bonded_wall = np.zeros(data_len) + self.T_bonded_wall_wetted = np.zeros(data_len) self.Q_outer = np.zeros(data_len) self.Q_inner = np.zeros(data_len) self.Q_outer_wetted = np.zeros(data_len) @@ -482,6 +483,7 @@ def run(self, disable_pbar=True): self.T_inner_wall_wetted[0] = self.T0 self.T_outer_wall_wetted[0] = self.T0 self.T_bonded_wall[0] = self.T0 + self.T_bonded_wall_wetted[0] = self.T0 self.liquid_level[0] = self.liquid_level0 if self.input["valve"]["flow"] == "discharge": self.T_vent[0] = self.T0 @@ -796,8 +798,11 @@ def run(self, disable_pbar=True): mesh = tm.Mesh( z, tm.LinearElement ) # Or `QuadraticElement` to - + mesh_w = tm.Mesh( + z, tm.LinearElement + ) # Or `QuadraticElement` to cpeek = tm.isothermal_model(k, rho, cp) + cpeek_w = tm.isothermal_model(k, rho, cp) if type(T_profile) == type(int()) and T_profile == 0: bc = [ @@ -814,10 +819,36 @@ def run(self, disable_pbar=True): "theta": theta, } t_bonded, T_profile = tm.solve_ht(domain, solver) + + bc_w = [ + {"T": self.T0}, + {"T": self.Tamb}, + ] + domain_w = tm.Domain(mesh_w, [cpeek_w], bc_w) + domain_w.set_T( + (self.Tamb + self.T0) + / 2 + * np.ones(len(mesh_w.nodes)) + ) + solver_w = { + "dt": 100, + "t_end": 10000, + "theta": theta, + } + t_bonded, T_profile = tm.solve_ht(domain, solver) + t_bonded_w, T_profile_w = tm.solve_ht( + domain_w, solver_w + ) else: bc = [ - {"q": self.Q_outer[i] / self.surf_area_outer}, - {"q": -self.Q_inner[i] / self.surf_area_inner}, + { + "q": self.Q_outer[i] + / (self.surf_area_inner - wetted_area) + }, + { + "q": -self.Q_inner[i] + / (self.surf_area_inner - wetted_area) + }, ] domain = tm.Domain(mesh, [cpeek], bc) domain.set_T(T_profile[-1, :]) @@ -827,18 +858,38 @@ def run(self, disable_pbar=True): "theta": theta, } t_bonded, T_profile = tm.solve_ht(domain, solver) + bc_w = [ + {"q": self.Q_outer_wetted[i] / wetted_area}, + {"q": -self.Q_inner_wetted[i] / wetted_area}, + ] + domain_w = tm.Domain(mesh_w, [cpeek_w], bc_w) + domain_w.set_T(T_profile_w[-1, :]) + solver = { + "dt": dt, + "t_end": self.tstep, + "theta": theta, + } + t_bonded_w, T_profile_w = tm.solve_ht( + domain_w, solver_w + ) solver = {"dt": dt, "t_end": self.tstep, "theta": theta} t, T_profile = tm.solve_ht(domain, solver) + solver_w = {"dt": dt, "t_end": self.tstep, "theta": theta} + t_w, T_profile_w = tm.solve_ht(domain_w, solver_w) self.temp_profile.append(T_profile[-1, :]) self.T_outer_wall[i] = T_profile[-1, 0] self.T_inner_wall[i] = T_profile[-1, -1] + self.T_outer_wall_wetted[i] = T_profile_w[-1, 0] + self.T_inner_wall_wetted[i] = T_profile_w[-1, -1] else: k_liner = self.input["vessel"]["liner_thermal_conductivity"] rho_liner = self.input["vessel"]["liner_density"] cp_liner = self.input["vessel"]["liner_heat_capacity"] liner = tm.isothermal_model(k_liner, rho_liner, cp_liner) shell = tm.isothermal_model(k, rho, cp) + liner_w = tm.isothermal_model(k_liner, rho_liner, cp_liner) + shell_w = tm.isothermal_model(k, rho, cp) thk = self.input["vessel"]["thickness"] # thickness in m nn = 11 # number of nodes @@ -849,9 +900,11 @@ def run(self, disable_pbar=True): z2 = np.hstack((z_liner, z_shell[1:])) self.z = z2 mesh2 = tm.Mesh(z2, tm.LinearElement) + mesh2_w = tm.Mesh(z2, tm.LinearElement) for j, elem in enumerate(mesh2.elem): if elem.nodes.mean() > 0.0: mesh2.subdomain[j] = 1 + mesh2_w.subdomain[j] = 1 if type(T_profile2) == type(int()) and T_profile2 == 0: bc = [ @@ -870,10 +923,34 @@ def run(self, disable_pbar=True): "theta": theta, } t_bonded, T_profile2 = tm.solve_ht(domain2, solver2) + bc_w = [ + {"T": self.T0}, + {"T": self.Tamb}, + ] + domain2_w = tm.Domain(mesh2_w, [liner_w, shell_w], bc_w) + domain2_w.set_T( + (self.Tamb + self.T0) + / 2 + * np.ones(len(mesh2.nodes)) + ) + solver2_w = { + "dt": 100, + "t_end": 10000, + "theta": theta, + } + t_bonded_w, T_profile2_w = tm.solve_ht( + domain2_w, solver2_w + ) else: bc = [ - {"q": -self.Q_inner[i] / self.surf_area_inner}, - {"q": self.Q_outer[i] / self.surf_area_outer}, + { + "q": -self.Q_inner[i] + / (self.surf_area_inner - wetted_area) + }, + { + "q": self.Q_outer[i] + / (self.surf_area_outer - wetted_area) + }, ] domain2 = tm.Domain(mesh2, [liner, shell], bc) domain2.set_T(T_profile2[-1, :]) @@ -883,10 +960,26 @@ def run(self, disable_pbar=True): "theta": theta, } t_bonded, T_profile2 = tm.solve_ht(domain2, solver2) - + bc_w = [ + {"q": -self.Q_inner_wetted[i] / (wetted_area)}, + {"q": self.Q_outer_wetted[i] / wetted_area}, + ] + domain2_w = tm.Domain(mesh2_w, [liner_w, shell_w], bc_w) + domain2_w.set_T(T_profile2_w[-1, :]) + solver2_w = { + "dt": dt, + "t_end": self.tstep, + "theta": theta, + } + t_bonded_w, T_profile2_w = tm.solve_ht( + domain2_w, solver2_w + ) self.T_outer_wall[i] = T_profile2[-1, -1] self.T_inner_wall[i] = T_profile2[-1, 0] self.T_bonded_wall[i] = T_profile2[-1, (nn - 1)] + self.T_outer_wall_wetted[i] = T_profile2_w[-1, -1] + self.T_inner_wall_wetted[i] = T_profile2_w[-1, 0] + self.T_bonded_wall_wetted[i] = T_profile2_w[-1, (nn - 1)] self.temp_profile.append(T_profile2[-1, :]) else: self.T_inner_wall[i] = self.T_vessel[i] @@ -1326,14 +1419,20 @@ def plot(self, filename=None, verbose=True): color="darkorange", label="Vessel wall wetted", ) - if "liner_thermal_conductivity" in self.input["vessel"].keys(): - plt.plot( - self.time_array, - self.T_bonded_wall - 273.15, - "g", - label="Liner/composite", - ) - + if "thermal_conductivity" in self.input["vessel"].keys(): + if "liner_thermal_conductivity" in self.input["vessel"].keys(): + plt.plot( + self.time_array, + self.T_bonded_wall - 273.15, + "g", + label="Liner/composite", + ) + plt.plot( + self.time_array, + self.T_bonded_wall_wetted - 273.15, + color="darkorange", + label="Liner/composite wetted", + ) plt.plot( self.time_array, self.T_inner_wall - 273.15, "g--", label="Inner wall" ) diff --git a/validation/CO2_tank_BDV.yml b/validation/CO2_tank_BDV.yml index 6fb7ede..de0b31e 100644 --- a/validation/CO2_tank_BDV.yml +++ b/validation/CO2_tank_BDV.yml @@ -1,17 +1,17 @@ vessel: length: 32.47 diameter: 7.8 - #thickness: 0.200 - #heat_capacity: 1257 - #density: 27.86 - #thermal_conductivity: 0.026 - #liner_thickness: 0.020 - #liner_heat_capacity: 490 - #liner_density: 7800. - #liner_thermal_conductivity: 45 - thickness: 0.020 - heat_capacity: 490 - density: 7800. + thickness: 0.200 + heat_capacity: 1257 + density: 27.86 + thermal_conductivity: 0.026 + liner_thickness: 0.020 + liner_heat_capacity: 490 + liner_density: 7800. + liner_thermal_conductivity: 45 + #thickness: 0.020 + #heat_capacity: 490 + #density: 7800. orientation: "horizontal" liquid_level: 0.0 type: "Hemispherical" @@ -35,6 +35,6 @@ valve: heat_transfer: type: "specified_h" temp_ambient: 303.15 - h_outer: 0 + h_outer: 8 h_inner: "calc" \ No newline at end of file From ccc2618f23d34d2fd00e82541031cf6d1ff3262b Mon Sep 17 00:00:00 2001 From: Anders Andreasen <58475535+andr1976@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:42:13 +0100 Subject: [PATCH 4/5] Two-phase WIP --- src/hyddown/examples/LPG-heat_load.txt | 159 +++++++++++++++++++++++++ src/hyddown/examples/LPG.yml | 8 +- src/hyddown/examples/LPG_small.yml | 27 +++++ src/hyddown/hdclass.py | 23 ++++ src/hyddown/transport.py | 5 +- validation/CO2_tank_BDV.yml | 2 +- 6 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 src/hyddown/examples/LPG-heat_load.txt create mode 100644 src/hyddown/examples/LPG_small.yml diff --git a/src/hyddown/examples/LPG-heat_load.txt b/src/hyddown/examples/LPG-heat_load.txt new file mode 100644 index 0000000..4db824c --- /dev/null +++ b/src/hyddown/examples/LPG-heat_load.txt @@ -0,0 +1,159 @@ + -1.3514 287.72 + 9.5147 3.2643 + 13.592 4.6632 + 17.67 6.0622 + 21.748 7.4612 + 25.825 8.8601 + 29.903 10.259 + 33.981 11.658 + 38.059 13.057 + 42.136 14.456 + 46.214 15.855 + 57.119 1172.3 + 61.275 4055.6 + 64.056 6362 + 65.455 7803.4 + 66.853 9244.8 + 68.252 10686 + 69.65 12128 + 71.048 13569 + 72.447 15010 + 73.845 16452 + 75.244 17893 + 76.642 19335 + 79.439 22217 + 80.837 23659 + 83.634 26542 + 86.431 29424 + 89.228 32307 + 92.025 35190 + 94.821 38073 + 96.228 39802 + 97.626 41244 + 100.42 43838 + 103.21 46721 + 104.61 48163 + 107.41 51045 + 110.2 53928 + 112.99 56523 + 114.41 58541 + 115.81 60270 + 117.23 62288 + 121.38 64883 + 126.88 67479 + 132.37 69498 + 136.53 72381 + 137.91 72958 + 148.8 73538 + 159.68 73830 + 165.12 74120 + 174.65 74700 + 181.46 74990 + 193.7 75283 + 204.59 75863 + 212.75 76154 + 219.55 76444 + 226.36 76735 + 234.52 77026 + 248.13 77607 + 260.38 78187 + 269.9 78479 + 275.35 78769 + 280.79 79059 + 291.68 79639 + 302.57 80219 + 313.46 80799 + 322.99 81379 + 333.88 81959 + 347.49 82828 + 351.58 83118 + 355.67 83407 + 359.75 83697 + 373.37 84566 + 386.98 85435 + 400.6 86305 + 412.86 87173 + 418.28 86887 + 431.85 86027 + 445.42 85167 + 450.85 84881 + 460.35 84308 + 465.78 84021 + 476.64 83449 + 484.78 82875 + 494.28 82302 + 499.71 82016 + 509.2 81443 + 521.42 80871 + 526.87 81161 + 536.4 81740 + 548.65 82321 + 558.17 82612 + 567.69 82904 + 579.93 83196 + 586.74 83487 + 597.6 83202 + 608.46 82629 + 617.96 82056 + 623.39 81770 + 635.61 81198 + 641.03 80912 + 654.61 80340 + 668.18 79480 + 681.75 78620 + 685.82 78333 + 699.4 78050 + 700.72 76321 + 702 73440 + 701.97 72575 + 701.95 71711 + 701.93 71134 + 701.91 70270 + 701.89 69405 + 703.17 66524 + 703.14 65371 + 703.11 64506 + 703.09 63642 + 703.07 62777 + 703.03 61624 + 704.32 58743 + 704.29 57879 + 705.57 54997 + 705.55 54133 + 706.84 51539 + 708.12 48658 + 709.4 45777 + 709.38 45200 + 709.36 44336 + 710.64 41454 + 710.63 40878 + 711.91 37996 + 711.88 36844 + 711.87 36555 + 711.84 35403 + 711.82 34826 + 711.8 33962 + 711.77 33097 + 711.74 31944 + 713.02 29063 + 713.01 28487 + 712.98 27622 + 712.96 26758 + 714.24 23876 + 715.52 20995 + 715.5 20130 + 715.48 19554 + 716.76 16672 + 718.04 13791 + 717.97 10909 + 717.96 10621 + 717.94 10045 + 717.93 9468.2 + 717.91 8891.8 + 717.89 8027.3 + 717.86 7162.7 + 719.15 4281.3 + 719.14 3993.1 + 720.42 1111.7 + 720.41 823.53 + 720.4 535.34 diff --git a/src/hyddown/examples/LPG.yml b/src/hyddown/examples/LPG.yml index 76d594f..be1ba90 100644 --- a/src/hyddown/examples/LPG.yml +++ b/src/hyddown/examples/LPG.yml @@ -5,19 +5,19 @@ vessel: heat_capacity: 500 density: 7700 thickness: 0.01185 - liquid_level: 1.15 #0.4668 + liquid_level: 0.4668 #1.15 initial: - temperature: 298.15 + temperature: 279 pressure: 550000 fluid: "propane" calculation: type: "energybalance" time_step: 1 - end_time: 900. + end_time: 660. valve: flow: "discharge" type: "psv" - diameter: 0.05 + diameter: 0.040 discharge_coef: 0.975 set_pressure: 1430000 blowdown: 0.20 diff --git a/src/hyddown/examples/LPG_small.yml b/src/hyddown/examples/LPG_small.yml new file mode 100644 index 0000000..063924c --- /dev/null +++ b/src/hyddown/examples/LPG_small.yml @@ -0,0 +1,27 @@ +vessel: + length: 2.26 + diameter: 0.51 + orientation: "horizontal" + heat_capacity: 500 + density: 7700 + thickness: 0.008 + liquid_level: 0.2 #0.4668 #1.15 +initial: + temperature: 279 + pressure: 550000 + fluid: "propane" +calculation: + type: "energybalance" + time_step: 1 + end_time: 360. +valve: + flow: "discharge" + type: "psv" + diameter: 0.014 + discharge_coef: 0.975 + set_pressure: 1690000 + blowdown: 0.10 + back_pressure: 101300. +heat_transfer: + type: "s-b" + fire: "scandpower_pool" \ No newline at end of file diff --git a/src/hyddown/hdclass.py b/src/hyddown/hdclass.py index 6758c69..048f800 100644 --- a/src/hyddown/hdclass.py +++ b/src/hyddown/hdclass.py @@ -35,6 +35,12 @@ def __init__(self, input): self.validate_input() self.read_input() self.initialize() + # sb_heat_load = np.loadtxt( + # "C:\\Users\\AndersAndreasen\\Documents\\GitHub\\HydDown\\src\\hyddown\\examples\\LPG-heat_load.txt" + # ) + # self.sb_heat_load = lambda x: np.interp( + # x, sb_heat_load[:, 0], sb_heat_load[:, 1] + # ) def validate_input(self): """ @@ -1036,14 +1042,27 @@ def run(self, disable_pbar=True): self.Q_outer[i] = ( fire.sb_fire(self.T_vessel[i - 1], self.fire_type) + # ( + # self.sb_heat_load(self.time_array[i]) + # - 0.85 * 5.67e-8 * self.T_vessel[i - 1] ** 4 + # ) * (self.surf_area_inner - wetted_area) * self.surf_area_outer / self.surf_area_inner ) + self.q_outer[i] = fire.sb_fire(self.T_vessel[i - 1], self.fire_type) + # ( + # self.sb_heat_load(self.time_array[i]) + # - 0.85 * 5.67e-8 * self.T_vessel[i - 1] ** 4 + # ) self.Q_outer_wetted[i] = ( fire.sb_fire(self.T_vessel_wetted[i - 1], self.fire_type) + # ( + # self.sb_heat_load(self.time_array[i]) + # - 0.85 * 5.67e-8 * self.T_vessel_wetted[i - 1] ** 4 + # ) * wetted_area * self.surf_area_outer / self.surf_area_inner @@ -1051,6 +1070,10 @@ def run(self, disable_pbar=True): self.q_outer_wetted[i] = fire.sb_fire( self.T_vessel_wetted[i - 1], self.fire_type ) + # ( + # self.sb_heat_load(self.time_array[i]) + # - 0.85 * 5.67e-8 * self.T_vessel_wetted[i - 1] ** 4 + # ) if np.isnan(self.Q_outer_wetted[i]): self.Q_outer_wetted[i] = 0 diff --git a/src/hyddown/transport.py b/src/hyddown/transport.py index 25f9b9f..989df54 100644 --- a/src/hyddown/transport.py +++ b/src/hyddown/transport.py @@ -348,8 +348,9 @@ def h_inside_wetted(L, Tvessel, Tfluid, fluid, master_fluid): h_boil = 0 h_conv = h_inside_liquid(L, Tvessel, Tfluid, fluid) - return max(h_boil, h_conv) - # return min(max(h_boil, h_conv, 1000), 3000) + # return min(h_boil, h_conv) + # return h_conv + return min(max(h_boil, h_conv), 3000) def gas_release_rate(P1, P2, rho, k, CD, area): diff --git a/validation/CO2_tank_BDV.yml b/validation/CO2_tank_BDV.yml index de0b31e..947c33b 100644 --- a/validation/CO2_tank_BDV.yml +++ b/validation/CO2_tank_BDV.yml @@ -22,7 +22,7 @@ initial: calculation: type: "energybalance" time_step: 10 - end_time: 80000 + end_time: 40000 valve: flow: "discharge" type: "orifice" From 21af7aa87ec2d8d69955633b6321318eabad414d Mon Sep 17 00:00:00 2001 From: Anders Andreasen <58475535+andr1976@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:49:27 +0100 Subject: [PATCH 5/5] Fix test --- {src/hyddown/examples => validation}/LPG-heat_load.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src/hyddown/examples => validation}/LPG-heat_load.txt (100%) diff --git a/src/hyddown/examples/LPG-heat_load.txt b/validation/LPG-heat_load.txt similarity index 100% rename from src/hyddown/examples/LPG-heat_load.txt rename to validation/LPG-heat_load.txt