Medium model

within AixLib.Utilities.Psychrometrics.Examples;
model TWetBul_TDryBulXi
  extends Modelica.Icons.Example;

 package Medium = AixLib.Media.Air "Medium model"

    Modelica.Blocks.Sources.Ramp TDryBul(
    height=10,
    duration=1,
    offset=273.15 + 30) "Dry bulb temperature"
  AixLib.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBul(         redeclare
      package Medium = Medium) "Model for wet bulb temperature"
  Modelica.Blocks.Sources.Constant p(k=101325) "Pressure"
    Modelica.Blocks.Sources.Ramp XHum(
    duration=1,
    height=(0.0133 - 0.0175),
    offset=0.0175) "Humidity concentration"
  AixLib.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBulApp(redeclare package
              Medium = Medium, approximateWetBulb=true)
    "Model for wet bulb temperature"
equation
  connect(p.y, wetBul.p)
  connect(XHum.y, wetBul.Xi[1])
  connect(TDryBul.y, wetBul.TDryBul)
  connect(p.y, wetBulApp.p)
  connect(XHum.y, wetBulApp.Xi[1])
  connect(TDryBul.y, wetBulApp.TDryBul)
end TWetBul_TDryBulXi;


Package with psychrometric functions

within AixLib.Utilities.Psychrometrics;
package Functions "Package with psychrometric functions"
  extends Modelica.Icons.Package;
end Functions;


Function to compute the water vapor partial pressure for a given dew point temperature of moist air. Dew point temperature calculation for moist air above freezing temperature.

within AixLib.Utilities.Psychrometrics.Functions;
function pW_TDewPoi
  "Function to compute the water vapor partial pressure for a given dew point temperature of moist air"
  extends Modelica.Icons.Function;
  input Modelica.Units.SI.Temperature T(min=100) "Dew point temperature";
  output Modelica.Units.SI.Pressure p_w(displayUnit="Pa", min=100)
    "Water vapor partial pressure";
protected
  constant Real C8=-5.800226E3;
  constant Real C9=1.3914993E0;
  constant Real C10=-4.8640239E-2;
  constant Real C11=4.1764768E-5;
  constant Real C12=-1.4452093E-8;
  constant Real C13=6.5459673E0;

algorithm
  p_w := Modelica.Math.exp(C8/T + C9 + T*(C10 + T*(C11 + T*C12)) + C13*
    Modelica.Math.log(T));
end pW_TDewPoi;


Function to compute the water vapor partial pressure for a given dew point temperature of moist air. Dew point temperature calculation for moist air between 0 degC and 30 degC.

within AixLib.Utilities.Psychrometrics.Functions;
function pW_TDewPoi_amb
  "Function to compute the water vapor partial pressure for a given dew point temperature of moist air"
  extends Modelica.Icons.Function;

  input Modelica.Units.SI.Temperature T "Dew point temperature";
  output Modelica.Units.SI.Pressure p_w(displayUnit="Pa", min=100)
    "Water vapor partial pressure";
protected
  constant Modelica.Units.SI.Temperature T1=283.15 "First support point";
  constant Modelica.Units.SI.Temperature T2=293.15 "Second support point";
  constant Modelica.Units.SI.Pressure p1=1227.97 "First support point";
  constant Modelica.Units.SI.Pressure p2=2338.76 "Second support point";

  constant Real a1=(Modelica.Math.log(p2) - Modelica.Math.log(p1)*T2/T1)/(1 -
      T2/T1);
  constant Real a2(unit="1/K")=(Modelica.Math.log(p1) - a1)/T1;

algorithm
  p_w := Modelica.Math.exp(a1 + a2*T);
end pW_TDewPoi_amb;


Water vapor pressure for given humidity ratio. Function to compute the water vapor partial pressure for a given humidity ratio.

within AixLib.Utilities.Psychrometrics.Functions;
function pW_X "Water vapor pressure for given humidity ratio"
  extends Modelica.Icons.Function;
  input Modelica.Units.SI.MassFraction X_w(
    min=0,
    max=0.99999,
    nominal=0.01) "Species concentration at dry bulb temperature";
  input Modelica.Units.SI.Pressure p=101325 "Total pressure";
  output Modelica.Units.SI.Pressure p_w(displayUnit="Pa")
    "Water vapor pressure";

protected
  Modelica.Units.SI.MassFraction x_w(nominal=0.01)
    "Water mass fraction per mass of dry air";
algorithm
  x_w := X_w/(1 - X_w);
  p_w := p*x_w/(0.62198 + x_w);
end pW_X;


within AixLib.Utilities.Psychrometrics.Functions;
function TDewPoi_pW
  "Function to compute the water vapor partial pressure for a given dew point temperature of moist air"
  extends Modelica.Icons.Function;

  input Modelica.Units.SI.Pressure p_w(displayUnit="Pa", min=200)
    "Water vapor partial pressure";
  output Modelica.Units.SI.Temperature T "Dew point temperature";

protected
  function pW_TDewPoi_inversion
    "Internal function to solve eps=f(NTU, Z) for NTU for cross flow unmixed"
    extends Modelica.Math.Nonlinear.Interfaces.partialScalarFunction;

    input Modelica.Units.SI.Pressure p_w(displayUnit="Pa", min=200)
      "Water vapor partial pressure";

  algorithm
    y :=AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi(T=u) - p_w;
  end pW_TDewPoi_inversion;

algorithm
  T := Modelica.Math.Nonlinear.solveOneNonlinearEquation(
      f=function pW_TDewPoi_inversion(p_w=p_w),
      u_min=200,
      u_max=400);
end TDewPoi_pW;


Function to compute the dew point temperature of moist air for a given water vapor partial pressure. Dew point temperature calculation for moist air between 0°C and 30°C
with partial pressure of water vapor as an input.

within AixLib.Utilities.Psychrometrics.Functions;
function TDewPoi_pW_amb
  "Function to compute the dew point temperature of moist air for a given water vapor partial pressure"
  extends Modelica.Icons.Function;

  input Modelica.Units.SI.Pressure p_w(displayUnit="Pa", min=100)
    "Water vapor partial pressure";
  output Modelica.Units.SI.Temperature T "Dew point temperature";
protected
  constant Modelica.Units.SI.Temperature T1=283.15 "First support point";
  constant Modelica.Units.SI.Temperature T2=293.15 "Second support point";
  constant Modelica.Units.SI.Pressure p1=1227.97 "First support point";
  constant Modelica.Units.SI.Pressure p2=2338.76 "Second support point";

  constant Real a1=(Modelica.Math.log(p2) - Modelica.Math.log(p1)*T2/T1)/(1 -
      T2/T1);
  constant Real a2(unit="1/K")=(Modelica.Math.log(p1) - a1)/T1;

algorithm
  T := (Modelica.Math.log(p_w) - a1)/a2;
end TDewPoi_pW_amb;


Mass fraction for given water vapor pressure. Function to compute the mass fraction for a given water vapor partial pressure.

within AixLib.Utilities.Psychrometrics.Functions;
function X_pW "Mass fraction for given water vapor pressure"
  extends Modelica.Icons.Function;
  input Modelica.Units.SI.Pressure p_w(
    displayUnit="Pa",
    min=0.003,
    nominal=1000) "Water vapor pressure";
  input Modelica.Units.SI.Pressure p=101325 "Total pressure";
  output Modelica.Units.SI.MassFraction X_w(
    min=0,
    max=1,
    nominal=0.01) "Species concentration at dry bulb temperature";

protected
  Modelica.Units.SI.MassFraction x_w(nominal=0.01)
    "Water mass fraction per mass of dry air";
algorithm
  x_w := 0.62198*p_w/(p - p_w);
  X_w := x_w/(1 + x_w);
end X_pW;


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


Model to test correct implementation of derivative. This example checks whether the function derivative
is implemented correctly. If the derivative implementation
is not correct, the model will stop with an assert statement.

within AixLib.Utilities.Psychrometrics.Functions.BaseClasses.Examples;
model DewPointTemperatureDerivativeCheck
  "Model to test correct implementation of derivative"
  extends Modelica.Icons.Example;

  Real y "Function value";
  Real y_comp "Function value for comparison";
  Real err "Integration error";
  Modelica.Units.SI.Temperature T "Temperature";
initial equation
  y=y_comp;
equation
  T =  273.15 + 50 + time^3 * 50;
  y=AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi(T=T);
  der(y)=der(y_comp);
  err = y-y_comp;
  assert(abs(err)/max(1, abs(y)) < 1E-2, "Derivative implementation has an error or solver tolerance is too low.");
end DewPointTemperatureDerivativeCheck;


within AixLib.Utilities.Psychrometrics.Functions.BaseClasses.Examples;
model DewPointTemperatureDerivativeCheck_amb
  "Model to test correct implementation of derivative"
  extends Modelica.Icons.Example;

  Real y "Function value";
  Real y_comp "Function value for comparison";
  Real err "Integration error";
  Modelica.Units.SI.Temperature T "Temperature";
initial equation
  y=y_comp;
equation
  T =  273.15 + 50 + time^3 * 50;
  y=AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi_amb(T=T);
  der(y)=der(y_comp);
  err = y-y_comp;
  assert(abs(err)/max(1, abs(y)) < 1E-2, "Derivative implementation has an error or solver tolerance is too low.");
end DewPointTemperatureDerivativeCheck_amb;


within AixLib.Utilities.Psychrometrics.Functions.BaseClasses.Examples;
model InverseDewPointTemperatureDerivativeCheck_amb
  "Model to test correct implementation of derivative"
  extends Modelica.Icons.Example;

  Real y "Function value";
  Real y_comp "Function value for comparison";
  Real err(unit="K", displayUnit="K") "Integration error";
  Modelica.Units.SI.Pressure p_w "Water vapor partial pressure";
initial equation
  y=y_comp;
equation
  p_w =  611 + (7383-661)/2 + (7383-661)/2 * time^3;
  y = AixLib.Utilities.Psychrometrics.Functions.TDewPoi_pW_amb(p_w=p_w);
  der(y) = der(y_comp);
  err = y-y_comp;
  assert(abs(err) < 1E-2, "Derivative implementation has an error or solver tolerance is too low.");
end InverseDewPointTemperatureDerivativeCheck_amb;


within AixLib.Utilities.Psychrometrics.Functions.BaseClasses;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within AixLib.Utilities.Psychrometrics.Functions.BaseClasses.Examples;
model SaturationPressureDerivativeCheck
  "Model to test correct implementation of derivative"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Temperature TMin=190 "Temperature";
  parameter Modelica.Units.SI.Temperature TMax=373.16 "Temperature";

  Real y "Function value";
  Real y_comp "Function value for comparison";
  Real err "Integration error";
  Modelica.Units.SI.Temperature T "Temperature";
initial equation
  y=y_comp;
equation
  T =  TMin + (TMax-TMin)/2 + (TMax-TMin)/2*time^3;
  y=AixLib.Utilities.Psychrometrics.Functions.saturationPressure(TSat=T);
  der(y)=der(y_comp);
  err = y-y_comp;
  assert(abs(err)/max(1, abs(y)) < 1E-2, "Derivative implementation has an error or solver tolerance is too low.");
end SaturationPressureDerivativeCheck;


within AixLib.Utilities.Psychrometrics.Functions.BaseClasses.Examples;
model WaterVaporPressureDerivativeCheck
  "Model to test correct implementation of derivative"
  extends Modelica.Icons.Example;

  Real y "Function value";
  Real y_comp "Function value for comparison";
  Real err "Integration error";
  Modelica.Units.SI.MassFraction X_w
    "Water vapor mass fraction at dry bulb temperature";
  Modelica.Units.SI.Pressure p "Total pressure";

initial equation
  y=y_comp;
equation
  X_w =  1.001 + 0.999/2*time^3;
  p = 101325+300*time^3;

  y=AixLib.Utilities.Psychrometrics.Functions.pW_X(X_w=X_w, p=p);
  der(y)=der(y_comp);
  err = y-y_comp;
  assert(abs(err)/max(1, abs(y)) < 1E-2, "Derivative implementation has an error or solver tolerance is too low.");
end WaterVaporPressureDerivativeCheck;


Model to test density_pTX. Model that tests the implementation of

AixLib.Utilities.Psychrometrics.Functions.density_pTX.

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model Density_pTX "Model to test density_pTX"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Pressure p=101325 "Pressure of the medium";
  Modelica.Units.SI.Temperature T "Temperature";
  Modelica.Units.SI.MassFraction X_w "Mass fraction";
  Modelica.Units.SI.Density d "Mass density";
  constant Real convT(unit="1/s") = 0.999 "Conversion factor";
  constant Real convX(unit="1/s") = 0.02 "Conversion factor";
equation
  if time < 0.5 then
    X_w = convX*time;
    T = 293.15;
  else
    X_w = 0.5*convX;
    T = 293.15+convT*(time-0.5)*10;
  end if;
  d = AixLib.Utilities.Psychrometrics.Functions.density_pTX(p=p, T=T, X_w=X_w);
end Density_pTX;


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


Model to test phi_pTX.

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model phi_pTX "Model to test phi_pTX"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Pressure p=101325 "Pressure of the medium";
  Modelica.Units.SI.Temperature T "Temperature";
  Modelica.Units.SI.MassFraction X_w "Mass fraction";
  Real phi "Relative humidity";
  Real X_inv "Inverse computation of mass fraction";
  constant Real convT(unit="1/s") = 0.999 "Conversion factor";
  constant Real convX(unit="1/s") = 0.02 "Conversion factor";
equation
  if time < 0.5 then
    X_w = convX*time;
    T = 293.15;
  else
    X_w = 0.5*convX;
    T = 293.15+convT*(time-0.5)*10;
  end if;
  phi = AixLib.Utilities.Psychrometrics.Functions.phi_pTX(p=p, T=T, X_w=X_w);
  X_inv=AixLib.Utilities.Psychrometrics.Functions.X_pTphi(p=p, T=T, phi=phi);
  assert(abs(X_inv-X_w) < 1e-5,
    "Inconsistency in the inverse implementation of phi_pTX: X_pTphi");
end phi_pTX;


Model to test pW_TDewPoi and its inverse function.

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model pW_TDewPoi "Model to test pW_TDewPoi and its inverse function"
  extends Modelica.Icons.Example;

  Modelica.Units.SI.Temperature T "Dew point temperature";
  Modelica.Units.SI.Temperature TInv "Dew point temperature";
  Modelica.Units.SI.TemperatureDifference dT "Difference between temperatures";
  Modelica.Units.SI.Pressure p_w "Water vapor partial pressure";
  constant Real conv(unit="K/s") = 100 "Conversion factor";
equation
  T = conv*time + 273.15;
  p_w = AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi(T);
  TInv = AixLib.Utilities.Psychrometrics.Functions.TDewPoi_pW(p_w);
  dT = T - TInv;
  assert(abs(dT) < 10E-12, "Error in function implementation.");
end pW_TDewPoi;


Model to test the approximation for pW_TDewPoi and its inverse function.

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model pW_TDewPoi_comparison
  "Model to test the approximation for pW_TDewPoi and its inverse function"
  extends Modelica.Icons.Example;

  Modelica.Units.SI.Temperature T "Dew point temperature";
  Modelica.Units.SI.Temperature TInv "Dew point temperature";
  Modelica.Units.SI.TemperatureDifference dT "Difference between temperatures";
  Modelica.Units.SI.Pressure p_w_ashrae
    "Water vapor partial pressure according to the ASHRAE handbook";
  Modelica.Units.SI.Pressure p_w "Water vapor partial pressure";

  constant Real conv(unit="K/s") = 30 "Conversion factor";
  Real r_p "Ratio of the two approximations";
equation
  T = conv*time + 273.15;
  p_w_ashrae = AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi(T);
  p_w = AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi_amb(T);
  r_p = p_w_ashrae/p_w;
  p_w = AixLib.Utilities.Psychrometrics.Functions.pW_TDewPoi_amb(TInv);
  dT = T - TInv;
  assert(abs(dT) < 10E-12, "Error in function implementation.");
end pW_TDewPoi_comparison;


Model to test pW_X and its inverse function.

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model pW_X "Model to test pW_X and its inverse function"
  extends Modelica.Icons.Example;

  Modelica.Units.SI.MassFraction X "Mass fraction";
  Modelica.Units.SI.MassFraction XInv "Mass fraction";
  Modelica.Units.SI.MassFraction dX "Difference between mass fraction";
  Modelica.Units.SI.Pressure p_w "Water vapor partial pressure";
  constant Real conv(unit="1/s") = 0.999 "Conversion factor";
equation
  X = conv*time;
  p_w = AixLib.Utilities.Psychrometrics.Functions.pW_X(X);
  XInv = AixLib.Utilities.Psychrometrics.Functions.X_pW(p_w);
  dX = X - XInv;
  assert(abs(dX) < 10E-12, "Error in function implementation.");
end pW_X;


Model to test the saturationPressure function. This example computes the saturation pressure of water.

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model SaturationPressure "Model to test the saturationPressure function"
  extends Modelica.Icons.Example;
  parameter Modelica.Units.SI.Temperature TMin=190 "Temperature";
  parameter Modelica.Units.SI.Temperature TMax=373.16 "Temperature";
  Modelica.Units.SI.Temperature T "Temperature";
  Modelica.Units.SI.AbsolutePressure pSat "Saturation pressure";
  constant Real conv(unit="1/s") = 1 "Conversion factor";
equation
  T = TMin + conv*time * (TMax-TMin);
  pSat = AixLib.Utilities.Psychrometrics.Functions.saturationPressure(T);
end SaturationPressure;


Model to test X_pSatpphi function

within AixLib.Utilities.Psychrometrics.Functions.Examples;
model X_pSatpphi "Model to test X_pSatpphi function"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Air "Medium model"
  parameter Modelica.Units.SI.Temperature T=293.15 "Temperature";
  parameter Modelica.Units.SI.Pressure p=101325 "Pressure of the fluid";

  Modelica.Units.SI.AbsolutePressure pSat "Saturation pressure";
  Real phi(min=0, max=1) "Relative humidity";
  Modelica.Units.SI.MassFraction X_w(
    min=0,
    max=1,
    nominal=0.01) "Water vapor concentration per total mass of air";

  constant Real conv(unit="1/s") = 1 "Conversion factor";
equation
  phi = time*conv;
  pSat = Medium.saturationPressure(T);
  X_w = AixLib.Utilities.Psychrometrics.Functions.X_pSatpphi(pSat=pSat, p=p, phi=phi);
end X_pSatpphi;


\. Overview

within AixLib.Utilities.Sensors;
model EnergyMeter
  "\"Integrates power [W] that is connected to input connector\""
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"
  Modelica.Blocks.Interfaces.RealInput p(unit="W")
  Modelica.Units.NonSI.Energy_kWh q_kWh;
  Modelica.Units.SI.Energy q_joule(
    stateSelect=StateSelect.avoid,
    start=0.0,
    fixed=energyDynamics == Modelica.Fluid.Types.Dynamics.FixedInitial);
equation
  der(q_joule) = p;
  q_kWh =Modelica.Units.Conversions.to_kWh(q_joule);
end EnergyMeter;


Fuel counter monitoring fuel consumption in a boiler model.

within AixLib.Utilities.Sensors;
model FuelCounter "Fuel counter monitoring fuel consumption in a boiler model"
  extends Modelica.Icons.RectangularSensor;
  Modelica.Units.NonSI.Energy_kWh counter;
  Modelica.Blocks.Interfaces.RealInput fuel_in
equation
  der(counter) = fuel_in / 3600 / 1000;
end FuelCounter;


Sensors

within AixLib.Utilities;
package Sensors "Sensors"
  extends Modelica.Icons.Package;
end Sensors;


Start reference temperature of medium

within AixLib.Utilities.Sensors.Examples;
model ExergyMeters

  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Temperature T_start=323.15
    "Start reference temperature of medium";

  parameter Integer n = 10 "Number of layers";

  parameter Modelica.Units.SI.Mass mass=1000 "Mass of one layer";

  package Medium = AixLib.Media.Water "Medium in the sensor"

  Modelica.Blocks.Sources.Sine pulse(
    each f=1/3600,
    each offset=3000,
    each amplitude=3000) "Sine wave to vary heat generation and demand"
  AixLib.Utilities.Sensors.ExergyMeter.StoredExergyMeter exergyStorageMeterMedium(
    redeclare package Medium = Medium,
    T_ref_start=T_ref.k,
    T_start=T_start,
    exergyContent_start=1.70904e+08,
    n=n,
    mass=mass)
    "Outputs the exergy content and rate of change of the considered storage"
  Modelica.Blocks.Sources.Constant T_ref(k=273.15) "Reference temperature"
  Modelica.Blocks.Sources.Constant p_ref(k=101300) "Reference pressure"
  Modelica.Blocks.Sources.Constant X_ref[1](k={1}) "Reference composition"
  inner Modelica.Fluid.System system(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
                                     "Basic parameters"
  AixLib.Utilities.Sensors.ExergyMeter.HeatExergyMeter exHeatSec
    "Exergy content of the heat flux on secondary side"
  AixLib.Fluid.Movers.FlowControlled_m_flow pumpPrim(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true,
    redeclare package Medium = Medium,
    T_start=T_start,
    m_flow_nominal=0.5,
    m_flow_small=0.001,
    dp_nominal=10000 + sum(bufferStorageHeatingcoils.heatingCoil1.pipe.res.dp_nominal))
  AixLib.Fluid.Storage.StorageDetailed bufferStorageHeatingcoils(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    redeclare package MediumHC1 = Medium,
    redeclare package MediumHC2 = Medium,
    m1_flow_nominal=0.5,
    m2_flow_nominal=0.5,
    mHC1_flow_nominal=0.5,
    useHeatingCoil1=true,
    useHeatingCoil2=false,
    useHeatingRod=false,
    TStart=fill(T_start, 10),
    redeclare DataBase.Storage.Generic_New_2000l data(
      hTank=1,
      hUpperPortDemand=0.95,
      hUpperPortSupply=0.95,
      hHC1Up=0.95,
      dTank=2,
      sIns=0.2,
      lambdaIns=0.075,
      hTS2=0.95),
    hConHC1=300,
    TStartWall=T_start,
    TStartIns=T_start,
    redeclare package Medium = Medium,
    hConIn=100,
    hConOut=10,
    n=10)
         "Storage tank"
  AixLib.Fluid.FixedResistances.PressureDrop      pipePrim(
    redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    dp_nominal=10000) "Main resistance in primary circuit"
  AixLib.Utilities.Sensors.ExergyMeter.FlowExergyMeter exPrimIn(redeclare
      package Medium =                                                                     Medium)
    "Exergy content of medium flow entering the storage on primary side"
  AixLib.Utilities.Sensors.ExergyMeter.FlowExergyMeter exPrimOut(redeclare
      package Medium =                                                                      Medium)
    "Exergy content of medium flow exiting the storage on primary side"
  Modelica.Fluid.Vessels.ClosedVolume heater(redeclare package Medium = Medium,
    nPorts=2,
    use_HeatTransfer=true,
    use_portsData=false,
    T_start=T_start,
    V(displayUnit="l") = 0.001)
                     "Volume to heat up the medium"
  AixLib.Fluid.Movers.FlowControlled_m_flow pumpSec(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true,
    redeclare package Medium = Medium,
    T_start=T_start,
    m_flow_nominal=0.5,
    m_flow_small=0.001,
    dp_nominal=10000)   "Pump in secondary circuit"
  AixLib.Fluid.FixedResistances.PressureDrop      pipeSec(
    redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    dp_nominal=10000) "Main resistance in secondary circuit"
  Modelica.Fluid.Vessels.ClosedVolume consumer(
    redeclare package Medium = Medium,
    use_HeatTransfer=true,
    use_portsData=false,
    nPorts=2,
    T_start=T_start,
    V(displayUnit="l") = 0.001)
                     "Volume to cool down the medium"
  AixLib.Utilities.Sensors.ExergyMeter.FlowExergyMeter exSecOut(redeclare
      package Medium =                                                                     Medium)
    "Exergy content of medium flow entering the storage on secondary side"
  AixLib.Utilities.Sensors.ExergyMeter.FlowExergyMeter exSecIn(redeclare
      package Medium =                                                                    Medium)
    "Exergy content of medium flow exiting the storage on secondary side"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow consumerHeatFlow
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heaterHeatFlow
  Modelica.Blocks.Math.Gain gain(k=-1)
    "Negative sign to switch the direction of the heat flux"
  AixLib.Utilities.Sensors.ExergyMeter.HeatExergyMeter exHeatPrim
    "Exergy content of the heat flux on primary side"
  Modelica.Blocks.Sources.RealExpression storageTemperatures[n](y=
        bufferStorageHeatingcoils.layer[:].heatPort.T)
    "Outputs the temperatures of the single storage layers"
  Modelica.Blocks.Sources.Constant pumpMassFlow(k=0.5)
  AixLib.Fluid.Sources.Boundary_pT expansionVesselSec(
    redeclare package Medium = Medium,
    nPorts=1,
    p=p_ref.k)
              "Expansion vessel in secondary circuit"
  AixLib.Fluid.Sources.Boundary_pT expansionVesselPrim(
    redeclare package Medium = Medium,
    nPorts=1,
    p=p_ref.k)
              "Expansion vessel in primary circuit"
  Modelica.Blocks.Math.Sum calcExergyDestructionLoss_1(nin=7, k={1,1,-1,-1,-1,-1,
        -1})
    "Calculate the sum of exergy destruction and loss, calculated from enthalpy flows"
  Modelica.Blocks.Math.Sum calcExergyDestructionLoss_2(nin=5, k={1,-1,-1,-1,-1})
    "Calculate the sum of exergy destruction and loss, calculated from heat flows"
  Modelica.Blocks.Math.Gain gain1(
                                 k=-1)
    "Negative sign to switch the direction of the exergy flow"
  AixLib.Utilities.Sensors.ExergyMeter.StoredExergyMeter exergyStorageMeterConsumer(
    redeclare package Medium = Medium,
    T_ref_start=T_ref.k,
    T_start=T_start,
    n=1,
    exergyContent_start=17074.08599,
    mass=1)
    "Outputs the exergy content and rate of change of the consumer volume"
  AixLib.Utilities.Sensors.ExergyMeter.StoredExergyMeter exergyStorageMeterHeater(
    redeclare package Medium = Medium,
    T_ref_start=T_ref.k,
    T_start=T_start,
    n=1,
    exergyContent_start=17074.08599,
    mass=1)
    "Outputs the exergy content and rate of change of the heater volume"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor heaterTemperature
    "Measure the temperature in the heater volume "
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor consumerTemperature
    "Measure the temperature in the consumer volume "
equation
  connect(T_ref.y, exergyStorageMeterMedium.T_ref)
  connect(p_ref.y, exergyStorageMeterMedium.p_ref)
  connect(X_ref.y, exergyStorageMeterMedium.X_ref)
  connect(p_ref.y, exergyStorageMeterMedium.p)
  connect(X_ref.y, exergyStorageMeterMedium.X)

  connect(pumpPrim.port_b, exPrimIn.port_a)
  connect(exPrimOut.port_b, pipePrim.port_a)
  connect(pipePrim.port_b, heater.ports[1])
  connect(heater.ports[2], pumpPrim.port_a)
  connect(exSecOut.port_b, pumpSec.port_a)
  connect(exSecIn.port_a, pipeSec.port_b)
  connect(pipeSec.port_a, consumer.ports[1])
  connect(pumpSec.port_b, consumer.ports[2])
  connect(consumerHeatFlow.Q_flow, gain.y)
  connect(pulse.y, gain.u)
  connect(pulse.y, heaterHeatFlow.Q_flow)
  connect(consumerHeatFlow.port, exHeatSec.port_a)
  connect(exHeatSec.port_b, consumer.heatPort)
  connect(heaterHeatFlow.port, exHeatPrim.port_a)
  connect(exHeatPrim.port_b, heater.heatPort)
  connect(T_ref.y, exHeatPrim.T_ref)
  connect(T_ref.y, exHeatSec.T_ref)
  connect(storageTemperatures.y, exergyStorageMeterMedium.T)
  connect(T_ref.y, exPrimOut.T_ref)
  connect(T_ref.y, exPrimIn.T_ref)
  connect(T_ref.y, exSecIn.T_ref)
  connect(T_ref.y, exSecOut.T_ref)
  connect(p_ref.y, exPrimOut.p_ref)
  connect(p_ref.y, exPrimIn.p_ref)
  connect(p_ref.y, exSecOut.p_ref)
  connect(p_ref.y, exSecIn.p_ref)
  connect(X_ref.y, exSecIn.X_ref)
  connect(X_ref.y, exSecOut.X_ref)
  connect(X_ref.y, exPrimOut.X_ref)
  connect(X_ref.y, exPrimIn.X_ref)
  connect(pumpMassFlow.y, pumpPrim.m_flow_in)
  connect(pumpMassFlow.y, pumpSec.m_flow_in)
  connect(expansionVesselSec.ports[1], pumpSec.port_a)
  connect(expansionVesselPrim.ports[1], pumpPrim.port_a)
  connect(exPrimIn.exergyFlow, calcExergyDestructionLoss_1.u[1])
  connect(exSecIn.exergyFlow, calcExergyDestructionLoss_1.u[2])
  connect(exPrimOut.exergyFlow, calcExergyDestructionLoss_1.u[3])
  connect(exSecOut.exergyFlow, calcExergyDestructionLoss_1.u[4])
  connect(exergyStorageMeterMedium.exergyChangeRate,
    calcExergyDestructionLoss_1.u[5])
  connect(exHeatPrim.exergyFlow, calcExergyDestructionLoss_2.u[1])
  connect(exergyStorageMeterMedium.exergyChangeRate,
    calcExergyDestructionLoss_2.u[3])
  connect(exHeatSec.exergyFlow, gain1.u)
  connect(gain1.y, calcExergyDestructionLoss_2.u[2])
  connect(p_ref.y, exergyStorageMeterConsumer.p_ref)
  connect(p_ref.y, exergyStorageMeterConsumer.p)
  connect(X_ref.y, exergyStorageMeterConsumer.X_ref)
  connect(X_ref.y, exergyStorageMeterConsumer.X)
  connect(T_ref.y, exergyStorageMeterConsumer.T_ref)
  connect(exergyStorageMeterConsumer.exergyChangeRate,
    calcExergyDestructionLoss_2.u[4])
  connect(X_ref.y, exergyStorageMeterHeater.X_ref)
  connect(X_ref.y, exergyStorageMeterHeater.X)
  connect(p_ref.y, exergyStorageMeterHeater.p_ref)
  connect(p_ref.y, exergyStorageMeterHeater.p)
  connect(T_ref.y, exergyStorageMeterHeater.T_ref)
  connect(exergyStorageMeterHeater.exergyChangeRate,
    calcExergyDestructionLoss_2.u[5])
  connect(exergyStorageMeterConsumer.exergyChangeRate,
    calcExergyDestructionLoss_1.u[6])
  connect(exergyStorageMeterHeater.exergyChangeRate,
    calcExergyDestructionLoss_1.u[7])
  connect(heaterTemperature.port, heater.heatPort)
  connect(heaterTemperature.T, exergyStorageMeterHeater.T[1])
  connect(consumerTemperature.port, consumer.heatPort)
  connect(consumerTemperature.T, exergyStorageMeterConsumer.T[1])
  connect(exPrimIn.port_b, bufferStorageHeatingcoils.portHC1In)
  connect(bufferStorageHeatingcoils.portHC1Out, exPrimOut.port_a)
  connect(exSecIn.port_b, bufferStorageHeatingcoils.fluidportBottom2)
  connect(bufferStorageHeatingcoils.fluidportTop2, exSecOut.port_a)
end ExergyMeters;


MassFraction

within AixLib.Utilities.Sensors.ExergyMeter;
model FlowExergyMeter

  extends AixLib.Fluid.Interfaces.PartialTwoPort;
  extends Modelica.Icons.RoundSensor;

  Modelica.Blocks.Interfaces.RealInput X_ref[Medium.nX](
  each final quantity="MassFraction", each final unit="1", each min=0, each max=1)
    "Reference composition"
  Modelica.Fluid.Sources.Boundary_pT referenceEnvironment(
    redeclare replaceable package Medium = Medium,
    use_p_in=true,
    nPorts=2,
    use_T_in=true,
    use_X_in=true) "The reference environment used for exergy calculations"
  Modelica.Fluid.Sensors.MassFlowRate massFlowRate(
  redeclare package Medium = Medium)
    "Mass flow rate of the medium flow used in exergy calculations"
  Modelica.Fluid.Sensors.SpecificEntropy specificEntropy(
  redeclare package Medium =
               Medium)
    "Specific entropy of the medium flow used in exergy calculations"
  Modelica.Fluid.Sensors.SpecificEnthalpy specificEnthalpy(redeclare package Medium =
               Medium)
    "Specific enthalpy of the medium flow used in exergy calculations"

  Modelica.Blocks.Interfaces.RealInput T_ref(final unit="K", displayUnit="degC",
    final quantity="ThermodynamicTemperature", min=0) "Reference temperature"
  Modelica.Blocks.Interfaces.RealInput p_ref(final quantity="Pressure",
  final unit="Pa", displayUnit="bar", min=0)
    "Reference pressure"
  Modelica.Fluid.Sensors.SpecificEnthalpy specificEnthalpyRef(redeclare package
                                                                                Medium =
               Medium) "Specific enthalpy of the reference environment"
  Modelica.Fluid.Sensors.SpecificEntropy specificEntropy_ref(redeclare package Medium =
               Medium) "Specific entropy of the reference environment"
  Modelica.Blocks.Interfaces.RealOutput exergyFlow(final quantity="Power",
      final unit="W") "Exergy content of the medium flow"
  Modelica.Blocks.Math.Add enthalpyDifference(k1=-1)
    "Difference between enthalpy content of medium flow and reference
    environment"
  Modelica.Blocks.Math.Add entropyDifference(k1=-1)
    "Difference between entropy content of medium flow and reference
    environment"
  Modelica.Blocks.Math.Product productWithReferenceTemperature
    "Calculate the product of reference temperature and entropy"
  Modelica.Blocks.Math.Add specificExergy(k1=-1)
    "Specific exergy as difference of enthalpy and product of reference
    temperature and entropy"
  Modelica.Blocks.Math.Product exergyFlowRate
    "Exergy flow rate as product of specific exergy and mass flow rate"
equation
  connect(specificEnthalpyRef.port, referenceEnvironment.ports[1])
  connect(referenceEnvironment.ports[2], specificEntropy_ref.port)
  connect(massFlowRate.port_b,specificEntropy. port)
  connect(specificEnthalpy.h_out, enthalpyDifference.u2)
  connect(specificEnthalpyRef.h_out, enthalpyDifference.u1)
  connect(T_ref, productWithReferenceTemperature.u2)
  connect(enthalpyDifference.y, specificExergy.u2)
  connect(port_a, specificEnthalpy.port)
  connect(specificEntropy.port, port_b)
  connect(specificEntropy_ref.s, entropyDifference.u1)
  connect(productWithReferenceTemperature.y, specificExergy.u1)
  connect(massFlowRate.m_flow, exergyFlowRate.u2)
  connect(exergyFlowRate.y, exergyFlow)
  connect(specificEntropy.s, entropyDifference.u2)
  connect(entropyDifference.y, productWithReferenceTemperature.u1)
  connect(specificExergy.y, exergyFlowRate.u1)
  connect(X_ref, referenceEnvironment.X_in)
  connect(p_ref, referenceEnvironment.p_in)
  connect(T_ref, referenceEnvironment.T_in)
  connect(specificEnthalpy.port, massFlowRate.port_a)
end FlowExergyMeter;


Set to 'true' in order to connect the meter to a convective heat port. Overview

within AixLib.Utilities.Sensors.ExergyMeter;
model HeatExergyMeter

  extends Modelica.Icons.RoundSensor;

  parameter Boolean useConvectiveHeatFlow=true
    "Set to 'true' in order to connect the meter to a convective heat port";
  parameter Boolean useRadiativeHeatFlow=false
    "Set to 'true' in order to connect the meter to a radiative heat port";
  parameter Boolean solarRadiation=false
    "Set to 'true' in order to connect the meter to a solar radiation port"
  parameter Modelica.Units.SI.ThermodynamicTemperature sunTemperature=6000
    "Temperature assumption for the solar radiation";
  Modelica.Blocks.Math.Add add(k2=-1) "Subtract the temperature ratio from one"
  Modelica.Blocks.Sources.Constant const(k=1) "Constant one in Carnot factor"
  Modelica.Blocks.Math.Division division
    "Ratio of reference temperature and temperature"
  Modelica.Blocks.Math.Product product
    "Product of heat flow rate and Carnot factor"
  Modelica.Blocks.Nonlinear.Limiter limiter(uMax=400, uMin=1)
    "Limits the temperature of the heat flux"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_a
  if useConvectiveHeatFlow
    "Entering convective heat"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port_b
  if useConvectiveHeatFlow
    "Outgoing convective heat"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heatFlowSensor
  if useConvectiveHeatFlow
    "Heat flow sensor used for convective heat"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temperatureSensorConv
  if useConvectiveHeatFlow
    "Temperature sensor for convective heat"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a radPort_a
  if useRadiativeHeatFlow
    "Entering radiation"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b radPort_b
  if useRadiativeHeatFlow
    "Outgoing radiation"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heatFlowSensorRad
  if useRadiativeHeatFlow "Heat flow sensor used for radiative heat"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temperatureSensorRad
  if useRadiativeHeatFlow
    "Temperature sensor for radiative heat"

  Modelica.Blocks.Interfaces.RealInput T_ref(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature",
    min=0) "Reference temperature"
  Modelica.Blocks.Interfaces.RealOutput exergyFlow(final quantity="Power",
      final unit="W") "Exergy content of the heat flux"
equation
  connect(const.y, add.u1)
  connect(division.y, add.u2)
  connect(add.y, product.u2)
  connect(limiter.y, division.u2)

  if useConvectiveHeatFlow then
    connect(temperatureSensorConv.T, limiter.u);
    connect(heatFlowSensor.Q_flow, product.u1);
    connect(port_a, heatFlowSensor.port_a);
    connect(heatFlowSensor.port_b, port_b);
    connect(port_a, temperatureSensorConv.port);

  end if;

  if useRadiativeHeatFlow then

    if solarRadiation then
      limiter.u = sunTemperature;
    else
      connect(temperatureSensorRad.T, limiter.u);
    end if;

    connect(heatFlowSensorRad.Q_flow, product.u1);
    connect(temperatureSensorRad.port, radPort_a);
    connect(heatFlowSensorRad.port_a, radPort_a);
    connect(heatFlowSensorRad.port_b, radPort_b);
  end if;

  connect(T_ref, division.u1)
  connect(product.y, exergyFlow)
end HeatExergyMeter;


<span style=\

within AixLib.Utilities.Sensors;
package ExergyMeter
end ExergyMeter;


Medium in the sensor

within AixLib.Utilities.Sensors.ExergyMeter;
model StoredExergyMeter

    extends Modelica.Icons.RoundSensor;

  replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium in the sensor"

  parameter Integer n=1 "Number of identical volumes";

  parameter Modelica.Units.SI.Mass mass=100 "mass of each layer";
  parameter Modelica.Units.SI.Temperature T_start=323.15
    "Start reference temperature of medium"
  parameter Modelica.Units.SI.Temperature T_ref_start=273.15
    "Start reference temperature"
  parameter Modelica.Units.SI.Energy exergyContent_start=1e+05
    "Start exergy content"

  Modelica.Fluid.Sensors.SpecificEntropy specificEntropy[n](redeclare package Medium =
               Medium)
    "Specific entropy of the medium used in exergy calculations"
  Modelica.Fluid.Sensors.SpecificEnthalpy specificEnthalpy[n](redeclare package
                                                                                Medium =
               Medium)
    "Specific enthalpy of the medium used in exergy calculations"

  Modelica.Blocks.Interfaces.RealInput T_ref(final unit="K", displayUnit="degC",
    final quantity="ThermodynamicTemperature", min=0)
    "Reference temperature for exergy calculations in K"
  Modelica.Blocks.Interfaces.RealInput p_ref(
  final quantity="Pressure", final unit="Pa", displayUnit="bar", min=0)
    "Reference pressure"
  Modelica.Fluid.Sensors.SpecificEnthalpy specificEnthalpyRef[n](redeclare
      package                                                                      Medium =
                       Medium) "Specific enthalpy of the reference environment"
  Modelica.Fluid.Sensors.SpecificEntropy specificEntropyRef[n](redeclare
      package                                                                    Medium =
                       Medium) "Specific enthalpy of the reference environment"
  Modelica.Blocks.Interfaces.RealOutput exergyChangeRate(final quantity="Power",
      final unit="W")
    "Rate of change of the exergy content of the considered storage"
  Modelica.Fluid.Sources.Boundary_pT referenceEnvironment[n](
    redeclare package Medium = Medium,
    each use_p_in=true,
    each nPorts=2,
    each use_T_in=true,
    each use_X_in=true)
    "The reference environment used for exergy calculations"
  Modelica.Fluid.Sources.Boundary_pT boundary[n](
    redeclare package Medium = Medium,
    each use_p_in=true,
    each use_T_in=true,
    each nPorts=2,
    each use_X_in=true)
    "Used for calculating the thermodynamic states of the considered medium"

  Modelica.Blocks.Interfaces.RealInput T[n](
    each final unit="K",
    each displayUnit="degC",
    each final quantity="ThermodynamicTemperature",
    each min=0) "Actual temperature"
  Modelica.Blocks.Interfaces.RealInput p(
    final quantity="Pressure",
    final unit="Pa",
    displayUnit="bar",
    min=0) "Actual pressure"
  Modelica.Blocks.Math.Sum enthalpySum(nin=n)
    "Sum up the enthalpy differences for all layers"
  Modelica.Blocks.Math.Gain multiplyMassEnthalpy(k=mass)
    "Multiply mass and specific enthalpy"
  Modelica.Blocks.Math.Add add[n](each k1=-1)
    "Difference between actual and reference enthalpy"
  Modelica.Blocks.Math.Add add1[n](each k1=-1)
    "Difference between actual and reference entropy"
  Modelica.Blocks.Math.Sum entropySum(nin=n)
    "Sum up the entropy differences for all layers"
  Modelica.Blocks.Math.Add differenceExergyContent(each k1=-1)
    "Difference between enthalpy and product of reference temperature and
    entropy"
  Modelica.Blocks.Continuous.Derivative derivative(
    x_start=exergyContent_start,
    initType=Modelica.Blocks.Types.Init.InitialState,
    T=10)
    "Derivative to calculate the rate of change of the exergy content of the
    storage"
  Modelica.Blocks.Interfaces.RealOutput exergyContent(
    start=exergyContent_start,
    final quantity="Energy",
    final unit="J") "Exergy content of the considered storage"
  Modelica.Blocks.Math.Product productTemperatureEntropy
    "Product of reference temperature and entropy difference"
  Modelica.Blocks.Math.Gain multiplyMassEntropy(k=mass)
    "Multiply mass and specific entropy"
  Modelica.Blocks.Interfaces.RealInput X_ref[Medium.nX](
  each final quantity="MassFraction", each final unit="1", each min=0, each max=1)
    "Reference composition"
  Modelica.Blocks.Interfaces.RealInput X[Medium.nX](
    each final quantity="MassFraction",
    each final unit="1",
    each min=0,
    each max=1) "Actual composition"
equation

  for i in 1:n loop
    connect(p, boundary[i].p_in)
    connect(T_ref, referenceEnvironment[i].T_in)
    connect(p_ref, referenceEnvironment[i].p_in)
    connect(X, boundary[i].X_in)
    connect(X_ref, referenceEnvironment[i].X_in)

  end for;

  connect(specificEnthalpy[:].port, boundary[:].ports[1])
  connect(specificEntropy[:].port, boundary[:].ports[2])
  connect(specificEnthalpyRef.h_out, add.u1)
  connect(specificEnthalpy.h_out, add.u2)
  connect(add.y, enthalpySum.u)
  connect(enthalpySum.y, multiplyMassEnthalpy.u)
  connect(specificEntropyRef.s, add1.u1)
  connect(specificEntropy.s, add1.u2)
  connect(add1.y, entropySum.u)
  connect(derivative.y,exergyChangeRate)
  connect(specificEnthalpyRef[:].port, referenceEnvironment[:].ports[1])
  connect(specificEntropyRef[:].port, referenceEnvironment[:].ports[2])
  connect(entropySum.y, multiplyMassEntropy.u)
  connect(multiplyMassEntropy.y, productTemperatureEntropy.u1)
  connect(T_ref, productTemperatureEntropy.u2)
  connect(derivative.u, differenceExergyContent.y)
  connect(multiplyMassEnthalpy.y, differenceExergyContent.u2)
  connect(productTemperatureEntropy.y, differenceExergyContent.u1)
  connect(differenceExergyContent.y, exergyContent)
  connect(T, boundary.T_in)
end StoredExergyMeter;


Default ambient pressure.

within AixLib.Utilities.Sources;
model BaseParameters
  parameter Modelica.Units.SI.AbsolutePressure p_ambient=101325
    "Default ambient pressure"
  parameter Modelica.Units.SI.Temperature T_ambient=293.15
    "Default ambient temperature"
  parameter Modelica.Units.SI.Acceleration g=9.81 "Gravity"
  parameter Modelica.Units.SI.DynamicViscosity mu_Water=1e-3
    "Dynamic viscosity of water"
  parameter Modelica.Units.SI.Density rho_Water=995.586 "Density of the fluid"
  parameter Modelica.Units.SI.SpecificHeatCapacity cp_Water=4184
    "Specific heat capacity of water"
  parameter Modelica.Units.SI.ThermalConductivity lambda_Water=0.6
    "Thermal conductivity of water"
  parameter Modelica.Units.SI.MolarMass M_Steam=0.01801 "Molar Mass of Steam"
  parameter Modelica.Units.SI.SpecificEnthalpy r_Steam=2500000
    "Specific enthalpy of vaporisation for water/steam"
  parameter Modelica.Units.SI.SpecificHeatCapacity cp_Steam=1868
    "Specific heat capacity of Steam"
  parameter Modelica.Units.SI.MolarMass M_Air=0.02897 "Molar Mass of Dry Air"
  parameter Modelica.Units.SI.SpecificHeatCapacity cp_Air=1005
    "Specific heat capacity of Dry Air"
  parameter Modelica.Units.SI.Temperature T_ref=273.15
    "Reference temperature at zero enthalpy"
  parameter Modelica.Units.SI.Temperature T0=T_ambient "Initial temperature"
  parameter Boolean calcMFlow = true "Calculate m_flow from p"
end BaseParameters;


Computes the hour of day taking the second of year as input.

within AixLib.Utilities.Sources;
model HourOfDay "Computes the hour of day taking the second of year as input"
  Modelica.Blocks.Sources.ContinuousClock clock(offset=-startTime)
  Modelica.Blocks.Interfaces.RealOutput SOY "second of the year"
  Modelica.Blocks.Interfaces.RealOutput H "passed hours"
  Modelica.Blocks.Interfaces.RealOutput D "passed days"
  Modelica.Blocks.Interfaces.RealOutput SOD "second of the day"
  Modelica.Blocks.Interfaces.RealOutput HOD "hour of the day"
  parameter Real startTime = 0
    "The start time of the simulation in reference to 1st of Jan. 0:00 o'clock";
equation
  // Modulo(SOY,SecondsInDay) gives the passed seconds of the current day.
  SOD = mod(SOY, 86400) "passed seconds of the current day";
  H = SOY / 3600 "passed hours";
  D = SOY / 86400 "passed days";
  // computes the hour of day from second of day.
  HOD = SOD / 3600;
  connect(clock.y, SOY)
end HourOfDay;


Module to establish if an element should opperate in night mode or not..

within AixLib.Utilities.Sources;
model NightMode
  "Module to establish if an element should opperate in night mode or not."
  import BaseLib = AixLib.Utilities;
  //Parameters
  parameter Real dayStart "hour when day operation starts";
  parameter Real dayEnd "hour when night operation starts";
  parameter Real startTime = 0
    "The start time of the simulation in reference to 1st of Jan. 0:00 o'clock";
  BaseLib.Sources.HourOfDay hourOfDay
  Modelica.Blocks.Logical.GreaterEqualThreshold greaterThreshold(threshold = dayStart)
  Modelica.Blocks.Logical.LessThreshold lessEqualThreshold(threshold = dayEnd)
  Modelica.Blocks.Logical.Nand IsNight
  Modelica.Blocks.Interfaces.BooleanOutput SwitchToNightMode
    "Connector of Boolean output signal"
equation
  connect(hourOfDay.HOD, lessEqualThreshold.u)
  connect(hourOfDay.HOD, greaterThreshold.u)
  connect(lessEqualThreshold.y, IsNight.u2)
  connect(greaterThreshold.y, IsNight.u1)
  connect(IsNight.y, SwitchToNightMode)
end NightMode;


Sources

within AixLib.Utilities;
package Sources "Sources"
  extends Modelica.Icons.Package;
end Sources;


variable radiation condition.

within AixLib.Utilities.Sources;
model PrescribedSolarRad "variable radiation condition"
  parameter Integer n=1 "number of output vector length";
  AixLib.Utilities.Interfaces.SolarRad_out solarRad_out[n]
  Modelica.Blocks.Interfaces.RealInput I[n] "radiation on surface (W/m2)"

  Modelica.Blocks.Interfaces.RealInput I_dir[n] "radiation on surface (W/m2)"
  Modelica.Blocks.Interfaces.RealInput I_diff[n] "radiation on surface (W/m2)"
  Modelica.Blocks.Interfaces.RealInput I_gr[n] "radiation on surface (W/m2)"
  Modelica.Blocks.Interfaces.RealInput AOI[n] "radiation on surface (W/m2)"
equation
  solarRad_out[:].I = I[:] "Radiant energy fluence rate";
  solarRad_out[:].I_dir = I_dir[:] "Radiant energy fluence rate";
  solarRad_out[:].I_diff = I_diff[:] "Radiant energy fluence rate";
  solarRad_out[:].I_gr = I_gr[:] "Radiant energy fluence rate";
  solarRad_out[:].AOI = AOI[:] "Radiant energy fluence rate";
end PrescribedSolarRad;


Zone definition.

within AixLib.Utilities.Sources.HeaterCooler;
model HeaterCoolerController

  parameter AixLib.DataBase.ThermalZones.ZoneBaseRecord zoneParam
    "Zone definition";
  BoundaryConditions.WeatherData.Bus weaBus
    "Weather data bus"
Modelica.Blocks.Sources.Constant TAirThresholdHeating(k=zoneParam.TThresholdHeater)
  "Threshold temperature below which heating is activated"
  Modelica.Blocks.Logical.Less less
  "check if outside temperature below threshold"
  Modelica.Blocks.Interfaces.BooleanOutput heaterActive
    "true if heater is active"
  Modelica.Blocks.Interfaces.BooleanOutput coolerActive
    "true if cooler is active"
  Modelica.Blocks.Logical.Greater greater
  "check if outside temperature above threshold"
Modelica.Blocks.Sources.Constant TAirThresholdCooling(k=zoneParam.TThresholdCooler)
  "Threshold temperature above which cooling is activated"
equation

  connect(TAirThresholdHeating.y, less.u2)
  connect(TAirThresholdCooling.y, greater.u2)
  connect(less.y, heaterActive)
  connect(weaBus.TDryBul, less.u1)
  connect(weaBus.TDryBul, greater.u1)
  connect(greater.y, coolerActive)
end HeaterCoolerController;


heater and cooler with variable setpoints.

within AixLib.Utilities.Sources.HeaterCooler;
model HeaterCoolerPI "heater and cooler with variable setpoints"
  extends AixLib.Utilities.Sources.HeaterCooler.PartialHeaterCoolerPI;
  parameter Boolean staOrDyn = true "Static or dynamic activation of heater"
  Modelica.Blocks.Interfaces.RealInput setPointCool(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") if ((recOrSep and zoneParam.CoolerOn) or (not recOrSep
     and Cooler_on))
  Modelica.Blocks.Interfaces.RealInput setPointHeat(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") if ((recOrSep and zoneParam.HeaterOn) or (not recOrSep
     and Heater_on))
  Modelica.Blocks.Sources.BooleanExpression booleanExpressionHeater(y=if not
        recOrSep then Heater_on else zoneParam.HeaterOn) if staOrDyn
  Modelica.Blocks.Sources.BooleanExpression booleanExpressionCooler(y=if not
        recOrSep then Cooler_on else zoneParam.CoolerOn) if staOrDyn
  Modelica.Blocks.Interfaces.BooleanInput heaterActive if not staOrDyn
    "Switches Controler on and off"
  Modelica.Blocks.Interfaces.BooleanInput coolerActive if not staOrDyn
    "Switches Controler on and off"
equation
  if staOrDyn then
    connect(booleanExpressionHeater.y, pITempHeat.onOff)
    connect(booleanExpressionCooler.y, pITempCool.onOff)
  else
    connect(heaterActive, pITempHeat.onOff)
    connect(pITempCool.onOff, coolerActive)
  end if;
  connect(setPointHeat, pITempHeat.setPoint)
  connect(setPointCool, pITempCool.setPoint)
end HeaterCoolerPI;


HeaterCooler

within AixLib.Utilities.Sources;
package HeaterCooler "HeaterCooler"
  extends Modelica.Icons.Package;

end HeaterCooler;


Heat port to thermal zone.

within AixLib.Utilities.Sources.HeaterCooler;
partial model PartialHeaterCooler
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatCoolRoom
    "Heat port to thermal zone"
end PartialHeaterCooler;


Activates the heater.

within AixLib.Utilities.Sources.HeaterCooler;
partial model PartialHeaterCoolerPI
  extends AixLib.Utilities.Sources.HeaterCooler.PartialHeaterCooler;
  parameter Boolean Heater_on = true "Activates the heater"
  parameter Boolean Cooler_on = true "Activates the cooler"
  parameter Real h_heater = 0 "Upper limit controller output of the heater"
  parameter Real l_heater = 0 "Lower limit controller output of the heater"
  parameter Real KR_heater = 1000 "Gain of the heating controller"
  parameter Modelica.Units.SI.Time TN_heater=1
    "Time constant of the heating controller"
  parameter Real h_cooler = 0 "Upper limit controller output of the cooler"
  parameter Real l_cooler = 0 "Lower limit controller output of the cooler"
  parameter Real KR_cooler = 1000 "Gain of the cooling controller"
  parameter Modelica.Units.SI.Time TN_cooler=1
    "Time constant of the cooling controller"
  parameter Boolean recOrSep = false "Use record or seperate parameters"
  parameter AixLib.DataBase.ThermalZones.ZoneBaseRecord zoneParam = AixLib.DataBase.ThermalZones.ZoneRecordDummy()
    "Zone definition"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow Cooling if ((
    recOrSep and zoneParam.CoolerOn) or (not recOrSep and Cooler_on))
  Controls.Continuous.PITemp
                 pITempCool(
    rangeSwitch=false,
    h=if not recOrSep then h_cooler else zoneParam.hCool,
    l=if not recOrSep then l_cooler else zoneParam.lCool,
    KR=if not recOrSep then KR_cooler else zoneParam.KRCool,
    TN=if not recOrSep then TN_cooler else zoneParam.TNCool) if ((recOrSep and
    zoneParam.CoolerOn) or (not recOrSep and Cooler_on))
    "PI control for cooler"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow Heating if ((
    recOrSep and zoneParam.HeaterOn) or (not recOrSep and Heater_on))
  Controls.Continuous.PITemp
                 pITempHeat(
    rangeSwitch=false,
    h=if not recOrSep then h_heater else zoneParam.hHeat,
    l=if not recOrSep then l_heater else zoneParam.lHeat,
    KR=if not recOrSep then KR_heater else zoneParam.KRHeat,
    TN=if not recOrSep then TN_heater else zoneParam.TNHeat) if ((recOrSep and
    zoneParam.HeaterOn) or (not recOrSep and Heater_on))
    "PI control for heater"
  Modelica.Blocks.Interfaces.RealOutput heatingPower(
   final quantity="HeatFlowRate",
   final unit="W") if ((recOrSep and zoneParam.HeaterOn) or (not recOrSep and
    Heater_on))    "Power for heating"
  Modelica.Blocks.Interfaces.RealOutput coolingPower(
   final quantity="HeatFlowRate",
   final unit="W") if ((recOrSep and zoneParam.CoolerOn) or (not recOrSep and
    Cooler_on))    "Power for cooling"
equation
  connect(Heating.port, heatCoolRoom)
  connect(pITempHeat.heatPort, heatCoolRoom)
  connect(pITempCool.y, Cooling.Q_flow)
  connect(Cooling.port, heatCoolRoom)
  connect(pITempCool.heatPort, heatCoolRoom)
  connect(Heating.Q_flow, pITempHeat.y)
  connect(Heating.Q_flow,heatingPower)
  connect(Cooling.Q_flow,coolingPower)
end PartialHeaterCoolerPI;


Altered CombiTable2D with the option to not extrapolate. As the standard model for two dimensional tables (Modelica.Blocks.Tables.CombiTable2D)
  does not allow extrapolation to be disabled, this models presents a
  work around. Using a simple limiter, extrapolation can be switched on
  or off.

within AixLib.Utilities.Tables;
model CombiTable2DExtra
  "Altered CombiTable2D with the option to not extrapolate"
  extends Modelica.Blocks.Interfaces.SI2SO;

  parameter Boolean extrapolation = true "False to hold last value";
  parameter Modelica.Blocks.Types.Smoothness smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments
    "Smoothness of table interpolation";
  parameter Real table[:,:]=[0,0]
    "Table matrix (grid u1 = first column, grid u2 = first row; e.g., table=[0,0;0,1])";
                                  //Set default value to [0,0] to obmit warnings
  Modelica.Blocks.Tables.CombiTable2Ds combiTable2D(
    final tableOnFile=false,
    final table=table,
    final smoothness=smoothness)
  Modelica.Blocks.Nonlinear.Limiter limiter1(final uMax=max(table[2:end, 1]),
      final uMin=min(table[2:end, 1])) if not extrapolation
  Modelica.Blocks.Nonlinear.Limiter limiter2(final uMax=max(table[1, 2:end]),
      final uMin=min(table[1, 2:end])) if not extrapolation
  Modelica.Blocks.Routing.RealPassThrough realPassThrough2 if extrapolation
  Modelica.Blocks.Routing.RealPassThrough realPassThrough1 if extrapolation
equation
  connect(combiTable2D.y, y)
  connect(u1, limiter1.u)
  connect(limiter1.y, combiTable2D.u1)
  connect(u2, limiter2.u)
  connect(limiter2.y, combiTable2D.u2)
  connect(u2, realPassThrough2.u)
  connect(realPassThrough2.y, combiTable2D.u2)
  connect(u1, realPassThrough1.u)
  connect(realPassThrough1.y, combiTable2D.u1)
end CombiTable2DExtra;


within AixLib.Utilities;
package Tables "Package containing table blocks altered from them in the standard library"
end Tables;


Computes the unix time stamp and calendar time from the simulation time. This blocks computes the unix time stamp, date and time
and the day of the week based on the Modelica
variable time.
As for the weather data reader

AixLib.BoundaryConditions.WeatherData.ReaderTMY3,
time=0 corresponds to January 1st at midnight
in the local time zone.
The computed outputs are thus also for the local time zone.
The year for which time=0 is determined by
the parameter zerTim.

within AixLib.Utilities.Time;
model CalendarTime
  "Computes the unix time stamp and calendar time from the simulation time"
  extends Modelica.Blocks.Icons.DiscreteBlock;
  parameter AixLib.Utilities.Time.Types.ZeroTime zerTim
    "Enumeration for choosing how reference time (time = 0) should be defined";
  parameter Integer yearRef(min=firstYear, max=lastYear) = 2016
    "Year when time = 0, used if zerTim=Custom"
  parameter Boolean outputUnixTimeStamp = false
    "= true, to output the unix time stamp (using GMT reference)"
  parameter Modelica.Units.SI.Time timZon(displayUnit="h") = 0
    "The local time zone, for computing the unix time stamp only"
  parameter Modelica.Units.SI.Time offset(displayUnit="h") = 0
    "Offset that is added to 'time', may be used for computing time in different time zones"

  Modelica.Blocks.Interfaces.RealOutput unixTimeStampLocal(final unit="s")
    "Unix time stamp at local time"
  Modelica.Blocks.Interfaces.RealOutput unixTimeStamp(final unit="s") = unixTimeStampLocal - timZon if outputUnixTimeStamp
    "Unix time stamp"
  discrete Modelica.Blocks.Interfaces.IntegerOutput year "Year"
  discrete Modelica.Blocks.Interfaces.IntegerOutput month "Month of the year"
  Modelica.Blocks.Interfaces.IntegerOutput day(fixed=false) "Day of the month"
  Modelica.Blocks.Interfaces.IntegerOutput hour(fixed=false) "Hour of the day"
  Modelica.Blocks.Interfaces.RealOutput minute "Minute of the hour"
  Modelica.Blocks.Interfaces.IntegerOutput weekDay(fixed=false)
    "Integer output representing week day (monday = 1, sunday = 7)"

protected
  final constant Real eps_time(final unit="s") = 1 "Small value for time";
  final constant Integer firstYear = 2010
    "First year that is supported, i.e. the first year in timeStampsNewYear[:]";
  final constant Integer lastYear = firstYear + size(timeStampsNewYear,1) - 1;
  constant Modelica.Units.SI.Time timeStampsNewYear[42]={1262304000.0,
    1293840000.0,1325376000.0,1356998400.0,1388534400.0,1420070400.0,
    1451606400.0,1483228800.0,1514764800.0,1546300800.0,1577836800.0,
    1609459200.0,1640995200.0,1672531200.0,1704067200.0,1735689600.0,
    1767225600.0,1798761600.0,1830297600.0,1861920000.0,1893456000.0,
    1924992000.0,1956528000.0,1988150400.0,2019686400.0,2051222400.0,
    2082758400.0,2114380800.0,2145916800.0,2177452800.0,2208988800.0,
    2240611200.0,2272147200.0,2303683200.0,2335219200.0,2366841600.0,
    2398377600.0,2429913600.0,2461449600.0,2493072000.0,2524608000.0,
    2556144000.0} "Epoch time stamps for new years day 2010 to 2051";
  constant Boolean isLeapYear[41] = {
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false, false, true, false,
    false}
    "List of leap years starting from firstYear (2010), up to and including 2050";
  final constant Integer dayInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    "Number of days in each month";
  parameter Modelica.Units.SI.Time timOff(fixed=false) "Time offset";
  // final parameters since the user may wrongly assume that this model shifts the
  // actual time of the simulation
  final constant Integer monthRef(min=1, max=12) = 1 "Month when time = 0"
  final constant Integer dayRef(min=1, max=31) = 1 "Day when time = 0"
  Integer daysSinceEpoch(fixed=false) "Number of days that passed since 1st of January 1970";
  discrete Integer yearIndex "Index of the current year in timeStampsNewYear";
  discrete Real epochLastMonth
    "Unix time stamp of the beginning of the current month";

  final parameter Modelica.Units.SI.Time hourSampleStart(fixed=false)
    "Time when the sampling every hour starts";
  final parameter Modelica.Units.SI.Time daySampleStart(fixed=false)
    "Time when the sampling every day starts";

  Boolean hourSampleTrigger "True, if hourly sample time instant";
  Boolean daySampleTrigger "True, if daily sample time instant";

  Boolean firstHourSampling(fixed=true, start=true)
    "=true if the hour is sampled the first time";
  Boolean firstDaySampling(fixed=true, start=true)
    "=true if the day is sampled the first time";
initial equation
  hourSampleStart = integer(time/3600)*3600 - offset;
  daySampleStart  = integer(time/(3600*24))*3600*24 - offset;

  hour = integer(floor(rem(unixTimeStampLocal,3600*24)/3600));
  daysSinceEpoch = integer(floor(unixTimeStampLocal/3600/24));

  day = integer(1+floor((unixTimeStampLocal-epochLastMonth)/3600/24));
  weekDay = integer(rem(4+daysSinceEpoch-1,7)+1);
initial algorithm
  // check if yearRef is in the valid range
  assert(not zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom
         or yearRef>=firstYear and yearRef<=lastYear,
    "The value you chose for yearRef (=" + String(yearRef) + ") is outside of
   the validity range of " + String(firstYear) + " to " + String(lastYear) + ".");

  // check if the day number exists for the chosen month and year
  assert(not zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom
         or dayInMonth[monthRef] + (if monthRef==2 and isLeapYear[yearRef-firstYear + 1] then 1 else 0) >=dayRef,
    "The day number you chose is larger than the number of days contained by the month you chose.");

  // compute the offset to be added to time based on the parameters specified by the user
  if zerTim == AixLib.Utilities.Time.Types.ZeroTime.UnixTimeStamp then
    timOff :=0;
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.UnixTimeStampGMT then
    timOff :=timZon;
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2010 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2010 then
      timOff :=timeStampsNewYear[1];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2011 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2011 then
      timOff :=timeStampsNewYear[2];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2012 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2012 then
      timOff :=timeStampsNewYear[3];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2013 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2013 then
      timOff :=timeStampsNewYear[4];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2014 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2014 then
      timOff :=timeStampsNewYear[5];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2015 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2015 then
      timOff :=timeStampsNewYear[6];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2016 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2016 then
      timOff :=timeStampsNewYear[7];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2017 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2017 then
      timOff :=timeStampsNewYear[8];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2018 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2018 then
      timOff :=timeStampsNewYear[9];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2019 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2019 then
      timOff :=timeStampsNewYear[10];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2020 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2020 then
      timOff :=timeStampsNewYear[11];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2021 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2021 then
      timOff :=timeStampsNewYear[12];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2022 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2022 then
      timOff :=timeStampsNewYear[13];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2023 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2023 then
      timOff :=timeStampsNewYear[14];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2024 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2024 then
      timOff := timeStampsNewYear[14];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2025 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2025 then
      timOff := timeStampsNewYear[15];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2026 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2026 then
      timOff := timeStampsNewYear[16];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2027 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2027 then
      timOff := timeStampsNewYear[17];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2028 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2028 then
      timOff := timeStampsNewYear[18];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2029 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2029 then
      timOff := timeStampsNewYear[19];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2030 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2030 then
      timOff := timeStampsNewYear[20];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2031 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2031 then
      timOff := timeStampsNewYear[21];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2032 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2032 then
      timOff := timeStampsNewYear[22];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2033 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2033 then
      timOff := timeStampsNewYear[23];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2034 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2034 then
      timOff := timeStampsNewYear[24];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2035 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2035 then
      timOff := timeStampsNewYear[25];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2036 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2036 then
      timOff := timeStampsNewYear[26];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2037 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2037 then
      timOff := timeStampsNewYear[27];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2038 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2038 then
      timOff := timeStampsNewYear[28];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2039 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2039 then
      timOff := timeStampsNewYear[29];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2040 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2040 then
      timOff := timeStampsNewYear[30];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2041 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2041 then
      timOff := timeStampsNewYear[31];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2042 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2042 then
      timOff := timeStampsNewYear[32];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2043 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2043 then
      timOff := timeStampsNewYear[33];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2044 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2044 then
      timOff := timeStampsNewYear[34];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2045 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2045 then
      timOff := timeStampsNewYear[35];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2046 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2046 then
      timOff := timeStampsNewYear[36];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2047 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2047 then
      timOff := timeStampsNewYear[37];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2048 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2048 then
      timOff := timeStampsNewYear[38];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2049 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2049 then
      timOff := timeStampsNewYear[39];
  elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.NY2050 or
    zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2050 then
      timOff := timeStampsNewYear[40];
  else
    timOff :=0;
    // this code should not be reachable
    assert(false, "No valid ZeroTime could be identified.
   This is a bug, please submit a bug report.");
  end if;

  // add additional offset when using a custom date and time
  if zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom then
    timOff :=timOff + ((dayRef - 1) + sum({dayInMonth[i] for i in 1:(monthRef - 1)})
     + (if monthRef > 2 and isLeapYear[yearRef - firstYear + 1] then 1 else 0))*3600*24;
  end if;

   // input data range checks at initial time
  assert(time + offset + timOff >= timeStampsNewYear[1],
    if zerTim == AixLib.Utilities.Time.Types.ZeroTime.UnixTimeStamp then
      "Could not initialize date in the CalendarTime block.
   You selected 1970 as the time=0 reference.
   Therefore the simulation startTime must be at least " + String(timeStampsNewYear[1]) + "."
    elseif zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom then
      if yearRef <firstYear then
        "Could not initialize date in the CalendarTime block.
   You selected a custom time=0 reference.
   The minimum value for yearRef is then " + String(firstYear) + " but your value is " + String(yearRef) + "."
      else
        "Could not initialize date in the CalendarTime block.
   You selected a custom time=0 reference.
   Possibly your startTime is too small."
      else
        "Could not initialize date in the CalendarTime block.
   Possibly your startTime is negative?");

  assert(time + offset + timOff < timeStampsNewYear[size(timeStampsNewYear,1)],
    if zerTim == AixLib.Utilities.Time.Types.ZeroTime.Custom and yearRef >= lastYear then
      "Could not initialize date in the CalendarTime block.
   You selected a custom time=0 reference.
   The maximum value for yearRef is then " + String(lastYear) +
   " but your value is " + String(yearRef) + "."
    else
       "Could not initialize date in the CalendarTime block.
       Possibly your startTime is too large.");

  // iterate to find the year at initialization
initial algorithm
  year :=0;
  for i in 1:size(timeStampsNewYear,1) loop
    // may be reformulated using break if JModelica fixes bug
    if unixTimeStampLocal < timeStampsNewYear[i]
      and (if i == 1 then true else unixTimeStampLocal >= timeStampsNewYear[i-1]) then
      yearIndex :=i - 1;
      year :=firstYear + i - 2;
    end if;
  end for;

  // iterate to find the month at initialization
  epochLastMonth := timeStampsNewYear[yearIndex];
  month:=13;
  for i in 1:12 loop
    if (unixTimeStampLocal-epochLastMonth)/3600/24 <
      (if i==2 and isLeapYear[yearIndex] then 1 + dayInMonth[i] else dayInMonth[i]) then
      // construction below avoids the need of a break, which bugs out JModelica
      month :=min(i,month);
    else
      epochLastMonth :=epochLastMonth + (if i == 2 and isLeapYear[yearIndex]
         then 1 + dayInMonth[i] else dayInMonth[i])*3600*24;
    end if;
  end for;

equation
  // compute unix time step based on found offset
  unixTimeStampLocal = time + offset + timOff;

  // compute other variables that can be computed without using when() statements
  hourSampleTrigger =sample(hourSampleStart, 3600);
  when hourSampleTrigger then
    if pre(firstHourSampling) then
      hour = integer(floor(rem(unixTimeStampLocal,3600*24)/3600));
    else
      hour = if (pre(hour) == 23) then 0 else (pre(hour) + 1);
    end if;
    firstHourSampling = false;
  end when;

  daySampleTrigger =sample(daySampleStart, 86400);
  when daySampleTrigger then
    if pre(firstDaySampling) then
      daysSinceEpoch = integer(floor(unixTimeStampLocal/3600/24));
      weekDay=integer(rem(4+daysSinceEpoch-1,7)+1);

    else
      daysSinceEpoch = pre(daysSinceEpoch) + 1;
      weekDay = if (pre(weekDay) == 7) then 1 else (pre(weekDay) + 1);
    end if;

    // update the year when passing the epoch time stamp of the next year
    if unixTimeStampLocal - timeStampsNewYear[pre(yearIndex)+1] > -eps_time then
      yearIndex=pre(yearIndex)+1;
      year = pre(year) + 1;
    else
      yearIndex = pre(yearIndex);
      year = pre(year);
    end if;
    assert(yearIndex<=size(timeStampsNewYear,1),
      "Index out of range for epoch vector: timeStampsNewYear needs to be extended beyond the year "
        + String(firstYear+size(timeStampsNewYear,1)));

    // update the month when passing the last day of the current month
    if unixTimeStampLocal - ( pre(epochLastMonth) + (if pre(month)==2 and isLeapYear[yearIndex] then 1 + dayInMonth[pre(month)] else dayInMonth[pre(month)])*3600*24)  > -eps_time then
      month = if pre(month) == 12 then 1 else pre(month) + 1;
      // Use floor(0.1 + ...) to avoid floating point errors when accumulating epochLastMonth.
      epochLastMonth = floor(0.1 + pre(epochLastMonth) +
        (if pre(month)==2 and isLeapYear[yearIndex]
          then 1 + dayInMonth[pre(month)] else dayInMonth[pre(month)])*3600*24);
    else
      month = pre(month);
      epochLastMonth = pre(epochLastMonth);
    end if;

    day = integer(1+floor((unixTimeStampLocal-epochLastMonth)/3600/24));

    firstDaySampling = false;
  end when;

  // using Real variables and operations for minutes since otherwise too many events are generated
  minute = (unixTimeStampLocal/60-daysSinceEpoch*60*24-hour*60);
end CalendarTime;


Set the output to true if the given daytime stamp is equal to current daytime. Using AixLib.Utilities.Time.CalendarTime,
  this model triggers a control if the current time is equal to a
  certain hour of the day and or day of the week.

within AixLib.Utilities.Time;
model DaytimeSwitch
  "Set the output to true if the given daytime stamp is equal to current daytime"
  parameter Boolean weekly=true
    "Switch between a daily or weekly trigger approach"

  parameter Integer weekDay = 1 "Day of the week"
  parameter Integer hourDay = 12
                                "Hour of the day";
  parameter AixLib.Utilities.Time.Types.ZeroTime zerTim
    "Enumeration for choosing how reference time (time = 0) should be defined";
  parameter Integer yearRef=2016 "Year when time = 0, used if zerTim=Custom";
  AixLib.Utilities.Time.CalendarTime calTim(zerTim=zerTim, yearRef=yearRef) "Used to get the unix time stamp and calendar time from the simulation time";

  Modelica.Blocks.Interfaces.BooleanOutput isDaytime "Output boolean if current time stamp matches the set parameters"

equation
  if weekly then
    isDaytime =(calTim.weekDay == weekDay and calTim.hour == hourDay); //Trigger every week
  else
    isDaytime =(calTim.hour == hourDay); //Trigger every day
  end if;
end DaytimeSwitch;


Model time. This component outputs the model time, which starts at the value at which the simulation starts.
For example, if a simulation starts at t=-1, then this block outputs first t=-1,
and its output is advanced at the same rate as the simulation time.

within AixLib.Utilities.Time;
block ModelTime "Model time"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Interfaces.RealOutput y "Model time"

equation
  y = time;
end ModelTime;


Package with models for time

within AixLib.Utilities;
package Time "Package with models for time"
  extends Modelica.Icons.Package;
end Time;


Example for the calendar time model. This model demonstrates the use of the

AixLib.Utilities.Time.CalendarTime
block.

within AixLib.Utilities.Time.Examples;
model CalendarTime "Example for the calendar time model"
  extends Modelica.Icons.Example;
  AixLib.Utilities.Time.CalendarTime calendarTime2016(
    zerTim=AixLib.Utilities.Time.Types.ZeroTime.NY2016)
    "Computes date and time assuming time=0 corresponds to new year 2016"

equation
end CalendarTime;


Test model for the ModelTime block. This model tests the implementation of
the block that outputs the model time.

within AixLib.Utilities.Time.Examples;
model ModelTime "Test model for the ModelTime block"
  extends Modelica.Icons.Example;
  AixLib.Utilities.Time.ModelTime modTim "Model time"
equation
end ModelTime;


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


Package with type definitions

within AixLib.Utilities.Time;
package Types "Package with type definitions"
 extends Modelica.Icons.TypesPackage;
end Types;


Validation model for the calendar time model. This model validates the use of the

AixLib.Utilities.Time.CalendarTime
block for a period of a couple of months.
This shorter simulation time has been selected to
store the reference results that are used in the regression tests
at a resulation that makes sense for the minute and hour outputs.

within AixLib.Utilities.Time.Validation;
model CalendarTimeMonths "Validation model for the calendar time model"
  extends Modelica.Icons.Example;
  AixLib.Utilities.Time.CalendarTime calTim(zerTim=AixLib.Utilities.Time.Types.ZeroTime.NY2015)
    "Computes date and time assuming time=0 corresponds to new year 2015"

equation
end CalendarTimeMonths;


Validation model for the calendar time model with start time slightly below the full hour. This model validates the use of the

AixLib.Utilities.Time.CalendarTime.
It is identical to

AixLib.Utilities.Time.Validation.CalendarTimeMonths
except that the start and end time are different.

within AixLib.Utilities.Time.Validation;
model CalendarTimeMonthsMinus
  "Validation model for the calendar time model with start time slightly below the full hour"
  extends AixLib.Utilities.Time.Validation.CalendarTimeMonths;
end CalendarTimeMonthsMinus;


Validation model for the calendar time model with start time slightly higher than the full hour. This model validates the use of the

AixLib.Utilities.Time.CalendarTime.
It is identical to

AixLib.Utilities.Time.Validation.CalendarTimeMonths
except that the start and end time are different.

within AixLib.Utilities.Time.Validation;
model CalendarTimeMonthsPlus
  "Validation model for the calendar time model with start time slightly higher than the full hour"
  extends AixLib.Utilities.Time.Validation.CalendarTimeMonths;
end CalendarTimeMonthsPlus;


within AixLib.Utilities.Time;
package Validation "Collection of models that validate the time models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings;
package Air "Package with models that are configured to use with air-based HVAC systems"
  extends Modelica.Icons.Package;
end Air;


within Buildings.Air;
package Systems "Package with pre-configured HVAC systems"
  extends Modelica.Icons.Package;
end Systems;


within Buildings.Air.Systems;
package SingleZone "Package with pre-configured system models that serve a single thermal zone"
  extends Modelica.Icons.Package;
end SingleZone;


within Buildings.Air.Systems.SingleZone.VAV;
model ChillerDXHeatingEconomizer
  "HVAC system model with a dry cooling coil, air-cooled chiller, electric heating coil,
   variable speed fan, and mixing box with economizer control."
  replaceable package MediumA = Buildings.Media.Air "Medium model for air"
  replaceable package MediumW = Buildings.Media.Water "Medium model for water"

  parameter Modelica.Units.SI.DimensionlessRatio COP_nominal=5.5
    "Nominal COP of the chiller";
  parameter Modelica.Units.SI.Temperature TSupChi_nominal
    "Design value for chiller leaving water temperature";
  parameter Modelica.Units.SI.MassFlowRate mAir_flow_nominal
    "Design airflow rate of system"
  parameter Modelica.Units.SI.Power QHea_flow_nominal(min=0)
    "Design capacity of heating coil"
  parameter Real etaHea_nominal(min=0, max=1, unit="1")
    "Design heating efficiency of the heating coil"
  parameter Modelica.Units.SI.Power QCoo_flow_nominal(max=0)
    "Design capacity of cooling coil"
  parameter Modelica.Units.SI.PressureDifference dp_nominal(displayUnit="Pa")=
       500 "Design pressure drop of flow leg with fan"
  final parameter Modelica.Units.SI.MassFlowRate mChiEva_flow_nominal=-
      QCoo_flow_nominal/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq/4
    "Design chilled water supply flow";
  final parameter Modelica.Units.SI.MassFlowRate mChiCon_flow_nominal=-
      QCoo_flow_nominal*(1 + 1/COP_nominal)/Buildings.Utilities.Psychrometrics.Constants.cpAir
      /10 "Design condenser air flow";

  Modelica.Blocks.Interfaces.BooleanInput chiOn "On signal for chiller plant"
  Modelica.Blocks.Interfaces.RealInput uFan(
    final unit="1") "Fan control signal"
  Modelica.Blocks.Interfaces.RealInput uHea(
    final unit="1") "Control input for heater"
  Modelica.Blocks.Interfaces.RealInput uCooVal(final unit="1")
    "Control signal for cooling valve"
  Modelica.Blocks.Interfaces.RealInput TSetChi(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Set point for leaving chilled water temperature"
  Modelica.Blocks.Interfaces.RealInput uEco
    "Control signal for economizer"
  Modelica.Fluid.Interfaces.FluidPort_a supplyAir(
    redeclare final package Medium = MediumA) "Supply air"
  Modelica.Fluid.Interfaces.FluidPort_b returnAir(
    redeclare final package Medium = MediumA) "Return air"
  Modelica.Blocks.Interfaces.RealOutput PFan(final unit="W")
    "Electrical power consumed by the supply fan"
  Modelica.Blocks.Interfaces.RealOutput QHea_flow(final unit="W")
    "Electrical power consumed by the heating equipment"
  Modelica.Blocks.Interfaces.RealOutput PCoo(final unit="W")
    "Electrical power consumed by the cooling equipment"
  Modelica.Blocks.Interfaces.RealOutput PPum(final unit="W")
    "Electrical power consumed by the pumps"
  Modelica.Blocks.Interfaces.RealOutput TMix(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Mixed air temperature"
  Modelica.Blocks.Interfaces.RealOutput TSup(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Supply air temperature after coils"

  Buildings.BoundaryConditions.WeatherData.Bus weaBus
    "Weather bus"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTSup(
    final m_flow_nominal=mAir_flow_nominal,
    final allowFlowReversal=false,
    final tau=0,
    redeclare package Medium = MediumA)
    "Supply air temperature sensor"
  Buildings.Fluid.HeatExchangers.HeaterCooler_u heaCoi(
    final m_flow_nominal=mAir_flow_nominal,
    final Q_flow_nominal=QHea_flow_nominal,
    final u(start=0),
    final dp_nominal=0,
    final allowFlowReversal=false,
    final tau=90,
    redeclare package Medium = MediumA,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final show_T=true)
    "Air heating coil"
  Buildings.Fluid.Movers.FlowControlled_m_flow fanSup(
    final m_flow_nominal=mAir_flow_nominal,
    final nominalValuesDefineDefaultPressureCurve=true,
    final dp_nominal=875,
    final per(final etaHydMet=Buildings.Fluid.Movers.BaseClasses.Types.HydraulicEfficiencyMethod.NotProvided,
        final etaMotMet=Buildings.Fluid.Movers.BaseClasses.Types.MotorEfficiencyMethod.NotProvided),
    final energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    final allowFlowReversal=false,
    final use_riseTime=false,
    redeclare package Medium = MediumA) "Supply fan"
  Buildings.Fluid.FixedResistances.PressureDrop totalRes(
    final m_flow_nominal=mAir_flow_nominal,
    final dp_nominal=dp_nominal,
    final allowFlowReversal=false,
    redeclare package Medium = MediumA)
    "Total resistance"
  Modelica.Blocks.Math.Gain eff(k=1/etaHea_nominal)
    "Heating efficiency"
  Buildings.Fluid.Sources.Outside out(
    final C=fill(0.0004, MediumA.nC),
    final nPorts=3,
    redeclare package Medium = MediumA)
    "Boundary conditions for outside air"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTMixAir(
    final m_flow_nominal=mAir_flow_nominal,
    final allowFlowReversal=false,
    final tau=0,
    redeclare package Medium = MediumA)
    "Mixed air temperature sensor"
  Buildings.Fluid.HeatExchangers.DryCoilEffectivenessNTU cooCoi(
    redeclare package Medium1 = MediumW,
    redeclare package Medium2 = MediumA,
    final dp1_nominal=0,
    final dp2_nominal=0,
    final m2_flow_nominal=mAir_flow_nominal,
    final Q_flow_nominal=QCoo_flow_nominal,
    final configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    final allowFlowReversal1=false,
    final allowFlowReversal2=false,
    final m1_flow_nominal=mChiEva_flow_nominal,
    final show_T=true,
    final T_a1_nominal=279.15,
    final T_a2_nominal=298.15)
    "Cooling coil"
  Buildings.Fluid.Sources.MassFlowSource_T souChiWat(
    redeclare package Medium = MediumA,
    final nPorts=1,
    final use_T_in=true,
    final m_flow=mChiCon_flow_nominal)
    "Mass flow source for chiller"
  Buildings.Fluid.Movers.FlowControlled_m_flow pumChiWat(
    final use_riseTime=false,
    final allowFlowReversal=false,
    redeclare package Medium = MediumW,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    final m_flow_nominal=mChiEva_flow_nominal,
    final addPowerToMedium=false,
    final per(
      efficiency(eta={1}),
      motorEfficiency(eta={0.9}),
      motorCooledByFluid=false),
    final dp_nominal=12000,
    final inputType=Buildings.Fluid.Types.InputType.Continuous,
    final nominalValuesDefineDefaultPressureCurve=true)
    "Pump for chilled water loop"
  Buildings.Fluid.Chillers.ElectricEIR chi(
    final allowFlowReversal1=false,
    final allowFlowReversal2=false,
    redeclare package Medium1 = MediumA,
    redeclare package Medium2 = MediumW,
    final m2_flow_nominal=mChiEva_flow_nominal,
    final dp1_nominal=0,
    final m1_flow_nominal=mChiCon_flow_nominal,
    final per(
      capFunT={1.0433811,0.0407077,0.0004506,-0.0041514,-8.86e-5,-0.0003467},
      PLRMax=1.2,
      EIRFunT={0.5961915,-0.0099496,0.0007888,0.0004506,0.0004875,-0.0007623},
      EIRFunPLR={1.6853121,-0.9993443,0.3140322},
      COP_nominal=COP_nominal,
      QEva_flow_nominal=QCoo_flow_nominal,
      mEva_flow_nominal=mChiEva_flow_nominal,
      mCon_flow_nominal=mChiCon_flow_nominal,
      TEvaLvg_nominal=TSupChi_nominal,
      PLRMinUnl=0.1,
      PLRMin=0.1,
      etaMotor=1,
      TEvaLvgMin=274.15,
      TEvaLvgMax=293.15,
      TConEnt_nominal=302.55,
      TConEntMin=274.15,
      TConEntMax=323.15),
    final dp2_nominal=12E3,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Air cooled chiller"
  Buildings.Fluid.Sources.Boundary_pT bouPreChi(
    redeclare package Medium = MediumW, nPorts=1)
    "Pressure boundary condition for chilled water loop"
  Modelica.Blocks.Math.Gain gaiFan(k=mAir_flow_nominal)
    "Gain for fan mass flow rate"
  IdealValve ideVal(
    redeclare package Medium = MediumW,
    final m_flow_nominal = mChiEva_flow_nominal)
    "Ideal valve"
  Modelica.Blocks.Math.BooleanToReal booToInt(
    final realTrue=mChiEva_flow_nominal)
    "Boolean to integer conversion"
  IdealValve ideEco(
    redeclare package Medium = MediumA,
    final m_flow_nominal=mAir_flow_nominal)
    "Ideal economizer"
  Fluid.Sensors.TemperatureTwoPort senTRetAir(
    final m_flow_nominal=mAir_flow_nominal,
    final allowFlowReversal=false,
    final tau=0,
    redeclare package Medium = MediumA)
    "Return air temperature sensor"
  Modelica.Blocks.Interfaces.RealOutput TRet(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Return air temperature"
  Fluid.Sensors.TraceSubstancesTwoPort senTraSub(
    redeclare package Medium=MediumA,
    final m_flow_nominal=mAir_flow_nominal,
    final tau=0)
    "Sensor for trace substance"

  Modelica.Blocks.Interfaces.RealOutput y_actual "Actual supply fan speed"
protected
  model IdealValve
    extends Modelica.Blocks.Icons.Block;
    replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium in the component"
    parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
      "Design chilled water supply flow";
    Modelica.Fluid.Interfaces.FluidPort_a port_1(
      redeclare package Medium = Medium)
    Modelica.Fluid.Interfaces.FluidPort_b port_2(
      redeclare package Medium = Medium)
    Modelica.Fluid.Interfaces.FluidPort_a port_3(
      redeclare package Medium = Medium)
    Modelica.Blocks.Interfaces.RealInput y(min=0, max=1)
    Fluid.Sensors.MassFlowRate senMasFlo(
      redeclare package Medium = Medium,
      allowFlowReversal=false)
      "Mass flow rate sensor"
    Fluid.Movers.BaseClasses.IdealSource preMasFlo(
      redeclare package Medium = Medium,
      control_m_flow=true,
      control_dp=false,
      m_flow_small=m_flow_nominal*1E-5,
      show_V_flow=false,
      allowFlowReversal=false)
      "Prescribed mass flow rate for the bypass"
    Modelica.Blocks.Math.Product pro "Product for mass flow rate computation"
    Modelica.Blocks.Sources.Constant one(final k=1) "Outputs one"
    Modelica.Blocks.Math.Feedback feedback
  equation
    connect(senMasFlo.m_flow, pro.u2)
    connect(feedback.u1, one.y)
    connect(y, feedback.u2)
    connect(preMasFlo.port_a, port_3)
    connect(feedback.y, pro.u1)
    connect(pro.y, preMasFlo.m_flow_in)
    connect(port_1, senMasFlo.port_a)
    connect(senMasFlo.port_b, port_2)
    connect(preMasFlo.port_b, senMasFlo.port_a)
  end IdealValve;

equation
  connect(fanSup.port_b, totalRes.port_a)
  connect(fanSup.P, PFan)
  connect(eff.y, QHea_flow)
  connect(weaBus, out.weaBus)
  connect(senTMixAir.port_b, fanSup.port_a)
  connect(heaCoi.Q_flow, eff.u)
  connect(heaCoi.port_b, cooCoi.port_a2)
  connect(cooCoi.port_b2, senTSup.port_a)
  connect(cooCoi.port_b1, ideVal.port_1)
  connect(chi.port_b2, pumChiWat.port_a)
  connect(souChiWat.ports[1], chi.port_a1)
  connect(chi.port_b1, out.ports[1])
  connect(weaBus.TDryBul, souChiWat.T_in)
  connect(pumChiWat.P, PPum)
  connect(chi.P, PCoo)
  connect(ideVal.port_2, chi.port_a2)
  connect(cooCoi.port_a1, pumChiWat.port_b)
  connect(cooCoi.port_a1, ideVal.port_3)
  connect(bouPreChi.ports[1], chi.port_a2)
  connect(totalRes.port_b, heaCoi.port_a)
  connect(senTSup.port_b, supplyAir)
  connect(gaiFan.y, fanSup.m_flow_in)
  connect(booToInt.y, pumChiWat.m_flow_in)
  connect(booToInt.u, chiOn)
  connect(chiOn, chi.on)
  connect(gaiFan.u, uFan)
  connect(heaCoi.u, uHea)
  connect(ideVal.y, uCooVal)
  connect(chi.TSet, TSetChi)
  connect(senTMixAir.T, TMix)
  connect(senTSup.T, TSup)
  connect(out.ports[2], ideEco.port_1)
  connect(ideEco.port_2, senTMixAir.port_a)
  connect(uEco, ideEco.y)
  connect(ideEco.port_3, senTRetAir.port_b)
  connect(senTRetAir.port_b, out.ports[3])
  connect(TRet, senTRetAir.T)
  connect(senTRetAir.port_a, senTraSub.port_b)
  connect(senTraSub.port_a, returnAir)

  connect(fanSup.y_actual, y_actual)
end ChillerDXHeatingEconomizer;


VAV system model

within Buildings.Air.Systems.SingleZone;
package VAV "VAV system model"
  extends Modelica.Icons.Package;
end VAV;


Controller for single zone VAV system. This is a controller for the single-zone VAV system with an economizer, a
heating coil and a cooling coil.

within Buildings.Air.Systems.SingleZone.VAV.BaseClasses;
model ControllerChillerDXHeatingEconomizer
  "Controller for single zone VAV system"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.Temperature TSupChi_nominal
    "Design value for chiller leaving water temperature";
  parameter Real minAirFlo(
    final min=0,
    final max=1,
    final unit="1")
    "Minimum airflow fraction of system"
  parameter Modelica.Units.SI.DimensionlessRatio minOAFra
    "Minimum outdoor air fraction of system"
  parameter Modelica.Units.SI.Temperature TSetSupAir
    "Cooling supply air temperature setpoint"
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeHea=
    Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real kHea(
    final unit="1/K")=0.1
    "Gain for heating coil control signal"
  parameter Real TiHea(
    final unit="s",
    final quantity="Time")=900
    "Time constant of integrator block for heating coil control signal"
  parameter Real TdHea(
    final unit="s",
    final quantity="Time")=0.1
    "Time constant of derivative block for heating coil control signal"
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeCoo=
    Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real kCoo(
    final unit="1/K")=0.1
    "Gain for cooling coil control signal"
  parameter Real TiCoo(
    final unit="s")=900
    "Time constant of integrator block for cooling coil control signal"
  parameter Real TdCoo(
    final unit="s")=0.1
    "Time constant of derivative block for cooling coil control signal"
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeFan=
    Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real kFan(final unit="1/K")=0.1
    "Gain for fan signal"
  parameter Real TiFan(
    final unit="s",
    final quantity="Time")=900
    "Time constant of integrator block for fan signal"
  parameter Real TdFan(
    final unit="s",
    final quantity="Time")=0.1
    "Time constant of derivative block for fan signal"
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerTypeEco=
    Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real kEco(final unit="1/K")=0.1
    "Gain for economizer control signal"
  parameter Real TiEco=300
    "Time constant of integrator block for economizer control signal"
  parameter Real TdEco(
    final unit="s",
    final quantity="Time")=0.1
    "Time constant of derivative block for economizer control signal"

  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSetRooCoo(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Zone cooling setpoint temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSetRooHea(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Zone heating setpoint temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TRoo(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Zone temperature measurement"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TMix(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Measured mixed air temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSup(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Measured supply air temperature after the cooling coil"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TOut(
    final unit="K",
    displayUnit="degC",
    final quantity="ThermodynamicTemperature")
    "Measured outside air temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yHea(
    final unit="1") "Control signal for heating coil"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yFan(
    final unit="1") "Control signal for fan"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yOutAirFra(
    final unit="1")
    "Control signal for outside air fraction"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCooCoiVal(
    final unit="1")
    "Control signal for cooling coil valve"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TSetSupChi(
    final unit="K",
    displayUnit="degC")
    "Set point for chiller leaving water temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput chiOn
    "On signal for chiller"

  BaseClasses.ControllerHeatingFan conSup(
    final controllerTypeHea=controllerTypeHea,
    final kHea=kHea,
    final TiHea=TiHea,
    final TdHea=TdHea,
    final controllerTypeFan=controllerTypeFan,
    final kFan=kFan,
    final TiFan=TiFan,
    final TdFan=TdFan,
    final minAirFlo = minAirFlo)
    "Heating coil and fan controller"
  BaseClasses.ControllerEconomizer conEco(
    final controllerTypeEco=controllerTypeEco,
    final kEco=kEco,
    final TiEco=TiEco,
    final TdEco=TdEco)
    "Economizer control"
  Buildings.Controls.Continuous.LimPID conCooVal(
    final controllerType=controllerTypeCoo,
    final k=kCoo,
    final Ti=TiCoo,
    final Td=TdCoo,
    final yMax=1,
    final yMin=0,
    final reverseActing=false)
    "Cooling coil valve controller"
  Buildings.Controls.OBC.CDL.Reals.Switch swi
    "Switch the outdoor air fraction to 0 when in unoccupied mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uOcc
    "Current occupancy period, true if it is in occupant period"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant con(k=0)
    "Zero outside air fraction"
  Buildings.Controls.OBC.CDL.Reals.Switch swiFan "Switch fan on"
  Buildings.Controls.OBC.CDL.Logical.MultiOr orFan(nin=3)
    "Switch fan on if heating, cooling, or occupied"
  Modelica.Blocks.Logical.And and1 "Logical and"
  Buildings.Controls.OBC.CDL.Reals.Greater chiOnTRoo(h=1)
    "Chiller on signal based on room temperature"

  Controls.OBC.CDL.Reals.Greater heaOnTRoo(h=0.5)
    "Heater on signal based on room temperature"
protected
  Modelica.Blocks.Sources.Constant TSetSupChiConst(
    final k=TSupChi_nominal)
    "Set point for chiller temperature"
  Modelica.Blocks.Sources.Constant conMinOAFra(
    final k=minOAFra)
    "Minimum outside air fraction"
  Modelica.Blocks.Sources.Constant TSetSupAirConst(
    final k=TSetSupAir)
    "Set point for supply air temperature"

equation
  connect(TSetSupAirConst.y,conCooVal. u_s)
  connect(conSup.TRoo, TRoo)
  connect(conEco.TRet, TRoo)
  connect(conSup.yHea, yHea)
  connect(conEco.yOutAirFra, yOutAirFra)
  connect(conCooVal.y, yCooCoiVal)
  connect(TSetSupChiConst.y, TSetSupChi)
  connect(conCooVal.u_m, TSup)
  connect(conMinOAFra.y, swi.u1)
  connect(uOcc, swi.u2)
  connect(swi.y, conEco.minOAFra)
  connect(con.y, swi.u3)
  connect(con.y, swiFan.u3)
  connect(conSup.yFan, swiFan.u1)
  connect(swiFan.y, yFan)
  connect(swiFan.u2, orFan.y)
  connect(conEco.TMixSet, conCooVal.u_s)
  connect(and1.y, chiOn)
  connect(conEco.yCoiSta, and1.u1)
  connect(uOcc, orFan.u[1])
  connect(TMix, conEco.TMix)
  connect(TOut, conEco.TOut)
  connect(TRoo, chiOnTRoo.u1)
  connect(TSetRooCoo, chiOnTRoo.u2)
  connect(TSetRooCoo, conSup.TSetRooCoo)
  connect(TSetRooHea, conSup.TSetRooHea)
  connect(chiOnTRoo.y, and1.u2)
  connect(chiOnTRoo.y, conEco.cooSta)

  connect(chiOnTRoo.y, orFan.u[2])
  connect(heaOnTRoo.y, orFan.u[3])
  connect(heaOnTRoo.u2, TRoo)
  connect(TSetRooHea, heaOnTRoo.u1)
end ControllerChillerDXHeatingEconomizer;