Search code examples
modelicadymolaopenmodelica

Heating fluid in lumped volumes modelica


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


Solution

  • 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;