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

185 lines
8.7 KiB
Python

from math import ceil, floor
from helix.calculators.subarray_graph import SubarrayGraph
from helix.calculators.subarray_helper import extract_subarray
from helix.constants.global_constants import minimum_racking_capacity
from helix.constants.panel_type import PanelType
from helix.models.subarray import Subarray
class SeismicCalculator(object):
def __init__(self, values, graph_repository):
self.values = values
self.system_type = values.system_type()
self.system_constants = values.module_system_constants()
self.anchor_type = values.anchor_type()
self.graph_repository = graph_repository
def assign_seismic_anchors(self, subarray, panels):
panel_data_for_subarray = extract_subarray(panels, subarray.subarray_number)
self.assign_anchors_to_subarray(panel_data_for_subarray, subarray)
return panels
def assign_anchors_to_subarray(self, panels, subarray):
sds = self.values.spectral_response()
wind_anchors = sum([panel.wind_anchors for panel in panels])
for panel in panels:
if panel.seismic_anchors is None:
panel.seismic_anchors = 0
required_anchors = subarray.required_seismic_anchors
if required_anchors == 0 and (wind_anchors == 0 or sds < 1):
return panels
graph = self.graph_repository.subarray_graph(subarray.subarray_number)
if len(graph.nodes) == 0:
return panels
more_anchors_needed = True
perimeter_covered = sds < 1.0
anchor_threshold = 0
while more_anchors_needed:
rung = graph.pop_rung()
interval = int(self.seismic_anchor_interval())
nodes_since_last_anchor = interval
if len(rung) == 0:
graph.reset()
anchor_threshold += 1
continue
while more_anchors_needed and interval >= 0:
for node in rung:
nodes_since_last_anchor += 1
if node.wind_anchor + node.seismic_anchor > anchor_threshold:
nodes_since_last_anchor = 0
if nodes_since_last_anchor > interval:
node.assign_seismic_anchor()
required_anchors -= 1
nodes_since_last_anchor = 0
more_anchors_needed = (not perimeter_covered) or required_anchors > 0
if not more_anchors_needed:
break
perimeter_covered = True
if interval <= 1:
interval -= 1
else:
interval /= 2
for idx, node in enumerate(graph.nodes):
panels[idx].seismic_anchors = node.seismic_anchor
return panels
def compute_provided_lateral_capacity(self, subarray_number, panels):
subarray_panels = extract_subarray(panels, subarray_number)
anchors = {PanelType.Corner: 0, PanelType.NorthSouth: 0, PanelType.EastWest: 0, PanelType.Middle: 0}
for panel in subarray_panels:
if panel.seismic_anchors is not None:
anchors[panel.panel_type] += panel.seismic_anchors
return self.anchors_shear_capacity(anchors[PanelType.Corner], anchors[PanelType.NorthSouth],
anchors[PanelType.EastWest], anchors[PanelType.Middle])
def seismic_anchors_for_subarray(self, F_p, subarray_weight, spectral_response, friction_coefficient,
seismic_anchors, corner_anchors,
north_south_anchors, east_west_anchors, middle_anchors, shear_capacity):
demand = self.seismic_demand_for_subarray(F_p, subarray_weight, spectral_response, friction_coefficient,
seismic_anchors, corner_anchors, north_south_anchors,
east_west_anchors, middle_anchors)
return ceil(demand / shear_capacity)
def anchors_shear_capacity(self, corner_anchors, north_south_anchors, east_west_anchors, middle_anchors):
anchor_shear_capacity = self.anchor_type.shear_capacity()
panel_racking_capacity = self.system_constants.racking_capacity
corner_capacity = corner_anchors * min(anchor_shear_capacity, panel_racking_capacity(PanelType.Corner))
north_south_capacity = north_south_anchors * min(anchor_shear_capacity, panel_racking_capacity(PanelType.NorthSouth))
east_west_capacity = east_west_anchors * min(anchor_shear_capacity, panel_racking_capacity(PanelType.EastWest))
middle_capacity = middle_anchors * min(anchor_shear_capacity, panel_racking_capacity(PanelType.Middle))
return corner_capacity + north_south_capacity + east_west_capacity + middle_capacity
def seismic_demand_for_subarray(self, F_p, subarray_weight, spectral_response, friction_coefficient,
seismic_anchors, corner_anchors,
north_south_anchors, east_west_anchors, middle_anchors):
if (corner_anchors + north_south_anchors + east_west_anchors + middle_anchors == 0) and seismic_anchors == 0:
return 0
existing_shear_resistance = self.anchors_shear_capacity(corner_anchors, north_south_anchors, east_west_anchors,
middle_anchors)
shear_force = 0.7 * F_p * subarray_weight - (
(0.6 - 0.14 * spectral_response) * 0.7 * friction_coefficient * subarray_weight) - existing_shear_resistance
return max(shear_force, 0)
def required_force_seismic_anchors(self, subarray_number, panels):
demand = self.required_force_seismic_demand(subarray_number, panels)
system_shear_capacity = min(self.anchor_type.shear_capacity(),
minimum_racking_capacity)
return ceil(demand / system_shear_capacity)
def required_force_seismic_demand(self, subarray_number, panels):
subarray_panels = extract_subarray(panels, subarray_number)
importance_factor = self.values.importance_factor()
spectral_response = self.values.spectral_response()
F_p = 1.2 * spectral_response / (1.5 / importance_factor)
# number of wind anchors by panel type
anchors = {PanelType.Corner: 0,
PanelType.NorthSouth: 0,
PanelType.EastWest: 0,
PanelType.Middle: 0}
# total weight
subarray_weight = 0
# total number of seismic anchors
seismic_anchors = 0
for panel in subarray_panels:
if panel.seismic_anchors is not None:
seismic_anchors += panel.seismic_anchors
# it could be calculated before the loop to avoid redundant calculations
effective_area = self.system_constants.surface_area / self.system_constants.ground_coverage_ratio
weight = panel.pressure * effective_area
anchors[panel.panel_type] += panel.wind_anchors
subarray_weight += weight
force_required_demand = self.seismic_demand_for_subarray(F_p, subarray_weight, spectral_response,
self.system_constants.friction_coefficient,
seismic_anchors,
anchors[PanelType.Corner],
anchors[PanelType.NorthSouth],
anchors[PanelType.EastWest],
anchors[PanelType.Middle])
return force_required_demand
def required_geometric_seismic_anchors(self, subarray_number, panels):
if panels[0].coordinate is None or self.values.spectral_response() < 1:
return 0
panel_data_for_subarray = extract_subarray(panels, subarray_number)
subarray = Subarray(required_seismic_anchors=0, subarray_number=subarray_number)
anchors_for_subarray = self.assign_anchors_to_subarray(panel_data_for_subarray, subarray)
return sum(panel.seismic_anchors for panel in anchors_for_subarray if panel.seismic_anchors)
def seismic_anchor_interval(self):
sds = self.values.spectral_response()
importance_factor = self.values.importance_factor()
interval_constant, interval_multiplier = self.system_constants.seismic_anchor_interval_constants
denom = (22.96 * importance_factor * sds - interval_constant + interval_multiplier * sds)
if denom <= 0:
return 15
return floor(minimum_racking_capacity / denom)