Files
old-krovovi-kalkulator/helix/calculators/mechanical_bom_calculator.py
2017-11-07 09:23:57 +01:00

149 lines
6.8 KiB
Python

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