Source code for viiapackage.strengthening.l4.l4b

### ===================================================================================================================
###   L4-B strengthening measure
### ===================================================================================================================
# Copyright ©VIIA 2024

### ===================================================================================================================
###   1. Import modules
### ===================================================================================================================

# General imports
from __future__ import annotations
from typing import TYPE_CHECKING, Union
from copy import deepcopy

# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.shapes import Wall
from rhdhv_fem.fem_tools import fem_axis_to_string
from rhdhv_fem.geometries import fem_get_profile_from_database
from rhdhv_fem.fem_shapes import fem_min_max_points
from rhdhv_fem.fem_math import fem_distance_coordinates, fem_unit_vector_2_points, fem_cross_product_vector, \
    fem_greater, fem_smaller

# References for functions and classes in the viiaPackage
from viiapackage.strengthening.helper_functions import viia_check_measure_in_gmc
if TYPE_CHECKING:
    from viiapackage.viiaStatus import ViiaProject
from viiapackage.shape_operations import viia_get_wall_horizontal_direction
from viiapackage.strengthening.helper_functions import viia_check_shape_argument, viia_find_wall_openings, \
    viia_sort_openings, viia_merge_openings, viia_find_min_max_z, viia_add_strengthening_shape


### ===================================================================================================================
###   2. Function to create L4-B strengthening measure
### ==================================================================================================================='

[docs]def viia_l4b( project: ViiaProject, variant: int, wall: Union[Wall, str], offset_bottom: float = 0.1, offset_top: float = 0.1, offset_left: float = 0.1, offset_right: float = 0.1): """ This function creates an L4-B-measure for a selected wall. It adds vertical steel columns (generally HEA100) with horizontal steel beams (generally IPE100), including eccentricity. It will model the columns and beams around wall openings with the specified offset. The wall should be vertical, but angled in horizontal plane is okay. Also, the top and bottom do not have to be straight. .. warning:: Function is currently not available, it requires updates, please send request to the VIIA automating team. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - variant (int): The variant number of the measure that is in the GMC. - wall (obj): The object reference of the wall that has to be strengthened. Alternative (str): Name of the wall to be strengthened. - offset_bottom (float): Not obligatory, default value is 0.1m. This is the offset of the steel beam to the bottom edge of the wall opening in [m]. - offset_top (float): Not obligatory, default value is 0.1m. This is the offset of the steel beam to the top edge of the wall opening in [m]. - offset_left (float): Not obligatory, default value is 0.1m. This is the offset of the steel column to the left edge of the wall opening in [m]. - offset_right (float): Not obligatory, default value is 0.1m. This is the offset of the steel column to the right edge of the wall opening in [m]. Output: - The strengthening measure is added to class of columns and beams and modelled in DIANA or SCIA. For example: >>> project.viia_l4b(project, wall, 0.3, 0.2, 0.1, 0) This example will apply the L4-B measure with vertical steel columns and horizontal steel beams around wall openings, for out-of-plane strengthening of Wall5 with bottom, top, left and right offset of 0.3, 0.2, 0.1 and 0 respectively. """ raise NotImplementedError("ERROR: Measure L4-B is currently not available, script needs updates.") # Argument handling wall = viia_check_shape_argument(project, wall, 'viia_l4b') # Check if measure is in GMC measure_type = 'L4-B' measure_sub_type = f"{measure_type}-{int(variant)}" viia_check_measure_in_gmc(project=project, measure_sub_type=measure_sub_type) # Find the length of the wall outer_dimensions_wall = fem_min_max_points(collection=[wall]) # Find starting number for column numbers nr_column = project.find_max_id(project.collections.columns) + 1 nr_beam = project.find_max_id(project.collections.beams) + 1 # Name, material and geometry to be used for strengthening measure # The eccentricity is set in direction of the outward normal vector of the wall. # Eccentricity is half the thickness of the wall and half of the column material_name = project.project_specific['strengthening_measures']['L4-B']['material'] material = None if material_name in [material.name for material in project.collections.materials]: for material in project.collections.materials: if material.name == material_name: break else: material = project.materials(project, material_name) outward_direction_vector = wall.outward_vector() # Geometries # Extract profile heights, which can differ for column and beam column_profile = project.project_specific['strengthening_measures']['L4-B']['column-profile'] column_height = fem_get_profile_from_database(data_name=column_profile)['height'] beam_profile = project.project_specific['strengthening_measures']['L4-B']['beam-profile'] beam_height = fem_get_profile_from_database(data_name=beam_profile)['height'] # Compute eccentricities column_eccentricity = fem_axis_to_string( [0, wall.geometry.geometry_model.thickness / 2 + column_height / 2, 0], project.rounding_precision) beam_eccentricity = fem_axis_to_string( [0, wall.geometry.geometry_model.thickness / 2 + beam_height / 2, 0], project.rounding_precision) # Create the geomerty objects column_geometry_name = 'KOLOM-' + column_profile if column_geometry_name not in [geometry.name for geometry in project.collections.geometries]: column_geometry = project.geometries(project, column_geometry_name) else: for geometry in project.collections.geometries: if geometry.name == column_geometry_name: column_geometry = geometry break beam_geometry_name = 'KOLOM-' + beam_profile if beam_geometry_name not in [geometry.name for geometry in project.collections.geometries]: beam_geometry = project.geometries(project, beam_geometry_name) else: for geometry in project.collections.geometries: if geometry.name == beam_geometry_name: beam_geometry = geometry break # # Compute element z axis with localAxis of geometryObject and outward normal vector # localZAxis = fem_cross_product_vector(viia_get_wall_horizontal_direction(project, wall), outward_direction_vector) # # # When the localAxis is defined from left to right seen from the inside, the ZAxis points up # # If this is not the case, use reversed localAxis # if (localZAxis[2] == 1): # localXAxis = geometryObject.localAxis # elif localZAxis[2] == -1: # localXAxis = fem_unit_vector([-geometryObject.localAxis[0], -geometryObject.localAxis[1], -geometryObject.localAxis[2]]) # Initiate element counters column_counter = 1 beam_counter = 1 # Find level of wall level = wall.name.split('-')[0] # Check for openings if wall.openings: # Find wall openings openings = viia_find_wall_openings(wall, viia_get_wall_horizontal_direction(project, wall)) # Sort openings with respect to localXAxis sorted_openings = viia_sort_openings(openings, viia_get_wall_horizontal_direction(project, wall)) # Merge overlapping openings, or openings that are to close to each other to put a column in between sorted_openings = viia_merge_openings( sorted_openings, localXAxis, 2 * project.project_specific['strengthening_measures']['L4-B']['minimum offset']) # Initiate container for columnPoints, which holds the x- and y-coordinates of column positions columnPoints = [] # Add first point, which is the point left to the first wall opening p1 = [0.0, 0.0, 0.0] for j in range(0, 3): p1[j] = sorted_openings[0][0][j] - localXAxis[j] * offset_left columnPoints.append(p1) if len(sorted_openings) > 1: mergecounter = 0 # Iterate through sortedOpenings # During each iteration, the distance between consecutive openings is considered, to determine whether and # where columns should be positioned for i in range(len(sorted_openings)-1): # Compute distance and unit vector between end point of current opening and start point of next opening distanceOpenings = fem_distance_coordinates(sorted_openings[i-mergecounter][1], sorted_openings[i+1-mergecounter][0]) # If distanceOpenings smaller than offsets + minDistance # Use only one column instead of two, for sortedOpenings that are close to each other if distanceOpenings < offset_left + offset_right + \ project.project_specific['strengthening_measures']['L4-B']['minimum distance']: # Compute p2, which is thus (approximately) in the middle of the two openings restDistance = distanceOpenings - offset_left - offset_right p2 = [0.0, 0.0, 0.0] for j in range(0, 3): p2[j] = sorted_openings[i-mergecounter][1][j] + (offset_right + restDistance / 2) * localXAxis[j] columnPoints.append(p2) # Else, sufficient space between consecutive sortedOpenings, put columns next to both openings else: # Compute p2 and p3, simply by using the specified offsets # p2 is the point right to the current opening p2 = [0.0, 0.0, 0.0] for j in range(0, 3): p2[j] = sorted_openings[i-mergecounter][1][j] + offset_right * localXAxis[j] columnPoints.append(p2) # p3 is the point left to the next opening p3 = [0.0, 0.0, 0.0] for j in range(0, 3): p3[j] = sorted_openings[i+1-mergecounter][0][j] - offset_left * localXAxis[j] columnPoints.append(p3) # Add last point, which is the point right to the last wall opening p4 = [0.0, 0.0, 0.0] for j in range(0, 3): p4[j] = sorted_openings[len(sorted_openings)-1][1][j] + offset_right * localXAxis[j] columnPoints.append(p4) # Iterate through columnPoints if len(columnPoints) > 1: for i in range(len(columnPoints)-1): x1Column = columnPoints[i][0] y1Column = columnPoints[i][1] x2Column = columnPoints[i+1][0] y2Column = columnPoints[i+1][1] # Initiate local minimum and maximum # Set equal to minimum and maximum for entire wall zmin = wallzmax zmax = wallzmin # Iterate through definitions of the wall openings, to compute local minima and maxima of Z between two consecutive columns for j in range(1, len(wall.points)): # Find coordinates of first point of opening x0 = wall.points[j][0][0] y0 = wall.points[j][0][1] # If X- and Y-coordinates between those of the columns, the entire wall opening must be also # x1Column, x2Column etc. are global coordinates, while a localXAxis is used # When the localXAxis is a negative vector, x1Column can be higher than x2Column # Here it is checked if x0 lies between xmin and xmax if ((x0 >= x1Column and x0 <= x2Column) or (x0 <= x1Column and x0 >= x2Column)) and \ ((y0 >= y1Column and y0 <= y2Column) or (y0 <= y1Column and y0 >= y2Column)): # Compute local minima and maxima for k in range(1, len(wall.points[j])): if fem_greater(zmin, wall.points[j][k][2]): zmin = wall.points[j][k][2] if fem_greater(wall.points[j][k][2], zmax): zmax = wall.points[j][k][2] # If values not adjusted during loop, no openings between current and next column if zmin == wallzmax and zmax == wallzmin: continue # Get columnPoints p1 = columnPoints[i] p2 = columnPoints[i+1] # Check if x- and y-coordinates of columns are within wall, otherwise continue, no columns or beams are added if not (wallxmax >= p1[0] >= wallxmin and wallymax >= p1[1] >= wallymin and wallxmax >= p2[0] >= wallxmin and wallymax >= p2[1] >= wallymin): continue # Find bottom and top intersection of column with wall intersections1 = sorted(viia_find_min_max_z(wall.points[0], p1)) intersections2 = sorted(viia_find_min_max_z(wall.points[0], p2)) # Compute bottom and top point of column p1bottom = deepcopy(p1) p1top = deepcopy(p1) p1bottom[2] = intersections1[0] p1top[2] = intersections1[-1] points1 = [p1bottom, p1top] # Compute vector between start and end point column column1vector = fem_unit_vector_2_points(p1bottom, p1top) # Find cross product with normal vector of wall (which is equal to the local Y-axis) # The cross product is the local Z-axis localZAxisvector = fem_cross_product_vector(column1vector, normalVector) localZAxis = '(' + str(localZAxisvector[0]) + ', ' + str(localZAxisvector[1]) + ', ' + \ str(localZAxisvector[2]) + ')' # Set geometry name of column, this name is equal for all columns of the wall geometryNameColumn = 'KOLOM-' + \ project.project_specific['strengthening_measures']['L4-B']['column-profile'] + \ '-' + localZAxis + '-' + eccentricitycolumn # Loop through columns to check if column left of opening has already been created in previous loop # This is possible when one column is applied between two wall openings firstcolumncreated = False for column_object in project.collections.columns: if column_object.points == points1: firstcolumncreated = True break # Create column if not firstcolumncreated: namecolumn1 = level + '-KOLOMMEN-L4B-' + materialName + '-' + \ project.project_specific['strengthening_measures']['L4-B']['column-profile'] + \ '-' + str(maxColumnNr + column_counter) column = project.create_column( namecolumn1, project.create_line(points1), materialName, geometryNameColumn) column_counter += 1 viia_add_strengthening_shape(shape=wall, strengthening_shape=column) # Compute bottom and top point of column p2bottom = deepcopy(p2) p2top = deepcopy(p2) p2bottom[2] = intersections2[0] p2top[2] = intersections2[-1] points2 = [p2bottom, p2top] # Create column namecolumn2 = level + '-KOLOMMEN-L4B-' + materialName + '-' + \ project.project_specific['strengthening_measures']['L4-B']['column-profile'] +\ '-' + str(maxColumnNr + column_counter) column = project.create_column(namecolumn2, project.create_line(points2), materialName, geometryNameColumn) column_counter += 1 viia_add_strengthening_shape(shape=wall, strengthening_shape=column) # Compute start and end point beam ptop1 = deepcopy(p1) ptop1[2] = zmax + offset_top ptop2 = deepcopy(p2) ptop2[2] = zmax + offset_top pointstop = [ptop1, ptop2] # Compute vector between start and end point beam beamtopvector = fem_unit_vector_2_points(ptop1, ptop2) # Find cross product with normal vector of wall (which is equal to the local Y-axis) # The cross product is the local Z-axis localZAxisvector = fem_cross_product_vector(beamtopvector, normalVector) localZAxis = '(' + str(localZAxisvector[0]) + ', ' + str(localZAxisvector[1]) + ', ' + str( localZAxisvector[2]) + ')' # Set geometry name of beam, this name is equal for all beams of the wall geometryNameBeam = 'BALK-' +\ project.project_specific['strengthening_measures']['L4-B']['beam-profile'] + \ '-' + localZAxis + '-' + eccentricitybeam # Create top beam if it not lies above the wall if fem_smaller(ptop1[2], intersections1[1]) and fem_smaller(ptop2[2], intersections1[1]): namebeamtop = level + '-BALKEN-L4B-' + materialName + '-' +\ project.project_specific['strengthening_measures']['L4-B']['beam-profile'] + \ '-' + str(maxBeamNr + beam_counter) beam = project.create_beam(namebeamtop, project.create_line(pointstop), materialName, geometryNameBeam) beam_counter += 1 viia_add_strengthening_shape(shape=wall, strengthening_shape=beam) # Compute start and end point beam pbottom1 = deepcopy(p1) pbottom1[2] = zmin - offset_bottom pbottom2 = deepcopy(p2) pbottom2[2] = zmin - offset_bottom pointsbottom = [pbottom1, pbottom2] # Create bottom beam if it not lies below the wall if fem_greater(pbottom1[2], intersections1[0]) and fem_greater(pbottom2[2], intersections2[0]): namebeambottom = level + '-BALKEN-L4B-' + materialName + '-' + \ project.project_specific['strengthening_measures']['L4-B']['beam-profile'] +\ '-' + str(maxBeamNr + beam_counter) beam = project.create_beam( namebeambottom, project.create_line(pointsbottom), materialName, geometryNameBeam) beam_counter += 1 viia_add_strengthening_shape(shape=wall, strengthening_shape=beam) # Update wall attribute with strengthening measure if column_counter > 1: wall.add_meta_data({'strengthening': measure_sub_type}) # Notifications for user project.write_log( f"L4-B measure applied on wall {wall.name}, number of applied columns: {column_counter - 1}, " f"number of applied beams: {beam_counter - 1}.") else: # Notifications for user project.write_log(f"L4-B measure not applied on wall {wall.name}.")
### =================================================================================================================== ### 3. End of script ### ===================================================================================================================