pulo 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pulo.rb +28 -0
  3. data/lib/pulo/exceptions.rb +6 -0
  4. data/lib/pulo/figure/figure2d.rb +248 -0
  5. data/lib/pulo/figure/figure3d.rb +166 -0
  6. data/lib/pulo/formatting.rb +140 -0
  7. data/lib/pulo/frames/frame.rb +289 -0
  8. data/lib/pulo/frames/frame_cell.rb +83 -0
  9. data/lib/pulo/frames/frame_column.rb +149 -0
  10. data/lib/pulo/frames/frame_row.rb +87 -0
  11. data/lib/pulo/helpers.rb +1 -0
  12. data/lib/pulo/machine/hydraulics/pipe.rb +71 -0
  13. data/lib/pulo/machine/machines.rb +10 -0
  14. data/lib/pulo/machine/mechanics/moments_of_inertia.rb +64 -0
  15. data/lib/pulo/machine/steam/boiler.rb +61 -0
  16. data/lib/pulo/machine/steam/boiler_deaerator.rb +64 -0
  17. data/lib/pulo/machine/steam/deaerator.rb +37 -0
  18. data/lib/pulo/machine/steam/desuperheater.rb +29 -0
  19. data/lib/pulo/machine/steam/header.rb +20 -0
  20. data/lib/pulo/machine/steam/if97.rb +378 -0
  21. data/lib/pulo/machine/steam/steam_process.rb +27 -0
  22. data/lib/pulo/machine/steam/steam_turbine.rb +42 -0
  23. data/lib/pulo/machine/steam/water_steam.rb +229 -0
  24. data/lib/pulo/material/water.rb +34 -0
  25. data/lib/pulo/quantity/dimension.rb +63 -0
  26. data/lib/pulo/quantity/numeric_overloads.rb +217 -0
  27. data/lib/pulo/quantity/quantity.rb +285 -0
  28. data/lib/pulo/quantity/quantity_builder.rb +185 -0
  29. data/lib/pulo/quantity/quantity_definitions.rb +8 -0
  30. data/lib/pulo/quantity/quantity_definitions/area_volume.rb +73 -0
  31. data/lib/pulo/quantity/quantity_definitions/basic.rb +157 -0
  32. data/lib/pulo/quantity/quantity_definitions/electric.rb +22 -0
  33. data/lib/pulo/quantity/quantity_definitions/energy.rb +50 -0
  34. data/lib/pulo/quantity/quantity_definitions/fluids.rb +23 -0
  35. data/lib/pulo/quantity/quantity_definitions/force_power.rb +82 -0
  36. data/lib/pulo/quantity/quantity_definitions/rotation.rb +49 -0
  37. data/lib/pulo/quantity/quantity_definitions/value.rb +65 -0
  38. data/lib/pulo/quantity/quantity_definitions/velocity_acc_flow.rb +66 -0
  39. data/lib/pulo/quantity/quantity_groups/quantity_groups.rb +36 -0
  40. data/lib/pulo/quantity/unit.rb +45 -0
  41. data/lib/pulo/quantity_checker.rb +13 -0
  42. data/lib/pulo/tables/density.rb +10 -0
  43. data/lib/pulo/tables/melting_temperature.rb +9 -0
  44. data/lib/pulo/tables/specific_energy.rb +10 -0
  45. data/lib/pulo/tables/speed_of_sound.rb +9 -0
  46. data/lib/pulo/tables/tables.rb +104 -0
  47. data/lib/pulo/tables/tensile_strength.rb +10 -0
  48. data/lib/pulo/tables/yield_strength.rb +10 -0
  49. data/lib/pulo/version.rb +3 -0
  50. metadata +51 -3
@@ -0,0 +1,149 @@
1
+ require 'descriptive_statistics'
2
+
3
+ module Pulo
4
+ class FrameColumn
5
+
6
+ attr_reader :name,:formula, :formatter, :column_class, :column_unit
7
+ attr_accessor :width
8
+
9
+ def initialize(name,parent_frame,hidden,&formula)
10
+ @name=name
11
+ @parent_frame=parent_frame
12
+ @formula=formula
13
+ @cells=[]
14
+ #@recalc_required=block_given?
15
+ @value_column=!block_given?
16
+ @standard_formatter=lambda {|v| v.to_s }
17
+ @formatter=@standard_formatter
18
+ @hidden=hidden
19
+ @width=3
20
+ @column_class=NilClass
21
+ @column_unit=NilClass
22
+ end
23
+
24
+ def set_formula &formula
25
+ @formula=formula
26
+ #@recalc_required=true
27
+ @value_column=false
28
+ end
29
+
30
+ def column_number
31
+ @parent_frame.column_names[@name]
32
+ end
33
+
34
+ def column_class= (klass)
35
+ @column_class=klass
36
+ if @column_class.respond_to?(:quantity_name) and @formatter==@standard_formatter
37
+ @formatter=lambda {|q| q.to_s(nil,true)}
38
+ end
39
+ end
40
+ def column_unit=(klass)
41
+ @column_unit=klass
42
+ end
43
+ def formatter= (lamb)
44
+ @formatter=lamb
45
+ end
46
+ def hidden?
47
+ @hidden
48
+ end
49
+ def hidden=value
50
+ @hidden=value
51
+ end
52
+ def name= new_name
53
+ if @parent_frame.column_names[new_name]
54
+ @name=new_name
55
+ else
56
+ @parent_frame.rename_column @name,new_name
57
+ end
58
+ end
59
+
60
+ def append_row(cell)
61
+ @cells<<cell
62
+ end
63
+ def insert_row(row_no,cell)
64
+ @cells.insert(row_no,cell)
65
+ end
66
+
67
+ def values=(vals)
68
+ raise ArgumentError,"Wrong number of values given for column - need an array of #{@cells.count}" unless vals.count==@cells.count
69
+ vals.each_with_index do |val,index|
70
+ @cells[index].value=val
71
+ end
72
+ end
73
+
74
+ def recalc with_timing=false
75
+ t_start=Time.now
76
+
77
+ @column_class=NilClass
78
+ @parent_frame.rows.each do |row|
79
+ begin
80
+ row[column_number].value=@formula.call(row)
81
+ row[column_number].unset_error
82
+ rescue Exception => e
83
+ #raise "Exception '#{e}' occured calculating column: #{@name} row: #{row.row_number}"
84
+ warn "Warning! Exception '#{e}' occured calculating column: #{@name} row: #{row.row_number}"
85
+ row[column_number].set_error
86
+ end
87
+ end
88
+
89
+ if with_timing
90
+ puts "Recalc column '#{@name}' in: #{((Time.now-t_start)*1000).to_i} ms."
91
+ end
92
+ end
93
+
94
+ def [](index)
95
+ raise IndexError,"No row number #{index} defined." unless @cells[index]
96
+ @cells[index]
97
+ end
98
+
99
+ def lookup(value)
100
+ (@cells.find_all {|cell| cell.value==value}).map {|cell| cell.row}
101
+ end
102
+
103
+ def map!(&block)
104
+ @cells.each {|cell| cell.value=block.call(cell.value)}
105
+ end
106
+
107
+ def to_a
108
+ @cells.map {|cell| cell.value}
109
+ end
110
+
111
+ def value_column?
112
+ @value_column
113
+ end
114
+
115
+ def recalc_width
116
+ @width=@cells.take(30).map {|c| c.to_s.length}.max
117
+ @width||=0
118
+ @width=[@width,@name.length].max
119
+ @width=[@width,column_class.to_s.length+1].max
120
+ end
121
+
122
+ def to_s
123
+ "#{@name}: #{(@cells.map {|c| c.to_s}).join(', ')}"
124
+ end
125
+ def inspect
126
+ "Frame Column Object"
127
+ end
128
+
129
+ def descriptive_statistics
130
+ vals=self.to_a
131
+ if @column_class.respond_to?(:quantity_name)
132
+ vals=vals.map{|val| val.send(@column_unit.name).value}
133
+ end
134
+ stats=vals.descriptive_statistics
135
+ if @column_class.respond_to?(:quantity_name)
136
+ stats.map{|val|
137
+
138
+ if val[0]!=:number
139
+ [val[0],@column_class.new(val[1],@column_unit)]
140
+ else
141
+ [val[0],val[1]]
142
+ end
143
+
144
+ }.to_h
145
+ end
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,87 @@
1
+ module Pulo
2
+ class FrameRow
3
+ attr_reader :cells
4
+ attr_accessor :row_number
5
+ def initialize(parent_frame, row_number)
6
+ @cells=[]
7
+ @parent_frame=parent_frame
8
+ @row_number=row_number
9
+ end
10
+
11
+ def append_column(cell)
12
+ @cells<<cell
13
+ end
14
+
15
+ def delete_column(index)
16
+ @cells.delete_at index
17
+ end
18
+
19
+ def [](column)
20
+ if column.is_a?(Integer)
21
+ raise IndexError,"No column number #{column} defined." unless @cells[column]
22
+ @cells[column]
23
+ else
24
+ @parent_frame[column][@row_number]
25
+ end
26
+ end
27
+
28
+ def previous_rows
29
+ Enumerator.new do |y|
30
+ for i in (0..(@row_number-1)).reverse_each
31
+ y.yield @parent_frame.rows[i]
32
+ end
33
+ end
34
+ end
35
+
36
+ def next_rows
37
+ Enumerator.new do |y|
38
+ for i in (@row_number+1)..@parent_frame.row_count-1
39
+ y.yield @parent_frame.rows[i]
40
+ end
41
+ end
42
+ end
43
+
44
+ def previous_row
45
+ if @row_number>0
46
+ @parent_frame.rows[@row_number-1]
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ def next_row
53
+ if @row_number<@parent_frame.row_count
54
+ @parent_frame.rows[@row_number+1]
55
+ else
56
+ nil
57
+ end
58
+ end
59
+
60
+ def to_s
61
+ "row #{@row_number}:".ljust(9,' ') + " #{((@cells.select {|s| !s.column.hidden?}).map {|c| c.to_s}).join(' ')}"
62
+ end
63
+ def inspect
64
+ "Frame Row Object"
65
+ end
66
+
67
+ def to_a
68
+ @cells.map {|cell| cell.value}
69
+ end
70
+
71
+ def to_a_values
72
+ value_cells.map {|cell| cell.value}
73
+ end
74
+
75
+ def value_cells
76
+ @cells.find_all { |cell| cell.value_column?}
77
+ end
78
+
79
+ def to_h
80
+ Hash[@parent_frame.column_names.keys.to_a.zip(to_a)]
81
+ end
82
+
83
+ def first_row?
84
+ @row_number==0
85
+ end
86
+ end
87
+ end
@@ -0,0 +1 @@
1
+ # encoding: utf-8
@@ -0,0 +1,71 @@
1
+ module Pulo
2
+
3
+ class PipeTypes
4
+ attr_reader :pipe_types
5
+ def initialize
6
+ pipe_groups={
7
+ uPvc: {Chw: 150, density: Density.kilograms_per_cubic_meter(1800), unit_length: Length.meters(6)}
8
+ }
9
+ @pipe_types={
10
+ class6_160: {group: :uPvc, od: Length.millimeters(160.0), id: Length.millimeters(153.6), unit_cost: Value.dollars(50)},
11
+ class6_200: {group: :uPvc, od: Length.millimeters(200.0), id: Length.millimeters(192.2), unit_cost: Value.dollars(78)},
12
+ class6_250: {group: :uPvc, od: Length.millimeters(250.0), id: Length.millimeters(242.0), unit_cost: Value.dollars(105)},
13
+ class6_315: {group: :uPvc, od: Length.millimeters(315.0), id: Length.millimeters(302.6), unit_cost: Value.dollars(232)},
14
+ class6_355: {group: :uPvc, od: Length.millimeters(355.0), id: Length.millimeters(341.0), unit_cost: Value.dollars(326)},
15
+ class6_400: {group: :uPvc, od: Length.millimeters(400.0), id: Length.millimeters(384.4), unit_cost: Value.dollars(440)},
16
+ class6_450: {group: :uPvc, od: Length.millimeters(450.0), id: Length.millimeters(428.8), unit_cost: Value.dollars(610)},
17
+ class6_500: {group: :uPvc, od: Length.millimeters(500.0), id: Length.millimeters(476.4), unit_cost: Value.dollars(750)}
18
+ }
19
+ @pipe_types.values.each do |pt|
20
+ pt.merge!(pipe_groups[pt[:group]])
21
+ end
22
+ end
23
+ end
24
+
25
+
26
+ class Pipeline
27
+
28
+ attr_reader :inside_cylinder,:outside_cylinder,:length
29
+ attr_reader :wall_thickness, :wall_area, :wall_volume, :mass
30
+ attr_reader :pipe_type
31
+ attr_reader :wall_density
32
+ attr_reader :inlet_pressure,:outlet_pressure, :flow
33
+ attr_reader :friction_gradient, :static_head, :friction_head, :total_head, :flow_velocity, :hydraulic_power
34
+ attr_reader :cost
35
+
36
+ def initialize(args)
37
+
38
+ @pipe_type_ref=args[:pipe]
39
+ @pipe_type=PipeTypes.new().pipe_types[@pipe_type_ref]
40
+
41
+ @length=args[:length]
42
+ @cost=@length*@pipe_type[:unit_cost]/@pipe_type[:unit_length]
43
+ @inside_cylinder=Cylinder.new(diameter: @pipe_type[:id], length: @length)
44
+ @outside_cylinder=Cylinder.new(diameter: @pipe_type[:od], length: @length)
45
+ @wall_thickness=@outside_cylinder.radius-@inside_cylinder.radius
46
+ @wall_area=@outside_cylinder.area-@inside_cylinder.area
47
+ @wall_volume=@outside_cylinder.volume-@inside_cylinder.volume
48
+ @mass=@wall_volume*@pipe_type[:density]
49
+
50
+ args[:static_head] ? @static_head=args[:static_head] : @static_head=Length.meters(0)
51
+ args[:inlet_pressure] ? @inlet_pressure=args[:inlet_pressure] : @inlet_pressure=Pressure.pascals(0)
52
+ args[:outlet_pressure] ? @outlet_pressure=args[:outlet_pressure] : @outlet_pressure=Pressure.pascals(0)
53
+ @pressure_head=(@outlet_pressure-@inlet_pressure)/(Water.standard_density*Acceleration.standard_gravity)
54
+ end
55
+
56
+ def flow=(val)
57
+ @flow=val
58
+ @flow_velocity=@flow/inside_cylinder.area
59
+ head_for_flow()
60
+ @hydraulic_power=((@flow*Water.standard_density)*Acceleration.standard_gravity)*@total_head
61
+ end
62
+
63
+ def head_for_flow()
64
+ k=(@pipe_type[:Chw]**1.85)*@inside_cylinder.face.diameter.meters.value**4.87
65
+ @friction_gradient=Dimensionless.n(10.67*@flow.cubic_meter_per_second.value**1.85/k)
66
+ @friction_head=@length * @friction_gradient
67
+ @total_head=@friction_head+@static_head+@pressure_head
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,10 @@
1
+ require_relative './steam/water_steam'
2
+ require_relative './steam/boiler'
3
+ require_relative './steam/deaerator'
4
+ require_relative './steam/boiler_deaerator'
5
+ require_relative './steam/desuperheater'
6
+ require_relative './steam/header'
7
+ require_relative './steam/steam_process'
8
+ require_relative './steam/steam_turbine'
9
+
10
+ require_relative './mechanics/moments_of_inertia'
@@ -0,0 +1,64 @@
1
+ module Pulo
2
+ class MomentOfInertia
3
+ def self.point_mass(mass, distance)
4
+ mass*distance**2
5
+ end
6
+
7
+ #rod around its mid point
8
+ def self.rod(mass, length)
9
+ (mass*distance**2)/12.0
10
+ end
11
+
12
+ #rod around its mid point
13
+ def self.rod_end(mass, length)
14
+ (mass*length**2)/3.0
15
+ end
16
+
17
+ #hoop
18
+ def self.hoop(mass, radius)
19
+ (mass*radius**2)/2.0
20
+ end
21
+
22
+ #disc
23
+ def self.disc(mass, radius)
24
+ (mass*radius**2)/4.0
25
+ end
26
+
27
+ #cylindrical shell on its axis
28
+ def self.cylindrical_shell(mass, radius)
29
+ (mass*radius**2)
30
+ end
31
+
32
+ def self.cylinder(mass, radius, height)
33
+ (3*radius**2+height**2)*mass/12.0
34
+ end
35
+
36
+ def self.tube(mass, inner_radius,outer_radius)
37
+ (inner_radius**2+outer_radius**2)*mass/2.0
38
+ end
39
+
40
+ def self.spherical_shell(mass, radius)
41
+ (2*mass*radius**2)/3.0
42
+ end
43
+
44
+ def self.sphere(mass, radius)
45
+ (2*mass*radius**2)/5.0
46
+ end
47
+
48
+ def self.thick_spherical_shell(mass, inner_radius,outer_radius)
49
+ ((outer_radius**5-inner_radius**5)/(outer_radius**3-inner_radius**3))*(2*mass/5)
50
+ end
51
+
52
+ def self.cone(mass, radius, height)
53
+ (radius**2+4*height**2)*(3*mass/20)
54
+ end
55
+
56
+ #cuboid or plate of arbitrary depth (in direction of axis of rotation)
57
+ def self.cuboid(mass, width, height)
58
+ (height**2+width**2)*(mass/12)
59
+ end
60
+
61
+
62
+
63
+ end
64
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ module Pulo
4
+ module Steam
5
+ class Boiler
6
+ attr_reader :feedwater, :steam, :blowdown
7
+ attr_reader :blowdown_rate, :combustion_efficiency
8
+ attr_reader :boiler_power, :fuel_power
9
+
10
+ def initialize(feedwater_pressure: nil,blowdown_rate: nil,combustion_efficiency:nil,steam_pressure: nil,
11
+ steam_temperature: nil,fuel_power: nil,
12
+ steam_massflow: nil,feedwater_massflow: nil)
13
+
14
+ raise "Need all parameters" unless
15
+ feedwater_pressure && blowdown_rate &&
16
+ combustion_efficiency && steam_pressure &&
17
+ (steam_temperature || fuel_power) &&
18
+ (steam_massflow || feedwater_massflow)
19
+
20
+ #steam_massflow=steam_massflow
21
+ @blowdown_rate=blowdown_rate
22
+ @combustion_efficiency=combustion_efficiency
23
+ @steam_temperature=steam_temperature
24
+ @feedwater_pressure=feedwater_pressure
25
+ @steam_pressure=steam_pressure
26
+ @fuel_power=fuel_power
27
+ #feedwater_massflow=feedwater_massflow
28
+
29
+ @blowdown=WaterSteam.new(pressure: @steam_pressure, quality: Dimensionless.new(0))
30
+ if steam_massflow
31
+ feedwater_massflow=steam_massflow/(1-@blowdown_rate)
32
+ else
33
+ steam_massflow=feedwater_massflow*(1-@blowdown_rate)
34
+ end
35
+
36
+ @blowdown.mass_flow=feedwater_massflow*@blowdown_rate
37
+ #@blowdown_power=@blowdown.specific_enthalpy*@blowdown_massflow
38
+
39
+ @feedwater=WaterSteam.new(pressure: @feedwater_pressure, quality: Dimensionless.new(0))
40
+ @feedwater.mass_flow=feedwater_massflow
41
+ #@feedwater_power=@feedwater.specific_enthalpy*@feedwater_massflow
42
+
43
+
44
+ if @steam_temperature
45
+ @steam=WaterSteam.new(pressure: @steam_pressure, temperature: @steam_temperature)
46
+ @steam.mass_flow=steam_massflow
47
+ #@steam_power=@steam.specific_enthalpy*@steam_massflow
48
+ @boiler_power=@steam.energy_flow + @blowdown.energy_flow - @feedwater.energy_flow
49
+ @fuel_power=@boiler_power/@combustion_efficiency
50
+ else
51
+ @boiler_power=@fuel_power*@combustion_efficiency
52
+ steam_power=@boiler_power-@blowdown.energy_flow+@feedwater.energy_flow
53
+ specific_enthalpy=steam_power/steam_massflow
54
+ @steam=WaterSteam.new(pressure: @steam_pressure, specific_enthalpy: specific_enthalpy)
55
+ @steam.mass_flow=steam_massflow
56
+ raise "Boiler not boiling!" if @steam.if97_region=="1"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end