Skip to content

Commit

Permalink
Add a simpler Pump.
Browse files Browse the repository at this point in the history
  • Loading branch information
HansOlsson committed Jun 13, 2023
1 parent bf66b23 commit 1acc495
Show file tree
Hide file tree
Showing 2 changed files with 338 additions and 1 deletion.
222 changes: 222 additions & 0 deletions Modelica/Fluid/Examples/Explanatory.mo
Original file line number Diff line number Diff line change
Expand Up @@ -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="<html>
<p>
Simple heating system with a closed flow cycle.
It is based on <a href=\"Modelica.Fluid.Examples.HeatingSystem\">HeatingSystem</a>.
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.
</p>
<p>
One can investigate the temperatures and flows for different settings of <code>system.energyDynamics</code>
(see Assumptions tab of the system object).</p>
<ul>
<li>With <code>system.energyDynamics==Types.Dynamics.FixedInitial</code> the states need to find their steady values during the simulation.</li>
<li>With <code>system.energyDynamics==Types.Dynamics.SteadyStateInitial</code> (default setting) the simulation starts in steady-state.</li>
<li>With <code>system.energyDynamics==Types.Dynamics.SteadyState</code> all but one dynamic states are eliminated.
The left state <code>tank.m</code> is to account for the closed flow cycle. It is constant as outflow and inflow are equal
in a steady-state simulation.</li>
</ul>
<p>
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.
</p>
<p>
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.
</p>
<p>
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.
</p>
<img src=\"modelica://Modelica/Resources/Images/Fluid/Examples/HeatingSystem.png\" border=\"1\"
alt=\"HeatingSystem.png\">
</html>"), experiment(StopTime=6000),
__Dymola_Commands(file(ensureSimulated=true)=
"modelica://Modelica/Resources/Scripts/Dymola/Fluid/HeatingSystem/plotResults.mos"
"plotResults"));
end SimplerHeatingSystem;
end Explanatory;
117 changes: 116 additions & 1 deletion Modelica/Fluid/Machines.mo
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,116 @@ Then the model can be replaced with a Pump with rotational shaft or with a Presc
</html>"));
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="<html>
<p>
This model describes a centrifugal pump (or a group of <code>nParallel</code> pumps)
with ideally controlled mass flow rate or pressure.
</p>
<p>
Nominal values are used to predefine an exemplary pump characteristics and to define the operation of the pump.
The input connectors <code>m_flow_set</code> or <code>p_set</code> can optionally be enabled to provide time varying set points.
</p>
<p>
Use this model if the pump characteristics is of <em>no</em> 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.
</p>
</html>",
revisions="<html>
<ul>
<li><em>13 June 2023</em>
by Hans Olsson<br />
Model added to the Fluid library based on <a href=\"modelica://Modelica.Fluid.Machines.ControlledPump\">ControlledPump</a></li>
</ul>
</html>"));
end SimplePump;

package BaseClasses
"Base classes used in the Machines package (only of interest to build new component models)"
extends Modelica.Icons.BasesPackage;
Expand Down Expand Up @@ -428,17 +538,22 @@ 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);
V_flow_single = V_flow/nParallel;
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
Expand Down

0 comments on commit 1acc495

Please sign in to comment.