How to construct a balanced connector for liquids in Modelica?

Personally, I would "go all the way" and use stream connectors for the following reasons:

  1. During the last 15–20 years, many attempts have been made to create good thermo-hydraulic connectors in Modelica. The effort resulted in stream connectors in 2008 which is currently state-of-the-art in Modelica. It allows you to transport specific enthalpy and substance fractions (or species concentrations) with one flow variable and it enables flow reversal. Using stream connectors is not overkill.
  2. Adhering to e.g. Modelica.Fluid.Interfaces.FluidPort, your work will be compatible with many existing libraries and models and you don't need to make pumps, pipes, valves, tank models etc. yourself.

You will be faced with a couple of challenges, though:

  1. You'll need to learn the syntax and the workings of stream connectors. You can find inspiration in https://github.com/justnielsen/ModelicaTutorials
  2. You must implement a medium model based on Modelica.Media for the fluid that you will be transporting in the stream connectors. A medium models doesn't have to be very complex if you can assume constant density and/or specific heat capacity, for example. If the medium model is simple, it is computationally easy to switch between volume/mass flow rate when you specify the boundary conditions (source/sinks).

The correct way would be either

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

or

connector LiquidCon
   Real c        “Component concentrations”;
   flow Real F       “Flow rate”;
end LiquidCon;

Depending on what you want to model. Rule of thumb is: number of potentials = number of flows. Since you only use one flow and multiple concentrations it implies that you have multiple tanks-like components each with some concentration, connected by pipe-like components that allow a flow rate.

For these i would recommend the second version i posted!

Some background information: A connector is never balanced, it is assumed to provide half the number of equations compared to its unknowns. Whenever you add a connector to a component, that component has to balance it. The reason is quite simple: E.g. a connector with one potential and one flow. The direction in which the information flows is unclear, but certain is, that either the flow variable is considered known or the potential is considered known, the other one will be computed by the equations of the component. For the tank the concentration is computed by its own equations and the flow is passed by the connector (vice versa for the pipe).

Whenever two or more connector are connected all potentials are set equal and all flows sum up to be zero (Modelica Language Specification section 9.2).

I changed your example such that i can actually individually test the components. Note that i added a default value to nc, otherwise it is not possible to check single components for consistency.

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 = 1                           "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";


        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;

With this i went to OMEdit and checked every component individually with the CheckModel button (Single check mark on green circle in the top middle of OMEdit). I realized that your connector has 3 unknowns and 1 equation which is illegal (as i said it should be 2:1 ratio). That also results in all your other components being illegal.

Since it would be quite the work to debug all your stuff i can only provide something i made some time ago for a student project but it should showcase what has to be done. You don't need to pass both pressure and concentration since they should be algebraically connected anyways. I used the height instead.

See following answer for model, it does not fit in this (and i can't add files here).

EDIT: I just made a git repository. Much easier actually:

HTTPS: https://github.com/kabdelhak/TankSystem

SSH: [email protected]:kabdelhak/TankSystem.git