VDI 6007 Test Case 11 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase11 "VDI 6007 Test Case 11 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    nInt=1,
    ratioWinConRad=0,
    AInt=75.5,
    RWin=0.00000001,
    hRad=5,
    RExt={0.00436791293674},
    RExtRem=0.03895919557,
    CExt={1600848.94},
    RInt={0.000595693407511},
    CInt={14836354.6282},
    hConInt=3,
    indoorPortIntWalls=true,
    VAir=0,
    nOrientations=1,
    redeclare final package Medium = Modelica.Media.Air.SimpleAir,
    AWin={0},
    ATransparent={0},
    AExt={10.5},
    extWallRC(thermCapExt(each der_T(fixed=true))),
    T_start=295.15,
    intWallRC(thermCapInt(each der_T(fixed=true))))
    "Thermal zone"
  Buildings.HeatTransfer.Sources.FixedTemperature preTem(
    T=295.15)
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall(
    dT(start=0))
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 21600,1000;
        25200,1000; 28800,1000; 32400,1000; 36000,1000; 39600,1000; 43200,1000;
        46800,1000; 50400,1000; 54000,1000; 57600,1000; 61200,1000; 64800,1000;
        64800,0; 68400,0; 72000,0; 75600,0; 79200,0; 82800,0; 86400,0],
    columns={2})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    columns={2,3,4},
    table=[0,22,0,0; 3600,22,0,0; 7200,22,0,0; 10800,22,0,0; 14400,22,0,0;
        18000,22,0,0; 21600,22,0,500; 25200,24.9,500,500; 28800,25.2,500,500;
        32400,25.6,500,500; 36000,25.9,500,500; 39600,26.2,500,500; 43200,26.5,
        500,500; 46800,26.8,500,464; 50400,27,464,397; 54000,27,397,333; 57600,
        27,333,272; 61200,27,272,215; 64800,27,215,-500; 68400,25.3,-500,-500;
        72000,25.2,-500,-500; 75600,25.1,-500,-500; 79200,24.9,-500,-500; 82800,
        24.8,-500,-500; 86400,24.7,-500,-500; 781200,26.2,-500,-500; 784800,
        26.1,-500,-500; 788400,26,-500,-500; 792000,25.8,-500,-500; 795600,25.7,
        -500,-500; 799200,25.6,-500,126; 802800,27,126,76; 806400,27,76,28;
        810000,27,28,100; 813600,27,-121,-391; 817200,27,-391,-500; 820800,27,-500,
        -500; 824400,27.1,-500,-500; 828000,27.2,-500,-500; 831600,27.3,-500,-500;
        835200,27.4,-500,-500; 838800,27.5,-500,-500; 842400,27.6,-500,-500;
        846000,27,-500,-500; 849600,26.9,-500,-500; 853200,26.7,-500,-500;
        856800,26.6,-500,-500; 860400,26.5,-500,-500; 864000,26.4,-500,-500;
        5101200,26.2,-500,-500; 5104800,26.1,-500,-500; 5108400,26,-500,-500;
        5112000,25.8,-500,-500; 5115600,25.7,-500,-500; 5119200,25.6,-500,126;
        5122800,27,126,76; 5126400,27,76,28; 5130000,27,28,100; 5133600,27,-122,
        -391; 5137200,27,-391,-500; 5140800,27,-500,-500; 5144400,27.1,-500,-500;
        5148000,27.2,-500,-500; 5151600,27.3,-500,-500; 5155200,27.4,-500,-500;
        5158800,27.5,-500,-500; 5162400,27.6,-500,-500; 5166000,27,-500,-500;
        5169600,26.9,-500,-500; 5173200,26.7,-500,-500; 5176800,26.6,-500,-500;
        5180400,26.5,-500,-500; 5184000,26.4,-500,-500])
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow machinesRad
    "Radiative heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.Constant const(k=0)
    "Solar radiation"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heat
    "Ideal heater with limit"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow cool
    "Ideal cooler with limit"
  Modelica.Blocks.Sources.CombiTimeTable setTemp(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    columns={2},
    smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments,
    table=[0,22; 3600,22; 7200,22; 10800,22; 14400,22; 18000,22; 21600,22;
        21600.1,27; 28800,27; 32400,27; 36000,27; 39600,27; 43200,27; 46800,27;
        50400,27; 54000,27; 57600,27; 61200,27; 64800,27; 64800.1,22; 72000,22;
        75600,22; 79200,22; 82800,22; 86400,22])
    "Set temperature for ideal heater/cooler"
  Modelica.Blocks.Math.UnitConversions.From_degC from_degC
    "Convert set temperature from degC to Kelvin"
  Modelica.Blocks.Math.Gain gainHea(k=500)
    "Gain for heating"
  Controls.Continuous.LimPID conHeaCoo(
    yMin=-1,
    Td=5,
    yMax=1,
    k=0.1,
    Ti=1.2)
    "Heating and cooling controller"
  Modelica.Blocks.Math.Gain gainCoo(k=500)
    "Gain for cooling"
  Modelica.Blocks.Logical.Switch switchCoo
    "Switch to limit cooling power"
  Modelica.Blocks.Logical.Hysteresis hysteresis(
    uLow=-0.0000001,
    uHigh=0.0000001,
    y(start=true))
    "Threshold for switching between heating and cooling"
  Modelica.Blocks.Sources.Constant DefPow(k=0)
    "Default power"
  Modelica.Blocks.Logical.Switch switchHea
    "Switch to limit heating power"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heatFlowSensor
    "Sensor for ideal heater"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor coolFlowSensor
    "Sensor for ideal cooler"
  Modelica.Blocks.Math.Add add(k1=1, k2=-1)
    "Addition for mean of results"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    endTime=86400,
    endTime2=864000,
    endTime3=5184000,
    threShold=1.5,
    startTime=3600,
    startTime2=781200,
    startTime3=5101200)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
  Modelica.Blocks.Logical.Switch switchMea
    "Switch to guess values"
  Modelica.Blocks.Logical.Not not1
    "Logical not"
  Modelica.Blocks.Logical.Timer timer
    "Timer since the control mode changed"
  Modelica.Blocks.Logical.LessEqualThreshold thr(threshold=120)
    "Skip the first 120 seconds of the day for comparison with reference values"
  Modelica.Blocks.Logical.Change cha
    "Outputs true if the input changes"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(intGai.y[1], machinesRad.Q_flow)
  connect(machinesRad.port, thermalZoneTwoElements.intGainsRad)
  connect(const.y, thermalZoneTwoElements.solRad[1])
  connect(setTemp.y[1],from_degC. u)
  connect(gainHea.y, heat.Q_flow)
  connect(gainCoo.y, cool.Q_flow)
  connect(switchHea.y, gainHea.u)
  connect(DefPow.y, switchHea.u3)
  connect(from_degC.y, conHeaCoo.u_s)
  connect(switchCoo.y, gainCoo.u)
  connect(hysteresis.y, switchCoo.u2)
  connect(DefPow.y, switchCoo.u1)
  connect(hysteresis.y, switchHea.u2)
  connect(conHeaCoo.y, switchHea.u1)
  connect(thermalZoneTwoElements.TAir, conHeaCoo.u_m)
  connect(heat.port, heatFlowSensor.port_b)
  connect(heatFlowSensor.port_a, thermalZoneTwoElements.intGainsConv)
  connect(cool.port, coolFlowSensor.port_a)
  connect(coolFlowSensor.port_b, thermalZoneTwoElements.intWallIndoorSurface)
  connect(coolFlowSensor.Q_flow, add.u1)
  connect(heatFlowSensor.Q_flow, add.u2)
  connect(hysteresis.u, switchHea.u1)
  connect(conHeaCoo.y, switchCoo.u3)
  connect(add.y, switchMea.u3)
  connect(reference.y[3], switchMea.u1)
  connect(timer.y, thr.u)
  connect(cha.y, not1.u)
  connect(not1.y, timer.u)
  connect(thr.y, switchMea.u2)
  connect(cha.u, hysteresis.y)
  connect(switchMea.y, mean.u)
  connect(reference.y[2], assEqu.u2)
  connect(mean.y, assEqu.u1)
end TestCase11;


VDI 6007 Test Case 12 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase12 "VDI 6007 Test Case 12 model"
  extends Modelica.Icons.Example;

  replaceable package Medium = Modelica.Media.Air.SimpleAir
   constrainedby Modelica.Media.Interfaces.PartialMedium "Medium model";

  RC.TwoElements thermalZoneTwoElements(
    redeclare final package Medium = Medium,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    hRad=5,
    nInt=1,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    RExt={0.00436791293674},
    RExtRem=0.03895919557,
    CExt={1600848.94},
    RInt={0.000595693407511},
    CInt={14836354.6282},
    ratioWinConRad=0.09,
    nPorts=2,
    nOrientations=1,
    VAir=0.1,
    AWin={0},
    ATransparent={7},
    AExt={10.5},
    extWallRC(thermCapExt(each T(fixed=true))),
    intWallRC(thermCapInt(each T(fixed=true))),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=295.15)
    "Thermal zone"
  Buildings.HeatTransfer.Sources.PrescribedTemperature preTem(port(T(
    start=300)))
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0,0,0; 3600,0,0,0; 7200,0,0,0; 10800,0,0,0; 14400,0,0,0; 18000,0,0,
        0; 21600,0,0,0; 25200,0,0,0; 25200,80,80,200; 28800,80,80,200; 32400,80,
        80,200; 36000,80,80,200; 39600,80,80,200; 43200,80,80,200; 46800,80,80,
        200; 50400,80,80,200; 54000,80,80,200; 57600,80,80,200; 61200,80,80,200;
        61200,0,0,0; 64800,0,0,0; 72000,0,0,0; 75600,0,0,0; 79200,0,0,0; 82800,
        0,0,0; 86400,0,0,0],
    columns={2,3,4})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    table=[0,21.5; 3600,21.5; 7200,21.2; 10800,21; 14400,20.9; 18000,21; 21600,
        21.3; 25200,21.9; 28800,24.1; 32400,24; 36000,24.4; 39600,24.8; 43200,
        25.1; 46800,25.3; 50400,25.5; 54000,25.6; 57600,26.3; 61200,26.3; 64800,
        25.2; 68400,25; 72000,24.6; 75600,24.2; 79200,24; 82800,23.8; 86400,
        23.6; 781200,29.1; 784800,28.7; 788400,28.4; 792000,28.2; 795600,28.3;
        799200,28.5; 802800,29; 806400,31.8; 810000,31.6; 813600,32; 817200,
        32.3; 820800,32.5; 824400,32.7; 828000,32.9; 831600,32.9; 835200,33.5;
        838800,33.5; 842400,31.7; 846000,31.5; 849600,31; 853200,30.6; 856800,
        30.3; 860400,30; 864000,29.8; 5101200,30.5; 5104800,30; 5108400,29.8;
        5112000,29.6; 5115600,29.6; 5119200,29.9; 5122800,30.3; 5126400,33.2;
        5130000,33; 5133600,33.4; 5137200,33.7; 5140800,33.9; 5144400,34.1;
        5148000,34.2; 5151600,34.3; 5155200,34.9; 5158800,34.8; 5162400,33;
        5166000,32.7; 5169600,32.2; 5173200,31.8; 5176800,31.4; 5180400,31.2;
        5184000,30.9],
    offset={273.15})
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow macConv
    "Convective heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.CombiTimeTable outdoorTemp(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    columns={2},
    table=[0,291.95; 3600,291.95; 3600,290.25; 7200,290.25; 7200,289.65; 10800,
        289.65; 10800,289.25; 14400,289.25; 14400,289.65; 18000,289.65; 18000,
        290.95; 21600,290.95; 21600,293.45; 25200,293.45; 25200,295.95; 28800,
        295.95; 28800,297.95; 32400,297.95; 32400,299.85; 36000,299.85; 36000,
        301.25; 39600,301.25; 39600,302.15; 43200,302.15; 43200,302.85; 46800,
        302.85; 46800,303.55; 50400,303.55; 50400,304.05; 54000,304.05; 54000,
        304.15; 57600,304.15; 57600,303.95; 61200,303.95; 61200,303.25; 64800,
        303.25; 64800,302.05; 68400,302.05; 68400,300.15; 72000,300.15; 72000,
        297.85; 75600,297.85; 75600,296.05; 79200,296.05; 79200,295.05; 82800,
        295.05; 82800,294.05; 86400,294.05])
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow perRad
    "Radiative heat flow persons"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow perCon
    "Convective heat flow persons"
  Modelica.Blocks.Sources.CombiTimeTable tableSolRadWindow(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    tableOnFile=false,
    table=[0,0; 3600,0; 10800,0; 14400,0; 14400,17; 18000,17; 18000,38; 21600,
        38; 21600,59; 25200,59; 25200,98; 28800,98; 28800,186; 32400,186; 32400,
        287; 36000,287; 36000,359; 39600,359; 39600,385; 43200,385; 43200,359;
        46800,359; 46800,287; 50400,287; 50400,186; 54000,186; 54000,98; 57600,
        98; 57600,59; 61200,59; 61200,38; 64800,38; 64800,17; 68400,17; 68400,0;
        72000,0; 82800,0; 86400,0],
    columns={2})
    "Solar radiation"
  Modelica.Blocks.Sources.Constant g_sunblind(k=0.15)
    "g value for sunblind closed"
  Modelica.Blocks.Sources.Constant sunblind_open(k=1)
    "g value for sunblind open"
  Modelica.Blocks.Logical.GreaterThreshold greaterThreshold1(threshold=100)
    "Threshold for sunblind for one direction"
  Modelica.Blocks.Math.Product product1
    "Solar radiation times g value for sunblind (open or closed) for one
    direction"
  Modelica.Blocks.Logical.Switch switch1
    "Determines g value for sunblind (open or closed) for one direction"
  Modelica.Blocks.Sources.CombiTimeTable ventRate(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,100; 3600,100; 7200,100; 10800,100; 14400,100; 18000,100; 21600,
        100; 25200,100; 25200,50; 28800,50; 32400,50; 36000,50; 39600,50; 43200,
        50; 46800,50; 50400,50; 54000,50; 57600,50; 61200,50; 61200,100; 64800,
        100; 72000,100; 75600,100; 79200,100; 82800,100; 86400,100])
    "Ventilation rate"
  Modelica.Blocks.Math.Gain gain(k=0.000330375898)
    "Conversion to kg/s"
  Fluid.Sources.MassFlowSource_T ventilationIn(
    use_m_flow_in=true,
    use_T_in=true,
    nPorts=1,
    redeclare package Medium = Medium)
    "Fan"
  Fluid.Sources.MassFlowSource_T ventilationOut(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    use_T_in=false)
    "Fan"
  Modelica.Blocks.Math.Gain gain1(k=-1)
    "Reverses ventilation rate"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=0.15)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(outdoorTemp.y[1], preTem.T)
  connect(perRad.port, thermalZoneTwoElements.intGainsRad)
  connect(intGai.y[1], perRad.Q_flow)
  connect(intGai.y[2], perCon.Q_flow)
  connect(intGai.y[3], macConv.Q_flow)
  connect(tableSolRadWindow.y[1],greaterThreshold1. u)
  connect(sunblind_open.y, switch1.u3)
  connect(g_sunblind.y, switch1.u1)
  connect(tableSolRadWindow.y[1], product1.u1)
  connect(greaterThreshold1.y, switch1.u2)
  connect(switch1.y, product1.u2)
  connect(ventRate.y[1], gain.u)
  connect(ventilationIn.ports[1], thermalZoneTwoElements.ports[1])
  connect(gain.y, ventilationIn.m_flow_in)
  connect(outdoorTemp.y[1], ventilationIn.T_in)
  connect(gain.y, gain1.u)
  connect(gain1.y, ventilationOut.m_flow_in)
  connect(ventilationOut.ports[1], thermalZoneTwoElements.ports[2])
  connect(perCon.port, thermalZoneTwoElements.intGainsConv)
  connect(macConv.port, thermalZoneTwoElements.intGainsConv)
  connect(product1.y, thermalZoneTwoElements.solRad[1])
  connect(thermalZoneTwoElements.TAir,mean. u)
  connect(mean.y,assEqu. u2)
  connect(reference.y[1],assEqu. u1)
end TestCase12;


VDI 6007 Test Case 2 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase2 "VDI 6007 Test Case 2 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    redeclare package Medium = Modelica.Media.Air.SimpleAir,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    nInt=1,
    ratioWinConRad=0,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    hRad=5,
    RExt={0.00436791293674},
    RExtRem=0.03895919557,
    CExt={1600848.94},
    RInt={0.000595693407511},
    CInt={14836354.6282},
    VAir=0,
    nOrientations=1,
    AWin={0},
    ATransparent={0},
    AExt={10.5},
    extWallRC(thermCapExt(each der_T(fixed=true))),
    T_start=295.15,
    intWallRC(thermCapInt(each der_T(fixed=true))))
    "Thermal zone"
  Buildings.HeatTransfer.Sources.FixedTemperature preTem(T=295.15)
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 21600,1000;
        25200,1000; 28800,1000; 32400,1000; 36000,1000; 39600,1000; 43200,1000;
        46800,1000; 50400,1000; 54000,1000; 57600,1000; 61200,1000; 64800,1000;
        64800,0; 68400,0; 72000,0; 75600,0; 79200,0; 82800,0; 86400,0],
    columns={2})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    offset={273.15},
    table=[0,22; 3600,22; 7200,22; 10800,22; 14400,22; 18000,22; 21600,22;
        25200,22.6; 28800,22.9; 32400,23.1; 36000,23.3; 39600,23.5; 43200,23.7;
        46800,23.9; 50400,24.1; 54000,24.3; 57600,24.6; 61200,24.8; 64800,25;
        68400,24.5; 72000,24.5; 75600,24.5; 79200,24.5; 82800,24.5; 86400,24.5;
        781200,37.7; 784800,37.7; 788400,37.6; 792000,37.5; 795600,37.5; 799200,
        37.4; 802800,38; 806400,38.2; 810000,38.3; 813600,38.5; 817200,38.6;
        820800,38.8; 824400,38.9; 828000,39.1; 831600,39.2; 835200,39.4; 838800,
        39.5; 842400,39.7; 846000,39.2; 849600,39.1; 853200,39.1; 856800,39;
        860400,38.9; 864000,38.9; 5101200,50; 5104800,49.9; 5108400,49.8;
        5112000,49.7; 5115600,49.6; 5119200,49.5; 5122800,50; 5126400,50.1;
        5130000,50.2; 5133600,50.3; 5137200,50.5; 5140800,50.6; 5144400,50.7;
        5148000,50.8; 5151600,50.9; 5155200,51; 5158800,51.1; 5162400,51.2;
        5166000,50.7; 5169600,50.6; 5173200,50.4; 5176800,50.3; 5180400,50.2;
        5184000,50.1])
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow machinesRad
    "Radiative heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.Constant const(k=0)
    "Solar radiation"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=0.15)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(intGai.y[1], machinesRad.Q_flow)
  connect(machinesRad.port, thermalZoneTwoElements.intGainsRad)
  connect(const.y, thermalZoneTwoElements.solRad[1])
  connect(thermalZoneTwoElements.TAir, mean.u)
  connect(mean.y, assEqu.u2)
  connect(reference.y[1], assEqu.u1)
end TestCase2;


VDI 6007 Test Case 3 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase3 "VDI 6007 Test Case 3 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    redeclare package Medium = Modelica.Media.Air.SimpleAir,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    hRad=5,
    nInt=1,
    ratioWinConRad=0,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    RExt={0.00404935160802},
    VAir=0,
    nOrientations=1,
    CExt={47900},
    RInt={0.003237138},
    CInt={7297100},
    RExtRem=0.039330865,
    AWin={0},
    ATransparent={0},
    AExt={10.5},
    extWallRC(thermCapExt(each der_T(fixed=true))),
    T_start=295.15,
    intWallRC(thermCapInt(each der_T(fixed=true))))
    "Thermal zone"
  Buildings.HeatTransfer.Sources.FixedTemperature preTem(T=295.15)
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 21600,1000;
        25200,1000; 28800,1000; 32400,1000; 36000,1000; 39600,1000; 43200,1000;
        46800,1000; 50400,1000; 54000,1000; 57600,1000; 61200,1000; 64800,1000;
        64800,0; 68400,0; 72000,0; 75600,0; 79200,0; 82800,0; 86400,0],
    columns={2})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    table=[0,22; 3600,22; 7200,22; 10800,22; 14400,22; 18000,22; 21600,22;
        25200,30.2; 28800,30.8; 32400,31.2; 36000,31.6; 39600,32; 43200,32.4;
        46800,32.8; 50400,33.2; 54000,33.6; 57600,34; 61200,34.3; 64800,34.7;
        68400,26.9; 72000,26.7; 75600,26.7; 79200,26.6; 82800,26.6; 86400,26.6;
        781200,43.7; 784800,43.5; 788400,43.4; 792000,43.2; 795600,43; 799200,
        42.9; 802800,50.9; 806400,51.3; 810000,51.6; 813600,51.8; 817200,52.1;
        820800,52.3; 824400,52.5; 828000,52.8; 831600,53; 835200,53.3; 838800,
        53.5; 842400,53.7; 846000,45.8; 849600,45.4; 853200,45.3; 856800,45.1;
        860400,44.9; 864000,44.7; 5101200,48.7; 5104800,48.5; 5108400,48.3;
        5112000,48.1; 5115600,47.9; 5119200,47.7; 5122800,55.7; 5126400,56;
        5130000,56.3; 5133600,56.5; 5137200,56.7; 5140800,56.9; 5144400,57.1;
        5148000,57.3; 5151600,57.5; 5155200,57.7; 5158800,57.9; 5162400,58.1;
        5166000,50.1; 5169600,49.8; 5173200,49.5; 5176800,49.3; 5180400,49.1;
        5184000,48.9],
    offset={273.15})
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow macConv
    "Convective heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.Constant const(k=0)
    "Solar radiation"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=0.15)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(intGai.y[1], macConv.Q_flow)
  connect(macConv.port, thermalZoneTwoElements.intGainsConv)
  connect(const.y, thermalZoneTwoElements.solRad[1])
  connect(thermalZoneTwoElements.TAir, mean.u)
  connect(mean.y, assEqu.u2)
  connect(reference.y[1], assEqu.u1)
end TestCase3;


VDI 6007 Test Case 4 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase4 "VDI 6007 Test Case 4 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    redeclare package Medium = Modelica.Media.Air.SimpleAir,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    nInt=1,
    ratioWinConRad=0,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    hRad=5,
    RExt={0.00404935160802},
    VAir=0,
    nOrientations=1,
    CExt={47900},
    RInt={0.003237138},
    CInt={7297100},
    RExtRem=0.039330865,
    AWin={0},
    ATransparent={0},
    AExt={10.5},
    extWallRC(thermCapExt(each der_T(fixed=true))),
    T_start=295.15,
    intWallRC(thermCapInt(each der_T(fixed=true))))
    "Thermal zone"
  Buildings.HeatTransfer.Sources.FixedTemperature preTem(T=295.15)
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 21600,1000;
        25200,1000; 28800,1000; 32400,1000; 36000,1000; 39600,1000; 43200,1000;
        46800,1000; 50400,1000; 54000,1000; 57600,1000; 61200,1000; 64800,1000;
        64800,0; 68400,0; 72000,0; 75600,0; 79200,0; 82800,0; 86400,0],
    columns={2})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    table=[0,22; 3600,22; 7200,22; 10800,22; 14400,22; 18000,22; 21600,22;
        25200,25.1; 28800,25.7; 32400,26.1; 36000,26.5; 39600,26.9; 43200,27.3;
        46800,27.7; 50400,28.1; 54000,28.5; 57600,28.9; 61200,29.3; 64800,29.7;
        68400,26.9; 72000,26.7; 75600,26.7; 79200,26.7; 82800,26.6; 86400,26.6;
        781200,43.8; 784800,43.6; 788400,43.5; 792000,43.3; 795600,43.1; 799200,
        43; 802800,45.9; 806400,46.3; 810000,46.6; 813600,46.8; 817200,47.1;
        820800,47.3; 824400,47.6; 828000,47.8; 831600,48.1; 835200,48.3; 838800,
        48.5; 842400,48.8; 846000,45.9; 849600,45.6; 853200,45.4; 856800,45.2;
        860400,45; 864000,44.8; 5101200,48.8; 5104800,48.6; 5108400,48.4;
        5112000,48.2; 5115600,48; 5119200,47.8; 5122800,50.7; 5126400,51.1;
        5130000,51.3; 5133600,51.5; 5137200,51.7; 5140800,51.9; 5144400,52.1;
        5148000,52.4; 5151600,52.6; 5155200,52.8; 5158800,53; 5162400,53.2;
        5166000,50.2; 5169600,49.9; 5173200,49.7; 5176800,49.5; 5180400,49.2;
        5184000,49],
    offset={273.15})
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow machinesRad
    "Radiative heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.Constant const(k=0)
    "Solar radiation"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=0.15)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(intGai.y[1], machinesRad.Q_flow)
  connect(machinesRad.port, thermalZoneTwoElements.intGainsRad)
  connect(const.y, thermalZoneTwoElements.solRad[1])
  connect(thermalZoneTwoElements.TAir, mean.u)
  connect(mean.y, assEqu.u2)
  connect(reference.y[1], assEqu.u1)
end TestCase4;


VDI 6007 Test Case 5 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase5 "VDI 6007 Test Case 5 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    redeclare package Medium = Modelica.Media.Air.SimpleAir,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    hRad=5,
    nInt=1,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    RExt={0.00436791293674},
    RExtRem=0.03895919557,
    CExt={1600848.94},
    RInt={0.000595693407511},
    CInt={14836354.6282},
    ratioWinConRad=0.09,
    VAir=0,
    nOrientations=1,
    AWin={0},
    ATransparent={7},
    AExt={10.5},
    extWallRC(thermCapExt(each T(fixed=true))),
    T_start=295.15,
    intWallRC(thermCapInt(each T(fixed=true))))
    "Thermal zone"
  Buildings.HeatTransfer.Sources.PrescribedTemperature preTem
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0,0,0; 3600,0,0,0; 7200,0,0,0; 10800,0,0,0; 14400,0,0,0; 18000,0,0,
        0; 21600,0,0,0; 25200,0,0,0; 25200,80,80,200; 28800,80,80,200; 32400,80,
        80,200; 36000,80,80,200; 39600,80,80,200; 43200,80,80,200; 46800,80,80,
        200; 50400,80,80,200; 54000,80,80,200; 57600,80,80,200; 61200,80,80,200;
        61200,0,0,0; 64800,0,0,0; 72000,0,0,0; 75600,0,0,0; 79200,0,0,0; 82800,
        0,0,0; 86400,0,0,0],
    columns={2,3,4})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    table=[0,22; 3600,22; 7200,22; 10800,21.9; 14400,21.9; 18000,22; 21600,22.2;
        25200,22.4; 28800,24.4; 32400,24.1; 36000,24.4; 39600,24.7; 43200,24.9;
        46800,25.1; 50400,25.2; 54000,25.3; 57600,26; 61200,25.9; 64800,24.3;
        68400,24.2; 72000,24.1; 75600,24.1; 79200,24.1; 82800,24.1; 86400,24.1;
        781200,34.9; 784800,34.8; 788400,34.7; 792000,34.6; 795600,34.7; 799200,
        34.8; 802800,34.9; 806400,36.9; 810000,36.6; 813600,36.8; 817200,37;
        820800,37.2; 824400,37.3; 828000,37.4; 831600,37.4; 835200,38.1; 838800,
        38; 842400,36.4; 846000,36.2; 849600,36.1; 853200,36.1; 856800,36;
        860400,35.9; 864000,35.9; 5101200,44.9; 5104800,44.8; 5108400,44.7;
        5112000,44.6; 5115600,44.6; 5119200,44.6; 5122800,44.8; 5126400,46.7;
        5130000,46.3; 5133600,46.5; 5137200,46.7; 5140800,46.8; 5144400,46.9;
        5148000,47; 5151600,47; 5155200,47.6; 5158800,47.5; 5162400,45.8;
        5166000,45.6; 5169600,45.4; 5173200,45.4; 5176800,45.3; 5180400,45.2;
        5184000,45.1],
    offset={273.15})
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow macConv
    "Convective heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.CombiTimeTable outdoorTemp(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    columns={2},
    table=[0,291.95; 3600,291.95; 3600,290.25; 7200,290.25; 7200,289.65; 10800,
        289.65; 10800,289.25; 14400,289.25; 14400,289.65; 18000,289.65; 18000,
        290.95; 21600,290.95; 21600,293.45; 25200,293.45; 25200,295.95; 28800,
        295.95; 28800,297.95; 32400,297.95; 32400,299.85; 36000,299.85; 36000,
        301.25; 39600,301.25; 39600,302.15; 43200,302.15; 43200,302.85; 46800,
        302.85; 46800,303.55; 50400,303.55; 50400,304.05; 54000,304.05; 54000,
        304.15; 57600,304.15; 57600,303.95; 61200,303.95; 61200,303.25; 64800,
        303.25; 64800,302.05; 68400,302.05; 68400,300.15; 72000,300.15; 72000,
        297.85; 75600,297.85; 75600,296.05; 79200,296.05; 79200,295.05; 82800,
        295.05; 82800,294.05; 86400,294.05])
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow perRad
    "Radiative heat flow persons"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow perCon
    "Convective heat flow persons"
  Modelica.Blocks.Sources.CombiTimeTable tableSolRadWindow(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    tableOnFile=false,
    table=[0,0; 3600,0; 10800,0; 14400,0; 14400,17; 18000,17; 18000,38; 21600,
        38; 21600,59; 25200,59; 25200,98; 28800,98; 28800,186; 32400,186; 32400,
        287; 36000,287; 36000,359; 39600,359; 39600,385; 43200,385; 43200,359;
        46800,359; 46800,287; 50400,287; 50400,186; 54000,186; 54000,98; 57600,
        98; 57600,59; 61200,59; 61200,38; 64800,38; 64800,17; 68400,17; 68400,0;
        72000,0; 82800,0; 86400,0],
    columns={2})
    "Solar radiation"
  Modelica.Blocks.Sources.Constant g_sunblind(k=0.15)
    "g value for sunblind closed"
  Modelica.Blocks.Sources.Constant sunblind_open(k=1)
    "g value for sunblind open"
  Modelica.Blocks.Logical.GreaterThreshold greaterThreshold1(
    threshold=100)
    "Threshold for sunblind"
  Modelica.Blocks.Math.Product product1
    "solar radiation times g value for sunblind (open or closed)"
  Modelica.Blocks.Logical.Switch switch1
    "Determines g value for sunblind (open or closed)"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=0.15)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(outdoorTemp.y[1], preTem.T)
  connect(perRad.port, thermalZoneTwoElements.intGainsRad)
  connect(intGai.y[1], perRad.Q_flow)
  connect(intGai.y[2], perCon.Q_flow)
  connect(intGai.y[3], macConv.Q_flow)
  connect(tableSolRadWindow.y[1],greaterThreshold1. u)
  connect(sunblind_open.y, switch1.u3)
  connect(g_sunblind.y, switch1.u1)
  connect(tableSolRadWindow.y[1], product1.u1)
  connect(greaterThreshold1.y, switch1.u2)
  connect(switch1.y, product1.u2)
  connect(perCon.port, thermalZoneTwoElements.intGainsConv)
  connect(macConv.port, thermalZoneTwoElements.intGainsConv)
  connect(product1.y, thermalZoneTwoElements.solRad[1])
  connect(thermalZoneTwoElements.TAir, mean.u)
  connect(mean.y, assEqu.u2)
  connect(reference.y[1], assEqu.u1)
end TestCase5;


VDI 6007 Test Case 6 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase6 "VDI 6007 Test Case 6 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    redeclare package Medium = Modelica.Media.Air.SimpleAir,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    nInt=1,
    ratioWinConRad=0,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    hRad=5,
    VAir=0,
    nOrientations=1,
    AWin={0},
    ATransparent={0},
    AExt={10.5},
    extWallRC(thermCapExt(each der_T(fixed=true))),
    intWallRC(thermCapInt(each der_T(fixed=true))),
    RExt={0.004367913},
    CExt={1600800},
    RInt={0.000595515},
    CInt={14836200},
    RExtRem=0.038959197,
    T_start=295.15)
    "Thermal zone"
  Buildings.HeatTransfer.Sources.FixedTemperature preTem(T=295.15)
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 21600,1000;
        25200,1000; 28800,1000; 32400,1000; 36000,1000; 39600,1000; 43200,1000;
        46800,1000; 50400,1000; 54000,1000; 57600,1000; 61200,1000; 64800,1000;
        64800,0; 68400,0; 72000,0; 75600,0; 79200,0; 82800,0; 86400,0],
    columns={2})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 25200,-764;
        28800,-696; 32400,-632; 36000,-570; 39600,-511; 43200,-455; 46800,-402;
        50400,-351; 54000,-302; 57600,-255; 61200,-210; 64800,-167; 68400,638;
        72000,610; 75600,583; 79200,557; 82800,533; 86400,511; 781200,774;
        784800,742; 788400,711; 792000,682; 795600,654; 799200,627; 802800,-163;
        806400,-120; 810000,-79; 813600,-40; 817200,-2; 820800,33; 824400,67;
        828000,99; 831600,130; 835200,159; 838800,187; 842400,214; 846000,1004;
        849600,960; 853200,919; 856800,880; 860400,843; 864000,808; 5101200,774;
        5104800,742; 5108400,711; 5112000,682; 5115600,654; 5119200,627;
        5122800,-163; 5126400,-120; 5130000,-78; 5133600,-39; 5137200,-2;
        5140800,33; 5144400,67; 5148000,99; 5151600,130; 5155200,159; 5158800,
        187; 5162400,214; 5166000,1004; 5169600,960; 5173200,919; 5176800,880;
        5180400,843; 5184000,808])
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow machinesRad
    "Radiative heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.Constant const(k=0)
    "Solar radiation"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heatFlowSensor
    "Sensor for ideal heater/cooler"
  Buildings.HeatTransfer.Sources.PrescribedTemperature preTem1
    "Prescribed temperature for ideal heater/cooler"
  Modelica.Blocks.Sources.CombiTimeTable setTemp(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    columns={2},
    smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments,
    table=[0,22; 3600,22; 7200,22; 10800,22; 14400,22; 18000,22; 21600,22;
        21600.1,27; 28800,27; 32400,27; 36000,27; 39600,27; 43200,27; 46800,27;
        50400,27; 54000,27; 57600,27; 61200,27; 64800,27; 64800.1,22; 72000,22;
        75600,22; 79200,22; 82800,22; 86400,22])
    "Set temperature for ideal heater/cooler"
  Modelica.Blocks.Math.UnitConversions.From_degC from_degC
    "Convert set temperature from degC to Kelvin"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=1.5)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
equation
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(intGai.y[1], machinesRad.Q_flow)
  connect(machinesRad.port, thermalZoneTwoElements.intGainsRad)
  connect(preTem1.port, heatFlowSensor.port_b)
  connect(heatFlowSensor.port_a, thermalZoneTwoElements.intGainsConv)
  connect(const.y, thermalZoneTwoElements.solRad[1])
  connect(preTem.port, theConWall.fluid)
  connect(from_degC.y, preTem1.T)
  connect(setTemp.y[1], from_degC.u)
  connect(mean.y,assEqu. u2)
  connect(reference.y[1],assEqu. u1)
  connect(heatFlowSensor.Q_flow, mean.u)
end TestCase6;


VDI 6007 Test Case 7 model

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
model TestCase7 "VDI 6007 Test Case 7 model"
  extends Modelica.Icons.Example;

  RC.TwoElements thermalZoneTwoElements(
    redeclare package Medium = Modelica.Media.Air.SimpleAir,
    hConExt=2.7,
    hConWin=2.7,
    gWin=1,
    nExt=1,
    nInt=1,
    ratioWinConRad=0,
    AInt=75.5,
    hConInt=2.24,
    RWin=0.00000001,
    hRad=5,
    RExt={0.00436791293674},
    RExtRem=0.03895919557,
    CExt={1600848.94},
    RInt={0.000595693407511},
    CInt={14836354.6282},
    VAir=0,
    nOrientations=1,
    AWin={0},
    ATransparent={0},
    AExt={10.5},
    extWallRC(thermCapExt(each der_T(fixed=true))),
    intWallRC(thermCapInt(each der_T(fixed=true))),
    T_start=295.15)
    "Thermal zone"
  Buildings.HeatTransfer.Sources.FixedTemperature preTem(
    T=295.15)
    "Outdoor air temperature"
  Modelica.Thermal.HeatTransfer.Components.Convection theConWall(Q_flow(start=0))
    "Outdoor convective heat transfer"
  Modelica.Blocks.Sources.CombiTimeTable intGai(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 21600,1000;
        25200,1000; 28800,1000; 32400,1000; 36000,1000; 39600,1000; 43200,1000;
        46800,1000; 50400,1000; 54000,1000; 57600,1000; 61200,1000; 64800,1000;
        64800,0; 68400,0; 72000,0; 75600,0; 79200,0; 82800,0; 86400,0],
    columns={2})
    "Table with internal gains"
  Modelica.Blocks.Sources.CombiTimeTable reference(
    tableOnFile=false,
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
    table=[0,0; 3600,0; 7200,0; 10800,0; 14400,0; 18000,0; 21600,0; 25200,500;
        28800,500; 32400,500; 36000,500; 39600,500; 43200,481; 46800,426; 50400,
        374; 54000,324; 57600,276; 61200,230; 64800,186; 68400,-500; 72000,-500;
        75600,-500; 79200,-500; 82800,-500; 86400,-500; 781200,-500; 784800,-500;
        788400,-500; 792000,-500; 795600,-500; 799200,-500; 802800,-142; 806400,
        -172; 810000,-201; 813600,-228; 817200,-254; 820800,-278; 824400,-302;
        828000,-324; 831600,-345; 835200,-366; 838800,-385; 842400,-404; 846000,
        -500; 849600,-500; 853200,-500; 856800,-500; 860400,-500; 864000,-500;
        5101200,-500; 5104800,-500; 5108400,-500; 5112000,-500; 5115600,-500;
        5119200,-500; 5122800,-149; 5126400,-179; 5130000,-207; 5133600,-234;
        5137200,-259; 5140800,-284; 5144400,-307; 5148000,-329; 5151600,-350;
        5155200,-371; 5158800,-390; 5162400,-408; 5166000,-500; 5169600,-500;
        5173200,-500; 5176800,-500; 5180400,-500; 5184000,-500])
    "Reference results"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow machinesRad
    "Radiative heat flow machines"
  Modelica.Blocks.Sources.Constant hConWall(k=25*10.5)
    "Outdoor coefficient of heat transfer for walls"
  Modelica.Blocks.Sources.Constant const(k=0)
    "Solar radiation"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heaCoo
    "Ideal heater/cooler with limit"
  Modelica.Blocks.Sources.CombiTimeTable setTemp(
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    columns={2},
    smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments,
    table=[0,22; 3600,22; 7200,22; 10800,22; 14400,22; 18000,22; 21600,22;
        21600.1,27; 28800,27; 32400,27; 36000,27; 39600,27; 43200,27; 46800,27;
        50400,27; 54000,27; 57600,27; 61200,27; 64800,27; 64800.1,22; 72000,22;
        75600,22; 79200,22; 82800,22; 86400,22])
    "Set temperature for ideal heater/cooler"
  Modelica.Blocks.Math.UnitConversions.From_degC from_degC
    "Convert set temperature from degC to Kelvin"
  Controls.Continuous.LimPID conHeaCoo(
    yMax=1,
    yMin=-1,
    k=0.1,
    Ti=4)
    "Heating and cooling controller"
  Modelica.Blocks.Math.Gain gainHeaCoo(k=500)
    "Gain for heating and cooling controller"
  BaseClasses.VerifyDifferenceThreePeriods assEqu(
    startTime=3600,
    endTime=86400,
    startTime2=781200,
    endTime2=864000,
    startTime3=5101200,
    endTime3=5184000,
    threShold=1.5)
    "Checks validation criteria"
  Modelica.Blocks.Math.Mean mean(f=1/3600)
    "Hourly mean of indoor air temperature"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heatFlowSensor
    "Sensor for ideal heater/cooler"
  Modelica.Blocks.Math.Gain gainMea(k=-1)
    "Gain for mean block"
equation
  connect(theConWall.fluid, preTem.port)
  connect(thermalZoneTwoElements.extWall, theConWall.solid)
  connect(hConWall.y, theConWall.Gc)
  connect(intGai.y[1], machinesRad.Q_flow)
  connect(machinesRad.port, thermalZoneTwoElements.intGainsRad)
  connect(const.y, thermalZoneTwoElements.solRad[1])
  connect(from_degC.y, conHeaCoo.u_s)
  connect(thermalZoneTwoElements.TAir, conHeaCoo.u_m)
  connect(conHeaCoo.y, gainHeaCoo.u)
  connect(gainHeaCoo.y, heaCoo.Q_flow)
  connect(setTemp.y[1], from_degC.u)
  connect(mean.y,assEqu. u2)
  connect(reference.y[1],assEqu. u1)
  connect(heaCoo.port, heatFlowSensor.port_b)
  connect(heatFlowSensor.port_a, thermalZoneTwoElements.intGainsConv)
  connect(mean.u, gainMea.y)
  connect(gainMea.u, heatFlowSensor.Q_flow)
end TestCase7;


VDI 6007 Test Case 8 model


VDI 6007 Test Case 9 model


within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007;
package BaseClasses "Base classes for VDI 6007 validation cases"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Assert when condition is violated. Block that outputs satisfied = false if
abs(u1-u2) > threShold within the prescribed time intervals,
or satisfied = true otherwise.

within Buildings.ThermalZones.ReducedOrder.Validation.VDI6007.BaseClasses;
block VerifyDifferenceThreePeriods "Assert when condition is violated"
  extends Buildings.Utilities.Diagnostics.BaseClasses.PartialInputCheck(
    message="Inputs differ by more than threShold.\n  Check output 'satisfied' for when violation(s) happened.");
  parameter Modelica.Units.SI.Time endTime=0
    "Start time for deactivating the assert (period one)";
  parameter Modelica.Units.SI.Time startTime2=0
    "Start time for activating the assert (period two)";
  parameter Modelica.Units.SI.Time endTime2=0
    "Start time for deactivating the assert (period two)";
  parameter Modelica.Units.SI.Time startTime3=0
    "Start time for activating the assert (period three)";
  parameter Modelica.Units.SI.Time endTime3=0
    "Start time for deactivating the assert (period three)";
  parameter Modelica.Units.SI.Time tau(min=1) = 60
    "Time constant for filtering signal";

  Modelica.Blocks.Interfaces.BooleanOutput satisfied(start=true, fixed=true)

  Modelica.Blocks.Interfaces.RealOutput diff "Difference abs(u1-u2) after filtering"

protected
  parameter Modelica.Units.SI.Time t1(fixed=false)
    "Simulation end time period one";
  parameter Modelica.Units.SI.Time t3(fixed=false)
    "Simulation end time period two";
  parameter Modelica.Units.SI.Time t5(fixed=false)
    "Simulation end time period three";
  parameter Modelica.Units.SI.Time t2(fixed=false)
    "Simulation start time period two";
  parameter Modelica.Units.SI.Time t4(fixed=false)
    "Simulation start time period three";
  Integer nFai "Number of test violations";
  Real diffExa "Exact, non-filtered value of the difference between the inputs";

initial equation
  t1 = time + endTime;
  t2 = time + startTime2;
  t3 = time + endTime2;
  t4 = time + startTime3;
  t5 = time + endTime3;
  nFai = 0;
  diff = if (time >= t0) and (time < t1) or
            (time >= t2) and (time < t3) or
            (time >= t4) and (time < t5)
         then
           abs(u1 - u2)
         else
           0;
equation
  if (time >= t0) and (time < t1) or
     (time >= t2) and (time < t3) or
     (time >= t4) and (time < t5) then
     diffExa = abs(u1 - u2);
  else
    diffExa = 0; // Test is not needed in this time domain
  end if;
  der(diff) = (diffExa-diff)/tau;

  // Output whether test is satisfied, using a small hysteresis that is scaled using threShold
  satisfied = not ( (pre(satisfied) and diff > 1.01*threShold) or (not pre(satisfied) and diff >= 0.99*threShold));

  // Count the number of failures and raise an assertion in the terminal section.
  // This ensures that if the model is in an FMU, no asserts are triggered during
  // the solver iterations.
  when not satisfied then
    nFai = pre(nFai) + 1;
  end when;

  when terminal() then
    assert(nFai == 0, message);
  end when;
end VerifyDifferenceThreePeriods;


Package with type definitions

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

  type Reset = enumeration(
    Disabled   "Disabled",
    Parameter   "Use parameter value",
    Input   "Use input signal")
    "Options for integrator reset"
end Types;


within Buildings.Types;
package Azimuth "List of possible constant values for surface azimuth"
   extends Modelica.Icons.TypesPackage;

constant Modelica.Units.SI.Angle S=0
  "Azimuth for an exterior wall whose outer surface faces south";
constant Modelica.Units.SI.Angle SW=+Modelica.Constants.pi/4
  "Azimuth for an exterior wall whose outer surface faces south-west";
constant Modelica.Units.SI.Angle W=+Modelica.Constants.pi/2
  "Azimuth for an exterior wall whose outer surface faces west";
constant Modelica.Units.SI.Angle NW=+Modelica.Constants.pi*3/4
  "Azimuth for an exterior wall whose outer surface faces north-west";
constant Modelica.Units.SI.Angle N=Modelica.Constants.pi
  "Azimuth for an exterior wall whose outer surface faces north";
constant Modelica.Units.SI.Angle NE=-Modelica.Constants.pi*3/4
  "Azimuth for an exterior wall whose outer surface faces north-east";
constant Modelica.Units.SI.Angle E=-Modelica.Constants.pi/2
  "Azimuth for an exterior wall whose outer surface faces east";
constant Modelica.Units.SI.Angle SE=-Modelica.Constants.pi/4
  "Azimuth for an exterior wall whose outer surface faces south-east";
end Azimuth;


within Buildings.Types;
package Tilt "List of possible constant values for surface tilt"
  extends Modelica.Icons.TypesPackage;

constant Modelica.Units.SI.Angle Ceiling=0 "Tilt for ceiling";
constant Modelica.Units.SI.Angle Floor=Modelica.Constants.pi "Tilt for floor";
constant Modelica.Units.SI.Angle Wall=Modelica.Constants.pi/2 "Tilt for wall";
end Tilt;


within Buildings;
package Utilities "Package with utility functions such as for I/O"
  extends Modelica.Icons.Package;
end Utilities;


Package with clustering functions

within Buildings.Utilities;
package Clustering "Package with clustering functions"
  extends Modelica.Icons.VariantsPackage;
end Clustering;


Model that verifies the k-means clustering function for 1d data. This example tests the k-means clustering algorithm on 1d data.

within Buildings.Utilities.Clustering.Validation;
model KMeans_1d "Model that verifies the k-means clustering function for 1d data"
  extends Modelica.Icons.Example;

  parameter Integer n_clusters = 3 "Number of clusters to be generated";
  parameter Real data[:,:] = [1;2;2;3;4] "Test data to be clustered";

  parameter Integer nDat = size(data,1) "Number of samples";
  parameter Integer nDim = size(data,2) "Number of features";
  parameter Real[n_clusters,nDim] centroids(each fixed=false)
    "Centroids of the clusters";
  parameter Integer[nDat] labels(each fixed=false)
    "Cluster label associated with each data point";
  parameter Integer[n_clusters] cluster_size(each fixed=false)
    "Size of the clusters";

  parameter Integer labelsExp[nDat]=
    {2,2,2,1,3}
    "Expected cluster labels";

  // Comparison result
  Boolean cmp "Comparison result";

initial equation
  (centroids, labels, cluster_size) = Buildings.Utilities.Clustering.KMeans(
    data, n_clusters, nDat, nDim);

equation
  cmp = Modelica.Math.Vectors.isEqual(labels, labelsExp);
end KMeans_1d;


Model that verifies the k-means clustering function for 2d data. This example tests the k-means clustering algorithm on 2d data.

within Buildings.Utilities.Clustering.Validation;
model KMeans_2d "Model that verifies the k-means clustering function for 2d data"
  extends Modelica.Icons.Example;

  parameter Integer n_clusters = 3 "Number of clusters to be generated";
  parameter Real data[:,:]=
    [ 1, 1;
      1, 2;
      2, 1;
      2, 1.2;
      3, 0;
      4, 0]
     "Test data to be clustered";

  parameter Integer nDat = size(data,1) "Number of samples";
  parameter Integer nDim = size(data,2) "Number of features";
  parameter Real[n_clusters,nDim] centroids(each fixed=false)
    "Centroids of the clusters";
  parameter Integer[nDat] labels(each fixed=false)
    "Cluster label associated with each data point";
  parameter Integer[n_clusters] cluster_size(each fixed=false)
    "Size of the clusters";

  parameter Integer labelsExp[nDat]=
    {2,2,1,2,1,3}
    "Expected cluster labels";

  // Comparison result
  Boolean cmp "Comparison result";

initial equation
  (centroids, labels, cluster_size) = Buildings.Utilities.Clustering.KMeans(
    data, n_clusters, nDat, nDim);

equation
  cmp = Modelica.Math.Vectors.isEqual(labels, labelsExp);
end KMeans_2d;


within Buildings.Utilities.Clustering;
package Validation "Validation models for clustering functions."
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Thermal comfort model according to Fanger. Thermal comfort model according to Fanger, as described in
the ASHRAE Fundamentals (2017).

within Buildings.Utilities.Comfort;
model Fanger "Thermal comfort model according to Fanger"
extends Buildings.BaseClasses.BaseIcon;

  Modelica.Blocks.Interfaces.RealOutput PMV "PMV"
  Modelica.Blocks.Interfaces.RealOutput PPD "PPD [0.05...1]"

  parameter Modelica.Units.SI.HeatFlux W(max=0) = 0
    "Rate of mechanical work accomplished (must be non-positive, typically equal to 0)";
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hRad(
    min=0,
    max=10) = 0.8*4.7 "Radiative heat transfer coefficient";

  parameter Boolean use_vAir_in=false
    "Get the air velocity from the input connector"
  parameter Boolean use_M_in= false
    "Get the metabolic rate from the input connector"
  parameter Boolean use_ICl_in= true
    "Get the clothing insulation from the input connector"
  parameter Boolean use_pAir_in= false
    "Get the air pressure from the input connector"

  parameter Modelica.Units.SI.Velocity vAir=0.05 "Fixed value for air velocity"
  parameter Modelica.Units.SI.HeatFlux M=60 "Fixed value for metabolic rate"
  parameter Real ICl = 0.7
    "Fixed value for clothing insulation in units of clo (summer=0.5; winter=0.9)"
  parameter Modelica.Units.SI.Pressure pAir=101325
    "Fixed value for air pressure"

  Modelica.Blocks.Interfaces.RealInput TAir(final quantity="ThermodynamicTemperature",
                                          final unit = "K", displayUnit = "degC")
    "Air temperature"
  Modelica.Blocks.Interfaces.RealInput TRad(final quantity="ThermodynamicTemperature",
                                          final unit = "K", displayUnit = "degC")
    "Radiation temperature"

  Modelica.Units.SI.Temperature TOpe "Operative temperature";
  Modelica.Units.SI.Temperature TClo(start=273.15 + 40)
    "Surface temperature of clothing";
  Modelica.Units.SI.Temperature TSki(min=273.15 + 10, max=273.15 + 42)
    "Skin temperature";

  Modelica.Blocks.Interfaces.RealInput phi(min=0, max=1) "Relative humidity"
  Modelica.Blocks.Interfaces.RealInput pAir_in(
    final quantity="Pressure",
    final unit="Pa",
    min=0) if use_pAir_in "Air pressure"
  Modelica.Blocks.Interfaces.RealInput ICl_in if use_ICl_in
    "Clothing thermal resistance in clo"
  Modelica.Blocks.Interfaces.RealInput vAir_in
    if use_vAir_in "Air velocity"
  Modelica.Blocks.Interfaces.RealInput M_in(
    min=40,
    max=600,
    final quantity="HeatFlux",
    final unit="W/m2") if use_M_in
    "Metabolic heat generation in W/m2 (not in met)"

  Modelica.Units.SI.CoefficientOfHeatTransfer hCom(min=0, max=10)
    "Combined heat transfer coefficient";

  Modelica.Units.SI.CoefficientOfHeatTransfer hCon(min=0, max=10)
    "Convective heat transfer coefficient";

  Modelica.Units.SI.Pressure pSte(min=0, max=3000)
    "Partial pressure of water vapor in ambient air";

  Modelica.Units.SI.HeatFlux L "Thermal load of the body";
  Real fCl(min=0) "Clothing area factor (61)";
  Modelica.Units.SI.ThermalInsulance RCl "Thermal resistance of clothing (10)";

protected
  Buildings.Utilities.Psychrometrics.X_pTphi steRat
    "Model to compute the steam mass fraction";
  Real fCl1 "work variable for fCl";
  Real fCl2 "work variable for fCl";

  Modelica.Blocks.Interfaces.RealInput vAir_in_internal
    "Needed to connect to conditional connector";
    Modelica.Blocks.Interfaces.RealInput M_in_internal(
    min=40,
    max=600,
    final quantity="HeatFlux",
    final unit="W/m2") "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput ICl_in_internal
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput pAir_in_internal(
    final quantity="Pressure",
    final unit="Pa",
    min=0) "Needed to connect to conditional connector";

initial equation
 assert(W <= 0, "Parameter W must be equal to zero or negative.");

equation
  // Conditional connectors
  connect(vAir_in, vAir_in_internal);
  if not use_vAir_in then
    vAir_in_internal = vAir;
  end if;
  connect(M_in, M_in_internal);
  if not use_M_in then
    M_in_internal = M;
  end if;
  connect(ICl_in, ICl_in_internal);
  if not use_ICl_in then
    ICl_in_internal = ICl;
  end if;
  connect(pAir_in, pAir_in_internal);
  if not use_pAir_in then
    pAir_in_internal = pAir;
  end if;

  TSki = 308.85 - 0.0275*(M_in_internal - W);

  // partial pressure of steam
  connect(steRat.p_in, pAir_in_internal);
  connect(steRat.T, TAir);
  connect(steRat.phi, phi);
  pSte = Psychrometrics.Functions.pW_X(X_w=steRat.X[1], p=pAir_in_internal);

  // clothing insulation value
  RCl = 0.155 * ICl_in_internal;
  // clothing area factor
  fCl1 = 1.00 + 0.2*ICl_in_internal;
  fCl2 = 1.05 + 0.1*ICl_in_internal;

  // fcl eq (61)
  fCl = fCl1 + (fCl2 - fCl1)*Buildings.Utilities.Math.Functions.smoothHeaviside(
    x=(ICl_in_internal - 0.5),
    delta=0.01);

  hCon = Buildings.Utilities.Math.Functions.smoothMax(
    x1=12.1*sqrt(abs(vAir_in_internal)),
    x2=2.38*abs(TClo - TAir)^0.25,
    deltaX=0.0001);

  hCom = hRad + hCon;

  // operative temperature (8)
  TOpe = (hRad*TRad + hCon*TAir)/hCom;

  // Clothing temperature (59)
  TClo = 35.7 - 0.028 * (M_in_internal-W) - RCl*((3.96E-8*fCl*((TClo)^4 - (TRad)^4))+ fCl*hCon*(TClo - TAir)) + 273.15;

  L = (M_in_internal - W)
       - 3.05E-3*(5733 - 6.99*(M_in_internal - W) - pSte)
        - 0.42*((M_in_internal - W) - 58.15)
        - 1.7E-5*M_in_internal*(5867 - pSte)
        - 0.0014*M_in_internal*(307.15 - TAir)
        - 3.96E-8*fCl*(TClo^4 - TRad^4)
        - fCl*hCon*(TClo - TAir);

  PMV = (0.303*Modelica.Math.exp(-0.036*M_in_internal) + 0.028)*L;
  PPD = 1 - 0.95*Modelica.Math.exp(-(0.03353*PMV^4 + 0.2179*PMV^2));
end Fanger;


Library with models for comfort

within Buildings.Utilities;
package Comfort "Library with models for comfort"
  extends Modelica.Icons.VariantsPackage;
end Comfort;


Test of Comfort Model. This is a test of the Thermal Comfort Model.

within Buildings.Utilities.Comfort.Examples;
model Fanger "Test of Comfort Model"
  extends Modelica.Icons.Example;

  Buildings.Utilities.Comfort.Fanger theCom(
    use_vAir_in=true,
    use_M_in=true,
    use_pAir_in=true) "Thermal comfort model"
  Modelica.Blocks.Sources.Constant ICl(k=0.9) "Clothing insulation"
  Modelica.Blocks.Sources.Constant vAir(k=0.05) "Air velocity"
  Modelica.Blocks.Sources.Constant M(k=60) "Metabolic heat generated"
  Modelica.Blocks.Sources.Ramp TAir(
    duration=1,
    height=10,
    offset=273.15 + 20) "Air temperature"
  Modelica.Blocks.Sources.Constant TRad(k=273.15 + 22) "Radiation temperature"
  Modelica.Blocks.Sources.Constant pAtm(k=101325)
  Modelica.Blocks.Sources.Constant phi(k=0.5) "Relative humidity"
  Buildings.Utilities.Comfort.Fanger theComFixPar(
    use_vAir_in=false,
    use_M_in=false,
    use_ICl_in=false,
    use_pAir_in=false,
    ICl=0.9) "Thermal comfort model with fixed parameters"
equation
  connect(pAtm.y, theCom.pAir_in)
  connect(TRad.y, theCom.TRad)
  connect(theCom.TAir, TAir.y)
  connect(theCom.vAir_in, vAir.y)
  connect(M.y, theCom.M_in)
  connect(ICl.y, theCom.ICl_in)
  connect(phi.y, theCom.phi)
  connect(TRad.y, theComFixPar.TRad)
  connect(theComFixPar.TAir, TAir.y)
  connect(phi.y, theComFixPar.phi)
end Fanger;


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


Script for comparing the PMV model with the CBE thermal comfort tool. This example validates the PMV values against values calculated with
the CBE (Center for the Built Environment, UC Berkeley)
Thermal Comfort Tool for a variety of cases.


within Buildings.Utilities.Comfort;
package Validation "Result comparison with a different comfort evaluation tool"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Package with cryptographic functions

within Buildings.Utilities;
package Cryptographics "Package with cryptographic functions"
  extends Modelica.Icons.VariantsPackage;
end Cryptographics;


within Buildings.Utilities.Cryptographics;
package Validation "Validation models for cryptographic functions."
extends Modelica.Icons.ExamplesPackage;
end Validation;


Model that verifies the SHA1 encryption C function. This validation function tests the C implementation of the SHA1 encryption for
the following strings:

within Buildings.Utilities.Cryptographics.Validation;
model SHA1 "Model that verifies the SHA1 encryption C function"
  extends Modelica.Icons.Example;

  //Test strings
  parameter String strIn1 = "abc"
    "First test string";
  parameter String strIn2 = ""
    "Second test string";
  parameter String strIn3 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
    "Third test string";
  parameter String strIn4 = "1.23e+4"
    "Fourth test string";
  parameter String strIn5 = Modelica.Utilities.Strings.repeat(509, string="a")
    "Fifth test string";

  //Expected outputs
  parameter String strEx1=
    "a9993e364706816aba3e25717850c26c9cd0d89d"
    "Encryption result of first string";
  parameter String strEx2=
    "da39a3ee5e6b4b0d3255bfef95601890afd80709"
    "Encryption result of second string";
  parameter String strEx3=
    "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
    "Encryption result of third string";
  parameter String strEx4=
    "bdd220adb45b392f17915af70ed8a006c382b983"
    "Encryption result of fourth string";
  parameter String strEx5=
    "edff7a135c2e06d4c8084e61b4516c901bd5fcd0"
    "Encryption result of fifth string";

  //Comparison results
  Boolean cmp1,cmp2,cmp3,cmp4,cmp5,cmpAll;

equation
  cmp1 = Modelica.Utilities.Strings.isEqual(Buildings.Utilities.Cryptographics.sha(strIn1),strEx1,false);
  cmp2 = Modelica.Utilities.Strings.isEqual(Buildings.Utilities.Cryptographics.sha(strIn2),strEx2,false);
  cmp3 = Modelica.Utilities.Strings.isEqual(Buildings.Utilities.Cryptographics.sha(strIn3),strEx3,false);
  cmp4 = Modelica.Utilities.Strings.isEqual(Buildings.Utilities.Cryptographics.sha(strIn4),strEx4,false);
  cmp5 = Modelica.Utilities.Strings.isEqual(Buildings.Utilities.Cryptographics.sha(strIn5),strEx5,false);
  cmpAll = cmp1 and cmp2 and cmp3 and cmp4 and cmp5;
end SHA1;


Assert when condition is violated. Model that triggers an assert if
|u1-u2| > threShold
and t > t0.

within Buildings.Utilities.Diagnostics;
block AssertEquality "Assert when condition is violated"
  extends BaseClasses.PartialInputCheck(message = "Inputs differ by more than threShold");
equation
  if noEvent(time > t0) then
    assert(noEvent(abs(u1 - u2) < threShold), message + "\n"
      + "  time       = " + String(time) + "\n"
      + "  u1         = " + String(u1) + "\n"
      + "  u2         = " + String(u2) + "\n"
      + "  abs(u1-u2) = " + String(abs(u1-u2)) + "\n"
      + "  threShold  = " + String(threShold));
  end if;
end AssertEquality;


Assert when condition is violated. Model that triggers an assert if
u1 > u2 - threShold
and t > t0.

within Buildings.Utilities.Diagnostics;
block AssertInequality "Assert when condition is violated"
  extends BaseClasses.PartialInputCheck(message = "Inputs differ by more than threShold",
     threShold = 0);
equation
  if noEvent(time > t0) then
    assert(noEvent(u1 > u2 - threShold), message + "\n"
      + "  time       = " + String(time) + "\n"
      + "  u1         = " + String(u1) + "\n"
      + "  u2         = " + String(u2) + "\n"
      + "  abs(u1-u2) = " + String(abs(u1-u2)) + "\n"
      + "  threShold  = " + String(threShold));
  end if;
end AssertInequality;


Check equality between inputs up to a threshold. Block that outputs 0 if the difference
|u1-u2| < threShold,
or else it outputs u2-u1.

within Buildings.Utilities.Diagnostics;
block CheckEquality "Check equality between inputs up to a threshold"
  extends Modelica.Blocks.Icons.Block;

  parameter Real threShold(min=0)=1e-2 "Threshold for equality comparison";

  Modelica.Blocks.Interfaces.RealInput u1 "Value to check"
  Modelica.Blocks.Interfaces.RealInput u2 "Value to check"
  Modelica.Blocks.Interfaces.RealOutput y "Error"

equation
  y = noEvent(if abs(u2-u1)< threShold then 0 else u2-u1);
end CheckEquality;


within Buildings.Utilities;
package Diagnostics "Library with models to diagnose model errors"
  extends Modelica.Icons.VariantsPackage;
end Diagnostics;


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


Assert when condition is violated. Partial model that can be used to check whether its
inputs satisfy a certain condition such as equality within
a prescribed threshold.

within Buildings.Utilities.Diagnostics.BaseClasses;
block PartialInputCheck "Assert when condition is violated"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.Time startTime=0
    "Start time for activating the assert";
  parameter Real threShold(min=0)=1E-2 "Threshold for equality comparison";
  parameter String message = "Inputs differ by more than threShold";
  Modelica.Blocks.Interfaces.RealInput u1 "Value to check"
  Modelica.Blocks.Interfaces.RealInput u2 "Value to check"
protected
  parameter Modelica.Units.SI.Time t0(fixed=false) "Simulation start time";
initial equation
  t0 = time + startTime;
end PartialInputCheck;


Validation model for the check equality model. This model validates the use of the

Buildings.Utilities.Diagnostics.CheckEquality.

within Buildings.Utilities.Diagnostics.Validation;
model CheckEquality "Validation model for the check equality model"
  extends Modelica.Icons.Example;

  Buildings.Utilities.Diagnostics.CheckEquality cheEqu
    "Checks for equality of the input"
  Modelica.Blocks.Sources.Constant con(k=0.1) "Input"
  Modelica.Blocks.Sources.Sine sin1(f=1, amplitude=0.03) "Input"
  Modelica.Blocks.Math.Add add "Adder to offset the sin input signal"
equation

  connect(con.y, cheEqu.u1)
  connect(add.u1, con.y)
  connect(sin1.y, add.u2)
  connect(add.y, cheEqu.u2)
end CheckEquality;


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


Input and output

within Buildings.Utilities;
package IO "Input and output"
  extends Modelica.Icons.Package;
end IO;


Block that exchanges data with the Building Controls Virtual Test Bed.

within Buildings.Utilities.IO.BCVTB;
model BCVTB
  "Block that exchanges data with the Building Controls Virtual Test Bed"
  extends Modelica.Blocks.Interfaces.DiscreteBlock(final startTime=0,
  final samplePeriod = if activateInterface then timeStep else Modelica.Constants.inf);
  parameter Boolean activateInterface = true
    "Set to false to deactivate interface and use instead yFixed as output"
  parameter Modelica.Units.SI.Time timeStep
    "Time step used for the synchronization"
  parameter String xmlFileName = "socket.cfg"
    "Name of the file that is generated by the BCVTB and that contains the socket information";
  parameter Integer nDblWri(min=0)
    "Number of double values to write to the BCVTB";
  parameter Integer nDblRea(min=0)
    "Number of double values to be read from the BCVTB";
  parameter Integer flaDblWri[nDblWri] = zeros(nDblWri)
    "Flag for double values (0: use current value, 1: use average over interval, 2: use integral over interval)";
  parameter Real uStart[nDblWri]
    "Initial input signal, used during first data transfer with BCVTB";
  parameter Real yRFixed[nDblRea] = zeros(nDblRea)
    "Fixed output, used if activateInterface=false"

  Modelica.Blocks.Interfaces.RealInput uR[nDblWri]
    "Real inputs to be sent to the BCVTB"
  Modelica.Blocks.Interfaces.RealOutput yR[nDblRea]
    "Real outputs received from the BCVTB"

 Integer flaRea "Flag received from BCVTB";
  Modelica.Units.SI.Time simTimRea
    "Current simulation time received from the BCVTB";
 Integer retVal "Return value from the BSD socket data exchange";
protected
  parameter Integer socketFD(fixed=false)
    "Socket file descripter, or a negative value if an error occurred";
  parameter Real _uStart[nDblWri](each fixed=false)
    "Initial input signal, used during first data transfer with BCVTB";
  constant Integer flaWri=0;
  Real uRInt[nDblWri] "Value of integral";
  Real uRIntPre[nDblWri] "Value of integral at previous sampling instance";
public
  Real uRWri[nDblWri] "Value to be sent to the interface";
initial algorithm
  socketFD :=if activateInterface then
      Buildings.Utilities.IO.BCVTB.BaseClasses.establishClientSocket(xmlFileName=xmlFileName) else
      0;
    // check for valid socketFD
     assert(socketFD >= 0, "Socket file descripter for BCVTB must be positive.\n" +
                         "   A negative value indicates that no connection\n" +
                         "   could be established. Check file 'utilSocket.log'.\n" +
                         "   Received: socketFD = " + String(socketFD));
   flaRea   := 0;
   uRInt    := zeros(nDblWri);
   uRIntPre := zeros(nDblWri);
   for i in 1:nDblWri loop
     assert(flaDblWri[i]>=0 and flaDblWri[i]<=2,
        "Parameter flaDblWri out of range for " + String(i) + "-th component.");
     if (flaDblWri[i] == 0) then
        _uStart[i] := uStart[i];               // Current value.
     elseif (flaDblWri[i] == 1) then
        _uStart[i] := uStart[i];                // Average over interval
     else
        _uStart[i] := uStart[i]*samplePeriod;  // Integral over the sampling interval
                                               // This is multiplied with samplePeriod because if
                                               // u is power, then uRWri needs to be energy.

     end if;
   end for;
   // Exchange initial values
    if activateInterface then
      (flaRea, simTimRea, yR, retVal) :=
        Buildings.Utilities.IO.BCVTB.BaseClasses.exchangeReals(
        socketFD=socketFD,
        flaWri=flaWri,
        simTimWri=time,
        dblValWri=_uStart,
        nDblWri=size(uRWri, 1),
        nDblRea=size(yR, 1));
    else
      flaRea := 0;
      simTimRea := time;
      yR := yRFixed;
      retVal := 0;
      end if;

equation
   for i in 1:nDblWri loop
      der(uRInt[i]) = if (flaDblWri[i] > 0) then uR[i] else 0;
   end for;
algorithm
  when {sampleTrigger} then
    assert(flaRea == 0, "BCVTB interface attempts to exchange data after Ptolemy reached its final time.\n" +
                        "   Aborting simulation. Check final time in Modelica and in Ptolemy.\n" +
                        "   Received: flaRea = " + String(flaRea));
     // Compute value that will be sent to the BCVTB interface
     for i in 1:nDblWri loop
       if (flaDblWri[i] == 0) then
         uRWri[i] :=pre(uR[i]);  // Send the current value.
                                 // Without the pre(), Dymola 7.2 crashes during translation of Examples.MoistAir
       else
         uRWri[i] :=uRInt[i] - uRIntPre[i]; // Integral over the sampling interval
         if (flaDblWri[i] == 1) then
            uRWri[i] := uRWri[i]/samplePeriod;   // Average value over the sampling interval
         end if;
       end if;
      end for;

    // Exchange data
    if activateInterface then
      (flaRea, simTimRea, yR, retVal) :=
        Buildings.Utilities.IO.BCVTB.BaseClasses.exchangeReals(
        socketFD=socketFD,
        flaWri=flaWri,
        simTimWri=time,
        dblValWri=uRWri,
        nDblWri=size(uRWri, 1),
        nDblRea=size(yR, 1));
    else
      flaRea := 0;
      simTimRea := time;
      yR := yRFixed;
      retVal := 0;
      end if;
    // Check for valid return flags
    assert(flaRea >= 0, "BCVTB sent a negative flag to Modelica during data transfer.\n" +
                        "   Aborting simulation. Check file 'utilSocket.log'.\n" +
                        "   Received: flaRea = " + String(flaRea));
    assert(retVal >= 0, "Obtained negative return value during data transfer with BCVTB.\n" +
                        "   Aborting simulation. Check file 'utilSocket.log'.\n" +
                        "   Received: retVal = " + String(retVal));

    // Store current value of integral
  uRIntPre:=uRInt;
  end when;
   // Close socket connnection
   when terminal() then
     if activateInterface then
        Buildings.Utilities.IO.BCVTB.BaseClasses.closeClientSocket(
                                                          socketFD);
     end if;
   end when;
end BCVTB;


Converts Celsius to Kelvin. Converts the input from Kelvin to degree Celsius.
Note that inside Modelica, by convention, all models use
Kelvin. This block is provided for convenience since the BCVTB
interface may couple Modelica to programs that use Celsius
as the unit for temperature.

within Buildings.Utilities.IO.BCVTB;
block From_degC "Converts Celsius to Kelvin"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Interfaces.RealInput Celsius(final quantity="ThermodynamicTemperature",
                                               final unit = "degC", displayUnit = "degC", min=-273.15)
    "Temperature in Celsius"
  Modelica.Blocks.Interfaces.RealOutput Kelvin(final quantity="ThermodynamicTemperature",
                                               final unit = "K", displayUnit = "degC", min=0)
    "Temperature in Kelvin"
equation
  Celsius =Modelica.Units.Conversions.to_degC(Kelvin);
end From_degC;


within Buildings.Utilities.IO.BCVTB;
model MoistAirInterface
  "Fluid interface that can be coupled to BCVTB for medium that model the air humidity"
  extends Buildings.Utilities.IO.BCVTB.BaseClasses.FluidInterface(bou(
        final use_X_in=true));

  Modelica.Blocks.Interfaces.RealOutput HLat_flow(unit="W")
    "Latent enthalpy flow rate, positive if flow into the component"
  Buildings.Fluid.Sensors.SensibleEnthalpyFlowRate senEntFloRat[nPorts](
    redeclare final package Medium = Medium,
    each final m_flow_nominal=m_flow_nominal) "Sensible enthalpy flow rates"
  Modelica.Blocks.Math.Sum sumHSen_flow(nin=nPorts)
    "Sum of sensible enthalpy flow rates"
  Modelica.Blocks.Math.Feedback diff
    "Difference between total and sensible enthalpy flow rate"
  Modelica.Blocks.Interfaces.RealInput phi "Medium relative humidity"
  Buildings.Utilities.Psychrometrics.X_pTphi masFra(use_p_in=false)
    "Mass fraction"
equation
  for i in 1:nPorts loop
  connect(senEntFloRat[i].port_a, ports[i])
  connect(senEntFloRat[i].H_flow, sumHSen_flow.u[i])
  end for;
  connect(senEntFloRat.port_b, totEntFloRat.port_a)
  connect(sumHSen_flow.y, HSen_flow)
  connect(sumHTot_flow.y, diff.u1)
  connect(diff.y, HLat_flow)
  connect(diff.u2, sumHSen_flow.y)
  connect(masFra.T, T_in)
  connect(masFra.phi, phi)
  connect(masFra.X, bou.X_in)
end MoistAirInterface;


within Buildings.Utilities.IO;
package BCVTB "Package with functions to communicate with the Building Controls Virtual Test Bed"
  extends Modelica.Icons.VariantsPackage;

package UsersGuide "User's Guide"
  extends Modelica.Icons.Information;
end UsersGuide;

end BCVTB;


Converts Kelvin to Celsius. Converts the input from degree Celsius to Kelvin.
Note that inside Modelica, it is strongly recommended to use
Kelvin. This block is provided for convenience since the BCVTB
interface may couple Modelica to programs that use Celsius
as the unit for temperature.

within Buildings.Utilities.IO.BCVTB;
block To_degC "Converts Kelvin to Celsius"
  extends Modelica.Blocks.Icons.Block;

  Modelica.Blocks.Interfaces.RealInput Kelvin(final quantity="ThermodynamicTemperature",
                                              final unit = "K", displayUnit = "degC", min=0)
    "Temperature in Kelvin"
  Modelica.Blocks.Interfaces.RealOutput Celsius(final quantity="ThermodynamicTemperature",
                                                final unit = "degC", displayUnit = "degC", min=-273.15)
    "Temperature in Celsius"
equation
  Kelvin =Modelica.Units.Conversions.from_degC(Celsius);
end To_degC;


within Buildings.Utilities.IO.BCVTB.BaseClasses;
partial model FluidInterface
  "Partial class for fluid interface that can be coupled to BCVTB"
  extends Buildings.BaseClasses.BaseIcon;

  replaceable package Medium =
      Modelica.Media.Interfaces.PartialMedium "Medium model within the source"

  parameter Integer nPorts=0 "Number of ports"
  Modelica.Blocks.Interfaces.RealInput m_flow_in if use_m_flow_in
    "Prescribed mass flow rate"
  Modelica.Blocks.Interfaces.RealInput T_in "Prescribed boundary temperature"

   parameter Boolean use_m_flow_in = false
    "Get the mass flow rate from the input connector"
  parameter Modelica.Units.SI.MassFlowRate m_flow=0
    "Fixed mass flow rate going out of the fluid port"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal(min=0)
    "Nominal mass flow rate, used for regularization near zero flow"
  parameter Modelica.Units.SI.MassFlowRate m_flow_small(min=0) = 1E-4*
    m_flow_nominal
    "For bi-directional flow, temperature is regularized in the region |m_flow| < m_flow_small (m_flow_small > 0 required)"

  Buildings.Fluid.Sensors.EnthalpyFlowRate totEntFloRat[nPorts](
    redeclare final package Medium = Medium,
    each final m_flow_nominal=m_flow_nominal)
    "Total enthalpy flow rate (sensible plus latent)"
  Modelica.Fluid.Interfaces.FluidPorts_b ports[
                                nPorts](
                     redeclare each package Medium = Medium,
                     each m_flow(max=if flowDirection==Modelica.Fluid.Types.PortFlowDirection.Leaving then 0 else
                                     +Modelica.Constants.inf,
                                 min=if flowDirection==Modelica.Fluid.Types.PortFlowDirection.Entering then 0 else
                                     -Modelica.Constants.inf))

  Modelica.Blocks.Math.Sum sumHTot_flow(nin=nPorts)
    "Sum of total enthalpy flow rates"
  Modelica.Blocks.Interfaces.RealOutput HSen_flow(unit="W")
    "Sensible enthalpy flow rate, positive if flow into the component"
  Buildings.Fluid.Sources.MassFlowSource_T bou(
    redeclare package Medium = Medium,
    final use_T_in=true,
    final nPorts=nPorts,
    use_X_in=false,
    use_C_in=false,
    final use_m_flow_in=true)
protected
  parameter Modelica.Fluid.Types.PortFlowDirection flowDirection=
                   Modelica.Fluid.Types.PortFlowDirection.Bidirectional
    "Allowed flow direction"

  Modelica.Blocks.Sources.Constant m_flow_par(final k=m_flow)
    "Mass flow rate if set as a parameter"
equation
  if use_m_flow_in then
    connect(m_flow_in, bou.m_flow_in)

  else
    connect(m_flow_par.y, bou.m_flow_in)
  end if;

  connect(totEntFloRat.port_b, bou.ports)
  connect(sumHTot_flow.u, totEntFloRat.H_flow)
  connect(bou.T_in, T_in)
end FluidInterface;


within Buildings.Utilities.IO.BCVTB;
package BaseClasses "Package with base classes for Buildings.Utilities.IO.BCVTB"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.Utilities.IO.BCVTB.Examples;
model MoistAir
  "Model with interfaces for media with moist air that will be linked to the BCVTB which models the response of the room"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=259.2*6/1.2/3600
    "Nominal mass flow rate";
  Buildings.Fluid.FixedResistances.PressureDrop dp1(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=200,
    from_dp=false,
    allowFlowReversal=false)
  Buildings.Fluid.Sources.Boundary_pT sou(
    nPorts=2,
    redeclare package Medium = Medium,
    use_T_in=true,
    use_X_in=true,
    p(displayUnit="Pa") = 101325,
    T=293.15)
  Buildings.Fluid.FixedResistances.PressureDrop dp2(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=200,
    from_dp=false,
    allowFlowReversal=false)
  Buildings.Utilities.IO.BCVTB.MoistAirInterface bouBCVTB(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow=0,
    use_m_flow_in=false,
    m_flow_nominal=m_flow_nominal)
  Buildings.Fluid.Humidifiers.Humidifier_u hum(
    m_flow_nominal=m_flow_nominal,
    dp_nominal=200,
    redeclare package Medium = Medium,
    mWat_flow_nominal=0.01*m_flow_nominal,
    from_dp=false,
    allowFlowReversal=false) "Humidifier"
  Buildings.Fluid.HeatExchangers.HeaterCooler_u hex(
    m_flow_nominal=m_flow_nominal,
    dp_nominal=200,
    redeclare package Medium = Medium,
    Q_flow_nominal=m_flow_nominal*50*1006,
    from_dp=false,
    allowFlowReversal=false) "Heat exchanger"
  Buildings.Fluid.Sensors.TemperatureTwoPort
                                      TRet(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal) "Return air temperature"
  Buildings.Fluid.Sensors.MassFractionTwoPort
                                       Xi_w(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal) "Measured air humidity"
  Modelica.Blocks.Sources.Constant XSet(k=0.005) "Set point for humidity"
  Modelica.Blocks.Sources.Constant TRooSetNig(k=273.15 + 16)
    "Set point for room air temperature"
  Buildings.Controls.Continuous.LimPID PIDHea(
    yMax=1,
    yMin=0,
    Td=1,
    k=0.1,
    Ti=600) "Controller for heating"
  Buildings.Controls.Continuous.LimPID PIDHum(
    yMax=1,
    yMin=0,
    k=20,
    Td=60,
    Ti=600) "Controller for humidifier"
  Buildings.Utilities.IO.BCVTB.BCVTB bcvtb(
    xmlFileName="socket.cfg",
    nDblRea=4,
    nDblWri=5,
    flaDblWri={1,1,1,1,1},
    uStart={0,0,0,0,20},
    activateInterface=true,
    timeStep=60)
  Modelica.Blocks.Routing.DeMultiplex4 deMultiplex2_1(
    n1=1,
    n2=1,
    n3=1,
    n4=1)
  Modelica.Blocks.Routing.Multiplex5 mul
  Buildings.Fluid.Sensors.TemperatureTwoPort
                                      TSup(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal) "Supply air temperature"
  Buildings.Fluid.Movers.SpeedControlled_y fan(
    redeclare package Medium = Medium,
    per(pressure(V_flow={0,m_flow_nominal/1.2}, dp={2*400,400})),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Sources.Constant yFan(k=1) "Fan control signal"
  Modelica.Blocks.Math.Gain perToRel(k=0.01) "Converts 0...100 to 0...1"
  Modelica.Blocks.Math.Gain perToRel1(
                                     k=0.01) "Converts 0...100 to 0...1"
  Buildings.Utilities.Psychrometrics.X_pTphi masFra(use_p_in=false)
    "Mass fraction"
  Buildings.Controls.SetPoints.OccupancySchedule occSch "Occupancy schedule"
  Modelica.Blocks.Logical.Switch switch1
  Modelica.Blocks.Sources.Constant TRooSetDay(k=273.15 + 20)
    "Set point for room air temperature"
  Buildings.Utilities.IO.BCVTB.From_degC from_degC
  Buildings.Utilities.IO.BCVTB.To_degC to_degC
  Buildings.Utilities.IO.BCVTB.From_degC from_degC1
equation
  connect(dp1.port_a, hum.port_b)
  connect(hex.port_b, hum.port_a)
  connect(TRet.T, PIDHea.u_m)
  connect(PIDHea.y, hex.u)
  connect(XSet.y, PIDHum.u_s)
  connect(PIDHum.y, hum.u)
  connect(bcvtb.yR, deMultiplex2_1.u)
  connect(mul.y, bcvtb.uR)
  connect(PIDHum.y, mul.u4[1])
  connect(PIDHea.y, mul.u3[1])
  connect(mul.u1[1], bouBCVTB.HSen_flow)
  connect(bouBCVTB.HLat_flow, mul.u2[1])
  connect(Xi_w.X, PIDHum.u_m)
  connect(fan.port_b, hex.port_a)
  connect(fan.port_a, sou.ports[1])
  connect(perToRel.y, bouBCVTB.phi)
  connect(deMultiplex2_1.y4[1], perToRel.u)
  connect(perToRel1.u, deMultiplex2_1.y3[1])
  connect(masFra.phi, perToRel1.y)
  connect(masFra.X, sou.X_in)
  connect(yFan.y, fan.y)
  connect(occSch.occupied, switch1.u2)
  connect(TRooSetNig.y, switch1.u3)
  connect(TRooSetDay.y, switch1.u1)
  connect(switch1.y, PIDHea.u_s)
  connect(from_degC.Kelvin, bouBCVTB.T_in)
  connect(TSup.T, to_degC.Kelvin)
  connect(to_degC.Celsius, mul.u5[1])
  connect(from_degC1.Kelvin, sou.T_in)
  connect(from_degC1.Celsius, deMultiplex2_1.y1[1])
  connect(deMultiplex2_1.y2[1], from_degC.Celsius)
  connect(from_degC1.Kelvin, masFra.T)
  connect(dp2.port_b, Xi_w.port_a)
  connect(Xi_w.port_b, TRet.port_a)
  connect(TRet.port_b, sou.ports[2])
  connect(dp1.port_b, TSup.port_a)
  connect(TSup.port_b, bouBCVTB.ports[1])
  connect(dp2.port_a, bouBCVTB.ports[2])
end MoistAir;


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


Thermal model of two rooms that will be linked to the BCVTB which models the controls.

within Buildings.Utilities.IO.BCVTB.Examples;
model TwoRooms
  "Thermal model of two rooms that will be linked to the BCVTB which models the controls"
  extends Modelica.Icons.Example;
  parameter Modelica.Units.SI.Time tau=2*3600 "Room time constant";
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nom=100 "Nominal heat flow";
  parameter Modelica.Units.SI.ThermalConductance UA=Q_flow_nom/20
    "Thermal conductance of room";
  parameter Modelica.Units.SI.Temperature TStart=283.15 "Start temperature";
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor C1(C=tau*UA, T(start=
          TStart, fixed=true)) "Heat capacity of room"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor UA1(G=UA)
    "Heat transmission of room"
  Buildings.HeatTransfer.Sources.FixedTemperature TOut1(T=278.15)
    "Outside air temperature"
  Buildings.HeatTransfer.Sources.PrescribedHeatFlow Q_flow_1
    "Heat input into the room"
  Modelica.Blocks.Math.Gain GaiQ_flow_nom1(k=Q_flow_nom)
    "Gain for nominal heat load"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor UA2(G=UA)
    "Heat transmission of room"
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor C2(C=2*tau*UA, T(start=
          TStart, fixed=true)) "Heat capacity of room"
  Buildings.HeatTransfer.Sources.FixedTemperature TOut2(T=278.15)
    "Outside air temperature"
  Buildings.HeatTransfer.Sources.PrescribedHeatFlow Q_flow_2
    "Heat input into the room"
  Modelica.Blocks.Math.Gain GaiQ_flow_nom2(k=Q_flow_nom)
    "Gain for nominal heat load"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TRoo1
    "Room temperature"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TRoo2
    "Room temperature"
  Buildings.Utilities.IO.BCVTB.BCVTB bcvtb(
    xmlFileName="socket.cfg",
    uStart={TStart - 273.15,TStart - 273.15},
    timeStep=60,
    final nDblWri=2,
    final nDblRea=2)
  Modelica.Blocks.Routing.Multiplex2 multiplex2_1
  Modelica.Blocks.Routing.DeMultiplex2 deMultiplex2_1
  Buildings.Utilities.IO.BCVTB.To_degC to_degC1
  Buildings.Utilities.IO.BCVTB.To_degC to_degC2
equation
  connect(TOut1.port, UA1.port_a)
  connect(UA1.port_b, C1.port)
  connect(TOut2.port, UA2.port_a)
  connect(UA2.port_b, C2.port)
  connect(Q_flow_1.port, C1.port)
  connect(Q_flow_2.port, C2.port)
  connect(C1.port, TRoo1.port)
  connect(C2.port, TRoo2.port)
  connect(GaiQ_flow_nom1.y, Q_flow_1.Q_flow)
  connect(GaiQ_flow_nom2.y, Q_flow_2.Q_flow)
  connect(bcvtb.yR, deMultiplex2_1.u)
  connect(deMultiplex2_1.y1[1], GaiQ_flow_nom1.u)
  connect(deMultiplex2_1.y2[1], GaiQ_flow_nom2.u)
  connect(multiplex2_1.y, bcvtb.uR)
  connect(TRoo1.T, to_degC1.Kelvin)
  connect(TRoo2.T, to_degC2.Kelvin)
  connect(to_degC2.Celsius, multiplex2_1.u2[1])
  connect(to_degC1.Celsius, multiplex2_1.u1[1])
end TwoRooms;


Model for writing results to a format that is readable by the model CombiTimeTable. This model samples the model inputs u and saves them to a .csv file,
which can be read by a

Modelica.Blocks.Sources.CombiTimeTable.
The
Modelica.Blocks.Sources.CombiTimeTable
must then have tableName=\"csv\", as illustrated in the example

Buildings.Utilities.IO.Files.Examples.CSVReader.

within Buildings.Utilities.IO.Files;
model CombiTimeTableWriter
  "Model for writing results to a format that is readable by the model CombiTimeTable"
  extends Buildings.Utilities.IO.Files.BaseClasses.FileWriter(
    final delimiter="\t",
    final isCombiTimeTable=true);

initial algorithm
  if writeHeader then
    str :="# time" + delimiter;
    for i in 1:nin-1 loop
      str :=str + headerNames[i] + delimiter;
      if mod(i+1,10)==0 then // write out buffer every 10 entries to avoid overflow
        writeLine(filWri, str, 1);
        str:="";
      end if;
    end for;
    str :=str + headerNames[nin] + "\n";
    writeLine(filWri, str, 1);
  end if;
end CombiTimeTableWriter;


Model for writing results to a .csv file. This model samples the model inputs u and saves them to a .csv file,
which can be read using e.g. Excel or Python.

within Buildings.Utilities.IO.Files;
model CSVWriter
  "Model for writing results to a .csv file"
  extends Buildings.Utilities.IO.Files.BaseClasses.FileWriter(
    final isCombiTimeTable=false);

initial algorithm
  if writeHeader then
    str := str + "time" + delimiter;
    for i in 1:nin-1 loop
      str := str + headerNames[i] + delimiter;
      if mod(i+1,10)==0 then // write out buffer every 10 entries to avoid overflow
        writeLine(filWri, str, 1);
        str:="";
      end if;
    end for;
    str := str + headerNames[nin] + "\n";
    writeLine(filWri, str, 1);
  end if;
end CSVWriter;


Model for writing results to a json file. This model samples the model inputs u and saves them to a json file.

within Buildings.Utilities.IO.Files;
model JSONWriter "Model for writing results to a json file"
  extends Modelica.Blocks.Icons.DiscreteBlock;
  parameter Integer nin
    "Number of inputs"
  parameter String fileName = getInstanceName() + ".json"
    "File name, including extension";
  parameter String[nin] varKeys = {"key" + String(i) for i in 1:nin}
    "Key names, indices by default";
  parameter Buildings.Utilities.IO.Files.BaseClasses.OutputTime outputTime=
    Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Terminal
    "Time when results are written to file"
  parameter Modelica.Units.SI.Time customTime=0
    "Custom time when results are stored, used if outputTime=Custom only"

  Modelica.Blocks.Interfaces.RealVectorInput[nin] u "Variables that are saved"
protected
  parameter String insNam = getInstanceName() "Instance name";
  Buildings.Utilities.IO.Files.BaseClasses.JSONWriterObject jsonWri=
      Buildings.Utilities.IO.Files.BaseClasses.JSONWriterObject(
        insNam,
        fileName,
        outputTime==Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Terminal,
        varKeys)
    "File writer object";
equation
  if outputTime==Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Terminal then
    Buildings.Utilities.IO.Files.BaseClasses.cacheVals(jsonWri, u);
  end if;

  if outputTime==Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Initial then
    when initial() then
      Buildings.Utilities.IO.Files.BaseClasses.writeJSON(jsonWri, u);
    end when;
  end if;

  if outputTime==Buildings.Utilities.IO.Files.BaseClasses.OutputTime.Custom then
    when time>=customTime then
      Buildings.Utilities.IO.Files.BaseClasses.writeJSON(jsonWri, u);
    end when;
  end if;
end JSONWriter;


Reports package

within Buildings.Utilities.IO;
package Files "Reports package"
  extends Modelica.Icons.Package;
end Files;


Model that prints values to a file. This model prints to a file or the terminal at a fixed sample interval.

within Buildings.Utilities.IO.Files;
model Printer "Model that prints values to a file"
  extends Modelica.Blocks.Interfaces.DiscreteBlock(
    firstTrigger(
      start=false,
      fixed=true));

  parameter String header="" "Header to be printed";
  parameter String fileName="" "File name (empty string is the terminal)";
  parameter Integer nin=1 "Number of inputs";
  parameter Integer configuration = 1
    "Index for treating final report (see documentation)";
  parameter Integer minimumLength =  1 "Minimum length of result string";
  parameter Integer significantDigits = 16 "Number of significant digits";
  Modelica.Blocks.Interfaces.RealInput x[nin] "Value to be printed"

initial algorithm
  if (fileName <> "") then
    Modelica.Utilities.Files.removeFile(fileName);
  end if;
  Modelica.Utilities.Streams.print(fileName=fileName, string=header);
equation
  if configuration < 3 then
  when {sampleTrigger, initial()} then
      Buildings.Utilities.IO.Files.BaseClasses.printRealArray(
                                      x=x, fileName=fileName,
                                      minimumLength=minimumLength,
                                      significantDigits=significantDigits);
  end when;
  end if;
  when terminal() then
    if configuration >= 2 then
       Buildings.Utilities.IO.Files.BaseClasses.printRealArray(
                                      x=x, fileName=fileName,
                                      minimumLength=minimumLength,
                                      significantDigits=significantDigits);
   end if;
  end when;
end Printer;


Weekly schedule. This model interprets a schedule file and performs a weekly, cyclic extrapolation on the source data.
An example for a schedule entry is

within Buildings.Utilities.IO.Files;
model WeeklySchedule "Weekly schedule"
  extends Modelica.Blocks.Icons.DiscreteBlock;
  parameter Integer[:] columns = {2}
    "Columns of the schedule to be produced at the output y. First column is time, hence value must be 2 or larger";
  parameter Boolean tableOnFile=false
    "= true, if table is defined on file; false if defined through parameter data"
  parameter String fileName = ""
    "Filename"
  parameter String data = "double tab1(3,2)
# For week-day, output 1 between 7:00 and 19:00, and 0 otherwise
mon,tue,wed,thu,fri:7:00:00  1
mon,tue,wed,thu,fri:19:00:00  0
# For week-end, output always 0. Note that this line is redundant in this example.
sat,sun:0:00:00 0"
    "String data with weekly schedule"
  parameter Modelica.Units.SI.Time t_offset=0
    "Timestamp that corresponds to midnight from Sunday to Monday";

  Modelica.Blocks.Interfaces.RealOutput[n_columns] y=
    {getCalendarValue(cal, iCol-1, time) for iCol in columns} "Schedule values"

protected
  Buildings.Utilities.IO.Files.BaseClasses.WeeklyScheduleObject cal=
      Buildings.Utilities.IO.Files.BaseClasses.WeeklyScheduleObject(tableOnFile, sourceName, t_offset, data)
    "Schedule object";

  final parameter Integer n_columns = size(columns,1) "Number of columns";
  parameter String sourceName = if tableOnFile then fileName else getInstanceName() +".data";

  pure function getCalendarValue
    "Returns the interpolated (zero order hold) value"
    extends Modelica.Icons.Function;
    input Buildings.Utilities.IO.Files.BaseClasses.WeeklyScheduleObject ID "Pointer to file writer object";
    input Integer iCol "Column index";
    input Real timeIn "Time for look-up";
    output Real y "Schedule value";
    external "C" y=getScheduleValue(ID, iCol, timeIn)
  end getCalendarValue;
end WeeklySchedule;


Partial model for writing results to a .csv file. Base class for a file writer.
See extending classes.

within Buildings.Utilities.IO.Files.BaseClasses;
model FileWriter "Partial model for writing results to a .csv file"
  extends Modelica.Blocks.Icons.DiscreteBlock;

  parameter Integer nin
    "Number of inputs"
  parameter String fileName = getInstanceName() + ".csv"
    "File name, including extension";
  parameter Modelica.Units.SI.Time samplePeriod
    "Sample period: equidistant interval for which the inputs are saved";
  parameter String delimiter = "\t"
    "Delimiter for csv file"
  parameter Boolean writeHeader = true
    "=true, to write header with variable names, otherwise no header will be written"
  parameter String[nin] headerNames = {"col"+String(i) for i in 1:nin}
    "Header names, indices by default"
  parameter Integer significantDigits(min=1,max=15) = 6
    "Number of significant digits that are used for converting inputs into string format"

  Modelica.Blocks.Interfaces.RealVectorInput[nin] u "Variables that are saved"

protected
  parameter Boolean isCombiTimeTable = false
    "=true, if CombiTimeTable header should be prepended upon destruction"
  parameter Modelica.Units.SI.Time t0(fixed=false) "First sample time instant";
  parameter String insNam = getInstanceName() "Instance name";
  Buildings.Utilities.IO.Files.BaseClasses.FileWriterObject filWri=
      Buildings.Utilities.IO.Files.BaseClasses.FileWriterObject(
        insNam,
        fileName,
        nin+1,
        isCombiTimeTable)
    "File writer object";

  discrete String str "Intermediate variable for constructing a single line";
  output Boolean sampleTrigger "True, if sample time instant";

  function writeLine
    "Prepend a string to an existing text file"
    extends Modelica.Icons.Function;
    input Buildings.Utilities.IO.Files.BaseClasses.FileWriterObject id "ID of the file writer";
    input String string "Written string";
    input Integer isMetaData "=1, if line should not be included for row count of combiTimeTable";
    external"C" writeLine(id, string, isMetaData)
  end writeLine;

initial equation
  t0 = time;

equation
  sampleTrigger = sample(t0, samplePeriod);

algorithm
  when sampleTrigger then
    str :=String(time,significantDigits=significantDigits) + delimiter;
    for i in 1:nin-1 loop
      str :=str + String(u[i],significantDigits=significantDigits) + delimiter;
      if mod(i+1,10)==0 then // write out buffer every 10 entries to avoid overflow
        writeLine(filWri, str, 1); // not adding this one to row count
        str:="";
      end if;
    end for;
    str :=str + String(u[nin],significantDigits=significantDigits) + "\n";
    writeLine(filWri, str, 0);
  end when;
end FileWriter;


within Buildings.Utilities.IO.Files;
package BaseClasses "Package with base classes for Buildings.Utilities.IO.Files"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Reader for csv files generated by CSVWriter. This model demonstrates how a CombiTimeTable can be used
to read a text file that contains a table. The text file is stored in
Buildings//Resources/Data/Utilities/IO/Files/Examples/CSVReader/Data.txt.
It has the format of a file that can be generated by

Buildings.Utilities.IO.Files.Examples.CSVWriter.

within Buildings.Utilities.IO.Files.Examples;
model CSVReader "Reader for csv files generated by CSVWriter"
  extends Buildings.Utilities.IO.Files.Examples.BaseClasses.PartialCSV;
  Modelica.Blocks.Sources.CombiTimeTable combiTimeTable(
    tableOnFile=true,
    fileName=Modelica.Utilities.Files.loadResource("modelica://Buildings//Resources/Data/Utilities/IO/Files/Examples/CSVReader/Data.txt"),
    columns={2,3},
    tableName="tab") "Reader for test.csv"
end CSVReader;


Example of csv writer use. This model demonstrates the use of the csv file writer.

within Buildings.Utilities.IO.Files.Examples;
model CSVWriter "Example of csv writer use"
  extends Buildings.Utilities.IO.Files.Examples.BaseClasses.PartialCSV;
  CombiTimeTableWriter combiTimeTableWriter(
    nin=2,
    samplePeriod=0.3,
    fileName="test.csv",
    significantDigits=10)
    "Model that writes two inputs to csv file in a format that can be read by a combiTimeTable"
  Buildings.Utilities.IO.Files.CSVWriter csvWriter(
    writeHeader=false,
    nin=2,
    samplePeriod=0.3)
    "Duplicate to test for conflicts when instantiating multiple file writers"

equation
  connect(cos.y, combiTimeTableWriter.u[1])
  connect(step.y, combiTimeTableWriter.u[2])
  connect(csvWriter.u[1], cos.y)
  connect(csvWriter.u[2], step.y)
end CSVWriter;