diff --git a/.impact/project.json b/.impact/project.json new file mode 100644 index 00000000..779c9bb8 --- /dev/null +++ b/.impact/project.json @@ -0,0 +1,57 @@ +{ + "name": "ThermofluidStream", + "format": "1.0.0", + "dependencies": [ + { + "name": "Modelica", + "versionSpecifier": "4.0.0" + } + ], + "content": [ + { + "relpath": "ThermofluidStream", + "contentType": "MODELICA", + "name": "ThermofluidStream", + "defaultDisabled": false, + "id": "e74f4457bc544294b6e50858706270d6" + }, + { + "relpath": "TILMediaWrapper", + "contentType": "MODELICA", + "name": "TILMediaWrapper", + "defaultDisabled": false, + "id": "a79a8cc6a9174ffdb2dd3823e48003ac" + }, + { + "relpath": "Resources/Views", + "contentType": "VIEWS", + "defaultDisabled": false, + "id": "aac16222f99f466c964a95374ce14877" + }, + { + "relpath": "Resources/Favorites", + "contentType": "FAVORITES", + "defaultDisabled": false, + "id": "a8b7ca68eff743bbbe6ef284693f7c5b" + }, + { + "relpath": "Resources/CustomFunctions", + "contentType": "CUSTOM_FUNCTIONS", + "defaultDisabled": false, + "id": "41005c09694840d1a8846873932506b8" + }, + { + "relpath": "Resources/Custom", + "contentType": "GENERIC", + "defaultDisabled": false, + "id": "7c56884aa265475b8c6c388a6fa8326e" + }, + { + "relpath": "Resources/ExperimentDefinitions", + "contentType": "EXPERIMENT_DEFINITIONS", + "defaultDisabled": false, + "id": "7c0cf26cfdd04ff198522c9ea7d6298e" + } + ], + "executionOptions": [] +} diff --git a/ThermofluidStream/HeatExchangers/CounterFlowNTU.mo b/ThermofluidStream/HeatExchangers/CounterFlowNTU.mo index 8384f2db..40d73d95 100644 --- a/ThermofluidStream/HeatExchangers/CounterFlowNTU.mo +++ b/ThermofluidStream/HeatExchangers/CounterFlowNTU.mo @@ -1,7 +1,7 @@ within ThermofluidStream.HeatExchangers; model CounterFlowNTU "Counter flow heat exchanger using the epsilon-NTU method" - extends ThermofluidStream.HeatExchangers.Internal.PartialNTU; + extends ThermofluidStream.HeatExchangers.Internal.PartialNTUCounterFlow; equation //Calculating heat exchanger effectiveness derived from NTU correlations (see VDI Waermeatlas) diff --git a/ThermofluidStream/HeatExchangers/CrossFlowNTU.mo b/ThermofluidStream/HeatExchangers/CrossFlowNTU.mo index 4bf8cc68..e180c7ed 100644 --- a/ThermofluidStream/HeatExchangers/CrossFlowNTU.mo +++ b/ThermofluidStream/HeatExchangers/CrossFlowNTU.mo @@ -1,7 +1,7 @@ within ThermofluidStream.HeatExchangers; model CrossFlowNTU "Cross flow heat exchanger using the epsilon-NTU method" - extends ThermofluidStream.HeatExchangers.Internal.PartialNTU(crossFlow=true); + extends ThermofluidStream.HeatExchangers.Internal.PartialNTUCrossFlow(crossFlow=true); equation //Calculating heat exchanger effectiveness derived from NTU correlations (see VDI Waermeatlas) diff --git a/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX.mo b/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX.mo index e622fc72..8d7193e3 100644 --- a/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX.mo +++ b/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX.mo @@ -1,7 +1,7 @@ within ThermofluidStream.HeatExchangers; model DiscretizedCounterFlowHEX "Discretized heat exchanger for single- or two-phase working fluids without pressure drop" - extends Internal.PartialDiscretizedHEX; + extends Internal.PartialDiscretizedHEXCounterFlow; initial equation if initializeMassFlow then diff --git a/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX_FR.mo b/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX_FR.mo index 7e202695..4d6bb8de 100644 --- a/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX_FR.mo +++ b/ThermofluidStream/HeatExchangers/DiscretizedCounterFlowHEX_FR.mo @@ -1,7 +1,7 @@ within ThermofluidStream.HeatExchangers; model DiscretizedCounterFlowHEX_FR "Discretized Heat Exchanger for single- or two-phase working fluid with pressure drop" - extends Internal.PartialDiscretizedHEX; + extends Internal.PartialDiscretizedHEXCrossFlow; parameter Real k1_A=1e2 "Linear flow resistance coefficient at side A" annotation (Dialog(group="Flow resistance coefficients")); diff --git a/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX.mo b/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX.mo index fa6a3804..9e536f92 100644 --- a/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX.mo +++ b/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX.mo @@ -1,7 +1,7 @@ within ThermofluidStream.HeatExchangers; model DiscretizedCrossFlowHEX "Discretized heat exchanger for single- or two-phase working fluid without pressure drop" - extends Internal.PartialDiscretizedHEX(nCellsParallel=nCells,crossFlow=true); + extends Internal.PartialDiscretizedHEXCrossFlow(nCellsParallel=nCells,crossFlow=true); Processes.FlowResistance flowResistanceA[nCells]( redeclare package Medium = MediumA, diff --git a/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX_FR.mo b/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX_FR.mo index e2867610..2714af04 100644 --- a/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX_FR.mo +++ b/ThermofluidStream/HeatExchangers/DiscretizedCrossFlowHEX_FR.mo @@ -1,7 +1,7 @@ within ThermofluidStream.HeatExchangers; model DiscretizedCrossFlowHEX_FR "Discretized Heat Exchanger for single- or two-phase working fluid with pressure drop" - extends Internal.PartialDiscretizedHEX(nCellsParallel=nCells,crossFlow=true); + extends Internal.PartialDiscretizedHEXCrossFlow(nCellsParallel=nCells,crossFlow=true); parameter Real k1_A=1e2 "Linear flow resistance coefficient at side A" annotation (Dialog(group="Flow resistance coefficients")); diff --git a/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEXCounterFlow.mo b/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEXCounterFlow.mo new file mode 100644 index 00000000..d93d5b51 --- /dev/null +++ b/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEXCounterFlow.mo @@ -0,0 +1,183 @@ +within ThermofluidStream.HeatExchangers.Internal; + +partial model PartialDiscretizedHEXCounterFlow "Base class for discretized heat exchangers" + + extends .ThermofluidStream.Utilities.DropOfCommonsPlus; + extends .ThermofluidStream.HeatExchangers.Internal.DiscretizedHexIcon; + + replaceable package MediumA = .ThermofluidStream.Media.myMedia.Interfaces.PartialMedium "Medium model side A" + annotation (choicesAllMatching=true, Dialog(group="Medium definitions")); + replaceable package MediumB = .ThermofluidStream.Media.myMedia.Interfaces.PartialMedium "Medium model side B" + annotation (choicesAllMatching=true, Dialog(group="Medium definitions")); + replaceable model ConductionElementA = .ThermofluidStream.HeatExchangers.Internal.ConductionElementHEX + constrainedby .ThermofluidStream.HeatExchangers.Internal.PartialConductionElementHEX( + final nCellsParallel=nCellsParallel, + final A=A/nCells, + final V=V_Hex/nCells, + redeclare package Medium = MediumA, + final enforce_global_energy_conservation=enforce_global_energy_conservation) "Heat transfer element model for side A" annotation (choicesAllMatching=true, Dialog(group="Medium definitions")); + replaceable model ConductionElementB = .ThermofluidStream.HeatExchangers.Internal.ConductionElementHEX + constrainedby .ThermofluidStream.HeatExchangers.Internal.PartialConductionElementHEX( + final nCellsParallel=1, + final A=A/nCells, + final V=V_Hex/nCells, + redeclare package Medium = MediumB, + final enforce_global_energy_conservation=enforce_global_energy_conservation) "Heat transfer element model for side B" annotation (choicesAllMatching=true, Dialog(group="Medium definitions")); + + parameter Integer nCells=3 "Number of discretization elements"; + parameter Boolean calculate_efficiency=false "= true, if heat exchanger efficiency is calculated" + annotation(Evaluate=true, HideResult=true, choices(checkBox=true)); + + parameter .Modelica.Units.SI.Area A=10 "Heat transfer area" + annotation (Dialog(group="Heat transfer parameters")); + parameter .Modelica.Units.SI.Volume V_Hex=0.001 "Volume for heat transfer calculation" + annotation (Dialog(group="Heat transfer parameters")); + parameter .Modelica.Units.SI.CoefficientOfHeatTransfer k_wall=100 "Coefficient of heat transfer for pipe wall" + annotation (Dialog(group="Heat transfer parameters")); + + parameter Boolean initializeMassFlow=false "= true, if inlet mass flow rates are initialized" + annotation (Dialog(tab="Initialization", group="Mass flow rate"),Evaluate=true, HideResult=true, choices(checkBox=true)); + parameter .Modelica.Units.SI.MassFlowRate m_flow_0_A=0 "Initial mass flow rate for side A" + annotation (Dialog( + tab="Initialization", + group="Mass flow rate", + enable=initializeMassFlow)); + parameter .Modelica.Units.SI.MassFlowRate m_flow_0_B=0 "Initial mass flow rate for side B" + annotation (Dialog( + tab="Initialization", + group="Mass flow rate", + enable=initializeMassFlow)); + parameter .Modelica.Units.SI.MassFlowRate m_flow_assert(max=0) = -dropOfCommons.m_flow_reg "Assertion threshold for negative mass flow rate" + annotation (Dialog(tab="Advanced")); + parameter Boolean enforce_global_energy_conservation=false "= true, if global conservation of energy is enforced" + annotation (Dialog(tab="Advanced"),Evaluate=true, HideResult=true, choices(checkBox=true)); + + // ------ Parameter Display Configuration ------------------------ + parameter Boolean displayArea = true "= true, if heat transfer area A is displayed" + annotation(Dialog(tab="Layout",group="Display parameters",enable=displayParameters),Evaluate=true, HideResult=true, choices(checkBox=true)); + final parameter Boolean d1A = displayParameters and displayArea "displayArea at position 1" + annotation(Evaluate=true, HideResult=true); //d1A -> Display at position 1 A=Area + //----------------------------------------------------------------- + + .ThermofluidStream.Interfaces.Inlet inletB(redeclare package Medium = MediumB) + annotation (Placement(transformation(extent={{-120,40},{-80,80}}), iconTransformation(extent={{-120,40},{-80,80}}))); + .ThermofluidStream.Interfaces.Outlet outletB(redeclare package Medium = MediumB) + annotation (Placement(transformation(extent={{80,40},{120,80}}), iconTransformation(extent={{80,40},{120,80}}))); + .ThermofluidStream.Interfaces.Inlet inletA(redeclare package Medium = MediumA) + annotation (Placement(transformation(extent={{120,-80},{80,-40}}), iconTransformation(extent={{120,-80},{80,-40}}, rotation=0))); + .ThermofluidStream.Interfaces.Outlet outletA(redeclare package Medium = MediumA) + annotation (Placement(transformation(extent={{-80,-80},{-120,-40}}), iconTransformation(extent={{-80,-80},{-120,-40}}, rotation=0))); + + + .Modelica.Units.SI.HeatFlowRate Q_flow_A=sum(thermalElementA.heatPort.Q_flow) "Heat flow rate into medium A"; + .Modelica.Units.SI.HeatFlowRate Q_flow_B=sum(thermalElementB.heatPort.Q_flow) "Heat flow rate into medium B"; + .Modelica.Units.SI.Mass M_A=sum(thermalElementA.M) "Mass of medium A"; + .Modelica.Units.SI.Mass M_B=sum(thermalElementB.M) "Mass of medium B"; + .Modelica.Units.SI.Energy deltaE_system=sum(thermalElementA.deltaE_system) + sum(thermalElementB.deltaE_system) "Error in global conservation of energy"; + + + .ThermofluidStream.HeatExchangers.Internal.DiscretizedHEXSummary summary "Summary record of Quantities"; + +protected + parameter Boolean crossFlow=false "Selection whether HEX is in crossflow or counterflow configuration"; + parameter Integer nCellsParallel=1 "Number of discretization elements in parallel"; + parameter .Modelica.Units.SI.ThermalConductance G=k_wall*A "Wall thermal conductance" + annotation (Dialog(group="Wall parameters")); + function efficiency = .ThermofluidStream.HeatExchangers.Internal.calculateEfficiency (redeclare package MediumA = MediumA, redeclare package MediumB = MediumB) "Heat exchanger efficiency"; + +public + .Modelica.Thermal.HeatTransfer.Components.ThermalConductor thermalConductor[nCells](each G=G/nCells) annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={0,0}))); + + ConductionElementB thermalElementB[nCells] annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + ConductionElementA thermalElementA[nCells] annotation (Placement(transformation(extent={{10,-50},{-10,-70}}))); + +equation + assert( + inletB.m_flow > m_flow_assert, + "Negative mass flow rate at inlet B", + dropOfCommons.assertionLevel); + assert( + inletA.m_flow > m_flow_assert, + "Negative massflow at inlet A", + dropOfCommons.assertionLevel); + + //Summary record + summary.Tin_B = MediumB.temperature(inletB.state); + summary.Tin_A = MediumA.temperature(inletA.state); + summary.Tout_B = MediumB.temperature(outletB.state); + summary.Tout_A = MediumA.temperature(outletA.state); + summary.hin_B = MediumB.specificEnthalpy(inletB.state); + summary.hin_A = MediumA.specificEnthalpy(inletA.state); + summary.hout_B = MediumB.specificEnthalpy(outletB.state); + summary.hout_A = MediumA.specificEnthalpy(outletA.state); + summary.dT_A = summary.Tout_A - summary.Tin_A; + summary.dT_B = summary.Tout_B - summary.Tin_B; + summary.dh_A = summary.hout_A - summary.hin_A; + summary.dh_B = summary.hout_B - summary.hin_B; + summary.Q_flow_A = Q_flow_A; + summary.Q_flow_B = Q_flow_B; + summary.efficiency = if calculate_efficiency then efficiency( + inletA.state, + inletB.state, + outletA.state, + outletB.state, + inletA.m_flow, + inletB.m_flow, + Q_flow_A) else 0; + + annotation (Documentation(info=" +

+This is the partial parent class for discretized heat exchangers. It contains +the inlet and outlet connectors as well as a number of conduction elements (which +is set by the parameter nCells) as discrete control volumes to +exchange heat between two fluid streams. +

+

+The conduction elements are computing a heat transfer coefficient between their +heatport and the fluid contained. They are replaceable with a choice between +a single-phase and a two-phase version, both can be further parametrized. +Although the single-phase version works for two-phase media (not the other +way around), using the two-phase one for two-phase media enables to set different +heat transfer coefficients depending on the phase (liquid/gaseous/2-phase) state +of the medium. +

+

+Note that since the model uses conductionElements as discrete control volumes that +in turn assume quasi-stationary mass and, therefore, are part of a fluid stream +rather than break it into two (like a full volume would), the same holds for +both sides of the heat exchanger – they are part of a fluid stream and +don't break it. The quasi-stationary mass assumption also implies that for +(fast) changing masses/densities in any of the conduction elements the heat +exchanger will (slightly) violate the conservation of energy. Furthermore, the +conduction elements change their behavior for reversed mass-flow, therefore, this +model asserts for negative mass-flow with the level +"DropOfCommons.assertionLevel". +

+

+The parameters A (heat transferring area), k_wall (heat +transfer coefficient of the wall between the streams) and the heat transfer +coefficients in the conduction elements scale the transferred heat (the middle +only if the wall and the latter only of the heat transfer into a fluid is the +choke of the heatflow). +

+

+The parameter V determines the amount of fluid in the heat exchanger +and, therefore, the dynamic for non-steady states. +

+

+The "Initialization" tab allows for a mass-flow initialization for both paths. +

+

+The "Advanced" tab allows to modify the massflow that triggers the +reverse-massflow-assertion and has an option to enforce global conservation of +energy. The latter is done by feeding back any energy the conduction elements +accumulated over time, basically making it impossible to store energy in their +fluid long-term. While this enforces long-term conservation of energy, it +changes the medium-/short-term dynamics of the system and is, therefore, +disabled by default. +

+")); +end PartialDiscretizedHEXCounterFlow; diff --git a/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEX.mo b/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEXCrossFlow.mo similarity index 94% rename from ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEX.mo rename to ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEXCrossFlow.mo index 4314df40..e51a1bb7 100644 --- a/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEX.mo +++ b/ThermofluidStream/HeatExchangers/Internal/PartialDiscretizedHEXCrossFlow.mo @@ -1,5 +1,5 @@ within ThermofluidStream.HeatExchangers.Internal; -partial model PartialDiscretizedHEX "Base class for discretized heat exchangers" +partial model PartialDiscretizedHEXCrossFlow "Base class for discretized heat exchangers" extends ThermofluidStream.Utilities.DropOfCommonsPlus; extends Internal.DiscretizedHexIcon; @@ -59,13 +59,13 @@ partial model PartialDiscretizedHEX "Base class for discretized heat exchangers" //----------------------------------------------------------------- Interfaces.Inlet inletB(redeclare package Medium = MediumB) - annotation (Placement(transformation(extent={{-120,40},{-80,80}}), iconTransformation(extent=if crossFlow then {{120,-80},{80,-40}} else {{-120,40},{-80,80}}))); + annotation (Placement(transformation(extent={{-120,40},{-80,80}}), iconTransformation(extent= {{120,-80},{80,-40}}))); Interfaces.Outlet outletB(redeclare package Medium = MediumB) - annotation (Placement(transformation(extent={{80,40},{120,80}}), iconTransformation(extent=if crossFlow then {{-80,-80},{-120,-40}} else {{80,40},{120,80}}))); + annotation (Placement(transformation(extent={{80,40},{120,80}}), iconTransformation(extent={{-80,-80},{-120,-40}}))); Interfaces.Inlet inletA(redeclare package Medium = MediumA) - annotation (Placement(transformation(extent={{120,-80},{80,-40}}), iconTransformation(extent=if crossFlow then {{-120,-20},{-80,20}} else {{120,-80},{80,-40}}, rotation=if crossFlow then -90 else 0))); + annotation (Placement(transformation(extent={{120,-80},{80,-40}}), iconTransformation(extent={{-120,-20},{-80,20}}, rotation=-90))); Interfaces.Outlet outletA(redeclare package Medium = MediumA) - annotation (Placement(transformation(extent={{-80,-80},{-120,-40}}), iconTransformation(extent=if crossFlow then {{80,-20},{120,20}} else {{-80,-80},{-120,-40}}, rotation=if crossFlow then -90 else 0))); + annotation (Placement(transformation(extent={{-80,-80},{-120,-40}}), iconTransformation(extent={{80,-20},{120,20}}, rotation=-90))); SI.HeatFlowRate Q_flow_A=sum(thermalElementA.heatPort.Q_flow) "Heat flow rate into medium A"; @@ -179,4 +179,4 @@ changes the medium-/short-term dynamics of the system and is, therefore, disabled by default.

")); -end PartialDiscretizedHEX; +end PartialDiscretizedHEXCrossFlow; diff --git a/ThermofluidStream/HeatExchangers/Internal/PartialNTU.mo b/ThermofluidStream/HeatExchangers/Internal/PartialNTUCounterFlow.mo similarity index 92% rename from ThermofluidStream/HeatExchangers/Internal/PartialNTU.mo rename to ThermofluidStream/HeatExchangers/Internal/PartialNTUCounterFlow.mo index 3fe56017..1a80da49 100644 --- a/ThermofluidStream/HeatExchangers/Internal/PartialNTU.mo +++ b/ThermofluidStream/HeatExchangers/Internal/PartialNTUCounterFlow.mo @@ -1,8 +1,9 @@ within ThermofluidStream.HeatExchangers.Internal; -partial model PartialNTU "Partial heat exchanger model using the epsilon-NTU method" +partial model PartialNTUCounterFlow "Partial heat exchanger model using the epsilon-NTU method" extends ThermofluidStream.Utilities.DropOfCommonsPlus; + replaceable package MediumA = ThermofluidStream.Media.myMedia.Interfaces.PartialMedium "Medium model A" annotation (choicesAllMatching=true); replaceable package MediumB = ThermofluidStream.Media.myMedia.Interfaces.PartialMedium "Medium model B" @@ -30,23 +31,23 @@ partial model PartialNTU "Partial heat exchanger model using the epsilon-NTU met annotation(Evaluate=true, HideResult=true); //----------------------------------------------------------------- - ThermofluidStream.Interfaces.Inlet inletA(redeclare package Medium = MediumA) annotation (Placement(transformation( + + ThermofluidStream.Interfaces.Inlet inletA(redeclare package Medium = MediumA) annotation (Placement(transformation( extent={{-20,-20},{20,20}}, rotation=0, - origin={-100,-60}), iconTransformation(extent=if crossFlow then {{-120,-20},{-80,20}} else {{-120,-80},{-80,-40}}))); + origin={-100,-60}), iconTransformation(extent={{-120,-80},{-80,-40}}))); ThermofluidStream.Interfaces.Outlet outletA(redeclare package Medium = MediumA) annotation (Placement(transformation( extent={{-20,-20},{20,20}}, rotation=0, - origin={100,-60}), iconTransformation(extent=if crossFlow then {{80,-20},{120,20}} else {{80,-80},{120,-40}}))); + origin={100,-60}), iconTransformation(extent={{80,-80},{120,-40}}))); ThermofluidStream.Interfaces.Inlet inletB(redeclare package Medium = MediumB) annotation (Placement(transformation( extent={{20,-20},{-20,20}}, rotation=0, - origin={100,60}), iconTransformation(extent=if crossFlow then {{-120,-20},{-80,20}} else {{120,80},{80,40}}, rotation=if crossFlow then -90 else 0))); + origin={100,60}), iconTransformation(extent={{120,80},{80,40}}, rotation=0))); ThermofluidStream.Interfaces.Outlet outletB(redeclare package Medium = MediumB) annotation (Placement(transformation( extent={{20,-20},{-20,20}}, rotation=0, - origin={-100,60}), iconTransformation(extent=if crossFlow then {{80,-20},{120,20}} else {{-80,80},{-120,40}}, rotation=if crossFlow then -90 else 0))); - + origin={-100,60}), iconTransformation(extent={{-80,80},{-120,40}}, rotation=0))); Modelica.Units.SI.TemperatureDifference Delta_T_max "Maximum temperature difference"; @@ -64,8 +65,8 @@ partial model PartialNTU "Partial heat exchanger model using the epsilon-NTU met ThermofluidStream.HeatExchangers.Internal.DiscretizedHEXSummary summary "Summary record of quantities"; -protected parameter Boolean crossFlow=false "Selection whether HEX is in crossflow or counterflow configuration"; +protected Modelica.Units.SI.Pressure p_A=MediumA.pressure(inletA.state) "Inlet A pressure"; Modelica.Units.SI.Pressure p_B=MediumB.pressure(inletB.state) "Inlet B pressure"; @@ -232,4 +233,4 @@ flow regularization close to zero: ")); -end PartialNTU; +end PartialNTUCounterFlow; diff --git a/ThermofluidStream/HeatExchangers/Internal/PartialNTUCrossFlow.mo b/ThermofluidStream/HeatExchangers/Internal/PartialNTUCrossFlow.mo new file mode 100644 index 00000000..5ea944af --- /dev/null +++ b/ThermofluidStream/HeatExchangers/Internal/PartialNTUCrossFlow.mo @@ -0,0 +1,237 @@ +within ThermofluidStream.HeatExchangers.Internal; + +partial model PartialNTUCrossFlow "Partial heat exchanger model using the epsilon-NTU method" + + extends .ThermofluidStream.Utilities.DropOfCommonsPlus; + + + replaceable package MediumA = .ThermofluidStream.Media.myMedia.Interfaces.PartialMedium "Medium model A" + annotation (choicesAllMatching=true); + replaceable package MediumB = .ThermofluidStream.Media.myMedia.Interfaces.PartialMedium "Medium model B" + annotation (choicesAllMatching=true); + + parameter .Modelica.Units.SI.Area A "Heat transfer area"; + parameter .Modelica.Units.SI.CoefficientOfHeatTransfer k_NTU=50 "Thermal transmittance"; + parameter .ThermofluidStream.Utilities.Units.Inertance L=dropOfCommons.L "Inertance" + annotation (Dialog(tab="Advanced")); + parameter .Modelica.Units.SI.MassFlowRate m_flow_reg=dropOfCommons.m_flow_reg "Nominal mass flow rate for regularization" + annotation (Dialog(tab="Advanced", group="Regularization parameters")); + parameter .Modelica.Units.SI.Time TC=0.01 "Time constant for specific enthalpy difference dh" + annotation (Dialog(tab="Advanced")); + + // ------ Parameter Display Configuration ------------------------ + parameter Boolean displayArea = true "= true, if the heat transfer area A is displayed" + annotation(Dialog(tab="Layout",group="Display parameters",enable=displayParameters),Evaluate=true, HideResult=true, choices(checkBox=true)); + parameter Boolean displaykNTU = true "= true, if the thermal transmittance k_NTU is displayed" + annotation(Dialog(tab="Layout",group="Display parameters",enable=displayParameters),Evaluate=true, HideResult=true, choices(checkBox=true)); + final parameter Boolean d1A = displayParameters and displayArea "displayArea at position 1" + annotation(Evaluate=true, HideResult=true); //d1A -> Display at position 1 A=Area + final parameter Boolean d1kNTU = displayParameters and displaykNTU and not d1A "displaykNTU at position 1" + annotation(Evaluate=true, HideResult=true); + final parameter Boolean d2kNTU = displayParameters and displaykNTU and not d1kNTU "displaykNTU at position 2" + annotation(Evaluate=true, HideResult=true); + //----------------------------------------------------------------- + + + .ThermofluidStream.Interfaces.Inlet inletA(redeclare package Medium = MediumA) annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={-100,-60}), iconTransformation(extent={{-120,-20},{-80,20}}))); + .ThermofluidStream.Interfaces.Outlet outletA(redeclare package Medium = MediumA) annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={100,-60}), iconTransformation(extent={{80,-20},{120,20}}))); + .ThermofluidStream.Interfaces.Inlet inletB(redeclare package Medium = MediumB) annotation (Placement(transformation( + extent={{20,-20},{-20,20}}, + rotation=0, + origin={100,60}), iconTransformation(extent={{-120,-20},{-80,20}}, rotation=-90))); + .ThermofluidStream.Interfaces.Outlet outletB(redeclare package Medium = MediumB) annotation (Placement(transformation( + extent={{20,-20},{-20,20}}, + rotation=0, + origin={-100,60}), iconTransformation(extent={{80,-20},{120,20}}, rotation=-90))); + + + .Modelica.Units.SI.TemperatureDifference Delta_T_max "Maximum temperature difference"; + + .Modelica.Units.SI.SpecificEnthalpy dh_A "Specific enthalpy difference medium A"; + .Modelica.Units.SI.SpecificEnthalpy dh_B "Specific enthalpy difference medium B"; + + .Modelica.Units.SI.HeatFlowRate q_flow "Heat flow rate (Q_flow)"; + Real effectiveness(unit="1") "Heat exchanger efficiency"; + Real NTU(unit="1") "Number of transfer units"; + + //Inlet and outlet temperatures + MediumA.Temperature T_in_MediumA "Inlet temperature of medium A"; + MediumB.Temperature T_in_MediumB "Inlet temperature of medium B"; + + .ThermofluidStream.HeatExchangers.Internal.DiscretizedHEXSummary summary "Summary record of quantities"; + + parameter Boolean crossFlow=false "Selection whether HEX is in crossflow or counterflow configuration"; +protected + + .Modelica.Units.SI.Pressure p_A=MediumA.pressure(inletA.state) "Inlet A pressure"; + .Modelica.Units.SI.Pressure p_B=MediumB.pressure(inletB.state) "Inlet B pressure"; + + MediumA.MassFraction Xi_A[MediumA.nXi]=MediumA.massFraction(inletA.state) "Inlet A mass fractions"; + MediumB.MassFraction Xi_B[MediumB.nXi]=MediumB.massFraction(inletB.state) "Inlet B mass fractions"; + + //Inlet and outlet specific enthalpies and enthalpy differences + .Modelica.Units.SI.SpecificEnthalpy h_in_A "Specific enthalpy at inlet A"; + .Modelica.Units.SI.SpecificEnthalpy h_in_B "Specific enthalpy at inlet B"; + .Modelica.Units.SI.SpecificEnthalpy h_out_A "Specific enthalpy at outlet A"; + .Modelica.Units.SI.SpecificEnthalpy h_out_B "Specific enthalpy at outlet B"; + + .Modelica.Units.SI.HeatFlowRate q_max "Maximum heat flow rate (Q_max)"; + .Modelica.Units.SI.HeatFlowRate q_flowA "Heat flow rate side A (Q_flowA)"; + .Modelica.Units.SI.HeatFlowRate q_flowB "Heat flow rate side B (Q_flowB)"; + + Real C_A(unit="J/(K.s)") "Heat capacity flow rate of Medium A"; + Real C_B(unit="J/(K.s)") "Heat capacity flow rate of Medium B"; + Real C_min(unit="J/(K.s)") "Minimum heat capacity flow rate"; + Real C_max(unit="J/(K.s)") "Maximum heat capacity flow rate"; + Real C_r(unit="1") "Ratio of heat capacity rates, Cmin/Cmax"; + + .Modelica.Units.SI.SpecificHeatCapacityAtConstantPressure cp_A "Specific heat capacity of Medium A"; + .Modelica.Units.SI.SpecificHeatCapacityAtConstantPressure cp_B "Specific heat capacity of Medium B"; + + .Modelica.Units.SI.MassFlowRate m_flow_A=inletA.m_flow "Mass flow rate on side A"; + .Modelica.Units.SI.MassFlowRate m_flow_B=inletB.m_flow "Mass flow rate on side B"; + + .Modelica.Units.SI.SpecificHeatCapacity cpA_in=MediumA.specificHeatCapacityCp(inletA.state) "Inlet A specific heat capacity"; + .Modelica.Units.SI.SpecificHeatCapacity cpA_out=MediumA.specificHeatCapacityCp(outletA.state) "Outlet A specific heat capacity"; + .Modelica.Units.SI.SpecificHeatCapacity cpB_in=MediumB.specificHeatCapacityCp(inletB.state) "Inlet B specific heat capacity"; + .Modelica.Units.SI.SpecificHeatCapacity cpB_out=MediumB.specificHeatCapacityCp(outletB.state) "Outlet B specific heat capacity"; + + constant Real eps(unit="kg/s") = .Modelica.Constants.eps "Mass flow rate regularization"; + +initial equation + h_out_A = h_in_A; + h_out_B = h_in_B; + +equation + //Balance Equations + inletA.m_flow + outletA.m_flow= 0; + inletB.m_flow + outletB.m_flow = 0; + inletA.r - outletA.r = der(inletA.m_flow)*L; + inletB.r - outletB.r = der(inletB.m_flow)*L; + + //Specific heat capacities + cp_A = (cpA_in + cpA_out)/2; + cp_B = (cpB_in + cpB_out)/2; + + //Heat capacity rates + C_A = (abs(inletA.m_flow) + eps)*cp_A; + C_B = (abs(inletB.m_flow) + eps)*cp_B; + + //Inlet temperatures and enthalpies + T_in_MediumA = MediumA.temperature(inletA.state); + T_in_MediumB = MediumB.temperature(inletB.state); + + h_in_A = MediumA.specificEnthalpy(inletA.state); + h_in_B = MediumB.specificEnthalpy(inletB.state); + + //Finding minimum heat capacity rate + if noEvent(C_A > C_B) then + C_min = C_B; + C_max = C_A; + else + C_min = C_A; + C_max = C_B; + end if; + + C_r = C_min/(max(C_max, 1e-3)); + + //Number of Transfer Units + NTU = (k_NTU*A)/(max(C_min, 1e-3)); + + + //Maximum possible temperature difference + Delta_T_max = T_in_MediumA - T_in_MediumB; + + //Maximum possible heat flow rate + q_max = Delta_T_max*C_min; + + //Actual heat flow rate + q_flow = effectiveness*q_max; + + if noEvent(C_A < C_B) then + + //No heat is transferred, if both mass flow rates are smaller than regularization mass flow rate + if noEvent(inletA.m_flow < m_flow_reg) and noEvent(inletB.m_flow < m_flow_reg) then + dh_A = 0; + else + dh_A = Delta_T_max*cp_A*effectiveness; + end if; + + q_flowA = m_flow_A*dh_A; + q_flowB = -q_flowA; + + //Based on regularization for mass flow + dh_B = (m_flow_B*q_flowB)/(m_flow_B^2 + (m_flow_reg/10)^2); + + der(h_out_A)*TC = h_in_A - dh_A - h_out_A; + der(h_out_B)*TC = h_in_B - dh_B - h_out_B; + + else + + //No heat is transferred, if both mass flow rates are smaller than regularization mass flow rate + if noEvent(inletA.m_flow < m_flow_reg) and noEvent(inletB.m_flow < m_flow_reg) then + dh_B = 0; + else + dh_B = -Delta_T_max*cp_B*effectiveness; + end if; + + q_flowB = m_flow_B*dh_B; + q_flowA = -q_flowB; + + //Based on regularization for mass flow + dh_A = (m_flow_A*q_flowA)/(m_flow_A^2 + (m_flow_reg/10)^2); + + der(h_out_A)*TC = h_in_A - dh_A - h_out_A; + der(h_out_B)*TC = h_in_B - dh_B - h_out_B; + + end if; + + outletA.state = MediumA.setState_phX( + p_A, + h_out_A, + Xi_A); + outletB.state = MediumB.setState_phX( + p_B, + h_out_B, + Xi_B); + + //Summary record + summary.Tin_B = MediumB.temperature(inletB.state); + summary.Tin_A = MediumA.temperature(inletA.state); + summary.Tout_B = MediumB.temperature(outletB.state); + summary.Tout_A = MediumA.temperature(outletA.state); + summary.hin_A = h_in_A; + summary.hout_A = h_out_A; + summary.hin_B = h_in_B; + summary.hout_B = h_out_B; + summary.dT_A = summary.Tout_A - summary.Tin_A; + summary.dT_B = summary.Tout_B - summary.Tin_B; + summary.dh_A = summary.hout_A - summary.hin_A; + summary.dh_B = summary.hout_B - summary.hin_B; + summary.Q_flow_A = q_flowA; + summary.Q_flow_B = q_flowB; + summary.efficiency = effectiveness; + + annotation (Documentation(info=" +

+This is the partial parent class for all heat exchangers based on the the +effectiveness-NTU method. +

+

+For stream dominated applications the following assumptions are made for mass +flow regularization close to zero: +

+ +")); +end PartialNTUCrossFlow; diff --git a/ThermofluidStream/HeatExchangers/Internal/package.order b/ThermofluidStream/HeatExchangers/Internal/package.order index 957c814a..4fd0c91a 100644 --- a/ThermofluidStream/HeatExchangers/Internal/package.order +++ b/ThermofluidStream/HeatExchangers/Internal/package.order @@ -1,8 +1,12 @@ +PartialCounterFlowInterface +PartialCrossFlowInterface PartialConductionElementHEX ConductionElementHEX ConductionElementHEX_twoPhase DiscretizedHEXSummary DiscretizedHexIcon calculateEfficiency -PartialDiscretizedHEX -PartialNTU +PartialDiscretizedHEXCrossFlow +PartialDiscretizedHEXCounterFlow +PartialNTUCounterFlow +PartialNTUCrossFlow \ No newline at end of file diff --git a/ThermofluidStream/HeatExchangers/package.order b/ThermofluidStream/HeatExchangers/package.order index 96bb7e14..56d59299 100644 --- a/ThermofluidStream/HeatExchangers/package.order +++ b/ThermofluidStream/HeatExchangers/package.order @@ -5,4 +5,4 @@ DiscretizedCrossFlowHEX DiscretizedCounterFlowHEX_FR DiscretizedCrossFlowHEX_FR Tests -Internal +Internal \ No newline at end of file