first commit

This commit is contained in:
Senad Uka
2017-11-07 09:23:57 +01:00
commit 0eee92660a
356 changed files with 747259 additions and 0 deletions

View File

View File

@@ -0,0 +1,23 @@
from helix.constants.parts import anchor_plate, anchor, anchor_washer
class OmgPowerGripParts(object):
parts = {
anchor_plate: 1,
anchor: 1,
anchor_washer: 1
}
class OmgPowerGripPlusParts(object):
parts = {
anchor_plate: 1,
anchor: 1,
anchor_washer: 1
}
class EcoFastenParts(object):
parts = {
anchor_plate: 1,
anchor: 1,
anchor_washer: 1
}

View File

@@ -0,0 +1,29 @@
from enum import Enum
from helix.constants.anchor_parts import OmgPowerGripParts, OmgPowerGripPlusParts, EcoFastenParts
from helix.constants.global_constants import system_force_capacity
class AnchorType(Enum):
OMG_PowerGrip = 'OMG PowerGrip'
OMG_PowerGrip_Plus = 'OMG PowerGrip Plus'
EcoFasten = 'EcoFasten Eco 65'
def uplift_capacity(self):
return min(system_force_capacity, {AnchorType.OMG_PowerGrip: 305.,
AnchorType.OMG_PowerGrip_Plus: 2000.,
AnchorType.EcoFasten: 1343.}[self])
def shear_capacity(self):
return {AnchorType.OMG_PowerGrip: 142.,
AnchorType.OMG_PowerGrip_Plus: 431.,
AnchorType.EcoFasten: 1008.}[self]
def parts(self):
return {AnchorType.OMG_PowerGrip: OmgPowerGripParts(),
AnchorType.OMG_PowerGrip_Plus: OmgPowerGripPlusParts(),
AnchorType.EcoFasten: EcoFastenParts()}[self]
@classmethod
def default_value(cls):
return cls.OMG_PowerGrip_Plus.value

View File

@@ -0,0 +1,4 @@
dt_chassis_fudge_factor = 1.04
leading_tray_fudge_factor = 1.05
bolts_per_package = 50

11
helix/constants/color.py Normal file
View File

@@ -0,0 +1,11 @@
from enum import Enum
class Color(Enum):
array_background = "white"
seismic_background = "#F1E8A2"
wind_background = "#B8F3E5"
default_panel_background = "#133256"
light_text = "white"
dark_text = "#6490BA"
border = "#537DAA"

View File

@@ -0,0 +1,89 @@
from helix.constants.module_type import ModuleType
from helix.constants.parts import *
class DualTiltParts(object):
east_west_panel_parts = {
dual_tilt_chassis: 1,
module: 2
}
center_panel_parts = {
dual_tilt_chassis: 1,
module: 2
}
sub_array_parts = {
leading_tray: 1
}
def __init__(self, module_type):
if module_type == ModuleType.PSeries:
self.corner_panel_parts = {
left_deflector_1_1: 1,
right_deflector_1_1: 1,
dual_tilt_chassis: 1.5,
module: 2
}
self.north_south_panel_parts = {
left_deflector_1_1: 1,
right_deflector_1_1: 1,
dual_tilt_chassis: 1.5,
module: 2
}
else:
self.corner_panel_parts = {
left_deflector: 1,
right_deflector: 1,
dual_tilt_chassis: 1.5,
module: 2
}
self.north_south_panel_parts = {
left_deflector: 1,
right_deflector: 1,
dual_tilt_chassis: 1.5,
module: 2
}
def row_parts(self, module_type):
if module_type == ModuleType.Cell96:
front_skirt_parts = front_skirt
else:
front_skirt_parts = front_skirt_1_1
return {
front_skirt_parts: 2,
leading_tray: 1
}
def column_parts(self, _):
return {}
def parts_per_panel_type(self):
return [
self.corner_panel_parts,
self.north_south_panel_parts,
self.east_west_panel_parts,
self.center_panel_parts
]
def dependent_parts(self, _):
return {
module: {
wire_clip: 2,
rubber_foot: 0.1
},
dual_tilt_chassis: {
dual_tilt_platform: 1,
platform_bolt: 4
}
}
def fudge_factors(self, used_fallback):
if used_fallback:
return {
dual_tilt_chassis: 1.04,
leading_tray: 1.05
}
return {
dual_tilt_chassis: 1.04,
}

View File

@@ -0,0 +1,7 @@
'''
Created on May 22, 2017
@author: jvazquez
'''
INVALID_DUAL_TILT_DESIGN = "Error - not a dual tilt file, or invalid "\
"dual tilt design."

View File

@@ -0,0 +1,281 @@
from helix.constants.inverter_type import InverterType
from helix.constants.module_type import ModuleType
from helix.constants.parts import *
from helix.constants.system_type import SystemType
inverter_model_parts = {
InverterType.SMA.MODEL_12KW: {sma_12kw_inverter: 1},
InverterType.SMA.MODEL_15KW: {sma_15kw_inverter: 1},
InverterType.SMA.MODEL_20KW: {sma_20kw_inverter: 1},
InverterType.SMA.MODEL_24KW: {sma_24kw_inverter: 1},
InverterType.DELTA.MODEL_36KW: {delta_36kw_inverter: 1},
InverterType.DELTA.MODEL_42KW: {delta_42kw_inverter: 1},
InverterType.DELTA.MODEL_60KW: {delta_60kw_inverter: 1},
InverterType.DELTA.MODEL_80KW: {delta_80kw_inverter: 1},
}
inverter_strings_parts = {
0: {},
2: {
harness_2_string_mf: 1,
harness_2_string_fm: 1
},
3: {
harness_3_string_mf: 1,
harness_3_string_fm: 1
},
4: {
harness_2_string_mf: 2,
harness_2_string_fm: 2
},
5: {
harness_2_string_mf: 1,
harness_2_string_fm: 1,
harness_3_string_mf: 1,
harness_3_string_fm: 1
},
6: {
harness_3_string_mf: 2,
harness_3_string_fm: 2
},
7: {
harness_3_string_mf: 1,
harness_3_string_fm: 1,
harness_4_string_mf: 1,
harness_4_string_fm: 1
},
8: {
harness_4_string_mf: 2,
harness_4_string_fm: 2
},
}
def shared_panel_board_parts(module_type, system_type):
v1_1_inverter_links = 0
if system_type == SystemType.singleTilt and (module_type == ModuleType.PSeries or module_type == ModuleType.Cell128):
v1_1_inverter_links = 1
return {
front_legs: 1,
back_legs: 1,
inverter_link: 2,
inverter_rail: 1,
rubber_foot: 3,
mounting_back_plate: 1,
ethernet_plug: 1.8,
flat_washer: 4,
hex_nut_three_eighths_16: 2,
hex_bolt_1_2: 9,
inverter_link_long: v1_1_inverter_links,
inverter_link_short: v1_1_inverter_links,
}
dc_switch_parts = {
dc_switch_bracket: 1,
dc_switch_box: 1,
hex_bolt_3_4: 4,
hex_bolt_quarter_20: 4,
hex_nut_three_eighths_16: 4,
hex_nut_quarter_20: 4,
flat_washer_quarter_inch: 4,
}
def panel_board_parts(inverter_quantity, with_aux):
if with_aux:
parts = {
1: {
panel_board_2_aux: 1,
},
2: {
panel_board_2_aux: 1,
},
3: {
panel_board_3_aux: 1,
},
4: {
panel_board_4_aux: 1,
}
}
else:
parts = {
1: {
panel_board_2: 1,
},
2: {
panel_board_2: 1,
},
3: {
panel_board_3: 1,
},
4: {
panel_board_4: 1,
}
}
return parts[inverter_quantity]
def panel_board_parts_with_monitor(inverter_quantity, monitor_controller_type):
parts = panel_board_parts(inverter_quantity, monitor_controller_type != monitor_controller_240_v)
parts[monitor_controller_type] = 1
return parts
def standalone_inverter_parts(inverter, system_type, module_type):
multiplier = 1
v1_1_inverter_links = 0
if inverter['model'] in InverterType.DELTA.all():
parts = {}
if system_type == SystemType.singleTilt:
parts = {**parts, delta_kit_inverter_mount: 1}
else:
parts = {**parts, delta_kit_inverter_mount_dt: 1}
if inverter['splice_box']:
parts = {**parts, delta_splice_box: 1}
return parts
if system_type == SystemType.singleTilt:
multiplier = 2
v1_1_inverter_links = 1 if module_type == ModuleType.PSeries or module_type == ModuleType.Cell128 else 0
return {
ac_switch: 1,
star_washer: 4,
phillips_screw: 4 * multiplier,
ac_inverter_bracket: 1 * multiplier,
hex_bolt_1_2: 4,
flat_washer_6: 4,
inverter_link_short: v1_1_inverter_links,
inverter_link_long: v1_1_inverter_links,
whip_tray: 1
}
standalone_inverter_attached_to_panel_board_parts = {
ac_splice_box: 1,
}
def inverter_parts(inverter, module_type):
if inverter['model'] in InverterType.DELTA.all():
return {
delta_inverter_leg: 3,
rubber_foot: 3,
}
else:
if module_type == ModuleType.PSeries:
return {
flat_washer: 8,
hex_nut_three_eighths_16: 6,
hex_bolt_3_4: 5,
hex_bolt_1_2: 18,
front_legs: 1,
back_legs: 1,
mounting_back_plate: 1,
rubber_foot: 3,
inverter_link: 2,
inverter_rail: 1,
stump: 6,
fuseshade: 1,
screw_12_24x1_25: 2,
fuseshade_brace: 1,
}
else:
return {
flat_washer: 4,
hex_nut_three_eighths_16: 4,
hex_bolt_3_4: 2,
hex_bolt_1_2: 18,
front_legs: 1,
back_legs: 1,
mounting_back_plate: 1,
rubber_foot: 3,
inverter_link: 2,
inverter_rail: 1,
stump: 6,
}
def dependent_parts(module_type, system_type):
v1_1_inverter_links = 0
if system_type == SystemType.singleTilt and (module_type == ModuleType.Cell128 or module_type == ModuleType.PSeries):
v1_1_inverter_links = 1
return {
panel_board_2: {
harness_ac_inner: 2,
whip_tray: 2,
comm_cable: 1
},
panel_board_2_aux: {
harness_ac_inner: 2,
whip_tray: 2,
comm_cable: 2
},
panel_board_3: {
harness_ac_inner: 2,
harness_ac_outer: 1,
whip_tray: 3,
comm_cable: 2,
inverter_link_short: v1_1_inverter_links,
inverter_link_long: v1_1_inverter_links,
inverter_link: -2 * v1_1_inverter_links,
},
panel_board_3_aux: {
harness_ac_inner: 2,
harness_ac_outer: 1,
whip_tray: 3,
comm_cable: 3,
inverter_link_short: v1_1_inverter_links,
inverter_link_long: v1_1_inverter_links,
inverter_link: -2 * v1_1_inverter_links,
},
panel_board_4: {
harness_ac_inner: 2,
harness_ac_outer: 2,
whip_tray: 4,
comm_cable: 3,
inverter_link_short: v1_1_inverter_links,
inverter_link_long: v1_1_inverter_links,
inverter_link: -2 * v1_1_inverter_links,
},
panel_board_4_aux: {
harness_ac_inner: 2,
harness_ac_outer: 2,
whip_tray: 4,
comm_cable: 4,
inverter_link_short: v1_1_inverter_links,
inverter_link_long: v1_1_inverter_links,
inverter_link: -2 * v1_1_inverter_links,
},
monitor_controller_480_v: {
monitor_power_plug: 1,
flat_washer: 4,
channel_nut: 4,
hex_nut_three_eighths_16: 2,
front_legs: 1,
back_legs: 1,
inverter_link: 2,
inverter_rail: 1,
rubber_foot: 3,
hex_bolt_1_2: 9,
mounting_back_plate: 1,
},
monitor_controller_240_v: {},
ac_splice_box: {
hex_bolt_1_2: 4,
hex_bolt_3_4: 4,
hex_nut_three_eighths_16: 8,
flat_washer: 8,
back_legs: 1,
front_legs: 1,
rubber_foot: 3,
inverter_rail: 1,
inverter_link: 2,
mounting_back_plate: 1,
},
inverter_link_long: {
inverter_link: -1,
},
inverter_link_short: {
inverter_link: -1,
}
}

View File

@@ -0,0 +1,34 @@
from enum import Enum
class ExposureCategory(Enum):
B = 'B'
C = 'C'
D = 'D'
B_C = 'B to C'
C_B = 'C to B'
def z_g(self):
return {
ExposureCategory.B: 1200.,
ExposureCategory.C: 900.,
ExposureCategory.D: 700.,
ExposureCategory.B_C: (1273., 906.),
ExposureCategory.C_B: (906., 1273.)
}[self]
def alpha(self):
return {
ExposureCategory.B: 7.,
ExposureCategory.C: 9.5,
ExposureCategory.D: 11.5,
ExposureCategory.B_C: (6.62, 9.5),
ExposureCategory.C_B: (9.5, 6.62)
}[self]
def is_interpolated(self):
return self in [ExposureCategory.B_C, ExposureCategory.C_B]
@classmethod
def default_value(cls):
return cls.C.value

View File

@@ -0,0 +1,50 @@
from enum import Enum
from helix.constants.system_type import SystemType
class FileValidationMessage(Enum):
Generic = 'Input file has invalid data'
InvalidHeaders = 'Input file has less than 5 headers'
InvalidRowCount = 'Input file has no data'
DualTiltWindZone = 'Invalid wind zone for Dual Tilt System'
SingleTiltWindZone = 'Invalid wind zone for Single Tilt System'
PanelTypeOutOfBounds = 'Invalid Panel Type (Not in 1-4)'
PanelTypeTooFewCornersSingleTilt = 'Input file must have at least 4 corner modules per subarray'
PanelTypeTooFewCornersDualTilt = 'Input file must have at least 2 corner modules per subarray'
UnknownFileUploaded = 'Please upload a valid .txt or .dxf file'
ExpectedTxtFile = 'Invalid file uploaded. Please upload a valid .txt file.'
ExpectedDxfFile = 'Invalid file uploaded. Please upload a valid .dxf file.'
OldDxfFormat = 'Invalid Aurora format uploaded. Please upload a new format.'
@classmethod
def invalid_wind_zones(cls, system_type):
if system_type == SystemType.singleTilt:
return cls.SingleTiltWindZone
else:
return cls.DualTiltWindZone
@classmethod
def panel_type_too_few_corners(cls, system_type):
return {
SystemType.singleTilt: cls.PanelTypeTooFewCornersSingleTilt,
SystemType.dualTilt: cls.PanelTypeTooFewCornersDualTilt,
}[system_type]
class FileValidationError(object):
def __init__(self, validation_message, row_number):
self.row_number = row_number
self.validation_message = validation_message
def format_error_message(self):
if self.row_number:
return self.validation_message.value + ' on line ' + str(self.row_number)
return self.validation_message.value
def __repr__(self):
return "<ValidationError: " + self.format_error_message() + ">"
def __eq__(self, other):
if self.__class__ != other.__class__:
return False
return self.row_number == other.row_number and self.validation_message == other.validation_message

View File

@@ -0,0 +1,9 @@
k_d = 0.85
k_zt = 1.
parapet_factor_max = 1.12
parapet_coefficients = 0.88, 1.2
system_force_capacity = 418.
minimum_racking_capacity = 226

View File

@@ -0,0 +1,25 @@
from enum import IntEnum
class InverterBrand(IntEnum):
SMA = 1
DELTA = 2
@property
def label(self):
return {
self.SMA: 'SMA',
self.DELTA: 'Delta',
}[self]
@classmethod
def default_value(cls):
return cls.SMA.value
@classmethod
def all(cls):
return [cls.SMA, cls.DELTA]
@classmethod
def dict(cls):
return {cls.SMA.label: cls.SMA.value, cls.DELTA.label: cls.DELTA.value}

View File

@@ -0,0 +1,94 @@
from enum import IntEnum
class InverterTypeSMA(IntEnum):
MODEL_12KW = 4
MODEL_15KW = 5
MODEL_20KW = 6
MODEL_24KW = 8
@property
def default_string(self):
return {
self.MODEL_12KW: 4,
self.MODEL_15KW: 5,
self.MODEL_20KW: 6,
self.MODEL_24KW: 8,
}[self]
@property
def label(self):
return {
self.MODEL_12KW: '12kW SMA Tripower - 514686',
self.MODEL_15KW: '15kW SMA Tripower - 514687',
self.MODEL_20KW: '20kW SMA Tripower - 512676',
self.MODEL_24KW: '24kW SMA Tripower - 514685',
}[self]
@property
def valid_string_ranges(self):
return {
self.MODEL_12KW: range(2, 9),
self.MODEL_15KW: range(2, 9),
self.MODEL_20KW: range(2, 9),
self.MODEL_24KW: range(2, 9),
}[self]
@classmethod
def default_value(cls):
return cls.MODEL_24KW.value
@classmethod
def all(cls):
return [cls.MODEL_12KW, cls.MODEL_15KW, cls.MODEL_20KW, cls.MODEL_24KW]
class InverterTypeDelta(IntEnum):
MODEL_36KW = 9
MODEL_42KW = 10
MODEL_60KW = 11
MODEL_80KW = 12
@property
def label(self):
return {
self.MODEL_36KW: '36kW Delta - 524952',
self.MODEL_42KW: '42kW Delta - 524969',
self.MODEL_60KW: '60kW Delta - 524954',
self.MODEL_80KW: '80kW Delta - 524955',
}[self]
@property
def default_string(self):
return {
self.MODEL_36KW: None,
self.MODEL_42KW: None,
self.MODEL_60KW: None,
self.MODEL_80KW: 14,
}[self]
@property
def valid_string_ranges(self):
return {
self.MODEL_36KW: None,
self.MODEL_42KW: None,
self.MODEL_60KW: None,
self.MODEL_80KW: range(14, 25),
}[self]
@classmethod
def default_value(cls):
return cls.MODEL_60KW.value
@classmethod
def all(cls):
return [cls.MODEL_36KW, cls.MODEL_42KW, cls.MODEL_60KW, cls.MODEL_80KW]
class InverterType:
SMA = InverterTypeSMA
DELTA = InverterTypeDelta
@classmethod
def all(cls):
return cls.SMA.all() + cls.DELTA.all()

View File

@@ -0,0 +1,11 @@
from enum import Enum
class ModuleType(Enum):
Cell96 = '96 Cell'
Cell128 = '128 Cell'
PSeries = 'P-Series'
@classmethod
def default_value(cls):
return cls.Cell96.value

View File

@@ -0,0 +1,113 @@
from numpy import array
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
class DualTilt128CellConstants(object):
panel_spacing = (88.24, 82.0) # inches
spacing_size_inches = 5.12 # This is inches
presenter_spacing = (1.5, 1.5)
panel_area = 23.29
surface_area = 46.58 # aka tent area
tributary_area = array([3.23, 6.84, 6.54, 13.57])
ground_coverage_ratio = 0.91
friction_coefficient = 0.59
seismic_anchor_interval_constants = (13.8768, 3.23792)
max_psf = 32
def c_p_lower_bound(self):
return array([0.06, 0.05, 0.052, 0.039])
def edge_factor(self, wind_zone, panel_type):
return 1
def racking_capacity(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return minimum_racking_capacity
else:
return 308
def c_p_constants(self, A_n, wind_zone):
if wind_zone == 'A':
if A_n < 825:
return -0.144, 1.1451
else:
return -0.058, 0.5651
elif wind_zone == 'B':
if A_n < 465:
return -0.117, 0.8824
elif A_n < 825:
return -0.087, 0.6981
else:
return -0.033, 0.3336
elif wind_zone == 'C':
if A_n < 465:
return -0.073, 0.5479
elif A_n < 825:
return -0.035, 0.3143
else:
return -0.015, 0.184
elif wind_zone == 'D':
if A_n < 465:
return -0.039, 0.303
elif A_n < 825:
return -0.023, 0.2023
else:
return -0.008, 0.102
else:
return 1, 1
def base_weight(self, panel_type, tray_count):
if panel_type == PanelType.Corner:
return [108.66, 110.96, 112.11, 116.44, 119.62, 122.80, 125.98][tray_count]
elif panel_type == PanelType.NorthSouth:
return [107.58, 109.88, 111.03, 114.21, 117.39, 120.57, 123.75][tray_count]
elif panel_type == PanelType.EastWest:
return [103.19, 105.49, 105.49, 108.67, 111.85, 115.03, 118.21][tray_count]
else:
return [102.11, 104.41, 104.41, 107.59, 110.77, 113.95, 117.13][tray_count]
def link_tray_thresholds(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [7.5, 10, 15]
else:
return [5, 7.5, 10]
def cross_tray_thresholds(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [15, 23, 31, 39, 47]
else:
return [10, 18, 26, 34, 42]
def weighted_average_c_p(self, corner, north_south, east_west, middle):
return (corner * 2. + east_west * 26. + middle * 104. + north_south * 8.) / 140.
def minimum_a_n_coefficients(self, uplift_c_p, wind_zone):
if wind_zone == 'A':
if uplift_c_p > 0.275:
return 1.5305, 0.187
else:
return 0.9252, 0.097
elif wind_zone == 'B':
if uplift_c_p > 0.2292:
return 1.2058, 0.159
elif uplift_c_p > 0.1534:
return 1.0334, 0.131
else:
return 0.4411, 0.043
elif wind_zone == 'C':
if uplift_c_p > 0.151:
return 0.7899, 0.104
elif uplift_c_p > 0.108:
return 0.5785, 0.07
else:
return 0.2921, 0.027
elif wind_zone == 'D':
if uplift_c_p > 0.0929:
return 0.3939, 0.049
elif uplift_c_p > 0.069:
return 0.3043, 0.035
else:
return 0.122, 0.008
return None

View File

@@ -0,0 +1,121 @@
from numpy import array
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
class DualTilt96CellConstants(object):
panel_spacing = (88.24, 62.0) # inches
spacing_size_inches = 5.12 # This is inches
presenter_spacing = (1.5, 1)
panel_area = 17.58
surface_area = 35.14 # aka tent area
tributary_area = array([3.32, 6.58, 7.29, 21.74]) # for each panel type
ground_coverage_ratio = 0.91
friction_coefficient = 0.59
seismic_anchor_interval_constants = (10.1598, 2.3706)
max_psf = 48
def c_p_lower_bound(self):
return array([0.06, 0.05, 0.052, 0.039])
def edge_factor(self, wind_zone, panel_type):
return 1
def racking_capacity(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return minimum_racking_capacity
else:
return 308
def c_p_constants(self, A_n, wind_zone):
if wind_zone == 'A':
if A_n < 825:
return -0.144, 1.1451
else:
return -0.058, 0.5651
elif wind_zone == 'B':
if A_n < 465:
return -0.117, 0.8824
elif A_n < 825:
return -0.087, 0.6981
else:
return -0.033, 0.3336
elif wind_zone == 'C':
if A_n < 465:
return -0.073, 0.5479
elif A_n < 825:
return -0.035, 0.3143
else:
return -0.015, 0.184
elif wind_zone == 'D':
if A_n < 465:
return -0.039, 0.303
elif A_n < 825:
return -0.023, 0.2023
else:
return -0.008, 0.102
else:
return 1, 1
def base_weight(self, panel_type, tray_count):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [92.58,
94.31,
96.03,
98.33,
100.63,
102.93,
105.23][tray_count]
else:
return [87.11,
88.84,
89.41,
91.71,
94.01,
96.31,
98.61][tray_count]
def link_tray_thresholds(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [7.5, 10, 15]
else:
return [5, 7.5, 10]
def cross_tray_thresholds(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [15, 24, 33, 42, 51]
else:
return [10, 19, 28, 37, 46]
def weighted_average_c_p(self, corner, north_south, east_west, middle):
return (corner * 2. + east_west * 26. + middle * 104. + north_south * 8.) / 140.
def minimum_a_n_coefficients(self, uplift_c_p, wind_zone):
if wind_zone == 'A':
if uplift_c_p > 0.275:
return 1.5305, 0.187
else:
return 0.9252, 0.097
elif wind_zone == 'B':
if uplift_c_p > 0.2292:
return 1.2058, 0.159
elif uplift_c_p > 0.1537:
return 1.0334, 0.131
else:
return 0.4411, 0.043
elif wind_zone == 'C':
if uplift_c_p > 0.151:
return 0.7899, 0.104
elif uplift_c_p > 0.108:
return 0.5785, 0.07
else:
return 0.2921, 0.027
elif wind_zone == 'D':
if uplift_c_p > 0.093:
return 0.3939, 0.049
elif uplift_c_p > 0.069:
return 0.3043, 0.035
else:
return 0.122, 0.008
return None

View File

@@ -0,0 +1,113 @@
from numpy import array
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
class DualTiltPSeriesConstants(object):
panel_spacing = (88.24, 82.0) # inches
spacing_size_inches = 8.8503937 # This is inches
presenter_spacing = (1.5, 1.5)
panel_area = 22.22
surface_area = 44.44 # aka tent area
tributary_area = array([3.23, 6.84, 6.54, 13.57])
ground_coverage_ratio = 0.91
friction_coefficient = 0.59
seismic_anchor_interval_constants = (12.6378, 2.94882)
max_psf = 32
def c_p_lower_bound(self):
return array([0.06, 0.05, 0.052, 0.039])
def edge_factor(self, wind_zone, panel_type):
return 1
def racking_capacity(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return minimum_racking_capacity
else:
return 308
def c_p_constants(self, A_n, wind_zone):
if wind_zone == 'A':
if A_n < 825:
return -0.144, 1.1451
else:
return -0.058, 0.5651
elif wind_zone == 'B':
if A_n < 465:
return -0.117, 0.8824
elif A_n < 825:
return -0.087, 0.6981
else:
return -0.033, 0.3336
elif wind_zone == 'C':
if A_n < 465:
return -0.073, 0.5479
elif A_n < 825:
return -0.035, 0.3143
else:
return -0.015, 0.184
elif wind_zone == 'D':
if A_n < 465:
return -0.039, 0.303
elif A_n < 825:
return -0.023, 0.2023
else:
return -0.008, 0.102
else:
return 1, 1
def base_weight(self, panel_type, tray_count):
if panel_type == PanelType.Corner:
return [103.66, 105.96, 107.11, 111.44, 114.62, 117.80, 120.98][tray_count]
elif panel_type == PanelType.NorthSouth:
return [102.58, 104.88, 106.03, 109.21, 112.39, 115.57, 118.75][tray_count]
elif panel_type == PanelType.EastWest:
return [98.19, 100.49, 100.49, 103.67, 106.85, 110.03, 113.21][tray_count]
else:
return [97.11, 99.41, 99.41, 102.59, 105.77, 108.95, 112.13][tray_count]
def link_tray_thresholds(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [7.5, 10, 15]
else:
return [5, 7.5, 10]
def cross_tray_thresholds(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.NorthSouth:
return [15, 23, 31, 39, 47]
else:
return [10, 18, 26, 34, 42]
def weighted_average_c_p(self, corner, north_south, east_west, middle):
return (corner * 2. + east_west * 26. + middle * 104. + north_south * 8.) / 140.
def minimum_a_n_coefficients(self, uplift_c_p, wind_zone):
if wind_zone == 'A':
if uplift_c_p > 0.275:
return 1.5305, 0.187
else:
return 0.9252, 0.097
elif wind_zone == 'B':
if uplift_c_p > 0.2292:
return 1.2058, 0.159
elif uplift_c_p > 0.1537:
return 1.0334, 0.131
else:
return 0.4411, 0.043
elif wind_zone == 'C':
if uplift_c_p > 0.151:
return 0.7899, 0.104
elif uplift_c_p > 0.108:
return 0.5785, 0.07
else:
return 0.2921, 0.027
elif wind_zone == 'D':
if uplift_c_p > 0.093:
return 0.3939, 0.049
elif uplift_c_p > 0.069:
return 0.3043, 0.035
else:
return 0.122, 0.008
return None

View File

@@ -0,0 +1,236 @@
from numpy import array
from numpy.ma import log
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
from helix.constants.system_type_constants.single_tilt_constants import SingleTiltConstants
class SingleTilt128CellConstants(object):
panel_spacing = (82.0, 60.0) # inches
presenter_spacing = (1.5, 1)
panel_area = 23.29
surface_area = 23.29
tributary_area = array([1.87, 3.24, 3.24, 3.82])
ground_coverage_ratio = 0.67
friction_coefficient = 0.42
seismic_anchor_interval_constants = (9.8784, 2.30496)
system_constants = SingleTiltConstants()
max_psf = 32
def c_p_lower_bound(self):
c_p_lower_bound = []
for index, area in enumerate(self.tributary_area):
if area < 9:
c_p = -0.0273 * log(area) + 0.1401
else:
c_p = -0.0146 * log(area) + 0.112
edge_factor = self.edge_factor(self.system_constants.wind_zones[-1], PanelType.from_index(index))
c_p_lower_bound.append(c_p * edge_factor)
return array(c_p_lower_bound)
def edge_factor(self, wind_zone, panel_type):
# corner, north/south, east/west, middle
edge_matrix = {'A': [1.2, 1.2, 1.0, 1.0],
'B': [1.2, 1.2, 1.0, 1.0],
'C': [1.4, 1.4, 1.0, 1.0],
'D': [1.4, 1.4, 1.0, 1.0],
'E': [1.5, 1.0, 1.5, 1.0],
'F': [1.3, 1.3, 1.0, 1.0],
'G': [1.0, 1.0, 1.0, 1.0],
'H': [1.0, 1.0, 1.0, 1.0],
'I': [1.0, 1.0, 1.0, 1.0],
'J': [2.0, 2.0, 1.0, 1.0],
'K': [1.4, 1.4, 1.0, 1.0]}
return edge_matrix[wind_zone][panel_type.index()]
def racking_capacity(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.EastWest:
return minimum_racking_capacity
else:
return 308
def c_p_constants(self, A_n, wind_zone):
if wind_zone == 'A':
if A_n < 421.5:
return -0.2245, 1.717
elif A_n < 2294.7:
return -0.1298, 1.1446
else:
return -0.0308, 0.3787
elif wind_zone == 'B':
if A_n < 421.5:
return -0.1818, 1.3585
elif A_n < 2294.7:
return -0.0708, 0.688
else:
return -0.0308, 0.3787
elif wind_zone == 'C':
if A_n < 421.5:
return -0.0735, 0.6443
elif A_n < 2294.7:
return -0.059, 0.5566
else:
return -0.021, 0.2627
elif wind_zone == 'D':
if A_n < 187.3:
return -0.1007, 0.6868
elif A_n < 421.5:
return -0.049, 0.4181
else:
return -0.0183, 0.2304
elif wind_zone == 'E':
if A_n < 187.3:
return -0.058, 0.4236
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
elif wind_zone == 'F':
if A_n < 187.3:
return -0.0655, 0.4682
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
elif wind_zone == 'G':
if A_n < 187.3:
return -0.0341, 0.2786
elif A_n < 421.5:
return -0.0271, 0.242
else:
return -0.0125, 0.1533
elif wind_zone == 'H':
if A_n < 187.3:
return -0.1161, 0.7872
elif A_n < 421.5:
return -0.074, 0.5672
elif A_n < 1685.9:
return -0.0433, 0.3816
else:
return -0.0117, 0.1473
elif wind_zone == 'I':
if A_n < 187.3:
return -0.3856, 2.258
elif A_n < 421.5:
return -0.148, 1.0143
elif A_n < 1685.9:
return -0.0433, 0.3816
else:
return -0.0117, 0.1473
elif wind_zone == 'J':
if A_n < 187.3:
return -0.1024, 0.6557
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
else:
return 1, 1
def base_weight(self, panel_type, tray_count):
if panel_type == PanelType.Corner:
return [71.91, 71.91, 75.09, 78.27][tray_count]
elif panel_type == PanelType.NorthSouth:
return [65.8, 65.8, 68.98, 72.16][tray_count]
elif panel_type == PanelType.EastWest:
return [69.75, 72.05, 75.23, 78.41][tray_count]
else:
return [65.08, 67.38, 70.56, 73.74][tray_count]
def link_tray_thresholds(self, panel_type):
return [[0, 13.0],
[0, 10.00],
[7, 14.5],
[6, 11.0]][panel_type.index()]
def cross_tray_thresholds(self, panel_type):
return [[13.0, 21.0, 29.0],
[10.00, 18.0, 26.0],
[14.5, 22.5, 30.5],
[11.0, 19.0, 27.0]][panel_type.index()]
def weighted_average_c_p(self, corner, north_south, east_west, middle):
""" Based on a 30 by 28 rectangular array """
return (middle * 182. + north_south * 14. + east_west * 13. + corner) / 210.
def minimum_a_n_coefficients(self, uplift_c_p, wind_zone):
if wind_zone == 'A':
if uplift_c_p > 0.360:
return 3.1178, 0.3769
elif uplift_c_p > 0.180:
return 2.4967, 0.274
else:
return 0.9691, 0.0685
elif wind_zone == 'B':
if uplift_c_p > 0.260:
return 2.3762, 0.2807
elif uplift_c_p > 0.160:
return 1.7699, 0.1803
else:
return 0.7209, 0.0392
elif wind_zone == 'C':
if uplift_c_p > 0.200:
return 1.7251, 0.215
elif uplift_c_p > 0.100:
return 1.2668, 0.1274
else:
return 0.4655, 0.0196
elif wind_zone == 'D':
if uplift_c_p > 0.120:
return 2.3762, 0.2807
elif uplift_c_p > 0.094:
return 1.7699, 0.1803
else:
return 0.7209, 0.0392
elif wind_zone == 'E':
if uplift_c_p > 0.078:
return 0.8096, 0.0976
elif uplift_c_p > 0.060:
return 0.438, 0.0361
else:
return 0.3227, 0.0206
elif wind_zone == 'F':
if uplift_c_p > 0.078:
return 0.6281, 0.0708
else:
return 0.328, 0.0212
elif wind_zone == 'G':
if uplift_c_p > 0.078:
return 0.6281, 0.0708
else:
return 0.328, 0.0212
elif wind_zone == 'H':
if uplift_c_p > 0.180:
return 1.8215, 0.2525
elif uplift_c_p > 0.120:
return 1.4679, 0.185
elif uplift_c_p > 0.060:
return 1.13479, 0.1298
else:
return 0.3227, 0.0206
elif wind_zone == 'I':
if uplift_c_p > 0.240:
return 4.3609, 0.6996
elif uplift_c_p > 0.120:
return 2.639, 0.3699
elif uplift_c_p > 0.060:
return 1.4027, 0.1659
else:
return 0.3277, 0.0206
elif wind_zone == 'J':
if uplift_c_p > 0.120:
return 0.7131, 0.0891
elif uplift_c_p > 0.078:
return 0.5503, 0.058
else:
return 0.328, 0.0212
elif wind_zone == 'K':
if uplift_c_p > 0.080:
return 0.3, 0.0455
else:
return 0.2465, 0.0212
else:
return 1, 1

View File

@@ -0,0 +1,231 @@
from numpy import array
from numpy.ma import log
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
from helix.constants.system_type_constants.single_tilt_constants import SingleTiltConstants
class SingleTilt96CellConstants(object):
panel_spacing = (62.0, 60.0) # inches
presenter_spacing = (1, 1)
panel_area = 17.58
surface_area = 17.57
tributary_area = array([2.07, 4.06, 4.06, 9.79])
ground_coverage_ratio = 0.67
friction_coefficient = 0.42
seismic_anchor_interval_constants = (7.2324, 1.6876)
system_constants = SingleTiltConstants()
max_psf = 48
def c_p_lower_bound(self):
c_p_lower_bound = []
for index, area in enumerate(self.tributary_area):
if area < 9:
c_p = -0.0273 * log(area) + 0.1401
else:
c_p = -0.0146 * log(area) + 0.112
edge_factor = self.edge_factor(self.system_constants.wind_zones[-1], PanelType.from_index(index))
c_p_lower_bound.append(c_p * edge_factor)
return array(c_p_lower_bound)
def edge_factor(self, wind_zone, panel_type):
# corner, north/south, east/west, middle
edge_matrix = {'A': [1.2, 1.2, 1.0, 1.0],
'B': [1.2, 1.2, 1.0, 1.0],
'C': [1.4, 1.4, 1.0, 1.0],
'D': [1.4, 1.4, 1.0, 1.0],
'E': [1.5, 1.0, 1.5, 1.0],
'F': [1.3, 1.3, 1.0, 1.0],
'G': [1.0, 1.0, 1.0, 1.0],
'H': [1.0, 1.0, 1.0, 1.0],
'I': [1.0, 1.0, 1.0, 1.0],
'J': [2.0, 2.0, 1.0, 1.0],
'K': [1.4, 1.4, 1.0, 1.0]}
return edge_matrix[wind_zone][panel_type.index()]
def racking_capacity(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.EastWest:
return minimum_racking_capacity
else:
return 308
def c_p_constants(self, A_n, wind_zone):
if wind_zone == 'A':
if A_n < 421.5:
return -0.2245, 1.717
elif A_n < 2294.7:
return -0.1298, 1.1446
else:
return -0.0308, 0.3787
elif wind_zone == 'B':
if A_n < 421.5:
return -0.1818, 1.3585
elif A_n < 2294.7:
return -0.0708, 0.688
else:
return -0.0308, 0.3787
elif wind_zone == 'C':
if A_n < 421.5:
return -0.0735, 0.6443
elif A_n < 2294.7:
return -0.059, 0.5566
else:
return -0.021, 0.2627
elif wind_zone == 'D':
if A_n < 187.3:
return -0.1007, 0.6868
elif A_n < 421.5:
return -0.049, 0.4181
else:
return -0.0183, 0.2304
elif wind_zone == 'E':
if A_n < 187.3:
return -0.058, 0.4236
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
elif wind_zone == 'F':
if A_n < 187.3:
return -0.0655, 0.4682
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
elif wind_zone == 'G':
if A_n < 187.3:
return -0.0341, 0.2786
elif A_n < 421.5:
return -0.0271, 0.242
else:
return -0.0125, 0.1533
elif wind_zone == 'H':
if A_n < 187.3:
return -0.1161, 0.7872
elif A_n < 421.5:
return -0.074, 0.5672
elif A_n < 1685.9:
return -0.0433, 0.3816
else:
return -0.0117, 0.1473
elif wind_zone == 'I':
if A_n < 187.3:
return -0.3856, 2.258
elif A_n < 421.5:
return -0.148, 1.0143
elif A_n < 1685.9:
return -0.0433, 0.3816
else:
return -0.0117, 0.1473
elif wind_zone == 'J':
if A_n < 187.3:
return -0.1024, 0.6557
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
else:
return 1, 1
def base_weight(self, panel_type, tray_count):
return [[54.50, 54.50, 56.80, 59.10],
[49.47, 49.47, 51.77, 54.07],
[53.42, 55.72, 58.02, 60.32],
[48.75, 51.05, 53.35, 55.65]][panel_type.index()][tray_count]
def link_tray_thresholds(self, panel_type):
return [[0, 12.0],
[0, 9.00],
[6, 13.5],
[5, 10.0]][panel_type.index()]
def cross_tray_thresholds(self, panel_type):
return [[12.0, 21.0, 30.0],
[9.00, 18.0, 27.0],
[13.5, 22.5, 31.5],
[10.0, 19.0, 28.0]][panel_type.index()]
def weighted_average_c_p(self, corner, north_south, east_west, middle):
""" Based on a 30 by 28 rectangular array """
return (middle * 182. + north_south * 14. + east_west * 13. + corner) / 210.
def minimum_a_n_coefficients(self, uplift_c_p, wind_zone):
if wind_zone == 'A':
if uplift_c_p > 0.360:
return 3.1178, 0.3769
elif uplift_c_p > 0.180:
return 2.4967, 0.274
else:
return 0.9691, 0.0685
elif wind_zone == 'B':
if uplift_c_p > 0.260:
return 2.3762, 0.2807
elif uplift_c_p > 0.160:
return 1.7699, 0.1803
else:
return 0.7209, 0.0392
elif wind_zone == 'C':
if uplift_c_p > 0.200:
return 1.7251, 0.215
elif uplift_c_p > 0.100:
return 1.2668, 0.1274
else:
return 0.4655, 0.0196
elif wind_zone == 'D':
if uplift_c_p > 0.120:
return 2.3762, 0.2807
elif uplift_c_p > 0.094:
return 1.7699, 0.1803
else:
return 0.7209, 0.0392
elif wind_zone == 'E':
if uplift_c_p > 0.078:
return 0.8096, 0.0976
elif uplift_c_p > 0.060:
return 0.438, 0.0361
else:
return 0.3227, 0.0206
elif wind_zone == 'F':
if uplift_c_p > 0.078:
return 0.6281, 0.0708
else:
return 0.328, 0.0212
elif wind_zone == 'G':
if uplift_c_p > 0.078:
return 0.6281, 0.0708
else:
return 0.328, 0.0212
elif wind_zone == 'H':
if uplift_c_p > 0.180:
return 1.8215, 0.2525
elif uplift_c_p > 0.120:
return 1.4679, 0.185
elif uplift_c_p > 0.060:
return 1.13479, 0.1298
else:
return 0.3227, 0.0206
elif wind_zone == 'I':
if uplift_c_p > 0.240:
return 4.3609, 0.6996
elif uplift_c_p > 0.120:
return 2.639, 0.3699
elif uplift_c_p > 0.060:
return 1.4027, 0.1659
else:
return 0.3277, 0.0206
elif wind_zone == 'J':
if uplift_c_p > 0.120:
return 0.7131, 0.0891
elif uplift_c_p > 0.078:
return 0.5503, 0.058
else:
return 0.328, 0.0212
elif wind_zone == 'K':
if uplift_c_p > 0.080:
return 0.3, 0.0455
else:
return 0.2465, 0.0212
else:
return 1, 1

View File

@@ -0,0 +1,235 @@
from numpy import array
from numpy.ma import log
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
from helix.constants.system_type_constants.single_tilt_constants import SingleTiltConstants
class SingleTiltPSeriesConstants(object):
panel_spacing = (82.0, 61.8755) # inches
presenter_spacing = (1.5, 1)
panel_area = 22.22
surface_area = 22.22
tributary_area = array([1.87, 3.24, 3.24, 3.82])
ground_coverage_ratio = 0.67
friction_coefficient = 0.42
seismic_anchor_interval_constants = (8.9964, 2.09916)
max_psf = 32
system_constants = SingleTiltConstants()
def c_p_lower_bound(self):
c_p_lower_bound = []
for index, area in enumerate(self.tributary_area):
if area < 9:
c_p = -0.0273 * log(area) + 0.1401
else:
c_p = -0.0146 * log(area) + 0.112
edge_factor = self.edge_factor(self.system_constants.wind_zones[-1], PanelType.from_index(index))
c_p_lower_bound.append(c_p * edge_factor)
return array(c_p_lower_bound)
def edge_factor(self, wind_zone, panel_type):
# corner, north/south, east/west, middle
edge_matrix = {'A': [1.2, 1.2, 1.0, 1.0],
'B': [1.2, 1.2, 1.0, 1.0],
'C': [1.4, 1.4, 1.0, 1.0],
'D': [1.4, 1.4, 1.0, 1.0],
'E': [1.5, 1.0, 1.5, 1.0],
'F': [1.3, 1.3, 1.0, 1.0],
'G': [1.0, 1.0, 1.0, 1.0],
'H': [1.0, 1.0, 1.0, 1.0],
'I': [1.0, 1.0, 1.0, 1.0],
'J': [2.0, 2.0, 1.0, 1.0],
'K': [1.4, 1.4, 1.0, 1.0]}
return edge_matrix[wind_zone][panel_type.index()]
def racking_capacity(self, panel_type):
if panel_type == PanelType.Corner or panel_type == PanelType.EastWest:
return minimum_racking_capacity
else:
return 308
def c_p_constants(self, A_n, wind_zone):
if wind_zone == 'A':
if A_n < 421.5:
return -0.2245, 1.717
elif A_n < 2294.7:
return -0.1298, 1.1446
else:
return -0.0308, 0.3787
elif wind_zone == 'B':
if A_n < 421.5:
return -0.1818, 1.3585
elif A_n < 2294.7:
return -0.0708, 0.688
else:
return -0.0308, 0.3787
elif wind_zone == 'C':
if A_n < 421.5:
return -0.0735, 0.6443
elif A_n < 2294.7:
return -0.059, 0.5566
else:
return -0.021, 0.2627
elif wind_zone == 'D':
if A_n < 187.3:
return -0.1007, 0.6868
elif A_n < 421.5:
return -0.049, 0.4181
else:
return -0.0183, 0.2304
elif wind_zone == 'E':
if A_n < 187.3:
return -0.058, 0.4236
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
elif wind_zone == 'F':
if A_n < 187.3:
return -0.0655, 0.4682
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
elif wind_zone == 'G':
if A_n < 187.3:
return -0.0341, 0.2786
elif A_n < 421.5:
return -0.0271, 0.242
else:
return -0.0125, 0.1533
elif wind_zone == 'H':
if A_n < 187.3:
return -0.1161, 0.7872
elif A_n < 421.5:
return -0.074, 0.5672
elif A_n < 1685.9:
return -0.0433, 0.3816
else:
return -0.0117, 0.1473
elif wind_zone == 'I':
if A_n < 187.3:
return -0.3856, 2.258
elif A_n < 421.5:
return -0.148, 1.0143
elif A_n < 1685.9:
return -0.0433, 0.3816
else:
return -0.0117, 0.1473
elif wind_zone == 'J':
if A_n < 187.3:
return -0.1024, 0.6557
elif A_n < 421.5:
return -0.0518, 0.391
else:
return -0.0125, 0.1533
else:
return 1, 1
def base_weight(self, panel_type, tray_count):
if panel_type == PanelType.Corner:
return [66.91, 66.91, 70.09, 73.27][tray_count]
elif panel_type == PanelType.NorthSouth:
return [60.8, 60.8, 63.98, 67.16][tray_count]
elif panel_type == PanelType.EastWest:
return [64.75, 67.05, 70.23, 73.41][tray_count]
else:
return [60.08, 62.38, 65.56, 68.74][tray_count]
def link_tray_thresholds(self, panel_type):
return [[0, 13.0],
[0, 10.00],
[7, 14.5],
[6, 11.0]][panel_type.index()]
def cross_tray_thresholds(self, panel_type):
return [[13.0, 21.0, 29.0],
[10.00, 18.0, 26.0],
[14.5, 22.5, 30.5],
[11.0, 19.0, 27.0]][panel_type.index()]
def weighted_average_c_p(self, corner, north_south, east_west, middle):
""" Based on a 30 by 28 rectangular array """
return (middle * 182. + north_south * 14. + east_west * 13. + corner) / 210.
def minimum_a_n_coefficients(self, uplift_c_p, wind_zone):
if wind_zone == 'A':
if uplift_c_p > 0.360:
return 3.1178, 0.3769
elif uplift_c_p > 0.180:
return 2.4967, 0.274
else:
return 0.9691, 0.0685
elif wind_zone == 'B':
if uplift_c_p > 0.260:
return 2.3762, 0.2807
elif uplift_c_p > 0.160:
return 1.7699, 0.1803
else:
return 0.7209, 0.0392
elif wind_zone == 'C':
if uplift_c_p > 0.200:
return 1.7251, 0.215
elif uplift_c_p > 0.100:
return 1.2668, 0.1274
else:
return 0.4655, 0.0196
elif wind_zone == 'D':
if uplift_c_p > 0.120:
return 2.3762, 0.2807
elif uplift_c_p > 0.094:
return 1.7699, 0.1803
else:
return 0.7209, 0.0392
elif wind_zone == 'E':
if uplift_c_p > 0.078:
return 0.8096, 0.0976
elif uplift_c_p > 0.060:
return 0.438, 0.0361
else:
return 0.3227, 0.0206
elif wind_zone == 'F':
if uplift_c_p > 0.078:
return 0.6281, 0.0708
else:
return 0.328, 0.0212
elif wind_zone == 'G':
if uplift_c_p > 0.078:
return 0.6281, 0.0708
else:
return 0.328, 0.0212
elif wind_zone == 'H':
if uplift_c_p > 0.180:
return 1.8215, 0.2525
elif uplift_c_p > 0.120:
return 1.4679, 0.185
elif uplift_c_p > 0.060:
return 1.13479, 0.1298
else:
return 0.3227, 0.0206
elif wind_zone == 'I':
if uplift_c_p > 0.240:
return 4.3609, 0.6996
elif uplift_c_p > 0.120:
return 2.639, 0.3699
elif uplift_c_p > 0.060:
return 1.4027, 0.1659
else:
return 0.3277, 0.0206
elif wind_zone == 'J':
if uplift_c_p > 0.120:
return 0.7131, 0.0891
elif uplift_c_p > 0.078:
return 0.5503, 0.058
else:
return 0.328, 0.0212
elif wind_zone == 'K':
if uplift_c_p > 0.080:
return 0.3, 0.0455
else:
return 0.2465, 0.0212
else:
return 1, 1

View File

@@ -0,0 +1,46 @@
from enum import Enum
class PanelType(Enum):
Corner = 0
NorthSouth = 1
EastWest = 2
Middle = 3
@classmethod
def from_number(cls, number):
if number == 1:
return cls.Corner
elif number == 2:
return cls.NorthSouth
elif number == 3:
return cls.EastWest
elif number == 4:
return cls.Middle
return None
@classmethod
def from_index(cls, index):
return PanelType(index)
@classmethod
def all(cls):
return [cls.Corner, cls.NorthSouth, cls.EastWest, cls.Middle]
def number(self):
return self.value + 1
def index(self):
return self.value
def snake_case(self):
return {
PanelType.Corner: 'corner',
PanelType.NorthSouth: 'north_south',
PanelType.EastWest: 'east_west',
PanelType.Middle: 'middle',
}[self]
def __sub__(self, other): # Used for testing (assert_array_almost_equal requires subtraction)
return self.value - other.value

241
helix/constants/parts.py Normal file
View File

@@ -0,0 +1,241 @@
# Mechanical Parts
single_tilt_chassis = ('513831', 'CHASSIS, SINGLE TILT, HELIX ROOF')
dual_tilt_chassis = ('514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF')
dual_tilt_platform = ('514057', 'PLATFORM, CHASSIS, DUAL TILT, HELIX ROOF')
platform_bolt = ('515063', 'SCREW, CAP, SH, M6 X 1 X 12, 18-8 SS (DIN 912)')
left_deflector = ('513841', 'DEFLECTOR, LH, HELIX ROOF')
right_deflector = ('513842', 'DEFLECTOR, RH, HELIX ROOF')
front_skirt = ('515928', 'FRONT SKIRT, HELIX ROOF')
rear_skirt = ('515929', 'REAR SKIRT, HELIX ROOF')
spoiler = ('513836', 'SPOILER, SINGLE TILT, HELIX ROOF')
rear_skirt_1_1 = ('520301', 'REAR SKIRT, HELIX ROOF V1.1')
spoiler_1_1 = ('520302', 'SPOILER, SINGLE TILT, HELIX ROOF V1.1')
front_skirt_1_1 = ('520303', 'FRONT SKIRT, HELIX ROOF V1.1')
cross_tray_1_1 = ('520306', 'TRAY, OPTIONAL BALLAST, HELIX ROOF V1.1')
left_deflector_1_1 = ('521794', 'DEFLECTOR, LH, HELIX ROOF V1.1')
right_deflector_1_1 = ('521795', 'DEFLECTOR, RH, HELIX ROOF V1.1')
leading_tray = ('517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION')
following_tray = ('513832', 'TRAY, FOLLOWING, HELIX ROOF')
link_tray = ('513833', 'TRAY, LINK, HELIX ROOF')
cross_tray = ('513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF')
anchor_plate = ('513843', 'PLATE, ANCHOR, HELIX ROOF')
anchor = ('TBD', 'Anchors')
anchor_washer = ('518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS')
module = ('TBD', 'Modules')
ballast = ('Contractor Supplied', 'Ballast Blocks')
rubber_foot = ('514265', 'FOOT, RECYCLED RUBBER, HELIX ROOF')
# Electrical Parts, per inverter
flat_washer = ('104813', 'WASHER, FLAT, 3/8, .812 OD, 18-8 SS (1500-731)')
channel_nut = ('106925', 'NUT, CHANNEL, 3/8-16, SS, UNISTRUT P3008 (1507-770)')
hex_nut_three_eighths_16 = ('107551', 'NUT, HEX, 3/8-16, 18-8 SS (5100-086)')
hex_bolt_3_4 = ('513007', 'BOLT, HH, 3/8-16 X 3/4, 316 SS')
hex_bolt_1_2 = ('514865', 'BOLT, HH, 3/8-16 X 1/2, 18-8 SS')
front_legs = ('512660', 'FRONT LEG, INVERTER RACK, HELIX ROOF')
back_legs = ('512661', 'BACK LEGS, INVERTER RACK, HELIX ROOF')
harness_2_string_fm = ('514437', 'HARNESS, DC COMBINATION, NO FUSE, 2 STRING, FEMALES TO MALE, HELIX')
harness_2_string_mf = ('514438', 'HARNESS, DC COMBINATION, NO FUSE, 2 STRING, MALES TO FEMALE, HELIX')
harness_3_string_fm = ('514435', 'HARNESS, DC COMBINATION, W/ FUSE, 3 STRING, FEMALES TO MALE, HELIX')
harness_3_string_mf = ('514436', 'HARNESS, DC COMBINATION, W/ FUSE, 3 STRING, MALES TO FEMALE, HELIX')
harness_4_string_fm = ('514439', 'HARNESS, DC COMBINATION, W/ FUSE, 4 STRING, FEMALES TO MALE, HELIX')
harness_4_string_mf = ('514440', 'HARNESS, DC COMBINATION, W/ FUSE, 4 STRING, MALES TO FEMALE, HELIX')
inverter_rail = ('512663', 'RAIL, INVERTER RACK, HELIX ROOF')
inverter_link = ('512662', 'LINK TO ARRAY, INVERTER RACK, HELIX ROOF')
inverter_link_short = ('521798', 'LINK TO ARRAY, LONG, INVERTER RACK, HELIX ROOF V1.1')
inverter_link_long = ('521797', 'LINK TO ARRAY, SHORT, INVERTER RACK, HELIX ROOF V1.1')
mounting_back_plate = ('518331', 'MOUNTING BACK PLATE, INVERTER/PANEL BOARD, HELIX ROOF/TRACKER')
sma_12kw_inverter = ('514686', 'INVERTER, SMA, STP, 12000TL-US-10 (SPR-12000m-3 XXX), AFCI, CONNECTORIZED')
sma_15kw_inverter = ('514687', 'INVERTER, SMA, STP, 15000TL-US-10 (SPR-15000m-3 XXX), AFCI, CONNECTORIZED')
sma_20kw_inverter = ('512676', 'INVERTER, SMA, STP, 20000TL-US-10 (SPR-20000m-3 XXX), AFCI, CONNECTORIZED')
sma_24kw_inverter = ('514685', 'INVERTER, SMA, STP, 24000TL-US-10 (SPR-24000m-3 XXX), AFCI, CONNECTORIZED')
delta_36kw_inverter = ('524952', 'INVERTER, DELTA, M36U_122(MC4), 10INPUT, 36KW, 3PH 480V AC,1000V DC')
delta_42kw_inverter = ('524969', 'INVERTER, DELTA, M42U_122(MC4), 12INPUT, 42KW, 3PH 480V AC,1000V DC')
delta_60kw_inverter = ('524954', 'INVERTER, DELTA, M60U_122 (MC4), 18INPUT, 60KW, 3PH 480V AC,1000V DC')
delta_80kw_inverter = ('524955', '-')
screw_12_24x1_25 = ('507985', 'SCREW, S-D, HWH, #12-24X 1-1/4", #3 PT, BI-METAL')
# Wire management
stump = ('512021', 'STUMP, WIRE MANAGEMENT, 50MM ID, HELIX ROOF')
cable_support = ('512511', 'CABLE SUPPORT, HELIX ROOF')
cable_support_lid = ('512510', 'LID, CABLE SUPPORT, HELIX ROOF')
wire_clip = ('512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2')
wire_clip_large = ('512199', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 1624MM ^ 2')
# Panel Boards
panel_board_4 = ('513299', 'COMBINER BOX, AC, 4 INPUT, NO AUX, W/ CONNECTOR')
panel_board_3 = ('513301', 'COMBINER BOX, AC, 3 INPUT, NO AUX, W/ CONNECTOR')
panel_board_2 = ('513303', 'COMBINER BOX, AC, 2 INPUT, NO AUX, W/ CONNECTOR')
harness_ac_inner = ('514477', 'HARNESS, AC, INNER, 72", HELIX ROOFTOP')
harness_ac_outer = ('514478', 'HARNESS, AC, OUTER, 108", HELIX ROOFTOP')
whip_tray = ('515059', 'ASSY, WHIP TRAY W/FUSE CLIPS, INVERTER, HELIX')
comm_cable = ('514697', 'COMM CABLE, INVERTER DAISY CHAIN, 118", HELIX ROOF')
ethernet_plug = ('518058', 'CONNECTOR, ETHERNET, PLUG, RJ-45, WEATHERPROOF, SHIELDED')
# Aux Plug
panel_board_4_aux = ('513300', 'COMBINER BOX, AC, 4 INPUT, W/ AUX, W/ CONNECTOR')
panel_board_3_aux = ('513302', 'COMBINER BOX, AC, 3 INPUT, W/ AUX, W/ CONNECTOR')
panel_board_2_aux = ('513304', 'COMBINER BOX, AC, 2 INPUT, W/ AUX, W/ CONNECTOR')
# Monitoring
monitor_power_plug = ('519008', 'HARNESS, MONITORING POWER CABLE, SINGLE CONNECTOR, HELIX ROOF')
monitor_controller_480_v = ('518059', 'CONTROLLER, MONITORING, COMMERCIAL, PVS5C BASED, 480VAC, US')
monitor_controller_240_v = ('517463', 'MONITORING SYSTEM, COMMERCIAL, <100KW, PVS5x BASED, 240VAC, US')
# DC Switch related
dc_switch_bracket = ('512575', 'BRACKET, DC SWITCH BOX, HELIX')
dc_switch_box = ('514698', 'DC SWITCH BOX, HELIX')
hex_bolt_quarter_20 = ('114961', 'BOLT, HH, 1/4-20 X 3/4", 18-8SS')
hex_nut_quarter_20 = ('107549', 'NUT, HEX, 1/4-20, 18-8 SS (5100-084)')
flat_washer_quarter_inch = ('107586', 'WASHER, FLAT, 1/4, 0.5 OD, 18-8 SS (5100-144)')
# Standalone Inverter
star_washer = ('105317', 'WASHER, STAR, #6, SS (1501-606)')
flat_washer_6 = ('111147', 'WASHER, FLAT, #6, 18-8 SS (1509-097)')
phillips_screw = ('107538', 'SCREW, PH, 6-32 X 1/2, SS (5100-073)')
ac_splice_box = ('516045', 'AC SPLICE BOX, CONNECTORIZED, HELIX ROOF')
ac_switch = ('516043', 'AC SWITCH, CONNECTORIZED, HELIX ROOF')
ac_inverter_bracket = ('513586', 'BRACKET, INVERTER AC SWITCH, HELIX')
delta_kit_inverter_mount = ('524781', 'KIT, INVERTER MOUNT, DELTA, HELIX ROOF')
delta_kit_inverter_mount_dt = ('525772', 'KIT, INVERTER MOUNT, DELTA, DT, HELIX ROOF')
delta_splice_box = ('525651', 'KIT, AC SPLICE, DELTA, HELIX ROOF')
delta_inverter_leg = ('524783', 'INVERTER LEG, DELTA, HELIX ROOF')
delta_branch_connector = ('TBD', 'Branch connector')
# Other Ebom
sunshade = ('512910', 'SUN SHADE, INVERTER, HELIX')
sunshade_bolt = ('805615', 'SCREW, HEXAGONAL HEAD, M10X20, SS A2')
sunshade_washer = ('521031', 'WASHER, FLAT, M10 X 20MM OD, SS')
fuseshade = ('521363', 'FUSE SHADE, HELIX ROOF')
fuseshade_brace = ('522020', 'BRACE, FUSE SHADE, HELIX ROOF')
# Package Sizes
package_sizes = {
flat_washer: 50,
flat_washer_quarter_inch: 100,
channel_nut: 50,
hex_nut_three_eighths_16: 50,
hex_nut_quarter_20: 100,
hex_bolt_3_4: 50,
hex_bolt_quarter_20: 50,
hex_bolt_1_2: 50,
wire_clip_large: 10,
wire_clip: 30,
platform_bolt: 50,
star_washer: 100,
anchor_washer: 25
}
all_parts = [
single_tilt_chassis,
dual_tilt_chassis,
dual_tilt_platform,
platform_bolt,
left_deflector,
right_deflector,
front_skirt,
rear_skirt,
spoiler,
rear_skirt_1_1,
spoiler_1_1,
front_skirt_1_1,
cross_tray_1_1,
leading_tray,
following_tray,
link_tray,
cross_tray,
anchor_plate,
anchor,
anchor_washer,
module,
ballast,
rubber_foot,
flat_washer,
channel_nut,
hex_nut_three_eighths_16,
hex_bolt_3_4,
hex_bolt_1_2,
front_legs,
back_legs,
harness_2_string_fm,
harness_2_string_mf,
harness_3_string_fm,
harness_3_string_mf,
harness_4_string_fm,
harness_4_string_mf,
inverter_rail,
inverter_link,
mounting_back_plate,
sma_12kw_inverter,
sma_15kw_inverter,
sma_20kw_inverter,
sma_24kw_inverter,
stump,
cable_support,
cable_support_lid,
wire_clip,
wire_clip_large,
panel_board_4,
panel_board_3,
panel_board_2,
harness_ac_inner,
harness_ac_outer,
whip_tray,
comm_cable,
ethernet_plug,
panel_board_4_aux,
panel_board_3_aux,
panel_board_2_aux,
monitor_power_plug,
monitor_controller_480_v,
dc_switch_bracket,
dc_switch_box,
hex_bolt_quarter_20,
hex_nut_quarter_20,
flat_washer_quarter_inch,
star_washer,
flat_washer_6,
phillips_screw,
ac_splice_box,
ac_switch,
ac_inverter_bracket,
sunshade,
sunshade_bolt,
sunshade_washer,
screw_12_24x1_25,
fuseshade_brace,
left_deflector_1_1,
right_deflector_1_1,
inverter_link_short,
inverter_link_long,
fuseshade,
monitor_controller_240_v
]

View File

@@ -0,0 +1,7 @@
import os
from helix.db.redis_manager import RedisManager
vcap_url = os.getenv('VCAP_SERVICES') # pws is best ws.
heroku_url = os.getenv('REDIS_URL')
redis_store = RedisManager.get_redis_connection(vcap_url, heroku_url)

View File

@@ -0,0 +1,5 @@
from enum import Enum
class SeismicAnchorValidationError(Enum):
TooFewAnchors = 'There are too few anchors in one or more subarrays'

View File

@@ -0,0 +1,94 @@
from helix.constants.module_type import ModuleType
from helix.constants.parts import *
class SingleTiltParts(object):
center_panel_parts = {
module: 1,
single_tilt_chassis: 1
}
sub_array_parts = {
leading_tray: 1
}
north_south_panel_parts = {
module: 1,
single_tilt_chassis: 0.5,
}
def __init__(self, module_type):
if module_type == ModuleType.PSeries:
self.corner_panel_parts = {
module: 1,
single_tilt_chassis: 1,
left_deflector_1_1: 0.5,
right_deflector_1_1: 0.5,
}
self.east_west_panel_parts = {
module: 1,
single_tilt_chassis: 1.5,
left_deflector_1_1: 0.5,
right_deflector_1_1: 0.5
}
else:
self.corner_panel_parts = {
module: 1,
single_tilt_chassis: 1,
left_deflector: 0.5,
right_deflector: 0.5
}
self.east_west_panel_parts = {
module: 1,
single_tilt_chassis: 1.5,
left_deflector: 0.5,
right_deflector: 0.5
}
def row_parts(self, _):
return {}
def column_parts(self, module_type):
if module_type == ModuleType.Cell96:
front_skirt_parts = front_skirt
else:
front_skirt_parts = front_skirt_1_1
return {
front_skirt_parts: 1,
leading_tray: 1
}
def parts_per_panel_type(self):
return [
self.corner_panel_parts,
self.north_south_panel_parts,
self.east_west_panel_parts,
self.center_panel_parts
]
def module(self, module_type):
if module_type == ModuleType.Cell96:
rear_skirt_parts = rear_skirt
spoiler_parts = spoiler
else:
rear_skirt_parts = rear_skirt_1_1
spoiler_parts = spoiler_1_1
return {
spoiler_parts: 1,
rear_skirt_parts: 1,
wire_clip: 2,
rubber_foot: 0.1
}
def dependent_parts(self, module_type):
return {
module: self.module(module_type),
leading_tray: {
following_tray: 1
}
}
def fudge_factors(self, _):
return {
single_tilt_chassis: 1.0525
}

View File

@@ -0,0 +1,6 @@
import os
from helix.db.sql_manager import SQLManager
def sql_session_maker():
return SQLManager.get_sql_session_maker(os.getenv('DATABASE_URL'))

View File

@@ -0,0 +1,6 @@
'''
Created on May 22, 2017
@author: jvazquez
'''
SUBARRAY_SIZE_BIG = "Array size is too big. Max is 150' by 150'."

View File

@@ -0,0 +1,60 @@
from enum import Enum
from helix.constants.module_type import ModuleType
from helix.constants.module_type_constants.dual_tilt_128_cell_constants import DualTilt128CellConstants
from helix.constants.module_type_constants.dual_tilt_96_cell_constants import DualTilt96CellConstants
from helix.constants.dual_tilt_parts import DualTiltParts
from helix.constants.module_type_constants.dual_tilt_pseries_constants import DualTiltPSeriesConstants
from helix.constants.module_type_constants.single_tilt_128_cell_constants import SingleTilt128CellConstants
from helix.constants.module_type_constants.single_tilt_96_cell_constants import SingleTilt96CellConstants
from helix.constants.module_type_constants.single_tilt_pseries_constants import SingleTiltPSeriesConstants
from helix.constants.single_tilt_parts import SingleTiltParts
from helix.constants.system_type_constants.dual_tilt_constants import DualTiltConstants
from helix.constants.system_type_constants.single_tilt_constants import SingleTiltConstants
class SystemType(Enum):
singleTilt = '0'
dualTilt = '1'
def system_constants(self):
return {
SystemType.singleTilt: SingleTiltConstants(),
SystemType.dualTilt: DualTiltConstants()
}[self]
def module_constants(self, module_type):
return {
SystemType.singleTilt: self.single_tilt_constants(module_type),
SystemType.dualTilt: self.dual_tilt_constants(module_type)
}[self]
def parts(self, module_type):
return {
SystemType.singleTilt: SingleTiltParts(module_type),
SystemType.dualTilt: DualTiltParts(module_type)
}[self]
def display_name(self):
return {
SystemType.singleTilt: 'Single-Tilt',
SystemType.dualTilt: 'Dual-Tilt'
}[self]
@classmethod
def default_value(cls):
return cls.dualTilt.value
def single_tilt_constants(self, module_type):
return {
ModuleType.Cell96: SingleTilt96CellConstants(),
ModuleType.Cell128: SingleTilt128CellConstants(),
ModuleType.PSeries: SingleTiltPSeriesConstants()
}[module_type]
def dual_tilt_constants(self, module_type):
return {
ModuleType.Cell96: DualTilt96CellConstants(),
ModuleType.Cell128: DualTilt128CellConstants(),
ModuleType.PSeries: DualTiltPSeriesConstants()
}[module_type]

View File

@@ -0,0 +1,4 @@
class DualTiltConstants(object):
wind_zones = ['A', 'B', 'C', 'D', 'E']
module_count = 2
minimum_corner_module_count = 2

View File

@@ -0,0 +1,4 @@
class SingleTiltConstants(object):
wind_zones = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
module_count = 1
minimum_corner_module_count = 4

View File

@@ -0,0 +1,7 @@
import os
def version():
if os.getenv('VERSION'):
return os.getenv('VERSION')
return 'release-9-72-g3e1c132'