Medium models for water

within Modelica.Media;
package Water "Medium models for water"

extends Modelica.Icons.VariantsPackage;

import Modelica.Media.Water.ConstantPropertyLiquidWater.simpleWaterConstants;

constant Modelica.Media.Interfaces.Types.TwoPhase.FluidConstants[1]
  waterConstants(
  each chemicalFormula="H2O",
  each structureFormula="H2O",
  each casRegistryNumber="7732-18-5",
  each iupacName="oxidane",
  each molarMass=0.018015268,
  each criticalTemperature=647.096,
  each criticalPressure=22064.0e3,
  each criticalMolarVolume=1/322.0*0.018015268,
  each normalBoilingPoint=373.124,
  each meltingPoint=273.15,
  each triplePointTemperature=273.16,
  each triplePointPressure=611.657,
  each acentricFactor=0.344,
  each dipoleMoment=1.8,
  each hasCriticalData=true);

package IdealSteam "Water: Steam as ideal gas from NASA source"

  extends IdealGases.SingleGases.H2O;
end IdealSteam;

package ConstantPropertyLiquidWater
  "Water: Simple liquid water medium (incompressible, constant data)"

  //   redeclare record extends FluidConstants
  //   end FluidConstants;

  constant Modelica.Media.Interfaces.Types.Basic.FluidConstants[1]
    simpleWaterConstants(
    each chemicalFormula="H2O",
    each structureFormula="H2O",
    each casRegistryNumber="7732-18-5",
    each iupacName="oxidane",
    each molarMass=0.018015268);

  extends Interfaces.PartialSimpleMedium(
    mediumName="SimpleLiquidWater",
    cp_const=4184,
    cv_const=4184,
    d_const=995.586,
    eta_const=1.e-3,
    lambda_const=0.598,
    a_const=1484,
    T_min=Cv.from_degC(-1),
    T_max=Cv.from_degC(130),
    T0=273.15,
    MM_const=0.018015268,
    fluidConstants=simpleWaterConstants);
end ConstantPropertyLiquidWater;

package StandardWater = WaterIF97_ph
  "Water using the IF97 standard, explicit in p and h. Recommended for most applications";

package StandardWaterOnePhase = WaterIF97_pT
  "Water using the IF97 standard, explicit in p and T. Recommended for one-phase applications";

package WaterIF97OnePhase_ph
  "Water using the IF97 standard, explicit in p and h, and only valid outside the two-phase dome"
  extends WaterIF97_base(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    final smoothModel=true,
    final onePhase=true);
end WaterIF97OnePhase_ph;

package WaterIF97_pT "Water using the IF97 standard, explicit in p and T"
  extends WaterIF97_base(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.pT,
    final ph_explicit=false,
    final dT_explicit=false,
    final pT_explicit=true,
    final smoothModel=true,
    final onePhase=true);
end WaterIF97_pT;

package WaterIF97_ph "Water using the IF97 standard, explicit in p and h"
  extends WaterIF97_base(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    smoothModel=false,
    onePhase=false);
end WaterIF97_ph;

partial package WaterIF97_base
  "Water: Steam properties as defined by IAPWS/IF97 standard"

  extends Interfaces.PartialTwoPhaseMedium(
    mediumName="WaterIF97",
    substanceNames={"water"},
    singleState=false,
    SpecificEnthalpy(start=1.0e5, nominal=5.0e5),
    Density(start=150, nominal=500),
    AbsolutePressure(
      start=50e5,
      nominal=10e5,
      min=611.657,
      max=100e6),
    Temperature(
      start=500,
      nominal=500,
      min=273.15,
      max=2273.15),
    smoothModel=false,
    onePhase=false,
    fluidConstants=waterConstants);

  redeclare record extends SaturationProperties
  end SaturationProperties;

  redeclare record extends ThermodynamicState "Thermodynamic state"
    SpecificEnthalpy h "Specific enthalpy";
    Density d "Density";
    Temperature T "Temperature";
    AbsolutePressure p "Pressure";
  end ThermodynamicState;

  constant Integer Region = 0 "Region of IF97, if known, zero otherwise";
  constant Boolean ph_explicit
    "True if explicit in pressure and specific enthalpy";
  constant Boolean dT_explicit "True if explicit in density and temperature";
  constant Boolean pT_explicit "True if explicit in pressure and temperature";

  redeclare replaceable model extends BaseProperties(
    h(stateSelect=if ph_explicit and preferredMediumStates then StateSelect.prefer
           else StateSelect.default),
    d(stateSelect=if dT_explicit and preferredMediumStates then StateSelect.prefer
           else StateSelect.default),
    T(stateSelect=if (pT_explicit or dT_explicit) and preferredMediumStates
           then StateSelect.prefer else StateSelect.default),
    p(stateSelect=if (pT_explicit or ph_explicit) and preferredMediumStates
           then StateSelect.prefer else StateSelect.default))
    "Base properties of water"
    Integer phase(
      min=0,
      max=2,
      start=1,
      fixed=false) "2 for two-phase, 1 for one-phase, 0 if not known";
  equation
    MM = fluidConstants[1].molarMass;
    if Region > 0 then // Fixed region
      phase = (if Region == 4 then 2 else 1);
    elseif smoothModel then
      if onePhase then
        phase = 1;
        if ph_explicit then
          assert(((h < bubbleEnthalpy(sat) or h > dewEnthalpy(sat)) or p >
            fluidConstants[1].criticalPressure),
            "With onePhase=true this model may only be called with one-phase states h < hl or h > hv!"
             + "(p = " + String(p) + ", h = " + String(h) + ")");
        else
          if dT_explicit then
            assert(not ((d < bubbleDensity(sat) and d > dewDensity(sat)) and T
               < fluidConstants[1].criticalTemperature),
              "With onePhase=true this model may only be called with one-phase states d > dl or d < dv!"
               + "(d = " + String(d) + ", T = " + String(T) + ")");
          end if;
        end if;
      else
        phase = 0;
      end if;
    else
      if ph_explicit then
        phase = if ((h < bubbleEnthalpy(sat) or h > dewEnthalpy(sat)) or p >
          fluidConstants[1].criticalPressure) then 1 else 2;
      elseif dT_explicit then
        phase = if not ((d < bubbleDensity(sat) and d > dewDensity(sat)) and T
           < fluidConstants[1].criticalTemperature) then 1 else 2;
      else
        phase = 1;
        //this is for the one-phase only case pT
      end if;
    end if;
    if dT_explicit then
      p = pressure_dT(
            d,
            T,
            phase,
            Region);
      h = specificEnthalpy_dT(
            d,
            T,
            phase,
            Region);
      sat.Tsat = T;
      sat.psat = saturationPressure(T);
    elseif ph_explicit then
      d = density_ph(
            p,
            h,
            phase,
            Region);
      T = temperature_ph(
            p,
            h,
            phase,
            Region);
      sat.Tsat = saturationTemperature(p);
      sat.psat = p;
    else
      h = specificEnthalpy_pT(
            p,
            T,
            Region);
      d = density_pT(
            p,
            T,
            Region);
      sat.psat = p;
      sat.Tsat = saturationTemperature(p);
    end if;
    u = h - p/d;
    R_s = Modelica.Constants.R/fluidConstants[1].molarMass;
    h = state.h;
    p = state.p;
    T = state.T;
    d = state.d;
    phase = state.phase;
  end BaseProperties;

  redeclare function density_ph
    "Computes density as a function of pressure and specific enthalpy"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input SpecificEnthalpy h "Specific enthalpy";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output Density d "Density";
  algorithm
    d := IF97_Utilities.rho_ph(
          p,
          h,
          phase,
          region);
  end density_ph;

  redeclare function temperature_ph
    "Computes temperature as a function of pressure and specific enthalpy"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input SpecificEnthalpy h "Specific enthalpy";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output Temperature T "Temperature";
  algorithm
    T := IF97_Utilities.T_ph(
          p,
          h,
          phase,
          region);
  end temperature_ph;

  redeclare function temperature_ps
    "Compute temperature from pressure and specific enthalpy"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input SpecificEntropy s "Specific entropy";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output Temperature T "Temperature";
  algorithm
    T := IF97_Utilities.T_ps(
          p,
          s,
          phase,
          region);
  end temperature_ps;

  redeclare function density_ps
    "Computes density as a function of pressure and specific enthalpy"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input SpecificEntropy s "Specific entropy";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output Density d "Density";
  algorithm
    d := IF97_Utilities.rho_ps(
          p,
          s,
          phase,
          region);
  end density_ps;

  redeclare function pressure_dT
    "Computes pressure as a function of density and temperature"
    extends Modelica.Icons.Function;
    input Density d "Density";
    input Temperature T "Temperature";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output AbsolutePressure p "Pressure";
  algorithm
    p := IF97_Utilities.p_dT(
          d,
          T,
          phase,
          region);
  end pressure_dT;

  redeclare function specificEnthalpy_dT
    "Computes specific enthalpy as a function of density and temperature"
    extends Modelica.Icons.Function;
    input Density d "Density";
    input Temperature T "Temperature";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output SpecificEnthalpy h "Specific enthalpy";
  algorithm
    h := IF97_Utilities.h_dT(
          d,
          T,
          phase,
          region);
  end specificEnthalpy_dT;

  redeclare function specificEnthalpy_pT
    "Computes specific enthalpy as a function of pressure and temperature"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input Temperature T "Temperature";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output SpecificEnthalpy h "Specific enthalpy";
  algorithm
    h := IF97_Utilities.h_pT(
          p,
          T,
          region);
  end specificEnthalpy_pT;

  redeclare function specificEnthalpy_ps
    "Computes specific enthalpy as a function of pressure and temperature"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input SpecificEntropy s "Specific entropy";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output SpecificEnthalpy h "Specific enthalpy";
  algorithm
    h := IF97_Utilities.h_ps(
          p,
          s,
          phase,
          region);
  end specificEnthalpy_ps;

  redeclare function density_pT
    "Computes density as a function of pressure and temperature"
    extends Modelica.Icons.Function;
    input AbsolutePressure p "Pressure";
    input Temperature T "Temperature";
    input FixedPhase phase=0 "2 for two-phase, 1 for one-phase, 0 if not known";
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
    output Density d "Density";
  algorithm
    d := IF97_Utilities.rho_pT(
          p,
          T,
          region);
  end density_pT;

  redeclare function extends setDewState
    "Set the thermodynamic state on the dew line"
  algorithm
    state := ThermodynamicState(
          phase=phase,
          p=sat.psat,
          T=sat.Tsat,
          h=dewEnthalpy(sat),
          d=dewDensity(sat));
  end setDewState;

  redeclare function extends setBubbleState
    "Set the thermodynamic state on the bubble line"
  algorithm
    state := ThermodynamicState(
          phase=phase,
          p=sat.psat,
          T=sat.Tsat,
          h=bubbleEnthalpy(sat),
          d=bubbleDensity(sat));
  end setBubbleState;

  redeclare function extends dynamicViscosity "Dynamic viscosity of water"
  algorithm
    eta := IF97_Utilities.dynamicViscosity(
          state.d,
          state.T,
          state.p,
          state.phase);
  end dynamicViscosity;

  redeclare function extends thermalConductivity
    "Thermal conductivity of water"
  algorithm
    lambda := IF97_Utilities.thermalConductivity(
          state.d,
          state.T,
          state.p,
          state.phase);
  end thermalConductivity;

  redeclare function extends surfaceTension
    "Surface tension in two phase region of water"
  algorithm
    sigma := IF97_Utilities.surfaceTension(sat.Tsat);
  end surfaceTension;

  redeclare function extends pressure "Return pressure of ideal gas"
  algorithm
    p := state.p;
  end pressure;

  redeclare function extends temperature "Return temperature of ideal gas"
  algorithm
    T := state.T;
  end temperature;

  redeclare function extends density "Return density of ideal gas"
  algorithm
    d := state.d;
  end density;

  redeclare function extends specificEnthalpy "Return specific enthalpy"
    extends Modelica.Icons.Function;
  algorithm
    h := state.h;
  end specificEnthalpy;

  redeclare function extends specificInternalEnergy
    "Return specific internal energy"
    extends Modelica.Icons.Function;
  algorithm
    u := state.h - state.p/state.d;
  end specificInternalEnergy;

  redeclare function extends specificGibbsEnergy "Return specific Gibbs energy"
    extends Modelica.Icons.Function;
  algorithm
    g := state.h - state.T*specificEntropy(state);
  end specificGibbsEnergy;

  redeclare function extends specificHelmholtzEnergy
    "Return specific Helmholtz energy"
    extends Modelica.Icons.Function;
  algorithm
    f := state.h - state.p/state.d - state.T*specificEntropy(state);
  end specificHelmholtzEnergy;

  redeclare function extends specificEntropy "Specific entropy of water"
  algorithm
    s := if dT_explicit then IF97_Utilities.s_dT(
          state.d,
          state.T,
          state.phase,
          Region) else if pT_explicit then IF97_Utilities.s_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.s_ph(
          state.p,
          state.h,
          state.phase,
          Region);
  end specificEntropy;

  redeclare function extends specificHeatCapacityCp
    "Specific heat capacity at constant pressure of water"
  algorithm
    cp := if dT_explicit then IF97_Utilities.cp_dT(
          state.d,
          state.T,
          Region) else if pT_explicit then IF97_Utilities.cp_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.cp_ph(
          state.p,
          state.h,
          Region);
  end specificHeatCapacityCp;

  redeclare function extends specificHeatCapacityCv
    "Specific heat capacity at constant volume of water"
  algorithm
    cv := if dT_explicit then IF97_Utilities.cv_dT(
          state.d,
          state.T,
          state.phase,
          Region) else if pT_explicit then IF97_Utilities.cv_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.cv_ph(
          state.p,
          state.h,
          state.phase,
          Region);
  end specificHeatCapacityCv;

  redeclare function extends isentropicExponent "Return isentropic exponent"
  algorithm
    gamma := if dT_explicit then IF97_Utilities.isentropicExponent_dT(
          state.d,
          state.T,
          state.phase,
          Region) else if pT_explicit then IF97_Utilities.isentropicExponent_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.isentropicExponent_ph(
          state.p,
          state.h,
          state.phase,
          Region);
  end isentropicExponent;

  redeclare function extends isothermalCompressibility
    "Isothermal compressibility of water"
  algorithm
    //    assert(state.phase <> 2, "Isothermal compressibility can not be computed with 2-phase inputs!");
    kappa := if dT_explicit then IF97_Utilities.kappa_dT(
          state.d,
          state.T,
          state.phase,
          Region) else if pT_explicit then IF97_Utilities.kappa_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.kappa_ph(
          state.p,
          state.h,
          state.phase,
          Region);
  end isothermalCompressibility;

  redeclare function extends isobaricExpansionCoefficient
    "Isobaric expansion coefficient of water"
  algorithm
    //    assert(state.phase <> 2, "The isobaric expansion coefficient can not be computed with 2-phase inputs!");
    beta := if dT_explicit then IF97_Utilities.beta_dT(
          state.d,
          state.T,
          state.phase,
          Region) else if pT_explicit then IF97_Utilities.beta_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.beta_ph(
          state.p,
          state.h,
          state.phase,
          Region);
  end isobaricExpansionCoefficient;

  redeclare function extends velocityOfSound
    "Return velocity of sound as a function of the thermodynamic state record"
  algorithm
    a := if dT_explicit then IF97_Utilities.velocityOfSound_dT(
          state.d,
          state.T,
          state.phase,
          Region) else if pT_explicit then IF97_Utilities.velocityOfSound_pT(
          state.p,
          state.T,
          Region) else IF97_Utilities.velocityOfSound_ph(
          state.p,
          state.h,
          state.phase,
          Region);
  end velocityOfSound;

  redeclare function extends isentropicEnthalpy "Compute h(s,p)"
  algorithm
    h_is := IF97_Utilities.isentropicEnthalpy(
          p_downstream,
          specificEntropy(refState),
          0);
  end isentropicEnthalpy;

  redeclare function extends density_derh_p
    "Density derivative by specific enthalpy"
  algorithm
    ddhp := IF97_Utilities.ddhp(
          state.p,
          state.h,
          state.phase,
          Region);
  end density_derh_p;

  redeclare function extends density_derp_h "Density derivative by pressure"
  algorithm
    ddph := IF97_Utilities.ddph(
          state.p,
          state.h,
          state.phase,
          Region);
  end density_derp_h;

  //   redeclare function extends density_derT_p
  //     "Density derivative by temperature"
  //   algorithm
  //     ddTp := IF97_Utilities.ddTp(state.p, state.h, state.phase);
  //   end density_derT_p;
  //
  //   redeclare function extends density_derp_T
  //     "Density derivative by pressure"
  //   algorithm
  //     ddpT := IF97_Utilities.ddpT(state.p, state.h, state.phase);
  //   end density_derp_T;

  redeclare function extends bubbleEnthalpy
    "Boiling curve specific enthalpy of water"
  algorithm
    hl := IF97_Utilities.BaseIF97.Regions.hl_p(sat.psat);
  end bubbleEnthalpy;

  redeclare function extends dewEnthalpy "Dew curve specific enthalpy of water"
  algorithm
    hv := IF97_Utilities.BaseIF97.Regions.hv_p(sat.psat);
  end dewEnthalpy;

  redeclare function extends bubbleEntropy
    "Boiling curve specific entropy of water"
  algorithm
    sl := IF97_Utilities.BaseIF97.Regions.sl_p(sat.psat);
  end bubbleEntropy;

  redeclare function extends dewEntropy "Dew curve specific entropy of water"
  algorithm
    sv := IF97_Utilities.BaseIF97.Regions.sv_p(sat.psat);
  end dewEntropy;

  redeclare function extends bubbleDensity
    "Boiling curve specific density of water"
  algorithm
    dl := if ph_explicit or pT_explicit then
      IF97_Utilities.BaseIF97.Regions.rhol_p(sat.psat) else
      IF97_Utilities.BaseIF97.Regions.rhol_T(sat.Tsat);
  end bubbleDensity;

  redeclare function extends dewDensity "Dew curve specific density of water"
  algorithm
    dv := if ph_explicit or pT_explicit then
      IF97_Utilities.BaseIF97.Regions.rhov_p(sat.psat) else
      IF97_Utilities.BaseIF97.Regions.rhov_T(sat.Tsat);
  end dewDensity;

  redeclare function extends saturationTemperature
    "Saturation temperature of water"
  algorithm
    T := IF97_Utilities.BaseIF97.Basic.tsat(p);
  end saturationTemperature;

  redeclare function extends saturationTemperature_derp
    "Derivative of saturation temperature w.r.t. pressure"
  algorithm
    dTp := IF97_Utilities.BaseIF97.Basic.dtsatofp(p);
  end saturationTemperature_derp;

  redeclare function extends saturationPressure "Saturation pressure of water"
  algorithm
    p := IF97_Utilities.BaseIF97.Basic.psat(T);
  end saturationPressure;

  redeclare function extends dBubbleDensity_dPressure
    "Bubble point density derivative"
  algorithm
    ddldp := IF97_Utilities.BaseIF97.Regions.drhol_dp(sat.psat);
  end dBubbleDensity_dPressure;

  redeclare function extends dDewDensity_dPressure
    "Dew point density derivative"
  algorithm
    ddvdp := IF97_Utilities.BaseIF97.Regions.drhov_dp(sat.psat);
  end dDewDensity_dPressure;

  redeclare function extends dBubbleEnthalpy_dPressure
    "Bubble point specific enthalpy derivative"
  algorithm
    dhldp := IF97_Utilities.BaseIF97.Regions.dhl_dp(sat.psat);
  end dBubbleEnthalpy_dPressure;

  redeclare function extends dDewEnthalpy_dPressure
    "Dew point specific enthalpy derivative"
  algorithm
    dhvdp := IF97_Utilities.BaseIF97.Regions.dhv_dp(sat.psat);
  end dDewEnthalpy_dPressure;

  redeclare function extends setState_dTX
    "Return thermodynamic state of water as function of d, T, and optional region"
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
  algorithm
    state := ThermodynamicState(
          d=d,
          T=T,
          phase=if region == 0 then 0 else if
        region == 4 then 2 else 1,
          h=specificEnthalpy_dT(
            d,
            T,
            region=region),
          p=pressure_dT(
            d,
            T,
            region=region));
  end setState_dTX;

  redeclare function extends setState_phX
    "Return thermodynamic state of water as function of p, h, and optional region"
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
  algorithm
    state := ThermodynamicState(
          d=density_ph(
            p,
            h,
            region=region),
          T=temperature_ph(
            p,
            h,
            region=region),
          phase=if region == 0 then 0 else if region==4 then 2 else 1,
          h=h,
          p=p);
  end setState_phX;

  redeclare function extends setState_psX
    "Return thermodynamic state of water as function of p, s, and optional region"
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
  algorithm
    state := ThermodynamicState(
          d=density_ps(
            p,
            s,
            region=region),
          T=temperature_ps(
            p,
            s,
            region=region),
          phase=if region == 0 then 0 else if region==4 then 2 else 1,
          h=specificEnthalpy_ps(
            p,
            s,
            region=region),
          p=p);
  end setState_psX;

  redeclare function extends setState_pTX
    "Return thermodynamic state of water as function of p, T, and optional region"
    input Integer region=Region
      "If 0, region is unknown, otherwise known and this input";
  algorithm
    state := ThermodynamicState(
          d=density_pT(
            p,
            T,
            region=region),
          T=T,
          phase=1,
          h=specificEnthalpy_pT(
            p,
            T,
            region=region),
          p=p);
  end setState_pTX;

  redeclare function extends setSmoothState
    "Return thermodynamic state so that it smoothly approximates: if x > 0 then state_a else state_b"
    import Modelica.Media.Common.smoothStep;
  algorithm
    state := ThermodynamicState(
          p=smoothStep(
            x,
            state_a.p,
            state_b.p,
            x_small),
          h=smoothStep(
            x,
            state_a.h,
            state_b.h,
            x_small),
          d=density_ph(smoothStep(
            x,
            state_a.p,
            state_b.p,
            x_small), smoothStep(
            x,
            state_a.h,
            state_b.h,
            x_small)),
          T=temperature_ph(smoothStep(
            x,
            state_a.p,
            state_b.p,
            x_small), smoothStep(
            x,
            state_a.h,
            state_b.h,
            x_small)),
          phase=0);
  end setSmoothState;
end WaterIF97_base;

partial package WaterIF97_fixedregion
  "Water: Steam properties as defined by IAPWS/IF97 standard, fixed region"
  extends WaterIF97_base(Region(min=1)=1);
end WaterIF97_fixedregion;

package WaterIF97_R4ph "Region 4 water according to IF97 standard"
  extends WaterIF97_fixedregion(
    final Region=4,
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    smoothModel=true,
    onePhase=false);
end WaterIF97_R4ph;

package WaterIF97_R5ph "Region 5 water according to IF97 standard"
  extends WaterIF97_fixedregion(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final Region=5,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    smoothModel=true,
    onePhase=true);
end WaterIF97_R5ph;

package WaterIF97_R1pT "Region 1 (liquid) water according to IF97 standard"
  extends WaterIF97_fixedregion(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.pT,
    final Region=1,
    final ph_explicit=false,
    final dT_explicit=false,
    final pT_explicit=true,
    smoothModel=true,
    onePhase=true);
end WaterIF97_R1pT;

package WaterIF97_R2pT "Region 2 (steam) water according to IF97 standard"
  extends WaterIF97_fixedregion(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.pT,
    final Region=2,
    final ph_explicit=false,
    final dT_explicit=false,
    final pT_explicit=true,
    smoothModel=true,
    onePhase=true);
end WaterIF97_R2pT;

package WaterIF97_R1ph "Region 1 (liquid) water according to IF97 standard"
  extends WaterIF97_fixedregion(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final Region=1,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    smoothModel=true,
    onePhase=true);
end WaterIF97_R1ph;

package WaterIF97_R2ph "Region 2 (steam) water according to IF97 standard"
  extends WaterIF97_fixedregion(
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final Region=2,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    smoothModel=true,
    onePhase=true);
end WaterIF97_R2ph;

package WaterIF97_R3ph "Region 3 water according to IF97 standard"
  extends WaterIF97_fixedregion(
    final Region=3,
    ThermoStates=Modelica.Media.Interfaces.Choices.IndependentVariables.ph,
    final ph_explicit=true,
    final dT_explicit=false,
    final pT_explicit=false,
    smoothModel=true,
    onePhase=true);
end WaterIF97_R3ph;
end Water;


within Modelica;
package Thermal "Library of thermal system components to model heat transfer and simple thermo-fluid pipe flow"
  extends Modelica.Icons.Package;
  import Modelica.Units.SI;
end Thermal;


within Modelica.Thermal;
package FluidHeatFlow "Simple components for 1-dimensional incompressible thermo-fluid flow models"
  extends Modelica.Icons.Package;
end FluidHeatFlow;


Base classes of FluidHeatFlow models

within Modelica.Thermal.FluidHeatFlow;
package BaseClasses "Base classes of FluidHeatFlow models"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Simple friction model. Definition of relationship between pressure drop and volume flow rate:

within Modelica.Thermal.FluidHeatFlow.BaseClasses;
partial model SimpleFriction "Simple friction model"
  parameter SI.VolumeFlowRate V_flowLaminar(min=Modelica.Constants.small, start=0.1)
    "Laminar volume flow"
  parameter SI.Pressure dpLaminar(start=0.1)
    "Laminar pressure drop"
  parameter SI.VolumeFlowRate V_flowNominal(start=1)
    "Nominal volume flow"
  parameter SI.Pressure dpNominal(start=1)
    "Nominal pressure drop"
  parameter Real frictionLoss(min=0, max=1) = 0
    "Part of friction losses fed to medium"
  SI.Pressure pressureDrop;
  SI.VolumeFlowRate volumeFlow;
  SI.Power Q_friction;
protected
  parameter SI.Pressure dpNomMin=dpLaminar/V_flowLaminar*V_flowNominal;
  parameter Real k(final unit="Pa.s2/m6", fixed=false);
initial algorithm
  assert(V_flowNominal>V_flowLaminar,
    "SimpleFriction: V_flowNominal has to be > V_flowLaminar!");
  assert(dpNominal>=dpNomMin,
    "SimpleFriction: dpNominal has to be > dpLaminar/V_flowLaminar*V_flowNominal!");
  k:=(dpNominal - dpNomMin)/(V_flowNominal - V_flowLaminar)^2;
equation
  if volumeFlow > +V_flowLaminar then
    pressureDrop = +dpLaminar/V_flowLaminar*volumeFlow + k*(volumeFlow - V_flowLaminar)^2;
  elseif volumeFlow < -V_flowLaminar then
    pressureDrop = +dpLaminar/V_flowLaminar*volumeFlow - k*(volumeFlow + V_flowLaminar)^2;
  else
    pressureDrop =  dpLaminar/V_flowLaminar*volumeFlow;
  end if;
  Q_friction = frictionLoss*volumeFlow*pressureDrop;
end SimpleFriction;


Partial model of a single port at the bottom. Partial model of single port at the bottom, defining the medium and the temperature at the port.

within Modelica.Thermal.FluidHeatFlow.BaseClasses;
partial model SinglePortBottom "Partial model of a single port at the bottom"
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Medium"
  parameter SI.Temperature T0(start=293.15, displayUnit="degC")
    "Initial temperature of medium";
  parameter Boolean T0fixed=false
    "Initial temperature guess value or fixed"
  output SI.Temperature T_port "Temperature at flowPort_a";
  output SI.Temperature T(start=T0, fixed=T0fixed) "Outlet temperature of medium";
  FluidHeatFlow.Interfaces.FlowPort_a flowPort(final medium=medium)
protected
  constant Boolean Exchange=true "Exchange of medium via flowport"
  SI.SpecificEnthalpy h "Specific enthalpy in the volume";
equation
  T_port=flowPort.h/medium.cp;
  T=h/medium.cp;
  // mass flow -> ambient: mixing rule
  // mass flow <- ambient: energy flow defined by ambient's temperature
  if Exchange then
    flowPort.H_flow = semiLinear(flowPort.m_flow,flowPort.h,h);
  else
    h=flowPort.h;
  end if;
end SinglePortBottom;


Partial model of a single port at the left. Partial model of single port at the left, defining the medium and the temperature at the port.

within Modelica.Thermal.FluidHeatFlow.BaseClasses;
partial model SinglePortLeft "Partial model of a single port at the left"
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Medium"
  parameter SI.Temperature T0(start=293.15, displayUnit="degC")
    "Initial temperature of medium";
  parameter Boolean T0fixed=false
    "Initial temperature guess value or fixed"
  output SI.Temperature T_port "Temperature at flowPort_a";
  output SI.Temperature T(start=T0, fixed=T0fixed) "Outlet temperature of medium";
  Interfaces.FlowPort_a flowPort(final medium=medium)
protected
  constant Boolean Exchange=true "Exchange of medium via flowport"
  SI.SpecificEnthalpy h "Specific enthalpy in the volume";
equation
  T_port=flowPort.h/medium.cp;
  T=h/medium.cp;
  // mass flow -> ambient: mixing rule
  // mass flow <- ambient: energy flow defined by ambient's temperature
  if Exchange then
    flowPort.H_flow = semiLinear(flowPort.m_flow,flowPort.h,h);
  else
    h=flowPort.h;
  end if;
end SinglePortLeft;


Partial model of two port. Partial model with two flowPorts.

within Modelica.Thermal.FluidHeatFlow.BaseClasses;
partial model TwoPort "Partial model of two port"
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Medium in the component"
  parameter SI.Mass m(start=1) "Mass of medium";
  parameter SI.Temperature T0(start=293.15, displayUnit="degC")
    "Initial temperature of medium"
  parameter Boolean T0fixed=false
    "Initial temperature guess value or fixed"
  parameter Real tapT(final min=0, final max=1)=1
    "Defines temperature of heatPort between inlet and outlet temperature";
  SI.Pressure dp "Pressure drop a->b";
  SI.VolumeFlowRate V_flow(start=0) "Volume flow a->b";
  SI.HeatFlowRate Q_flow "Heat exchange with ambient";
  output SI.Temperature T(start=T0, fixed=T0fixed)
    "Outlet temperature of medium";
  output SI.Temperature T_a "Temperature at flowPort_a";
  output SI.Temperature T_b "Temperature at flowPort_b";
  output SI.TemperatureDifference dT
    "Temperature increase of coolant in flow direction";
  SI.Temperature T_q
    "Temperature relevant for heat exchange with ambient";
protected
  SI.SpecificEnthalpy h(start=medium.cp*T0) "Medium's specific enthalpy";
public
  FluidHeatFlow.Interfaces.FlowPort_a flowPort_a(final medium=medium)
  FluidHeatFlow.Interfaces.FlowPort_b flowPort_b(final medium=medium)
equation
  dp=flowPort_a.p - flowPort_b.p;
  V_flow=flowPort_a.m_flow/medium.rho;
  T_a=flowPort_a.h/medium.cp;
  T_b=flowPort_b.h/medium.cp;
  dT=if noEvent(V_flow>=0) then T-T_a else T_b-T;
  h = medium.cp*T;
  T_q = T  - noEvent(sign(V_flow))*(1 - tapT)*dT;
  // mass balance
  flowPort_a.m_flow + flowPort_b.m_flow = 0;
  // energy balance
  if m>Modelica.Constants.small then
    flowPort_a.H_flow + flowPort_b.H_flow + Q_flow = m*medium.cv*der(T);
  else
    flowPort_a.H_flow + flowPort_b.H_flow + Q_flow = 0;
  end if;
  // mass flow a->b mixing rule at a, energy flow at b defined by medium's temperature
  // mass flow b->a mixing rule at b, energy flow at a defined by medium's temperature
  flowPort_a.H_flow = semiLinear(flowPort_a.m_flow,flowPort_a.h,h);
  flowPort_b.H_flow = semiLinear(flowPort_b.m_flow,flowPort_b.h,h);
end TwoPort;


Simple model of a piston in a cylinder. This is a simple model of a piston in a cylinder:

within Modelica.Thermal.FluidHeatFlow.Components;
model Cylinder "Simple model of a piston in a cylinder"
  import Modelica.Constants.small;
  extends FluidHeatFlow.BaseClasses.SinglePortLeft(final Exchange=true);

  parameter SI.Area A "Cross section of cylinder/piston";
  parameter SI.Length L "Length of cylinder";
  extends
    Modelica.Mechanics.Translational.Interfaces.PartialElementaryOneFlangeAndSupport2
    (s(start=small));
  SI.Force f=flange.f "Force at piston";
protected
  SI.Mass m "Mass of medium";
  SI.Enthalpy H "Enthalpy of medium";
equation
  assert(s>=small, getInstanceName()+": Piston hit bottom of cylinder!");
  assert(s<=L, getInstanceName()+":Piston hit top of cylinder!");
  flowPort.p*A = -f;
  m = medium.rho*A*s;
  der(m) = flowPort.m_flow;
  H = m*h;
  der(H)=flowPort.H_flow;
end Cylinder;


Simple one-way valve. Simple one-way valve, comparable to the electrical ideal diode model.

within Modelica.Thermal.FluidHeatFlow.Components;
model OneWayValve "Simple one-way valve"
  extends FluidHeatFlow.BaseClasses.TwoPort(m(start=0), final tapT=1);

  parameter SI.VolumeFlowRate V_flowNominal(start=1) "Nominal volume flow rate (forward)";
  parameter SI.Pressure dpForward(displayUnit="bar")=1e-6 "Pressure drop at nominal flow (forward)";
  parameter SI.Pressure dpNominal(displayUnit="bar", start=1e5) "Nominal pressure (backward)";
  parameter SI.VolumeFlowRate V_flowBackward(start=1E-6) "Leakage volume flow rate (backward)";
  parameter Real frictionLoss(min=0, max=1, start=0)
    "Part of friction losses fed to medium";
  Boolean backward(start=true) "State forward=false / backward=true";
protected
  Real s(start=0, final unit="1")
    "Auxiliary variable for actual position on the valve characteristic";
  /* s < 0: backward, leakage flow
         s > 0: forward, small pressure drop */
  constant SI.VolumeFlowRate unitVolumeFlowRate = 1;
  constant SI.Pressure unitPressureDrop = 1;
equation
  backward = s<0;
  dp     = (s*unitVolumeFlowRate)*(if backward then 1 else dpForward/V_flowNominal);
  V_flow = (s*unitPressureDrop)  *(if backward then V_flowBackward/dpNominal else 1);
  Q_flow = frictionLoss*V_flow*dp;
end OneWayValve;


Model of a tank under ambient pressure. This is a simple model of an open tank with volume A*h. The level and the temperature of the medium are measured and provided as output.

within Modelica.Thermal.FluidHeatFlow.Components;
model OpenTank "Model of a tank under ambient pressure"
  extends FluidHeatFlow.BaseClasses.SinglePortBottom(final Exchange=true);

  parameter SI.Area ATank(start=1) "Cross section of tank";
  parameter SI.Length hTank(start=1) "Height of tank";
  parameter SI.Pressure pAmbient(start=0) "Ambient pressure";
  parameter SI.Acceleration g(final min=0)=Modelica.Constants.g_n "Gravitation";
  parameter Boolean useHeatPort = false "= true, if HeatPort is enabled"
  SI.Mass m "Mass of medium in tank";
protected
  SI.Enthalpy H "Enthalpy of medium";
  SI.HeatFlowRate Q_flow "Heat flow at the optional heatPort";
public
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort(final T=T, final Q_flow=Q_flow) if useHeatPort
    "Optional port for cooling or heating the medium in the tank"
  Modelica.Blocks.Interfaces.RealOutput level(quantity="Length", unit="m", start=0)
    "Level of medium in tank"
  Modelica.Blocks.Interfaces.RealOutput TTank(quantity="Temperature", unit="K", displayUnit="degC")
    "Temperature of medium in tank"
equation
  //output medium temperature
  TTank = T;
  //optional heating/cooling
  if not useHeatPort then
    Q_flow = 0;
  end if;
  //check level
  assert(level>=0, "Tank got empty!");
  assert(level<=hTank, "Tank got full!");
  //mass balance
  m = medium.rho*ATank*level;
  der(m) = flowPort.m_flow;
  //energy balance
  H = m*h;
  der(H) = flowPort.H_flow + Q_flow;
  //pressure at bottom
  flowPort.p = pAmbient + m*g/ATank;
end OpenTank;


Basic components (pipes, valves)

within Modelica.Thermal.FluidHeatFlow;
package Components "Basic components (pipes, valves)"
  extends Modelica.Icons.Package;
end Components;


Pipe with optional heat exchange. Pipe with optional heat exchange.

within Modelica.Thermal.FluidHeatFlow.Components;
model Pipe "Pipe with optional heat exchange"
  extends FluidHeatFlow.BaseClasses.TwoPort;
  extends FluidHeatFlow.BaseClasses.SimpleFriction;

  parameter Boolean useHeatPort = false "= true, if HeatPort is enabled"
  parameter SI.Length h_g(start=0)
    "Geodetic height (height difference from flowPort_a to flowPort_b)";
  parameter SI.Acceleration g(final min=0)=Modelica.Constants.g_n "Gravitation";
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort(T=T_q, Q_flow=Q_flowHeatPort) if useHeatPort
protected
  SI.HeatFlowRate Q_flowHeatPort "Heat flow at conditional heatPort";
equation
  if not useHeatPort then
    Q_flowHeatPort=0;
  end if;
  // coupling with FrictionModel
  volumeFlow = V_flow;
  dp = pressureDrop + medium.rho*g*h_g;
  // energy exchange with medium
  Q_flow = Q_flowHeatPort + Q_friction;
end Pipe;


Simple valve. Simple controlled valve.

within Modelica.Thermal.FluidHeatFlow.Components;
model Valve "Simple valve"
  extends FluidHeatFlow.BaseClasses.TwoPort(m(start=0), final tapT=1);

  parameter Boolean LinearCharacteristic(start=true)
    "Type of characteristic"
  parameter Real y1(min=small, start=1) "Max. valve opening"
  parameter SI.VolumeFlowRate Kv1(min=small, start=1)
    "Max. flow @ y = y1"
  parameter Real kv0(min=small,max=1-small, start=0.01)
    "Leakage flow / max.flow @ y = 0"
  parameter SI.Pressure dp0(start=1) "Standard pressure drop"
  parameter SI.Density rho0(start=10)
    "Standard medium's density"
  parameter Real frictionLoss(min=0, max=1, start=0)
    "Part of friction losses fed to medium";
protected
  constant SI.VolumeFlowRate unitVolumeFlowRate = 1;
  constant Real small = Modelica.Constants.small;
  constant SI.VolumeFlowRate smallVolumeFlowRate = eps*unitVolumeFlowRate;
  constant Real eps = Modelica.Constants.eps;
  Real yLim = max(min(y,y1),0) "Limited valve opening";
  SI.VolumeFlowRate Kv "Standard flow rate";
public
  Modelica.Blocks.Interfaces.RealInput y
initial algorithm
  assert(y1>small, "Valve characteristic: y1 has to be > 0 !");
  assert(Kv1>smallVolumeFlowRate, "Valve characteristic: Kv1 has to be > 0 !");
  assert(kv0>small, "Valve characteristic: kv0 has to be > 0 !");
  assert(kv0<1-eps, "Valve characteristic: kv0 has to be < 1 !");
equation
  // evaluate standard characteristic
  Kv/Kv1 = if LinearCharacteristic then (kv0 + (1-kv0)*yLim/y1) else kv0*exp(Modelica.Math.log(1/kv0)*yLim/y1);
  // pressure drop under real conditions
  dp/dp0 = medium.rho/rho0*(V_flow/Kv)*abs(V_flow/Kv);
  // no energy exchange with medium
  Q_flow = frictionLoss*V_flow*dp;
end Valve;


Indirect cooling circuit. 3rd test example: IndirectCooling

within Modelica.Thermal.FluidHeatFlow.Examples;
model IndirectCooling "Indirect cooling circuit"
  extends Modelica.Icons.Example;
  parameter FluidHeatFlow.Media.Medium outerMedium=FluidHeatFlow.Media.Medium()
    "Outer medium"
  parameter FluidHeatFlow.Media.Medium innerMedium=FluidHeatFlow.Media.Medium()
    "Inner medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  output SI.TemperatureDifference dTSource=
    prescribedHeatFlow.port.T-TAmb "Temperature difference between heat source and ambient condition";
  output SI.TemperatureDifference dTtoPipe=prescribedHeatFlow.port.T-pipe1.T_q
    "Temperature difference between heat source and coolant in pipe 1";
  output SI.TemperatureDifference dTinnerCoolant=pipe1.dT
    "Inner Coolant's temperature increase";
  output SI.TemperatureDifference dTCooler=innerPipe.T_q-outerPipe.T_q
    "Coolant temperature difference between inner pipe and outer pipe";
  output SI.TemperatureDifference dTouterCoolant=outerPipe.dT
    "Outer coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=outerMedium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow outerPump(
    medium=outerMedium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=outerMedium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor
    thermalConductor(G=1)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor(
    C=0.05, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow
    prescribedHeatFlow
  FluidHeatFlow.Components.Pipe pipe1(
    medium=innerMedium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=1,
    V_flowNominal=2,
    h_g=0,
    T0fixed=true,
    useHeatPort=true,
    dpLaminar=1000,
    dpNominal=2000)
  FluidHeatFlow.Sources.AbsolutePressure absolutePressure(p=10000, medium=
        innerMedium)
  FluidHeatFlow.Sources.VolumeFlow innerPump(
    medium=innerMedium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  Modelica.Blocks.Sources.Constant heatFlow(k=10)
  Modelica.Blocks.Sources.Constant outerVolumeFlow(k=1)
  Modelica.Blocks.Sources.Constant innerVolumeFlow(k=1)
  Modelica.Blocks.Sources.Constant outerGc(k=2)
  Modelica.Blocks.Sources.Constant innerGc(k=2)
  FluidHeatFlow.Components.Pipe outerPipe(
    medium=outerMedium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe innerPipe(
    medium=innerMedium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  Modelica.Thermal.HeatTransfer.Components.Convection innerConvection
  Modelica.Thermal.HeatTransfer.Components.Convection outerConvection
equation
  connect(ambient1.flowPort, outerPump.flowPort_a)
  connect(prescribedHeatFlow.port, thermalConductor.port_a)
  connect(heatCapacitor.port, thermalConductor.port_a)
  connect(pipe1.heatPort, thermalConductor.port_b)
  connect(pipe1.flowPort_b, innerPump.flowPort_a)
  connect(absolutePressure.flowPort, pipe1.flowPort_a)
  connect(heatFlow.y, prescribedHeatFlow.Q_flow)
  connect(innerPump.flowPort_b, innerPipe.flowPort_a)
  connect(innerPipe.flowPort_b, absolutePressure.flowPort)
  connect(outerPump.flowPort_b, outerPipe.flowPort_a)
  connect(outerPipe.flowPort_b,ambient2. flowPort)
  connect(outerPipe.heatPort, outerConvection.fluid)
  connect(outerConvection.solid, innerConvection.solid)
  connect(innerConvection.fluid, innerPipe.heatPort)
  connect(innerGc.y, innerConvection.Gc)
  connect(outerGc.y, outerConvection.Gc)
  connect(outerVolumeFlow.y, outerPump.volumeFlow)
  connect(innerVolumeFlow.y, innerPump.volumeFlow)
end IndirectCooling;


Cooling of one hot mass. 7th test example: OneMass

within Modelica.Thermal.FluidHeatFlow.Examples;
model OneMass "Cooling of one hot mass"
  extends Modelica.Icons.Example;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  parameter SI.Temperature TMass(displayUnit="degC")=313.15
    "Initial temperature of mass";
  output SI.TemperatureDifference dTMass=
    heatCapacitor.port.T-TAmb "Temperature difference between mass and ambient condition";
  output SI.TemperatureDifference dTtoPipe=heatCapacitor.port.T-pipe.T_q
    "Temperature difference between mass and coolant";
  output SI.TemperatureDifference dTCoolant=pipe.dT
    "Coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow pump(
    medium=medium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  FluidHeatFlow.Components.Pipe pipe(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor(
    C=0.1, T(start=TMass, fixed=true))
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor thermalConductor(G=1)
  FluidHeatFlow.Examples.Utilities.DoubleRamp volumeFlow(
    offset=0,
    height_1=1,
    height_2=-2)
equation
  connect(ambient1.flowPort, pump.flowPort_a)
  connect(pump.flowPort_b, pipe.flowPort_a)
  connect(pipe.flowPort_b, ambient2.flowPort)
  connect(thermalConductor.port_a, heatCapacitor.port)
  connect(pipe.heatPort, thermalConductor.port_b)
  connect(volumeFlow.y, pump.volumeFlow)
end OneMass;


within Modelica.Thermal.FluidHeatFlow;
package Examples "Examples that demonstrate the usage of the FluidHeatFlow components"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Cooling circuit with parallel branches. 2nd test example: ParallelCooling

within Modelica.Thermal.FluidHeatFlow.Examples;
model ParallelCooling "Cooling circuit with parallel branches"
  extends Modelica.Icons.Example;

  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  output SI.TemperatureDifference dTSource1=
    prescribedHeatFlow1.port.T-TAmb "Temperature difference between heat source 1 and ambient condition";
  output SI.TemperatureDifference dTtoPipe1=prescribedHeatFlow1.port.T-pipe1.T_q
    "Temperature difference between heat source 1 and coolant in pipe 1";
  output SI.TemperatureDifference dTCoolant1=pipe1.dT
    "Coolant1's temperature increase in pipe 1";
  output SI.TemperatureDifference dTSource2=
    prescribedHeatFlow2.port.T-TAmb "Temperature difference between Heat source 2 and ambient condition";
  output SI.TemperatureDifference dTtoPipe2=prescribedHeatFlow2.port.T-pipe2.T_q
    "Temperature difference between heat source 2 and coolant in pipe 2";
  output SI.TemperatureDifference dTCoolant2=pipe2.dT
    "Coolant2's temperature increase in pipe 2";
  output SI.TemperatureDifference dTmixedCoolant=ambient2.T_port-ambient1.T_port
    "Mixed Coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow pump(
    medium=medium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  FluidHeatFlow.Components.Pipe pipe1(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe pipe2(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe pipe3(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=false)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor1(
                   C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow
    prescribedHeatFlow1
  Modelica.Thermal.HeatTransfer.Components.Convection convection1
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor2(
                   C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow
    prescribedHeatFlow2
  Modelica.Thermal.HeatTransfer.Components.Convection convection2
  Modelica.Blocks.Sources.Constant volumeFlow(k=1)
  Modelica.Blocks.Sources.Constant heatFlow1(k=5)
  Modelica.Blocks.Sources.Constant heatFlow2(k=10)
  Modelica.Blocks.Sources.Constant thermalConductance1(k=1)
  Modelica.Blocks.Sources.Constant thermalConductance2(k=1)
equation
  connect(ambient1.flowPort, pump.flowPort_a)
  connect(pump.flowPort_b, pipe1.flowPort_a)
  connect(pump.flowPort_b, pipe2.flowPort_a)
  connect(heatFlow2.y,prescribedHeatFlow2. Q_flow)
  connect(heatFlow1.y,prescribedHeatFlow1. Q_flow)
  connect(thermalConductance2.y, convection2.Gc)
  connect(thermalConductance1.y, convection1.Gc)
  connect(pipe1.heatPort,convection1. fluid)
  connect(convection2.fluid,pipe2. heatPort)
  connect(convection2.solid,prescribedHeatFlow2. port)
  connect(convection2.solid,heatCapacitor2. port)
  connect(convection1.solid,prescribedHeatFlow1. port)
  connect(convection1.solid,heatCapacitor1. port)
  connect(pipe2.flowPort_b,pipe3. flowPort_a)
  connect(pipe1.flowPort_b,pipe3. flowPort_a)
  connect(pipe3.flowPort_b,ambient2. flowPort)
  connect(volumeFlow.y, pump.volumeFlow)
end ParallelCooling;


Cooling circuit with parallel branches and drop out of pump. 6th test example: ParallelPumpDropOut

within Modelica.Thermal.FluidHeatFlow.Examples;
model ParallelPumpDropOut
  "Cooling circuit with parallel branches and drop out of pump"
  extends Modelica.Icons.Example;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  output SI.TemperatureDifference dTSource1=
    prescribedHeatFlow1.port.T-TAmb "Temperature difference between heat source 1 and ambient condition";
  output SI.TemperatureDifference dTtoPipe1=prescribedHeatFlow1.port.T-pipe1.T_q
    "Temperature difference between heat source 1 and coolant in pipe 1";
  output SI.TemperatureDifference dTCoolant1=pipe1.dT
    "Coolant1's temperature increase";
  output SI.TemperatureDifference dTSource2=
    prescribedHeatFlow2.port.T-TAmb "Temperature difference between heat source 2 and ambient condition";
  output SI.TemperatureDifference dTtoPipe2=prescribedHeatFlow2.port.T-pipe2.T_q
    "Temperature difference between heat source 2 and coolant in pipe 2";
  output SI.TemperatureDifference dTCoolant2=pipe2.dT
    "Coolant2's temperature increase";
  output SI.TemperatureDifference dTmixedCoolant=ambient2.T_port-ambient1.T_port
    "Overall change in coolant temperature";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow pump(
    medium=medium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  FluidHeatFlow.Components.Pipe pipe1(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe pipe2(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe pipe3(
    medium=medium,
    T0=TAmb,
    m=0.1,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor1(
    C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow
    prescribedHeatFlow1
  Modelica.Thermal.HeatTransfer.Components.Convection Convection1
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor2(
    C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow prescribedHeatFlow2
  Modelica.Thermal.HeatTransfer.Components.Convection convection2
  FluidHeatFlow.Examples.Utilities.DoubleRamp volumeFlow
  Modelica.Blocks.Sources.Constant heatFlow1(k=5)
  Modelica.Blocks.Sources.Constant heatFlow2(k=10)
  Modelica.Blocks.Sources.Constant thermalConductance1(k=1)
  Modelica.Blocks.Sources.Constant thermalConductance2(k=1)
equation
  connect(ambient1.flowPort, pump.flowPort_a)
  connect(pump.flowPort_b, pipe1.flowPort_a)
  connect(pump.flowPort_b, pipe2.flowPort_a)
  connect(heatFlow2.y,prescribedHeatFlow2. Q_flow)
  connect(heatFlow1.y,prescribedHeatFlow1. Q_flow)
  connect(thermalConductance2.y, convection2.Gc)
  connect(thermalConductance1.y, Convection1.Gc)
  connect(pipe1.heatPort, Convection1.fluid)
  connect(convection2.fluid,pipe2. heatPort)
  connect(convection2.solid,prescribedHeatFlow2. port)
  connect(convection2.solid,heatCapacitor2. port)
  connect(Convection1.solid,prescribedHeatFlow1. port)
  connect(Convection1.solid,heatCapacitor1. port)
  connect(pipe2.flowPort_b,pipe3. flowPort_a)
  connect(pipe1.flowPort_b,pipe3. flowPort_a)
  connect(pipe3.flowPort_b,ambient2. flowPort)
  connect(volumeFlow.y, pump.volumeFlow)
end ParallelPumpDropOut;


Cooling circuit with pump and valve. 4th test example: PumpAndValve

within Modelica.Thermal.FluidHeatFlow.Examples;
model PumpAndValve "Cooling circuit with pump and valve"
  extends Modelica.Icons.Example;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  output SI.TemperatureDifference dTSource=
    prescribedHeatFlow.port.T-TAmb "Source over Ambient";
  output SI.TemperatureDifference dTtoPipe=prescribedHeatFlow.port.T-pipe.T_q
    "Temperature difference between heat source and ambient condition";
  output SI.TemperatureDifference dTCoolant=pipe.dT
    "Coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.IdealPump idealPump(
    medium=medium,
    m=0,
    T0=TAmb,
    V_flow0=2,
    wNominal(displayUnit="rad/s") = 1,
    dp0(displayUnit="Pa") = 2)
  FluidHeatFlow.Components.Valve valve(
    medium=medium,
    m=0,
    T0=TAmb,
    LinearCharacteristic=false,
    y1=1,
    Kv1=1,
    kv0=0.01,
    dp0(displayUnit="Pa") = 1,
    rho0=10,
    frictionLoss=0)
  FluidHeatFlow.Components.Pipe pipe(
    medium=medium,
    T0=TAmb,
    m=0.1,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor(
    C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow prescribedHeatFlow
  Modelica.Blocks.Sources.Constant heatFlow(k=10)
  Modelica.Thermal.HeatTransfer.Components.Convection convection
  Modelica.Blocks.Sources.Constant thermalConductance(k=1)
  Modelica.Mechanics.Rotational.Sources.Speed speed(exact=true, useSupport=
        false)
  Modelica.Blocks.Sources.Ramp speedRamp(
    height=0.5,
    offset=0.5,
    duration=0.1,
    startTime=0.4)
  Modelica.Blocks.Sources.Ramp valveRamp(
    height=0.5,
    offset=0.5,
    duration=0.1,
    startTime=0.9)
equation
  connect(pipe.flowPort_b, ambient2.flowPort)
  connect(heatFlow.y, prescribedHeatFlow.Q_flow)
  connect(convection.solid, prescribedHeatFlow.port)
  connect(convection.solid, heatCapacitor.port)
  connect(pipe.heatPort, convection.fluid)
  connect(thermalConductance.y, convection.Gc)
  connect(ambient1.flowPort, idealPump.flowPort_a)
  connect(idealPump.flowPort_b, valve.flowPort_a)
  connect(valve.flowPort_b, pipe.flowPort_a)
  connect(speedRamp.y, speed.w_ref)
  connect(valveRamp.y, valve.y)
  connect(speed.flange, idealPump.flange_a)
end PumpAndValve;


Cooling circuit with drop out of pump. 5th test example: PumpDropOut

within Modelica.Thermal.FluidHeatFlow.Examples;
model PumpDropOut "Cooling circuit with drop out of pump"
  extends Modelica.Icons.Example;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  output SI.TemperatureDifference dTSource=
    prescribedHeatFlow.port.T-TAmb "Temperature difference between heat source and ambient condition";
  output SI.TemperatureDifference dTtoPipe=prescribedHeatFlow.port.T-pipe.T_q
    "Temperature difference between heat source and coolant";
  output SI.TemperatureDifference dTCoolant=pipe.dT
    "Coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow pump(
    medium=medium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  FluidHeatFlow.Components.Pipe pipe(
    medium=medium,
    T0=TAmb,
    m=0.1,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor(
    C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow prescribedHeatFlow
  FluidHeatFlow.Examples.Utilities.DoubleRamp volumeFlow
  Modelica.Blocks.Sources.Constant heatFlow(k=10)
  Modelica.Thermal.HeatTransfer.Components.Convection convection
  Modelica.Blocks.Sources.Constant thermalConductance(k=1)
equation
  connect(ambient1.flowPort, pump.flowPort_a)
  connect(pump.flowPort_b, pipe.flowPort_a)
  connect(pipe.flowPort_b, ambient2.flowPort)
  connect(heatFlow.y, prescribedHeatFlow.Q_flow)
  connect(convection.solid, prescribedHeatFlow.port)
  connect(convection.solid, heatCapacitor.port)
  connect(pipe.heatPort, convection.fluid)
  connect(thermalConductance.y, convection.Gc)
  connect(volumeFlow.y, pump.volumeFlow)
end PumpDropOut;


Simple cooling circuit. 1st test example: SimpleCooling

within Modelica.Thermal.FluidHeatFlow.Examples;
model SimpleCooling "Simple cooling circuit"
  extends Modelica.Icons.Example;

  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  output SI.TemperatureDifference dTSource=
    prescribedHeatFlow.port.T-TAmb "Temperature difference between heat source and ambient condition";
  output SI.TemperatureDifference dTtoPipe=prescribedHeatFlow.port.T-pipe.T_q
    "Temperature difference between heat source and coolant";
  output SI.TemperatureDifference dTCoolant=pipe.dT
    "Coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow pump(
    medium=medium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
  FluidHeatFlow.Components.Pipe pipe(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor(
                   C=0.1, T(start=TAmb, fixed=true))
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow
    prescribedHeatFlow
  Modelica.Blocks.Sources.Constant volumeFlow(k=1)
  Modelica.Blocks.Sources.Constant heatFlow(k=10)
  Modelica.Thermal.HeatTransfer.Components.Convection convection
  Modelica.Blocks.Sources.Constant thermalConductance(k=1)
equation
  connect(ambient1.flowPort, pump.flowPort_a)
  connect(pump.flowPort_b, pipe.flowPort_a)
  connect(pipe.flowPort_b, ambient2.flowPort)
  connect(heatFlow.y, prescribedHeatFlow.Q_flow)
  connect(convection.solid, prescribedHeatFlow.port)
  connect(convection.solid, heatCapacitor.port)
  connect(pipe.heatPort, convection.fluid)
  connect(thermalConductance.y, convection.Gc)
  connect(volumeFlow.y, pump.volumeFlow)
end SimpleCooling;


Two cylinder system. Test of a system with 2 cylinders (with same volume):

within Modelica.Thermal.FluidHeatFlow.Examples;
model TestCylinder "Two cylinder system"
  extends Modelica.Icons.Example;
  output SI.Force f1=-10*cylinder1.f "10 x Force on piston 1";
  output SI.Position s1=0.1*cylinder1.s "0.1 x Position of piston 1";
  output SI.Position s2=cylinder2.s "Position of piston 2";
  output SI.Force f2=-cylinder2.f "Force on piston 2";
  output SI.Force f=springDamper.f "Force of springDamper";
  Modelica.Blocks.Sources.CombiTimeTable combiTimeTable(
    table=[0,0; 0.25,-1; 0.5,0; 0.75,0],
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments)
  Modelica.Mechanics.Translational.Sources.Force force
  FluidHeatFlow.Components.Cylinder cylinder1(
    A=0.1,
    L=10,
    s(fixed=true, start=cylinder1.L/2),
    T0=313.15,
    T0fixed=true)
  FluidHeatFlow.Components.Cylinder cylinder2(
    T(fixed=true),
    A=1,
    L=1,
    T0=313.15,
    T0fixed=true)
  Modelica.Mechanics.Translational.Components.Mass mass(m=1)
  Modelica.Mechanics.Translational.Components.SpringDamper springDamper(
    s_rel0=cylinder2.L/2,
    c=100,
    s_rel(fixed=true, start=cylinder2.L/2),
    v_rel(fixed=true, start=0),
    d=10)
  Modelica.Mechanics.Translational.Components.Fixed fixed
equation
  connect(cylinder1.flowPort, cylinder2.flowPort)
  connect(force.flange, cylinder1.flange)
  connect(combiTimeTable.y[1], force.f)
  connect(cylinder2.flange, mass.flange_a)
  connect(springDamper.flange_b, mass.flange_b)
  connect(springDamper.flange_a, fixed.flange)
end TestCylinder;


Test the OpenTank model. First, the medium is pumped out of the tank (initial level = 0.5 m, T = 40°C) to an (infinite) ambient (T = 20°C):

within Modelica.Thermal.FluidHeatFlow.Examples;
model TestOpenTank "Test the OpenTank model"
  extends Modelica.Icons.Example;
  output SI.VolumeFlowRate V_flow=volumeFlow.V_flow "Volume flow rate to tank";
  output SI.Length level=openTank.level "Level in tank";
  output SI.Temperature T(displayUnit="degC")=openTank.TTank "Temperature in tank";
  FluidHeatFlow.Components.OpenTank openTank(
    ATank=1,
    hTank=1,
    useHeatPort=false,
    pAmbient=0,
    g=10,
    level(fixed=true, start=0.5),
    T0=313.15,
    T0fixed=true)
  FluidHeatFlow.Sources.Ambient ambient(constantAmbientPressure=0,
      constantAmbientTemperature=293.15)
  FluidHeatFlow.Sources.VolumeFlow volumeFlow(
    m=0,
    useVolumeFlowInput=true,
    constantVolumeFlow=1,
    T0=293.15)
  Modelica.Blocks.Sources.CombiTimeTable combiTimeTable(
    table=[0,0; 0.5,0; 0.5,-1; 0.75, -1; 0.75,1; 1,1; 1,0; 1.5,0])
equation
  connect(combiTimeTable.y[1], volumeFlow.volumeFlow)
  connect(openTank.flowPort, volumeFlow.flowPort_b)
  connect(volumeFlow.flowPort_a, ambient.flowPort)
end TestOpenTank;


Cooling of two hot masses. 8th test example: TwoMass

within Modelica.Thermal.FluidHeatFlow.Examples;
model TwoMass "Cooling of two hot masses"
  extends Modelica.Icons.Example;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Cooling medium"
  parameter SI.Temperature TAmb(displayUnit="degC")=293.15
    "Ambient temperature";
  parameter SI.Temperature TMass1(displayUnit="degC")=313.15
    "Initial temperature of mass1";
  parameter SI.Temperature TMass2(displayUnit="degC")=333.15
    "Initial temperature of mass2";
  output SI.TemperatureDifference dTMass1=
    heatCapacitor1.port.T-TAmb "Temperature difference between mass 1 and ambient condition";
  output SI.TemperatureDifference dTtoPipe1=heatCapacitor1.port.T-pipe1.T_q
    "Temperature difference between mass 1 and coolant in pipe 1";
  output SI.TemperatureDifference dTCoolant1=pipe1.dT
    "Change in coolant temperature in pipe 1";
  output SI.TemperatureDifference dTMass2=
    heatCapacitor2.port.T-TAmb "Temperature difference between mass 2 and ambient condition";
  output SI.TemperatureDifference dTtoPipe2=heatCapacitor2.port.T-pipe2.T_q
    "Temperature difference between mass 2 and coolant in pipe 2";
  output SI.TemperatureDifference dTCoolant2=pipe2.dT
    "Coolant2's temperature increase";
  output SI.TemperatureDifference dTmixedCoolant=ambient2.T_port-ambient1.T_port
    "Mixed Coolant's temperature increase";
  FluidHeatFlow.Sources.Ambient ambient1(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  FluidHeatFlow.Sources.VolumeFlow pump(
    medium=medium,
    m=0,
    T0=TAmb,
    useVolumeFlowInput=true,
    constantVolumeFlow=1)
   FluidHeatFlow.Components.Pipe pipe1(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe pipe2(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true,
    useHeatPort=true)
  FluidHeatFlow.Components.Pipe pipe3(
    medium=medium,
    m=0.1,
    T0=TAmb,
    V_flowLaminar=0.1,
    dpLaminar(displayUnit="Pa") = 0.1,
    V_flowNominal=1,
    dpNominal(displayUnit="Pa") = 1,
    h_g=0,
    T0fixed=true)
  FluidHeatFlow.Sources.Ambient ambient2(
    constantAmbientTemperature=TAmb,
    medium=medium,
    constantAmbientPressure=0)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor1(
    C=0.1, T(start=TMass1, fixed=true))
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor
    thermalConductor1(G=1)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor2(
    C=0.1, T(start=TMass2, fixed=true))
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor
    thermalConductor2(G=1)
  FluidHeatFlow.Examples.Utilities.DoubleRamp volumeFlow(
    offset=0,
    height_1=1,
    height_2=-2)
equation
  connect(ambient1.flowPort, pump.flowPort_a)
  connect(pump.flowPort_b, pipe1.flowPort_a)
  connect(pump.flowPort_b, pipe2.flowPort_a)
  connect(pipe2.flowPort_b,pipe3. flowPort_a)
  connect(pipe1.flowPort_b,pipe3. flowPort_a)
  connect(pipe3.flowPort_b,ambient2. flowPort)
  connect(heatCapacitor2.port,thermalConductor2. port_a)
  connect(thermalConductor2.port_b,pipe2. heatPort)
  connect(pipe1.heatPort,thermalConductor1. port_b)
  connect(thermalConductor1.port_a, heatCapacitor1.port)
  connect(volumeFlow.y, pump.volumeFlow)
end TwoMass;


Two connected open tanks. Two tanks are connected with a pipe:

within Modelica.Thermal.FluidHeatFlow.Examples;
model TwoTanks "Two connected open tanks"
  extends Modelica.Icons.Example;
  output SI.VolumeFlowRate V_flow=pipe.V_flow "Volume flow rate tank 1 -> tank 2";
  output SI.Length level1=openTank1.level "Level in tank 1";
  output SI.Temperature T1(displayUnit="degC")=openTank1.TTank "Temperature in tank 1";
  output SI.Length level2=openTank2.level "Level in tank 2";
  output SI.Temperature T2(displayUnit="degC")=openTank2.TTank "Temperature in tank 2";
  FluidHeatFlow.Components.OpenTank openTank1(
    ATank=1,
    hTank=1,
    useHeatPort=false,
    g=10,
    level(fixed=true, start=0.9),
    T0=313.15,
    T0fixed=true,
    pAmbient=100000)
  FluidHeatFlow.Components.OpenTank openTank2(
    ATank=1,
    hTank=1,
    useHeatPort=false,
    g=10,
    level(fixed=true, start=0.1),
    T0=293.15,
    T0fixed=true,
    pAmbient=100000)
  FluidHeatFlow.Components.Pipe pipe(
    m=0,
    h_g=0,
    T0=293.15,
    V_flowLaminar=2,
    dpLaminar=10,
    V_flowNominal=4,
    dpNominal=30)
equation
  connect(openTank1.flowPort, pipe.flowPort_a)
  connect(pipe.flowPort_b, openTank2.flowPort)
end TwoTanks;


Water pumping station. There are two reservoirs at ambient pressure, the second one 25 m higher than the first one.
The ideal pump is driven by a speed source, starting from zero and going up to 1.2 times nominal speed.
To avoid water flowing back, the one way valve is used.

within Modelica.Thermal.FluidHeatFlow.Examples;
model WaterPump "Water pumping station"
  extends Modelica.Icons.Example;
  import Modelica.Constants.pi;
  output SI.VolumeFlowRate V_flow=volumeFlowSensor.y "Volume flow rate";
  output SI.Pressure p(displayUnit="bar")=pressureSensor.y "Pressure at pump outlet";
  output SI.AngularVelocity w(displayUnit="1/min")=multiSensor.w "Pump speed";
  output SI.Torque tau=multiSensor.tau "Pump torque";
  output SI.Power power=multiSensor.power "Pump power";
  Modelica.Blocks.Sources.Trapezoid trapezoid(
    period=2,
    nperiod=1,
    offset=0,
    rising=0.6,
    width=0.6,
    falling=0.6,
    startTime=0.1,
    amplitude=1.2)
  Modelica.Blocks.Math.Gain gain(k=idealPump.wNominal)
  Modelica.Mechanics.Rotational.Sources.Speed speed(exact=true)
  Modelica.Mechanics.Rotational.Sensors.MultiSensor multiSensor(w(displayUnit="1/min"))
  FluidHeatFlow.Sources.Ambient ambient1(
    medium=FluidHeatFlow.Media.Water(),
    constantAmbientPressure=100000,
    constantAmbientTemperature=293.15)
  FluidHeatFlow.Sources.IdealPump idealPump(
    medium=FluidHeatFlow.Media.Water(),
    m=0,
    V_flow0=0.18,
    T0=293.15,
    wNominal=104.71975511966,
    dp0=500000)
  FluidHeatFlow.Sensors.VolumeFlowSensor volumeFlowSensor(medium=
        FluidHeatFlow.Media.Water())
  FluidHeatFlow.Sensors.PressureSensor pressureSensor(medium=
        FluidHeatFlow.Media.Water())
  FluidHeatFlow.Components.OneWayValve oneWayValve(
    medium=FluidHeatFlow.Media.Water(),
    m=0,
    frictionLoss=0,
    T0=293.15,
    V_flowNominal=0.18,
    dpForward=10000,
    dpNominal=500000,
    V_flowBackward=1e-6)
  FluidHeatFlow.Components.Pipe pipe(
    m=0,
    V_flowLaminar=0.09,
    V_flowNominal=0.18,
    h_g=25,
    medium=FluidHeatFlow.Media.Water(),
    T0=293.15,
    dpLaminar=10000,
    dpNominal=30000)
  FluidHeatFlow.Sources.Ambient ambient2(
    medium=FluidHeatFlow.Media.Water(),
    constantAmbientPressure=100000,
    constantAmbientTemperature=293.15)
equation
  connect(idealPump.flowPort_a, ambient1.flowPort)
  connect(speed.flange, multiSensor.flange_a)
  connect(oneWayValve.flowPort_a, volumeFlowSensor.flowPort_b)
  connect(volumeFlowSensor.flowPort_a, idealPump.flowPort_b)
  connect(ambient2.flowPort, pipe.flowPort_b)
  connect(pipe.flowPort_a, oneWayValve.flowPort_b)
  connect(multiSensor.flange_b, idealPump.flange_a)
  connect(oneWayValve.flowPort_a, pressureSensor.flowPort)
  connect(gain.y, speed.w_ref)
  connect(trapezoid.y, gain.u)
end WaterPump;


Ramp going up and down.

within Modelica.Thermal.FluidHeatFlow.Examples.Utilities;
model DoubleRamp "Ramp going up and down"
  extends Modelica.Blocks.Interfaces.SO;
  parameter Real offset=1 "Offset of ramps";
  parameter SI.Time startTime=0.2 "StartTime of 1st ramp";
  parameter SI.Time interval=0.2
    "Interval between end of 1st and beginning of 2nd ramp";
  parameter Real height_1=-1 "Height of ramp"
  parameter SI.Time duration_1(min=Modelica.Constants.small)=0.2
    "Duration of ramp"
  parameter Real height_2=1 "Height of ramp"
  parameter SI.Time duration_2(min=Modelica.Constants.small)=0.2
    "Duration of ramp"

  Modelica.Blocks.Math.Add add
  Modelica.Blocks.Sources.Ramp ramp1(
    final height=height_1,
    final duration=duration_1,
    final startTime=startTime,
    final offset=offset)
  Modelica.Blocks.Sources.Ramp ramp2(
    final height=height_2,
    final duration=duration_2,
    final startTime=startTime + duration_1 + interval,
    final offset=0)
equation
  connect(ramp1.y, add.u1)
  connect(ramp2.y, add.u2)
  connect(add.y, y)
end DoubleRamp;


Utility models for examples

within Modelica.Thermal.FluidHeatFlow.Examples;
package Utilities "Utility models for examples"
  extends Modelica.Icons.UtilitiesPackage;
end Utilities;


Partial model of absolute sensor. Partial model for an absolute sensor (pressure/temperature).

within Modelica.Thermal.FluidHeatFlow.Interfaces;
partial model AbsoluteSensor "Partial model of absolute sensor"
  extends Modelica.Icons.RoundSensor;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Sensor's medium"
  FluidHeatFlow.Interfaces.FlowPort_a flowPort(final medium=medium)
  Modelica.Blocks.Interfaces.RealOutput y
equation
  // no mass exchange
  flowPort.m_flow = 0;
  // no energy exchange
  flowPort.H_flow = 0;
end AbsoluteSensor;


Partial model of flow sensor. Partial model for a flow sensor (mass flow/heat flow).

within Modelica.Thermal.FluidHeatFlow.Interfaces;
partial model FlowSensor "Partial model of flow sensor"
  extends Modelica.Icons.RoundSensor;
  extends FluidHeatFlow.BaseClasses.TwoPort(
    final m=0,
    final T0=293.15,
    final T0fixed=false,
    final tapT=1);
  Modelica.Blocks.Interfaces.RealOutput y
equation
  // no pressure drop
  dp = 0;
  // no energy exchange
  Q_flow = 0;
end FlowSensor;


Connectors and partial models

within Modelica.Thermal.FluidHeatFlow;
package Interfaces "Connectors and partial models"
  extends Modelica.Icons.InterfacesPackage;
end Interfaces;


Partial model of relative sensor. Partial model for a relative sensor (pressure drop/temperature difference).

within Modelica.Thermal.FluidHeatFlow.Interfaces;
partial model RelativeSensor "Partial model of relative sensor"
  extends RelativeSensorBase;
  Modelica.Blocks.Interfaces.RealOutput y
end RelativeSensor;


Partial model of relative sensor without signal output. Partial model for a relative sensor (pressure drop/temperature difference) without signal output.

within Modelica.Thermal.FluidHeatFlow.Interfaces;
partial model RelativeSensorBase "Partial model of relative sensor without signal output"
  extends Modelica.Icons.RoundSensor;
  parameter FluidHeatFlow.Media.Medium medium=FluidHeatFlow.Media.Medium()
    "Sensor's medium"
  FluidHeatFlow.Interfaces.FlowPort_a flowPort_a(final medium=medium)
  FluidHeatFlow.Interfaces.FlowPort_b flowPort_b(final medium=medium)
equation
  // no mass exchange
  flowPort_a.m_flow = 0;
  flowPort_b.m_flow = 0;
  // no energy exchange
  flowPort_a.H_flow = 0;
  flowPort_b.H_flow = 0;
end RelativeSensorBase;


Medium properties

within Modelica.Thermal.FluidHeatFlow;
package Media "Medium properties"
  extends Modelica.Icons.MaterialPropertiesPackage;
end Media;


Enthalpy flow sensor. The EnthalpyFlowSensor measures the enthalpy flow rate.

within Modelica.Thermal.FluidHeatFlow.Sensors;
model EnthalpyFlowSensor "Enthalpy flow sensor"

  extends FluidHeatFlow.Interfaces.FlowSensor(y(unit="W")
      "Enthalpy flow as output signal");
equation
  y = flowPort_a.H_flow;
end EnthalpyFlowSensor;


Mass flow sensor. The MassFlowSensor measures the mass flow rate.

within Modelica.Thermal.FluidHeatFlow.Sensors;
model MassFlowSensor "Mass flow sensor"

  extends FluidHeatFlow.Interfaces.FlowSensor(y(unit="kg/s")
      "Mass flow as output signal");
equation
  y = V_flow*medium.rho;
end MassFlowSensor;


within Modelica.Thermal.FluidHeatFlow;
package Sensors "Ideal sensors to measure port properties"
  extends Modelica.Icons.SensorsPackage;
end Sensors;


Absolute pressure sensor. The PressureSensor measures the absolute pressure.

within Modelica.Thermal.FluidHeatFlow.Sensors;
model PressureSensor "Absolute pressure sensor"

  extends FluidHeatFlow.Interfaces.AbsoluteSensor(y(unit="Pa", displayUnit=
          "bar") "Absolute pressure as output signal");
equation
  y = flowPort.p;
end PressureSensor;


Pressure difference sensor. The RelPressureSensor measures the pressure drop between flowPort_a and flowPort_b.

within Modelica.Thermal.FluidHeatFlow.Sensors;
model RelPressureSensor "Pressure difference sensor"

  extends FluidHeatFlow.Interfaces.RelativeSensorBase;
  Modelica.Blocks.Interfaces.RealOutput y(unit="Pa", displayUnit="bar")
    "Pressure difference as output signal"
equation
  y = flowPort_a.p - flowPort_b.p;
end RelPressureSensor;


Temperature difference sensor. The RelTemperatureSensor measures the temperature difference between flowPort_a and flowPort_b.

within Modelica.Thermal.FluidHeatFlow.Sensors;
model RelTemperatureSensor "Temperature difference sensor"

  extends FluidHeatFlow.Interfaces.RelativeSensorBase;
  Modelica.Blocks.Interfaces.RealOutput y(unit="K")
    "Temperature difference as output signal"
equation
  medium.cp*y = flowPort_a.h - flowPort_b.h;
end RelTemperatureSensor;


Absolute temperature sensor. The TempreatureSensor measures the absolute temperature (Kelvin).

within Modelica.Thermal.FluidHeatFlow.Sensors;
model TemperatureSensor "Absolute temperature sensor"

  extends FluidHeatFlow.Interfaces.AbsoluteSensor(y(unit="K")
      "Absolute temperature as output signal");
equation
  medium.cp*y = flowPort.h;
end TemperatureSensor;


Volume flow sensor. The VolumeFlowSensor measures the volume flow rate.

within Modelica.Thermal.FluidHeatFlow.Sensors;
model VolumeFlowSensor "Volume flow sensor"

  extends FluidHeatFlow.Interfaces.FlowSensor(y(unit="m3/s")
      "Volume flow as output signal");
equation
  y = V_flow;
end VolumeFlowSensor;


Defines absolute pressure level. AbsolutePressure to define pressure level of a closed cooling cycle.

within Modelica.Thermal.FluidHeatFlow.Sources;
model AbsolutePressure "Defines absolute pressure level"
  extends FluidHeatFlow.BaseClasses.SinglePortLeft(
    final Exchange=false,
    final T0=293.15,
    final T0fixed=false);
  parameter SI.Pressure p(start=0) "Pressure ground";
equation
  // defining pressure
  flowPort.p = p;
  // no no mass flow means no energy flow
  flowPort.H_flow = 0;
end AbsolutePressure;


Ambient with constant properties. (Infinite) ambient with constant pressure and temperature.

within Modelica.Thermal.FluidHeatFlow.Sources;
model Ambient "Ambient with constant properties"

  extends FluidHeatFlow.BaseClasses.SinglePortLeft(
    final Exchange=true,
    final T0=293.15,
    final T0fixed=false);
  parameter Boolean usePressureInput=false
    "Enable / disable pressure input"
  parameter SI.Pressure constantAmbientPressure(start=0)
    "Ambient pressure"
  parameter Boolean useTemperatureInput=false
    "Enable / disable temperature input"
  parameter SI.Temperature constantAmbientTemperature(start=293.15, displayUnit="degC")
    "Ambient temperature"
  Modelica.Blocks.Interfaces.RealInput ambientPressure=pAmbient if usePressureInput
  Modelica.Blocks.Interfaces.RealInput ambientTemperature=TAmbient if useTemperatureInput
protected
  SI.Pressure pAmbient;
  SI.Temperature TAmbient;

equation
  if not usePressureInput then
    pAmbient = constantAmbientPressure;
  end if;
  if not useTemperatureInput then
    TAmbient = constantAmbientTemperature;
  end if;
  flowPort.p = pAmbient;
  T = TAmbient;
end Ambient;


Model of an ideal pump. Simple fan resp. pump where characteristic is dependent on shaft's speed,

torque * speed = pressure increase * volume flow (without losses)

Pressure increase versus volume flow is defined by a linear function,
from dp0(V_flow=0) to V_flow0(dp=0).

The axis intersections vary with speed as follows:

within Modelica.Thermal.FluidHeatFlow.Sources;
model IdealPump "Model of an ideal pump"

  extends FluidHeatFlow.BaseClasses.TwoPort(final tapT=1);
  parameter SI.AngularVelocity wNominal(start=1, displayUnit="rev/min")
    "Nominal speed"
  parameter SI.Pressure dp0(start=2)
    "Max. pressure increase @ V_flow=0"
  parameter SI.VolumeFlowRate V_flow0(start=2)
    "Max. volume flow rate @ dp=0"
  SI.AngularVelocity w=der(flange_a.phi) "Speed";
protected
  SI.Pressure dp1;
  SI.VolumeFlowRate V_flow1;
public
  Modelica.Mechanics.Rotational.Interfaces.Flange_a flange_a
equation
  // pump characteristic
  dp1 = dp0*sign(w/wNominal)*(w/wNominal)^2;
  V_flow1 = V_flow0*(w/wNominal);
  if noEvent(abs(w)<Modelica.Constants.small) then
    dp = 0;
    flange_a.tau = 0;
  else
    dp = -dp1*(1 - V_flow/V_flow1);
    flange_a.tau*w = -dp*V_flow;
  end if;
  // no energy exchange with medium
  Q_flow = 0;
end IdealPump;


within Modelica.Thermal.FluidHeatFlow;
package Sources "Ideal fluid sources, e.g., ambient, volume flow"
  extends Modelica.Icons.SourcesPackage;
end Sources;


Enforces constant pressure increase. Fan resp. pump with constant pressure increase. Mass resp. volume flow is the response of the whole system.

within Modelica.Thermal.FluidHeatFlow.Sources;
model PressureIncrease "Enforces constant pressure increase"

  extends FluidHeatFlow.BaseClasses.TwoPort(final tapT=1);
  parameter Boolean usePressureIncreaseInput=false
    "Enable / disable pressure increase input"
  parameter SI.Pressure constantPressureIncrease(start=1)
    "Pressure increase"
  Modelica.Blocks.Interfaces.RealInput pressureIncrease(unit="Pa")=internalPressureIncrease if usePressureIncreaseInput
protected
  SI.Pressure internalPressureIncrease;
equation
  if not usePressureIncreaseInput then
    internalPressureIncrease = constantPressureIncrease;
  end if;
  Q_flow = 0;
  dp = -internalPressureIncrease;
end PressureIncrease;


Enforces constant volume flow. Fan resp. pump with constant volume flow rate. Pressure increase is the response of the whole system.

within Modelica.Thermal.FluidHeatFlow.Sources;
model VolumeFlow "Enforces constant volume flow"

  extends FluidHeatFlow.BaseClasses.TwoPort(final tapT=1);
  parameter Boolean useVolumeFlowInput=false
    "Enable / disable volume flow input"
  parameter SI.VolumeFlowRate constantVolumeFlow(start=1)
    "Volume flow rate"
  Modelica.Blocks.Interfaces.RealInput volumeFlow(unit="m3/s")=internalVolumeFlow if useVolumeFlowInput
protected
  SI.VolumeFlowRate internalVolumeFlow;
equation
  if not useVolumeFlowInput then
    internalVolumeFlow = constantVolumeFlow;
  end if;
  Q_flow = 0;
  V_flow = internalVolumeFlow;
end VolumeFlow;


within Modelica.Thermal;
package HeatTransfer "Library of 1-dimensional heat transfer with lumped elements"
  extends Modelica.Icons.Package;
end HeatTransfer;


Fixed temperature boundary condition in degree Celsius. This model defines a fixed temperature T at its port in [degC],
i.e., it defines a fixed temperature as a boundary condition.

within Modelica.Thermal.HeatTransfer.Celsius;
model FixedTemperature
  "Fixed temperature boundary condition in degree Celsius"
  extends HeatTransfer.Icons.FixedTemperature;
  parameter Modelica.Units.NonSI.Temperature_degC T
    "Fixed temperature at the port";
  Interfaces.HeatPort_b port
equation
  port.T = Modelica.Units.Conversions.from_degC(T);
end FixedTemperature;


Conversion from Kelvin to degree Celsius. This component converts an input signal from Kelvin to Celsius
and provides is as output signal.

within Modelica.Thermal.HeatTransfer.Celsius;
model FromKelvin "Conversion from Kelvin to degree Celsius"
  extends HeatTransfer.Icons.Conversion;
  Modelica.Blocks.Interfaces.RealInput Kelvin(unit="K")
  Modelica.Blocks.Interfaces.RealOutput Celsius(unit="degC")
equation
  Celsius = Modelica.Units.Conversions.to_degC(Kelvin);
end FromKelvin;


within Modelica.Thermal.HeatTransfer;
package Celsius "Components with Celsius input and/or output"
  extends Modelica.Icons.VariantsPackage;
</pre></blockquote>
</html>"));
end Celsius;


Variable temperature boundary condition in degCelsius. This model represents a variable temperature boundary condition
The temperature value in [degC] is given by the input signal
to the model. The effect is that an instance of this model acts as
an infinite reservoir able to absorb or generate as much energy
as required to keep the temperature at the specified value.

within Modelica.Thermal.HeatTransfer.Celsius;
model PrescribedTemperature
  "Variable temperature boundary condition in degCelsius"
  extends HeatTransfer.Icons.PrescribedTemperature;
  Interfaces.HeatPort_b port
  Modelica.Blocks.Interfaces.RealInput T(unit="degC")
equation
  port.T = Modelica.Units.Conversions.from_degC(T);
end PrescribedTemperature;


Absolute temperature sensor in degCelsius. This is an ideal absolute temperature sensor which returns
the temperature of the connected port in Celsius as an output
signal.  The sensor itself has no thermal interaction with
whatever it is connected to.  Furthermore, no
thermocouple-like lags are associated with this
sensor model.

within Modelica.Thermal.HeatTransfer.Celsius;
model TemperatureSensor "Absolute temperature sensor in degCelsius"

  Modelica.Blocks.Interfaces.RealOutput T(unit="degC")
    "Absolute temperature in degree Celsius as output signal"
  Interfaces.HeatPort_a port
equation
  T = Modelica.Units.Conversions.to_degC(port.T);
  port.Q_flow = 0;
end TemperatureSensor;


Conversion from degree Celsius to Kelvin. This component converts an input signal from Celsius to Kelvin
and provide is as output signal.

within Modelica.Thermal.HeatTransfer.Celsius;
model ToKelvin "Conversion from degree Celsius to Kelvin"
  extends HeatTransfer.Icons.Conversion;
  Modelica.Blocks.Interfaces.RealInput Celsius(unit="degC")
  Modelica.Blocks.Interfaces.RealOutput Kelvin(unit="K")
equation
  Kelvin = Modelica.Units.Conversions.from_degC(Celsius);
end ToKelvin;


Lumped thermal element for radiation heat transfer. This is a model describing the thermal radiation, i.e., electromagnetic
radiation emitted between two bodies as a result of their temperatures.
The following constitutive equation is used:

within Modelica.Thermal.HeatTransfer.Components;
model BodyRadiation "Lumped thermal element for radiation heat transfer"
  extends Interfaces.Element1D;
  parameter Real Gr(unit="m2")
    "Net radiation conductance between two surfaces (see docu)";
equation
  Q_flow = Gr*Modelica.Constants.sigma*(port_a.T^4 - port_b.T^4);

where Gr is the radiation conductance and sigma is the Stefan-Boltzmann
constant (= Modelica.Constants.sigma). Gr may be determined by
measurements and is assumed to be constant over the range of operations.

For simple cases, Gr may be analytically computed. The analytical
equations use epsilon, the emission value of a body which is in the
range 0..1. Epsilon=1, if the body absorbs all radiation (= black body).
Epsilon=0, if the body reflects all radiation and does not absorb any.

Typical values for epsilon:
aluminium, polished    0.04
copper, polished       0.04
gold, polished         0.02
paper                  0.09
rubber                 0.95
silver, polished       0.02
wood                   0.85..0.9

Analytical Equations for Gr

Small convex object in large enclosure
(e.g., a hot machine in a room):

Gr = e*A
where
   e: Emission value of object (0..1)
   A: Surface area of object where radiation
      heat transfer takes place

Two parallel plates:

Gr = A/(1/e1 + 1/e2 - 1)
where
   e1: Emission value of plate1 (0..1)
   e2: Emission value of plate2 (0..1)
   A : Area of plate1 (= area of plate2)

Two long cylinders in each other, where radiation takes
place from the inner to the outer cylinder):

Gr = 2*pi*r1*L/(1/e1 + (1/e2 - 1)*(r1/r2))
where
   pi: = Modelica.Constants.pi
   r1: Radius of inner cylinder
   r2: Radius of outer cylinder
   L : Length of the two cylinders
   e1: Emission value of inner cylinder (0..1)
   e2: Emission value of outer cylinder (0..1)

"));
end BodyRadiation;


Lumped thermal element for heat convection (Q_flow = Gc*dT). This is a model of linear heat convection, e.g., the heat transfer between a plate and the surrounding air; see also:
ConvectiveResistor.
It may be used for complicated solid geometries and fluid flow over the solid by determining the
convective thermal conductance Gc by measurements. The basic constitutive equation for convection is

within Modelica.Thermal.HeatTransfer.Components;
model Convection
  "Lumped thermal element for heat convection (Q_flow = Gc*dT)"
  SI.HeatFlowRate Q_flow "Heat flow rate from solid -> fluid";
  SI.TemperatureDifference dT "= solid.T - fluid.T";
  Modelica.Blocks.Interfaces.RealInput Gc(unit="W/K")
    "Signal representing the convective thermal conductance in [W/K]"
  Interfaces.HeatPort_a solid
  Interfaces.HeatPort_b fluid
equation
  dT = solid.T - fluid.T;
  solid.Q_flow = Q_flow;
  fluid.Q_flow = -Q_flow;
  Q_flow = Gc*dT;
Q_flow: Heat flow rate from connector 'solid' (e.g., a plate)
   to connector 'fluid' (e.g., the surrounding air)

Gc = G.signal[1] is an input signal to the component, since Gc is
nearly never constant in practice. For example, Gc may be a function
of the speed of a cooling fan. For simple situations,
Gc may be calculated according to

Gc = A*h
A: Convection area (e.g., perimeter*length of a box)
h: Heat transfer coefficient

where the heat transfer coefficient h is calculated
from properties of the fluid flowing over the solid. Examples:

Machines cooled by air (empirical, very rough approximation according
to [Fischer2017, p. 452]:

h = 7.8*v^0.78 [W/(m2.K)] (forced convection)
  = 12         [W/(m2.K)] (free convection)
where
  v: Air velocity in [m/s]

Laminar flow with constant velocity of a fluid along a
flat plate where the heat flow rate from the plate
to the fluid (= solid.Q_flow) is kept constant
(according to [Holman2010, p.265]):

h  = Nu*k/x;
Nu = 0.453*Re^(1/2)*Pr^(1/3);
where
   h  : Heat transfer coefficient
   Nu : = h*x/k       (Nusselt number)
   Re : = v*x*rho/mu  (Reynolds number)
   Pr : = cp*mu/k     (Prandtl number)
   v  : Absolute velocity of fluid
   x  : distance from leading edge of flat plate
   rho: density of fluid (material constant
   mu : dynamic viscosity of fluid (material constant)
   cp : specific heat capacity of fluid (material constant)
   k  : thermal conductivity of fluid (material constant)
and the equation for h holds, provided
   Re < 5e5 and 0.6 < Pr < 50

"),
       Diagram(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},
            {100,100}}), graphics={
        Line(points={{100,0},{100,0}}, color={0,127,255}),
        Line(points={{100,0},{100,0}}, color={0,127,255}),
        Line(points={{100,0},{100,0}}, color={0,127,255})}));
end Convection;


Lumped thermal element for heat convection (dT = Rc*Q_flow). This is a model of linear heat convection, e.g., the heat transfer between a plate and the surrounding air; same as the
Convection component
but using the convective resistance instead of the convective conductance as an input.
This is advantageous for series connections of ConvectiveResistors,
especially if it shall be allowed that a convective resistance is defined to be zero (i.e. no temperature difference).

within Modelica.Thermal.HeatTransfer.Components;
model ConvectiveResistor
  "Lumped thermal element for heat convection (dT = Rc*Q_flow)"
  SI.HeatFlowRate Q_flow "Heat flow rate from solid -> fluid";
  SI.TemperatureDifference dT "= solid.T - fluid.T";
  Modelica.Blocks.Interfaces.RealInput Rc(unit="K/W")
    "Signal representing the convective thermal resistance in [K/W]"
  Interfaces.HeatPort_a solid
  Interfaces.HeatPort_b fluid
equation
  dT = solid.T - fluid.T;
  solid.Q_flow = Q_flow;
  fluid.Q_flow = -Q_flow;
  dT = Rc*Q_flow;
end ConvectiveResistor;


Signal adaptor for a HeatTransfer port with temperature and derivative of temperature as outputs and heat flow as input (especially useful for FMUs). Adaptor between a heatport connector and a signal representation of the flange.
This component is used to provide a pure signal interface around a HeatTransfer model
and export this model in form of an input/output block,
especially as FMU (Functional Mock-up Unit).
Examples of the usage of this adaptor are provided in
HeatTransfer.Examples.GenerationOfFMUs.
This adaptor has heatflow as input and temperature and derivative of temperature as output signals.

within Modelica.Thermal.HeatTransfer.Components;
model GeneralHeatFlowToTemperatureAdaptor
  "Signal adaptor for a HeatTransfer port with temperature and derivative of temperature as outputs and heat flow as input (especially useful for FMUs)"
  extends Modelica.Blocks.Interfaces.Adaptors.FlowToPotentialAdaptor(
    final Name_p="T",
    final Name_pder="dT",
    final Name_pder2="d2T",
    final Name_f="Q",
    final Name_fder="der(Q)",
    final Name_fder2="der2(Q)",
    final use_pder2=false,
    final use_fder=false,
    final use_fder2=false,
    p(unit="K", displayUnit="degC"),
    final pder(unit="K/s"),
    final pder2(unit="K/s2"),
    final f(unit="W"),
    final fder(unit="W/s"),
    final fder2(unit="W/s2"));
  HeatTransfer.Interfaces.HeatPort_a heatPort
equation
  y = heatPort.T "output = potential = temperature";
  u = heatPort.Q_flow "input = flow = heat flow";
end GeneralHeatFlowToTemperatureAdaptor;


Signal adaptor for a HeatTransfer port with heat flow as output and temperature and derivative of temperature as input (especially useful for FMUs). Adaptor between a heatport connector and a signal representation of the flange.
This component is used to provide a pure signal interface around a HeatTransfer model
and export this model in form of an input/output block,
especially as FMU (Functional Mock-up Unit).
Examples of the usage of this adaptor are provided in
HeatTransfer.Examples.GenerationOfFMUs.
This adaptor has temperature and derivative of temperature as input signals and heatflow as output signal.

within Modelica.Thermal.HeatTransfer.Components;
model GeneralTemperatureToHeatFlowAdaptor
  "Signal adaptor for a HeatTransfer port with heat flow as output and temperature and derivative of temperature as input (especially useful for FMUs)"
  extends Modelica.Blocks.Interfaces.Adaptors.PotentialToFlowAdaptor(
    final Name_p="T",
    final Name_pder="dT",
    final Name_pder2="d2T",
    final Name_f="Q",
    final Name_fder="der(Q)",
    final Name_fder2="der2(Q)",
    final use_pder2=false,
    final use_fder=false,
    final use_fder2=false,
    p(unit="K", displayUnit="degC"),
    final pder(unit="K/s"),
    final pder2(unit="K/s2"),
    final f(unit="W"),
    final fder(unit="W/s"),
    final fder2(unit="W/s2"));
  HeatTransfer.Interfaces.HeatPort_b heatPort
equation
  y = heatPort.Q_flow "output = flow = heat flow";
  u = heatPort.T "input = potential = temperature";
end GeneralTemperatureToHeatFlowAdaptor;


Lumped thermal element storing heat. This is a generic model for the heat capacity of a material.
No specific geometry is assumed beyond a total volume with
uniform temperature for the entire volume.
Furthermore, it is assumed that the heat capacity
is constant (independent of temperature).

within Modelica.Thermal.HeatTransfer.Components;
model HeatCapacitor "Lumped thermal element storing heat"
  parameter SI.HeatCapacity C
    "Heat capacity of element (= cp*m)";
  SI.Temperature T(start=293.15, displayUnit="degC")
    "Temperature of element";
  SI.TemperatureSlope der_T(start=0)
    "Time derivative of temperature (= der(T))";
  Interfaces.HeatPort_a port
equation
  T = port.T;
  der_T = der(T);
  C*der(T) = port.Q_flow;
end HeatCapacitor;


Lumped thermal components

within Modelica.Thermal.HeatTransfer;
package Components "Lumped thermal components"
  extends Modelica.Icons.Package;
end Components;


Collects m heat flows. This is a model to collect the heat flows from m heatports to one single heatport.

within Modelica.Thermal.HeatTransfer.Components;
model ThermalCollector "Collects m heat flows"
  parameter Integer m(min=1)=3 "Number of collected heat flows";
  Interfaces.HeatPort_a port_a[m]
  Interfaces.HeatPort_b port_b

equation
  port_b.Q_flow + sum(port_a.Q_flow) = 0;
  port_a.T = fill(port_b.T, m);
end ThermalCollector;


Collects Ns x Np heat flows. This is a model to collect the heat flows from Ns x Np heatports to one single heatport.

within Modelica.Thermal.HeatTransfer.Components;
model ThermalCollectorMatrix "Collects Ns x Np heat flows"
  parameter Integer Ns(min=1) "Number of rows";
  parameter Integer Np(min=1) "Number of columns";
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_a[Ns, Np]
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port_b
equation
  port_b.Q_flow + sum(port_a.Q_flow) = 0;
  port_a.T = fill(port_b.T, Ns, Np);
end ThermalCollectorMatrix;