Source code for viiapackage.general.viia_cost_key_figures
### ===================================================================================================================
### MYVIIA handling cost key figures
### ===================================================================================================================
# Copyright ©VIIA 2024
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
import os
from pathlib import Path
from datetime import date, datetime
from openpyxl import load_workbook
from typing import TYPE_CHECKING, List, Union, Dict
# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.fem_tools import fem_find_object
from rhdhv_fem.shapes import Wall, Roof, Fstrip
from rhdhv_fem.fem_math import fem_greater
# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
from viiapackage.database import myviia_get_cost, myviia_post_cost
### ===================================================================================================================
### 2. Compute the cost key figures from the model
### ===================================================================================================================
[docs]def viia_compute_cost_key_figures(
project: ViiaProject, facade_list: List[Union[str, Wall]] = None) -> Dict[str, Union[float, int]]:
"""
This function computes the cost key figures required by the cost engineer (at request of the client).
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- facade_list (list of obj): List with names or object references of the wall objects that should be considered
facades of the building structure. Default value is None, the area of the facade and the opening area of the
facade are not computed.
Output:
- Returns a dictionary containing the following information:
- BVO: Area of all the modelled floors (no fstrip and roofs), excluding the openings > 5m2, in [m2].
- BBO: Area of all the modelled ground floors, in [m2].
- BGO: Area of the facade including the openings, in [m2].
- OGO: Area of the openings in the facade, in [m2].
- BBWO: Area of the inner walls including the openings, in [m2].
- BDO: Area of all the modelled roofs including the openings, in [m2].
- ODO: Area of all the openings in the modelled roofs, in [m2].
"""
key_figures = {}
# Calculate BVO
area = 0
for floor in [floor for floor in project.collections.floors
if not isinstance(floor, Roof) and not isinstance(floor, Fstrip)]:
area += floor.contour.get_area()
if floor.openings:
for opening in floor.openings:
if fem_greater(opening.get_area(), 5):
area -= opening.get_area()
key_figures['BVO'] = area
# Calculate OBG
area = 0
for floor in [floor for floor in project.collections.floors if 'N0' in floor.name]:
area += floor.contour.get_area()
key_figures['BBO'] = area
# Calculate BGO & OGO
area = 0
area_openings = 0
if facade_list:
for i, wall in enumerate(facade_list):
if type(wall) == str:
wall = fem_find_object(wall, project.collections.walls)
if wall:
area += wall.contour.get_area()
if wall.openings:
for opening in wall.openings:
area_openings += opening.get_area()
else:
project.write_log(
f"WARNING: Wall in facadelist '{facade_list[i]}' of viia_create_cost_key_figures is not "
f"recognised. Please check input.")
key_figures['BGO'] = area
key_figures['OGO'] = area_openings
# Calculate BDO & ODO
area = 0
area_openings = 0
if facade_list:
for roof in project.collections.roofs:
area += roof.contour.get_area()
if roof.openings:
for opening in roof.openings:
area_openings += opening.get_area()
key_figures['BDO'] = area
key_figures['ODO'] = area_openings
return key_figures
### ===================================================================================================================
### 3. Send cost key figures to MYVIIA
### ===================================================================================================================
[docs]def viia_send_cost_key_figures_to_myviia(
project: ViiaProject, data: Dict[str, Union[float, int]]) -> Dict[str, Union[int, float, str]]:
"""
Function to send cost key figures to MYVIIA. It checks if there is already an existing record and if that record
needs to be updated. In that case a new record is added.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- data (dict): Dictionary with the cost key figures, the keys 'BVO', 'BBO', 'BGO', 'OGO', 'BDO' and 'ODO'
should be present in this dictionary. The values should be floats, in [m2].
Output:
- Compares and posts new values to MYVIIA.
- Notifications of the process are provided.
- Returns the response of the post in case the values on MYVIIA have been updated. If not, None is returned.
"""
# Check if data is complete
if not {'BVO', 'BBO', 'BGO', 'OGO', 'BDO', 'ODO'}.issubset(data):
raise ValueError(f"ERROR: Data for excel cost key figures is incomplete: {', '.join(data.keys())}.")
# Convert data for MYVIIA (lowercase keys)
data = {k.lower(): v for k, v in data.items()}
# Get the current information from MYVIIA
myviia_data = myviia_get_cost(object_deel_id=project.get_myviia_object_deel_id(), token=project.token)
# Get the date of today in isoformat
current_date = f"{datetime.now().isoformat()}Z"
# Check the status on MYVIIA
post_response = None
if not myviia_data:
# No previous data on MYVIIA, create new record
post_response = myviia_post_cost(
data={'object_deel_id': project.get_myviia_object_deel_id(), 'date': current_date, **data},
token=project.token).json()
project.write_log(
f"Cost key-figures sent to MYVIIA: {', '.join([f'{k} = {round(v, 2)} m2' for k, v in data.items()])}.")
# Data already present on MYVIIA
else:
# Get the latest record and replace None items by 0.0
myviia_data = sorted(myviia_data, key=lambda d: (d['date'], d['id']))[-1]
for k, v in myviia_data.items():
if k.upper() in data and v is None:
myviia_data[k] = 0.0
# Check if any value needs to be updates
updating = {k: [v, myviia_data[k.lower()]] for k, v in data.items() if myviia_data[k.lower()] != v}
if updating.keys():
# Update the record on MYVIIA
post_response = myviia_post_cost(
data={'object_deel_id': project.get_myviia_object_deel_id(), 'date': current_date, **data},
token=project.token).json()
updates = [f'{k} updated from {round(v[1], 2)} m2 to {round(v[0], 2)} m2' for k, v in updating.items()]
project.write_log(
f"Cost key-figures updated on MYVIIA: {', '.join(updates)}.")
else:
project.write_log("Cost key-figures are already up-to-date on MYVIIA.")
# Inform user if the response was not correct
if post_response and 'resource_id' not in post_response:
project.write_log(
"WARNING: Some issue occurred while sending to MYVIIA. Please check on MYVIIA, "
"and contact VIIA-automating team if issue persists.")
# Return the response of MYVIIA if new item is posted
return post_response
### ===================================================================================================================
### 4. Function to create excel file with cost key figures
### ===================================================================================================================
[docs]def viia_cost_key_figures_to_excel(project: 'ViiaProject', data: Dict[str, Union[float, int]]) -> Path:
"""
This function fills the Excel template with the provided data for the cost key figures.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- data (dict): Dictionary with the cost key figures, the keys 'BVO', 'BBO', 'BGO', 'OGO', 'BDO' and 'ODO'
should be present in this dictionary. The values should be floats, in [m2].
Output:
- Creates an Excel sheet with the values filled. The location of the file is returned as path.
"""
# Check if data is complete
if not {'BVO', 'BBO', 'BGO', 'OGO', 'BDO', 'ODO'}.issubset(data):
raise ValueError(f"ERROR: Data for excel cost key figures is incomplete: {', '.join(data.keys())}.")
# Load the template for the output file in Excel
cost_workbook = load_workbook(
project.viia_settings.project_specific_package_location / 'general' / 'template_cost_key_figures.xlsx')
cost_sheet = cost_workbook['Sheet1']
# Fill the data in the Excel, hard coded
cost_sheet['C9'] = data['BVO']
cost_sheet['C11'] = data['BBO']
cost_sheet['C13'] = data['BGO']
cost_sheet['C14'] = data['OGO']
cost_sheet['C15'] = data['BDO']
cost_sheet['C16'] = data['ODO']
# Information on current run
cost_sheet['C6'] = datetime.now().strftime("%d-%m-%Y | %H:%M:%S")
cost_sheet['C7'] = os.getlogin()
# Save the updated excel in the working directory
# The default name of the Excel document is set
document = f"{project.name}-v{str(project.version).zfill(3)}-COST-{date.today().strftime('%Y%m%d')}.xlsx"
output_file = project.workfolder_location / document
cost_workbook.save(output_file)
# Notification
project.write_log(
f"Key-figures from fem-model are exported to excel for cost engineer VIIA.\n"
f" File: {output_file.as_posix()}")
return output_file
### ===================================================================================================================
### 5. End of script
### ===================================================================================================================