diff --git a/bpeng/__init__.py b/bpeng/__init__.py index d561008879f4b64ffce49ece4fbc7cd8144b8100..6c4b6bcc175afd0111cb3ad379fbc1e8dde7cba9 100644 --- a/bpeng/__init__.py +++ b/bpeng/__init__.py @@ -4,4 +4,4 @@ BlocPower Engine library. Engineering and Financial modeling. """ -__version__ = '0.3.1' +__version__ = '0.3.2' diff --git a/bpeng/reports/cbra_diag.py b/bpeng/reports/cbra_diag.py index 8dd62e3efcbe9a5f980de802f60b250fe4eddaaf..1e9ea5d3a67e04b0376311d8a3dea07a5c8df6a2 100644 --- a/bpeng/reports/cbra_diag.py +++ b/bpeng/reports/cbra_diag.py @@ -22,7 +22,7 @@ from pptx.enum.text import ( # pylint: disable=no-name-in-module ) from pptx.util import Inches, Pt -from .constants import ECM_TO_SLIDE, RETROFIT_TO_CBRA_RETROFIT +from .constants import MASTER_TO_SLIDE, RETROFIT_TO_CBRA_RETROFIT class CbraDiagnostic: @@ -36,7 +36,7 @@ class CbraDiagnostic: project_summary_data, util_break_data, heat_loss_data, - ecm_data, + retrofit_data, ): """ Generate powerpoint file @@ -50,7 +50,7 @@ class CbraDiagnostic: util_break_data (dict): python dictionary of utility breakdown [$] by end usage heat_loss_data (dict): python dictionary of building components and heat loss values - ecm_data (dict): python dictionary of selected retrofits and calculated percent + retrofit_data (dict): python dictionary of selected retrofits and calculated percent savings on utility bill [$] by fuel @@ -77,40 +77,40 @@ class CbraDiagnostic: heat_loss_cat = heat_loss_data['heat_loss_cat'] heat_loss_val = heat_loss_data['heat_loss_val'] - ecm_list = ecm_data['ecm_list'] - ecm_heat_save = ecm_data['ecm_heat_save'] - ecm_elec_save = ecm_data['ecm_elec_save'] + retrofit_list = retrofit_data['retrofit_list'] + retrofit_heat_save = retrofit_data['retrofit_heat_save'] + retrofit_elec_save = retrofit_data['retrofit_elec_save'] # Convert database strings to presentation strings # Also calculate new heat or elec save in cases where - # database ecm's are combined to a single presentation ecm - new_ecm_list = [] - new_ecm_heat_save = [] - new_ecm_elec_save = [] - for name, heat, elec in zip(ecm_list, ecm_heat_save, ecm_elec_save): - presentation_name = ECM_TO_SLIDE[name]['slide_name'] - if presentation_name in new_ecm_list: - combine_index = new_ecm_list.index(presentation_name) + # database retrofit's are combined to a single presentation retrofit + new_retrofit_list = [] + new_retrofit_heat_save = [] + new_retrofit_elec_save = [] + for name, heat, elec in zip(retrofit_list, retrofit_heat_save, retrofit_elec_save): + presentation_name = MASTER_TO_SLIDE[name]['slide_name'] + if presentation_name in new_retrofit_list: + combine_index = new_retrofit_list.index(presentation_name) # Right now we just add together heat and elec. # In the future we might want to calculate the combined value for - # heat and elec differently based on the ECM - new_ecm_heat_save[combine_index] += heat - new_ecm_elec_save[combine_index] += elec + # heat and elec differently based on the retrofit + new_retrofit_heat_save[combine_index] += heat + new_retrofit_elec_save[combine_index] += elec else: - new_ecm_list.append(presentation_name) - new_ecm_heat_save.append(heat) - new_ecm_elec_save.append(elec) - ecm_list = new_ecm_list - ecm_heat_save = new_ecm_heat_save - ecm_elec_save = new_ecm_elec_save - - # Create a delete list by adding everything not in the ecm_list - ecm_delete_list = [] - for slide in ECM_TO_SLIDE.values(): - if slide['slide_name'] not in ecm_list and slide['slide_index'] not in ecm_delete_list: - ecm_delete_list.append(slide['slide_index']) + new_retrofit_list.append(presentation_name) + new_retrofit_heat_save.append(heat) + new_retrofit_elec_save.append(elec) + retrofit_list = new_retrofit_list + retrofit_heat_save = new_retrofit_heat_save + retrofit_elec_save = new_retrofit_elec_save + + # Create a delete list by adding everything not in the retrofit_list + retrofit_delete_list = [] + for slide in MASTER_TO_SLIDE.values(): + if slide['slide_name'] not in retrofit_list and slide['slide_index'] not in retrofit_delete_list: + retrofit_delete_list.append(slide['slide_index']) # Put delete list in reverse order so we delete from the back - ecm_delete_list.sort(reverse=True) + retrofit_delete_list.sort(reverse=True) # Define presentation to edit as the finished template diag_rep = Presentation(template_file) @@ -147,7 +147,7 @@ class CbraDiagnostic: crnyc_intro_run.text = 'Community Retrofit NYC’s engineering feasibility study provides ' \ 'a cost effective and energy efficient solution for {}. ' \ - 'Implementation of the recommended ECMs would ' \ + 'Implementation of the recommended retrofits would ' \ 'result in the following:'.format(project_address) crnyc_intro_run.font.name = 'Arial' @@ -256,7 +256,7 @@ class CbraDiagnostic: heat_loss_labels.font.bold = True # Slide 4: Potential Savings, includes utility expenses stacked bar charts for - # pre+post-retrofit, ECM table w/ names, savings for elec and gas, and total savings + # pre+post-retrofit, retrofit table w/ names, savings for elec and gas, and total savings # Slide 4: Utility breakdown utility_projection_slide = diag_rep.slides[3] @@ -316,60 +316,60 @@ class CbraDiagnostic: util_break_chart.value_axis.has_major_gridlines = False util_break_chart.value_axis.tick_label_position = XL_TICK_LABEL_POSITION.NONE - # Create ECM summary table + # Create retrofit summary table - ecm_count = len(ecm_list) - ecm_table_head = [ + retrofit_count = len(retrofit_list) + retrofit_table_head = [ 'Energy Conservation Measure', "Heating Savings*", "Electricity Savings*", "Water Savings*" ] - ecm_table = utility_projection_slide.shapes.add_table( - ecm_count + 2, - len(ecm_table_head), + retrofit_table = utility_projection_slide.shapes.add_table( + retrofit_count + 2, + len(retrofit_table_head), Inches(3.62), Inches(0.08), Inches(6.12), Inches(4.9) ) - ecm_table.last_row = True - ecm_table.horz_banding = False - ecm_table.table.columns[0].width = Inches(3.12) - ecm_table.table.columns[1].width = Inches(1) - ecm_table.table.columns[2].width = Inches(1) - ecm_table.table.columns[3].width = Inches(1) - - for j in range(len(ecm_table_head)): # pylint: disable=consider-using-enumerate - ecm_table.table.cell(0, j).text = ecm_table_head[j] - ecm_table.table.cell(0, j).text_frame.paragraphs[0].font.size = Pt(12) - ecm_table.table.cell(0, j).text_frame.paragraphs[0].font.bold = True - - for k, j in zip(ecm_list, range(len(ecm_list))): - ecm_table.table.cell(j+1, 0).text_frame.paragraphs[0].font.size = Pt(10) - ecm_table.table.cell(j+1, 0).text = k - ecm_table.table.cell(j+1, 1).text_frame.paragraphs[0].font.size = Pt(10) - ecm_table.table.cell(j+1, 1).text = str(int(ecm_heat_save[j])) + '\N{PERCENT SIGN}' - ecm_table.table.cell(j+1, 1).text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER - ecm_table.table.cell(j+1, 1).text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE - ecm_table.table.cell(j+1, 2).text_frame.paragraphs[0].font.size = Pt(10) - ecm_table.table.cell(j+1, 2).text = str(int(ecm_elec_save[j])) + '\N{PERCENT SIGN}' - ecm_table.table.cell(j+1, 2).text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER - ecm_table.table.cell(j+1, 2).text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE - - ecm_table.table.cell(ecm_count+1, 0).text_frame.paragraphs[0].font.size = Pt(12) - ecm_table.table.cell(ecm_count+1, 0).text_frame.paragraphs[0].font.bold = True - ecm_table.table.cell(ecm_count+1, 0).text = 'Total' - - ecm_table.table.cell(ecm_count+1, 2).text_frame.paragraphs[0].font.size = Pt(12) - ecm_table.table.cell(ecm_count+1, 2).text_frame.paragraphs[0].font.bold = True - ecm_table.table.cell(ecm_count+1, 2).text = str(annual_utility_percent) + '\N{PERCENT SIGN}' + retrofit_table.last_row = True + retrofit_table.horz_banding = False + retrofit_table.table.columns[0].width = Inches(3.12) + retrofit_table.table.columns[1].width = Inches(1) + retrofit_table.table.columns[2].width = Inches(1) + retrofit_table.table.columns[3].width = Inches(1) + + for j in range(len(retrofit_table_head)): # pylint: disable=consider-using-enumerate + retrofit_table.table.cell(0, j).text = retrofit_table_head[j] + retrofit_table.table.cell(0, j).text_frame.paragraphs[0].font.size = Pt(12) + retrofit_table.table.cell(0, j).text_frame.paragraphs[0].font.bold = True + + for k, j in zip(retrofit_list, range(len(retrofit_list))): + retrofit_table.table.cell(j+1, 0).text_frame.paragraphs[0].font.size = Pt(10) + retrofit_table.table.cell(j+1, 0).text = k + retrofit_table.table.cell(j+1, 1).text_frame.paragraphs[0].font.size = Pt(10) + retrofit_table.table.cell(j+1, 1).text = str(int(retrofit_heat_save[j])) + '\N{PERCENT SIGN}' + retrofit_table.table.cell(j+1, 1).text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER + retrofit_table.table.cell(j+1, 1).text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE + retrofit_table.table.cell(j+1, 2).text_frame.paragraphs[0].font.size = Pt(10) + retrofit_table.table.cell(j+1, 2).text = str(int(retrofit_elec_save[j])) + '\N{PERCENT SIGN}' + retrofit_table.table.cell(j+1, 2).text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER + retrofit_table.table.cell(j+1, 2).text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE + + retrofit_table.table.cell(retrofit_count+1, 0).text_frame.paragraphs[0].font.size = Pt(12) + retrofit_table.table.cell(retrofit_count+1, 0).text_frame.paragraphs[0].font.bold = True + retrofit_table.table.cell(retrofit_count+1, 0).text = 'Total' + + retrofit_table.table.cell(retrofit_count+1, 2).text_frame.paragraphs[0].font.size = Pt(12) + retrofit_table.table.cell(retrofit_count+1, 2).text_frame.paragraphs[0].font.bold = True + retrofit_table.table.cell(retrofit_count+1, 2).text = str(annual_utility_percent) + '\N{PERCENT SIGN}' # Slides 5-end: removing slides based on recommendations - for ecm_index in ecm_delete_list: + for retrofit_index in retrofit_delete_list: diag_rep.slides.delete_slide( diag_rep, - ecm_index, + retrofit_index, ) # After slides have been deleted, update the table of contents in the executive summary @@ -400,16 +400,17 @@ class CbraDiagnostic: project_summary_data, util_break_data, heat_loss_data, - ecm_data + retrofit_data ) = CbraDiagnostic.parse_arguments(sheet_input) project_address, diag_rep = CbraDiagnostic._generate_report( template_file, project_summary_data, util_break_data, heat_loss_data, - ecm_data, + retrofit_data, ) diag_rep.save('EEDR {}.pptx'.format(project_address)) + print('Report generated!') @staticmethod def parse_arguments(sheet_input): @@ -423,7 +424,7 @@ class CbraDiagnostic: dict: A dictionary containing all of the project summary data dict: A dictionary containing all of the utility breakdown data dict: A dictionary containing all of the heat loss data - dict: A dictionary containing all of the ECM data + dict: A dictionary containing all of the retrofit data """ project_summary_data = { @@ -452,25 +453,25 @@ class CbraDiagnostic: 'heat_loss_val': input_values[9:15], } - ecm_list = [] - ecm_heat_save = [] - ecm_elec_save = [] + retrofit_list = [] + retrofit_heat_save = [] + retrofit_elec_save = [] for j in range(len(input_values)): # pylint: disable=C0200 if input_values[j] == 'Y': # Convert to database string - ecm_list.append( + retrofit_list.append( RETROFIT_TO_CBRA_RETROFIT[input_list[j]] ) - ecm_heat_save.append(input_values[j+1]) - ecm_elec_save.append(input_values[j+2]) + retrofit_heat_save.append(input_values[j+1]) + retrofit_elec_save.append(input_values[j+2]) - ecm_data = { - 'ecm_list': ecm_list, - 'ecm_heat_save': ecm_heat_save, - 'ecm_elec_save': ecm_elec_save, + retrofit_data = { + 'retrofit_list': retrofit_list, + 'retrofit_heat_save': retrofit_heat_save, + 'retrofit_elec_save': retrofit_elec_save, } - return project_summary_data, util_break_data, heat_loss_data, ecm_data + return project_summary_data, util_break_data, heat_loss_data, retrofit_data @staticmethod def cbra_multi_rep(): @@ -497,14 +498,14 @@ class CbraDiagnostic: project_summary_data, util_break_data, heat_loss_data, - ecm_data + retrofit_data ) = CbraDiagnostic.parse_arguments(sheet_input) proj_loc, diag_rep = CbraDiagnostic._generate_report( template_file, project_summary_data, util_break_data, heat_loss_data, - ecm_data, + retrofit_data, ) diag_rep.save('EEDR {}.pptx'.format(proj_loc)) print('Reports generated!') diff --git a/bpeng/reports/constants.py b/bpeng/reports/constants.py index 1e661b312a4cf4bb7f0a35871cbbe60a88afa1b9..7ccdfef248860bb11149d8ca91c662d17d1de799 100644 --- a/bpeng/reports/constants.py +++ b/bpeng/reports/constants.py @@ -1,4 +1,4 @@ -ECM_TO_SLIDE = { +MASTER_TO_SLIDE = { 'Weatherstripping (Exterior Doors)': { 'slide_index': 4, 'slide_name': 'Install Weather-stripping',