pulo 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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