Class: HeatingSystemCalculator::ElementFinderByZones
- Inherits:
-
BaseElementFinder
- Object
- BaseItemFinder
- BaseElementFinder
- HeatingSystemCalculator::ElementFinderByZones
- Defined in:
- app/services/heating_system_calculator/element_finder_by_zones.rb
Overview
Service object: element finder by zones.
Instance Attribute Summary
Attributes inherited from BaseElementFinder
#coverage_percentage, #elements, #error, #target_area
Instance Method Summary collapse
- #find_cable_fitting_solution_using(cables, target_dims) ⇒ Object
- #find_mat_fitting_solution(target_dims) ⇒ Object
- #fit_elements_into_heated_area_zones(zones, heated_area_sqft) ⇒ Object
- #get_elements_for_zone(zone) ⇒ Object
- #get_target_area_sub_zones_from_zone(zone) ⇒ Object
-
#initialize(options) ⇒ ElementFinderByZones
constructor
A new instance of ElementFinderByZones.
Methods inherited from BaseElementFinder
#consolidate_elements, #find_best_solution
Methods inherited from BaseItemFinder
#get_number_of_poles_from_consolidated_elements, #get_total_from_solution
Constructor Details
#initialize(options) ⇒ ElementFinderByZones
Returns a new instance of ElementFinderByZones.
5 6 7 8 9 10 11 |
# File 'app/services/heating_system_calculator/element_finder_by_zones.rb', line 5 def initialize() @element_set = [:element_set] @expansion_joint_spacing = [:expansion_joint_spacing] @skip_expansion_joint = [:skip_expansion_joint] @cable_spacing = [:cable_spacing] @element_type = [:element_type] end |
Instance Method Details
#find_cable_fitting_solution_using(cables, target_dims) ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'app/services/heating_system_calculator/element_finder_by_zones.rb', line 97 def find_cable_fitting_solution_using(cables, target_dims) solution = [] # first do a check on target_dims size to trivially calculate the number of the largest cable size we have rather than the very slow method of using the "mat fit" method to do this. Convention is last cable in element set is the biggest. # the closest integral length of cable required to fill the target_dims length by width this is: # CL = (W*L + W*CS(0.5708))/CS biggest_target_dim = (((target_dims.max * target_dims.min) + (target_dims.min * @cable_spacing * 0.5708 / 12.0)) * 144.0 / @cable_spacing).floor.to_f biggest_cable_length = cables.last[1].to_f num_of_longest_cables = (biggest_target_dim / biggest_cable_length).floor biggest_target_dim_remnant = biggest_target_dim - (num_of_longest_cables.to_f * biggest_cable_length) if ((biggest_target_dim_remnant.to_f / biggest_target_dim) > 0.25) && (cables.length > 1) # This means we can't cover the zone. Try again with longest cables removed cables.pop find_cable_fitting_solution_using(cables, target_dims) else # use a modified version of mat fitter to get the right set of cables by setting 'length' of target_dims to the closest integral length of cable required to fill the target_dims length by width, where we use the remnant after using the trivially calculated num_of_longest_cables cable_target_dims = [1, biggest_target_dim_remnant.floor] cable_fitter = MatFitter.new(*cable_target_dims) result = cable_fitter.fit_mats(cables) fitted_cables = result[:items] # here we push the trivially calculated number of the last cables into the result for proper image rendering etc. num_of_longest_cables.times do |_i| fitted_cables.push(cables.last) end fitted_cables.each do |cable| elem = @element_set.find { |e| e['sku'] == cable[2] } solution << elem end solution end end |
#find_mat_fitting_solution(target_dims) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'app/services/heating_system_calculator/element_finder_by_zones.rb', line 83 def find_mat_fitting_solution(target_dims) all_mats = @element_set.map { |e| [e['width'].ceil, e['length'].ceil, e['sku']] } target_dims = [target_dims[0] * 12, target_dims[1] * 12] # convert to inches mat_fitter = MatFitter.new(*target_dims) result = mat_fitter.fit_mats(all_mats) fitted_mats = result[:items] solution = [] fitted_mats.each do |mat| elem = @element_set.find { |e| e['sku'] == mat[2] } solution << elem end solution end |
#fit_elements_into_heated_area_zones(zones, heated_area_sqft) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'app/services/heating_system_calculator/element_finder_by_zones.rb', line 13 def fit_elements_into_heated_area_zones(zones, heated_area_sqft) if @skip_expansion_joint != true && @expansion_joint_spacing && ((@expansion_joint_spacing < RoomConfigurationConstants::MIN_CONCRETE_EXPANSION_JOINT_SPACING) || (@expansion_joint_spacing > RoomConfigurationConstants::MAX_CONCRETE_EXPANSION_JOINT_SPACING)) @error = { error_status: :expansion_joint_spacing_invalid, error_message: "Expansion joint spacing is invalid, please choose a value between #{RoomConfigurationConstants::MIN_CONCRETE_EXPANSION_JOINT_SPACING} and #{RoomConfigurationConstants::MAX_CONCRETE_EXPANSION_JOINT_SPACING} feet." } return self elsif zones.any? && zones.any? { |z| z[:length].blank? && z[:width].blank? } @error = { error_status: :no_solutions_found, error_message: "We can't calculate a solution for this request unless you enter rectangular heated areas." } return self end element_results = zones.map do |zone| get_elements_for_zone(zone) end if element_results.empty? @error = { error_status: :no_solutions_found, error_message: 'No matching heating elements found.' } else @elements = consolidate_elements(element_results.flatten) @coverage_percentage = [(100.0 * get_total_from_solution(@elements, 'area').to_f / heated_area_sqft).round, 100].min @target_area = heated_area_sqft end self end |
#get_elements_for_zone(zone) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'app/services/heating_system_calculator/element_finder_by_zones.rb', line 35 def get_elements_for_zone(zone) = get_target_area_sub_zones_from_zone(zone) num_sub_zones = [:num_sub_zones] target_dims = [[:sub_zone_length], [:sub_zone_width]] min_area = @element_set[0]['area'] # Check if we have too small an area to even proceed return [] if [:sub_zone_target_area] < min_area if @element_type == :cable cables_to_use = @element_set.map { |e| [1, e['length'].to_f.ceil, e['sku']] } solution = find_cable_fitting_solution_using(cables_to_use, target_dims.reverse) else # here we compare two solutions one with target_dims rotated, and choose the one with the closest area match and least cost solution1 = find_mat_fitting_solution(target_dims) solution2 = find_mat_fitting_solution(target_dims.reverse) ind = find_best_solution([solution1, solution2], [:sub_zone_target_area], true) solution = [solution1, solution2][ind] end # get consolidated elements list elements = consolidate_elements(solution) # multiply out the elements needed for all sub zones elements.each do |elem| elem['qty'] = num_sub_zones * elem['qty'] end elements end |
#get_target_area_sub_zones_from_zone(zone) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'app/services/heating_system_calculator/element_finder_by_zones.rb', line 66 def get_target_area_sub_zones_from_zone(zone) # handle exp joint spacing if an issue if @skip_expansion_joint != true && @expansion_joint_spacing num_sub_zones_length = (zone[:length].to_f / @expansion_joint_spacing).ceil num_sub_zones_width = (zone[:width] / @expansion_joint_spacing).ceil else num_sub_zones_length = 1 num_sub_zones_width = 1 end sub_zone_length = (zone[:length] / num_sub_zones_length) sub_zone_width = (zone[:width] / num_sub_zones_width) sub_zone_target_area = sub_zone_width * sub_zone_length num_sub_zones = num_sub_zones_width * num_sub_zones_length { num_sub_zones:, sub_zone_target_area:, sub_zone_width:, sub_zone_length: } end |