diff --git a/include/components/CoaxialJunction1Phase.h b/include/components/CoaxialJunction1Phase.h new file mode 100644 index 0000000..8c8e8be --- /dev/null +++ b/include/components/CoaxialJunction1Phase.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Component.h" +#include "InputParameters.h" + +class CoaxialJunction1Phase : public Component { +public: + static InputParameters validParams(); + + CoaxialJunction1Phase(const InputParameters ¶ms); + +protected: + /// Connects the same solid region of two coaxial pipes + void ConnectSolidRegion(const std::string ®ion_name, + const ComponentName &component1, + const ComponentName &component2); + + /// Connects the same flow region of two coaxial pipes + void ConnectFlowRegion(const std::string ®ion_name, + const ComponentName &component1, + const ComponentName &component2); +}; \ No newline at end of file diff --git a/include/components/CoaxialPipe1Phase.h b/include/components/CoaxialPipe1Phase.h index 97785b8..4ceb4b2 100644 --- a/include/components/CoaxialPipe1Phase.h +++ b/include/components/CoaxialPipe1Phase.h @@ -1,4 +1,6 @@ -#include +#pragma once + +#include #include #include diff --git a/src/components/CoaxialJunction1Phase.C b/src/components/CoaxialJunction1Phase.C new file mode 100644 index 0000000..8a02f1a --- /dev/null +++ b/src/components/CoaxialJunction1Phase.C @@ -0,0 +1,131 @@ +#include "CoaxialJunction1Phase.h" +#include "Component.h" +#include "InputParameters.h" +#include "MooseTypes.h" +#include "Registry.h" + +registerMooseObject("ProteusApp", CoaxialJunction1Phase); + +namespace { +// Splits component name into component and boundary pair and checks validity +inline std::pair +getComponentAndBoundary(const ComponentName &component) { + auto it = component.rfind(":"); + if (it == component.size()) + mooseError("No boundary specified. 'coaxial_connections' must be specified " + "as :."); + + auto comp = component.substr(0, it); + auto boundary = component.substr(it + 1); + + if (!(boundary == "in" || boundary == "out")) + mooseError("Boundary must be 'in' or 'out', not '", boundary, "'."); + + return {comp, boundary}; +} +} // namespace + +InputParameters CoaxialJunction1Phase::validParams() { + auto params = Component::validParams(); + params.addRequiredParam>( + "coaxial_connections", "Coaxial pipes boundaries to connect. " + ":in indicates start of the pipe, " + ":out indicates the end of the pipe."); + + // Passed to 2D coupler + params.addRequiredParam("tube_htc", + "HTC used for coupling tube regions."); + params.addRequiredParam("shell_htc", + "HTC used for coupling shell regions."); + + // Allows other componenets such as pumps to be inserted instead + params.addParam("connect_inner", true, + "Whether to connect inner pipe."); + params.addParam("connect_outer", true, + "Whether to connect the outer annulus."); + + params.addParam("connect_tube", true, + "Whether to connect the solid tube regions."); + params.addParam("connect_shell", true, + "Whether to connect the solid shell regions."); + + return params; +} + +CoaxialJunction1Phase::CoaxialJunction1Phase(const InputParameters ¶ms) + : Component(params) { + + auto coaxials = params.get>("coaxial_connections"); + + if (coaxials.size() != 2) + mooseError("'coaxial_connections' must have size 2."); + + if (getParam("connect_tube")) { + ConnectSolidRegion("tube", coaxials[0], coaxials[1]); + } + + if (getParam("connect_shell")) { + ConnectSolidRegion("shell", coaxials[0], coaxials[1]); + } + + if (params.get("connect_inner")) { + ConnectFlowRegion("inner", coaxials[0], coaxials[1]); + } + if (params.get("connect_outer")) { + ConnectFlowRegion("outer", coaxials[0], coaxials[1]); + } +} + +void CoaxialJunction1Phase::ConnectSolidRegion( + const std::string ®ion_name, const ComponentName &component1, + const ComponentName &component2) { + auto comp_boundary1 = getComponentAndBoundary(component1); + auto comp_boundary2 = getComponentAndBoundary(component2); + + const std::string class_name = "HeatStructure2DCoupler"; + auto params = _factory.getValidParams(class_name); + params.set("_thm_problem") = &getTHMProblem(); + + // The ends of the solid regions are called start and end rather than in and + // out + auto boundary1 = (comp_boundary1.second == "in") ? "start" : "end"; + auto boundary2 = (comp_boundary2.second == "in") ? "start" : "end"; + + params.set("primary_heat_structure") = + comp_boundary1.first + "/" + region_name; + params.set("primary_boundary") = + comp_boundary1.first + "/" + region_name + ":" + boundary1; + + params.set("secondary_heat_structure") = + comp_boundary2.first + "/" + region_name; + params.set("secondary_boundary") = + comp_boundary2.first + "/" + region_name + ":" + boundary2; + + params.set("heat_transfer_coefficient") = + parameters().get(region_name + "_htc"); + + getTHMProblem().addComponent(class_name, + name() + "/" + region_name + "_coupler", params); +} + +void CoaxialJunction1Phase::ConnectFlowRegion(const std::string ®ion_name, + const ComponentName &component1, + const ComponentName &component2) { + auto comp_boundary1 = getComponentAndBoundary(component1); + auto comp_boundary2 = getComponentAndBoundary(component2); + + // In the future, we could create a component to account for form + // loss due to geometry changes + const std::string class_name = "JunctionOneToOne1Phase"; + auto params = _factory.getValidParams(class_name); + params.set("_thm_problem") = &getTHMProblem(); + + std::vector connections = { + comp_boundary1.first + "/" + region_name + ":" + comp_boundary1.second, + comp_boundary2.first + "/" + region_name + ":" + comp_boundary2.second, + }; + params.set>("connections") = connections; + + getTHMProblem().addComponent( + class_name, name() + "/" + region_name + "_junction", params); +} diff --git a/src/components/CoaxialPipe1Phase.C b/src/components/CoaxialPipe1Phase.C index bf22a5b..0afc3fe 100644 --- a/src/components/CoaxialPipe1Phase.C +++ b/src/components/CoaxialPipe1Phase.C @@ -130,8 +130,10 @@ InputParameters CoaxialPipe1Phase::validParams() { params.addParam("initial_p", "Global pressure initialisation"); params.addParam("initial_vel", "Global velocity initialisation"); - params.addParamNamesToGroup("fp closures initial_T initial_p initial_vel", - "global"); + params.addParam( + "gravity_vector", RealVectorValue{0, 0, -9.81}, "Gravity vector"); + params.addParamNamesToGroup( + "fp closures initial_T initial_p initial_vel gravity_vector", "global"); return params; } @@ -175,6 +177,10 @@ void CoaxialPipe1Phase::AddInnerPipe(const InputParameters ¶ms) { params.get("orientation"); pipe_params.set>("length") = params.get>("length"); + pipe_params.set>("axial_region_names") = + params.get>("axial_region_names"); + pipe_params.set("gravity_vector") = + params.get("gravity_vector"); Real radius = params.get("tube_inner_radius"); @@ -214,6 +220,10 @@ void CoaxialPipe1Phase::AddOuterAnnulus(const InputParameters ¶ms) { params.get("orientation"); pipe_params.set>("length") = params.get>("length"); + pipe_params.set>("axial_region_names") = + params.get>("axial_region_names"); + pipe_params.set("gravity_vector") = + params.get("gravity_vector"); Real tube_radius = params.get("tube_inner_radius"); auto tube_widths = params.get>("tube_widths"); @@ -264,6 +274,8 @@ void CoaxialPipe1Phase::AddSolidTube(const InputParameters ¶ms) { params.get("orientation"); tube_params.set>("length") = params.get>("length"); + tube_params.set>("axial_region_names") = + params.get>("axial_region_names"); copyParamFromParamWithGlobal("initial_T", "tube_initial_T", "initial_T", tube_params, params); @@ -297,6 +309,8 @@ void CoaxialPipe1Phase::AddSolidShell(const InputParameters ¶ms) { params.get("orientation"); tube_params.set>("length") = params.get>("length"); + tube_params.set>("axial_region_names") = + params.get>("axial_region_names"); copyParamFromParamWithGlobal("initial_T", "shell_initial_T", "initial_T", tube_params, params); diff --git a/test/tests/components/coaxial_junction/junction_fluid.i b/test/tests/components/coaxial_junction/junction_fluid.i new file mode 100644 index 0000000..13a7154 --- /dev/null +++ b/test/tests/components/coaxial_junction/junction_fluid.i @@ -0,0 +1,210 @@ +# Energy balance test +# =================== +# +# Apply 10 kW/m^2 to outer surface of the +# shell and check the increase in temperature at the fluid outlets + +T = 300 +press = 1e5 # operating pressure + +L = 1 # length of pipe + +[GlobalParams] + initial_p = ${press} + closures = thm_closures + fp=fluid + gravity_vector = '0 0 0' +[] + +[FluidProperties] + [fluid] # mimic of water + type = SimpleFluidProperties + cv = 4000 + [] + [fluid2] # mimic of water + type = SimpleFluidProperties + cv = 2000 + [] +[] + +[SolidProperties] + [adamantium] # fake solid material that ensures solid heats quickly + type = ThermalFunctionSolidProperties + cp = 1 + k = 1 + rho = 1 + [] + [ebony] # fake solid material that ensures solid heats quickly + type = ThermalFunctionSolidProperties + cp = 1 + k = 4 + rho = 16 + [] +[] + +[Closures] # defines friction factors and heat transfer coefficients + [thm_closures] + type = Closures1PhaseTHM # default Churchill friction factor, DB HTC + [] +[] + +[Components] + [inlet_inner] + type = InletMassFlowRateTemperature1Phase + T = ${T} + m_dot = 1. + input = coaxial1/inner:in + [] + [inlet_outer] + type = InletMassFlowRateTemperature1Phase + T = ${T} + m_dot = 1. + input = coaxial2/outer:out + [] + [coaxial1] + type = CoaxialPipe1Phase + length = '${L}' + n_elems = '10' + orientation = '1 0 0' + position = '${fparse -L} 0 0' + shell_inner_radius = 0.075 + shell_materials = 'adamantium' + shell_n_elems = '1' + shell_names = 'shell' + shell_widths = '0.025' + shell_T_ref = '${T}' + tube_T_ref = ${T} + tube_inner_radius = 0.025 + tube_materials = 'adamantium' + tube_n_elems = '1' + tube_names = 'tube' + tube_widths = '0.025' + inner_initial_vel = 0. + outer_initial_vel = 0. + initial_T = ${T} + inner_tube_Hw = 0. + outer_tube_Hw = 0. + outer_shell_Hw = 0. + [] + [jct] + type = CoaxialJunction1Phase + coaxial_connections = 'coaxial1:out coaxial2:in' + shell_htc = 1e10 + tube_htc = 1e10 + [] + [coaxial2] + type = CoaxialPipe1Phase + length = '${L}' + n_elems = '10' + orientation = '1 0 0' + position = '0 0 0' + shell_inner_radius = 0.075 + shell_materials = 'ebony' + shell_n_elems = '1' + shell_names = 'shell' + shell_widths = '0.025' + shell_T_ref = '${T}' + tube_T_ref = ${T} + tube_inner_radius = 0.025 + tube_materials = 'ebony' + tube_n_elems = '1' + tube_names = 'tube' + tube_widths = '0.025' + inner_initial_vel = 0. + outer_initial_vel = 0. + initial_T = ${T} + inner_tube_Hw = 0. + outer_tube_Hw = 0. + outer_shell_Hw = 0. + [] + [outlet_outer] + type =Outlet1Phase + input = coaxial1/outer:in + p = ${press} + [] + [outlet_inner] + type =Outlet1Phase + input = coaxial2/inner:out + p = ${press} + [] + [tube_start1] + type = HSBoundarySpecifiedTemperature + T = ${T} + boundary = 'coaxial1/tube:start' + hs = coaxial1/tube + [] + [shell_start1] + type = HSBoundarySpecifiedTemperature + T = ${T} + boundary = 'coaxial1/shell:start' + hs = coaxial1/tube + [] + [tube_end2] + type = HSBoundarySpecifiedTemperature + T = ${T} + boundary = 'coaxial2/tube:end' + hs = coaxial1/tube + [] + [shell_end2] + type = HSBoundarySpecifiedTemperature + T = ${T} + boundary = 'coaxial2/shell:end' + hs = coaxial2/tube + [] + +[] + + +[Postprocessors] + [mdot_inner] + type = ADFlowBoundaryFlux1Phase + boundary = outlet_inner + equation = mass + [] + [mdot_outer] + type = ADFlowBoundaryFlux1Phase + boundary = outlet_outer + equation = mass + [] + +[] + +[Preconditioning] + [pc] + type = SMP + full = true + [] +[] + +[Executioner] + type = Transient + start_time = 0 + + dt = 1. + end_time = 10 + + line_search = basic + solve_type = NEWTON + + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + + nl_rel_tol = 1e-4 + nl_abs_tol = 1e-6 + nl_max_its = 25 + automatic_scaling = true + steady_state_detection = true + # steady_state_tolerance = 2e-7 +[] + +[Outputs] + exodus = true + csv = true + [console] + type = Console + max_rows = 1 + execute_postprocessors_on = final + outlier_variable_norms = false + [] + print_linear_residuals = false +[] diff --git a/test/tests/components/coaxial_junction/junction_solid.i b/test/tests/components/coaxial_junction/junction_solid.i new file mode 100644 index 0000000..6bc34f0 --- /dev/null +++ b/test/tests/components/coaxial_junction/junction_solid.i @@ -0,0 +1,222 @@ +# Energy balance test +# =================== +# +# Apply 10 kW/m^2 to outer surface of the +# shell and check the increase in temperature at the fluid outlets + +T_1 = 301 +T_2 = 300 +press = 1e5 # operating pressure + +L = 1 # length of pipe + +[GlobalParams] + initial_p = ${press} + closures = thm_closures + fp=fluid + gravity_vector = '0 0 0' +[] + +[FluidProperties] + [fluid] # mimic of water + type = SimpleFluidProperties + cv = 4000 + [] + [fluid2] # mimic of water + type = SimpleFluidProperties + cv = 2000 + [] +[] + +[SolidProperties] + [adamantium] # fake solid material that ensures solid heats quickly + type = ThermalFunctionSolidProperties + cp = 1 + k = 1 + rho = 1 + [] + [ebony] # fake solid material that ensures solid heats quickly + type = ThermalFunctionSolidProperties + cp = 1 + k = 4 + rho = 16 + [] +[] + +[Closures] # defines friction factors and heat transfer coefficients + [thm_closures] + type = Closures1PhaseTHM # default Churchill friction factor, DB HTC + [] +[] + +[Components] + [inlet_inner] + type = InletMassFlowRateTemperature1Phase + T = ${fparse 0.5*(T_1 + T_2)} + m_dot = 0. + input = coaxial1/inner:in + [] + [inlet_outer] + type = InletMassFlowRateTemperature1Phase + T = ${fparse 0.5*(T_1 + T_2)} + m_dot = 0. + input = coaxial2/outer:out + [] + [coaxial1] + type = CoaxialPipe1Phase + length = '${fparse L/3} ${fparse L/3} ${fparse L/3}' + axial_region_names = 'part1 part2 part3' + n_elems = '8 16 32' + orientation = '1 0 0' + position = '${fparse -L} 0 0' + shell_inner_radius = 0.075 + shell_materials = 'adamantium' + shell_n_elems = '1' + shell_names = 'shell' + shell_widths = '0.025' + shell_T_ref = '${T_1}' + tube_T_ref = ${T_1} + tube_inner_radius = 0.025 + tube_materials = 'adamantium' + tube_n_elems = '1' + tube_names = 'tube' + tube_widths = '0.025' + inner_initial_vel = 0. + outer_initial_vel = 0. + initial_T = ${T_1} + inner_tube_Hw = 0. + outer_tube_Hw = 0. + outer_shell_Hw = 0. + [] + [jct] + type = CoaxialJunction1Phase + coaxial_connections = 'coaxial1:out coaxial2:in' + shell_htc = 1e10 + tube_htc = 1e10 + [] + [coaxial2] + type = CoaxialPipe1Phase + length = '${fparse L/3} ${fparse L/3} ${fparse L/3}' + axial_region_names = 'part1 part2 part3' + n_elems = '32 16 8' + orientation = '1 0 0' + position = '0 0 0' + shell_inner_radius = 0.075 + shell_materials = 'ebony' + shell_n_elems = '1' + shell_names = 'shell' + shell_widths = '0.025' + shell_T_ref = '${T_2}' + tube_T_ref = ${T_2} + tube_inner_radius = 0.025 + tube_materials = 'ebony' + tube_n_elems = '1' + tube_names = 'tube' + tube_widths = '0.025' + inner_initial_vel = 0. + outer_initial_vel = 0. + initial_T = ${T_2} + inner_tube_Hw = 0. + outer_tube_Hw = 0. + outer_shell_Hw = 0. + [] + [outlet_outer] + type =Outlet1Phase + input = coaxial1/outer:in + p = ${press} + [] + [outlet_inner] + type =Outlet1Phase + input = coaxial2/inner:out + p = ${press} + [] + [tube_start1] + type = HSBoundarySpecifiedTemperature + T = ${T_1} + boundary = 'coaxial1/tube:start' + hs = coaxial1/tube + [] + [shell_start1] + type = HSBoundarySpecifiedTemperature + T = ${T_1} + boundary = 'coaxial1/shell:start' + hs = coaxial1/tube + [] + [tube_end2] + type = HSBoundarySpecifiedTemperature + T = ${T_2} + boundary = 'coaxial2/tube:end' + hs = coaxial1/tube + [] + [shell_end2] + type = HSBoundarySpecifiedTemperature + T = ${T_2} + boundary = 'coaxial2/shell:end' + hs = coaxial2/tube + [] + +[] + + +[Postprocessors] + [T_shell_out1] + type = SideAverageValue + boundary = coaxial1/shell:end + variable = T_solid + [] + [T_shell_in2] + type = SideAverageValue + boundary = coaxial2/shell:start + variable = T_solid + [] + [T_tube_out1] + type = SideAverageValue + boundary = coaxial1/tube:end + variable = T_solid + [] + [T_tube_in2] + type = SideAverageValue + boundary = coaxial2/tube:start + variable = T_solid + [] +[] + +[Preconditioning] + [pc] + type = SMP + full = true + [] +[] + +[Executioner] + type = Transient + start_time = 0 + + dt = 0.0001 + end_time = 0.01 + + line_search = basic + solve_type = NEWTON + + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + + nl_rel_tol = 1e-4 + nl_abs_tol = 1e-6 + nl_max_its = 25 + automatic_scaling = true + steady_state_detection = true + # steady_state_tolerance = 2e-7 +[] + +[Outputs] + exodus = true + csv = true + [console] + type = Console + max_rows = 1 + execute_postprocessors_on = final + outlier_variable_norms = false + [] + print_linear_residuals = false +[] diff --git a/test/tests/components/coaxial_junction/junction_solid_expand.i b/test/tests/components/coaxial_junction/junction_solid_expand.i new file mode 100644 index 0000000..9b4aee7 --- /dev/null +++ b/test/tests/components/coaxial_junction/junction_solid_expand.i @@ -0,0 +1,222 @@ +# Energy balance test +# =================== +# +# Apply 10 kW/m^2 to outer surface of the +# shell and check the increase in temperature at the fluid outlets + +T_1 = 301 +T_2 = 300 +press = 1e5 # operating pressure + +L = 1 # length of pipe + +[GlobalParams] + initial_p = ${press} + closures = thm_closures + fp=fluid + gravity_vector = '0 0 0' +[] + +[FluidProperties] + [fluid] # mimic of water + type = SimpleFluidProperties + cv = 4000 + [] + [fluid2] # mimic of water + type = SimpleFluidProperties + cv = 2000 + [] +[] + +[SolidProperties] + [adamantium] # fake solid material that ensures solid heats quickly + type = ThermalFunctionSolidProperties + cp = 1 + k = 1 + rho = 1 + [] + [ebony] # fake solid material that ensures solid heats quickly + type = ThermalFunctionSolidProperties + cp = 1 + k = 4 + rho = 16 + [] +[] + +[Closures] # defines friction factors and heat transfer coefficients + [thm_closures] + type = Closures1PhaseTHM # default Churchill friction factor, DB HTC + [] +[] + +[Components] + [inlet_inner] + type = InletMassFlowRateTemperature1Phase + T = ${fparse 0.5*(T_1 + T_2)} + m_dot = 0. + input = coaxial1/inner:in + [] + [inlet_outer] + type = InletMassFlowRateTemperature1Phase + T = ${fparse 0.5*(T_1 + T_2)} + m_dot = 0. + input = coaxial2/outer:out + [] + [coaxial1] + type = CoaxialPipe1Phase + length = '${fparse L/3} ${fparse L/3} ${fparse L/3}' + axial_region_names = 'part1 part2 part3' + n_elems = '8 16 32' + orientation = '1 0 0' + position = '${fparse -L} 0 0' + shell_inner_radius = 0.075 + shell_materials = 'adamantium' + shell_n_elems = '2' + shell_names = 'shell' + shell_widths = '0.025' + shell_T_ref = '${T_1}' + tube_T_ref = ${T_1} + tube_inner_radius = 0.025 + tube_materials = 'adamantium' + tube_n_elems = '1' + tube_names = 'tube' + tube_widths = '0.025' + inner_initial_vel = 0. + outer_initial_vel = 0. + initial_T = ${T_1} + inner_tube_Hw = 0. + outer_tube_Hw = 0. + outer_shell_Hw = 0. + [] + [jct] + type = CoaxialJunction1Phase + coaxial_connections = 'coaxial1:out coaxial2:in' + shell_htc = 1e10 + tube_htc = 1e10 + [] + [coaxial2] + type = CoaxialPipe1Phase + length = '${fparse L/3} ${fparse L/3} ${fparse L/3}' + axial_region_names = 'part1 part2 part3' + n_elems = '32 16 8' + orientation = '1 0 0' + position = '0 0 0' + shell_inner_radius = 0.08 + shell_materials = 'ebony' + shell_n_elems = '2' + shell_names = 'shell' + shell_widths = '0.025' + shell_T_ref = '${T_2}' + tube_T_ref = ${T_2} + tube_inner_radius = 0.025 + tube_materials = 'ebony' + tube_n_elems = '1' + tube_names = 'tube' + tube_widths = '0.025' + inner_initial_vel = 0. + outer_initial_vel = 0. + initial_T = ${T_2} + inner_tube_Hw = 0. + outer_tube_Hw = 0. + outer_shell_Hw = 0. + [] + [outlet_outer] + type =Outlet1Phase + input = coaxial1/outer:in + p = ${press} + [] + [outlet_inner] + type =Outlet1Phase + input = coaxial2/inner:out + p = ${press} + [] + [tube_start1] + type = HSBoundarySpecifiedTemperature + T = ${T_1} + boundary = 'coaxial1/tube:start' + hs = coaxial1/tube + [] + [shell_start1] + type = HSBoundarySpecifiedTemperature + T = ${T_1} + boundary = 'coaxial1/shell:start' + hs = coaxial1/tube + [] + [tube_end2] + type = HSBoundarySpecifiedTemperature + T = ${T_2} + boundary = 'coaxial2/tube:end' + hs = coaxial1/tube + [] + [shell_end2] + type = HSBoundarySpecifiedTemperature + T = ${T_2} + boundary = 'coaxial2/shell:end' + hs = coaxial2/tube + [] + +[] + + +[Postprocessors] + [T_shell_out1] + type = SideAverageValue + boundary = coaxial1/shell:end + variable = T_solid + [] + [T_shell_in2] + type = SideAverageValue + boundary = coaxial2/shell:start + variable = T_solid + [] + [T_tube_out1] + type = SideAverageValue + boundary = coaxial1/tube:end + variable = T_solid + [] + [T_tube_in2] + type = SideAverageValue + boundary = coaxial2/tube:start + variable = T_solid + [] +[] + +[Preconditioning] + [pc] + type = SMP + full = true + [] +[] + +[Executioner] + type = Transient + start_time = 0 + + dt = 0.0001 + end_time = 0.01 + + line_search = basic + solve_type = NEWTON + + petsc_options_iname = '-pc_type' + petsc_options_value = 'lu' + + nl_rel_tol = 1e-4 + nl_abs_tol = 1e-6 + nl_max_its = 25 + automatic_scaling = true + steady_state_detection = true + # steady_state_tolerance = 2e-7 +[] + +[Outputs] + exodus = true + csv = true + [console] + type = Console + max_rows = 1 + execute_postprocessors_on = final + outlier_variable_norms = false + [] + print_linear_residuals = false +[] diff --git a/test/tests/components/coaxial_junction/test.py b/test/tests/components/coaxial_junction/test.py new file mode 100644 index 0000000..5281641 --- /dev/null +++ b/test/tests/components/coaxial_junction/test.py @@ -0,0 +1,65 @@ +"""Python test module for coaxial junction.""" + +import unittest +import numpy as np + +def heat_flux(time: float, + temp_cold: float, + temp_hot: float, + k1: float, + k2: float, + rho_cp1: float, + rho_cp2: float) -> np.ndarray: + """Computes boundary heat flux at junction.""" + + numerator = (temp_hot - temp_cold) * np.sqrt(k2 * rho_cp2) + denominator = np.sqrt(k1 * rho_cp1) + np.sqrt(k2 * rho_cp2) + arg = 1 / (2 * np.sqrt(k1 / rho_cp1 * time)) + return k1*(numerator / denominator) * 2*arg/np.sqrt(np.pi) + + + +class TestCoaxialJunction(unittest.TestCase): + """Test class for the coaxial junction component.""" + def test_solid_continuity(self): + """Checks the solid temperature is similar on both sides on the solid coupler.""" + + time, t_shell_in2, t_shell_out1, t_tube_in2, t_tube_out1 = np.loadtxt( + "junction_solid_out.csv", + skiprows=2, + delimiter=',', + unpack=True + ) + + # The 2D coupling uses a HTC approach. Here we set it very high: 1e10. + # This means that we should expect a small but finite difference between each + # side of the coupler + # The minimum difference should be delta_t = qw/HTC + # qw can be calculated from the analytical solution + qw = heat_flux(time, 300, 301, 1, 4, 1, 16) + eps = 5e-9 # account numerical errors, set small but arbitrary + expected_err = qw/1e10 + eps + + diff = abs(t_shell_out1 - t_shell_in2) + + idx = np.argmax(diff-expected_err) + assert all(diff < expected_err), \ + f"shell temperature difference ({time[idx]}) " \ + f"greater than {expected_err[idx]}: {diff[idx]}" + + diff = abs(t_tube_out1 - t_tube_in2) + + idx = np.argmax(diff-expected_err) + assert all(diff < expected_err), \ + f"tube temperature difference ({time[idx]}) " \ + f"greater than {expected_err[idx]}: {diff[idx]}" + + def test_fluid_mdot(self): + """Checks the outlet mass flow rate of second coaxial pipe matches inlet.""" + _, mdot_inner, mdot_outer = np.loadtxt("junction_solid_out.csv", + skiprows=1, + delimiter=',', + unpack=True)[:,-1] + + assert abs(mdot_inner -1) < 1e-4, "Inner mass flow rate incorrect." + assert abs(mdot_outer -1) < 1e-4, "Outer mass flow rate incorrect." diff --git a/test/tests/components/coaxial_junction/tests b/test/tests/components/coaxial_junction/tests new file mode 100644 index 0000000..365efdd --- /dev/null +++ b/test/tests/components/coaxial_junction/tests @@ -0,0 +1,55 @@ +[coaxial_junction] + [test_solid_connection] + [run] + type = RunApp + input = junction_solid.i + [] + [verify] + type = PythonUnitTest + input = test.py + test_case = TestCoaxialJunction.test_solid_continuity + prereq = test_solid_connection/run + [] + [run_expansion] + type = RunApp + input = junction_solid_expand.i + requirement = "This system shall allow the coaxial junction to have small changes in geometry" + [] + [check_insufficient_connections] + type = RunException + input = junction_solid.i + cli_args = "Components/jct/coaxial_connections='coaxial1:out'" + expect_err = 'must have size 2' + [] + [check_boundary] + type = RunException + input = junction_solid.i + cli_args = "Components/jct/coaxial_connections='coaxial1:out coaxial2:in1'" + expect_err = 'Boundary must be' + [] + [check_no_inner] + type = RunException + input = junction_solid.i + cli_args = "Components/jct/connect_inner=false" + expect_err = "inner' does not have connected inlet." + [] + [check_no_outer] + type = RunException + input = junction_solid.i + cli_args = "Components/jct/connect_outer=false" + expect_err = "outer' does not have connected inlet." + [] + [] + [test_fluid_connection] + [run] + type = RunApp + input = junction_fluid.i + [] + [verify] + type = PythonUnitTest + input = test.py + test_case = TestCoaxialJunction.test_solid_continuity + prereq = test_fluid_connection/run + [] + [] +[] \ No newline at end of file