### ===================================================================================================================
### FUNCTION: Get limits for VIIA pictures
### ===================================================================================================================
# Copyright ©VIIA 2024
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
from typing import TYPE_CHECKING, Union, Dict, List, Tuple, Optional
# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.shapes import Shapes, Reinforcements
from rhdhv_fem.output_items import OutputItem, StrainOutputItem, StressOutputItem
# References for function and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
from viiapackage.results.result_functions.viia_limits import viia_find_limits_NLTH
### ===================================================================================================================
### 2. Function to get the VIIA limits for result pictures
### ===================================================================================================================
[docs]def viia_get_limits(
project: ViiaProject, shape_set: Union[Dict, List], output_item: OutputItem, pic_type: str, scope: str,
component: str, material: str = None) -> Tuple[Optional[float], Optional[float], Optional[bool]]:
"""
This function returns the limit values (maximum and minimum) for the NLTH result pictures. The limits comply to the
check mentioned in the most recent Bass of Design report.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- shape_set (dictionary or list): List of shapes or dictionary with subdivisions for different sets of shapes or
connections.
- output_item (obj): Instance of output item for what the limits should be found.
- pic_type (str): The result type of the result picture, this is defined in the viia-result_pictures yaml-file.
- scope (str): The scope of the result picture, this is defined in the viia-result_pictures yaml-file.
- component (str): Component of the plot result type.
- material (str): Material name of the shape. Default value is None.
Output:
- Returns the maximum and minimum value for different scope and shape sets.
"""
# Get limits for different scope
max_value, min_value = None, None
limit_found = True
if scope == 'Building' or scope == 'Floors-interstorey':
max_value, min_value = None, None
elif scope == 'Walls-storey' and 'CrackWidth' not in pic_type:
limits = []
ran = []
for shape in shape_set:
if shape.material.name.lower() in ["lin-dummy-plate"]:
continue
limits.append(viia_find_limits_NLTH(project=project, shape=shape))
if component == material.split('_')[1] and component in ['x', 'y']:
for limit in limits:
if 'In-plane' in limit:
ran.append(limit['In-plane'])
else:
for limit in limits:
if 'Out-of-plane' in limit:
ran.append(limit['Out-of-plane'])
if not ran:
project.write_log(
f"WARNING: Could not find proper limit value for result picture {scope}, component {component}. The "
f"shapes in the picture are: {', '.join([shape.name for shape in shape_set])}. Limits found: {limits}.")
return None, None, False
if pic_type.split('-')[-1] == 'Max':
max_value = min(ran)
min_value = 0
else:
max_value = 0
min_value = -min(ran)
elif scope == 'Walls-storey' and 'CrackWidth' in pic_type:
thickness = [float(wall.geometry.name.split('-')[1]) for wall in shape_set]
max_value = 0.05*min(thickness)/1000
min_value = 0
elif scope == 'Beams-Material-storey':
limit = None
for shape in shape_set:
if shape.material.name.lower() in ["lin-dummy-plate"]:
continue
limit = viia_find_limits_NLTH(project=project, shape=shape)
if limit:
break
if not limit:
limit_found = False
elif all(val not in limit for val in ('f_t', 'f_b', 'f_vm')):
limit_found = False
project.write_log(
f"WARNING: Could not find proper limit value for result picture {scope}, component {component}. The "
f"shapes in the picture are: {', '.join([shape.name for shape in shape_set])}. Limits found: {limit}.")
else:
min_value = 0
if material == 'LIN-BETON':
max_value = limit['f_t']
elif 'LIN-HOUT' in material:
max_value = limit['f_b']
elif 'LIN-STAAL' in material:
max_value = limit['f_vm']
elif scope == 'Columns-Material-storey':
limit = None
for shape in shape_set:
if shape.material.name.lower() in ["lin-dummy-plate"]:
continue
limit = viia_find_limits_NLTH(project=project, shape=shape)
if limit:
break
if not limit:
limit_found = False
elif all(val not in limit for val in ('f_c', 'f_b', 'f_vm')):
limit_found = False
project.write_log(
f"WARNING: Could not find proper limit value for result picture {scope}, component {component}. The "
f"shapes in the picture are: {', '.join([shape.name for shape in shape_set])}. Limits found: {limit}.")
else:
max_value = 0
if material == 'LIN-BETON':
min_value = -limit['f_c']
elif 'LIN-HOUT' in material:
min_value = -limit['f_b']
elif 'LIN-STAAL' in material:
max_value = limit['f_vm']
min_value = 0
elif scope == 'Reinforcements-storey':
limits = {}
for shape in [item for item in shape_set if isinstance(item, Reinforcements) and isinstance(item, Shapes)]:
limits = viia_find_limits_NLTH(project=project, shape=shape)
if limits:
break
# Return if no limits are found
if not limits:
limit_found = False
elif 'f_y' in limits:
if 'Max' in pic_type:
max_value = limits['f_y']
min_value = 0
elif 'Min' in pic_type:
max_value = 0
min_value = -limits['f_y']
elif 'e_u' in limits:
if 'Max' in pic_type:
max_value = limits['e_u']
min_value = 0
elif 'Min' in pic_type:
max_value = 0
min_value = -limits['e_u']
elif scope in ['Floors-Material-storey', 'Roofs-Material-storey', 'Roofs-Timber'] and \
isinstance(output_item, StressOutputItem):
limits = {}
for shape in shape_set:
material = shape.material.name
if material.lower() in ["lin-dummy-plate"]:
continue
limits = viia_find_limits_NLTH(project=project, shape=shape)
if limits:
break
# Return if no limits are found
if not limits:
limit_found = False
elif 'N_in' not in limits:
limit_found = False
project.write_log(
f"WARNING: Could not find proper limit value for result picture {scope}, component {component}. The "
f"shapes in the picture are: {', '.join([shape.name for shape in shape_set])}. Limits found: {limits}.")
else:
if 'Max' in pic_type:
max_value = limits['N_in']
min_value = 0
else:
min_value = -limits['N_in']
max_value = 0
elif scope in ['Floors-Timber-storey', 'Roofs-Timber'] and isinstance(output_item, StrainOutputItem):
if 'Max' in pic_type:
max_value = 2.5E-02
min_value = 0
elif 'Min' in pic_type:
min_value = -2.5E-02
max_value = 0
# Not all interfaces have upper and lower bound limits and therefore the checks are for particular interfaces
elif scope == 'Interfaces-storey-Line':
maximum = []
minimum = []
for shape in shape_set:
if shape.name.split('-')[3] in ['D2.01', 'D2.02', 'D2.13'] and component == 'z' and \
isinstance(output_item, StrainOutputItem) and output_item.output_type == 'total' and \
output_item.theoretical_formulation == 'relative displacement' and output_item.operation == 'local':
thickness = float(shape.connecting_shapes['source_connecting_shape'].name.split('-')[-2])/1000
if 'Max' in pic_type:
maximum.append(thickness/2)
minimum.append(0)
elif 'Min' in pic_type:
maximum.append(0)
minimum.append(-thickness/2)
else:
project.write_log(
f"WARNING: No limits are applicable for the {shape.name} interface and for the {pic_type} "
f"component.")
# Remove duplicates and select the minimum value for conservative purpose
if maximum and minimum:
max_value = min(list(dict.fromkeys(maximum)))
min_value = max(list(dict.fromkeys(minimum)))
elif scope == 'Interfaces-storey-Point':
maximum = []
minimum = []
for shape in shape_set:
if shape.name.split('-')[3] == 'D2.01B' and component == 'y' and \
isinstance(output_item, StrainOutputItem) and output_item.output_type == 'total' and \
output_item.theoretical_formulation == 'relative displacement' and output_item.operation == 'local':
thickness = float(shape.connecting_shapes['source_connecting_shape'].name.split('-')[-2]) / 1000
if 'Max' in pic_type:
maximum.append(thickness / 2)
minimum.append(0)
elif 'Min' in pic_type:
maximum.append(0)
minimum.append(-thickness / 2)
else:
project.write_log(
f'No limits are applicable for the {shape.name} interface and for the {pic_type} component.')
# Remove duplicates and select the minimum value for conservative purpose
if maximum and minimum:
max_value = min(list(dict.fromkeys(maximum)))
min_value = max(list(dict.fromkeys(minimum)))
if (max_value is None and min_value is not None) or (min_value is None and max_value is not None):
max_value = None
min_value = None
limit_found = False
project.write_log(
f"WARNING: One of limits (max or min) value are not found/applicable for the shape set {shape_set} with "
f"material {material}in the scope {scope}. Both max and min limits are set to default as None, and results "
f"pictures are saved in the Non-standard materials sub-folder.")
return max_value, min_value, limit_found
### ===================================================================================================================
### 3. End of script
### ===================================================================================================================