from math import sqrt, log import math from helix.constants.global_constants import parapet_coefficients, parapet_factor_max from numpy import array from numpy.ma import maximum from helix.constants.panel_type import PanelType class PressureCoefficientCalculator(object): def __init__(self, user_values): self.values = user_values self.system_constants = self.values.system_type().system_constants() self.module_constants = self.values.module_system_constants() def c_p_matrix(self, L_B): parapet = self.parapet_factor() return self.compute_c_p_matrix(L_B, parapet) def L_B(self): """ Building scaling factor """ height = max(15, self.values.building_height()) length = self.values.building_length() width = self.values.building_width() longest_side = max(width, length) return min(height, 0.4 * sqrt(height * max(1, longest_side))) def minimum_array_size(self, L_B): panel_area = self.module_constants.panel_area module_count = self.system_constants.module_count minimum_array_size = [] for minimum_A_n in self.minimum_A_n(L_B): if minimum_A_n is None: value = 6 else: value = int(math.ceil((minimum_A_n * L_B ** 2) / (panel_area * 1000) / module_count)) minimum_array_size.append(value) return minimum_array_size # Normalized area, scales the tributary area by the building scaling factor and panel area def A_n(self, L_B): return self.module_constants.tributary_area * (self.module_constants.panel_area * 1000. / L_B ** 2) def compute_c_p_matrix(self, L_B, parapet): A_n = self.A_n(L_B) wind_zones = self.system_constants.wind_zones return array([self.c_p_row(A_n, wind_zone, parapet) for wind_zone in wind_zones]) def c_p_row(self, A_n_row, wind_zone, parapet_factor): c_p_lower_bound = self.module_constants.c_p_lower_bound() if wind_zone == self.system_constants.wind_zones[-1]: return c_p_lower_bound computed_row = [] for index, A_n in enumerate(A_n_row): edge_factor = self.module_constants.edge_factor(wind_zone, PanelType.from_index(index)) computed_row.append(self.c_p(A_n, wind_zone, parapet_factor, edge_factor)) return maximum(array(computed_row), c_p_lower_bound) def c_p(self, A_n, wind_zone, parapet_factor, edge_factor): c0, c1 = self.module_constants.c_p_constants(A_n, wind_zone) return max(0., c0 * log(A_n) + c1) * parapet_factor * edge_factor def parapet_factor(self): height = max(15, self.values.building_height()) parapet_height = max(0, self.values.building_parapet_height()) factor = parapet_height / height c0, c1 = parapet_coefficients return min(parapet_factor_max, c0 + c1 * factor) def ideal_subarray_average_uplift_c_p(self, L_B): c_p_matrix = self.compute_c_p_matrix(L_B, 1) return [self.module_constants.weighted_average_c_p(c, n, e, m) for c, n, e, m in c_p_matrix] def minimum_A_n(self, L_B): uplift_c_p = self.ideal_subarray_average_uplift_c_p(L_B) minimum_A_n = [] for idx, wind_zone in enumerate(self.system_constants.wind_zones): wind_zone_uplift = uplift_c_p[idx] coefficients = self.module_constants.minimum_a_n_coefficients(wind_zone_uplift, wind_zone) if not coefficients: minimum_A_n.append(None) continue value = math.exp((coefficients[0] - wind_zone_uplift) / coefficients[1]) minimum_A_n.append(value) return minimum_A_n