first commit
This commit is contained in:
148
helix/calculators/mechanical_bom_calculator.py
Normal file
148
helix/calculators/mechanical_bom_calculator.py
Normal file
@@ -0,0 +1,148 @@
|
||||
from math import ceil, floor
|
||||
|
||||
from helix.calculators.bom_helper import add_parts_to_list, apply_fudge_factors, \
|
||||
get_panel_type_counts
|
||||
from helix.calculators.subarray_helper import extract_subarray
|
||||
from helix.constants.module_type import ModuleType
|
||||
from helix.constants.panel_type import PanelType
|
||||
from helix.constants.parts import link_tray, cross_tray, ballast, cross_tray_1_1, leading_tray
|
||||
from helix.constants.system_type import SystemType
|
||||
|
||||
|
||||
class MechanicalBomCalculator(object):
|
||||
def __init__(self, values, panels, subarrays):
|
||||
self.values = values
|
||||
self.panels = panels
|
||||
self.subarrays = subarrays
|
||||
|
||||
def mechanical_bom(self):
|
||||
module_type = self.values.module_type()
|
||||
system_type = self.values.system_type()
|
||||
system_parts = system_type.parts(module_type)
|
||||
combined_parts_list = {}
|
||||
|
||||
for subarray in self.subarrays:
|
||||
panels = extract_subarray(self.panels, subarray.subarray_number)
|
||||
|
||||
ballast_count = sum(panel.ballast for panel in panels)
|
||||
cross_count = sum(panel.cross_tray for panel in panels)
|
||||
assigned_seismic_anchors_count = sum(panel.seismic_anchors for panel in panels)
|
||||
required_seismic_anchors_count = subarray.required_seismic_anchors
|
||||
seismic_anchors_count = max(assigned_seismic_anchors_count, required_seismic_anchors_count)
|
||||
required_wind_anchors_count = sum(panel.wind_anchors for panel in panels)
|
||||
anchor_count = required_wind_anchors_count + seismic_anchors_count
|
||||
panel_type_counts = get_panel_type_counts(panels)
|
||||
|
||||
subarray_parts_list = {}
|
||||
|
||||
for index, panel_type_parts in enumerate(system_parts.parts_per_panel_type()):
|
||||
add_parts_to_list(subarray_parts_list, panel_type_parts, panel_type_counts[PanelType.from_index(index)])
|
||||
|
||||
add_parts_to_list(subarray_parts_list, self.values.anchor_type().parts().parts, anchor_count)
|
||||
|
||||
link_count = self.link_count(panel_type_counts, panels, subarray)
|
||||
|
||||
add_parts_to_list(subarray_parts_list, {link_tray: 1}, link_count)
|
||||
cross_tray_parts = cross_tray if self.values.module_type() == ModuleType.Cell96 else cross_tray_1_1
|
||||
add_parts_to_list(subarray_parts_list, {cross_tray_parts: 1}, cross_count)
|
||||
add_parts_to_list(subarray_parts_list, {ballast: 1}, ballast_count)
|
||||
|
||||
add_parts_to_list(subarray_parts_list, system_parts.row_parts(module_type), subarray.row_count)
|
||||
add_parts_to_list(subarray_parts_list, system_parts.column_parts(module_type), subarray.column_count)
|
||||
|
||||
add_parts_to_list(subarray_parts_list, system_parts.sub_array_parts, 1)
|
||||
|
||||
apply_fudge_factors(subarray_parts_list, system_parts.fudge_factors(not subarray.row_counted_geometrically))
|
||||
|
||||
dependent_parts_list = {}
|
||||
for part, quantity in subarray_parts_list.items():
|
||||
dependent_parts = system_parts.dependent_parts(module_type).get(part)
|
||||
if dependent_parts:
|
||||
add_parts_to_list(dependent_parts_list, dependent_parts, quantity)
|
||||
|
||||
subarray_parts_list.update(dependent_parts_list)
|
||||
add_parts_to_list(combined_parts_list, subarray_parts_list)
|
||||
|
||||
return combined_parts_list
|
||||
|
||||
def link_count(self, panel_type_counts, panels, subarray):
|
||||
if self.values.system_type() == SystemType.dualTilt:
|
||||
|
||||
# check if info about position of panels is available
|
||||
coordinates_available = all(p.coordinate for p in panels) \
|
||||
and not all(p.coordinate.x == 0 and p.coordinate.y == 0 for p in panels)
|
||||
|
||||
if coordinates_available:
|
||||
# initially every C, NS, EW panels has 2 link trays attached
|
||||
panel_types = [PanelType.Corner, PanelType.NorthSouth, PanelType.EastWest]
|
||||
layout = dict([((p.coordinate.x, p.coordinate.y), 2) for p in panels if p.panel_type in panel_types])
|
||||
|
||||
row_count = ceil(subarray.row_count)
|
||||
column_count = ceil(subarray.column_count)
|
||||
|
||||
# reduce number of link trays between every two vertically adjoining panels
|
||||
for y in range(row_count):
|
||||
for x in range(column_count):
|
||||
|
||||
if (x, y) not in layout:
|
||||
continue
|
||||
|
||||
if (x, y + 1) in layout:
|
||||
layout[(x, y + 1)] = 1
|
||||
|
||||
# count link trays located on perimeter
|
||||
link_count = sum([layout[p] for p in layout])
|
||||
|
||||
# subtract places reserved for leading trays
|
||||
link_count -= subarray.row_count + 1
|
||||
|
||||
# add link trays for panels of type Middle
|
||||
link_count += sum([1 for panel in panels if panel.link_tray != 0 and panel.panel_type == PanelType.Middle])
|
||||
|
||||
return max(link_count, 0)
|
||||
else:
|
||||
total_possible_link_trays = len(panels) + subarray.column_count
|
||||
link_count = total_possible_link_trays
|
||||
|
||||
for panel in panels:
|
||||
if panel.link_tray == 0 and panel.panel_type == PanelType.Middle:
|
||||
link_count -= 1
|
||||
|
||||
link_count -= floor(subarray.row_count)
|
||||
|
||||
return link_count
|
||||
else:
|
||||
return sum([self.compute_link_count_single_tilt(panel_type, panel_type_counts, panels) for panel_type in PanelType.all()])
|
||||
|
||||
def compute_link_count_single_tilt(self, panel_type, panel_type_counts, panels):
|
||||
if panel_type == PanelType.Corner:
|
||||
return 0
|
||||
elif panel_type == PanelType.NorthSouth:
|
||||
return 0
|
||||
elif panel_type == PanelType.EastWest:
|
||||
return panel_type_counts[panel_type] * 2
|
||||
elif panel_type == PanelType.Middle:
|
||||
return self.get_panel_type_middle_link_trays_single_tilt(panels)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_panel_type_middle_link_trays_single_tilt(self, panels):
|
||||
wind_zones = self.values.system_type().system_constants().wind_zones
|
||||
|
||||
middle_panels_per_wind_zone = [0 for _ in wind_zones]
|
||||
middle_link_trays_per_wind_zone = [0 for _ in wind_zones]
|
||||
|
||||
for panel in panels:
|
||||
if panel.panel_type != PanelType.Middle:
|
||||
continue
|
||||
|
||||
wind_zone = panel.wind_zone
|
||||
middle_panels_per_wind_zone[wind_zone] += 1
|
||||
middle_link_trays_per_wind_zone[wind_zone] += panel.link_tray # use calculated number of link trays to see if it is non-zero
|
||||
|
||||
total_link_trays_required = 0
|
||||
for wind_zone, panel_count in enumerate(middle_panels_per_wind_zone):
|
||||
if middle_link_trays_per_wind_zone[wind_zone] > 0: # if any middle panels in this wind zone need link trays
|
||||
total_link_trays_required += ceil(panel_count * 1.05)
|
||||
return total_link_trays_required
|
||||
|
||||
Reference in New Issue
Block a user