within AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses;
partial model PartialExpansionValve
  "Base model for all expansion valve models"

  // Definition of parameters
  //
  parameter Modelica.Units.SI.Area AVal=2.5e-6
    "Cross-sectional area of the valve when it is fully opened"
  parameter Modelica.Units.SI.Diameter dInlPip=7.5e-3
    "Diameter of the pipe at valve's inlet"

  parameter Boolean useInpFil = true
    "= true, if transient behaviour of valve opening or closing is computed"
  parameter Modelica.Units.SI.Time risTim=0.5
    "Time until valve opening reaches 99.6 % of its set value"

  parameter Utilities.Types.CalcProc calcProc=Utilities.Types.CalcProc.nominal
    "Chose predefined calculation method for flow coefficient"
  parameter Modelica.Units.SI.MassFlowRate mFlowNom=m_flow_nominal
    "Mass flow at nominal conditions"
  parameter Modelica.Units.SI.PressureDifference dpNom=15e5
    "Pressure drop at nominal conditions"

  // Definition of model describing flow coefficient
  //
  replaceable model FlowCoefficient =
    Utilities.FlowCoefficient.SpecifiedFlowCoefficients.ConstantFlowCoefficient
                                                      constrainedby PartialFlowCoefficient
    "Model that describes the calculation of the flow coefficient"

  // Extends from partial two port (insert here for position of tabs)
  //
  extends AixLib.Fluid.Interfaces.PartialTwoPortTransport(
    redeclare replaceable package Medium =
        Modelica.Media.R134a.R134a_ph,
    show_T = false,
    show_V_flow = false,
    dp_start = 1e6,
    m_flow_start = 0.5*m_flow_nominal,
    m_flow_small = 1e-6*m_flow_nominal);

  // Definition of parameters describing diagnostic options
  //
  parameter Medium.MassFlowRate m_flow_nominal = 0.1
    "Nominal mass flow rate"
  parameter Boolean show_flow_coefficient = true
    "= true, if flow coefficient model is computed"
  parameter Boolean show_staInl = true
    "= true, if thermodynamic state at valve's inlet is computed"
  parameter Boolean show_staOut = false
    "= true, if thermodynamic state at valve's outlet is computed"

  // Definition of variables
  //
  Medium.ThermodynamicState staInl
    "Thermodynamic state of the fluid at inlet condtions"
  Medium.ThermodynamicState staOut
    "Thermodynamic state of the fluid at outlet condtions"
  FlowCoefficient flowCoefficient(
    redeclare package Medium = Medium,
    opening = opening,
    AVal = AVal,
    dInlPip = dInlPip,
    staInl = staInl,
    staOut = staOut,
    pInl = pInl,
    pOut = pOut)
    "Instance of model 'flow coefficient'";
     //
  Real C "Flow coefficient used to calculate mass flow and pressure drop";

  // Definition of connectors and submodels
  //
  Modelica.Blocks.Interfaces.RealInput manVarVal(min=0, max=1)
    "Prescribed expansion valve's opening"
  Modelica.Blocks.Interfaces.RealOutput curManVarVal(min=0, max=1)
    "Current expansion valve's opening"
  Modelica.Blocks.Continuous.Filter filterOpening(
    final analogFilter=Modelica.Blocks.Types.AnalogFilter.CriticalDamping,
    final filterType=Modelica.Blocks.Types.FilterType.LowPass,
    order=2,
    f_cut=5/(2*Modelica.Constants.pi*risTim),
    x(each stateSelect=StateSelect.always))
     if useInpFil
    "Second order filter to approximate valve opening or closing time"
  Modelica.Blocks.Routing.RealPassThrough openingThrough
    "Dummy passing through of opening signal to allow usage of filter"

protected
  Modelica.Units.SI.Area AThr "Current cross-sectional area of the valve";
  Real opening(unit="1")
    "Current valve's opening";

  Modelica.Units.SI.Density dInl=Medium.density(staInl)
    "Density at valves's inlet conditions";
  Modelica.Units.SI.AbsolutePressure pInl=port_a.p
    "Pressure of the fluid at inlet conditions";
  Modelica.Units.SI.AbsolutePressure pOut=port_b.p
    "Pressure of the fluid at outlet conditions";

equation
  // Calculation of thermodynamic states
  //
  staInl = Medium.setState_phX(port_a.p,
    actualStream(port_a.h_outflow), actualStream(port_a.Xi_outflow))
    "Thermodynamic state of the fluid at inlet condtions";
  staOut = Medium.setState_phX(port_b.p,
    actualStream(port_b.h_outflow), actualStream(port_b.Xi_outflow))
    "Thermodynamic state of the fluid at outlet condtions";

  // Calculation of valve's opening degree
  //
  connect(filterOpening.u, manVarVal);
  if useInpFil then
    connect(openingThrough.u, filterOpening.y)
      "Transient behaviour of valve's opening";
  else
    connect(openingThrough.u, manVarVal)
      "No transient behaiviour of valve's opnening";
  end if;
  opening = smooth(1, noEvent(if openingThrough.y>0 then
                              openingThrough.y else 1e-15))
    "Current valve's opening";

  // Calculation of active cross-sectional flow area
  //
  AThr = opening * AVal "Current cross-sectional area of the valve";

  // Calculation of outputs
  //
  curManVarVal = opening "Current valve's opening";
end PartialExpansionValve;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses;
partial model PartialFlowCoefficient
  "Partial model describing base flow coefficient"

  // Definition of inputs
  //
  replaceable package Medium =
    Modelica.Media.R134a.R134a_ph
    constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
    "Definition of two-phase medium";

  input Real opening(unit="1")
    "Current valve's opening";
  input Modelica.Units.SI.Area AVal
    "Cross-sectional area of the expansion valve";
  input Modelica.Units.SI.Diameter dInlPip
    "Diameter of the pipe at valve's inlet";

  input Medium.ThermodynamicState staInl
    "Thermodynamic state at valve's inlet conditions";
  input Medium.ThermodynamicState staOut
    "Thermodynamic state at valve's outlet conditions";
  input Modelica.Units.SI.AbsolutePressure pInl
    "Pressure at valves's inlet conditions";
  input Modelica.Units.SI.AbsolutePressure pOut
    "Pressure at valves's outlet conditions";

  // Definition of base variables
  //
  Real C(unit="1", min = 0, max = 100, nominal = 25)
    "Mass flow coefficient used for expansion valves";
end PartialFlowCoefficient;


Base model for all isenthalpic expansion valves. This is a base model for simple isenthalpic expansion valves that are
  used, for example, in close-loop systems like heat pumps or chillers.
  This model inherits from
  AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses.PartialExpansionValve
  and, hence, please check out the PartialExpansionValve model if
  detailed information is required about the modelling approach.

within AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses;
partial model PartialIsenthalpicExpansionValve
  "Base model for all isenthalpic expansion valves"
  extends BaseClasses.PartialExpansionValve;

equation
  // Calculation of energy balance
  //
  port_a.h_outflow = inStream(port_b.h_outflow) "Isenthalpic expansion valve";
  port_b.h_outflow = inStream(port_a.h_outflow) "Isenthalpic expansion valve";
end PartialIsenthalpicExpansionValve;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses;
partial model PartialModularExpansionVavles
  "Base model for all modular expansion valve models"

  // Definition of parameters describing the modular approach in general
  //
  parameter Integer nVal = 1
    "Number of valves - each valve will be connected to an individual port_b"

  // Definition of replaceable expansion valve models
  //
  replaceable model SimpleExpansionValve =
    SimpleExpansionValves.IsenthalpicExpansionValve
    constrainedby PartialExpansionValve
    "Model of simple expansion valve"

  SimpleExpansionValve modExpVal[nVal](
    redeclare each final package Medium = Medium,
    final AVal=AVal,
    final dInlPip=dInlPip,
    final useInpFil=useInpFil,
    final risTim=risTim,
    final calcProc=calcProc,
    final mFlowNom=mFlowNom,
    final dpNom=dpNom,
    redeclare final model FlowCoefficient = FlowCoefficient,
    each final allowFlowReversal=allowFlowReversal,
    each final dp_start=dp_start,
    final m_flow_nominal=mFlowNom)
    "Array of expansion valves"

  // Definition of parameters describing the expansion valves
  //
  parameter Modelica.Units.SI.Area AVal[nVal]=fill(2e-6, nVal)
    "Cross-sectional areas of the valves when they are fully opened"
  parameter Modelica.Units.SI.Diameter dInlPip[nVal]=fill(7.5e-3, nVal)
    "Diameters of the pipes at valves' inlets"

  parameter Boolean useInpFil[nVal] = fill(false, nVal)
    "= true, if transient behaviours of valves opening or closing are computed"
  parameter Modelica.Units.SI.Time risTim[nVal]=fill(0.5, nVal)
    "Time until valves opening reach 99.6 % of the set values"

  parameter Utilities.Types.CalcProc calcProc[nVal]=fill(Utilities.Types.CalcProc.flowCoefficient,
      nVal) "Chose predefined calculation method for flow coefficients"
  parameter Modelica.Units.SI.MassFlowRate mFlowNom[nVal]={m_flow_nominal/sum(
      AVal)*AVal[i] for i in 1:nVal} "Mass flow at nominal conditions"
  parameter Modelica.Units.SI.PressureDifference dpNom[nVal]=fill(dp_nominal,
      nVal) "Pressure drop at nominal conditions"

  replaceable model FlowCoefficient =
    Utilities.FlowCoefficient.SpecifiedFlowCoefficients.ConstantFlowCoefficient
    constrainedby BaseClasses.PartialFlowCoefficient
    "Model that describes the calculation of the flow coefficient"

  /*Parameters presented above are used to define each element of the
    expansion valve vector. Therefore, the parameters are identically to the
    parameters of a simple expension valve aside from the fact that the
    parameters are introduced as arraies
  */

  // Definition of replaceable controller model
  //
  replaceable model ModularController =
    Controls.HeatPump.ModularHeatPumps.ModularExpansionValveController
    constrainedby Controls.HeatPump.ModularHeatPumps.BaseClasses.PartialModularController
    "Model of the modular controller"

  ModularController expValCon(
    final nCom=nVal,
    final useExt=useExt,
    final controllerType=controllerType,
    final reverseAction=reverseAction,
    final reset=reset,
    final k=k,
    final Ti=Ti,
    final Ni=Ni,
    final Td=Td,
    final Nd=Nd,
    final wp=wp,
    final wd=wd,
    final yMax=yMax,
    final yMin=yMin,
    final initType=initType,
    final xi_start=xi_start,
    final xd_start=xd_start,
    final y_start=y_start)
    "Model of internal controller"

  // Definition of parameters describing the expansion valve controller
  //
  parameter Boolean useExt = false
    "= true, if external signal is used instead of internal controllers"
  parameter Modelica.Blocks.Types.SimpleController controllerType[nVal]=
    fill(Modelica.Blocks.Types.SimpleController.PID,nVal)
    "Type of controller"
  parameter Boolean reverseAction[nVal] = fill(false,nVal)
    "= true, if medium flow rate is throttled through cooling coil controller"
  parameter AixLib.Types.Reset reset[nVal]=
    fill(AixLib.Types.Reset.Disabled,nVal)
    "Type of controller output reset"

  parameter Real k[nVal] = fill(1,nVal)
    "Gain of controller"
  parameter Modelica.Units.SI.Time Ti[nVal]=fill(0.5, nVal)
    "Time constant of integrator block"
  parameter Real Ni[nVal] = fill(0.9,nVal)
    "Ni*Ti is time constant of anti-windup compensation"
  parameter Modelica.Units.SI.Time Td[nVal]=fill(0.1, nVal)
    "Time constant of derivative block"
  parameter Real Nd[nVal] = fill(10,nVal)
    "The higher Nd, the more ideal the derivative block"

  parameter Real wp[nVal] = fill(1,nVal)
    "Set-point weight for Proportional block (0..1)"
  parameter Real wd[nVal] = fill(0,nVal)
    "Set-point weight for Derivative block (0..1)"
  parameter Real yMax[nVal] = fill(1,nVal)
    "Upper limit of output"
  parameter Real yMin[nVal] = fill(0,nVal)
    "Lower limit of output"

  parameter Modelica.Blocks.Types.Init initType[nVal]=fill(Modelica.Blocks.Types.Init.InitialState,
      nVal)
    "Init: (1: no init, 2: steady state, 3: initial state, 4: initial output)"
  parameter Real xi_start[nVal]=fill(0, nVal)
    "Initial or guess value value for integrator output (= integrator state)"
  parameter Real xd_start[nVal]=fill(0, nVal)
    "Initial or guess value for state of derivative block"
  parameter Real y_start[nVal]=fill(0, nVal)
    "Initial value of output"

  /*Parameters presented above are used to define each element of the
    expansion valve controller. Therefore, the parameters are identically to the
    parameters of the controller aside from the fact that the
    parameters are introduced as arraies
  */

  // Extends base port model and set base parameters
  //
  extends Fluid.Interfaces.PartialModularPort_b(
    redeclare replaceable package Medium =
      Modelica.Media.R134a.R134a_ph,
    final nPorts=nVal);

  // Definition of parameters describing diagnostics
  //
  parameter Boolean show_parVal = false
    "= true, if expansions valves' input parameters are shown in results"
  parameter Boolean show_parCon = false
    "= true, if controller's input parameters are shown in results"

  // Definition of connectors
  //
  Controls.Interfaces.ModularHeatPumpControlBus dataBus(
    final nVal=nVal) "Data bus connector"

equation
  // Connect port_a with inlet ports of expansion valves
  //
  for i in 1:nVal loop
    connect(port_a, modExpVal[i].port_a);
  end for;

  // Connect data bus and further control signals
  //
  connect(expValCon.manVar, modExpVal.manVarVal)
  connect(modExpVal.curManVarVal, expValCon.curManVar)
  connect(dataBus, expValCon.dataBus)
end PartialModularExpansionVavles;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Examples;
model BaseModelStaticHeatPumps
  "Base model to test compressors using static heat pump boundaries"
  extends Modelica.Icons.Example;

  // Definition of medium
  //
  replaceable package Medium =
    Modelica.Media.R134a.R134a_ph
    constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
    "Medium of the compressor"

  // Definition of parameters describing compressors
  //
  parameter Integer nVal = 1
    "Numer of compressors in parallel"

  // Definition of parameters describing boundary conditions
  //
  parameter Modelica.Units.SI.TemperatureDifference dTPinEva=2
    "Pinch temperature at evaporator's outlet"
  parameter Modelica.Units.SI.TemperatureDifference dTSupHea=1
    "Superheating of working fluid"

  parameter Modelica.Units.SI.TemperatureDifference dTPinCond=2
    "Pinch temperature at condenser's outlet"
  parameter Modelica.Units.SI.TemperatureDifference dTSubCool=4
    "Supercooling of working fluid"

  parameter Modelica.Units.SI.Density dSec=1000
    "Constant density of secondary fluid"
  parameter Modelica.Units.SI.SpecificHeatCapacity cpSec=4.1813e3
    "Constant specific heat capacity of secondary fluid"
  parameter Modelica.Units.SI.VolumeFlowRate V_flowSec=(0.776 + 0.781 + 0.44)/3
      /3600 "Constant volume flow of secondary fluid"

  // Definition of variables describing boundary conditions
  //
  Modelica.Blocks.Sources.CombiTimeTable inpDat(
    extrapolation=Modelica.Blocks.Types.Extrapolation.NoExtrapolation,
    columns=2:7,
    table=[0,64,285.15,5180,308.15,900,5.755555556; 1,64,283.15,4920,308.15,910,
        5.406593407; 2,63,280.15,4370,308.15,930,4.698924731; 3,64,285.15,4980,318.15,
        1140,4.368421053; 4,64,283.15,4730,318.15,1140,4.149122807; 5,55,285.15,
        4180,328.15,1240,3.370967742; 6,64,283.15,4650,328.15,1380,3.369565217;
        7,63,280.15,4160,318.15,1610,2.583850932; 8,55,275.15,2800,308.15,790,3.544303797;
        9,106,258.15,3760,308.15,1570,2.394904459; 10,115,266.15,4850,308.15,1940,
        2.5; 11,55,275.15,2640,318.15,960,2.75; 12,111,258.15,4150,318.15,2120,1.95754717;
        13,107,270.15,4780,318.15,2210,2.162895928; 14,113,266.15,4560,318.15,2290,
        1.991266376; 15,100,266.15,3880,328.15,2240,1.732142857; 16,63,275.15,3280,
        328.15,1330,2.466165414; 17,63,280.15,4080,328.15,1400,2.914285714],
    smoothness=Modelica.Blocks.Types.Smoothness.ContinuousDerivative)
    "Static boundaries of compressor model"

  Modelica.Blocks.Sources.RealExpression inpSetSpeEnt(y=con.hOut)
    "Expressions describing set point of specific enthalpy"
  Modelica.Blocks.Sources.RealExpression inpAmbTemp(y=inpDat.y[2])
    "Expressions describing ambient temperature"
  Modelica.Blocks.Sources.RealExpression inpColCap(y=inpDat.y[3] - inpDat.y[5])
    "Expressions describing col capacity"
  Modelica.Blocks.Sources.RealExpression inpHeaCap(y=inpDat.y[3])
    "Expressions describing heat capacity"
  Modelica.Blocks.Sources.RealExpression inpTFlo(y=inpDat.y[4])
    "Expressions describing flow temperature at heat capacity"

  // Definition of subcomponents
  //
  StaticEvaporator eva(
    redeclare final package Medium = Medium,
    final dTPin=dTPinEva,
    final dTSupHea=dTSupHea,
    nPorts=nVal)
    "Model that describes a simple static evaporator"

  Modelica.Blocks.Continuous.LimPID conPID(
    k=0.001,
    Ti=10,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    yMax=1,
    yMin=0.05) "PID controller to set valves' openings"
  Modelica.Blocks.Sources.RealExpression inpCurSpeEnt(y=eva.hInl)
    "Expressions describing current specific enthalpy"
  Modelica.Blocks.Routing.Replicator repMea(nout=nVal)
    "Replicating the current value of the manipulated variables"
  ModularExpansionValves.ModularExpansionValvesSensors modExpVal(
    redeclare package Medium = Medium,
    nVal=nVal,
    redeclare model SimpleExpansionValve =
        SimpleExpansionValves.IsenthalpicExpansionValve,
    AVal=fill(1.767e-6, nVal),
    useExt=true,
    useInpFil=fill(true, nVal),
    redeclare model FlowCoefficient =
        Utilities.FlowCoefficient.SpecifiedFlowCoefficients.Poly_R22R407CR410A_EEV_15_22,
    risTim=fill(0.01328, nVal))
    "Model that describes modular expansion valves in parallel"

  StaticCondenser con(
    redeclare package Medium = Medium,
    dTSubCool=dTSubCool,
    dTPin=dTPinCond,
    dSec=dSec,
    cpSec=cpSec,
    V_flowSec=V_flowSec)
    "Model that describes a simple static condenser"

  AixLib.Controls.Interfaces.ModularHeatPumpControlBus dataBus(nVal=nVal)
    "Connector that contains all control signals"

protected
  model StaticEvaporator
    "Static evaporator assuming constant pinch point at evaporator's outlet"

    // Definition of medium
    //
    replaceable package Medium = Modelica.Media.R134a.R134a_ph
      constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
      "Medium of the expansion valve"

    // Definition of parameters describing evaporator
    //
    parameter Integer nPorts = 1;

    parameter Modelica.Units.SI.TemperatureDifference dTPin=5
      "Pinch temperature at evaporator's outlet"
    parameter Modelica.Units.SI.TemperatureDifference dTSupHea=1
      "Superheating of working fluid"

    // Definition of parameters describing assumptions
    //
    parameter Boolean allowFlowReversal = false
      "= false to simplify equations, assuming, but not enforcing, no flow reversal"

    // Definition of connecotrs
    //
    Modelica.Fluid.Interfaces.FluidPorts_b ports_b[nPorts](
      redeclare each final package Medium = Medium,
      h_outflow(each start = Medium.h_default),
      m_flow(each max=Modelica.Constants.inf))
      "Fluid connectors b (positive design flow direction is from port_a to port_b)"
    Modelica.Blocks.Interfaces.RealInput inpTAmb
      "Input of ambient temperature"
    Modelica.Blocks.Interfaces.RealInput inpQ_flow
      "Input of cold capacity"

    // Definition of submodels
    //
    Modelica.Blocks.Sources.RealExpression inlPEva(y=pSat)
      "Expressions describing saturation pressure at evaporator's inlet"
    Modelica.Blocks.Sources.RealExpression inlhEva(y=hInl)
      "Expressions describing specific enthalpy at evaporator's inlet"

    AixLib.Fluid.Sources.Boundary_ph source(
      redeclare package Medium = Medium,
      use_p_in=true,
      use_h_in=true,
      nPorts=1)
      "Source with constant pressure and specific enthalpy"
    Interfaces.PortsAThroughPortB outVal(
      redeclare package Medium = Medium, nVal=nPorts)
      "Model that combines the outputs of modular expansion valves"
    Sensors.SpecificEnthalpyTwoPort senSpeEnt[nPorts](
      redeclare package Medium = Medium,
      each m_flow_nominal=0.05,
      each initType=Modelica.Blocks.Types.Init.NoInit,
      each tau=0,
      each h_out_start=275e3) "Sensor that measures current specific enthalpy"
    Sensors.MassFlowRate senMasFlo[nPorts](redeclare package Medium = Medium)
      "Sensor that measures current mas flow rate"

    // Definition of variables describing evaporator
    //
    Medium.SaturationProperties satEva
      "Saturation properties of the evaporator's working fluid"
    Medium.ThermodynamicState staOut
      "Thermodynamic state of the working fluid  at evaporator's outlet"

  public
    Modelica.Units.SI.AbsolutePressure pSat
      "Absolute pressure at evaporator's outlet";
    Modelica.Units.SI.Temperature TSat "Saturation temperature";

    Modelica.Units.SI.SpecificEnthalpy hInl
      "Specific enthalpy at evaporator's inlet";
    Modelica.Units.SI.SpecificEnthalpy hOut
      "Specific enthalpy at evaporator's outlet";
    Modelica.Units.SI.Temperature TOut "Temperature at evaporator's outlet";

    Modelica.Units.SI.Temperature TAmb "Temperature of ambient";

    Modelica.Units.SI.MassFlowRate m_flow "Mass flow rate";
    Modelica.Units.SI.HeatFlowRate Q_flow "Cooling capacity";

  equation
    // Connection of ports
    //
    connect(inlPEva.y, source.p_in)
    connect(inlhEva.y, source.h_in)
    connect(ports_b, senSpeEnt.port_a)
    connect(senSpeEnt.port_b, senMasFlo.port_a)
    connect(source.ports[1], outVal.port_b)
    connect(senMasFlo.port_b, outVal.ports_a)

    TAmb = inpTAmb
      "Temperature of ambient";
    m_flow = senMasFlo[1].m_flow
      "Mass flow rate";
    Q_flow = inpQ_flow
      "Cooling capacity";

    // Calculation of state properties of working fluid
    //
    satEva = Medium.setSat_T(T=TSat)
      "Saturation properties";
    staOut = Medium.setState_pT(p=pSat,T=TOut)
      "Thermodynamic state of the working fluid at evaporator's outlet";

    pSat = Medium.saturationPressure(satEva.Tsat)
      "Absolute pressure at evaporator's outlet";
    TSat = TOut - dTSupHea
      "Saturation temperature";

    hInl = hOut - Q_flow/m_flow
      "Specific enthalpy at evaporator's inlet";

    TOut = TAmb - dTPin
      "Temperature at evaporator's outlet";
    hOut = Medium.specificEnthalpy(staOut)
      "Specific enthalpy at evaporator's outlet";
  end StaticEvaporator;

  model StaticCondenser
    "Static condenser assuming constant pinch point at condenser's outlet"

    // Definition of medium
    //
    replaceable package Medium = Modelica.Media.R134a.R134a_ph
      constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
      "Medium of the expansion valve"

    // Definition of parameters describing condenser
    //
    parameter Modelica.Units.SI.TemperatureDifference dTPin=5
      "Pinch temperature at condenser's outlet"
    parameter Modelica.Units.SI.TemperatureDifference dTSubCool=8
      "Supercooling of working fluid"

    parameter Modelica.Units.SI.Density dSec=1000
      "Constant density of secondary fluid"
    parameter Modelica.Units.SI.SpecificHeatCapacity cpSec=4.1813e3
      "Constant specific heat capacity of secondary fluid"
    parameter Modelica.Units.SI.VolumeFlowRate V_flowSec=(0.776 + 0.781 + 0.44)
        /3/3600 "Constant volume flow of secondary fluid"

    // Definition of parameters describing assumptions
    //
    parameter Boolean allowFlowReversal = false
      "= false to simplify equations, assuming, but not enforcing, no flow reversal"

    // Definition of connecotrs
    //
    Modelica.Fluid.Interfaces.FluidPort_b port_b(
      redeclare final package Medium = Medium,
      m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0),
       h_outflow(start = Medium.h_default))
      "Fluid connector b (positive design flow direction is from port_a to port_b)"
    Modelica.Blocks.Interfaces.RealInput inpQ_flow
      "Heat capacity"
    Modelica.Blocks.Interfaces.RealInput inpTFlo
      "Temperature flow at heat capacity"

    // Definition of subcomponents
    //
    Modelica.Blocks.Sources.RealExpression inlPCond(y=pSat)
      "Expressions describing saturation pressure at condenser's inlet"
    Modelica.Blocks.Sources.RealExpression inlTCon(y=TOut)
      "Expressions describing temperature at condenser's inlet"
    AixLib.Fluid.Sources.Boundary_pT sink(
      redeclare package Medium = Medium,
      use_p_in=true,
      use_T_in=true,
      nPorts=1) "Source with constant pressure and temperature"

    AixLib.Fluid.Sensors.SpecificEnthalpyTwoPort senSpeEnt(
      redeclare package Medium = Medium,
      m_flow_nominal=0.05,
      initType=Modelica.Blocks.Types.Init.NoInit,
      h_out_start=400e3,
      tau=0) "Sensor that measures current specific enthalpy"
    AixLib.Fluid.Sensors.MassFlowRate senMasFlo(
      redeclare package Medium =Medium)
      "Sensor that measures current mas flow rate"

    // Definition of variables describing condenser
    //
    Medium.SaturationProperties satCon
      "Saturation properties of the condenser's working fluid"
    Medium.ThermodynamicState staOut
      "Thermodynamic state of the working fluid  at condenser's outlet"

  public
    Modelica.Units.SI.AbsolutePressure pSat
      "Absolute pressure at condenser's outlet";
    Modelica.Units.SI.Temperature TSat "Saturation temperature";

    Modelica.Units.SI.Temperature TOut "Temperature at condenser's outlet";
    Modelica.Units.SI.SpecificEnthalpy hOut
      "Specific enthalpy at condenser's outlet";

    Modelica.Units.SI.MassFlowRate m_flow "Mass flow rate";
    Modelica.Units.SI.HeatFlowRate Q_flow "Heat capacity";

    Modelica.Units.SI.MassFlowRate m_flowSec
      "Mass flow rate of secondary fluid";
    Modelica.Units.SI.Temperature TFlo "Temperature flow at heat capacity";
    Modelica.Units.SI.Temperature TRetFlo
      "Temperature return flow at heat capacity";

  equation
    // Connection of ports
    //
    connect(inlPCond.y, sink.p_in)
    connect(inlTCon.y, sink.T_in)
    connect(sink.ports[1], senMasFlo.port_b)
    connect(senMasFlo.port_a, senSpeEnt.port_b)
    connect(senSpeEnt.port_a,port_b)

    m_flow = senMasFlo.m_flow
      "Mass flow rate";
    Q_flow = inpQ_flow
      "Heat capacity";
    TFlo = inpTFlo
      "Temperature flow at heat capacity";

    // Calculation of state properties of working fluid
    //
    satCon = Medium.setSat_T(T=TSat)
      "Saturation properties";
    staOut = Medium.setState_pT(p=pSat,T=TOut)
      "Thermodynamic state of the working fluid at condenser's outlet";

    pSat = Medium.saturationPressure(T=TSat)
      "Absolute pressure at condenser's outlet";
    TSat = TOut + dTSubCool
      "Saturation temperature";

    TOut = TRetFlo + dTPin
      "Temperature at condenser's outlet";
    hOut = Medium.specificEnthalpy(state=staOut)
      "Specific enthalpy at condenser's outlet";

    TRetFlo = TFlo - Q_flow/(m_flowSec*cpSec)
      "Temperature return flow at heat capacity";
    m_flowSec = dSec*V_flowSec
      "Mass flow rate of secondary fluid";
  end StaticCondenser;

equation
  // Connection of main components
  //
  connect(con.port_b, modExpVal.port_a)

  // Connection of signals
  //
  connect(modExpVal.dataBus, dataBus)
  connect(inpHeaCap.y, con.inpQ_flow)
  connect(inpTFlo.y, con.inpTFlo)
  connect(repMea.y, dataBus.expValBus.extManVarVal)
  connect(inpColCap.y, eva.inpQ_flow)
  connect(inpAmbTemp.y, eva.inpTAmb)
  connect(inpCurSpeEnt.y, conPID.u_m)
  connect(inpSetSpeEnt.y, conPID.u_s)
  connect(conPID.y, repMea.u)
  connect(eva.ports_b, modExpVal.ports_b)
end BaseModelStaticHeatPumps;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Examples;
model ExpansionValveMassFlowRate
  "Simple model to check different flow coefficient models with fixed mass
   flow rate"
  extends Modelica.Icons.Example;

  // Define medium and parameters
  //
  package Medium =
   Modelica.Media.R134a.R134a_ph
   "Actual medium of the compressor";

  parameter Modelica.Units.SI.Temperature TInl=343.15
    "Actual temperature at inlet conditions";
  parameter Modelica.Units.SI.AbsolutePressure pOut=Medium.pressure(
      Medium.setDewState(Medium.setSat_T(TOut)))
    "Actual set point of the compressor's outlet pressure";
  parameter Modelica.Units.SI.Temperature TOut=278.15
    "Actual temperature at outlet conditions";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.1
    "Nominal mass flow rate";

  // Define components
  //
  AixLib.Fluid.Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    T=TInl,
    nPorts=1,
    m_flow=1)
    "Source of constant mass flow and temperature"
  Modelica.Blocks.Sources.Sine valOpe(
    f=1,
    amplitude=0.3,
    offset=0.7) "Input signal to prediscribe expansion valve's opening"
  SimpleExpansionValves.IsenthalpicExpansionValve linearValve(
    redeclare package Medium = Medium,
    m_flow_small=1e-6,
    m_flow_nominal=m_flow_nominal,
    show_flow_coefficient=false,
    show_staInl=false,
    show_staOut=false,
    dp_start=1e6,
    AVal=2.55e-5,
    calcProc=Utilities.Types.CalcProc.flowCoefficient,
    useInpFil=true,
    risTim=0.25,
    dpNom=1000000,
    redeclare model FlowCoefficient =
        Utilities.FlowCoefficient.SpecifiedFlowCoefficients.Poly_R407c_EEV_18)
    "Simple isothermal valve"
  AixLib.Fluid.FixedResistances.PressureDrop simplePipe(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=7.5e5)
    " Simple pipe to provide pressure loss"
  Sources.Boundary_pT                sink(
    redeclare package Medium = Medium,
    p=pOut,
    T=TOut,
    nPorts=1)
    "Sink of constant pressure and temperature"

equation
  // Define connections of components
  //
  connect(valOpe.y, linearValve.manVarVal)
  connect(linearValve.port_b, simplePipe.port_a)
  connect(simplePipe.port_b,sink. ports[1])
  connect(source.ports[1], linearValve.port_a)
end ExpansionValveMassFlowRate;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Examples;
model ExpansionValvePressureDifference
  "Simple model to check different flow coefficient models with fixed inlet
   and outlet states"
  extends Modelica.Icons.Example;

  // Define medium and parameters
  //
  package Medium =
   Modelica.Media.R134a.R134a_ph
   "Actual medium of the compressor";

  parameter Modelica.Units.SI.AbsolutePressure pInl=Medium.pressure(
      Medium.setBubbleState(Medium.setSat_T(TInl + 5)))
    "Actual pressure at inlet conditions";
  parameter Modelica.Units.SI.Temperature TInl=348.15
    "Actual temperature at inlet conditions";
  parameter Modelica.Units.SI.AbsolutePressure pOut=Medium.pressure(
      Medium.setDewState(Medium.setSat_T(TOut)))
    "Actual set point of the compressor's outlet pressure";
  parameter Modelica.Units.SI.Temperature TOut=278.15
    "Actual temperature at outlet conditions";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.1
    "Nominal mass flow rate";

  // Define components
  //
  Sources.Boundary_pT                source(
    redeclare package Medium = Medium,
    nPorts=1,
    p=pInl,
    T=TInl)
    "Source of constant pressure and temperature"
  Modelica.Blocks.Sources.Sine valOpe(
    amplitude=0.45,
    f=1,
    offset=0.5) "Input signal to prediscribe expansion valve's opening"
  SimpleExpansionValves.IsenthalpicExpansionValve linearValve(
    redeclare package Medium = Medium,
    show_flow_coefficient=true,
    show_staInl=true,
    show_staOut=false,
    useInpFil=false,
    AVal=2.01e-6,
    m_flow_nominal=m_flow_nominal,
    calcProc=AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.Types.CalcProc.flowCoefficient,
    dpNom=1000000,
    redeclare model FlowCoefficient =
        Utilities.FlowCoefficient.SpecifiedFlowCoefficients.Power_R134a_EEV_15)
    "Simple isothermal valve"

  Sources.Boundary_pT                sink(
    redeclare package Medium = Medium,
    p=pOut,
    T=TOut,
    nPorts=1)
    "Sink of constant pressure and temperature"

equation
  // Define connections of components
  //
  connect(source.ports[1], linearValve.port_a)
  connect(valOpe.y, linearValve.manVarVal)
  connect(linearValve.port_b,sink. ports[1])
end ExpansionValvePressureDifference;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Examples;
model ModularExpansionValvesMassFlowRate
  "Simple model to check modular expansion valves models with fixed mass
  flow rate"
  extends Modelica.Icons.Example;

  // Definition of medium and parameters
  //
  package Medium =
   Modelica.Media.R134a.R134a_ph
   "Current medium of the compressor";

  parameter Integer nVal = 3
    "Number of valves - each valve will be connected to an individual port_b";
  parameter Modelica.Units.SI.AbsolutePressure pInl=Medium.pressure(
      Medium.setBubbleState(Medium.setSat_T(TInl + 5)))
    "Current pressure at inlet conditions";
  parameter Modelica.Units.SI.Temperature TInl=348.15
    "Current temperature at inlet conditions";
  parameter Modelica.Units.SI.AbsolutePressure pOut=Medium.pressure(
      Medium.setDewState(Medium.setSat_T(TOut)))
    "Current set point of the compressor's outlet pressure";
  parameter Modelica.Units.SI.Temperature TOut=278.15
    "Current temperature at outlet conditions";

  // Definition of models
  //
  Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    T=TInl,
    nPorts=1,
    m_flow=1) "Source of constant mass flow and temperature"
  replaceable ModularExpansionValves.ModularExpansionValvesSensors modVal(
    redeclare package Medium = Medium,
    nVal=nVal,
    redeclare model SimpleExpansionValve =
        SimpleExpansionValves.IsenthalpicExpansionValve,
    show_parVal=false,
    show_parCon=false,
    useInpFil={true,true,true},
    AVal={2e-6,1.5e-6,1e-6},
    risTim={0.25,0.25,0.5},
    controllerType={Modelica.Blocks.Types.SimpleController.P,Modelica.Blocks.Types.SimpleController.P,
        Modelica.Blocks.Types.SimpleController.P},
    useExt=true,
    redeclare model FlowCoefficient =
        Utilities.FlowCoefficient.SpecifiedFlowCoefficients.Power_R134a_EEV_15,
    redeclare model ModularController =
        Controls.HeatPump.ModularHeatPumps.ModularExpansionValveController)
    "Modular expansion valves in parallel"
  Interfaces.PortsAThroughPortB portsAThroughPortB(
    redeclare package Medium = Medium, nVal=nVal)
    "Model to connect each valves' outlet pipe with each other"
  AixLib.Fluid.Sources.Boundary_pT                sink(
    redeclare package Medium = Medium,
    p=pOut,
    T=TOut,
    nPorts=1)
    "Sink of constant pressure and temperature"

  Controls.Interfaces.ModularHeatPumpControlBus dataBus(nVal=nVal)
    "Data bus used to enable communication with dummy signals"
  Modelica.Blocks.Routing.Replicator repValOpe(nout=nVal)
    "Replicating the valves' opening signal"
  Modelica.Blocks.Sources.Sine valOpe(
    f=1,
    amplitude=0.45,
    offset=0.5) "Input signal to prediscribe expansion valve's opening"
  Modelica.Blocks.Routing.Replicator repInt(nout=nVal)
    "Replicating the internal set signal"
  Modelica.Blocks.Routing.Replicator repCur(nout=nVal)
    "Replicating the actual value of the manipulated variables"
  Modelica.Blocks.Sources.Ramp ramCur(
    height=0.5,
    offset=0.3,
    duration=1)
    "Ramp to fake actual value of the controlled variables"

equation
  connect(source.ports[1], modVal.port_a)
  connect(modVal.ports_b, portsAThroughPortB.ports_a)
  connect(portsAThroughPortB.port_b,sink. ports[1])
  connect(valOpe.y, repValOpe.u)
  connect(valOpe.y, repInt.u)
  connect(ramCur.y,repCur. u)
  connect(modVal.dataBus, dataBus)
  connect(repValOpe.y, dataBus.expValBus.extManVarVal)
  connect(repInt.y, dataBus.expValBus.intSetPoiVal)
  connect(repCur.y, dataBus.expValBus.meaConVarVal)
end ModularExpansionValvesMassFlowRate;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Examples;
model ModularExpansionValvesPressureDifference
  "Simple model to check modular expansion valves models with fixed inlet
   and outlet states"
  extends Modelica.Icons.Example;

  // Definition of medium and parameters
  //
  package Medium =
   Modelica.Media.R134a.R134a_ph
   "Current medium of the compressor";

  parameter Integer nVal = 3
    "Number of valves - each valve will be connected to an individual port_b";
  parameter Modelica.Units.SI.AbsolutePressure pInl=Medium.pressure(
      Medium.setBubbleState(Medium.setSat_T(TInl + 5)))
    "Current pressure at inlet conditions";
  parameter Modelica.Units.SI.Temperature TInl=348.15
    "Current temperature at inlet conditions";
  parameter Modelica.Units.SI.AbsolutePressure pOut=Medium.pressure(
      Medium.setDewState(Medium.setSat_T(TOut)))
    "Current set point of the compressor's outlet pressure";
  parameter Modelica.Units.SI.Temperature TOut=278.15
    "Current temperature at outlet conditions";

  // Definition of models
  //
Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    T=TInl,
    nPorts=1,
    m_flow=1) "Source of constant mass flow and temperature"
  replaceable ModularExpansionValves.ModularExpansionValvesSensors modVal(
    redeclare package Medium = Medium,
    nVal=nVal,
    redeclare model SimpleExpansionValve =
        SimpleExpansionValves.IsenthalpicExpansionValve,
    show_parVal=false,
    show_parCon=false,
    useInpFil={true,true,true},
    AVal={2e-6,1.5e-6,1e-6},
    risTim={0.25,0.25,0.5},
    useExt=true,
    redeclare model FlowCoefficient =
        Utilities.FlowCoefficient.SpecifiedFlowCoefficients.ConstantFlowCoefficient,
    redeclare model ModularController =
        Controls.HeatPump.ModularHeatPumps.ModularExpansionValveController)
    "Modular expansion valves in parallel"
  Interfaces.PortsAThroughPortB portsAThroughPortB(
    redeclare package Medium = Medium, nVal=nVal)
    "Model to connect each valves' outlet pipe with each other"
  AixLib.Fluid.Sources.Boundary_pT sink(
    redeclare package Medium = Medium,
    p=pOut,
    T=TOut,
    nPorts=1)
    "Sink of constant pressure and temperature"
  Controls.Interfaces.ModularHeatPumpControlBus dataBus(nVal=nVal)
    "Data bus used to enable communication with dummy signals"
  Modelica.Blocks.Routing.Replicator repValOpe(nout=nVal)
    "Replicating the valves' opening signal"
  Modelica.Blocks.Sources.Sine valOpe(
    f=1,
    amplitude=0.45,
    offset=0.5) "Input signal to prediscribe expansion valve's opening"
  Modelica.Blocks.Routing.Replicator repInt(nout=nVal)
    "Replicating the internal set signal"
  Modelica.Blocks.Routing.Replicator repCur(nout=nVal)
    "Replicating the current value of the manipulated variables"
  Modelica.Blocks.Sources.Ramp ramCur(
    height=0.5,
    offset=0.3,
    duration=1)
    "Ramp to fake current value of the controlled variables"

equation
  connect(source.ports[1], modVal.port_a)
  connect(modVal.ports_b, portsAThroughPortB.ports_a)
  connect(portsAThroughPortB.port_b,sink. ports[1])
  connect(valOpe.y, repValOpe.u)
  connect(valOpe.y, repInt.u)
  connect(ramCur.y,repCur. u)
  connect(modVal.dataBus, dataBus)
  connect(repValOpe.y, dataBus.expValBus.extManVarVal)
  connect(repInt.y, dataBus.expValBus.intSetPoiVal)
  connect(repCur.y, dataBus.expValBus.meaConVarVal)
end ModularExpansionValvesPressureDifference;


Package that contains example models

within AixLib.Fluid.Actuators.Valves.ExpansionValves;
package Examples "Package that contains example models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Examples;
model StaticHeatPumpBoundaries
  "Base model to test expansion valve using static heat pump boundaries"
  extends Modelica.Icons.Example;

  // Definition of medium
  //
  replaceable package Medium =
    Modelica.Media.R134a.R134a_ph
    constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
    "Medium of the compressor"

  // Definition of parameters describing compressors
  //
  parameter Integer nVal = 1
    "Numer of compressors in parallel"

  // Definition of parameters describing boundary conditions
  //
  parameter Modelica.Units.SI.TemperatureDifference dTPinEva=2
    "Pinch temperature at evaporator's outlet"
  parameter Modelica.Units.SI.TemperatureDifference dTSupHea=1
    "Superheating of working fluid"

  parameter Modelica.Units.SI.TemperatureDifference dTPinCond=2
    "Pinch temperature at condenser's outlet"
  parameter Modelica.Units.SI.TemperatureDifference dTSubCool=4
    "Supercooling of working fluid"

  parameter Modelica.Units.SI.Density dSec=1000
    "Constant density of secondary fluid"
  parameter Modelica.Units.SI.SpecificHeatCapacity cpSec=4.1813e3
    "Constant specific heat capacity of secondary fluid"
  parameter Modelica.Units.SI.VolumeFlowRate V_flowSec=(0.776 + 0.781 + 0.44)/3
      /3600 "Constant volume flow of secondary fluid"

  // Definition of variables describing boundary conditions
  //
  Modelica.Blocks.Sources.CombiTimeTable inpDat(
    extrapolation=Modelica.Blocks.Types.Extrapolation.NoExtrapolation,
    columns=2:7,
    table=[0,64,285.15,5180,308.15,900,5.755555556; 1,64,283.15,4920,308.15,910,
        5.406593407; 2,63,280.15,4370,308.15,930,4.698924731; 3,64,285.15,4980,318.15,
        1140,4.368421053; 4,64,283.15,4730,318.15,1140,4.149122807; 5,55,285.15,
        4180,328.15,1240,3.370967742; 6,64,283.15,4650,328.15,1380,3.369565217;
        7,63,280.15,4160,318.15,1610,2.583850932; 8,55,275.15,2800,308.15,790,3.544303797;
        9,106,258.15,3760,308.15,1570,2.394904459; 10,115,266.15,4850,308.15,1940,
        2.5; 11,55,275.15,2640,318.15,960,2.75; 12,111,258.15,4150,318.15,2120,1.95754717;
        13,107,270.15,4780,318.15,2210,2.162895928; 14,113,266.15,4560,318.15,2290,
        1.991266376; 15,100,266.15,3880,328.15,2240,1.732142857; 16,63,275.15,3280,
        328.15,1330,2.466165414; 17,63,280.15,4080,328.15,1400,2.914285714],
    smoothness=Modelica.Blocks.Types.Smoothness.ContinuousDerivative)
    "Static boundaries of compressor model"

  Modelica.Blocks.Sources.RealExpression inpSetSpeEnt(y=con.hOut)
    "Expressions describing set point of specific enthalpy"
  Modelica.Blocks.Sources.RealExpression inpAmbTemp(y=inpDat.y[2])
    "Expressions describing ambient temperature"
  Modelica.Blocks.Sources.RealExpression inpColCap(y=inpDat.y[3] - inpDat.y[5])
    "Expressions describing col capacity"
  Modelica.Blocks.Sources.RealExpression inpHeaCap(y=inpDat.y[3])
    "Expressions describing heat capacity"
  Modelica.Blocks.Sources.RealExpression inpTFlo(y=inpDat.y[4])
    "Expressions describing flow temperature at heat capacity"

  // Definition of subcomponents
  //
  StaticEvaporator eva(
    redeclare final package Medium = Medium,
    final dTPin=dTPinEva,
    final dTSupHea=dTSupHea,
    nPorts=nVal)
    "Model that describes a simple static evaporator"

  Modelica.Blocks.Continuous.LimPID conPID(
    k=0.001,
    Ti=10,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    yMax=1,
    yMin=0.05) "PID controller to set valves' openings"
  Modelica.Blocks.Sources.RealExpression inpCurSpeEnt(y=eva.hInl)
    "Expressions describing current specific enthalpy"
  Modelica.Blocks.Routing.Replicator repMea(nout=nVal)
    "Replicating the current value of the manipulated variables"
  ModularExpansionValves.ModularExpansionValvesSensors modExpVal(
    redeclare package Medium = Medium,
    nVal=nVal,
    redeclare model SimpleExpansionValve =
        SimpleExpansionValves.IsenthalpicExpansionValve,
    AVal=fill(1.767e-6, nVal),
    useExt=true,
    useInpFil=fill(true, nVal),
    redeclare model FlowCoefficient =
        Utilities.FlowCoefficient.SpecifiedFlowCoefficients.Poly_R22R407CR410A_EEV_15_22,
    risTim=fill(0.01328, nVal))
    "Model that describes modular expansion valves in parallel"

  StaticCondenser con(
    redeclare package Medium = Medium,
    dTSubCool=dTSubCool,
    dTPin=dTPinCond,
    dSec=dSec,
    cpSec=cpSec,
    V_flowSec=V_flowSec)
    "Model that describes a simple static condenser"

  AixLib.Controls.Interfaces.ModularHeatPumpControlBus dataBus(nVal=nVal)
    "Connector that contains all control signals"

protected
  model StaticEvaporator
    "Static evaporator assuming constant pinch point at evaporator's outlet"

    // Definition of medium
    //
    replaceable package Medium = Modelica.Media.R134a.R134a_ph
      constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
      "Medium of the expansion valve"

    // Definition of parameters describing evaporator
    //
    parameter Integer nPorts = 1;

    parameter Modelica.Units.SI.TemperatureDifference dTPin=5
      "Pinch temperature at evaporator's outlet"
    parameter Modelica.Units.SI.TemperatureDifference dTSupHea=1
      "Superheating of working fluid"

    // Definition of parameters describing assumptions
    //
    parameter Boolean allowFlowReversal = false
      "= false to simplify equations, assuming, but not enforcing, no flow reversal"

    // Definition of connecotrs
    //
    Modelica.Fluid.Interfaces.FluidPorts_b ports_b[nPorts](
      redeclare each final package Medium = Medium,
      h_outflow(each start = Medium.h_default),
      m_flow(each max=Modelica.Constants.inf))
      "Fluid connectors b (positive design flow direction is from port_a to port_b)"
    Modelica.Blocks.Interfaces.RealInput inpTAmb
      "Input of ambient temperature"
    Modelica.Blocks.Interfaces.RealInput inpQ_flow
      "Input of cold capacity"

    // Definition of submodels
    //
    Modelica.Blocks.Sources.RealExpression inlPEva(y=pSat)
      "Expressions describing saturation pressure at evaporator's inlet"
    Modelica.Blocks.Sources.RealExpression inlhEva(y=hInl)
      "Expressions describing specific enthalpy at evaporator's inlet"

    AixLib.Fluid.Sources.Boundary_ph source(
      redeclare package Medium = Medium,
      use_p_in=true,
      use_h_in=true,
      nPorts=1)
      "Source with constant pressure and specific enthalpy"
    Interfaces.PortsAThroughPortB outVal(
      redeclare package Medium = Medium, nVal=nPorts)
      "Model that combines the outputs of modular expansion valves"
    Sensors.SpecificEnthalpyTwoPort senSpeEnt[nPorts](
      redeclare package Medium = Medium,
      each m_flow_nominal=0.05,
      each initType=Modelica.Blocks.Types.Init.NoInit,
      each tau=0,
      each h_out_start=275e3) "Sensor that measures current specific enthalpy"
    Sensors.MassFlowRate senMasFlo[nPorts](redeclare package Medium = Medium)
      "Sensor that measures current mas flow rate"

    // Definition of variables describing evaporator
    //
    Medium.SaturationProperties satEva
      "Saturation properties of the evaporator's working fluid"
    Medium.ThermodynamicState staOut
      "Thermodynamic state of the working fluid  at evaporator's outlet"

  public
    Modelica.Units.SI.AbsolutePressure pSat
      "Absolute pressure at evaporator's outlet";
    Modelica.Units.SI.Temperature TSat "Saturation temperature";

    Modelica.Units.SI.SpecificEnthalpy hInl
      "Specific enthalpy at evaporator's inlet";
    Modelica.Units.SI.SpecificEnthalpy hOut
      "Specific enthalpy at evaporator's outlet";
    Modelica.Units.SI.Temperature TOut "Temperature at evaporator's outlet";

    Modelica.Units.SI.Temperature TAmb "Temperature of ambient";

    Modelica.Units.SI.MassFlowRate m_flow "Mass flow rate";
    Modelica.Units.SI.HeatFlowRate Q_flow "Cooling capacity";

  equation
    // Connection of ports
    //
    connect(inlPEva.y, source.p_in)
    connect(inlhEva.y, source.h_in)
    connect(ports_b, senSpeEnt.port_a)
    connect(senSpeEnt.port_b, senMasFlo.port_a)
    connect(source.ports[1], outVal.port_b)
    connect(senMasFlo.port_b, outVal.ports_a)

    TAmb = inpTAmb
      "Temperature of ambient";
    m_flow = senMasFlo[1].m_flow
      "Mass flow rate";
    Q_flow = inpQ_flow
      "Cooling capacity";

    // Calculation of state properties of working fluid
    //
    satEva = Medium.setSat_T(T=TSat)
      "Saturation properties";
    staOut = Medium.setState_pT(p=pSat,T=TOut)
      "Thermodynamic state of the working fluid at evaporator's outlet";

    pSat = Medium.saturationPressure(satEva.Tsat)
      "Absolute pressure at evaporator's outlet";
    TSat = TOut - dTSupHea
      "Saturation temperature";

    hInl = hOut - Q_flow/m_flow
      "Specific enthalpy at evaporator's inlet";

    TOut = TAmb - dTPin
      "Temperature at evaporator's outlet";
    hOut = Medium.specificEnthalpy(staOut)
      "Specific enthalpy at evaporator's outlet";
  end StaticEvaporator;

  model StaticCondenser
    "Static condenser assuming constant pinch point at condenser's outlet"

    // Definition of medium
    //
    replaceable package Medium = Modelica.Media.R134a.R134a_ph
      constrainedby Modelica.Media.Interfaces.PartialTwoPhaseMedium
      "Medium of the expansion valve"

    // Definition of parameters describing condenser
    //
    parameter Modelica.Units.SI.TemperatureDifference dTPin=5
      "Pinch temperature at condenser's outlet"
    parameter Modelica.Units.SI.TemperatureDifference dTSubCool=8
      "Supercooling of working fluid"

    parameter Modelica.Units.SI.Density dSec=1000
      "Constant density of secondary fluid"
    parameter Modelica.Units.SI.SpecificHeatCapacity cpSec=4.1813e3
      "Constant specific heat capacity of secondary fluid"
    parameter Modelica.Units.SI.VolumeFlowRate V_flowSec=(0.776 + 0.781 + 0.44)
        /3/3600 "Constant volume flow of secondary fluid"

    // Definition of parameters describing assumptions
    //
    parameter Boolean allowFlowReversal = false
      "= false to simplify equations, assuming, but not enforcing, no flow reversal"

    // Definition of connecotrs
    //
    Modelica.Fluid.Interfaces.FluidPort_b port_b(
      redeclare final package Medium = Medium,
      m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0),
       h_outflow(start = Medium.h_default))
      "Fluid connector b (positive design flow direction is from port_a to port_b)"
    Modelica.Blocks.Interfaces.RealInput inpQ_flow
      "Heat capacity"
    Modelica.Blocks.Interfaces.RealInput inpTFlo
      "Temperature flow at heat capacity"

    // Definition of subcomponents
    //
    Modelica.Blocks.Sources.RealExpression inlPCond(y=pSat)
      "Expressions describing saturation pressure at condenser's inlet"
    Modelica.Blocks.Sources.RealExpression inlTCon(y=TOut)
      "Expressions describing temperature at condenser's inlet"
    AixLib.Fluid.Sources.Boundary_pT sink(
      redeclare package Medium = Medium,
      use_p_in=true,
      use_T_in=true,
      nPorts=1) "Source with constant pressure and temperature"

    AixLib.Fluid.Sensors.SpecificEnthalpyTwoPort senSpeEnt(
      redeclare package Medium = Medium,
      m_flow_nominal=0.05,
      initType=Modelica.Blocks.Types.Init.NoInit,
      h_out_start=400e3,
      tau=0) "Sensor that measures current specific enthalpy"
    AixLib.Fluid.Sensors.MassFlowRate senMasFlo(
      redeclare package Medium =Medium)
      "Sensor that measures current mas flow rate"

    // Definition of variables describing condenser
    //
    Medium.SaturationProperties satCon
      "Saturation properties of the condenser's working fluid"
    Medium.ThermodynamicState staOut
      "Thermodynamic state of the working fluid  at condenser's outlet"

  public
    Modelica.Units.SI.AbsolutePressure pSat
      "Absolute pressure at condenser's outlet";
    Modelica.Units.SI.Temperature TSat "Saturation temperature";

    Modelica.Units.SI.Temperature TOut "Temperature at condenser's outlet";
    Modelica.Units.SI.SpecificEnthalpy hOut
      "Specific enthalpy at condenser's outlet";

    Modelica.Units.SI.MassFlowRate m_flow "Mass flow rate";
    Modelica.Units.SI.HeatFlowRate Q_flow "Heat capacity";

    Modelica.Units.SI.MassFlowRate m_flowSec
      "Mass flow rate of secondary fluid";
    Modelica.Units.SI.Temperature TFlo "Temperature flow at heat capacity";
    Modelica.Units.SI.Temperature TRetFlo
      "Temperature return flow at heat capacity";

  equation
    // Connection of ports
    //
    connect(inlPCond.y, sink.p_in)
    connect(inlTCon.y, sink.T_in)
    connect(sink.ports[1], senMasFlo.port_b)
    connect(senMasFlo.port_a, senSpeEnt.port_b)
    connect(senSpeEnt.port_a,port_b)

    m_flow = senMasFlo.m_flow
      "Mass flow rate";
    Q_flow = inpQ_flow
      "Heat capacity";
    TFlo = inpTFlo
      "Temperature flow at heat capacity";

    // Calculation of state properties of working fluid
    //
    satCon = Medium.setSat_T(T=TSat)
      "Saturation properties";
    staOut = Medium.setState_pT(p=pSat,T=TOut)
      "Thermodynamic state of the working fluid at condenser's outlet";

    pSat = Medium.saturationPressure(T=TSat)
      "Absolute pressure at condenser's outlet";
    TSat = TOut + dTSubCool
      "Saturation temperature";

    TOut = TRetFlo + dTPin
      "Temperature at condenser's outlet";
    hOut = Medium.specificEnthalpy(state=staOut)
      "Specific enthalpy at condenser's outlet";

    TRetFlo = TFlo - Q_flow/(m_flowSec*cpSec)
      "Temperature return flow at heat capacity";
    m_flowSec = dSec*V_flowSec
      "Mass flow rate of secondary fluid";
  end StaticCondenser;

equation
  // Connection of main components
  //
  connect(con.port_b, modExpVal.port_a)

  // Connection of signals
  //
  connect(modExpVal.dataBus, dataBus)
  connect(inpHeaCap.y, con.inpQ_flow)
  connect(inpTFlo.y, con.inpTFlo)
  connect(repMea.y, dataBus.expValBus.extManVarVal)
  connect(inpColCap.y, eva.inpQ_flow)
  connect(inpAmbTemp.y, eva.inpTAmb)
  connect(inpCurSpeEnt.y, conPID.u_m)
  connect(inpSetSpeEnt.y, conPID.u_s)
  connect(conPID.y, repMea.u)
  connect(eva.ports_b, modExpVal.ports_b)
end StaticHeatPumpBoundaries;


Model of modular expansion valves, i.g. each valves is in front
  of an evaporator. This is a model of modular expansion valves that are used, for
  example, in close-loop systems like heat pumps or chillers.

  It consists of nVal expansion valves in parallel and
  also nVal PID conrollers if no external controller is
  used.

within AixLib.Fluid.Actuators.Valves.ExpansionValves.ModularExpansionValves;
model ModularExpansionValves
  "Model of modular expansion valves, i.g. each valves is in front
  of an evaporator"
  extends BaseClasses.PartialModularExpansionVavles;

equation
  // Connect ports_b with outlet ports of expansion valves
  //
  for i in 1:nVal loop
    connect(modExpVal[i].port_b, ports_b[i]);
  end for;
end ModularExpansionValves;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.ModularExpansionValves;
model ModularExpansionValvesSensors
  "Model of modular expansion valves, i.g. each valves is in front
  of an evaporator, combined with sensors"
  extends BaseClasses.PartialModularExpansionVavles;

  // Definition of parameters
  //
  parameter Modelica.Units.SI.Time tau=1 "Time constant at nominal flow rate"

  parameter Boolean transferHeat = false
    "if true, temperature T converges towards TAmb when no flow"
  parameter Modelica.Units.SI.Temperature TAmb=Medium.T_default
    "Fixed ambient temperature for heat transfer"
  parameter Modelica.Units.SI.Time tauHeaTra=1200
    "Time constant for heat transfer, default 20 minutes"

  parameter Modelica.Blocks.Types.Init initTypeSen=
    Modelica.Blocks.Types.Init.InitialState
    "Type of initialization (InitialState and InitialOutput are identical)"
  parameter Modelica.Units.SI.Temperature T_start=Medium.T_default
    "Initial or guess value of output (= state)"
  parameter Modelica.Units.SI.SpecificEnthalpy h_out_start=
      Medium.specificEnthalpy_pTX(
      p=Medium.p_default,
      T=Medium.T_default,
      X=Medium.X_default) "Initial or guess value of output (= state)"

  parameter Boolean show_parSen = false
    "= true, if sensors' input parameters are shown in results"

  // Definition of models
  //
  Utilities.ModularSensors modularSensors(
    redeclare final package Medium = Medium,
    final nPorts=nVal,
    final m_flow_nominal=m_flow_nominal,
    final m_flow_small=1e-6*m_flow_nominal,
    final tau=tau,
    final transferHeat=transferHeat,
    final TAmb=TAmb,
    final tauHeaTra=tauHeaTra,
    final initType=initTypeSen,
    final T_start=T_start,
    final h_out_start=h_out_start)
    "Model that contains different sensors located behind expansion valves"

equation
  // Connect expansion valves with sensors and sensors with ports_b
  //
  for i in 1:nVal loop
    connect(modExpVal[i].port_b, modularSensors.ports_a[i]);
    connect(modularSensors.ports_b[i],ports_b[i]);
  end for;

  // Connect sensors with data bus
  //
  connect(modularSensors.preMea, dataBus.senBus.meaPreVal)
  connect(modularSensors.temMea, dataBus.senBus.meaTemVal)
  connect(modularSensors.masFloMea, dataBus.senBus.meaMasFloVal)
  connect(modularSensors.quaMea, dataBus.senBus.meaPhaVal)
end ModularExpansionValvesSensors;


within AixLib.Fluid.Actuators.Valves.ExpansionValves;
package ModularExpansionValves "Package that contains models of modular expansion valves based on simple
  expansion valves"
  extends Modelica.Icons.VariantsPackage;
end ModularExpansionValves;


Model of a simple isenthalpic expansion valve. This is a model of a simple expansion valve that is used, for
  example, in close-loop systems like heat pumps or chillers. It
  inherits from PartialIsenthalpicExpansionValve which inherits from
  PartialExpansionValve. Therefore, please checkout these sub-models
  for further information of underlying modeling approaches and
  parameterisation:

within AixLib.Fluid.Actuators.Valves.ExpansionValves.SimpleExpansionValves;
model IsenthalpicExpansionValve "Model of a simple isenthalpic expansion valve"
  extends BaseClasses.PartialIsenthalpicExpansionValve;

equation
  // Calculation of mass flow and pressure drop
  //
  if (calcProc == Utilities.Types.CalcProc.linear) then
    C = 1  "Linear relationship";
    m_flow = C * AThr * dp
    "Simple linear relationship between mass flow and pressure drop";

  elseif (calcProc == Utilities.Types.CalcProc.nominal) then
    C * dpNom = mFlowNom "Nominal relationship";
    m_flow = C * AThr * dp
    "Simple nominal relationship between mass flow and pressure drop";

  elseif (calcProc == Utilities.Types.CalcProc.flowCoefficient) then
    C = flowCoefficient.C "Flow coefficient model";
    m_flow = homotopy(C * AThr * sqrt(abs(2*dInl*dp)),
                      mFlowNom/dpNom * AThr * dp)
    "Usage of flow coefficient model";

  else
    assert(false, "Invalid choice of calculation procedure");
  end if;
end IsenthalpicExpansionValve;


within AixLib.Fluid.Actuators.Valves.ExpansionValves;
package SimpleExpansionValves "Package that contains simple expansion valves"
  extends Modelica.Icons.VariantsPackage;
end SimpleExpansionValves;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities;
model ModularSensors
  "Model that contains mass flow, pressure, temperature and quality sensors
  for modular heat pump models"

  // Definition of parameters
  //
  parameter Modelica.Units.SI.Time tau=1 "Time constant at nominal flow rate"

  parameter Boolean transferHeat=false
    "if true, temperature T converges towards TAmb when no flow"
  parameter Modelica.Units.SI.Temperature TAmb=Medium.T_default
    "Fixed ambient temperature for heat transfer"
  parameter Modelica.Units.SI.Time tauHeaTra=1200
    "Time constant for heat transfer, default 20 minutes"

  parameter Modelica.Blocks.Types.Init initType=
    Modelica.Blocks.Types.Init.InitialState
    "Type of initialization (InitialState and InitialOutput are identical)"
  parameter Modelica.Units.SI.Temperature T_start=Medium.T_default
    "Initial or guess value of output (= state)"
  parameter Modelica.Units.SI.SpecificEnthalpy h_out_start=
      Medium.specificEnthalpy_pTX(
      p=Medium.p_default,
      T=Medium.T_default,
      X=Medium.X_default) "Initial or guess value of output (= state)"

  // Extensions
  //
  extends Interfaces.PartialModularPort_ab;

  // Definition of variables
  //
  Medium.SaturationProperties satPro[nPorts]
    "Saturation states for each fluid port";

  Modelica.Units.SI.SpecificEnthalpy bubEnt[nPorts]
    "Bubble enthalpies for each fluid port";
  Modelica.Units.SI.SpecificEnthalpy dewEnt[nPorts]
    "Dew enthalpies for each fluid port";
  Real pTriCri[nPorts]
    "Trigger to check if medium exceeds critical pressure";

  // Definition of models
  //
  Sensors.MassFlowRate senMasFlo[nPorts](
    redeclare each final package Medium = Medium) "Mass flow sensors"
  Sensors.Pressure senPre[nPorts](
    redeclare each final package Medium = Medium) "Pressure sensors"
  Sensors.TemperatureTwoPort senTem[nPorts](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=m_flow_nominal,
    each final m_flow_small=m_flow_small,
    each final tau=tau,
    each final initType=initType,
    each final T_start=T_start,
    each final transferHeat=transferHeat,
    each final TAmb=TAmb,
    each final tauHeaTra=tauHeaTra) "Temperature sensors"
  Sensors.SpecificEnthalpyTwoPort senSpeEnt[nPorts](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=m_flow_nominal,
    each final m_flow_small=m_flow_small,
    each final tau=tau,
    each final initType=initType,
    each final h_out_start=h_out_start) "Specific enthalpy sensors"

  // Definition of connectors
  //
  Modelica.Blocks.Interfaces.RealOutput preMea[nPorts]
    "Pressures measured by sensors"
  Modelica.Blocks.Interfaces.RealOutput temMea[nPorts]
    "Temperatures measured by sensors"
  Modelica.Blocks.Interfaces.RealOutput masFloMea[nPorts]
    "Mass flow rates measured by sensors"
  Modelica.Blocks.Interfaces.RealOutput quaMea[nPorts]
    "Qualities measured by sensors"

equation
  // Calculating vapour qualities
  //
  for i in 1:nPorts loop
    satPro[i] = Medium.setSat_p(senPre[i].p) "Set saturation properties";
    bubEnt[i] = Medium.bubbleEnthalpy(satPro[i]) "Calculate bubble enthalpies";
    dewEnt[i] = Medium.dewEnthalpy(satPro[i]) "Calculate dew enthalpies";
    pTriCri[i] = senPre[i].p/Medium.fluidConstants[1].criticalPressure
      "Check if medium exceeds critical pressure";
   quaMea[i] = noEvent(if (pTriCri[i]<1 and senSpeEnt[i].h_out<bubEnt[i]) then 0
     else if (pTriCri[i]<1 and senSpeEnt[i].h_out>bubEnt[i] and
     senSpeEnt[i].h_out<dewEnt[i]) then (senSpeEnt[i].h_out - bubEnt[i])/
     max(dewEnt[i] - bubEnt[i], 1e-6) else 1.0)
     "Calculate vapour qualities";
  end for;

  // Connection of sensors
  //
  for i in 1:nPorts loop
    connect(ports_a[i],senMasFlo[i].port_a);
    connect(senMasFlo[i].port_b,senPre[i].port);
    connect(senMasFlo[i].port_b,senTem[i].port_a);
    connect(senTem[i].port_b,senSpeEnt[i].port_a);
    connect(senSpeEnt[i].port_b,ports_b[i]);
  end for;

  // Connection of outputs
  //
  connect(preMea,senPre.p);
  connect(temMea,senTem.T);
  connect(masFloMea,senMasFlo.m_flow);
end ModularSensors;


within AixLib.Fluid.Actuators.Valves.ExpansionValves;
package Utilities "Package that contains further functions needed to compute
  the expnasion valves"
  extends Modelica.Icons.UtilitiesPackage;
end Utilities;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities;
package FlowCoefficient "Package that contains models describing different flow coefficients"
  extends Modelica.Icons.Package;
end FlowCoefficient;


Model describing flow coefficient based on polynomial approach. This model contains calculation procedures for flow coefficients (for
  more information, please check out
  AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses.PartialExpansionValve).
  The calculation procedures based on a polynomial approach and are
  presented below.

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient;
model PolynomialFlowCoefficient
  "Model describing flow coefficient based on polynomial approach"
  extends BaseClasses.PartialFlowCoefficient;

  // Definition of parameters
  //
  parameter Types.PolynomialModels polyMod=Types.PolynomialModels.ShanweiEtAl2005
    "Chose predefined polynomial model for flow coefficient"
  parameter Real a[:]
    "Multiplication factors for each summand"
  parameter Real b[:]
    "Exponents for each summand"
  parameter Integer nT = size(a,1)
    "Number of terms used for the calculation procedure"

  parameter Modelica.Units.SI.Diameter dCle=0.02e-3
    "Clearance diameter dCle = d_inner - d_needle"
  parameter Real pDifRat = 0.84
    "Pressure differential ratio factor depending on valve moddeld"

  // Definition of coefficients
  //
  Real P[nT]
    "Array that contains all coefficients used for the calculation procedure";
  Real corFact
    "Corraction factor used to correct flow coefficient";

  /*The correction factor is used to correct the flow coefficient if the
    formula presented by the author is not equal to
    m_flow = C_D*A*sqrt(2*rho_inlet*(pInl-pOut))
  */

protected
  Medium.SaturationProperties satInl
    "Saturation properties at valve's inlet conditions";
  Medium.SaturationProperties satOut
    "Saturation properties at valve's outlet conditions";

equation
  // Calculation of protected variables
  //
  satInl = Medium.setSat_p(pInl)
    "Saturation properties at valve's inlet conditions";
  satOut = Medium.setSat_p(pOut)
    "Saturation properties at valve's outlet conditions";

  // Calculation of coefficients
  //
  if (polyMod == Types.PolynomialModels.ShanweiEtAl2005) then
    /*Polynomial approach presented by Shanwei et al. (2005):
      C_D = a1*AVal + a2*rho_inlet + a3*rho_outlet + a4*T_subcooling +
      a5*dCle + a6*(pInl-pOut)

      Caution with units - In the following, none S.I units are presented:
        Pressure:       in kPa
        Temperature:    in °C
        Heat capacity:  in kJ/(kg*K)
        Heat of vap.:   in kJ/kg
    */
    P[1] = opening*AVal
      "Actual coss-sectional flow area";
    P[2] = Medium.bubbleDensity(satInl)
      "Density at valve's inlet";
    P[3] = Medium.density(staOut)
      "Density at valve's outlet";
    P[4] = satInl.Tsat - Medium.temperature(staInl)
      "Degree of subcooling";
    P[5] = dCle
      "Radial clearance";
    P[6] = (pInl-pOut)*1e-3
      "Pressure difference between inlet and outlet";

    corFact = 1
      "No correction factor is needed";

  elseif (polyMod == Types.PolynomialModels.Li2013) then
    /*Polynomial approach presented by Li (2013):
      C_D = a1 + a2*opening + a3*opening^2 + a4*opening*(T_subcooling/T_crit) +
      a5*(T_subcooling/T_crit) + a6*(T_subcooling/T_crit)^2

      Caution with units - In the following, none S.I units are presented:
        Pressure:       in kPa
        Temperature:    in °C
    */
    P[1] = 1
      "Dummy coefficient since no coefficient is needed";
    P[2] = opening
      "Degree of valve's opening";
    P[3] = opening^2
      "Quadratic degree of valve's opening";
    P[4] = opening*(satInl.Tsat - Medium.temperature(staInl))/
      (Medium.fluidConstants[1].criticalTemperature-273.15)
      "Degree of valve's opening times degree of subcooling";
    P[5] = (satInl.Tsat - Medium.temperature(staInl))/
     (Medium.fluidConstants[1].criticalTemperature-273.15)
      "Degree of subcooling";
    P[6] = ((satInl.Tsat - Medium.temperature(staInl))/
      (Medium.fluidConstants[1].criticalTemperature-273.15))^2
      "Quadratic degree of subcooling";

    corFact = 1 - ((1-pOut/pInl)/
      (3*(Medium.isentropicExponent(staOut)/1.4)*pDifRat))
      "Correction factor taking partial vaporisation into account";

      /*The correction factos takes into accout that a partial vaporisation
        takes place while throttling process. It is a function of the pressure
        difference between inlet and outlet, the isentropic exponent and the
        pressure differential ratio factor depending on the valve moddeld.
      */

  else
    assert(false, "Invalid choice of polynomial approach");
  end if;

  // Calculationg of flow coefficient
  //
  C = corFact * sum(a[i]*P[i]^b[i] for i in 1:nT)
    "Calculation procedure of general polynomial";
end PolynomialFlowCoefficient;


Model describing flow coefficient based on power approach. This model contains calculation procedures for flow coefficients (for
  more information, please check out
  AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses.PartialExpansionValve).
  The calculation procedures based on a power approach and are
  presented below.

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient;
model PowerFlowCoefficient
  "Model describing flow coefficient based on power approach"
  extends BaseClasses.PartialFlowCoefficient;

  // Definition of parameters
  //
  parameter Types.PowerModels powMod=Types.PowerModels.ShanweiEtAl2005
    "Chose predefined power model for flow coefficient"
  parameter Real a
    "Multiplication factor for generic power approach"
  parameter Real b[:]
    "Exponents for each multiplier"
  parameter Integer nT = size(b,1)
    "Number of terms used for the calculation procedure"

  parameter Modelica.Units.SI.Diameter dCle=0.02e-3
    "Clearance diameter dCle = d_inner - d_needle"
  parameter Real pDifRat = 0.84
    "Pressure differential ratio factor depending on valve moddeld"

  // Definition of coefficients
  //
  Real P[nT]
    "Array that contains all coefficients used for the calculation procedure";
  Real corFact
    "Corraction factor used to correct flow coefficient";

  /*The correction factor is used to correct the flow coefficient if the
    formula presented by the author is not equal to
    m_flow = C_D*A*sqrt(2*rho_inlet*(pInl-pOut))
  */

protected
  Medium.SaturationProperties satInl
    "Saturation properties at valve's inlet conditions";
  Medium.SaturationProperties satOut
    "Saturation properties at valve's outlet conditions";

equation
  // Calculation of protected variables
  //
  satInl = Medium.setSat_p(pInl)
    "Saturation properties at valve's inlet conditions";
  satOut = Medium.setSat_p(pOut)
    "Saturation properties at valve's outlet conditions";

  // Calculation of coefficients
  //
  if (powMod == Types.PowerModels.ShanweiEtAl2005) then
    /*Polynomial approach presented by Shanwei et al. (2005):
      C_D = C * (AVal/dCle^2)^b1 * ((pInl-pOut)/p_crit)^b2 *
      (T_crit/T_supercooled)^b3 * (rho_inlet/rho_outlet)^b4 *
      (quality)^b5

      Caution with units - In the following, none S.I units are presented:
        Pressure:       in kPa
        Temperature:    in °C
        Heat capacity:  in kJ/(kg*K)
        Heat of vap.:   in kJ/kg
    */
    P[1] = opening*AVal/(dCle^2)
      "Actual coss-sectional flow area";
    P[2] = (pInl-pOut)/Medium.fluidConstants[1].criticalPressure
      "Pressure difference";
    P[3] = (Medium.fluidConstants[1].criticalTemperature-273.15)/
      max((satInl.Tsat - Medium.temperature(staInl)),0.01)
      "Degree of subooling";
    P[4] = Medium.bubbleDensity(satInl)/Medium.density(staOut)
      "Density at valve's inlet and at valve's outlet";
    P[5] = (Medium.bubbleDensity(satOut)/Medium.density(staOut)- 1)/
      (Medium.bubbleDensity(satOut)/Medium.dewDensity(satOut) - 1)
      "Vapour quality at valve's outlet";

    corFact = 1
      "No correction factor is needed";

  elseif (powMod == Types.PowerModels.ZhifangAndOu2008) then
    /*Polynomial approach presented by Zhifang and Ou (2008):
      C_D = C * ((pInl-pOut)*sqrt(AVal)/sigma_inlet)^b1 *
      (dInlPip*sqrt(rho_inlet*pInl)/eta_inlet)^b2

      Caution with units - In the following, none S.I units are presented:
        Pressure:        in kPa
    */
    P[1] = (pInl-pOut)*1e-3*sqrt(abs(opening*AVal))/
      max(Medium.surfaceTension(satInl),1e-6)
      "Surface tension at valve's inlet";
    P[2] = dInlPip*sqrt(abs(Medium.density(staInl)*pInl*1e-3))/
      Medium.dynamicViscosity(staInl)
      "Dynamic viscosity at valve's inlet";

    corFact = 1
      "No correction factor is needed";

  elseif (powMod == Types.PowerModels.Li2013) then
    /*Polynomial approach presented by Li (2013):
      C_D = C * (opening)^b1 * (T_supercooled/T_crit)^b2

      Caution with units - In the following, none S.I units are presented:
        Pressure:       in kPa
        Temperature:    in °C
    */
    P[1] = opening
      "Degree of valve's opening";
    P[2] = (satInl.Tsat - Medium.temperature(staInl))/
      (Medium.fluidConstants[1].criticalTemperature-273.15)
      "Degree of subcooling";

    corFact = 1 - ((1-pOut/pInl)/
      (3*(Medium.isentropicExponent(staOut)/1.4)*pDifRat))
      "Correction factor taking partial vaporisation into account";

    /*The correction factos takes into accout that a partial vaporisation
      takes place while throttling process. It is a function of the pressure
      difference between inlet and outlet, the isentropic exponent and the
      pressure differential ratio factor depending on the valve moddeld.
    */

  else
    assert(false, "Invalid choice of power approach");
  end if;

  // Calculationg of flow coefficient
  //
  C = corFact * a * product(abs(P[i])^b[i] for i in 1:nT)
    "Calculation procedure of generic power approach";
end PowerFlowCoefficient;


Buckingham - Similitude for R22, R407C, R410A - EEV - 1.5 mm to 2.2 mm . This model contains a calculation procedure for flow coefficients
  presented by Shanwei et al. (2005).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Buck_R22R407CR410A_EEV_15_22
  "Buckingham - Similitude for R22, R407C, R410A - EEV - 1.5 mm to 2.2 mm "
  extends PowerFlowCoefficient(
    final powMod=Types.PowerModels.ShanweiEtAl2005,
    final a=0.2343,
    final b={0.0281,0.0260,-0.0477,-0.1420,-0.1291},
    final dCle=0.02e-3);
end Buck_R22R407CR410A_EEV_15_22;


Buckingham - Similitude for R22, R407C, R410A - EEV - 1.6 mm to 1.8 mm . This model contains a calculation procedure for flow coefficients
  presented by Li (2013).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Buck_R22R407CR410A_EEV_16_18
  "Buckingham - Similitude for R22, R407C, R410A - EEV - 1.6 mm to 1.8 mm "
  extends PowerFlowCoefficient(
    final powMod=Types.PowerModels.Li2013,
    final a=1.066,
    final b={0.8006,0.0609},
    final pDifRat=0.84);
end Buck_R22R407CR410A_EEV_16_18;


General model that describes a constant flow coefficient. This model contains a simple calculation procedure for flow
  coefficients (for more information, please check out
  AixLib.Fluid.Actuators.Valves.ExpansionValves.BaseClasses.PartialExpansionValve).
  The model provides a constant flow coefficient and is the most basic
  flow coefficient model.

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model ConstantFlowCoefficient
  "General model that describes a constant flow coefficient"
  extends BaseClasses.PartialFlowCoefficient;

  // Definition of parameters
  //
  parameter Real C_const(unit="1", min = 0, max = 100, nominal = 25) = 15
    "Constant flow coefficient";

equation
  // Calculate flow coefficient
  //
  C = C_const "Allocation of constant flow coefficient";
end ConstantFlowCoefficient;


within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient;
package SpecifiedFlowCoefficients "Package that cointains flow coefficients that are specified"
  extends Modelica.Icons.VariantsPackage;
end SpecifiedFlowCoefficients;


Polynomial   - Similitude for R22, R407C, R410A - EEV - 1.5 mm to 2.2 mm. This model contains a calculation procedure for flow coefficients
  presented by Shanwei et al. (2005).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Poly_R22R407CR410A_EEV_15_22
  "Polynomial   - Similitude for R22, R407C, R410A - EEV - 1.5 mm to 2.2 mm"
  extends PolynomialFlowCoefficient(
    final polyMod=Types.PolynomialModels.ShanweiEtAl2005,
    final a={-1.615e4,3.328e-4,1.4465e-3,2.9968e-3,-3.3890e2,7.0925e-5},
    final b={1,1,1,1,1,1},
    final dCle=0.02e-3);
end Poly_R22R407CR410A_EEV_15_22;


Polynomial - R22 - EEV - 1.6 mm. This model contains a calculation procedure for flow coefficients
  presented by Li (2013).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Poly_R22_EEV_16 "Polynomial - R22 - EEV - 1.6 mm"
  extends PolynomialFlowCoefficient(
    final polyMod=Types.PolynomialModels.Li2013,
    final a={-0.03469,1.64866,-0.84227,1.19513,0,0},
    final b={1,1,1,1,1,1},
    final pDifRat=0.84);
end Poly_R22_EEV_16;


Polynomial - R407c - EEV - 1.8 mm. This model contains a calculation procedure for flow coefficients
  presented by Li (2013).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Poly_R407c_EEV_18 "Polynomial - R407c - EEV - 1.8 mm"
  extends PolynomialFlowCoefficient(
    final polyMod=Types.PolynomialModels.Li2013,
    final a={-0.07154,1.67713,-0.79141,1.09516,0,0},
    final b={1,1,1,1,1,1},
    final pDifRat=0.84);
end Poly_R407c_EEV_18;


Polynomial - R410a - EEV - 1.8 mm. This model contains a calculation procedure for flow coefficients
  presented by Li (2013).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Poly_R410a_EEV_18 "Polynomial - R410a - EEV - 1.8 mm"
  extends PolynomialFlowCoefficient(
    final polyMod=Types.PolynomialModels.Li2013,
    final a={-0.07374,1.5461,-0.73679,1.09651,0,0},
    final b={1,1,1,1,1,1},
    final pDifRat=0.84);
end Poly_R410a_EEV_18;


Power - R134a - EEV - 1.5 mm. This model contains a calculation procedure for flow coefficients
  presented by Zhifang et al. (2008).<br/>

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities.FlowCoefficient.SpecifiedFlowCoefficients;
model Power_R134a_EEV_15 "Power - R134a - EEV - 1.5 mm"
  extends PowerFlowCoefficient(
    final powMod=Types.PowerModels.ZhifangAndOu2008,
    final a=1.1868e-13,
    final b={-1.4347,3.6426});
end Power_R134a_EEV_15;


Types, constants to define menu choices

within AixLib.Fluid.Actuators.Valves.ExpansionValves.Utilities;
package Types "Types, constants to define menu choices"
  extends Modelica.Icons.TypesPackage;

  // Types describing calculation procedures of mass flow and pressure drop
  //
  // Types describing calculation procedures of flow coefficients
  //
end Types;


Collection of validation models

within AixLib.Fluid.Actuators.Valves;
package Validation "Collection of validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


within AixLib.Fluid.Actuators.Valves.Validation;
model ThreeWayValveParameterization
  "Test model for parameterization of three-way valves"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Water "Medium in the component";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.4
    "Design mass flow rate";
  parameter Modelica.Units.SI.PressureDifference dp_nominal=4500
    "Design pressure drop";

  parameter Real Kv_SI = m_flow_nominal/sqrt(dp_nominal)
    "Flow coefficient for fully open valve in SI units, Kv=m_flow/sqrt(dp) [kg/s/(Pa)^(1/2)]";

  parameter Real Kv = Kv_SI/(rhoStd/3600/sqrt(1E5))
    "Kv (metric) flow coefficient [m3/h/(bar)^(1/2)]";
  parameter Real Cv = Kv_SI/(rhoStd*0.0631/1000/sqrt(6895))
    "Cv (US) flow coefficient [USG/min/(psi)^(1/2)]";
  parameter Modelica.Units.SI.Area Av=Kv_SI/sqrt(rhoStd)
    "Av (metric) flow coefficient";

  parameter Modelica.Units.SI.Density rhoStd=Medium.density_pTX(
      101325,
      273.15 + 4,
      Medium.X_default) "Standard density";

  AixLib.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valOPPoi(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    CvData=AixLib.Fluid.Types.CvTypes.OpPoint,
    dpValve_nominal(displayUnit="kPa") = 4500,
    use_inputFilter=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
                           "Three way valve with operating point as parameter"

  AixLib.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valKv(
    redeclare package Medium = Medium,
    CvData=AixLib.Fluid.Types.CvTypes.Kv,
    m_flow_nominal=m_flow_nominal,
    Kv=Kv,
    use_inputFilter=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
                           "Three way valve with Kv-value as parameter"

  AixLib.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valCv(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    CvData=AixLib.Fluid.Types.CvTypes.Cv,
    Cv=Cv,
    use_inputFilter=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
                           "Three way valve with Cv-value as parameter"

  AixLib.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valAv(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    Av=Av,
    use_inputFilter=false,
    CvData=AixLib.Fluid.Types.CvTypes.Av,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Three way valve with Av-value as parameter"

  AixLib.Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    nPorts=4,
    use_p_in=false,
    p(displayUnit="Pa") = 300000 + 4500,
    T=293.15) "Boundary condition for flow source"
  AixLib.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    nPorts=4,
    use_p_in=false,
    p=300000,
    T=293.15) "Boundary condition for flow sink"
    Modelica.Blocks.Sources.Ramp y(
    duration=1,
    height=1,
    offset=0) "Control signal"

  AixLib.Fluid.Sensors.MassFlowRate senM_flowOpPoi(
    redeclare package Medium = Medium) "Mass flow rate sensor"
  AixLib.Fluid.Sensors.MassFlowRate senM_flowKv(
    redeclare package Medium = Medium) "Mass flow rate sensor"
  AixLib.Fluid.Sensors.MassFlowRate senM_flowCv(
    redeclare package Medium = Medium) "Mass flow rate sensor"

  AixLib.Fluid.Sensors.MassFlowRate senM_flowAv(redeclare package Medium =
        Medium) "Mass flow rate sensor"
  AixLib.Fluid.Sources.Boundary_pT sou3(
    redeclare package Medium = Medium,
    nPorts=4,
    use_p_in=false,
    p(displayUnit="Pa") = 300000 + 4500,
    T=293.15) "Boundary condition for flow source"
equation
  connect(sou1.ports[1], valOPPoi.port_1)
  connect(sou1.ports[2], valKv.port_1)
  connect(sou1.ports[3], valCv.port_1)
  connect(sou1.ports[4], valAv.port_1)
  connect(sou3.ports[1], valOPPoi.port_3)
  connect(sou3.ports[2], valKv.port_3)
  connect(sou3.ports[3], valCv.port_3)
  connect(sou3.ports[4], valAv.port_3)
  connect(valOPPoi.port_2, senM_flowOpPoi.port_a)
  connect(valKv.port_2, senM_flowKv.port_a)
  connect(valCv.port_2, senM_flowCv.port_a)
  connect(valAv.port_2, senM_flowAv.port_a)
  connect(senM_flowOpPoi.port_b, sin.ports[1])
  connect(senM_flowKv.port_b, sin.ports[2])
  connect(senM_flowCv.port_b, sin.ports[3])
  connect(senM_flowAv.port_b, sin.ports[4])
  connect(y.y, valOPPoi.y)
  connect(y.y, valKv.y)
  connect(y.y, valCv.y)
  connect(y.y, valAv.y)
end ThreeWayValveParameterization;


within AixLib.Fluid.Actuators.Valves.Validation;
model TwoWayValveParameterization
  "Model to test and illustrate different parameterization for valves"
  extends Modelica.Icons.Example;

 package Medium = AixLib.Media.Water;

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.4
    "Design mass flow rate";
  parameter Modelica.Units.SI.PressureDifference dp_nominal=4500
    "Design pressure drop";

  parameter Real Kv_SI = m_flow_nominal/sqrt(dp_nominal)
    "Flow coefficient for fully open valve in SI units, Kv=m_flow/sqrt(dp) [kg/s/(Pa)^(1/2)]";

  parameter Real Kv = Kv_SI/(rhoStd/3600/sqrt(1E5))
    "Kv (metric) flow coefficient [m3/h/(bar)^(1/2)]";
  parameter Real Cv = Kv_SI/(rhoStd*0.0631/1000/sqrt(6895))
    "Cv (US) flow coefficient [USG/min/(psi)^(1/2)]";
  parameter Modelica.Units.SI.Area Av=Kv_SI/sqrt(rhoStd)
    "Av (metric) flow coefficient";

  parameter Modelica.Units.SI.Density rhoStd=Medium.density_pTX(
      101325,
      273.15 + 4,
      Medium.X_default) "Standard density";

  AixLib.Fluid.Actuators.Valves.TwoWayLinear valOPPoi(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    CvData=AixLib.Fluid.Types.CvTypes.OpPoint,
    dpValve_nominal(displayUnit="kPa") = dp_nominal,
    use_inputFilter=false) "Valve model, linear opening characteristics"
    Modelica.Blocks.Sources.Ramp     y(duration=1)
                                            "Control signal"
  Valves.TwoWayLinear valKv(
    redeclare package Medium = Medium,
    CvData=AixLib.Fluid.Types.CvTypes.Kv,
    m_flow_nominal=m_flow_nominal,
    Kv=Kv,
    use_inputFilter=false) "Valve model, linear opening characteristics"

  Valves.TwoWayLinear valCv(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    CvData=AixLib.Fluid.Types.CvTypes.Cv,
    Cv=Cv,
    use_inputFilter=false) "Valve model, linear opening characteristics"

  AixLib.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    nPorts=4,
    p(displayUnit="Pa") = 300000 + 4500,
    T=293.15) "Boundary condition for flow source"
  AixLib.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    nPorts=4,
    use_p_in=false,
    p=300000,
    T=293.15) "Boundary condition for flow sink"

  AixLib.Fluid.Sensors.MassFlowRate senM_flowOpPoi(
    redeclare package Medium = Medium) "Mass flow rate sensor"
  AixLib.Fluid.Sensors.MassFlowRate senM_flowKv(
    redeclare package Medium = Medium) "Mass flow rate sensor"
  AixLib.Fluid.Sensors.MassFlowRate senM_flowCv(
    redeclare package Medium = Medium) "Mass flow rate sensor"
  Valves.TwoWayLinear valAv(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    use_inputFilter=false,
    CvData=AixLib.Fluid.Types.CvTypes.Av,
    Av=Av) "Valve model, linear opening characteristics"
  AixLib.Fluid.Sensors.MassFlowRate senM_flowAv(redeclare package Medium =
        Medium) "Mass flow rate sensor"
equation
  connect(y.y, valOPPoi.y)
  connect(y.y, valKv.y)
  connect(valKv.port_a, sou.ports[2])
  connect(sou.ports[3], valCv.port_a)
  connect(y.y, valCv.y)
  connect(sou.ports[1], valOPPoi.port_a)
  connect(valOPPoi.port_b, senM_flowOpPoi.port_a)
  connect(valKv.port_b, senM_flowKv.port_a)
  connect(valCv.port_b, senM_flowCv.port_a)
  connect(senM_flowCv.port_b, sin.ports[3])
  connect(senM_flowKv.port_b, sin.ports[2])
  connect(senM_flowOpPoi.port_b, sin.ports[1])
  connect(sou.ports[4], valAv.port_a)
  connect(valAv.port_b, senM_flowAv.port_a)
  connect(senM_flowAv.port_b, sin.ports[4])
  connect(valAv.y, y.y)
end TwoWayValveParameterization;


Filter used for actuators of valves, dampers and movers. This block implements a filter that is used to approximate the actuators
of valves, dampers and fans.

within AixLib.Fluid.BaseClasses;
block ActuatorFilter
  "Filter used for actuators of valves, dampers and movers"
  import Modelica.Blocks.Types.Init;
  extends Modelica.Blocks.Interfaces.SISO;

  constant Integer n=2 "Order of filter";
  parameter Modelica.Units.SI.Frequency f(start=1) "Cut-off frequency";
  parameter Boolean normalized = true
    "= true, if amplitude at f_cut is 3 dB, otherwise unmodified filter";
  parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.NoInit
    "Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)"
  parameter Real x_start[n]=zeros(n) "Initial or guess values of states"
  parameter Real y_start=0.0
    "Initial value of output (remaining states are in steady state)"

  parameter Real u_nominal = 1 "Magnitude of input";

  Real x[n](each final stateSelect=StateSelect.never) = u_nom*s
    "Transformed filter states";

protected
  final parameter Real u_nom = if abs(u_nominal-1) < 1E-12 then 1-1E-12 else u_nominal
    "Magnitude of input (set to a value different from 1 to avoid elimination by symbolic processing)";

  parameter Real alpha=if normalized then sqrt(2^(1/n) - 1) else 1.0
    "Frequency correction factor for normalized filter";
  parameter Real w_u=2*Modelica.Constants.pi*f/alpha/u_nom;

  Real s[n](start=x_start/u_nom) "Filter states";

initial equation
  if initType == Init.SteadyState then
    der(s) = zeros(n);
  elseif initType == Init.InitialState then
    s = x_start/u_nom;
  elseif initType == Init.InitialOutput then
    y = y_start;
    der(s[1:n - 1]) = zeros(n - 1);
  end if;

equation
  der(s[1]) = (u - u_nom*s[1])*w_u;
  for i in 2:n loop
    der(s[i]) = (u_nom*s[i - 1] - u_nom*s[i])*w_u;
  end for;
  y =u_nom*s[n];
end ActuatorFilter;


within AixLib.Fluid.BaseClasses;
block IndexMassFraction
  "Computes the index of a substance in the mass fraction vector Xi"
  replaceable package Medium =
      Modelica.Media.Interfaces.PartialCondensingGases "Medium model"
  parameter String substanceName="" "Name of species substance";

protected
  parameter Integer i_x = sum(
    if Modelica.Utilities.Strings.isEqual(string1=Medium.substanceNames[i],
                                          string2=substanceName,
                                          caseSensitive=false) then i else 0
                                          for i in 1:Medium.nXi) "Index of substance"
initial equation
  assert(i_x > 0, "Substance '" + substanceName + "' is not present in medium '"
                  + Medium.mediumName + "'.\n"
                  + "Change medium model to one that has '" + substanceName + "' as a substance.");
end IndexMassFraction;


Model that multiplies the mass flow rate. This model multiplies the mass flow rate so that
0 = port_b.m_flow + gain * port_a.m_flow
where gain > 0 is either equal to
the input variable u if use_input
is set to true, or equal to
the parameter k if use_input
is set to false.

within AixLib.Fluid.BaseClasses;
model MassFlowRateMultiplier "Model that multiplies the mass flow rate"
  extends AixLib.Fluid.Interfaces.PartialTwoPort;

  parameter Boolean use_input=false
    "Set to true for multiplier factor provided as an input instead of a parameter"
  parameter Real k=1
    "Gain for mass flow rate"

  Modelica.Blocks.Interfaces.RealInput u(
    final unit="1",
    final min=Modelica.Constants.small) if use_input
    "Multiplier factor"
  Modelica.Blocks.Interfaces.RealOutput uInv if use_input
    "Inverse of the multiplier factor"
protected
  Modelica.Blocks.Interfaces.RealInput u_internal
    "Connector for multiplier factor for internal use only"

  Modelica.Blocks.Sources.Constant cst(
    final k=k) if not use_input
    "Constant gain value"
  Modelica.Blocks.Math.Division div1 if use_input
    "Compute the inverse"
  Modelica.Blocks.Sources.Constant one(
    final k=1) if use_input
    "Constant 1"

initial equation
  assert(k > Modelica.Constants.small,
    "Gain must be strictly positive. Received k = " + String(k));
equation
  assert(u_internal > Modelica.Constants.small,
    "Gain must be strictly positive. Received u = " + String(u_internal));

  // Pressure drop in design flow direction
  port_a.p = port_b.p;

  // Mass balance (mass is not conserved by this model!)
  port_b.m_flow = -u_internal * port_a.m_flow;

  // Specific enthalpy flow rate
  port_a.h_outflow = inStream(port_b.h_outflow);
  port_b.h_outflow = inStream(port_a.h_outflow);
  // Transport of substances
  port_a.Xi_outflow = inStream(port_b.Xi_outflow);
  port_b.Xi_outflow = inStream(port_a.Xi_outflow);

  port_a.C_outflow = inStream(port_b.C_outflow);
  port_b.C_outflow = inStream(port_a.C_outflow);

  connect(cst.y, u_internal)
  connect(u_internal, div1.u2)
  connect(one.y, div1.u1)
  connect(div1.y, uInv)
  connect(u, u_internal)
end MassFlowRateMultiplier;


within AixLib.Fluid;
package BaseClasses "Package with base classes for AixLib.Fluid"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Partial model for a hydraulic resistance. Partial model for a flow resistance, possible with variable flow coefficient.
Models that extend this class need to implement an equation that relates
m_flow and dp, and they need to assign the parameter
m_flow_turbulent.

within AixLib.Fluid.BaseClasses;
partial model PartialResistance "Partial model for a hydraulic resistance"
    extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
     show_T=false,
     dp(nominal=if dp_nominal_pos > Modelica.Constants.eps
          then dp_nominal_pos else 1),
     m_flow(
        nominal=if m_flow_nominal_pos > Modelica.Constants.eps
          then m_flow_nominal_pos else 1),
     final m_flow_small = 1E-4*abs(m_flow_nominal));

  constant Boolean homotopyInitialization = true "= true, use homotopy method"

  parameter Boolean from_dp = false
    "= true, use m_flow = f(dp) else dp = f(m_flow)"

  parameter Modelica.Units.SI.PressureDifference dp_nominal(displayUnit="Pa")
    "Pressure drop at nominal mass flow rate"

  parameter Boolean linearized = false
    "= true, use linear relation between m_flow and dp for any flow rate"

  parameter Modelica.Units.SI.MassFlowRate m_flow_turbulent(min=0)
    "Turbulent flow if |m_flow| >= m_flow_turbulent";

protected
  parameter Medium.ThermodynamicState sta_default=
     Medium.setState_pTX(T=Medium.T_default, p=Medium.p_default, X=Medium.X_default);
  parameter Modelica.Units.SI.DynamicViscosity eta_default=
      Medium.dynamicViscosity(sta_default)
    "Dynamic viscosity, used to compute transition to turbulent flow regime";

  final parameter Modelica.Units.SI.MassFlowRate m_flow_nominal_pos=abs(
      m_flow_nominal) "Absolute value of nominal flow rate";
  final parameter Modelica.Units.SI.PressureDifference dp_nominal_pos(
      displayUnit="Pa") = abs(dp_nominal)
    "Absolute value of nominal pressure difference";
initial equation
  assert(homotopyInitialization, "In " + getInstanceName() +
    ": The constant homotopyInitialization has been modified from its default value. This constant will be removed in future releases.",
    level = AssertionLevel.warning);

equation
  // Isenthalpic state transformation (no storage and no loss of energy)
  port_a.h_outflow = if allowFlowReversal then inStream(port_b.h_outflow) else Medium.h_default;
  port_b.h_outflow = inStream(port_a.h_outflow);

  // Mass balance (no storage)
  port_a.m_flow + port_b.m_flow = 0;

  // Transport of substances
  port_a.Xi_outflow = if allowFlowReversal then inStream(port_b.Xi_outflow) else Medium.X_default[1:Medium.nXi];
  port_b.Xi_outflow = inStream(port_a.Xi_outflow);

  port_a.C_outflow = if allowFlowReversal then inStream(port_b.C_outflow) else zeros(Medium.nC);
  port_b.C_outflow = inStream(port_a.C_outflow);
end PartialResistance;