def _validate_input(self): """Validate entry when unfocusing text input.""" if not self.text_input.focus: try: input_value = float(self.text_input.text) except ValueError: # No text entered. input_value = self.param_slider.value self.text_input.text = str(input_value) return if input_value > self.param_max or input_value < self.param_min: # If input value is out of range. popup = WarningPopup() popup.popup_text.text = '{param_name} must be between {param_min} and {param_max} (got {input_val}).'.format( param_name=self.name.text[:1].upper() + self.name.text[1:], param_min=self.param_min, param_max=self.param_max, input_val=input_value) popup.open() input_value = self.param_slider.value self.text_input.text = str(input_value) else: # Set slider value to input value. anim = Animation(transition='out_expo', duration=SLIDER_DUR, value=input_value) anim.start(self.param_slider)
def next_screen(self): try: self.get_selections() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: self.manager.current = self.manager.next()
def get_inputs(self): try: params = self._validate_inputs() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: return params
def get_selections(self): """Retrieves screen's selections.""" try: load_profile_selected = self._validate_inputs() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: return load_profile_selected
def get_selections(self): """Retrieves screen's selections.""" try: params, params_desc = self._validate_inputs() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: return params, params_desc
def next_screen(self): """Check if all input data is valid before proceeding to the net metering screen.""" try: self._validate_inputs() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: self.manager.current = self.manager.next()
def get_selections(self): """Retrieves UI selections.""" try: peak_kw_min, peak_kw_max, net_metering_type, sell_price = self._validate_inputs( ) except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: return peak_kw_min, peak_kw_max, net_metering_type, sell_price
def get_selections(self): """Retrieves UI selections.""" try: weekday_schedule, weekend_schedule, tou_rates_dict, flat_rates_dict = self._validate_inputs( ) except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: return weekday_schedule.tolist(), weekend_schedule.tolist( ), tou_rates_dict, flat_rates_dict
def launch_btm(self): """""" data_manager = App.get_running_app().data_manager try: data_manager.scan_btm_data_bank() except FileNotFoundError: # 'data' directory does not exist. no_data_popup = WarningPopup() no_data_popup.popup_text.text = "Looks like you haven't downloaded any data yet. Try using QuESt Data Manager to get some data before returning here!" no_data_popup.open() else: self.current = 'btm_home'
def _next_screen(self): if not self.manager.has_screen('summary'): screen = CostSavingsWizardSummary(name='summary') self.manager.add_widget(screen) try: self.get_selections() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: self.manager.transition.duration = BASE_TRANSITION_DUR self.manager.transition.direction = 'left' self.manager.current = 'summary'
def _execute_search(): # Open loading screen. # self.loading_screen = LoadingModalView() # self.loading_screen.loading_text.text = 'Retrieving rate structures...' # self.loading_screen.open() if self.utility_ref_table.empty: try: self._download_utility_ref_table() except requests.ConnectionError: popup = ConnectionErrorPopup() popup.popup_text.text = 'There was an issue connecting to and downloading the lists of utilities. Check your connection settings and try again.' popup.open() return finally: self.search_button.disabled = False # Filter DataFrame by search type/query and drop duplicate entries. if search_type == 'state': utility_data_filtered = self.utility_ref_table.loc[ self.utility_ref_table['state'].str.lower( ).str.contains(search_query) | self.utility_ref_table['state name'].str.lower( ).str.contains(search_query)] elif search_type == 'zip': utility_data_filtered = self.utility_ref_table.loc[ self.utility_ref_table[search_type] == search_query] else: utility_data_filtered = self.utility_ref_table.loc[ self.utility_ref_table[search_type].str.lower( ).str.contains(search_query)] utility_data_filtered = utility_data_filtered[[ 'eiaid', 'utility_name', 'state', 'ownership' ]] utility_data_filtered.drop_duplicates(inplace=True) logging.info( 'RateStructureDM: Utility table filter completed.') self.search_button.disabled = False if utility_data_filtered.empty: logging.warning( 'RateStructureDM: No results matched the query.') popup = WarningPopup() popup.popup_text.text = 'No results matched your query.' popup.open() # Enable search results selector. fade_in_animation(self.utility_select_bx) self._populate_utility_selector(utility_data_filtered)
def finalize_selections(self): """Validates the specified data based on the selected columns using a validation function. Returns ------- Pandas DataFrame Dataframe with the data series str Name of the data column """ try: import_df, data_column_name = self._validate_columns_selected() except ValueError as e: exception_popup = WarningPopup() exception_popup.popup_text.text = e.args[0] exception_popup.open() else: logging.info("DataImporter: Data format validation completed without issues.") completion_popup = self.manager.completion_popup completion_popup.open() return import_df, data_column_name
def on_enter(self): # change the navigation bar title ab = self.manager.nav_bar ab.build_valuation_advanced_nav_bar() ab.set_title('Single Run: Set Parameters') data_manager = App.get_running_app().data_manager MODEL_PARAMS = data_manager.get_valuation_model_params(self.iso) if not MODEL_PARAMS: popup = WarningPopup() popup.bind(on_dismiss=partial(ab.go_to_screen, 'load_data')) popup.dismiss_button.text = 'Go back' popup.popup_text.text = 'We need a market area in the "Select Data" screen selected first to populate this area.' popup.open()
def run_batch(self): try: requests = self._generate_requests() except ValueError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: solver_name = App.get_running_app().config.get( 'optimization', 'solver') handler = self.manager.get_screen('valuation_home').handler handler.solver_name = solver_name try: solved_ops, handler_status = handler.process_requests(requests) except BadParameterException as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: self.completion_popup = BatchRunCompletePopup() self.completion_popup.view_results_button.bind( on_release=self._go_to_view_results) if len(handler_status) > 0: if solved_ops: # At least one model solved successfully. self.completion_popup.title = "Success!*" self.completion_popup.popup_text.text = '\n'.join([ 'All finished, but we found these issues:', ] + list(handler_status)) else: # No models solved successfully. self.completion_popup.title = "Hmm..." self.completion_popup.popup_text.text = '\n'.join([ 'Unfortunately, none of the models were able to be solved. We found these issues:', ] + list(handler_status)) self.completion_popup.open()
def save_rate_structure(self): """Saves the rate structure details to an object on disk.""" # Retrieve selections from other screens. utility_search_screen = self.manager.get_screen('start') utility_selected, rate_structure_selected = utility_search_screen.get_selections( ) energy_rate_screen = self.manager.get_screen('energy_rate_structure') energy_weekday_schedule, energy_weekend_schedule, energy_rates_dict = energy_rate_screen.get_selections( ) demand_rate_screen = self.manager.get_screen('demand_rate_structure') demand_weekday_schedule, demand_weekend_schedule, demand_tou_rates_dict, demand_flat_rates_dict = demand_rate_screen.get_selections( ) try: peak_kw_min, peak_kw_max, net_metering_type, sell_price = self.get_selections( ) except TypeError: return # Form dictionary object for saving. rate_structure_object = {} if not self.save_name_field.text: popup = WarningPopup() popup.popup_text.text = 'Please specify a name to save the rate structure as.' popup.open() return else: rate_structure_object['name'] = self.save_name_field.text rate_structure_object['utility'] = { 'utility name': utility_selected['utility_name'], 'rate structure name': rate_structure_selected['name'] } rate_structure_object['energy rate structure'] = { 'weekday schedule': energy_weekday_schedule, 'weekend schedule': energy_weekend_schedule, 'energy rates': energy_rates_dict } rate_structure_object['demand rate structure'] = { 'weekday schedule': demand_weekday_schedule, 'weekend schedule': demand_weekend_schedule, 'time of use rates': demand_tou_rates_dict, 'flat rates': demand_flat_rates_dict, 'minimum peak demand': peak_kw_min, 'maximum peak demand': peak_kw_max } rate_structure_object['net metering'] = { 'type': net_metering_type, 'energy sell price': sell_price } # Save to JSON. # Strip non-alphanumeric chars from given name for filename. delchars = ''.join(c for c in map(chr, range(256)) if not c.isalnum()) fname = rate_structure_object['name'].translate( {ord(i): None for i in delchars}) destination_dir = os.path.join(DATA_HOME, 'rate_structures') os.makedirs(destination_dir, exist_ok=True) destination_file = os.path.join(destination_dir, fname + '.json') if not os.path.exists(destination_file): with open(destination_file, 'w') as outfile: json.dump(rate_structure_object, outfile) popup = WarningPopup() popup.title = 'Success!' popup.popup_text.text = 'Rate structure data successfully saved.' popup.open() else: # File already exists with same name. popup = WarningPopup() popup.popup_text.text = 'A rate structure with the provided name already exists. Please specify a new name.' popup.open()
def __init__(self, write_directory=None, write_function=None, chooser_description=None, format_description=None, data_validation_function=None, **kwargs): super(DataImporter, self).__init__(**kwargs) if write_directory is None: self.write_directory = "" else: self.write_directory = write_directory if write_function is None: def _write_time_series_csv(fname, dataframe): """Writes a generic time series dataframe to a two-column csv. The data is inferred to be at an hourly time resolution for one standard year. Parameters ---------- fname : str Name of the file to be saved without an extension dataframe : Pandas DataFrame DataFrame containing a single Series of the data Returns ------- str The save destination of the resulting file. """ save_destination = os.path.join(self.write_directory, fname + ".csv") data_column_name = dataframe.columns[0] datetime_start = datetime(2019, 1, 1, 0) hour_range = pd.date_range(start=datetime_start, periods=len(dataframe), freq="H") dataframe["DateTime"] = hour_range dataframe[["DateTime", data_column_name]].to_csv(save_destination, index=False) return save_destination self.write_function = _write_time_series_csv else: self.write_function = write_function if chooser_description is None: self.chooser_description = "Select a .csv file to import data from." else: self.chooser_description = chooser_description file_chooser_screen = self.screen_manager.get_screen("FileChooser") file_chooser_screen.file_chooser_body_text.text = self.chooser_description if format_description is None: self.format_description = "Specify the data column." else: self.format_description = format_description format_analyzer_screen = self.screen_manager.get_screen("FormatAnalyzer") format_analyzer_screen.format_analyzer_body_text.text = self.format_description if data_validation_function is None: def _default_data_validation_function(dataframe, data_column_name): if len(dataframe) != 8760: raise ValueError("The length of the time series must be 8760 (got {0}).".format(len(dataframe))) data_column = dataframe[data_column_name] try: data_column.astype("float") except ValueError: raise ValueError("The selected data column could not be interpeted as numeric float values.") self.data_validation_function = _default_data_validation_function else: self.data_validation_function = data_validation_function # Bind DataImporter dismissal to successful data import. completion_popup = WarningPopup() completion_popup.title = "Success!" completion_popup.popup_text.text = "Data successfully imported." completion_popup.bind(on_dismiss=self.dismiss) self.screen_manager.completion_popup = completion_popup
def _query_api(self, api_query): """Uses PVWatts API to query for a PV profile.""" ssl_verify, proxy_settings = check_connection_settings() try: with requests.Session() as req: http_request = req.get(api_query, proxies=proxy_settings, timeout=10, verify=ssl_verify, stream=True) if http_request.status_code != requests.codes.ok: http_request.raise_for_status() except requests.HTTPError as e: logging.error('PVProfileDM: {0}'.format(repr(e))) raise requests.ConnectionError except requests.exceptions.ProxyError: logging.error('PVProfileDM: Could not connect to proxy.') raise requests.ConnectionError except requests.ConnectionError as e: logging.error( 'PVProfileDM: Failed to establish a connection to the host server.' ) raise requests.ConnectionError except requests.Timeout as e: logging.error('PVProfileDM: The connection timed out.') raise requests.ConnectionError except requests.RequestException as e: logging.error('PVProfileDM: {0}'.format(repr(e))) raise requests.ConnectionError except Exception as e: # Something else went wrong. logging.error( 'PVProfileDM: An unexpected error has occurred. ({0})'.format( repr(e))) raise requests.ConnectionError else: request_content = http_request.json() if not self.save_name_field.text: popup = WarningPopup() popup.popup_text.text = 'Please specify a name to save the PV profile as.' popup.open() return else: outname = self.save_name_field.text # Strip non-alphanumeric chars from given name for filename. delchars = ''.join(c for c in map(chr, range(256)) if not c.isalnum()) outname = outname.translate({ord(i): None for i in delchars}) # Save. destination_dir = os.path.join(DATA_HOME, 'pv') os.makedirs(destination_dir, exist_ok=True) destination_file = os.path.join(destination_dir, outname + '.json') if not os.path.exists(destination_file): with open(destination_file, 'w') as outfile: json.dump(request_content, outfile) logging.info('PVProfileDM: Profile successfully saved.') popup = WarningPopup() popup.title = 'Success!' popup.popup_text.text = 'PV profile successfully saved.' popup.open() else: # File already exists with same name. popup = WarningPopup() popup.popup_text.text = 'A PV profile with the provided name already exists. Please specify a new name.' popup.open() finally: self.save_button.disabled = False
def execute_query(self): """Executes the PVWatts query using the given parameters.""" try: api_key, pv_params = self.get_inputs() self.api_key = api_key except ValueError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: # Reset screen. self.reset_screen() self.save_button.disabled = True # Form query. api_query = URL_PVWATTS query_segs = [] for k, v in pv_params.items(): query_segs.append('{key}={value}'.format(key=k, value=v)) api_query += '&'.join(query_segs) # print(api_query) try: self._query_api(api_query) except requests.ConnectionError: popup = ConnectionErrorPopup() popup.popup_text.text = 'There was an issue connecting to the API. Check your connection settings and try again.' popup.open()
def run_batch(self): try: requests = self._generate_requests() except ValueError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: solver_name = App.get_running_app().config.get('optimization', 'solver') handler = self.manager.get_screen('valuation_home').handler handler.solver_name = solver_name try: _, handler_status = handler.process_requests(requests) except BadParameterException as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: self.completion_popup = BatchRunCompletePopup() self.completion_popup.view_results_button.bind(on_release=self._go_to_view_results) if not handler_status: self.completion_popup.title = "Success!*" self.completion_popup.popup_text.text = "Your specified batch runs have been completed.\n\n*At least one model (month) had issues being built and/or solved. Any such model will be omitted from the results." self.completion_popup.open()
def save_load_data(self): """Saves the data for the building type selected.""" try: csv_link = self._validate_selections() except Exception as e: print(e) else: ssl_verify, proxy_settings = check_connection_settings() attempt_download = True n_tries = 0 self.connection_error_occurred = False while attempt_download: n_tries += 1 if n_tries >= MAX_WHILE_ATTEMPTS: logging.warning('LoadProfileDM: Hit download retry limit.') attempt_download = False self.connection_error_occurred = True break if App.get_running_app().root.stop.is_set(): return try: with requests.Session() as req: page = req.get(csv_link, timeout=10, verify=ssl_verify, proxies=proxy_settings) if page.status_code != requests.codes.ok: page.raise_for_status() else: attempt_download = False except requests.HTTPError as e: logging.error('LoadProfileDM: {0}'.format(repr(e))) except requests.exceptions.ProxyError: logging.error('LoadProfileDM: Could not connect to proxy.') except requests.ConnectionError as e: logging.error( 'LoadProfileDM: Failed to establish a connection to the host server.' ) except requests.Timeout as e: logging.error('LoadProfileDM: The connection timed out.') except requests.RequestException as e: logging.error('LoadProfileDM: {0}'.format(repr(e))) except Exception as e: # Something else went wrong. logging.error( 'LoadProfileDM: An unexpected error has occurred. ({0})' .format(repr(e))) else: data_down = page.content.decode(page.encoding) csv_data = pd.read_csv(io.StringIO(data_down)) electricity_data = csv_data[[ 'Date/Time', 'Electricity:Facility [kW](Hourly)' ]] # Save to persistent object on disk. url_split = csv_link.split('/') destination_dir = os.path.join(DATA_HOME, 'load', 'residential', url_split[-2]) os.makedirs(destination_dir, exist_ok=True) destination_file = os.path.join(destination_dir, url_split[-1]) electricity_data.to_csv(destination_file, sep=',', index=False) popup = WarningPopup() popup.title = 'Success!' popup.popup_text.text = 'Load data successfully saved.' popup.open() logging.info( 'LoadProfileDM: Load data successfully saved.')
def execute_single_run(self, *args): try: requests = self._generate_requests() except ValueError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() except InputError as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() except BadParameterException as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: solver_name = App.get_running_app().config.get( 'optimization', 'solver') handler = self.manager.get_screen('valuation_home').handler handler.solver_name = solver_name try: _, handler_status = handler.process_requests(requests) except BadParameterException as e: popup = WarningPopup() popup.popup_text.text = str(e) popup.open() else: self.completion_popup = ValuationSingleRunCompletePopup() self.completion_popup.view_results_button.bind( on_release=self._go_to_view_results) if not handler_status: self.completion_popup.title = "Oops!" self.completion_popup.popup_text.text = "The optimization model had issues being built and/or solved. This is most likely due to bad data. No results have been recorded." self.completion_popup.open()