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

within Buildings.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 = Buildings.Utilities.Psychrometrics.Functions.saturationPressure(T);
end SaturationPressure;


Model to test X_pSatpphi function

within Buildings.Utilities.Psychrometrics.Functions.Examples;
model X_pSatpphi "Model to test X_pSatpphi function"
  extends Modelica.Icons.Example;
  package Medium = Buildings.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 = Buildings.Utilities.Psychrometrics.Functions.X_pSatpphi(pSat=pSat, p=p, phi=phi);
end X_pSatpphi;


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

Buildings.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 Buildings.Utilities.Time;
model CalendarTime
  "Computes the unix time stamp and calendar time from the simulation time"
  extends Modelica.Blocks.Icons.DiscreteBlock;
  parameter Buildings.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 == Buildings.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 == Buildings.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 == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStamp then
    timOff :=0;
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.UnixTimeStampGMT then
    timOff :=timZon;
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2010 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2010 then
      timOff :=timeStampsNewYear[1];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2011 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2011 then
      timOff :=timeStampsNewYear[2];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2012 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2012 then
      timOff :=timeStampsNewYear[3];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2013 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2013 then
      timOff :=timeStampsNewYear[4];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2014 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2014 then
      timOff :=timeStampsNewYear[5];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2015 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2015 then
      timOff :=timeStampsNewYear[6];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2016 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2016 then
      timOff :=timeStampsNewYear[7];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2017 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2017 then
      timOff :=timeStampsNewYear[8];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2018 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2018 then
      timOff :=timeStampsNewYear[9];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2019 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2019 then
      timOff :=timeStampsNewYear[10];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2020 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2020 then
      timOff :=timeStampsNewYear[11];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2021 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2021 then
      timOff :=timeStampsNewYear[12];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2022 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2022 then
      timOff :=timeStampsNewYear[13];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2023 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2023 then
      timOff :=timeStampsNewYear[14];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2024 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2024 then
      timOff := timeStampsNewYear[14];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2025 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2025 then
      timOff := timeStampsNewYear[15];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2026 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2026 then
      timOff := timeStampsNewYear[16];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2027 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2027 then
      timOff := timeStampsNewYear[17];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2028 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2028 then
      timOff := timeStampsNewYear[18];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2029 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2029 then
      timOff := timeStampsNewYear[19];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2030 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2030 then
      timOff := timeStampsNewYear[20];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2031 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2031 then
      timOff := timeStampsNewYear[21];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2032 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2032 then
      timOff := timeStampsNewYear[22];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2033 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2033 then
      timOff := timeStampsNewYear[23];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2034 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2034 then
      timOff := timeStampsNewYear[24];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2035 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2035 then
      timOff := timeStampsNewYear[25];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2036 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2036 then
      timOff := timeStampsNewYear[26];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2037 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2037 then
      timOff := timeStampsNewYear[27];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2038 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2038 then
      timOff := timeStampsNewYear[28];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2039 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2039 then
      timOff := timeStampsNewYear[29];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2040 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2040 then
      timOff := timeStampsNewYear[30];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2041 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2041 then
      timOff := timeStampsNewYear[31];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2042 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2042 then
      timOff := timeStampsNewYear[32];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2043 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2043 then
      timOff := timeStampsNewYear[33];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2044 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2044 then
      timOff := timeStampsNewYear[34];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2045 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2045 then
      timOff := timeStampsNewYear[35];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2046 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2046 then
      timOff := timeStampsNewYear[36];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2047 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2047 then
      timOff := timeStampsNewYear[37];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2048 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2048 then
      timOff := timeStampsNewYear[38];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2049 or
    zerTim == Buildings.Utilities.Time.Types.ZeroTime.Custom and yearRef == 2049 then
      timOff := timeStampsNewYear[39];
  elseif zerTim == Buildings.Utilities.Time.Types.ZeroTime.NY2050 or
    zerTim == Buildings.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 == Buildings.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 == Buildings.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 == Buildings.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 == Buildings.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;


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 Buildings.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 Buildings.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

Buildings.Utilities.Time.CalendarTime
block.

within Buildings.Utilities.Time.Examples;
model CalendarTime "Example for the calendar time model"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.CalendarTime calendarTime2016(
    zerTim=Buildings.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 Buildings.Utilities.Time.Examples;
model ModelTime "Test model for the ModelTime block"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.ModelTime modTim "Model time"
equation
end ModelTime;


within Buildings.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 Buildings.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

Buildings.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 Buildings.Utilities.Time.Validation;
model CalendarTimeMonths "Validation model for the calendar time model"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.CalendarTime calTim(zerTim=Buildings.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

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

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

within Buildings.Utilities.Time.Validation;
model CalendarTimeMonthsMinus
  "Validation model for the calendar time model with start time slightly below the full hour"
  extends Buildings.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

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

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

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


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


within AixLib;
package Airflow "Package to compute airflow and contaminant transport between rooms"
  extends Modelica.Icons.Package;
end Airflow;


Ideal model for the usage of an air curtain in the context of low order retail zones.

within AixLib.Airflow.AirCurtain;
model AirCurtainSimplified
  "Ideal model for the usage of an air curtain in the context of low order retail zones"
  parameter Modelica.Units.SI.VolumeFlowRate V_flowAirCur=5
    "Design volume flow rate of the air curtain";
  parameter Modelica.Units.SI.TemperatureDifference TAddAirCur=5
    "Temperature increase over the air curtain";
  parameter Real etaAirCur = 0.73
    "Efficiency of the air curtain";
  parameter Modelica.Units.SI.Density rho=1.25 "Air density";
  parameter Modelica.Units.SI.SpecificHeatCapacity c=1000
    "Specific heat capacity of air";
  parameter Modelica.Units.SI.Temperature TBou=287.15
    "Threshold of the ambient temperature when aircurtain becomes active";
  parameter Modelica.Units.SI.Power PAirCur=27500
    "The thermal Power of the air curtain, simplified use";
  Utilities.Psychrometrics.MixedTemperature mixedTemperature
  Modelica.Blocks.Interfaces.RealInput TAmb "Ambient airtemperature in K"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b
    port_b "heat port for heat transfer"

  Modelica.Blocks.Interfaces.RealOutput Power "Power used by the air curtain"
  Modelica.Blocks.Interfaces.RealInput schedule "Signal for the schedule"
equation

  if TAmb <= TBou and schedule > 0 then
    mixedTemperature.flowRate_flow2 = (1 - etaAirCur) * V_flowAirCur;
    mixedTemperature.flowRate_flow1 = etaAirCur * V_flowAirCur;
    mixedTemperature.temperature_flow1 = port_b.T + TAddAirCur;
    port_b.Q_flow = - etaAirCur * V_flowAirCur * rho * c * (mixedTemperature.mixedTemperatureOut - port_b.T);
    Power = PAirCur;
  else
    mixedTemperature.flowRate_flow2 = (1 - etaAirCur) * V_flowAirCur;
    mixedTemperature.flowRate_flow1 = etaAirCur * V_flowAirCur;
    mixedTemperature.temperature_flow1 = port_b.T;
    port_b.Q_flow = 0;
    Power = 0;
  end if;

  connect(TAmb, mixedTemperature.temperature_flow2)
end AirCurtainSimplified;


Package of different air curtain models

within AixLib.Airflow;
package AirCurtain "Package of different air curtain models"
end AirCurtain;


This model is an example for the use of an air curtain in the low order model.

within AixLib.Airflow.AirCurtain.Examples;
model AirCurtain
  "This model is an example for the use of an air curtain in the low order model"
  extends Modelica.Icons.Example;
  AirCurtainSimplified                    airCurtainSimplyfied(
    V_flowAirCur=5,
    TAddAirCur=5,
    etaAirCur=0.73,
    PAirCur=50000,
    TBou=287.15)
  ThermalZones.HighOrder.Components.DryAir.Airload airload(T0=293.15, V=48)
  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    calTSky=AixLib.BoundaryConditions.Types.SkyTemperatureCalculation.HorizontalRadiation,
    computeWetBulbTemperature=false,
    filNam=Modelica.Utilities.Files.loadResource(
        "modelica://AixLib/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data reader"

  Modelica.Blocks.Sources.Pulse pulse(
    amplitude=1,
    width=50,
    period=86400,
    offset=0,
    startTime=25200)
  BoundaryConditions.WeatherData.Bus        weaBus
    "Weather data bus"
equation
  connect(airCurtainSimplyfied.port_b, airload.port)
  connect(pulse.y, airCurtainSimplyfied.schedule)
  connect(weaDat.weaBus, weaBus)
  connect(weaBus.TDryBul, airCurtainSimplyfied.TAmb)
end AirCurtain;


Air Handling Unit with Heat Recovery System, Cooling, Heating, Humidification (adiabatic), Dehumidification.

within AixLib.Airflow.AirHandlingUnit;
model AHU
  "Air Handling Unit with Heat Recovery System, Cooling, Heating, Humidification (adiabatic), Dehumidification"
  extends AixLib.Airflow.AirHandlingUnit.BaseClasses.PartialAHU;
  /*
 indices and abbreviations:
 HRS = heat recovery system
 sup = supply air
 eta = extract air
 oda = outdoor air
 eha = exhaust air
 BPF = By-pass factor
 DeHu = dehumidification
 Hu = humidification
 H = heat(ing)
 C = cool(ing)
 sat = saturation
 phi_t is the HRS' efficiency not a relative humidity like other phis
 */

  //// Variables
  // Booleans for transitions to State Machines
  inner Boolean stateToDeHuHRS_true;
  inner Boolean stateToDeHuHRS_false;
  inner Boolean stateToHuPreHHRS_true;
  inner Boolean stateToHuPreHHRS_false;
  inner Boolean stateToHuCHRS_true;
  inner Boolean stateToHuCHRS_false;
  inner Boolean stateToOnlyHeatingHRS_true;
  inner Boolean stateToOnlyHeatingHRS_false;
  inner Boolean stateToOnlyCoolingHRS_true;
  inner Boolean stateToOnlyCoolingHRS_false;

  Boolean tooHighX(start=false);
  Boolean tooLowX(start=false);
  Boolean choiceX(start=true);
  Boolean allCond(start=false);

  // Variables that will be set with parameteres of HRS efficiency
  inner Real phi_t_withHRS(start=efficiencyHRS_enabled)
    "efficiency of HRS in the AHU modes when HRS is enabled";
  inner Real phi_t_withoutHRS(start=efficiencyHRS_disabled)
    "efficiency of HRS in the AHU modes when HRS is disabled";
  inner Real phi_t(start=0.5);

  inner Modelica.Units.SI.Temperature T_oda;
                                      //(start=288.15);
  inner Modelica.Units.SI.Temperature T_1(start=290.15);
  inner Modelica.Units.SI.Temperature T_5(start=293.15);
  inner Modelica.Units.SI.Temperature T_sup(start=295.15);
  inner Modelica.Units.SI.Temperature T_eta(start=296.15);
  inner Modelica.Units.SI.Temperature T_6;
                                    //(start=296.15);

  inner Modelica.Units.SI.MassFraction X_oda(start=0.007);
  Modelica.Units.SI.MassFraction X_odaSat(start=0.007);
  Modelica.Units.SI.MassFraction X_odaRaw(start=0.007);
  inner Modelica.Units.SI.MassFraction X_sup(start=0.008);
  Modelica.Units.SI.MassFraction X_supplyMin(start=0.006);
  Modelica.Units.SI.MassFraction X_supplyMax(start=0.010);
  inner Modelica.Units.SI.MassFraction X_supMin(start=0.006);
  inner Modelica.Units.SI.MassFraction X_supMax(start=0.010);
  Modelica.Units.SI.MassFraction X_extractAir(start=0.008);
  Modelica.Units.SI.MassFraction X_eta(start=0.008);
  Real phi_sup(start=0.5);

  inner Modelica.Units.SI.HeatFlowRate Q_dot_C(start=1e-3);
  inner Modelica.Units.SI.HeatFlowRate Q_dot_H(start=1e-3);
  Modelica.Units.SI.Power P_el_sup(start=1e-3);
  Modelica.Units.SI.Power P_el_eta(start=1e-3);
  inner Modelica.Units.SI.VolumeFlowRate V_dot_sup(start=1e-3);
  inner Modelica.Units.SI.VolumeFlowRate V_dot_eta(start=1e-3);

  // Constants from formulas collection of Thermodynamik (institute: LTT)
  constant Modelica.Units.SI.SpecificHeatCapacityAtConstantPressure c_pL_iG=1E3;
  constant Modelica.Units.SI.SpecificHeatCapacityAtConstantPressure c_pW_iG=
      1.86E3;
  constant Modelica.Units.SI.SpecificEnthalpy r_0=2465E3
    "enthalpy of vaporization at temperature between T_dew(X_sup=0.008)=11 degC and T_sup = 22 degC";
  constant Modelica.Units.SI.Density rho=1.2;
  constant Modelica.Units.SI.Pressure p_0=101325;
  constant Modelica.Units.SI.SpecificEnthalpy dhV=2501.3E3;
  constant Modelica.Units.SI.Temperature T_0=273.15;
  constant Real molarMassRatio=Modelica.Media.IdealGases.Common.SingleGasesData.H2O.MM
      /Modelica.Media.Air.SimpleAir.MM_const;

  // auxiliary variable
  Modelica.Units.SI.TemperatureDifference dTFan;
  Modelica.Units.SI.Temperature TsupplyAirOut(start=295.15);

  // Sampler (time-continous to time-discrete variables)

  Modelica.Clocked.RealSignals.Sampler.SampleVectorizedAndClocked sample(n=9)

  Modelica.Clocked.ClockSignals.Clocks.PeriodicRealClock periodicClock(
    solverMethod="ExplicitRungeKutta4",
    useSolver=true,
    period=clockPeriodGeneric)

  //
  ////////////////////////////
  //State Machines////////////
  ////////////////////////////
  //
  //Start State

  block StartState
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;

  equation
    Q_dot_C = previous(Q_dot_C);
    Q_dot_H = previous(Q_dot_H);
  end StartState;

  StartState startState

  //
  //
  // (comments for state machines only in the dehumidification state machine as representive comments)
  //
  // Dehumidification

  block DeHuHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2(start=290);
    Modelica.Units.SI.Temperature T_3(start=282);
    Modelica.Units.SI.Temperature T_4(start=282);
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMax;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;
    outer parameter Real BPF_DeHu;
    Modelica.Units.SI.SpecificEnthalpy h_2(start=0.003) "h_in of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_surface(start=0.002)
      "h_surface of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_CoilOut(start=0.001) "h_out of cooler";
    Modelica.Units.SI.Pressure p_sat_surface(start=2300);
    Modelica.Units.SI.MassFraction X_surface(start=0.005);
    Modelica.Units.SI.Temperature T_surface(start=280);
    Modelica.Units.SI.Temperature T_CoilOut(start=278);

  equation
    phi_t = phi_t_withHRS "heat recovery system is enabled";
    X_sup = previous(X_supMax);
    T_1 = T_2;
    T_3 = T_CoilOut;
    T_4 = T_3;

    BPF_DeHu = (h_CoilOut - h_surface)/max(h_2 - h_surface, 0.01);
    h_2 = c_pL_iG*(previous(T_2) - T_0) + previous(X_oda)*(c_pW_iG*(previous(
      T_2) - T_0) + dhV);
    h_surface = c_pL_iG*(T_surface - T_0) + X_surface*(c_pW_iG*(T_surface - T_0)
       + dhV);
    h_CoilOut = c_pL_iG*(T_CoilOut - T_0) + X_sup*(c_pW_iG*(T_CoilOut - T_0) +
      dhV);
    (previous(T_2) - T_surface)/max(previous(X_oda) - X_surface, 0.00009) = (
      T_CoilOut - T_surface)/max(previous(X_supMax) - X_surface, 0.00001);

    /*
  p_sat_surface = 611.2*exp(17.62*(T_surface - T_0)/(243.12 + T_surface - T_0));
  //Magnus formula over water, improved by Sonntag (1990), Range: -45 degC to +60 degC
  2 Alternatives for calculation of water vapor pressure, which are not so stable during simulation:
  p_sat_surface = 10^(-7.90298*(373.15/T_surface - 1)
          +5.02808*log10(373.15/T_surface)
          -1.3816*10^(-7)*(10^(11.344*(1 - T_surface/373.15))-1)
          +8.1328*10^(-3)*(10^(-3.49149*(373.15/T_surface - 1))-1)
          +log10(1013.246))*100; //The Goff Gratch equation for the vapor pressure over liquid water covers a region of -50 degC to +102 degC.
*/
    p_sat_surface = Modelica.Media.Air.MoistAir.saturationPressure(T_surface);

    X_surface = molarMassRatio*p_sat_surface/(p_0 - p_sat_surface);

    Q_dot_C = previous(V_dot_sup)*rho*((c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - T_CoilOut) + (previous(X_oda) - X_sup)*r_0);
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + X_sup*c_pW_iG)*(previous(T_5) -
      T_CoilOut);
  end DeHuHRS_true;
  DeHuHRS_true deHuHRS_true "Dehumidification and Heat Recovery System enabled"

  //
  //
  //
  //

  block DeHuHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2(start=290);
    Modelica.Units.SI.Temperature T_3(start=282);
    Modelica.Units.SI.Temperature T_4(start=282);
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMax;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;
    outer parameter Real BPF_DeHu;
    Modelica.Units.SI.SpecificEnthalpy h_2(start=0.003) "h_in of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_surface(start=0.002)
      "h_surface of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_CoilOut(start=0.001) "h_out of cooler";
    Modelica.Units.SI.Pressure p_sat_surface(start=2300);
    Modelica.Units.SI.MassFraction X_surface(start=0.005);
    Modelica.Units.SI.Temperature T_surface(start=280);
    Modelica.Units.SI.Temperature T_CoilOut(start=278);

  equation
    phi_t = phi_t_withoutHRS "heat recovery system is disabled";
    X_sup = previous(X_supMax);
    T_1 = T_2;
    T_3 = T_CoilOut;
    T_4 = T_3;

    BPF_DeHu = (h_CoilOut - h_surface)/max(h_2 - h_surface, 0.01);
    h_2 = c_pL_iG*(previous(T_2) - T_0) + previous(X_oda)*(c_pW_iG*(previous(
      T_2) - T_0) + dhV);
    h_surface = c_pL_iG*(T_surface - T_0) + X_surface*(c_pW_iG*(T_surface - T_0)
       + dhV);
    h_CoilOut = c_pL_iG*(T_CoilOut - T_0) + X_sup*(c_pW_iG*(T_CoilOut - T_0) +
      dhV);
    (previous(T_2) - T_surface)/max(previous(X_oda) - X_surface, 0.00009) = (
      T_CoilOut - T_surface)/max(previous(X_supMax) - X_surface, 0.00001);

    /*
  p_sat_surface = 611.2*exp(17.62*(T_surface - T_0)/(243.12 + T_surface - T_0));
  //Magnus formula over water, improved by Sonntag (1990), Range: -45 degC to +60 degC
  2 Alternatives for calculation of water vapor pressure, which are not so stable during simulation:
  p_sat_surface = 10^(-7.90298*(373.15/T_surface - 1)
          +5.02808*log10(373.15/T_surface)
          -1.3816*10^(-7)*(10^(11.344*(1 - T_surface/373.15))-1)
          +8.1328*10^(-3)*(10^(-3.49149*(373.15/T_surface - 1))-1)
          +log10(1013.246))*100; //The Goff Gratch equation for the vapor pressure over liquid water covers a region of -50 degC to +102 degC.
*/
    p_sat_surface = Modelica.Media.Air.MoistAir.saturationPressure(T_surface);

    X_surface = molarMassRatio*p_sat_surface/(p_0 - p_sat_surface);

    Q_dot_C = previous(V_dot_sup)*rho*((c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - T_CoilOut) + (previous(X_oda) - X_sup)*r_0);
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + X_sup*c_pW_iG)*(previous(T_5) -
      T_CoilOut);
  end DeHuHRS_false;
  DeHuHRS_false deHuHRS_false
    "Dehumidification and Heat Recovery System disabled"

  //
  //
  //
  // Humidification

  block HuPreHHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    X_sup = previous(X_supMin);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_1)) + previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
  end HuPreHHRS_true;
  HuPreHHRS_true huPreHHRS_true
    "Humidification with Preheating and Heat Recovery System enabled"

  //
  //
  //
  //

  block HuPreHHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    X_sup = previous(X_supMin);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_1)) + previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
  end HuPreHHRS_false;
  HuPreHHRS_false huPreHHRS_false
    "Humidification with Preheating and Heat Recovery System disabled"

  //
  //
  //
  //

  block HuCHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    X_sup = previous(X_supMin);
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3)) - previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
    Q_dot_H = 0;
  end HuCHRS_true;
  HuCHRS_true huCHRS_true
    "Humidification with additional Cooling and Heat Recovery System enabled"

  //
  //
  //
  //

  block HuCHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    X_sup = previous(X_supMin);
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3)) - previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
    Q_dot_H = 0;
  end HuCHRS_false;
  HuCHRS_false huCHRS_false
    "Humidification with additional Cooling and Heat Recovery System disabled"

  //
  //
  //
  // Only Heating

  block OnlyHeatingHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    T_1 = T_2;
    T_2 = T_3;
    T_3 = T_4;
    X_sup = previous(X_oda);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_4));
  end OnlyHeatingHRS_true;
  OnlyHeatingHRS_true onlyHeatingHRS_true
    "Heating and Heat Recovery System enabled"

  //
  //
  //
  //

  block OnlyHeatingHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    T_1 = T_2;
    T_2 = T_3;
    T_3 = T_4;
    X_sup = previous(X_oda);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_4));
  end OnlyHeatingHRS_false;
  OnlyHeatingHRS_false onlyHeatingHRS_false
    "Heating and Heat Recovery System disabled"

  //
  //
  //
  // Only Cooling

  block OnlyCoolingHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;
    X_sup = previous(X_oda);

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3));
    Q_dot_H = 0;
  end OnlyCoolingHRS_true;
  OnlyCoolingHRS_true onlyCoolingHRS_true
    "Cooling and Heat Recovery System enabled"

  //
  //
  //
  //

  block OnlyCoolingHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;
    X_sup = previous(X_oda);

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3));
    Q_dot_H = 0;
  end OnlyCoolingHRS_false;
  OnlyCoolingHRS_false onlyCoolingHRS_false
    "Cooling and Heat Recovery System disabled"

  //
  //
  //
  ////////////////////////////
  //EQUATION//////EQUATION////
  ////////////////////////////
  //
  //
  //

  Modelica.Blocks.Sources.RealExpression hold_phi_sup(y=hold(previous(phi_sup)))
  Modelica.Blocks.Sources.RealExpression TsupAirOut(y=hold(TsupplyAirOut))
    "see if else decision in source code"
  StateExtra stateExtra
equation
  // variables that will be set with parameteres of HRS efficiency
  phi_t_withHRS = if HRS then efficiencyHRS_enabled else 0;
  phi_t_withoutHRS = if HRS then efficiencyHRS_disabled else 0;

  //// sampler inputs
  // connecting clock signal with sampler
  connect(periodicClock.y, sample.clock)

  // converting inputs (coming from the outside of AHUFull) into time-discrete variables for state machines.

  X_supplyMin = sample.u[5];
  X_supplyMax = sample.u[6];
  X_extractAir = sample.u[7];

  T_oda = sample.y[1];
  X_odaRaw = sample.y[2];
  T_sup = sample.y[3];
  T_eta = sample.y[4];
  X_supMin = sample.y[5];
  X_supMax = sample.y[6];
  X_eta = sample.y[7];
  V_dot_sup = sample.y[8];
  V_dot_eta = sample.y[9];

  // absolute humidity for state of saturated outdoor air
  X_odaSat = molarMassRatio*(611.2*exp(17.62*(T_oda - T_0)/(243.12 + T_oda -
    T_0)))/(p_0 - (611.2*exp(17.62*(T_oda - T_0)/(243.12 + T_oda - T_0))));
  // if absolute humidity from weather file should be in region of phi_oda>1 then restrict to absolute humdity for phi_oda=1. Prevents calculation errors!
  X_oda = if X_odaRaw > X_odaSat then X_odaSat else X_odaRaw;

  // calculates T_1 according to assumption of HRS' efficiency phi_t
  phi_t = (T_1 - T_oda)/(T_6 - T_oda + 1e-3);

  // conditions for transitions to State Machines
  tooHighX = if previous(X_oda) > previous(X_supMax) then true else false;
  tooLowX = if previous(X_oda) < previous(X_supMin) then true else false;
  choiceX = if
     (tooHighX and not dehumidification)
     or
     (tooLowX and not humidification)
     or
     (previous(X_oda) <= previous(X_supMax) and previous(X_oda) >= previous(X_supMin))
     then true else false;

  // now really the conditions for the transitions
  stateToDeHuHRS_true = if
     tooHighX
     and dehumidification and HRS then true else false;

  stateToDeHuHRS_false = if
    tooHighX
    and dehumidification and not HRS then true else false;

  stateToHuPreHHRS_true = if
    tooLowX
    and
    ((previous(T_5) >= previous(T_1))
    or
    ((previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) >= abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))))
    and humidification and HRS then true else false;

  stateToHuPreHHRS_false = if
    tooLowX
    and
    ((previous(T_5) >= previous(T_1))
    or
    ((previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) >= abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))))
    and humidification and not HRS then true else false;

  stateToHuCHRS_true = if
    tooLowX
    and
    (previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) < abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))
    and humidification and HRS then true else false;

  stateToHuCHRS_false = if
    tooLowX
    and
    (previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) < abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))
    and humidification and not HRS then true else false;

  stateToOnlyHeatingHRS_true = if
     choiceX
     and
     (previous(T_5) >= pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and heating and HRS then true else false;

  stateToOnlyHeatingHRS_false = if
     choiceX
     and
     (previous(T_5) >= pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and heating and not HRS then true else false;

  stateToOnlyCoolingHRS_true = if
     choiceX
     and
     (previous(T_5) < pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and cooling and HRS then true else false;

  stateToOnlyCoolingHRS_false = if
     choiceX
     and
     (previous(T_5) < pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and cooling and not HRS then true else false;

  X_supplyMin = (molarMassRatio*phi_supplyAir[1]*
    Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir))/(p_0 -
    phi_supplyAir[1]*Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir));
  X_supplyMax = (molarMassRatio*phi_supplyAir[2]*
    Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir))/(p_0 -
    phi_supplyAir[2]*Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir));
  X_extractAir = (molarMassRatio*phi_extractAir*
    Modelica.Media.Air.MoistAir.saturationPressure(T_extractAir))/(p_0 -
    phi_extractAir*Modelica.Media.Air.MoistAir.saturationPressure(T_extractAir));

  // calculation of T_5 and T_6 regarding the electrical power consumption
  P_el_sup = V_dot_sup*dp_sup/eta_sup
    "Calculation of electrical power consumption";
  P_el_sup = V_dot_sup*rho*(c_pL_iG + X_sup*c_pW_iG)*(T_sup - T_5)
    "Calculation of T_5 by using V_dot_sup, efficiency eta_sup and input variable T_sup";
  P_el_eta = V_dot_eta*dp_eta/eta_eta
    "Calculation of electrical power consumption";
  P_el_eta = V_dot_eta*rho*(c_pL_iG + X_eta*c_pW_iG)*(T_6 - T_eta)
    "Calculation of T_6 by using V_dot_eta, efficiency eta_eta and input variable T_eta";

  // Calculation of relativ humidity of supply Air. Necessary for some superior model assamblies.
  X_sup = (molarMassRatio*phi_sup*
    Modelica.Media.Air.MoistAir.saturationPressure(T_sup))/(p_0 - phi_sup*
    Modelica.Media.Air.MoistAir.saturationPressure(T_sup));

  // converts time-discrete outputs of state machines into time-continous variables and limitation of thermal energies so that they cannot be negative
  allCond = if stateToDeHuHRS_true or stateToDeHuHRS_false or
    stateToHuPreHHRS_true or stateToHuPreHHRS_false or stateToHuCHRS_true or
    stateToHuCHRS_false or stateToOnlyHeatingHRS_true or
    stateToOnlyHeatingHRS_false or stateToOnlyCoolingHRS_true or
    stateToOnlyCoolingHRS_false then true else false;

  Vflow_out = hold(V_dot_sup);
  if Vflow_out > 0 and hold(V_dot_eta) <= 0 then
    Pel = hold(P_el_sup);
  elseif Vflow_out <= 0 and hold(V_dot_eta) > 0 then
    Pel = hold(P_el_eta);
  elseif Vflow_out > 0 and hold(V_dot_eta) > 0 then
    Pel = hold(P_el_eta) + hold(P_el_sup);
  else
    Pel = 0;
  end if;

  QflowH = if hold(Q_dot_H) > 0 then hold(Q_dot_H) else 0;
  QflowC = if hold(Q_dot_C) > 0 then hold(Q_dot_C) else 0;

  // The following part decides whether T_supplyAir input connector is passed through or outdoor air temp (+ slight changes) is used. Only necessery if either only heating or cooling is activated.
  if
    heating and not cooling and not dehumidification and not humidification then
    TsupplyAirOut = if stateToOnlyHeatingHRS_true or stateToOnlyHeatingHRS_false then T_sup else T_oda + phi_t_withoutHRS*(T_6 - T_oda) + dTFan;
  elseif
    cooling and not heating and not dehumidification and not humidification then
    TsupplyAirOut = if stateToOnlyCoolingHRS_true or stateToOnlyCoolingHRS_false then T_sup else T_oda + phi_t_withoutHRS*(T_6 - T_oda) + dTFan;
  elseif
    not heating and not cooling and not dehumidification and not humidification then
    TsupplyAirOut = T_oda + phi_t_withoutHRS*(T_6 - T_oda) + dTFan;
  else
    TsupplyAirOut = T_sup;
  end if;
  // with:
  P_el_sup = dTFan * V_dot_sup * rho * (c_pL_iG + X_oda * c_pW_iG);

  // transitions and conditions between state machines.
  initialState(startState)
  transition(
    startState,
    deHuHRS_true,
    stateToDeHuHRS_true,
    priority=1,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    deHuHRS_true,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToDeHuHRS_true==false,
  transition(
    startState,
    deHuHRS_false,
    stateToDeHuHRS_false,
    priority=2,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    deHuHRS_false,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToDeHuHRS_false==false,
  transition(
    startState,
    onlyHeatingHRS_true,
    stateToOnlyHeatingHRS_true,
    priority=7,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    startState,
    onlyHeatingHRS_false,
    stateToOnlyHeatingHRS_false,
    priority=8,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    startState,
    onlyCoolingHRS_true,
    stateToOnlyCoolingHRS_true,
    priority=9,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    startState,
    onlyCoolingHRS_false,stateToOnlyCoolingHRS_false,
    priority=10,
    immediate=false,
    reset=false,
    synchronize=false)
  transition(
    onlyHeatingHRS_true,
    startState,true,
    immediate=false,
    reset=false,
    synchronize=false,
    priority=11)
  //stateToOnlyHeatingHRS_true==false,
  transition(
    onlyHeatingHRS_false,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToOnlyHeatingHRS_false==false,
  transition(
    onlyCoolingHRS_true,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToOnlyCoolingHRS_true==false,
  transition(
    onlyCoolingHRS_false,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToOnlyCoolingHRS_false==false,
  transition(
    startState,
    huPreHHRS_true,
    stateToHuPreHHRS_true,
    priority=5,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huPreHHRS_true,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToHuPreHHRS_true==false,
  transition(
    startState,
    huPreHHRS_false,
    stateToHuPreHHRS_false,
    priority=6,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huPreHHRS_false,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToHuPreHHRS_false==false,
  transition(
    startState,
    huCHRS_true,
    stateToHuCHRS_true,
    priority=3,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huCHRS_true,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToHuCHRS_true==false,
  transition(
    startState,
    huCHRS_false,
    stateToHuCHRS_false,
    priority=4,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huCHRS_false,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToHuCHRS_false==false,

  connect(T_outdoorAir, sample.u[1])
  connect(X_outdoorAir, sample.u[2])
  connect(T_supplyAir, sample.u[3])
  connect(T_extractAir, sample.u[4])
  connect(Vflow_in, sample.u[8])
  connect(Vflow_in_extractAir_internal, sample.u[9]);
  connect(hold_phi_sup.y, phi_supply)
  connect(TsupAirOut.y, T_supplyAirOut)
public
  block StateExtra
  end StateExtra;
equation
  transition(
    startState,
    stateExtra,Q_dot_C > 0 and Q_dot_H > 0,
    immediate=false,
    reset=false,
    priority=11,synchronize=false)
  transition(
    stateExtra,
    startState,true,
    immediate=false,
    reset=false,synchronize=false,priority=1)
end AHU;


No AHU. This model can be seen as
  a dummy. Connectors exist due to partialAHU but outputs are zero and
  inputs do not have any effect. As a conclusion it is easier to choose
  whether an AHU exist in a building or not. For an example see
  AixLib.Building.LowOrder.Examples.MultizoneExample.

within AixLib.Airflow.AirHandlingUnit;
model NoAHU "No AHU"
  extends AixLib.Airflow.AirHandlingUnit.BaseClasses.PartialAHU;
  Modelica.Blocks.Sources.Constant dummyPhi_supply(k=0.5)
  Modelica.Blocks.Sources.Constant zeroVFlowOut(k(unit="m3/s") = 0)
  Modelica.Blocks.Sources.Constant dummyT_supplyAirOut(k=293)
  Modelica.Blocks.Sources.CombiTimeTable zeroPowerElAndHeat1(
    tableOnFile=false,
    table=[0,0.0],
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint)
equation
  connect(dummyPhi_supply.y, phi_supply)
  connect(zeroVFlowOut.y, Vflow_out)
  connect(dummyT_supplyAirOut.y, T_supplyAirOut)
  connect(zeroPowerElAndHeat1.y[1], QflowC)
  connect(zeroPowerElAndHeat1.y[1], QflowH)
  connect(zeroPowerElAndHeat1.y[1], Pel)
end NoAHU;


Defines necessary parameters and connectors. Base class to provide
  connectors. Thus, it is possible to declare parameters in a general
  way in superior building model and give the opportunity whether an
  AHU exist or
  does not.

within AixLib.Airflow.AirHandlingUnit.BaseClasses;
partial model PartialAHU "Defines necessary parameters and connectors"

  parameter Real clockPeriodGeneric(min=0) = 1800
    "time period in s for sampling (= converting time-continous into time-discrete) input variables. Recommendation: half of the duration of one simulation interval"
    // Booleans for possible AHU modes
  inner parameter Boolean heating=true "Heating Function of AHU"
  inner parameter Boolean cooling=true "Cooling Function of AHU"
  inner parameter Boolean dehumidificationSet=if heating and cooling then true
       else false
    "Dehumidification Function of AHU (Cooling and Heating must be enabled)"
  inner parameter Boolean humidificationSet=if heating and cooling then true else false
    "Humidification Function of AHU (Cooling and Heating must be enabled)"
  inner Boolean dehumidification;
  inner Boolean humidification;
  inner parameter Real BPF_DeHu(
    min=0,
    max=1) = 0.2
    "By-pass factor of cooling coil during dehumidification. Necessary to
    calculate the real outgoing enthalpy flow of heat exchanger in
    dehumidification mode taking the surface enthalpy of the cooling coil into account"
  inner parameter Boolean HRS=true
    "Is a HeatRecoverySystem physically integrated in the AHU?"
  parameter Boolean use_Vflow_in_extractAir=false
    "If incoming volume flow of outdoor/supply air should not equal the
    volume flow of extract air, set this parameter to true"
  // Efficiency of HRS
  parameter Real efficiencyHRS_enabled(
    min=0,
    max=1) = 0.8 "efficiency of HRS in the AHU modes when HRS is enabled"
  parameter Real efficiencyHRS_disabled(
    min=0,
    max=1) = 0.2
    "taking a little heat transfer into account although HRS is disabled
    (in case that a HRS is physically installed in the AHU)"
  // assumed increase in ventilator pressure
  parameter Modelica.Units.SI.Pressure dp_sup=800
    "pressure difference over supply fan"
  parameter Modelica.Units.SI.Pressure dp_eta=800
    "pressure difference over extract fan"
  // assumed efficiencies of the ventilators
  parameter Modelica.Units.SI.Efficiency eta_sup=0.7 "efficiency of supply fan"
  parameter Modelica.Units.SI.Efficiency eta_eta=0.7
    "efficiency of extract fan"

  Modelica.Blocks.Interfaces.RealInput Vflow_in(unit="m3/s") "m3/s"
  Modelica.Blocks.Interfaces.RealInput T_outdoorAir(unit="K", start=288.15) "K"
  Modelica.Blocks.Interfaces.RealInput X_outdoorAir(start=0.007)
    "kg of water/kg of dry air"
  Modelica.Blocks.Interfaces.RealInput T_extractAir(unit="K", start=296.15) "K"
  Modelica.Blocks.Interfaces.RealInput phi_extractAir(start=0.8)
    "relativ Humidity [Range: 0...1]"
  Modelica.Blocks.Interfaces.RealOutput phi_supply(start=0.8)
    "relativ Humidity [Range: 0...1]"
  Modelica.Blocks.Interfaces.RealInput T_supplyAir(unit="K", start=295.15)
    "K (use as PortIn)"
  Modelica.Blocks.Interfaces.RealInput phi_supplyAir[2](start={0.4,0.6})
    "relativ Humidity [Range: 0...1] (Vector: [1] min, [2] max)"
  Modelica.Blocks.Interfaces.RealOutput QflowC(unit="W", min=0, start=0.01)
    "The absorbed cooling power supplied from a cooling circuit [W]"
  Modelica.Blocks.Interfaces.RealOutput QflowH(unit="W", min=0, start=0.01)
    "The absorbed heating power supplied from a heating circuit [W]"
  Modelica.Blocks.Interfaces.RealOutput Pel(unit="W", min=0, start=1e-3)
    "The consumed electrical power supplied from the mains [W]"
  Modelica.Blocks.Interfaces.RealOutput Vflow_out(unit="m3/s",start=1e-3)
    "supply volume flow in m3/s"
  Modelica.Blocks.Interfaces.RealOutput T_supplyAirOut(unit="K", start=295.15)
    "K (use as PortOut)"
  Modelica.Blocks.Interfaces.RealInput Vflow_in_extractAir(unit="m3/s")
if use_Vflow_in_extractAir "Volume flow of extract air"
protected
  Modelica.Blocks.Interfaces.RealInput Vflow_in_extractAir_internal(unit="m3/s") "Needed to connect to conditional connector";
equation
  dehumidification = if dehumidificationSet and heating and cooling then dehumidificationSet else false;
  humidification = if humidificationSet and heating and cooling then humidificationSet else false;

  connect(Vflow_in_extractAir, Vflow_in_extractAir_internal);

  if not use_Vflow_in_extractAir then
    Vflow_in_extractAir_internal = Vflow_in;
  end if;
end PartialAHU;


Example to test all states of the AHU model - Play with the possible modes (boolean parameters for: heating, cooling, de-/humidification.

within AixLib.Airflow.AirHandlingUnit.Examples;
model AHU
  "Example to test all states of the AHU model - Play with the possible modes (boolean parameters for: heating, cooling, de-/humidification"
    extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.Sine tempOutside(
    amplitude=10,
    f=1/86400,
    phase=-3.1415/2,
    offset=292)
  Modelica.Blocks.Sources.Constant Vflow_in(k=100)
  Modelica.Blocks.Sources.Constant desiredT_sup(k=293)
  .AixLib.Airflow.AirHandlingUnit.AHU ahu(
    clockPeriodGeneric=30,
    heating=true,
    cooling=true,
    HRS=true)
  Modelica.Blocks.Sources.Constant phi_roomMin(k=0.47)
  Modelica.Blocks.Sources.Constant phi_roomMax(k=0.55)

  Modelica.Blocks.Sources.Sine waterLoadOutside(
    f=1/86400,
    offset=0.008,
    amplitude=0.002,
    phase=-0.054829518451402)
  Modelica.Blocks.Sources.Constant phi_RoomExtractAir(k=0.6)
  Modelica.Blocks.Sources.Sine tempAddInRoom(
    f=1/86400,
    amplitude=2,
    phase=-3.1415/4,
    offset=1.7)
  Modelica.Blocks.Math.Add addToExtractTemp
  Modelica.Blocks.Interfaces.RealOutput QFlowCool(
   final quantity="Power",
   final unit="W")
  Modelica.Blocks.Interfaces.RealOutput QFlowHeat(
   final quantity="Power",
   final unit="W")
  Modelica.Blocks.Interfaces.RealOutput PEl(
   final quantity="Power",
   final unit="W")
equation

  connect(desiredT_sup.y, ahu.T_supplyAir)
  connect(tempOutside.y, ahu.T_outdoorAir)
  connect(Vflow_in.y, ahu.Vflow_in)
  connect(phi_roomMin.y, ahu.phi_supplyAir[1])
  connect(waterLoadOutside.y, ahu.X_outdoorAir)
  connect(phi_RoomExtractAir.y, ahu.phi_extractAir)
  connect(phi_roomMax.y, ahu.phi_supplyAir[2])
  connect(ahu.T_extractAir, addToExtractTemp.y)
  connect(tempAddInRoom.y, addToExtractTemp.u1)
  connect(desiredT_sup.y, addToExtractTemp.u2)
  connect(ahu.QflowC, QFlowCool)
  connect(ahu.QflowH, QFlowHeat)
  connect(ahu.Pel, PEl)
end AHU;


within AixLib.Airflow.AirHandlingUnit;
package Examples "Contains examples for Air Handling Units"
extends Modelica.Icons.ExamplesPackage;
end Examples;


within AixLib.Airflow.FacadeVentilationUnit;
model FacadeVentilationUnit
  "Facade Ventilation Unit (FVU) equipped with a recuperator"
  replaceable package Water = AixLib.Media.Water
    "Water Model in the system";
  replaceable package Air = AixLib.Media.Air
    "Air Model in the system";

  parameter AixLib.Airflow.FacadeVentilationUnit.DataBase.FVUBaseRecord
    fVUParam=AixLib.Airflow.FacadeVentilationUnit.DataBase.FVUBaseRecord()
    "Record containing the characteristic parameters of the unit";

  parameter Modelica.Units.SI.ThermodynamicTemperature T_start=273.15 + 20
    "Initial temperature in unit";

  AixLib.Airflow.FacadeVentilationUnit.BaseClasses.SetPower fanExhaustAir(
    redeclare package Medium = Air,
    noUnits=fVUParam.noUnits,
    m_flow_nominal=fVUParam.m2_flow_nominal_heater,
    T_start=T_start,
    p_start=fVUParam.dp2_nominal_heater)
    "The fan on the exhaust air side"
  AixLib.Airflow.FacadeVentilationUnit.BaseClasses.SetPower fanSupplyAir(
    redeclare package Medium = Air,
    noUnits=fVUParam.noUnits,
    m_flow_nominal=fVUParam.m2_flow_nominal_heater,
    p_start=5*fVUParam.dp2_nominal_heater,
    dp_nominal=5*fVUParam.dp2_nominal_heater)
    "The fan on the supply air side"
  Modelica.Fluid.Sensors.Temperature extractAirTemperature(redeclare package Medium =
               Air) "Temperature of the extract air"
  AixLib.Fluid.HeatExchangers.ConstantEffectiveness heater(
    redeclare package Medium2 = Air,
    redeclare package Medium1 = Water,
    m1_flow_nominal=fVUParam.m1_flow_nominal_heater,
    m2_flow_nominal=fVUParam.m2_flow_nominal_heater,
    dp1_nominal(displayUnit="Pa") = fVUParam.dp1_nominal_heater,
    dp2_nominal(displayUnit="Pa") = fVUParam.dp2_nominal_heater)
    "The heat exchanger used for heating"
  Modelica.Fluid.Interfaces.FluidPort_b exhaustAirConnector(redeclare package Medium =
               Air) "Connector to the exhaust air sink"
  Modelica.Fluid.Interfaces.FluidPort_a freshAirConnector(redeclare package Medium =
               Air) "Connector to the fresh air source"
  Modelica.Fluid.Interfaces.FluidPort_a extractAirConnector(redeclare package Medium =
               Air) "Connector to the extract air source"
  Modelica.Fluid.Interfaces.FluidPort_b supplyAirConnector(redeclare package Medium =
               Air) "Connector to the supply air sink"
  AixLib.Fluid.HeatExchangers.ConstantEffectiveness cooler(
    redeclare package Medium2 = Air,
    redeclare package Medium1 = Water,
    dp1_nominal(displayUnit="Pa") = fVUParam.dp1_nominal_cooler,
    dp2_nominal(displayUnit="Pa") = fVUParam.dp2_nominal_cooler,
    m1_flow_nominal=fVUParam.m1_flow_nominal_cooler,
    m2_flow_nominal=fVUParam.m2_flow_nominal_cooler)
    "The heat exchanger used for cooling"
  Modelica.Fluid.Interfaces.FluidPort_b heaterReturnConnector(redeclare package
                                                                                Medium =
               Water) "Connector to the heating water sink"
  Modelica.Fluid.Interfaces.FluidPort_a heaterFlowConnector(redeclare package Medium =
               Water) "Connector to the heating water source"
  Modelica.Fluid.Interfaces.FluidPort_b coolerReturnConnector(redeclare package
                                                                                Medium =
               Water) "Connector to the cooling water source"
  Modelica.Fluid.Interfaces.FluidPort_a coolerFlowConnector(redeclare package Medium =
               Water) "Connector to the cooling water source"
  Modelica.Fluid.Sensors.Temperature freshAirTemperature(redeclare package Medium =
               Air) "Temperature of the fresh air"
  Modelica.Fluid.Sensors.Temperature exhaustAirTemperature(redeclare package Medium =
               Air) "Temperature of the exhaust air"
  Modelica.Fluid.Sensors.Temperature coolerTemperature(redeclare package Medium =
           Air) "Temperature of the supply air stream behind the cooler"
  Modelica.Fluid.Sensors.Temperature heatRecoveryTemperature(redeclare package Medium =
               Air) "Temperature behind the recuperator"

  Modelica.Blocks.Math.Add oppositeOpening(k1=-1)
    "Provides the relative opening of the complementary damper of the
    recuperator"
  Modelica.Blocks.Sources.Constant one(k=1) "Output the Real value 1 "
  Modelica.Fluid.Sensors.Temperature mixAirTemperature(redeclare package Medium =
           Air) "Temperature of the mixed circulation and fresh air streams"
  inner Modelica.Fluid.System system
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperCirculationAir(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeLong,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
                 "Damper that controls the air stream that is recirculated"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperBypass(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeLong,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
    "The second of two dampers that control the air flow through the
    recuperator"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperHeatRecovery(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeLong,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
    "The first of two dampers that control the air flow through the recuperator"
  Modelica.Fluid.Sensors.Temperature heaterTemperature(redeclare package Medium =
                Air) "Temperature of the supply air stream behind the heater"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperFreshAir(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeShort,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
                 "Can be used to disconnect the unit from fresh air source"
  AixLib.Fluid.HeatExchangers.ConstantEffectiveness recuperator(
    redeclare package Medium1 = Air,
    redeclare package Medium2 = Air,
    eps=0.6,
    m1_flow_nominal=fVUParam.m2_flow_nominal_heater,
    m2_flow_nominal=fVUParam.m2_flow_nominal_heater,
    dp1_nominal=fVUParam.dp2_nominal_heater,
    dp2_nominal=fVUParam.dp2_nominal_heater)
    "The heat exchanger used for recovering heat or cold from extract air
    stream"
  Modelica.Fluid.Vessels.ClosedVolume volume(
    nPorts=4,
    use_portsData=false,
    V=0.01,
    redeclare package Medium = Air,
    T_start=T_start)
    "Volume where the circulation air and the fresh air stream mix"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening heatingValve(
    redeclare package Medium = Water,
    riseTime=fVUParam.damperRiseTimeLong,
    dpValve_nominal=fVUParam.dp1_nominal_heater,
    m_flow_nominal=fVUParam.m1_flow_nominal_heater)
    "Valve controlling the heating water flow into the unit"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening coolingValve(
    redeclare package Medium = Water,
    riseTime=fVUParam.damperRiseTimeLong,
    dpValve_nominal=fVUParam.dp1_nominal_heater,
    m_flow_nominal=fVUParam.m1_flow_nominal_heater)
    "Valve controlling the cooling water flow into the unit"
  AixLib.Controls.Interfaces.FVUControlBus fVUControlBus
    "Bus with controller signals"
equation

  connect(cooler.port_b2, supplyAirConnector)
  connect(extractAirTemperature.port, extractAirConnector)
  connect(freshAirTemperature.port, freshAirConnector)
  connect(exhaustAirTemperature.port, fanExhaustAir.port_b)
  connect(cooler.port_b2, coolerTemperature.port)

  connect(oppositeOpening.u2, one.y)

  connect(mixAirTemperature.port, fanSupplyAir.port_a)
  connect(freshAirConnector, freshAirConnector)
  connect(oppositeOpening.y, damperBypass.y)
  connect(extractAirConnector, extractAirConnector)
  connect(heaterTemperature.port, heater.port_b2)
  connect(damperFreshAir.port_b, damperHeatRecovery.port_a)
  connect(freshAirConnector, damperFreshAir.port_a)
  connect(damperFreshAir.port_b, damperBypass.port_a)
  connect(fanSupplyAir.port_b, heater.port_a2)
  connect(extractAirConnector, recuperator.port_a2)
  connect(recuperator.port_b2, fanExhaustAir.port_a)
  connect(recuperator.port_b1, volume.ports[1])
  connect(damperBypass.port_b, volume.ports[2])
  connect(damperCirculationAir.port_b, volume.ports[3])
  connect(fanSupplyAir.port_a, volume.ports[4])
  connect(heatRecoveryTemperature.port, recuperator.port_b1)
  connect(heater.port_b2, cooler.port_a2)
  connect(heater.port_a1, heatingValve.port_a)
  connect(heatingValve.port_b, heaterFlowConnector)
  connect(coolerReturnConnector, cooler.port_b1)
  connect(cooler.port_a1, coolingValve.port_a)
  connect(coolingValve.port_b, coolerFlowConnector)
  connect(heaterReturnConnector, heater.port_b1)
  connect(extractAirConnector, damperCirculationAir.port_a)
  connect(damperCirculationAir.y, fVUControlBus.circulationDamperOpening)
  connect(fanSupplyAir.powerShare, fVUControlBus.fanSupplyAirPower)
  connect(fanExhaustAir.powerShare, fVUControlBus.fanExhaustAirPower)
  connect(damperFreshAir.y, fVUControlBus.freshAirDamperOpening)
  connect(damperHeatRecovery.y, fVUControlBus.hRCDamperOpening)
  connect(oppositeOpening.u1, fVUControlBus.hRCDamperOpening)
  connect(heatingValve.y, fVUControlBus.heatingValveOpening)
  connect(coolingValve.y, fVUControlBus.coolingValveOpening)
  connect(damperHeatRecovery.port_b, recuperator.port_a1)
  connect(fanExhaustAir.port_b, exhaustAirConnector)
  connect(coolerTemperature.T, fVUControlBus.supplyTemperature)
  connect(mixAirTemperature.T, fVUControlBus.mixTemperature)
end FacadeVentilationUnit;


within AixLib.Airflow;
package FacadeVentilationUnit "Package for decentralized air handling unit"
end FacadeVentilationUnit;


within AixLib.Airflow.FacadeVentilationUnit.BaseClasses;
model SetPower
  "This model defines a specific mass flow rate based on the input power
    share"

  extends Modelica.Fluid.Interfaces.PartialTwoPort;

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.05
    "Nominal mass flow rate of fan";
  parameter Medium.AbsolutePressure p_start=Medium.p_default
    "Start value of pressure";
  parameter Integer noUnits=1 "Number of identical FVU units";
  parameter Modelica.Units.SI.PressureDifference dp_nominal=500
    "Initial pressure difference";
  parameter Medium.Temperature T_start=Medium.T_default
    "Start value of temperature";

  Modelica.Blocks.Tables.CombiTable1Dv volumeFlow(table=[0,1; 0.1,25; 0.2,40;
        0.3,60; 0.4,90; 0.5,100; 0.6,140; 0.7,175; 0.8,200; 0.9,225; 1,260])
    "Correlates the relative input signal and a volume flow rate"
  Modelica.Blocks.Interfaces.RealInput powerShare(
    min=0,
    max=1,
    nominal=0.6) "Power share 0..1 for fan"

  AixLib.Fluid.Movers.FlowControlled_m_flow fan(
    redeclare package Medium = Medium,
    addPowerToMedium=false,
    m_flow_nominal=m_flow_nominal,
    T_start=T_start,
    m_flow(start=m_flow_nominal),
    dp(start=dp_nominal),
    dp_nominal=dp_nominal,
    p_start=p_start,
    riseTime=120,
    nominalValuesDefineDefaultPressureCurve=true)
    "Mass-flow-controlled mover setting mass flow rate from table"
  Modelica.Blocks.Math.Gain transforMassFlow(k=1.2/3600*noUnits, y(unit="kg/s"))
    "Used to transform the volume flow rate in m3/h into a mass flow rate in kg/s"
equation

  connect(port_a, fan.port_a)
  connect(fan.port_b, port_b)
  connect(powerShare, volumeFlow.u[1])
  connect(transforMassFlow.u, volumeFlow.y[1])
  connect(transforMassFlow.y, fan.m_flow_in)
end SetPower;


within AixLib.Airflow.FacadeVentilationUnit;
package DataBase "Contains parameter records of the facade ventilation unit"
extends Modelica.Icons.Package;
end DataBase;


within AixLib.Airflow.FacadeVentilationUnit.Examples;
model FacadeVentilationUnit
  "Example showing the use of facade ventilation unit and controller"
  extends Modelica.Icons.Example;

  package Medium1 = AixLib.Media.Air;
  package Medium2 = AixLib.Media.Water;

  AixLib.Controls.AirHandling.FVUController FVUController(
      maxSupFanPower=0.6,
      maxExFanPower=0.6)
    "Comprehensive rule-based controller for the facade ventilation unit"
  AixLib.Airflow.FacadeVentilationUnit.FacadeVentilationUnit FVU(redeclare
      package                                                                      Air =
                    Medium1, redeclare package Water = Medium2)
    "The facade ventilation unit to be tested in this example"
  AixLib.Fluid.Sources.Boundary_pT freshAirSource(
    nPorts=1,
    redeclare package Medium = Medium1,
    use_T_in=true,
    p(displayUnit="Pa") = 101300) "Sink of the exhaust air"
  AixLib.Fluid.Sources.Boundary_pT exhaustAirSink(
    nPorts=1,
    redeclare package Medium = Medium1,
    p(displayUnit="Pa") = 101300) "Source of freah air"
  AixLib.Fluid.Sources.Boundary_pT heatingSnk(
    redeclare package Medium = Medium2,
    nPorts=1,
    p=100000) "Sink of the heating water"
  AixLib.Fluid.Sources.Boundary_pT coolingSink(
    redeclare package Medium = Medium2,
    nPorts=1,
    p=100000) "Sink of the cooling water"
  AixLib.Fluid.Sources.Boundary_pT coolingSource(
    redeclare package Medium = Medium2,
    use_T_in=true,
    nPorts=1,
    p=101000) "Source of the cooling water"
  AixLib.Fluid.Sources.Boundary_pT heatingSource(
    redeclare package Medium = Medium2,
    use_T_in=true,
    nPorts=1,
    p=101000) "Source of the heating water"
  AixLib.Fluid.Sources.Boundary_pT supplyAirSink(
    redeclare package Medium = Medium1,
    use_T_in=false,
    nPorts=1,
    p(displayUnit="Pa") = 101300) "Sink of the supply air"
  AixLib.Fluid.Sources.Boundary_pT extractAirSource(
    nPorts=1,
    redeclare package Medium = Medium1,
    use_T_in=true,
    p(displayUnit="Pa") = 101300) "Source of the extract air"
  Modelica.Blocks.Sources.Constant heatingWaterTemperature(k=273.15 + 30)
    "Provides a test value of the heating water temperatrure"
  Modelica.Blocks.Sources.Constant coolingWaterTemperature(k=273.15 + 17)
    "Provides a test value of the cooling water temperatiure"
  AixLib.Fluid.Sensors.TemperatureTwoPort supplyAirTemperature(redeclare
      package                                                                    Medium =
                       Medium1, m_flow_nominal=0.1)
    "Measures the supply air temperature"
  Modelica.Blocks.Sources.Sine roomTemperature(
    amplitude=5,
    f=1/86400,
    phase=3.1415926535898,
    offset=273.15 + 20) "Provides a test value of the room temperature"
  Modelica.Blocks.Sources.Sine roomSetTemperature(
    amplitude=5,
    f=1/86400,
    phase=1.5707963267949,
    offset=273.15 + 20) "Provides a test value of the room set temperature"
  Modelica.Blocks.Sources.Constant co2Concentration(k=1000)
    "Provides a test value of the CO2 concnetration"
  Modelica.Blocks.Sources.Sine outdoorTemperature(
    amplitude=5,
    f=1/86400,
    offset=273.15 + 10) "Provides a test value of the outdoor temperature"
  AixLib.Controls.Interfaces.FVUControlBus fVUControlBus
  "Bus with controller sginals"
equation
  connect(FVU.extractAirConnector, extractAirSource.ports[1])
  connect(heatingSnk.ports[1], FVU.heaterReturnConnector)
  connect(coolingSource.ports[1], FVU.coolerFlowConnector)
  connect(heatingWaterTemperature.y, heatingSource.T_in)
  connect(coolingWaterTemperature.y, coolingSource.T_in)
  connect(FVU.coolerReturnConnector, coolingSink.ports[1])
  connect(heatingSource.ports[1], FVU.heaterFlowConnector)
  connect(exhaustAirSink.ports[1], FVU.exhaustAirConnector)
  connect(freshAirSource.ports[1], FVU.freshAirConnector)
  connect(FVU.supplyAirConnector, supplyAirTemperature.port_a)
  connect(supplyAirTemperature.port_b, supplyAirSink.ports[1])
  connect(FVU.fVUControlBus, FVUController.fVUControlBus)
  connect(FVUController.fVUControlBus, fVUControlBus)
  connect(roomTemperature.y, extractAirSource.T_in)
  connect(outdoorTemperature.y,freshAirSource. T_in)
  connect(roomTemperature.y, fVUControlBus.roomTemperature)
  connect(outdoorTemperature.y, fVUControlBus.outdoorTemperature)
  connect(roomSetTemperature.y, fVUControlBus.roomSetTemperature)
  connect(co2Concentration.y, fVUControlBus.co2Concentration)
end FacadeVentilationUnit;


Powerlaw with coefficient for mass flow rate. This model describes the one-directional pressure driven air flow through an opening, using the equation

within AixLib.Airflow.Multizone;
model Coefficient_m_flow "Powerlaw with coefficient for mass flow rate"
  extends AixLib.Airflow.Multizone.BaseClasses.PartialOneWayFlowElement(
    m_flow=rho*AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
        C=C,
        dp=dp,
        m=m,
        a=a,
        b=b,
        c=c,
        d=d,
        dp_turbulent=dp_turbulent),
    final m_flow_nominal=k*dp_turbulent,
    final m_flow_small=1E-4*abs(m_flow_nominal));
  extends AixLib.Airflow.Multizone.BaseClasses.PowerLawResistanceParameters(
    m = 0.5);
  parameter Real k "Flow coefficient, k = m_flow/ dp^m";
protected
  parameter Real C=k/rho_default "Flow coefficient, C = V_flow/dp^m";
end Coefficient_m_flow;


Power law with coefficient for volume flow rate. This model describes the one-directional pressure driven air flow through an opening, using the equation

within AixLib.Airflow.Multizone;
model Coefficient_V_flow "Power law with coefficient for volume flow rate"
  extends AixLib.Airflow.Multizone.BaseClasses.PartialOneWayFlowElement(
    m_flow = V_flow*rho,
    V_flow = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
      C=C,
      dp=dp,
      m=m,
      a=a,
      b=b,
      c=c,
      d=d,
      dp_turbulent=dp_turbulent),
    final m_flow_nominal=rho_default*C*dp_turbulent,
    final m_flow_small=1E-4*abs(m_flow_nominal));
   extends AixLib.Airflow.Multizone.BaseClasses.PowerLawResistanceParameters(
     m = 0.5);

  parameter Real C "Flow coefficient, C = V_flow/ dp^m";
end Coefficient_V_flow;


Door model using discretization along height coordinate. This model describes the bi-directional air flow through an open door.

within AixLib.Airflow.Multizone;
model DoorDiscretizedOpen
  "Door model using discretization along height coordinate"
  extends AixLib.Airflow.Multizone.BaseClasses.DoorDiscretized;

  parameter Real CD=0.65 "Discharge coefficient"

protected
  constant Real mFixed = 0.5 "Fixed value for flow coefficient";
  constant Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  constant Real a = gamma
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real b = 1/8*mFixed^2 - 3*gamma - 3/2*mFixed + 35.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real c = -1/4*mFixed^2 + 3*gamma + 5/2*mFixed - 21.0/4
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real d = 1/8*mFixed^2 - gamma - mFixed + 15.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
equation
  m=mFixed;
  A = wOpe*hOpe;
  CVal = CD*dA*sqrt(2/rho_default);
  // orifice equation
  for i in 1:nCom loop
    dV_flow[i] = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
      C=CVal,
      dp=dpAB[i],
      m=mFixed,
      a=a,
      b=b,
      c=c,
      d=d,
      dp_turbulent=dp_turbulent);
  end for;
end DoorDiscretizedOpen;


within AixLib.Airflow.Multizone;
model DoorDiscretizedOperable
  "Door model using discretization along height coordinate"
  extends AixLib.Airflow.Multizone.BaseClasses.DoorDiscretized;

  parameter Modelica.Units.SI.PressureDifference dpCloRat(
    min=0,
    displayUnit="Pa") = 4 "Pressure drop at rating condition of closed door"

  parameter Real CDCloRat(min=0, max=1)=1
    "Discharge coefficient at rating conditions of closed door"

  parameter Modelica.Units.SI.Area LClo(min=0)
    "Effective leakage area of closed door"

  parameter Real CDOpe=0.65 "Discharge coefficient of open door"
  parameter Real CDClo=0.65 "Discharge coefficient of closed door"

  parameter Real mOpe = 0.5 "Flow exponent for door of open door"
  parameter Real mClo= 0.65 "Flow exponent for crack of closed door"

  Modelica.Blocks.Interfaces.RealInput y(min=0, max=1, unit="1")
    "Opening signal, 0=closed, 1=open"
protected
  parameter Modelica.Units.SI.Area AOpe=wOpe*hOpe "Open aperture area";
  parameter Modelica.Units.SI.Area AClo(fixed=false) "Closed aperture area";

  Real COpe "Open aperture flow coefficient, C = V_flow/ dp^m";
  Real CClo "Closed aperture flow coefficient, C = V_flow/ dp^m";

 Real fraOpe "Fraction of aperture that is open";
initial equation
  AClo=CDClo/CDCloRat * LClo * dpCloRat^(0.5-mClo);
equation
  fraOpe =y;
  CClo = CDClo * AClo/nCom * sqrt(2/rho_default);
  COpe = CDOpe * AOpe/nCom * sqrt(2/rho_default);

  // flow exponent
  m    = fraOpe*mOpe + (1-fraOpe)*mClo;
  // opening area
  A = fraOpe*AOpe + (1-fraOpe)*AClo;
  // friction coefficient for power law
  CVal = fraOpe*COpe + (1-fraOpe)*CClo;

  // orifice equation
  for i in 1:nCom loop
    dV_flow[i] = AixLib.Airflow.Multizone.BaseClasses.powerLaw(C=CVal,
      dp=dpAB[i],
      m=m,
      dp_turbulent=dp_turbulent);
  end for;
end DoorDiscretizedOperable;


Door model for bi-directional air flow between rooms. Model for bi-directional air flow through a large opening such as a door.

within AixLib.Airflow.Multizone;
model DoorOpen
  "Door model for bi-directional air flow between rooms"
  extends AixLib.Airflow.Multizone.BaseClasses.Door(
    final vAB = VAB_flow/AOpe,
    final vBA = VBA_flow/AOpe);

  parameter Real CD=0.65 "Discharge coefficient"

  parameter Real m = 0.5 "Flow coefficient"

protected
  constant Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  constant Real a = gamma
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real b = 1/8*m^2 - 3*gamma - 3/2*m + 35.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real c = -1/4*m^2 + 3*gamma + 5/2*m - 21.0/4
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real d = 1/8*m^2 - gamma - m + 15.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";

  parameter Real CVal=CD*AOpe*sqrt(2/rho_default)
    "Flow coefficient, C = V_flow/ dp^m";
  parameter Real kT = rho_default * CD * AOpe/3 *
    sqrt(Modelica.Constants.g_n /(Medium.T_default*conTP) * hOpe)
    "Constant coefficient for buoyancy driven air flow rate";

  parameter Modelica.Units.SI.MassFlowRate m_flow_turbulent=CVal*rho_default*
      sqrt(dp_turbulent)
    "Mass flow rate where regularization to laminar flow occurs for temperature-driven flow";

equation
  // Air flow rate due to static pressure difference
  VABp_flow = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(C=CVal,
      dp=port_a1.p-port_a2.p,
      m=m,
      a=a,
      b=b,
      c=c,
      d=d,
      dp_turbulent=dp_turbulent);
  // Air flow rate due to buoyancy
  // Because powerLawFixedM requires as an input a pressure difference pa-pb,
  // we convert Ta-Tb by multiplying it with rho*R, and we divide
  // above the constant expression by (rho*R)^m on the right hand-side of kT.
  // Note that here, k is for mass flow rate, whereas in powerLawFixedM, it is for volume flow rate.
  // We can use m=0.5 as this is from Bernoulli.
  mABt_flow = AixLib.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp(
      k=kT,
      dp=conTP*(Medium.temperature(state_a1_inflow)-Medium.temperature(state_a2_inflow)),
      m_flow_turbulent=m_flow_turbulent);
end DoorOpen;


Door model for bi-directional air flow between rooms that can be open or closed. Model for bi-directional air flow through a large opening such as a door which can be opened or closed
based on the control input signal <i>y</i>.

within AixLib.Airflow.Multizone;
model DoorOperable
  "Door model for bi-directional air flow between rooms that can be open or closed"
  extends AixLib.Airflow.Multizone.BaseClasses.Door(
    final vAB = VAB_flow/A,
    final vBA = VBA_flow/A);

  parameter Real CDOpe=0.65 "Discharge coefficient of open door"

  parameter Real mOpe = 0.5 "Flow exponent for door of open door"

  parameter Modelica.Units.SI.Area LClo(min=0)
    "Effective leakage area of closed door"

  parameter Real mClo= 0.65 "Flow exponent for crack of closed door"

  parameter Modelica.Units.SI.PressureDifference dpCloRat(
    min=0,
    displayUnit="Pa") = 4 "Pressure drop at rating condition of closed door"

  parameter Real CDCloRat(min=0, max=1)=1
    "Discharge coefficient at rating conditions of closed door"

  Modelica.Blocks.Interfaces.RealInput y(min=0, max=1, unit="1")
    "Opening signal, 0=closed, 1=open"

protected
  parameter Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  parameter Real[2] a = {gamma, gamma}
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real b[2] = {1/8*m^2 - 3*gamma - 3/2*m + 35.0/8 for m in {mOpe, mClo}}
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real c[2] = {-1/4*m^2 + 3*gamma + 5/2*m - 21.0/4 for m in {mOpe, mClo}}
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real d[2] = {1/8*m^2 - gamma - m + 15.0/8 for m in {mOpe, mClo}}
    "Polynomial coefficient for regularized implementation of flow resistance";

  parameter Modelica.Units.SI.Area AClo=LClo*dpCloRat^(0.5 - mClo)
    "Closed area";
  parameter Real CVal[2]=
    {CDOpe*AOpe*sqrt(2/rho_default),
    CDCloRat*AClo*sqrt(2/rho_default)}
    "Flow coefficient, C = V_flow/ dp^m";

  parameter Real kT = rho_default * CDOpe * AOpe/3 *
    sqrt(Modelica.Constants.g_n /(Medium.T_default*conTP) * hOpe)
    "Constant coefficient for buoyancy driven air flow rate";

  parameter Modelica.Units.SI.MassFlowRate m_flow_turbulent=CVal[1]*rho_default
      *sqrt(dp_turbulent)
    "Mass flow rate where regularization to laminar flow occurs for temperature-driven flow";

  Modelica.Units.SI.VolumeFlowRate VABpOpeClo_flow[2](each nominal=0.001)
    "Volume flow rate from A to B if positive due to static pressure difference";

  Modelica.Units.SI.Area A "Current opening area";
equation
  // Air flow rate due to static pressure difference
  VABpOpeClo_flow = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
    C=CVal,
    dp=port_a1.p-port_a2.p,
    m={mOpe, mClo},
    a=a,
    b=b,
    c=c,
    d=d,
    dp_turbulent=dp_turbulent);
  VABp_flow = y*VABpOpeClo_flow[1] + (1-y)*VABpOpeClo_flow[2];
  A = y*AOpe + (1-y)*AClo;
  // Air flow rate due to buoyancy
  // Because powerLawFixedM requires as an input a pressure difference pa-pb,
  // we convert Ta-Tb by multiplying it with rho*R, and we divide
  // above the constant expression by (rho*R)^m on the right hand-side of kT.
  mABt_flow = y*AixLib.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp(
      k=kT,
      dp=conTP*(Medium.temperature(state_a1_inflow)-Medium.temperature(state_a2_inflow)),
      m_flow_turbulent=m_flow_turbulent);
end DoorOperable;


Effective air leakage area. This model describes the one-directional pressure driven
air flow through a crack-like opening, using the equation

within AixLib.Airflow.Multizone;
model EffectiveAirLeakageArea "Effective air leakage area"
  extends AixLib.Airflow.Multizone.Coefficient_V_flow(
    m=0.65,
    final C=L * CDRat * sqrt(2.0/rho_default) * dpRat^(0.5-m));

  parameter Modelica.Units.SI.PressureDifference dpRat(
    min=0,
    displayUnit="Pa") = 4 "Pressure drop"
  parameter Real CDRat(
    min=0,
    max=1) = 1 "Discharge coefficient"

  parameter Modelica.Units.SI.Area L(min=0) "Effective leakage area";

  Modelica.Units.SI.Velocity v(nominal=1) = V_flow/L "Average velocity";
end EffectiveAirLeakageArea;