line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# Author: Jaap Voets - Xperience Automatisering |
3
|
|
|
|
|
|
|
# A van der Waals Gas Blender |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
package SCUBA::Blender; |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
29072
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
106
|
|
9
|
1
|
|
|
1
|
|
7
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
217
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '0.1'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# vanderwaals constants |
14
|
|
|
|
|
|
|
my %GASES; |
15
|
|
|
|
|
|
|
$GASES{'AIR'}{'a'} = 1.3725; |
16
|
|
|
|
|
|
|
$GASES{'AIR'}{'b'} = 0.0372; |
17
|
|
|
|
|
|
|
$GASES{'AIR'}{'weight'} = 28.84; # gram /mole |
18
|
|
|
|
|
|
|
$GASES{'O2'}{'a'} = 1.382; |
19
|
|
|
|
|
|
|
$GASES{'O2'}{'b'} = 0.0318; |
20
|
|
|
|
|
|
|
$GASES{'O2'}{'weight'} = 32; # gram /mole |
21
|
|
|
|
|
|
|
$GASES{'N2'}{'a'} = 1.37; |
22
|
|
|
|
|
|
|
$GASES{'N2'}{'b'} = 0.0387; |
23
|
|
|
|
|
|
|
$GASES{'N2'}{'weight'} = 28; # gram /mole |
24
|
|
|
|
|
|
|
$GASES{'HE'}{'a'} = 0.0346; |
25
|
|
|
|
|
|
|
$GASES{'HE'}{'b'} = 0.0238; |
26
|
|
|
|
|
|
|
$GASES{'HE'}{'weight'} = 4; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Universal Gas Constant when using Bar and Liters |
29
|
1
|
|
|
1
|
|
6
|
use constant R => 0.08314472; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
1958
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub new { |
32
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
33
|
0
|
|
|
|
|
|
my $self = {}; |
34
|
0
|
|
|
|
|
|
bless($self, $class); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# start with empty gas list |
37
|
0
|
|
|
|
|
|
$self->{start}->{pressure} = 0; # bar |
38
|
0
|
|
|
|
|
|
$self->{start}->{mix} = { '02' => 0.21, 'N2' => 0.79, 'HE' => 0, 'AIR' => 0}; # start with air |
39
|
0
|
|
|
|
|
|
$self->{end}->{pressure} = 200; # bar |
40
|
0
|
|
|
|
|
|
$self->{end}->{mix} = { '02' => 0.21, 'N2' => 0.79, 'HE' => 0, 'AIR' => 0}; # end with air by default |
41
|
0
|
|
|
|
|
|
$self->{temperature} = 293; # Kelvin |
42
|
0
|
|
|
|
|
|
$self->{volume} = 10; #liter |
43
|
0
|
|
|
|
|
|
$self->{fillorder} = ['O2','HE','AIR']; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# place holders for result of calculation |
46
|
0
|
|
|
|
|
|
$self->{results} = {}; |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
|
|
|
return $self; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# set temperature |
52
|
|
|
|
|
|
|
sub temperature { |
53
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
54
|
0
|
|
|
|
|
|
my $temp = shift; |
55
|
0
|
0
|
|
|
|
|
if ($temp < 100) { |
56
|
|
|
|
|
|
|
# sounds like celsius |
57
|
0
|
|
|
|
|
|
$temp += 273; # make kelvin |
58
|
|
|
|
|
|
|
} |
59
|
0
|
|
|
|
|
|
$self->{temperature} = $temp; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub volume { |
63
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
64
|
0
|
|
|
|
|
|
my $volume = shift; |
65
|
0
|
|
|
|
|
|
$self->{volume} = $volume; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# set starting values |
69
|
|
|
|
|
|
|
# first param is pressure, rest is gas list with percentages |
70
|
|
|
|
|
|
|
sub start_mix { |
71
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
72
|
0
|
|
|
|
|
|
my $pressure = shift; |
73
|
0
|
|
|
|
|
|
$self->{start}->{mix} = $self->_gasfractions( @_ ); |
74
|
0
|
|
|
|
|
|
$self->{start}->{pressure} = $pressure; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# e.g. |
78
|
|
|
|
|
|
|
# mixer->end_mix(210, 'O2' => 32, 'N2' => 68); |
79
|
|
|
|
|
|
|
sub end_mix { |
80
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
81
|
0
|
|
|
|
|
|
my $pressure = shift; |
82
|
0
|
|
|
|
|
|
$self->{end}->{pressure} = $pressure; |
83
|
0
|
|
|
|
|
|
$self->{end}->{mix} = $self->_gasfractions( @_ ); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# set the fill order of the gases |
87
|
|
|
|
|
|
|
sub fill_order { |
88
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
89
|
0
|
|
|
|
|
|
$self->{fillorder} = []; |
90
|
0
|
|
|
|
|
|
my @gases = @_; |
91
|
0
|
|
|
|
|
|
foreach my $gas (@gases) { |
92
|
0
|
|
|
|
|
|
$gas = uc($gas); |
93
|
0
|
0
|
|
|
|
|
if (exists $GASES{$gas}) { |
94
|
0
|
|
|
|
|
|
push @{$self->{fillorder}}, $gas; |
|
0
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
} else { |
96
|
0
|
|
|
|
|
|
croak "Unknown gas $gas!"; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# set fractions |
103
|
|
|
|
|
|
|
sub _gasfractions { |
104
|
0
|
|
|
0
|
|
|
my $self = shift; |
105
|
0
|
|
|
|
|
|
my %gaslist = @_; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# first make empty list based on %GASES |
108
|
0
|
|
|
|
|
|
my %fractions; |
109
|
0
|
|
|
|
|
|
foreach my $gas (keys %GASES) { |
110
|
0
|
|
|
|
|
|
$fractions{$gas} = 0; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
my $totalfraction = 0; |
114
|
0
|
|
|
|
|
|
foreach my $key (keys %gaslist) { |
115
|
0
|
|
|
|
|
|
my $gas = uc($key); |
116
|
0
|
0
|
|
|
|
|
if (exists $GASES{$gas} ) { |
117
|
0
|
|
|
|
|
|
my $fraction = $gaslist{$key}; |
118
|
0
|
0
|
|
|
|
|
$fraction = $fraction / 100 if ($fraction > 1); |
119
|
0
|
|
|
|
|
|
$fractions{$gas} = $fraction; |
120
|
0
|
|
|
|
|
|
$totalfraction += $fraction; |
121
|
|
|
|
|
|
|
} else { |
122
|
0
|
|
|
|
|
|
croak "Unknown gas $key!"; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
# maybe they left out nitrogen, so complement the mix |
126
|
0
|
0
|
|
|
|
|
if ($totalfraction < 1.0) { |
127
|
0
|
|
|
|
|
|
$fractions{'N2'} = 1 - $fractions{'O2'} - $fractions{'HE'}; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
return \%fractions; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# determine new A & B depending on mix of gases |
134
|
|
|
|
|
|
|
# note: this depends on the MOLAR fractions, not the partial pressure fractions |
135
|
|
|
|
|
|
|
sub compositeAB { |
136
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
137
|
0
|
|
|
|
|
|
my $gaslist_ref = shift; |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
my $a = 0; |
140
|
0
|
|
|
|
|
|
my $b = 0; |
141
|
0
|
|
|
|
|
|
foreach my $gas1 ( keys %{ $gaslist_ref } ) { |
|
0
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
foreach my $gas2 ( keys %{ $gaslist_ref } ) { |
|
0
|
|
|
|
|
|
|
143
|
0
|
|
|
|
|
|
$a += sqrt( $GASES{$gas1}{a} * $GASES{$gas2}{a} ) * $gaslist_ref->{$gas1} * $gaslist_ref->{$gas2}; |
144
|
0
|
|
|
|
|
|
$b += sqrt( $GASES{$gas1}{b} * $GASES{$gas2}{b} ) * $gaslist_ref->{$gas1} * $gaslist_ref->{$gas2}; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
0
|
|
|
|
|
|
return ($a, $b); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# do the calculation |
152
|
|
|
|
|
|
|
sub calc { |
153
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# determine starting moles of each gas and the corresponding composite a and b values |
156
|
0
|
|
|
|
|
|
my ($a_start, $b_start) = $self->compositeAB( $self->{start}->{mix} ); |
157
|
|
|
|
|
|
|
# and the initial molar amounts of each gas (hashref) |
158
|
0
|
|
|
|
|
|
my $start_moles = _molesInMix( $self->{start}->{mix}, $self->{start}->{pressure}, $self->{temperature}, $self->{volume}, $a_start, $b_start); |
159
|
0
|
|
|
|
|
|
_adjustforAir($start_moles); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# same for the end mix |
162
|
0
|
|
|
|
|
|
my ($a_end, $b_end) = $self->compositeAB( $self->{end}->{mix} ); |
163
|
0
|
|
|
|
|
|
my $end_moles = _molesInMix( $self->{end}->{mix}, $self->{end}->{pressure}, $self->{temperature}, $self->{volume}, $a_end, $b_end); |
164
|
0
|
|
|
|
|
|
_adjustforAir($end_moles); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# we now know how much to add for each gas |
167
|
0
|
|
|
|
|
|
my %add_moles; |
168
|
0
|
|
|
|
|
|
foreach my $gas (keys %GASES) { |
169
|
0
|
|
|
|
|
|
$add_moles{$gas} = $end_moles->{$gas} - $start_moles->{$gas}; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# so let's see how we fill the tank in bars instead of moles |
173
|
0
|
|
|
|
|
|
my $mix = $start_moles; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# it's determined by the fillorder |
176
|
0
|
|
|
|
|
|
my $previous_pressure = $self->{start}->{pressure}; |
177
|
0
|
|
|
|
|
|
foreach my $gas ( $self->_order_all() ) { |
178
|
|
|
|
|
|
|
|
179
|
0
|
0
|
|
|
|
|
if ($add_moles{$gas} != 0 ) { |
180
|
0
|
|
|
|
|
|
$mix->{$gas} += $add_moles{$gas}; |
181
|
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
$self->{results}->{$gas}->{mole_add} = $add_moles{$gas}; |
183
|
0
|
|
|
|
|
|
$self->{results}->{$gas}->{mole_total} = $mix->{$gas}; |
184
|
0
|
|
|
|
|
|
$self->{results}->{$gas}->{weight} = $mix->{$gas} * $GASES{$gas}{weight}; # in grams |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# get the new fractions of this fresh mix |
187
|
0
|
|
|
|
|
|
my ($gas_fractions, $moles) = _recalc_fractions($mix); |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# then calculate the new a and b |
190
|
0
|
|
|
|
|
|
my ($a, $b) = $self->compositeAB( $gas_fractions ); |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# and get the pressure to fill to with these params |
193
|
|
|
|
|
|
|
# (P + a*n^2/V^2)*(V - n*b) = n*R*T |
194
|
|
|
|
|
|
|
# so P = (n*R*T) / (V - n*b) - a*n^2/V^2 |
195
|
0
|
|
|
|
|
|
my $P = ($moles * R * $self->{temperature}) / ( $self->{volume} - $moles * $b) - $a * _sqr($moles / $self->{volume}); |
196
|
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
|
$self->{results}->{$gas}->{end_pressure} = $P; |
198
|
0
|
|
|
|
|
|
$self->{results}->{$gas}->{pressure} = $P - $previous_pressure; |
199
|
|
|
|
|
|
|
|
200
|
0
|
|
|
|
|
|
$previous_pressure = $P; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# make a human friendly string of the mix |
206
|
|
|
|
|
|
|
sub mix_to_string { |
207
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
208
|
0
|
|
|
|
|
|
my $mix_ref = shift; |
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
|
my $string = ''; |
211
|
0
|
|
|
|
|
|
$string .= int($mix_ref->{'O2'} * 100) . "% O2"; |
212
|
0
|
0
|
|
|
|
|
if ($mix_ref->{'HE'} > 0 ) { |
213
|
0
|
|
|
|
|
|
$string .= ', ' . int($mix_ref->{'HE'} * 100) . "% He"; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
return $string; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# get all gases, but preserve the fill order |
220
|
|
|
|
|
|
|
sub _order_all { |
221
|
0
|
|
|
0
|
|
|
my $self = shift; |
222
|
0
|
|
|
|
|
|
my @order = @{ $self->{fillorder} }; |
|
0
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
|
foreach my $gas ( keys %GASES ) { |
224
|
0
|
0
|
|
|
|
|
if ( ! grep ( { /$gas/ } @order) ) { |
|
0
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
push @order, $gas; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
} |
228
|
0
|
|
|
|
|
|
return @order; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# make a nice report of the results |
232
|
|
|
|
|
|
|
sub report { |
233
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
234
|
0
|
|
|
|
|
|
my $report = ''; |
235
|
|
|
|
|
|
|
|
236
|
0
|
|
|
|
|
|
my $desired_mix = $self->mix_to_string( $self->{end}->{mix} ); |
237
|
0
|
|
|
|
|
|
my $start_mix = $self->mix_to_string( $self->{start}->{mix} ); |
238
|
0
|
|
|
|
|
|
$report .= 'To fill a tank of ' . $self->{volume} . " liters with $desired_mix to a pressure of " . $self->{end}->{pressure} . " bar\n"; |
239
|
0
|
|
|
|
|
|
$report .= "starting with $start_mix at a pressure of " . $self->{start}->{pressure} . " bar\n\n"; |
240
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
my $total_weight = 0; |
242
|
0
|
|
|
|
|
|
foreach my $gas ( $self->_order_all() ) { |
243
|
0
|
0
|
|
|
|
|
if (exists $self->{results}->{$gas} ) { |
244
|
0
|
|
|
|
|
|
$report .= "add $gas to " . int($self->{results}->{$gas}->{end_pressure}) . " bar"; |
245
|
0
|
|
|
|
|
|
$report .= " (adding " . int($self->{results}->{$gas}->{pressure}) . " bars)\n"; |
246
|
0
|
|
|
|
|
|
$total_weight += $self->{results}->{$gas}->{weight}; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
|
$report .= "\ntotal weight of mix is " . int($total_weight) . " grams\n"; |
251
|
0
|
|
|
|
|
|
return $report; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# get a mix of moles |
255
|
|
|
|
|
|
|
# and return the same mix as fractions |
256
|
|
|
|
|
|
|
sub _recalc_fractions { |
257
|
0
|
|
|
0
|
|
|
my $mix = shift; |
258
|
0
|
|
|
|
|
|
my $frac = {}; |
259
|
0
|
|
|
|
|
|
my $total_moles = 0; |
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
foreach my $gas ( %{ $mix } ) { |
|
0
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
|
$total_moles += $mix->{$gas}; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
0
|
0
|
|
|
|
|
if ($total_moles > 0) { |
266
|
0
|
|
|
|
|
|
foreach my $gas ( %{ $mix } ) { |
|
0
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
$frac->{$gas} = $mix->{$gas} / $total_moles; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
0
|
|
|
|
|
|
return ($frac, $total_moles); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# solve the vanderwaals equation for n |
274
|
|
|
|
|
|
|
# (P + a*n^2/V^2)*(V - n*b) = n*R*T |
275
|
|
|
|
|
|
|
# for a mix with a composite a and b |
276
|
|
|
|
|
|
|
# this will give the TOTAL number of moles of the gas |
277
|
|
|
|
|
|
|
# |
278
|
|
|
|
|
|
|
# we will be using a newton iteration |
279
|
|
|
|
|
|
|
sub _molesInMix { |
280
|
0
|
|
|
0
|
|
|
my ($mix_ref, $P, $T, $V, $a, $b) = @_; |
281
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
|
my $n = 1; |
283
|
0
|
|
|
|
|
|
my $success = 0; |
284
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
|
my $max_iteration = 100; |
286
|
0
|
|
|
|
|
|
my $epsilon = 0.0001; |
287
|
|
|
|
|
|
|
# function to solve |
288
|
0
|
|
|
|
|
|
for (my $i = 1; $i < $max_iteration; $i++) { |
289
|
0
|
|
|
|
|
|
my $function_val = ( $P + $a * _sqr($n / $V)) * ( $V - $n*$b) - $n * R * $T; |
290
|
|
|
|
|
|
|
# dF/dn = -b*P + 2a*n/V - 3ab * n^2/V^2 -RT |
291
|
0
|
|
|
|
|
|
my $funcderiv_val = -1 * $P * $b + 2 * $a * $n/$V -3 * $a * $b * _sqr($n/$V) - R * $T; |
292
|
|
|
|
|
|
|
# calculate new n |
293
|
0
|
|
|
|
|
|
$n = $n - $function_val/$funcderiv_val; |
294
|
0
|
0
|
|
|
|
|
if ( abs( $function_val ) < $epsilon ) { |
295
|
|
|
|
|
|
|
# we are close enough to the root |
296
|
0
|
|
|
|
|
|
$success = 1; |
297
|
0
|
|
|
|
|
|
last; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
0
|
0
|
|
|
|
|
if ($success) { |
301
|
0
|
|
|
|
|
|
my $moles_mix = {}; |
302
|
0
|
|
|
|
|
|
foreach my $gas (keys %{ $mix_ref } ) { |
|
0
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
|
$moles_mix->{$gas} = $mix_ref->{$gas} * $n; |
304
|
|
|
|
|
|
|
} |
305
|
0
|
|
|
|
|
|
return $moles_mix; |
306
|
|
|
|
|
|
|
} else { |
307
|
0
|
|
|
|
|
|
croak "Couldn't solve"; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# we do not fill with pure nitrogen |
313
|
|
|
|
|
|
|
# but with air |
314
|
|
|
|
|
|
|
# so correct both the nitrogen and oxygen parts |
315
|
|
|
|
|
|
|
sub _adjustforAir { |
316
|
0
|
|
|
0
|
|
|
my $mix_ref = shift; |
317
|
|
|
|
|
|
|
# the nitrogen comes from the air, so we know how much air we need |
318
|
0
|
|
|
|
|
|
$mix_ref->{'AIR'} = $mix_ref->{'N2'} / 0.79; |
319
|
0
|
|
|
|
|
|
$mix_ref->{'O2'} = $mix_ref->{'O2'} - 0.21 * $mix_ref->{'AIR'}; |
320
|
|
|
|
|
|
|
# now clear the pure nitrogen part |
321
|
0
|
|
|
|
|
|
$mix_ref->{'N2'} = 0; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# square a number |
325
|
|
|
|
|
|
|
sub _sqr { |
326
|
0
|
|
|
0
|
|
|
my $n = shift; |
327
|
0
|
|
|
|
|
|
return ($n * $n); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
1; |
331
|
|
|
|
|
|
|
__END__ |