### ===================================================================================================================
### 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
### ===================================================================================================================