first commit
This commit is contained in:
0
helix/constants/__init__.py
Normal file
0
helix/constants/__init__.py
Normal file
23
helix/constants/anchor_parts.py
Normal file
23
helix/constants/anchor_parts.py
Normal 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
|
||||
}
|
||||
29
helix/constants/anchor_type.py
Normal file
29
helix/constants/anchor_type.py
Normal 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
|
||||
4
helix/constants/bom_constants.py
Normal file
4
helix/constants/bom_constants.py
Normal 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
11
helix/constants/color.py
Normal 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"
|
||||
89
helix/constants/dual_tilt_parts.py
Normal file
89
helix/constants/dual_tilt_parts.py
Normal 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,
|
||||
}
|
||||
7
helix/constants/dxf_validation.py
Normal file
7
helix/constants/dxf_validation.py
Normal 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."
|
||||
281
helix/constants/ebom_parts.py
Normal file
281
helix/constants/ebom_parts.py
Normal 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,
|
||||
}
|
||||
}
|
||||
34
helix/constants/exposure_category.py
Normal file
34
helix/constants/exposure_category.py
Normal 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
|
||||
50
helix/constants/file_validation_error.py
Normal file
50
helix/constants/file_validation_error.py
Normal 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
|
||||
9
helix/constants/global_constants.py
Normal file
9
helix/constants/global_constants.py
Normal 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
|
||||
25
helix/constants/inverter_brand.py
Normal file
25
helix/constants/inverter_brand.py
Normal 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}
|
||||
94
helix/constants/inverter_type.py
Normal file
94
helix/constants/inverter_type.py
Normal 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()
|
||||
11
helix/constants/module_type.py
Normal file
11
helix/constants/module_type.py
Normal 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
|
||||
0
helix/constants/module_type_constants/__init__.py
Normal file
0
helix/constants/module_type_constants/__init__.py
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
46
helix/constants/panel_type.py
Normal file
46
helix/constants/panel_type.py
Normal 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
241
helix/constants/parts.py
Normal 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
|
||||
]
|
||||
7
helix/constants/redis_constant.py
Normal file
7
helix/constants/redis_constant.py
Normal 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)
|
||||
5
helix/constants/seismic_anchor_validation_error.py
Normal file
5
helix/constants/seismic_anchor_validation_error.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class SeismicAnchorValidationError(Enum):
|
||||
TooFewAnchors = 'There are too few anchors in one or more subarrays'
|
||||
94
helix/constants/single_tilt_parts.py
Normal file
94
helix/constants/single_tilt_parts.py
Normal 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
|
||||
}
|
||||
6
helix/constants/sql_constant.py
Normal file
6
helix/constants/sql_constant.py
Normal 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'))
|
||||
6
helix/constants/subarray.py
Normal file
6
helix/constants/subarray.py
Normal 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'."
|
||||
60
helix/constants/system_type.py
Normal file
60
helix/constants/system_type.py
Normal 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]
|
||||
0
helix/constants/system_type_constants/__init__.py
Normal file
0
helix/constants/system_type_constants/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
class DualTiltConstants(object):
|
||||
wind_zones = ['A', 'B', 'C', 'D', 'E']
|
||||
module_count = 2
|
||||
minimum_corner_module_count = 2
|
||||
@@ -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
|
||||
7
helix/constants/version.py
Normal file
7
helix/constants/version.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import os
|
||||
|
||||
|
||||
def version():
|
||||
if os.getenv('VERSION'):
|
||||
return os.getenv('VERSION')
|
||||
return 'release-9-72-g3e1c132'
|
||||
Reference in New Issue
Block a user