Converts the simulation time to calendar time in scale of 1 year (365 days), or a multiple of a year. This component converts the simulation time to calendar time in a scale of 1 year (365 days),
or a multiple of it, if this is the length of the weather file.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block ConvertTime
  "Converts the simulation time to calendar time in scale of 1 year (365 days), or a multiple of a year"
  extends PartialConvertTime;
  Modelica.Blocks.Interfaces.RealInput modTim(
    final quantity="Time",
    final unit="s") "Simulation time"
  Modelica.Blocks.Interfaces.RealOutput calTim(
    final quantity="Time",
    final unit="s") "Calendar time"

protected
  constant Modelica.Units.SI.Time shiftSolarRad=1800
    "Number of seconds for the shift for solar radiation calculation";

equation
  calTim = calTimAux;
  modTimAux = modTim;
  assert(canRepeatWeatherFile or noEvent((time - weaDatEndTim) < shiftSolarRad),
    "In " + getInstanceName() + ": Insufficient weather data provided for the desired simulation period.
    The simulation time " + String(time) +
    " exceeds the end time " + String(weaDatEndTim) + " of the weather data file.",
    AssertionLevel.error);

  assert(canRepeatWeatherFile or noEvent(time >= weaDatStaTim),
    "In " + getInstanceName() + ": Insufficient weather data provided for the desired simulation period.
    The simulation time " + String(time) +
    " is less than the start time " + String(weaDatStaTim) + " of the weather data file.",
    AssertionLevel.error);
end ConvertTime;


Equation of time. This component computes the difference between solar noon and noon of local civil time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block EquationOfTime "Equation of time"
  extends PartialConvertTime;
  Modelica.Blocks.Interfaces.RealInput nDay(
    quantity="Time",
    unit="s")
    "Zero-based day number in seconds (January 1=0, January 2=86400)"
  Modelica.Blocks.Interfaces.RealOutput eqnTim(
    final quantity="Time",
    final unit="s",
    displayUnit="min") "Equation of time"
protected
  Real Bt "Intermediate variable";
equation
  modTimAux = nDay;
  Bt = Modelica.Constants.pi*((calTimAux + 86400)/86400 - 81)/182
    "Our unit is s instead of day in (A.4.2b)";
  eqnTim = 60*(9.87*Modelica.Math.sin(2*Bt) - 7.53*Modelica.Math.cos(Bt) - 1.5*
    Modelica.Math.sin(Bt)) "Our unit is s instead of min in (A.4.2a)";
end EquationOfTime;


Block that limits the relative humidity. Block that limits the cloud cover ceiling height to be positive.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterCeilingHeight "Block that limits the relative humidity"
  extends PartialLimiterMin;

  Modelica.Blocks.Interfaces.RealOutput ceiHei(
    final unit="m") = max(0, u) "Cloud cover ceiling height"
end LimiterCeilingHeight;


Block that limits the horizontal infrared irradiation. Block that limits the horizontal infrared irradiation to be positive.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterHorizontalInfraredIrradiation
  "Block that limits the horizontal infrared irradiation"
  extends PartialLimiterMin;

  Modelica.Blocks.Interfaces.RealOutput HHorIR(
    final unit="W/m2") = max(0, u) "Horizontal infrared irradiation"
end LimiterHorizontalInfraredIrradiation;


Block that limits the opaque sky cover. Block that limits the opaque sky cover.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterOpaqueSkyCover "Block that limits the opaque sky cover"
  extends PartialLimiter;

  Modelica.Blocks.Interfaces.RealOutput nOpa(
    final unit="1") "Opaque sky cover"

equation
  nOpa = min(uMax, max(uMin, u));
end LimiterOpaqueSkyCover;


Block that limits the relative humidity. Block that limits the relative humidity.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterRelativeHumidity "Block that limits the relative humidity"
  extends PartialLimiter;

  Modelica.Blocks.Interfaces.RealOutput relHum(
    final unit="1") "Relative humidity"

equation
  relHum = min(uMax, max(uMin, u));
end LimiterRelativeHumidity;


Block that limits the total sky cover. Block that limits the total sky cover.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterTotalSkyCover "Block that limits the total sky cover"
  extends PartialLimiter;

  Modelica.Blocks.Interfaces.RealOutput nTot(
    final unit="1") "Total sky cover"

equation
  nTot = min(uMax, max(uMin, u));
end LimiterTotalSkyCover;


Block that limits the wind direction. Block that limits the wind direction.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterWindDirection "Block that limits the wind direction"
  extends PartialLimiter(
    final uMax=2*Modelica.Constants.pi);

  Modelica.Blocks.Interfaces.RealOutput winDir(
    final unit="rad") "Wind direction"

equation
  winDir = min(uMax, max(uMin, u));
end LimiterWindDirection;


Block that limits the wind speed. Block that limits the wind speed to be positive.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LimiterWindSpeed "Block that limits the wind speed"
  extends PartialLimiterMin;

  Modelica.Blocks.Interfaces.RealOutput winSpe(
    final unit="m/s") = max(0, u) "Wind speed"
end LimiterWindSpeed;


Converts the clock time to local civil time.. This component converts the clock time to local civil time.
The parameter timZon represents the time zone of the facility  (relative to Greenwich Mean Time or the 0th meridian). Time zones west of GMT (e.g. North America) are represented as negative;
east of GMT as positive. Fraction of hours are represented in decimals (e.g. for 6:30, use 6.5).

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block LocalCivilTime "Converts the clock time to local civil time."
  extends PartialConvertTime;
  Modelica.Blocks.Interfaces.RealInput cloTim(
    final quantity="Time",
    final unit="s") "Clock time"
  parameter Modelica.Units.SI.Time timZon(displayUnit="h") "Time zone";
  parameter Modelica.Units.SI.Angle lon(displayUnit="deg") "Longitude";
  Modelica.Blocks.Interfaces.RealOutput locTim(
    final quantity="Time",
    final unit="s") "Local civil time"
protected
  final parameter Modelica.Units.SI.Time diff=-timZon + lon*43200/Modelica.Constants.pi
    "Difference between local and clock time";
equation
  modTimAux = cloTim;
  locTim = calTimAux + diff;
end LocalCivilTime;


within Buildings.BoundaryConditions.WeatherData;
package BaseClasses "Package with base classes for Buildings.BoundaryConditions.WeatherData"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.BoundaryConditions.WeatherData.BaseClasses;
partial block PartialConvertTime
  "Converts the simulation time to calendar time in scale of 1 year (365 days), or a multiple of a year"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.Time weaDatStaTim(displayUnit="d") = 0
    "Start time of weather data";
  parameter Modelica.Units.SI.Time weaDatEndTim(displayUnit="d") = 31536000
    "End time of weather data";
  Modelica.Units.SI.Time modTimAux "Model time";
  Modelica.Units.SI.Time calTimAux "Calendar time";

protected
  parameter Modelica.Units.SI.Time lenWea=weaDatEndTim - weaDatStaTim
    "Length of weather data";

  parameter Boolean canRepeatWeatherFile = abs(mod(lenWea, 365*24*3600)) < 1E-2
    "=true, if the weather file can be repeated, since it has the length of a year or a multiple of it";

  discrete Modelica.Units.SI.Time tNext(start=0, fixed=true)
    "Start time of next period";

equation
  when {initial(), canRepeatWeatherFile and modTimAux > pre(tNext)} then
    // simulation time stamp went over the end time of the weather file
    //(last time stamp of the weather file + average increment)
    tNext = if canRepeatWeatherFile then integer(modTimAux/lenWea)*lenWea + lenWea else time;
  end when;
  calTimAux = if canRepeatWeatherFile then modTimAux - tNext + lenWea else modTimAux;
end PartialConvertTime;


Partial block to limit a signal. Block that computes y_internal=min(uMax, max(uMin, u)),
where y_internal is a protected connector.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
partial block PartialLimiter
  "Partial block to limit a signal"
  extends Modelica.Blocks.Icons.Block;

  constant Real uMin = 0 "Minimum value";
  constant Real uMax = 1 "Maximum value";

  Modelica.Blocks.Interfaces.RealInput u "Connector of Real input signal"
end PartialLimiter;


Partial block to limit a signal. Partial block that is used to limit a signal by a minimum value.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
partial block PartialLimiterMin
  "Partial block to limit a signal"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Interfaces.RealInput u "Connector of Real input signal"
end PartialLimiterMin;


Solar time. This component computes the local solar time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block SolarTime "Solar time"
  extends Modelica.Blocks.Icons.Block;
  Modelica.Blocks.Interfaces.RealInput locTim(quantity="Time", unit="s")
    "Local time"
  Modelica.Blocks.Interfaces.RealInput equTim(quantity="Time", unit="s")
    "Equation of time"
  Modelica.Blocks.Interfaces.RealOutput solTim(
    final quantity="Time",
    final unit="s",
    displayUnit="s") "Solar time"
equation
  solTim = locTim + equTim "Our unit is s in stead of h in (A.4.3)";
end SolarTime;


Block that selects as its output either a parameter value or its input. Block that produces at its output the input value uCon, uFil
or the parameter value p depending on the parameter value
datSou.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block SourceSelector
  "Block that selects as its output either a parameter value or its input"
  extends Modelica.Blocks.Interfaces.SO;
  parameter Buildings.BoundaryConditions.Types.DataSource datSou "Data source"
  parameter Real p "Parameter value";
  Modelica.Blocks.Interfaces.RealInput uFil
   if datSou == Buildings.BoundaryConditions.Types.DataSource.File
    "Input signal from file reader"
  Modelica.Blocks.Interfaces.RealInput uCon
  if datSou == Buildings.BoundaryConditions.Types.DataSource.Input
    "Input signal from input connector"
equation
  if datSou == Buildings.BoundaryConditions.Types.DataSource.Parameter then
    y = p;
  end if;
  connect(uCon, y);
  connect(uFil, y);
end SourceSelector;


Block that selects the solar radiation source and outputs the solar radiation quantities. Block that outputs the direct normal, diffuse horizontal and diffuse global
solar irradiation.
This block computes these output quantities based on conditionally provided
input signals.

within Buildings.BoundaryConditions.WeatherData.BaseClasses;
block SourceSelectorRadiation
  "Block that selects the solar radiation source and outputs the solar radiation quantities"
  extends Modelica.Blocks.Icons.Block;
  parameter Buildings.BoundaryConditions.Types.RadiationDataSource datSou "Data source"

  Modelica.Blocks.Interfaces.RealInput HDirNorFil(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
   if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.File
    "Direct normal solar irradiation from weather data file"

  Modelica.Blocks.Interfaces.RealInput HDirNorIn(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
   if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HDirNor_HDifHor or
      datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HDirNor_HGloHor
    "Direct normal solar irradiation from input connector"

  Modelica.Blocks.Interfaces.RealInput HDifHorFil(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
  if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.File
    "Diffuse horizontal solar irradiation from weather data file"

  Modelica.Blocks.Interfaces.RealInput HDifHorIn(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
  if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HGloHor_HDifHor or
     datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HDirNor_HDifHor
    "Diffuse horizontal solar irradiation from input connector"

  Modelica.Blocks.Interfaces.RealInput HGloHorFil(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
   if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.File
    "Global horizontal solar irradiation from weather data file"

  Modelica.Blocks.Interfaces.RealInput HGloHorIn(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
   if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HGloHor_HDifHor or
      datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HDirNor_HGloHor
    "Global horizontal solar irradiation from input connector"

  Modelica.Blocks.Interfaces.RealInput zen(
    final quantity="Angle",
    final unit="rad")
    "Zenith angle"

  Modelica.Blocks.Interfaces.RealOutput HDirNor(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
    "Direct normal solar irradiation"
  Modelica.Blocks.Interfaces.RealOutput HDifHor(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
    "Diffuse horizontal solar irradiation"
  Modelica.Blocks.Interfaces.RealOutput HGloHor(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2")
    "Global horizontal solar irradiation"

protected
  constant Real epsCos = 1e-6 "Small value to avoid division by 0";
  constant Modelica.Units.SI.HeatFlux solCon=1367.7 "Solar constant";

  // Conditional connectors
  Modelica.Blocks.Interfaces.RealInput HGloHor_in_internal(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2") "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput HDifHor_in_internal(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2") "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput HDirNor_in_internal(
    final quantity="RadiantEnergyFluenceRate",
    final unit="W/m2") "Needed to connect to conditional connector";

equation
  // Conditional connect statements
  connect(HGloHor_in_internal, HGloHorFil);
  connect(HDifHor_in_internal, HDifHorFil);
  connect(HDirNor_in_internal, HDirNorFil);
  connect(HGloHor_in_internal, HGloHorIn);
  connect(HDifHor_in_internal, HDifHorIn);
  connect(HDirNor_in_internal, HDirNorIn);

  //---------------------------------------------------------------------------
  // Select global horizontal radiation connector
  if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HDirNor_HDifHor then
    HGloHor = max(0, HDirNor_in_internal*cos(zen)+HDifHor_in_internal)
      "Calculate the HGloHor using HDirNor and HDifHor according to (A.4.14) and (A.4.15)";
    HGloHor_in_internal = 0;
  else
    HGloHor = max(0, HGloHor_in_internal)
      "Get HGloHor using weather data file or input connector of weather data reader";
  end if;

  //---------------------------------------------------------------------------
  // Select diffuse horizontal radiation connector
  if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HDirNor_HGloHor then
    HDifHor = max(0, HGloHor_in_internal - HDirNor_in_internal*cos(zen))
      "Calculate the HGloHor using HDirNor and HDifHor according to (A.4.14) and (A.4.15)";
    HDifHor_in_internal = 0;
  else
    HDifHor = max(0, HDifHor_in_internal)
      "Get HDifHor using weather data file or input connector of weather data reader";
  end if;

  //---------------------------------------------------------------------------
  // Select direct normal radiation connector
  if datSou == Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HGloHor_HDifHor then
      HDirNor = max(0, min(
        solCon,
        (HGloHor_in_internal -HDifHor_in_internal)*
          Buildings.Utilities.Math.Functions.spliceFunction(
            x=cos(zen),
            pos=Buildings.Utilities.Math.Functions.inverseXRegularized(cos(zen), epsCos),
            neg=0,
            deltax=epsCos)))
      "Calculate the HDirNor using HGloHor and HDifHor according to (A.4.14) and (A.4.15)";
    HDirNor_in_internal = 0;
  else
    HDirNor = max(0, HDirNor_in_internal)
      "Get HDirNor using weather data file or input connector of weather data reader";
  end if;
end SourceSelectorRadiation;


Test model for CheckBlackBodySkyTemperature. This example tests the model that checks the black-body sky temperature.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model CheckBlackBodySkyTemperature
  "Test model for CheckBlackBodySkyTemperature"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.BaseClasses.CheckBlackBodySkyTemperature
    cheSkyBlaBodTem "Check for the black body sky temperature"
  Modelica.Blocks.Sources.Ramp TBlaBod(
    height=140-0.02,
    duration=1,
    offset=273.15 - 69.99) "Black body sky temperature"
equation
  connect(TBlaBod.y, cheSkyBlaBodTem.TIn)
end CheckBlackBodySkyTemperature;


Test model for pressure check. This example tests the model that asserts that the pressure is within acceptable bounds.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model CheckPressure "Test model for pressure check"
  extends Modelica.Icons.Example;

  Buildings.BoundaryConditions.WeatherData.BaseClasses.CheckPressure chePre
    "Block that checks the pressure"
  Buildings.Utilities.Time.ModelTime modTim
    "Block that outputs simulation time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.ConvertTime conTim(
    weaDatStaTim=0,
    weaDatEndTim=31536000)
    "Block that converts time"
protected
  Modelica.Blocks.Tables.CombiTable1Ds datRea(
    tableOnFile=true,
    tableName="tab1",
    fileName=Modelica.Utilities.Files.loadResource(
       Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")),
    columns=2:30,
    smoothness=Modelica.Blocks.Types.Smoothness.ContinuousDerivative)
    "Data reader"
equation
  connect(datRea.y[4], chePre.PIn)
  connect(modTim.y, conTim.modTim)
  connect(conTim.calTim, datRea.u)
end CheckPressure;


Test model for CheckTemperature. This example tests the model that checks the temperature.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model CheckTemperature "Test model for CheckTemperature"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.BaseClasses.CheckDryBulbTemperature
    cheTemDryBul "Check dry bulb temperature "
  Buildings.BoundaryConditions.WeatherData.BaseClasses.CheckDewPointTemperature
    cheTemDewPoi "Check dew point temperature"
  Buildings.Utilities.Time.ModelTime modTim
    "Block that outputs the model time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.ConvertTime conTim(
    weaDatStaTim=0,
    weaDatEndTim=31536000)
    "Block that converts time"
  Modelica.Blocks.Math.UnitConversions.From_degC from_degC
    "Block that converts temperature"
  Modelica.Blocks.Math.UnitConversions.From_degC from_degC1
    "Block that converts temperature"
protected
  Modelica.Blocks.Tables.CombiTable1Ds datRea(
    tableOnFile=true,
    tableName="tab1",
    fileName=Modelica.Utilities.Files.loadResource(
       Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")),
    columns=2:30,
    smoothness=Modelica.Blocks.Types.Smoothness.ContinuousDerivative)
    "Data reader"
equation
  connect(modTim.y, conTim.modTim)
  connect(conTim.calTim, datRea.u)
  connect(datRea.y[1], from_degC.u)
  connect(from_degC.y, cheTemDryBul.TIn)
  connect(datRea.y[2], from_degC1.u)
  connect(from_degC1.y, cheTemDewPoi.TIn)
end CheckTemperature;


Test model for converting time. This example tests the model that converts time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model ConvertTime "Test model for converting time"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.ModelTime modTim
    "Block that outputs simulation time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.ConvertTime conTim(
    weaDatStaTim=0,
    weaDatEndTim=31536000)
    "Block that converts time"
equation
  connect(modTim.y, conTim.modTim)
end ConvertTime;


Validation of time conversion for negative start time. This example tests the model that converts time for negative start time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model ConvertTimeNegativeStart
  "Validation of time conversion for negative start time"
  extends Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples.ConvertTime;
end ConvertTimeNegativeStart;


Validation of time conversion for positive start time. This example tests the model that converts time for positive start time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model ConvertTimePositiveStart
  "Validation of time conversion for positive start time"
  extends Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples.ConvertTime;
end ConvertTimePositiveStart;


Test model for equation of time. This example tests the model that computes the equation of time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model EquationOfTime "Test model for equation of time"
  extends Modelica.Icons.Example;
  Utilities.Time.ModelTime modTim "Block that outputs simulation time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.EquationOfTime eqnTim
    "Block that computes the equation of time"
equation
  connect(modTim.y, eqnTim.nDay)
end EquationOfTime;


Test model to get the absolute path of a URI. This model tests the function that gets the absolute path of a URI.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model GetAbsolutePath "Test model to get the absolute path of a URI"
  extends Modelica.Icons.Example;
  parameter String f = Modelica.Utilities.Files.loadResource("modelica://Buildings/package.mo")
   "Name of a file that exists";
  parameter String fAbs=
    Buildings.BoundaryConditions.WeatherData.BaseClasses.getAbsolutePath(uri=f)
    "Absolute path of f";
  final parameter Integer dummy = 1
    "Dummy variable, used to have a result as needed for the unit tests";
initial algorithm
  Modelica.Utilities.Streams.print("Absolute path = " + fAbs);
end GetAbsolutePath;


Test model to get Altitude of TMY3. This example tests getting the location altitude of a TMY3 weather data file.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model GetAltitudeTMY3 "Test model to get Altitude of TMY3"
  extends Modelica.Icons.Example;
  parameter String filNam = Modelica.Utilities.Files.loadResource(
  "modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")
    "Name of weather data file";
  parameter Modelica.Units.SI.Length alt = Buildings.BoundaryConditions.WeatherData.BaseClasses.getAltitudeLocationTMY3(
  filNam) "Altitude of TMY3 location";
end GetAltitudeTMY3;


Test model to get header element. This example tests getting the header of the TMY3 weather data file.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model GetHeaderElement "Test model to get header element"
  extends Modelica.Icons.Example;
  parameter Modelica.Units.SI.Angle longitude(fixed=false, displayUnit="deg")
    "Longitude";
  parameter Modelica.Units.SI.Angle latitude(fixed=false, displayUnit="deg")
    "Latitude";
  parameter Modelica.Units.SI.Time timeZone(fixed=false, displayUnit="h")
    "Time zone";

  parameter String filNam = Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")
    "Name of weather data file";

  final parameter String absFilNam = Buildings.BoundaryConditions.WeatherData.BaseClasses.getAbsolutePath(filNam)
    "Absolute path of the file";
initial equation
  longitude = Buildings.BoundaryConditions.WeatherData.BaseClasses.getLongitudeTMY3(
    filNam=absFilNam);
  latitude = Buildings.BoundaryConditions.WeatherData.BaseClasses.getLatitudeTMY3(
    filNam=absFilNam);
  timeZone = Buildings.BoundaryConditions.WeatherData.BaseClasses.getTimeZoneTMY3(
    filNam=absFilNam);
  assert(abs(longitude*180/Modelica.Constants.pi+87.92) < 1,
      "Error when parsing longitude, longitude = " + String(longitude));
  assert(abs(latitude*180/Modelica.Constants.pi-41.98) < 1,
      "Error when parsing latitude, latitude = " + String(latitude));
  assert(abs(timeZone+6*3600) < 1, "Error when parsing time zone, timeZone = "
    + String(timeZone));
end GetHeaderElement;


Test model to get the time span of a weather file. This example tests getting the time span of a TMY3 weather data file.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model GetTimeSpanTMY3 "Test model to get the time span of a weather file"
  extends Modelica.Icons.Example;

  parameter String filNam = Modelica.Utilities.Files.loadResource(
  "modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")
    "Name of weather data file";
  parameter String tabNam = "tab1" "Name of table on weather file";

  parameter Modelica.Units.SI.Time[2] timeSpan(each fixed=false)
    "Start time, end time of weather data";

protected
  constant Modelica.Units.SI.Time endTim=365*24*3600.;
  constant Modelica.Units.SI.Time staTim=0.;

initial equation
  timeSpan = Buildings.BoundaryConditions.WeatherData.BaseClasses.getTimeSpanTMY3(
  filNam, tabNam);

  assert(abs(timeSpan[2]-endTim) < 1E-5  and abs(timeSpan[1]-staTim) < 1E-5,
      "Error in weather file, start time " + String(timeSpan[1]) +
      " and end time " + String(timeSpan[2]) +
      ", but expected " + String(staTim) + " and " + String(endTim) + ".");
end GetTimeSpanTMY3;


Test model to get the time span of a weather file with a long header line. This example tests getting the time span of a TMY3 weather data file with a long line in the
header of the weather file.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model GetTimeSpanTMY3LongHeader
  "Test model to get the time span of a weather file with a long header line"
  extends Modelica.Icons.Example;

  parameter String filNam=Modelica.Utilities.Files.loadResource(
  "modelica://Buildings/Resources/Data/BoundaryConditions/WeatherData/BaseClasses/Examples/weatherWithLongHeader.mos")
   "Name of weather data file";

  final parameter Modelica.Units.SI.Time[2] timeSpan=
      Buildings.BoundaryConditions.WeatherData.BaseClasses.getTimeSpanTMY3(filNam,
      "tab1") "Start time, end time of weather data";

initial equation
  assert(abs(timeSpan[2]-14400) < 0.1, "Error in getting time span.");
end GetTimeSpanTMY3LongHeader;


Test model to get time span of a weather file, start time is non zero. This example tests getting time span of a TMY3 weather data file that
starts at a non-zero time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model GetTimeSpanTMY3_NonzeroStart
  "Test model to get time span of a weather file, start time is non zero"
  extends Modelica.Icons.Example;
  extends Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples.GetTimeSpanTMY3(
    filNam = Modelica.Utilities.Files.loadResource(
 "modelica://Buildings/Resources/Data/BoundaryConditions/WeatherData/Validation/DecemberToJanuary.mos"),
    staTim = 30992400,
    endTim = 31863600);
end GetTimeSpanTMY3_NonzeroStart;


Test model for ceiling height check. This example tests the model that constrains the ceiling height.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model LimitMin "Test model for ceiling height check"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.ModelTime modTim
  Buildings.BoundaryConditions.WeatherData.BaseClasses.LimiterCeilingHeight limCeiHei
    "Block that constrains the ceiling height"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.ConvertTime conTim(
    weaDatStaTim=0,
    weaDatEndTim=31536000)
    "Block that converts time"
protected
  Modelica.Blocks.Tables.CombiTable1Ds datRea(
    tableOnFile=true,
    tableName="tab1",
    fileName=Modelica.Utilities.Files.loadResource(
       Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos")),
    columns=2:30,
    smoothness=Modelica.Blocks.Types.Smoothness.ContinuousDerivative)
    "Data reader"
equation
  connect(datRea.y[20],limCeiHei.u)
  connect(modTim.y, conTim.modTim)
  connect(conTim.calTim, datRea.u)
end LimitMin;


Test model for calculate local civil time. This example tests the model that computes the local civil time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model LocalCivilTime "Test model for calculate local civil time"
  extends Modelica.Icons.Example;
  Buildings.Utilities.Time.ModelTime modTim
    "Block that outputs the model time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.LocalCivilTime locTim(
      timZon=-21600, lon=-1.5293932423067)
equation
  connect(modTim.y, locTim.cloTim)
end LocalCivilTime;


within Buildings.BoundaryConditions.WeatherData.BaseClasses;
package Examples "Collection of models that illustrate model use and test models"
extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for solar time. This example tests the model that computes the solar time.

within Buildings.BoundaryConditions.WeatherData.BaseClasses.Examples;
model SolarTime "Test model for solar time"
  extends Modelica.Icons.Example;
  Utilities.Time.ModelTime modTim "Block that outputs simulation time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.LocalCivilTime locTim(
      timZon=-21600,
      lon=-1.7039261675061) "Block that computes the local civil time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.SolarTime solTim
    "Block that computes the solar time"
  Buildings.BoundaryConditions.WeatherData.BaseClasses.EquationOfTime eqnTim
    "Block that computes the equation of time"
equation
  connect(modTim.y, locTim.cloTim)
  connect(locTim.locTim, solTim.locTim)
  connect(modTim.y, eqnTim.nDay)
  connect(eqnTim.eqnTim, solTim.equTim)
end SolarTime;


within Buildings.BoundaryConditions.WeatherData;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for reading weather data. This model tests the TMY3 data reader.
The instance weaDat obtains all weather data from the weather file,
whereas the instance weaDatInpCon obtains the global horizontal and
the diffuse horizontal solar radiation from its input connectors.

within Buildings.BoundaryConditions.WeatherData.Examples;
model ReaderTMY3 "Test model for reading weather data"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
    "Weather data reader"
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDatInpCon(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"),
      HSou=Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HGloHor_HDifHor)
    "Weather data reader with radiation data obtained from input connector"
  Modelica.Blocks.Sources.Constant HDifHor(k=0) "Diffuse horizontal radiation"
  Modelica.Blocks.Sources.Constant HGloHor(k=0) "Horizontal global radiation"
equation
  connect(HGloHor.y, weaDatInpCon.HGloHor_in)
  connect(HDifHor.y, weaDatInpCon.HDifHor_in)
end ReaderTMY3;


Validation model for a data reader that has data spanning only some hours in December to January. This is a validation case for a data file that has a few incomplete days in December and goes into
a few days into January. The data does not start and does not end at midnight.

within Buildings.BoundaryConditions.WeatherData.Validation;
model DecemberToJanuary
  "Validation model for a data reader that has data spanning only some hours in December to January"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    computeWetBulbTemperature=false,
    TDewPoiSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    HInfHorSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    HInfHor=100,
    calTSky=Buildings.BoundaryConditions.Types.SkyTemperatureCalculation.HorizontalRadiation,
    filNam=Modelica.Utilities.Files.loadResource(
        "modelica://Buildings/Resources/Data/BoundaryConditions/WeatherData/Validation/DecemberToJanuary.mos"))
    "Weather data reader with data file going from December to January"

end DecemberToJanuary;


Validation model for a simulation extending with two months over one year but using data for only one year. This is a validation case for a simulation extending with two months over one year,
but using data for only one year.

within Buildings.BoundaryConditions.WeatherData.Validation;
model OverAYear_usingOneYearData
  "Validation model for a simulation extending with two months over one year but using data for only one year"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    computeWetBulbTemperature=false,
    TDewPoiSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    HInfHorSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    HInfHor=100,
    calTSky=Buildings.BoundaryConditions.Types.SkyTemperatureCalculation.HorizontalRadiation,
    filNam=Modelica.Utilities.Files.loadResource(
        "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data reader with data file for one year, hourly data"

end OverAYear_usingOneYearData;


Collection of validation models

within Buildings.BoundaryConditions.WeatherData;
package Validation "Collection of validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Test model for calculating the direct normal radiation. This model tests the calculation of the direct normal radiation.
The instance weaDatInpCon obtains the global horizontal and
the diffuse horizontal solar radiation from its inputs connectors.

within Buildings.BoundaryConditions.WeatherData.Validation;
model ReaderTMY3HDirNor
  "Test model for calculating the direct normal radiation"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDatInpCon(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"),
      HSou=Buildings.BoundaryConditions.Types.RadiationDataSource.Input_HGloHor_HDifHor)
    "Weather data reader with radiation data obtained from the inputs' connectors"
protected
  Modelica.Blocks.Sources.Sine HGloHor1(
    f=1/86400,
    startTime=25200,
    offset=0,
    amplitude=100) "Horizontal global radiation"

  Modelica.Blocks.Sources.Sine HGloHor(
    f=1/86400,
    startTime=68428,
    offset=0,
    amplitude=100) "Horizontal global radiation"
  Modelica.Blocks.Math.Add add
  Modelica.Blocks.Math.Gain gaiHDifHor(k=0.5)
    "Gain for diffuse solar radiation"
equation
  connect(HGloHor.y, add.u1)
  connect(HGloHor1.y, add.u2)
  connect(add.y, weaDatInpCon.HGloHor_in)
  connect(add.y, gaiHDifHor.u)
  connect(gaiHDifHor.y, weaDatInpCon.HDifHor_in)
end ReaderTMY3HDirNor;


Validation model for a simulation spanning three years but using only two years of data. This is a validation case for a simulation extending over three years,
but using only two years of data with equidistant monthly values.

within Buildings.BoundaryConditions.WeatherData.Validation;
model ThreeYears_usingTwoYearData
  "Validation model for a simulation spanning three years but using only two years of data"
  extends Modelica.Icons.Example;
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    computeWetBulbTemperature=false,
    TDewPoiSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    HInfHorSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    HInfHor=100,
    calTSky=Buildings.BoundaryConditions.Types.SkyTemperatureCalculation.HorizontalRadiation,
    filNam=Modelica.Utilities.Files.loadResource(
        "modelica://Buildings/Resources/Data/BoundaryConditions/WeatherData/Validation/TwoYears_DataOnceAMonth_TMY3.mos"))
    "Weather data reader with data for two years, only monthly values"

end ThreeYears_usingTwoYearData;


Validation model for a simulation spanning three years, starting at a negative time and using only two years of data. This is a validation case for a simulation extending over six years
starting at a negative start date,
but using only two years of data with equidistant monthly values.

within Buildings.BoundaryConditions.WeatherData.Validation;
model ThreeYears_usingTwoYearDataNegativeStart
  "Validation model for a simulation spanning three years, starting at a negative time and using only two years of data"
  extends
    Buildings.BoundaryConditions.WeatherData.Validation.ThreeYears_usingTwoYearData;

end ThreeYears_usingTwoYearDataNegativeStart;


Validation model for a simulation spanning three years, starting at a positive time and using only two years of data. This is a validation case for a simulation extending over six years
starting at a positive start date,
but using only two years of data with equidistant monthly values.

within Buildings.BoundaryConditions.WeatherData.Validation;
model ThreeYears_usingTwoYearDataPositiveStart
  "Validation model for a simulation spanning three years, starting at a positive time and using only two years of data"
  extends
    Buildings.BoundaryConditions.WeatherData.Validation.ThreeYears_usingTwoYearData;

end ThreeYears_usingTwoYearDataPositiveStart;


Package with models for controls

within Buildings;
package Controls "Package with models for controls"
  extends Modelica.Icons.Package;
end Controls;


Package with type definitions

within Buildings.Controls;
package Types "Package with type definitions"
  extends Modelica.Icons.TypesPackage;

  constant Integer nDayTypes = 3 "Integer with the number of day types";

  type Day = enumeration(
      WorkingDay "Working day, such as Monday through Friday",
      NonWorkingDay "Non-working day, such as week-ends, but not holidays",
      Holiday "Holiday") "Enumeration for the day types"
end Types;


P, PI, PD, and PID controller with limited output, anti-windup compensation and setpoint weighting. PID controller in the standard form

within Buildings.Controls.Continuous;
block LimPID
  "P, PI, PD, and PID controller with limited output, anti-windup compensation and setpoint weighting"

  extends Modelica.Blocks.Interfaces.SVcontrol;
  output Real controlError = u_s - u_m
    "Control error (set point - measurement)";

  parameter Modelica.Blocks.Types.SimpleController controllerType=
         Modelica.Blocks.Types.SimpleController.PI "Type of controller";
  parameter Real k(min=0) = 1 "Gain of controller";
  parameter Modelica.Units.SI.Time Ti(min=Modelica.Constants.small) = 0.5
    "Time constant of Integrator block"
  parameter Modelica.Units.SI.Time Td(min=0) = 0.1
    "Time constant of Derivative block"
  parameter Real yMax(start=1)=1 "Upper limit of output";
  parameter Real yMin=0 "Lower limit of output";
  parameter Real wp(min=0) = 1 "Set-point weight for Proportional block (0..1)";
  parameter Real wd(min=0) = 0 "Set-point weight for Derivative block (0..1)"
  parameter Real Ni(min=100*Modelica.Constants.eps) = 0.9
    "Ni*Ti is time constant of anti-windup compensation"
  parameter Real Nd(min=100*Modelica.Constants.eps) = 10
    "The higher Nd, the more ideal the derivative block"
  parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.InitialState
    "Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)"
      // Removed as the Limiter block no longer uses this parameter.
      // parameter Boolean limitsAtInit = true
      //  "= false, if limits are ignored during initialization"
      //
  parameter Real xi_start=0
    "Initial or guess value value for integrator output (= integrator state)"
  parameter Real xd_start=0
    "Initial or guess value for state of derivative block"
  parameter Real y_start=0 "Initial value of output"
  parameter Boolean strict=true "= true, if strict limits with noEvent(..)"

  parameter Boolean reverseActing = true
    "Set to true for reverse acting, or false for direct acting control action";

  parameter Buildings.Types.Reset reset = Buildings.Types.Reset.Disabled
    "Type of controller output reset"

  parameter Real y_reset=xi_start
    "Value to which the controller output is reset if the boolean trigger has a rising edge, used if reset == Buildings.Types.Reset.Parameter"

  Modelica.Blocks.Interfaces.BooleanInput trigger
    if reset <> Buildings.Types.Reset.Disabled
    "Resets the controller output when trigger becomes true"

  Modelica.Blocks.Interfaces.RealInput y_reset_in
    if reset == Buildings.Types.Reset.Input
    "Input signal for state to which integrator is reset, enabled if reset = Buildings.Types.Reset.Input"

  Modelica.Blocks.Math.Add addP(k1=revAct*wp, k2=-revAct) "Adder for P gain"
  Modelica.Blocks.Math.Add addD(k1=revAct*wd, k2=-revAct) if with_D
    "Adder for D gain"
  Modelica.Blocks.Math.Gain P(k=1) "Proportional term"
  Utilities.Math.IntegratorWithReset I(
    final reset=if reset == Buildings.Types.Reset.Disabled then reset else Buildings.Types.Reset.Input,

    final y_reset=y_reset,
    final k=unitTime/Ti,
    final y_start=xi_start,
    final initType=if initType == Modelica.Blocks.Types.Init.SteadyState then
        Modelica.Blocks.Types.Init.SteadyState else if initType == Modelica.Blocks.Types.Init.InitialState
         or initType == Modelica.Blocks.Types.Init.InitialState then Modelica.Blocks.Types.Init.InitialState
         else Modelica.Blocks.Types.Init.NoInit) if with_I "Integral term"

  Modelica.Blocks.Continuous.Derivative D(
    final k=Td/unitTime,
    final T=max([Td/Nd,1.e-14]),
    final x_start=xd_start,
    final initType=if initType == Modelica.Blocks.Types.Init.SteadyState or
        initType == Modelica.Blocks.Types.Init.InitialOutput then Modelica.Blocks.Types.Init.SteadyState
         else if initType == Modelica.Blocks.Types.Init.InitialState then
        Modelica.Blocks.Types.Init.InitialState else Modelica.Blocks.Types.Init.NoInit)
    if with_D "Derivative term"

  Modelica.Blocks.Math.Add3 addPID(
    final k1=1,
    final k2=1,
    final k3=1) "Adder for the gains"

protected
  constant Modelica.Units.SI.Time unitTime=1

  final parameter Real revAct = if reverseActing then 1 else -1
    "Switch for sign for reverse or direct acting controller";

  parameter Boolean with_I = controllerType==Modelica.Blocks.Types.SimpleController.PI or
                             controllerType==Modelica.Blocks.Types.SimpleController.PID
    "Boolean flag to enable integral action"
  parameter Boolean with_D = controllerType==Modelica.Blocks.Types.SimpleController.PD or
                             controllerType==Modelica.Blocks.Types.SimpleController.PID
    "Boolean flag to enable derivative action"

  Modelica.Blocks.Sources.Constant Dzero(final k=0) if not with_D
    "Zero input signal"

  Modelica.Blocks.Sources.Constant Izero(final k=0) if not with_I
    "Zero input signal"

  Modelica.Blocks.Interfaces.RealInput y_reset_internal
   "Internal connector for controller output reset"

  Modelica.Blocks.Math.Add3 addI(
    final k1=revAct,
    final k2=-revAct) if with_I
    "Adder for I gain"

  Modelica.Blocks.Math.Add addSat(
    final k1=+1,
    final k2=-1) if with_I
    "Adder for integrator feedback"

  Modelica.Blocks.Math.Gain gainPID(final k=k) "Multiplier for control gain"

  Modelica.Blocks.Math.Gain gainTrack(k=1/(k*Ni)) if with_I
    "Gain for anti-windup compensation"

  Limiter limiter(
    final uMax=yMax,
    final uMin=yMin,
    final strict=strict)
    "Output limiter"

  Modelica.Blocks.Sources.RealExpression intRes(
    final y=y_reset_internal/k - addPID.u1 - addPID.u2)
    if reset <> Buildings.Types.Reset.Disabled
    "Signal source for integrator reset"

  // The block Limiter below has been implemented as it is introduced in MSL 3.2.3, but
  // not all tools include MSL 3.2.3.
  // See https://github.com/ibpsa/modelica-ibpsa/pull/1222#issuecomment-554114617
block Limiter "Limit the range of a signal"
  parameter Real uMax(start=1) "Upper limits of input signals";
  parameter Real uMin= -uMax "Lower limits of input signals";
  parameter Boolean strict=false "= true, if strict limits with noEvent(..)"
  parameter Boolean limitsAtInit=true
    "Has no longer an effect and is only kept for backwards compatibility (the implementation uses now the homotopy operator)"
  extends Modelica.Blocks.Interfaces.SISO;

equation
  assert(uMax >= uMin, "Limiter: Limits must be consistent. However, uMax (=" + String(uMax) +
                       ") < uMin (=" + String(uMin) + ")");

  if strict then
    y = smooth(0, noEvent(if u > uMax then uMax else if u < uMin then uMin else u));
  else
    y = smooth(0,if u > uMax then uMax else if u < uMin then uMin else u);
  end if;
end Limiter;

initial equation
  if initType == Modelica.Blocks.Types.Init.InitialOutput then
     gainPID.y = y_start;
  end if;

equation
  assert(yMax >= yMin, "LimPID: Limits must be consistent. However, yMax (=" + String(yMax) +
                       ") < yMin (=" + String(yMin) + ")");
  if initType == Modelica.Blocks.Types.Init.InitialOutput and (y_start < yMin
       or y_start > yMax) then
      Modelica.Utilities.Streams.error("LimPID: Start value y_start (=" + String(y_start) +
         ") is outside of the limits of yMin (=" + String(yMin) +") and yMax (=" + String(yMax) + ")");
  end if;

  // Equations for conditional connectors
  connect(y_reset_in, y_reset_internal);

  if reset <> Buildings.Types.Reset.Input then
    y_reset_internal = y_reset;
  end if;

  connect(u_s, addP.u1)
  connect(u_s, addD.u1)
  connect(u_s, addI.u1)
  connect(addP.y, P.u)
  connect(addD.y, D.u)
  connect(addI.y, I.u)
  connect(P.y, addPID.u1)
  connect(D.y, addPID.u2)
  connect(I.y, addPID.u3)
  connect(addPID.y, gainPID.u)
  connect(gainPID.y, addSat.u2)
  connect(gainPID.y, limiter.u)
  connect(limiter.y, addSat.u1)
  connect(limiter.y, y)
  connect(addSat.y, gainTrack.u)
  connect(gainTrack.y, addI.u3)
  connect(u_m, addP.u2)
  connect(u_m, addD.u2)
  connect(u_m, addI.u2)
  connect(Dzero.y, addPID.u2)
  connect(Izero.y, addPID.u3)
  connect(trigger, I.trigger)
  connect(intRes.y, I.y_reset_in)
end LimPID;


Outputs the number of signals that are above/below a certain threshold. Block that outputs the number of inputs that exceed a threshold.
The parameter kind is used to determine the kind of the
inequality. The table below shows the allowed settings.

within Buildings.Controls.Continuous;
block NumberOfRequests
  "Outputs the number of signals that are above/below a certain threshold"
   extends Modelica.Blocks.Icons.Block;

  parameter Integer nin "Number of inputs";
  parameter Real threShold = 0 "Threshold";
  parameter Integer kind
    "Set to 0 for u>threShold, to 1 for >=, to 2 for <= or to 3 for <";
  Modelica.Blocks.Interfaces.IntegerOutput y
    "Number of input signals that violate the threshold"
  Modelica.Blocks.Interfaces.RealInput u[nin] "Input signals"
algorithm
  y := 0;
  for i in 1:nin loop
    if kind == 0 then
      if u[i] > threShold then
        y := y+1;
      end if;
    end if;
    if kind == 1 then
      if u[i] >= threShold then
        y := y+1;
      end if;
    end if;
    if kind == 2 then
      if u[i] <= threShold then
        y := y+1;
      end if;
    end if;
    if kind == 3 then
      if u[i] < threShold then
        y := y+1;
      end if;
    end if;
  end for;
end NumberOfRequests;


Records the time since the input changed to false. Timer that starts at the initial time with a value of 0,
and gets reset each time the input signal switches to false.

within Buildings.Controls.Continuous;
model OffTimer "Records the time since the input changed to false"
  extends Modelica.Blocks.Icons.PartialBooleanBlock;

  Modelica.Blocks.Interfaces.BooleanInput u "Connector of Boolean input signal"
  Modelica.Blocks.Interfaces.RealOutput y "Connector of Real output signal"

protected
  discrete Modelica.Units.SI.Time entryTime "Time instant when u became true";
initial equation
  pre(entryTime) = time;
equation
  when (not u) then
    entryTime = time;
  end when;
  y = time - entryTime;
end OffTimer;


within Buildings.Controls;
package Continuous "Package with models for discrete time controls"
  extends Modelica.Icons.Package;
end Continuous;


Ranks output signals such that y[i] >= y[i+1]. Block that sorts the input signal u[:] such that the output
signal satisfies y[i] >= y[i+1] for all i=1, ..., nin-1.

within Buildings.Controls.Continuous;
block SignalRanker "Ranks output signals such that y[i] >= y[i+1]"
   extends Modelica.Blocks.Interfaces.MIMO(final nout=nin);
equation
  y = Modelica.Math.Vectors.sort(u, ascending=false);
end SignalRanker;


Test model for PID controller with optional reverse action. This model tests the implementation of the
PID controller with optional reverse action.
The model limPIDOri is the original
implementation of the controller from the Modelica
Standard Library. The models limPID
and limPIDRev are the implementations
from the Buildings library. The model
limPIDRev is parameterized to have
reverse action.
The assertion blocks test whether the results
of all three controllers are identical.

within Buildings.Controls.Continuous.Examples;
model LimPID "Test model for PID controller with optional reverse action"
  extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.Pulse pulse(period=0.25)
  Buildings.Controls.Continuous.LimPID limPID(
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    Ti=1,
    Td=1,
    yMax=1,
    yMin=-1,
    initType=Modelica.Blocks.Types.Init.InitialState)
  Buildings.Controls.Continuous.LimPID limPIDRev(
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    reverseActing=false,
    Ti=1,
    Td=1,
    yMax=1,
    yMin=-1,
    initType=Modelica.Blocks.Types.Init.InitialState)
    "Controller with reverse action"
  Modelica.Blocks.Sources.Constant const(k=0.5)
  Modelica.Blocks.Math.Gain gain(k=-1)
  Buildings.Utilities.Diagnostics.AssertEquality assertEquality(
    threShold=1e-3)
  Modelica.Blocks.Continuous.LimPID limPIDOri(
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    Ti=1,
    Td=1,
    yMax=1,
    yMin=-1,
    initType=Modelica.Blocks.Types.Init.InitialState)
  Buildings.Utilities.Diagnostics.AssertEquality assertEquality1(
    threShold=1e-3)
equation
  connect(pulse.y, limPID.u_s)
  connect(pulse.y, limPIDRev.u_s)
  connect(const.y, limPID.u_m)
  connect(const.y, limPIDRev.u_m)
  connect(limPIDRev.y, gain.u)
  connect(gain.y, assertEquality.u2)
  connect(limPID.y, assertEquality.u1)
  connect(pulse.y, limPIDOri.u_s)
  connect(const.y, limPIDOri.u_m)
  connect(assertEquality1.u1, limPIDOri.y)
  connect(assertEquality1.u2, limPID.y)
end LimPID;


Example that demonstrates the controller output reset. Plant model for

Buildings.Controls.Continuous.Examples.LimPIDWithReset.
consisting of a simple heat transfer model.

within Buildings.Controls.Continuous.Examples;
model LimPIDWithReset
  "Example that demonstrates the controller output reset"
  extends Modelica.Icons.Example;

  Plant plaWitRes "Plant connected to controller with reset"
  Controller conWitRes(reset=Buildings.Types.Reset.Parameter)
    "Controller with reset"
  Plant plaNoRes "Plant connected to controller without reset"
  Controller conNoRes(reset=Buildings.Types.Reset.Disabled)
    "Controller without reset"
  Modelica.Blocks.Sources.Pulse TSet(
    amplitude=20,
    width=50,
    offset=293.15,
    y(unit="K"),
    period=180)    "Temperature set point"

protected
  model Plant
    "Plant model"
    extends Modelica.Blocks.Icons.Block;

    Modelica.Blocks.Interfaces.RealInput Q_flow(unit="W")
      "Heat flow rate added to system"
    Modelica.Blocks.Interfaces.RealOutput T(unit="K")
      "Controlled temperature"

    Modelica.Thermal.HeatTransfer.Components.HeatCapacitor cap(
      C=10,
      T(fixed=true,
        start=293.15)) "Heat capacitor"
    Modelica.Thermal.HeatTransfer.Components.HeatCapacitor cap1(
      C=10,
      T(fixed=true,
          start=293.15)) "Heat capacitor"

    Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temSen
      "Temperature sensor"
    Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea
      "Prescribed heat flow rate"
    Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=5)
      "Thermal conductor"
    Buildings.HeatTransfer.Sources.FixedTemperature TBou(T=293.15)
      "Boundary condition"
    Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon1(G=1)
      "Thermal conductor"

  equation
    connect(Q_flow, preHea.Q_flow)
    connect(T, temSen.T)
    connect(TBou.port, theCon.port_a)
    connect(cap.port, theCon1.port_a)
    connect(theCon1.port_b, cap1.port)
    connect(cap1.port, temSen.port)
    connect(theCon.port_b, cap.port)
    connect(preHea.port, cap.port)
  end Plant;

  model Controller "PID controller with optional output reset"
    extends Modelica.Blocks.Icons.Block;

    parameter Buildings.Types.Reset reset=Buildings.Types.Reset.Disabled
      "Type of controller output reset";

    Modelica.Blocks.Interfaces.RealInput TSet(unit="K") "Temperature set point"

    Modelica.Blocks.Interfaces.RealInput u_m(unit="K")
      "Measured temperature"

    Modelica.Blocks.Interfaces.RealOutput y
      "Control signal"

    Buildings.Controls.Continuous.LimPID conPID(
      final reset=reset,
      yMax=1,
      yMin=0,
      Ti=1,
      k=10) "PI controller"
    Modelica.Blocks.Math.Gain gain(k=5000)
                                          "Gain for heat flow rate"
    Modelica.Blocks.Logical.GreaterThreshold trigger(threshold=303.15)
      "Trigger input for controller reset"

  equation
    connect(conPID.y,gain. u)
    connect(trigger.y,conPID. trigger)
    connect(u_m, conPID.u_m)
    connect(conPID.u_s, TSet)
    connect(trigger.u, TSet)
    connect(gain.y, y)
  end Controller;

equation
  connect(plaWitRes.T, conWitRes.u_m)
  connect(conWitRes.y, plaWitRes.Q_flow)

  connect(plaNoRes.T, conNoRes.u_m)
  connect(conNoRes.y, plaNoRes.Q_flow)
  connect(TSet.y, conWitRes.TSet)
  connect(TSet.y, conNoRes.TSet)
end LimPIDWithReset;


Example model for block that outputs the number of requests. Example that demonstrates the use of the block

Buildings.Controls.Continuous.NumberOfRequests.
The parameters of the block are such that the output is incremented
for each input signal that is strictly larger than 0.
The figure below shows the inputs and the output of the block.

within Buildings.Controls.Continuous.Examples;
model NumberOfRequests
  "Example model for block that outputs the number of requests"
  extends Modelica.Icons.Example;
  Buildings.Controls.Continuous.NumberOfRequests numReq(
    nin=2,
    threShold=0,
    kind=0)
  Modelica.Blocks.Sources.Sine sine(f=2)
  Modelica.Blocks.Sources.Pulse pulse(
    amplitude=1-pulse.offset,
    period=0.35,
    offset=-0.01)
equation
  connect(sine.y, numReq.u[1])
  connect(pulse.y, numReq.u[2])
end NumberOfRequests;


Example model for off timer. Example that demonstrates the use of the model

Buildings.Controls.Continuous.OffTimer.
The input to the two timers are alternating boolean values.
Whenever the input becomes false(=0), the timer is reset.
The figures below show the input and output of the blocks.

within Buildings.Controls.Continuous.Examples;
model OffTimer "Example model for off timer"
  extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.BooleanPulse booleanPulse(period=0.2)
  Buildings.Controls.Continuous.OffTimer offTim1
  Buildings.Controls.Continuous.OffTimer offTim2
  Modelica.Blocks.Logical.Not not1
equation
  connect(booleanPulse.y, offTim1.u)
  connect(booleanPulse.y, not1.u)
  connect(offTim2.u, not1.y)
end OffTimer;


within Buildings.Controls.Continuous;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Example model for signal ranker. Example that demonstrates the use of the signal ranker model.
The figure below shows the input and output signals of the block.
Note that
sigRan.y[1] ≥ sigRan.y[2] ≥ sigRan.y[3].

within Buildings.Controls.Continuous.Examples;
model SignalRanker "Example model for signal ranker"
  extends Modelica.Icons.Example;
  Modelica.Blocks.Sources.Sine sine(f=2, startTime=0.025) "Sine source"
  Modelica.Blocks.Sources.Pulse pulse(period=0.25)
    "Pulse source"
  Buildings.Controls.Continuous.SignalRanker sigRan(nin=3)
    "Signal ranker"
  Modelica.Blocks.Sources.ExpSine expSine(f=10, damping=1)
    "Exponential sine source"
equation
  connect(sine.y, sigRan.u[1])
  connect(pulse.y, sigRan.u[2])
  connect(expSine.y, sigRan.u[3])
end SignalRanker;


Test model for PID controller with optional intgerator reset. This model tests the implementation the
Buildings.Controls.Continuous.LimPID
with integrator reset.

within Buildings.Controls.Continuous.Validation;
model LimPIDReset
  "Test model for PID controller with optional intgerator reset"
  extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.Sine setPoi(f=1) "Set point signal"
  Buildings.Controls.Continuous.LimPID limPIDPar(
    yMax=1,
    yMin=-1,
    reset=Buildings.Types.Reset.Parameter,
    y_reset=0.2,
    Ti=20,
    Td=10,
    k=0.2,
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    initType=Modelica.Blocks.Types.Init.InitialOutput,
    y_start=0.3) "PId controller with integrator reset to a parameter value"
  Modelica.Blocks.Sources.Constant mea(k=0.5) "Measured signal"
  Buildings.Controls.Continuous.LimPID limPIDDef(
    initType=Modelica.Blocks.Types.Init.InitialState,
    Td=10,
    k=1,
    Ti=1,
    yMax=100,
    yMin=-100,
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    xi_start=0.2,
    xd_start=0.1) "PID controller without integrator reset"
  Modelica.Blocks.Sources.BooleanPulse trigger(
    width=50,
    startTime=0.1,
    period=0.2) "Boolean pulse to reset integrator"
  Buildings.Controls.Continuous.LimPID limPIDInp(
    y_reset=0.2,
    Td=10,
    reset=Buildings.Types.Reset.Input,
    yMax=1,
    yMin=-1,
    k=0.2,
    Ti=20,
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    initType=Modelica.Blocks.Types.Init.InitialOutput,
    y_start=0.3) "PId controller with integrator reset to an input value"
  Modelica.Blocks.Sources.Constant conRes(k=0.9)
    "Signal to which integrator will be reset to"
  Modelica.Blocks.Continuous.LimPID limPIDOri(
    initType=Modelica.Blocks.Types.Init.InitialState,
    Td=10,
    k=1,
    Ti=1,
    yMax=100,
    yMin=-100,
    controllerType=Modelica.Blocks.Types.SimpleController.PID,
    xi_start=0.2,
    xd_start=0.1) "PID controller from Standard Modelica Library"
  Buildings.Utilities.Diagnostics.AssertEquality assEqu
equation
  connect(setPoi.y, limPIDPar.u_s)
  connect(mea.y, limPIDPar.u_m)
  connect(setPoi.y, limPIDDef.u_s)
  connect(mea.y, limPIDDef.u_m)
  connect(trigger.y, limPIDPar.trigger)
  connect(setPoi.y, limPIDInp.u_s)
  connect(mea.y, limPIDInp.u_m)
  connect(trigger.y, limPIDInp.trigger)
  connect(conRes.y, limPIDInp.y_reset_in)
  connect(setPoi.y, limPIDOri.u_s)
  connect(mea.y, limPIDOri.u_m)
  connect(assEqu.u1, limPIDOri.y)
  connect(limPIDDef.y, assEqu.u2)
end LimPIDReset;


Test model for off timer with negative start time. This model tests the implementation the
Buildings.Controls.Continuous.OffTimer
for negative start time.

within Buildings.Controls.Continuous.Validation;
model OffTimerNonZeroStart
  "Test model for off timer with negative start time"
  extends Buildings.Controls.Continuous.Examples.OffTimer(
    booleanPulse(startTime=-1));
end OffTimerNonZeroStart;


Collection of validation models

within Buildings.Controls.Continuous;
package Validation "Collection of validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Demand response client. Model for a data-driven demand response client that predicts the future load and
allows to apply a load shedding factor.

within Buildings.Controls.DemandResponse;
model Client "Demand response client"
  extends Modelica.Blocks.Icons.DiscreteBlock;

  final parameter Modelica.Units.SI.Time tPeriod=24*3600
    "Period, generally one day";

  parameter Integer nSam
    "Number of samples in a day. For 1 hour sampling, set to 24";
  parameter Integer nPre(min=1) = 1
    "Number of intervals for which future load need to be predicted (set to one to only predict current time, or to nSam to predict one day)";

  parameter Integer nHis(min=1) = 10
    "Number of history terms to be stored for baseline computation";

  parameter Buildings.Controls.Predictors.Types.PredictionModel
    predictionModel=
      Buildings.Controls.Predictors.Types.PredictionModel.WeatherRegression
    "Load prediction model";

  Buildings.Controls.Interfaces.DayTypeInput typeOfDay[integer((nPre-1)/nSam)+2] "Type of day for the current and the future days for which a prediction is to be made.
    Typically, this has dimension 2 for predictions up to and including 24 hours, and 2+n for any additional day"

  Modelica.Blocks.Interfaces.BooleanInput isEventDay
    "If true, this day remains an event day until midnight"
   Modelica.Blocks.Interfaces.RealInput ECon(unit="J")
    "Consumed electrical power"

  Modelica.Blocks.Interfaces.BooleanInput shed
    "Signal, true if load needs to be shed at the current time"

  Modelica.Blocks.Interfaces.RealInput yShed(min=-1, max=1, unit="1")
    "Amount of load to shed. Set to 0.5 to shed 50% of load"

  Modelica.Blocks.Interfaces.RealInput TOut(unit="K", displayUnit="degC")
  if (predictionModel == Buildings.Controls.Predictors.Types.PredictionModel.WeatherRegression)
    "Outside air temperature"

  Modelica.Blocks.Interfaces.RealInput TOutFut[nPre-1](each unit="K")
    if (predictionModel == Buildings.Controls.Predictors.Types.PredictionModel.WeatherRegression)
    "Future outside air temperatures"

  Modelica.Blocks.Interfaces.RealOutput PPre(unit="W")
    "Predicted power consumption for the current time interval, taking into account yShed"
  Modelica.Blocks.Interfaces.RealOutput PPreNoShe[nPre](each unit="W")
    "Predicted power consumption for the current and future time intervals, not taking into account yShed"

protected
  OBC.CDL.Reals.Multiply she "Outputs load taking shed signal into account"
  OBC.CDL.Routing.RealExtractor extIndRea
  OBC.CDL.Integers.Sources.Constant conInt(k=1)
    "Outputs 1 to extract the first signal of the demand prediction array"
  BaseClasses.BaselinePrediction comBasLin(
    final nSam=nSam,
    final nHis=nHis,
    final nPre=nPre,
    final predictionModel=predictionModel)
           "Baseline prediction"

  Modelica.Blocks.Logical.Switch switch
    "Switch to select normal or shedded load"
equation
  connect(comBasLin.ECon, ECon)

  connect(isEventDay, comBasLin.isEventDay)
  connect(comBasLin.TOut, TOut)
  connect(typeOfDay, comBasLin.typeOfDay)
  connect(comBasLin.TOutFut, TOutFut)
  // Only PPre[1] will take into account the shedded load.
  connect(switch.y, PPre)
  connect(comBasLin.PPre, PPreNoShe)
  connect(switch.u1, she.y)
  connect(yShed, she.u2)
  connect(shed, switch.u2)
  connect(comBasLin.PPre, extIndRea.u)
  connect(conInt.y, extIndRea.index)
  connect(switch.u3, extIndRea.y)
  connect(extIndRea.y, she.u1)
end Client;


within Buildings.Controls;
package DemandResponse "Package with models for demand response controllers"
  extends Modelica.Icons.Package;
end DemandResponse;


Predicts the baseline consumption. Block that computes the baseline for a demand response client.
This implementation computes the 10/10 average baseline.
This baseline is the average of the consumed power of the previous
10 days for the same time interval. For example, if the base line is
computed every 1 hour, then there are 24 baseline values for each day.
Separate baselines are computed for any types of days.
The type of day is an input signal received from the connector
typeOfDay, and must be equal to any value defined
in

Buildings.Controls.Types.Day.

within Buildings.Controls.DemandResponse.BaseClasses;
block BaselinePrediction "Predicts the baseline consumption"
  extends Modelica.Blocks.Icons.DiscreteBlock;

  parameter Integer nSam
    "Number of intervals in a day for which baseline is computed";

  parameter Integer nPre(min=1)
    "Number of intervals for which future load need to be predicted (set to one to only predict current time, or to nSam to predict one day)";

  parameter Buildings.Controls.Predictors.Types.PredictionModel predictionModel
    "Load prediction model";

  parameter Integer nHis(min=1) = 10 "Number of history terms to be stored";

  Modelica.Blocks.Interfaces.RealInput ECon(unit="J")
    "Consumed electrical energy"
  Modelica.Blocks.Interfaces.RealOutput PPre[nPre](each unit="W")
    "Predicted power consumption for the current time interval"

  Modelica.Blocks.Interfaces.RealInput TOutFut[nPre-1](each unit="K")
    if (predictionModel == Buildings.Controls.Predictors.Types.PredictionModel.WeatherRegression)
    "Future outside air temperatures"

  Modelica.Blocks.Interfaces.RealInput TOut(unit="K", displayUnit="degC")
  if (predictionModel == Buildings.Controls.Predictors.Types.PredictionModel.WeatherRegression)
    "Outside air temperature"

  Buildings.Controls.Interfaces.DayTypeInput typeOfDay[integer((nPre-1)/nSam)+2] "Type of day for the current and the future days for which a prediction is to be made.
    Typically, this has dimension 2 for predictions up to and including 24 hours, and 2+n for any additional day"

  Modelica.Blocks.Interfaces.BooleanInput isEventDay
    "If true, this day remains an event day until midnight"
protected
  Buildings.Controls.Predictors.ElectricalLoad basLin(
    final nSam=nSam,
    final nPre=nPre,
    final nHis=nHis,
    final predictionModel=predictionModel) "Model that computes the base line"
  Modelica.Blocks.Logical.Not stoHis
    "Boolean signal to set whether history should be stored"
equation
  connect(basLin.ECon, ECon)
  connect(TOut, basLin.TOut)
  connect(basLin.PPre, PPre)
  connect(stoHis.u, isEventDay)
  connect(stoHis.y, basLin.storeHistory)
  connect(basLin.typeOfDay, typeOfDay)
  connect(basLin.TOutFut, TOutFut)
end BaselinePrediction;


Package with base classes

within Buildings.Controls.DemandResponse;
package BaseClasses "Package with base classes"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Demand response client with input data from building 90 at LBNL. Model that demonstrates the demand response client,
using as an input for the actual electrical consumption simulated
data from building 90 at LBNL.
Output of the data reader are the outdoor dry-bulb temperature,
the total electrical consumption,
and a signal that indicates whether load shedding is required.

within Buildings.Controls.DemandResponse.Examples;
model ClientLBNL90
  "Demand response client with input data from building 90 at LBNL"
  extends Modelica.Icons.Example;
  parameter Integer nSam = 24*4 "Number of samples in a day";
  Client clientAverage(
    nSam=nSam,
    predictionModel=Buildings.Controls.Predictors.Types.PredictionModel.Average)
    "Demand response client"
  Sources.DayType dayType "Outputs the type of the day"
  Modelica.Blocks.Sources.CombiTimeTable bui90(
    tableOnFile=true,
    tableName="b90",
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    fileName=Modelica.Utilities.Files.loadResource(
      "modelica://Buildings/Resources/Data/Controls/DemandResponse/Examples/B90_DR_Data.mos"),
    columns={2,3,4}) "LBNL building 90 data"

  Modelica.Blocks.Logical.GreaterThreshold drSig(threshold=0.5)
    "Demand response signal"
  Modelica.Blocks.Math.Add errorAverage(k2=-1)
    "Difference between predicted minus actual load"
  Client clientWeather(
    nSam=nSam,
    predictionModel=Buildings.Controls.Predictors.Types.PredictionModel.WeatherRegression)
    "Demand response client with weather regression model"
  Modelica.Blocks.Math.Add errorWeather(k2=-1)
    "Difference between predicted minus actual load"
  Modelica.Blocks.Math.Gain relErrAverage(k=1/400000)
    "Relative error, normalized by a value that is close to the peak power consumption"
  Modelica.Blocks.Math.Gain relErrWeather(k=1/400000)
    "Relative error, normalized by a value that is close to the peak power consumption"
  Modelica.Blocks.Continuous.Integrator ene(u(unit="W"))
    "Integrator to compute energy from power"
  Modelica.Blocks.Sources.Constant yShed(k=0.5)
    "Amount of load to be shed during DR event"
equation
  connect(clientAverage.isEventDay, clientAverage.shed)
  connect(drSig.u, bui90.y[3])
  connect(drSig.y, clientAverage.shed)
  connect(clientAverage.PPre, errorAverage.u1)

  connect(clientWeather.isEventDay, clientWeather.shed)
  connect(drSig.y, clientWeather.shed)
  connect(clientWeather.PPre, errorWeather.u1)
  connect(clientWeather.TOut, bui90.y[1])
  connect(relErrAverage.u, errorAverage.y)
  connect(relErrWeather.u, errorWeather.y)
  connect(ene.u, bui90.y[2])
  connect(ene.y, clientWeather.ECon)
  connect(ene.y, clientAverage.ECon)
  connect(errorWeather.u2, bui90.y[2])
  connect(errorAverage.u2, bui90.y[2])
  connect(dayType.y, clientAverage.typeOfDay)
  connect(dayType.y, clientWeather.typeOfDay)
  connect(yShed.y, clientAverage.yShed)
  connect(clientWeather.yShed, yShed.y)
end ClientLBNL90;


within Buildings.Controls.DemandResponse;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Zero order hold for boolean variable. Block that delays the boolean input signal by
one sampling interval.
For example,
if u denotes the input,
y denotes the output, and
ti and ti+1
denote subsequent sampling
instants, then the model outputs

within Buildings.Controls.Discrete;
block BooleanDelay "Zero order hold for boolean variable"
  extends Modelica.Blocks.Interfaces.BooleanSISO;
  extends Modelica.Blocks.Interfaces.DiscreteBlock(
    firstTrigger(fixed=true,
                 start=firstTrigger_start));
  parameter Boolean firstTrigger_start=false
    "Start value for rising edge signals first sample instant"
protected
  Boolean ySample;
algorithm
  when {sampleTrigger, initial()} then
    y := ySample;
    ySample := u;
  end when;
end BooleanDelay;


within Buildings.Controls;
package Discrete "Package with models for discrete time controls"
  extends Modelica.Icons.Package;
end Discrete;


Example model for boolean delay. Example that demonstrates the use of the boolean delay block.
The output signal of the block is delayed by one sampling interval.

within Buildings.Controls.Discrete.Examples;
model BooleanDelay "Example model for boolean delay"
  extends Modelica.Icons.Example;
  Buildings.Controls.Discrete.BooleanDelay del(samplePeriod=0.05)
  Modelica.Blocks.Sources.BooleanPulse booleanPulse(
    period=0.1,
    width=50,
    startTime=0.01)
equation
  connect(booleanPulse.y, del.u)
end BooleanDelay;


within Buildings.Controls.Discrete;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within Buildings.Controls;
package Interfaces "Package with interfaces for demand response models"
  extends Modelica.Icons.InterfacesPackage;
end Interfaces;


within Buildings.Controls;
package OBC "Blocks and preconfigured control sequences"
  extends Modelica.Icons.Package;
end OBC;


User's Guide

within Buildings.Controls.OBC;
package UsersGuide "User's Guide"
  extends Modelica.Icons.Information;

  class Conventions "Naming conventions in OBC package"
    extends Modelica.Icons.Information;
  end Conventions;
end UsersGuide;


within Buildings.Controls.OBC;
package ASHRAE "Package with control sequences from ASHRAE projects"
end ASHRAE;


within Buildings.Controls.OBC.ASHRAE;
package G36 "Package with control sequences from ASHRAE Guideline 36"
end G36;


within Buildings.Controls.OBC.ASHRAE.G36;
package AHUs "AHU Sequences as defined in guideline G36"
end AHUs;


Sequences for multi zone AHU control

within Buildings.Controls.OBC.ASHRAE.G36.AHUs;
package MultiZone "Sequences for multi zone AHU control"
end MultiZone;