root/branches/maintenance/3.0/Modelica/Media/Air.mo

Revision 887, 57.2 kB (checked in by otter, 12 months ago)

Removed superfluous "fillPattern" annotations, if not accommpanied by a "fillColor" annotation (using special Dymola version provided by Erik)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1within Modelica.Media;
2package Air "Medium models for air"
3
4  package SimpleAir "Air: Simple dry air model (0..100 degC)"
5
6    extends Interfaces.PartialSimpleIdealGasMedium(
7       mediumName="SimpleAir",
8       cp_const=1005.45,
9       MM_const=0.0289651159,
10       R_gas=Constants.R/0.0289651159,
11       eta_const=1.82e-5,
12       lambda_const=0.026,
13       T_min=Cv.from_degC(0),
14       T_max=Cv.from_degC(100));
15
16    import SI = Modelica.SIunits;
17    import Cv = Modelica.SIunits.Conversions;
18    import Modelica.Constants;
19
20    constant FluidConstants[nS] fluidConstants=
21      FluidConstants(iupacName={"simple air"},
22                     casRegistryNumber={"not a real substance"},
23                     chemicalFormula={"N2, O2"},
24                     structureFormula={"N2, O2"},
25                     molarMass=Modelica.Media.IdealGases.Common.SingleGasesData.N2.MM)
26      "constant data for the fluid";
27
28    annotation (Documentation(info="<html>
29                              <h4>Simple Ideal gas air model for low temperatures</h4>
30                              <p>This model demonstrats how to use the PartialSimpleIdealGas base class to build a
31                              simple ideal gas model with a limited temperature validity range.</p>
32                              </html>"));
33  end SimpleAir;
34
35  package DryAirNasa "Air: Detailed dry air model as ideal gas (200..6000 K)"
36    extends IdealGases.Common.SingleGasNasa(
37     mediumName="Air",
38     data=IdealGases.Common.SingleGasesData.Air,
39     fluidConstants={IdealGases.Common.FluidData.N2});
40    annotation ( Documentation(info="<HTML>
41      <IMG SRC=\"../Images/Media/IdealGases/SingleGases/Air.png\"></HTML>"));
42
43    import Cv = Modelica.SIunits.Conversions;
44
45  redeclare function dynamicViscosity
46      "Simple polynomial for dry air (moisture influence small), valid from 73.15 K to 373.15 K"
47    extends Modelica.Icons.Function;
48    input ThermodynamicState state "Thermodynamic state record";
49    output DynamicViscosity eta "Dynamic viscosity";
50  algorithm
51    eta := Incompressible.TableBased.Polynomials_Temp.evaluate({(-4.96717436974791E-011), 5.06626785714286E-008, 1.72937731092437E-005}, Cv.to_degC(state.T));
52      annotation (Documentation(info="<html>
53Dynamic viscosity is computed from temperature using a second order polynomial with a range of validity between 73 and 373 K.
54</html>"));
55  end dynamicViscosity;
56
57    redeclare function thermalConductivity
58      "Simple polynomial for dry air (moisture influence small), valid from 73.15 K to 373.15 K"
59      extends Modelica.Icons.Function;
60      input ThermodynamicState state "Thermodynamic state record";
61      input Integer method=1 "Dummy for compatibility reasons";
62      output ThermalConductivity lambda "Thermal conductivity";
63    algorithm
64      lambda := Incompressible.TableBased.Polynomials_Temp.evaluate({(-4.8737307422969E-008), 7.67803133753502E-005, 0.0241814385504202},Cv.to_degC(state.T));
65
66      annotation (Documentation(info="<html>
67Thermal conductivity is computed from temperature using a second order polynomial with a range of validity between 73 and 373 K.
68</html>"));
69    end thermalConductivity;
70
71    annotation (Documentation(info="<html>
72Ideal gas medium model for dry air based on the package <a href=Modelica:Modelica.Media.IdealGases>IdealGases</a> with additional functions for dynamic viscosity and thermal conductivity in a limited temperature range.
73</html>"));
74  end DryAirNasa;
75
76  package MoistAir "Air: Moist air model (240 ... 400 K)"
77    extends Interfaces.PartialCondensingGases(
78       mediumName="Moist air",
79       substanceNames={"water", "air"},
80       final reducedX=true,
81       final singleState=false,
82       reference_X={0.01,0.99},
83       fluidConstants = {IdealGases.Common.FluidData.H2O,IdealGases.Common.FluidData.N2});
84
85    constant Integer Water=1
86      "Index of water (in substanceNames, massFractions X, etc.)";
87    constant Integer Air=2
88      "Index of air (in substanceNames, massFractions X, etc.)";
89    //     constant SI.Pressure psat_low=saturationPressureWithoutLimits(200.0);
90    //     constant SI.Pressure psat_high=saturationPressureWithoutLimits(422.16);
91    constant Real k_mair =  steam.MM/dryair.MM "ratio of molar weights";
92
93    constant IdealGases.Common.DataRecord dryair = IdealGases.Common.SingleGasesData.Air;
94    constant IdealGases.Common.DataRecord steam = IdealGases.Common.SingleGasesData.H2O;
95    constant SI.MolarMass[2] MMX = {steam.MM,dryair.MM}
96      "Molar masses of components";
97
98    import Modelica.Media.Interfaces;
99    import Modelica.Math;
100    import SI = Modelica.SIunits;
101    import Cv = Modelica.SIunits.Conversions;
102    import Modelica.Constants;
103    import Modelica.Media.IdealGases.Common.SingleGasNasa;
104
105    redeclare record extends ThermodynamicState
106      "ThermodynamicState record for moist air"
107    end ThermodynamicState;
108
109    redeclare replaceable model extends BaseProperties(
110      T(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default),
111      p(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default),
112      Xi(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default),
113      redeclare final constant Boolean standardOrderComponents=true)
114      "Moist air base properties record"
115
116      /* p, T, X = X[Water] are used as preferred states, since only then all
117     other quantities can be computed in a recursive sequence.
118     If other variables are selected as states, static state selection
119     is no longer possible and non-linear algebraic equations occur.
120      */
121      MassFraction x_water "Mass of total water/mass of dry air";
122      Real phi "Relative humidity";
123      annotation(Documentation(info="<html>
124This model computes thermodynamic properties of moist air from three independent (thermodynamic or/and numerical) state variables. Preferred numerical states are temperature T, pressure p and the reduced composition vector Xi, which contains the water mass fraction only. As an EOS the <b>ideal gas law</b> is used and associated restrictions apply. The model can also be used in the <b>fog region</b>, when moisture is present in its liquid state. However, it is assumed that the liquid water volume is negligible compared to that of the gas phase. Computation of thermal properties is based on property data of <a href=Modelica:Modelica.Media.Air.DryAirNasa> dry air</a> and water (source: VDI-W&auml;rmeatlas), respectively. Besides the standard thermodynamic variables <b>absolute and relative humidity</b>, x_water and phi, respectively, are given by the model. Upper case X denotes absolute humidity with respect to mass of moist air while absolute humidity with respect to mass of dry air only is denoted by a lower case x throughout the model. See <a href=Modelica:Modelica.Media.Air.MoistAir>package description</a> for further information.
125</html>"));
126
127    protected
128      MassFraction X_liquid "Mass fraction of liquid or solid water";
129      MassFraction X_steam "Mass fraction of steam water";
130      MassFraction X_air "Mass fraction of air";
131      MassFraction X_sat
132        "Steam water mass fraction of saturation boundary in kg_water/kg_moistair";
133      MassFraction x_sat
134        "Steam water mass content of saturation boundary in kg_water/kg_dryair";
135      AbsolutePressure p_steam_sat "Partial saturation pressure of steam";
136    equation
137      assert(T >= 200.0 and T <= 423.15, "
138Temperature T is not in the allowed range
139200.0 K <= (T =" + String(T) + " K) <= 423.15 K
140required from medium model \""       + mediumName + "\".");
141      MM = 1/(Xi[Water]/MMX[Water]+(1.0-Xi[Water])/MMX[Air]);
142
143      p_steam_sat = min(saturationPressure(T),0.999*p);
144      X_sat = min(p_steam_sat * k_mair/max(100*Constants.eps, p - p_steam_sat)*(1 - Xi[Water]), 1.0)
145        "Water content at saturation with respect to actual water content";
146      X_liquid = max(Xi[Water] - X_sat, 0.0);
147      X_steam  = Xi[Water]-X_liquid;
148      X_air    = 1-Xi[Water];
149
150      h = specificEnthalpy_pTX(p,T,Xi);
151      R = dryair.R*(X_air/(1 - X_liquid)) + steam.R*X_steam/(1 - X_liquid);
152      //
153      u = h - R*T;
154      d = p/(R*T);
155      /* Note, u and d are computed under the assumption that the volume of the liquid
156         water is neglible with respect to the volume of air and of steam
157      */
158      state.p = p;
159      state.T = T;
160      state.X = X;
161
162      // these x are per unit mass of DRY air!
163      x_sat    = k_mair*p_steam_sat/max(100*Constants.eps,p - p_steam_sat);
164      x_water = Xi[Water]/max(X_air,100*Constants.eps);
165      phi = p/p_steam_sat*Xi[Water]/(Xi[Water] + k_mair*X_air);
166    end BaseProperties;
167
168    redeclare function setState_pTX
169      "Return thermodynamic state as function of pressure p, temperature T and composition X"
170      extends Modelica.Icons.Function;
171      input AbsolutePressure p "Pressure";
172      input Temperature T "Temperature";
173      input MassFraction X[:]=reference_X "Mass fractions";
174      output ThermodynamicState state "Thermodynamic state";
175    algorithm
176      state := if size(X,1) == nX then ThermodynamicState(p=p,T=T, X=X) else 
177             ThermodynamicState(p=p,T=T, X=cat(1,X,{1-sum(X)}));
178      annotation (Documentation(info="<html>
179The <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state record</a> is computed from pressure p, temperature T and composition X.
180</html>"));
181    end setState_pTX;
182
183    redeclare function setState_phX
184      "Return thermodynamic state as function of pressure p, specific enthalpy h and composition X"
185      extends Modelica.Icons.Function;
186      input AbsolutePressure p "Pressure";
187      input SpecificEnthalpy h "Specific enthalpy";
188      input MassFraction X[:]=reference_X "Mass fractions";
189      output ThermodynamicState state "Thermodynamic state";
190    algorithm
191      state := if size(X,1) == nX then ThermodynamicState(p=p,T=T_phX(p,h,X),X=X) else 
192             ThermodynamicState(p=p,T=T_phX(p,h,X), X=cat(1,X,{1-sum(X)}));
193      annotation (Documentation(info="<html>
194The <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state record</a> is computed from pressure p, specific enthalpy h and composition X.
195</html>"));
196    end setState_phX;
197
198    redeclare function setState_dTX
199      "Return thermodynamic state as function of density d, temperature T and composition X"
200      extends Modelica.Icons.Function;
201      input Density d "density";
202      input Temperature T "Temperature";
203      input MassFraction X[:]=reference_X "Mass fractions";
204      output ThermodynamicState state "Thermodynamic state";
205    algorithm
206      state := if size(X,1) == nX then ThermodynamicState(p=d*({steam.R,dryair.R}*X)*T,T=T,X=X) else 
207             ThermodynamicState(p=d*({steam.R,dryair.R}*cat(1,X,{1-sum(X)}))*T,T=T, X=cat(1,X,{1-sum(X)}));
208      annotation (Documentation(info="<html>
209The <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state record</a> is computed from density d, temperature T and composition X.
210</html>"));
211    end setState_dTX;
212
213    function Xsaturation
214      "Return absolute humitity per unit mass of moist air at saturation as a function of the thermodynamic state record"
215      input ThermodynamicState state "Thermodynamic state record";
216      output MassFraction X_sat "Steam mass fraction of sat. boundary";
217    algorithm
218      X_sat := k_mair/(state.p/min(saturationPressure(state.T),0.999*state.p) - 1 + k_mair);
219      annotation (Documentation(info="<html>
220Absolute humidity per unit mass of moist air at saturation is computed from pressure and temperature in the state record. Note, that unlike X_sat in the BaseProperties model this mass fraction refers to mass of moist air at saturation.
221</html>"));
222    end Xsaturation;
223
224    function xsaturation
225      "Return absolute humitity per unit mass of dry air at saturation as a function of the thermodynamic state record"
226      input ThermodynamicState state "Thermodynamic state record";
227      output MassFraction x_sat "Absolute humidity per unit mass of dry air";
228    algorithm
229      x_sat:=k_mair*saturationPressure(state.T)/max(100*Constants.eps,state.p - saturationPressure(state.T));
230      annotation (Documentation(info="<html>
231Absolute humidity per unit mass of dry air at saturation is computed from pressure and temperature in the thermodynamic state record.
232</html>"));
233    end xsaturation;
234
235    function xsaturation_pT
236      "Return absolute humitity per unit mass of dry air at saturation as a function of pressure p and temperature T"
237      input AbsolutePressure p "Pressure";
238      input SI.Temperature T "Temperature";
239      output MassFraction x_sat "Absolute humidity per unit mass of dry air";
240    algorithm
241      x_sat:=k_mair*saturationPressure(T)/max(100*Constants.eps,p - saturationPressure(T));
242      annotation (Documentation(info="<html>
243Absolute humidity per unit mass of dry air at saturation is computed from pressure and temperature.
244</html>"));
245    end xsaturation_pT;
246
247    function massFraction_pTphi
248      "Return steam mass fraction as a function of relative humidity phi and temperature T"
249      input AbsolutePressure p "Pressure";
250      input Temperature T "Temperature";
251      input Real phi "Relative humidity (0 ... 1.0)";
252      output MassFraction X_steam "Absolute humidity, steam mass fraction";
253    protected
254      constant Real k = 0.621964713077499 "Ratio of molar masses";
255      AbsolutePressure psat = saturationPressure(T) "Saturation pressure";
256    algorithm
257      X_steam := phi*k/(k*phi+p/psat-phi);
258      annotation (Documentation(info="<html>
259Absolute humidity per unit mass of moist air is computed from temperature, pressure and relative humidity.
260</html>"));
261    end massFraction_pTphi;
262
263    function relativeHumidity_pTX
264      "Return relative humidity as a function of pressure p, temperature T and composition X"
265      input SI.Pressure p "Pressure";
266      input SI.Temperature T "Temperature";
267      input SI.MassFraction[:] X "Composition";
268      output Real phi "Relative humidity";
269    protected
270      SI.Pressure p_steam_sat "Saturation pressure";
271      SI.MassFraction X_air "Dry air mass fraction";
272    algorithm
273      p_steam_sat :=min(saturationPressure(T), 0.999*p);
274      X_air    :=1 - X[Water];
275      phi :=max(0.0,min(1.0, p/p_steam_sat*X[Water]/(X[Water] + k_mair*X_air)));
276      annotation (Documentation(info="<html>
277Relative humidity is computed from pressure, temperature and composition with 1.0 as the upper limit at saturation. Water mass fraction is the first entry in the composition vector.
278</html>"));
279    end relativeHumidity_pTX;
280
281    function relativeHumidity
282      "Return relative humidity as a function of the thermodynamic state record"
283      input ThermodynamicState state "Thermodynamic state";
284      output Real phi "Relative humidity";
285    algorithm
286      phi:=relativeHumidity_pTX(state.p, state.T, state.X);
287      annotation (Documentation(info="<html>
288Relative humidity is computed from the thermodynamic state record with 1.0 as the upper limit at saturation.
289</html>"));
290    end relativeHumidity;
291
292    /*   
293    redeclare function setState_psX "Return thermodynamic state as function of p, s and composition X"
294      extends Modelica.Icons.Function;
295      input AbsolutePressure p "Pressure";
296      input SpecificEntropy s "Specific entropy";
297      input MassFraction X[:]=reference_X "Mass fractions";
298      output ThermodynamicState state;
299    algorithm
300      state := if size(X,1) == nX then ThermodynamicState(p=p,T=T_psX(s,p,X),X=X)
301        else ThermodynamicState(p=p,T=T_psX(p,s,X), X=cat(1,X,{1-sum(X)}));       
302    end setState_psX;
303*/
304
305    redeclare function extends gasConstant
306      "Return ideal gas constant as a function from thermodynamic state, only valid for phi<1"
307    algorithm
308      R := dryair.R*(1-state.X[Water]) + steam.R*state.X[Water];
309      annotation (Documentation(info="<html>
310The ideal gas constant for moist air is computed from <a href=Modelica:Modelica.Media.Air.MoistAir.ThermodynamicState>thermodynamic state</a> assuming that all water is in the gas phase.
311</html>"));
312    end gasConstant;
313
314    function gasConstant_X
315      "Return ideal gas constant as a function from composition X"
316      input SI.MassFraction X[:] "Gas phase composition";
317      output SI.SpecificHeatCapacity R "Ideal gas constant";
318    algorithm
319      R := dryair.R*(1-X[Water]) + steam.R*X[Water];
320      annotation (Documentation(info="<html>
321The ideal gas constant for moist air is computed from the gas phase composition. The first entry in composition vector X is the steam mass fraction of the gas phase.
322</html>"));
323    end gasConstant_X;
324
325    function saturationPressureLiquid
326      "Return saturation pressure of water as a function of temperature T in the range of 273.16 to 373.16 K"
327
328      extends Modelica.Icons.Function;
329      input SI.Temperature Tsat "saturation temperature";
330      output SI.AbsolutePressure psat "saturation pressure";
331      annotation(Inline=false,smoothOrder=5,
332        Documentation(derivative=saturationPressureLiquid_der,info="<html>
333Saturation pressure of water above the triple point temperature is computed from temperature. It's range of validity is between
334273.16 and 373.16 K. Outside these limits a less accurate result is returned.
335</html>"));
336    algorithm
337      psat := 611.657*Math.exp(17.2799 - 4102.99/(Tsat - 35.719));
338    end saturationPressureLiquid;
339
340    function saturationPressureLiquid_der
341      "Time derivative of saturationPressureLiquid"
342
343      extends Modelica.Icons.Function;
344      input SI.Temperature Tsat "Saturation temperature";
345      input Real dTsat(unit="K/s") "Saturation temperature derivative";
346      output Real psat_der(unit="Pa/s") "Saturation pressure";
347      annotation(Inline=false,smoothOrder=5,
348        Documentation(info="<html>
349Derivative function of <a href=Modelica:Modelica.Media.Air.MoistAir.saturationPressureLiquid>saturationPressureLiquid</a>
350</html>"));
351    algorithm
352    /*psat := 611.657*Math.exp(17.2799 - 4102.99/(Tsat - 35.719));*/
353      psat_der:=611.657*Math.exp(17.2799 - 4102.99/(Tsat - 35.719))*4102.99*dTsat/(Tsat - 35.719)/(Tsat - 35.719);
354
355    end saturationPressureLiquid_der;
356
357    function sublimationPressureIce
358      "Return sublimation pressure of water as a function of temperature T between 223.16 and 273.16 K"
359
360      extends Modelica.Icons.Function;
361      input SI.Temperature Tsat "sublimation temperature";
362      output SI.AbsolutePressure psat "sublimation pressure";
363      annotation(Inline=false,smoothOrder=5,
364        Documentation(derivative=sublimationPressureIce_der,info="<html>
365Sublimation pressure of water below the triple point temperature is computed from temperature. It's range of validity is between
366 223.16 and 273.16 K. Outside of these limits a less accurate result is returned.
367</html>"));
368    algorithm
369      psat := 611.657*Math.exp(22.5159*(1.0 - 273.16/Tsat));
370    end sublimationPressureIce;
371
372    function sublimationPressureIce_der
373      "Derivative function for 'sublimationPressureIce'"
374
375      extends Modelica.Icons.Function;
376      input SI.Temperature Tsat "Sublimation temperature";
377      input Real dTsat(unit="K/s") "Time derivative of sublimation temperature";
378      output Real psat_der(unit="Pa/s") "Sublimation pressure";
379      annotation(Inline=false,smoothOrder=5,
380        Documentation(info="<html>
381Derivative function of <a href=Modelica:Modelica.Media.Air.MoistAir.sublimationPressureIce>saturationPressureIce</a>
382</html>"));
383    algorithm
384      /*psat := 611.657*Math.exp(22.5159*(1.0 - 273.16/Tsat));*/
385      psat_der:=611.657*Math.exp(22.5159*(1.0 - 273.16/Tsat))*22.5159*273.16*dTsat/Tsat/Tsat;
386    end sublimationPressureIce_der;
387
388    redeclare function extends saturationPressure
389      "Return saturation pressure of water as a function of temperature T between 223.16 and 373.16 K"
390
391      annotation(Inline=false,smoothOrder=5,
392        Documentation(derivative=saturationPressure_der,info="<html>
393Saturation pressure of water in the liquid and the solid region is computed using an Antoine-type correlation. It's range of validity is between 223.16 and 373.16 K. Outside of these limits a (less accurate) result is returned. Functions for the
394<a href=Modelica.Media.Air.MoistAir.sublimationPressureIce>solid</a> and the <a href=\"Modelica.Media.MoistAir.saturationPressureLiquid\"> liquid</a> region, respectively, are combined using the first derivative continuous <a href=Modelica.Media.MoistAir.Utilities.spliceFunction>spliceFunction</a>.
395</html>"));
396    algorithm
397      psat := Utilities.spliceFunction(saturationPressureLiquid(Tsat),sublimationPressureIce(Tsat),Tsat-273.16,1.0);
398    end saturationPressure;
399
400    function saturationPressure_der
401      "Derivative function for 'saturationPressure'"
402      input Temperature Tsat "Saturation temperature";
403      input Real dTsat(unit="K/s") "Time derivative of saturation temperature";
404      output Real psat_der(unit="Pa/s") "Saturation pressure";
405      annotation(Inline=false,smoothOrder=5,
406        Documentation(info="<html>
407Derivative function of <a href=Modelica:Modelica.Media.Air.MoistAir.saturationPressure>saturationPressure</a>
408</html>"));
409
410    algorithm
411      /*psat := Utilities.spliceFunction(saturationPressureLiquid(Tsat),sublimationPressureIce(Tsat),Tsat-273.16,1.0);*/
412      psat_der := Utilities.spliceFunction_der(
413        saturationPressureLiquid(Tsat),
414        sublimationPressureIce(Tsat),
415        Tsat - 273.16,
416        1.0,
417        saturationPressureLiquid_der(Tsat=Tsat, dTsat=dTsat),
418        sublimationPressureIce_der(Tsat=Tsat, dTsat=dTsat),
419        dTsat,
420        0);
421    end saturationPressure_der;
422
423    function saturationTemperature
424      "Return saturation temperature of water as a function of (partial) pressure p"
425
426      input SI.Pressure p "Pressure";
427      input SI.Temperature T_min=200 "Lower boundary of solution";
428      input SI.Temperature T_max=400 "Upper boundary of solution";
429      output SI.Temperature T "Saturation temperature";
430
431    protected
432    package Internal
433       extends Modelica.Media.Common.OneNonLinearEquation;
434
435     redeclare record extends f_nonlinear_Data
436       // Define data to be passed to user function
437     end f_nonlinear_Data;
438
439     redeclare function extends f_nonlinear
440     algorithm
441        y:=saturationPressure(x);
442      // Compute the non-linear equation: y = f(x, Data)
443     end f_nonlinear;
444
445     // Dummy definition
446     redeclare function extends solve
447     end solve;
448    end Internal;
449    algorithm
450      T:=Internal.solve(p, T_min, T_max);
451      annotation (Documentation(info="<html>
452 Computes saturation temperature from (partial) pressure via numerical inversion of the function <a href=Modelica:Modelica.Media.Air.MoistAir.saturationPressure>saturationPressure</a>. Therefore additional inputs are required (or the defaults are used) for upper and lower temperature bounds. 
453</html>"));
454    end saturationTemperature;
455
456   redeclare function extends enthalpyOfVaporization
457      "Return enthalpy of vaporization of water as a function of temperature T, 0 - 130 degC"
458   algorithm
459    /*r0 := 1e3*(2501.0145 - (T - 273.15)*(2.3853 + (T - 273.15)*(0.002969 - (T
460      - 273.15)*(7.5293e-5 + (T - 273.15)*4.6084e-7))));*/
461   //katrin: replaced by linear correlation, simpler and more accurate in the entire region
462   //source VDI-Waermeatlas, linear inter- and extrapolation between values for 0.01°C and 40°C.
463   r0:=(2405900-2500500)/(40-0)*(T-273.16)+2500500;
464      annotation (Documentation(info="<html>
465Enthalpy of vaporization of water is computed from temperature in the region of 0 to 130 °C.
466</html>"));
467   end enthalpyOfVaporization;
468
469    function HeatCapacityOfWater
470      "Return specific heat capacity of water (liquid only) as a function of temperature T"
471      extends Modelica.Icons.Function;
472      input Temperature T "Temperature";
473      output SpecificHeatCapacity cp_fl "Specific heat capacity of liquid";
474      annotation (Documentation(info="<html>
475The specific heat capacity of water (liquid and solid) is calculated using a
476                 polynomial approach and data from VDI-Waermeatlas 8. Edition (Db1)
477</html>"));
478    algorithm
479      cp_fl := 1e3*(4.2166 - (T - 273.15)*(0.0033166 + (T - 273.15)*(0.00010295
480         - (T - 273.15)*(1.3819e-6 + (T - 273.15)*7.3221e-9))));
481    end HeatCapacityOfWater;
482
483   redeclare function extends enthalpyOfLiquid
484      "Return enthalpy of liquid water as a function of temperature T(use enthalpyOfWater instead)"
485
486     annotation(Inline=false,smoothOrder=5,
487        Documentation(info="<html>
488Specific enthalpy of liquid water is computed from temperature using a polynomial approach. Kept for compatibility reasons, better use <a href=Modelica:Modelica.Media.Air.MoistAir.enthalpyOfWater>enthalpyOfWater</a> instead.
489</html>"));
490   algorithm
491     h := (T - 273.15)*1e3*(4.2166 - 0.5*(T - 273.15)*(0.0033166 + 0.333333*(T - 273.15)*(0.00010295
492        - 0.25*(T - 273.15)*(1.3819e-6 + 0.2*(T - 273.15)*7.3221e-9))));
493   end enthalpyOfLiquid;
494
495   redeclare function extends enthalpyOfGas
496      "Return specific enthalpy of gas (air and steam) as a function of temperature T and composition X"
497
498     annotation(Inline=false,smoothOrder=5,
499        Documentation(info="<html>
500Specific enthalpy of moist air is computed from temperature, provided all water is in the gaseous state. The first entry in the composition vector X must be the mass fraction of steam. For a function that also covers the fog region please refer to <a href=Modelica:Modelica.Media.Air.MoistAir.h_pTX>h_pTX</a>.
501</html>"));
502   algorithm
503     h := SingleGasNasa.h_Tlow(data=steam, T=T, refChoice=3, h_off=46479.819+2501014.5)*X[Water]
504          + SingleGasNasa.h_Tlow(data=dryair, T=T, refChoice=3, h_off=25104.684)*(1.0-X[Water]);
505   end enthalpyOfGas;
506
507   redeclare function extends enthalpyOfCondensingGas
508      "Return specific enthalpy of steam as a function of temperature T"
509
510     annotation(Inline=false,smoothOrder=5,
511        Documentation(info="<html>
512Specific enthalpy of steam is computed from temperature.
513</html>"));
514   algorithm
515     h := SingleGasNasa.h_Tlow(data=steam, T=T, refChoice=3, h_off=46479.819+2501014.5);
516   end enthalpyOfCondensingGas;
517
518  function enthalpyOfWater
519      "Computes specific enthalpy of water (solid/liquid) near atmospheric pressure from temperature T"
520    input SIunits.Temperature T "Temperature";
521    output SIunits.SpecificEnthalpy h "Specific enthalpy of water";
522  annotation (derivative=enthalpyOfWater_der, Documentation(info="<html>
523Specific enthalpy of water (liquid and solid) is computed from temperature using constant properties as follows:<br>
524<ul>
525<li>  heat capacity of liquid water:4200 J/kg
526<li>  heat capacity of solid water: 2050 J/kg
527<li>  enthalpy of fusion (liquid=>solid): 333000 J/kg
528</ul>
529Pressure is assumed to be around 1 bar. This function is usually used to determine the specific enthalpy of the liquid or solid fraction of moist air.
530</html>"));
531  algorithm
532  /*simple model assuming constant properties:
533  heat capacity of liquid water:4200 J/kg
534  heat capacity of solid water: 2050 J/kg
535  enthalpy of fusion (liquid=>solid): 333000 J/kg*/
536
537    h:=Utilities.spliceFunction(4200*(T-273.15),2050*(T-273.15)-333000,T-273.16,0.1);
538  end enthalpyOfWater;
539
540  function enthalpyOfWater_der "Derivative function of enthalpyOfWater"
541    input SIunits.Temperature T "Temperature";
542    input Real dT(unit="K/s") "Time derivative of temperature";
543    output Real dh(unit="J/(kg.s)") "Time derivative of specific enthalpy";
544  algorithm
545  /*simple model assuming constant properties:
546  heat capacity of liquid water:4200 J/kg
547  heat capacity of solid water: 2050 J/kg
548  enthalpy of fusion (liquid=>solid): 333000 J/kg*/
549
550    //h:=Utilities.spliceFunction(4200*(T-273.15),2050*(T-273.15)-333000,T-273.16,0.1);
551    dh:=Utilities.spliceFunction_der(4200*(T-273.15),2050*(T-273.15)-333000,T-273.16,0.1,4200*dT,2050*dT,dT,0);
552      annotation (Documentation(info="<html>
553Derivative function for <a href=Modelica:Modelica.Media.Air.MoistAir.enthalpyOfWater>enthalpyOfWater</a>.
554 
555</html>"));
556  end enthalpyOfWater_der;
557
558   redeclare function extends pressure
559      "Returns pressure of ideal gas as a function of the thermodynamic state record"
560   algorithm
561    p := state.p;
562      annotation (Documentation(info="<html>
563Pressure is returned from the thermodynamic state record input as a simple assignment.
564</html>"));
565   end pressure;
566
567   redeclare function extends temperature
568      "Return temperature of ideal gas as a function of the thermodynamic state record"
569   algorithm
570     T := state.T;
571      annotation (Documentation(info="<html>
572Temperature is returned from the thermodynamic state record input as a simple assignment.
573</html>"));
574   end temperature;
575
576  function T_phX
577      "Return temperature as a function of pressure p, specific enthalpy h and composition X"
578    input AbsolutePressure p "Pressure";
579    input SpecificEnthalpy h "Specific enthalpy";
580    input MassFraction[:] X "Mass fractions of composition";
581    output Temperature T "Temperature";
582
583    protected
584  package Internal
585        "Solve h(data,T) for T with given h (use only indirectly via temperature_phX)"
586    extends Modelica.Media.Common.OneNonLinearEquation;
587    redeclare record extends f_nonlinear_Data
588          "Data to be passed to non-linear function"
589      extends Modelica.Media.IdealGases.Common.DataRecord;
590    end f_nonlinear_Data;
591
592    redeclare function extends f_nonlinear
593    algorithm
594        y := h_pTX(p,x,X);
595    end f_nonlinear;
596
597    // Dummy definition has to be added for current Dymola
598    redeclare function extends solve
599    end solve;
600  end Internal;
601
602  algorithm
603    T := Internal.solve(h, 200, 6000, p, X[1:nXi], steam);
604      annotation (Documentation(info="<html>
605Temperature is computed from pressure, specific enthalpy and composition via numerical inversion of function <a href=Modelica:Modelica.Media.Air.MoistAir.h_pTX>h_pTX</a>.
606</html>"));
607  end T_phX;
608
609   redeclare function extends density
610      "Returns density of ideal gas as a function of the thermodynamic state record"
611   algorithm
612     d := state.p/(gasConstant(state)*state.T);
613      annotation (Documentation(info="<html>
614Density is computed from pressure, temperature and composition in the thermodynamic state record applying the ideal gas law.
615</html>"));
616   end density;
617
618  redeclare function extends specificEnthalpy
619      "Return specific enthalpy of moist air as a function of the thermodynamic state record"
620  algorithm
621    h := h_pTX(state.p, state.T, state.X);
622      annotation (Documentation(info="<html>
623Specific enthalpy of moist air is computed from the thermodynamic state record. The fog region is included for both, ice and liquid fog.
624</html>"));
625  end specificEnthalpy;
626
627  function h_pTX
628      "Return specific enthalpy of moist air as a function of pressure p, temperature T and composition X"
629    extends Modelica.Icons.Function;
630    input SI.Pressure p "Pressure";
631    input SI.Temperature T "Temperature";
632    input SI.MassFraction X[:] "Mass fractions of moist air";
633    output SI.SpecificEnthalpy h "Specific enthalpy at p, T, X";
634    annotation(Inline=false,smoothOrder=1,
635        Documentation(derivative=h_pTX_der,info="<html>
636Specific enthalpy of moist air is computed from pressure, temperature and composition with X[1] as the total water mass fraction. The fog region is included for both, ice and liquid fog.
637</html>"));
638    protected
639    SI.AbsolutePressure p_steam_sat "Partial saturation pressure of steam";
640    SI.MassFraction X_sat "Absolute humidity per unit mass of moist air";
641    SI.MassFraction X_liquid "mass fraction of liquid water"