### ===================================================================================================================
### Function to get the properties of the geometry-model
### ===================================================================================================================
# Copyright ©VIIA 2024
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
import math
from typing import TYPE_CHECKING, Dict, Union
from copy import deepcopy
# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.fem_config import Config
from rhdhv_fem.geometries import fem_get_profile_from_database
# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
### ===================================================================================================================
### 2. Get the geometry-model properties based on geomtery-name and geometry-group
### ===================================================================================================================
[docs]def viia_get_geometry_model_properties(
project: ViiaProject, geometry_name: str, geometry_group: str) -> Dict[str, Union[str, float, int]]:
"""
This function collects the geometry-model properties, based on the geometry name according to VIIA naming
conventions.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- geometry_name (str): Name of the element geometry.
- geometry_group (str): Name of the geometry-group.
Output:
- Returns a dictionary with the properties for the geometry model.
"""
# Initialise the output dictionaries
geometry_model = dict()
geometry_model_properties = dict()
# Geometry models for volumes
if geometry_group == 'volumes':
if not geometry_model:
if 'RUBBER' in geometry_name:
geometry_model['model'] = 'rubber solid elements'
else:
geometry_model['model'] = 'regular structural solids elements'
# Geometry models for surfaces
elif geometry_group == 'surfaces':
if not geometry_model:
if 'FOS' in geometry_name:
geometry_model['model'] = 'structural surface interface elements'
elif 'VLOERHBV' in geometry_name or 'WANDHSB' in geometry_name:
geometry_model['model'] = 'regular flat shell elements'
else:
geometry_model['model'] = 'regular curved shell elements'
if geometry_model['model'] in [
'flat plate elements', 'regular flat shell elements', 'flat shell with drilling dof']:
geometry_model['orthotropic thickness'] = False
if geometry_model['model'] in [
'regular curved shell elements', 'curved shell with drilling dof', 'layered shell elements',
'layered shell with drilling dof', 'structural surface interface elements']:
geometry_model['underlying geometry'] = False
if geometry_model['model'] == 'boundary surface elements':
geometry_model['free field specifications'] = False
# Geometry models for surface reinforcements
elif geometry_group == 'surface-reinforcements':
geometry_model['model'] = 'grid reinforcement'
if 'CFRPMESH' in geometry_name:
geometry_model['thickness'] = 'direct input'
else:
geometry_model['thickness'] = 'diameter and spacing'
# Geometry models for lines
elif geometry_group == 'lines':
if not geometry_model:
if 'STAAF' in geometry_name:
geometry_model['model'] = '3d is_simplified truss element'
elif 'DISCREET' in geometry_name:
geometry_model['model'] = 'distributed line mass'
else:
geometry_model['model'] = '3d class-iii beam elements'
if geometry_model['model'] == '3d class-i beam elements':
geometry_model['cross-section definition type'] = 'predefined profiles'
if geometry_model['model'] in [
'3d class-ii beam elements', '3d class-iii beam elements', '3d is_simplified truss element',
'distributed line mass'] or (geometry_model['model'] == '3d class-i beam elements' and
geometry_model['cross-section definition type'] == 'predefined profiles'):
geometry_model_properties = _viia_cross_section_shape(project, geometry_name)
if geometry_model['model'] == '3d line interface elements (2 normal, 1 shear)':
geometry_model['line geometry'] = 'diameter'
if geometry_model['model'] == 'shell line interface elements':
geometry_model['shape definition type'] = 'flat'
# Geometry models for line reinforcements without bond slip
elif geometry_group == 'line-reinforcements':
geometry_model['model'] = 'bar reinforcement'
geometry_model['reinforcement type'] = 'embedded'
# Geometry models for line reinforcements with bond slip
elif geometry_group == 'line-reinforcements-with-bondslip':
geometry_model['model'] = 'bar reinforcement'
geometry_model['reinforcement type'] = 'truss bondslip'
# Geometry models for points
elif geometry_group == 'points':
if not geometry_model:
if 'ROTVEER' in geometry_name:
geometry_model['model'] = 'rotation springs/dashpots'
elif 'PUNTIF' in geometry_name:
geometry_model['model'] = '3d point interface'
elif 'PUNTMASSA' in geometry_name:
geometry_model['model'] = '3d point mass'
else:
geometry_model['model'] = 'translation springs/dashpots'
# Create the geometry dictionary
geometry_model_properties = {**deepcopy(geometry_model), **geometry_model_properties}
# Extend properties with some additional information for shells and reinforcement
geometry_model_properties = \
_viia_extend_geometry_model_properties(
project=project, geometry_name=geometry_name, geometry_model_properties=geometry_model_properties)
# Return the variable with the geometry_model with all options selected
return geometry_model_properties
[docs]def _viia_cross_section_shape(project: ViiaProject, geometry_name: str) -> Dict[str, Union[str, float, int]]:
"""
This function filters the cross-sectional properties from the name of the geometry. The function will retrieve the
properties for class I, class II and class III beams.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- geometry_name (str): Name of the element geometry of a line element.
Output:
- A dictionary is returned with the key 'shape' indicating the type of cross-section and the other entries are
the cross-sectional dimensions, depending on the type of shape.
"""
# Note that the order of the section checks is important
# Isolate the profile specifications in geometry name
# Example of expected name: 'KOLOM-R70-(1,0,0)'
geometry = '-'.join(geometry_name.split('-')[1:]).split('-(')[0]
if 'LIJNMASSA' in geometry_name:
if 'DISCREET' in geometry_name:
return {'predefined': False, 'class': 'LineMassGM'}
return {
'predefined': False,
'profile_name': project.project_specific['dummy_profile_linemass'],
'class': 'Rectangle',
'height': project.project_specific['dummy_dimension_linemass'],
'width': project.project_specific['dummy_dimension_linemass']}
# If geometry in database, only return as profile name in shape dictionary
if fem_get_profile_from_database(data_name=geometry) is not None:
return {
'predefined': True,
'profile_name': geometry}
# The section is not in the database and should be retrieved by the properties in the name (VIIA naming convention)
shape_dictionary = {
'predefined': False,
'profile_name': deepcopy(geometry)}
geometry = geometry.lower()
# Check for truss-shapes sections
# Example of expected geometry_name: 'STAAF-10000'
if 'staaf' in geometry_name.lower():
shape_dictionary['class'] = 'TrussProfile'
geometry = geometry.replace('o', '').replace('staaf', '')
shape_dictionary['cross-section'] = float(geometry) / 1000000
return shape_dictionary
# Check for L-shapes sections
elif 'l' in geometry:
shape_dictionary['class'] = 'LShape'
# Naming convention is: 'L30x30x5' or 'L30x30x5x8'
# Dimensions in geometry name are in [mm], these are converted to [m]
geometry = [int(float(dim)) / 1000 for dim in geometry.replace('l', '').split('x')]
# Determine the properties based on the number of items seperated by 'x'
if len(geometry) == 2:
# If only 2 dimensions are given: body and leg have same thickness and length, e.g. 'L30x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[0]
shape_dictionary['thickness_flange_bottom'] = geometry[1]
shape_dictionary['thickness_left_leg'] = geometry[1]
elif len(geometry) == 3:
# If only 3 dimensions are given: body and leg have same thickness, e.g. 'L30x30x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[1]
shape_dictionary['thickness_flange_bottom'] = geometry[2]
shape_dictionary['thickness_left_leg'] = geometry[2]
elif len(geometry) == 4:
# If 4 dimensions are given: all required dimensions are specified, e.g. 'L30x30x5x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[1]
shape_dictionary['thickness_flange_bottom'] = geometry[2]
shape_dictionary['thickness_left_leg'] = geometry[3]
else:
# Error if parameters are not clear
raise ValueError(
f"ERROR: A L-shape section is detected, but parameters are unknown for geometry: {geometry_name}.")
# Return the dictionary with geometrical properties of the L-shape
return shape_dictionary
# Check for T-shapes sections
elif 't' in geometry:
shape_dictionary['class'] = 'TShape'
# Naming convention is: 'T20x20x3' or 'T20x20x3x5'
# Dimensions in geometry name are in [mm], these are converted to [m]
geometry = [int(float(dim)) / 1000 for dim in geometry.replace('t', '').split('x')]
# Determine the properties based on the number of items seperated by 'x'
if len(geometry) == 2:
# If only 2 dimensions are given: body and leg have same thickness and length, e.g. 'T20x3'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width_flange_top'] = geometry[0]
shape_dictionary['thickness_flange_top'] = geometry[1]
shape_dictionary['thickness_web'] = geometry[1]
elif len(geometry) == 3:
# If only 3 dimensions are given: body and leg have same thickness, e.g. 'T20x20x3'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width_flange_top'] = geometry[1]
shape_dictionary['thickness_flange_top'] = geometry[2]
shape_dictionary['thickness_web'] = geometry[2]
elif len(geometry) == 4:
# If 4 dimensions are given: all required dimensions are specified, e.g. 'T20x20x3x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width_flange_top'] = geometry[1]
shape_dictionary['thickness_flange_top'] = geometry[2]
shape_dictionary['thickness_web'] = geometry[3]
else:
# Error if parameters are not clear
raise ValueError(
f"ERROR: A T-shape section is detected, but parameters are unknown for geometry: {geometry_name}.")
# Return the dictionary with geometrical properties of the T-shape
return shape_dictionary
# Check for circular hollow sections (or tube)
elif ('d' in geometry or 'rd' in geometry or 'chs' in geometry) and 'x' in geometry:
shape_dictionary['class'] = 'Pipe'
# Naming convention is: 'D40x4', 'RD40x4' or 'CHS193.7x7.1'
# Dimensions in geometry name are in [mm], these are converted to [m]
geometry = [
int(float(dim)) / 1000
for dim in geometry.replace('rd', '').replace('d', '').replace('chs', '').split('x')]
# Determine the properties based on the number of items seperated by 'x'
if len(geometry) == 2:
# If 2 dimensions are given: all required dimensions are specified, e.g. 'D40x4'
shape_dictionary['diameter'] = geometry[0]
shape_dictionary['thickness'] = geometry[1]
else:
# Error if parameters are not clear
raise ValueError(
f"ERROR: A hollow shape section (tube) is detected, but parameters are unknown for geometry: "
f"{geometry_name}.")
# Return the dictionary with geometrical properties of the tube shape
return shape_dictionary
# Check for square hollow sections (or rectangular box)
elif geometry[0] == 'k' or geometry[:3] == 'rhs':
shape_dictionary['class'] = 'Box'
# Naming convention is 'K40x40x3' or 'K40x40x3x5' or 'RHS193.7x7.1'
# Indication of cold formed profiles is removed ('CF')
# Dimensions in geometry name are in [mm], these are converted to [m]
geometry = [
int(float(dim)) / 1000
for dim in geometry.replace('k', '').replace('rhs', '').replace('cf', '').split('x')]
# Determine the properties based on the number of items seperated by 'x'
if len(geometry) == 2:
# If only 2 dimensions are given: bodies and flanges have same height and thickness, e.g. 'K30x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[0]
shape_dictionary['thickness_flange_top'] = geometry[1]
shape_dictionary['thickness_flange_bottom'] = geometry[1]
shape_dictionary['thickness_left_web'] = geometry[1]
shape_dictionary['thickness_right_web'] = geometry[1]
elif len(geometry) == 3:
# If only 3 dimensions are given: bodies and flanges have same thickness, e.g. 'K40x30x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[1]
shape_dictionary['thickness_flange_top'] = geometry[2]
shape_dictionary['thickness_flange_bottom'] = geometry[2]
shape_dictionary['thickness_left_web'] = geometry[2]
shape_dictionary['thickness_right_web'] = geometry[2]
elif len(geometry) == 4:
# If only 4 dimensions are given: thickness of flanges and of web are equal, e.g. 'K50x30x10x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[1]
shape_dictionary['thickness_flange_top'] = geometry[2]
shape_dictionary['thickness_flange_bottom'] = geometry[2]
shape_dictionary['thickness_left_web'] = geometry[3]
shape_dictionary['thickness_right_web'] = geometry[3]
elif len(geometry) == 6:
# If all6 dimensions are given: all required dimensions are specified, e.g. 'K50x30x12x10x8x5'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[1]
shape_dictionary['thickness_flange_top'] = geometry[2]
shape_dictionary['thickness_flange_bottom'] = geometry[3]
shape_dictionary['thickness_left_web'] = geometry[4]
shape_dictionary['thickness_right_web'] = geometry[5]
else:
# Error if parameters are not clear
raise ValueError(
f"ERROR: A rectangular box (hollow square section) is detected, but parameters are unknown "
f"for geometry: {geometry_name}.")
# Return the dictionary with geometrical properties of the rectangular box shape
return shape_dictionary
# Check for circular sections (or bar)
elif 'd' in geometry or 'r' in geometry or 'rd' in geometry:
shape_dictionary['class'] = 'CircleProfile'
# Naming convention is: 'D10' or 'RD280'
geometry = geometry.replace('d', '').replace('r', '')
# Dimensions in geometry name are in [mm], these are converted to [m]
try:
shape_dictionary['diameter'] = int(float(geometry)) / 1000
except ValueError:
# Error if parameters are not clear
print(f"ERROR: A circular cross-section is detected, but parameters are unknown for geometry: "
f"{geometry_name}.")
raise
# Return the dictionary with geometrical properties of the circular cross-section shape
return shape_dictionary
# Check for rectangular sections
elif geometry.count('x') == 1 or geometry.isdigit():
shape_dictionary['class'] = 'Rectangle'
# Naming convention is '500x400'
# Dimensions in geometry name are in [mm], these are converted to [m]
geometry = [int(float(dim)) / 1000 for dim in geometry.split('x')]
# Determine the properties based on the number of items seperated by 'x'
if len(geometry) == 1:
# If only 1 dimension is given: height and width are equal, e.g. '400'
shape_dictionary['height'] = geometry[0]
shape_dictionary['width'] = geometry[0]
elif len(geometry) == 2:
# If 2 dimensions are given: all required dimensions have been specified, e.g. '500x400'
shape_dictionary['width'] = geometry[0]
shape_dictionary['height'] = geometry[1]
else:
# Error if parameters are not clear
raise ValueError(
f"ERROR: A rectangular section is detected, but parameters are unknown for geometry: {geometry_name}.")
# Return the dictionary with geometrical properties of the rectangular shape
return shape_dictionary
else:
# Profile is not (clearly) defined, notification is given
project.write_log(f"ERROR: {geometry_name} profile is not defined properly.")
shape_dictionary['class'] = 'unknown'
# Return the dictionary with geometrical properties of the shape
return shape_dictionary
[docs]def _viia_extend_geometry_model_properties(
project: ViiaProject, geometry_name: str, geometry_model_properties: Dict[str, Union[str, float, int]]) \
-> Dict[str, Union[str, float, int]]:
"""
This function extends the geometry properties dictionary for additional information for orthotropic surfaces and
reinforcements.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- geometry_name (str): Name of the element geometry of a line element.
- geometry_model_properties (dict): Dictionary with the geometry properties, which will be extended.
Output:
- The dictionary with geometry properties is returned with the added keys for shell or reinforcement.
"""
if geometry_model_properties['model'] == 'regular curved shell elements' or \
geometry_model_properties['model'] == 'curved shell with drilling dof' or \
geometry_model_properties['model'] == 'layered shell elements' or \
geometry_model_properties['model'] == 'layered shell with drilling dof':
if geometry_name in ['RIB-FLEVO-VLOER', 'RIB-CVP-VLOER', 'RIB-OMNIA-VLOER']:
material_name = 'LIN-' + geometry_name.replace('-VLOER', '')
geometry_model_properties['thickness'] = \
project.viia_get_material(material_name, 'LinearOrthotropic')['thickness']
else:
geometry_model_properties['thickness'] = float(geometry_name.split('-')[1]) / 1000
elif geometry_model_properties['model'] == 'regular flat shell elements':
geometry_model_properties['shape factor'] = 1
thickness = float(geometry_name.split('(')[0].split('-')[1]) / 1000 # Example name 'VLOERHBV-30.5-(1,0,0)'
geometry_model_properties['orthotropic thickness'] = thickness
geometry_model_properties['thickness'] = thickness
elif geometry_model_properties['model'] == 'grid reinforcement':
# Check for type of rebar
if 'CFRPMESH' in geometry_name:
# Example: 'WANDEN-L5P-CFRPMESH'
geometry_model_properties['equivalent_thickness_x'] =\
project.project_specific['strengthening_measures']['L5-P']['vertical_mesh']
geometry_model_properties['equivalent_thickness_y'] =\
project.project_specific['strengthening_measures']['L5-P']['horizontal_mesh']
else:
# Find part of geometry_name in which the reinforcement is defined
geometry_name_split = geometry_name.split('-')
# Example: 'R12_150xR12_150' (horizontal x vertical)
rebar = None
for i in range(0, len(geometry_name_split)-1):
if 'WAP' in geometry_name_split[i]:
rebar = geometry_name_split[i + 1]
break
horizontal_rebar = rebar.split('x')[0]
vertical_rebar = rebar.split('x')[1]
if horizontal_rebar[0] == 'R':
number_of_bars_horizontal = 1
else:
number_of_bars_horizontal = int(horizontal_rebar.split('R')[0])
if vertical_rebar[0] == 'R':
number_of_bars_vertical = 1
else:
number_of_bars_vertical = int(vertical_rebar.split('R')[0])
diameter_horizontal = float(horizontal_rebar.split('R')[1].split('_')[0]) / 1000
diameter_vertical = float(vertical_rebar.split('R')[1].split('_')[0]) / 1000
# Round equivalent diameter with check_precision, which is more precise than round_precision.
equivalent_diameter_horizontal = \
round(math.sqrt(number_of_bars_horizontal * diameter_horizontal ** 2), Config.CHECK_PRECISION)
equivalent_diameter_vertical = \
round(math.sqrt(number_of_bars_vertical * diameter_vertical ** 2), Config.CHECK_PRECISION)
geometry_model_properties['bar_diameter_x'] = equivalent_diameter_horizontal
geometry_model_properties['bar_diameter_y'] = equivalent_diameter_vertical
geometry_model_properties['spacing_x'] = \
round(float(horizontal_rebar.split('_')[1]) / 1000, Config.CHECK_PRECISION)
geometry_model_properties['spacing_y'] = \
round(float(vertical_rebar.split('_')[1]) / 1000, Config.CHECK_PRECISION)
elif geometry_model_properties['model'] == 'bar reinforcement':
# Adding properties for CFRPSTRIP
if 'CFRPSTRIP' in geometry_name:
strip_section = geometry_name.split('-')[-1]
geometry_model_properties['truss_name'] = geometry_name
geometry_model_properties['cross_section_area'] = \
project.project_specific['strengthening_measures']['L4-O']['cross section'][strip_section]
geometry_model_properties['contact_perimeter'] = \
project.project_specific['strengthening_measures']['L4-O']['contact perimeter'][strip_section]
# Returns the updated parameters in the geometry dictionary
return geometry_model_properties
### ===================================================================================================================
### 3. End of script
### ===================================================================================================================