Devices for storing fluid

within Modelica.Fluid;
package Vessels "Devices for storing fluid"
    extends Modelica.Icons.VariantsPackage;

    model ClosedVolume
    "Volume of fixed size, closed to the ambient, with inlet/outlet ports"
    import Modelica.Constants.pi;

      // Mass and energy balance, ports
      extends Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel(
        final fluidVolume = V,
        vesselArea = pi*(3/4*V)^(2/3),
        heatTransfer(surfaceAreas={4*pi*(3/4*V/pi)^(2/3)}));

      parameter SI.Volume V "Volume";

    equation
      Wb_flow = 0;
      for i in 1:nPorts loop
        vessel_ps_static[i] = medium.p;
      end for;
    end ClosedVolume;

model OpenTank "Simple tank with inlet/outlet ports"
    import Modelica.Constants.pi;

  // Tank properties
  SI.Height level(stateSelect=StateSelect.prefer, start=level_start_eps)
      "Level height of tank";
  SI.Volume V(stateSelect=StateSelect.never) "Actual tank volume";

  // Tank geometry
  parameter SI.Height height "Height of tank";
  parameter SI.Area crossArea "Area of tank";

  // Ambient
  parameter Medium.AbsolutePressure p_ambient=system.p_ambient
      "Tank surface pressure"
  parameter Medium.Temperature T_ambient=system.T_ambient
      "Tank surface Temperature"

  // Initialization
  parameter SI.Height level_start(min=0) = 0.5*height
      "Start value of tank level"

  // Mass and energy balance, ports
  extends Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel(
    final fluidVolume = V,
    final fluidLevel = level,
    final fluidLevel_max = height,
    final vesselArea = crossArea,
    heatTransfer(surfaceAreas={crossArea+2*sqrt(crossArea*pi)*level}),
    final initialize_p = false,
    final p_start = p_ambient);

  protected
  final parameter SI.Height level_start_eps = max(level_start, Modelica.Constants.eps);

equation
  // Total quantities
  V = crossArea*level "Volume of fluid";
  medium.p = p_ambient;

  // Source termsEnergy balance
  if Medium.singleState or energyDynamics == Types.Dynamics.SteadyState then
    Wb_flow = 0
        "Mechanical work is neglected, since also neglected in medium model (otherwise unphysical small temperature change, if tank level changes)";
  else
    Wb_flow = -p_ambient*der(V);
  end if;

  //Determine port properties
  for i in 1:nPorts loop
    vessel_ps_static[i] = max(0, level - portsData_height[i])*system.g*medium.d + p_ambient;
  end for;

initial equation
  if massDynamics == Types.Dynamics.FixedInitial then
    level = level_start_eps;
  elseif massDynamics == Types.Dynamics.SteadyStateInitial then
    der(level) = 0;
  end if;
end OpenTank;

  package BaseClasses
    "Base classes used in the Vessels package (only of interest to build new component models)"
    extends Modelica.Icons.BasesPackage;

      partial model PartialLumpedVessel
      "Lumped volume with a vector of fluid ports and replaceable heat transfer model"
        extends Modelica.Fluid.Interfaces.PartialLumpedVolume;

        // Port definitions
        parameter Integer nPorts=0 "Number of ports"
        VesselFluidPorts_b ports[nPorts](redeclare each package Medium = Medium)
        "Fluid inlets and outlets"

        // Port properties
        parameter Boolean use_portsData=true
        "= false to neglect pressure loss and kinetic energy"
        parameter Modelica.Fluid.Vessels.BaseClasses.VesselPortsData[if use_portsData then nPorts else 0]
        portsData "Data of inlet/outlet ports"

        parameter Medium.MassFlowRate m_flow_nominal = if system.use_eps_Re then system.m_flow_nominal else 1e2*system.m_flow_small
        "Nominal value for mass flow rates in ports"
        parameter SI.MassFlowRate m_flow_small(min=0) = if system.use_eps_Re then system.eps_m_flow*m_flow_nominal else system.m_flow_small
        "Regularization range at zero mass flow rate"
        parameter Boolean use_Re = system.use_eps_Re
        "= true, if turbulent region is defined by Re, otherwise by m_flow_small"

        Medium.EnthalpyFlowRate ports_H_flow[nPorts];
        Medium.MassFlowRate ports_mXi_flow[nPorts,Medium.nXi];
        Medium.MassFlowRate[Medium.nXi] sum_ports_mXi_flow
        "Substance mass flows through ports";
        Medium.ExtraPropertyFlowRate ports_mC_flow[nPorts,Medium.nC];
        Medium.ExtraPropertyFlowRate[Medium.nC] sum_ports_mC_flow
        "Trace substance mass flows through ports";

        // Heat transfer through boundary
        parameter Boolean use_HeatTransfer = false
        "= true to use the HeatTransfer model"
        replaceable model HeatTransfer =
            Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer
          constrainedby
        Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer
        "Wall heat transfer"
        HeatTransfer heatTransfer(
          redeclare package Medium = Medium,
          final n=1,
          final states = {medium.state},
          final use_k = use_HeatTransfer)
        Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort if use_HeatTransfer

        // Conservation of kinetic energy
        Medium.Density[nPorts] portInDensities
        "Densities of the fluid at the device boundary";
        SI.Velocity[nPorts] portVelocities
        "Velocities of fluid flow at device boundary";
        SI.EnergyFlowRate[nPorts] ports_E_flow
        "Flow of kinetic and potential energy at device boundary";

        // Note: should use fluidLevel_start - portsData.height
        Real[nPorts] s(each start = fluidLevel_max)
        "Curve parameters for port flows vs. port pressures; for further details see, Modelica Tutorial: Ideal switching devices";
        Real[nPorts] ports_penetration
        "Penetration of port with fluid, depending on fluid level and port diameter";

        // treatment of pressure losses at ports
        SI.Area[nPorts] portAreas = {Modelica.Constants.pi/4*portsData_diameter[i]^2 for i in 1:nPorts};
        Medium.AbsolutePressure[nPorts] vessel_ps_static
        "Static pressures inside the vessel at the height of the corresponding ports, zero flow velocity";

        // determination of turbulent region
        constant SI.ReynoldsNumber Re_turbulent = 100 "cf. suddenExpansion";
        SI.MassFlowRate[nPorts] m_flow_turbulent;

    protected
        input SI.Height fluidLevel = 0
        "Level of fluid in the vessel for treating heights of ports";
        parameter SI.Height fluidLevel_max = 1
        "Maximum level of fluid in the vessel";
        parameter SI.Area vesselArea = Modelica.Constants.inf
        "Area of the vessel used to relate to cross flow area of ports";

        // Treatment of use_portsData=false to neglect portsData and to not require its specification either in this case.
        // Remove portsData conditionally if use_portsData=false. Simplify their use in model equations by always
        // providing portsData_diameter and portsData_height, independent of the use_portsData setting.
        // Note: this moreover serves as work-around if a tool does not support a zero sized portsData record.
        Modelica.Blocks.Interfaces.RealInput[nPorts]
        portsData_diameter_internal = portsData.diameter if use_portsData and nPorts > 0;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_height_internal = portsData.height if use_portsData and nPorts > 0;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_in_internal = portsData.zeta_in if use_portsData and nPorts > 0;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_out_internal = portsData.zeta_out if use_portsData and nPorts > 0;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_diameter;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_height;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_in;
        Modelica.Blocks.Interfaces.RealInput[nPorts] portsData_zeta_out;
        Modelica.Blocks.Interfaces.BooleanInput[nPorts] regularFlow(each start=true);
        Modelica.Blocks.Interfaces.BooleanInput[nPorts] inFlow(each start=false);

      equation
        mb_flow = sum(ports.m_flow);
        mbXi_flow = sum_ports_mXi_flow;
        mbC_flow  = sum_ports_mC_flow;
        Hb_flow = sum(ports_H_flow) + sum(ports_E_flow);
        Qb_flow = heatTransfer.Q_flows[1];

        // Only one connection allowed to a port to avoid unwanted ideal mixing
        for i in 1:nPorts loop
          assert(cardinality(ports[i]) <= 1,"
each ports[i] of volume can at most be connected to one component.
If two or more connections are present, ideal mixing takes
place with these connections, which is usually not the intention
of the modeller. Increase nPorts to add an additional port.
");
        end for;
        // Check for correct solution
        assert(fluidLevel <= fluidLevel_max, "Vessel is overflowing (fluidLevel > fluidLevel_max = " + String(fluidLevel) + ")");
        assert(fluidLevel > -1e-6*fluidLevel_max, "Fluid level (= " + String(fluidLevel) + ") is below zero meaning that the solution failed.");

        // Boundary conditions

        // treatment of conditional portsData
        connect(portsData_diameter, portsData_diameter_internal);
        connect(portsData_height, portsData_height_internal);
        connect(portsData_zeta_in, portsData_zeta_in_internal);
        connect(portsData_zeta_out, portsData_zeta_out_internal);
        if not use_portsData then
          portsData_diameter = zeros(nPorts);
          portsData_height = zeros(nPorts);
          portsData_zeta_in = zeros(nPorts);
          portsData_zeta_out = zeros(nPorts);
        end if;

        // actual definition of port variables
        for i in 1:nPorts loop
          portInDensities[i] = Medium.density(Medium.setState_phX(vessel_ps_static[i], inStream(ports[i].h_outflow), inStream(ports[i].Xi_outflow)));
          if use_portsData then
            // dp = 0.5*zeta*d*v*|v|
            // Note: assume vessel_ps_static for portVelocities to avoid algebraic loops for ports.p
            portVelocities[i] = smooth(0, ports[i].m_flow/portAreas[i]/Medium.density(Medium.setState_phX(vessel_ps_static[i], actualStream(ports[i].h_outflow), actualStream(ports[i].Xi_outflow))));
            // Note: the penetration should not go too close to zero as this would prevent a vessel from running empty
            ports_penetration[i] = Utilities.regStep(fluidLevel - portsData_height[i] - 0.1*portsData_diameter[i], 1, 1e-3, 0.1*portsData_diameter[i]);
            m_flow_turbulent[i]=if not use_Re then m_flow_small else
              max(m_flow_small, (Modelica.Constants.pi/8)*portsData_diameter[i]
                                 *(Medium.dynamicViscosity(Medium.setState_phX(vessel_ps_static[i], inStream(ports[i].h_outflow), inStream(ports[i].Xi_outflow)))
                                   + Medium.dynamicViscosity(medium.state))*Re_turbulent);
          else
            // an infinite port diameter is assumed
            portVelocities[i] = 0;
            ports_penetration[i] = 1;
            m_flow_turbulent[i] = Modelica.Constants.inf;
          end if;

          // fluid flow through ports
          regularFlow[i] = fluidLevel >= portsData_height[i];
          inFlow[i]      = not regularFlow[i] and (s[i] > 0 or portsData_height[i] >= fluidLevel_max);
          if regularFlow[i] then
            // regular operation: fluidLevel is above ports[i]
            // Note: >= covers default values of zero as well
            if use_portsData then
              /* Without regularization
                 ports[i].p = vessel_ps_static[i] + 0.5*ports[i].m_flow^2/portAreas[i]^2
                              * noEvent(if ports[i].m_flow>0 then zeta_in[i]/portInDensities[i] else -zeta_out[i]/medium.d);
              */

              ports[i].p = vessel_ps_static[i] + (0.5/portAreas[i]^2*Utilities.regSquare2(ports[i].m_flow, m_flow_turbulent[i],
                                (portsData_zeta_in[i] - 1 + portAreas[i]^2/vesselArea^2)/portInDensities[i]*ports_penetration[i],
                                (portsData_zeta_out[i] + 1 - portAreas[i]^2/vesselArea^2)/medium.d/ports_penetration[i]));
              /*
                // alternative formulation m_flow=f(dp); not allowing the ideal portsData_zeta_in[i]=1 though
                ports[i].m_flow = smooth(2, portAreas[i]*Utilities.regRoot2(ports[i].p - vessel_ps_static[i], dp_small,
                                       2*portInDensities[i]/portsData_zeta_in[i],
                                       2*medium.d/portsData_zeta_out[i]));
              */
            else
              ports[i].p = vessel_ps_static[i];
            end if;
            s[i] = fluidLevel - portsData_height[i];

          elseif inFlow[i] then
            // ports[i] is above fluidLevel and has inflow
            ports[i].p = vessel_ps_static[i];
            s[i] = ports[i].m_flow;

          else
            // ports[i] is above fluidLevel, preventing outflow
            ports[i].m_flow = 0;
            s[i] = (ports[i].p - vessel_ps_static[i])/Medium.p_default*(portsData_height[i] - fluidLevel);
          end if;

          ports[i].h_outflow  = medium.h;
          ports[i].Xi_outflow = medium.Xi;
          ports[i].C_outflow  = C;

          ports_H_flow[i] = ports[i].m_flow * actualStream(ports[i].h_outflow)
          "Enthalpy flow";
          ports_E_flow[i] = ports[i].m_flow*(0.5*portVelocities[i]*portVelocities[i] + system.g*portsData_height[i])
          "Flow of kinetic and potential energy";
          ports_mXi_flow[i,:] = ports[i].m_flow * actualStream(ports[i].Xi_outflow)
          "Component mass flow";
          ports_mC_flow[i,:]  = ports[i].m_flow * actualStream(ports[i].C_outflow)
          "Trace substance mass flow";
        end for;

        for i in 1:Medium.nXi loop
          sum_ports_mXi_flow[i] = sum(ports_mXi_flow[:,i]);
        end for;

        for i in 1:Medium.nC loop
          sum_ports_mC_flow[i]  = sum(ports_mC_flow[:,i]);
        end for;

        connect(heatPort, heatTransfer.heatPorts[1])
      end PartialLumpedVessel;

  package HeatTransfer "HeatTransfer models for vessels"
    extends Modelica.Icons.Package;

    partial model PartialVesselHeatTransfer
        "Base class for vessel heat transfer models"
      extends Modelica.Fluid.Interfaces.PartialHeatTransfer;
    end PartialVesselHeatTransfer;

    model IdealHeatTransfer
        "IdealHeatTransfer: Ideal heat transfer without thermal resistance"
      extends PartialVesselHeatTransfer;

    equation
      Ts = heatPorts.T;
    end IdealHeatTransfer;

    model ConstantHeatTransfer
        "ConstantHeatTransfer: Constant heat transfer coefficient"
      extends PartialVesselHeatTransfer;
      parameter SI.CoefficientOfHeatTransfer alpha0
          "Constant heat transfer coefficient";

    equation
      Q_flows = {(alpha0+k)*surfaceAreas[i]*(heatPorts[i].T - Ts[i]) for i in 1:n};
    end ConstantHeatTransfer;

  end HeatTransfer;

    record VesselPortsData "Data to describe inlet/outlet ports at vessels:
    diameter -- Inner (hydraulic) diameter of inlet/outlet port
    height -- Height over the bottom of the vessel
    zeta_out -- Hydraulic resistance out of vessel, default 0.5 for small diameter mounted flush with the wall
    zeta_in -- Hydraulic resistance into vessel, default 1.04 for small diameter mounted flush with the wall"
          extends Modelica.Icons.Record;
      parameter SI.Diameter diameter
        "Inner (hydraulic) diameter of inlet/outlet port";
      parameter SI.Height height = 0 "Height over the bottom of the vessel";
      parameter Real zeta_out(min=0)=0.5
        "Hydraulic resistance out of vessel, default 0.5 for small diameter mounted flush with the wall";
      parameter Real zeta_in(min=0)=1.04
        "Hydraulic resistance into vessel, default 1.04 for small diameter mounted flush with the wall"; only the ζ
loss factors are discussed further. All data is quoted from Idelchik (1994).

Outlet Coefficients

If a straight pipe with constant cross section is mounted flush with the wall, its outlet pressure loss coefficient will be ζ = 0.5 (Idelchik, p. 160, Diagram 3-1, paragraph 2).

If a straight pipe with constant cross section is mounted into a vessel such that the entrance into it is at a distance b from the wall (inside) the following table can be used. Herein, δ is the tube wall thickness (Idelchik, p. 160, Diagram 3-1, paragraph 1).

Pressure loss coefficients for outlets, entrance at a distance from wall

    	    	 b / D_hyd

    	    	 0.000 	 0.005 	 0.020 	 0.100 	 0.500-∞

     δ / D_hyd	  0.000 	 0.50 	 0.63  	 0.73  	 0.86  	      1.00

               0.008 	 0.50 	 0.55  	 0.62  	 0.74  	      0.88

               0.016 	 0.50 	 0.51  	 0.55  	 0.64  	      0.77

               0.024 	 0.50 	 0.50  	 0.52  	 0.58  	      0.68

               0.040 	 0.50 	 0.50  	 0.51  	 0.51  	      0.54

If a straight pipe with a circular bellmouth inlet (collector) without baffle is mounted flush with the wall then its pressure loss coefficient can be established from the following table. Herein, r is the radius of the bellmouth inlet surface (Idelchik, p. 164 f., Diagram 3-4, paragraph b)

Pressure loss coefficients for outlets, bellmouth flush with wall

    	  r / D_hyd

    	  0.01 	 0.03 	 0.05 	 0.08 	 0.16 	≥0.20

     ζ	  0.44 	 0.31 	 0.22  	 0.15  	 0.06  	      0.03

If a straight pipe with a circular bellmouth inlet (collector) without baffle is mounted at a distance from a wall then its pressure loss coefficient can be established from the following table. Herein, r is the radius of the bellmouth inlet surface (Idelchik, p. 164 f., Diagram 3-4, paragraph a)

Pressure loss coefficients for outlets, bellmouth at a distance of wall

    	  r / D_hyd

    	  0.01 	 0.03 	 0.05 	 0.08 	 0.16 	≥0.20

     ζ	  0.87 	 0.61 	 0.40  	 0.20  	 0.06  	      0.03

Inlet Coefficients

If a straight pipe with constant circular cross section is mounted flush with the wall, its vessel inlet pressure loss coefficient will be according to the following table (Idelchik, p. 209 f., Diagram 4-2 with A_port/A_vessel = 0 and Idelchik, p. 640, Diagram 11-1, graph a). According to the text, m = 9 is appropriate for fully developed turbulent flow.

Pressure loss coefficients for inlets, circular tube flush with wall

    	  m

    	  1.0 	 2.0 	 3.0 	 4.0 	 7.0 	9.0

     ζ	  2.70 	 1.50 	 1.25  	 1.15  	 1.06  	      1.04

For larger port diameters, relative to the area of the vessel, the inlet pressure loss coefficient will be according to the following table (Idelchik, p. 209 f., Diagram 4-2 with m = 7).

Pressure loss coefficients for inlets, circular tube flush with wall

    	  A_port / A_vessel

    	  0.0 	 0.1 	 0.2 	 0.4 	 0.6 	0.8

     ζ	  1.04 	 0.84 	 0.67  	 0.39  	 0.18  	      0.06

References

Idelchik I.E. (1994):

Handbook
        of Hydraulic Resistance. 3rd edition, Begell House, ISBN
        0-8493-9908-4

"));
    end VesselPortsData;

    connector VesselFluidPorts_a
      "Fluid connector with filled, large icon to be used for horizontally aligned vectors of FluidPorts (vector dimensions must be added after dragging)"
      extends Interfaces.FluidPort;
    end VesselFluidPorts_a;

    connector VesselFluidPorts_b
      "Fluid connector with outlined, large icon to be used for horizontally aligned vectors of FluidPorts (vector dimensions must be added after dragging)"
      extends Interfaces.FluidPort;
    end VesselFluidPorts_b;
  end BaseClasses;
end Vessels;


within Modelica.Fluid.Examples;
package AST_BatchPlant
  "Model of the experimental batch plant at the Process Dynamics and Operations Group (DYN) at University of Dortmund (Prof. Engell)"
  extends Modelica.Icons.ExamplesPackage;

  model BatchPlant_StandardWater "Model of an experimental batch plant"
      extends Modelica.Icons.Example;
    replaceable package BatchMedium = Modelica.Media.Water.StandardWater constrainedby
      Modelica.Media.Interfaces.PartialTwoPhaseMedium "Component media";

    parameter SI.Length pipeDiameter = 0.01 "Pipe diameter";

    BaseClasses.TankWith3InletOutletArraysWithEvaporatorCondensor B5(
      redeclare package Medium = BatchMedium,
      height=0.5,
      n_SidePorts=1,
      V0=0.001,
      n_BottomPorts=1,
      bottom_pipeArea={0.0001},
      top_pipeArea={0.0001},
      n_TopPorts=1,
      min_level_for_heating=0.0001,
      level_start=0.0009,
      crossArea=0.05,
      initType=BaseClasses.Init.InitialValues,
      side_pipeArea={0.0001},
      redeclare model HeatTransfer =
          Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer (k=
              4.9))
    Modelica.Fluid.Valves.ValveDiscreteRamp V12(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V15(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow HeatB5
    Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow CoolingB7
    Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow CoolingB6

    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.Controller controller(
        Transition3(enableTimer=true, waitTime=60), Transition7(
        condition=true,
        enableTimer=true,
        waitTime=300))

    Modelica.Fluid.Valves.ValveDiscreteRamp V11(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V8(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V9(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V2(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V4(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V3(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Fittings.TeeJunctionIdeal volume2(
      redeclare package Medium = BatchMedium)
    Modelica.Fluid.Valves.ValveDiscreteRamp V6(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Fittings.TeeJunctionIdeal volume8(
      redeclare package Medium = BatchMedium)
    Modelica.Fluid.Valves.ValveDiscreteRamp V23(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V1(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 0.1,
      dp_nominal = 1000,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V22(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 0.1,
      dp_nominal = 1000,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V5(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 0.1,
      dp_nominal = 1000,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V24(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V25(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 0.1,
      dp_nominal = 1000,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V20(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V19(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V10(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Valves.ValveDiscreteRamp V21(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Modelica.Fluid.Fittings.TeeJunctionVolume volume5(
      redeclare package Medium = BatchMedium,
      V=0.001)
    Modelica.Fluid.Valves.ValveDiscreteRamp V18(
      redeclare package Medium = BatchMedium,
      m_flow_nominal = 1,
      dp_nominal = 100,
      Topen = 0.1)
    Machines.PrescribedPump P1(
      redeclare package Medium = BatchMedium,
      m_flow_start=0.1,
      N_nominal=200,
      use_N_in=true,
      redeclare model Monitoring =
          Modelica.Fluid.Machines.BaseClasses.PumpMonitoring.PumpMonitoringNPSH,
      V(displayUnit="ml") = 0.0001,
      energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
      massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
      redeclare function flowCharacteristic =
          Modelica.Fluid.Machines.BaseClasses.PumpCharacteristics.quadraticFlow
          (V_flow_nominal={0,0.1e-3,0.15e-3}, head_nominal={10,5,0}),
      p_a_start=100000,
      p_b_start=100000)
    Machines.PrescribedPump P2(
      redeclare package Medium = BatchMedium,
      m_flow_start=0.1,
      N_nominal=200,
      use_N_in=true,
      redeclare model Monitoring =
          Modelica.Fluid.Machines.BaseClasses.PumpMonitoring.PumpMonitoringNPSH,
      V(displayUnit="ml") = 0.0001,
      energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
      massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
      redeclare function flowCharacteristic =
          Modelica.Fluid.Machines.BaseClasses.PumpCharacteristics.quadraticFlow
          (V_flow_nominal={0,0.1e-3,0.15e-3}, head_nominal={10,5,0}),
      p_a_start=100000,
      p_b_start=100000)
    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts B1(
      level_start=0.2,
      redeclare package Medium = BatchMedium,
      height=0.5,
      crossArea=0.05,
      V0=0.0001,
      nTopPorts=1,
      nPorts=1,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
        diameter=0.011,
        height=0)},
      stiffCharacteristicForEmptyPort=false)
    inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial, dp_small=1000)
    Modelica.Blocks.Logical.TriggeredTrapezoid P1_on(rising=0.3,
        amplitude=200)
    Modelica.Blocks.Logical.TriggeredTrapezoid P2_on(rising=0.3,
        amplitude=200)
    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts B2(
      level_start=0.2,
      redeclare package Medium = BatchMedium,
      height=0.5,
      crossArea=0.05,
      V0=0.0001,
      nTopPorts=1,
      nPorts=1,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
        diameter=0.011,
        height=0)},
      stiffCharacteristicForEmptyPort=false)
    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts B3(
      redeclare package Medium = BatchMedium,
      height=0.5,
      crossArea=0.05,
      V0=0.0001,
      nTopPorts=2,
      nPorts=2,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
        diameter=0.011,
        height=0),Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(diameter=
           0.011, height=0)},
      level_start=0.02,
      stiffCharacteristicForEmptyPort=false)
    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts B4(
      redeclare package Medium = BatchMedium,
      height=0.5,
      crossArea=0.05,
      V0=0.0001,
      level_start=0.015,
      nTopPorts=1,
      nPorts=1,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
        diameter=0.011,
        height=0)},
      stiffCharacteristicForEmptyPort=false)
    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts B7(
      redeclare package Medium = BatchMedium,
      V0=0.0001,
      nTopPorts=1,
      nPorts=1,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
        diameter=0.011,
        height=0)},
      level_start=0.009,
      height=0.5,
      crossArea=0.05,
      stiffCharacteristicForEmptyPort=false,
      use_HeatTransfer=true,
      T_start=298,
      redeclare model HeatTransfer =
          Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer (k=
              4.9))
    Pipes.DynamicPipe pipeB1B2(
      redeclare package Medium = BatchMedium,
      length=1,
      diameter=pipeDiameter,
      height_ab=0)
    Pipes.StaticPipe pipeB1B3(
      redeclare package Medium = BatchMedium,
      length=1,
      redeclare model FlowModel =
          Modelica.Fluid.Pipes.BaseClasses.FlowModels.DetailedPipeFlow,
      diameter=pipeDiameter,
      height_ab=-0.1)
    Pipes.StaticPipe pipeB2B3(
      redeclare package Medium = BatchMedium,
      length=1,
      redeclare model FlowModel =
          Modelica.Fluid.Pipes.BaseClasses.FlowModels.DetailedPipeFlow,
      diameter=pipeDiameter,
      height_ab=-0.1)
    Pipes.StaticPipe pipeB1B1(
      redeclare package Medium = BatchMedium,
      diameter=pipeDiameter,
      length=1,
      height_ab=-0.5)
    Pipes.StaticPipe pipeB6Pump(
      redeclare package Medium = BatchMedium,
      length=0.5,
      diameter=pipeDiameter,
      height_ab=-0.5)
    Pipes.StaticPipe pipeB7Pump(
      redeclare package Medium = BatchMedium,
      length=1,
      diameter=pipeDiameter,
      height_ab=-0.1)
    Pipes.DynamicPipe pipePump1B1(
      redeclare package Medium = BatchMedium,
      diameter=pipeDiameter,
      height_ab=3,
      length=3)
    Pipes.DynamicPipe pipePump2B2(
      redeclare package Medium = BatchMedium,
      diameter=pipeDiameter,
      height_ab=3,
      length=3)
    Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts B6(
      redeclare package Medium = BatchMedium,
      V0=0.0001,
      nTopPorts=1,
      height=0.5,
      crossArea=0.05,
      level_start=0.02,
      nPorts=1,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
        diameter=0.011,
        height=0)},
      stiffCharacteristicForEmptyPort=false,
      use_HeatTransfer=true,
      T_start=298,
      redeclare model HeatTransfer =
          Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer (k=
              4.9))
    Fittings.MultiPort multiPort(redeclare package Medium = BatchMedium,
        nPorts_b=3)
    Modelica.Fluid.Fittings.TeeJunctionVolume volume4(
      redeclare package Medium = BatchMedium,
      V=0.001)
  equation
    controller.sensors.LIS_301 = B3.level;
    controller.sensors.QI_302 = 0;//B3.medium.X[2];
    controller.sensors.LIS_501 = B5.level;
    controller.sensors.QIS_502 = 0;//B5.medium.X[2];
    controller.sensors.TI_503 = B5.medium.T;
    controller.sensors.LIS_601 = B6.level;
    controller.sensors.TIS_602 = B6.medium.T;
    controller.sensors.LIS_701 = B7.level;
    controller.sensors.TIS_702 = B7.medium.T;

    P1_on.u = controller.actuators.P1;
    P2_on.u = controller.actuators.P2;
    V1.open = controller.actuators.V1;
    V2.open = controller.actuators.V2;
    V3.open = controller.actuators.V3;
    V4.open = controller.actuators.V4;
    V5.open = controller.actuators.V5;
    V6.open = controller.actuators.V6;
    V8.open = controller.actuators.V8;
    V9.open = controller.actuators.V9;
    V10.open = controller.actuators.V10;
    V11.open = controller.actuators.V11;
    V12.open = controller.actuators.V12;
    V15.open = controller.actuators.V15;
    V18.open = controller.actuators.V18;
    V19.open = controller.actuators.V19;
    V20.open = controller.actuators.V20;
    V21.open = controller.actuators.V21;
    V22.open = controller.actuators.V22;
    V23.open = controller.actuators.V23;
    V24.open = controller.actuators.V24;
    V25.open = controller.actuators.V25;
    HeatB5.Q_flow = if controller.actuators.T5_Heater then 20000 else 0;
    CoolingB6.Q_flow = if controller.actuators.T6_Cooling then -2000 else 0;
    CoolingB7.Q_flow = if controller.actuators.T7_Cooling then -2000 else 0;

    connect(V24.port_b, P2.port_a)
    connect(V15.port_a, B5.BottomFluidPort[1])
    connect(P1_on.y, P1.N_in)
    connect(P2_on.y, P2.N_in)
    connect(B4.ports[1], V12.port_b)
    connect(CoolingB7.port, B7.heatPort)
    connect(pipeB1B2.port_a, V4.port_b)
    connect(B5.TopFluidPort[1], V12.port_a)
    connect(V15.port_b, B7.topPorts[1])
    connect(pipePump1B1.port_a, V22.port_b)
    connect(V25.port_b, pipePump2B2.port_a)
    connect(B6.topPorts[1], B5.Condensed)
    connect(CoolingB6.port, B6.heatPort)
    connect(HeatB5.port, B5.heatPort)
    connect(V1.port_b, volume2.port_1)
    connect(volume8.port_2, V4.port_a)
    connect(volume8.port_1, V5.port_b)
    connect(volume5.port_1, V21.port_b)
    connect(volume5.port_2, V24.port_a)
    connect(P2.port_b, V25.port_a)
    connect(V22.port_a, P1.port_b)
    connect(V5.port_a, pipePump2B2.port_b)
    connect(V1.port_a, pipePump1B1.port_b)
    connect(P1.port_a, V23.port_b)
    connect(V23.port_a, volume4.port_1)
    connect(volume4.port_2, V21.port_a)
    connect(multiPort.port_a, volume4.port_3)
    connect(multiPort.ports_b[3], V19.port_b)
    connect(V18.port_b, multiPort.ports_b[1])
    connect(V10.port_b, multiPort.ports_b[2])
    connect(V11.port_b, B4.topPorts[1])
    connect(B3.ports[1], V11.port_a)
    connect(V20.port_b, volume5.port_3)
    connect(V2.port_b, pipeB1B2.port_b)
    connect(volume2.port_2, V2.port_a)
    connect(volume2.port_3, V3.port_a)
    connect(V3.port_b, B1.topPorts[1])
    connect(volume8.port_3, V6.port_a)
    connect(V6.port_b, B2.topPorts[1])
    connect(B2.ports[1], V9.port_a)
    connect(V9.port_b, pipeB2B3.port_a)
    connect(pipeB2B3.port_b, B3.topPorts[2])
    connect(B1.ports[1], V8.port_a)
    connect(V8.port_b, pipeB1B3.port_a)
    connect(B3.topPorts[1], pipeB1B3.port_b)
    connect(B7.ports[1], pipeB7Pump.port_a)
    connect(pipeB7Pump.port_b, V18.port_a)
    connect(B6.ports[1], pipeB6Pump.port_a)
    connect(pipeB6Pump.port_b, V20.port_a)
    connect(V19.port_a, pipeB6Pump.port_b)
    connect(pipeB1B1.port_b, V10.port_a)
    connect(B3.ports[2], pipeB1B1.port_a)
  end BatchPlant_StandardWater;

  package BaseClasses
    extends Modelica.Icons.BasesPackage;

    model TankWith3InletOutletArraysWithEvaporatorCondensor
      "Tank with Heating and Evaporation"
      import Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.Init;
      replaceable package Medium = Modelica.Media.Water.WaterIF97_ph
        constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
        "Medium in the component"
    // parameter for Tank
      parameter SI.Area crossArea "Tank area";
      parameter SI.Area top_pipeArea[n_TopPorts] "Area of outlet pipe";
      parameter SI.Area side_pipeArea[n_SidePorts] "Area of outlet pipe";
      parameter SI.Area bottom_pipeArea[n_BottomPorts] "Area of outlet pipe";
      parameter SI.Height height = 10 "Height of Tank";
      parameter SI.Volume V0=0 "Volume of the liquid when the level is zero";
      constant SI.Acceleration g=Modelica.Constants.g_n;
      parameter SI.Height side_heights[n_SidePorts]=zeros(n_SidePorts) "Side heights";
      parameter SI.Height bottom_heights[n_BottomPorts]=zeros(n_BottomPorts) "Bottom heights";
      parameter SI.Height top_heights[n_TopPorts]=fill(height, n_TopPorts) "Top heights";
      parameter SI.Height level_start "Initial tank level"
      parameter Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.Init
        initType = Init.GuessValues
        "Initialization option"
      parameter Boolean use_T_start=true
        "= true, if T_start is used, otherwise h_start"
      parameter Medium.Temperature T_start=if use_T_start then 293.15 else
          Medium.temperature_phX(p_ambient, h_start, X_start)
        "Start value of temperature"
      parameter Medium.SpecificEnthalpy h_start=if use_T_start then Medium.specificEnthalpy_pTX(
          p_ambient, T_start, X_start[1:Medium.nXi]) else 1e4
        "Start value of specific enthalpy"
      parameter Medium.MassFraction X_start[Medium.nX]=Medium.reference_X
        "Start value of mass fractions m_i/m"
      parameter Medium.AbsolutePressure p_ambient=101325
        "Tank surface pressure";
      parameter Medium.Temperature T_ambient=293.15 "Tank surface Temperature";
      parameter Integer n_TopPorts=1 "Number of top connectors";
      parameter Integer n_SidePorts=1 "Number of side connectors";
      parameter Integer n_BottomPorts=1 "Number of bottom connectors";
      Medium.BaseProperties medium(
        preferredMediumStates=true,
        p(start=p_ambient),
        T(start=T_start),
        Xi(start=X_start[1:Medium.nXi]));
      SI.Height level(
        stateSelect=StateSelect.prefer,
        min=0,
        max=height) "Level height of tank";
      SI.Volume V(stateSelect=StateSelect.never) "Actual tank volume";
      SI.Energy U "Internal energy of tank volume";
      Real m(unit="kg") "Mass of tank volume";
      Real mXi[Medium.nXi](each unit="kg")
        "Component masses of the independent substances";
    // additional variables
      Real H_flow_BottomPorts[n_BottomPorts];
      Real H_flow_SidePorts[n_SidePorts];
      Real H_flow_TopPorts[n_TopPorts];
      Real m_flow_BottomPorts[n_BottomPorts];
      Real m_flow_SidePorts[n_SidePorts];
      Real m_flow_TopPorts[n_TopPorts];

      Real m_flow_BottomPorts_pos[n_BottomPorts];
      Real m_flow_SidePorts_pos[n_SidePorts];
      Real m_flow_TopPorts_pos[n_TopPorts];
      Real m_flow_pos;
      Medium.MassFlowRate mXi_flow_topPorts[n_TopPorts,Medium.nXi];
      Medium.MassFlowRate mXi_flowBottomPorts[n_BottomPorts,Medium.nXi];
      Medium.MassFlowRate mXi_flow_sidePorts[n_SidePorts,Medium.nXi];

    // Connectors and InnerTanks
      Modelica.Fluid.Interfaces.FluidPort_b BottomFluidPort[n_BottomPorts](
        redeclare package Medium = Medium,
        m_flow(each start=0))
      Modelica.Fluid.Interfaces.FluidPort_a TopFluidPort[n_TopPorts](
        redeclare package Medium = Medium,
        m_flow(each start=0))
      Modelica.Fluid.Interfaces.FluidPort_b SideFluidPort[n_SidePorts](
        redeclare package Medium = Medium,
        m_flow(each start=0))
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.InnerTank InnerTankTop[n_TopPorts](
        each h=medium.h,
        each p_ambient=p_ambient,
        each d=medium.d,
        each Xi = medium.Xi,
        aboveLevel={level - top_heights[i] for i in 1:n_TopPorts},
        pipeArea={top_pipeArea[i] for i in 1:n_TopPorts},
        redeclare package Medium = Medium)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.InnerTank
        InnerTankSide[n_SidePorts](
        each h=medium.h,
        each p_ambient=p_ambient,
        each d=medium.d,
        each Xi = medium.Xi,
        aboveLevel={level - side_heights[i] for i in 1:n_SidePorts},
        pipeArea={side_pipeArea[i] for i in 1:n_SidePorts},
        redeclare package Medium = Medium)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.InnerTank
        InnerTankBottom[n_BottomPorts](
        each h=medium.h,
        each p_ambient=p_ambient,
        each d=medium.d,
        each Xi = medium.Xi,
        aboveLevel={level - bottom_heights[i] for i in 1:n_BottomPorts},
        pipeArea={bottom_pipeArea[i] for i in 1:n_BottomPorts},
        redeclare package Medium = Medium)
      Modelica.Fluid.Interfaces.FluidPort_b Condensed(redeclare package Medium =
            Medium)

      // Heat transfer through boundary
      replaceable model HeatTransfer =
          Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer
        constrainedby
        Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer
        "Wall heat transfer"
      HeatTransfer heatTransfer(
        redeclare package Medium = Medium,
        final n=1,
        final states = {medium.state},
        surfaceAreas={crossArea+2*sqrt(crossArea*Modelica.Constants.pi)*level},
        final use_k = true)
      Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort

    // parameter for Evaporator
      parameter SI.Height min_level_for_heating "Minimum level for heating";

      Medium.SaturationProperties sat
        "State vector to compute saturation properties";
      Medium.SpecificEnthalpy h_v=Medium.dewEnthalpy(sat)
        "Specific enthalpy of vapour";
      Medium.SpecificEnthalpy h_l=Medium.bubbleEnthalpy(sat)
        "Specific enthalpy of liquid";
      Medium.SpecificEnthalpy h "Actual specific enthalpy of liquid";
      Medium.Density rho_v=Medium.dewDensity(sat) "Density in vapour phase";
      Medium.Density rho_l=Medium.bubbleDensity(sat) "Density in liquid phase";
      Medium.Density rho "Actual density in liquid phase";

    equation
      H_flow_TopPorts   = InnerTankTop.H_flow;
      m_flow_TopPorts   = InnerTankTop.m_flow;
      mXi_flow_topPorts = InnerTankTop.mXi_flow;

      H_flow_SidePorts   = InnerTankSide.H_flow;
      m_flow_SidePorts   = InnerTankSide.m_flow;
      mXi_flow_sidePorts = InnerTankSide.mXi_flow;

      H_flow_BottomPorts  = InnerTankBottom.H_flow;
      m_flow_BottomPorts  = InnerTankBottom.m_flow;
      mXi_flowBottomPorts = InnerTankBottom.mXi_flow;

      for i in 1:n_BottomPorts loop
        m_flow_BottomPorts_pos[i] = (if m_flow_BottomPorts[i] > 0 then
          m_flow_BottomPorts[i] else 0);
      end for;
      for i in 1:n_SidePorts loop
        m_flow_SidePorts_pos[i] = if m_flow_SidePorts[i] > 0 then m_flow_SidePorts[
          i] else 0;
      end for;
      for i in 1:n_TopPorts loop
        m_flow_TopPorts_pos[i] = if m_flow_TopPorts[i] > 0 then m_flow_TopPorts[i] else
                0;
      end for;
      for i in 1:n_BottomPorts loop
        connect(InnerTankBottom[i].port, BottomFluidPort[i])
      end for;
      for i in 1:n_TopPorts loop
        connect(InnerTankTop[i].port, TopFluidPort[i])
      end for;
      for i in 1:n_SidePorts loop
        connect(InnerTankSide[i].port, SideFluidPort[i])
      end for;

      medium.p = p_ambient;
    // Mass balance
      der(m) = sum(m_flow_BottomPorts) + sum(m_flow_SidePorts) + sum(
        m_flow_TopPorts) + Condensed.m_flow;
    // Energy balance

      U = m*medium.h - p_ambient*V "Internal energy of fluid";
      m = V*medium.d "Mass of fluid";
      V = crossArea*level + V0 "Volume of fluid";
      mXi = m*medium.Xi "Mass of fluid components";
      sat.psat = medium.p;
      sat.Tsat = Medium.saturationTemperature(medium.p);

      if noEvent(medium.T < sat.Tsat) then
        if Medium.singleState then
          der(U) = sum(H_flow_BottomPorts) + sum(H_flow_SidePorts) + sum(
            H_flow_TopPorts) + Condensed.m_flow*actualStream(Condensed.h_outflow) + heatTransfer.Q_flows[1]
            "Mechanical work is neglected";
        else
          der(U) = sum(H_flow_BottomPorts) + sum(H_flow_SidePorts) + sum(
            H_flow_TopPorts) + Condensed.m_flow*actualStream(Condensed.h_outflow) - p_ambient*der(V) +
            heatTransfer.Q_flows[1];
        end if;
        Condensed.h_outflow = h;
        Condensed.m_flow = 0;
        rho = medium.d;
        h = medium.h;
      else
        if Medium.singleState then
          der(U) = sum(H_flow_BottomPorts) + sum(H_flow_SidePorts) + sum(H_flow_TopPorts)
             + Condensed.m_flow*actualStream(Condensed.h_outflow)
            "Mechanical work is neglected";
        else
          der(U) = sum(H_flow_BottomPorts) + sum(H_flow_SidePorts) + sum(
            H_flow_TopPorts) + Condensed.m_flow*actualStream(Condensed.h_outflow) - p_ambient*der(V);
        end if;
        Condensed.h_outflow = h;
        Condensed.m_flow = -heatTransfer.Q_flows[1]/(h_v - h_l);
        rho = rho_l;//Density = liquid Density
        h = h_l;    //Enthalpy = liquid Enthalpy
        if noEvent(heatPort.Q_flow > 0.0) then
          assert(noEvent(abs(m_flow_pos) <= 0.01), "Attempt to fill tank while evaporating.");
        end if;

      end if;

      m_flow_pos = sum(m_flow_TopPorts_pos) + sum(m_flow_SidePorts_pos) + sum(
        m_flow_BottomPorts_pos);

      for i in 1:Medium.nXi loop
           der(mXi[i]) = sum(mXi_flowBottomPorts[:,i]) +
                         sum(mXi_flow_sidePorts[:,i]) +
                         sum(mXi_flow_topPorts[:,i]);
      end for;

      assert(level < height, "Tank is overflowing.");

      assert(not (heatPort.Q_flow > 0.0 and level <= min_level_for_heating),
        "Attempting to heat an empty tank.");

    initial equation
      if initType == Init.GuessValues then
        // no initial equations
      elseif initType == Init.InitialValues then
        level = level_start;
        if use_T_start then
          medium.T = T_start;
        else
          medium.h = h_start;
        end if;
        medium.Xi = X_start[1:Medium.nXi];
      elseif initType == Init.SteadyStateHydraulic then
        der(level) = 0;
        if use_T_start then
          medium.T = T_start;
        else
          medium.h = h_start;
        end if;
        medium.Xi = X_start[1:Medium.nXi];
      else
        assert(false, "Unsupported initialization option");
      end if;

    equation
      connect(heatPort, heatTransfer.heatPorts[1])
    end TankWith3InletOutletArraysWithEvaporatorCondensor;

    model InnerTank
        replaceable package Medium =
        Modelica.Media.Interfaces.PartialMedium "Medium in the component"

        Modelica.Fluid.Interfaces.FluidPort_a port(redeclare package Medium =
            Medium)
        Boolean m_flow_negative( start = true, fixed = true)
        "= true, if mass flow out of tank";
        constant SI.Acceleration g=Modelica.Constants.g_n;
        input Real aboveLevel;
        input Real d;
        input Real p_ambient;
        input Real h;
        input Medium.MassFraction Xi[Medium.nXi]
        "Actual mass fractions of fluid in tank"
        input Real pipeArea;
        output Real H_flow;
        output Real m_flow;
       output Medium.MassFlowRate mXi_flow[Medium.nXi]
        "= port.mXi_flow (used to transform vector of connectors in vector of Real numbers)";

    equation
    m_flow_negative = (pre(m_flow_negative) and not port.p>p_ambient) or (port.m_flow < -1e-6);

    if noEvent(aboveLevel > 0) then
      port.p = aboveLevel*g*d + p_ambient - smooth(2,noEvent(if noEvent(m_flow < 0) then m_flow^2/(2*d*pipeArea^2) else 0));
    else
     if pre(m_flow_negative) then
        port.m_flow = 0;
      else
        port.p = p_ambient;
      end if;
    end if;

      H_flow = port.m_flow*actualStream(port.h_outflow);
      m_flow = port.m_flow;
      mXi_flow = port.m_flow*actualStream(port.Xi_outflow);
      port.h_outflow = h;
      port.Xi_outflow = Xi;
    end InnerTank;

    model Controller

      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.ControllerUtilities.Port_Sensors
        sensors
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.ControllerUtilities.Port_Actuators
        actuators

      parameter Real w_dilution=0.003 "Dilution";
      parameter Real w_concentrate=0.005 "Concentrate";
      parameter Real startTime=1 "Start time";
      parameter Real T5_batch_level=0.211 "T5 batch level";

      Modelica.StateGraph.InitialStep InitialStep1(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition1(enableTimer=true, waitTime=
            startTime)
      Modelica.StateGraph.Step Step1(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition2(condition=LIS_301 >= 0.13)
      Modelica.StateGraph.Step Step2(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition3(
        condition=true,
        enableTimer=true,
        waitTime=500)
      Modelica.StateGraph.Step Step3(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition4(condition=LIS_301 <= 0.01)
      Modelica.StateGraph.Step Step4(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition5(condition=T5_idle)
      Modelica.StateGraph.Step Step5(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition6(condition=LIS_501 >=
            T5_batch_level)
      Modelica.StateGraph.Step Step6(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition7(
        condition=true,
        enableTimer=true,
        waitTime=300)
      Modelica.StateGraph.Parallel Parallel1
      Modelica.StateGraph.Step Step7(nIn=1, nOut=1)
      Modelica.StateGraph.Step Step8(nIn=1, nOut=1)
      Modelica.StateGraph.Step Step9(nIn=1, nOut=1)
      Modelica.StateGraph.Step Step10(       nOut=1, nIn=1)
      Modelica.StateGraph.Step Step11(nIn=1, nOut=1)
      Modelica.StateGraph.Step Step12(nIn=1, nOut=1)
      Modelica.StateGraph.Step Step13b(nIn=1, nOut=1)
      Modelica.StateGraph.Step Step14(nIn=1, nOut=1)
      Modelica.StateGraph.Transition Transition8(condition=T7_idle)
      Modelica.StateGraph.Transition Transition9(condition=LIS_501 <= 0.01)
      Modelica.StateGraph.Transition Transition10(condition=TIS_702 <= 298)
      Modelica.StateGraph.Transition Transition11(condition=LIS_701 <= 0.01)
      Modelica.StateGraph.Transition Transition12(condition=TIS_602 <= 298)
      Modelica.StateGraph.Transition Transition13(condition=LIS_601 <= 0.01)

      Real LIS_301;
      Real LIS_501;
      Real LIS_601;
      Real LIS_701;
      Real QI_302;
      Real QIS_502;
      Real TIS_602;
      Real TIS_702;
      Boolean T5_idle;
      Boolean T7_idle;
      Modelica.StateGraph.TransitionWithSignal TransitionWithSignal1
      Modelica.Blocks.Sources.BooleanExpression BooleanExpression1(y=time >= 2500)
      inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
      StateGraph.Step Step13(nIn=1, nOut=1)
      StateGraph.Transition Transition13b(
        condition=true,
        enableTimer=true,
        waitTime=1)
      StateGraph.Step Step10b(nIn=1, nOut=1)
      StateGraph.Transition Transition10b(
        condition=true,
        enableTimer=true,
        waitTime=1)
    equation
      LIS_301 = sensors.LIS_301;
      LIS_501 = sensors.LIS_501;
      LIS_601 = sensors.LIS_601;
      LIS_701 = sensors.LIS_701;
      QI_302 = sensors.QI_302;
      QIS_502 = sensors.QIS_502;
      TIS_602 = sensors.TIS_602;
      TIS_702 = sensors.TIS_702;
      T5_idle = not actuators.V12 and not actuators.V15 and not actuators.T5_Heater
         and sensors.LIS_501 < 0.01;
      T7_idle = not actuators.V15 and not actuators.V18 and not actuators.
        T7_Cooling and sensors.LIS_701 < 0.01;

      actuators.P1 = Step10.active or Step10b.active;
      actuators.P2 = Step13.active or Step13b.active;
      actuators.T5_Heater = Step6.active;
      actuators.T7_Cooling = Step9.active;
      actuators.T6_Cooling = Step12.active;
      actuators.V1 = Step10.active or Step10b.active;
      actuators.V2 = false;
      actuators.V3 = Step10.active;
      actuators.V4 = false;
      actuators.V5 =Step13.active or Step13b.active;
      actuators.V6 =Step13.active;
      actuators.V8 = Step1.active;
      actuators.V9 = Step2.active;
      actuators.V10 = false;
      actuators.V11 = Step3.active;
      actuators.V12 = Step5.active;
      actuators.V15 = Step8.active;
      actuators.V18 = Step10.active;
      actuators.V19 = false;
      actuators.V20 =Step13.active;
      actuators.V21 = false;
      actuators.V22 = Step10.active or Step10b.active;
      actuators.V23 = Step10.active or Step10b.active;
      actuators.V25 =Step13.active or Step13b.active;
      actuators.V24 =Step13.active or Step13b.active;

      connect(InitialStep1.outPort[1], Transition1.inPort)
      connect(Transition1.outPort, Step1.inPort[1])
      connect(Step1.outPort[1], Transition2.inPort)
      connect(Transition2.outPort, Step2.inPort[1])
      connect(Step2.outPort[1], Transition3.inPort)
      connect(Transition3.outPort, Step3.inPort[1])
      connect(Step3.outPort[1], Transition4.inPort)
      connect(Transition4.outPort, Step4.inPort[1])
      connect(Step4.outPort[1], Transition5.inPort)
      connect(Transition5.outPort, Step5.inPort[1])
      connect(Step5.outPort[1], Transition6.inPort)
      connect(Transition6.outPort, Step6.inPort[1])
      connect(Step6.outPort[1], Transition7.inPort)
      connect(Step12.inPort[1], Parallel1.split[1])
      connect(Step12.outPort[1], Transition12.inPort)
      connect(Transition12.outPort, Step13b.inPort[1])
      connect(Transition13.outPort, Step14.inPort[1])
      connect(Step14.outPort[1], Parallel1.join[1])
      connect(Step7.inPort[1], Parallel1.split[2])
      connect(Step7.outPort[1], Transition8.inPort)
      connect(Transition8.outPort, Step8.inPort[1])
      connect(Step8.outPort[1], Transition9.inPort)
      connect(Transition9.outPort, Step9.inPort[1])
      connect(Step9.outPort[1], Transition10.inPort)
      connect(Step10.outPort[1], Transition11.inPort)
      connect(Transition11.outPort, Step11.inPort[1])
      connect(Step11.outPort[1], Parallel1.join[2])
      connect(Transition7.outPort, Parallel1.inPort)
      connect(TransitionWithSignal1.inPort, Parallel1.outPort)
      connect(TransitionWithSignal1.outPort, InitialStep1.inPort[1])
      connect(BooleanExpression1.y, TransitionWithSignal1.condition)
      connect(Step13b.outPort[1], Transition13b.inPort)
      connect(Transition13b.outPort, Step13.inPort[1])
      connect(Step13.outPort[1], Transition13.inPort)
      connect(Transition10.outPort, Step10b.inPort[1])
      connect(Step10b.outPort[1], Transition10b.inPort)
      connect(Transition10b.outPort, Step10.inPort[1])
    end Controller;

    package ControllerUtilities
      extends Modelica.Icons.Package;
      class Adapter_Inference
        Port_IdleTanks idleTanks;
      end Adapter_Inference;

      class Adapter_Superposition
        Port_Actuators actuators;
      end Adapter_Superposition;

      class Block_Recipe_TBD
        parameter Real startTime "Start time";
        parameter Real w_dilution=0.003 "Dilution";
        parameter Real w_concentrate=0.005 "Concentrate";
        parameter Real T3_batch_level=0.1273 "T5 batch level";
        parameter Real T5_batch_level=0.211 "T3 batch level";
        Boolean trig;
        Boolean S0(start=true);
        Boolean S1;
        Boolean S2;
        Boolean S3;
        Boolean S4;
        Boolean S5;
        Boolean S6;
        Boolean S7;
        Boolean S8;
        Boolean S9;
        Boolean S10;
        Boolean S11;
        Boolean S12;
        Boolean S13;
        Boolean S14;
        Boolean tr0;
        Boolean tr1;
        Boolean tr2;
        Boolean tr3;
        Boolean tr4;
        Boolean tr5;
        Boolean tr6;
        Boolean tr7;
        Boolean tr8;
        Boolean tr9;
        Boolean tr10;
        Boolean tr11;
        Boolean tr12;
        Boolean tr13;
        Port_Actuators act
      end Block_Recipe_TBD;

      class BlockMain
        Boolean trig;

        Port_Actuators actuators
        Block_Recipe_TBD Recipe1
        Block_Recipe_TBD Recipe2
        Adapter_Inference Inference
        Adapter_Superposition Superposition
      end BlockMain;

      class Buffer_Recipe_TBD
        Port_Actuators act;
        Boolean S0;
        Boolean S1;
        Boolean S2;
        Boolean S3;
        Boolean S4;
        Boolean S5;
        Boolean S6;
        Boolean S7;
        Boolean S8;
        Boolean S9;
        Boolean S10;
        Boolean S11;
        Boolean S12;
        Boolean S13;
        Boolean S14;
      end Buffer_Recipe_TBD;

      class BufferMain
        Buffer_Recipe_TBD Recipe1;
        Buffer_Recipe_TBD Recipe2;
      end BufferMain;

      connector Port_Actuators
        output Boolean P1;
        output Boolean P2;
        output Boolean T5_Heater;
        output Boolean T7_Cooling;
        output Boolean T6_Cooling;
        output Boolean V1;
        output Boolean V2;
        output Boolean V3;
        output Boolean V4;
        output Boolean V5;
        output Boolean V6;
        output Boolean V8;
        output Boolean V9;
        output Boolean V10;
        output Boolean V11;
        output Boolean V12;
        output Boolean V15;
        output Boolean V18;
        output Boolean V19;
        output Boolean V20;
        output Boolean V21;
        output Boolean V22;
        output Boolean V23;
        output Boolean V24;
        output Boolean V25;
      end Port_Actuators;

      connector Port_IdleTanks
        Boolean T5_idle;
        Boolean T7_idle;
      end Port_IdleTanks;

      connector Port_Sensors
        input Real LIS_301;
        input Real QI_302;
        input Real LIS_501;
        input Real QIS_502;
        input Real TI_503;
        input Real LIS_601;
        input Real TIS_602;
        input Real LIS_701;
        input Real TIS_702;
      end Port_Sensors;
    end ControllerUtilities;

    type Init = enumeration(
        GuessValues
          "GuessValues -- Guess values (not fixed) for p, T or h, X, C",
        InitialValues "InitialValues -- Initial values for p, T or h, X, C",
        SteadyStateMomentum "SteadyStateMomentum: Steady state momentum",
        SteadyStateHydraulic
          "SteadyStateHydraulic -- Hydraulic steady state (der(p)=0), guess value for p, initial values for T or h, X, C",
        SteadyState
          "SteadyState -- Steady state (guess values for p, T or h, X, C)")
      "Enumeration to define initialization options"

  model TankWithTopPorts
      "Tank with inlet/outlet ports and with inlet ports at the top"

      import Modelica.Constants;
      import Modelica.Fluid.Fittings.BaseClasses.lossConstant_D_zeta;
      import Modelica.Fluid.Utilities.regRoot2;
      import Modelica.Fluid.Vessels.BaseClasses.VesselPortsData;

    SI.Length level(stateSelect=StateSelect.prefer, start=level_start)
        "Fluid level in the tank";

    //Tank geometry
    parameter SI.Height height "Maximum level of tank before it overflows";
    parameter SI.Area crossArea "Area of tank";
    parameter SI.Volume V0=0 "Volume of the liquid when level = 0";

    //Ambient
    parameter Medium.AbsolutePressure p_ambient=system.p_ambient
        "Tank surface pressure"
    parameter Medium.Temperature T_ambient=system.T_ambient
        "Tank surface Temperature"

    //Initialization
    parameter SI.Height level_start(min=0) = 0.5*height
        "Start value of tank level"

    //Mass and energy balance
    extends Modelica.Fluid.Interfaces.PartialLumpedVolume(
      final fluidVolume = V,
      final initialize_p = false,
      final p_start = p_ambient);

    //Port definitions
    parameter Integer nTopPorts = 0 "Number of inlet ports above height (>= 1)"

    Vessels.BaseClasses.VesselFluidPorts_a topPorts[nTopPorts](redeclare
          package Medium = Medium, m_flow(each start=0, each min=0))
        "Inlet ports over height at top of tank (fluid flows only from the port in to the tank)"

    parameter Integer nPorts = 0
        "Number of inlet/outlet ports (on bottom and on the side)"
    parameter Modelica.Fluid.Vessels.BaseClasses.VesselPortsData portsData[nPorts]
        "Data of inlet/outlet ports at side and bottom of tank";

    Vessels.BaseClasses.VesselFluidPorts_b ports[nPorts](redeclare package
          Medium = Medium, m_flow(each start=0))
        "Inlet/outlet ports at bottom or side of tank (fluid flows in to or out of port; a port might be above the fluid level)"

    // Heat transfer through boundary
    parameter Boolean use_HeatTransfer = false
        "= true, if HeatTransfer model is used"
    replaceable model HeatTransfer =
        Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer
      constrainedby
        Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer
        "Wall heat transfer"
    HeatTransfer heatTransfer(
      redeclare package Medium = Medium,
      final n=1,
      final states = {medium.state},
      surfaceAreas={crossArea+2*sqrt(crossArea*Modelica.Constants.pi)*level},
      final use_k = use_HeatTransfer)
    Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort if use_HeatTransfer

    // Advanced
    parameter Real hysteresisFactor(min=0) = 0.1
        "Hysteresis for empty pipe = diameter*hysteresisFactor"
    parameter Boolean stiffCharacteristicForEmptyPort = false
        "= true, if steep pressure loss characteristic for empty pipe port"
    parameter Real zetaLarge(min=0) = 1e5
        "Large pressure loss factor if mass flows out of empty pipe port"
    parameter SI.MassFlowRate m_flow_small(min=0) = system.m_flow_small
        "Regularization range at zero mass flow rate"

    // Tank properties
    SI.Volume V(stateSelect=StateSelect.never) "Actual tank volume";
    Medium.EnthalpyFlowRate H_flow_top[nTopPorts]
        "Enthalpy flow rates from the top ports in to the tank";
    Medium.EnthalpyFlowRate port_b_H_flow_bottom[nPorts]
        "Enthalpy flow rates from the bottom ports in to the tank";
    Medium.MassFlowRate mXi_flow_top[nTopPorts, Medium.nXi]
        "Substance mass flow rates from the top ports into the tank";
    Medium.MassFlowRate port_b_mXi_flow_bottom[nPorts, Medium.nXi]
        "Substance mass flow rates from the bottom ports into the tank";
    Medium.MassFlowRate mC_flow_top[nTopPorts, Medium.nC]
        "Trace substance mass flow rates from the top ports into the tank";
    Medium.MassFlowRate port_b_mC_flow_bottom[nPorts, Medium.nC]
        "Trace substance mass flow rates from the bottom ports into the tank";
    protected
      SI.Area bottomArea[nPorts];
      SI.Diameter ports_emptyPipeHysteresis[nPorts];
      SI.Length levelAbovePort[nPorts] "Height of fluid over bottom ports";
      Boolean ports_m_flow_out[nPorts](each start = true, each fixed=true);
      Boolean aboveLevel[nPorts] "= true, if level >= ports[i].height";
      Real zetas_out[nPorts];
      Modelica.Blocks.Interfaces.RealInput portsData_diameter[nPorts] = portsData.diameter if nPorts > 0;
      Modelica.Blocks.Interfaces.RealInput portsData_diameter2[nPorts];
      Modelica.Blocks.Interfaces.RealInput portsData_height[nPorts] = portsData.height if nPorts > 0;
      Modelica.Blocks.Interfaces.RealInput portsData_height2[nPorts];
  equation
    assert(level <= height, "Tank starts to overflow (level = height = " + String(level) + ")");
    assert(m>=0, "Mass in tank is zero");

    // Compute constant data
    connect(portsData_diameter, portsData_diameter2);
    connect(portsData_height,portsData_height2);

    for i in 1:nPorts loop
        bottomArea[i]=Constants.pi*(portsData_diameter2[i]/2)^2;
        ports_emptyPipeHysteresis[i] = portsData_diameter2[i]*hysteresisFactor;
    end for;

    // Only one connection allowed to a port to avoid unwanted ideal mixing
  /*
for i in 1:nTopPorts loop
  assert(cardinality(topPorts[i]) <= 1,"
topPorts[" + String(i) + "] of volume can at most be connected to one component.
If two or more connections are present, ideal mixing takes
place with these connections which is usually not the intention
of the modeller.
");
end for;

for i in 1:nPorts loop
  assert(cardinality(ports[i]) <= 1,"
ports[" + String(i) + "] of volume can at most be connected to one component.
If two or more connections are present, ideal mixing takes
place with these connections which is usually not the intention
of the modeller.
");
end for;
*/

    // Total quantities
    medium.p = p_ambient;
    V = crossArea*level + V0 "Volume of fluid";

    // Mass balances
    mb_flow = sum(topPorts.m_flow) + sum(ports.m_flow);
    for i in 1:Medium.nXi loop
      mbXi_flow[i] = sum(mXi_flow_top[:,i]) + sum(port_b_mXi_flow_bottom[:,i]);
    end for;
    for i in 1:Medium.nC loop
      mbC_flow[i]  = sum(mC_flow_top[:,i])  + sum(port_b_mC_flow_bottom[:,i]);
    end for;

    // Energy balance
    Hb_flow = sum(H_flow_top) + sum(port_b_H_flow_bottom);
    Qb_flow = heatTransfer.Q_flows[1];
    if Medium.singleState or energyDynamics == Types.Dynamics.SteadyState then
      Wb_flow = 0
          "Mechanical work is neglected, since also neglected in medium model (otherwise unphysical small temperature change, if tank level changes)";
    else
      Wb_flow = -p_ambient*der(V);
    end if;

    // Properties at top ports
      for i in 1:nTopPorts loop
         // It is assumed that fluid flows only from one of the top ports in to the tank and never vice versa
         H_flow_top[i]     = topPorts[i].m_flow*actualStream(topPorts[i].h_outflow);
         mXi_flow_top[i,:] = topPorts[i].m_flow*actualStream(topPorts[i].Xi_outflow);
         mC_flow_top[i,:]  = topPorts[i].m_flow*actualStream(topPorts[i].C_outflow);
         topPorts[i].p     = p_ambient;
         topPorts[i].h_outflow = h_start;
         topPorts[i].Xi_outflow = X_start[1:Medium.nXi];
         topPorts[i].C_outflow  = C_start;
  /*
       assert(topPorts[i].m_flow > -1, "Mass flows out of tank via topPorts[" + String(i) + "]\n" +
                                         "This indicates a wrong model");
*/
      end for;

    // Properties at bottom ports
      for i in 1:nPorts loop
         port_b_H_flow_bottom[i]   = ports[i].m_flow*actualStream(ports[i].h_outflow);
         port_b_mXi_flow_bottom[i,:] = ports[i].m_flow*actualStream(ports[i].Xi_outflow);
         port_b_mC_flow_bottom[i,:]  = ports[i].m_flow*actualStream(ports[i].C_outflow);
         aboveLevel[i] = level >= (portsData_height2[i] + ports_emptyPipeHysteresis[i])
                         or pre(aboveLevel[i]) and level >= (portsData_height2[i] - ports_emptyPipeHysteresis[i]);
         levelAbovePort[i] = if aboveLevel[i] then level - portsData_height2[i] else 0;
         ports[i].h_outflow = medium.h;
         ports[i].Xi_outflow = medium.Xi;
         ports[i].C_outflow  = C;

         if stiffCharacteristicForEmptyPort then
            // If port is above fluid level, use large zeta if fluid flows out of port (= small mass flow rate)
            zetas_out[i] = 1 + (if aboveLevel[i] then 0 else zetaLarge);
            ports[i].p = p_ambient + levelAbovePort[i]*system.g*medium.d
                                 + Modelica.Fluid.Utilities.regSquare2(ports[i].m_flow, m_flow_small,
                                       lossConstant_D_zeta(portsData_diameter2[i], 0.01)/medium.d,
                                       lossConstant_D_zeta(portsData_diameter2[i], zetas_out[i])/medium.d);
            ports_m_flow_out[i] = false;

         else
            // Handling according to Remelhe/Poschlad
            ports_m_flow_out[i] = (pre(ports_m_flow_out[i]) and not ports[i].p>p_ambient)
                                       or ports[i].m_flow < -1e-6;
           if aboveLevel[i] then
               ports[i].p = p_ambient + levelAbovePort[i]*system.g*medium.d -
                                 smooth(2,noEvent(if ports[i].m_flow < 0 then ports[i].m_flow^2/
                                       (2*medium.d*bottomArea[i]^2) else 0));
           else
              if pre(ports_m_flow_out[i]) then
                 ports[i].m_flow = 0;
              else
                 ports[i].p = p_ambient;
              end if;
           end if;
            zetas_out[i] =0;
         end if;
       end for;

  initial equation
      for i in 1:nPorts loop
         pre(aboveLevel[i]) = level_start >= portsData_height2[i];
      end for;

      if massDynamics == Types.Dynamics.FixedInitial then
        level = level_start;
      elseif massDynamics == Types.Dynamics.SteadyStateInitial then
        der(level) = 0;
      end if;

  equation
      connect(heatPort, heatTransfer.heatPorts[1])
  end TankWithTopPorts;
  end BaseClasses;

  package Test "Test of used tank models"
    extends Modelica.Icons.ExamplesPackage;

    model OneTank
      "Tank with one time-varying top inlet mass flow rate and a bottom outlet into the ambient"
      import Modelica.Units.Conversions.from_bar;
      extends Modelica.Icons.Example;

      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        crossArea=1,
        height=1,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.1, height=0)},
        V0=0.1,
        nTopPorts=1,
        nPorts=1,
        level_start=0.8,
        stiffCharacteristicForEmptyPort=false,
        hysteresisFactor=0.01)

      Sources.MassFlowSource_T flowSource(nPorts=1,
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        m_flow=20,
        T=system.T_ambient,
        use_m_flow_in=true)
      inner Modelica.Fluid.System system
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed(nPorts=1,
                                             redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
      Modelica.Fluid.Pipes.StaticPipe pipe(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=-1)
      Modelica.Blocks.Sources.TimeTable timeTable(table=[0,0; 10,0; 10,40; 20,40;
            20,10; 50,10; 50,0; 60,0; 60,20; 70,20; 80,55; 80,0; 100,0])
    equation
      connect(flowSource.ports[1], tank.topPorts[1])
      connect(tank.ports[1], pipe.port_a)
      connect(pipe.port_b, ambient_fixed.ports[1])
      connect(timeTable.y, flowSource.m_flow_in)
    end OneTank;

    model TwoTanks
      import Modelica.Units.Conversions.from_bar;
      extends Modelica.Icons.Example;
      parameter Boolean stiffCharacteristicForEmptyPort=true
        "= true, if steep pressure loss characteristic for empty pipe port";

      inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
          massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank1(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        stiffCharacteristicForEmptyPort = stiffCharacteristicForEmptyPort,
        crossArea=1,
        height=4,
        level_start=3,
        T_start=Modelica.Units.Conversions.from_degC(50),
        nPorts=1,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.1, height=0)})
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank2(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        stiffCharacteristicForEmptyPort = stiffCharacteristicForEmptyPort,
        crossArea=1,
        height=4,
        level_start=1,
        T_start=Modelica.Units.Conversions.from_degC(100),
        nPorts=1,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.1, height=0)})
      Modelica.Fluid.Pipes.StaticPipe pipe(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1)
    equation
      connect(tank1.ports[1], pipe.port_a)
      connect(pipe.port_b, tank2.ports[1])
    end TwoTanks;

    model TankWithEmptyingPipe1
      "Demonstrates a tank with one constant top inlet mass flow rate and a bottom outlet into the ambient"
      import Modelica.Units.Conversions.from_bar;
      extends Modelica.Icons.Example;

      Sources.MassFlowSource_T flowSource(
        nPorts=1,
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        m_flow=50,
        T=system.T_ambient)
      inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
          massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed(nPorts=1,
                                             redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
      Modelica.Fluid.Valves.ValveDiscrete valveDiscrete(
                                                redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        dp_nominal(displayUnit="Pa") = 1,
        m_flow_nominal=100)
      Modelica.Blocks.Sources.BooleanConstant open(k=false)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank1(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        crossArea=1,
        V0=0.1,
        height=2,
        level_start=0.1,
        nPorts=2,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.05, height=0),
            Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
                                                            diameter=0.1,
            height=1)},
        stiffCharacteristicForEmptyPort=true)
      Modelica.Fluid.Pipes.StaticPipe pipe(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=1)
    equation
      connect(ambient_fixed.ports[1], valveDiscrete.port_a)
      connect(open.y, valveDiscrete.open)
      connect(flowSource.ports[1], pipe.port_b)
      connect(valveDiscrete.port_b, tank1.ports[1])
      connect(pipe.port_a, tank1.ports[2])
    end TankWithEmptyingPipe1;

    model TankWithEmptyingPipe2
      "Demonstrates a tank with one constant top inlet mass flow rate and a bottom outlet into the ambient"
      import Modelica.Units.Conversions.from_bar;
      extends Modelica.Icons.Example;

      inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
          massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed(nPorts=1,
                                             redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank1(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        crossArea=1,
        V0=0.1,
        height=2,
        nPorts=2,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.05, height=0),
            Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
                                                            diameter=0.1,
            height=1)},
        level_start=2,
        stiffCharacteristicForEmptyPort=true)
      Modelica.Fluid.Pipes.StaticPipe pipe1(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=1)

      Modelica.Fluid.Pipes.StaticPipe pipe2(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=1)
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed1(nPorts=1,
                                             redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
    equation
      connect(tank1.ports[1], pipe1.port_b)
      connect(ambient_fixed.ports[1], pipe1.port_a)
      connect(tank1.ports[2], pipe2.port_b)
      connect(ambient_fixed1.ports[1], pipe2.port_a)
    end TankWithEmptyingPipe2;

    model TanksWithEmptyingPipe1
      "Demonstrates a tank with one constant top inlet mass flow rate and a bottom outlet into the ambient"
      import Modelica.Units.Conversions.from_bar;
      extends Modelica.Icons.Example;

      inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
          massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed1(nPorts=1,
                                              redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank1(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        crossArea=1,
        V0=0.1,
        height=2,
        nPorts=2,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.05, height=0),
            Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
                                                            diameter=0.1,
            height=1)},
        level_start=2,
        stiffCharacteristicForEmptyPort=true)
      Modelica.Fluid.Pipes.StaticPipe pipe1(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=1)

      Modelica.Fluid.Pipes.StaticPipe pipe2(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=1)
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed2(nPorts=1,
                                             redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank2(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        crossArea=1,
        V0=0.1,
        height=2,
        nPorts=2,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.05, height=0),
            Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
                                                            diameter=0.1,
            height=0.5)},
        level_start=0.1,
        stiffCharacteristicForEmptyPort=true)
      Modelica.Fluid.Pipes.StaticPipe pipe3(
        redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        length=1,
        diameter=0.1,
        height_ab=-0.5)
    equation
      connect(tank1.ports[1], pipe1.port_b)
      connect(ambient_fixed1.ports[1], pipe1.port_a)
      connect(ambient_fixed2.ports[1], pipe2.port_a)
      connect(tank2.ports[1], pipe2.port_b)
      connect(pipe3.port_a, tank1.ports[2])
      connect(pipe3.port_b, tank2.ports[2])
    end TanksWithEmptyingPipe1;

    model TanksWithEmptyingPipe2
      "Demonstrates a tank with one constant top inlet mass flow rate and a bottom outlet into the ambient"
      parameter Boolean stiffCharacteristicForEmptyPort=true
        "= true, if steep pressure loss characteristic for empty pipe port";
      import Modelica.Units.Conversions.from_bar;
      extends Modelica.Icons.Example;
      replaceable package Medium =
         Modelica.Media.Water.ConstantPropertyLiquidWater constrainedby
        Modelica.Media.Interfaces.PartialMedium "Medium in the component"

      inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
          massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
      Modelica.Fluid.Sources.Boundary_pT ambient_fixed(nPorts=1,
                                             redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        p=system.p_ambient,
        T=system.T_ambient)
      Modelica.Fluid.Valves.ValveDiscrete valveDiscrete(
                                                redeclare package Medium =
            Modelica.Media.Water.ConstantPropertyLiquidWater,
        dp_nominal(displayUnit="Pa") = 1,
        m_flow_nominal=100)
      Modelica.Blocks.Sources.BooleanConstant open(k=false)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank3(
        redeclare package Medium = Medium,
        crossArea=1,
        V0=0.1,
        height=20,
        nPorts=2,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.05, height=0),
            Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
              diameter=0.05,
              height=6.5)},
        level_start=6,
        nTopPorts=1,
        stiffCharacteristicForEmptyPort = stiffCharacteristicForEmptyPort)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank1(
        redeclare package Medium = Medium,
        crossArea=1,
        V0=0.1,
        height=10,
        nPorts=1,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.1, height=0)},
        level_start=9,
        stiffCharacteristicForEmptyPort = stiffCharacteristicForEmptyPort)
      Modelica.Fluid.Examples.AST_BatchPlant.BaseClasses.TankWithTopPorts tank2(
        redeclare package Medium = Medium,
        crossArea=1,
        V0=0.1,
        height=10,
        nPorts=3,
        portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.05, height=0),
            Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
                                                            diameter=0.05,
            height=2),Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.1, height=3)},
        level_start=1,
        stiffCharacteristicForEmptyPort = stiffCharacteristicForEmptyPort)
      Pipes.StaticPipe pipe1(redeclare package Medium = Medium,
          height_ab=2,
        length=2,
        diameter=0.1)
      Pipes.StaticPipe pipe2(redeclare package Medium = Medium,
          height_ab=2,
        length=2,
        diameter=0.1)
      Pipes.StaticPipe pipe3(redeclare package Medium = Medium,
          height_ab=2,
        length=2,
        diameter=0.1)
    equation
      connect(ambient_fixed.ports[1], valveDiscrete.port_a)
      connect(open.y, valveDiscrete.open)
      connect(valveDiscrete.port_b,tank3. ports[1])
      connect(pipe1.port_b, tank1.ports[1])
      connect(pipe2.port_a, tank3.ports[2])
      connect(pipe3.port_a, tank3.topPorts[1])
      connect(pipe3.port_b, tank2.ports[1])
      connect(pipe1.port_a, tank2.ports[3])
      connect(pipe2.port_b, tank2.ports[2])
    end TanksWithEmptyingPipe2;
  end Test;
end AST_BatchPlant;


within Modelica.Fluid.Examples;
model BranchingDynamicPipes
  "Multi-way connections of pipes with dynamic momentum balance, pressure wave and flow reversal"
extends Modelica.Icons.Example;
replaceable package Medium=Modelica.Media.Air.MoistAir constrainedby
    Modelica.Media.Interfaces.PartialMedium;
//replaceable package Medium=Modelica.Media.Water.StandardWater constrainedby Modelica.Media.Interfaces.PartialMedium;

  inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial,
      momentumDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial)
  Modelica.Fluid.Sources.Boundary_pT boundary1(nPorts=1,
    redeclare package Medium = Medium,
    p=150000)
  Pipes.DynamicPipe             pipe1(
    redeclare package Medium=Medium,
    use_T_start=true,
    nNodes=5,
    diameter=2.54e-2,
    m_flow_start=0.02,
    height_ab=50,
    length=50,
    p_a_start=150000,
    p_b_start=130000,
    modelStructure=Modelica.Fluid.Types.ModelStructure.a_v_b)
 Pipes.DynamicPipe             pipe2(
    redeclare package Medium = Medium,
    use_T_start=true,
    nNodes=5,
    redeclare model HeatTransfer =
        Modelica.Fluid.Pipes.BaseClasses.HeatTransfer.LocalPipeFlowHeatTransfer,
    use_HeatTransfer=true,
    diameter=2.54e-2,
    m_flow_start=0.01,
    length=50,
    height_ab=25,
    p_a_start=130000,
    p_b_start=120000,
    modelStructure=Modelica.Fluid.Types.ModelStructure.av_vb)

  Pipes.DynamicPipe             pipe3(
    redeclare package Medium=Medium,
    use_T_start=true,
    nNodes=5,
    diameter=2.54e-2,
    m_flow_start=0.01,
    length=25,
    height_ab=25,
    p_a_start=130000,
    p_b_start=120000,
    modelStructure=Modelica.Fluid.Types.ModelStructure.a_v_b)
  Pipes.DynamicPipe             pipe4(
    redeclare package Medium=Medium,
    use_T_start=true,
    nNodes=5,
    diameter=2.54e-2,
    m_flow_start=0.02,
    height_ab=50,
    length=50,
    p_a_start=120000,
    p_b_start=100000,
    modelStructure=Modelica.Fluid.Types.ModelStructure.a_v_b)
  Modelica.Fluid.Sources.Boundary_pT boundary4(nPorts=1,
    redeclare package Medium = Medium,
    use_p_in=true,
    use_T_in=false,
    p=100000)
  Modelica.Blocks.Sources.Ramp ramp1(
    offset=1e5,
    startTime=2,
    height=1e5,
    duration=0)
  Modelica.Thermal.HeatTransfer.Sources.FixedHeatFlow[
                                              pipe2.nNodes] heat2(Q_flow=200*
        pipe2.dxs, alpha=-1e-2*ones(pipe2.n))
equation
  connect(ramp1.y, boundary4.p_in)
  connect(boundary1.ports[1],pipe1. port_a)
  connect(pipe1.port_b,pipe2. port_a)
  connect(pipe1.port_b,pipe3. port_a)
  connect(pipe2.port_b,pipe4. port_a)
  connect(pipe3.port_b,pipe4. port_a)
  connect(pipe4.port_b, boundary4.ports[1])
  connect(heat2.port,pipe2. heatPorts)
end BranchingDynamicPipes;


within Modelica.Fluid.Examples;
package ControlledTankSystem
  "Tank system with controller, start/stop/shut operation and diagram animation"
  extends Modelica.Icons.ExamplesPackage;

  model ControlledTanks
    "Demonstrating the controller of a tank filling/emptying system"
    extends Modelica.Icons.Example;
    package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater;

    Modelica.Fluid.Examples.ControlledTankSystem.Utilities.TankController
      tankController(
      waitTime=50,
      maxLevel=0.9*tank1.height,
      minLevel=0.01)
    Modelica.Blocks.Sources.RadioButtonSource start(
      reset={stop.on,shut.on},
      buttonTimeTable={20,280})
    Modelica.Blocks.Sources.RadioButtonSource stop(
      reset={start.on,shut.on},
      buttonTimeTable={220,650})
    Modelica.Blocks.Sources.RadioButtonSource shut(
      reset={start.on,stop.on},
      buttonTimeTable={700})
    Modelica.Fluid.Valves.ValveDiscrete valve1(                     redeclare
        package Medium = Medium,
      m_flow_nominal=40,
      dp_nominal=100000)
    Modelica.Fluid.Vessels.OpenTank tank1(
      level_start=0.05,
      redeclare package Medium = Medium,
      crossArea=6,
      height=4,
      nPorts=2,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.2,
            height=4,
            zeta_out=0,
            zeta_in=1),Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.2,
            height=0,
            zeta_out=0,
            zeta_in=1)})
    Modelica.Blocks.Sources.RealExpression level1(y=tank1.level)
    Modelica.Fluid.Valves.ValveDiscrete valve2(        redeclare package Medium
        = Medium,
      dp_nominal(displayUnit="Pa") = 1,
      m_flow_nominal=100)
    Modelica.Fluid.Valves.ValveDiscrete valve3(        redeclare package Medium
        = Medium,
      dp_nominal(displayUnit="Pa") = 1,
      m_flow_nominal=10)
    Modelica.Fluid.Vessels.OpenTank tank2(
      level_start=0.05,
      redeclare package Medium = Medium,
      height=5,
      crossArea=6,
      nPorts=2,
      portsData={Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.2,
            height=5,
            zeta_out=0,
            zeta_in=1),Modelica.Fluid.Vessels.BaseClasses.VesselPortsData(
            diameter=0.2,
            height=0,
            zeta_out=0,
            zeta_in=1)})
    Modelica.Fluid.Sources.Boundary_pT ambient1(redeclare package Medium =
          Medium,nPorts=1,
      p=system.p_ambient,
      T=system.T_ambient)
    Modelica.Blocks.Sources.RealExpression level2(y=tank2.level)
    Modelica.Fluid.Sources.Boundary_pT source(redeclare package Medium =
          Medium, p=2.5e6,nPorts=1,
      T=system.T_ambient)
    inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  equation
    connect(shut.on, tankController.shut)
    connect(stop.on, tankController.stop)
    connect(start.on, tankController.start)
    connect(tankController.valve1, valve1.open)
    connect(level1.y, tankController.level1)
    connect(tankController.valve2, valve2.open)
    connect(tankController.valve3, valve3.open)
    connect(level2.y, tankController.level2)

    connect(source.ports[1], valve1.port_a)
    connect(valve3.port_b, ambient1.ports[1])
    connect(tank2.ports[2], valve3.port_a)
    connect(valve2.port_b, tank2.ports[1])
    connect(valve1.port_b, tank1.ports[1])
    connect(tank1.ports[2], valve2.port_a)
  end ControlledTanks;

  package Utilities
    extends Modelica.Icons.UtilitiesPackage;

    model TankController "Controller for tank system"
          extends Modelica.StateGraph.Interfaces.PartialStateGraphIcon;
      parameter SI.Height maxLevel "Fill level of tank 1";
      parameter SI.Height minLevel "Lowest level of tank 1 and 2";
      parameter SI.Time waitTime "Wait time, between operations";

      Modelica.StateGraph.InitialStep s1(nIn=2, nOut=1)
      Modelica.Fluid.Examples.ControlledTankSystem.Utilities.NormalOperation
        normal(
        maxLevel=maxLevel,
        minLevel=minLevel,
        waitTime=waitTime)
      Modelica.StateGraph.Transition T1(condition=start)
      Modelica.StateGraph.Transition T2(condition=level2 < minLevel)
      Modelica.StateGraph.Transition T3(condition=stop)
      Modelica.StateGraph.Step s2(nIn=1, nOut=2)
      Modelica.StateGraph.Transition T4(condition=start)
      Modelica.StateGraph.Transition T5(condition=shut)
      Modelica.StateGraph.Step emptyTanks(nIn=1, nOut=1)
      Modelica.StateGraph.Transition T6(condition=level1 < minLevel and level2
             < minLevel)
      Modelica.Blocks.Interfaces.BooleanInput start
      Modelica.Blocks.Interfaces.BooleanInput stop
      Modelica.Blocks.Interfaces.BooleanInput shut
      Modelica.Blocks.Interfaces.RealInput level1
      Modelica.Blocks.Interfaces.RealInput level2
      Modelica.Blocks.Interfaces.BooleanOutput valve1
      Modelica.Blocks.Interfaces.BooleanOutput valve2
      Modelica.Blocks.Interfaces.BooleanOutput valve3
      Modelica.Blocks.Sources.BooleanExpression setValve1(y=normal.fillTank1.
            active)
      Modelica.Blocks.Sources.BooleanExpression setValve2(y=normal.fillTank2.
            active or emptyTanks.active and level1 > minLevel)
      Modelica.Blocks.Sources.BooleanExpression setValve3(y=normal.emptyTank2.
            active or emptyTanks.active and level2 > minLevel)
      inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
    equation

      connect(s1.outPort[1], T1.inPort)
      connect(T1.outPort, normal.inPort)
      connect(normal.outPort, T2.inPort)
      connect(T5.outPort, emptyTanks.inPort[1])
      connect(emptyTanks.outPort[1], T6.inPort)
      connect(setValve1.y, valve1)
      connect(setValve2.y, valve2)
      connect(setValve3.y, valve3)
      connect(normal.suspend[1], T3.inPort)
      connect(T3.outPort, s2.inPort[1])
      connect(level1, normal.level1)
      connect(s2.outPort[1], T5.inPort)
      connect(s2.outPort[2], T4.inPort)
      connect(T2.outPort, s1.inPort[1])
      connect(T6.outPort, s1.inPort[2])
      connect(T4.outPort, normal.resume[1])
    end TankController;

    model NormalOperation
      "Normal operation of tank system (button start pressed)"
          extends Modelica.StateGraph.PartialCompositeStep;
      parameter SI.Height maxLevel "Fill level of tank 1";
      parameter SI.Height minLevel "Lowest level of tank 1 and 2";
      parameter SI.Time waitTime "Wait time between operations";

      Modelica.Blocks.Interfaces.RealInput level1
      Modelica.StateGraph.Step fillTank1(nIn=1, nOut=1)
      Modelica.StateGraph.Transition T1(condition=level1 > maxLevel)
      Modelica.StateGraph.Step fillTank2(nIn=1, nOut=1)
      Modelica.StateGraph.Transition T3(condition=level1 < minLevel)
      Modelica.StateGraph.Step emptyTank2(nIn=1, nOut=1)
      Modelica.StateGraph.Step wait1(nIn=1, nOut=1)
      Modelica.StateGraph.Transition T2(enableTimer=true, waitTime=waitTime)
      Modelica.StateGraph.Step wait2(nIn=1, nOut=1)
      Modelica.StateGraph.Transition T4(enableTimer=true, waitTime=waitTime)
    equation
      connect(fillTank1.inPort[1], inPort)
      connect(fillTank1.outPort[1], T1.inPort)
      connect(fillTank2.outPort[1], T3.inPort)
      connect(emptyTank2.outPort[1], outPort)
      connect(wait1.outPort[1], T2.inPort)
      connect(T2.outPort, fillTank2.inPort[1])
      connect(T1.outPort, wait1.inPort[1])
      connect(wait2.outPort[1], T4.inPort)
      connect(T3.outPort, wait2.inPort[1])
      connect(T4.outPort,emptyTank2.inPort[1])
    end NormalOperation;
  end Utilities;
end ControlledTankSystem;