### ===================================================================================================================
### Functions to get the reference object models from MYVIIA
### ===================================================================================================================
# Copyright ©VIIA 2024
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
from pathlib import Path
from datetime import datetime
from typing import TYPE_CHECKING, List, Optional
# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.fem_tools import fem_create_folder
# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
from viiapackage.reference_approach.reference_wall.ref_wall_ip import RefWallIP
from viiapackage.reference_approach.reference_wall.ref_wall_oop import RefWallOOP
# References for openpyxl functions
from openpyxl import load_workbook
from openpyxl.utils.cell import get_column_letter
### ===================================================================================================================
### 2. Collect data for the In-Plane failure checks
### ===================================================================================================================
[docs]def viia_generate_ref_ip_data(obj_vs_measures: dict, ref_models: dict) -> List[RefWallIP]:
"""
Function to generate the required data for the in-plane failure mechanism according the Reference Approach.
Input:
- obj_vs_measures (dict): Dictionary with object parts and the applied measures
- ref_models (dict): Dictionary with reference models that need to be considered.
Output:
- Returns a tuple, first is a list of instances of RefWallIP with data and scores per wall. The second item
is the current wall as instance of CurrentWall.
"""
# Raise error if no reference models were loaded in
if not ref_models:
raise ValueError("ERROR: No reference models available for the in-plane failure check.")
# Collect all walls of all reference objects with models in a list
total_wall_list = []
for ref_model in ref_models.values():
subproject = ref_model['model']
measures = obj_vs_measures[f"{ref_model['object']} - {ref_model['object_part']}"]
for wall in subproject.collections.walls:
total_wall_list.append(RefWallIP(wall=wall, measures=measures))
# Returns the list in data structure for reporting and include the current wall
return total_wall_list
### ===================================================================================================================
### 3. Collect data for the Out-of-Plane failure checks
### ===================================================================================================================
[docs]def viia_generate_ref_oop_data(obj_vs_measures: dict, ref_models: dict) -> List[RefWallOOP]:
"""
Function to generate the required data for the out-of-plane failure mechanism according the Reference Approach.
Input:
- obj_vs_measures (dict): Dictionary with object parts and the applied measures
- ref_models (dict): Dictionary with reference models that need to be considered.
Output:
- Returns a tuple, first is a list of instances of RefWallOOP with data and scores per wall. The second item
is the current wall as instance of CurrentWall.
"""
# Raise error if no reference models were loaded in
if not ref_models:
raise ValueError("ERROR: No reference models available for the out-of-plane failure check.")
# Collect all walls of all reference objects with models in a list
total_wall_list = []
for ref_model in ref_models.values():
subproject = ref_model['model']
measures = obj_vs_measures[f"{ref_model['object']} - {ref_model['object_part']}"]
for wall in subproject.collections.walls:
segments = wall.get_segments()
if segments is None or len(segments) == 0:
# Skip any non-complying walls
continue
if len(segments) == 1:
total_wall_list.append(RefWallOOP(wall=wall, measures=measures, segment_width=segments[0]))
continue
for i, segment in enumerate(segments):
total_wall_list.append(RefWallOOP(wall=wall, measures=measures, segment_width=segment, segment_nr=i+1))
# Returns the list in data structure for reporting and include the current wall
return total_wall_list
### ===================================================================================================================
### 4. Create and fill excel for In-Plane and Out-of-Plane failure checks
### ===================================================================================================================
[docs]def viia_generate_ref_report(
project: ViiaProject, wall_data: List[dict], failure_mechanism: str,
output_folder: Optional[Path] = None) -> Path:
"""
This function creates an excel-sheet with a (sorted) list of all walls in the referenced object models.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- wall_data (list of obj): List of data about the walls in the reference objects, including the current wall at
first position.
- failure_mechanism (str): The type of report required. Possible options are 'IP' and 'OOP'.
- output_folder (Path): Optional input for location where to create the report. Default value is None,
indicating the default location is used. In normal production objects do not change this!
Output:
- Creates an excel-sheet with the detailed data of the walls in the reference objects, ranked by comparison to
the current wall that is being investigated
"""
# Collect template file
template_location = None
if failure_mechanism == 'IP':
template_location = project.viia_settings.project_specific_package_location / 'reference_approach' / \
'templates' / 'VIIA_Template_REF_in_plane_20221130.xlsx'
elif failure_mechanism == 'OOP':
template_location = project.viia_settings.project_specific_package_location / 'reference_approach' / \
'templates' / 'VIIA_Template_REF_out_of_plane_20230125.xlsx'
if not template_location.exists():
raise FileNotFoundError(
f"ERROR: REF template file could not be found in expected location "
f"'{template_location.as_posix()}'. Please provide it manually to generate this report.")
# Create or check the location where the report is to be generated
if output_folder is None:
# Create subfolder
fem_create_folder('ER', ref_folder=project.workfolder_location)
report_location = project.workfolder_location / 'ER'
else:
if isinstance(output_folder, str):
output_folder = Path(output_folder)
report_location = output_folder
# Check if output-folder is created
if not report_location.exists():
raise FileNotFoundError("ERROR: The specified output-folder does not exist, please check input.")
# Generate the report
time_reference = datetime.now().strftime('%Y%m%d%H%M%S')
document_name = 'REF-IP' if failure_mechanism == 'IP' else 'REF-OOP'
output_document_name = f"VIIA-{project.name}-{document_name}-{time_reference}.xlsx"
target_file = report_location / output_document_name
# Writing to excel
wb = load_workbook(template_location)
ws = wb.worksheets[0]
# Fill in header
ws['C2'] = project.project_information['objectnummer_viia']
ws['C3'] = f"{project.project_information['objectdeel']} ({project.project_information['analysis_subtype']})"
ws['C4'] = datetime.now()
# Collect table object
table = ws.tables['WallsInPlane'] if failure_mechanism == 'IP' else ws.tables['WallsOutofPlane']
# Set up top left cell
top_left_cell = table.ref.split(':')[0] # table.ref looks like 'A5:AD17'
top_left_row = ""
for ch in top_left_cell:
if not ch.isalpha():
top_left_row += ch # Removes the column letters from the top left cell string
top_left_row = int(top_left_row)
# Set up bottom right cell
bottom_right_cell = table.ref.split(':')[1]
bottom_right_column = ""
for ch in bottom_right_cell:
if ch.isalpha():
bottom_right_column += ch # Removes the row numbers from the bottom right cell string
# Table length is header + current wall + reference walls + totals column
bottom_right_cell = bottom_right_column + str(top_left_row + 1 + len(wall_data) + 1)
# Set up new table size
table.ref = f"{top_left_cell}:{bottom_right_cell}"
# Loop over data entries of the reference objects and fill in template
row_pointer = top_left_row
for data_entry in wall_data:
row_pointer += 1
for k, v in data_entry.items():
if k in table.column_names:
if isinstance(v, list) and len(v) == 0:
ws[get_column_letter(table.column_names.index(k) + 1) + str(row_pointer)] = '-'
elif isinstance(v, list):
try:
ws[get_column_letter(table.column_names.index(k) + 1) + str(row_pointer)] = (', '.join(v))
except TypeError:
ws[get_column_letter(table.column_names.index(k) + 1) + str(row_pointer)] = str(v)
else:
ws[get_column_letter(table.column_names.index(k) + 1) + str(row_pointer)] = v
# Save the target excel file
wb.save(target_file)
excel_sheet = 'in-plane' if failure_mechanism == 'IP' else 'out-of-plane'
project.write_log(
f"Successfully created {excel_sheet} excel-sheet for reference approach at '{target_file.as_posix()}'.")
return target_file
### ===================================================================================================================
### 5. End of script
### ===================================================================================================================