pulo 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pulo.rb +28 -0
- data/lib/pulo/exceptions.rb +6 -0
- data/lib/pulo/figure/figure2d.rb +248 -0
- data/lib/pulo/figure/figure3d.rb +166 -0
- data/lib/pulo/formatting.rb +140 -0
- data/lib/pulo/frames/frame.rb +289 -0
- data/lib/pulo/frames/frame_cell.rb +83 -0
- data/lib/pulo/frames/frame_column.rb +149 -0
- data/lib/pulo/frames/frame_row.rb +87 -0
- data/lib/pulo/helpers.rb +1 -0
- data/lib/pulo/machine/hydraulics/pipe.rb +71 -0
- data/lib/pulo/machine/machines.rb +10 -0
- data/lib/pulo/machine/mechanics/moments_of_inertia.rb +64 -0
- data/lib/pulo/machine/steam/boiler.rb +61 -0
- data/lib/pulo/machine/steam/boiler_deaerator.rb +64 -0
- data/lib/pulo/machine/steam/deaerator.rb +37 -0
- data/lib/pulo/machine/steam/desuperheater.rb +29 -0
- data/lib/pulo/machine/steam/header.rb +20 -0
- data/lib/pulo/machine/steam/if97.rb +378 -0
- data/lib/pulo/machine/steam/steam_process.rb +27 -0
- data/lib/pulo/machine/steam/steam_turbine.rb +42 -0
- data/lib/pulo/machine/steam/water_steam.rb +229 -0
- data/lib/pulo/material/water.rb +34 -0
- data/lib/pulo/quantity/dimension.rb +63 -0
- data/lib/pulo/quantity/numeric_overloads.rb +217 -0
- data/lib/pulo/quantity/quantity.rb +285 -0
- data/lib/pulo/quantity/quantity_builder.rb +185 -0
- data/lib/pulo/quantity/quantity_definitions.rb +8 -0
- data/lib/pulo/quantity/quantity_definitions/area_volume.rb +73 -0
- data/lib/pulo/quantity/quantity_definitions/basic.rb +157 -0
- data/lib/pulo/quantity/quantity_definitions/electric.rb +22 -0
- data/lib/pulo/quantity/quantity_definitions/energy.rb +50 -0
- data/lib/pulo/quantity/quantity_definitions/fluids.rb +23 -0
- data/lib/pulo/quantity/quantity_definitions/force_power.rb +82 -0
- data/lib/pulo/quantity/quantity_definitions/rotation.rb +49 -0
- data/lib/pulo/quantity/quantity_definitions/value.rb +65 -0
- data/lib/pulo/quantity/quantity_definitions/velocity_acc_flow.rb +66 -0
- data/lib/pulo/quantity/quantity_groups/quantity_groups.rb +36 -0
- data/lib/pulo/quantity/unit.rb +45 -0
- data/lib/pulo/quantity_checker.rb +13 -0
- data/lib/pulo/tables/density.rb +10 -0
- data/lib/pulo/tables/melting_temperature.rb +9 -0
- data/lib/pulo/tables/specific_energy.rb +10 -0
- data/lib/pulo/tables/speed_of_sound.rb +9 -0
- data/lib/pulo/tables/tables.rb +104 -0
- data/lib/pulo/tables/tensile_strength.rb +10 -0
- data/lib/pulo/tables/yield_strength.rb +10 -0
- data/lib/pulo/version.rb +3 -0
- metadata +51 -3
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
module Pulo
|
3
|
+
module Steam
|
4
|
+
class SteamProcess
|
5
|
+
|
6
|
+
attr_reader :supply, :condensate
|
7
|
+
attr_reader :supply_pressure, :supply_quality, :process_power, :condensate_recovery
|
8
|
+
attr_reader :supply_massflow, :condensate_massflow, :condensate_power
|
9
|
+
def initialize(supply_pressure: nil, supply_quality:nil, process_power: nil, condensate_recovery: nil)
|
10
|
+
raise "Need all parameters" unless supply_pressure && supply_quality && process_power && condensate_recovery
|
11
|
+
|
12
|
+
@supply_pressure=supply_pressure
|
13
|
+
@supply_quality=supply_quality
|
14
|
+
@process_power=process_power
|
15
|
+
@condensate_recovery=condensate_recovery
|
16
|
+
|
17
|
+
@supply=WaterSteam.new(pressure: @supply_pressure, quality: @supply_quality)
|
18
|
+
@condensate=WaterSteam.new(pressure: supply_pressure, quality: Dimensionless.n(0))
|
19
|
+
@evap_energy=@supply.specific_enthalpy-@condensate.specific_enthalpy
|
20
|
+
|
21
|
+
@supply_massflow=@process_power/@evap_energy
|
22
|
+
@condensate_massflow=@supply_massflow*@condensate_recovery
|
23
|
+
@condensate_power=@condensate.specific_enthalpy*@condensate_massflow
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Pulo
|
2
|
+
module Steam
|
3
|
+
class SteamTurbine
|
4
|
+
attr_reader :inlet_steam,:outlet_steam
|
5
|
+
attr_reader :isentropic_efficiency,:mechanical_efficiency
|
6
|
+
attr_reader :electrical_power
|
7
|
+
|
8
|
+
def initialize(inlet_pressure: nil, inlet_temperature:nil,outlet_pressure: nil,isentropic_efficiency: nil, mechanical_efficiency: nil,
|
9
|
+
electrical_power: nil, mass_flow:nil)
|
10
|
+
|
11
|
+
raise "Need all parameters" unless isentropic_efficiency && mechanical_efficiency &&
|
12
|
+
inlet_pressure && outlet_pressure && inlet_temperature &&
|
13
|
+
(electrical_power || mass_flow)
|
14
|
+
|
15
|
+
@electrical_power=electrical_power
|
16
|
+
@isentropic_efficiency=isentropic_efficiency
|
17
|
+
@mechanical_efficiency=mechanical_efficiency
|
18
|
+
|
19
|
+
@inlet_steam=WaterSteam.new(pressure: inlet_pressure, temperature: inlet_temperature)
|
20
|
+
outlet_ideal=WaterSteam.new(pressure: outlet_pressure, specific_entropy: @inlet_steam.specific_entropy)
|
21
|
+
outlet_enthalpy=outlet_enthalpy_from_isentropic(@inlet_steam.specific_enthalpy,outlet_ideal.specific_enthalpy,@isentropic_efficiency)
|
22
|
+
@outlet_steam=WaterSteam.new(pressure: outlet_pressure,specific_enthalpy: outlet_enthalpy)
|
23
|
+
if @electrical_power
|
24
|
+
energy_output=@electrical_power/@mechanical_efficiency
|
25
|
+
outlet_steam.mass_flow=energy_output/(@inlet_steam.specific_enthalpy-outlet_enthalpy)
|
26
|
+
else
|
27
|
+
outlet_steam.mass_flow=mass_flow
|
28
|
+
energy_output=mass_flow*(@inlet_steam.specific_enthalpy-outlet_enthalpy)
|
29
|
+
@electrical_power=energy_output*@mechanical_efficiency
|
30
|
+
end
|
31
|
+
inlet_steam.mass_flow=outlet_steam.mass_flow
|
32
|
+
end
|
33
|
+
|
34
|
+
def isentropic_efficiency_from_enthalpy inlet_enthalpy,outlet_enthalpy,ideal_outlet_enthalpy
|
35
|
+
(inlet_enthalpy-outlet_enthalpy)/(inlet_enthalpy-ideal_outlet_enthalpy)
|
36
|
+
end
|
37
|
+
def outlet_enthalpy_from_isentropic inlet_enthalpy,ideal_outlet_enthalpy,isentropic_efficiency
|
38
|
+
inlet_enthalpy-isentropic_efficiency*(inlet_enthalpy-ideal_outlet_enthalpy)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative '../../../../lib/pulo/machine/steam/if97'
|
4
|
+
|
5
|
+
module Pulo
|
6
|
+
module Steam
|
7
|
+
class WaterSteam
|
8
|
+
attr_accessor :pressure,:temperature
|
9
|
+
attr_accessor :specific_volume,:specific_volume_liquid
|
10
|
+
attr_accessor :specific_internal_energy,:specific_entropy,:specific_enthalpy
|
11
|
+
attr_accessor :saturation_temperature, :saturation_pressure
|
12
|
+
attr_accessor :state,:if97_region
|
13
|
+
attr_accessor :quality
|
14
|
+
attr_reader :mass_flow, :energy_flow
|
15
|
+
|
16
|
+
def to_s(us: false)
|
17
|
+
r=case if97_region
|
18
|
+
when "1"
|
19
|
+
"Water "
|
20
|
+
when "2" || "3"
|
21
|
+
"Superheated "
|
22
|
+
when "4"
|
23
|
+
case quality
|
24
|
+
when Dimensionless.n(1)
|
25
|
+
"Dry steam "
|
26
|
+
when Dimensionless.n(0)
|
27
|
+
"Water "
|
28
|
+
else
|
29
|
+
"Quality:#{quality} "
|
30
|
+
end
|
31
|
+
|
32
|
+
else
|
33
|
+
if97_region.to_s
|
34
|
+
end.ljust(12)
|
35
|
+
if us
|
36
|
+
r+="mf:#{mass_flow.pounds_per_hour.to_s(0).rjust(15)} ef:#{energy_flow.millions_btu_per_hour.to_s.rjust(17)} p:#{pressure.psig.to_s.rjust(9)} t:#{temperature.fahrenheit.to_s(0).rjust(8)} h:#{specific_enthalpy.btu_per_pound.to_s(0).rjust(15)} s:#{specific_entropy.btu_per_pound_rankine}"
|
37
|
+
else
|
38
|
+
r+="mf:#{mass_flow.kilograms_per_second.to_s(0).rjust(15)} ef:#{energy_flow.megawatts.to_s.rjust(17)} p:#{pressure.megapascals} t:#{temperature.kelvin} #{temperature.celsius} h:#{specific_enthalpy.kilojoules_per_kilogram} s:#{specific_entropy.kilojoules_per_kilogram_kelvin}"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def mass_flow=(val)
|
44
|
+
@mass_flow=val
|
45
|
+
if @specific_enthalpy
|
46
|
+
@energy_flow=@mass_flow*@specific_enthalpy
|
47
|
+
end
|
48
|
+
end
|
49
|
+
def energy_flow=(val)
|
50
|
+
@energy_flow=val
|
51
|
+
if @specific_enthalpy
|
52
|
+
@mass_flow=@energy_flow/@specific_enthalpy
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(pressure: nil,temperature: nil,specific_entropy: nil, specific_enthalpy: nil, quality: nil)
|
57
|
+
|
58
|
+
return if !pressure && !temperature && !specific_entropy && !specific_enthalpy && !quality
|
59
|
+
|
60
|
+
@temperature=temperature.kelvin if temperature
|
61
|
+
@pressure=pressure.megapascals if pressure
|
62
|
+
@specific_entropy=specific_entropy.kilojoules_per_kilogram_kelvin if specific_entropy
|
63
|
+
@specific_enthalpy=specific_enthalpy.kilojoules_per_kilogram if specific_enthalpy
|
64
|
+
@quality=quality.n if quality
|
65
|
+
@mass_flow=MassFlow.new(0)
|
66
|
+
@energy_flow=Power.new(0)
|
67
|
+
|
68
|
+
if @temperature && (@temperature>Temperature.kelvin(1073.15) || @temperature<Temperature.kelvin(273.15))
|
69
|
+
raise "Temperature outside valid range 273.15K to 1073.15K"
|
70
|
+
#TODO: Implement R5
|
71
|
+
end
|
72
|
+
if @pressure && (@pressure<Pressure.megapascals(0) || @pressure>Pressure.megapascals(100))
|
73
|
+
raise "Pressure outside valid range 0MPa to 100MPa"
|
74
|
+
end
|
75
|
+
|
76
|
+
if (quality && (pressure || temperature))
|
77
|
+
@if97_region="4"
|
78
|
+
if temperature
|
79
|
+
@pressure=IF97.pressure_from_temperature_r4 @temperature
|
80
|
+
else
|
81
|
+
@temperature=IF97.temperature_from_pressure_r4 @pressure
|
82
|
+
end
|
83
|
+
fluid=WaterSteam.new
|
84
|
+
IF97.other_props_r1(@temperature,@pressure,fluid)
|
85
|
+
|
86
|
+
gas=WaterSteam.new
|
87
|
+
IF97.other_props_r2(@temperature,@pressure,gas)
|
88
|
+
|
89
|
+
@specific_enthalpy=fluid.specific_enthalpy+(gas.specific_enthalpy-fluid.specific_enthalpy)*@quality
|
90
|
+
@specific_entropy=fluid.specific_entropy+(gas.specific_entropy-fluid.specific_entropy)*@quality
|
91
|
+
@specific_volume=fluid.specific_volume+(gas.specific_volume-fluid.specific_volume)*@quality
|
92
|
+
@specific_internal_energy=fluid.specific_internal_energy+(gas.specific_internal_energy-fluid.specific_internal_energy)*@quality
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
if (temperature && !pressure && !specific_entropy && !specific_enthalpy) || (!temperature && pressure && !specific_entropy && !specific_enthalpy)
|
97
|
+
#if97 region 4 saturated steam
|
98
|
+
@if97_region="4"
|
99
|
+
if temperature
|
100
|
+
@pressure=IF97.pressure_from_temperature_r4 @temperature
|
101
|
+
else
|
102
|
+
@temperature=IF97.temperature_from_pressure_r4 @pressure
|
103
|
+
end
|
104
|
+
@saturation_temperature=@temperature
|
105
|
+
@saturation_pressure=@pressure
|
106
|
+
return
|
107
|
+
end
|
108
|
+
|
109
|
+
if @temperature && @pressure
|
110
|
+
#determine region
|
111
|
+
if @temperature<Temperature.kelvin(623.15)
|
112
|
+
@saturation_pressure=IF97.pressure_from_temperature_r4 @temperature
|
113
|
+
@saturation_temperature=IF97.temperature_from_pressure_r4 @pressure
|
114
|
+
if @pressure<@saturation_pressure
|
115
|
+
@if97_region="2"
|
116
|
+
IF97.other_props_r2(@temperature,@pressure,self)
|
117
|
+
else
|
118
|
+
@if97_region="1"
|
119
|
+
IF97.other_props_r1(@temperature,@pressure,self)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
p_b23=IF97.pressure_from_b23(@temperature)
|
123
|
+
if @pressure>p_b23
|
124
|
+
@if97_region="3"
|
125
|
+
#TODO: Implement R3 forward
|
126
|
+
else
|
127
|
+
@if97_region="2"
|
128
|
+
IF97.other_props_r2(temperature,@pressure,self)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
return
|
132
|
+
end
|
133
|
+
|
134
|
+
if @pressure && @specific_enthalpy
|
135
|
+
region=IF97.get_region_ph(@pressure,@specific_enthalpy)
|
136
|
+
case region
|
137
|
+
when 1
|
138
|
+
#raise "Reverse for region 1 not implemented"
|
139
|
+
IF97.temperature_from_pressure_enthalpy_r1(@pressure,@specific_enthalpy,self)
|
140
|
+
IF97.other_props_r1(@temperature,@pressure,self)
|
141
|
+
@if97_region="1"
|
142
|
+
when 2
|
143
|
+
IF97.temperature_from_pressure_enthalpy_r2(@pressure,@specific_enthalpy,self)
|
144
|
+
IF97.other_props_r2(@temperature,@pressure,self)
|
145
|
+
@if97_region="2"
|
146
|
+
when 3
|
147
|
+
raise "Reverse for region 3 not implemented"
|
148
|
+
@if97_region="3"
|
149
|
+
when 4
|
150
|
+
@temperature=IF97.temperature_from_pressure_r4 @pressure
|
151
|
+
@if97_region="4"
|
152
|
+
|
153
|
+
fluid=WaterSteam.new
|
154
|
+
IF97.other_props_r1(@temperature,@pressure,fluid)
|
155
|
+
|
156
|
+
gas=WaterSteam.new
|
157
|
+
IF97.other_props_r2(@temperature,@pressure,gas)
|
158
|
+
|
159
|
+
@quality=(self.specific_enthalpy-fluid.specific_enthalpy)/(gas.specific_enthalpy-fluid.specific_enthalpy)
|
160
|
+
@specific_entropy=fluid.specific_entropy+(gas.specific_entropy-fluid.specific_entropy)*@quality
|
161
|
+
@specific_volume=fluid.specific_volume+(gas.specific_volume-fluid.specific_volume)*@quality
|
162
|
+
@specific_internal_energy=fluid.specific_internal_energy+(gas.specific_internal_energy-fluid.specific_internal_energy)*@quality
|
163
|
+
end
|
164
|
+
return
|
165
|
+
end
|
166
|
+
|
167
|
+
if @pressure && @specific_entropy
|
168
|
+
#get the r1,r2 boundary saturation entropy
|
169
|
+
region=IF97.get_region_ps(@pressure,@specific_entropy)
|
170
|
+
|
171
|
+
case region
|
172
|
+
when 1
|
173
|
+
IF97.temperature_from_pressure_entropy_r1(@pressure,@specific_entropy,self)
|
174
|
+
IF97.other_props_r1(@temperature,@pressure,self)
|
175
|
+
@if97_region="1"
|
176
|
+
when 2
|
177
|
+
IF97.temperature_from_pressure_entropy_r2(@pressure,@specific_entropy,self)
|
178
|
+
IF97.other_props_r2(@temperature,@pressure,self)
|
179
|
+
@if97_region="2"
|
180
|
+
when 3
|
181
|
+
raise "Reverse for region 3 not implemented"
|
182
|
+
@if97_region="3"
|
183
|
+
when 4
|
184
|
+
@temperature=IF97.temperature_from_pressure_r4 @pressure
|
185
|
+
@if97_region="4"
|
186
|
+
|
187
|
+
fluid=WaterSteam.new
|
188
|
+
IF97.other_props_r1(@temperature,@pressure,fluid)
|
189
|
+
|
190
|
+
gas=WaterSteam.new
|
191
|
+
IF97.other_props_r2(@temperature,@pressure,gas)
|
192
|
+
|
193
|
+
@quality=(self.specific_entropy-fluid.specific_entropy)/(gas.specific_entropy-fluid.specific_entropy)
|
194
|
+
@specific_enthalpy=fluid.specific_enthalpy+(gas.specific_enthalpy-fluid.specific_enthalpy)*@quality
|
195
|
+
@specific_volume=fluid.specific_volume+(gas.specific_volume-fluid.specific_volume)*@quality
|
196
|
+
@specific_internal_energy=fluid.specific_internal_energy+(gas.specific_internal_energy-fluid.specific_internal_energy)*@quality
|
197
|
+
end
|
198
|
+
|
199
|
+
case region
|
200
|
+
when 1
|
201
|
+
IF97.temperature_from_pressure_entropy_r1(@pressure,@specific_entropy,self)
|
202
|
+
@if97_region="1"
|
203
|
+
when 2
|
204
|
+
IF97.temperature_from_pressure_entropy_r2(@pressure,@specific_entropy,self)
|
205
|
+
@if97_region="2"
|
206
|
+
when 3
|
207
|
+
raise "Reverse for region 3 not implemented"
|
208
|
+
@if97_region="3"
|
209
|
+
when 4
|
210
|
+
@temperature=IF97.temperature_from_pressure_r4 @pressure
|
211
|
+
@if97_region="4"
|
212
|
+
|
213
|
+
fluid=WaterSteam.new
|
214
|
+
IF97.other_props_r1(@temperature,@pressure,fluid)
|
215
|
+
|
216
|
+
gas=WaterSteam.new
|
217
|
+
IF97.other_props_r2(@temperature,@pressure,gas)
|
218
|
+
|
219
|
+
@quality=(self.specific_entropy-fluid.specific_entropy)/(gas.specific_entropy-fluid.specific_entropy)
|
220
|
+
@specific_enthalpy=fluid.specific_enthalpy+(gas.specific_enthalpy-fluid.specific_enthalpy)*@quality
|
221
|
+
@specific_volume=fluid.specific_volume+(gas.specific_volume-fluid.specific_volume)*@quality
|
222
|
+
@specific_internal_energy=fluid.specific_internal_energy+(gas.specific_internal_energy-fluid.specific_internal_energy)*@quality
|
223
|
+
return
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Pulo
|
4
|
+
|
5
|
+
class Water
|
6
|
+
#def self.bulk_modulus
|
7
|
+
#BulkModulus.new(2.15*10**9)
|
8
|
+
#end
|
9
|
+
#def self.expansion_coefficient
|
10
|
+
# Dimensionless.n(0.000088)
|
11
|
+
#end
|
12
|
+
#def self.enthalpy_of_vaporization
|
13
|
+
# 40680
|
14
|
+
#end
|
15
|
+
def self.standard_density
|
16
|
+
Density.kilograms_per_cubic_meter(1000)
|
17
|
+
end
|
18
|
+
#def self.density(temperature,pressure)
|
19
|
+
# tmp=temperature.is_a?(Temperature) ? temperature.value : temperature
|
20
|
+
# pres=pressure.is_a?(Pressure) ? pressure.value : pressure
|
21
|
+
# Density.new(999.8 / (1 + Water.expansion_coefficient * tmp) / (1 - (pres - 1105) / Water.bulk_modulus.value))
|
22
|
+
#end
|
23
|
+
#def self.boiling_point(pressure)
|
24
|
+
# pres=pressure.is_a?(Pressure) ? pressure.value : pressure
|
25
|
+
# k=GAS_CONSTANT/Water.enthalpy_of_vaporization
|
26
|
+
# Temperature.new(1/((1/Temperature.new(100).kelvin)-k*Math.log(pres/Atmosphere.standard_pressure.value)),:kelvin)
|
27
|
+
#end
|
28
|
+
#def self.melting_point(pressure)
|
29
|
+
# pres=pressure.is_a?(Pressure) ? pressure.value : pressure
|
30
|
+
# Temperature.new(Math::E**(Math.log(Temperature.new(0).kelvin)+((-1.56*10**-6)/6030)*(pres-Atmosphere.standard_pressure.value)),:kelvin)
|
31
|
+
#end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Pulo
|
4
|
+
class Dimension
|
5
|
+
include Comparable
|
6
|
+
def initialize(spec)
|
7
|
+
@spec=spec #hash keyed on dimension name as a symbol eg :L
|
8
|
+
clean
|
9
|
+
end
|
10
|
+
def spec
|
11
|
+
@spec
|
12
|
+
end
|
13
|
+
|
14
|
+
#def is_base?
|
15
|
+
# @spec.count==1 && @spec.first[1]==1
|
16
|
+
#end
|
17
|
+
|
18
|
+
def +(other_spec)
|
19
|
+
Dimension.new @spec.merge(other_spec.spec) {|_key,val1,val2| val1+val2}
|
20
|
+
end
|
21
|
+
def -(other_spec)
|
22
|
+
new_hash = Hash[other_spec.spec.map{|k,itm| [k,-itm] } ]
|
23
|
+
Dimension.new @spec.merge(new_hash) {|_key,val1,val2| val1+val2}
|
24
|
+
end
|
25
|
+
def *(val)
|
26
|
+
Dimension.new Hash[@spec.map{|itm| [itm[0],itm[1]*val]}]
|
27
|
+
end
|
28
|
+
def /(val)
|
29
|
+
Dimension.new Hash[@spec.map{|itm| [itm[0],itm[1]/val]}]
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(other_spec)
|
33
|
+
val=(@spec.merge(other_spec.spec) {|_key,val1,val2| val1-val2}).inject(0) {|sum,n| sum+n[1].abs}
|
34
|
+
val==0
|
35
|
+
end
|
36
|
+
def eql?(other_spec)
|
37
|
+
self==(other_spec)
|
38
|
+
end
|
39
|
+
def hash
|
40
|
+
@spec.to_s.hash
|
41
|
+
end
|
42
|
+
def to_s(supress_pretty=false)
|
43
|
+
sort_spec=@spec.sort_by { |item| item[1]*-1}
|
44
|
+
|
45
|
+
if supress_pretty
|
46
|
+
sort_spec.reduce('') do |ret,item|
|
47
|
+
ret+item[0].to_s + item[1].to_s
|
48
|
+
end
|
49
|
+
else
|
50
|
+
sort_spec.reduce('') do |ret,item|
|
51
|
+
ret+=item[0].to_s + (item[1]==1 ? '' : Pulo.super_digit(item[1])) + '.'
|
52
|
+
end[0..-2]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def clean
|
60
|
+
@spec=Hash[@spec.delete_if {|_key,value| value==0}.sort]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#Cos, Sin and Tan of angles
|
4
|
+
class Numeric
|
5
|
+
def clamp(min, max)
|
6
|
+
if self < min
|
7
|
+
min
|
8
|
+
else
|
9
|
+
self > max ? max : self
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Math
|
15
|
+
class << self
|
16
|
+
alias :old_sqrt :sqrt
|
17
|
+
def sqrt(val)
|
18
|
+
if val.is_a?(Pulo::Quantity)
|
19
|
+
val.rt(2)
|
20
|
+
else
|
21
|
+
self.old_sqrt(val)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :old_cos :cos
|
26
|
+
def cos(angle)
|
27
|
+
if angle.is_a?(Pulo::Angle)
|
28
|
+
Pulo::Dimensionless.n(self.old_cos(angle.radians.value))
|
29
|
+
else
|
30
|
+
self.old_cos(angle)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :old_acos :acos
|
35
|
+
def acos(dimless)
|
36
|
+
if dimless.is_a?(Pulo::Dimensionless)
|
37
|
+
Pulo::Angle.radians(self.old_acos(dimless.n.value.clamp(-1,1)))
|
38
|
+
else
|
39
|
+
self.old_acos(dimless)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
alias :old_sin :sin
|
44
|
+
def sin(angle)
|
45
|
+
if angle.is_a?(Pulo::Angle)
|
46
|
+
Pulo::Dimensionless.n(self.old_sin(angle.radians.value))
|
47
|
+
else
|
48
|
+
self.old_sin(angle)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
alias :old_asin :asin
|
53
|
+
def asin(dimless)
|
54
|
+
if dimless.is_a?(Pulo::Dimensionless)
|
55
|
+
Pulo::Angle.radians(self.old_asin(dimless.n.value.clamp(-1,1)))
|
56
|
+
else
|
57
|
+
self.old_asin(dimless)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
alias :old_tan :tan
|
62
|
+
def tan(angle)
|
63
|
+
if angle.is_a?(Pulo::Angle)
|
64
|
+
Pulo::Dimensionless.n(self.old_tan(angle.radians.value))
|
65
|
+
else
|
66
|
+
self.old_tan(angle)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
alias :old_atan :atan
|
71
|
+
def atan(dimless)
|
72
|
+
if dimless.is_a?(Pulo::Dimensionless)
|
73
|
+
Pulo::Angle.radians(self.old_tan(dimless.n.value))
|
74
|
+
else
|
75
|
+
self.old_atan(dimless)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#Add and subtract work for Dimensionless
|
83
|
+
class BigDecimal
|
84
|
+
alias :old_minus :-
|
85
|
+
def -(other)
|
86
|
+
if other.is_a?(Pulo::Dimensionless)
|
87
|
+
Pulo::Dimensionless.new(self-other.to_base_unit.value)
|
88
|
+
else
|
89
|
+
self.old_minus(other)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Integer
|
95
|
+
alias :old_minus :-
|
96
|
+
def -(other)
|
97
|
+
if other.is_a?(Pulo::Dimensionless)
|
98
|
+
Pulo::Dimensionless.new(self-other.to_base_unit.value)
|
99
|
+
else
|
100
|
+
self.old_minus(other)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Float
|
106
|
+
alias :old_minus :-
|
107
|
+
def -(other)
|
108
|
+
if other.is_a?(Pulo::Dimensionless)
|
109
|
+
Pulo::Dimensionless.new(self-other.to_base_unit.value)
|
110
|
+
else
|
111
|
+
self.old_minus(other)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class BigDecimal
|
117
|
+
alias :old_plus :+
|
118
|
+
def +(other)
|
119
|
+
if other.is_a?(Pulo::Dimensionless)
|
120
|
+
Pulo::Dimensionless.new(self+other.to_base_unit.value)
|
121
|
+
else
|
122
|
+
self.old_plus(other)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Integer
|
128
|
+
alias :old_plus :+
|
129
|
+
def +(other)
|
130
|
+
if other.is_a?(Pulo::Dimensionless)
|
131
|
+
Pulo::Dimensionless.new(self+other.to_base_unit.value)
|
132
|
+
else
|
133
|
+
self.old_plus(other)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class Float
|
139
|
+
alias :old_plus :+
|
140
|
+
def +(other)
|
141
|
+
if other.is_a?(Pulo::Dimensionless)
|
142
|
+
Pulo::Dimensionless.new(self+other.to_base_unit.value)
|
143
|
+
else
|
144
|
+
self.old_plus(other)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
#Division (Scalar/Quantity) gives (1/Quantity) * Scalar
|
150
|
+
class BigDecimal
|
151
|
+
alias :old_div :/
|
152
|
+
def /(other)
|
153
|
+
if other.is_a?(Pulo::Quantity)
|
154
|
+
other.inverse*self
|
155
|
+
else
|
156
|
+
self.old_div(other)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class Integer
|
162
|
+
alias :old_div :/
|
163
|
+
def /(other)
|
164
|
+
if other.is_a?(Pulo::Quantity)
|
165
|
+
other.inverse*self
|
166
|
+
else
|
167
|
+
self.old_div(other)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class Float
|
173
|
+
alias :old_div :/
|
174
|
+
def /(other)
|
175
|
+
if other.is_a?(Pulo::Quantity)
|
176
|
+
other.inverse*self
|
177
|
+
else
|
178
|
+
self.old_div(other)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
#Multiplication is a reversal for Quantity * Scalar
|
184
|
+
class BigDecimal
|
185
|
+
alias :old_times :*
|
186
|
+
def *(other)
|
187
|
+
if other.is_a?(Pulo::Quantity)
|
188
|
+
other*self
|
189
|
+
else
|
190
|
+
self.old_times(other)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class Integer
|
196
|
+
alias :old_times :*
|
197
|
+
def *(other)
|
198
|
+
if other.is_a?(Pulo::Quantity)
|
199
|
+
other*self
|
200
|
+
else
|
201
|
+
self.old_times(other)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
class Float
|
208
|
+
alias :old_times :*
|
209
|
+
def *(other)
|
210
|
+
if other.is_a?(Pulo::Quantity)
|
211
|
+
other*self
|
212
|
+
else
|
213
|
+
self.old_times(other)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|