within AixLib.Fluid.Chillers.ModularReversible.Validation.BaseClasses;
partial model PartialModularComparison
  "Partial model for comparison to the Carnot model"
  extends AixLib.Fluid.HeatPumps.ModularReversible.Validation.Comparative.BaseClasses.PartialComparison(
    m1_flow_nominal=chi.mCon_flow_nominal,
    m2_flow_nominal=chi.mEva_flow_nominal,
    sou1(nPorts=1),
    sin2(nPorts=1),
    sou2(nPorts=1),
    sin1(nPorts=1));

  Modular chi(
    redeclare final package MediumCon = Medium1,
    redeclare final package MediumEva = Medium2,
    QCoo_flow_nominal=-QUse_flow_nominal,
    redeclare final model RefrigerantCycleInertia =
        AixLib.Fluid.HeatPumps.ModularReversible.RefrigerantCycle.Inertias.NoInertia,
    final use_rev=false,
    final use_intSafCtr=false,
    final tauCon=tau1,
    final TConCoo_nominal=TCon_nominal,
    final dTCon_nominal=dTCon_nominal,
    final dpCon_nominal=dp1_nominal,
    final use_conCap=false,
    final CCon=0,
    final GConOut=0,
    final TEvaHea_nominal=0,
    final TConHea_nominal=0,
    final GConIns=0,
    final tauEva=tau2,
    final TEvaCoo_nominal=TEva_nominal,
    final dTEva_nominal=dTEva_nominal,
    final dpEva_nominal=dp2_nominal,
    final use_evaCap=false,
    final CEva=0,
    final GEvaOut=0,
    final GEvaIns=0,
    final TCon_start=T1_start,
    final TEva_start=T2_start,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Modular chiller model"

equation
  connect(chi.port_a1, sou1.ports[1])
  connect(chi.port_b2, sin2.ports[1])
  connect(chi.port_a2, sou2.ports[1])
  connect(chi.port_b1, sin1.ports[1])
  connect(chi.ySet, uCom.y)
end PartialModularComparison;


within AixLib.Fluid.Chillers.Validation;
model CarnotVerifyCOP
  "Test model to verify the COP computation for non-zero approach temperatures"
  extends Modelica.Icons.Example;

  package Medium = AixLib.Media.Water "Medium model";

  parameter Real COP_nominal = 3 "Coefficient of performance";

  parameter Modelica.Units.SI.Temperature TCon_nominal=273.15 + 30
    "Nominal condenser temperature";
  parameter Modelica.Units.SI.Temperature TEva_nominal=273.15 + 5
    "Nominal evaporator temperature";

  parameter Modelica.Units.SI.HeatFlowRate QEva_flow_nominal=-10E3
    "Nominal evaporator heat flow rate (QEva_flow_nominal < 0)";

  parameter Modelica.Units.SI.HeatFlowRate QCon_flow_nominal=-QEva_flow_nominal
      *(1 + 1/COP_nominal)
    "Nominal condenser heat flow rate (QCon_flow_nominal > 0)";

  parameter Modelica.Units.SI.TemperatureDifference dTEva_nominal=-10
    "Temperature difference evaporator outlet-inlet";

  parameter Modelica.Units.SI.TemperatureDifference dTCon_nominal=10
    "Temperature difference condenser outlet-inlet";

  parameter Modelica.Units.SI.MassFlowRate mCon_flow_nominal=QCon_flow_nominal/
      cp_default/dTCon_nominal "Nominal mass flow rate at condenser";

  parameter Modelica.Units.SI.MassFlowRate mEva_flow_nominal=QEva_flow_nominal/
      cp_default/dTEva_nominal "Nominal mass flow rate of evaporator";

  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(Medium.setState_pTX(
      p=Medium.p_default,
      T=Medium.T_default,
      X=Medium.X_default))
    "Specific heat capacity of medium 1 at default medium state";

  Carnot_TEva chi_TEva(
    dp1_nominal=0,
    dp2_nominal=0,
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    QEva_flow_nominal=QEva_flow_nominal,
    dTEva_nominal=dTEva_nominal,
    dTCon_nominal=dTCon_nominal,
    m1_flow_nominal=mCon_flow_nominal,
    m2_flow_nominal=mEva_flow_nominal,
    use_eta_Carnot_nominal=false,
    COP_nominal=COP_nominal,
    show_T=true,
    TCon_nominal=TCon_nominal,
    TEva_nominal=TEva_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Chiller with evaporator leaving water temperature as set point"

  Sources.MassFlowSource_T bouCon(
    nPorts=1,
    redeclare package Medium = Medium,
    m_flow=mCon_flow_nominal,
    T=TCon_nominal - QCon_flow_nominal/cp_default/mCon_flow_nominal)
    "Boundary condition for condenser"
  Sources.MassFlowSource_T bouEva(
    redeclare package Medium = Medium,
    nPorts=1,
    m_flow=mEva_flow_nominal,
    T=TEva_nominal - QEva_flow_nominal/cp_default/mEva_flow_nominal)
    "Boundary condition for evaporator"

  Modelica.Blocks.Sources.Constant TEvaLvg(k=273.15 + 5)
    "Leaving water temperature"
  Sources.Boundary_pT bou(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"
  Sources.Boundary_pT bou1(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"

  Carnot_y chi_y(
    dp1_nominal=0,
    dp2_nominal=0,
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    dTEva_nominal=dTEva_nominal,
    dTCon_nominal=dTCon_nominal,
    m1_flow_nominal=mCon_flow_nominal,
    m2_flow_nominal=mEva_flow_nominal,
    use_eta_Carnot_nominal=false,
    COP_nominal=COP_nominal,
    show_T=true,
    TCon_nominal=TCon_nominal,
    TEva_nominal=TEva_nominal,
    P_nominal=QEva_flow_nominal + QCon_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Chiller with control signal as set point"
  Sources.MassFlowSource_T bouCon1(
    nPorts=1,
    redeclare package Medium = Medium,
    m_flow=mCon_flow_nominal,
    T=TCon_nominal - QCon_flow_nominal/cp_default/mCon_flow_nominal)
    "Boundary condition for condenser"
  Sources.MassFlowSource_T bouEva1(
    redeclare package Medium = Medium,
    nPorts=1,
    m_flow=mEva_flow_nominal,
    T=TEva_nominal - QEva_flow_nominal/cp_default/mEva_flow_nominal)
    "Boundary condition for evaporator"
  Modelica.Blocks.Sources.Constant y(k=1) "Control signal"
  Sources.Boundary_pT bou2(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"
  Sources.Boundary_pT bou3(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"
equation
  connect(bouCon.ports[1], chi_TEva.port_a1)
  connect(TEvaLvg.y, chi_TEva.TSet)
  connect(bou.ports[1], chi_TEva.port_b2)
  connect(chi_TEva.port_a2, bouEva.ports[1])
  connect(bou1.ports[1], chi_TEva.port_b1)
  connect(bouCon1.ports[1], chi_y.port_a1)
  connect(bou2.ports[1], chi_y.port_b2)
  connect(chi_y.port_a2, bouEva1.ports[1])
  connect(bou3.ports[1], chi_y.port_b1)
  connect(y.y, chi_y.y)
end CarnotVerifyCOP;


within AixLib.Fluid.Chillers.Validation;
model CarnotVerifyEtaCarnot
  "Test model to verify the Carnot effectiveness computation for non-zero approach temperatures"
  extends Modelica.Icons.Example;

  package Medium = AixLib.Media.Water "Medium model";

  parameter Real etaCarnot_nominal=0.315046
    "Carnot effectiveness (=COP/COP_Carnot) used if use_eta_Carnot_nominal = true";

  parameter Modelica.Units.SI.TemperatureDifference TAppCon_nominal=2
    "Temperature difference between refrigerant and working fluid outlet in condenser";

  parameter Modelica.Units.SI.TemperatureDifference TAppEva_nominal=2
    "Temperature difference between refrigerant and working fluid outlet in evaporator";

  parameter Real COP_nominal = etaCarnot_nominal * (TEva_nominal-TAppEva_nominal)/
    (TCon_nominal + TAppCon_nominal - (TEva_nominal-TAppEva_nominal))  "Coefficient of performance";

  parameter Modelica.Units.SI.Temperature TCon_nominal=273.15 + 30
    "Nominal condenser temperature";

  parameter Modelica.Units.SI.Temperature TEva_nominal=273.15 + 5
    "Nominal evaporator temperature";

  parameter Modelica.Units.SI.HeatFlowRate QEva_flow_nominal=-10E3
    "Nominal evaporator heat flow rate (QEva_flow_nominal < 0)";

  parameter Modelica.Units.SI.HeatFlowRate QCon_flow_nominal=-QEva_flow_nominal
      *(1 + 1/COP_nominal)
    "Nominal condenser heat flow rate (QCon_flow_nominal > 0)";

  parameter Modelica.Units.SI.TemperatureDifference dTEva_nominal=-10
    "Temperature difference evaporator outlet-inlet";

  parameter Modelica.Units.SI.TemperatureDifference dTCon_nominal=10
    "Temperature difference condenser outlet-inlet";

  parameter Modelica.Units.SI.MassFlowRate mCon_flow_nominal=QCon_flow_nominal/
      cp_default/dTCon_nominal "Nominal mass flow rate at condenser";

  parameter Modelica.Units.SI.MassFlowRate mEva_flow_nominal=QEva_flow_nominal/
      cp_default/dTEva_nominal "Nominal mass flow rate of evaporator";

  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(Medium.setState_pTX(
      p=Medium.p_default,
      T=Medium.T_default,
      X=Medium.X_default))
    "Specific heat capacity of medium 1 at default medium state";

  Carnot_TEva chi_TEva(
    dp1_nominal=0,
    dp2_nominal=0,
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    QEva_flow_nominal=QEva_flow_nominal,
    dTEva_nominal=dTEva_nominal,
    dTCon_nominal=dTCon_nominal,
    m1_flow_nominal=mCon_flow_nominal,
    m2_flow_nominal=mEva_flow_nominal,
    show_T=true,
    TCon_nominal=TCon_nominal,
    TEva_nominal=TEva_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    etaCarnot_nominal=etaCarnot_nominal,
    TAppCon_nominal=TAppCon_nominal,
    TAppEva_nominal=TAppEva_nominal)
    "Chiller with evaporator leaving water temperature as set point"

  Sources.MassFlowSource_T bouCon(
    nPorts=1,
    redeclare package Medium = Medium,
    m_flow=mCon_flow_nominal,
    T=TCon_nominal - QCon_flow_nominal/cp_default/mCon_flow_nominal)
    "Boundary condition for condenser"
  Sources.MassFlowSource_T bouEva(
    redeclare package Medium = Medium,
    nPorts=1,
    m_flow=mEva_flow_nominal,
    T=TEva_nominal - QEva_flow_nominal/cp_default/mEva_flow_nominal)
    "Boundary condition for evaporator"

  Modelica.Blocks.Sources.Constant TEvaLvg(k=273.15 + 5)
    "Leaving water temperature"
  Sources.Boundary_pT bou(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"
  Sources.Boundary_pT bou1(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"

  Carnot_y chi_y(
    dp1_nominal=0,
    dp2_nominal=0,
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    dTEva_nominal=dTEva_nominal,
    dTCon_nominal=dTCon_nominal,
    m1_flow_nominal=mCon_flow_nominal,
    m2_flow_nominal=mEva_flow_nominal,
    show_T=true,
    TCon_nominal=TCon_nominal,
    TEva_nominal=TEva_nominal,
    P_nominal=QEva_flow_nominal + QCon_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    etaCarnot_nominal=etaCarnot_nominal,
    TAppCon_nominal=TAppCon_nominal,
    TAppEva_nominal=TAppEva_nominal)
    "Chiller with control signal as set point"
  Sources.MassFlowSource_T bouCon1(
    nPorts=1,
    redeclare package Medium = Medium,
    m_flow=mCon_flow_nominal,
    T=TCon_nominal - QCon_flow_nominal/cp_default/mCon_flow_nominal)
    "Boundary condition for condenser"
  Sources.MassFlowSource_T bouEva1(
    redeclare package Medium = Medium,
    nPorts=1,
    m_flow=mEva_flow_nominal,
    T=TEva_nominal - QEva_flow_nominal/cp_default/mEva_flow_nominal)
    "Boundary condition for evaporator"
  Modelica.Blocks.Sources.Constant y(k=1) "Control signal"
  Sources.Boundary_pT bou2(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"
  Sources.Boundary_pT bou3(
    nPorts=1,
    redeclare package Medium = Medium)
    "Pressure boundary condition"

equation
  connect(bouCon.ports[1], chi_TEva.port_a1)
  connect(TEvaLvg.y, chi_TEva.TSet)
  connect(bou.ports[1], chi_TEva.port_b2)
  connect(chi_TEva.port_a2, bouEva.ports[1])
  connect(bou1.ports[1], chi_TEva.port_b1)
  connect(bouCon1.ports[1], chi_y.port_a1)
  connect(bou2.ports[1], chi_y.port_b2)
  connect(chi_y.port_a2, bouEva1.ports[1])
  connect(bou3.ports[1], chi_y.port_b1)
  connect(y.y, chi_y.y)
end CarnotVerifyEtaCarnot;


within AixLib.Fluid.Chillers.Validation;
model Carnot_TEva_2ndLaw
  "Test model to verify that the 2nd law is not violated"
  extends Modelica.Icons.Example;

  package Medium = AixLib.Media.Water "Medium model";

  parameter Modelica.Units.SI.TemperatureDifference dTEva_nominal=-4
    "Temperature difference evaporator outlet-inlet";
  parameter Modelica.Units.SI.TemperatureDifference dTCon_nominal=4
    "Temperature difference condenser outlet-inlet";
  parameter Real COPc_nominal = 3 "Chiller COP";
  parameter Modelica.Units.SI.HeatFlowRate QEva_flow_nominal=-100E3
    "Evaporator heat flow rate";
  final parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=
      QEva_flow_nominal/dTEva_nominal/4200
    "Nominal mass flow rate at chilled water side";

  final parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=-
      m2_flow_nominal/dTCon_nominal*dTEva_nominal
    "Nominal mass flow rate at condenser water side";

  Modelica.Blocks.Sources.Constant TEvaIn(k=273.15 + 20)
    "Evaporator inlet temperature"
  Modelica.Blocks.Sources.Constant dTEva(k=dTEva_nominal)
    "Temperature difference over evaporator"
  Modelica.Blocks.Math.Add TSetEvaLvg
    "Set point for evaporator leaving temperature"
  Modelica.Blocks.Sources.Ramp dTConEva(
    duration=1,
    offset=25,
    height=-25)
               "Temperature lift condenser inlet minus evaporator outlet"
  Modelica.Blocks.Math.Add TConIn "Condenser inlet temperature"
  Chiller chi_b(
    redeclare final package Medium1 = Medium,
    redeclare final package Medium2 = Medium,
    final dTEva_nominal=dTEva_nominal,
    final dTCon_nominal=dTCon_nominal,
    final QEva_flow_nominal=QEva_flow_nominal,
    final m2_flow_nominal=m2_flow_nominal,
    final m1_flow_nominal=m1_flow_nominal)
    "Chiller model that uses port_b to compute Carnot efficiency"

protected
  model Chiller "Subsystem model with the chiller"

   replaceable package Medium1 = Modelica.Media.Interfaces.PartialMedium
      "Medium model";
   replaceable package Medium2 = Modelica.Media.Interfaces.PartialMedium
      "Medium model";

    parameter Modelica.Units.SI.TemperatureDifference dTEva_nominal
      "Temperature difference evaporator outlet-inlet";
    parameter Modelica.Units.SI.TemperatureDifference dTCon_nominal
      "Temperature difference condenser outlet-inlet";
    parameter Modelica.Units.SI.HeatFlowRate QEva_flow_nominal
      "Evaporator heat flow rate";
    parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal
      "Nominal mass flow rate at condenser water side";
    parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal
      "Nominal mass flow rate at chilled water side";

    AixLib.Fluid.Sources.MassFlowSource_T sou1(
      redeclare package Medium = Medium1,
      nPorts=1,
      use_m_flow_in=false,
      use_T_in=true,
      m_flow=m1_flow_nominal)
                     "Mass flow rate source"
    AixLib.Fluid.Sources.Boundary_pT sin1(redeclare package Medium = Medium2, nPorts=1)
      "Pressure source"
    AixLib.Fluid.Chillers.Carnot_TEva chi(
      redeclare package Medium1 = Medium1,
      redeclare package Medium2 = Medium2,
      dTEva_nominal=dTEva_nominal,
      dTCon_nominal=dTCon_nominal,
      m2_flow_nominal=m2_flow_nominal,
      show_T=true,
      QEva_flow_nominal=QEva_flow_nominal,
      allowFlowReversal1=false,
      allowFlowReversal2=false,
      dp1_nominal=0,
      dp2_nominal=0,
      energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
      use_eta_Carnot_nominal=true) "Chiller model"
    AixLib.Fluid.Sources.MassFlowSource_T sou2(
      redeclare package Medium = Medium2,
      m_flow=m2_flow_nominal,
      use_T_in=true,
      T=293.15,
      nPorts=1) "Mass flow rate source"
    AixLib.Fluid.Sensors.EntropyFlowRate S_a1(
      redeclare package Medium = Medium1,
      m_flow_nominal=m1_flow_nominal,
      tau=0) "Entropy flow rate sensor"
    AixLib.Fluid.Sensors.EntropyFlowRate S_a2(
      redeclare package Medium = Medium1,
      m_flow_nominal=m1_flow_nominal,
      tau=0) "Entropy flow rate sensor"
    AixLib.Fluid.Sensors.EntropyFlowRate S_a3(
      redeclare package Medium = Medium1,
      m_flow_nominal=m1_flow_nominal,
      tau=0) "Entropy flow rate sensor"
    AixLib.Fluid.Sensors.EntropyFlowRate S_a4(
      redeclare package Medium = Medium1,
      m_flow_nominal=m1_flow_nominal,
      tau=0) "Entropy flow rate sensor"
    AixLib.Fluid.Sources.Boundary_pT sin2(redeclare package Medium = Medium2, nPorts=1)
      "Pressure source"
    Modelica.Blocks.Math.Add SIn_flow
      "Entropy carried by flow that goes into the chiller"
    Modelica.Blocks.Math.Add SOut_flow
      "Entropy carried by flow that leaves the chiller"
    Modelica.Blocks.Math.Add dS_flow(k1=-1)
      "Change in entropy inflow and outflow"

    Modelica.Blocks.Interfaces.RealInput TSetEvaLea(unit="K")
      "Set point for evaporator leaving temperature"
    Modelica.Blocks.Interfaces.RealOutput SGen_flow "Entropy generated"
    Modelica.Blocks.Interfaces.RealInput TConIn(final unit="K", displayUnit=
          "degC") "Condenser inlet temperature"
    Modelica.Blocks.Interfaces.RealInput TEvaIn(final unit="K", displayUnit=
          "degC") "Evaporator inlet temperature"
  equation
    assert(SGen_flow > 0, "Entropy generated is zero or negative, which violates the 2nd law.
  This is because the model is configured to use the inlet temperatures
  to compute the Carnot efficiency, which can lead to non-physical results.",
    level = AssertionLevel.warning);
    connect(SIn_flow.y, dS_flow.u1)
    connect(sin1.ports[1],S_a2. port_b)
    connect(sou1.ports[1],S_a1. port_a)
    connect(S_a1.port_b,chi. port_a1)
    connect(chi.port_b1,S_a4. port_a)
    connect(S_a4.port_b,sin2. ports[1])
    connect(S_a3.port_a,sou2. ports[1])
    connect(S_a2.port_a,chi. port_b2)
    connect(S_a3.port_b,chi. port_a2)
    connect(S_a4.S_flow,SOut_flow. u2)
    connect(S_a2.S_flow,SOut_flow. u1)
    connect(S_a3.S_flow,SIn_flow. u2)
    connect(S_a1.S_flow,SIn_flow. u1)
    connect(SOut_flow.y,dS_flow. u2)
    connect(TSetEvaLea, chi.TSet)
    connect(SGen_flow, dS_flow.y)
    connect(TConIn, sou1.T_in)
    connect(TEvaIn, sou2.T_in)
  end Chiller;
equation
  connect(TSetEvaLvg.u1, TEvaIn.y)
  connect(dTEva.y, TSetEvaLvg.u2)
  connect(TSetEvaLvg.y, TConIn.u1)
  connect(dTConEva.y, TConIn.u2)
  connect(TEvaIn.y, chi_b.TEvaIn)
  connect(TSetEvaLvg.y, chi_b.TSetEvaLea)
  connect(chi_b.TConIn, TConIn.y)
end Carnot_TEva_2ndLaw;


Test model for the part load efficiency curve with evaporator leaving temperature as input signal. This example extends from

AixLib.Fluid.Chillers.Examples.Carnot_TEva
but has a part load efficiency that varies with the load.

within AixLib.Fluid.Chillers.Validation;
model Carnot_TEva_etaPL
  "Test model for the part load efficiency curve with evaporator leaving temperature as input signal"
  extends Examples.Carnot_TEva(
    chi(a={0.7,0.3},
    QEva_flow_min=-100000));
end Carnot_TEva_etaPL;


Test model for Carnot_TEva with high evaporator temperature. This example extends from

AixLib.Fluid.Chillers.Examples.Carnot_TEva
but increases the set point for the leaving evaporator temperature
to be above its inlet temperature, in which case the model provides no cooling.
Towards the end of the simulation, the inlet temperature of the evaporator is increased
to be above the condenser temperature. In this domain, the model requires cooling
again. While this is not a meaningful operating point for the model, the example
verifies that it robustly simulates this regime.

within AixLib.Fluid.Chillers.Validation;
model Carnot_TEva_HighTemperature
  "Test model for Carnot_TEva with high evaporator temperature"
  extends Examples.Carnot_TEva(TEvaLvg(height=34), sou2(use_T_in=true));
  Modelica.Blocks.Sources.Ramp TEvaEnt(
    startTime=3000,
    height=38,
    offset=273.15 + 22,
    duration=60) "Control signal for evaporator entering temperature"
equation
  connect(TEvaEnt.y, sou2.T_in)
end Carnot_TEva_HighTemperature;


Test model for Carnot_TEva with limited heating capacity. This example extends from

AixLib.Fluid.Chillers.Examples.Carnot_TEva
but limits the cooling capacity.

within AixLib.Fluid.Chillers.Validation;
model Carnot_TEva_LimitedCapacity
  "Test model for Carnot_TEva with limited heating capacity"
  extends Examples.Carnot_TEva(
    chi(QEva_flow_min=-100000));
end Carnot_TEva_LimitedCapacity;


within AixLib.Fluid.Chillers.Validation;
model Carnot_TEva_reverseFlow
  "Test model for chiller based on Carnot efficiency and evaporator outlet temperature control signal"
  extends Modelica.Icons.Example;
 package Medium1 = AixLib.Media.Water "Medium model";
 package Medium2 = AixLib.Media.Water "Medium model";

  parameter Modelica.Units.SI.TemperatureDifference dTEva_nominal=-10
    "Temperature difference evaporator inlet-outlet";
  parameter Modelica.Units.SI.TemperatureDifference dTCon_nominal=10
    "Temperature difference condenser outlet-inlet";
  parameter Real COPc_nominal = 3 "Chiller COP";
  parameter Modelica.Units.SI.HeatFlowRate QEva_flow_nominal=-100E3
    "Evaporator heat flow rate";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=QEva_flow_nominal/
      dTEva_nominal/4200 "Nominal mass flow rate at chilled water side";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=m2_flow_nominal*(
      COPc_nominal + 1)/COPc_nominal
    "Nominal mass flow rate at condenser water wide";

  AixLib.Fluid.Chillers.Carnot_TEva chi(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    dTEva_nominal=dTEva_nominal,
    dTCon_nominal=dTCon_nominal,
    use_eta_Carnot_nominal=true,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    show_T=true,
    QEva_flow_nominal=QEva_flow_nominal,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal=6000,
    dp2_nominal=6000) "Chiller model"
  AixLib.Fluid.Sources.MassFlowSource_T sou1(nPorts=1,
    redeclare package Medium = Medium1,
    m_flow=m1_flow_nominal,
    use_T_in=false,
    use_m_flow_in=true,
    T=298.15)
  AixLib.Fluid.Sources.MassFlowSource_T sou2(nPorts=1,
    redeclare package Medium = Medium2,
    m_flow=m2_flow_nominal,
    use_T_in=false,
    use_m_flow_in=true,
    T=295.15)
  AixLib.Fluid.Sources.Boundary_pT sin1(
    redeclare package Medium = Medium1,
    nPorts=1)
  AixLib.Fluid.Sources.Boundary_pT sin2(nPorts=1,
    redeclare package Medium = Medium2)
  Modelica.Blocks.Sources.Constant TEvaLvg(k=273.15 + 10)
    "Control signal for evaporator leaving temperature"
  Modelica.Blocks.Math.Gain mCon_flow(k=-1/cp1_default/dTEva_nominal)
    "Condenser mass flow rate"
  Modelica.Blocks.Math.Add QCon_flow(k2=-1) "Condenser heat flow rate"

  final parameter Modelica.Units.SI.SpecificHeatCapacity cp1_default=
      Medium1.specificHeatCapacityCp(Medium1.setState_pTX(
      Medium1.p_default,
      Medium1.T_default,
      Medium1.X_default))
    "Specific heat capacity of medium 1 at default medium state";
  Modelica.Blocks.Sources.Ramp mEva_flow(
    duration=60,
    startTime=1800,
    height=-2*m2_flow_nominal,
    offset=m2_flow_nominal) "Mass flow rate for evaporator"
equation
  connect(sou1.ports[1], chi.port_a1)
  connect(sou2.ports[1], chi.port_a2)
  connect(sin2.ports[1], chi.port_b2)
  connect(TEvaLvg.y, chi.TSet)
  connect(chi.P, QCon_flow.u1)
  connect(chi.QEva_flow, QCon_flow.u2)
  connect(QCon_flow.y, mCon_flow.u)
  connect(mCon_flow.y, sou1.m_flow_in)
  connect(chi.port_b1, sin1.ports[1])
  connect(mEva_flow.y, sou2.m_flow_in)
end Carnot_TEva_reverseFlow;


Test model for the part load efficiency curve with compressor speed as input signal. This example extends from

AixLib.Fluid.Chillers.Examples.Carnot_y
but uses a part load efficiency curve that is different from 1.

within AixLib.Fluid.Chillers.Validation;
model Carnot_y_etaPL
  "Test model for the part load efficiency curve with compressor speed as input signal"
  extends Examples.Carnot_y(chi(a={0.7,0.3}));
end Carnot_y_etaPL;


within AixLib.Fluid.Chillers;
package Validation "Collection of models that validate the chiller models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Delay element, approximated by a first order differential equation. This model approximates a transport delay using first order differential equations.

within AixLib.Fluid.Delays;
model DelayFirstOrder
  "Delay element, approximated by a first order differential equation"
  extends AixLib.Fluid.MixingVolumes.MixingVolume(
    final V=V_nominal,
    final massDynamics=energyDynamics,
    final mSenFac=1);

  parameter Modelica.Units.SI.Time tau=60 "Time constant at nominal flow"

protected
  parameter Modelica.Units.SI.Volume V_nominal=m_flow_nominal*tau/rho_default
    "Volume of delay element";
end DelayFirstOrder;


Package with delay models

within AixLib.Fluid;
package Delays "Package with delay models"
  extends Modelica.Icons.VariantsPackage;
end Delays;


within AixLib.Fluid.Delays.Examples;
model Delay
  extends Modelica.Icons.Example;
// We set X_default to a small enough value to avoid saturation at the medium temperature
// that is used in this model.
 package Medium = AixLib.Media.Air(X_default={0.001, 0.999});

    Modelica.Blocks.Sources.Constant PAtm(k=101325)
    Modelica.Blocks.Sources.Ramp P(
      duration=1,
    height=20,
    offset=101315)
  AixLib.Fluid.FixedResistances.PressureDrop res1(
    from_dp=true,
    m_flow_nominal=5,
    dp_nominal=5,
    redeclare package Medium = Medium)
  AixLib.Fluid.Sources.Boundary_pT sou(
                T=293.15, redeclare package Medium = Medium,
    use_p_in=true,
    nPorts=1)
  AixLib.Fluid.Sources.Boundary_pT sin(
                T=283.15, redeclare package Medium = Medium,
    use_p_in=true,
    nPorts=1)
  AixLib.Fluid.FixedResistances.PressureDrop res2(
    from_dp=true,
    m_flow_nominal=5,
    dp_nominal=5,
    redeclare package Medium = Medium)
  AixLib.Fluid.Delays.DelayFirstOrder del(         m_flow_nominal=5, redeclare
      package Medium = Medium,
    nPorts=2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=283.15)
    "Fluid volume that is a first order approximation of the transport delay"

equation
  connect(P.y, sou.p_in)
  connect(PAtm.y, sin.p_in)
  connect(sou.ports[1], res1.port_a)
  connect(sin.ports[1], res2.port_b)
  connect(res1.port_b, del.ports[1])
  connect(res2.port_a, del.ports[2])
end Delay;


within AixLib.Fluid.Delays;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within AixLib.Fluid;
package DistrictHeatingCooling "Models for District Heating and Cooling networks"
end DistrictHeatingCooling;


within AixLib.Fluid.DistrictHeatingCooling;
model UsersGuide "Users' Guide for the District Heating and Cooling package"
  extends Modelica.Icons.Information;
end UsersGuide;


within AixLib.Fluid.DistrictHeatingCooling;
package BaseClasses "Base classes for modular DHC system assembly"
extends Modelica.Icons.BasesPackage;
end BaseClasses;


Base classes for supply node models

within AixLib.Fluid.DistrictHeatingCooling.BaseClasses;
package Supplies "Base classes for supply node models"
extends Modelica.Icons.BasesPackage;
end Supplies;


within AixLib.Fluid.DistrictHeatingCooling.BaseClasses.Supplies;
package OpenLoop "Base classes for open loop design supply models"
extends Modelica.Icons.BasesPackage;
end OpenLoop;


within AixLib.Fluid.DistrictHeatingCooling.BaseClasses.Supplies.OpenLoop;
partial model PartialSupply
  "Base class for modeling supply nodes in DHC systems without return lines"
  extends AixLib.Fluid.Interfaces.PartialTwoPort;

  replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium model"

  AixLib.Fluid.Sensors.TemperatureTwoPort senT_supply(redeclare package Medium =
        Medium, m_flow_nominal=1,
    tau=0)                        "Supply flow temperature sensor"
  AixLib.Fluid.Sensors.MassFlowRate senMasFlo(redeclare package Medium =
        Medium) "Mass flow rate sensor"
  Modelica.Blocks.Interfaces.RealInput TIn(unit="K")
    "Prescribed supply temperature"
  Modelica.Blocks.Interfaces.RealInput dpIn(unit="Pa")
    "Prescribed pressure rise"
  Sensors.TemperatureTwoPort              senT_return(redeclare package Medium =
        Medium, m_flow_nominal=1,
    tau=0)                        "Return temperature sensor"
equation
  connect(senMasFlo.port_a, senT_supply.port_b)
  connect(senMasFlo.port_b, port_b)
  connect(port_a, senT_return.port_b)
end PartialSupply;


Demand nodes for DHC system models

within AixLib.Fluid.DistrictHeatingCooling;
package Demands "Demand nodes for DHC system models"
end Demands;


within AixLib.Fluid.DistrictHeatingCooling.Demands.ClosedLoop;
model DHCSubstationHeatPumpChiller
  "Substation model for bidirctional low-temperature networks for buildings with  heat pump and chiller"

    replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium model for water"

  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 30000
    "Nominal pressure drop";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=max(max((heaDem_max/(
      cp_default*deltaT_heaSecSet)), -cooDem_max/(cp_default*deltaT_cooSecSet)),
      0.0001)
    "Nominal mass flow rate based on max. demand and set temperature difference";

  parameter Modelica.Units.SI.HeatFlowRate heaDem_max
    "Maximum heat demand for scaling of heatpump in Watt"

  parameter Modelica.Units.SI.HeatFlowRate cooDem_max
    "Maximum cooling demand for scaling of chiller in Watt (negative values)"

  parameter Modelica.Units.SI.Temperature T_heaSecSet=273.15 + 55
    "Set supply temperature for space heating on secondary side (building system)"

  parameter Modelica.Units.SI.TemperatureDifference deltaT_heaSecSet
    "Set temperature difference for heating on secondary site (building system)"

  parameter Modelica.Units.SI.Temperature T_cooSecSet=273.15 + 12
    "Set supply temperature for cooling on secondary side (building system)"

  parameter Modelica.Units.SI.Temperature deltaT_cooSecSet
    "Set temperature difference for cooling on secondary site (building system)"

  parameter Modelica.Units.SI.Temperature deltaT_heaPriSet
    "Set temperature difference for heating on primary site (grid)"

  parameter Modelica.Units.SI.Temperature deltaT_cooPriSet
    "Set temperature difference for cooling on primary site (grid)"

  AixLib.Fluid.Delays.DelayFirstOrder vol(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal)
  AixLib.Fluid.Delays.DelayFirstOrder vol1(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal)
  AixLib.Fluid.Movers.FlowControlled_m_flow pumHea(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    addPowerToMedium=false,
    use_inputFilter=false,
    m_flow_nominal=m_flow_nominal)
    "decentral distribution pump for heating on primary side"
  AixLib.Fluid.Sources.MassFlowSource_T souHeaSec(
    use_m_flow_in=true,
    use_T_in=true,
    redeclare package Medium = Medium,
    nPorts=1)
  Modelica.Blocks.Sources.Constant T_heaPumInSec(k=T_heaSecSet -
        deltaT_heaSecSet) "Inlet temperatur of heat pump on secondary side"
  Sources.Boundary_pT sinHeaSec(redeclare package Medium = Medium, nPorts=1)
  Modelica.Blocks.Sources.Constant const(k=(cp_default*deltaT_heaSecSet))
  Modelica.Blocks.Math.Division division
public
  Modelica.Fluid.Interfaces.FluidPort_a port_a(redeclare package Medium =
        Medium)
    "Fluid connector for connecting the substation to the warm line of the network"
  Modelica.Fluid.Interfaces.FluidPort_b port_b(redeclare package Medium =
        Medium)
    "Fluid connector for connecting the substation to the cold line of the network"
  AixLib.Fluid.HeatPumps.Carnot_TCon heaPum(redeclare package Medium1 = Medium,
      redeclare package Medium2 = Medium,
    allowFlowReversal1=false,
    allowFlowReversal2=false,
    dp1_nominal=dp_nominal,
    dp2_nominal=dp_nominal,
    use_eta_Carnot_nominal=true,
    show_T=true,
    etaCarnot_nominal=0.5,
    QCon_flow_max=heaDem_max,
    QCon_flow_nominal=heaDem_max)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Interfaces.RealInput heaDem(unit="W")
    "Input for heat demand profile of substation"
  Modelica.Blocks.Math.Add add1(k2=-1)
  AixLib.Fluid.FixedResistances.Junction jun(
    redeclare package Medium = Medium,
    tau=60,
    dp_nominal={0,dp_nominal,dp_nominal},
    portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    portFlowDirection_3=Modelica.Fluid.Types.PortFlowDirection.Entering,
    m_flow_nominal=max(m_flow_nominal, 1)*{1,1,1})

  AixLib.Fluid.FixedResistances.Junction jun1(
    redeclare package Medium = Medium,
    tau=60,
    dp_nominal={0,dp_nominal,dp_nominal},
    portFlowDirection_3=Modelica.Fluid.Types.PortFlowDirection.Entering,
    m_flow_nominal=max(m_flow_nominal, 1)*{1,1,1})
  AixLib.Fluid.Chillers.Carnot_TEva chi(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    allowFlowReversal1=false,
    allowFlowReversal2=false,
    use_eta_Carnot_nominal=true,
    dp1_nominal=dp_nominal,
    dp2_nominal=dp_nominal,
    etaCarnot_nominal=0.4,
    QEva_flow_min=cooDem_max,
    QEva_flow_nominal=cooDem_max)
  AixLib.Fluid.Movers.FlowControlled_m_flow pumCoo(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    addPowerToMedium=false,
    use_inputFilter=false,
    m_flow_nominal=m_flow_nominal)
    "decentral distribution pump for cooling on primary side"
  Modelica.Blocks.Interfaces.RealInput cooDem(unit="W")
    "Input for cooling demand profile of substation"
  AixLib.Fluid.Sources.MassFlowSource_T souCoo(
    use_m_flow_in=true,
    use_T_in=true,
    redeclare package Medium = Medium,
    nPorts=1)
  Sources.Boundary_pT sinCoo(redeclare package Medium = Medium, nPorts=1)
  Modelica.Blocks.Math.Add add2(k2=+1)
  Modelica.Blocks.Math.Division division2
  Modelica.Blocks.Math.Division division3
  Modelica.Blocks.Sources.Constant const2(k=cp_default*deltaT_cooSecSet)

  Modelica.Blocks.Interfaces.RealOutput P_el_heaPum(unit="W")
    "Power demand of heat pump"
  Modelica.Blocks.Interfaces.RealOutput P_el_chi(unit="W")
    "Power demand of chiller"
  Modelica.Blocks.Interfaces.RealOutput P_el_subSta(unit="W")
    "Power demand of substation for heat pump, chiller and distribution pumps on primary side (grid)"
  Modelica.Blocks.Math.Sum sum1(nin=4)
  Modelica.Blocks.Sources.Constant T_heaPumSet(k=T_heaSecSet)
  Modelica.Blocks.Sources.RealExpression
                                   realExpression2(y=heaPum.P)
  Modelica.Blocks.Sources.RealExpression
                                   realExpression1(y=heaDem)
  Modelica.Blocks.Sources.RealExpression realExpression(y=cp_default*
        deltaT_heaPriSet)
  Modelica.Blocks.Sources.RealExpression
                                   realExpression3(y=heaPum.P)
  Modelica.Blocks.Sources.RealExpression
                                   realExpression4(y=chi.P)
  Modelica.Blocks.Sources.RealExpression
                                   realExpression5(y=chi.P)
  Modelica.Blocks.Sources.Constant const3(k=cp_default*deltaT_cooPriSet)
  Modelica.Blocks.Sources.Constant T_chiSet(k=T_cooSecSet)
  Modelica.Blocks.Sources.RealExpression realExpression6(y=T_cooSecSet +
        deltaT_cooSecSet)

protected
  final parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi]) "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";

equation
  connect(port_a,vol. ports[1])
  connect(port_b,vol1. ports[1])
  connect(chi.port_b1, jun.port_3)
  connect(heaPum.port_b2, jun1.port_3)
  connect(pumHea.port_b, heaPum.port_a2)
  connect(chi.port_a1, pumCoo.port_b)
  connect(heaDem, add1.u1)
  connect(add1.y, division1.u1)
  connect(division1.y, pumHea.m_flow_in)
  connect(souHeaSec.ports[1], heaPum.port_a1)
  connect(sinHeaSec.ports[1], heaPum.port_b1)
  connect(division.u2, const.y)
  connect(division.y, souHeaSec.m_flow_in)
  connect(souCoo.ports[1], chi.port_a2)
  connect(chi.port_b2, sinCoo.ports[1])
  connect(division2.u1, add2.y)
  connect(division2.y, pumCoo.m_flow_in)
  connect(const2.y, division3.u2)
  connect(division3.y, souCoo.m_flow_in)
  connect(port_a, port_a)
  connect(sum1.y, P_el_subSta)
  //Power Consumptin Calculation
  connect(chi.P, sum1.u[1]);
  connect(heaPum.P, sum1.u[2]);
  connect(pumCoo.P, sum1.u[3]);
  connect(pumHea.P, sum1.u[4]);

  connect(vol.ports[2], jun.port_1)
  connect(jun.port_2, pumHea.port_a)
  connect(jun1.port_2, pumCoo.port_a)
  connect(vol1.ports[2], jun1.port_1)
  connect(souHeaSec.T_in, T_heaPumInSec.y)
  connect(heaPum.TSet, T_heaPumSet.y)
  connect(realExpression2.y, add1.u2)
  connect(division.u1, realExpression1.y)
  connect(realExpression.y, division1.u2)
  connect(P_el_heaPum, realExpression3.y)
  connect(P_el_chi, realExpression4.y)
  connect(add2.u1, cooDem)
  connect(add2.u2, realExpression5.y)
  connect(division2.u2, const3.y)
  connect(division3.u1, cooDem)
  connect(chi.TSet, T_chiSet.y)
  connect(realExpression6.y, souCoo.T_in)
end DHCSubstationHeatPumpChiller;


within AixLib.Fluid.DistrictHeatingCooling.Demands.ClosedLoop;
model DHCSubstationHeatPumpDirectCooling "Substation model for bidirctional low-temperature networks for buildings with
  heat pump and direct cooling."

      replaceable package Medium = Modelica.Media.Interfaces.PartialMedium "Medium model for water"

  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 30000
    "Nominal pressure drop";

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

  parameter Modelica.Units.SI.HeatFlowRate heaDem_max
    "Maximum heat demand for scaling of heat pump"

  parameter Modelica.Units.SI.Temperature deltaT_heaSecSet=10
    "Set temperature difference for heating on secondary site (building system)"

  parameter Modelica.Units.SI.Temperature T_heaSecSet=273.15 + 55
    "Set supply temperature for space heating on secondary side (building)"

  parameter Modelica.Units.SI.Temperature T_heaPriSet=273.15 + 22
    "Set temperature of primary side (warm line of grid)"
  parameter Modelica.Units.SI.Temperature T_cooPriSet=273.15 + 12
    "Set temperature of primary side (cold line of grid)"

  Delays.DelayFirstOrder              vol(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    tau=60)
  Delays.DelayFirstOrder              vol1(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    tau=60)
  Movers.FlowControlled_m_flow pumHeaPri(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    addPowerToMedium=false,
    use_inputFilter=false,
    m_flow_nominal=m_flow_nominal)
    "decentral distribution pump for heating on primary side"
  Sources.MassFlowSource_T souHeaSec(
    use_m_flow_in=true,
    use_T_in=true,
    redeclare package Medium = Medium,
    nPorts=1)
  Modelica.Blocks.Sources.Constant T_heaPumInSec(k=T_heaSecSet -
        deltaT_heaSecSet) "Inlet temperatur of heat pump on secondary side"
  Sources.Boundary_pT sinHeaSec(redeclare package Medium = Medium, nPorts=1)
  Modelica.Blocks.Sources.Constant const(k=(cp_default*deltaT_heaSecSet))
  Modelica.Blocks.Math.Division m_flow_heaSec
    "Mass flow rate on secondary side"
  HeatPumps.Carnot_TCon              heaPum(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    dp1_nominal=dp_nominal,
    dp2_nominal=dp_nominal,
    use_eta_Carnot_nominal=true,
    show_T=true,
    etaCarnot_nominal=0.5,
    QCon_flow_nominal=heaDem_max)
  Modelica.Blocks.Math.Division division1
  Modelica.Blocks.Sources.RealExpression realExpression(y=(cp_default*(
        senT_heaPumInPri.T - T_cooPriSet)))
  Modelica.Blocks.Math.Add add1(k2=-1)
  FixedResistances.Junction              jun(
    redeclare package Medium = Medium,
    dp_nominal={0,dp_nominal,dp_nominal},
    portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    portFlowDirection_3=Modelica.Fluid.Types.PortFlowDirection.Entering,
    m_flow_nominal=m_flow_nominal*{1,1,1})
  FixedResistances.Junction              jun1(
    redeclare package Medium = Medium,
    dp_nominal={0,dp_nominal,dp_nominal},
    portFlowDirection_3=Modelica.Fluid.Types.PortFlowDirection.Entering,
    m_flow_nominal=m_flow_nominal*{1,1,1})
  Delays.DelayFirstOrder dirCoo(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Ideal heat exchanger for direct cooling"
  Movers.FlowControlled_m_flow pumCoo(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    addPowerToMedium=false,
    use_inputFilter=false,
    m_flow_nominal=m_flow_nominal)
    "decentral distribution pump for cooling on primary side"
  Modelica.Blocks.Math.Division division2
  Modelica.Blocks.Sources.RealExpression realExpression1(y=(cp_default*(
        T_heaPriSet - senT_dirCooInPri.T)))
  Modelica.Blocks.Sources.Constant T_heaPumSet(k=T_heaSecSet)
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow prescribedHeatFlow
  Sensors.TemperatureTwoPort senT_heaPumOutPri(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal)
  Sensors.TemperatureTwoPort senT_heaPumInPri(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal)
  Sensors.TemperatureTwoPort senT_heaPumOutSec(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal)
    "Outlet temperature of heat pump on secondary side"
  Sensors.TemperatureTwoPort senT_heaPumInSec(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal)
    "Inlet temperatur of heat pump on secondary side"
  Sensors.TemperatureTwoPort senT_dirCooInPri(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal)
    "Inlet temperature of ideal heat exchanger for direct cooling on primary side"
  Sensors.TemperatureTwoPort senT_dirCooOutPri(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal)
    "Outlet temperature of ideal heat exchanger for direct cooling on primary side"
  Modelica.Blocks.Sources.RealExpression
                                   realExpression2(y=heaPum.P)
  Modelica.Blocks.Sources.RealExpression
                                   realExpression3(y=heaPum.P)
  Modelica.Blocks.Sources.RealExpression realExpression4(y=heaDem)
public
  Modelica.Fluid.Interfaces.FluidPort_a port_a(redeclare package Medium =
        Medium)
    "Fluid connector for connecting the substation to the warm line of the network"
  Modelica.Fluid.Interfaces.FluidPort_b port_b(redeclare package Medium =
        Medium)
    "Fluid connector for connecting the substation to the cold line of the network"
  Modelica.Blocks.Interfaces.RealInput heaDem(unit="W")
    "Input for heat demand profile of substation"
  Modelica.Blocks.Interfaces.RealInput cooDem(unit="W")
    "Input for cooling demand profile of substation"
  Modelica.Blocks.Interfaces.RealOutput P_el_heaPum(unit="W")
    "Electrical power consumed by heat pump"

protected
  final parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi]) "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";

equation
  connect(port_a,vol. ports[1])
  connect(port_b,vol1. ports[1])
  connect(heaDem, add1.u1)
  connect(add1.y,division1. u1)
  connect(realExpression.y,division1. u2)
  connect(m_flow_heaSec.u2, const.y)
  connect(m_flow_heaSec.y, souHeaSec.m_flow_in)
  connect(division2.u2,realExpression1. y)
  connect(port_a,port_a)
  connect(T_heaPumSet.y, heaPum.TSet)
  connect(dirCoo.ports[1], pumCoo.port_b)
  connect(cooDem, division2.u1)
  connect(prescribedHeatFlow.port, dirCoo.heatPort)
  connect(prescribedHeatFlow.Q_flow, cooDem)
  connect(pumHeaPri.port_b, senT_heaPumInPri.port_a)
  connect(senT_heaPumInPri.port_b, heaPum.port_a2)
  connect(heaPum.port_b2, senT_heaPumOutPri.port_a)
  connect(senT_heaPumOutPri.port_b, jun1.port_3)
  connect(senT_heaPumOutSec.port_a, heaPum.port_b1)
  connect(senT_heaPumOutSec.port_b, sinHeaSec.ports[1])
  connect(senT_dirCooInPri.port_b, jun1.port_2)
  connect(division2.y, pumCoo.m_flow_in)
  connect(division1.y, pumHeaPri.m_flow_in)
  connect(senT_dirCooOutPri.port_b, dirCoo.ports[2])
  connect(jun.port_3, senT_dirCooOutPri.port_a)
  connect(souHeaSec.T_in, T_heaPumInSec.y)
  connect(realExpression2.y,add1. u2)
  connect(senT_heaPumInSec.port_b, heaPum.port_a1)

  connect(senT_heaPumInSec.port_a, souHeaSec.ports[1])
  connect(realExpression3.y, P_el_heaPum)
  connect(m_flow_heaSec.u1, realExpression4.y)
  connect(vol.ports[2], jun.port_1)
  connect(jun.port_2, pumHeaPri.port_a)
  connect(pumCoo.port_a, senT_dirCooInPri.port_a)
  connect(jun1.port_1, vol1.ports[2])
end DHCSubstationHeatPumpDirectCooling;


Substation with closed loop design

within AixLib.Fluid.DistrictHeatingCooling.Demands;
package ClosedLoop "Substation with closed loop design"
end ClosedLoop;


Fluid in the pipes

within AixLib.Fluid.DistrictHeatingCooling.Demands.Examples;
model DHCSubstationHeatPumpChiller
  import AixLib;
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Water "Fluid in the pipes";
  AixLib.Fluid.Sources.Boundary_pT warmLine(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=1) "Warm Line of network"
  AixLib.Fluid.Sources.Boundary_pT coldLine(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=1) "Cold line of network"
  Modelica.Blocks.Sources.Constant T_coldLine(k=12 + 273.15)
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem(redeclare package Medium =
        Medium, m_flow_nominal=2)
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem1(redeclare package Medium =
        Medium, m_flow_nominal=2)
  Modelica.Blocks.Sources.Constant T_warmLine(k=22 + 273.15)
  Modelica.Blocks.Sources.TimeTable coolingDemand(table=[0,0; 3600,0; 3600,1500;
        7200,1500; 7200,2000; 10800,1000; 14400,0; 18000,0; 18000,2000])
  Modelica.Blocks.Sources.TimeTable heatDemand(table=[0,2000; 3600,2000; 3600,0;
        7200,0; 7200,3000; 10800,4000; 14400,4000; 14400,2500; 18000,2500])
  AixLib.Fluid.DistrictHeatingCooling.Demands.ClosedLoop.DHCSubstationHeatPumpChiller
    DHCsubstationHeatingDirectCooling(
    redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater,
    m_flow_nominal=2,
    heaDem_max=4000,
    cooDem_max=-2500,
    deltaT_heaSecSet(displayUnit="K") = 10,
    T_heaSecSet=328.15,
    T_cooSecSet=285.15,
    deltaT_cooSecSet=279.15,
    deltaT_heaPriSet(displayUnit="K") = 5,
    deltaT_cooPriSet(displayUnit="K") = 5)

equation
  connect(T_warmLine.y, warmLine.T_in)
  connect(senTem1.port_b, coldLine.ports[1])
  connect(warmLine.ports[1], senTem.port_a)
  connect(T_coldLine.y, coldLine.T_in)
  connect(DHCsubstationHeatingDirectCooling.port_b, senTem1.port_a)
  connect(senTem.port_b, DHCsubstationHeatingDirectCooling.port_a)
  connect(coolingDemand.y, DHCsubstationHeatingDirectCooling.cooDem)
  connect(DHCsubstationHeatingDirectCooling.heaDem, heatDemand.y)
end DHCSubstationHeatPumpChiller;


Fluid in the pipes

within AixLib.Fluid.DistrictHeatingCooling.Demands.Examples;
model DHCSubstationHeatPumpDirectCooling
  import AixLib;
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Water "Fluid in the pipes";
  AixLib.Fluid.Sources.Boundary_pT warmLine(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=1) "Warm Line of network"
  AixLib.Fluid.Sources.Boundary_pT coldLine(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=1) "Cold line of network"
  Modelica.Blocks.Sources.Constant T_coldLine(k=12 + 273.15)
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem(redeclare package Medium =
        Medium, m_flow_nominal=2)
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem1(redeclare package Medium =
        Medium, m_flow_nominal=2)
  Modelica.Blocks.Sources.Constant T_warmLine(k=22 + 273.15)
  Modelica.Blocks.Sources.TimeTable coolingDemand(table=[0,0; 3600,0; 3600,1500;
        7200,1500; 7200,2000; 10800,1000; 14400,0; 18000,0; 18000,2000])
  Modelica.Blocks.Sources.TimeTable heatDemand(table=[0,2000; 3600,2000; 3600,0;
        7200,0; 7200,3000; 10800,4000; 14400,4000; 14400,2500; 18000,2500])
  AixLib.Fluid.DistrictHeatingCooling.Demands.ClosedLoop.DHCSubstationHeatPumpDirectCooling
    DHCsubstationHeatingDirectCooling(
    redeclare package Medium = Modelica.Media.Water.ConstantPropertyLiquidWater,
    m_flow_nominal=2,
    heaDem_max=4000,
    deltaT_heaSecSet=283.15,
    T_heaSecSet=328.15,
    T_heaPriSet=295.15,
    T_cooPriSet=285.15)

equation
  connect(T_warmLine.y, warmLine.T_in)
  connect(senTem1.port_b, coldLine.ports[1])
  connect(warmLine.ports[1], senTem.port_a)
  connect(T_coldLine.y, coldLine.T_in)
  connect(DHCsubstationHeatingDirectCooling.port_b, senTem1.port_a)
  connect(senTem.port_b, DHCsubstationHeatingDirectCooling.port_a)
  connect(coolingDemand.y, DHCsubstationHeatingDirectCooling.cooDem)
  connect(DHCsubstationHeatingDirectCooling.heaDem, heatDemand.y)
end DHCSubstationHeatPumpDirectCooling;


within AixLib.Fluid.DistrictHeatingCooling.Demands.Examples;
model OpenLoopHeatPumpCarnot
  "A small open loop example with a heat pump in the substation"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Temperature T_amb=283.15
    "Ambient temperature around pipes";

  package Medium = AixLib.Media.Specialized.Water.ConstantProperties_pT (
    T_nominal=273.15+15,
    p_nominal=600000.0,
    T_default=273.15+15);

  Supplies.OpenLoop.SourceIdeal sourceIdeal(
    redeclare package Medium = Medium,
    TReturn=273.15 + 10,
    pReturn=200000)      "Simple suppy model"
  .AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop.HeatPumpCarnot demand(
    redeclare package Medium = Medium,
    dp_nominal=50000,
    redeclare package MediumBuilding = Medium,
    dTBuilding=10,
    Q_flow_nominal=78239.1,
    dTDesign=10,
    TReturn=283.15,
    TSupplyBuilding=313.15) "Simple demand model"
  FixedResistances.PlugFlowPipe pipeSupply(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Supply pipe"
  FixedResistances.PlugFlowPipe pipeReturn(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Return pipe"
  Modelica.Blocks.Sources.Constant TSet(k=20 + 273.15)
                                                      "Set supply temperature"
  Modelica.Blocks.Sources.Constant dpSet(k=1.4e5)
    "Set pressure difference for substation"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TGround
    "Ground temperature"
  Modelica.Blocks.Sources.Constant TGroundSet(k=10 + 273.15)
    "Set ground temperature"
  Modelica.Blocks.Sources.Sine sine(
    amplitude=12000,
    f=1/10000,
    offset=24000) "A sine wave for varying heat demands"
  Modelica.Blocks.Continuous.LimPID pControl(controllerType=Modelica.Blocks.Types.SimpleController.PI,
      yMax=6e5) "Pressure controller"
equation
  connect(sourceIdeal.port_b, pipeSupply.port_a)
  connect(pipeSupply.port_b, demand.port_a)
  connect(demand.port_b, pipeReturn.port_a)
  connect(pipeReturn.port_b, sourceIdeal.port_a)
  connect(TSet.y, sourceIdeal.TIn)
  connect(TGroundSet.y, TGround.T)
  connect(TGround.port, pipeReturn.heatPort)
  connect(TGround.port, pipeSupply.heatPort)
  connect(demand.Q_flow_input, sine.y)
  connect(dpSet.y, pControl.u_s)
  connect(demand.dpOut, pControl.u_m)
  connect(pControl.y, sourceIdeal.dpIn)
end OpenLoopHeatPumpCarnot;


within AixLib.Fluid.DistrictHeatingCooling.Demands.Examples;
model OpenLoopVarTSupplyDp
  "A small open loop example with a Substation with variable dT for fixed return temperature"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Temperature T_amb=283.15
    "Ambient temperature around pipes";

  package Medium = AixLib.Media.Specialized.Water.ConstantProperties_pT (
    T_nominal=273.15+60,
    p_nominal=600000.0,
    T_default=273.15+60);

  Supplies.OpenLoop.SourceIdeal sourceIdeal(
    redeclare package Medium = Medium,
    TReturn=273.15 + 60,
    pReturn=200000)      "Simple suppy model"
  AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop.VarTSupplyDp    demand(
    redeclare package Medium = Medium,
    dp_nominal=50000,
    Q_flow_nominal=78239.1,
    dTDesign=15,
    TReturn=333.15)         "Simple demand model"
  FixedResistances.PlugFlowPipe pipeSupply(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Supply pipe"
  FixedResistances.PlugFlowPipe pipeReturn(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Return pipe"
  Modelica.Blocks.Sources.Constant TSet(k=75 + 273.15)
                                                      "Set supply temperature"
  Modelica.Blocks.Sources.Constant dpSet(k=1.4e5)
    "Set pressure difference for substation"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TGround
    "Ground temperature"
  Modelica.Blocks.Sources.Constant TGroundSet(k=10 + 273.15)
    "Set ground temperature"
  Modelica.Blocks.Sources.Sine sine(
    amplitude=12000,
    f=1/10000,
    offset=24000) "A sine wave for varying heat demands"
  Modelica.Blocks.Continuous.LimPID pControl(controllerType=Modelica.Blocks.Types.SimpleController.PI,
      yMax=6e5) "Pressure controller"
equation
  connect(sourceIdeal.port_b, pipeSupply.port_a)
  connect(pipeSupply.port_b, demand.port_a)
  connect(demand.port_b, pipeReturn.port_a)
  connect(pipeReturn.port_b, sourceIdeal.port_a)
  connect(TSet.y, sourceIdeal.TIn)
  connect(TGroundSet.y, TGround.T)
  connect(TGround.port, pipeReturn.heatPort)
  connect(TGround.port, pipeSupply.heatPort)
  connect(demand.Q_flow_input, sine.y)
  connect(dpSet.y, pControl.u_s)
  connect(demand.dpOut, pControl.u_m)
  connect(pControl.y, sourceIdeal.dpIn)
end OpenLoopVarTSupplyDp;


within AixLib.Fluid.DistrictHeatingCooling.Demands.Examples;
model OpenLoopVarTSupplyDpBypass
  "A small open loop example with a Substation with variable dT for fixed return temperature"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Temperature T_amb=283.15
    "Ambient temperature around pipes";

  package Medium = AixLib.Media.Specialized.Water.ConstantProperties_pT (
    T_nominal=273.15+60,
    p_nominal=600000.0,
    T_default=273.15+60);

  Supplies.OpenLoop.SourceIdeal sourceIdeal(
    redeclare package Medium = Medium,
    TReturn=273.15 + 60,
    pReturn=200000)      "Simple suppy model"
  AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop.VarTSupplyDpBypass
                                                                       demand(
    redeclare package Medium = Medium,
    dp_nominal=50000,
    Q_flow_nominal=78239.1,
    dTDesign=15,
    TReturn=283.15,
    m_flo_bypass=0.00)      "Simple demand model"
  FixedResistances.PlugFlowPipe pipeSupply(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Supply pipe"
  FixedResistances.PlugFlowPipe pipeReturn(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Return pipe"
  Modelica.Blocks.Sources.Constant TSet(k=75 + 273.15)
                                                      "Set supply temperature"
  Modelica.Blocks.Sources.Constant dpSet(k=1.4e5)
    "Set pressure difference for substation"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TGround
    "Ground temperature"
  Modelica.Blocks.Sources.Constant TGroundSet(k=10 + 273.15)
    "Set ground temperature"
  Modelica.Blocks.Sources.Sine sine(
    amplitude=12000,
    f=1/10000,
    offset=24000) "A sine wave for varying heat demands"
  Modelica.Blocks.Continuous.LimPID pControl(controllerType=Modelica.Blocks.Types.SimpleController.PI,
      yMax=6e5) "Pressure controller"
equation
  connect(sourceIdeal.port_b, pipeSupply.port_a)
  connect(pipeSupply.port_b, demand.port_a)
  connect(demand.port_b, pipeReturn.port_a)
  connect(pipeReturn.port_b, sourceIdeal.port_a)
  connect(TSet.y, sourceIdeal.TIn)
  connect(TGroundSet.y, TGround.T)
  connect(TGround.port, pipeReturn.heatPort)
  connect(TGround.port, pipeSupply.heatPort)
  connect(demand.Q_flow_input, sine.y)
  connect(dpSet.y, pControl.u_s)
  connect(demand.dpOut, pControl.u_m)
  connect(pControl.y, sourceIdeal.dpIn)
end OpenLoopVarTSupplyDpBypass;


within AixLib.Fluid.DistrictHeatingCooling.Demands.Examples;
model OpenLoopVarTSupplyDpFixedTempDifferenceBypass
  "A small open loop example with a Substation with variable supply temperature and fixed dT"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Temperature T_amb=283.15
    "Ambient temperature around pipes";

  package Medium = AixLib.Media.Specialized.Water.ConstantProperties_pT (
    T_nominal=273.15+60,
    p_nominal=600000.0,
    T_default=273.15+60);

  Supplies.OpenLoop.SourceIdeal sourceIdeal(
    redeclare package Medium = Medium,
    TReturn=273.15 + 60,
    pReturn=200000)      "Simple suppy model"
  AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop.VarTSupplyDpFixedTempDifferenceBypass
                                                                       demand(
    redeclare package Medium = Medium,
    dp_nominal=50000,
    Q_flow_nominal=78239.1,
    dTDesign=15,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flo_bypass=0.003)     "Simple demand model"
  FixedResistances.PlugFlowPipe pipeSupply(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Supply pipe"
  FixedResistances.PlugFlowPipe pipeReturn(
    redeclare package Medium = Medium,
    dh=0.05,
    length=50,
    m_flow_nominal=1,
    dIns=0.03,
    kIns=0.027) "Return pipe"
  Modelica.Blocks.Sources.Constant TSet(k=75 + 273.15)
                                                      "Set supply temperature"
  Modelica.Blocks.Sources.Constant dpSet(k=1.4e5)
    "Set pressure difference for substation"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TGround
    "Ground temperature"
  Modelica.Blocks.Sources.Constant TGroundSet(k=10 + 273.15)
    "Set ground temperature"
  Modelica.Blocks.Sources.Sine sine(
    amplitude=12000,
    f=1/10000,
    offset=24000) "A sine wave for varying heat demands"
  Modelica.Blocks.Continuous.LimPID pControl(controllerType=Modelica.Blocks.Types.SimpleController.PI,
      yMax=6e5) "Pressure controller"
equation
  connect(sourceIdeal.port_b, pipeSupply.port_a)
  connect(pipeSupply.port_b, demand.port_a)
  connect(demand.port_b, pipeReturn.port_a)
  connect(pipeReturn.port_b, sourceIdeal.port_a)
  connect(TSet.y, sourceIdeal.TIn)
  connect(TGroundSet.y, TGround.T)
  connect(TGround.port, pipeReturn.heatPort)
  connect(TGround.port, pipeSupply.heatPort)
  connect(demand.Q_flow_input, sine.y)
  connect(dpSet.y, pControl.u_s)
  connect(demand.dpOut, pControl.u_m)
  connect(pControl.y, sourceIdeal.dpIn)
end OpenLoopVarTSupplyDpFixedTempDifferenceBypass;


  This package contains examples for the use of models that can be
  found in <a href=
  \

within AixLib.Fluid.DistrictHeatingCooling.Demands;
package Examples
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop;
model HeatPumpCarnot "Substation with a heat pump carnot model"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow(start=0),
    final dp(start=0),
    final allowFlowReversal=false,
    final m_flow_nominal = Q_flow_nominal/cp_default/dTDesign);

  replaceable package MediumBuilding =
    Modelica.Media.Interfaces.PartialMedium
      "Medium in the building heating system"

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat flow rate added to medium";

  parameter Modelica.Units.SI.TemperatureDifference dTDesign(displayUnit="K")
    "Design temperature difference for the heat pump on its district heating side";

  parameter Modelica.Units.SI.Temperature TReturn "Fixed return temperature";

  parameter Modelica.Units.SI.TemperatureDifference dTBuilding(displayUnit="K")
    "Design temperature difference for the building's heating system";

  parameter Modelica.Units.SI.Temperature TSupplyBuilding
    "Fixed supply temperature for the building heating system";

  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 30000
    "Pressure difference at nominal flow rate"

  parameter Real deltaM=0.1
    "Fraction of nominal flow rate where flow transitions to laminar"
  parameter Modelica.Units.SI.Time tau=30
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState
    "Type of energy balance: dynamic (3 initialization options) or steady state"
  parameter Modelica.Fluid.Types.Dynamics massDynamics=energyDynamics
    "Type of mass balance: dynamic (3 initialization options) or steady state"

protected
  final parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi]) "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid in the district heating system";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default_building=
      MediumBuilding.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid in the building heating system";

public
  Modelica.Blocks.Interfaces.RealInput Q_flow_input "Prescribed heat flow"
  Sensors.TemperatureTwoPort              senT_supply(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Supply flow temperature sensor"
  Sensors.TemperatureTwoPort              senT_return(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Return flow temperature sensor"
  Modelica.Blocks.Math.Add deltaT(k2=-1)
    "Differernce of flow and return line temperature in K"
  Modelica.Blocks.Sources.Constant dTheaPum(k=dTDesign)
    "Temperature drop over heat pump in K"
  Modelica.Blocks.Math.Gain gain(k(unit="J/(kg.K)")=cp_default, y(unit="J/(kg.K)"))
  Modelica.Blocks.Math.Division hea2MasFlo
  Sources.MassFlowSource_T              sink(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1) "Sink extracting prescribed flow from the network"
  Modelica.Blocks.Math.Gain changeSign(k=-1)
    "Changes sign of prescribed flow for extraction from network"
  Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    T=TReturn,
    use_T_in=true)
               "Source sending prescribed flow back to the network"
  Modelica.Blocks.Interfaces.RealOutput dpOut
    "Output signal of pressure difference"
  HeatPumps.Carnot_TCon              heaPum(
    redeclare package Medium1 = MediumBuilding,
    dp1_nominal=dp_nominal,
    dp2_nominal=dp_nominal,
    use_eta_Carnot_nominal=true,
    etaCarnot_nominal=0.3,
    show_T=true,
    redeclare package Medium2 = Medium,
    QCon_flow_nominal=Q_flow_nominal)
  Modelica.Blocks.Math.Add Q_con(k2=-1)
    "Differernce of heat demand and electric power of heat pump"
  Sources.MassFlowSource_T              sourceHeating(
    use_m_flow_in=true,
    redeclare package Medium = MediumBuilding,
    use_T_in=true,
    nPorts=1)
  Sources.Boundary_pT                sinkHeating(
                          redeclare package Medium = MediumBuilding, nPorts=1)
  Modelica.Blocks.Math.Gain masFloBuilding(k=1/(cp_default_building*dTBuilding))
    "Changes sign of prescribed flow for extraction from network"
  Modelica.Blocks.Sources.Constant temperatureSupplyBuilding(k=TSupplyBuilding)
    "Temperature of supply line"
  Modelica.Blocks.Sources.Constant deltaTBuilding(k=dTBuilding)
    "Temperature difference in building heating system"
  Modelica.Blocks.Math.Add temperatureReturnBuilding(k2=-1)
    "Temperature returning from building heating system"
  Modelica.Blocks.Math.Gain gainInput(k=1) "Optional gain on the input"
  Modelica.Blocks.Sources.Constant minT_return(k=273.15 + 10)
    "Minimal return Temperature"
  Modelica.Blocks.Math.Max max
equation

  dpOut = dp;

  connect(port_a, senT_supply.port_a)
  connect(port_b, senT_return.port_b)
  connect(gain.y, hea2MasFlo.u2)
  connect(source.ports[1], senT_return.port_a)
  connect(hea2MasFlo.y, changeSign.u)
  connect(changeSign.y, sink.m_flow_in)
  connect(hea2MasFlo.y, source.m_flow_in)
  connect(senT_supply.port_b, heaPum.port_a2)
  connect(sink.ports[1], heaPum.port_b2)
  connect(Q_con.y, hea2MasFlo.u1)
  connect(heaPum.P, Q_con.u2)
  connect(masFloBuilding.y, sourceHeating.m_flow_in)
  connect(temperatureSupplyBuilding.y, heaPum.TSet)
  connect(sourceHeating.T_in, temperatureReturnBuilding.y)
  connect(temperatureSupplyBuilding.y, temperatureReturnBuilding.u1)
  connect(deltaTBuilding.y, temperatureReturnBuilding.u2)
  connect(sinkHeating.ports[1], heaPum.port_b1)
  connect(heaPum.port_a1, sourceHeating.ports[1])
  connect(dTheaPum.y, gain.u)
  connect(senT_supply.T, deltaT.u1)
  connect(dTheaPum.y, deltaT.u2)
  connect(Q_flow_input, gainInput.u)
  connect(Q_con.u1, gainInput.y)
  connect(gainInput.y,masFloBuilding. u)
  connect(deltaT.y, max.u2)
  connect(minT_return.y, max.u1)
  connect(max.y, source.T_in)
end HeatPumpCarnot;


Substation with an open loop design

within AixLib.Fluid.DistrictHeatingCooling.Demands;
package OpenLoop "Substation with an open loop design"
end OpenLoop;


within AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop;
model VarTSupplyDp
  "Substation with variable dT for fixed return temperature"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow(start=0),
    final dp(start=0),
    final allowFlowReversal=false,
    final m_flow_nominal = Q_flow_nominal/cp_default/dTDesign);

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat flow rate added to medium";

  parameter Modelica.Units.SI.TemperatureDifference dTDesign(displayUnit="K")
    "Design temperature difference for the substation's heat exchanger";

  parameter Modelica.Units.SI.Temperature TReturn "Fixed return temperature";

  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 30000
    "Pressure difference at nominal flow rate"

  parameter Real deltaM=0.1
    "Fraction of nominal flow rate where flow transitions to laminar"
  parameter Modelica.Units.SI.Time tau=30
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState
    "Type of energy balance: dynamic (3 initialization options) or steady state"
  parameter Modelica.Fluid.Types.Dynamics massDynamics=energyDynamics
    "Type of mass balance: dynamic (3 initialization options) or steady state"

protected
  final parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi]) "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";

public
  Modelica.Blocks.Interfaces.RealInput Q_flow_input "Prescribed heat flow"
  Sensors.TemperatureTwoPort              senT_supply(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Supply flow temperature sensor"
  Sensors.TemperatureTwoPort              senT_return(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Return flow temperature sensor"
  Modelica.Blocks.Math.Add deltaT(k1=+1, k2=-1)
    "Differernce of flow and return line temperature in K"
  Modelica.Blocks.Sources.Constant temRet(k=TReturn)
    "Temperature of return line in °C"
  Modelica.Blocks.Math.Gain gain(k(unit="J/(kg.K)")=cp_default, y(unit="J/(kg.K)"))
  Modelica.Blocks.Math.Division hea2MasFlo
  Sources.MassFlowSource_T              sink(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1) "Sink extracting prescribed flow from the network"
  Modelica.Blocks.Math.Gain changeSign(k=-1)
    "Changes sign of prescribed flow for extraction from network"
  Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    T=TReturn,
    use_T_in=true)
               "Source sending prescribed flow back to the network"
  Modelica.Blocks.Interfaces.RealOutput dpOut
    "Output signal of pressure difference"
  Modelica.Blocks.Sources.Constant mindeltaT(k=20)
    "Temperature of return line in °C"
  Modelica.Blocks.Math.Max max
  Modelica.Blocks.Math.Min min
  Modelica.Blocks.Sources.Constant temRet_nominal(k=TReturn)
    "Temperature of return line in °C"
  Modelica.Blocks.Math.Add deltaT1(k1=+1, k2=-1)
    "Differernce of flow and return line temperature in K"
equation

  dpOut = dp;

  connect(port_a, senT_supply.port_a)
  connect(port_b, senT_return.port_b)
  connect(temRet.y, deltaT.u2)
  connect(gain.y, hea2MasFlo.u2)
  connect(Q_flow_input, hea2MasFlo.u1)
  connect(source.ports[1], senT_return.port_a)
  connect(hea2MasFlo.y, changeSign.u)
  connect(changeSign.y, sink.m_flow_in)
  connect(hea2MasFlo.y, source.m_flow_in)
  connect(senT_supply.port_b, sink.ports[1])
  connect(senT_supply.T, deltaT.u1)
  connect(max.y, gain.u)
  connect(deltaT.y, max.u1)
  connect(mindeltaT.y, max.u2)
  connect(min.y, source.T_in)
  connect(temRet_nominal.y, min.u1)
  connect(deltaT1.y, min.u2)
  connect(senT_supply.T, deltaT1.u1)
  connect(mindeltaT.y, deltaT1.u2)
end VarTSupplyDp;


within AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop;
model VarTSupplyDpBypass
  "Substation with variable dT for fixed return temperature"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow(start=0),
    final dp(start=0),
    final allowFlowReversal=false,
    final m_flow_nominal = Q_flow_nominal/cp_default/dTDesign);

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat flow rate added to medium";

  parameter Modelica.Units.SI.TemperatureDifference dTDesign(displayUnit="K")
    "Design temperature difference for the substation's heat exchanger";

  parameter Modelica.Units.SI.Temperature TReturn "Fixed return temperature";

  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 30000
    "Pressure difference at nominal flow rate"

  parameter Real deltaM=0.1
    "Fraction of nominal flow rate where flow transitions to laminar"
  parameter Modelica.Units.SI.Time tau=30
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState
    "Type of energy balance: dynamic (3 initialization options) or steady state"
  parameter Modelica.Fluid.Types.Dynamics massDynamics=energyDynamics
    "Type of mass balance: dynamic (3 initialization options) or steady state"

  parameter Modelica.Units.SI.MassFlowRate m_flo_bypass
    "Minimum bypass flow through substation";

protected
  final parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi]) "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";

public
  Modelica.Blocks.Interfaces.RealInput Q_flow_input "Prescribed heat flow"
  Sensors.TemperatureTwoPort              senT_supply(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Supply flow temperature sensor"
  Sensors.TemperatureTwoPort              senT_return(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Return flow temperature sensor"
  Modelica.Blocks.Math.Add deltaT(k1=+1, k2=-1)
    "Differernce of flow and return line temperature in K"
  Modelica.Blocks.Sources.Constant temRet(k=TReturn)
    "Temperature of return line in °C"
  Modelica.Blocks.Math.Gain gain(k(unit="J/(kg.K)")=cp_default, y(unit="J/(kg.K)"))
  Modelica.Blocks.Math.Division hea2MasFlo
  Sources.MassFlowSource_T              sink(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1) "Sink extracting prescribed flow from the network"
  Modelica.Blocks.Math.Gain changeSign(k=-1)
    "Changes sign of prescribed flow for extraction from network"
  Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    T=TReturn,
    use_T_in=true)
               "Source sending prescribed flow back to the network"
  Modelica.Blocks.Interfaces.RealOutput dpOut
    "Output signal of pressure difference"
  Modelica.Blocks.Sources.Constant mindeltaT(k=20)
    "Temperature of return line in °C"
  Modelica.Blocks.Math.Max max
  Modelica.Blocks.Math.Min min
  Modelica.Blocks.Sources.Constant temRet_nominal(k=TReturn)
    "Temperature of return line in °C"
  Modelica.Blocks.Math.Add deltaT1(k1=+1, k2=-1)
    "Differernce of flow and return line temperature in K"
  Modelica.Blocks.Sources.RealExpression m_flo_min(y=m_flo_bypass)
  Utilities.Math.SmoothMax smoothMax(deltaX=0.001)
  Modelica.Blocks.Logical.LessEqualThreshold lessEqualThreshold(threshold=
        m_flo_bypass)
  Utilities.Logical.SmoothSwitch switch1
equation

  dpOut = dp;

  connect(port_a, senT_supply.port_a)
  connect(port_b, senT_return.port_b)
  connect(temRet.y, deltaT.u2)
  connect(gain.y, hea2MasFlo.u2)
  connect(Q_flow_input, hea2MasFlo.u1)
  connect(source.ports[1], senT_return.port_a)
  connect(changeSign.y, sink.m_flow_in)
  connect(senT_supply.port_b, sink.ports[1])
  connect(senT_supply.T, deltaT.u1)
  connect(max.y, gain.u)
  connect(deltaT.y, max.u1)
  connect(mindeltaT.y, max.u2)
  connect(temRet_nominal.y, min.u1)
  connect(deltaT1.y, min.u2)
  connect(senT_supply.T, deltaT1.u1)
  connect(mindeltaT.y, deltaT1.u2)
  connect(smoothMax.y, changeSign.u)
  connect(hea2MasFlo.y, smoothMax.u2)
  connect(m_flo_min.y, smoothMax.u1)
  connect(smoothMax.y, lessEqualThreshold.u)
  connect(lessEqualThreshold.y, switch1.u2)
  connect(min.y, switch1.u3)
  connect(senT_supply.T, switch1.u1)
  connect(switch1.y, source.T_in)
  connect(changeSign.y, source.m_flow_in)
end VarTSupplyDpBypass;


within AixLib.Fluid.DistrictHeatingCooling.Demands.OpenLoop;
model VarTSupplyDpFixedTempDifferenceBypass
  "Substation with variable supply temperature and fixed dT"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow(start=0),
    final dp(start=0),
    final allowFlowReversal=false,
    final m_flow_nominal = Q_flow_nominal/cp_default/dTDesign);

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat flow rate added to medium";

  parameter Modelica.Units.SI.TemperatureDifference dTDesign(displayUnit="K")
    "Constant temperature difference for the substation's heat exchanger";

  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 30000
    "Pressure difference at nominal flow rate"

  parameter Real deltaM=0.1
    "Fraction of nominal flow rate where flow transitions to laminar"
  parameter Modelica.Units.SI.Time tau=30
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState
    "Type of energy balance: dynamic (3 initialization options) or steady state"
  parameter Modelica.Fluid.Types.Dynamics massDynamics=energyDynamics
    "Type of mass balance: dynamic (3 initialization options) or steady state"

  parameter Modelica.Units.SI.MassFlowRate m_flo_bypass
    "Minimum bypass flow through substation";

protected
  final parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi]) "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";

public
  Modelica.Blocks.Interfaces.RealInput Q_flow_input "Prescribed heat flow"
  Sensors.TemperatureTwoPort              senT_supply(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Supply flow temperature sensor"
  Sensors.TemperatureTwoPort              senT_return(redeclare package Medium =
        Medium, m_flow_nominal=m_flow_nominal) "Return flow temperature sensor"
  Modelica.Blocks.Math.Gain gain(k(unit="J/(kg.K)")=cp_default, y(unit="J/(kg.K)"))
  Modelica.Blocks.Math.Division hea2MasFlo
  Sources.MassFlowSource_T              sink(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1) "Sink extracting prescribed flow from the network"
  Modelica.Blocks.Math.Gain changeSign(k=-1)
    "Changes sign of prescribed flow for extraction from network"
  Sources.MassFlowSource_T source(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true,
    nPorts=1)  "Source sending prescribed flow back to the network"
  Modelica.Blocks.Interfaces.RealOutput dpOut
    "Output signal of pressure difference"
  Modelica.Blocks.Sources.Constant deltaT(k=dTDesign)
    "Fixed temperature difference between supply and return"
  Modelica.Blocks.Math.Add temRet(k1=-1, k2=+1)
  Utilities.Math.SmoothMax smoothMax(deltaX=0.001)
  Modelica.Blocks.Sources.RealExpression m_flo_min(y=m_flo_bypass)
  Utilities.Logical.SmoothSwitch switch1
  Modelica.Blocks.Logical.LessEqualThreshold lessEqualThreshold(threshold=
        m_flo_bypass)
  MixingVolumes.MixingVolume vol(
    energyDynamics=energyDynamics,
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    V=m_flow_nominal*30/995.58)
equation

  dpOut = dp;

  connect(port_a, senT_supply.port_a)
  connect(port_b, senT_return.port_b)
  connect(Q_flow_input, hea2MasFlo.u1)
  connect(changeSign.y, sink.m_flow_in)
  connect(senT_supply.port_b, sink.ports[1])
  connect(deltaT.y, gain.u)
  connect(deltaT.y, temRet.u1)
  connect(senT_supply.T, temRet.u2)
  connect(gain.y, hea2MasFlo.u2)
  connect(smoothMax.y, changeSign.u)
  connect(smoothMax.y, source.m_flow_in)
  connect(smoothMax.u1, hea2MasFlo.y)
  connect(m_flo_min.y, smoothMax.u2)
  connect(lessEqualThreshold.y, switch1.u2)
  connect(smoothMax.y, lessEqualThreshold.u)
  connect(senT_supply.T, switch1.u1)
  connect(temRet.y, switch1.u3)
  connect(switch1.y, source.T_in)
  connect(source.ports[1], vol.ports[1])
  connect(vol.ports[2], senT_return.port_a)
end VarTSupplyDpFixedTempDifferenceBypass;


Generic pipe model for DHC applications

within AixLib.Fluid.DistrictHeatingCooling.Pipes;
model DHCPipe "Generic pipe model for DHC applications"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(show_T=true);

  parameter Boolean use_zeta=false
    "= true HydraulicResistance is implemented, zeta value has to be given next"

  parameter Boolean use_soil=false
    "= true 3 cylindric heat transfers are implemented, representing the soil around the pipe, otherwise direct heat throughzeta value has to be given next"

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

  parameter Modelica.Units.SI.Length dh=sqrt(4*m_flow_nominal/rho_default/
      v_nominal/Modelica.Constants.pi)
    "Hydraulic diameter (assuming a round cross section area)"

  parameter Modelica.Units.SI.Velocity v_nominal=1.5
    "Velocity at m_flow_nominal (used to compute default value for hydraulic diameter dh)"

  parameter Real ReC=4000
    "Reynolds number where transition to turbulent starts";

  parameter Modelica.Units.SI.Height roughness=2.5e-5
    "Average height of surface asperities (default: smooth steel pipe)"

  parameter Modelica.Units.SI.Length length "Pipe length"

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

  parameter Modelica.Units.SI.MassFlowRate m_flow_small=1E-4*abs(m_flow_nominal)
    "Small mass flow rate for regularization of zero flow"

  parameter Modelica.Units.SI.Length dIns
    "Thickness of pipe insulation, used to compute R"

  parameter Modelica.Units.SI.ThermalConductivity kIns
    "Heat conductivity of pipe insulation, used to compute R"

  parameter Modelica.Units.SI.SpecificHeatCapacity cPip=2300
    "Specific heat of pipe wall material. 2300 for PE, 500 for steel"

  parameter Modelica.Units.SI.Density rhoPip(displayUnit="kg/m3") = 930
    "Density of pipe wall material. 930 for PE, 8000 for steel"

  parameter Modelica.Units.SI.Length thickness=0.0035 "Pipe wall thickness"

  parameter Modelica.Units.SI.Temperature T_start_in(start=Medium.T_default)=
    Medium.T_default "Initialization temperature at pipe inlet"
  parameter Modelica.Units.SI.Temperature T_start_out(start=Medium.T_default)=
       T_start_in "Initialization temperature at pipe outlet"
  parameter Boolean initDelay(start=false) = false
    "Initialize delay for a constant mass flow rate if true, otherwise start from 0"
  parameter Modelica.Units.SI.MassFlowRate m_flow_start=0
    "Initial value of mass flow rate through pipe"

  parameter Real R(unit="(m.K)/W")=1/(kIns*2*Modelica.Constants.pi/
    Modelica.Math.log((dh/2 + dIns)/(dh/2)))
    "Thermal resistance per unit length from fluid to boundary temperature"

  parameter Real fac= 1.0
    "Factor to take into account flow resistance of bends etc., fac=dp_nominal/dpStraightPipe_nominal"

  parameter Real sum_zetas=0
    "Sum of all zeta values. Takes into account additional pressure drops due to bends/valves/etc. if use_zeta"

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

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

  //Ground/Soil: values for sandy soil with clay content based on "SIMULATIONSMODELL
  //"ERDWÄRMEKOLLEKTOR" zur wärmetechnischen Beurteilung von Wärmequellen,
  //Wärmesenken und Wärme-/Kältespeichern" by Bernd Glück --> move to docu

  parameter Modelica.Units.SI.Density rho_soi=1630 "Density of material/soil"

  parameter Modelica.Units.SI.SpecificHeatCapacity c=1046
    "Specific heat capacity of material/soil"
  parameter Modelica.Units.SI.Length thickness_soi=0.6
    "thickness of soil layer for heat loss calulcation"

  parameter Modelica.Units.SI.ThermalConductivity lambda=1.5
    "Heat conductivity of material/soil"

  final parameter Modelica.Units.SI.Length d_in=dh + 2*thickness
    "Inner diameter of pipe"

  final parameter Modelica.Units.SI.Temperature T0=289.15 "Initial temperature"

  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort
    "Heat transfer to or from surroundings (heat loss from pipe results in a positive heat flow)"

  replaceable AixLib.Fluid.FixedResistances.BaseClasses.PlugFlowCore pipCor(
    redeclare final package Medium = Medium,
    final dh=dh,
    final v_nominal=v_nominal,
    final length=length,
    final C=C,
    final R=R,
    final m_flow_small=m_flow_small,
    final m_flow_nominal=m_flow_nominal,
    final T_start_in=T_start_in,
    final T_start_out=T_start_out,
    final m_flow_start=m_flow_start,
    final initDelay=initDelay,
    final from_dp=from_dp,
    final fac=if not use_zeta then fac else 1.0,
    final ReC=ReC,
    final thickness=thickness,
    final roughness=roughness,
    final allowFlowReversal=allowFlowReversal,
    final homotopyInitialization=homotopyInitialization,
    final linearized=linearized) constrainedby Interfaces.PartialTwoPort(
    redeclare package Medium = Medium,
    dh=dh,
    v_nominal=v_nominal,
    length=length,
    C=C,
    R=R,
    m_flow_small=m_flow_small,
    m_flow_nominal=m_flow_nominal,
    T_start_in=T_start_in,
    T_start_out=T_start_out,
    m_flow_start=m_flow_start,
    initDelay=initDelay,
    from_dp=from_dp,
    fac=if not use_zeta then fac else 1.0,
    ReC=ReC,
    thickness=thickness,
    roughness=roughness,
    allowFlowReversal=allowFlowReversal,
    homotopyInitialization=homotopyInitialization,
    linearized=linearized) "Describing the pipe behavior"

  // In the volume, below, we scale down V and use
  // mSenFac. Otherwise, for air, we would get very large volumes
  // which affect the delay of water vapor and contaminants.
  // See also AixLib.Fluid.FixedResistances.Validation.PlugFlowPipes.TransportWaterAir
  // for why mSenFac is 10 and not 1000, as this gives more reasonable
  // temperature step response
  AixLib.Fluid.MixingVolumes.MixingVolume vol(
    redeclare final package Medium = Medium,
    final m_flow_nominal=m_flow_nominal,
    final V=if rho_default > 500 then VEqu else VEqu/1000,
    final nPorts=2,
    final T_start=T_start_out,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final mSenFac = if rho_default > 500 then 1 else 10)
    "Control volume connected to ports_b. Represents equivalent pipe wall thermal capacity."

  AixLib.Utilities.HeatTransfer.CylindricHeatTransfer cylHeaTra1(
    final energyDynamics=energyDynamics,
    final rho=rho_soi,
    final c=c,
    final d_in=dh + 2*thickness,
    final d_out=d_in + thickness_soi/3,
    final length=length,
    final lambda=lambda,
    T0=283.15) if use_soil

  AixLib.Utilities.HeatTransfer.CylindricHeatTransfer cylHeaTra2(
    final energyDynamics=energyDynamics,
    final rho=rho_soi,
    final c=c,
    final d_in=dh + 2*thickness + thickness_soi/3,
    final d_out=d_in + 2*thickness_soi/3,
    final length=length,
    final lambda=lambda,
    T0=283.15) if use_soil
  AixLib.Utilities.HeatTransfer.CylindricHeatTransfer cylHeaTra3(
    final energyDynamics=energyDynamics,
    final rho=rho_soi,
    final c=c,
    final d_in=dh + 2*thickness + 2*thickness_soi/3,
    final d_out=d_in + thickness_soi,
    final length=length,
    final lambda=lambda,
    T0=283.15) if use_soil

protected
  parameter Modelica.Units.SI.HeatCapacity CPip=length*((dh + 2*thickness)^2 -
      dh^2)*Modelica.Constants.pi/4*cPip*rhoPip "Heat capacity of pipe wall";

  final parameter Modelica.Units.SI.Volume VEqu=CPip/(rho_default*cp_default)
    "Equivalent water volume to represent pipe wall thermal inertia";

  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default) "Default medium state";

  parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(state=sta_default)
    "Heat capacity of medium";

  parameter Real C(unit="J/(K.m)")=
    rho_default*Modelica.Constants.pi*(dh/2)^2*cp_default
    "Thermal capacity per unit length of water in pipe";

  parameter Modelica.Units.SI.Density rho_default=Medium.density_pTX(
      p=Medium.p_default,
      T=Medium.T_default,
      X=Medium.X_default)
    "Default density (e.g., rho_liquidWater = 995, rho_air = 1.2)"

  Modelica.Units.SI.Velocity v_med "Velocity of the medium in the pipe";

  Modelica.Units.SI.Heat Q_los(start=0.0, fixed=true)
    "Integrated heat loss of the pipe";
  Modelica.Units.SI.Heat Q_gai(start=0.0, fixed=true)
    "Integrated heat gain of the pipe";

public
  FixedResistances.HydraulicResistance hydRes(
    diameter=dh,
    m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium,
    zeta=sum_zetas,
    allowFlowReversal=allowFlowReversal,
    from_dp=from_dp,
    homotopyInitialization=homotopyInitialization,
    linearized=linearized,
    m_flow_start=m_flow_start) if use_zeta
  Modelica.Thermal.HeatTransfer.Components.ThermalCollector thePasThr(final m=1)
    if not use_soil "Thermal pass through if there is no soil activated"
  Interfaces.PassThroughMedium pasThrMed(redeclare package Medium = Medium)
                                                 if not use_zeta
equation
  //calculation of the flow velocity of water in the pipes
  v_med = (4 * port_a.m_flow) / (Modelica.Constants.pi * rho_default * dh * dh);

  //calculation of heat losses and heat gains of pipe
  der(Q_los) = min(0, pipCor.heatPort.Q_flow);
  der(Q_gai) = max(0, pipCor.heatPort.Q_flow);

  connect(vol.ports[2], port_b)

  connect(pipCor.port_b, vol.ports[1])
  connect(pipCor.heatPort, cylHeaTra1.port_a)
  connect(cylHeaTra1.port_b, cylHeaTra2.port_a)
  connect(cylHeaTra2.port_b, cylHeaTra3.port_a)
  connect(cylHeaTra3.port_b, heatPort)
  connect(pipCor.heatPort, thePasThr.port_a[1])
  connect(thePasThr.port_b, heatPort)
  connect(port_a, hydRes.port_a)
  connect(hydRes.port_b, pipCor.port_a)
  connect(port_a, port_a)
  connect(port_a, pasThrMed.port_a)
  connect(pasThrMed.port_b, pipCor.port_a)
end DHCPipe;


Models for DHC systems' pipe networks

within AixLib.Fluid.DistrictHeatingCooling;
package Pipes "Models for DHC systems' pipe networks"
end Pipes;


within AixLib.Fluid.DistrictHeatingCooling.Pipes;
model PlugFlowPipeEmbedded
  "Embedded pipe model using spatialDistribution for temperature delay"

  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(show_T=true);

  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  parameter Boolean use_zeta=false
    "= true HydraulicResistance is implemented, zeta value has to be given next"

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

  parameter Modelica.Units.SI.Length dh=sqrt(4*m_flow_nominal/rho_default/
      v_nominal/Modelica.Constants.pi)
    "Hydraulic diameter (assuming a round cross section area)"

  parameter Modelica.Units.SI.Velocity v_nominal=1.5
    "Velocity at m_flow_nominal (used to compute default value for hydraulic diameter dh)"

  parameter Real ReC=4000
    "Reynolds number where transition to turbulent starts";

  parameter Modelica.Units.SI.Height roughness=2.5e-5
    "Average height of surface asperities (default: smooth steel pipe)"

  parameter Modelica.Units.SI.Length length "Pipe length"

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

  parameter Modelica.Units.SI.MassFlowRate m_flow_small=1E-4*abs(m_flow_nominal)
    "Small mass flow rate for regularization of zero flow"

  parameter Modelica.Units.SI.Length dIns
    "Thickness of pipe insulation, used to compute R"

  parameter Modelica.Units.SI.ThermalConductivity kIns
    "Heat conductivity of pipe insulation, used to compute R"

  parameter Modelica.Units.SI.SpecificHeatCapacity cPip=2300
    "Specific heat of pipe wall material. 2300 for PE, 500 for steel"

  parameter Modelica.Units.SI.Density rhoPip(displayUnit="kg/m3") = 930
    "Density of pipe wall material. 930 for PE, 8000 for steel"

  parameter Modelica.Units.SI.Length thickness=0.0035 "Pipe wall thickness"

  parameter Modelica.Units.SI.Temperature T_start_in(start=Medium.T_default)=
    Medium.T_default "Initialization temperature at pipe inlet"
  parameter Modelica.Units.SI.Temperature T_start_out(start=Medium.T_default)=
       T_start_in "Initialization temperature at pipe outlet"
  parameter Boolean initDelay(start=false) = false
    "Initialize delay for a constant mass flow rate if true, otherwise start from 0"
  parameter Modelica.Units.SI.MassFlowRate m_flow_start=0
    "Initial value of mass flow rate through pipe"

  parameter Real R(unit="(m.K)/W")=1/(kIns*2*Modelica.Constants.pi/
    Modelica.Math.log((dh/2 + dIns)/(dh/2)))
    "Thermal resistance per unit length from fluid to boundary temperature"

  parameter Real fac=1
    "Factor to take into account flow resistance of bends etc., fac=dp_nominal/dpStraightPipe_nominal"

  parameter Real sum_zetas=0
    "Sum of all zeta values. Takes into account additional pressure drops due to bends/valves/etc."

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

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

  //Ground/Soil: values for sandy soil with clay content based on "SIMULATIONSMODELL
  //"ERDWÄRMEKOLLEKTOR" zur wärmetechnischen Beurteilung von Wärmequellen,
  //Wärmesenken und Wärme-/Kältespeichern" by Bernd Glück

  parameter Modelica.Units.SI.Density rho_soi=1630 "Density of material/soil"

  parameter Modelica.Units.SI.SpecificHeatCapacity c=1046
    "Specific heat capacity of material/soil"
  parameter Modelica.Units.SI.Length thickness_soi=0.6
    "thickness of soil layer for heat loss calulcation"

  parameter Modelica.Units.SI.ThermalConductivity lambda=1.5
    "Heat conductivity of material/soil"

  final parameter Modelica.Units.SI.Length d_in=dh + 2*thickness
    "Inner diameter of pipe"
  final parameter Integer nParallel = 1 "Number of identical parallel pipes"
  final parameter Modelica.Units.SI.Temperature T0=289.15 "Initial temperature"

  Modelica.Units.SI.Velocity v_med "Velocity of the medium in the pipe";

  AixLib.Fluid.DistrictHeatingCooling.Pipes.PlugFlowPipeZeta plugFlowPipeZeta(
    redeclare final package Medium = Medium,
    final dh=dh,
    final v_nominal=v_nominal,
    final ReC=ReC,
    final roughness=roughness,
    final length=length,
    final m_flow_nominal=m_flow_nominal,
    final dIns=dIns,
    final kIns=kIns,
    final cPip=cPip,
    final rhoPip=rhoPip,
    final thickness=thickness,
    final R=R,
    final fac=fac,
    final sum_zetas=sum_zetas,
    final use_zeta=true)

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort
    "Heat transfer to or from surroundings (heat loss from pipe results in a positive heat flow)"

  AixLib.Utilities.HeatTransfer.CylindricHeatTransfer cylindricHeatTransfer_1(
    final energyDynamics=energyDynamics,
    final rho=rho_soi,
    final c=c,
    final d_in=dh + 2*thickness,
    final d_out=d_in + thickness_soi/3,
    final length=length,
    final lambda=lambda,
    T0=283.15)

  AixLib.Utilities.HeatTransfer.CylindricHeatTransfer cylindricHeatTransfer_2(
    final energyDynamics=energyDynamics,
    final rho=rho_soi,
    final c=c,
    final d_in=dh + 2*thickness + thickness_soi/3,
    final d_out=d_in + 2*thickness_soi/3,
    final length=length,
    final lambda=lambda,
    T0=283.15)
  AixLib.Utilities.HeatTransfer.CylindricHeatTransfer cylindricHeatTransfer_3(
    final energyDynamics=energyDynamics,
    final rho=rho_soi,
    final c=c,
    final d_in=dh + 2*thickness + 2*thickness_soi/3,
    final d_out=d_in + thickness_soi,
    final length=length,
    final lambda=lambda,
    T0=283.15)

protected
  parameter Modelica.Units.SI.HeatCapacity CPip=length*((dh + 2*thickness)^2 -
      dh^2)*Modelica.Constants.pi/4*cPip*rhoPip "Heat capacity of pipe wall";

  final parameter Modelica.Units.SI.Volume VEqu=CPip/(rho_default*cp_default)
    "Equivalent medium volume to represent pipe wall thermal inertia";

  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default) "Default medium state";

  parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(state=sta_default)
    "Heat capacity of medium";

  parameter Real C(unit="J/(K.m)")=
    rho_default*Modelica.Constants.pi*(dh/2)^2*cp_default
    "Thermal capacity per unit length of medium in pipe";

  parameter Modelica.Units.SI.Density rho_default=Medium.density_pTX(
      p=Medium.p_default,
      T=Medium.T_default,
      X=Medium.X_default)
    "Default density (e.g., rho_liquidWater = 995, rho_air = 1.2)"

equation
 //calculation of the flow velocity of medium in the pipes
 v_med = (4 * port_a.m_flow) / (Modelica.Constants.pi * rho_default * dh * dh);

  connect(plugFlowPipeZeta.heatPort, cylindricHeatTransfer_1.port_a)
  connect(cylindricHeatTransfer_1.port_b, cylindricHeatTransfer_2.port_a)
  connect(cylindricHeatTransfer_2.port_b,cylindricHeatTransfer_3. port_a)
  connect(cylindricHeatTransfer_3.port_b, heatPort)
  connect(port_a, plugFlowPipeZeta.port_a)
  connect(plugFlowPipeZeta.port_b, port_b)
end PlugFlowPipeEmbedded;