Skip to content

Commit

Permalink
fix(version): Handle PHPP v9/10 Verification Worksheet errors
Browse files Browse the repository at this point in the history
  • Loading branch information
ed-p-may committed Dec 16, 2022
1 parent f352589 commit 6610c18
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 105 deletions.
133 changes: 120 additions & 13 deletions PHX/PHPP/phpp_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,34 @@

"""Controller for managing the PHPP Connection."""


from typing import List, Dict, Optional
from typing import List, Dict

from PHX.model import project, certification, building, components
from PHX.model.hvac.collection import NoVentUnitFoundError

from PHX.xl import xl_app
from PHX.xl.xl_typing import xl_Sheet_Protocol
from PHX.PHPP import sheet_io, phpp_localization
from PHX.PHPP.phpp_localization.shape_model import PhppShape
from PHX.PHPP.phpp_model import (areas_surface, areas_data, areas_thermal_bridges,
climate_entry, electricity_item, uvalues_constructor,
component_glazing, component_frame, component_vent,
ventilation_data, windows_rows, shading_rows,
vent_space, vent_units, vent_ducts, verification_data,
hot_water_tank, hot_water_piping)
hot_water_tank, hot_water_piping, version)


class PHPPConnection:

def __init__(self, _xl: xl_app.XLConnection, _phpp_shape: Optional[phpp_localization.PhppShape]=None):
# -- Get the localized (units, language) PHPP Shape with worksheet names and column locations
if not _phpp_shape:
self.shape: phpp_localization.PhppShape = phpp_localization.get_phpp_shape(_xl)
else:
self.shape: phpp_localization.PhppShape = _phpp_shape

"""Interface for a PHPP Excel Document."""

def __init__(self, _xl: xl_app.XLConnection):
# -- Setup the Excel connection and facade object.
self.xl = _xl


# -- Get the localized (units, language) PHPP Shape with worksheet names and column locations
self.version = self.get_phpp_version()
self.shape: PhppShape = phpp_localization.get_phpp_shape(self.xl, self.version)

# -- Setup all the individual worksheet Classes.
self.verification = sheet_io.Verification(self.xl, self.shape.VERIFICATION)
self.climate = sheet_io.Climate(self.xl, self.shape.CLIMATE)
Expand All @@ -51,10 +51,117 @@ def __init__(self, _xl: xl_app.XLConnection, _phpp_shape: Optional[phpp_localiza
self.per = sheet_io.PER(self.xl, self.shape.PER)
self.overview = sheet_io.Overview(self.xl, self.shape.OVERVIEW)

def get_data_worksheet(self) -> xl_Sheet_Protocol:
"""Return the 'Data' worksheet from the active PHPP file, support English, German, Spanish."""
valid_data_worksheet_names = ["Data", "Daten", "Datos"]
worksheet_names = self.xl.get_worksheet_names()
for worksheet_name in valid_data_worksheet_names:
if worksheet_name in worksheet_names:
return self.xl.get_sheet_by_name(worksheet_name)

raise Exception(
f"Error: Cannot find a '{valid_data_worksheet_names}' worksheet in the Excel file: {self.xl.wb.name}?"
)

def get_phpp_version(
self,
_search_col: str = "A",
_row_start: int = 1,
_row_end: int = 10,
) -> version.PHPPVersion:
"""Find the PHPP Version and Language of the active xl-file.
Arguments:
----------
* _xl (xl_app.XLConnection):
* _search_col (str)
* _row_start (int) default=1
* _row_end (int) default=10
Returns:
--------
* PHPPVersion: The PHPPVersion with a number and Language for the Active PHPP.
"""

# ---------------------------------------------------------------------
# -- Find the right 'Data' worksheet
data_worksheet: xl_Sheet_Protocol = self.get_data_worksheet()

# ---------------------------------------------------------------------
# -- Pull the search Column data from the Active XL Instance
data = self.xl.get_single_column_data(
_sheet_name=data_worksheet.name,
_col=_search_col,
_row_start=_row_start,
_row_end=_row_end,
)

for i, xl_rang_data in enumerate(data, start=_row_start):
if str(xl_rang_data).upper().strip().replace(" ", "").startswith("PHPP"):
data_row = i
break
else:
raise Exception(
f"Error: Cannot determine the PHPP Version? Expected 'PHPP' in"
f"col: {_search_col} of the {data_worksheet.name} worksheet?"
)

# ---------------------------------------------------------------------
# -- Pull the search row data from the Active XL Instance
data = self.xl.get_single_row_data(data_worksheet.name, data_row)
data = [_ for _ in data if _ is not None and _ is not ""] # Filter out all the blanks

# ---------------------------------------------------------------------
# -- Find the right Version number
raw_version_id: str = str(data[1]) # Use the second value in the row - data (will this always work?)
ver_major, ver_minor = raw_version_id.split(".")

# ---------------------------------------------------------------------
# - Figure out the PHPP language
# - In <v10 the actual language is not noted in the 'Data' worksheet, so
# - use the PE factor name as a proxy
language_search_data = {
"1-PE-FAKTOREN": "DE",
"1-FACTORES EP": "ES",
"1-PE-FACTORS": "EN",
}
language = None
for search_string in language_search_data.keys():
if search_string in str(data[-1]).upper().strip():
language = language_search_data[search_string]
language = language.strip().replace(" ", "_").replace(".", "_")
break
if not language:
raise Exception(
"Error: Cannot determine the PHPP language? Only English, German and Spanish are supported."
)

# ---------------------------------------------------------------------
# -- Build the new PHPPVersion object
return version.PHPPVersion(ver_major, ver_minor, language)

def phpp_version_equals_phx_phi_cert_version(self, _phx_variant: project.PhxVariant) -> bool:
"""Return True if the PHX PHI Certification Version and the PHPP Version match."""
if not int(_phx_variant.phi_certification_major_version) == int(self.version.number_major):
return False
return True

def write_certification_config(self, phx_project: project.PhxProject) -> None:

for phx_variant in phx_project.variants:

# # TODO: multiple variants?
# TODO: how to handle multiple variants?

if not self.phpp_version_equals_phx_phi_cert_version(phx_variant):
# -- If the versions don't match, don't try and write anything.
msg = (
f"\n\tPHPPVersionWarning: the HBJSON PHI "
f"Certification version (V={phx_variant.phi_certification_major_version}) "
f"does not match the PHPP Version (V={self.version.number_major})? "
f"Ignoring all writes to the '{self.shape.VERIFICATION.name}' worksheet.\n"
)
self.xl.output(msg)
return

# --- Building Type / Use
self.verification.write_item(
Expand Down
100 changes: 13 additions & 87 deletions PHX/PHPP/phpp_localization/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,94 +6,18 @@

import pathlib
import os
from typing import Tuple

from PHX.xl import xl_app
from PHX.xl.xl_typing import xl_Sheet_Protocol
from PHX.PHPP.phpp_localization.shape_model import PhppShape
from PHX.PHPP.phpp_model import version
from PHX.xl import xl_app


def get_data_worksheet(_xl: xl_app.XLConnection) -> xl_Sheet_Protocol:
"""Return the 'Data' worksheet from the active PHPP file, support English, German, Spanish."""
worksheet_names = _xl.get_worksheet_names()
for worksheet_name in ["Data", "Daten", "Datos"]:
if worksheet_name in worksheet_names:
return _xl.get_sheet_by_name(worksheet_name)

raise Exception(
f"Error: Cannot fine a 'Data' worksheet in the Excel file: {_xl.wb.name}?"
)


def get_phpp_version(
_xl: xl_app.XLConnection,
_search_col: str = "A",
_row_start: int = 1,
_row_end: int = 10,
) -> Tuple[str, str]:
"""Find the PHPP Version and Language of the active xl-file.
Arguments:
----------
* _xl (xl_app.XLConnection):
* _search_col (str)
* _row_start (int) default=1
* _row_end (int) default=10
Returns:
--------
* (Tuple[str, str]): The Version number and Language of the Active PHPP.
"""

# -- Find the right 'Data' worksheet
data_worksheet: xl_Sheet_Protocol = get_data_worksheet(_xl)

# -- Pull the search Column data from the Active XL Instance
data = _xl.get_single_column_data(
_sheet_name=data_worksheet.name,
_col=_search_col,
_row_start=_row_start,
_row_end=_row_end,
)

for i, xl_rang_data in enumerate(data, start=_row_start):
if str(xl_rang_data).upper().strip().replace(" ", "").startswith("PHPP"):
data_row = i
break
else:
raise Exception(
f"Error: Cannot determine the PHPP Version? Expected 'PHPP' in"
"col: {_search_col} of the {data_worksheet.name} worksheet?"
)

# -- Pull the search row data from the Active XL Instance
data = _xl.get_single_row_data(data_worksheet.name, data_row)
data = [_ for _ in data if _ is not None and _ is not ""]

# -- Find the right Versions number
version = str(data[1]).upper().strip().replace(" ", "").replace(".", "_")

# - Figure out the PHPP language
language_search_data = {
"1-PE-FAKTOREN": "DE",
"1-FACTORES EP": "ES",
"1-PE-FACTORS": "EN",
}
language = None
for search_string in language_search_data.keys():
if search_string in str(data[-1]).upper().strip():
language = language_search_data[search_string]
language = language.strip().replace(" ", "_").replace(".", "_")
break
if not language:
raise Exception(
"Error: Cannot determine the PHPP language? Only English, German and Spanish are supported."
)

return version, language
def phpp_version_as_file_name(version: version.PHPPVersion):
"""Return the version as a file-name."""
return f"{version.language}_{version.number_major}_{version.number_minor}"


def get_shape_filepath(_xl: xl_app.XLConnection, _shape_file_directory: pathlib.Path):
def get_shape_filepath(version: version.PHPPVersion, _shape_file_directory: pathlib.Path):
"""Returns the path to the PHPP Shape File based on the language and PHPP version found.
Arguments:
Expand All @@ -105,8 +29,10 @@ def get_shape_filepath(_xl: xl_app.XLConnection, _shape_file_directory: pathlib.
--------
* (pathlib.Path): The path to the correct PHPP Shape File.
"""
phpp_version, phpp_language = get_phpp_version(_xl)
shape_file_name = f"{phpp_language}_{phpp_version}.json"
# phpp_version, phpp_language = get_phpp_version(_xl)
# shape_file_name = f"{phpp_language}_{phpp_version}.json"
shape_file_name = phpp_version_as_file_name(version)
shape_file_name = f"{shape_file_name}.json"
shape_file_path = pathlib.Path(_shape_file_directory, shape_file_name)

if not os.path.exists(shape_file_path):
Expand All @@ -117,12 +43,12 @@ def get_shape_filepath(_xl: xl_app.XLConnection, _shape_file_directory: pathlib.
return shape_file_path


def get_phpp_shape(_xl: xl_app.XLConnection) -> PhppShape:
def get_phpp_shape(_xl: xl_app.XLConnection, version: version.PHPPVersion) -> PhppShape:
"""Return the PhppShape Object."""

shape_file_dir = pathlib.Path(__file__).parent
phpp_shape_filepath = get_shape_filepath(_xl, shape_file_dir)
print(f"Loading PHPP Shapefile:\n\t{phpp_shape_filepath}")
phpp_shape_filepath = get_shape_filepath(version, shape_file_dir)
_xl.output(f"Loading PHPP Shapefile:\n\t{phpp_shape_filepath}")
phpp_shape = PhppShape.parse_file(phpp_shape_filepath)

return phpp_shape
21 changes: 21 additions & 0 deletions PHX/PHPP/phpp_model/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# -*- Python Version: 3.7 -*-

"""Class for managing PHPP Version data."""


class PHPPVersion:
"""Manage the PHPP Version number and language information."""

def __init__(self, _number_major: str, _number_minor: str, _language: str):
self.number_major = self.clean_input(_number_major)
self.number_minor = self.clean_input(_number_minor)
self.language = self.clean_input(_language)

def clean_input(self, _input):
"""Upper, strip, replace spaces."""
return str(_input).upper().strip().replace(" ", "").replace(".", "_")

def number(self) -> str:
"""Return the full version number (ie: "9.6", "10.4", etc..)"""
return f"{self.number_major}.{self.number_minor}"
3 changes: 3 additions & 0 deletions PHX/from_HBJSON/create_variant.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,14 @@ def add_phi_certification_from_hb_room(
"""
# alias cus' all this shit is deep in there...
hbph_settings: phi.PhiCertification = _hb_room.properties.ph.ph_bldg_segment.phi_certification # type: ignore
phx_phi_cert = _variant.phi_certification
phx_settings = _variant.phi_certification.phi_certification_settings # type: ignore

if hbph_settings.attributes.phpp_version == 10:
phx_phi_cert.version = 10
set_phx_phpp10_settings(phx_settings, hbph_settings.attributes)
elif hbph_settings.attributes.phpp_version == 9:
phx_phi_cert.version = 9
set_phx_phpp9_settings(phx_settings, hbph_settings.attributes)
else:
msg = f"Error: Unknown PHPP Settings Version? Got: '{hbph_settings.attributes.phpp_version}'"
Expand Down
1 change: 1 addition & 0 deletions PHX/model/certification.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,4 @@ class PhxPhiCertification:
phi_certification_settings: PhxPhiCertificationSettings = field(
default_factory=PhxPhiCertificationSettings
)
version: int = 9
4 changes: 4 additions & 0 deletions PHX/model/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ def graphics3D(self):
phx_graphics3D.add_polygons(phx_component.polygons)
return phx_graphics3D

@property
def phi_certification_major_version(self) -> int:
return self.phi_certification.version

def __post_init__(self) -> None:
self.__class__._count += 1
self.id_num = self.__class__._count
Expand Down
Loading

0 comments on commit 6610c18

Please sign in to comment.