modelicaopenmodelicajmodelica

How to construct a balanced connector for liquids in Modelica?


Status of the post:

200313 Got an answer with code DEMO_v42 that I accept for the bounty!

200310 I comment on two key papers suggested yesterday. Still do not understand how to update DEMO_v41.

200309 I want to underline that the key problem is how to introduce the concept of stream in the code DEMO_v41 (if possible) and in this way make the connector balanced. The variable c that is the concentration should be declared stream, but how should equations be updated with inStream or actualStream - that I would be glad to see!

200226 The post example DEMO_v41 was added and is a simplified and I hope more readable code than the first DEMO_v40.

200225 I gave some comments to the answers given and to tried to focus the readers on the actual problems, but little happened.

200224 I got some input to the post both general and detailed. The detailed comments was of less value and partly an effect of misunderstanding the problem. The more general answer from Rene is good but too general. I really like to understand how to use the concept of stream with small examples, before I think about using Modelica.Media etc. It is a learning process.


I want to know how to correctly define a connector for a liquid that has a number of components with different concentrations in solution and then that solution has a flow rate. Pressure in the liquid is negligible. The standard connector I have used for long time is:

connector LiquidCon
   nc=5;
   Real c[nc]        “Component concentrations”;
   flow Real F       “Flow rate”;
end LiquidCon;

The connector works well in JModelica and OpenModelica, but I get warnings in OpenModelica that the connector is not balanced. In the Modelica language specification, section 9.3.1 I see that my construct is actually not legal, see https://www.modelica.org/documents/ModelicaSpec34.pdf. How can I make a connector that satisfy the demands?

I have spent some time reading chapter 5.10 on the concept of “stream” in Fritzons book 2n edition, but I need to study it in more detail.

The reason my simple connector brings a warning is that when you declare a flow variable the compiler assumes that the other variable is a potential variable to that flow variable, i.e. at least the number of flow and potential variables must be the same in a connector. Then of course in my case the component concentration is not a potential variable, but that the compiler cannot detect.

In the introductory section of chapter 5.10 the scope of the concept of “stream" seems to be “...application of bidirectional flows of matter with associated properties…”. In my area of applications I doubt that I need to consider bidirectional flows. This means that use of stream is an “overkill”. But that seems also to imply that I should not use the concept of “flow” either, which is a bit of a pity. Should we really stop using the concept “flow” here?

Anyway, I have tried to put together a more basic example than could be found in the book of Fritzson on this subject to see how use of the concept of “stream” would look and also what overhead in computation time etc you get. In the example below I model flow of a liquid from feed tank to harvest tank. The flow is governed by a pressure difference now. The code DEMO_v41 works and gives a warning that the connector is not balanced. If I now declare substrate concentration c to be “stream”, how should I now update the code with use of inStream and actualStream to make it work the same way, but now with this balanced connector?

package DEMO_v41

//  ---------------------------------------------------------------------------------------------
//     Interfaces  
//  ---------------------------------------------------------------------------------------------

    import Modelica.Blocks.Interfaces.RealInput;
    import Modelica.Blocks.Interfaces.RealOutput;

//  ---------------------------------------------------------------------------------------------
//     Equipment
//  ---------------------------------------------------------------------------------------------

    package EquipmentLib

        connector LiquidCon
            Real P                                             "Pressure"; 
            flow Real F                                        "Flow rate";
            Real c                                             "Substance conc";
        end LiquidCon;

        model PipeType
            LiquidCon inlet, outlet;
            parameter Real area = 1;
        equation
            inlet.F = -outlet.F;
            outlet.F = -area^2*(inlet.P - outlet.P);           // Linearized Bernoulli equation
            outlet.c = inlet.c;
        end PipeType;

        model FeedtankType
            LiquidCon outlet;                                  
            parameter Real P = 0.1                             "Pressure"; 
            parameter Real V_0 = 100                           "Initial feed volume";         
            parameter Real c_in = 1.0                          "Feedtank conc"; 
            Real V(start=V_0, fixed=true)                      "Feed volume";
        equation    
            outlet.c = c_in;
            outlet.P = P;
            der(V) = outlet.F;               
        end FeedtankType;

        model HarvesttankType
            LiquidCon inlet;
            parameter Real P = 0.0                             "Pressure";                      
            parameter Real V_0 = 1.0                           "Initial harvest liquid volume";
            parameter Real m_0 = 0.0                           "Initial substance mass";
            Real V(start=V_0, fixed=true)                      "Harvest liquid volume";
            Real m(start=m_0, fixed=true)                      "Substance mass";
            Real c                                             "Substance conc"; 
        equation
            inlet.P = P;
            der(V) = inlet.F;
            der(m) = inlet.c*inlet.F;
            c = m/V;            
        end HarvesttankType;
    end EquipmentLib;

//  ---------------------------------------------------------------------------------------------
//     Example of system 
//  ---------------------------------------------------------------------------------------------

    model Test
        EquipmentLib.FeedtankType feedtank;
        EquipmentLib.HarvesttankType harvesttank;
        EquipmentLib.PipeType pipe;
    equation
        connect(feedtank.outlet, pipe.inlet);
        connect(pipe.outlet, harvesttank.inlet);
    end Test;

end DEMO_v41;

The older example DEMO_v40 below is more general and harder to read, but kept for reference since one early answer around this example.

The compilation (JModelica 2.14) error message I get is: “Error in flattened model: The system is structurally singular. The following variables(s) could not be matched to an equation: harvesttank.inlet.c[1], pipe.outlet.c[1]. OpenModelica (1.16) gives about the same message. What is wrong here?

package DEMO_v40

//  ---------------------------------------------------------------------------------------------
//     Interfaces  
//  ---------------------------------------------------------------------------------------------

    import Modelica.Blocks.Interfaces.RealInput;
    import Modelica.Blocks.Interfaces.RealOutput;

    partial package MediumBase
        constant String name                                   "Medium name";
        constant Integer nc                                    "Number of substances";
        replaceable type Concentration = Real[nc]              "Substance conc";        
    end MediumBase;

    package Medium1 
        extends MediumBase
            (name="One component medium",
             nc=1);
        constant Real[nc] mw = {10}                            "Substance weight";  
        constant Integer A = 1                                 "Substance index";
    end Medium1;

    record Medium_data
        constant String name = Medium1.name;
        constant Integer nc = Medium1.nc;
        constant Real[nc] mw = Medium1.mw;
        constant Integer A = Medium1.A;
    end Medium_data;

//  ---------------------------------------------------------------------------------------------
//     Equipment dependent on the medium  
//  ---------------------------------------------------------------------------------------------

    package EquipmentLib
        replaceable package Medium = MediumBase                // formal parameter - EquipmentLib
            constrainedby MediumBase;

        connector LiquidCon
            Real P                                             "Pressure"; 
            flow Real F (unit="m3/s")                          "Flow rate";
            stream Medium.Concentration c                      "Substance conc";
        end LiquidCon;

        model PipeType
            LiquidCon inlet, outlet;
            parameter Real area = 1;
        equation
            inlet.F = -outlet.F;
            outlet.F = area^2*(inlet.P - outlet.P);            // Linearized Bernoulli equation
            for i in 1:Medium.nc loop
                outlet.c[i] = inlet.c[i];
            end for;
        end PipeType;

        model FeedtankType
            LiquidCon outlet;                                  
            parameter Real P = 0.1                             "Pressure"; 
            parameter Real V_0 (unit="m3") = 100               "Initial feed volume";         
            parameter Real[Medium.nc] c_in (each unit="kg/m3") 
                            = {1.0*k for k in 1:Medium.nc}     "Feed inlet conc";                        
            Real V(start=V_0, fixed=true, unit="m3")           "Feed volume";
        equation    
            for i in 1:Medium.nc loop
                outlet.c[i] = c_in[i];
            end for;
            outlet.P = P;
            der(V) = outlet.F;               
        end FeedtankType;

        model HarvesttankType
            LiquidCon inlet;
            parameter Real P = 0.0                             "Pressure";                      
            parameter Real V_0 (unit="m3") = 1.0               "Initial harvest liquid volume";
            parameter Real[Medium.nc] m_0 
                  (each unit="kg/m3") = zeros(Medium.nc)       "Initial substance mass";
            Real[Medium.nc] m 
                  (start=m_0, each fixed=true)                 "Substance mass";
            Real[Medium.nc] c                                  "Substance conc"; 
            Real V(start=V_0, fixed=true, unit="m3")           "Harvest liquid volume";
        equation
            inlet.P = P;
            der(V) = inlet.F;
            for i in 1:Medium.nc loop
                der(m[i]) = inStream(inlet.c[i])*inlet.F;
                c[i] = m[i]/V;
            end for;               
        end HarvesttankType;
    end EquipmentLib;

//  ---------------------------------------------------------------------------------------------
//     Adaptation of package Equipment to Medium1 
//  ---------------------------------------------------------------------------------------------

    package Equipment
        import DEMO_v40.EquipmentLib;
        extends EquipmentLib(redeclare package Medium=Medium1);
    end Equipment;

//  ---------------------------------------------------------------------------------------------
//     Examples of systems 
//  ---------------------------------------------------------------------------------------------

    model Test
        Medium_data medium;
        Equipment.FeedtankType feedtank;
        Equipment.HarvesttankType harvesttank;
        Equipment.PipeType pipe;
    equation
        connect(feedtank.outlet, pipe.inlet);
        connect(pipe.outlet, harvesttank.inlet);
    end Test;

end DEMO_v40;

Solution

  • After some thought I believe the following is your example converted to use stream variables directly (although I agree that making it compatible with MSL would be good, as @ReneJustNielsen suggested).

    package DEMO_v42
    
    //  ---------------------------------------------------------------------------------------------
    //     Interfaces  
    //  ---------------------------------------------------------------------------------------------
    
        import Modelica.Blocks.Interfaces.RealInput;
        import Modelica.Blocks.Interfaces.RealOutput;
    
    //  ---------------------------------------------------------------------------------------------
    //     Equipment
    //  ---------------------------------------------------------------------------------------------
    
        package EquipmentLib
    
            connector LiquidCon
                Real P                                             "Pressure";
                flow Real F                                        "Flow rate";
          stream Real c_outflow "Substance conc";
            end LiquidCon;
    
            model PipeType
                LiquidCon inlet, outlet;
                parameter Real area = 1;
            equation 
                inlet.F = -outlet.F;
                outlet.F = -area^2*(inlet.P - outlet.P);           // Linearized Bernoulli equation
                outlet.c_outflow = inStream(inlet.c_outflow);
                inlet.c_outflow=inStream(outlet.c_outflow);
            end PipeType;
    
            model FeedtankType
                LiquidCon outlet;
                parameter Real P = 0.1                             "Pressure";
                parameter Real V_0 = 100                           "Initial feed volume";
                parameter Real c_in = 1.0                          "Feedtank conc";
                Real V(start=V_0, fixed=true)                      "Feed volume";
            equation 
                outlet.c_outflow = c_in;
                outlet.P = P;
                der(V) = outlet.F;
            end FeedtankType;
    
            model HarvesttankType
                LiquidCon inlet;
                parameter Real P = 0.0                             "Pressure";
                parameter Real V_0 = 1.0                           "Initial harvest liquid volume";
                parameter Real m_0 = 0.0                           "Initial substance mass";
                Real V(start=V_0, fixed=true)                      "Harvest liquid volume";
                Real m(start=m_0, fixed=true)                      "Substance mass";
                Real c                                             "Substance conc";
                Real inletC=actualStream(inlet.c_outflow);
            equation 
                inlet.P = P;
                inlet.c_outflow=c;
                der(V) = inlet.F;
                der(m) = actualStream(inlet.c_outflow)*inlet.F;
                c = m/V;
            end HarvesttankType;
        end EquipmentLib;
    
    //  ---------------------------------------------------------------------------------------------
    //     Example of system 
    //  ---------------------------------------------------------------------------------------------
    
        model Test
            EquipmentLib.FeedtankType feedtank;
            EquipmentLib.HarvesttankType harvesttank;
            EquipmentLib.PipeType pipe;
        equation 
            connect(feedtank.outlet, pipe.inlet);
            connect(pipe.outlet, harvesttank.inlet);
        end Test;
    
    end DEMO_v42;
    

    I added inletC to be able to compare the concentrations with the previous models.

    The major change is that for a stream variable, c_outflow, there are in fact two/three different variables to use:

    So for the pipe you write that the concentration flowing out from one port equals the concentration flowing into the other port, and vice versa. For the tank you just write the equation for c_outflow, but use actualStream to get the actual concentration in the flow.