From 173a8265a6d66a78ea13a43687e1ecd7f173f2dc Mon Sep 17 00:00:00 2001 From: HOS Date: Tue, 13 Jun 2023 13:57:01 +0200 Subject: [PATCH 1/6] Add a simpler Pump. Closes #2413 --- Modelica/Fluid/Examples/Explanatory.mo | 222 +++++++++++++++++++++++++ Modelica/Fluid/Machines.mo | 117 ++++++++++++- 2 files changed, 338 insertions(+), 1 deletion(-) diff --git a/Modelica/Fluid/Examples/Explanatory.mo b/Modelica/Fluid/Examples/Explanatory.mo index 1ac9297547..a41d276589 100644 --- a/Modelica/Fluid/Examples/Explanatory.mo +++ b/Modelica/Fluid/Examples/Explanatory.mo @@ -267,4 +267,226 @@ The total pressures offer an additional perspective on the model. After setting "Plot the model results"), experiment(StopTime=1.1)); end MomentumBalanceFittings; + + model SimplerHeatingSystem + "Simpler model of a heating system; the N in pump is ignored" + extends Modelica.Icons.Example; + replaceable package Medium = + Modelica.Media.CompressibleLiquids.LinearWater_pT_Ambient + constrainedby Modelica.Media.Interfaces.PartialMedium; + + Modelica.Fluid.Vessels.OpenTank tank( + redeclare package Medium = Medium, + crossArea=0.01, + height=2, + level_start=1, + nPorts=2, + massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, + use_HeatTransfer=true, + portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(diameter= + 0.01),Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(diameter= + 0.01)}, + redeclare model HeatTransfer = + Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer (k=10), + ports(each p(start=1.1e5)), + T_start=Modelica.Units.Conversions.from_degC(20)) + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Machines.SimplePump pump( + redeclare package Medium = Medium, + N_nominal=1500, + use_T_start=true, + T_start=Modelica.Units.Conversions.from_degC(40), + m_flow_start=0.01, + m_flow_nominal=0.01, + control_m_flow=false, + allowFlowReversal=false, + p_a_start=110000, + p_b_start=130000, + p_a_nominal=110000, + p_b_nominal=130000) + annotation (Placement(transformation(extent={{-50,10},{-30,30}}))); + Modelica.Fluid.Valves.ValveIncompressible valve( + redeclare package Medium = Medium, + CvData=Modelica.Fluid.Types.CvTypes.OpPoint, + m_flow_nominal=0.01, + show_T=true, + allowFlowReversal=false, + dp_start=18000, + dp_nominal=10000) + annotation (Placement(transformation(extent={{60,-80},{40,-60}}))); + protected + Modelica.Blocks.Interfaces.RealOutput m_flow(unit="kg/s") + annotation (Placement(transformation(extent={{-6,34},{6,46}}))); + public + Sensors.MassFlowRate sensor_m_flow(redeclare package Medium = Medium) + annotation (Placement(transformation(extent={{-20,10},{0,30}}))); + Modelica.Thermal.HeatTransfer.Sources.FixedTemperature T_ambient(T=system.T_ambient) + annotation (Placement(transformation(extent={{-14,-27},{0,-13}}))); + Modelica.Thermal.HeatTransfer.Components.ThermalConductor wall(G=1.6e3/20) + annotation (Placement(transformation( + origin={10,-48}, + extent={{8,-10},{-8,10}}, + rotation=90))); + Modelica.Thermal.HeatTransfer.Sources.FixedHeatFlow burner( + Q_flow=1.6e3, + T_ref=343.15, + alpha=-0.5) + annotation (Placement(transformation(extent={{16,30},{36,50}}))); + inner Modelica.Fluid.System system( + m_flow_small=1e-4, energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial) + annotation (Placement(transformation(extent={{-90,70},{ + -70,90}}))); + Pipes.DynamicPipe heater( + redeclare package Medium = Medium, + use_T_start=true, + T_start=Modelica.Units.Conversions.from_degC(80), + length=2, + redeclare model HeatTransfer = + Modelica.Fluid.Pipes.BaseClasses.HeatTransfer.IdealFlowHeatTransfer, + diameter=0.01, + nNodes=1, + redeclare model FlowModel = + Modelica.Fluid.Pipes.BaseClasses.FlowModels.DetailedPipeFlow, + use_HeatTransfer=true, + modelStructure=Modelica.Fluid.Types.ModelStructure.a_v_b, + p_a_start=130000) + annotation (Placement(transformation(extent={{30,10},{50,30}}))); + + Pipes.DynamicPipe radiator( + use_T_start=true, + redeclare package Medium = Medium, + length=10, + T_start=Modelica.Units.Conversions.from_degC(40), + redeclare model HeatTransfer = + Modelica.Fluid.Pipes.BaseClasses.HeatTransfer.IdealFlowHeatTransfer, + diameter=0.01, + nNodes=1, + redeclare model FlowModel = + Modelica.Fluid.Pipes.BaseClasses.FlowModels.DetailedPipeFlow, + use_HeatTransfer=true, + modelStructure=Modelica.Fluid.Types.ModelStructure.a_v_b, + p_a_start=110000, + state_a(p(start=110000)), + state_b(p(start=110000))) + annotation (Placement(transformation(extent={{20,-80},{0,-60}}))); + + protected + Modelica.Blocks.Interfaces.RealOutput T_forward(unit="K") + annotation (Placement(transformation(extent={{74,34},{86,46}}))); + Modelica.Blocks.Interfaces.RealOutput T_return(unit="K") + annotation (Placement(transformation(extent={{-46,-56},{-58,-44}}))); + public + Modelica.Fluid.Sensors.Temperature sensor_T_forward(redeclare package Medium = + Medium) + annotation (Placement(transformation(extent={{50,30},{70,50}}))); + Modelica.Fluid.Sensors.Temperature sensor_T_return(redeclare package Medium = + Medium) + annotation (Placement(transformation(extent={{-20,-60},{-40,-40}}))); + protected + Modelica.Blocks.Interfaces.RealOutput tankLevel(unit="m") + annotation (Placement(transformation(extent={{-56,34}, + {-44,46}}))); + public + Modelica.Blocks.Sources.Step handle( + startTime=2000, + height=0.9, + offset=0.1) annotation (Placement(transformation(extent={{26,-27},{40,-13}}))); + Pipes.DynamicPipe pipe( + redeclare package Medium = Medium, + use_T_start=true, + T_start=Modelica.Units.Conversions.from_degC(80), + redeclare model HeatTransfer = + Modelica.Fluid.Pipes.BaseClasses.HeatTransfer.IdealFlowHeatTransfer, + diameter=0.01, + redeclare model FlowModel = + Modelica.Fluid.Pipes.BaseClasses.FlowModels.DetailedPipeFlow, + length=10, + p_a_start=130000) + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=-90, + origin={80,-20}))); + + equation + tankLevel = tank.level; + connect(sensor_m_flow.m_flow, m_flow) annotation (Line(points={{-10,31}, + {-10,40},{0,40}}, color={0,0,127})); + connect(sensor_m_flow.port_b, heater.port_a) + annotation (Line(points={{0,20},{0, + 20},{30,20}}, color={0,127,255})); + connect(T_ambient.port, wall.port_a) annotation (Line( + points={{0,-20},{10,-20},{10,-40}}, color={191,0,0})); + connect(sensor_T_forward.T, T_forward) annotation (Line(points={{67,40},{ + 80,40}}, color={0,0,127})); + connect(radiator.port_a, valve.port_b) annotation (Line(points={{20,-70},{20, + -70},{40,-70}}, color={0,127,255})); + connect(sensor_T_return.port, radiator.port_b) + annotation (Line(points={{-30,-60}, + {-30,-70},{0,-70}}, color={0,127,255})); + connect(tank.ports[2], pump.port_a) annotation (Line( + points={{-69,30},{-69,20},{-50,20}}, color={0,127,255})); + connect(handle.y, valve.opening) annotation (Line( + points={{40.7,-20},{50,-20},{50,-62}}, color={0,0,127})); + connect(pump.port_b, sensor_m_flow.port_a) + annotation (Line( + points={{-30,20},{-20,20}}, color={0,127,255})); + connect(sensor_T_return.T, T_return) annotation (Line( + points={{-37,-50},{-52,-50}}, color={0,0,127})); + connect(burner.port, heater.heatPorts[1]) + annotation (Line( + points={{36,40},{40.1,40},{40.1,24.4}}, color={191,0,0})); + connect(wall.port_b, radiator.heatPorts[1]) annotation (Line( + points={{10,-56},{10,-65.6},{9.9,-65.6}}, color={191,0,0})); + connect(sensor_T_forward.port, heater.port_b) + annotation (Line( + points={{60,30},{60,20},{50,20}}, color={0,127,255})); + connect(heater.port_b, pipe.port_a) annotation (Line( + points={{50,20},{80,20},{80,-10}}, color={0,127,255})); + connect(pipe.port_b, valve.port_a) annotation (Line( + points={{80,-30},{80,-70},{60,-70}}, color={0,127,255})); + connect(radiator.port_b, tank.ports[1]) annotation (Line( + points={{0,-70},{-71,-70},{-71,30}}, color={0,127,255})); + annotation (Documentation(info=" +

+Simple heating system with a closed flow cycle. +It is based on HeatingSystem. +The only change is that pump is simpler removing a non-linear system of equations for N that could in some cases fail. + +After 2000s of simulation time the valve fully opens. A simple idealized control is embedded +into the respective components, so that the heating system can be regulated with the valve: +the pump controls the pressure, the burner controls the temperature. +

+

+One can investigate the temperatures and flows for different settings of system.energyDynamics +(see Assumptions tab of the system object).

+ +

+Note that a closed flow cycle generally causes circular equalities for the mass flow rates and leaves the pressure undefined. +This is why the tank.massDynamics, i.e., the tank level determining the port pressure, is modified locally to Types.Dynamics.FixedInitial. +

+

+Also note that the tank is thermally isolated against its ambient. This way the temperature of the tank is also +well defined for zero flow rate in the heating system, e.g., for valveOpening.offset=0 at the beginning of a simulation. +The pipe however is assumed to be perfectly isolated. +If steady-state values shall be obtained with the valve fully closed, then a thermal +coupling between the pipe and its ambient should be defined as well. +

+

+Moreover it is worth noting that the idealized direct connection between the heater and the pipe, resulting in equal port pressures, +is treated as high-index DAE, as opposed to a nonlinear equation system for connected pressure loss correlations. A pressure loss correlation +could be additionally introduced to model the fitting between the heater and the pipe, e.g., to adapt different diameters. +

+ +\"HeatingSystem.png\" +"), experiment(StopTime=6000), + __Dymola_Commands(file(ensureSimulated=true)= + "modelica://Modelica/Resources/Scripts/Dymola/Fluid/HeatingSystem/plotResults.mos" + "plotResults")); + end SimplerHeatingSystem; end Explanatory; diff --git a/Modelica/Fluid/Machines.mo b/Modelica/Fluid/Machines.mo index 11c293215c..102046f832 100644 --- a/Modelica/Fluid/Machines.mo +++ b/Modelica/Fluid/Machines.mo @@ -292,6 +292,116 @@ Then the model can be replaced with a Pump with rotational shaft or with a Presc ")); end PrescribedPump; + model SimplePump + "Centrifugal pump with ideally controlled mass flow rate; without N" + import Modelica.Units.NonSI.AngularVelocity_rpm; + extends Modelica.Fluid.Machines.BaseClasses.PartialPump( + final ignoreN=true, + final checkValve=false, + redeclare function efficiencyCharacteristic = + Modelica.Fluid.Machines.BaseClasses.PumpCharacteristics.constantEfficiency + (eta_nominal=0.8), + final use_powerCharacteristic=false, + N_nominal=1500, + redeclare function flowCharacteristic = + Modelica.Fluid.Machines.BaseClasses.PumpCharacteristics.quadraticFlow + ( V_flow_nominal={0, V_flow_op, 1.5*V_flow_op}, + head_nominal={2*head_op, head_op, 0})); + + // nominal values + parameter Medium.AbsolutePressure p_a_nominal + "Nominal inlet pressure for predefined pump characteristics"; + parameter Medium.AbsolutePressure p_b_nominal + "Nominal outlet pressure, fixed if not control_m_flow and not use_p_set"; + parameter Medium.MassFlowRate m_flow_nominal + "Nominal mass flow rate, fixed if control_m_flow and not use_m_flow_set"; + + // what to control + parameter Boolean control_m_flow = true + "= false to control outlet pressure port_b.p instead of m_flow" + annotation(Evaluate = true); + parameter Boolean use_m_flow_set = false + "= true to use input signal m_flow_set instead of m_flow_nominal" + annotation (Dialog(enable = control_m_flow)); + parameter Boolean use_p_set = false + "= true to use input signal p_set instead of p_b_nominal" + annotation (Dialog(enable = not control_m_flow)); + + // exemplary characteristics + final parameter SI.VolumeFlowRate V_flow_op = m_flow_nominal/rho_nominal + "Operational volume flow rate according to nominal values"; + final parameter SI.Position head_op = (p_b_nominal-p_a_nominal)/(rho_nominal*g) + "Operational pump head according to nominal values"; + + Modelica.Blocks.Interfaces.RealInput m_flow_set(unit="kg/s") if use_m_flow_set + "Prescribed mass flow rate" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={-50,82}))); + Modelica.Blocks.Interfaces.RealInput p_set(unit="Pa") if use_p_set + "Prescribed outlet pressure" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={50,82}))); + + protected + Modelica.Blocks.Interfaces.RealInput m_flow_set_internal(unit="kg/s") + "Needed to connect to conditional connector"; + Modelica.Blocks.Interfaces.RealInput p_set_internal(unit="Pa") + "Needed to connect to conditional connector"; + equation + // Ideal control + if control_m_flow then + m_flow = m_flow_set_internal; + else + dp_pump = p_set_internal - port_a.p; + end if; + + // Internal connector value when use_m_flow_set = false + if not use_m_flow_set then + m_flow_set_internal = m_flow_nominal; + end if; + if not use_p_set then + p_set_internal = p_b_nominal; + end if; + connect(m_flow_set, m_flow_set_internal); + connect(p_set, p_set_internal); + + annotation (defaultComponentName="pump", + Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},{100, + 100}}), graphics={Text( + visible=use_p_set, + extent={{82,108},{176,92}}, + textString="p_set"), Text( + visible=use_m_flow_set, + extent={{-20,108},{170,92}}, + textString="m_flow_set")}), + Documentation(info=" +

+This model describes a centrifugal pump (or a group of nParallel pumps) +with ideally controlled mass flow rate or pressure. +

+

+Nominal values are used to predefine an exemplary pump characteristics and to define the operation of the pump. +The input connectors m_flow_set or p_set can optionally be enabled to provide time varying set points. +

+

+Use this model if the pump characteristics is of no interest. +The actual characteristics can be configured later on for the appropriate rotational speed N. +Then the model can be replaced with a Pump with rotational shaft or with a PrescribedPump. +

+", + revisions=" + +")); + end SimplePump; + package BaseClasses "Base classes used in the Machines package (only of interest to build new component models)" extends Modelica.Icons.BasesPackage; @@ -428,8 +538,9 @@ Then the model can be replaced with a Pump with rotational shaft or with a Presc protected constant SI.Position unitHead = 1; constant SI.MassFlowRate unitMassFlowRate = 1; - + parameter Boolean ignoreN = false "Only use if checkValve=false and use_powerCharacteristic=false"; equation + assert(not ignoreN or (not checkValve and not use_powerCharacteristic), "Can only ignore N in simple configuration"); // Flow equations V_flow = homotopy(m_flow/rho, m_flow/rho_nominal); @@ -437,8 +548,12 @@ Then the model can be replaced with a Pump with rotational shaft or with a Presc if not checkValve then // Regular flow characteristics without check valve // The simplified model uses an approximation of the tangent to the head curve in the initialization point + if ignoreN then + N=N_nominal; + else head = homotopy((N/N_nominal)^2*flowCharacteristic(V_flow_single*N_nominal/N), N/N_nominal*(flowCharacteristic(V_flow_single_init)+(V_flow_single-V_flow_single_init)*noEvent(if abs(V_flow_single_init)>0 then delta_head_init/(0.1*V_flow_single_init) else 0))); + end if; s = 0; else // Flow characteristics when check valve is open From c384baafdafdf7574b003e57f08c095cb740bca3 Mon Sep 17 00:00:00 2001 From: Hans Olsson Date: Mon, 15 Jan 2024 09:23:19 +0100 Subject: [PATCH 2/6] Update Modelica/Fluid/Examples/Explanatory.mo --- Modelica/Fluid/Examples/Explanatory.mo | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Modelica/Fluid/Examples/Explanatory.mo b/Modelica/Fluid/Examples/Explanatory.mo index a41d276589..2de054dec2 100644 --- a/Modelica/Fluid/Examples/Explanatory.mo +++ b/Modelica/Fluid/Examples/Explanatory.mo @@ -484,9 +484,6 @@ could be additionally introduced to model the fitting between the heater and the \"HeatingSystem.png\" -"), experiment(StopTime=6000), - __Dymola_Commands(file(ensureSimulated=true)= - "modelica://Modelica/Resources/Scripts/Dymola/Fluid/HeatingSystem/plotResults.mos" - "plotResults")); +"), experiment(StopTime=6000)); end SimplerHeatingSystem; end Explanatory; From a636274d87e2332ffe2b5aa59d3784dc8fc1606e Mon Sep 17 00:00:00 2001 From: HOS Date: Mon, 15 Jan 2024 09:28:16 +0100 Subject: [PATCH 3/6] Add comparison signals. --- .../SimplerHeatingSystem/comparisonSignals.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt diff --git a/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt b/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt new file mode 100644 index 0000000000..5c6ab028bc --- /dev/null +++ b/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt @@ -0,0 +1,11 @@ +time +heater.mediums[1].h +heater.mediums[1].p +pipe.mediums[1].h +pipe.mediums[1].p +pipe.mediums[2].h +pipe.mediums[2].p +radiator.mediums[1].h +radiator.mediums[1].p +tank.level +tank.medium.h From f7ed7824a066cd99f3f2cc749203504b4cb737d0 Mon Sep 17 00:00:00 2001 From: HOS Date: Wed, 17 Jan 2024 10:31:23 +0100 Subject: [PATCH 4/6] Use Dialog.enable and have usual description text. Note that this is a protected parameter so it is only shown for base-classes. I decided to have the conditions both as description and as Dialog.enable to make it understandable. --- Modelica/Fluid/Machines.mo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modelica/Fluid/Machines.mo b/Modelica/Fluid/Machines.mo index 102046f832..9b86b3eafa 100644 --- a/Modelica/Fluid/Machines.mo +++ b/Modelica/Fluid/Machines.mo @@ -538,7 +538,8 @@ Then the model can be replaced with a Pump with rotational shaft or with a Presc protected constant SI.Position unitHead = 1; constant SI.MassFlowRate unitMassFlowRate = 1; - parameter Boolean ignoreN = false "Only use if checkValve=false and use_powerCharacteristic=false"; + parameter Boolean ignoreN = false "= true to ignore N of pump; only use if checkValve=false and use_powerCharacteristic=false" + annotation(Dialog(enable=not checkValve and not use_powerCharacteristic)); equation assert(not ignoreN or (not checkValve and not use_powerCharacteristic), "Can only ignore N in simple configuration"); // Flow equations From 334c427ebf073706ff1b4f9989b74118e6f41df9 Mon Sep 17 00:00:00 2001 From: Hans Olsson Date: Wed, 17 Jan 2024 11:37:39 +0100 Subject: [PATCH 5/6] Update Modelica/Fluid/Machines.mo Co-authored-by: tobolar --- Modelica/Fluid/Machines.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modelica/Fluid/Machines.mo b/Modelica/Fluid/Machines.mo index 9b86b3eafa..95b6fa883c 100644 --- a/Modelica/Fluid/Machines.mo +++ b/Modelica/Fluid/Machines.mo @@ -535,7 +535,7 @@ Then the model can be replaced with a Pump with rotational shaft or with a Presc final state_in = Medium.setState_phX(port_a.p, inStream(port_a.h_outflow), inStream(port_a.Xi_outflow)), final state = medium.state) "Monitoring model" annotation (Placement(transformation(extent={{-64,-42},{-20,0}}))); - protected + protected constant SI.Position unitHead = 1; constant SI.MassFlowRate unitMassFlowRate = 1; parameter Boolean ignoreN = false "= true to ignore N of pump; only use if checkValve=false and use_powerCharacteristic=false" From 786119f7e3e36c8793faf54523bbf21bcf92769e Mon Sep 17 00:00:00 2001 From: Hans Olsson Date: Wed, 19 Mar 2025 08:55:34 +0100 Subject: [PATCH 6/6] Update Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt Co-authored-by: Thomas Beutlich --- .../Explanatory/SimplerHeatingSystem/comparisonSignals.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt b/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt index 5c6ab028bc..7e6d53fa0f 100644 --- a/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt +++ b/Modelica/Resources/Reference/Modelica/Fluid/Examples/Explanatory/SimplerHeatingSystem/comparisonSignals.txt @@ -9,3 +9,4 @@ radiator.mediums[1].h radiator.mediums[1].p tank.level tank.medium.h +