예제 #1
0
    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)
예제 #2
0
 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()
예제 #3
0
 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
예제 #4
0
 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
예제 #5
0
 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
예제 #6
0
 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()
예제 #7
0
 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
예제 #8
0
 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
예제 #9
0
파일: main.py 프로젝트: Damon501/snl-quest
    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'
예제 #10
0
 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'
예제 #11
0
            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)
예제 #12
0
    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
예제 #13
0
    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()
예제 #14
0
    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()
예제 #15
0
    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()
예제 #16
0
    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
예제 #17
0
    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
예제 #18
0
    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()
예제 #19
0
    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()            
예제 #20
0
    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.')
예제 #21
0
    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()