File Coverage

blib/lib/Physics/Water/SoundSpeed.pm
Criterion Covered Total %
statement 132 178 74.1
branch 15 34 44.1
condition 11 33 33.3
subroutine 11 13 84.6
pod 0 10 0.0
total 169 268 63.0


line stmt bran cond sub pod time code
1             package Physics::Water::SoundSpeed;
2              
3             #use 5.010001;
4 1     1   23765 use strict;
  1         4  
  1         44  
5 1     1   6 use warnings;
  1         3  
  1         29  
6              
7 1     1   1124 use Data::Dumper;
  1         14903  
  1         4579  
8              
9             require Exporter;
10              
11             our @ISA = qw(Exporter);
12              
13             # Items to export into callers namespace by default. Note: do not export
14             # names by default without a very good reason. Use EXPORT_OK instead.
15             # Do not simply export all your public functions/methods/constants.
16              
17             # This allows declaration use Physics::Water::SoundSpeed ':all';
18             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
19             # will save memory.
20             our %EXPORT_TAGS = ( 'all' => [ qw(
21              
22             ) ] );
23              
24             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
25              
26             our @EXPORT = qw(
27              
28             );
29              
30             our $VERSION = '0.92';
31              
32             # Preloaded methods go here.
33              
34             # ------------------------------------------------
35             # Class Data and methods
36             {
37             my %default_hsh = (
38             'ppm' => 35,
39             'stdpres' => 0.101325,
40             'density_pure' => 1000,
41             'density_sea' => 1027
42             );
43              
44             $default_hsh{'units'} = 'SI';
45              
46             $default_hsh{'conv'} =
47             {
48             'f2c' => 5/9,
49             'ft2m' => 0.3048,
50             'psi2kpa' => 6.89475729,
51             'psi2mpa' => .00689475729,
52             'm2ft' => 3.2808399
53             };
54              
55             # Class methods
56             sub set_defaults
57             {
58 0     0 0 0 my $class = shift @_;
59              
60 0         0 my %set_hsh;
61 0 0       0 if ( ref($_[0]) eq "HASH" ) { %set_hsh = %{ $_[0] } }
  0         0  
  0         0  
62 0         0 else { %set_hsh = @_ }
63              
64             # Merge with existing hash
65 0         0 %default_hsh = ( %default_hsh, %set_hsh);
66              
67 0         0 return %default_hsh;
68             }
69              
70             sub get_defaults
71             {
72 2     2 0 22 return %default_hsh;
73             }
74             }
75              
76             # --------------------------
77             sub new
78             {
79 2     2 0 274 my $caller = shift @_;
80              
81             # In case someone wants to sub-class
82 2         5 my $caller_is_obj = ref($caller);
83 2   33     12 my $class = $caller_is_obj || $caller;
84              
85             # Passing reference or hash
86 2         3 my %arg_hsh;
87 2 50       7 if ( ref($_[0]) eq "HASH" ) { %arg_hsh = %{ shift @_ } }
  0         0  
  0         0  
88 2         5 else { %arg_hsh = @_ }
89              
90             # Override default hash with arguments
91 2         8 my %conf_hsh = __PACKAGE__->get_defaults();
92              
93 2         14 %conf_hsh = (%conf_hsh, %arg_hsh); # overwrite defaults
94              
95             # The object data structure
96 2         17 my $self = bless {
97             'units' => $conf_hsh{'units'},
98             'conv' => $conf_hsh{'conv'},
99             'ppm' => $conf_hsh{'ppm'},
100             'stdpres' => $conf_hsh{'stdpres'},
101             'density_pure' => $conf_hsh{'density_pure'},
102             'density_sea' => $conf_hsh{'density_sea'},
103             'err' => ''
104             }, $class;
105              
106 2         9 return $self;
107             }
108              
109             sub sound_speed
110             {
111 1     1 0 264 my $self = shift;
112 1         3 my $arg1 = shift;
113 1         3 my $arg2 = shift;
114              
115 1 50 33     51 if ( ( ref $arg1 eq 'ARRAY' ) && ( ref $arg2 eq 'ARRAY' ) )
    50 33        
    50 33        
    50 33        
    50 33        
    0 33        
      33        
      33        
116             {
117             # Input temp and pres arrays
118 0         0 my @ss;
119 0         0 for ( my $i = 0; $i <= $#$arg1; $i++ )
120             {
121 0         0 push @ss, sound_speed_tp($self, $arg1->[$i],$arg2->[$i],);
122             }
123 0         0 return \@ss;
124             }
125             elsif ( ( ref $arg1 eq 'ARRAY' ) && ( not ref $arg2 ) && ( $arg2 =~ /\d+/ ) )
126             {
127             # Input temp array and constant pres
128 0         0 my @ss;
129 0         0 for ( my $i = 0; $i <= $#$arg1; $i++ )
130             {
131 0         0 push @ss, sound_speed_tp($self, $arg1->[$i],$arg2);
132             }
133 0         0 return \@ss;
134             }
135             elsif ( ( not ref $arg1 ) && ( $arg1 =~ /\d+/ ) && ( ref $arg2 eq 'ARRAY' ) )
136             {
137             # Input temp array and constant pres
138 0         0 my @ss;
139 0         0 for ( my $i = 0; $i <= $#$arg2; $i++ )
140             {
141 0         0 push @ss, sound_speed_tp($self, $arg1, $arg2->[$i]);
142             }
143 0         0 return \@ss;
144             }
145             elsif ( ref $arg1 eq 'ARRAY' )
146             {
147             # Input temp array only
148 0         0 my @ss;
149 0         0 foreach my $temp ( @$arg1 )
150             {
151 0         0 push @ss, sound_speed_t($self, $temp);
152             }
153              
154 0         0 return \@ss;
155             }
156             elsif ( ( not ref $arg1 ) && ( $arg1 =~ /\d+/ ) && ( not ref $arg2 ) && ( $arg2 =~ /\d+/ ) )
157             {
158             # Input temp and pres scalars
159 1         5 my $ss = sound_speed_tp($self, $arg1, $arg2);
160 1         4 return $ss;
161             }
162             elsif ( $arg1 )
163             {
164             # Input temp scalar only
165 0         0 my $ss = sound_speed_t($self, $arg1);
166 0         0 return $ss;
167             }
168              
169 0         0 $self->{'err'} = "Input not recognized";
170 0         0 return '';
171             }
172              
173             # Sound Speed as function of T
174             # Marczak Equation: W. Marczak (1997), Water as a standard in the measurements of speed of sound in liquids J. Acoust. Soc. Am. 102(5) pp 2776-2779.
175             sub sound_speed_t
176             {
177 3     3 0 321 my $self = shift;
178 3         4 my $temp = shift;
179              
180 3 100       9 if ( $self->{units} eq 'US' )
181             {
182 1         3 $temp = $self->{conv}->{f2c} * ( $temp - 32 );
183             }
184              
185 3         15 my $ss = (1402.385)
186             + (5.038813 * $temp)
187             - (5.799136 * 10**-2 * $temp**2)
188             + (3.287156 * 10**-4 * $temp**3)
189             - (1.398845 * 10**-6 * $temp**4)
190             + (2.787860 * 10**-9 * $temp**5);
191              
192 3 100       7 if ( $self->{units} eq 'US' )
193             {
194 1         3 $ss = $ss * $self->{conv}->{'m2ft'};
195             }
196              
197 3         12 return $ss;
198             }
199              
200             # Sound Speed as function of T
201             # Belogol'skii, Sekoyan, Samorukova, Stefanov and Levtsov (1999), Pressure dependence of the sound velocity in distilled water, Measurement Techniques, Vol 42, No 4, pp 406-413.
202             sub sound_speed_tp
203             {
204 1     1 0 2 my $self = shift;
205 1         568 my $temp = shift;
206 1         4 my $pres = shift;
207              
208 1 50       7 if ( $self->{units} eq 'US' )
209             {
210 0         0 $temp = $self->{conv}->{f2c} * ( $temp - 32 );
211 0         0 $pres = $self->{conv}->{psi2mpa} * $pres;
212             }
213              
214 1         2 my @a;
215 1         4 $a[0][0] = 1402.38744;
216 1         2 $a[1][0] = 5.03836171;
217 1         4 $a[2][0] = -5.81172916 * 10**-2;
218 1         2 $a[3][0] = 3.34638117 * 10**-4;
219 1         3 $a[4][0] = -1.48259672 * 10**-6;
220 1         2 $a[5][0] = 3.16585020 * 10**-9;
221 1         3 $a[0][1] = 1.49043589;
222 1         2 $a[1][1] = 1.077850609 * 10**-2;
223 1         1 $a[2][1] = -2.232794656 * 10**-4;
224 1         2 $a[3][1] = 2.718246452 * 10**-6;
225 1         1 $a[0][2] = 4.31532833 * 10**-3;
226 1         2 $a[1][2] = -2.938590293 * 10**-4;
227 1         2 $a[2][2] = 6.822485943 * 10**-6;
228 1         1 $a[3][2] = -6.674551162 * 10**-8;
229 1         2 $a[0][3] = -1.852993525 * 10**-5;
230 1         2 $a[1][3] = 1.481844713 * 10**-6;
231 1         1 $a[2][3] = -3.940994021 * 10**-8;
232 1         2 $a[3][3] = 3.939902307 * 10**-10;
233              
234 1         7 my $c0 = $a[0][0] + $a[1][0]*$temp + $a[2][0]*$temp**2 + $a[3][0]*$temp**3 + $a[4][0]*$temp**4 + $a[5][0]*$temp**5;
235              
236 1         1 my @M;
237 1         4 $M[1] = $a[0][1] + $a[1][1]*$temp + $a[2][1]*$temp**2 + $a[3][1]*$temp**3;
238 1         4 $M[2] = $a[0][2] + $a[1][2]*$temp + $a[2][2]*$temp**2 + $a[3][2]*$temp**3;
239 1         17 $M[3] = $a[0][3] + $a[1][3]*$temp + $a[2][3]*$temp**2 + $a[3][3]*$temp**3;
240 1         7 my $ss = $c0 + $M[1] * ($pres - $self->{stdpres}) + $M[2] * ($pres - $self->{stdpres})**2 + $M[3] * ($pres - $self->{stdpres})**3;
241              
242 1 50       4 if ( $self->{units} eq 'US' )
243             {
244 0         0 $ss = $ss * $self->{conv}->{'m2ft'};
245             }
246              
247 1         6 return $ss;
248              
249             }
250              
251             # - - - - - - - -
252             sub sound_speed_sea_tps
253             {
254 2     2 0 573 my $self = shift;
255 2         3 my $tm = shift;
256 2         2 my $pr = shift;
257 2   33     5 my $sl = shift || $self->{ppm};
258              
259 2 50       6 if ( $self->{units} eq 'US' )
260             {
261 0         0 $tm = $self->{conv}->{f2c} * ( $tm - 32 );
262 0         0 $pr = $self->{conv}->{psi2mpa} * $pr;
263             }
264              
265 2         4 $pr = $pr * 10; # Eqn is in bars
266              
267 2         15 print "====> $pr\n";
268              
269 2         3 my $C00=1402.388;
270 2         3 my $C01=5.03830;
271 2         2 my $C02=-5.81090*10**-2;
272 2         3 my $C03=3.3432*10**-4;
273 2         2 my $C04=-1.47797*10**-6;
274 2         3 my $C05=3.1419*10**-9;
275 2         2 my $C10=0.153563;
276 2         2 my $C11=6.8999*10**-4;
277 2         3 my $C12=-8.1829*10**-6;
278 2         3 my $C13=1.3632*10**-7;
279 2         2 my $C14=-6.1260*10**-10;
280 2         3 my $C20=3.1260*10**-5;
281 2         3 my $C21=-1.7111*10**-6;
282 2         3 my $C22=2.5986*10**-8;
283 2         3 my $C23=-2.5353*10**-10;
284 2         1 my $C24=1.0415*10**-12;
285 2         2 my $C30=-9.7729*10**-9;
286 2         3 my $C31=3.8513*10**-10;
287 2         2 my $C32=-2.3654*10**-12;
288 2         6 my $A00=1.389;
289 2         3 my $A01=-1.262*10**-2;
290 2         2 my $A02=7.166*10**-5;
291 2         1 my $A03=2.008*10**-6;
292 2         3 my $A04=-3.21*10**-8;
293 2         3 my $A10=9.4742*10**-5;
294 2         1 my $A11=-1.2583*10**-5;
295 2         2 my $A12=-6.4928*10**-8;
296 2         3 my $A13=1.0515*10**-8;
297 2         3 my $A14=-2.0142*10**-10;
298 2         2 my $A20=-3.9064*10**-7;
299 2         2 my $A21=9.1061*10**-9;
300 2         2 my $A22=-1.6009*10**-10;
301 2         2 my $A23=7.994*10**-12;
302 2         3 my $A30=1.100*10**-10;
303 2         2 my $A31=6.651*10**-12;
304 2         2 my $A32=-3.391*10**-13;
305 2         3 my $B00=-1.922*10**-2;
306 2         2 my $B01=-4.42*10**-5;
307 2         2 my $B10=7.3637*10**-5;
308 2         3 my $B11=1.7950*10**-7;
309 2         1 my $D00=1.727*10**-3;
310 2         3 my $D10=-7.9836*10**-6;
311              
312 2         25 my $Cw = ($C00 + $C01*$tm + $C02*$tm**2 + $C03*$tm**3 + $C04*$tm**4 + $C05*$tm**5) +
313             ($C10 + $C11*$tm + $C12*$tm**2 + $C13*$tm**3 + $C14*$tm**4)*$pr +
314             ($C20 +$C21*$tm +$C22*$tm**2 + $C23*$tm**3 + $C24*$tm**4)*$pr**2 +
315             ($C30 + $C31*$tm + $C32*$tm**2)*$pr**3;
316              
317 2         585 my $A = ($A00 + $A01*$tm + $A02*$tm**2 +$A03*$tm**3 +$A04*$tm**4 ) +
318             ($A10 + $A11*$tm + $A12*$tm**2 +$A13*$tm**3 + $A14*$tm**4)*$pr +
319             ($A20 +$A21*$tm +$A22*$tm**2 +$A23*$tm**3)*$pr**2 +
320             ($A30 + $A31*$tm + $A32*$tm**2)*$pr**3;
321 2         5 my $B = $B00 + $B01*$tm + ($B10 + $B11*$tm)*$pr;
322 2         3 my $D = $D00+($D10*$pr);
323              
324 2         16 my $C = $Cw + $A*$sl + $B*$sl**(3/2) + $D*($sl**2);
325              
326 2         9 return $C;
327              
328             }
329              
330              
331             # -------
332             sub d2p_fresh
333             {
334 1     1 0 308 my $self = shift;
335 1         2 my $depth = shift;
336              
337 1         4 return d2p($self,$depth,$self->{'density_pure'});
338             }
339              
340             # -------
341             sub d2p_sea
342             {
343 0     0 0 0 my $self = shift;
344 0         0 my $depth = shift;
345              
346 0         0 return d2p($self,$depth,$self->{'density_sea'});
347             }
348              
349             # Depth to pressure
350             sub d2p
351             {
352 1     1 0 1 my $self = shift;
353 1         2 my $depth = shift;
354 1   33     4 my $density = shift || $self->{'density_pure'};
355              
356 1 50       4 if ( ref $depth eq 'ARRAY' )
357             {
358 1         2 my @pres;
359 1         2 foreach my $d (@$depth)
360             {
361 4 50       10 if ( $self->{units} eq 'US' ) { $d = $self->{conv}->{ft2m} * $d }
  0         0  
362 4         10 push @pres, ( $density * 9.807 * $d / 1000000 + $self->{stdpres});
363             }
364              
365 1         5 return \@pres;
366             }
367              
368 0 0         if ( $depth =~ /\d+/)
369             {
370 0 0         if ( $self->{units} eq 'US' ) { $depth = $self->{conv}->{ft2m} * $depth }
  0            
371 0           my $pres = $density * 9.807 * $depth / 1000000 + $self->{stdpres};
372              
373 0           return $pres;
374             }
375              
376 0           $self->{'err'} = "Input Not Recognized\n";
377 0           return '';
378              
379             }
380              
381             1;
382             __END__