I am having some difficulty in finding exactly the best way to write the energy balance of a simple lumped volume, say a pipe, with fluid flow and a heat flow output. I basically just want to add a Q_loss term in the energy balance to reduce the temperature of any fluid flowing through, but keep the overall model super simple (no friction, pressure, convection losses etc).
I tried to write a simple model but I am getting stuck having one less equation than I need. Is there a way to do this without fixing the pressure?
My code (the medium is not standard and may need to be redeclared):
model IdealLossPipe
extends SolarTherm.Interfaces.Models.Pipe;
Medium.BaseProperties medium;
replaceable package Medium = SolarTherm.Media.MoltenSalt.MoltenSalt_base
constrainedby Modelica.Media.Interfaces.PartialMedium
Modelica.Fluid.Interfaces.FluidPort_a fluid_a(redeclare package Medium =
Medium);
Modelica.Fluid.Interfaces.FluidPort_b fluid_b(redeclare package Medium =
Medium) annotation (Placement(transformation(extent={{110,-10},{90,10}}, rotation=0),
iconTransformation(extent={{110,-10},{90,10}})));
parameter Real Q_loss_spec(unit="W/m") = 284 "Heat loss per m of piping";
SI.HeatFlowRate Q_loss;
parameter SI.Length length = 13.1 annotation(Dialog(group="Length"));
parameter SI.Length diameter = 0.052;
SI.Energy U;
SI.Mass m;
SI.Volume V;
equation
V = length*(diameter/2)^2*Modelica.Constants.pi;
m=V*medium.d;
U=m*medium.u;
fluid_a.p=medium.p;
fluid_b.p=medium.p;
(instream(fluid_a.h_outflow)+fluid_b.h_outflow)/2=medium.h;
fluid_a.h_outflow=0;
Q_loss=-length*Q_loss_spec;
//Mass Balance
fluid_a.m_flow+fluid_b.m_flow=der(m);
//Energy Balance
der(U)= fluid_a.m_flow*inStream(fluid_a.h_outflow) + fluid_b.m_flow*fluid_b.h_outflow + Q_loss;
end IdealLossPipe;
Thank you in advance for helping me out!!
EDIT: removed unecessary heatPort in my model
I edited your model (see below). Some additions included initialization of medium
which is required if using that approach for base properties. It would be helpful to take a close look at existing open-source fluid libraries (e.g., Modelica Standard Library, TRANSFORM, or ThermoPower) to see how they do things or use their components.
model IdealLossPipe
import SI = Modelica.SIunits;
replaceable package Medium = Modelica.Media.Water.StandardWater
constrainedby Modelica.Media.Interfaces.PartialMedium annotation (
choicesAllMatching=true);
Medium.BaseProperties medium(
each preferredMediumStates=true,
p(start=p_start),
T(start=T_start),
h(start=Medium.specificEnthalpy(Medium.setState_pT(p_start, T_start))),
d(start=Medium.density(Medium.setState_pT(p_start, T_start))),
u(start=Medium.specificInternalEnergy(Medium.setState_pT(p_start, T_start))),
Xi(start=X_start[1:Medium.nXi]),
X(start=X_start));
Modelica.Fluid.Interfaces.FluidPort_a fluid_a(redeclare package Medium =
Medium) annotation (Placement(transformation(extent={{-90,-10},{-110,10}},
rotation=0), iconTransformation(extent={{-90,-10},{-110,10}})));
Modelica.Fluid.Interfaces.FluidPort_b fluid_b(redeclare package Medium =
Medium) annotation (Placement(transformation(extent={{110,-10},{90,10}},
rotation=0), iconTransformation(extent={{110,-10},{90,10}})));
parameter Real Q_loss_spec(unit="W/m") = 284 "Heat loss per m of piping";
parameter SI.Length length=13.1 annotation (Dialog(group="Length"));
parameter SI.Length diameter=0.052;
// Initialization
parameter SI.Pressure p_start=1e5;
parameter SI.Temperature T_start=293.15;
parameter SI.MassFraction X_start[Medium.nX]=Medium.X_default "Mass fraction";
SI.HeatFlowRate Q_loss;
SI.Energy U;
SI.Mass m;
SI.Volume V;
equation
V = length*(diameter/2)^2*Modelica.Constants.pi;
m = V*medium.d;
U = m*medium.u;
Q_loss = -length*Q_loss_spec;
//Mass Balance
fluid_a.m_flow + fluid_b.m_flow = der(m);
//Energy Balance
der(U) = fluid_a.m_flow*inStream(fluid_a.h_outflow) + fluid_b.m_flow*inStream(
fluid_b.h_outflow) + Q_loss;
// Port definitions
fluid_a.h_outflow = medium.h;
fluid_b.h_outflow = medium.h;
fluid_a.p = medium.p;
fluid_b.p = medium.p;
fluid_a.Xi_outflow = medium.Xi;
fluid_b.Xi_outflow = medium.Xi;
fluid_a.C_outflow = inStream(fluid_b.C_outflow);
fluid_b.C_outflow = inStream(fluid_a.C_outflow);
end IdealLossPipe;
One thing to keep in mind is the "flow vs volume" or "non-state (flow) vs state (non-flow/volume)" representation of models. A port which exposes a state sets the value of the state variables of the connectors (i.e., pressure for fluid) while a non-state port sets the flow variables of the connector (i.e., mass flow rate for fluid). So for fluids, you want to make sure you do not connect ports that each set the pressure (state variable). Similar with mass flow rate but that tends to be more forgiving by the solver.
For reference, your model sets the state variable (fluid_a.p = medium.p
, fluid_b.p = medium.p
). A simple model example would want to connect each port with a model that sets the mass flow rate such as a mass flow source on fluid_a
and a resistance element followed by a pressure boundary on fluid_b
.
model Example
Unnamed pipe(redeclare package Medium = Modelica.Media.Water.StandardWater,
Q_loss_spec=10000)
annotation (Placement(transformation(extent={{-68,4},{-48,24}})));
Modelica.Fluid.Sources.Boundary_pT boundary(
nPorts=1,
redeclare package Medium = Modelica.Media.Water.StandardWater,
p=100000,
T=293.15) annotation (Placement(transformation(extent={{34,2},{14,22}})));
Modelica.Fluid.Sources.MassFlowSource_T boundary1(
nPorts=1,
redeclare package Medium = Modelica.Media.Water.StandardWater,
m_flow=1,
T=293.15)
annotation (Placement(transformation(extent={{-124,2},{-104,22}})));
Modelica.Fluid.Valves.ValveLinear valveLinear(
redeclare package Medium = Modelica.Media.Water.StandardWater,
dp_nominal=100000,
m_flow_nominal=1)
annotation (Placement(transformation(extent={{-30,4},{-10,24}})));
Modelica.Blocks.Sources.Constant const(k=1)
annotation (Placement(transformation(extent={{-52,30},{-32,50}})));
equation
connect(boundary1.ports[1], pipe.fluid_a) annotation (Line(points={{-104,12},{
-86,12},{-86,14},{-68,14}}, color={0,127,255}));
connect(pipe.fluid_b, valveLinear.port_a)
annotation (Line(points={{-48,14},{-30,14}}, color={0,127,255}));
connect(valveLinear.port_b, boundary.ports[1]) annotation (Line(points={{-10,14},
{2,14},{2,12},{14,12}}, color={0,127,255}));
connect(const.y, valveLinear.opening)
annotation (Line(points={{-31,40},{-20,40},{-20,22}}, color={0,0,127}));
end Example;