within Buildings.Fluid.SolarCollectors.BaseClasses.Examples;
model EN12975HeatLoss "Example showing the use of EN12975HeatLoss"
  extends Modelica.Icons.Example;
  parameter Buildings.Fluid.SolarCollectors.Data.GenericEN12975 per=
    Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_VerificationModel()
    "Performance data"
  Modelica.Blocks.Sources.Sine TEnv(
    f=0.01,
    offset=273.15 + 10,
    amplitude=15) "Temperature of the surrounding environment"
  Modelica.Blocks.Sources.Sine T1(
    amplitude=15,
    f=0.1,
    offset=273.15 + 10) "Temperature of the first segment"
  Modelica.Blocks.Sources.Sine T2(
    f=0.1,
    amplitude=15,
    offset=273.15 + 15) "Temperature of the second segment"
  Modelica.Blocks.Sources.Sine T3(
    f=0.1,
    amplitude=15,
    offset=273.15 + 20) "Temperature of the third segment"
  Buildings.Fluid.SolarCollectors.BaseClasses.EN12975HeatLoss heaLos(
    nSeg=3,
    redeclare package Medium = Buildings.Media.Water,
    a1=per.a1,
    a2=per.a2,
    A_c=per.A)       "Heat loss model using EN12975 calculations"
equation
  connect(TEnv.y, heaLos.TEnv)
  connect(T3.y, heaLos.TFlu[3])
  connect(T2.y, heaLos.TFlu[2])
  connect(T1.y, heaLos.TFlu[1])
end EN12975HeatLoss;


within Buildings.Fluid.SolarCollectors.BaseClasses.Examples;
model EN12975SolarGain "Example showing the use of EN12975SolarGain"
  extends Modelica.Icons.Example;
  parameter Buildings.Fluid.SolarCollectors.Data.GenericEN12975 per=
    Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_VerificationModel()
    "Performance data"
  Buildings.Fluid.SolarCollectors.BaseClasses.EN12975SolarGain solGai(
    eta0=per.eta0,
    incAngDat=per.incAngDat,
    incAngModDat=per.incAngModDat,
    nSeg=3,
    A_c=per.A,
    iamDiff=per.IAMDiff,
    shaCoe=0,
    use_shaCoe_in=true,
    redeclare package Medium = Buildings.Media.Water)
    "Solar heat gain model using EN12975 calculations"
  Modelica.Blocks.Sources.Ramp incAng(duration=86400,
    height=60*(2*Modelica.Constants.pi/360)) "Incidence angle"
  Modelica.Blocks.Sources.Sine HDirTil(
    offset=400,
    amplitude=300,
    f=2/86400) "Direct beam radiation, tilted surface"
  Modelica.Blocks.Sources.Sine HDifTil(
    amplitude=200,
    f=1/86400,
    offset=300) "Diffuse radiation, tilted surface"
  Modelica.Blocks.Sources.Ramp shaCoe(
    duration=86400,
    offset=1,
    height=-1) "Shading coefficient"
  Modelica.Blocks.Sources.Sine T3(
    f=2/86400,
    amplitude=50,
    offset=273.15 + 110)
  Modelica.Blocks.Sources.Sine T2(
    f=2/86400,
    amplitude=50,
    offset=273.15 + 100)
  Modelica.Blocks.Sources.Sine T1(
    f=2/86400,
    amplitude=50,
    offset=273.15 + 90)
equation
  connect(incAng.y, solGai.incAng)
  connect(shaCoe.y, solGai.shaCoe_in)
  connect(HDirTil.y, solGai.HDirTil)
  connect(HDifTil.y, solGai.HSkyDifTil)
  connect(T3.y, solGai.TFlu[3])
  connect(T2.y, solGai.TFlu[2])
  connect(T1.y, solGai.TFlu[1])
end EN12975SolarGain;


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


Controller which activates a circulation pump when solar radiation is above a critical level. Pump on/off controller for a solar thermal system.

within Buildings.Fluid.SolarCollectors.Controls;
model CollectorPump
  "Controller which activates a circulation pump when solar radiation is above a critical level"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.HeatFlowRate delQ_flow(min=1)=10
    "Required estimated heat gain per unit area of collector to switch system on";
  parameter Modelica.Units.SI.Angle azi(displayUnit="deg")
    "Surface azimuth (0 for south-facing; -90 degree for east-facing; +90 degree for west facing";
  parameter Modelica.Units.SI.Angle til(displayUnit="deg")
    "Surface tilt (0 for horizontally mounted collector)";
  parameter Real rho(
    final min=0,
    final max=1,
    final unit = "1") = 0.2 "Ground reflectance";

  parameter Buildings.Fluid.SolarCollectors.Data.GenericASHRAE93 per
    "Performance data"

  Modelica.Blocks.Interfaces.RealInput TIn(
    final unit = "K",
    final displayUnit = "degC",
    quantity = "ThermodynamicTemperature")
    "Fluid temperature entering the collector"

  Modelica.Blocks.Interfaces.BooleanOutput on
    "Ouputs true if collector pump should be on"

  Buildings.BoundaryConditions.WeatherData.Bus weaBus "Weather data input"

  Buildings.Fluid.SolarCollectors.Controls.BaseClasses.GCritCalc criSol(
    final slope=per.slope,
    final y_intercept=per.y_intercept)
    "Calculates the critical insolation based on collector design and current weather conditions"
  BoundaryConditions.SolarIrradiation.DiffusePerez HDifTilIso(
    final til=til,
    final azi=azi,
    final rho=rho) "Diffuse solar irradiation on a tilted surface"
  BoundaryConditions.SolarIrradiation.DirectTiltedSurface HDirTil(
    final til=til,
    final azi=azi)
      "Direct solar irradiation on a tilted surface"
  Modelica.Blocks.Math.Add HTotTil(
    u1(final unit="W/m2"),
    u2(final unit="W/m2"),
    y(final unit="W/m2"))
    "Total irradiation on tilted surface"

  Modelica.Blocks.Logical.Hysteresis hys(
    final uLow=0,
    final uHigh=delQ_flow)
protected
  Modelica.Blocks.Math.Add sub(
    final k2=-1)
    "Difference between incident solar and required incident to compensate thermal losses"
equation
  connect(TIn, criSol.TIn)
  connect(weaBus.TDryBul, criSol.TEnv)
  connect(HDirTil.weaBus, weaBus)
  connect(HDifTilIso.weaBus, weaBus)
  connect(HDifTilIso.H, HTotTil.u1)
  connect(HDirTil.H, HTotTil.u2)
  connect(HTotTil.y, sub.u1)
  connect(criSol.G_TC, sub.u2)
  connect(hys.u, sub.y)
  connect(on, hys.y)
end CollectorPump;


within Buildings.Fluid.SolarCollectors;
package Controls "Package for solar thermal collector controllers"
  extends Modelica.Icons.Package;
end Controls;


Model calculating the critical insolation level. This component calculates the solar radiation necessary for the fluid
in the collector to gain heat. It is used in the model

Buildings.Fluid.SolarCollectors.Controls.CollectorPump.

within Buildings.Fluid.SolarCollectors.Controls.BaseClasses;
model GCritCalc "Model calculating the critical insolation level"

  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.CoefficientOfHeatTransfer slope
    "Slope from ratings data";
  parameter Real y_intercept(final unit="1") "y_intercept from ratings data";

  Modelica.Blocks.Interfaces.RealInput TIn(
    final unit="K",
    displayUnit = "degC",
    quantity = "ThermodynamicTemperature")
    "Temperature of water entering the collector"
  Modelica.Blocks.Interfaces.RealOutput G_TC(
    final unit="W/m2",
    quantity = "RadiantEnergyFluenceRate") "Critical radiation level"
  Modelica.Blocks.Interfaces.RealInput TEnv(
    final unit="K",
    displayUnit = "degC",
    quantity = "ThermodynamicTemperature")
    "Ambient temperature at the collector"

equation
  G_TC = -slope * (TIn - TEnv) / y_intercept;
end GCritCalc;


within Buildings.Fluid.SolarCollectors.Controls;
package BaseClasses "Package of BaseClass models used to create the models in the Controls package"
extends Modelica.Icons.Package;
end BaseClasses;


Example showing the use of GCritCalc. This model provides an example of how to use the

Buildings.Fluid.SolarCollectors.Controls.BaseClasses.GCritCalc model.

within Buildings.Fluid.SolarCollectors.Controls.BaseClasses.Examples;
model GCritCalc "Example showing the use of GCritCalc"
  extends Modelica.Icons.Example;
  Buildings.Fluid.SolarCollectors.Controls.BaseClasses.GCritCalc criSol(slope=-3.764,
      y_intercept=0.602)
    "Calculates the critical insolation based on collector design and current weather conditions"
  Modelica.Blocks.Sources.Sine TEnv(
    amplitude=10,
    f=0.1,
    offset=10)
  Modelica.Blocks.Sources.Sine TIn(
    amplitude=10,
    f=0.01,
    offset=30)
equation
  connect(TEnv.y, criSol.TEnv)
  connect(TIn.y, criSol.TIn)
end GCritCalc;


within Buildings.Fluid.SolarCollectors.Controls.BaseClasses;
package Examples "Package containing examples demonstrating the use of Controls.BaseClasses models"

  extends Modelica.Icons.ExamplesPackage;
end Examples;


within Buildings.Fluid.SolarCollectors.Controls;
package Examples "Examples for solar thermal collector controller models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Example for the solar pump controller. This model illustrates the use of the

Buildings.Fluid.SolarCollectors.Controls.CollectorPump model.
Based on weather data and inlet temperature, the controller switches the pump on
and off.

within Buildings.Fluid.SolarCollectors.Controls.Examples;
model SolarPumpController "Example for the solar pump controller"
  extends Modelica.Icons.Example;
  Buildings.Fluid.SolarCollectors.Controls.CollectorPump pumCon(
    azi=0,
    til=0.78539816339745,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_ThermaLiteHS20())
    "Model controlling the on/off status of the pump"
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
     filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data input file"
  Modelica.Blocks.Sources.Sine sine(
    amplitude=20,
    f=0.0001,
    offset=273.15 + 40) "Water inlet temperature"
equation
  connect(weaDat.weaBus, pumCon.weaBus)
  connect(sine.y, pumCon.TIn)
end SolarPumpController;


Data for solar thermal collectors

within Buildings.Fluid.SolarCollectors;
package Data "Data for solar thermal collectors"
extends Modelica.Icons.MaterialPropertiesPackage;
end Data;


Generic data record providing common inputs for ASHRAE93 and EN12975 solar collector models. Partial record containing common performance parameters for ASHRAE93 and EN12975
solar collector models.

within Buildings.Fluid.SolarCollectors.Data.BaseClasses;
record Generic
  "Generic data record providing common inputs for ASHRAE93 and EN12975 solar collector models"
  extends Modelica.Icons.Record;

  parameter Modelica.Units.SI.Area A "Area";
  parameter Buildings.Fluid.SolarCollectors.Types.HeatCapacity CTyp
    "Total thermal capacity or fluid volume and 'dry' thermal capacity or mass";
  parameter Modelica.Units.SI.HeatCapacity C
    "Dry or total thermal capacity of the solar thermal collector";
  parameter Modelica.Units.SI.Volume V "Fluid volume ";
  parameter Modelica.Units.SI.Mass mDry "Dry mass";
  parameter Real mperA_flow_nominal(final unit="kg/(s.m2)")
    "Nominal mass flow rate per unit area of collector";
  parameter Modelica.Units.SI.PressureDifference dp_nominal(displayUnit="Pa")
    "Nominal pressure drop";
  parameter Modelica.Units.SI.Angle[:] incAngDat=Modelica.Units.Conversions.from_deg({0,10,20,30,40,50,60,70,80,90})
    "Incident angle data";
  parameter Real[size(incAngDat,1)] incAngModDat(
    each final min=0,
    each final unit="1")
    "Incident angle modifier data";

  final parameter Boolean validated = validateAngles(
    incAngDat=incAngDat,
    incAngModDat=incAngModDat)
    "True if data are valid, otherwise an assertion is issued";
end Generic;


within Buildings.Fluid.SolarCollectors.Data;
package BaseClasses "Package with base classes for data records of solar thermal collectors"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


FP - All inputs necessary for verification of EN12975 models.

within Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate;
record FP_VerificationModel =
  Buildings.Fluid.SolarCollectors.Data.GenericEN12975 (
    final A=4.302,
    final CTyp=Buildings.Fluid.SolarCollectors.Types.HeatCapacity.DryMass,
    final C=0,
    final V=4.4/1000,
    final dp_nominal = 100,
    final mperA_flow_nominal=0.0241,
    final eta0=0.720,
    final IAMDiff=0.133,
    final a1=2.8312,
    final a2=0.00119,
    final incAngDat=Modelica.Units.Conversions.from_deg({0,10,20,30,40,50,60,70,80,90}),
    final incAngModDat={1.0,0.9967,0.9862,0.9671,0.9360,0.8868,0.8065,0.6686,0.4906,0.0},
    final mDry=484)
  "FP - All inputs necessary for verification of EN12975 models"


within Buildings.Fluid.SolarCollectors.Data;
package GlazedFlatPlate "Package with SRCC rating information for glazed flat-plate solar thermal collectors"
extends Modelica.Icons.MaterialPropertiesPackage;
end GlazedFlatPlate;


within Buildings.Fluid.SolarCollectors.Data;
package Tubular "Package with SRCC rating information for tubular solar thermal collectors"
extends Modelica.Icons.MaterialPropertiesPackage;
end Tubular;


Test model for FlatPlate

within Buildings.Fluid.SolarCollectors.Examples;
model FlatPlate "Test model for FlatPlate"
  extends Modelica.Icons.Example;
  replaceable package Medium = Modelica.Media.Incompressible.Examples.Glycol47
    "Medium in the system";

  Buildings.Fluid.SolarCollectors.ASHRAE93 solCol(
    redeclare package Medium = Medium,
    shaCoe=0,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Array,
    nPanelsSer=5,
    nPanelsPar=5,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_GuangdongFSPTY95(),
    nPanels=25,
    nSeg=9,
    azi=0.3,
    til=0.5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    massDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Flat plate solar collector model"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data input file"
  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    p(displayUnit="bar") = 100000,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sensors.TemperatureTwoPort TOut(
    redeclare package Medium = Medium,
    T_start(displayUnit="K"),
    m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort TIn(redeclare package Medium =
    Medium, m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    T=273.15 + 10,
    nPorts=1,
    use_p_in=true) "Inlet for water flow"
  Modelica.Blocks.Sources.Sine sine(
    f=3/86400,
    amplitude=-solCol.dp_nominal,
    offset=1E5) "Pressure source"
equation
  connect(solCol.port_b, TOut.port_a)
  connect(sou.ports[1], TIn.port_a)
  connect(weaDat.weaBus, solCol.weaBus)
  connect(TIn.port_b, solCol.port_a)
  connect(TOut.port_b, sin.ports[1])
  connect(sine.y, sou.p_in)
end FlatPlate;


within Buildings.Fluid.SolarCollectors.Examples;
model FlatPlateShaCoeTrue "Test model for FlatPlate with use_shaCoe_in = true"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";
  Buildings.Fluid.SolarCollectors.ASHRAE93          solCol(
    redeclare package Medium = Medium,
    shaCoe=0,
    from_dp=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    use_shaCoe_in=true,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_GuangdongFSPTY95(),
    rho=0.2,
    azi=0,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=5,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series,
    nSeg=9,
    til=0.5235987755983) "Flat plate solar collector with 3 segments"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data input file"
  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sensors.TemperatureTwoPort TOut(
    redeclare package Medium = Medium,
    T_start(displayUnit="K"),
    m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort TIn(redeclare package Medium =
    Medium, m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    use_p_in=false,
    nPorts=1,
    T=273.15 + 10,
    p(displayUnit="Pa") = 101325 + 5*solCol.per.dp_nominal)
    "Inlet for water flow"
  Modelica.Blocks.Sources.Ramp shaCoe(
    startTime=34040,
    height=1,
    duration=24193) "Varying shading coefficient"
equation
  connect(solCol.port_b, TOut.port_a)
  connect(TOut.port_b, sin.ports[1])
  connect(TIn.port_b, solCol.port_a)
  connect(sou.ports[1], TIn.port_a)
  connect(shaCoe.y, solCol.shaCoe_in)
  connect(weaDat.weaBus, solCol.weaBus)
end FlatPlateShaCoeTrue;


within Buildings.Fluid.SolarCollectors.Examples;
model FlatPlateTotalArea "Example showing the use of TotalArea and nSeg"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";

  Buildings.Fluid.SolarCollectors.ASHRAE93          solCol(
    redeclare package Medium = Medium,
    shaCoe=0,
    from_dp=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_SolahartKf(),
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=10,
    nSeg=9,
    azi=0.3,
    til=0.5) "Flat plate solar collector model"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data input file"
  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=2) "Outlet for water flow"
  Buildings.Fluid.Sensors.TemperatureTwoPort TOut(
    redeclare package Medium = Medium,
    T_start(displayUnit="K"),
    m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort TIn(redeclare package Medium =
    Medium, m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    T=273.15 + 10,
    use_p_in=false,
    nPorts=2,
    p(displayUnit="Pa") = 101325 + solCol.dp_nominal) "Inlet for water flow"

  Buildings.Fluid.SolarCollectors.ASHRAE93 solCol1(
    redeclare package Medium = Medium,
    shaCoe=0,
    from_dp=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_SolahartKf(),
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=10,
    nSeg=27,
    azi=0.3,
    til=0.5) "Flat plate solar collector model"
  Buildings.Fluid.Sensors.TemperatureTwoPort TOut1(
    redeclare package Medium = Medium,
    T_start(displayUnit="K"),
    m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort TIn1(
    redeclare package Medium =
    Medium, m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
equation
  connect(solCol.port_b, TOut.port_a)
  connect(TOut.port_b, sin.ports[1])
  connect(TIn.port_b, solCol.port_a)
  connect(sou.ports[1], TIn.port_a)
  connect(weaDat.weaBus, solCol.weaBus)
  connect(solCol1.port_b, TOut1.port_a)
  connect(TIn1.port_b, solCol1.port_a)
  connect(weaDat.weaBus, solCol1.weaBus)
  connect(sou.ports[2], TIn1.port_a)
  connect(TOut1.port_b, sin.ports[2])
end FlatPlateTotalArea;


within Buildings.Fluid.SolarCollectors.Examples;
model FlatPlateWithTank
  "Example showing use of the flat plate solar collector in a complete solar thermal system"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water
    "Fluid in the storage tank";
  replaceable package Medium_2 = Buildings.Media.Water "Fluid flowing through the collector";

  parameter Modelica.Units.SI.Angle azi=0.3
    "Surface azimuth (0 for south-facing; -90 degree for east-facing; +90 degree for west facing";
  parameter Modelica.Units.SI.Angle til=0.78539816339745
    "Surface tilt (0 for horizontally mounted collector)";
  parameter Real rho=0.2 "Ground reflectance";

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

  Buildings.Fluid.SolarCollectors.ASHRAE93 solCol(
    redeclare package Medium = Medium_2,
    shaCoe=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=5,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_SolahartKf(),
    nSeg=9,
    final azi=azi,
    final til=til,
    final rho=rho) "Flat plate solar collector model"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
    computeWetBulbTemperature=false) "Weather data file reader"
  Buildings.Fluid.Sensors.TemperatureTwoPort TOut(
    T_start(displayUnit="K"),
    m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium_2) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort TIn(m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium_2) "Temperature sensor"
  Buildings.Fluid.Storage.StratifiedEnhancedInternalHex
   tan(
    nSeg=4,
    redeclare package Medium = Medium,
    hTan=1.8,
    m_flow_nominal=m_flow_nominal,
    VTan=1.5,
    dIns=0.07,
    redeclare package MediumHex = Medium_2,
    CHex=200,
    dExtHex=0.01905,
    hHex_a=0.9,
    hHex_b=0.65,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=3000,
    mHex_flow_nominal=3000/20/4200,
    T_start=293.15,
    TTan_nominal=293.15,
    THex_nominal=323.15,
    energyDynamicsHex=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Storage tank model"
  Buildings.Fluid.SolarCollectors.Controls.CollectorPump pumCon(
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_ThermaLiteHS20(),
    final azi=azi,
    final til=til,
    final rho=rho)
    "Pump controller"
  Buildings.HeatTransfer.Sources.FixedTemperature rooT(T=293.15)
    "Room temperature"
  Buildings.Fluid.Sources.Boundary_pT bou(redeclare package Medium =
    Medium, nPorts=1) "Outlet for hot water draw"
  Buildings.Fluid.Sources.MassFlowSource_T bou1(
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    nPorts=1,
    m_flow=0.001,
    T=288.15) "Inlet and flow rate for hot water draw"
  Buildings.Fluid.Movers.FlowControlled_m_flow pum(
    redeclare package Medium = Medium_2,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    nominalValuesDefineDefaultPressureCurve=true)
    "Pump forcing circulation through the system"
  Buildings.Fluid.Storage.ExpansionVessel exp(
    redeclare package Medium = Medium_2,
    V_start=0.1) "Expansion tank"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TTan
    "Temperature in the tank water that surrounds the heat exchanger"

  Modelica.Blocks.Math.BooleanToReal booToRea(
    realTrue=m_flow_nominal)
    "Conversion of control signal to real-valued signal"
equation
  connect(solCol.port_b,TOut. port_a)
  connect(TIn.port_b,solCol. port_a)
  connect(weaDat.weaBus,solCol. weaBus)
  connect(weaDat.weaBus, pumCon.weaBus)
  connect(rooT.port, tan.heaPorTop)
  connect(rooT.port, tan.heaPorSid)
  connect(pum.port_b, TIn.port_a)
  connect(pum.port_a, exp.port_a)
  connect(exp.port_a, tan.portHex_b)
  connect(TOut.port_b, tan.portHex_a)
  connect(bou.ports[1], tan.port_a)
  connect(bou1.ports[1], tan.port_b)
  connect(tan.heaPorVol[3], TTan.port)
  connect(TTan.T, pumCon.TIn)
  connect(pumCon.on, booToRea.u)
  connect(pum.m_flow_in, booToRea.y)
end FlatPlateWithTank;


within Buildings.Fluid.SolarCollectors;
package Examples "Examples demonstrating the use of models in the SolarCollectors package"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Example showing the use of Tubular

within Buildings.Fluid.SolarCollectors.Examples;
model Tubular "Example showing the use of Tubular"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";
  Buildings.Fluid.SolarCollectors.ASHRAE93 solCol(
    redeclare package Medium = Medium,
    shaCoe=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    use_shaCoe_in=false,
    per=Buildings.Fluid.SolarCollectors.Data.Tubular.T_AMKCollectraAGOWR20(),
    nPanels=10,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Parallel,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    rho=0.2,
    nSeg=9,
    azi=0.3,
    til=0.5) "Tubular solar collector model"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data input file"
  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Inlet for fluid flow"
  Buildings.Fluid.Sensors.TemperatureTwoPort TOut(
    redeclare package Medium = Medium,
    T_start(displayUnit="K"),
    m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort TIn(redeclare package Medium =
    Medium, m_flow_nominal=solCol.m_flow_nominal) "Temperature sensor"
  Modelica.Blocks.Sources.Sine sine(
    f=3/86400,
    offset=101325,
    amplitude=-0.1*solCol.dp_nominal)
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    T=273.15 + 10,
    nPorts=1,
    use_p_in=true,
    p(displayUnit="Pa")) "Inlet for water flow"
equation
  connect(solCol.port_b,TOut. port_a)
  connect(TOut.port_b,sin. ports[1])
  connect(TIn.port_b,solCol. port_a)
  connect(weaDat.weaBus, solCol.weaBus)
  connect(sine.y, sou.p_in)
  connect(sou.ports[1], TIn.port_a)
end Tubular;


within Buildings.Fluid.SolarCollectors;
package Types "Package with type definitions used in solar collector data records"
  extends Modelica.Icons.TypesPackage;
end Types;


within Buildings.Fluid.SolarCollectors.Validation;
model EN12975NPanels
  "Validation model for collector according to EN12975 with different settings for nPanel"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";

  parameter Integer nPanels=10 "Number of panels";

  Buildings.Fluid.SolarCollectors.EN12975 solCol(
    redeclare package Medium = Medium,
    per=datSolCol,
    shaCoe=0,
    azi=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=1,
    nSeg=30,
    til=0.78539816339745)
    "Flat plate solar collector model, has been modified for validation purposes"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
      computeWetBulbTemperature=false)
    "Weather data file reader"
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou(
    nPorts=1,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=false,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"

  Buildings.Fluid.SolarCollectors.EN12975 solCol1(
    redeclare package Medium = Medium,
    per=datSolCol,
    shaCoe=0,
    azi=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nSeg=30,
    til=0.78539816339745,
    nPanels=nPanels)
    "Flat plate solar collector model, has been modified for validation purposes"
  Buildings.Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou1(
    nPorts=1,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=false,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"
  Modelica.Blocks.Math.Gain gaiNPan(k=nPanels) "Gain for number of panels"
  Modelica.Blocks.Sources.RealExpression difHeaGai(y=solCol.QGai[30].Q_flow -
        solCol1.QGai[30].Q_flow/nPanels)
    "Difference in heat gain at last panel between model with 1 and with 30 panels"
  Modelica.Blocks.Sources.RealExpression difHeaLos(y=solCol.QLos[30].Q_flow -
        solCol1.QLos[30].Q_flow/nPanels)
    "Difference in heat loss at last panel between model with 1 and with 30 panels"
  Modelica.Blocks.Sources.Constant m_flow_nominal(k=datSolCol.A*datSolCol.mperA_flow_nominal)
    "Nominal flow rate for one panel"
  parameter Data.GlazedFlatPlate.FP_VerificationModel datSolCol
equation
  connect(weaDat.weaBus, solCol1.weaBus)
  connect(bou1.ports[1], solCol1.port_a)
  connect(sou1.ports[1], solCol1.port_b)
  connect(gaiNPan.y, bou1.m_flow_in)
  connect(solCol.port_a, bou.ports[1])
  connect(solCol.port_b, sou.ports[1])
  connect(solCol.weaBus, weaDat.weaBus)
  connect(m_flow_nominal.y, bou.m_flow_in)
  connect(gaiNPan.u, m_flow_nominal.y)
end EN12975NPanels;


within Buildings.Fluid.SolarCollectors.Validation;
model EN12975_Array
  "Validation model for collector according to EN12975 in array configuration"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=solCol.per.A*
      solCol.per.mperA_flow_nominal "Nominal mass flow rate";

  model Collector
    extends Buildings.Fluid.SolarCollectors.EN12975(
    redeclare final package Medium = Buildings.Media.Water,
    final show_T = true,
    final per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_VerificationModel(),
    final shaCoe=0,
    final azi=0,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final rho=0.2,
    final nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=1,
    final til=0.78539816339745,
    final use_shaCoe_in=false,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series);

  end Collector;

  Collector solCol(
    nPanels=4,
    nSeg=3,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Array,
    nPanelsSer=2,
    nPanelsPar=2)
    "Flat plate solar collector model, has been modified for validation purposes"

  Collector solCol1(nSeg=3, nPanels=2)
    "Flat plate solar collector model, has been modified for validation purposes"

  Collector solCol2(nSeg=3, nPanels=2)
    "Flat plate solar collector model, has been modified for validation purposes"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
      computeWetBulbTemperature=false)
    "Weather data file reader"
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou(
    nPorts=1,
    redeclare package Medium = Medium,
    use_T_in=false,
    m_flow=m_flow_nominal,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"

  Buildings.Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou1(
    nPorts=1,
    redeclare package Medium = Medium,
    use_T_in=false,
    m_flow=m_flow_nominal/2,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"

  Sensors.TemperatureTwoPort senTem(
     redeclare package Medium = Medium,
     tau=0,
     m_flow_nominal=m_flow_nominal)
    "Temperature sensor"
  Sensors.TemperatureTwoPort senTem1(
    redeclare package Medium = Medium,
    tau=0,
    m_flow_nominal=m_flow_nominal)
    "Temperature sensor"
  Modelica.Blocks.Math.Add dT(final k2=-1) "Temperature difference (must be zero)"
  Sources.MassFlowSource_T                 bou2(
    nPorts=1,
    redeclare package Medium = Medium,
    use_T_in=false,
    m_flow=m_flow_nominal/2,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"
equation
  connect(weaDat.weaBus, solCol1.weaBus)
  connect(bou1.ports[1], solCol1.port_a)
  connect(solCol.port_a, bou.ports[1])
  connect(solCol.weaBus, weaDat.weaBus)
  connect(weaDat.weaBus, solCol2.weaBus)
  connect(solCol.port_b, senTem.port_a)
  connect(senTem.port_b, sou.ports[1])
  connect(sou1.ports[1], senTem1.port_b)
  connect(dT.u1, senTem.T)
  connect(senTem1.T, dT.u2)
  connect(bou2.ports[1], solCol2.port_a)
  connect(solCol1.port_b, senTem1.port_a)
  connect(solCol2.port_b, senTem1.port_a)
end EN12975_Array;


within Buildings.Fluid.SolarCollectors.Validation;
model EN12975_Series
  "Validation model for collector according to EN12975 with different panels in series"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=solCol.per.A*
      solCol.per.mperA_flow_nominal "Nominal mass flow rate";

  model Collector
    extends Buildings.Fluid.SolarCollectors.EN12975(
    redeclare final package Medium = Buildings.Media.Water,
    final show_T = true,
    final per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_VerificationModel(),
    final shaCoe=0,
    final azi=0,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final rho=0.2,
    final nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=1,
    final til=0.78539816339745,
    final use_shaCoe_in=false,
    final sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series);

  end Collector;

  Collector solCol(nPanels=2, nSeg=6)
    "Flat plate solar collector model, has been modified for validation purposes"

  Collector solCol1(nSeg=3, nPanels=1)
    "Flat plate solar collector model, has been modified for validation purposes"

  Collector solCol2(nSeg=3, nPanels=1)
    "Flat plate solar collector model, has been modified for validation purposes"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
      computeWetBulbTemperature=false)
    "Weather data file reader"
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou(
    nPorts=1,
    redeclare package Medium = Medium,
    use_T_in=false,
    m_flow=m_flow_nominal,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"

  Buildings.Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou1(
    nPorts=1,
    redeclare package Medium = Medium,
    use_T_in=false,
    m_flow=m_flow_nominal,
    T=303.15) "Inlet for water flow, at a prescribed flow rate and temperature"

  Sensors.TemperatureTwoPort senTem(
     redeclare package Medium = Medium,
     tau=0,
     m_flow_nominal=m_flow_nominal)
    "Temperature sensor"
  Sensors.TemperatureTwoPort senTem1(
    redeclare package Medium = Medium,
    tau=0,
    m_flow_nominal=m_flow_nominal)
    "Temperature sensor"
  Modelica.Blocks.Math.Add dT(final k2=-1) "Temperature difference (must be zero)"
equation
  connect(weaDat.weaBus, solCol1.weaBus)
  connect(bou1.ports[1], solCol1.port_a)
  connect(solCol.port_a, bou.ports[1])
  connect(solCol.weaBus, weaDat.weaBus)
  connect(solCol2.port_a, solCol1.port_b)
  connect(weaDat.weaBus, solCol2.weaBus)
  connect(solCol.port_b, senTem.port_a)
  connect(senTem.port_b, sou.ports[1])
  connect(sou1.ports[1], senTem1.port_b)
  connect(senTem1.port_a, solCol2.port_b)
  connect(dT.u1, senTem.T)
  connect(senTem1.T, dT.u2)
end EN12975_Series;


within Buildings.Fluid.SolarCollectors.Validation;
model ExtremeAmbientConditions
  "Validation model for to ensure that collectors do not freeze or boil"
  extends Modelica.Icons.Example;

  replaceable package Medium = Buildings.Media.Water(T_min=273.15, T_max=273.15+100)
    "Medium in the system";

  ASHRAE93 solAsh(
    redeclare package Medium = Medium,
    shaCoe=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_GuangdongFSPTY95(),
    nPanels=1,
    azi=0.3,
    til=0.5,
    T_start=313.15) "Flat plate solar collector model using the ASHRAE model"
  EN12975 solEn(
    redeclare package Medium = Medium,
    shaCoe=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    sysConfig=Buildings.Fluid.SolarCollectors.Types.SystemConfiguration.Series,
    nPanels=1,
    azi=0.3,
    til=0.5,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_VerificationModel(),
    T_start=313.15) "Flat plate solar collector model using the EN 12975 model"

  Sources.MassFlowSource_T sou(
    redeclare package Medium = Medium,
    nPorts=1,
    m_flow=0) "Inlet boundary conditions"
  Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    p(displayUnit="Pa"),
    use_p_in=false,
    nPorts=2) "Inlet boundary conditions"
  Modelica.Blocks.Sources.Ramp TAmb(
    offset=273.15 + 40,
    height=-100,
    duration=10*3600) "Ambient temperature"
  Modelica.Blocks.Sources.Ramp HSol(
    duration=12*3600,
    height=1000,
    startTime=10*3600) "Solar irradiation"

  Sources.MassFlowSource_T sou2(
    redeclare package Medium = Medium,
    nPorts=1,
    m_flow=0) "Inlet boundary conditions"
  BoundaryConditions.WeatherData.Bus weaBus
  Modelica.Blocks.Sources.Constant const(k=0) "Constant that outputs zero"
  Modelica.Blocks.Sources.Constant solTim(k=12*3600) "Solar time"
  Modelica.Blocks.Sources.Constant lat(k=0.656593) "Location latitude"
  Modelica.Blocks.Sources.Constant alt(k=2) "Location altitude"
  Modelica.Blocks.Sources.Constant const1(k=0)
                                              "Constant that outputs zero"
equation
  connect(sou.ports[1], solAsh.port_a)
  connect(sou2.ports[1], solEn.port_a)
  connect(solAsh.port_b, sou1.ports[1])
  connect(solEn.port_b, sou1.ports[2])
  connect(weaBus, solAsh.weaBus)
  connect(TAmb.y, weaBus.TDryBul)
  connect(HSol.y, weaBus.HDifHor)
  connect(HSol.y, weaBus.HGloHor)
  connect(const.y, weaBus.solZen)
  connect(solTim.y, weaBus.solTim)
  connect(HSol.y, weaBus.HDirNor)
  connect(solEn.weaBus, weaBus)
  connect(lat.y, weaBus.lat)
  connect(alt.y, weaBus.alt)
  connect(const1.y, weaBus.cloTim)
end ExtremeAmbientConditions;


Validation model for FlatPlate

within Buildings.Fluid.SolarCollectors.Validation;
model FlatPlate "Validation model for FlatPlate"
  extends Modelica.Icons.Example;
  replaceable package Medium = Buildings.Media.Water "Medium in the system";
  Buildings.Fluid.SolarCollectors.ASHRAE93
   solCol(
    redeclare package Medium = Medium,
    shaCoe=0,
    azi=0,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_TRNSYSValidation(),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nPanels=1,
    nSeg=30,
    til=0.78539816339745)
    "Flat plate solar collector model, has been modified for validation purposes"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
      computeWetBulbTemperature=false)
    "Weather data file reader"
  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou(
    nPorts=1,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true)
    "Inlet for water flow, at a prescribed flow rate and temperature"
  Modelica.Blocks.Math.Add add
    "Converts TRNSYS data from degree Celsius to Kelving"
  Modelica.Blocks.Sources.CombiTimeTable datRea(
    tableOnFile=true,
    tableName="TRNSYS",
    columns=2:5,
    fileName=Modelica.Utilities.Files.loadResource(
       "modelica://Buildings/Resources/Data/Fluid/SolarCollectors/Validation/FlatPlate/TRNSYSAnnualData.txt"),
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments)
    "Data reader with inlet conditions from TRNSYS"

  Modelica.Blocks.Sources.Constant const(k=273.15)
    "Used to convert TRNSYS data from degree Celsius to Kelving"

equation
  connect(weaDat.weaBus, solCol.weaBus)
  connect(bou.ports[1], solCol.port_a)
  connect(const.y, add.u2)
  connect(add.y, bou.T_in)
  connect(datRea.y[1], add.u1)
  connect(datRea.y[4], bou.m_flow_in)
  connect(sou.ports[1], solCol.port_b)
end FlatPlate;


within Buildings.Fluid.SolarCollectors.Validation;
model FlatPlateNPanels
  "Validation model for flat plate collector with different settings for nPanel"
  extends Buildings.Fluid.SolarCollectors.Validation.FlatPlate;
  parameter Integer nPanels = 10 "Number of panels";
  Buildings.Fluid.SolarCollectors.ASHRAE93
   solCol1(
    redeclare package Medium = Medium,
    shaCoe=0,
    azi=0,
    per=Buildings.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_TRNSYSValidation(),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=Buildings.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nSeg=30,
    til=0.78539816339745,
    nPanels=nPanels)
    "Flat plate solar collector model, has been modified for validation purposes"
  Buildings.Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  Buildings.Fluid.Sources.MassFlowSource_T bou1(
    nPorts=1,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true)
    "Inlet for water flow, at a prescribed flow rate and temperature"
  Modelica.Blocks.Math.Gain gaiNPan(k=nPanels) "Gain for number of panels"
  Modelica.Blocks.Sources.RealExpression difHeaGai(y=solCol.QGai[30].Q_flow -
        solCol1.QGai[30].Q_flow/nPanels)
    "Difference in heat gain at last panel between model with 1 and with 30 panels"
  Modelica.Blocks.Sources.RealExpression difHeaLos(y=solCol.QLos[30].Q_flow -
        solCol1.QLos[30].Q_flow/nPanels)
    "Difference in heat loss at last panel between model with 1 and with 30 panels"
equation
  connect(weaDat.weaBus, solCol1.weaBus)
  connect(bou1.ports[1], solCol1.port_a)
  connect(add.y, bou1.T_in)
  connect(sou1.ports[1], solCol1.port_b)
  connect(gaiNPan.y, bou1.m_flow_in)
  connect(gaiNPan.u, datRea.y[4])
end FlatPlateNPanels;


Collection of validation models

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


Boundary with prescribed pressure, specific enthalpy, composition and trace substances. Defines prescribed values for boundary conditions:

within Buildings.Fluid.Sources;
model Boundary_ph
  "Boundary with prescribed pressure, specific enthalpy, composition and trace substances"
  extends Buildings.Fluid.Sources.BaseClasses.PartialSource_Xi_C;

  parameter Boolean use_p_in = false
    "Get the pressure from the input connector"
  parameter Medium.AbsolutePressure p = Medium.p_default
    "Fixed value of pressure"

  parameter Boolean use_h_in= false
    "Get the specific enthalpy from the input connector"
  parameter Medium.SpecificEnthalpy h = Medium.h_default
    "Fixed value of specific enthalpy"

  Modelica.Blocks.Interfaces.RealInput p_in(final unit="Pa") if use_p_in
    "Prescribed boundary pressure"

  Modelica.Blocks.Interfaces.RealInput h_in(final unit="J/kg") if use_h_in
    "Prescribed boundary specific enthalpy"
  // Boolean constants to avoid a potential string comparison in an equation section
protected
  constant Boolean checkWaterPressure = Medium.mediumName == "SimpleLiquidWater"
    "Evaluates to true if the pressure should be checked";
  constant Boolean checkAirPressure = Medium.mediumName == "Air"
    "Evaluates to true if the pressure should be checked";

  Modelica.Blocks.Interfaces.RealInput h_in_internal(final unit="J/kg")
    "Needed to connect to conditional connector";
initial equation
  if not use_p_in then
    if checkWaterPressure then
      assert(p_in_internal>1e4, "In "+getInstanceName() +
        ": The parameter value p="+String(p_in_internal)+" is low for water. This is likely an error.");
    end if;
    if checkAirPressure then
      assert(p_in_internal>5e4 and p_in_internal < 1.5e5, "In "+getInstanceName() +
        ": The parameter value p="+String(p_in_internal)+" is not within a realistic range for air. This is likely an error.");
    end if;
  end if;
equation
  if use_p_in then
    if checkWaterPressure then
      assert(p_in_internal>1e4, "In "+getInstanceName() +
        ": The value of p_in="+String(p_in_internal)+" is low for water. This is likely an error.");
    end if;
    if checkAirPressure then
      assert(p_in_internal>5e4 and p_in_internal < 1.5e5, "In "+getInstanceName() +
        ": The value of p_in="+String(p_in_internal)+" is not within a realistic range for air. This is likely an error.");
    end if;
  end if;

  // Pressure
  connect(p_in, p_in_internal);
  if not use_p_in then
    p_in_internal = p;
  end if;
  for i in 1:nPorts loop
    ports[i].p = p_in_internal;
  end for;
  // Enthalpy
  connect(h_in, h_in_internal);
  if not use_h_in then
    h_in_internal = h;
  end if;
  for i in 1:nPorts loop
     ports[i].h_outflow  = h_in_internal;
  end for;
  connect(medium.h, h_in_internal);
end Boundary_ph;


Boundary with prescribed pressure, temperature, composition and trace substances. Defines prescribed values for boundary conditions:

within Buildings.Fluid.Sources;
model Boundary_pT
  "Boundary with prescribed pressure, temperature, composition and trace substances"
  extends Buildings.Fluid.Sources.BaseClasses.PartialSource_Xi_C;

  parameter Boolean use_p_in = false
    "Get the pressure from the input connector"
  parameter Medium.AbsolutePressure p = Medium.p_default
    "Fixed value of pressure"

  parameter Boolean use_T_in= false
    "Get the temperature from the input connector"
  parameter Medium.Temperature T = Medium.T_default
    "Fixed value of temperature"

  Modelica.Blocks.Interfaces.RealInput p_in(final unit="Pa") if use_p_in
    "Prescribed boundary pressure"

  Modelica.Blocks.Interfaces.RealInput T_in(final unit="K",
                                            displayUnit="degC") if use_T_in
    "Prescribed boundary temperature"

    // Boolean constants to avoid a potential string comparison in an equation section
protected
  constant Boolean checkWaterPressure = Medium.mediumName == "SimpleLiquidWater"
    "Evaluates to true if the pressure should be checked";
  constant Boolean checkAirPressure = Medium.mediumName == "Air"
    "Evaluates to true if the pressure should be checked";

  Modelica.Blocks.Interfaces.RealInput T_in_internal(final unit="K",
                                                     displayUnit="degC")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput h_internal=
    Medium.specificEnthalpy(Medium.setState_pTX(p_in_internal, T_in_internal, X_in_internal))
    "Internal connector for enthalpy";

initial equation
  if not use_p_in then
    if checkWaterPressure then
      assert(p_in_internal>1e4, "In "+getInstanceName() +
        ": The parameter value p="+String(p_in_internal)+" is low for water. This is likely an error.");
    end if;
    if checkAirPressure then
      assert(p_in_internal>5e4 and p_in_internal < 1.5e5, "In "+getInstanceName() +
        ": The parameter value p="+String(p_in_internal)+" is not within a realistic range for air. This is likely an error.");
    end if;
  end if;
equation
  if use_p_in then
    if checkWaterPressure then
      assert(p_in_internal>1e4, "In "+getInstanceName() +
        ": The value of p_in="+String(p_in_internal)+" is low for water. This is likely an error.");
    end if;
    if checkAirPressure then
      assert(p_in_internal>5e4 and p_in_internal < 1.5e5, "In "+getInstanceName() +
        ": The value of p_in="+String(p_in_internal)+" is not within a realistic range for air. This is likely an error.");
    end if;
  end if;
  // Pressure
  connect(p_in, p_in_internal);
  if not use_p_in then
    p_in_internal = p;
  end if;
  for i in 1:nPorts loop
    ports[i].p = p_in_internal;
  end for;

  // Temperature
  connect(T_in, T_in_internal);
  if not use_T_in then
    T_in_internal = T;
  end if;
  for i in 1:nPorts loop
     ports[i].h_outflow  = h_internal;
  end for;
  connect(medium.h, h_internal);
end Boundary_pT;


Ideal flow source that produces a prescribed mass flow with prescribed specific enthalpy, composition and trace substances. Models an ideal flow source, with prescribed values of flow rate, specific enthalpy, composition and trace substances:

within Buildings.Fluid.Sources;
model MassFlowSource_h
  "Ideal flow source that produces a prescribed mass flow with prescribed specific enthalpy, composition and trace substances"
  extends Buildings.Fluid.Sources.BaseClasses.PartialSource_Xi_C;

  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 Boolean use_h_in= false
    "Get the specific enthalpy from the input connector"
  parameter Medium.SpecificEnthalpy h = Medium.h_default
    "Fixed value of specific enthalpy"

  Modelica.Blocks.Interfaces.RealInput m_flow_in(final unit="kg/s") if use_m_flow_in
    "Prescribed mass flow rate"

  Modelica.Blocks.Interfaces.RealInput h_in(final unit="J/kg") if use_h_in
    "Prescribed boundary specific enthalpy"

protected
  Modelica.Blocks.Interfaces.RealInput m_flow_in_internal(final unit="kg/s")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput h_in_internal(final unit="J/kg")
    "Needed to connect to conditional connector";

equation
  // Mass flow rate
  connect(m_flow_in, m_flow_in_internal);
  if not use_m_flow_in then
    m_flow_in_internal = m_flow;
  end if;
  for i in 1:nPorts loop
    ports[i].p = p_in_internal;
  end for;
  sum(ports.m_flow) = -m_flow_in_internal;
  // Enthalpy
  connect(h_in, h_in_internal);
  if not use_h_in then
    h_in_internal = h;
  end if;
  for i in 1:nPorts loop
     ports[i].h_outflow  = h_in_internal;
  end for;
  connect(medium.h, h_in_internal);
end MassFlowSource_h;


Ideal flow source that produces a prescribed mass flow with prescribed temperature, composition and trace substances. Models an ideal flow source, with prescribed values of flow rate, temperature, composition and trace substances:

within Buildings.Fluid.Sources;
model MassFlowSource_T
  "Ideal flow source that produces a prescribed mass flow with prescribed temperature, composition and trace substances"
  extends Buildings.Fluid.Sources.BaseClasses.PartialSource_Xi_C;

  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 Boolean use_T_in= false
    "Get the temperature from the input connector"
  parameter Medium.Temperature T = Medium.T_default
    "Fixed value of temperature"

  Modelica.Blocks.Interfaces.RealInput m_flow_in(final unit="kg/s") if use_m_flow_in
    "Prescribed mass flow rate"

  Modelica.Blocks.Interfaces.RealInput T_in(final unit="K",
                                            displayUnit="degC") if use_T_in
    "Prescribed boundary temperature"

protected
  Modelica.Blocks.Interfaces.RealInput m_flow_in_internal(final unit="kg/s")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput T_in_internal(final unit="K",
                                                     displayUnit="degC")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput h_internal=
    Medium.specificEnthalpy(Medium.setState_pTX(p_in_internal, T_in_internal, X_in_internal))
    "Internal connector for enthalpy";

equation
  // Mass flow rate
  connect(m_flow_in, m_flow_in_internal);
  if not use_m_flow_in then
    m_flow_in_internal = m_flow;
  end if;
  for i in 1:nPorts loop
    ports[i].p = p_in_internal;
  end for;
  sum(ports.m_flow) = -m_flow_in_internal;
  // Enthalpy
  connect(T_in, T_in_internal);
  if not use_T_in then
    T_in_internal = T;
  end if;
  for i in 1:nPorts loop
     ports[i].h_outflow  = h_internal;
  end for;
  connect(medium.h, h_internal);
end MassFlowSource_T;


Ideal flow source that produces a prescribed mass flow with prescribed
  trace substances, outside specific enthalpy and mass fraction . Models an ideal flow source, with prescribed values of flow rate and trace
substances, with temperature and specific enthalpy from outside:

within Buildings.Fluid.Sources;
model MassFlowSource_WeatherData
  "Ideal flow source that produces a prescribed mass flow with prescribed
  trace substances, outside specific enthalpy and mass fraction "
  extends Buildings.Fluid.Sources.BaseClasses.PartialAirSource(final verifyInputs=true);
  parameter Boolean use_m_flow_in = false
    "Get the mass flow rate from the input connector"
  parameter Boolean use_C_in = false
    "Get the trace substances from the input connector"
  parameter Modelica.Units.SI.MassFlowRate m_flow=0
    "Fixed mass flow rate going out of the fluid port"
  parameter Medium.ExtraProperty C[Medium.nC](
    final quantity=Medium.extraPropertiesNames)=fill(0, Medium.nC)
    "Fixed values of trace substances"
  Modelica.Blocks.Interfaces.RealInput m_flow_in(final unit="kg/s")
    if use_m_flow_in "Prescribed mass flow rate"
  Modelica.Blocks.Interfaces.RealInput C_in[Medium.nC](
    final quantity=Medium.extraPropertiesNames) if use_C_in
    "Prescribed boundary trace substances"
  Buildings.BoundaryConditions.WeatherData.Bus weaBus "Bus with weather data"

protected
  Modelica.Blocks.Interfaces.RealOutput TDryBul(
    final unit="K",
    displayUnit="degC")
    "Needed to calculate specific enthalpy";
  Modelica.Blocks.Interfaces.RealOutput pAtm(
    final unit="Pa")
    "Needed to calculate specific enthalpy";
  Modelica.Blocks.Interfaces.RealOutput h_out_internal(
    final unit="J/kg")
    "Needed to connect to conditional connector";

  final parameter Boolean singleSubstance = (Medium.nX == 1)
     "True if single substance medium";
  Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi if (not singleSubstance)
      "Block to compute water vapor concentration";
  Modelica.Blocks.Interfaces.RealOutput m_flow_in_internal(
    final unit="kg/s")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput h_in_internal(
    final unit="J/kg")
    "Needed to connect to conditional connector";

equation
  Modelica.Fluid.Utilities.checkBoundary(
    Medium.mediumName,
    Medium.substanceNames,
    Medium.singleState,
    true,
    X_in_internal,
    "MassFlowSourceFromOutside_h");

  // Connections and calculation to find specific enthalpy
  connect(weaBus.pAtm, pAtm);
  connect(weaBus.TDryBul, TDryBul);
  h_out_internal = Medium.specificEnthalpy(Medium.setState_pTX(
    pAtm, TDryBul, X_in_internal));

  // Connections to compute species concentration
  connect(weaBus.pAtm, x_pTphi.p_in);
  connect(weaBus.TDryBul, x_pTphi.T);
  connect(weaBus.relHum, x_pTphi.phi);
  connect(x_pTphi.X, X_in_internal);

  connect(m_flow_in, m_flow_in_internal);
  connect(C_in, C_in_internal);
  connect(h_out_internal, h_in_internal);

  if singleSubstance then
    X_in_internal = ones(Medium.nX);
  end if;
  if not use_m_flow_in then
    m_flow_in_internal = m_flow;
  end if;
  if not use_C_in then
    C_in_internal = C;
  end if;

  sum(ports.m_flow) = -m_flow_in_internal;
  connect(medium.h, h_in_internal);
  connect(medium.Xi, Xi_in_internal);
  ports.C_outflow = fill(C_in_internal, nPorts);

  connect(X_in_internal[1:Medium.nXi], Xi_in_internal);

  if not verifyInputs then
    h_in_internal = Medium.h_default;
    p_in_internal = Medium.p_default;
    X_in_internal = Medium.X_default;
    TDryBul       = Medium.T_default;
  end if;

  for i in 1:nPorts loop
    ports[i].p          = p_in_internal;
    ports[i].h_outflow  = h_in_internal;
    ports[i].Xi_outflow = Xi_in_internal;
  end for;
end MassFlowSource_WeatherData;


Boundary that takes weather data, and optionally trace substances, as an input. This model describes boundary conditions for
pressure, enthalpy, and species concentration that can be obtained
from weather data.

within Buildings.Fluid.Sources;
model Outside
  "Boundary that takes weather data, and optionally trace substances, as an input"
  extends Buildings.Fluid.Sources.BaseClasses.Outside;

equation
  connect(weaBus.pAtm, p_in_internal);
  connect(weaBus.TDryBul, T_in_internal);
end Outside;


Boundary that takes weather data, and optionally the wind pressure coefficient and trace substances, as an input. This model describes boundary conditions for
pressure, enthalpy, and species concentration that can be obtained
from weather data. The model is identical to

Buildings.Fluid.Sources.Outside,
except that it allows adding the wind pressure to the
pressure at the fluid port ports.

within Buildings.Fluid.Sources;
model Outside_Cp
  "Boundary that takes weather data, and optionally the wind pressure coefficient and trace substances, as an input"
  extends Buildings.Fluid.Sources.BaseClasses.Outside;

  parameter Boolean use_Cp_in= false
    "Get the wind pressure coefficient from the input connector"
  parameter Real Cp = 0.6 "Fixed value of wind pressure coefficient"

  Modelica.Blocks.Interfaces.RealInput Cp_in(unit="1")
  if use_Cp_in "Prescribed wind pressure coefficient"
  Modelica.Units.SI.Pressure pWin(displayUnit="Pa")
    "Change in pressure due to wind force";

protected
  Modelica.Blocks.Interfaces.RealInput Cp_in_internal(unit="1")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput pWea(min=0, nominal=1E5, unit="Pa")
    "Pressure from weather bus";
  Modelica.Blocks.Interfaces.RealInput vWin(unit="m/s")
    "Wind speed from weather bus";
  Modelica.Blocks.Interfaces.RealOutput pTot(min=0, nominal=1E5, unit="Pa")
    "Sum of atmospheric pressure and wind pressure";
equation
  connect(Cp_in, Cp_in_internal);
  if not use_Cp_in then
    Cp_in_internal = Cp;
  end if;
  pWin = 0.5*Cp_in_internal*vWin*vWin
    *Medium.density(Medium.setState_pTX(
      p=pWea,
      T=T_in_internal,
      X=Medium.X_default));
  pTot = pWea + pWin;

  connect(weaBus.winSpe, vWin);
  connect(weaBus.pAtm, pWea);
  connect(p_in_internal, pTot);
  connect(weaBus.TDryBul, T_in_internal);
end Outside_Cp;


Boundary that takes weather data as an input and computes the wind pressure from a given wind pressure profile. This model describes boundary conditions for
pressure, enthalpy, and species concentration that can be obtained
from weather data. The model is identical to

Buildings.Fluid.Sources.Outside,
except that it adds the wind pressure to the
pressure at the fluid ports ports.

within Buildings.Fluid.Sources;
model Outside_CpData
  "Boundary that takes weather data as an input and computes the wind pressure from a given wind pressure profile"
  extends Buildings.Fluid.Sources.BaseClasses.Outside;

  parameter Modelica.Units.SI.Angle azi "Surface azimuth (South:0, West:pi/2)"

  parameter Modelica.Units.SI.Angle incAngSurNor[:](
    each displayUnit="deg")
    "Wind incidence angles, relative to the surface normal (normal=0), first point must be 0, last smaller than 2 pi(=360 deg)";
  parameter Real Cp[:](
    each final unit="1")
    "Cp values at the corresponding incAngSurNor";

  parameter Real Cs(
    final min=0,
    final unit="1")=1
    "Wind speed modifier";

  Modelica.Units.SI.Pressure pWin(displayUnit="Pa") = Cs*0.5*CpAct*d*vWin*vWin
   "Change in pressure due to wind force";

  Real CpAct(
    final unit="1") = Buildings.Airflow.Multizone.BaseClasses.windPressureProfile(
      alpha=alpha,incAngTab=
      incAngExt,
      CpTab=CpExt,
      d=deri) "Actual wind pressure coefficient";

  Modelica.Units.SI.Angle alpha = winDir-surOut
    "Wind incidence angle (0: normal to wall)";

protected
  final parameter Modelica.Units.SI.Angle surOut = azi-Modelica.Constants.pi
    "Angle of surface that is used to compute the wind incidence angle relative to the surface normal";

  final parameter Integer n=size(incAngSurNor, 1)
    "Number of data points provided by user";
  final parameter Modelica.Units.SI.Angle incAngExt[n + 3](each displayUnit=
        "deg") = cat(
    1,
    {incAngSurNor[n - 1] - (2*Modelica.Constants.pi)},
    incAngSurNor,
    2*Modelica.Constants.pi .+ {incAngSurNor[1],incAngSurNor[2]})
    "Extended number of incidence angles";
  final parameter Real CpExt[n+3]=cat(1, {Cp[n-1]}, Cp, {Cp[1], Cp[2]})
    "Extended number of Cp values";

  final parameter Real[n+3] deri=
      Buildings.Utilities.Math.Functions.splineDerivatives(
      x=incAngExt,
      y=CpExt,
      ensureMonotonicity=false) "Derivatives for table interpolation";

  Modelica.Blocks.Interfaces.RealInput pAtm(
    min=0,
    nominal=1E5,
    final unit="Pa") "Atmospheric pressure";
  Modelica.Blocks.Interfaces.RealInput vWin(final unit="m/s")
    "Wind speed from weather bus";
  Modelica.Blocks.Interfaces.RealInput winDir(final unit="rad",displayUnit="deg") "Wind direction from weather bus";

  Modelica.Blocks.Interfaces.RealOutput pTot(min=0, nominal=1E5, final unit="Pa")=pAtm + pWin
    "Sum of atmospheric pressure and wind pressure";

  Modelica.Units.SI.Density d = Medium.density(
    Medium.setState_pTX(p_in_internal, T_in_internal, X_in_internal))
    "Air density";

initial equation
  assert(size(incAngSurNor, 1) == size(Cp, 1), "In " + getInstanceName() +
    ": Size of parameters are size(CpincAng, 1) = " + String(size(incAngSurNor,
    1)) + " and size(Cp, 1) = " + String(size(Cp, 1)) + ". They must be equal.");

  assert(abs(incAngSurNor[1]) < 1E-4, "In " + getInstanceName() +
    ": First point in the table CpAngAtt must be 0.");

  assert(2*Modelica.Constants.pi - incAngSurNor[end] > 1E-4, "In " +
    getInstanceName() +
    ": Last point in the table CpAngAtt must be smaller than 2 pi (360 deg).");

equation
  connect(weaBus.winDir, winDir);
  connect(weaBus.winSpe, vWin);
  connect(weaBus.pAtm,pAtm);
  connect(p_in_internal, pTot);
  connect(weaBus.TDryBul, T_in_internal);
end Outside_CpData;


Boundary that takes weather data as an input and computes the wind pressure for low-rise buildings based on the equation from Swami and Chandra (1987). This model describes boundary conditions for
pressure, enthalpy, and species concentration that can be obtained
from weather data. The model is identical to

Buildings.Fluid.Sources.Outside,
except that it adds the wind pressure to the
pressure at the fluid port ports.
The correlation that is used to compute the wind pressure is based
on Swami and Chandra (1987) and valid for low-rise buildings
with rectangular shape.
The same correlation is also implemented in CONTAM (Persily and Ivy, 2001).
For other buildings, the model

Buildings.Fluid.Sources.Outside_CpData or

Buildings.Fluid.Sources.Outside_Cp
should be used that takes
the wind pressure coefficient as a parameter or an input.

within Buildings.Fluid.Sources;
model Outside_CpLowRise
  "Boundary that takes weather data as an input and computes the wind pressure for low-rise buildings based on the equation from Swami and Chandra (1987)"
  extends Buildings.Fluid.Sources.BaseClasses.Outside;

  parameter Real Cp0(min=0, max=1, final unit="1") = 0.6
    "Wind pressure coefficient for wind normal to wall";
  parameter Real s(final min=0, final unit="1")
    "Side ratio, s=length of this wall/length of adjacent wall";
  parameter Modelica.Units.SI.Angle azi "Surface azimuth (South:0, West:pi/2)"

  Modelica.Units.SI.Angle alpha = winDir-surOut
    "Wind incidence angle (0: normal to wall)";
  Real CpAct(final unit="1")=
   Buildings.Airflow.Multizone.BaseClasses.windPressureLowRise(
     Cp0=Cp0,
     alpha=alpha,
     G=G)
   "Actual wind pressure coefficient";
  Modelica.Units.SI.Pressure pWin(displayUnit="Pa")=
    0.5*CpAct*d*vWin*vWin
    "Change in pressure due to wind force";
protected
  Modelica.Blocks.Interfaces.RealInput pWea(min=0, nominal=1E5, final unit="Pa")
    "Pressure from weather bus";
  Modelica.Blocks.Interfaces.RealInput vWin(final unit="m/s")
    "Wind speed from weather bus";
  Modelica.Blocks.Interfaces.RealOutput pTot(
    min=0,
    nominal=1E5,
    final unit="Pa") = pWea + pWin
    "Sum of atmospheric pressure and wind pressure";
  final parameter Real G = Modelica.Math.log(s)
    "Natural logarithm of side ratio";

  Modelica.Blocks.Interfaces.RealInput winDir(final unit="rad",
                                              displayUnit="deg")
    "Wind direction from weather bus";
  Modelica.Units.SI.Angle surOut=azi - Modelica.Constants.pi
    "Angle of surface that is used to compute angle of attack of wind";
  Modelica.Units.SI.Density d = Medium.density(
    Medium.setState_pTX(p_in_internal, T_in_internal, X_in_internal))
    "Air density";

equation
  connect(weaBus.winDir, winDir);
  connect(weaBus.winSpe, vWin);
  connect(weaBus.pAtm, pWea);
  connect(p_in_internal, pTot);
  connect(weaBus.TDryBul, T_in_internal);
end Outside_CpLowRise;


Package with boundary condition models

within Buildings.Fluid;
package Sources "Package with boundary condition models"
  extends Modelica.Icons.SourcesPackage;
end Sources;


Model for overriding fluid properties that flow through the component, using specific enthalpy input. Model that changes the properties,
but not the mass flow rate,
of the fluid that passes through it.

within Buildings.Fluid.Sources;
model PropertySource_h
  "Model for overriding fluid properties that flow through the component, using specific enthalpy input"
  // The parameter declaration is before 'extends',
  // since this affects the parameter order in the parameters window.
  parameter Boolean use_h_in= false
    "Set to true to get the specific enthalpy from the input connector"

  extends Buildings.Fluid.Sources.BaseClasses.PartialPropertySource;

  Modelica.Blocks.Interfaces.RealInput h_in if use_h_in
    "Prescribed value for leaving specific enthalpy"
equation
  connect(h_internal_a, h_in);
  connect(h_internal_b, h_in);
  if not (use_h_in) then
    connect(h_internal_a,h_in_b);
    connect(h_internal_b,h_in_a);
  end if;
end PropertySource_h;


Model for overriding fluid properties that flow through the component, using temperature input. Model that changes the properties,
but not the mass flow rate,
of the fluid that passes through it.

within Buildings.Fluid.Sources;
model PropertySource_T
  "Model for overriding fluid properties that flow through the component, using temperature input"
  // The parameter declaration is before 'extends',
  // since this affects the parameter order in the parameters window.
  parameter Boolean use_T_in= false
    "Set to true to get the leaving fluid temperature from the input connector"
  extends Buildings.Fluid.Sources.BaseClasses.PartialPropertySource;
  Modelica.Blocks.Interfaces.RealInput T_in if use_T_in
    "Prescribed value for leaving fluid temperature"
protected
  Modelica.Blocks.Interfaces.RealOutput T_in_internal(unit="K")
    "Internal connector for leaving fluid temperature";
  Modelica.Blocks.Interfaces.RealOutput h_T_a=
    Medium.specificEnthalpy(
      Medium.setState_pTX(port_a.p, T_in_internal, port_a.Xi_outflow)) if use_T_in
      "Conditional connector for enthalpy leaving port a";
  Modelica.Blocks.Interfaces.RealOutput h_T_b=
    Medium.specificEnthalpy(
      Medium.setState_pTX(port_b.p, T_in_internal, port_b.Xi_outflow)) if use_T_in
      "Conditional connector for enthalpy leaving port b";

equation
  connect(h_internal_a, h_T_a);
  connect(h_internal_b, h_T_b);
  if use_T_in then
    connect(T_in_internal, T_in);
  else
    T_in_internal = 293.15;
    connect(h_internal_a, h_in_b);
    connect(h_internal_b, h_in_a);
  end if;
end PropertySource_T;


within Buildings.Fluid.Sources;
model TraceSubstancesFlowSource
  "Source with mass flow that does not take part in medium mass balance (such as CO2)"

  replaceable package Medium =
    Buildings.Media.Air(extraPropertiesNames={"CO2"}) "Medium in the component"

  parameter Integer nPorts=0 "Number of ports"

  parameter String substanceName = "CO2" "Name of trace substance";
  parameter Boolean use_m_flow_in = false
    "Get the trace substance 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"
  Modelica.Blocks.Interfaces.RealInput m_flow_in(final unit="kg/s")
    if use_m_flow_in "Prescribed mass flow rate for extra property"

  Modelica.Fluid.Interfaces.FluidPorts_b ports[nPorts](
    redeclare each package Medium = Medium)
    "Connector for fluid ports"

protected
  parameter Medium.ExtraProperty C_in_internal[Medium.nC](
    final quantity=Medium.extraPropertiesNames)=
     {if (Modelica.Utilities.Strings.isEqual(string1=Medium.extraPropertiesNames[i],
                                             string2=substanceName,
                                             caseSensitive=false)) then 1 else 0
                                             for i in 1:Medium.nC}
     "Boundary trace substances"
  Modelica.Blocks.Interfaces.RealInput m_flow_in_internal(final unit="kg/s")
    "Needed to connect to conditional connector";

  Modelica.Units.SI.SpecificEnthalpy h_default=Medium.specificEnthalpy(
      Medium.setState_pTX(
      Medium.p_default,
      Medium.T_default,
      Medium.X_default)) "Enthalpy of outstreaming medium";

initial equation
  assert(sum(C_in_internal) > 1E-4, "Trace substance '" + substanceName + "' is not present in medium '"
         + Medium.mediumName + "'.\n"
         + "Check source parameter and medium model.");

  // Only one connection allowed to a port to avoid unwanted ideal mixing
  for i in 1:nPorts loop
    assert(cardinality(ports[i]) <= 1,"
Each ports[i] of boundary shall at most be connected to one component.
If two or more connections are present, ideal mixing takes
place in these connections, which is usually not the intention
of the modeller. Increase nPorts to add an additional port.
");
  end for;

equation
  sum(ports.m_flow) = -m_flow_in_internal;

  connect(m_flow_in, m_flow_in_internal);
  if not use_m_flow_in then
    m_flow_in_internal = m_flow;
  end if;

  assert(m_flow_in_internal >= 0, "Reverse flow for species source is not yet implemented.");

  for i in 2:nPorts loop
    ports[1].p = ports[i].p;
  end for;

  ports.C_outflow = fill(C_in_internal, nPorts);
  ports.h_outflow = fill(h_default, nPorts);
  ports.Xi_outflow = fill(Medium.X_default[1:Medium.nXi], nPorts);
end TraceSubstancesFlowSource;


Boundary that takes weather data, and optionally trace substances, as an input. This is the base class for models that describes boundary conditions for
pressure, enthalpy, and species concentration that can be obtained
from weather data, and that may be modified based on the wind pressure.

within Buildings.Fluid.Sources.BaseClasses;
partial model Outside
  "Boundary that takes weather data, and optionally trace substances, as an input"
  extends Buildings.Fluid.Sources.BaseClasses.PartialAirSource(final verifyInputs=true);

  parameter Boolean use_C_in = false
    "Get the trace substances from the input connector"
  parameter Medium.ExtraProperty C[Medium.nC](
    final quantity=Medium.extraPropertiesNames)=fill(0, Medium.nC)
    "Fixed values of trace substances"

  Modelica.Blocks.Interfaces.RealInput C_in[Medium.nC](
    final quantity=Medium.extraPropertiesNames) if use_C_in
    "Prescribed boundary trace substances"

  Buildings.BoundaryConditions.WeatherData.Bus weaBus "Bus with weather data"
protected
  final parameter Boolean singleSubstance = (Medium.nX == 1)
    "True if single substance medium";
  Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi
    if not singleSubstance "Block to compute water vapor concentration";

  Modelica.Blocks.Interfaces.RealInput T_in_internal(final unit="K",
                                                     displayUnit="degC")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput h_internal = Medium.specificEnthalpy(
    Medium.setState_pTX(p_in_internal, T_in_internal, X_in_internal));

equation
  // Check medium properties
  Modelica.Fluid.Utilities.checkBoundary(Medium.mediumName, Medium.substanceNames,
    Medium.singleState, true, X_in_internal, "Boundary_pT");

  // Conditional connectors for trace substances
  connect(C_in, C_in_internal);
  if not use_C_in then
    C_in_internal = C;
  end if;
  // Connections to input. This is required to obtain the data from
  // the weather bus in case that the component x_pTphi is conditionally removed
  connect(weaBus.TDryBul, T_in_internal);

  // Connections to compute species concentration
  connect(p_in_internal, x_pTphi.p_in);
  connect(T_in_internal, x_pTphi.T);
  connect(weaBus.relHum, x_pTphi.phi);

  connect(X_in_internal, x_pTphi.X);
  if singleSubstance then
    X_in_internal = ones(Medium.nX);
  end if;

  connect(X_in_internal[1:Medium.nXi], Xi_in_internal);

  ports.C_outflow = fill(C_in_internal, nPorts);

  if not verifyInputs then
    h_internal    = Medium.h_default;
    p_in_internal = Medium.p_default;
    X_in_internal = Medium.X_default;
    T_in_internal = Medium.T_default;
  end if;

  // Assign medium properties
  connect(medium.h, h_internal);
  connect(medium.Xi, Xi_in_internal);

  for i in 1:nPorts loop
    ports[i].p          = p_in_internal;
    ports[i].h_outflow  = h_internal;
    ports[i].Xi_outflow = Xi_in_internal;
  end for;
end Outside;


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


within Buildings.Fluid.Sources.BaseClasses;
partial model PartialAirSource
  "Partial component air source with one fluid connector"

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

  parameter Integer nPorts=0 "Number of ports"
  parameter Boolean verifyInputs = false
    "Set to true to stop the simulation with an error if the medium temperature is outside its allowable range"

  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),
    each h_outflow(nominal=Medium.h_default),
    each Xi_outflow(each nominal=0.01))
    "Fluid ports"

protected
  parameter Modelica.Fluid.Types.PortFlowDirection flowDirection=Modelica.Fluid.Types.PortFlowDirection.Bidirectional
    "Allowed flow direction"
  Modelica.Blocks.Interfaces.RealInput p_in_internal(final unit="Pa")
    "Needed to connect to conditional connector";
  Medium.BaseProperties medium(
      T(start=Medium.T_default)
    ) if verifyInputs "Medium in the source";
  Modelica.Blocks.Interfaces.RealInput Xi_in_internal[Medium.nXi](
    each final unit = "kg/kg")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput X_in_internal[Medium.nX](
    each final unit = "kg/kg")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput C_in_internal[Medium.nC](
    final quantity=Medium.extraPropertiesNames)
    "Needed to connect to conditional connector";

initial equation
  // Only one connection allowed to a port to avoid unwanted ideal mixing
  for i in 1:nPorts loop
    assert(cardinality(ports[i]) <= 1,"
Each ports[i] of boundary shall at most be connected to one component.
If two or more connections are present, ideal mixing takes
place in these connections, which is usually not the intention
of the modeller. Increase nPorts to add an additional port.
");
  end for;

equation
  connect(medium.p, p_in_internal);
end PartialAirSource;


Partial model for overriding fluid properties that flow through the component. Model that changes the properties,
but not the mass flow rate,
of the fluid that passes through it.

within Buildings.Fluid.Sources.BaseClasses;
partial model PartialPropertySource
  "Partial model for overriding fluid properties that flow through the component"
  extends Buildings.Fluid.Interfaces.PartialTwoPort;

  parameter Boolean use_Xi_in= false
    "Set to true to get the composition from the input connector"
  parameter Boolean use_C_in= false
    "Set to true to get the trace substances from the input connector"

  Modelica.Blocks.Interfaces.RealInput Xi_in[Medium.nXi] if use_Xi_in
    "Prescribed values for composition"
  Modelica.Blocks.Interfaces.RealInput C_in[Medium.nC](
    final quantity=Medium.extraPropertiesNames) if use_C_in
    "Prescribed values for trace substances"
protected
  Modelica.Blocks.Interfaces.RealOutput h_internal_a
    "Internal outlet value of port_a.h_outflow";
  Modelica.Blocks.Interfaces.RealOutput h_internal_b
    "Internal outlet value of port_b.h_outflow";
  Modelica.Blocks.Interfaces.RealOutput h_in_a = inStream(port_a.h_outflow)
    "Connector for inStream value of port_a.h_outflow";
  Modelica.Blocks.Interfaces.RealOutput h_in_b = inStream(port_b.h_outflow)
    "Connector for inStream value of port_b.h_outflow";

  Modelica.Blocks.Interfaces.RealOutput[Medium.nXi] Xi_internal_a
    "Internal outlet value of port_a.Xi_outflow";
  Modelica.Blocks.Interfaces.RealOutput[Medium.nXi] Xi_internal_b
    "Internal outlet value of port_b.Xi_outflow";
  Modelica.Blocks.Interfaces.RealOutput[Medium.nXi] Xi_in_a = inStream(port_a.Xi_outflow)
    "Connector for inStream value of port_a.Xi_outflow";
  Modelica.Blocks.Interfaces.RealOutput[Medium.nXi] Xi_in_b = inStream(port_b.Xi_outflow)
    "Connector for inStream value of port_b.Xi_outflow";

  Modelica.Blocks.Interfaces.RealInput[Medium.nC] C_internal_a
    "Internal outlet value of port_a.C_outflow";
  Modelica.Blocks.Interfaces.RealInput[Medium.nC] C_internal_b
    "Internal outlet value of port_b.C_outflow";
  Modelica.Blocks.Interfaces.RealOutput[Medium.nC] C_in_a = inStream(port_a.C_outflow)
    "Connector for inStream value of port_a.C_outflow";
  Modelica.Blocks.Interfaces.RealOutput[Medium.nC] C_in_b = inStream(port_b.C_outflow)
    "Connector for inStream value of port_b.C_outflow";
equation
  connect(Xi_internal_a, Xi_in);
  connect(Xi_internal_b, Xi_in);
  if not (use_Xi_in) then
    connect(Xi_internal_a,Xi_in_b);
    connect(Xi_internal_b,Xi_in_a);
  end if;

  connect(C_internal_a, C_in);
  connect(C_internal_b, C_in);
  if not (use_C_in) then
    connect(C_internal_a,C_in_b);
    connect(C_internal_b,C_in_a);
  end if;

  port_a.h_outflow = if allowFlowReversal then h_internal_a else Medium.h_default;
  port_b.h_outflow = h_internal_b;
  port_a.Xi_outflow = if allowFlowReversal then Xi_internal_a else Medium.X_default[1:Medium.nXi];
  port_b.Xi_outflow = Xi_internal_b;
  port_a.C_outflow = if allowFlowReversal then C_internal_a else zeros(Medium.nC);
  port_b.C_outflow = C_internal_b;

  port_a.p = port_b.p;
  port_a.m_flow + port_b.m_flow = 0;
end PartialPropertySource;


within Buildings.Fluid.Sources.BaseClasses;
partial model PartialSource
  "Partial component source with one fluid connector"

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

  parameter Integer nPorts=0 "Number of ports"
  parameter Boolean verifyInputs = false
    "Set to true to stop the simulation with an error if the medium temperature is outside its allowable range"

  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),
    each h_outflow(nominal=Medium.h_default),
    each Xi_outflow(each nominal=0.01))
    "Fluid ports"

protected
  parameter Modelica.Fluid.Types.PortFlowDirection flowDirection=Modelica.Fluid.Types.PortFlowDirection.Bidirectional
    "Allowed flow direction"
  Modelica.Blocks.Interfaces.RealInput p_in_internal(final unit="Pa")
    "Needed to connect to conditional connector";
  Medium.BaseProperties medium if verifyInputs "Medium in the source";
  Modelica.Blocks.Interfaces.RealInput Xi_in_internal[Medium.nXi](
    each final unit = "kg/kg")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput X_in_internal[Medium.nX](
    each final unit = "kg/kg")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput C_in_internal[Medium.nC](
    final quantity=Medium.extraPropertiesNames)
    "Needed to connect to conditional connector";

initial equation
  // Only one connection allowed to a port to avoid unwanted ideal mixing
  for i in 1:nPorts loop
    assert(cardinality(ports[i]) <= 1,"
Each ports[i] of boundary shall at most be connected to one component.
If two or more connections are present, ideal mixing takes
place in these connections, which is usually not the intention
of the modeller. Increase nPorts to add an additional port.
");
  end for;

equation
  connect(medium.p, p_in_internal);
end PartialSource;


Partial component source with parameter definitions for Xi and C. Partial model that defines outflowing properties
ports.Xi_outflow and ports.C_outflow
using an optional input for both.
Otherwise the parameter value is used.

within Buildings.Fluid.Sources.BaseClasses;
partial model PartialSource_Xi_C
  "Partial component source with parameter definitions for Xi and C"
  extends Buildings.Fluid.Sources.BaseClasses.PartialSource;

  parameter Boolean use_X_in = false
    "Get the composition (all fractions) from the input connector"
  parameter Boolean use_Xi_in = false
    "Get the composition (independent fractions) from the input connector"
  parameter Boolean use_C_in = false
    "Get the trace substances from the input connector"
  parameter Medium.MassFraction X[Medium.nX](
    final quantity=Medium.substanceNames) = Medium.X_default
    "Fixed value of composition"
  parameter Medium.ExtraProperty C[Medium.nC](
    final quantity=Medium.extraPropertiesNames) = fill(0, Medium.nC)
    "Fixed values of trace substances"
  Modelica.Blocks.Interfaces.RealInput X_in[Medium.nX](
    each final unit = "kg/kg",
    final quantity=Medium.substanceNames) if use_X_in
    "Prescribed boundary composition"
  Modelica.Blocks.Interfaces.RealInput Xi_in[Medium.nXi](
    each final unit = "kg/kg",
    final quantity=Medium.substanceNames[1:Medium.nXi]) if use_Xi_in
    "Prescribed boundary composition"
  Modelica.Blocks.Interfaces.RealInput C_in[Medium.nC](
    final quantity=Medium.extraPropertiesNames) if use_C_in
    "Prescribed boundary trace substances"

initial equation
  assert(not use_X_in or not use_Xi_in,
    "Cannot use both X and Xi inputs, choose either use_X_in or use_Xi_in.");

  if not use_X_in and not use_Xi_in then
    Modelica.Fluid.Utilities.checkBoundary(Medium.mediumName, Medium.substanceNames,
      Medium.singleState, true, X_in_internal, "Boundary_pT");
  end if;

equation
  if use_X_in or use_Xi_in then
    Modelica.Fluid.Utilities.checkBoundary(Medium.mediumName, Medium.substanceNames,
      Medium.singleState, true, X_in_internal, "Boundary_pT");
  end if;

  // Assign Xi_in_internal and X_in_internal
  // Note that at most one of X_in or Xi_in is present
  connect(X_in, X_in_internal);
  connect(Xi_in, Xi_in_internal);

  if use_Xi_in then
    // Must assign all components of X_in_internal, using Xi_in
    X_in_internal[1:Medium.nXi] = Xi_in_internal[1:Medium.nXi];
    // If reducedX = true, medium contains the equation sum(X) = 1.0
    // Media with only one substance (e.g., water) have reducedX=true
    // FlueGas and SimpleNaturalGas has reducedX = false
    if Medium.reducedX then
      X_in_internal[Medium.nX] = 1-sum(Xi_in_internal);
    end if;
  elseif use_X_in then
    X_in_internal[1:Medium.nXi] = Xi_in_internal[1:Medium.nXi];
  else
    // No connector is used. Use parameter X.
    X_in_internal = X;
    Xi_in_internal = X[1:Medium.nXi];
  end if;

  connect(C_in, C_in_internal);

  if not use_C_in then
    C_in_internal = C;
  end if;

  for i in 1:nPorts loop
    ports[i].Xi_outflow = Xi_in_internal;
    ports[i].C_outflow = C_in_internal;
  end for;
end PartialSource_Xi_C;


within Buildings.Fluid.Sources.Examples;
model MassFlowSource_WeatherData
  "Test model for source (sink) with weather bus"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
  Buildings.Fluid.Sources.MassFlowSource_WeatherData sin_with_h(
    redeclare package Medium = Medium,
    m_flow=-1,
    nPorts=1) "Mass flow source model receiving h and X from weather data through
     weather bus"
  Buildings.Fluid.Sources.Outside bou(redeclare package Medium = Medium, nPorts=1)
    "Model with outside conditions"
  Buildings.Fluid.Sensors.RelativeHumidityTwoPort senRelHum(redeclare package
      Medium = Medium, m_flow_nominal=1,
    tau=0)                               "Sensor for relative humidity"
  Buildings.Fluid.Sensors.MassFractionTwoPort senMasFra(redeclare package Medium =
        Medium, m_flow_nominal=1,
    tau=0)                        "Sensor for mass fraction of water"
  Sensors.TemperatureTwoPort senTem(redeclare package Medium = Medium,
      m_flow_nominal=1,
    tau=0)              "Temperature sensor"
equation
  connect(bou.ports[1], senRelHum.port_a)
  connect(senRelHum.port_b, senMasFra.port_a)
  connect(senMasFra.port_b, senTem.port_a)
  connect(senTem.port_b, sin_with_h.ports[1])
  connect(weaDat.weaBus, bou.weaBus)
  connect(weaDat.weaBus, sin_with_h.weaBus)
end MassFlowSource_WeatherData;


within Buildings.Fluid.Sources.Examples;
model Outside
  "Test model for source and sink with outside weather data"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";
  Buildings.Fluid.Sources.Outside bou(
   redeclare package Medium = Medium,
   nPorts=1) "Model with outside conditions"
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
  Buildings.Fluid.Sources.MassFlowSource_T sin(
    redeclare package Medium = Medium,
    m_flow=-1,
    nPorts=1) "Sink"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTem(
    redeclare package Medium = Medium,
    m_flow_nominal=1) "Temperature sensor"
  Buildings.Fluid.Sensors.RelativeHumidityTwoPort senRelHum(
    redeclare package Medium = Medium,
    m_flow_nominal=1) "Sensor for relative humidity"
  Buildings.Fluid.Sensors.MassFractionTwoPort senMasFra(
    redeclare package Medium = Medium,
    m_flow_nominal=1) "Sensor for mass fraction of water"
equation
  connect(weaDat.weaBus, bou.weaBus)
  connect(senTem.port_b, sin.ports[1])
  connect(senRelHum.port_a, bou.ports[1])
  connect(senRelHum.port_b, senMasFra.port_a)
  connect(senMasFra.port_b, senTem.port_a)
end Outside;


within Buildings.Fluid.Sources.Examples;
model Outside_Cp
  "Test model for source and sink with outside weather data and wind pressure"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";
  Buildings.Fluid.Sources.Outside_Cp bou1(
    redeclare package Medium = Medium,
    nPorts=1,
    Cp=0.6) "Model with outside conditions"
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
  Buildings.Fluid.Sources.Outside bouFix(redeclare package Medium = Medium,
      nPorts=2) "Model with outside conditions"
  Modelica.Blocks.Sources.Constant Cp(k=0.6)
    "Constant value for Cp (used to demonstrate input connector)"
  Buildings.Airflow.Multizone.Orifice ori1(A=0.1, redeclare package Medium =
        Medium) "Orifice"
  Buildings.Fluid.Sources.Outside_Cp bou2(
    redeclare package Medium = Medium,
    nPorts=1,
    use_Cp_in=true) "Model with outside conditions"
  Buildings.Airflow.Multizone.Orifice ori2(A=0.1, redeclare package Medium =
        Medium) "Orifice"
equation
  connect(weaDat.weaBus, bou1.weaBus)
  connect(bou1.ports[1], ori1.port_a)
  connect(ori1.port_b, bouFix.ports[1])
  connect(weaDat.weaBus, bouFix.weaBus)
  connect(bou2.Cp_in, Cp.y)
  connect(bou2.ports[1], ori2.port_a)
  connect(ori2.port_b, bouFix.ports[2])
  connect(weaDat.weaBus, bou2.weaBus)
end Outside_Cp;


within Buildings.Fluid.Sources.Examples;
model Outside_CpData
  "Test model for source and sink with outside weather data and wind pressure using user-defined Cp values"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))

  parameter Modelica.Units.SI.Angle incAngSurNor[:]=
    {0, 45, 90, 135, 180, 225, 270, 315}*2*Modelica.Constants.pi/360
    "Wind incidence angles";
  parameter Real Cp[:] = {0.4, 0.1, -0.3, -0.35, -0.2, -0.35, -0.3, 0.1}
    "Cp values";
  Buildings.Fluid.Sources.Outside_CpData west(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=Buildings.Types.Azimuth.W) "Model with outside conditions"
  Buildings.Fluid.Sources.Outside_CpData north(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=Buildings.Types.Azimuth.N) "Model with outside conditions"
  Buildings.Fluid.Sources.Outside_CpData south(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=Buildings.Types.Azimuth.S) "Model with outside conditions"
  Buildings.Fluid.Sources.Outside_CpData east(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=Buildings.Types.Azimuth.E) "Model with outside conditions"
equation
  connect(weaDat.weaBus, west.weaBus)
  connect(weaDat.weaBus, north.weaBus)
  connect(weaDat.weaBus, south.weaBus)
  connect(weaDat.weaBus, east.weaBus)
end Outside_CpData;


within Buildings.Fluid.Sources.Examples;
model Outside_CpData_Angles
  "Test model for source and sink with outside weather data and wind pressure using user-defined Cp values"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";

  parameter Modelica.Units.SI.Angle incAngSurNor[:]=
    {0, 45, 90, 135, 180, 225, 270, 315}*2*Modelica.Constants.pi/360
    "Wind incidence angles";
  parameter Real CpSym[:]={0.4, 0.1, -0.3, -0.35, -0.2, -0.35, -0.3, 0.1}
    "Cp values that are symmetric";
  parameter Real CpAsy[:]={0.4, 0.1, -0.3, -0.35, -0.2, -0.6, -0.9, -0.1}
    "Cp values that are asymmetric";
  Buildings.Fluid.Sources.Outside_CpData symNor(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpSym,
    azi=Buildings.Types.Azimuth.N)
    "Model to compute wind pressure on North-facing surface"
  Buildings.Fluid.Sources.Outside_CpData asyNor(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpAsy,
    azi=Buildings.Types.Azimuth.N)
    "Model to compute wind pressure on North-facing surface"
  Buildings.Fluid.Sources.Outside_CpData asyWes(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpAsy,
    azi=Buildings.Types.Azimuth.W)
    "Model to compute wind pressure on West-facing surface"
  Buildings.Fluid.Sources.Outside_CpData symWes(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpSym,
    azi=Buildings.Types.Azimuth.W)
    "Model to compute wind pressure on West-facing surface"

  Modelica.Blocks.Sources.Ramp winDir(
    height=2*Modelica.Constants.pi,
    duration=10,
    startTime=5) "Wind direction"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
    winSpeSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    winSpe=1,
    winDirSou=Buildings.BoundaryConditions.Types.DataSource.Input)

equation
  connect(weaDat.weaBus, symNor.weaBus)
  connect(weaDat.weaBus, asyNor.weaBus)
  connect(winDir.y, weaDat.winDir_in)
  connect(asyWes.weaBus, weaDat.weaBus)
  connect(symWes.weaBus, weaDat.weaBus)
end Outside_CpData_Angles;


Test model for wind pressure profile

within Buildings.Fluid.Sources.Examples;
model Outside_CpData_Specification
  "Test model for wind pressure profile"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";

  Buildings.Fluid.Sources.Outside_CpData nor(
    redeclare package Medium = Medium,
    incAngSurNor={0,90,180,315}*2*Modelica.Constants.pi/360,
    Cp={1,0.2,0.5,0.8},
    azi=Buildings.Types.Azimuth.N,
    Cs=2/1.2) "Model to compute wind pressure on North-facing surface"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
    winSpeSou=Buildings.BoundaryConditions.Types.DataSource.Parameter,
    winSpe=1,
    winDirSou=Buildings.BoundaryConditions.Types.DataSource.Input)

  Modelica.Blocks.Sources.Ramp winDir(
    height=2*Modelica.Constants.pi,
    duration=24*3600)
    "Wind direction"

equation
  connect(weaDat.winDir_in, winDir.y)
  connect(weaDat.weaBus, nor.weaBus)
end Outside_CpData_Specification;


within Buildings.Fluid.Sources.Examples;
model Outside_CpLowRise
  "Test model for source and sink with outside weather data and wind pressure"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air "Medium model for air";
  Buildings.Fluid.Sources.Outside_CpLowRise west(
    redeclare package Medium = Medium,
    s=5,
    azi=Buildings.Types.Azimuth.W,
    Cp0=0.6) "Model with outside conditions"
  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
  Buildings.Fluid.Sources.Outside_CpLowRise north(
    redeclare package Medium = Medium,
    s=1/5,
    azi=Buildings.Types.Azimuth.N,
    Cp0=0.6) "Model with outside conditions"
  Buildings.Fluid.Sources.Outside_CpLowRise south(
    redeclare package Medium = Medium,
    s=1/5,
    azi=Buildings.Types.Azimuth.S,
    Cp0=0.6) "Model with outside conditions"
  Buildings.Fluid.Sources.Outside_CpLowRise east(
    redeclare package Medium = Medium,
    s=5,
    azi=Buildings.Types.Azimuth.E,
    Cp0=0.6) "Model with outside conditions"
equation
  connect(weaDat.weaBus, west.weaBus)
  connect(weaDat.weaBus, north.weaBus)
  connect(weaDat.weaBus, south.weaBus)
  connect(weaDat.weaBus, east.weaBus)
end Outside_CpLowRise;


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


within Buildings.Fluid.Sources.Examples;
model PropertySource_h "Model that illustrates the use of PropertySource_h"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air(extraPropertiesNames={"CO2"});

  Buildings.Fluid.Sources.PropertySource_h proSouXi(
    redeclare package Medium = Medium,
    use_Xi_in=true)
    "Property source that prescribes Xi"
  Buildings.Fluid.Sources.MassFlowSource_h bouXi(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true)
    "Boundary for Xi test"

  Buildings.Fluid.Sources.Boundary_ph sin(
    redeclare package Medium = Medium,
    nPorts=3)
    "Sink model"
  Buildings.Fluid.Sources.PropertySource_h proSouH(
    redeclare package Medium = Medium,
    use_h_in=true)
    "Property source that prescribes the specific enthalpy"
  Buildings.Fluid.Sources.PropertySource_h proSouC(
    redeclare package Medium = Medium,
    use_C_in=true)   "Property source that prescribes C"
  Buildings.Fluid.Sources.MassFlowSource_h bouH(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true)
    "Boundary for specific enthalpy test"
  Buildings.Fluid.Sources.MassFlowSource_h bouC(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true)
    "Boundary for C test"
  Modelica.Blocks.Sources.Constant h(
    k=Medium.h_default + 1e3)
    "Fixed specific enthalpy value"
  Modelica.Blocks.Sources.Constant Xi(k=0.0123)
    "Fixed Xi value"
  Modelica.Blocks.Sources.Constant C(k=0.1)
    "Fixed C value"
  Modelica.Blocks.Sources.Ramp ramp(
    height=-2,
    duration=1,
    offset=1)
    "Ramp for mass flow rate"
equation
  connect(bouXi.ports[1], proSouXi.port_a)
  connect(bouC.ports[1], proSouC.port_a)
  connect(bouH.ports[1], proSouH.port_a)
  connect(proSouH.port_b, sin.ports[1])
  connect(proSouXi.port_b, sin.ports[2])
  connect(proSouC.port_b, sin.ports[3])
  connect(h.y, proSouH.h_in)
  connect(Xi.y, proSouXi.Xi_in[1])
  connect(C.y, proSouC.C_in[1])
  connect(bouH.m_flow_in, ramp.y)
  connect(ramp.y, bouXi.m_flow_in)
  connect(ramp.y, bouC.m_flow_in)
end PropertySource_h;