log14dec2015.txt

This commit is contained in:
Bruce Wernick
2015-12-14 08:39:30 +02:00
parent 016d90ec83
commit f9bb7748b3
6 changed files with 487 additions and 504 deletions

View File

@@ -1,21 +1,21 @@
{
Project 4: CoolProp Graphic Demo
Bruce Wernick, 13 December 2015
}
program Project4;
uses
Forms,
main in 'main.pas' {MainForm},
uMolChart in 'uMolChart.pas',
cpIntf in 'cpIntf.pas';
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
{
Project 4: CoolProp Graphic Demo
Bruce Wernick, 13 December 2015
}
program Project4;
uses
Forms,
main in 'main.pas' {MainForm},
uMolChart in 'uMolChart.pas',
cpIntf in 'cpIntf.pas';
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.

View File

@@ -1,39 +1,21 @@
CoolProp Delphi Wrapper Demo
============================
Bruce Wernick,
info@coolit.co.za
Created: 13 December 2015
This demo is based on the win32 shared DLL downloaded from the CoolProp site.
There are two parts to the demo:
1. The actual DLL interface.
2. A simple ph-chart builder.
The original CoolProp code is written in C++. In the source folder, you can find the text file exports.txt
that details the complete list of functions exported by the CoolProp DLL. I have only implemented
the essential ones but it would be easy to add any ones I have omitted. The interface mimics the
C header file but there are a few options. The returning string is an array of character. In Delphi,
you could use an array of AnsiChar parameter. Instead, I chose to use the PAnsiChar because it makes
the dll interface cleaner and more universal. One thing you have to be aware of - the calling
program has to create a buffer for the result. If this is not sized sufficiently, then a blank string
is returned. This could happen, for example, if a lot of fluids are added to the file.
The graphical part draws the saturation curve on conventional log(p) vs enthalpy axes. The program main
form has a Delphi VCL TListView and a TPaintBox. On startup, the program uses the DLL to populate the
ListView with all of the available fluids. The PaintBox is a very basic components that is basically
just a canvas. The main program creates a TMolChart class that does all the work on a canvas. When
the OnPaint fires in the main form, the chart is re-drawn.
The chart is auto scaled around the critical point and atmospheric pressure (where possible). This
makes it quite convenient for comparing the shape of the various saturation curves. What it needs is
some isotherms and some isentropic lines. If anyone has the urge to add these I would like to get an
update.
Lazarus users
-------------
With some minor changes, you could quite easily run this code with Lazarus.
CoolProp Delphi Wrapper Demo.
Bruce Wernick, info@coolit.co.za
13 December 2015
This demo is based on the win32 shared DLL downloaded from the CoolProp site.
There are two parts to the demo:
1. The actual DLL interface.
2. A simple ph-chart builder.
The original code was written in C++. In the source folder, you can find the text file exports.txt that details the complete list of functions exported by the CoolProp DLL. I have only implemented the essential ones but it would be easy to add any ones I have omitted. The interface mimics the C header file but there are a few options. The returning string is an array of char. In Delphi, you could use an array of char parameter. Instead, I chose to use the PAnsiChar because it makes the dll interface simplere and more universal. One thing you have to be aware of - the calling program has to create a buffer for the result. If this is not sized sufficiently, then a blank string is returned. This could happen, for example, if a lot of fluids are added to the file.
The graphical part draws the saturation curve on conventional log(p) vs enthalpy axes. The program main form has a Delphi VCL TListView and a TPaintBox. On startup, the program uses the DLL to populate the ListView with all of the available fluids. The PaintBox is a very basic components that is basically just a canvas. The main program creates a TMolChart class that does all the work on a canvas. When the OnPaint fires in the main form, the chart is re-drawn.
The chart is auto scaled around the critical point and atmospheric pressure (where possible). This makes it quite convenient for comparing the shape of the various saturation curves. What it needs is some isotherms and some isentropic lines. If anyone has the urge to add these I would like to get an update.
Lazarus users
With some minor changes, you could quite easily run this code with Lazarus.

View File

@@ -1,59 +1,59 @@
{
Delphi Interface for CoolProp
Bruce Wernick, 13 December 2015
Notes:
All of the char parameters are PAnsiChar, the floating point numbers are
Double and the integer types are either LongInt or Integer depending on the
type in the dll. Where there is an output string, the calling program must
create the space for the result. Be aware here that insufficient space will
result in a empty string. So for example, you should ensure sufficient space
for the refrigerant list.
}
unit cpIntf;
interface
const
cpdll = 'CoolProp.dll';
function get_global_param_string(
param: PAnsiChar;
res: PAnsiChar;
n: Integer): LongInt; stdcall;
external cpdll name '_get_global_param_string@12';
function get_fluid_param_string(
fluid: PAnsiChar;
param: PAnsiChar;
res: PAnsiChar;
n: Integer): Longint; stdcall;
external cpdll name '_get_fluid_param_string@12';
function PropsSI(
spec: PAnsiChar;
prop1: PAnsiChar; val1: Double;
prop2: PAnsiChar; val2: Double;
fluid: PAnsiChar): Double; stdcall;
external cpdll name '_PropsSI@32';
function Props1SI(
fluid: PAnsiChar;
res: PAnsiChar): Double; stdcall;
external cpdll name '_Props1SI@8';
function HAPropsSI(
spec: PAnsiChar;
prop1: PAnsiChar; val1: Double;
prop2: PAnsiChar; val2: Double;
prop3: PAnsiChar; val3: Double): Double; stdcall;
external cpdll name '_HAPropsSI@40';
implementation
initialization
{Disable floating point exception
This is a problem with the Delphi compiler only}
Set8087CW($133f);
end.
{
Delphi Interface for CoolProp
Bruce Wernick, 13 December 2015
Notes:
All of the char parameters are PAnsiChar, the floating point numbers are
Double and the integer types are either LongInt or Integer depending on the
type in the dll. Where there is an output string, the calling program must
create the space for the result. Be aware here that insufficient space will
result in a empty string. So for example, you should ensure sufficient space
for the refrigerant list.
}
unit cpIntf;
interface
const
cpdll = 'CoolProp.dll';
function get_global_param_string(
param: PAnsiChar;
res: PAnsiChar;
n: Integer): LongInt; stdcall;
external cpdll name '_get_global_param_string@12';
function get_fluid_param_string(
fluid: PAnsiChar;
param: PAnsiChar;
res: PAnsiChar;
n: Integer): Longint; stdcall;
external cpdll name '_get_fluid_param_string@12';
function PropsSI(
spec: PAnsiChar;
prop1: PAnsiChar; val1: Double;
prop2: PAnsiChar; val2: Double;
fluid: PAnsiChar): Double; stdcall;
external cpdll name '_PropsSI@32';
function Props1SI(
fluid: PAnsiChar;
res: PAnsiChar): Double; stdcall;
external cpdll name '_Props1SI@8';
function HAPropsSI(
spec: PAnsiChar;
prop1: PAnsiChar; val1: Double;
prop2: PAnsiChar; val2: Double;
prop3: PAnsiChar; val3: Double): Double; stdcall;
external cpdll name '_HAPropsSI@40';
implementation
initialization
{Disable floating point exception
This is a problem with the Delphi compiler only}
Set8087CW($133f);
end.

View File

@@ -1,62 +1,63 @@
object MainForm: TMainForm
Left = 0
Top = 0
Caption = 'CoolProp Demo'
ClientHeight = 372
ClientWidth = 595
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnActivate = FormActivate
OnCreate = FormCreate
DesignSize = (
595
372)
PixelsPerInch = 96
TextHeight = 13
object PaintBox1: TPaintBox
Left = 175
Top = 40
Width = 412
Height = 301
Anchors = [akLeft, akTop, akRight, akBottom]
OnMouseDown = PaintBox1MouseDown
OnMouseLeave = PaintBox1MouseLeave
OnMouseMove = PaintBox1MouseMove
OnPaint = PaintBox1Paint
end
object ListBox1: TListBox
Left = 8
Top = 40
Width = 161
Height = 324
Anchors = [akLeft, akTop, akBottom]
ItemHeight = 13
TabOrder = 0
OnClick = ListBox1Click
end
object StaticText1: TStaticText
Left = 175
Top = 347
Width = 412
Height = 17
Anchors = [akLeft, akRight, akBottom]
AutoSize = False
BorderStyle = sbsSunken
Caption = 'Chart position...'
TabOrder = 1
end
object Button1: TButton
Left = 8
Top = 8
Width = 49
Height = 25
Caption = 'Copy'
TabOrder = 2
OnClick = Button1Click
end
end
object MainForm: TMainForm
Left = 0
Top = 0
Caption = 'CoolProp Demo'
ClientHeight = 372
ClientWidth = 595
Color = clBtnFace
DoubleBuffered = True
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnActivate = FormActivate
OnCreate = FormCreate
DesignSize = (
595
372)
PixelsPerInch = 96
TextHeight = 13
object PaintBox1: TPaintBox
Left = 175
Top = 40
Width = 412
Height = 301
Anchors = [akLeft, akTop, akRight, akBottom]
OnMouseDown = PaintBox1MouseDown
OnMouseLeave = PaintBox1MouseLeave
OnMouseMove = PaintBox1MouseMove
OnPaint = PaintBox1Paint
end
object ListBox1: TListBox
Left = 8
Top = 40
Width = 161
Height = 324
Anchors = [akLeft, akTop, akBottom]
ItemHeight = 13
TabOrder = 0
OnClick = ListBox1Click
end
object StaticText1: TStaticText
Left = 175
Top = 347
Width = 412
Height = 17
Anchors = [akLeft, akRight, akBottom]
AutoSize = False
BorderStyle = sbsSunken
Caption = 'Chart position...'
TabOrder = 1
end
object Button1: TButton
Left = 8
Top = 8
Width = 49
Height = 25
Caption = '&Copy'
TabOrder = 2
OnClick = Button1Click
end
end

View File

@@ -1,132 +1,132 @@
{
CoolProp Graphic Demo - Main form
Bruce Wernick, 13 December 2015
}
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
uMolChart;
type
TMainForm = class(TForm)
ListBox1: TListBox;
PaintBox1: TPaintBox;
StaticText1: TStaticText;
Button1: TButton;
procedure FormActivate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseLeave(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
private
fluid: AnsiString;
ref: PAnsiChar;
MolChart: TMolChart;
public
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
uses
clipbrd,
cpIntf;
procedure TMainForm.FormCreate(Sender: TObject);
const
n = 80;
var
res: AnsiString;
begin
Caption := 'CoolProp Demo';
SetLength(res, n);
get_global_param_string('version', PAnsiChar(res), n);
Caption := Caption + ' ' + 'Version ' + string(res);
get_global_param_string('gitrevision', PAnsiChar(res), n);
Caption := Caption + ' ' + 'Revision ' + string(res);
MolChart := TMolChart.Create(PaintBox1.Canvas);
fluid := 'R22'; // initial fluid
ref := PAnsiChar(fluid)
end;
procedure TMainForm.FormActivate(Sender: TObject);
const
n = 2048;
var
res: AnsiString;
begin
SetLength(res, n);
get_global_param_string('FluidsList', PAnsiChar(res), n);
ListBox1.Items.CommaText := string(res);
ListBox1.ItemIndex := ListBox1.Items.IndexOf(ref)
end;
procedure TMainForm.ListBox1Click(Sender: TObject);
begin
fluid := AnsiString(ListBox1.Items[ListBox1.ItemIndex]);
ref := PAnsiChar(fluid);
PaintBox1.Refresh
end;
procedure TMainForm.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
h, p: Double;
begin
h := MolChart.P2X(X); p := MolChart.P2Y(Y);
Clipboard.AsText := format('h:%0.3f, p:%0.3f', [h, p]);
end;
procedure TMainForm.PaintBox1MouseLeave(Sender: TObject);
begin
StaticText1.Caption := fluid
end;
procedure TMainForm.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
const
k0 = 273.15;
fmt = '%s: t=%0.2fC, p=%0.3f MPa, h=%0.3f kJ/kg, s=%0.4f kJ/kg-K';
var
h, p, t, s: Double;
begin
h := MolChart.P2X(X); p := MolChart.P2Y(Y);
t := PropsSI('T', 'P', 1e6*p, 'H', 1e3*h, ref);
s := 1e-3*PropsSI('S', 'P', 1e6*p, 'T', t+k0, ref);
StaticText1.Caption := format(fmt, [fluid, t-k0, p, h, s])
end;
procedure TMainForm.PaintBox1Paint(Sender: TObject);
begin
StaticText1.Caption := fluid;
MolChart.DrawChart(ref, PaintBox1.Width, PaintBox1.Height)
end;
procedure TMainForm.Button1Click(Sender: TObject);
var
MyFormat: Word;
AData: THandle;
APalette: HPALETTE;
bmp: TBitmap;
begin
bmp := self.GetFormImage;
try
bmp.SaveToClipBoardFormat(MyFormat, AData, APalette);
ClipBoard.SetAsHandle(MyFormat,AData);
finally
bmp.Free;
end;
end;
end.
{
CoolProp Graphic Demo - Main form
Bruce Wernick, 13 December 2015
}
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
uMolChart;
type
TMainForm = class(TForm)
ListBox1: TListBox;
PaintBox1: TPaintBox;
StaticText1: TStaticText;
Button1: TButton;
procedure FormActivate(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseLeave(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
private
fluid: AnsiString;
ref: PAnsiChar;
MolChart: TMolChart;
public
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
uses
clipbrd,
cpIntf;
procedure TMainForm.FormCreate(Sender: TObject);
const
n = 80;
var
res: AnsiString;
begin
Caption := 'CoolProp Demo';
SetLength(res, n);
get_global_param_string('version', PAnsiChar(res), n);
Caption := Caption + ' ' + 'Version ' + string(res);
get_global_param_string('gitrevision', PAnsiChar(res), n);
Caption := Caption + ' ' + 'Revision ' + string(res);
MolChart := TMolChart.Create(PaintBox1.Canvas);
fluid := 'R22'; // initial fluid
ref := PAnsiChar(fluid)
end;
procedure TMainForm.FormActivate(Sender: TObject);
const
n = 2048;
var
res: AnsiString;
begin
SetLength(res, n);
get_global_param_string('FluidsList', PAnsiChar(res), n);
ListBox1.Items.CommaText := string(res);
ListBox1.ItemIndex := ListBox1.Items.IndexOf(string(ref))
end;
procedure TMainForm.ListBox1Click(Sender: TObject);
begin
fluid := AnsiString(ListBox1.Items[ListBox1.ItemIndex]);
ref := PAnsiChar(fluid);
PaintBox1.Refresh
end;
procedure TMainForm.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
h, p: Double;
begin
h := MolChart.P2X(X); p := MolChart.P2Y(Y);
Clipboard.AsText := format('h:%0.3f, p:%0.3f', [h, p]);
end;
procedure TMainForm.PaintBox1MouseLeave(Sender: TObject);
begin
StaticText1.Caption := string(fluid)
end;
procedure TMainForm.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
const
k0 = 273.15;
fmt = '%s: t=%0.2fC, p=%0.3f MPa, h=%0.3f kJ/kg, s=%0.4f kJ/kg-K';
var
h, p, t, s: Double;
begin
h := MolChart.P2X(X); p := MolChart.P2Y(Y);
t := PropsSI('T', 'P', 1e6*p, 'H', 1e3*h, ref);
s := 1e-3*PropsSI('S', 'P', 1e6*p, 'T', t+k0, ref);
StaticText1.Caption := format(fmt, [fluid, t-k0, p, h, s])
end;
procedure TMainForm.PaintBox1Paint(Sender: TObject);
begin
StaticText1.Caption := string(fluid);
MolChart.DrawChart(ref, PaintBox1.Width, PaintBox1.Height)
end;
procedure TMainForm.Button1Click(Sender: TObject);
var
MyFormat: Word;
AData: THandle;
APalette: HPALETTE;
bmp: TBitmap;
begin
bmp := self.GetFormImage;
try
bmp.SaveToClipBoardFormat(MyFormat, AData, APalette);
ClipBoard.SetAsHandle(MyFormat,AData);
finally
bmp.Free;
end;
end;
end.

View File

@@ -1,191 +1,191 @@
{
Mollier Chart (ph-chart) generator
Bruce Wernick, 13 December 2015
}
unit uMolChart;
interface
uses
SysUtils, Windows, Graphics, Classes,
cpIntf;
type
fvec = array of Double;
TMolChart = class
private
FCanvas: TCanvas;
R: TRect;
FMargin: Integer;
x0, x1, y0, y1: Double;
lny0, lny1: Double;
xf, yf: Double;
procedure CalcScaleFactor;
public
constructor Create(Canvas: TCanvas);
function X2P(x: Double): Integer;
function Y2P(y: Double): Integer;
function P2X(p: Integer): Double;
function P2Y(p: Integer): Double;
procedure MoveTo(x, y: Double);
procedure Lineto(x, y: Double);
procedure DrawPoint(x, y: Double; Color: TColor);
procedure DrawLine(x0, y0, x1, y1: Double; Color: TColor; PenWidth: Integer);
procedure DrawVec(x, y: fvec; Color: TColor; PenWidth: Integer);
procedure DrawChart(ref: PAnsiChar; Width, Height: Integer);
end;
implementation
uses
Math;
constructor TMolChart.Create(Canvas: TCanvas);
begin
FMargin := 25;
FCanvas := Canvas
end;
procedure TMolChart.CalcScaleFactor;
{calculate the scale factor}
begin
xf := (x1-x0)/(R.Right-R.Left);
lny0 := ln(y0);
lny1 := ln(y1);
yf := (lny1-lny0)/(R.Top-R.Bottom)
end;
function TMolChart.X2P(x: Double): Integer;
{X scale value to chart pixel value}
begin
Result := Trunc(R.Left+(x-x0)/xf)
end;
function TMolChart.Y2P(y: Double): Integer;
{Y scale value to chart pixel value}
begin
Result := Trunc(R.Bottom+(ln(y)-lny0)/yf)
end;
function TMolChart.P2X(p: Integer): Double;
{pixel point to x scale value}
begin
Result := x0+(p-R.Left)*xf
end;
function TMolChart.P2Y(p: Integer): Double;
{pixel point to y scale value}
begin
Result := exp(lny0+(p-R.Bottom)*yf)
end;
procedure TMolChart.MoveTo(x, y: Double);
{move to (x,y) scale position}
begin
FCanvas.MoveTo(X2P(x), Y2P(y))
end;
procedure TMolChart.LineTo(x, y: Double);
{line to (x,y) scale position}
begin
FCanvas.LineTo(X2P(x), Y2P(y))
end;
procedure TMolChart.DrawPoint(x, y: Double; Color: TColor);
{draw a square at (x,y) scale position}
var
px, py: Integer;
begin
FCanvas.Pen.Color := Color;
px := X2P(x);
py := Y2P(y);
FCanvas.Rectangle(px-1, py+1, px+1, py-1)
end;
procedure TMolChart.DrawLine(x0, y0, x1, y1: Double; Color: TColor; PenWidth: Integer);
{draw a line from (x0,y0) to (x1,y1) scale co-ordinates}
begin
FCanvas.Pen.Color := Color;
FCanvas.Pen.Width := PenWidth;
MoveTo(x0, y0);
LineTo(x1, y1)
end;
procedure TMolChart.DrawVec(x, y: fvec; Color: TColor; PenWidth: Integer);
{draw a (xi,yi) vector}
var
i: Integer;
begin
FCanvas.Pen.Color := Color;
FCanvas.Pen.Width := PenWidth;
MoveTo(x[0], y[0]);
for i := 1 to length(x)-1 do
LineTo(x[i], y[i])
end;
procedure TMolChart.DrawChart(ref: PAnsiChar; Width, Height: Integer);
{draw the mollier chart}
const
n = 23;
var
i, Count: Integer;
pc, tc, dc, hc: Double;
p, hf, hg: fvec;
dx, dy: Double;
_hf, _hg: Double;
begin
R := Rect(0, 0, Width, Height);
FCanvas.Brush.Color := $00f8fcfa;
FCanvas.FillRect(R);
InflateRect(R, -FMargin, -FMargin);
FCanvas.Pen.Color := clGray;
FCanvas.Pen.Width := 1;
FCanvas.Rectangle(R);
pc := 1e-6*Props1SI('PCRIT', ref);
tc := Props1SI('TCRIT', ref);
dc := Props1SI('RHOCRIT', ref);
hc := 1e-3*PropsSI('H', 'T', tc, 'D', dc, ref);
y0 := 0.1;
y1 := pc;
// test for fluid critical pressure < 1 Mpa
if y1 <= y0 then y0 := 0.1*y1;
// generate n points
SetLength(p, n);
SetLength(hf, n);
SetLength(hg, n);
Count := 0;
for i := 0 to n-1 do begin
p[i] := y0 + i*(y1-y0)/n;
_hf := 1e-3*PropsSI('H', 'P', 1e6*p[i], 'Q', 0, ref);
_hg := 1e-3*PropsSI('H', 'P', 1e6*p[i], 'Q', 1, ref);
if IsInfinite(_hf) or IsInfinite(_hg) then continue;
if (_hf=0) or (_hg=0) then continue;
hf[Count] := _hf;
hg[Count] := _hg;
Count := Count + 1;
end;
SetLength(p, Count);
SetLength(hf, Count);
SetLength(hg, Count);
// adjust the scale
x0 := MinValue(hf);
_hg := MinValue(hg);
if _hg < x0 then x0 := _hg;
x1 := MaxValue(hg);
_hf := MaxValue(hf);
if _hf > x1 then x1 := _hf;
dx := x1-x0;
dy := y1-y0;
x0 := x0-0.1*dx;
x1 := x1+0.4*dx;
y1 := y1+0.1*dy;
CalcScaleFactor;
DrawVec(hf, p, clGreen, 2); // liquid line
DrawVec(hg, p, clRed, 2); // vapor line
DrawPoint(hc, pc, clBlue) // critical point
end;
end.
{
Mollier Chart (ph-chart) generator
Bruce Wernick, 13 December 2015
}
unit uMolChart;
interface
uses
SysUtils, Windows, Graphics, Classes,
cpIntf;
type
fvec = array of Double;
TMolChart = class
private
FCanvas: TCanvas;
R: TRect;
FMargin: Integer;
x0, x1, y0, y1: Double;
lny0, lny1: Double;
xf, yf: Double;
procedure CalcScaleFactor;
public
constructor Create(Canvas: TCanvas);
function X2P(x: Double): Integer;
function Y2P(y: Double): Integer;
function P2X(p: Integer): Double;
function P2Y(p: Integer): Double;
procedure MoveTo(x, y: Double);
procedure Lineto(x, y: Double);
procedure DrawPoint(x, y: Double; Color: TColor);
procedure DrawLine(x0, y0, x1, y1: Double; Color: TColor; PenWidth: Integer);
procedure DrawVec(x, y: fvec; Color: TColor; PenWidth: Integer);
procedure DrawChart(ref: PAnsiChar; Width, Height: Integer);
end;
implementation
uses
Math;
constructor TMolChart.Create(Canvas: TCanvas);
begin
FMargin := 25;
FCanvas := Canvas
end;
procedure TMolChart.CalcScaleFactor;
{calculate the scale factor}
begin
xf := (x1-x0)/(R.Right-R.Left);
lny0 := ln(y0);
lny1 := ln(y1);
yf := (lny1-lny0)/(R.Top-R.Bottom)
end;
function TMolChart.X2P(x: Double): Integer;
{X scale value to chart pixel value}
begin
Result := Trunc(R.Left+(x-x0)/xf)
end;
function TMolChart.Y2P(y: Double): Integer;
{Y scale value to chart pixel value}
begin
Result := Trunc(R.Bottom+(ln(y)-lny0)/yf)
end;
function TMolChart.P2X(p: Integer): Double;
{pixel point to x scale value}
begin
Result := x0+(p-R.Left)*xf
end;
function TMolChart.P2Y(p: Integer): Double;
{pixel point to y scale value}
begin
Result := exp(lny0+(p-R.Bottom)*yf)
end;
procedure TMolChart.MoveTo(x, y: Double);
{move to (x,y) scale position}
begin
FCanvas.MoveTo(X2P(x), Y2P(y))
end;
procedure TMolChart.LineTo(x, y: Double);
{line to (x,y) scale position}
begin
FCanvas.LineTo(X2P(x), Y2P(y))
end;
procedure TMolChart.DrawPoint(x, y: Double; Color: TColor);
{draw a square at (x,y) scale position}
var
px, py: Integer;
begin
FCanvas.Pen.Color := Color;
px := X2P(x);
py := Y2P(y);
FCanvas.Rectangle(px-1, py+1, px+1, py-1)
end;
procedure TMolChart.DrawLine(x0, y0, x1, y1: Double; Color: TColor; PenWidth: Integer);
{draw a line from (x0,y0) to (x1,y1) scale co-ordinates}
begin
FCanvas.Pen.Color := Color;
FCanvas.Pen.Width := PenWidth;
MoveTo(x0, y0);
LineTo(x1, y1)
end;
procedure TMolChart.DrawVec(x, y: fvec; Color: TColor; PenWidth: Integer);
{draw a (xi,yi) vector}
var
i: Integer;
begin
FCanvas.Pen.Color := Color;
FCanvas.Pen.Width := PenWidth;
MoveTo(x[0], y[0]);
for i := 1 to length(x)-1 do
LineTo(x[i], y[i])
end;
procedure TMolChart.DrawChart(ref: PAnsiChar; Width, Height: Integer);
{draw the mollier chart}
const
n = 23;
var
i, Count: Integer;
pc, tc, dc, hc: Double;
p, hf, hg: fvec;
dx, dy: Double;
_hf, _hg: Double;
begin
R := Rect(0, 0, Width, Height);
FCanvas.Brush.Color := $00f8fcfa;
FCanvas.FillRect(R);
InflateRect(R, -FMargin, -FMargin);
FCanvas.Pen.Color := clGray;
FCanvas.Pen.Width := 1;
FCanvas.Rectangle(R);
pc := 1e-6*Props1SI('PCRIT', ref);
tc := Props1SI('TCRIT', ref);
dc := Props1SI('RHOCRIT', ref);
hc := 1e-3*PropsSI('H', 'T', tc, 'D', dc, ref);
y0 := 0.1;
y1 := pc;
// test for fluid critical pressure < 1 Mpa
if y1 <= y0 then y0 := 0.1*y1;
// generate n points
SetLength(p, n);
SetLength(hf, n);
SetLength(hg, n);
Count := 0;
for i := 0 to n-1 do begin
p[i] := y0 + i*(y1-y0)/n;
_hf := 1e-3*PropsSI('H', 'P', 1e6*p[i], 'Q', 0, ref);
_hg := 1e-3*PropsSI('H', 'P', 1e6*p[i], 'Q', 1, ref);
if IsInfinite(_hf) or IsInfinite(_hg) then continue;
if (_hf=0) or (_hg=0) then continue;
hf[Count] := _hf;
hg[Count] := _hg;
Count := Count + 1;
end;
SetLength(p, Count);
SetLength(hf, Count);
SetLength(hg, Count);
// adjust the scale
x0 := MinValue(hf);
_hg := MinValue(hg);
if _hg < x0 then x0 := _hg;
x1 := MaxValue(hg);
_hf := MaxValue(hf);
if _hf > x1 then x1 := _hf;
dx := x1-x0;
dy := y1-y0;
x0 := x0-0.1*dx;
x1 := x1+0.4*dx;
y1 := y1+0.1*dy;
CalcScaleFactor;
DrawVec(hf, p, clGreen, 2); // liquid line
DrawVec(hg, p, clRed, 2); // vapor line
DrawPoint(hc, pc, clBlue) // critical point
end;
end.