within AixLib.Fluid.SolarCollectors.Validation;
model FlatPlateNPanels
  "Validation model for flat plate collector with different settings for nPanel"
  extends AixLib.Fluid.SolarCollectors.Validation.FlatPlate;
  parameter Integer nPanels = 10 "Number of panels";
  AixLib.Fluid.SolarCollectors.ASHRAE93
   solCol1(
    redeclare package Medium = Medium,
    shaCoe=0,
    azi=0,
    per=AixLib.Fluid.SolarCollectors.Data.GlazedFlatPlate.FP_TRNSYSValidation(),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    rho=0.2,
    nColType=AixLib.Fluid.SolarCollectors.Types.NumberSelection.Number,
    nSeg=30,
    til=0.78539816339745,
    nPanels=nPanels)
    "Flat plate solar collector model, has been modified for validation purposes"
  AixLib.Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    nPorts=1) "Outlet for water flow"
  AixLib.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 AixLib.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 AixLib.Fluid.Sources;
model Boundary_ph
  "Boundary with prescribed pressure, specific enthalpy, composition and trace substances"
  extends AixLib.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 AixLib.Fluid.Sources;
model Boundary_pT
  "Boundary with prescribed pressure, temperature, composition and trace substances"
  extends AixLib.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 AixLib.Fluid.Sources;
model MassFlowSource_h
  "Ideal flow source that produces a prescribed mass flow with prescribed specific enthalpy, composition and trace substances"
  extends AixLib.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 AixLib.Fluid.Sources;
model MassFlowSource_T
  "Ideal flow source that produces a prescribed mass flow with prescribed temperature, composition and trace substances"
  extends AixLib.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 AixLib.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 AixLib.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"
  AixLib.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";
  AixLib.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 AixLib.Fluid.Sources;
model Outside
  "Boundary that takes weather data, and optionally trace substances, as an input"
  extends AixLib.Fluid.Sources.BaseClasses.Outside;

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


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

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

within AixLib.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 AixLib.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") = AixLib.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=
      AixLib.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

AixLib.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).

within AixLib.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 AixLib.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")=
   AixLib.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 AixLib.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 AixLib.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 AixLib.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 AixLib.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 AixLib.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 AixLib.Fluid.Sources;
model TraceSubstancesFlowSource
  "Source with mass flow that does not take part in medium mass balance (such as CO2)"

  replaceable package Medium =
    AixLib.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 AixLib.Fluid.Sources.BaseClasses;
partial model Outside
  "Boundary that takes weather data, and optionally trace substances, as an input"
  extends AixLib.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"

  AixLib.BoundaryConditions.WeatherData.Bus weaBus "Bus with weather data"
protected
  final parameter Boolean singleSubstance = (Medium.nX == 1)
    "True if single substance medium";
  AixLib.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 AixLib.Fluid.Sources;
package BaseClasses "Package with base classes for AixLib.Fluid.Sources"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within AixLib.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 AixLib.Fluid.Sources.BaseClasses;
partial model PartialPropertySource
  "Partial model for overriding fluid properties that flow through the component"
  extends AixLib.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 AixLib.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 AixLib.Fluid.Sources.BaseClasses;
partial model PartialSource_Xi_C
  "Partial component source with parameter definitions for Xi and C"
  extends AixLib.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 AixLib.Fluid.Sources.Examples;
model MassFlowSource_WeatherData
  "Test model for source (sink) with weather bus"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Air "Medium model for air";

  AixLib.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://AixLib/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
  AixLib.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"
  AixLib.Fluid.Sources.Outside bou(redeclare package Medium = Medium, nPorts=1)
    "Model with outside conditions"
  AixLib.Fluid.Sensors.RelativeHumidityTwoPort senRelHum(redeclare package
      Medium = Medium, m_flow_nominal=1,
    tau=0)                               "Sensor for relative humidity"
  AixLib.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 AixLib.Fluid.Sources.Examples;
model Outside
  "Test model for source and sink with outside weather data"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Air "Medium model for air";
  AixLib.Fluid.Sources.Outside bou(
   redeclare package Medium = Medium,
   nPorts=1) "Model with outside conditions"
  AixLib.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://AixLib/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
  AixLib.Fluid.Sources.MassFlowSource_T sin(
    redeclare package Medium = Medium,
    m_flow=-1,
    nPorts=1) "Sink"
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem(
    redeclare package Medium = Medium,
    m_flow_nominal=1) "Temperature sensor"
  AixLib.Fluid.Sensors.RelativeHumidityTwoPort senRelHum(
    redeclare package Medium = Medium,
    m_flow_nominal=1) "Sensor for relative humidity"
  AixLib.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 AixLib.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 = AixLib.Media.Air "Medium model for air";
  AixLib.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://AixLib/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";
  AixLib.Fluid.Sources.Outside_CpData west(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.W) "Model with outside conditions"
  AixLib.Fluid.Sources.Outside_CpData north(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.N) "Model with outside conditions"
  AixLib.Fluid.Sources.Outside_CpData south(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.S) "Model with outside conditions"
  AixLib.Fluid.Sources.Outside_CpData east(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.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 AixLib.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 = AixLib.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";
  AixLib.Fluid.Sources.Outside_CpData symNor(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpSym,
    azi=AixLib.Types.Azimuth.N)
    "Model to compute wind pressure on North-facing surface"
  AixLib.Fluid.Sources.Outside_CpData asyNor(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpAsy,
    azi=AixLib.Types.Azimuth.N)
    "Model to compute wind pressure on North-facing surface"
  AixLib.Fluid.Sources.Outside_CpData asyWes(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpAsy,
    azi=AixLib.Types.Azimuth.W)
    "Model to compute wind pressure on West-facing surface"
  AixLib.Fluid.Sources.Outside_CpData symWes(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=CpSym,
    azi=AixLib.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"

  AixLib.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://AixLib/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
    winSpeSou=AixLib.BoundaryConditions.Types.DataSource.Parameter,
    winSpe=1,
    winDirSou=AixLib.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 AixLib.Fluid.Sources.Examples;
model Outside_CpData_Specification
  "Test model for wind pressure profile"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Air "Medium model for air";

  AixLib.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=AixLib.Types.Azimuth.N,
    Cs=2/1.2) "Model to compute wind pressure on North-facing surface"

  AixLib.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://AixLib/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"),
    winSpeSou=AixLib.BoundaryConditions.Types.DataSource.Parameter,
    winSpe=1,
    winDirSou=AixLib.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 AixLib.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 = AixLib.Media.Air "Medium model for air";
  AixLib.Fluid.Sources.Outside_CpLowRise west(
    redeclare package Medium = Medium,
    s=5,
    azi=AixLib.Types.Azimuth.W,
    Cp0=0.6) "Model with outside conditions"
  AixLib.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://AixLib/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
  AixLib.Fluid.Sources.Outside_CpLowRise north(
    redeclare package Medium = Medium,
    s=1/5,
    azi=AixLib.Types.Azimuth.N,
    Cp0=0.6) "Model with outside conditions"
  AixLib.Fluid.Sources.Outside_CpLowRise south(
    redeclare package Medium = Medium,
    s=1/5,
    azi=AixLib.Types.Azimuth.S,
    Cp0=0.6) "Model with outside conditions"
  AixLib.Fluid.Sources.Outside_CpLowRise east(
    redeclare package Medium = Medium,
    s=5,
    azi=AixLib.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 AixLib.Fluid.Sources;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


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

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

  AixLib.Fluid.Sources.Boundary_ph sin(
    redeclare package Medium = Medium,
    nPorts=3)
    "Sink model"
  AixLib.Fluid.Sources.PropertySource_h proSouH(
    redeclare package Medium = Medium,
    use_h_in=true)
    "Property source that prescribes the specific enthalpy"
  AixLib.Fluid.Sources.PropertySource_h proSouC(
    redeclare package Medium = Medium,
    use_C_in=true)   "Property source that prescribes C"
  AixLib.Fluid.Sources.MassFlowSource_h bouH(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true)
    "Boundary for specific enthalpy test"
  AixLib.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;


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

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

  AixLib.Fluid.Sources.Boundary_ph sin(
    redeclare package Medium = Medium,
    nPorts=3)
   "Sink model"
  AixLib.Fluid.Sources.PropertySource_T proSouT(
    redeclare package Medium = Medium,
    use_T_in=true)
    "Property source that prescribes the temperature"
  AixLib.Fluid.Sources.PropertySource_T proSouC(
    redeclare package Medium = Medium,
    use_C_in=true)
    "Property source that prescribes C"
  AixLib.Fluid.Sources.MassFlowSource_T bouT(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true)
    "Boundary for temperature test"
  AixLib.Fluid.Sources.MassFlowSource_T bouC(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true)
    "Boundary for C test"
  Modelica.Blocks.Sources.Constant T(k=Medium.T_default + 1)
    "Fixed temperature 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"
  AixLib.Fluid.Sensors.TemperatureTwoPort senTemT(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    tau=0)
    "Temperature sensor for when using temperature input"
  AixLib.Fluid.Sensors.TemperatureTwoPort senTemXi(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    tau=0)
    "Temperature sensor for when using Xi input"
  AixLib.Fluid.Sensors.TemperatureTwoPort senTemC(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    tau=0)
    "Temperature sensor for when using C input"
equation
  connect(bouXi.ports[1], proSouXi.port_a)
  connect(bouC.ports[1], proSouC.port_a)
  connect(bouT.ports[1], proSouT.port_a)
  connect(Xi.y, proSouXi.Xi_in[1])
  connect(C.y, proSouC.C_in[1])
  connect(bouT.m_flow_in, ramp.y)
  connect(ramp.y, bouXi.m_flow_in)
  connect(ramp.y, bouC.m_flow_in)
  connect(T.y, proSouT.T_in)
  connect(proSouC.port_b, senTemC.port_a)
  connect(senTemC.port_b, sin.ports[1])
  connect(senTemXi.port_b, sin.ports[2])
  connect(senTemT.port_b, sin.ports[3])
  connect(proSouT.port_b, senTemT.port_a)
  connect(proSouXi.port_b, senTemXi.port_a)
end PropertySource_T;


within AixLib.Fluid.Sources.Examples;
model TraceSubstancesFlowSource
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Air(extraPropertiesNames={"CO2"});

  MixingVolumes.MixingVolume vol(
    redeclare package Medium = Medium,
    V=100,
    m_flow_nominal=1,
    nPorts=3,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Mixing volume"
  Sources.TraceSubstancesFlowSource sou(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1)
  Modelica.Blocks.Sources.Step step(
    startTime=0.5,
    height=-2,
    offset=2)
  FixedResistances.PressureDrop res(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  MixingVolumes.MixingVolume vol1(
    redeclare package Medium = Medium,
    V=100,
    m_flow_nominal=1,
    nPorts=3,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Mixing volume"
  Sources.TraceSubstancesFlowSource sou1(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1)
  AixLib.Utilities.Diagnostics.AssertEquality assEqu(threShold=1E-4)
    "Assert that both volumes have the same concentration"
  MixingVolumes.MixingVolume vol2(
    redeclare package Medium = Medium,
    p_start=Medium.p_default,
    V=100,
    m_flow_nominal=1,
    nPorts=3,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Mixing volume"
  MixingVolumes.MixingVolume vol3(
    redeclare package Medium = Medium,
    p_start=Medium.p_default,
    V=100,
    m_flow_nominal=1,
    nPorts=3,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Mixing volume"
  AixLib.Utilities.Diagnostics.AssertEquality assEqu1(threShold=1E-4)
    "Assert that both volumes have the same concentration"
  MixingVolumes.MixingVolume vol4(
    redeclare package Medium = Medium,
    nPorts=4,
    p_start=Medium.p_default,
    V=100,
    m_flow_nominal=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Mixing volume"
  Sources.TraceSubstancesFlowSource sou2(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1)
  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium,
    p=101325,
    nPorts=1,
    T=293.15)
  AixLib.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    nPorts=2,
    p=101320,
    T=293.15) "Sink boundary conditions"
  FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  FixedResistances.PressureDrop res2(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  FixedResistances.PressureDrop res3(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"

  Sensors.TraceSubstances C(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "Trace substance sensor"
  Sensors.TraceSubstances C1(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "Trace substance sensor"
  Sensors.TraceSubstances C2(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "Trace substance sensor"
  Sensors.TraceSubstances C3(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "Trace substance sensor"
  FixedResistances.PressureDrop res4(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  FixedResistances.PressureDrop res6(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  FixedResistances.PressureDrop res5(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  FixedResistances.PressureDrop res7(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1)
    "Resistance, used to check if species are transported between ports"
  AixLib.Fluid.Sources.Boundary_pT sin1(
    redeclare package Medium = Medium,
    nPorts=2,
    p=101320,
    T=293.15) "Sink boundary conditions"
equation
  connect(res3.port_b, vol4.ports[2])
  connect(res1.port_b, sin.ports[1])
  connect(res2.port_b, sin.ports[2])
  connect(bou.ports[1], res3.port_a)
  connect(sou1.ports[1], res.port_a)
  connect(sou2.ports[1], vol4.ports[1])
  connect(step.y, sou.m_flow_in)
  connect(step.y, sou1.m_flow_in)
  connect(step.y, sou2.m_flow_in)
  connect(assEqu.u1, C.C)
  connect(C1.C, assEqu.u2)
  connect(assEqu1.u1, C2.C)
  connect(C3.C, assEqu1.u2)
  connect(sou.ports[1], vol.ports[1])
  connect(vol.ports[2], C.port)
  connect(res.port_b, vol1.ports[1])
  connect(vol1.ports[2], C1.port)
  connect(vol2.ports[1], res1.port_a)
  connect(vol3.ports[1], res2.port_a)
  connect(C2.port, vol2.ports[2])
  connect(C3.port, vol3.ports[2])
  connect(vol4.ports[3], res4.port_a)
  connect(vol4.ports[4], res6.port_a)
  connect(res6.port_b, vol3.ports[3])
  connect(res4.port_b, vol2.ports[3])
  connect(vol.ports[3], res5.port_a)
  connect(res5.port_b, sin1.ports[1])
  connect(vol1.ports[3], res7.port_a)
  connect(res7.port_b, sin1.ports[2])
end TraceSubstancesFlowSource;


within AixLib.Fluid.Sources.Validation;
model Boundary "Validation model for boundary with different media"
  extends Modelica.Icons.Example;

 AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouWat(
   redeclare package Medium = AixLib.Media.Water)
   "Boundary with water"
 AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouProGly(
    redeclare package Medium = Media.Antifreeze.PropyleneGlycolWater(property_T=293.15, X_a=0.40))
    "Boundary with propylene glycol"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouMoiAir(
    redeclare package Medium = AixLib.Media.Air)
    "Boundary with moist air"
  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouMoiAirCO2(
    redeclare package Medium = AixLib.Media.Air(extraPropertiesNames={"CO2"}))
    "Boundary with moist air"
 AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouProFluGas(
   redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.FlueGasSixComponents)
    "Boundary with flue gas"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouNatGas(
    redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.SimpleNaturalGas)
   "Boundary with natural gas"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem bouNatGasFix(
    redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.SimpleNaturalGasFixedComposition)
    "Boundary with natural gas"
end Boundary;


within AixLib.Fluid.Sources.Validation;
model BoundaryWithXi_in
  "Validation model for boundary with different media and independent mass fraction input"
  extends Modelica.Icons.Example;

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithXi_in bouMoiAir(
    redeclare package Medium = AixLib.Media.Air)
    "Boundary with moist air"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithXi_in bouMoiAirCO2(
    redeclare package Medium = AixLib.Media.Air(extraPropertiesNames={"CO2"}))
    "Boundary with moist air"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithXi_in bouProFluGas(
   redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.FlueGasSixComponents)
    "Boundary with flue gas"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithXi_in bouNatGas(
    redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.SimpleNaturalGas)
    "Boundary with natural gas"

  Modelica.Blocks.Sources.Constant Xi_1[1](k={0.015})
    "Prescribed mass fraction"
  Modelica.Blocks.Sources.Constant Xi_6[6](k={0.5,0.2,0.0,0.3,0.0,0.0})
    "Prescribed mass fraction"

equation
  connect(Xi_6.y, bouProFluGas.Xi_in)
  connect(Xi_1.y, bouMoiAir.Xi_in)
  connect(Xi_6.y, bouNatGas.Xi_in)
  connect(Xi_1.y, bouMoiAirCO2.Xi_in)
end BoundaryWithXi_in;


within AixLib.Fluid.Sources.Validation;
model BoundaryWithX_in
  "Validation model for boundary with different media and mass fraction input"
  extends Modelica.Icons.Example;

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithX_in bouMoiAir(
    redeclare package Medium = AixLib.Media.Air)
    "Boundary with moist air"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithX_in bouMoiAirCO2(
    redeclare package Medium = AixLib.Media.Air(extraPropertiesNames={"CO2"}))
    "Boundary with moist air"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithX_in bouProFluGas(
   redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.FlueGasSixComponents)
    "Boundary with flue gas"

  AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystemWithX_in bouNatGas(
    redeclare package Medium =
        Modelica.Media.IdealGases.MixtureGases.SimpleNaturalGas)
    "Boundary with natural gas"

  Modelica.Blocks.Sources.Constant X_2[2](k={0.015, 0.985})
    "Prescribed mass fraction"
  Modelica.Blocks.Sources.Constant X_6[6](k={0.5,0.2,0.0,0.3,0.0,0.0})
    "Prescribed mass fraction"

equation
  connect(X_6.y, bouProFluGas.X_in)
  connect(X_2.y, bouMoiAir.X_in)
  connect(X_6.y, bouNatGas.X_in)
  connect(X_2.y, bouMoiAirCO2.X_in)
end BoundaryWithX_in;


within AixLib.Fluid.Sources.Validation;
model Outside_CpData_Directions
  "Test model for wind pressure using a wind pressure profile that is 1 for normal angle of attack, and goes to zero otherwise"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Air "Medium model for air";

  parameter Modelica.Units.SI.Angle incAngSurNor[:]=
    {0,1,5,90,180,315,355,359}*2*Modelica.Constants.pi/360
    "Wind incidence angles";
  parameter Real Cp[:]={1,0.01,0,0,0,0,0,0.01}
    "Cp values at the relative surface wind incidence angles";
  AixLib.Fluid.Sources.Outside_CpData nor(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.N)
    "Model to compute wind pressure on North-facing surface"
  AixLib.Fluid.Sources.Outside_CpData eas(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.E)
    "Model to compute wind pressure on East-facing surface"
  AixLib.Fluid.Sources.Outside_CpData sou(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.S)
    "Model to compute wind pressure on South-facing surface"
  AixLib.Fluid.Sources.Outside_CpData wes(
    redeclare package Medium = Medium,
    incAngSurNor=incAngSurNor,
    Cp=Cp,
    azi=AixLib.Types.Azimuth.W)
    "Model to compute wind pressure on West-facing surface"

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

  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)
  connect(weaDat.weaBus, eas.weaBus)
  connect(weaDat.weaBus, sou.weaBus)
  connect(weaDat.weaBus, wes.weaBus)
end Outside_CpData_Directions;


Collection of validation models

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


within AixLib.Fluid.Sources.Validation.BaseClasses;
model BoundarySystem "System model for testing of boundary condition"
  extends Modelica.Blocks.Icons.Block;
  replaceable package Medium =
    Modelica.Media.Interfaces.PartialMedium "Medium in the component";

 Boundary_pT sou(redeclare final package Medium = Medium, nPorts=1) "Boundary"
  MassFlowSource_T sin(
    redeclare final package Medium = Medium,
    m_flow=-1,
    nPorts=1) "Mass flow source"
  Modelica.Units.SI.Temperature T=senTem.T
    "Temperature coming out of the source";
  Modelica.Units.SI.MassFraction Xi[Medium.nXi]=sou.ports[1].Xi_outflow
    "Mass fraction coming out of the source";
  Modelica.Units.SI.Pressure p=sou.ports[1].p "Pressure in the source";
  Modelica.Fluid.Sensors.TemperatureTwoPort senTem(
    redeclare package Medium = Medium,
    allowFlowReversal=false,
    m_flow_nominal=1,
    m_flow_small=1E-4) "Temperature sensor"
  inner Modelica.Fluid.System system
equation
  connect(sou.ports[1], senTem.port_a)
  connect(sin.ports[1], senTem.port_b)
end BoundarySystem;


System model for testing boundary condition with mass fraction input. System model used to test the boundary conditions for different media
with independent prescribed mass fraction Xi.

within AixLib.Fluid.Sources.Validation.BaseClasses;
model BoundarySystemWithXi_in
  "System model for testing boundary condition with mass fraction input"
  extends AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem(sou(use_Xi_in=true));
  Modelica.Blocks.Interfaces.RealInput Xi_in[Medium.nXi]
    "Prescribed boundary composition"
equation
  for i in 1:Medium.nXi loop
    assert(abs(Xi[i] - Xi_in[i]) < 1E-6, "Error in implementation of mass fraction");
  end for;
  connect(sou.Xi_in, Xi_in)
end BoundarySystemWithXi_in;


System model for testing boundary condition with mass fraction input. System model used to test the boundary conditions for different media
with prescribed mass fraction X.

within AixLib.Fluid.Sources.Validation.BaseClasses;
model BoundarySystemWithX_in
  "System model for testing boundary condition with mass fraction input"
  extends AixLib.Fluid.Sources.Validation.BaseClasses.BoundarySystem(sou(use_X_in=true));
  Modelica.Blocks.Interfaces.RealInput X_in[Medium.nX]
    "Prescribed boundary composition"
equation
  for i in 1:Medium.nXi loop
    assert(abs(Xi[i] - X_in[i]) < 1E-6, "Error in implementation of mass fraction");
  end for;
  connect(sou.X_in, X_in)
end BoundarySystemWithX_in;


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


Expansion vessel with fixed pressure

within AixLib.Fluid.Storage;
model ExpansionVessel "Expansion vessel with fixed pressure"
 extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations(
   final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
   final massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
   final mSenFac=1);
  parameter Modelica.Units.SI.Volume V_start(start=1)
    "Volume of liquid stored in the vessel at the start of the simulation";

  Modelica.Fluid.Interfaces.FluidPort_a port_a(
    redeclare package Medium = Medium) "Fluid port"
  Modelica.Units.SI.Mass m "Mass of liquid in the vessel";

protected
  final parameter Medium.ThermodynamicState state_start = Medium.setState_pTX(
      T=T_start,
      p=p_start,
      X=X_start[1:Medium.nXi]) "Medium state at start values";
  final parameter Modelica.Units.SI.Density rho_start=Medium.density(state=
      state_start) "Density, used to compute start and guess values";

  Modelica.Units.SI.Energy H "Internal energy of fluid";
  Modelica.Units.SI.Mass[Medium.nXi] mXi
    "Masses of independent components in the fluid";
  Modelica.Units.SI.Mass[Medium.nC] mC
    "Masses of trace substances in the fluid";
  Medium.ExtraProperty C[Medium.nC](nominal=C_nominal)
    "Trace substance mixture content";

initial equation
  m = V_start * rho_start;
  H = m*Medium.specificInternalEnergy(
          Medium.setState_pTX(p=p_start, T=T_start, X= X_start[1:Medium.nXi]));
  mXi = m*X_start[1:Medium.nXi];
  mC = m*C_start[1:Medium.nC];
equation
  assert(m > 1.0E-8,
    "Expansion vessel is undersized. You need to increase the value of the parameter V_start.");
  // Conservation equations
  der(m)   = port_a.m_flow;
  der(H)   = port_a.m_flow * actualStream(port_a.h_outflow);
  der(mXi) = port_a.m_flow * actualStream(port_a.Xi_outflow);
  der(mC)  = port_a.m_flow * actualStream(port_a.C_outflow);
  // Properties of outgoing flow.
  // The port pressure is set to a constant value.
  port_a.p          = p_start;
  m*port_a.h_outflow  = H;
  m*port_a.Xi_outflow = mXi;
  m*port_a.C_outflow  = mC;
end ExpansionVessel;


within AixLib.Fluid;
package Storage "Package with thermal energy storage models"
  extends Modelica.Icons.VariantsPackage;
end Storage;


within AixLib.Fluid.Storage;
model StorageDetailed
  "Buffer Storage Model with support for heating rod and two heating coils"

  extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations(
    final T_start=sum(TStart)/n);

  replaceable package MediumHC1 =
      Modelica.Media.Interfaces.PartialMedium "Medium model for HC1"

  replaceable package MediumHC2 =
      Modelica.Media.Interfaces.PartialMedium "Medium model for HC2"
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal(min=0)
    "Nominal mass flow rate of fluid 1 ports"
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal(min=0)
    "Nominal mass flow rate of fluid 2 ports"

  parameter Modelica.Units.SI.MassFlowRate mHC1_flow_nominal(min=0) if useHeatingCoil1
    "Nominal mass flow rate of fluid 1 ports"
  parameter Modelica.Units.SI.MassFlowRate mHC2_flow_nominal(min=0) if useHeatingCoil2
    "Nominal mass flow rate of fluid 1 ports"

  parameter Boolean useHeatingCoil1=true "Use Heating Coil1?"
  parameter Boolean useHeatingCoil2=true "Use Heating Coil2?"
  parameter Boolean useHeatingRod=true "Use Heating Rod?"

  parameter Integer n(min=3)=5 "Number of Layers";
  parameter Modelica.Units.SI.Temperature TStart[n]=fill(298.15,n)
    "Start Temperature of fluid in each layer. e.g. for a 3 layer model: {20, 20, 20}"

  replaceable parameter AixLib.DataBase.Storage.StorageDetailedBaseDataDefinition data
    constrainedby AixLib.DataBase.Storage.StorageDetailedBaseDataDefinition
    "Data record for Storage"

////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////CONVECTION/////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hConIn=100 "Model assumptions heat transfer coefficient water <-> wall";
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hConOut=10 "Model assumptions heat transfer coefficient insulation <-> air";
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hConHC1=100 "Model assumptions Coefficient of Heat Transfer HC1 <-> Heating Water"
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hConHC2=100 " Model assumptions Coefficient of Heat Transfer HC2 <-> Heating Water"
  parameter Boolean upToDownHC1 = true
    "Heating Coil 1 orientation from up to down?"
  parameter Boolean upToDownHC2 = true
    "Heating Coil 2 orientation from up to down?"

  parameter Modelica.Units.SI.Temperature TStartWall=293.15
    "Starting Temperature of wall in K"
  parameter Modelica.Units.SI.Temperature TStartIns=293.15
    "Starting Temperature of insulation in K"

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////Advanced parameters/////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
  parameter Integer nLowerPortSupply=integer(max(AixLib.Utilities.Math.Functions.round(data.hLowerPortSupply/(data.hTank/n) + 0.5,0),1)) "Layer number lower end of supply is connected to"
  parameter Integer nUpperPortSupply=integer(min(AixLib.Utilities.Math.Functions.round(data.hUpperPortSupply/(data.hTank/n) + 0.5,0),n)) "Layer number upper end of supply is connected to"
  parameter Integer nLowerPortDemand=integer(max(AixLib.Utilities.Math.Functions.round(data.hLowerPortDemand/(data.hTank/n) + 0.5,0),1)) "Layer number lower end of demand is connected to"
  parameter Integer nUpperPortDemand=integer(min(AixLib.Utilities.Math.Functions.round(data.hUpperPortDemand/(data.hTank/n) + 0.5,0),n)) "Layer number upper end of demand is connected to"
  parameter Integer nTS1=integer(AixLib.Utilities.Math.Functions.round(data.hTS1/(data.hTank/n) + 0.5,0)) "Layer number lower temperature sensor is connected to"
  parameter Integer nTS2=integer(AixLib.Utilities.Math.Functions.round(data.hTS2/(data.hTank/n) + 0.5,0)) "Layer number upper temperature sensor is connected to"

  parameter Integer nHC1Up=integer(ceil(data.hHC1Up/(data.hTank/n))) "Layer number upper end of heating coil 1 is connected to"
  parameter Integer nHC1Low=integer(floor(data.hHC1Low/(data.hTank/n))+1) "Layer number lower end of heating coil 1 is connected to"
  parameter Integer nHC2Up=integer(ceil(data.hHC2Up/(data.hTank/n))) "Layer number upper end of heating coil 2 is connected to"
  parameter Integer nHC2Low=integer(floor(data.hHC2Low/(data.hTank/n))+1) "Layer number lower end of heating coil 2 is connected to"
  parameter Integer nHR=integer(AixLib.Utilities.Math.Functions.round(data.hHR/(data.hTank/n) + 0.5,0)) "Layer number heating rod is connected to"

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////final parameters////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
 final parameter Integer disHC1 = nHC1Up-nHC1Low+1;
 final parameter Integer disHC2 = nHC2Up-nHC2Low+1;

 final parameter Boolean inpLowLayDemand=(nLowerPortDemand == 1); //if there is an input at the lowest layer
 final parameter Boolean inpHigLayDemand=(nUpperPortDemand == n);

 final parameter Boolean inpLowLaySupply=(nLowerPortSupply == 1); //if there is an input at the lowest layer
 final parameter Boolean inpHigLaySupply=(nUpperPortSupply == n);

 final parameter Integer[n] inpActLay = cat(1,{if (nLowerPortDemand==k or nLowerPortSupply==k) then (if (nUpperPortDemand==k or nUpperPortSupply==k) then 2 else 1) else (if (nUpperPortDemand==k or nUpperPortSupply==k) then 1 else 0) for k in 1:n});
 final parameter Integer[n] portsLayer=cat(1,{if inpActLay[1]==1 then 3 else 1},{inpActLay[k]*2+2 for k in 2:n-1},{if inpActLay[n]==1 then 3 else 1});
////////////////////////////////////////////////////////////////////////////////////////////////////
///////////components/////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatportOutside "Outer heat port"
  Modelica.Blocks.Interfaces.RealOutput TTop(
      final quantity="ThermodynamicTemperature",
      final unit = "K",
      min=0,
      displayUnit = "degC")
    "Temperature at the top"
  Modelica.Blocks.Interfaces.RealOutput TBottom(
      final quantity="ThermodynamicTemperature",
      final unit = "K",
      min=0,
      displayUnit = "degC")
    "Temperature at the Bottom"
  Modelica.Fluid.Interfaces.FluidPort_a fluidportTop1(redeclare final package
      Medium =  Medium)
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_a fluidportBottom2(redeclare final
      package Medium =
               Medium)
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b fluidportBottom1(redeclare final
      package Medium =
                 Medium)
    "Fluid connector b (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b fluidportTop2(redeclare final package
      Medium =
        Medium)
    "Fluid connector b (positive design flow direction is from port_a to port_b)"

  HeatTransfer heatTransfer(final n=n,
      redeclare final package Medium = Medium,
      final data=data)
      "Heat transfer model"

  AixLib.Fluid.MixingVolumes.MixingVolume layer[n](
    each final energyDynamics=energyDynamics,
    each final massDynamics=massDynamics,
    each final p_start=p_start,
    each final X_start=X_start,
    each final C_start=C_start,
    each final C_nominal=C_nominal,
    each final mSenFac=mSenFac,
    each final allowFlowReversal=allowFlowReversal_layers,
    each final m_flow_small=m_flow_small,
    final V=fill(data.hTank/n*Modelica.Constants.pi/4*data.dTank^2,n),
    final nPorts = portsLayer,
    final T_start=TStart,
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=m1_flow_nominal + m2_flow_nominal)
    "Layer volumes"
    replaceable model HeatTransfer =
      AixLib.Fluid.Storage.BaseClasses.HeatTransferOnlyConduction
    constrainedby AixLib.Fluid.Storage.BaseClasses.PartialHeatTransferLayers
    "Heat Transfer Model between fluid layers"

///////////////////////////////////////////////////////////////////////////////////////
/////HEATING COILS AND RODS/////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////
/////HEATING COIL 1 ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////

  Modelica.Fluid.Interfaces.FluidPort_a portHC1In(redeclare final package
      Medium =
        MediumHC1) if useHeatingCoil1
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b portHC1Out(redeclare final package
      Medium =
        MediumHC1) if useHeatingCoil1
    "Fluid connector b (positive design flow direction is from port_a to port_b)"

//////////////////////////////////////////////////////////////////////////////////////////
/////HEATING COIL 2 ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////

  Modelica.Fluid.Interfaces.FluidPort_a portHC2In(redeclare final package
      Medium =
        MediumHC2) if useHeatingCoil2
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b portHC2Out(redeclare final package
      Medium =
        MediumHC2) if useHeatingCoil2
    "Fluid connector b (positive design flow direction is from port_a to port_b)"

//////////////////////////////////////////////////////////////////////////////////////////
/////HEATING ROD ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatingRod
                                       if useHeatingRod

//////////////////////////////////////////////////////////////////////////////////////////
/////COVER / INSULATION  ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////

  AixLib.Fluid.Storage.BaseClasses.StorageCover topCover(
    final energyDynamics=energyDynamics,
    final lambdaWall=data.lambdaWall,
    final lambdaIns=data.lambdaIns,
    final hConIn=hConIn,
    final hConOut=hConOut,
    final TStartWall=TStartWall,
    final TStartIns=TStartIns,
    final rhoIns=data.rhoIns,
    final cIns=data.cIns,
    final rhoWall=data.rhoWall,
    final cWall=data.cWall,
    final D1=data.dTank,
    final sWall=data.sWall,
    final sIns=data.sIns)
  AixLib.Fluid.Storage.BaseClasses.StorageMantle storageMantle[n](
    each final energyDynamics=energyDynamics,
    each final lambdaWall=data.lambdaWall,
    each final lambdaIns=data.lambdaIns,
    each final TStartWall=TStartWall,
    each final TStartIns=TStartIns,
    each final rhoIns=data.rhoIns,
    each final cIns=data.cIns,
    each final rhoWall=data.rhoWall,
    each final cWall=data.cWall,
    each final height=data.hTank/n,
    each final D1=data.dTank,
    each final sWall=data.sWall,
    each final sIns=data.sIns,
    each final hConIn=hConIn,
    each final hConOut=hConOut)
  AixLib.Fluid.Storage.BaseClasses.StorageCover bottomCover(
    final energyDynamics=energyDynamics,
    final lambdaWall=data.lambdaWall,
    final lambdaIns=data.lambdaIns,
    final hConIn=hConIn,
    final hConOut=hConOut,
    final TStartWall=TStartWall,
    final TStartIns=TStartIns,
    final rhoIns=data.rhoIns,
    final cIns=data.cIns,
    final rhoWall=data.rhoWall,
    final cWall=data.cWall,
    final D1=data.dTank,
    final sWall=data.sWall,
    final sIns=data.sIns)

  AixLib.Fluid.Storage.BaseClasses.HeatingCoil heatingCoil1(
    m_flow_small=m_flow_small_HC1,
    disHC=disHC1,
    hConHC=hConHC1,
    redeclare package Medium = MediumHC1,
    lengthHC=data.lengthHC1,
    pipeHC=data.pipeHC1,
    allowFlowReversal=allowFlowReversal_HC1,
    final m_flow_nominal=mHC1_flow_nominal,
    TStart=sum(TStart)/n) if useHeatingCoil1
  AixLib.Fluid.Storage.BaseClasses.HeatingCoil heatingCoil2(
    m_flow_small=m_flow_small_HC2,
    disHC=disHC2,
    lengthHC=data.lengthHC2,
    hConHC=hConHC2,
    pipeHC=data.pipeHC2,
    redeclare package Medium = MediumHC2,
    allowFlowReversal=allowFlowReversal_HC2,
    final m_flow_nominal=mHC2_flow_nominal,
    TStart=sum(TStart)/n) if useHeatingCoil2

  parameter Modelica.Units.SI.MassFlowRate m_flow_small_HC1=1E-4*abs(mHC1_flow_nominal) if useHeatingCoil1
    "Small mass flow rate for regularization of zero flow"
  parameter Modelica.Units.SI.MassFlowRate m_flow_small_HC2=1E-4*abs(mHC2_flow_nominal) if useHeatingCoil2
    "Small mass flow rate for regularization of zero flow"
  parameter Modelica.Units.SI.MassFlowRate m_flow_small=1E-4*abs(m1_flow_nominal + m2_flow_nominal)
    "Small mass flow rate for regularization of zero flow"
  parameter Boolean allowFlowReversal_layers=true
    "= false to simplify equations, assuming, but not enforcing, no flow reversal. Used only if model has two ports."
  parameter Boolean allowFlowReversal_HC1=true
    "= false to simplify equations, assuming, but not enforcing, no flow reversal"
  parameter Boolean allowFlowReversal_HC2=true
    "= false to simplify equations, assuming, but not enforcing, no flow reversal"
initial equation
   assert(data.hHC1Up<=data.hTank and data.hHC1Up>=0.0 and
     data.hHC1Low<=data.hTank and data.hHC1Low>=0.0,
     "Storage coil 1 inlet and outlet must be within tank's height.",
     level = AssertionLevel.error);
   assert(data.hHC1Up>data.hHC1Low,
     "Storage coil 1 upper port must be higher than lower port.",
     level = AssertionLevel.error);

   assert(data.hHC2Up<=data.hTank and data.hHC2Up>=0.0 and
     data.hHC2Low<=data.hTank and data.hHC2Low>=0.0,
     "Storage coil 2 inlet and outlet must be within tank's height.",
     level = AssertionLevel.error);
   assert(data.hHC2Up>data.hHC2Low,
     "Storage coil 2 upper port must be higher than lower port.",
     level = AssertionLevel.error);

equation
////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////connection of Heating Coils//////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
 if useHeatingCoil1 then

 for i in nHC1Low:nHC1Up loop

   if upToDownHC1 == true then
     connect(heatingCoil1.Therm1[nHC1Up+1-i], layer[i].heatPort);
   else
     connect(heatingCoil1.Therm1[i-nHC1Low+1], layer[i].heatPort);
 end if;

end for;

connect(portHC1In, heatingCoil1.port_a)
  connect(portHC1Out, heatingCoil1.port_b)

end if;

 if useHeatingCoil2 then

 for i in nHC2Low:nHC2Up loop

   if upToDownHC2 == true then
     connect(heatingCoil2.Therm1[nHC2Up+1-i], layer[i].heatPort);
   else
     connect(heatingCoil2.Therm1[i-nHC2Low+1], layer[i].heatPort);
   end if;
   end for;

  connect(portHC2In, heatingCoil2.port_a)
  connect(portHC2Out, heatingCoil2.port_b)

 end if;

////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////connection of Heating Rod//////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

if useHeatingRod then

connect(heatingRod, layer[nHR].heatPort);
end if;

////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////  connection of Temperature Sensor///////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
  if nTS1 <= 1 then
    TBottom = layer[1].heatPort.T;
  elseif nTS1 >= n then
    TBottom = layer[n].heatPort.T;
  else
    TBottom = layer[nTS1].heatPort.T;
  end if;
  if nTS2 <= 1 then
    TTop = layer[1].heatPort.T;
  elseif nTS2 >= n then
    TTop = layer[n].heatPort.T;
  else
    TTop = layer[nTS2].heatPort.T;
  end if;
////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////connection of volumes and walls//////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
   for i in 1:n loop
     connect(layer[i].heatPort, storageMantle[i].heatportInner);
     connect(storageMantle[i].heatportOuter, heatportOutside);
   end for;
    connect(layer[1].heatPort, bottomCover.heatportInner);
    connect(layer[n].heatPort,topCover.heatportInner);

    connect(bottomCover.heatportOuter, heatportOutside);
    connect(topCover.heatportOuter, heatportOutside);

////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////connections of inner layers//////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
for i in 2:(n-1) loop
    if nLowerPortDemand == i then
       connect(layer[i].ports[4], fluidportBottom2);
       if nUpperPortDemand == i then
         connect(layer[i].ports[6],fluidportTop2);
       end if;
    elseif nUpperPortDemand ==i then
         connect(layer[i].ports[4],fluidportTop2);
    end if;

   connect(layer[i].ports[2],layer[i+1].ports[1]);
  end for;

    for i in 2:(n-1) loop
    if nLowerPortSupply == i then
       connect(layer[i].ports[3], fluidportBottom1);
       if nUpperPortSupply == i then
         connect(layer[i].ports[5],fluidportTop1);
       end if;
    elseif nUpperPortSupply ==i then
         connect(layer[i].ports[3],fluidportTop1);
    end if;

  end for;
////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////connections of upper and lower layer/////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
  if nLowerPortDemand == 1 then
    connect(layer[1].ports[3],fluidportBottom2);
  end if;
  connect(layer[1].ports[1],layer[2].ports[1]);

  if nUpperPortDemand == n then
    connect(layer[n].ports[3],fluidportTop2);
  end if;

  if nLowerPortSupply == 1 then
    connect(layer[1].ports[2],fluidportBottom1);
  end if;
  connect(layer[1].ports[1],layer[2].ports[1]);

  if nUpperPortSupply == n then
    connect(layer[n].ports[2],fluidportTop1);
  end if;
////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////connections of heat transfer model///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
  connect(heatTransfer.therm, layer.heatPort);
end StorageDetailed;


within AixLib.Fluid.Storage;
model StorageSimple
  "Simplified multi-layer storage model with volumes as heat exchangers without pressure losses"

  replaceable package Medium =
     Modelica.Media.Water.ConstantPropertyLiquidWater
     constrainedby Modelica.Media.Interfaces.PartialMedium;

  parameter Integer n(min = 3) "number of layers";
  parameter Modelica.Units.SI.Length d "storage diameter";
  parameter Modelica.Units.SI.Length h "storage height";
  parameter Modelica.Units.SI.ThermalConductivity lambda_ins
    "thermal conductivity of insulation"
  parameter Modelica.Units.SI.Length s_ins "thickness of insulation"
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hConIn "Iinternal heat transfer coefficient"
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hConOut "External heat transfer coefficient"
  parameter Modelica.Units.SI.Volume V_HE "heat exchanger volume"
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer k_HE
    "heat exchanger heat transfer coefficient"
  parameter Modelica.Units.SI.Area A_HE "heat exchanger area"
  parameter Modelica.Units.SI.RelativePressureCoefficient beta = 350e-6
  parameter Real kappa = 0.4

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal_layer
    "Nominal mass flow rate in layers";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal_HE
    "Nominal mass flow rate of heat exchanger layers";

  //Optional temperature outputs
  parameter Boolean use_TOut = true "Use temperature real outputs";

  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state in layers and layers_HE";

  //Initialization parameters
  parameter Modelica.Units.SI.Temperature T_start[n]
    "Start value of temperature of each layer, e.g. for 3 layers: {20, 20, 20}"
  parameter Modelica.Media.Interfaces.Types.AbsolutePressure p_start=Medium.p_default
    "Start value of pressure"

  //Mass flow rates to regulate zero flow
  parameter Modelica.Units.SI.MassFlowRate m_flow_small_layer=1E-4*abs(m_flow_nominal_layer)
    "Small mass flow rate for regularization of zero flow"
   parameter Modelica.Units.SI.MassFlowRate m_flow_small_layer_HE=1E-4*abs(m_flow_nominal_HE)
    "Small mass flow rate for regularization of zero flow"

  Modelica.Fluid.Interfaces.FluidPort_a
                    port_a_consumer(redeclare final package Medium = Medium)
  Modelica.Fluid.Interfaces.FluidPort_b
                    port_b_consumer(redeclare final package Medium = Medium)
  Fluid.MixingVolumes.MixingVolume
                     layer[n](
    each final energyDynamics=energyDynamics,
    each final p_start=p_start,
    T_start=T_start,
    each final m_flow_small=m_flow_small_layer,
    each final V = V / n,
    redeclare final package Medium = Medium,
    each final nPorts=2,
    each final m_flow_nominal=m_flow_nominal_layer)
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort
    "connect to ambient temperature around the storage"
  Modelica.Fluid.Interfaces.FluidPort_b
    port_b_heatGenerator(redeclare final package Medium = Medium)
  Modelica.Fluid.Interfaces.FluidPort_a
    port_a_heatGenerator(redeclare final package Medium = Medium)
  Fluid.MixingVolumes.MixingVolume
    layer_HE[n](
    each final energyDynamics=energyDynamics,
    each final p_start=p_start,
    T_start=T_start,
    each final m_flow_small=m_flow_small_layer_HE,
    each final V = V_HE / n,
    redeclare final package Medium = Medium,
    each final nPorts=2,
    each final m_flow_nominal=m_flow_nominal_HE)

  Modelica.Thermal.HeatTransfer.Components.ThermalConductor heatTransfer_HE[n](each final G = k_HE * A_HE / n)
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor heatTransfer[n](final G = cat(1, {G_top_bottom}, array(G_middle for k in 2:n - 1), {G_top_bottom}))
  BaseClasses.Bouyancy bouyancy[n - 1](
    each final rho=Medium.density(Medium.setState_phX(
        port_a_consumer.p,
        inStream(port_a_consumer.h_outflow),
        inStream(port_a_consumer.Xi_outflow))),
    each final lambda=Medium.thermalConductivity(Medium.setState_phX(
        port_a_consumer.p,
        inStream(port_a_consumer.h_outflow),
        inStream(port_a_consumer.Xi_outflow))),
    each final g=Modelica.Constants.g_n,
    each final cp=Medium.specificHeatCapacityCp(Medium.setState_phX(
        port_a_consumer.p,
        inStream(port_a_consumer.h_outflow),
        inStream(port_a_consumer.Xi_outflow))),
    each final A=A,
    each final beta=beta,
    each final dx=dx,
    each final kappa=kappa)

  Modelica.Blocks.Interfaces.RealOutput TLayer[n](
    each final quantity="ThermodynamicTemperature",
    each final unit="K",
    each min=0,
    each displayUnit="degC") if use_TOut "Temperature in the top layer"
  Modelica.Blocks.Interfaces.RealOutput TLayer_HE[n](
    each final quantity="ThermodynamicTemperature",
    each final unit="K",
    each min=0,
    each displayUnit="degC") if use_TOut "Temperature in the top layer"
protected
  parameter Modelica.Units.SI.Volume V = A * h;
  parameter Modelica.Units.SI.Area A = Modelica.Constants.pi * d ^ 2 / 4;
  parameter Modelica.Units.SI.Length dx = V / A / n;
  parameter Modelica.Units.SI.ThermalConductance G_middle=
  2*Modelica.Constants.pi*h/n/(1/(hConIn*d/2) + 1/lambda_ins*
  log((d/2 + s_ins)/(d/2)) + 1/(hConOut*(d/2 + s_ins)));
  parameter Modelica.Units.SI.ThermalConductance G_top_bottom=
   G_middle + lambda_ins / s_ins * A;

equation
  //Connect layers to the upper and lower ports
  connect(port_a_consumer, layer[1].ports[1])
  connect(layer[n].ports[2], port_b_consumer)

  //Connect layers
  for k in 1:n - 1 loop
    connect(layer[k].ports[2], layer[k + 1].ports[1]);
  end for;
  //Connect Heat Transfer to the Outside
  for k in 1:n loop
    connect(heatTransfer[k].port_a, layer[k].heatPort);
    connect(heatTransfer[k].port_b, heatPort);
  end for;
  //Connect layers of Heat Exchanger
  connect(port_a_heatGenerator, layer_HE[n].ports[2])
  connect(port_b_heatGenerator, layer_HE[1].ports[1])
  for k in 1:n - 1 loop
    connect(layer_HE[k].ports[2], layer_HE[k + 1].ports[1]);
  end for;
  //Connect heat exchanger to storage layers
  for k in 1:n loop
    connect(heatTransfer_HE[k].port_a, layer[k].heatPort);
    connect(heatTransfer_HE[k].port_b, layer_HE[k].heatPort);
  end for;
  //Connect bouyancy element
  for k in 1:n - 1 loop
    connect(bouyancy[k].port_a, layer[k + 1].heatPort);
    connect(bouyancy[k].port_b, layer[k].heatPort);
  end for;
  connect(heatPort, heatPort)

///////////////////////////////////////////////////////////////////////////////
///////////////////  connection of Temperature Sensor//////////////////////////
///////////////////////////////////////////////////////////////////////////////

  if use_TOut then
    for k in 1:n loop

      TLayer[k] = layer[k].heatPort.T;

      TLayer_HE[k] = layer_HE[k].heatPort.T;

    end for;
  end if;
end StorageSimple;