root/branches/maintenance/2.2.2/Modelica/Media/Incompressible.mo

Revision 597, 31.9 kB (checked in by otter, 15 months ago)

Changed inconsistent writing of "user's guide" at all places to
"User's Guide" (reported by Dietmar Winkler)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1within Modelica.Media;
2package Incompressible
3  "Medium model for T-dependent properties, defined by tables or polynomials" 
4 
5  import SI = Modelica.SIunits;
6  import Cv = Modelica.SIunits.Conversions;
7  import Modelica.Constants;
8  import Modelica.Math;
9 
10  package Common "Common data structures" 
11   
12    // Extended record for input to functions based on polynomials
13    record BaseProps_Tpoly "Fluid state record" 
14      extends Modelica.Media.Interfaces.PartialMedium.ThermodynamicState;
15      //      SI.SpecificHeatCapacity cp "specific heat capacity";
16      SI.Temperature T "temperature";
17      SI.Pressure p "pressure";
18      //    SI.Density d "density";
19    end BaseProps_Tpoly;
20   
21    //     record BaseProps_Tpoly_old "fluid state record"
22    //       extends Modelica.Media.Interfaces.PartialMedium.ThermodynamicState;
23    //       //      SI.SpecificHeatCapacity cp "specific heat capacity";
24    //       SI.Temperature T "temperature";
25    //       SI.Pressure p "pressure";
26    //       //    SI.Density d "density";
27    //       parameter Real[:] poly_rho "polynomial coefficients";
28    //       parameter Real[:] poly_Cp "polynomial coefficients";
29    //       parameter Real[:] poly_eta "polynomial coefficients";
30    //       parameter Real[:] poly_pVap "polynomial coefficients";
31    //       parameter Real[:] poly_lam "polynomial coefficients";
32    //       parameter Real[:] invTK "inverse T [1/K]";
33    //     end BaseProps_Tpoly_old;
34  end Common;
35 
36  package TableBased "Incompressible medium properties based on tables" 
37   
38    import Poly = Modelica.Media.Incompressible.TableBased.Polynomials_Temp;
39   
40    extends Modelica.Media.Interfaces.PartialMedium(
41       final reducedX=true,
42       mediumName="tableMedium",
43       redeclare record ThermodynamicState=Common.BaseProps_Tpoly,
44       singleState=true);
45    // Constants to be set in actual Medium
46    constant Boolean enthalpyOfT=true 
47      "true if enthalpy is approximated as a function of T only, (p-dependence neglected)";
48    constant Boolean densityOfT = size(tableDensity,1) > 1 
49      "true if density is a function of temperature";
50    constant Temperature T_min "Minimum temperature valid for medium model";
51    constant Temperature T_max "Maximum temperature valid for medium model";
52    constant Temperature T0=273.15 "reference Temperature";
53    constant SpecificEnthalpy h0=0 "reference enthalpy at T0, reference_p";
54    constant SpecificEntropy s0=0 "reference entropy at T0, reference_p";
55    constant MolarMass MM_const=0.1 "Molar mass";
56    constant Integer npol=2 "degree of polynomial used for fitting";
57    constant Integer neta=size(tableViscosity,1) 
58      "number of data points for viscosity";
59    constant Real[:,:] tableDensity "Table for rho(T)";
60    constant Real[:,:] tableHeatCapacity "Table for Cp(T)";
61    constant Real[:,:] tableViscosity "Table for eta(T)";
62    constant Real[:,:] tableVaporPressure "Table for pVap(T)";
63    constant Real[:,:] tableConductivity "Table for lambda(T)";
64    //    constant Real[:] TK=tableViscosity[:,1]+T0*ones(neta) "Temperature for Viscosity";
65    constant Boolean TinK "true if T[K],Kelvin used for table temperatures";
66    constant Boolean hasDensity = not (size(tableDensity,1)==0);
67    constant Boolean hasHeatCapacity = not (size(tableHeatCapacity,1)==0);
68    constant Boolean hasViscosity = not (size(tableViscosity,1)==0);
69    constant Boolean hasVaporPressure = not (size(tableVaporPressure,1)==0);
70    final constant Real invTK[neta] = invertTemp(tableViscosity[:,1],TinK);
71  annotation(keepConstant = true, Documentation(info="<HTML>
72<p>
73This is the base package for medium models of incompressible fluids based on
74tables. The minimal data to provide for a useful medium description is tables
75of density and heat capacity as functions of temperature.
76</p>
77
78<h4>Using the package TableBased</h4>
79<p>
80To implement a new medium model, create a package that <b>extends</b> TableBased
81and provides one or more of the constant tables:
82</p>
83
84<pre>
85tableDensity        = [T, d];
86tableHeatCapacity   = [T, Cp];
87tableConductivity   = [T, lam];
88tableViscosity      = [T, eta];
89tableVaporPressure  = [T, pVap];
90</pre>
91
92<p>
93The table data is used to fit constant polynomials of order <b>npol</b>, the
94temperature data points do not need to be same for different properties. Properties
95like enthalpy, inner energy and entropy are calculated consistently from integrals
96and derivatives of d(T) and Cp(T). The minimal
97data for a useful medium model is thus density and heat capacity. Transport
98properties and vapor pressure are optional, if the data tables are empty the corresponding
99function calls can not be used.
100</p>
101</HTML>"));
102    final constant Real poly_rho[:] = if hasDensity then 
103                                         Poly.fitting(tableDensity[:,1],tableDensity[:,2],npol) else 
104                                           zeros(npol+1) annotation(keepConstant = true);
105    final constant Real poly_Cp[:] = if hasHeatCapacity then 
106                                         Poly.fitting(tableHeatCapacity[:,1],tableHeatCapacity[:,2],npol) else 
107                                           zeros(npol+1) annotation(keepConstant = true);
108    final constant Real poly_eta[:] = if hasViscosity then 
109                                         Poly.fitting(invTK, Math.log(tableViscosity[:,2]),npol) else 
110                                           zeros(npol+1) annotation(keepConstant = true);
111    final constant Real poly_pVap[:] = if hasVaporPressure then 
112                                         Poly.fitting(tableVaporPressure[:,1],tableVaporPressure[:,2],npol) else 
113                                            zeros(npol+1) annotation(keepConstant= true);
114    final constant Real poly_lam[:] = if size(tableConductivity,1)>0 then 
115                                         Poly.fitting(tableConductivity[:,1],tableConductivity[:,2],npol) else 
116                                           zeros(npol+1) annotation(keepConstant = true);
117    function invertTemp "function to invert temperatures" 
118      input Real[:] table "table temperature data";
119      input Boolean Tink "flag for Celsius or Kelvin";
120      output Real invTable[size(table,1)] "inverted temperatures";
121    algorithm 
122      for i in 1:size(table,1) loop
123        invTable[i] := if TinK then 1/table[i] else 1/Cv.from_degC(table[i]);
124      end for;
125    end invertTemp;
126   
127    redeclare model extends BaseProperties(
128      R=Modelica.Constants.R,
129      p_bar=Cv.to_bar(p),
130      T_degC(start = T_start-273.15)=Cv.to_degC(T),
131      T(start = T_start,
132        stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default)) 
133      "Base properties of T dependent medium" 
134     
135      annotation(Documentation(info="<html>
136<p>
137Note that the inner energy neglects the pressure dependence, which is only
138true for an incompressible medium with d = constant. The neglected term is
139p-reference_p)/rho*(T/rho)*(partial rho /partial T). This is very small for
140liquids due to proportionality to 1/d^2, but can be problematic for gases that are
141modeled incompressible.
142</p>
143
144<p>                               
145Enthalpy is never a function of T only (h = h(T) + (p-reference_p)/d), but the
146error is also small and non-linear systems can be avoided. In particular,
147non-linear systems are small and local as opposed to large and over all volumes.
148</p>                               
149   
150<p>
151Entropy is calculated as
152</p>
153<pre>
154  s = s0 + integral(Cp(T)/T,dt)
155</pre>
156<p>
157which is only exactly true for a fluid with constant density d=d0.
158</p>
159</html>
160      "));
161      SI.SpecificHeatCapacity cp "specific heat capacity";
162      parameter SI.Temperature T_start = 298.15 "initial temperature";
163    equation 
164      assert(hasDensity,"Medium " + mediumName +
165                        " can not be used without assigning tableDensity.");
166      assert(T >= T_min and T <= T_max, "Temperature T (= " + String(T) +
167             " K) is not in the allowed range (" + String(T_min) +
168             " K <= T <= " + String(T_max) + " K) required from medium model \""
169             + mediumName + "\".");
170      cp = Poly.evaluate(poly_Cp,if TinK then T else T_degC);
171      h = if enthalpyOfT then h_T(T) else  h_pT(p,T,densityOfT);
172      if singleState then
173        u = h_T(T) - reference_p/d;
174      else
175        u = h - p/d;
176      end if;
177      d = Poly.evaluate(poly_rho,if TinK then T else T_degC);
178      state.T = T;
179      state.p = p;
180      MM = MM_const;
181    end BaseProperties;
182   
183    redeclare function extends setState_pTX
184      "Returns state record, given pressure and temperature" 
185    algorithm 
186      state := ThermodynamicState(p=p,T=T);
187    end setState_pTX;
188   
189    redeclare function extends setState_dTX
190      "Returns state record, given pressure and temperature" 
191    algorithm 
192      assert(false, "for incompressible media with d(T) only, state can not be set from density and temperature");
193    end setState_dTX;
194   
195    function setState_pT "returns state record as function of p and T" 
196      input AbsolutePressure p "pressure";
197      input Temperature T "temperature";
198      output ThermodynamicState state "thermodynamic state";
199    algorithm 
200      state.T := T;
201      state.p := p;
202    end setState_pT;
203   
204    redeclare function extends setState_phX
205      "Returns state record, given pressure and specific enthalpy" 
206    algorithm 
207      state :=ThermodynamicState(p=p,T=T_ph(p,h));
208    end setState_phX;
209   
210    function setState_ph "returns state record as function of p and h" 
211      input AbsolutePressure p "pressure";
212      input SpecificEnthalpy h "specific enthalpy";
213      output ThermodynamicState state "thermodynamic state";
214    algorithm 
215      state :=ThermodynamicState(p=p,T=T_ph(p,h));
216    end setState_ph;
217   
218    redeclare function extends setState_psX
219      "Returns state record, given pressure and specific entropy" 
220    algorithm 
221      state :=ThermodynamicState(p=p,T=T_ps(p,s));
222    end setState_psX;
223   
224    function setState_ps "returns state record as function of p and s" 
225      input AbsolutePressure p "pressure";
226      input SpecificEntropy s "specific entropy";
227      output ThermodynamicState state "thermodynamic state";
228    algorithm 
229      state :=ThermodynamicState(p=p,T=T_ps(p,s));
230    end setState_ps;
231   
232    redeclare function extends specificHeatCapacityCv
233      "Specific heat capacity at constant volume (or pressure) of medium" 
234     
235     annotation(smoothOrder=2);
236    algorithm 
237      assert(hasHeatCapacity,"Specific Heat Capacity, Cv, is not defined for medium "
238                                             + mediumName + ".");
239      cv := Poly.evaluate(poly_Cp,if TinK then state.T else state.T - 273.15);
240    end specificHeatCapacityCv;
241   
242    redeclare function extends specificHeatCapacityCp
243      "Specific heat capacity at constant volume (or pressure) of medium" 
244     
245     annotation(smoothOrder=2);
246    algorithm 
247      assert(hasHeatCapacity,"Specific Heat Capacity, Cv, is not defined for medium "
248                                             + mediumName + ".");
249      cp := Poly.evaluate(poly_Cp,if TinK then state.T else state.T - 273.15);
250    end specificHeatCapacityCp;
251   
252    redeclare function extends dynamicViscosity
253     
254     annotation(smoothOrder=2);
255    algorithm 
256      assert(size(tableViscosity,1)>0,"DynamicViscosity, eta, is not defined for medium "
257                                             + mediumName + ".");
258      eta := Math.exp(Poly.evaluate(poly_eta, 1/state.T));
259    end dynamicViscosity;
260   
261    redeclare function extends thermalConductivity
262     
263     annotation(smoothOrder=2);
264    algorithm 
265      assert(size(tableConductivity,1)>0,"ThermalConductivity, lambda, is not defined for medium "
266                                             + mediumName + ".");
267      lambda := Poly.evaluate(poly_lam,if TinK then state.T else Cv.to_degC(state.T));
268    end thermalConductivity;
269   
270    function s_T "compute specific entropy" 
271      input Temperature T "temperature";
272      output SpecificEntropy s "specific entropy";
273    algorithm 
274      s := s0 + (if TinK then 
275        Poly.integralValue(poly_Cp[1:npol],T, T0) else 
276        Poly.integralValue(poly_Cp[1:npol],Cv.to_degC(T),Cv.to_degC(T0)))
277        + Modelica.Math.log(T/T0)*
278        Poly.evaluate(poly_Cp,if TinK then 0 else Modelica.Constants.T_zero);
279    end s_T;
280   
281    redeclare function extends specificEntropy
282    protected 
283      Integer npol=size(poly_Cp,1)-1;
284     annotation(smoothOrder=2);
285    algorithm 
286      assert(hasHeatCapacity,"Specific Entropy, s(T), is not defined for medium "
287                                             + mediumName + ".");
288      s := s_T(state.T);
289    end specificEntropy;
290   
291    function h_T "Compute specific enthalpy from temperature" 
292      import Modelica.SIunits.Conversions.to_degC;
293      extends Modelica.Icons.Function;
294      input SI.Temperature T "Temperature";
295      output SI.SpecificEnthalpy h "Specific enthalpy at p, T";
296     annotation(derivative=h_T_der);
297    algorithm 
298      h :=h0 + Poly.integralValue(poly_Cp, if TinK then T else Cv.to_degC(T), if TinK then 
299      T0 else Cv.to_degC(T0));
300    end h_T;
301   
302    function h_T_der "Compute specific enthalpy from temperature" 
303      import Modelica.SIunits.Conversions.to_degC;
304      extends Modelica.Icons.Function;
305      input SI.Temperature T "Temperature";
306      input Real dT "temperature derivative";
307      output Real dh "derivative of Specific enthalpy at T";
308    algorithm 
309      dh :=Poly.evaluate(poly_Cp, if TinK then T else Cv.to_degC(T))*dT;
310    end h_T_der;
311   
312    function h_pT "Compute specific enthalpy from pressure and temperature" 
313      import Modelica.SIunits.Conversions.to_degC;
314      extends Modelica.Icons.Function;
315      input SI.Pressure p "Pressure";
316      input SI.Temperature T "Temperature";
317      input Boolean densityOfT = false 
318        "include or neglect density derivative dependence of enthalpy" annotation(Evaluate);
319      output SI.SpecificEnthalpy h "Specific enthalpy at p, T";
320     annotation(smoothOrder=2);
321    algorithm 
322      h :=h0 + Poly.integralValue(poly_Cp, if TinK then T else Cv.to_degC(T), if TinK then 
323      T0 else Cv.to_degC(T0)) + (p - reference_p)/Poly.evaluate(poly_rho, if TinK then 
324              T else Cv.to_degC(T))
325        *(if densityOfT then (1 + T/Poly.evaluate(poly_rho, if TinK then T else Cv.to_degC(T))
326      *Poly.derivativeValue(poly_rho,if TinK then T else Cv.to_degC(T))) else 1.0);
327    end h_pT;
328   
329    function density_T
330      input Temperature T "temperature";
331      output Density d "density";
332    algorithm 
333      d := Poly.evaluate(poly_rho,if TinK then T else Cv.to_degC(T));
334    end density_T;
335   
336    redeclare function extends temperature
337    algorithm 
338     T := state.T;
339    end temperature;
340   
341    redeclare function extends pressure
342    algorithm 
343     p := state.p;
344    end pressure;
345   
346    redeclare function extends density
347    algorithm 
348      d := Poly.evaluate(poly_rho,if TinK then state.T else Cv.to_degC(state.T));
349    end density;
350   
351    redeclare function extends specificEnthalpy
352    algorithm 
353      h := if enthalpyOfT then h_T(state.T) else h_pT(state.p,state.T);
354    end specificEnthalpy;
355   
356    redeclare function extends specificInternalEnergy
357    algorithm 
358      u := if enthalpyOfT then h_T(state.T) else h_pT(state.p,state.T)
359        - (if singleState then  reference_p/density(state) else state.p/density(state));
360    end specificInternalEnergy;
361   
362    function T_ph "Compute temperature from pressure and specific enthalpy" 
363      input AbsolutePressure p "pressure";
364      input SpecificEnthalpy h "specific enthalpy";
365      output Temperature T "temperature";
366    protected 
367      package Internal
368        "Solve h(T) for T with given h (use only indirectly via temperature_phX)" 
369        extends Modelica.Media.Common.OneNonLinearEquation;
370       
371        redeclare record extends f_nonlinear_Data
372          "superfluous record, fix later when better structure of inverse functions exists" 
373            constant Real[5] dummy = {1,2,3,4,5};
374        end f_nonlinear_Data;
375       
376        redeclare function extends f_nonlinear "p is smuggled in via vector" 
377        algorithm 
378          y := if singleState then h_T(x) else h_pT(p,x);
379        end f_nonlinear;
380       
381        // Dummy definition has to be added for current Dymola
382        redeclare function extends solve
383        end solve;
384      end Internal;
385    algorithm 
386     T := Internal.solve(h, T_min, T_max, p, {1}, Internal.f_nonlinear_Data());
387    end T_ph;
388   
389    function T_ps "Compute temperature from pressure and specific enthalpy" 
390      input AbsolutePressure p "pressure";
391      input SpecificEntropy s "specific entropy";
392      output Temperature T "temperature";
393    protected 
394      package Internal
395        "Solve h(T) for T with given h (use only indirectly via temperature_phX)" 
396        extends Modelica.Media.Common.OneNonLinearEquation;
397       
398        redeclare record extends f_nonlinear_Data
399          "superfluous record, fix later when better structure of inverse functions exists" 
400            constant Real[5] dummy = {1,2,3,4,5};
401        end f_nonlinear_Data;
402       
403        redeclare function extends f_nonlinear "p is smuggled in via vector" 
404        algorithm 
405          y := s_T(x);
406        end f_nonlinear;
407       
408        // Dummy definition has to be added for current Dymola
409        redeclare function extends solve
410        end solve;
411      end Internal;
412    algorithm 
413     T := Internal.solve(s, T_min, T_max, p, {1}, Internal.f_nonlinear_Data());
414    end T_ps;
415   
416    package Polynomials_Temp
417      "Temporary Functions operating on polynomials (including polynomial fitting); only to be used in Modelica.Media.Incompressible.TableBased" 
418      extends Modelica.Icons.Library;
419     
420      annotation (Documentation(info="<HTML>
421<p>
422This package contains functions to operate on polynomials,
423in particular to determine the derivative and the integral
424of a polynomial and to use a polynomial to fit a given set
425of data points.
426</p>
427<p>
428
429<p><b>Copyright &copy; 2004-2007, Modelica Association and DLR.</b></p>
430
431<p><i>
432This package is <b>free</b> software. It can be redistributed and/or modified
433under the terms of the <b>Modelica license</b>, see the license conditions
434and the accompanying <b>disclaimer</b> in the documentation of package
435Modelica in file \"Modelica/package.mo\".
436</i>
437</p>
438
439</HTML>
440",     revisions="<html>
441<ul>
442<li><i>Oct. 22, 2004</i> by Martin Otter (DLR):<br>
443       Renamed functions to not have abbrevations.<br>
444       Based fitting on LAPACK<br>
445       New function to return the polynomial of an indefinite integral<li>
446<li><i>Sept. 3, 2004</i> by Jonas Eborn (Scynamics):<br>
447       polyderval, polyintval added<li>
448<li><i>March 1, 2004</i> by Martin Otter (DLR):<br>
449       first version implemented
450</li>
451</ul>
452</html>"),     uses(Modelica(version="2.1"), Modelica_Interpolation(version="0.94")));
453      function evaluate "Evaluate polynomial at a given abszissa value" 
454        extends Modelica.Icons.Function;
455        input Real p[:] 
456          "Polynomial coefficients (p[1] is coefficient of highest power)";
457        input Real u "Abszissa value";
458        output Real y "Value of polynomial at u";
459        annotation(derivative(zeroDerivative=p)=evaluate_der);
460      algorithm 
461        y := p[1];
462        for j in 2:size(p, 1) loop
463          y := p[j] + u*y;
464        end for;
465      end evaluate;
466     
467      function derivative "Derivative of polynomial" 
468        extends Modelica.Icons.Function;
469        input Real p1[:] 
470          "Polynomial coefficients (p1[1] is coefficient of highest power)";
471        output Real p2[size(p1, 1) - 1] "Derivative of polynomial p1";
472      protected 
473        Integer n=size(p1, 1);
474      algorithm 
475        for j in 1:n-1 loop
476          p2[j] := p1[j]*(n - j);
477        end for;
478      end derivative;
479     
480      function derivativeValue
481        "Value of derivative of polynomial at abszissa value u" 
482        extends Modelica.Icons.Function;
483        input Real p[:] 
484          "Polynomial coefficients (p[1] is coefficient of highest power)";
485        input Real u "Abszissa value";
486        output Real y "Value of derivative of polynomial at u";
487        annotation(derivative(zeroDerivative=p)=derivativeValue_der);
488      protected 
489        Integer n=size(p, 1);
490      algorithm 
491        y := p[1]*(n - 1);
492        for j in 2:size(p, 1)-1 loop
493          y := p[j]*(n - j) + u*y;
494        end for;
495      end derivativeValue;
496     
497      function secondDerivativeValue
498        "Value of 2nd derivative of polynomial at abszissa value u" 
499        extends Modelica.Icons.Function;
500        input Real p[:] 
501          "Polynomial coefficients (p[1] is coefficient of highest power)";
502        input Real u "Abszissa value";
503        output Real y "Value of 2nd derivative of polynomial at u";
504      protected 
505        Integer n=size(p, 1);
506      algorithm 
507        y := p[1]*(n - 1)*(n - 2);
508        for j in 2:size(p, 1)-2 loop
509          y := p[j]*(n - j)*(n - j - 1) + u*y;
510        end for;
511      end secondDerivativeValue;
512     
513      function integral "Indefinite integral of polynomial p(u)" 
514        extends Modelica.Icons.Function;
515        input Real p1[:] 
516          "Polynomial coefficients (p1[1] is coefficient of highest power)";
517        output Real p2[size(p1, 1) + 1] 
518          "Polynomial coefficients of indefinite integral of polynomial p1 (polynomial p2 + C is the indefinite integral of p1, where C is an arbitrary constant)";
519      protected 
520        Integer n=size(p1, 1) + 1 "degree of output polynomial";
521      algorithm 
522        for j in 1:n-1 loop
523          p2[j] := p1[j]/(n-j);
524        end for;
525      end integral;
526     
527      function integralValue "Integral of polynomial p(u) from u_low to u_high" 
528        extends Modelica.Icons.Function;
529        input Real p[:] "Polynomial coefficients";
530        input Real u_high "High integrand value";
531        input Real u_low=0 "Low integrand value, default 0";
532        output Real integral=0.0 
533          "Integral of polynomial p from u_low to u_high";
534        annotation(derivative(zeroDerivative=p)=integralValue_der);
535      protected 
536        Integer n=size(p, 1) "degree of integrated polynomial";
537        Real y_low=0 "value at lower integrand";
538      algorithm 
539        for j in 1:n loop
540          integral := u_high*(p[j]/(n - j + 1) + integral);
541          y_low := u_low*(p[j]/(n - j + 1) + y_low);
542        end for;
543        integral := integral - y_low;
544      end integralValue;
545     
546      function fitting
547        "Computes the coefficients of a polynomial that fits a set of data points in a least-squares sense" 
548        extends Modelica.Icons.Function;
549        input Real u[:] "Abscissa data values";
550        input Real y[size(u, 1)] "Ordinate data values";
551        input Integer n(min=1) 
552          "Order of desired polynomial that fits the data points (u,y)";
553        output Real p[n + 1] 
554          "Polynomial coefficients of polynomial that fits the date points";
555        annotation (Documentation(info="<HTML>
556<p>
557Polynomials.fitting(u,y,n) computes the coefficients of a polynomial
558p(u) of degree \"n\" that fits the data \"p(u[i]) - y[i]\"
559in a least squares sense. The polynomial is
560returned as a vector p[n+1] that has the following definition:
561</p>
562<pre>
563  p(u) = p[1]*u^n + p[2]*u^(n-1) + ... + p[n]*u + p[n+1];
564</pre>
565</HTML>"));
566      protected 
567        Real V[size(u, 1), n + 1] "Vandermonde matrix";
568      algorithm 
569        // Construct Vandermonde matrix
570        V[:, n + 1] := ones(size(u, 1));
571        for j in n:-1:1 loop
572          V[:, j] := {u[i] * V[i, j + 1] for i in 1:size(u,1)};
573        end for;
574       
575        // Solve least squares problem
576        p :=Modelica.Math.Matrices.leastSquares(V, y);
577      end fitting;
578     
579      function evaluate_der "Evaluate polynomial at a given abszissa value" 
580        extends Modelica.Icons.Function;
581        input Real p[:] 
582          "Polynomial coefficients (p[1] is coefficient of highest power)";
583        input Real u "Abszissa value";
584        input Real du "Abszissa value";
585        output Real dy "Value of polynomial at u";
586      protected 
587        Integer n=size(p, 1);
588      algorithm 
589        dy := p[1]*(n - 1);
590        for j in 2:size(p, 1)-1 loop
591          dy := p[j]*(n - j) + u*dy;
592        end for;
593        dy := dy*du;
594      end evaluate_der;
595     
596      function integralValue_der
597        "Time derivative of integral of polynomial p(u) from u_low to u_high, assuming only u_high as time-dependent (Leibnitz rule)" 
598        extends Modelica.Icons.Function;
599        input Real p[:] "Polynomial coefficients";
600        input Real u_high "High integrand value";
601        input Real u_low=0 "Low integrand value, default 0";
602        input Real du_high "High integrand value";
603        input Real du_low=0 "Low integrand value, default 0";
604        output Real dintegral=0.0 
605          "Integral of polynomial p from u_low to u_high";
606      algorithm 
607        dintegral := evaluate(p,u_high)*du_high;
608      end integralValue_der;
609     
610      function derivativeValue_der
611        "time derivative of derivative of polynomial" 
612        extends Modelica.Icons.Function;
613        input Real p[:] 
614          "Polynomial coefficients (p[1] is coefficient of highest power)";
615        input Real u "Abszissa value";
616        input Real du "delta of abszissa value";
617        output Real dy
618          "time-derivative of derivative of polynomial w.r.t. input variable at u";
619      protected 
620        Integer n=size(p, 1);
621      algorithm 
622        dy := secondDerivativeValue(p,u)*du;
623      end derivativeValue_der;
624    end Polynomials_Temp;
625  annotation (
626    preferedView="info",
627    Documentation(info="<HTML>
628<h4>Table based media</h4>
629<p>
630This is the base package for medium models of incompressible fluids based on
631tables. The minimal data to provide for a useful medium description is tables
632of density and heat capacity as functions of temperature.
633</p>
634<h4>Using the package TableBased</h4>
635<p>
636To implement a new medium model, create a package that <b>extends</b> TableBased
637and provides one or more of the constant tables:
638<pre>
639tableDensity        = [T, d];
640tableHeatCapacity   = [T, Cp];
641tableConductivity   = [T, lam];
642tableViscosity      = [T, eta];
643tableVaporPressure  = [T, pVap];
644</pre>
645The table data is used to fit constant polynomials of order <b>npol</b>, the
646temperature data points do not need to be same for different properties. Properties
647like enthalpy, inner energy and entropy are calculated consistently from integrals
648and derivatives of d(T) and Cp(T). The minimal
649data for a useful medium model is thus density and heat capacity. Transport
650properties and vapor pressure are optional, if the data tables are empty the corresponding
651function calls can not be used.
652</HTML>"));
653  end TableBased;
654 
655  package Examples "Examples for incompressible media" 
656   
657  package Glycol47 "1,2-Propylene glycol, 47% mixture with water" 
658    extends TableBased(
659      mediumName="Glycol-Water 47%",
660      T_min = Cv.from_degC(-30), T_max = Cv.from_degC(100),
661      TinK = false, T0=273.15,
662      tableDensity=
663        [-30, 1066; -20, 1062; -10, 1058; 0, 1054;
664         20, 1044; 40, 1030; 60, 1015; 80, 999; 100, 984