diff --git a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der.mo b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der.mo index 335c0fa6cb..0e6f795b48 100644 --- a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der.mo +++ b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der.mo @@ -11,7 +11,7 @@ function basicFlowFunction_dp_der "Mass flow rate where transition to turbulent flow occurs"; input Real dp_der "Derivative of pressure difference between port_a and port_b (= port_a.p - port_b.p)"; - output Real m_flow_der(unit="kg/s2") + output Real m_flow_der "Derivative of mass flow rate in design flow direction"; protected Modelica.Units.SI.PressureDifference dp_turbulent=(m_flow_turbulent/k)^2 @@ -30,8 +30,14 @@ Documentation(info="

Function that implements the first order derivative of -IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp -with respect to the mass flow rate. +IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp, +assuming a constant flow coefficient. +

+

+When called with dp_der=der(dp), this function returns +the time derivative of m_flow. +When called with dp_der=1, this function returns +the derivative of m_flow with respect to dp.

", revisions=" diff --git a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der2.mo b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der2.mo index e64a9fbdb6..eb9fbdfb33 100644 --- a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der2.mo +++ b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_dp_der2.mo @@ -1,6 +1,6 @@ within IBPSA.Fluid.BaseClasses.FlowModels; function basicFlowFunction_dp_der2 - "2nd derivative of flow function2nd derivative of function that computes mass flow rate for given pressure drop" + "2nd derivative of function that computes mass flow rate for given pressure drop" extends Modelica.Icons.Function; input Modelica.Units.SI.PressureDifference dp(displayUnit="Pa") @@ -35,8 +35,16 @@ Documentation(info="

Function that implements the second order derivative of -IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp -with respect to the mass flow rate. +IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp, +assuming a constant flow coefficient. +

+

+When called with dp_der=der(dp) and dp_der2=der(dp_der), +this function returns the second order derivative of m_flow +with respect to time. +When called with dp_der=1 and dp_der2=0, +this function returns the second order derivative of m_flow +with respect to dp.

", revisions=" diff --git a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der.mo b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der.mo index 05c27661a2..bd6e5449e3 100644 --- a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der.mo +++ b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der.mo @@ -9,7 +9,7 @@ function basicFlowFunction_m_flow_der "Flow coefficient, k=m_flow/sqrt(dp), with unit=(kg.m)^(1/2)"; input Modelica.Units.SI.MassFlowRate m_flow_turbulent(min=0) "Mass flow rate where transition to turbulent flow occurs"; - input Real m_flow_der(unit="kg/s2") + input Real m_flow_der "Derivative of mass flow rate in design flow direction"; output Real dp_der "Derivative of pressure difference between port_a and port_b (= port_a.p - port_b.p)"; @@ -31,8 +31,14 @@ Documentation(info="

Function that implements the first order derivative of -IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_m_flow -with respect to the mass flow rate. +IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_m_flow, +assuming a constant flow coefficient. +

+

+When called with m_flow_der=der(m_flow), this function returns +the time derivative of dp. +When called with m_flow_der=1, this function returns +the derivative of dp with respect to m_flow.

", revisions=" diff --git a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der2.mo b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der2.mo index 6c70c3ef0e..df610a653a 100644 --- a/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der2.mo +++ b/IBPSA/Fluid/BaseClasses/FlowModels/basicFlowFunction_m_flow_der2.mo @@ -9,9 +9,9 @@ function basicFlowFunction_m_flow_der2 "Flow coefficient, k=m_flow/sqrt(dp), with unit=(kg.m)^(1/2)"; input Modelica.Units.SI.MassFlowRate m_flow_turbulent(min=0) "Mass flow rate where transition to turbulent flow occurs"; - input Real m_flow_der(unit="kg/s2") + input Real m_flow_der "1st derivative of mass flow rate in design flow direction"; - input Real m_flow_der2(unit="kg/s3") + input Real m_flow_der2 "2nd derivative of mass flow rate in design flow direction"; output Real dp_der2 "2nd derivative of pressure difference between port_a and port_b (= port_a.p - port_b.p)"; @@ -35,8 +35,16 @@ Documentation(info="

Function that implements the second order derivative of -IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_m_flow -with respect to the mass flow rate. +IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_m_flow, +assuming a constant flow coefficient. +

+

+When called with m_flow_der=der(m_flow) and m_flow_der2=der(m_flow_der), +this function returns the second order derivative of dp +with respect to time. +When called with m_flow_der=1 and m_flow_der2=0, +this function returns the second order derivative of dp +with respect to m_flow.

", revisions=" diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/FixedEvaporating.mo b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/FixedEvaporating.mo new file mode 100644 index 0000000000..b7ffed5fa4 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/FixedEvaporating.mo @@ -0,0 +1,213 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses; +model FixedEvaporating + "Thermodynamic computations of the ORC with fixed evaporating temperature" + extends IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.InterpolateStates( + TEva=TWorEva, + TCon=TWorCon); + + parameter Modelica.Units.SI.TemperatureDifference dTPinEva_set( + final min = 0) + "Set evaporator pinch point temperature difference" + annotation(Dialog(group="Evaporator")); + parameter Modelica.Units.SI.SpecificHeatCapacity cpHot + "Constant specific heat capacity" + annotation(Dialog(group="Evaporator")); + parameter Modelica.Units.SI.ThermodynamicTemperature TWorEva + "Working fluid evaporator temperature" + annotation(Dialog(group="Evaporator")); + parameter Modelica.Units.SI.TemperatureDifference dTPinCon + "Pinch point temperature difference of condenser" + annotation(Dialog(group="Condenser")); + parameter Modelica.Units.SI.SpecificHeatCapacity cpCol + "Constant specific heat capacity" + annotation(Dialog(group="Condenser")); + parameter Boolean useLowCondenserPressureWarning = true + "If true, issues warning if pCon < 101325 Pa"; + parameter Modelica.Units.SI.MassFlowRate mWor_flow_max( + final min = 0) + "Upper bound of working fluid flow rate" + annotation(Dialog(group="Cycle")); + parameter Modelica.Units.SI.MassFlowRate mWor_flow_min( + final min = 0) + "Lower bound of working fluid flow rate" + annotation(Dialog(group="Cycle")); + parameter Modelica.Units.SI.MassFlowRate mWor_flow_hysteresis( + final min = 0) + "Hysteresis for turning off the cycle when flow too low" + annotation(Dialog(group="Cycle")); + + Modelica.Blocks.Interfaces.RealInput THotIn( + final quantity="ThermodynamicTemperature", + final unit="K", + displayUnit="degC") "Incoming temperature of hot fluid in evaporator" + annotation (Placement( + transformation(extent={{-140,60},{-100,100}}), iconTransformation( + extent={{-120,70},{-100,90}}))); + Modelica.Blocks.Interfaces.RealInput mHot_flow( + final quantity="MassFlowRate", + final unit="kg/s") "Evaporator hot fluid flow rate" + annotation (Placement(transformation(extent={{-140,20},{-100,60}}), + iconTransformation(extent={{-120,30},{-100,50}}))); + Modelica.Blocks.Interfaces.RealInput TColIn( + final quantity="ThermodynamicTemperature", + final unit="K", + displayUnit="degC") "Incoming temperature of cold fluid in condenser" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-120,-50},{-100,-30}}))); + Modelica.Blocks.Interfaces.RealInput mCol_flow( + final quantity="MassFlowRate", + final unit="kg/s") "Condenser cold fluid flow rate" annotation (Placement( + transformation(extent={{-140,-100},{-100,-60}}), iconTransformation( + extent={{-120,-90},{-100,-70}}))); + Modelica.Blocks.Interfaces.BooleanInput ena + "Enable cycle; set false to force working fluid flow to zero" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-120,-10},{-100,10}}))); + + Modelica.Blocks.Interfaces.RealOutput QEva_flow( + final quantity="HeatFlowRate", + final unit="W") "Evaporator heat flow rate into the cycle" + annotation (Placement(transformation(extent={{100,60},{140,100}}), + iconTransformation(extent={{100,70},{120,90}}))); + Modelica.Blocks.Interfaces.RealOutput QCon_flow( + final quantity="HeatFlowRate", + final unit="W") "Condenser heat flow rate out of the cycle" + annotation (Placement( + transformation(extent={{100,-100},{140,-60}}),iconTransformation(extent={{100,-90}, + {120,-70}}))); + Modelica.Blocks.Interfaces.RealOutput PExp( + final quantity="Power", + final unit="W") "Expander power generation" annotation (Placement( + transformation(extent={{100,20},{140,60}}), iconTransformation(extent={{100,30}, + {120,50}}))); + Modelica.Blocks.Interfaces.RealOutput PPum( + final quantity="Power", + final unit="W") + "Electrical power consumption of the pump" annotation (Placement( + transformation(extent={{100,-60},{140,-20}}),iconTransformation(extent={ + {100,-50},{120,-30}}))); + Modelica.Blocks.Interfaces.BooleanOutput on_actual = ena and hys.y + "Actual on off status of the cycle" annotation (Placement(transformation( + extent={{100,-20},{140,20}}), iconTransformation(extent={{100,-10},{120, + 10}}))); + + Modelica.Units.SI.ThermodynamicTemperature THotOut( + start = TWorEva + dTPinEva_set) + "Outgoing temperature of the evaporator hot fluid"; + Modelica.Units.SI.ThermodynamicTemperature THotPin( + start = TWorEva + dTPinEva_set) + "Hot fluid temperature at pinch point"; + Modelica.Units.SI.TemperatureDifference dTPinEva(start = dTPinEva_set) + "Pinch point temperature difference of evaporator"; + Modelica.Units.SI.ThermodynamicTemperature TWorCon + "Working fluid condensing temperature"; + Modelica.Units.SI.ThermodynamicTemperature TColOut + "Fluid temperature out of the condenser"; + Modelica.Units.SI.ThermodynamicTemperature TColPin( + start = 300) + "Cold fluid temperature at pinch point"; + Modelica.Units.SI.MassFlowRate mWor_flow + "Mass flow rate of the working fluid" + annotation (Dialog(group="Cycle")); + Modelica.Blocks.Logical.Hysteresis hys( + uLow = mWor_flow_min, + uHigh = mWor_flow_min + mWor_flow_hysteresis, + u = mWor_flow_internal, + y(start = false)) + "Hysteresis for turning off cycle when working fluid flow too low"; + +protected + Modelica.Units.SI.MassFlowRate mWor_flow_internal( + start = (mWor_flow_max + mWor_flow_min) / 2) + "Working fluid flow rate, intermediate variable"; + Modelica.Units.SI.ThermodynamicTemperature THotPin_internal + "Hot fluid temperature at pinch point, intermedaite variable"; + Modelica.Units.SI.ThermodynamicTemperature THotOut_internal + "Hot fluid outgoing temperature, intermediate variable"; + Modelica.Units.SI.HeatFlowRate QEva_flow_internal + "Evaporator heat flow rate, intermediate variable"; + +equation + + assert(not (TWorCon > TWorEva - 1 and ena), +"*** In " + getInstanceName() + +": Working fluid condensing temperature is too high and close to evaporating temperature. +This is likely caused by the flow rate of cold fluid in the condenser being too low +when the ORC is on."); + + assert(not (pCon < 101325 - 1 and ena and useLowCondenserPressureWarning), +"*** In " + getInstanceName() + +": Working fluid condensing pressure is lower than 101325 Pa. +If this is intended, set useLowCondenserPressureWarning = false to turn off this warning.", +level=AssertionLevel.warning); + + if ena then + // Evaporator + QEva_flow = mHot_flow * cpHot * (THotOut - THotIn); + QEva_flow = mWor_flow * (hPumOut - hExpInl); + (THotPin - THotOut) * (hExpInl - hPumOut) + = (hPinEva - hPumOut) * (THotIn - THotOut); + // Condenser + QCon_flow = mCol_flow * cpCol * (TColOut - TColIn); + QCon_flow = mWor_flow * (hExpOut - hPumInl); + (TColPin - TColIn) * (hExpOut - hPumInl) + = (hPinCon - hPumInl) * (TColOut - TColIn); + else + // Evaporator + QEva_flow = 0; + THotOut = THotIn; + THotPin = THotOut; + // Condenser + QCon_flow = 0; + TColOut = TColIn; + TColPin = TColIn; + end if; + dTPinEva = THotPin - TWorEva; // Evaporator + dTPinCon = TWorCon - TColPin; // Condenser + + // Evaporator internal computation + QEva_flow_internal = mHot_flow * cpHot * (THotOut_internal - THotIn); + QEva_flow_internal = mWor_flow_internal * (hPumOut - hExpInl); + (THotPin_internal - THotOut_internal) * (hExpInl - hPumOut) + = (hPinEva - hPumOut) * (THotIn - THotOut_internal); + dTPinEva_set = THotPin_internal - TWorEva; + + // Other components + PExp = mWor_flow * (hExpOut - hExpInl); + PPum = mWor_flow * (hPumOut - hPumInl); + mWor_flow = + if on_actual + then + IBPSA.Utilities.Math.Functions.smoothMin( + x1=mWor_flow_internal, + x2=mWor_flow_max, + deltaX=mWor_flow_min*1E-2) + else 0; + + annotation(defaultComponentName="cyc", + Documentation(info=" +

+This model computes the pinch points and the energy exchange, +and interfaces with the input and output variables. +The evaporating temperature is fixed as a parameter. +See the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +for more details. +", revisions=" +

+"), + Icon(graphics={Line( + points={{-28,20},{66,50}}, + color={238,46,47}, + thickness=1), Line( + points={{-30,-54},{64,-24}}, + color={28,108,200}, + thickness=1)})); +end FixedEvaporating; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/InterpolateStates.mo b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/InterpolateStates.mo new file mode 100644 index 0000000000..23f6e68c15 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/InterpolateStates.mo @@ -0,0 +1,322 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses; +model InterpolateStates "Interpolate states of a working fluid" + + // Input properties + replaceable parameter IBPSA.Fluid.CHPs.OrganicRankine.Data.Generic pro + "Property records of the working fluid" + annotation(Dialog(group="ORC inputs"), choicesAllMatching = true); + parameter Modelica.Units.SI.SpecificEnthalpy h_small = + (max(pro.hSatVap) - min(pro.hSatLiq)) * 1E-4 + "A small value for specific enthalpy regularisation" + annotation(Dialog(tab="Advanced")); + + input Modelica.Units.SI.ThermodynamicTemperature TEva + "Evaporating temperature"; + input Modelica.Units.SI.ThermodynamicTemperature TCon + "Condensing temperature"; + input Modelica.Units.SI.Efficiency etaExp + "Expander efficiency"; + input Modelica.Units.SI.Efficiency etaPum + "Pump efficiency"; + + // Once-interpolated properties + Modelica.Units.SI.AbsolutePressure pEva( + displayUnit = "kPa") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TEva, + xd = pro.T, + yd = pro.p, + d = pDer_T) + "Evaporating pressure"; + Modelica.Units.SI.AbsolutePressure pCon( + displayUnit = "kPa") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.p, + d = pDer_T) + "Condensing pressure"; + Modelica.Units.SI.Density rhoLiq = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.rhoLiq, + d = rhoLiqDer_T) + "Saturated liquid density"; + Modelica.Units.SI.SpecificEntropy sPumInl = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.sSatLiq, + d = sSatLiqDer_T) + "Specific entropy at pump inlet"; + Modelica.Units.SI.SpecificEnthalpy hPumInl( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.hSatLiq, + d = hSatLiqDer_T) + "Specific enthalpy at pump inlet"; + Modelica.Units.SI.SpecificEnthalpy hPinEva( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TEva, + xd = pro.T, + yd = pro.hSatLiq, + d = hSatLiqDer_T) + "Specific enthalpy at evaporator-side pinch point"; + Modelica.Units.SI.SpecificEnthalpy hPinCon( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.hSatVap, + d = hSatVapDer_T) + "Specific enthalpy at condenser-side pinch point"; + Modelica.Units.SI.SpecificEntropy sSatVapCon( + start = max(pro.sSatVap) * 0.1 + min(pro.sSatVap) * 0.9) = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.sSatVap, + d = sSatVapDer_T) + "Specific entropy of saturated vapor at the condenser"; + Modelica.Units.SI.SpecificEntropy sRefCon = + IBPSA.Utilities.Math.Functions.interpolate( + u = pCon, + xd = pro.p, + yd = pro.sRef, + d = sRefDer_p) + "Specific entropy on reference line at condensing pressure"; + Modelica.Units.SI.SpecificEntropy sSatVapEva = + IBPSA.Utilities.Math.Functions.interpolate( + u = TEva, + xd = pro.T, + yd = pro.sSatVap, + d = sSatVapDer_T) + "Specific entropy of saturated vapor at evaporating temperature"; + Modelica.Units.SI.SpecificEnthalpy hSatVapEva( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TEva, + xd = pro.T, + yd = pro.hSatVap, + d = hSatVapDer_T) + "Specific enthalpy of saturated vapor at evaporating temperature"; + Modelica.Units.SI.SpecificEntropy sRefEva = + IBPSA.Utilities.Math.Functions.interpolate( + u = pEva, + xd = pro.p, + yd = pro.sRef, + d = sRefDer_p) + "Specific entropy on reference line at evaporating pressure"; + Modelica.Units.SI.SpecificEnthalpy hSatVapCon( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = TCon, + xd = pro.T, + yd = pro.hSatVap, + d = hSatVapDer_T) + "Specific enthalpy of saturated vapor at the condensing temperature"; + Modelica.Units.SI.SpecificEnthalpy hRefCon( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = pCon, + xd = pro.p, + yd = pro.hRef, + d = hRefDer_p) + "Specific enthalpy on reference line at condensing pressure"; + Modelica.Units.SI.SpecificEnthalpy hRefEva( + displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.interpolate( + u = pEva, + xd = pro.p, + yd = pro.hRef, + d = hRefDer_p) + "Specific enthalpy on reference line at evaporating pressure"; + + // Computed properties not interpolated + Modelica.Units.SI.SpecificEnthalpy hPumOut(displayUnit = "kJ/kg") = + hPumInl + wPum + "Specific enthalpy at pump outlet"; + Modelica.Units.SI.SpecificEnthalpy hExpInl(displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.regStep( + x = h_reg, + y1 = hSatVapEva, + y2 = hExpInlWet, + x_small = h_small) + "Specific enthalpy at expander inlet"; + Modelica.Units.SI.SpecificEnthalpy hExpOut(displayUnit = "kJ/kg") = + IBPSA.Utilities.Math.Functions.regStep( + x = h_reg, + y1 = hExpOutDry, + y2 = hSatVapCon, + x_small = h_small) + "Specific enthalpy at expander inlet"; + Modelica.Units.SI.TemperatureDifference dTSup = max(0, dTSupWet) + "Superheating temperature differential"; + + // Energy transfer + Modelica.Units.SI.SpecificEnergy qEva = hPumOut - hExpInl + "Evaporator specific energy transfer into the cycle"; + Modelica.Units.SI.SpecificEnergy qCon = hExpOut - hPumInl + "Condenser specific energy transfer out of the cycle"; + Modelica.Units.SI.SpecificEnergy wExp = hExpOut - hExpInl + "Expander specific work"; + Modelica.Units.SI.SpecificEnergy wPum = (pEva - pCon) / (rhoLiq * etaPum) + "Pump specific work"; + Modelica.Units.SI.Efficiency etaThe(min=0) = + (wExp + wPum) / qEva "Thermal efficiency"; + +protected + Modelica.Units.SI.SpecificEnthalpy h_reg = hExpOutDry - hSatVapCon + "For regularisation; if > 0, dry cycle"; + + // Intermediate property computation + // 1. Dry cycle + // expander inlet = saturated vapor at evaporating pressure (known), + // expander outlet = superheated vapor at condensing pressure (solved). + Modelica.Units.SI.SpecificEntropy sExpOutDryIse = sSatVapEva + "Specific entropy at isentropic expander outlet, assuming dry cycle"; + Modelica.Units.SI.SpecificEnthalpy hExpOutDryIse( + displayUnit = "kJ/kg") = + if sExpOutDryIse > sSatVapCon + then (hRefCon - hSatVapCon) * (sExpOutDryIse - sSatVapCon) + / (sRefCon - sSatVapCon) + hSatVapCon + else (hSatVapCon - hPumInl) * (sExpOutDryIse - sPumInl) + / (sSatVapCon - sPumInl) + hPumInl + "Specific enthalpy at expander outlet, assuming dry cycle"; + Modelica.Units.SI.SpecificEnthalpy hExpOutDry( + displayUnit = "kJ/kg") = + hSatVapEva - (hSatVapEva - hExpOutDryIse) * etaExp + "Specific enthalpy at expander outlet, assuming dry cycle"; + // 2. Wet cycle + // expander inlet = superheated vapor at evaporating pressure (solved), + // expander outlet = saturated vapor at condensing pressure (known). + Modelica.Units.SI.SpecificEntropy sExpInlWetIse = sSatVapCon + "Specific entropy at isentropic expander inlet, assuming wet cycle"; + Modelica.Units.SI.SpecificEnthalpy hExpInlWetIse( + displayUnit = "kJ/kg") = + (hRefEva - hSatVapEva) * (sExpInlWetIse - sSatVapEva) + / (sRefEva - sSatVapEva) + hSatVapEva + "Specific enthalpy at expander inlet, assuming wet cycle"; + Modelica.Units.SI.SpecificEnthalpy hExpInlWet( + displayUnit = "kJ/kg") = + (hExpInlWetIse - hSatVapCon) * etaExp + hSatVapCon + "Specific enthalpy at expander inlet, assuming wet cycle"; + Modelica.Units.SI.TemperatureDifference dTSupWet( + displayUnit = "K") = + (hExpInlWet - hSatVapEva) * pro.dTRef / (hRefEva - hSatVapEva) + "Superheating temperature differential, assuming wet cycle"; + + // Derivatives + final parameter Real pDer_T[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.T, + y = pro.p, + ensureMonotonicity = true) + "Derivative of saturation pressure vs. saturation temperature for cubic spline"; + final parameter Real rhoLiqDer_T[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.T, + y = pro.rhoLiq, + ensureMonotonicity = true) + "Derivative of saturated liquid density vs. temperature for cubic spline"; + final parameter Real sSatLiqDer_T[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.T, + y = pro.sSatLiq, + ensureMonotonicity = true) + "Derivative of saturated liquid entropy vs. temperature for cubic spline"; + final parameter Real sSatVapDer_T[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.T, + y = pro.sSatVap, + ensureMonotonicity = false) + "Derivative of saturated vapor entropy vs. temperature for cubic spline"; + final parameter Real sRefDer_p[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.p, + y = pro.sRef, + ensureMonotonicity = false) + "Derivative of reference entropy vs. pressure for cubic spline"; + final parameter Real hSatLiqDer_T[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.T, + y = pro.hSatLiq, + ensureMonotonicity = true) + "Derivative of saturated liquid enthalpy vs. temperature for cubic spline"; + final parameter Real hSatVapDer_T[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.T, + y = pro.hSatVap, + ensureMonotonicity = false) + "Derivative of saturated vapor enthalpy vs. temperature for cubic spline"; + final parameter Real hRefDer_p[pro.n]= + IBPSA.Utilities.Math.Functions.splineDerivatives( + x = pro.p, + y = pro.hRef, + ensureMonotonicity = false) + "Derivative of reference enthaly vs. pressure for cubic spline"; + + annotation (defaultComponentName="cyc", + Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + fillColor={135,135,135}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Line( + points={{-60,-60},{-28,-20},{16,32},{40,60},{52,60},{54,30},{48,2},{52, + -38},{58,-58}}, + color={255,255,255}, + smooth=Smooth.Bezier, + thickness=0.5), + Line( + points={{6,20},{52,20},{66,-6},{50,-18},{-26,-18},{-24,-6},{6,20}}, + color={255,255,255}, + thickness=0.5, + pattern=LinePattern.Dash), + Line(points={{-66,61},{-66,-78}}, color={255,255,255}), + Polygon( + points={{-66,73},{-74,51},{-58,51},{-66,73}}, + lineColor={255,255,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Polygon( + points={{63,-67},{41,-59},{41,-75},{63,-67}}, + lineColor={255,255,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line(points={{-80,-67},{57,-67}}, color={255,255,255}), + Text( + extent={{-100,100},{-64,58}}, + textColor={255,255,255}, + textString="T"), + Text( + extent={{64,-58},{100,-100}}, + textColor={255,255,255}, + textString="s"), + Text( + extent={{-151,-100},{149,-140}}, + textColor={0,0,255}, + textString="%name")}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +

+This model performs the property interpolations of a given working fluid. +See the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +for more details. +", revisions=" +

+")); +end InterpolateStates; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/DryFluid.mo b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/DryFluid.mo new file mode 100644 index 0000000000..e4bdda432e --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/DryFluid.mo @@ -0,0 +1,47 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.Validation; +model DryFluid + "Organic Rankine cycle with a dry working fluid" + extends Modelica.Icons.Example; + + parameter Modelica.Units.SI.ThermodynamicTemperature TEva = 450 + "Evaporating temperature"; + parameter Modelica.Units.SI.ThermodynamicTemperature TCon = 310 + "Condensing temperature"; + parameter Modelica.Units.SI.Efficiency etaExp = 0.85 + "Expander efficiency"; + parameter Modelica.Units.SI.Efficiency etaPum = 0.7 + "Pump efficiency"; + + IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.InterpolateStates cyc( + final pro = pro, + final TEva = TEva, + final TCon = TCon, + final etaExp = etaExp, + final etaPum = etaPum) "Interpolate working fluid states in the cycle" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + replaceable parameter + IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids.Toluene pro + constrainedby IBPSA.Fluid.CHPs.OrganicRankine.Data.Generic + "Property record of the working fluid" + annotation (Placement(transformation(extent={{60,60},{80,80}})), + choicesAllMatching=true); + +annotation(experiment(StopTime=1, Tolerance=1e-6), + __Dymola_Commands(file="modelica://IBPSA/Resources/Scripts/Dymola/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/DryFluid.mos" + "Simulate and plot"), + Documentation(info=" +

+This model validates the basic use of + +IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.InterpolateStates. +

+",revisions=" + +")); +end DryFluid; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/WetFluid.mo b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/WetFluid.mo new file mode 100644 index 0000000000..b30755ddbf --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/WetFluid.mo @@ -0,0 +1,33 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.Validation; +model WetFluid + "Organic Rankine cycle with a wet working fluid" + extends + IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.Validation.DryFluid( + TEva = 350, + redeclare parameter + IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids.R134a pro); +annotation (experiment(StopTime=1, Tolerance=1e-6), + __Dymola_Commands(file="modelica://IBPSA/Resources/Scripts/Dymola/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/WetFluid.mos" + "Simulate and plot"), + Documentation(info=" +

+This model is largely the same as + +IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.Validation.DryFluid, +except that it validates the handling of wet working fluids. +As a result, a superheating temperature is computed that ensures +the expansion does not land under the dome. +How this superheating temperature is found is explained in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation. +

+",revisions=" + +")); +end WetFluid; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/package.mo new file mode 100644 index 0000000000..9eb6745516 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/package.mo @@ -0,0 +1,9 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses; +package Validation "Package for validation models" + extends Modelica.Icons.ExamplesPackage; + annotation (Documentation(info=" +

+Package for validation models for the base classes. +

+")); +end Validation; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/package.order new file mode 100644 index 0000000000..bfd2d4d207 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/Validation/package.order @@ -0,0 +1,2 @@ +DryFluid +WetFluid diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/package.mo new file mode 100644 index 0000000000..9395391a20 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/package.mo @@ -0,0 +1,9 @@ +within IBPSA.Fluid.CHPs.OrganicRankine; +package BaseClasses "Package with base classes" + extends Modelica.Icons.BasesPackage; + annotation (Documentation(info=" +

+Package for base classes. +

+")); +end BaseClasses; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/package.order new file mode 100644 index 0000000000..52d5e32f17 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/BaseClasses/package.order @@ -0,0 +1,3 @@ +FixedEvaporating +InterpolateStates +Validation diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/ConstantEvaporation.mo b/IBPSA/Fluid/CHPs/OrganicRankine/ConstantEvaporation.mo new file mode 100644 index 0000000000..3e051e3624 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/ConstantEvaporation.mo @@ -0,0 +1,504 @@ +within IBPSA.Fluid.CHPs.OrganicRankine; +model ConstantEvaporation "Organic Rankine cycle as a bottoming cycle" + + extends IBPSA.Fluid.Interfaces.FourPortHeatMassExchanger( + final m1_flow_nominal = mHot_flow_nominal, + final dp1_nominal = dpHot_nominal, + final m2_flow_nominal = mCol_flow_nominal, + final dp2_nominal = dpCol_nominal, + energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, + T1_start = max(pro.T)*2/3 + min(pro.T)*1/3, + T2_start = max(pro.T)*1/10 + min(pro.T)*9/10, + redeclare final IBPSA.Fluid.MixingVolumes.MixingVolume vol2( + V=m2_flow_nominal*tau2/rho2_nominal, + nPorts=2, + final prescribedHeatFlowRate=true), + final vol1( + final prescribedHeatFlowRate=true)); + + replaceable parameter IBPSA.Fluid.CHPs.OrganicRankine.Data.Generic pro + constrainedby IBPSA.Fluid.CHPs.OrganicRankine.Data.Generic + "Property records of the working fluid" + annotation(choicesAllMatching = true,Dialog(group="Cycle")); + parameter Modelica.Units.SI.MassFlowRate mHot_flow_nominal + "Nominal mass flow rate of the evaporator fluid" + annotation(Dialog(group="Evaporator")); + parameter Modelica.Units.SI.PressureDifference dpHot_nominal( + displayUnit="Pa") + "Nominal pressure drop of the hot fluid in evaporator" + annotation(Dialog(group="Evaporator")); + parameter Modelica.Units.SI.TemperatureDifference dTPinEva_set( + final min = 0) = 5 + "Set evaporator pinch point temperature difference" + annotation(Dialog(group="Evaporator")); + parameter Boolean useEvaporatingPressure = false + "Set true to specify working fluid evaporating pressure instead of temperature" + annotation(Dialog(group="Evaporator")); + parameter Modelica.Units.SI.ThermodynamicTemperature TWorEva = + max(pro.T)*2/3 + min(pro.T)*1/3 + "Evaporating temperature of the working fluid" + annotation(Dialog(group="Evaporator", enable = not useEvaporatingPressure)); + parameter Modelica.Units.SI.Pressure pWorEva(displayUnit="kPa") = + max(pro.p)*2/3 + min(pro.p)*1/3 + "Evaporating pressure of the working fluid" + annotation(Dialog(group="Evaporator", enable = useEvaporatingPressure)); + parameter Modelica.Units.SI.MassFlowRate mCol_flow_nominal + "Nominal mass flow rate of the condenser fluid" + annotation(Dialog(group="Condenser")); + parameter Modelica.Units.SI.PressureDifference dpCol_nominal( + displayUnit="Pa") + "Nominal pressure drop of the cold fluid in condenser" + annotation(Dialog(group="Condenser")); + parameter Modelica.Units.SI.TemperatureDifference dTPinCon( + final min = 0) = 10 + "Condenser pinch point temperature difference" + annotation(Dialog(group="Condenser")); + parameter Boolean useLowCondenserPressureWarning = true + "If true, issues warning if pCon < 101325 Pa" + annotation(Dialog(group="Condenser")); + parameter Modelica.Units.SI.MassFlowRate mWor_flow_max( + final min = 0) + "Upper bound of working fluid flow rate" + annotation(Dialog(group="Cycle")); + parameter Modelica.Units.SI.MassFlowRate mWor_flow_min( + final min = 0) + "Lower bound of working fluid flow rate" + annotation(Dialog(group="Cycle")); + parameter Modelica.Units.SI.MassFlowRate mWor_flow_hysteresis + = mWor_flow_min + (mWor_flow_max - mWor_flow_min) * 0.1 + "Hysteresis for turning off the cycle when flow too low" + annotation(Dialog(group="Cycle")); + parameter Modelica.Units.SI.Efficiency etaExp + "Expander efficiency" + annotation(Dialog(group="Cycle")); + parameter Modelica.Units.SI.Efficiency etaPum + "Pump efficiency" + annotation(Dialog(group="Cycle")); + + Modelica.Blocks.Interfaces.BooleanInput ena + "Enable cycle; set false to force working fluid flow to zero" annotation ( + Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-120,-10},{-100,10}}))); + + Modelica.Blocks.Interfaces.RealOutput PExp( + final quantity="Power", + final unit="W") "Expander power generation" + annotation (Placement( + transformation(extent={{100,10},{140,50}}), iconTransformation(extent={{100,20}, + {120,40}}))); + Modelica.Blocks.Interfaces.RealOutput QEva_flow( + final quantity="HeatFlowRate", + final unit="W") "Evaporator heat flow rate into the cycle" annotation ( + Placement(transformation(extent={{100,70},{140,110}}),iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={110,90}))); + Modelica.Blocks.Interfaces.RealOutput QCon_flow( + final quantity="HeatFlowRate", + final unit="W") "Condenser heat flow rate out of the cycle" annotation ( + Placement(transformation(extent={{100,-110},{140,-70}}), + iconTransformation(extent={{-10,-10},{10,10}}, + rotation=0, + origin={110,-90}))); + Modelica.Blocks.Interfaces.BooleanOutput on_actual(start = false) + "Actual on off status of the cycle" annotation (Placement(transformation( + extent={{100,-20},{140,20}}), iconTransformation(extent={{100,-10},{ + 120,10}}))); + Modelica.Blocks.Interfaces.RealOutput PPum( + final quantity="Power", + final unit="W") + "Electrical power consumption of the pump" annotation (Placement( + transformation(extent={{100,-50},{140,-10}}),iconTransformation(extent={{100,-40}, + {120,-20}}))); + + IBPSA.Fluid.CHPs.OrganicRankine.BaseClasses.FixedEvaporating cyc( + final pro=pro, + final mWor_flow_max=mWor_flow_max, + final mWor_flow_min=mWor_flow_min, + final mWor_flow_hysteresis=mWor_flow_hysteresis, + final TWorEva = + if useEvaporatingPressure + then IBPSA.Utilities.Math.Functions.smoothInterpolation( + x = pWorEva, + xSup = pro.p, + ySup = pro.T) + else TWorEva, + final dTPinEva_set=dTPinEva_set, + final dTPinCon=dTPinCon, + final cpHot=Medium1.specificHeatCapacityCp(sta1_nominal), + final cpCol=Medium2.specificHeatCapacityCp(sta2_nominal), + final etaExp=etaExp, + final etaPum=etaPum, + final useLowCondenserPressureWarning=useLowCondenserPressureWarning) + "Thermodynamic computations of the organic Rankine cycle" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + +protected + Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFloEva + "Prescribed heat flow rate" + annotation (Placement(transformation(extent={{39,30},{19,50}}))); + Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFloCon + "Prescribed heat flow rate" + annotation (Placement(transformation(extent={{41,-70},{21,-50}}))); + Modelica.Blocks.Sources.RealExpression expTHotIn(y=Medium1.temperature( + state=Medium1.setState_phX( + p=port_a1.p, + h=inStream(port_a1.h_outflow), + X=inStream(port_a1.Xi_outflow)))) + "Expression for evaporator hot fluid incoming temperature" + annotation (Placement(transformation(extent={{-60,20},{-40,40}}))); + Modelica.Blocks.Sources.RealExpression expMHot_flow(y=m1_flow) + "Expression for evaporator hot fluid flow rate" + annotation (Placement(transformation(extent={{-60,0},{-40,20}}))); + Modelica.Blocks.Sources.RealExpression expTColIn(y=Medium2.temperature( + state=Medium2.setState_phX( + p=port_a2.p, + h=inStream(port_a2.h_outflow), + X=inStream(port_a2.Xi_outflow)))) + "Expression for condenser cold fluid incoming temperature" + annotation (Placement(transformation(extent={{-60,-20},{-40,0}}))); + Modelica.Blocks.Sources.RealExpression expMCol_flow(y=m2_flow) + "Expression for condenser cold fluid flow rate" + annotation (Placement(transformation(extent={{-60,-40},{-40,-20}}))); +equation + connect(preHeaFloEva.port, vol1.heatPort) annotation (Line(points={{19,40},{-16, + 40},{-16,60},{-10,60}}, color={191,0,0})); + connect(preHeaFloCon.port, vol2.heatPort) annotation (Line(points={{21,-60},{12, + -60}}, color={191,0,0})); + connect(expTHotIn.y, cyc.THotIn) annotation (Line(points={{-39,30},{-20,30},{-20, + 8},{-11,8}}, color={0,0,127})); + connect(expMHot_flow.y, cyc.mHot_flow) annotation (Line(points={{-39,10},{-30, + 10},{-30,4},{-11,4}}, color={0,0,127})); + connect(expTColIn.y, cyc.TColIn) annotation (Line(points={{-39,-10},{-30,-10}, + {-30,-4},{-11,-4}}, color={0,0,127})); + connect(expMCol_flow.y, cyc.mCol_flow) annotation (Line(points={{-39,-30},{-20, + -30},{-20,-8},{-11,-8}}, color={0,0,127})); + connect(cyc.PExp,PExp) annotation (Line(points={{11,4},{84,4},{84,30},{120,30}}, + color={0,0,127})); + connect(ena, cyc.ena) + annotation (Line(points={{-120,0},{-11,0}}, color={255,0,255})); + connect(cyc.QEva_flow, QEva_flow) annotation (Line(points={{11,8},{80,8},{80,90}, + {120,90}}, color={0,0,127})); + connect(cyc.QCon_flow, QCon_flow) annotation (Line(points={{11,-8},{80,-8},{ + 80,-70},{96,-70},{96,-90},{120,-90}}, + color={0,0,127})); + connect(cyc.on_actual, on_actual) annotation (Line(points={{11,0},{120,0}}, + color={255,0,255})); + connect(cyc.PPum, PPum) annotation (Line(points={{11,-4},{84,-4},{84,-30},{120, + -30}}, color={0,0,127})); + connect(cyc.QEva_flow, preHeaFloEva.Q_flow) + annotation (Line(points={{11,8},{80,8},{80,40},{39,40}}, color={0,0,127})); + connect(cyc.QCon_flow, preHeaFloCon.Q_flow) annotation (Line(points={{11,-8}, + {80,-8},{80,-60},{41,-60}}, color={0,0,127})); + annotation (defaultComponentName = "orc", + Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{-60,-60},{-28,-20},{16,32},{40,60},{52,60},{54,30},{48,2},{ + 52,-38},{58,-58}}, + color={255,255,255}, + smooth=Smooth.Bezier, + thickness=0.5), + Line( + points={{6,20},{52,20},{66,-6},{50,-18},{-26,-18}}, + color={255,255,255}, + thickness=0.5, + pattern=LinePattern.Dash)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), +Documentation(info=" +

+Model of an organic Rankine cycle (ORC) as a bottoming cycle. +

+

+The thermodynamic cycle is steady-state while the evaporator and the condenser +can be configured to have first order dynamics. +The fluid stream 1 (using Medium1, port_a1, etc.) +is the evaporator hot fluid, e.g., waste heat, +and the stream 2 is the condenser cold fluid. +The working fluid of the cycle is not based on a typical Modelica medium model. +See the Thermodynamic Properties section of this document for the rational. +

+

Cycle Architecture and Governing Equations

+

+The implemented ORC is modeled based on the simplified cycle shown in the figure below. +The cycle has two variants depending on the shape of the saturation lines of +the working fluid and ηexp. +For any given working fluid, the cycle is fully determined by providing +the working fluid evaporating temperature Tw,eva, +the working fluid condensing temperature Tw,con, +the expander efficiency ηexp, and +the pump efficiency ηpum. +The superheating temperature difference ΔTsup +is minimized, meaning it is zero whenever possible; otherwise it assumes +the smallest value not to cause the expander outlet state to fall +under the two-phase region, i.e. the \"dome\". +Subcooling after the condenser is not considered. +The Thermodynamic Properties section of this document details how these +state points are found. +

+

+An important assumption is that all heat is dissipated, i.e., +the cycle is not controlled by thermal load. +

+

+

+

+The cycle processes the heat at a fixed +Tw,eva provided by the user. +The evaporator heat exchange is governed by +

+

+Q̇eva = ṁh cp,h (Th,out - Th,in),
+Q̇eva = ṁw (hpum,out - hexp,in), +

+

+where the subscripts are +eva for evaporator, +exp for expander, +h for hot fluid of the evaporator, i.e. the fluid carrying heat, +pum for pump, and +w for working fluid. +

+

+The cycle accommodates the variable flow rate and temperature +of the waste heat stream by changing the working fluid mass flow rate w +to maintain a constant pinch point (PP) temperature difference +at the evaporator ΔTpin,eva. +This difference is found from +

+

+(Tpin,eva - Th,out) (hexp,in - hpum,out) += (Th,in - Th,out) (heva,pin - hpum,out),
+ΔTpin,eva = Tpin,eva - Tw,eva. +

+

+The condenser side uses the same equations with the evaporator variables +replaced by their condenser counterparts where appropriate. Hence, +

+

+Q̇con = ṁc cp,c (Tc,out - Tc,in),
+Q̇con = ṁw (hpum,in - hexp,out),
+(Tc,pin - Tc,in) (hexp,out - hpum,in) += (Tc,out - Tc,in) (hcon,pin - hpum,in),
+ΔTcon,pin = Tw,con - Tc,pin, +

+

+where the subscripts are +con for condenser, and +c for cold fluid in the condenser.
+

+

+The electric power output of the expander is +

+

+Pexp = ṁw (hexp,in - hexp,out). +

+

+The electric power consumption of the pump is +

+

+Ppum = ṁw (hpum,out - hpum,in). +

+

+The pump work is +

+

+Ppum = ṁw  +(peva - pcon) / (ρpum,in ηpum). +

+

+This takes advantage of the negligible density change of the liquid +to avoid a property search in the subcooled liquid region. +

+

+In summary, the model has the following information flow: +

+ + + + + + + + + + + +
User-specified parametersInputsOutputs
+Tw,eva - Working fluid evaporating temperature,
+ΔTpin,eva - Evaporator pinch point temperature difference,
+ΔTpin,con - Condenser pinch point temperature difference,
+ηexp - Expander efficiency,
+ηpum - Pump efficiency. +
+Th,in - Evaporator hot fluid incoming temperature,
+h - Evaporator hot fluid flow rate,
+Tc,in - Condenser cold fluid incoming temperature,
+c - Condenser cold fluid flow rate. +
+w - Working fluid flow rate,
+Tw,con - Working fluid condensing temperature,
+Th,out - Evaporator hot fluid outgoing temperature,
+Tc,out - Condenser cold fluid outgoing temperature,
+eva - Evaporator heat flow rate,
+con - Condenser heat flow rate,
+Pexp - Expander power output,
+Ppum - Pump power consumption. +
+

Constraints

+

+The ORC system controls w to maintain the prescribed +evaporator PP temperature difference set point. +Although the model does not implement this as a control loop, +an upper limit and a lower limit are imposed on +w to reflect the capacity constraints of a sized cycle. +

+ +

+How these constraints affect the cycle's behavior reacting to +a variable waste heat fluid stream is demonstrated in + +IBPSA.Fluid.CHPs.OrganicRankine.Validation.VariableSource. +

+

Thermodynamic Properties

+

+The thermodynamic properties of the working fluid are not computed by a typical +Modelica medium model, but by interpolating data records in + +IBPSA.Fluid.CHPs.OrganicRankine.Data. +Specific enthalpy and specific entropy values are provided as support points +on the saturated liquid line, the saturated vapor line, and +a superheated vapor line (called the reference line). +The values of these support points were obtained using CoolProp +(https://www.coolprop.org; +Bell et al., 2014) through its Python wrapper and stored as Modelica records. +An example Python file is provided in +IBPSA/Resources/Python-Sources/MakeORCFluidRecord.py, +but note that this file is not maintained. +The records included in this library have ten data points for each line. +It is recommended to have at least four points to take full advantage of +the cubit Hermite spline interpolation that is set up in this model. +

+

+Thermodynamic state points in the cycle are determined by various schemes +of interpolation and extrapolation. +

+

+

+ +

+The cycle can be completely defined by providing the following quantities: +evaporating temperature Teva or pressure peva, +condensing temperature Tcon or pressure pcon, +expander efficiency ηexp, and +pump efficiency ηpum. +Most of the important state points can be found via the interpolation schemes +described above. The only exceptions are the expander inlet, expander outlet, +and the pump outlet. +

+

+

+ +

Implementation

+The user can parameterise the evaporating condition by providing either the +evaporating temperature TWorEva or the evaporating pressure +pWorEva. To support this, a default parameter assignment is +provided to both. Otherwise there would be unassigned parameters even though +they are not needed. +

References

+

+Bell IH, Wronski J, Quoilin S, Lemort V. +Pure and pseudo-pure fluid thermophysical property evaluation and the open-source thermophysical property library CoolProp. +Industrial & engineering chemistry research. + +2014 Feb 12;53(6):2498-508. +https://doi.org/10.1021/ie4033999 +

+", revisions=" + +")); +end ConstantEvaporation; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/Generic.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/Generic.mo new file mode 100644 index 0000000000..3c06937ad1 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/Generic.mo @@ -0,0 +1,40 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data; +record Generic "Generic data record for working fluid properties" + extends Modelica.Icons.Record; + + parameter Modelica.Units.SI.ThermodynamicTemperature T[:] + "Thermodynamic temperature"; + parameter Modelica.Units.SI.AbsolutePressure p[n] + "Saturation pressure"; + parameter Modelica.Units.SI.Density rhoLiq[n] + "Density of saturated liquid"; + parameter Modelica.Units.SI.TemperatureDifference dTRef + "Superheating temperature difference"; + parameter Modelica.Units.SI.SpecificEntropy sSatLiq[n] + "Specific entropy of saturated liquid"; + parameter Modelica.Units.SI.SpecificEntropy sSatVap[n] + "Specific entropy of saturated vapor"; + parameter Modelica.Units.SI.SpecificEntropy sRef[n] + "Specific entropy of superheated vapor reference line"; + parameter Modelica.Units.SI.SpecificEnthalpy hSatLiq[n] + "Specific enthalpy of saturated liquid"; + parameter Modelica.Units.SI.SpecificEnthalpy hSatVap[n] + "Specific enthalpy of saturated vapor"; + parameter Modelica.Units.SI.SpecificEnthalpy hRef[n] + "Specific enthalpy of superheated vapor reference line"; + + final parameter Integer n = size(T,1) + "Array length"; +annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing parameters for working fluid properties. +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Generic; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Acetone.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Acetone.mo new file mode 100644 index 0000000000..fb4f3c0a26 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Acetone.mo @@ -0,0 +1,58 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record Acetone "Data record for acetone" + extends Generic( + T = { + 263.15 ,289.255555556,315.361111111,341.466666667, + 367.572222222,393.677777778,419.783333333,445.888888889, + 471.994444444,498.1 }, + p = { + 5344.990110825, 20650.833566074, 61555.897854858, + 151351.563616118, 321797.046994737, 612178.548912226, + 1068684.448400072,1745219.888869215,2707418.650799205, + 4046245.515470347}, + rhoLiq = { + 822.882971808,794.503127301,765.124111199,734.248636529, + 701.245557689,665.234774298,624.858127478,577.729019236, + 518.607501298,426.621585717}, + dTRef = 30, + sSatLiq = { + -479.028530758,-280.940806531, -94.928726727, 81.991049561, + 252.145020847, 417.505066333, 580.003385303, 742.022980174, + 907.767378748,1092.563132257}, + sSatVap = { + 1681.191059012,1596.661258221,1542.5487283 ,1510.043720587, + 1492.612391749,1484.868192175,1481.705802931,1477.167997198, + 1461.519799448,1404.254266854}, + sRef = { + 1817.036318829,1731.286422698,1677.739234558,1647.046003462, + 1632.468103167,1628.870285847,1632.074409953,1638.412725056, + 1644.396794592,1646.431943962}, + hSatLiq = { + -141608.840175549, -86907.602970965, -30644.702178538, + 27561.220566805, 88109.595870881, 151467.211307906, + 218265.291981649, 289522.609167944, 367363.173547648, + 459910.837559632}, + hSatVap = { + 426852.944874144,456199.225381078,485752.007459114, + 515193.605967011,544070.943987246,571664.354771464, + 596784.938528286,617315.603980879,628731.239715757, + 615164.191702174}, + hRef = { + 464617.330003106,497136.67139577 ,530386.531973482, + 563997.6626978 ,597536.243125905,630465.696202391, + 662097.963586358,691534.659141209,717607.015924844, + 738837.945805182}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of acetone. +Its name in CoolProp is \"Acetone\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Acetone; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Ethanol.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Ethanol.mo new file mode 100644 index 0000000000..61427d8ba1 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Ethanol.mo @@ -0,0 +1,56 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record Ethanol "Data record for ethanol" + extends Generic( + T = { + 263.15,289.99,316.83,343.67,370.51,397.35,424.19,451.03,477.87, + 504.71}, + p = { + 7.689358061e+02,4.849943515e+03,2.156311297e+04,7.357097999e+04, + 2.046081847e+05,4.845344677e+05,1.008761409e+06,1.891911004e+06, + 3.263511383e+06,5.282165193e+06}, + rhoLiq = { + 814.799753232,792.036393251,768.756136609,744.093991385, + 716.886637425,685.51349857 ,647.811686098,601.669643931, + 543.369863156,438.527983321}, + dTRef = 30, + sSatLiq = { + -726.973851775,-505.583513991,-286.35608663 , -65.626950104, + 159.007283346, 389.527126652, 627.103332946, 869.931756177, + 1118.157181986,1411.006366334}, + sSatVap = { + 2902.952478464,2699.032398467,2551.227443872,2442.903267896, + 2361.504494341,2297.490986936,2243.294159242,2191.508999328, + 2129.791721023,2005.324094606}, + sRef = { + 3048.947765906,2841.665343912,2692.531793967,2585.157296558, + 2507.385719926,2450.24466807 ,2407.200424972,2373.310666428, + 2343.951307193,2312.828603679}, + hSatLiq = { + -223584.403049121,-162359.292050491, -95822.158648172, + -22850.994379185, 57554.398921637, 146473.200208431, + 244865.515469934, 352554.405086509, 470265.911621738, + 618471.162521627}, + hSatVap = { + 731630.710753397,766947.276403163,803209.431320732, + 839255.585640969,873601.64056746 ,904602.640092255, + 930437.502076461,948625.389064672,953695.708791375, + 918429.263157366}, + hRef = { + 772225.371527353, 810437.156029444, 850086.320725499, + 890262.545389702, 929818.501889787, 967557.529390266, + 1002370.800231913,1033259.201313757,1059056.681099724, + 1077479.396060467}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of ethanol. +Its name in CoolProp is \"Ethanol\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Ethanol; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Heptane.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Heptane.mo new file mode 100644 index 0000000000..3e56924888 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Heptane.mo @@ -0,0 +1,57 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record Heptane "Data record for n-heptane" + extends Generic( + T = { + 263.15 ,292.814444444,322.478888889,352.143333333, + 381.807777778,411.472222222,441.136666667,470.801111111, + 500.465555556,530.13 }, + p = { + 7.989173434e+02,4.640431854e+03,1.836462559e+04,5.521023193e+04, + 1.357341530e+05,2.872627666e+05,5.428996069e+05,9.414295237e+05, + 1.530128640e+06,2.375428955e+06}, + rhoLiq = { + 708.744161335,684.005361466,658.664692095,632.281562559, + 604.301119943,573.933259524,539.893343103,499.714554172, + 447.233450033,353.248453405}, + dTRef = 30, + sSatLiq = { + -796.989852616,-565.365137693,-345.670277761,-134.519732505, + 70.367270161, 270.657778517, 467.830116908, 663.725205376, + 861.998498724,1078.641393707}, + sSatVap = { + 672.954567605, 692.831668803, 739.301918155, 803.885808983, + 880.494448383, 964.465721538,1051.759799165,1137.935524319, + 1215.655239687,1260.938470215}, + sRef = { + 841.855369762, 858.118161463, 902.502690963, 966.060882441, + 1042.44988716 ,1127.000908946,1216.047379616,1306.364617459, + 1394.627619853,1477.085968924}, + hSatLiq = { + -251949.774148952,-187591.55369971 ,-120007.324894362, + -48744.573432347, 26561.273589323, 106252.748227298, + 190762.393341302, 280852.494718802, 378399.475308805, + 492237.654496714}, + hSatVap = { + 134866.100032261,180826.645196058,229873.303319793, + 281708.681968285,335874.131225473,391735.444337536, + 448355.186941404,504111.239777487,555392.492651129, + 588878.803666001}, + hRef = { + 181833.569133815,231695.382441082,284942.600720626, + 341242.380998298,400129.988352552,461040.039711463, + 523275.529594887,585905.759075288,647581.728725064, + 706410.769546266}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of n-heptane. +Its name in CoolProp is \"n-Heptane\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Heptane; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Pentane.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Pentane.mo new file mode 100644 index 0000000000..487640a3b1 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Pentane.mo @@ -0,0 +1,58 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record Pentane "Data record for n-pentane (R601)" + extends Generic( + T = { + 263.15 ,284.988888889,306.827777778,328.666666667, + 350.505555556,372.344444444,394.183333333,416.022222222, + 437.861111111,459.7 }, + p = { + 15196.961880746, 40847.01461526 , 93347.760875795, + 188229.761547615, 344161.604577882, 582381.684493329, + 926479.361144566,1402869.463375476,2042636.912945348, + 2888164.842888385}, + rhoLiq = { + 654.994012423,634.140752869,612.406165595,589.474257693, + 564.920053506,538.129125681,508.125336463,473.116841092, + 428.954697374,359.39054261 }, + dTRef = 30, + sSatLiq = { + -364.770358607,-188.383459065, -18.245572622, 147.200487718, + 309.214016986, 468.928951023, 627.576629898, 786.91058507 , + 950.457609042,1131.212144756}, + sSatVap = { + 1124.757616955,1132.064676189,1153.78271919 ,1185.735649416, + 1224.628540081,1267.744136879,1312.410414419,1355.214297416, + 1390.117806445,1397.022012012}, + sRef = { + 1296.158077524,1301.28713228 ,1321.950521732,1353.859341364, + 1393.796088528,1439.208143314,1487.913190685,1537.898827489, + 1587.138246557,1633.295767519}, + hSatLiq = { + -104421.898943934, -56052.79734228 , -5633.016486273, + 47087.837000979, 102370.736056908, 160525.092863763, + 221987.014134065, 287509.248703003, 358766.967642045, + 442086.536306975}, + hSatVap = { + 287547.387825234,320260.24955903 ,353977.819783112, + 388419.726812333,423228.612037831,457959.489455307, + 491937.078095822,523936.222010323,551277.070188378, + 564279.332284564}, + hRef = { + 335209.266682762,371013.610228284,408087.525730008, + 446185.930365794,485045.348695265,524354.800753776, + 563719.721538978,602626.895309489,640395.197254024, + 676083.07721731 }); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of n-pentane (R601). +Its name in CoolProp is \"n-Pentane\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Pentane; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Propane.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Propane.mo new file mode 100644 index 0000000000..e092686f71 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Propane.mo @@ -0,0 +1,58 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record Propane "Data record for propane (R290)" + extends Generic( + T = { + 263.15 ,273.898888889,284.647777778,295.396666667, + 306.145555556,316.894444444,327.643333333,338.392222222, + 349.141111111,359.89 }, + p = { + 345279.941449901, 485400.605038304, 664016.115440719, + 887052.541165123,1160724.363224234,1491611.619687285, + 1886825.956981318,2354347.829390035,2903681.060029375, + 3547408.027345188}, + rhoLiq = { + 541.798297226,527.579836833,512.585365108,496.632038772, + 479.466931165,460.721062294,439.816371148,415.748472388, + 386.451358179,346.106437325}, + dTRef = 30, + sSatLiq = { + 908.965062614,1006.779440037,1103.648845716,1200.001618811, + 1296.323530695,1393.220337369,1491.541227233,1592.663453966, + 1699.311221116,1819.013862619}, + sSatVap = { + 2384.567612711,2371.574136657,2361.266030228,2352.732953327, + 2345.022612092,2337.032274329,2327.310860571,2313.560971451, + 2291.337848494,2249.306043938}, + sRef = { + 2566.79611772 ,2555.493081644,2547.750842968,2542.843699325, + 2540.115085679,2538.952119832,2538.763840737,2538.951963132, + 2538.886989404,2537.853328788}, + hSatLiq = { + 175348.350832337,201875.066749143,229271.052773913, + 257657.444992465,287189.506335636,318079.809438811, + 350645.399680575,385417.4820846 ,423455.88738496 , + 467665.980896495}, + hSatVap = { + 563653.161890421,575690.817715341,587248.989642776, + 598170.43877048 ,608244.069220794,617168.568861843, + 624479.74824603 ,629363.595020986,630156.721875167, + 622523.83403136 }, + hRef = { + 614311.232841951,628792.518193016,643090.993507643, + 657134.020145737,670838.112039704,684105.52633736 , + 696821.020909884,708845.675908959,720012.482475496, + 730115.169718242}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of propane (R290). +Its name in CoolProp is \"Propane\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Propane; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R123.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R123.mo new file mode 100644 index 0000000000..423a9d7632 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R123.mo @@ -0,0 +1,57 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record R123 "Data record for R123" + extends Generic( + T = { + 263.15 ,283.559,303.968,324.377,344.786,365.195,385.604,406.013, + 426.422,446.831}, + p = { + 20246.950661932, 51440.14631405 , 112811.739858567, + 220592.87790875 , 394048.867245572, 654989.103061425, + 1027610.766894902,1539001.458950504,2221087.046991277, + 3117580.036383462}, + rhoLiq = { + 1550.145747115,1500.60589786 ,1448.898149661,1394.435970728, + 1336.357791907,1273.304710472,1202.9813059 ,1121.108147556, + 1018.10852222 , 859.35313126 }, + dTRef = 30, + sSatLiq = { + 963.291211716,1037.235356603,1107.652872739,1175.077198776, + 1240.006769354,1302.97149577 ,1364.616830223,1425.874631908, + 1488.488045482,1558.197778977}, + sSatVap = { + 1667.453790836,1662.601605167,1663.373652146,1667.947333911, + 1674.895925087,1683.00895072 ,1691.101277177,1697.69913848 , + 1700.178917251,1689.912023319}, + sRef = { + 1737.810016884,1731.404036564,1730.991249439,1734.765535334, + 1741.355559816,1749.682490995,1758.849314222,1768.045202032, + 1776.452208741,1783.116337598}, + hSatLiq = { + 190149.271365683,210376.227418011,231098.48911094 , + 252352.625193384,274200.267099774,296749.550182631, + 320190.923599748,344878.267191074,371581.94622093 , + 402995.865537189}, + hSatVap = { + 375449.654061047,387704.455494463,400019.822985702, + 412228.361018181,424143.959548608,435537.32854304 , + 446084.632282771,455242.550578245,461851.591142172, + 461849.873050608}, + hRef = { + 395009.975047329,408236.58362893 ,421577.684105208, + 434894.002641602,448042.779209191,460871.335148106, + 473205.248708475,484829.998039268,495465.443515065, + 504727.638630622}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of R123. +Its name in CoolProp is \"R123\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end R123; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R134a.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R134a.mo new file mode 100644 index 0000000000..0265b1f00c --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R134a.mo @@ -0,0 +1,58 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record R134a "Data record for R134a" + extends Generic( + T = { + 263.15 ,274.378888889,285.607777778,296.836666667, + 308.065555556,319.294444444,330.523333333,341.752222222, + 352.981111111,364.21 }, + p = { + 200603.307472702, 306065.144055732, 449719.915074148, + 639730.094514731, 884904.588817354,1194757.011967908, + 1579685.738808544,2051381.787343061,2623740.847778454, + 3315235.242079038}, + rhoLiq = { + 1327.126163441,1290.706177259,1252.384215745,1211.660788636, + 1167.846607299,1119.946901702,1066.43367865 ,1004.714189346, + 929.529223158, 825.767527903}, + dTRef = 30, + sSatLiq = { + 950.647690901,1006.000704972,1060.270839535,1113.712093542, + 1166.611338723,1219.319709948,1272.312300214,1326.324896806, + 1382.758644761,1445.49325885 }, + sSatVap = { + 1733.350797261,1726.412875563,1721.041565618,1716.692460392, + 1712.816408039,1708.79575006 ,1703.835616881,1696.731056518, + 1685.221329816,1663.254186971}, + sRef = { + 1825.651782765,1819.26336679 ,1814.857399221,1811.970391363, + 1810.194406344,1809.157628299,1808.50662669 ,1807.888965926, + 1806.93261727 ,1805.200478092}, + hSatLiq = { + 186696.59112921 ,201653.015599322,216960.445937552, + 232677.402848669,248882.679090854,265687.289291076, + 283257.907432927,301870.718852068,322069.176904733, + 345362.177321903}, + hSatVap = { + 392664.913567861,399318.906508085,405681.704634567, + 411664.085009797,417149.647216853,421974.269587487, + 425886.432468616,428457.847058395,428832.791544889, + 424672.884952779}, + hRef = { + 418317.035128306,426163.587402212,433855.473474184, + 441342.371701698,448569.586759484,455475.412466164, + 461988.043511396,468022.071596944,473474.189346821, + 478212.639980691}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of R134a. +Its name in CoolProp is \"R134a\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end R134a; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R245fa.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R245fa.mo new file mode 100644 index 0000000000..74dda59b71 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R245fa.mo @@ -0,0 +1,58 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record R245fa "Data record for R245fa" + extends Generic( + T = { + 263.15 ,280.245555556,297.341111111,314.436666667, + 331.532222222,348.627777778,365.723333333,382.818888889, + 399.914444444,417.01 }, + p = { + 33074.455269577, 72887.366701788, 144193.124203996, + 261432.955364019, 441494.101343335, 703414.198474153, + 1068359.342462996,1560145.848431753,2206880.485192474, + 3045794.17123294 }, + rhoLiq = { + 1428.970464918,1385.766605559,1340.65562986 ,1293.01283556 , + 1241.96829885 ,1186.239888383,1123.767592805,1050.81390283 , + 959.216593671, 822.828460561}, + dTRef = 30, + sSatLiq = { + 956.193112483,1035.364417516,1111.944630847,1186.435838862, + 1259.293596381,1330.986299328,1402.082979051,1473.433817707, + 1546.692369155,1626.938235226}, + sSatVap = { + 1753.339480749,1752.701557681,1756.61081491 ,1763.705762957, + 1772.828904987,1782.876329527,1792.610957024,1800.320573857, + 1802.878905152,1791.348871671}, + sRef = { + 1843.301914471,1841.682942619,1845.068883248,1852.125571196, + 1861.778475563,1873.119878874,1885.336511854,1897.653409147, + 1909.296310246,1919.468376844}, + hSatLiq = { + 188217.135523087,209752.050428183,231916.973241534, + 254789.508127216,278461.658759156,303057.594061445, + 328767.54169158 ,355926.037457738,385245.530754186, + 418981.075267556}, + hSatVap = { + 397986.202332377,410782.595794416,423602.732706635, + 436304.338826503,448715.160811117,460599.011089822, + 471592.735555778,481064.462239284,487698.226971601, + 487541.954771701}, + hRef = { + 422999.193929367,437043.348637611,451220.086433009, + 465419.510903738,479522.71650364 ,493393.292575899, + 506866.898229809,519740.667011956,531767.47525367 , + 542662.050436945}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of R245fa. +Its name in CoolProp is \"R245fa\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end R245fa; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R32.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R32.mo new file mode 100644 index 0000000000..5d27e81c87 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/R32.mo @@ -0,0 +1,58 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record R32 "Data record for R32" + extends Generic( + T = { + 263.15 ,271.828333333,280.506666667,289.185 , + 297.863333333,306.541666667,315.22 ,323.898333333, + 332.576666667,341.255 }, + p = { + 582632.423455563, 779227.155447199,1022507.826631392, + 1319243.784536832,1676689.244070605,2102683.141551342, + 2605825.859299297,3195797.469126429,3883981.451679397, + 4684958.748097608}, + rhoLiq = { + 1088.762616995,1059.796758515,1029.295189956, 996.920197574, + 962.201981414, 924.453822345, 882.605293946, 834.832837403, + 777.582757731, 702.054968683}, + dTRef = 30, + sSatLiq = { + 936.52451307 , 991.659733916,1046.223239241,1100.490775854, + 1154.795359523,1209.572891273,1265.450416315,1323.441013333, + 1385.463021423,1456.23976066 }, + sSatVap = { + 2191.530923721,2159.130803487,2127.849016758,2097.105691514, + 2066.253567277,2034.508896214,2000.819981866,1963.579527028, + 1919.859591813,1862.561221543}, + sRef = { + 2304.157093291,2274.544797147,2246.748153968,2220.383262429, + 2195.095643776,2170.551795417,2146.430627551,2122.413280091, + 2098.166495379,2073.295617553}, + hSatLiq = { + 182764.696330276,197695.34939879 ,212996.704346489, + 228747.503919312,245052.432711042,262058.639462482, + 279988.045994578,299208.744263246,320424.342790452, + 345361.467556621}, + hSatVap = { + 513019.633293376,515047.064455002,516399.945778408, + 516953.588304626,516542.412668788,514935.89731114 , + 511791.24044753 ,506548.541951439,498152.172848862, + 484020.697690199}, + hRef = { + 544272.165701895,548069.095566735,551444.02060146 , + 554348.972337043,556731.55185084 ,558534.039175514, + 559692.26585121 ,560133.992100001,559775.669486533, + 558511.071672622}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of R32. +Its name in CoolProp is \"R32\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end R32; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Toluene.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Toluene.mo new file mode 100644 index 0000000000..97423305d3 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/Toluene.mo @@ -0,0 +1,56 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids; +record Toluene "Data record for toluene" + extends Generic( + T = { + 263.15,298.55,333.95,369.35,404.75,440.15,475.55,510.95,546.35, + 581.75}, + p = { + 4.658645382e+02,3.878506476e+03,1.913620075e+04,6.607278574e+04, + 1.775240880e+05,3.982149511e+05,7.826031771e+05,1.394511614e+06, + 2.312008822e+06,3.647284909e+06}, + rhoLiq = { + 894.591737923,861.787657162,828.382229573,793.747189122, + 757.123274828,717.4577212 ,673.073614045,620.835702655, + 553.321381336,437.838439728}, + dTRef = 30, + sSatLiq = { + -670.300584422,-462.345778557,-265.173474299, -75.486089983, + 108.735317728, 288.918011292, 466.37022759 , 642.81477669 , + 821.684991655,1017.475208721}, + sSatVap = { + 978.30668321 , 919.722310325, 907.690979281, 926.229656023, + 964.682067033,1015.530364113,1072.870878952,1130.921098435, + 1181.095766989,1195.352192032}, + sRef = { + 1091.412085347,1033.610736055,1022.489953315,1042.016294547, + 1081.594543273,1133.917046387,1193.599794878,1256.201212851, + 1317.428314692,1372.739080272}, + hSatLiq = { + -215928.299658583,-157558.83018377 , -95210.963812949, + -28467.959306084, 42965.246838653, 119373.480365183, + 201168.191553062, 289147.81263614 , 385288.937285889, + 498520.557921947}, + hSatVap = { + 217902.702818657,255057.597752471,296467.120460337, + 341515.751482012,389409.693620114,439191.907459599, + 489589.576308111,538545.73773166 ,581653.014389845, + 602000.492963232}, + hRef = { + 249364.004857819,290767.909737456,336525.499214213, + 386015.721699957,438478.677428664,493067.399188192, + 548799.919772023,604412.858652115,658123.631255034, + 707533.724749596}); + annotation ( + defaultComponentPrefixes = "parameter", + defaultComponentName = "pro", + Documentation(info=" +

+Record containing properties of toluene. +Its name in CoolProp is \"Toluene\". +A figure in the documentation of + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +shows which lines these arrays represent. +

+")); +end Toluene; \ No newline at end of file diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/package.mo new file mode 100644 index 0000000000..af0fe1a2ec --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/package.mo @@ -0,0 +1,9 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Data; +package WorkingFluids "Package with working fluid data" + extends Modelica.Icons.Package; + annotation (Documentation(info=" +

+Package for data records of specific working fluids. +

+")); +end WorkingFluids; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/package.order new file mode 100644 index 0000000000..a579853c54 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/WorkingFluids/package.order @@ -0,0 +1,10 @@ +Acetone +Ethanol +Heptane +Pentane +Propane +R123 +R134a +R245fa +R32 +Toluene diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Data/package.mo new file mode 100644 index 0000000000..66dbc9604a --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/package.mo @@ -0,0 +1,9 @@ +within IBPSA.Fluid.CHPs.OrganicRankine; +package Data "Package with working fluid data" + extends Modelica.Icons.MaterialPropertiesPackage; + annotation (Documentation(info=" +

+Package for data records of working fluids. +

+")); +end Data; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Data/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/Data/package.order new file mode 100644 index 0000000000..954861e71c --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Data/package.order @@ -0,0 +1,2 @@ +Generic +WorkingFluids diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Examples/ORCHotWater.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Examples/ORCHotWater.mo new file mode 100644 index 0000000000..2f9103521f --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Examples/ORCHotWater.mo @@ -0,0 +1,224 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Examples; +model ORCHotWater "ORC that outputs hot water at a fixed temperature" + extends Modelica.Icons.Example; + + package MediumHot = IBPSA.Media.Air "Evaporator hot fluid"; + package MediumCol = IBPSA.Media.Water "Condenser cold fluid"; + + parameter Modelica.Units.SI.MassFlowRate mHot_flow_nominal = 1 + "Nominal mass flow rate of evaporator hot fluid"; + parameter Modelica.Units.SI.MassFlowRate mCol_flow_nominal = 1.35 + "Nominal mass flow rate of condenser cold fluid"; + parameter Modelica.Units.SI.PressureDifference dpCon_nominal( + displayUnit = "Pa") = 10000 + "Nominal pressure drop across the ORC condenser"; + parameter Modelica.Units.SI.PressureDifference dpValCol_nominal( + displayUnit = "Pa") = 10000 + "Nominal pressure difference used for valves in the cold fluid loop"; + parameter Modelica.Units.SI.ThermodynamicTemperature TCol_start = 35 + 273.15 + "Start value for cold fluid temperature"; + + IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation orc( + redeclare final package Medium1 = MediumHot, + redeclare final package Medium2 = MediumCol, + T2_start=TCol_start, + redeclare IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids.R123 pro, + final mHot_flow_nominal=mHot_flow_nominal, + dTPinEva_set=5, + TWorEva=373.15, + pWorEva(displayUnit="bar"), + final mCol_flow_nominal=mCol_flow_nominal, + dpHot_nominal=0, + dpCol_nominal=0, + dTPinCon=5, + mWor_flow_max=0.5, + mWor_flow_min=0.1, + mWor_flow_hysteresis=0.05, + etaExp=0.8, + etaPum=0.6) "Organic Rankine cycle" + annotation (Placement(transformation(extent={{-40,-44},{-20,-24}}))); + + IBPSA.Fluid.Sources.MassFlowSource_T souHot( + redeclare final package Medium = MediumHot, + m_flow=mHot_flow_nominal, + T=423.15, + nPorts=1) "Evaporator hot fluid source" + annotation (Placement(transformation(extent={{-180,80},{-160,100}}))); + IBPSA.Fluid.Sources.Boundary_pT sinHot( + redeclare final package Medium = MediumHot, + nPorts=1) "Evaporator hot fluid sink" + annotation (Placement(transformation(extent={{120,80},{100,100}}))); + IBPSA.Controls.Continuous.LimPID conPI( + controllerType=Modelica.Blocks.Types.SimpleController.PI, + k=0.25, + Ti=30, + Ni=0.2, + initType=Modelica.Blocks.Types.Init.InitialOutput, + y_start=0, + reverseActing=false) "PI controller" + annotation (Placement(transformation(extent={{40,0},{60,20}}))); + Modelica.Blocks.Sources.Constant TWatOut_set(k=55 + 273.15) + "Set point of hot water output" + annotation (Placement(transformation(extent={{0,0},{20,20}}))); + IBPSA.Fluid.Sources.Boundary_pT colBou( + redeclare final package Medium = MediumCol, + use_T_in=true, + nPorts=2) "Cold fluid boundary conditions" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0,origin={110,-60}))); + IBPSA.Fluid.Sensors.TemperatureTwoPort senTWatSup( + redeclare final package Medium = MediumCol, + m_flow_nominal=mCol_flow_nominal, + T_start=TCol_start) + "Water supply temperature" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={70,-80}))); + IBPSA.Fluid.Sensors.TemperatureTwoPort senTWatRet( + redeclare final package Medium = MediumCol, + m_flow_nominal=mCol_flow_nominal, + T_start=TCol_start) + "Water return temperature" annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={70,-40}))); + Modelica.Blocks.Sources.TimeTable TWatRet( + y(final unit="K", displayUnit="degC"), + table=[0,35; 3,35; 6,45; 9,45], + timeScale=100, + offset=273.15) "Water return temperature values" + annotation (Placement(transformation(extent={{170,-70},{150,-50}}))); + IBPSA.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear val( + redeclare final package Medium = MediumCol, + energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, + T_start=TCol_start, + from_dp=false, + use_strokeTime=false, + final m_flow_nominal=mCol_flow_nominal, + final dpValve_nominal=dpValCol_nominal, + final dpFixed_nominal=fill(dpCon_nominal, 2)) "Control valve" + annotation (Placement(transformation( + extent={{-10,10},{10,-10}}, + rotation=180, + origin={40,-40}))); + IBPSA.Fluid.Movers.Preconfigured.FlowControlled_m_flow pum( + redeclare final package Medium = MediumCol, + energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState, + T_start=TCol_start, + addPowerToMedium=false, + m_flow_nominal=mCol_flow_nominal, + dp_nominal=dpCon_nominal + dpValCol_nominal, + m_flow_start=0) "Cooling water pump" + annotation (Placement(transformation(extent={{-100,-50},{-120,-30}}))); + IBPSA.Fluid.FixedResistances.Junction spl( + redeclare final package Medium = MediumCol, + energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState, + final dp_nominal=fill(0,3), + final m_flow_nominal=mCol_flow_nominal .* {1,-1,-1}, + final from_dp=false, + T_start=TCol_start) "Flow splitter" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=180, + origin={40,-80}))); + Modelica.Blocks.Math.BooleanToReal booToRea( + realTrue = mCol_flow_nominal) + "Constant speed primary pump control signal" + annotation (Placement(transformation(extent={{-140,0},{-120,20}}))); + Modelica.Blocks.Logical.Hysteresis hys( + uLow=mCol_flow_nominal/3, + uHigh=mCol_flow_nominal/2) "Hysteresis" + annotation (Placement(transformation(extent={{-180,40},{-160,60}}))); + Modelica.Blocks.Logical.And and1 + annotation (Placement(transformation(extent={{-140,40},{-120,60}}))); + IBPSA.Fluid.Sensors.TemperatureTwoPort senTColOut( + redeclare final package Medium = MediumCol, + m_flow_nominal=mCol_flow_nominal, + T_start=TCol_start) annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={-70,-40}))); + IBPSA.Fluid.Sensors.MassFlowRate senMasFlo( + redeclare final package Medium = MediumCol) + "Mass flow rate sensor for the ORC condenser cold fluid" + annotation (Placement(transformation(extent={{-140,-50},{-160,-30}}))); + Modelica.Blocks.Sources.BooleanTable booTab(table={100}, startValue=false) + "Boolean table with initial false" + annotation (Placement(transformation(extent={{-180,0},{-160,20}}))); +equation + connect(orc.port_b1, sinHot.ports[1]) annotation (Line(points={{-20,-28},{-14, + -28},{-14,90},{100,90}}, + color={0,127,255})); + connect(souHot.ports[1], orc.port_a1) annotation (Line(points={{-160,90},{-46, + 90},{-46,-28},{-40,-28}}, + color={0,127,255})); + connect(TWatOut_set.y, conPI.u_s) + annotation (Line(points={{21,10},{38,10}}, color={0,0,127})); + connect(colBou.ports[1], senTWatSup.port_b) annotation (Line(points={{100,-61}, + {100,-80},{80,-80}}, color={0,127,255})); + connect(senTWatRet.port_a, colBou.ports[2]) annotation (Line(points={{80,-40}, + {100,-40},{100,-59}}, color={0,127,255})); + connect(TWatRet.y, colBou.T_in) annotation (Line(points={{149,-60},{132,-60}, + {132,-56},{122,-56}},color={0,0,127})); + connect(senTWatRet.port_b, val.port_1) + annotation (Line(points={{60,-40},{50,-40}}, color={0,127,255})); + connect(spl.port_3, val.port_3) annotation (Line(points={{40,-70},{40,-50}}, + color={0,127,255})); + connect(spl.port_2, senTWatSup.port_a) annotation (Line(points={{50,-80},{60,-80}}, + color={0,127,255})); + connect(conPI.y, val.y) + annotation (Line(points={{61,10},{80,10},{80,-20},{40,-20},{40,-28}}, + color={0,0,127})); + connect(and1.y, orc.ena) annotation (Line(points={{-119,50},{-54,50},{-54,-34}, + {-41,-34}},color={255,0,255})); + connect(orc.port_b2,senTColOut. port_a) annotation (Line(points={{-40,-40},{-60, + -40}}, color={0,127,255})); + connect(senTColOut.port_b, pum.port_a) + annotation (Line(points={{-80,-40},{-100,-40}}, color={0,127,255})); + connect(senTColOut.T, conPI.u_m) annotation (Line(points={{-70,-29},{-70,-12}, + {50,-12},{50,-2}}, color={0,0,127})); + connect(val.port_2, orc.port_a2) annotation (Line(points={{30,-40},{-20,-40}}, + color={0,127,255})); + connect(pum.m_flow_in, booToRea.y) + annotation (Line(points={{-110,-28},{-110,10},{-118,10}}, + color={0,0,127})); + connect(spl.port_1, senMasFlo.port_b) annotation (Line(points={{30,-80},{-180, + -80},{-180,-40},{-160,-40}}, + color={0,127,255})); + connect(senMasFlo.port_a, pum.port_b) + annotation (Line(points={{-140,-40},{-120,-40}}, color={0,127,255})); + connect(booTab.y, booToRea.u) + annotation (Line(points={{-159,10},{-142,10}}, color={255,0,255})); + connect(booTab.y, and1.u2) annotation (Line(points={{-159,10},{-150,10},{-150, + 42},{-142,42}}, color={255,0,255})); + connect(hys.y, and1.u1) + annotation (Line(points={{-158,50},{-142,50}}, color={255,0,255})); + connect(senMasFlo.m_flow, hys.u) annotation (Line(points={{-150,-29},{-150,-20}, + {-190,-20},{-190,50},{-182,50}}, color={0,0,127})); +annotation(experiment(StopTime=900,Tolerance=1E-6), + __Dymola_Commands(file="modelica://IBPSA/Resources/Scripts/Dymola/Fluid/CHPs/OrganicRankine/Examples/ORCHotWater.mos" + "Simulate and plot"), + Documentation(info=" +

+This example model demonstrates how + +IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation +can be integrated in a system. +The three-way valve is controlled to track the hot water +output temperature, which is the cold fluid of the ORC, +at a set point of 55°C. +In addition, a safety control sequence prevents the ORC from turning on +until a minimum flow rate is established in the condenser water loop. +

+",revisions=" + +"), + Diagram(coordinateSystem(extent={{-200,-100},{180,120}})), + Icon(coordinateSystem(extent={{-100,-100},{100,100}}))); +end ORCHotWater; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Examples/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Examples/package.mo new file mode 100644 index 0000000000..b65f7b7652 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Examples/package.mo @@ -0,0 +1,9 @@ +within IBPSA.Fluid.CHPs.OrganicRankine; +package Examples "Package containing example models" + extends Modelica.Icons.ExamplesPackage; +annotation (preferredView="info", Documentation(info=" +

+This package contains examples. +

+")); +end Examples; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Examples/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/Examples/package.order new file mode 100644 index 0000000000..8ad1dded5c --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Examples/package.order @@ -0,0 +1 @@ +ORCHotWater diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Validation/VariableSource.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Validation/VariableSource.mo new file mode 100644 index 0000000000..9df9da0be9 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Validation/VariableSource.mo @@ -0,0 +1,155 @@ +within IBPSA.Fluid.CHPs.OrganicRankine.Validation; +model VariableSource + "ORC with waste heat stream with variable flow rate and temperature" + extends Modelica.Icons.Example; + + package MediumHot = IBPSA.Media.Air "Evaporator hot fluid"; + package MediumCol = IBPSA.Media.Water "Condenser cold fluid"; + + parameter IBPSA.Fluid.CHPs.OrganicRankine.Data.WorkingFluids.R245fa pro + "Property record of the working fluid" + annotation (Placement(transformation(extent={{20,60},{40,80}}))); + parameter Modelica.Units.SI.MassFlowRate mHot_flow_nominal = 1 + "Nominal mass flow rate of evaporator hot fluid"; + parameter Modelica.Units.SI.MassFlowRate mCol_flow_nominal = 1 + "Nominal mass flow rate of condenser cold fluid"; + + IBPSA.Fluid.CHPs.OrganicRankine.ConstantEvaporation orc( + redeclare package Medium1 = MediumHot, + redeclare package Medium2 = MediumCol, + pro=pro, + tau1=0, + tau2=0, + energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState, + T1_start(displayUnit="K") = 350, + T2_start(displayUnit="K") = 290, + dpHot_nominal = 0, + dpCol_nominal = 0, + mHot_flow_nominal=mHot_flow_nominal, + mCol_flow_nominal=mCol_flow_nominal, + mWor_flow_max = + 3E4 / ( + IBPSA.Utilities.Math.Functions.smoothInterpolation( + x = orc.TWorEva, + xSup = pro.T, + ySup = pro.hSatVap) - + IBPSA.Utilities.Math.Functions.smoothInterpolation( + x = 300, + xSup = pro.T, + ySup = pro.hSatLiq)), + mWor_flow_min = orc.mWor_flow_max * 0.2, + TWorEva=350, + etaExp=0.7, + etaPum=0.7) "Organic Rankine cycle" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + IBPSA.Fluid.Sources.MassFlowSource_T souHot( + redeclare final package Medium = MediumHot, + m_flow=mHot_flow_nominal, + T=orc.TWorEva + 20, + nPorts=1, + use_m_flow_in=true, + use_T_in=true) "Evaporator hot fluid source" + annotation (Placement(transformation(extent={{-40,20},{-20,40}}))); + IBPSA.Fluid.Sources.Boundary_pT sinHot( + redeclare final package Medium = MediumHot, + nPorts=1) "Evaporator hot fluid sink" + annotation (Placement(transformation(extent={{80,20},{60,40}}))); + IBPSA.Fluid.Sources.MassFlowSource_T souCol( + redeclare final package Medium = MediumCol, + m_flow=mCol_flow_nominal, + nPorts=1) "Condenser cold fluid source" + annotation (Placement(transformation(extent={{40,-40},{20,-20}}))); + IBPSA.Fluid.Sources.Boundary_pT sinCol( + redeclare final package Medium = MediumCol, + nPorts=1) "Condenser cold fluid sink" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}}))); + IBPSA.Fluid.Sensors.TemperatureTwoPort THotOut( + redeclare final package Medium = MediumHot, + final m_flow_nominal=mHot_flow_nominal, + tau=0) "Outgoing temperature of evaporator hot fluid" + annotation (Placement(transformation(extent={{30,20},{50,40}}))); + IBPSA.Fluid.Sensors.TemperatureTwoPort TColOut( + redeclare final package Medium = MediumCol, + final m_flow_nominal=mCol_flow_nominal, + tau=0) "Outgoing temperature of condenser cold fluid" + annotation (Placement(transformation(extent={{-30,-40},{-50,-20}}))); + + Modelica.Blocks.Sources.BooleanConstant tru(k=true) "Constant true" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + + Modelica.Blocks.Sources.TimeTable mHot_flow_set(table=[ + 0,0; + 20,0; + 50,mHot_flow_nominal*1.5; + 250,mHot_flow_nominal*1.5; + 280,0; + 300,0]) + "Sets the hot fluid flow rate in the evaporator" + annotation (Placement(transformation(extent={{-80,40},{-60,60}}))); + Modelica.Blocks.Sources.TimeTable THotIn_set(table=[ + 0,orc.TWorEva + 20; + 100,orc.TWorEva + 20; + 150,orc.TWorEva - 5; + 200,orc.TWorEva + 20; + 300,orc.TWorEva + 20]) + "Sets the hot fluid incoming temperature in the evaporator" + annotation (Placement(transformation(extent={{-80,0},{-60,20}}))); +equation + connect(souHot.ports[1],orc. port_a1) annotation (Line(points={{-20,30},{-16,30}, + {-16,6},{-10,6}}, color={0,127,255})); + connect(souCol.ports[1],orc. port_a2) annotation (Line(points={{20,-30},{16,-30}, + {16,-6},{10,-6}}, color={0,127,255})); + connect(sinHot.ports[1],THotOut. port_b) + annotation (Line(points={{60,30},{50,30}}, color={0,127,255})); + connect(THotOut.port_a,orc. port_b1) annotation (Line(points={{30,30},{16,30}, + {16,6},{10,6}}, color={0,127,255})); + connect(TColOut.port_a,orc. port_b2) annotation (Line(points={{-30,-30},{-16,-30}, + {-16,-6},{-10,-6}}, color={0,127,255})); + connect(sinCol.ports[1], TColOut.port_b) + annotation (Line(points={{-60,-30},{-50,-30}}, color={0,127,255})); + connect(tru.y, orc.ena) + annotation (Line(points={{-19,0},{-11,0}},color={255,0,255})); + connect(mHot_flow_set.y, souHot.m_flow_in) annotation (Line(points={{-59,50},{ + -50,50},{-50,38},{-42,38}}, color={0,0,127})); + connect(THotIn_set.y, souHot.T_in) annotation (Line(points={{-59,10},{-50,10}, + {-50,34},{-42,34}}, color={0,0,127})); + annotation(experiment(StopTime=300,Tolerance=1E-6), + __Dymola_Commands(file="modelica://IBPSA/Resources/Scripts/Dymola/Fluid/CHPs/OrganicRankine/Validation/VariableSource.mos" + "Simulate and plot"), + Documentation(info=" +

+This model demonstrates how the ORC model reacts to variable flow rate +and temperature of the incoming hot fluid carrying waste heat. +Normally, the working fluid flow rate of the cycle +w is found from +the set point for the evaporator pinch point temperature differential +ΔTpin,eva. +This constraint is relaxed under any of the following two conditions: +

+ +",revisions=" + +")); +end VariableSource; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Validation/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/Validation/package.mo new file mode 100644 index 0000000000..62441fab23 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Validation/package.mo @@ -0,0 +1,20 @@ +within IBPSA.Fluid.CHPs.OrganicRankine; +package Validation "Collection of validation models" + extends Modelica.Icons.ExamplesPackage; + +annotation (preferredView="info", Documentation(info=" +

+This package contains validation models for the classes in + +IBPSA.Fluid.CHPs.OrganicRankine. +

+

+Note that most validation models contain simple input data +which may not be realistic, but for which the correct +output can be obtained through an analytic solution. +The examples plot various outputs, which have been verified against these +solutions. These model outputs are stored as reference data and +used for continuous validation whenever models in the library change. +

+")); +end Validation; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/Validation/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/Validation/package.order new file mode 100644 index 0000000000..cd35ba383f --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/Validation/package.order @@ -0,0 +1 @@ +VariableSource diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/package.mo b/IBPSA/Fluid/CHPs/OrganicRankine/package.mo new file mode 100644 index 0000000000..9a4fcf0106 --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/package.mo @@ -0,0 +1,9 @@ +within IBPSA.Fluid.CHPs; +package OrganicRankine "Package for the rankine cycle" + extends Modelica.Icons.VariantsPackage; + annotation (Documentation(info=" +

+Package with a model of an organic Rankine cycle. +

+")); +end OrganicRankine; diff --git a/IBPSA/Fluid/CHPs/OrganicRankine/package.order b/IBPSA/Fluid/CHPs/OrganicRankine/package.order new file mode 100644 index 0000000000..cdf4e1c5fa --- /dev/null +++ b/IBPSA/Fluid/CHPs/OrganicRankine/package.order @@ -0,0 +1,5 @@ +ConstantEvaporation +Data +Examples +Validation +BaseClasses diff --git a/IBPSA/Fluid/CHPs/package.mo b/IBPSA/Fluid/CHPs/package.mo new file mode 100644 index 0000000000..91192f873f --- /dev/null +++ b/IBPSA/Fluid/CHPs/package.mo @@ -0,0 +1,10 @@ +within IBPSA.Fluid; +package CHPs "Package with model for combined heat and power device" + extends Modelica.Icons.VariantsPackage; + +annotation (preferredView="info", Documentation(info=" +

+This package contains models for combined heat and power plant. +

+")); +end CHPs; diff --git a/IBPSA/Fluid/CHPs/package.order b/IBPSA/Fluid/CHPs/package.order new file mode 100644 index 0000000000..7ec1bfe1a5 --- /dev/null +++ b/IBPSA/Fluid/CHPs/package.order @@ -0,0 +1 @@ +OrganicRankine diff --git a/IBPSA/Fluid/FixedResistances/CheckValve.mo b/IBPSA/Fluid/FixedResistances/CheckValve.mo index 883f7acc25..2ba8be8f9f 100644 --- a/IBPSA/Fluid/FixedResistances/CheckValve.mo +++ b/IBPSA/Fluid/FixedResistances/CheckValve.mo @@ -27,48 +27,85 @@ model CheckValve "Check valve that avoids flow reversal" else 0 "Flow coefficient of fixed resistance that may be in series with valve, k=m_flow/sqrt(dp), with unit=(kg.m)^(1/2)."; - - Real k(min=Modelica.Constants.small) - "Flow coefficient of valve and pipe in series in allowed/forward direction, - k=m_flow/sqrt(dp), with unit=(kg.m)^(1/2)."; - protected - Real a - "Scaled pressure variable"; - Real cv - "Twice differentiable Heaviside check valve characteristic"; - Real kCv - "Smoothed restriction characteristic"; - + parameter Real k_min=if dpFixed_nominal > Modelica.Constants.eps then + sqrt(1 / (1 / kFixed ^ 2 + 1 /(l * Kv_SI) ^ 2)) else l * Kv_SI + "Minimum flow coefficient (valve closed)"; + parameter Real k_max=if dpFixed_nominal > Modelica.Constants.eps then + sqrt(1 / (1 / kFixed ^ 2 + 1 / Kv_SI ^ 2)) else Kv_SI + "Maximum flow coefficient (valve fully open)"; + parameter Modelica.Units.SI.MassFlowRate m1_flow = 0 + "Flow rate through closed valve with zero pressure drop"; + parameter Modelica.Units.SI.MassFlowRate m2_flow = + IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp( + dp=dpValve_closing, + k=k_max, + m_flow_turbulent=m_flow_turbulent) + "Flow rate through fully open valve exposed to dpValve_closing"; + parameter Real dm1_flow_dp = + IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp_der( + dp=0, + k=k_min, + m_flow_turbulent=m_flow_turbulent, + dp_der=1) + "Derivative of closed valve flow function at dp=0"; + parameter Real dm2_flow_dp = + IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp_der( + dp=dpValve_closing, + k=k_max, + m_flow_turbulent=m_flow_turbulent, + dp_der=1) + "Derivative of open valve flow function at dp=dpValve_closing"; + parameter Real d2m1_flow_dp = + IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp_der2( + dp=0, + k=k_min, + m_flow_turbulent=m_flow_turbulent, + dp_der=1, + dp_der2=0) + "Second derivative of closed valve flow function at dp=0"; + parameter Real d2m2_flow_dp = + IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp_der2( + dp=dpValve_closing, + k=k_max, + m_flow_turbulent=m_flow_turbulent, + dp_der=1, + dp_der2=0) + "Second derivative of open valve flow function at dp=dpValve_closing"; + Modelica.Units.SI.MassFlowRate m_flow_smooth + "Smooth interpolation result between two flow regimes"; initial equation - assert(dpFixed_nominal > -Modelica.Constants.eps, - "In " + getInstanceName() + ": We require dpFixed_nominal >= 0. + assert(dpFixed_nominal > - Modelica.Constants.eps, "In " + getInstanceName() + + ": We require dpFixed_nominal >= 0. Received dpFixed_nominal = " + String(dpFixed_nominal) + " Pa."); - assert(l > -Modelica.Constants.eps, - "In " + getInstanceName() + ": We require l >= 0. Received l = " + String(l)); + assert(l > - Modelica.Constants.eps, "In " + getInstanceName() + + ": We require l >= 0. Received l = " + String(l)); equation - a = dp/dpValve_closing; - cv = smooth(2, max(0, min(1, a^3*(10+a*(-15+6*a))))); - kCv = Kv_SI*(cv*(1-l) + l); - - if (dpFixed_nominal > Modelica.Constants.eps) then - k = sqrt(1/(1/kFixed^2 + 1/kCv^2)); - else - k = kCv; - end if; - + m_flow_smooth=noEvent(smooth(2, + if dp <= 0 then IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp( + dp=dp, + k=k_min, + m_flow_turbulent=m_flow_turbulent) + elseif dp >= dpValve_closing then IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp( + dp=dp, + k=k_max, + m_flow_turbulent=m_flow_turbulent) + else IBPSA.Utilities.Math.Functions.quinticHermite( + x=dp, + x1=0, + x2=dpValve_closing, + y1=0, + y2=m2_flow, + y1d=dm1_flow_dp, + y2d=dm2_flow_dp, + y1dd=d2m1_flow_dp, + y2dd=d2m2_flow_dp))); if homotopyInitialization then - m_flow = homotopy( - actual=IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp( - dp = dp, - k = k, - m_flow_turbulent = m_flow_turbulent), - simplified = m_flow_nominal_pos*dp/dp_nominal_pos); + m_flow=homotopy( + actual=m_flow_smooth, + simplified=m_flow_nominal_pos * dp / dp_nominal_pos); else - m_flow = IBPSA.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp( - dp = dp, - k = k, - m_flow_turbulent = m_flow_turbulent); + m_flow=m_flow_smooth; end if; annotation (Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100}, {100,100}}), graphics={ @@ -103,7 +140,7 @@ defaultComponentName="cheVal", Documentation(info="

Implementation of a hydraulic check valve. -Note that the small reverse flows can still occur with this model. +Note that small reverse flows can still occur with this model.

Main equations

@@ -113,26 +150,22 @@ The basic flow function ṁ = sign(Δp) k √ Δp  ,

-with regularization near the origin, is used to compute the pressure drop. -The flow coefficient -

-

- k = ṁ ⁄ √ Δp   -

-

-is increased from l*KV_Si to KV_Si, -where KV_Si is equal to Kv but in SI units. -Therefore, the flow coefficient k is set to a value close to zero for negative pressure differences, thereby -restricting reverse flow to a small value. -The flow coefficient k saturates to its maximum value at the pressure dpValve_closing. -For larger pressure drops, the pressure drop is a quadratic function of the flow rate. +with regularization near the origin, is used to compute the mass flow rate +through the fully closed and fully open valve, respectively. +The valve is considered fully closed when subjected to a negative pressure drop, +and its flow coefficient k is then equal to l * Kv_SI, +where Kv_SI is equal to Kv but in SI units. +The valve is considered fully open when the pressure drop exceeds +dpValve_closing, +and its flow coefficient k is then equal to Kv_SI. +For valve positions between these two extremes, a quintic spline interpolation +is applied to determine the mass flow rate as a function of +the pressure drop across the valve.

Typical use and important parameters

The parameters m_flow_nominal and dpValve_nominal -determine the flow coefficient of the check valve when it is fully opened. -A typical value for a nominal flow rate of 1 m/s is -dpValve_nominal = 3400 Pa. +determine the flow coefficient of the check valve when it is fully open. The leakage ratio l determines the minimum flow coefficient, for negative pressure differences. The parameter dpFixed_nominal allows to include a series @@ -156,8 +189,13 @@ by default. ", revisions="