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

170 lines
8.0 KiB
Python

from math import ceil, floor
import copy
from helix.Repositories.graph_repository import GraphRepository
from helix.calculators.ballast_calculator import BallastCalculator
from helix.calculators.bom_calculator import BomCalculator
from helix.calculators.coordinates_calculator import CoordinatesCalculator
from helix.calculators.pressure_coefficient_calculator import PressureCoefficientCalculator
from helix.calculators.seismic_calculator import SeismicCalculator
from helix.calculators.subarray_helper import get_subarray_sizes_and_rows, extract_subarray
from helix.calculators.summary_values_calculator import SummaryValuesCalculator
from helix.calculators.wind_pressure_calculator import WindPressureCalculator
class Calculator(object):
def __init__(self, user_values, calculate_panel_data=True):
self.values = user_values
self._q_z = None
self._c_p_matrix = None
self._L_B = None
self._K_z = None
self.subarrays = None
self.buildings = self.values.buildings_polygons()
self.buildings_for_drawing = []
self.panels = self.values.csv()
if calculate_panel_data and self.panels is not None:
for idx, panel in enumerate(self.panels):
panel.id = idx + 1
self.panels.sort(key=lambda x: x.subarray)
self.subarrays = get_subarray_sizes_and_rows(self.panels)
self.__compute_ballast()
_,_,self.buildings_for_drawing = self.__transform_coordinates()
self.graph_repository = GraphRepository(self.panels, self.subarrays, self.values.system_type())
if self.values.user_override_seismic_anchors():
user_provided_panels = self.values.get_user_provided_seismic_anchors()
for user_panel in user_provided_panels:
panel = [panel for panel in self.panels if panel.id == user_panel.id][0]
panel.seismic_anchors = user_panel.seismic_anchors
self.__compute_seismic_anchors(self.panels) # Update subarrays to include required seismic anchors
self.__update_ballast(self.panels)
else:
# Update subarrays *and panels* to include required seismic anchors
self.panels = self.__compute_seismic_anchors(self.panels)
def k_z(self):
if self._K_z is None:
self._K_z = WindPressureCalculator(self.values).K_z()
return self._K_z
def L_B(self):
if self._L_B is None:
self._L_B = PressureCoefficientCalculator(self.values).L_B()
return self._L_B
def summary_table(self):
return BallastCalculator(self.values).summary_table(self.__c_p_matrix(), self.q_z())
def minimum_array_sizes(self):
return PressureCoefficientCalculator(self.values).minimum_array_size(self.L_B())
# Used in the array summary page - is the table of weight, psf, anchors, ballast, etc. for the entire system
def summary_values(self):
seismic_anchors = self.subarray_summary()
ballast_calculator = BallastCalculator(self.values)
seismic_interval = SeismicCalculator(self.values, self.graph_repository).seismic_anchor_interval()
return SummaryValuesCalculator(self.values).summary_values(self.panels, seismic_anchors, self.__c_p_matrix(),
self.q_z(), seismic_interval, ballast_calculator)
def documentation_summary_values(self):
seismic_anchors = self.subarray_summary()
ballast_calculator = BallastCalculator(self.values)
seismic_interval = SeismicCalculator(self.values, self.graph_repository).seismic_anchor_interval()
return SummaryValuesCalculator(self.values).documentation_summary_values(self.panels, seismic_anchors, self.__c_p_matrix(),
self.q_z(), seismic_interval, ballast_calculator)
# used in the array visualization - is parsed into json and displayed using the fancy canvas
def get_computed_csv_columns(self):
return BallastCalculator(self.values).show_presented_link_trays(self.panels)
def compute_bom(self):
required_seismic_anchors = self.subarray_summary()
return BomCalculator(self.values, self.panels, required_seismic_anchors, self.graph_repository).compute_bom()
def documentation_bom(self):
required_seismic_anchors = self.subarray_summary()
return BomCalculator(self.values, self.panels, required_seismic_anchors, self.graph_repository).documentation_bom()
# used in the array summary page - is part of the fancy scrolling table of summing up each subarray
def subarray_summary(self):
summary_values_calculator = SummaryValuesCalculator(self.values)
for subarray in self.subarrays:
panels_for_subarray = extract_subarray(self.panels, subarray.subarray_number)
weight, _ = summary_values_calculator.system_weight_and_pressure(panels_for_subarray)
subarray.weight = weight
return self.subarrays
def q_z(self):
if self._q_z is None:
self._q_z = WindPressureCalculator(self.values).q_z(self.k_z())
return self._q_z
def __c_p_matrix(self):
if self._c_p_matrix is None:
self._c_p_matrix = PressureCoefficientCalculator(self.values).c_p_matrix(self.L_B())
return self._c_p_matrix
def __compute_seismic_anchors(self, panels):
panels = copy.deepcopy(panels)
seismic_calculator = SeismicCalculator(self.values, self.graph_repository)
for subarray in self.subarrays:
if subarray.required_seismic_anchors is None:
subarray.required_seismic_anchors = 0
panels = self.__seismic_anchors_for_subarray(panels, subarray, seismic_calculator)
return panels
def __seismic_anchors_for_subarray(self, panels, subarray, seismic_calculator):
# do first estimation to obtain upper bound
required_seismic = seismic_calculator.required_force_seismic_anchors(subarray.subarray_number, panels)
test_value = required_seismic
tried_acceptable_values = []
def assign_seismic_anchors(count):
subarray.required_seismic_anchors = count
seismic_calculator.assign_seismic_anchors(subarray, panels)
self.__update_ballast(panels)
assigned = sum([panel.seismic_anchors for panel in panels if panel.seismic_anchors is not None])
return assigned
step = max(1, test_value // 2)
while True:
seismic_anchors_assigned = assign_seismic_anchors(test_value)
provided_force = seismic_calculator.compute_provided_lateral_capacity(subarray.subarray_number, panels)
required_seismic_force = seismic_calculator.required_force_seismic_demand(subarray.subarray_number, panels)
if seismic_anchors_assigned == 0:
# anchors were not assigned propably because self.graph_repository.subarray_graph(subarray.subarray_number) is empty
# which may be because of test construction
return panels
if provided_force < required_seismic_force:
test_value += step
else:
if (test_value in tried_acceptable_values) or (required_seismic_force == 0):
return panels
tried_acceptable_values.append(test_value)
test_value = max(0, test_value - step)
step = max(1, step // 2)
def __transform_coordinates(self):
return CoordinatesCalculator(self.values).transform_coordinates(self.panels, self.subarrays, self.buildings)
def __compute_ballast(self):
ballast_calculator = BallastCalculator(self.values)
changed_panels = ballast_calculator.ballast_and_trays_matrix(self.__c_p_matrix(), self.q_z(), self.panels)
self.panels = [panel.merge(changed_panels[idx]) for idx, panel in enumerate(self.panels)]
def __update_ballast(self, panels):
BallastCalculator(self.values).update_ballast(self.__c_p_matrix(), self.q_z(), panels)