def remove_from_queue_if_in_queue(db_path, scenario, queue_order_id): """ :param db_path: :param scenario: :param queue_order_id: :return: If running from the queue, remove from the queue """ conn = connect_to_database(db_path=db_path) c = conn.cursor() if queue_order_id is not None: print("Removing scenario ID {} from queue".format(scenario)) sql = """ UPDATE scenarios SET queue_order_id = NULL WHERE scenario_name = ? """ spin_on_database_lock(conn=conn, cursor=c, sql=sql, data=(scenario, ), many=False) else: pass conn.close()
def launch_scenario_process( db_path, scenarios_directory, scenario_id, solver, solver_executable ): """ :param db_path: :param scenarios_directory: :param scenario_id: integer, the scenario_id from the database :param solver: string, the solver name :param solver_executable: string, the solver executable :return: Launch a process to run the scenario. """ # Get the scenario name for this scenario ID # TODO: pass both from the client and do a check here that they exist conn = connect_to_database(db_path=db_path) c = conn.cursor() scenario_name = get_scenario_name_from_scenario_id( cursor=c, scenario_id=scenario_id ) # First, check if the scenario is already running run_status, process_id = check_scenario_run_status( db_path=db_path, scenario_id=scenario_id ) if run_status == "running": # This shouldn't ever happen, as the Run Scenario button should # disappear when status changes to 'running' print("Scenario already running.") emit("scenario_already_running") # If the scenario is not found among the running processes, launch a # process else: print("Starting process for scenario_id " + str(scenario_id)) # Get the run_gridpath_e2e entry point script from the # sys.executable run_gridpath_e2e_executable = get_executable_path( script_name="gridpath_run_e2e" ) p = subprocess.Popen( [ run_gridpath_e2e_executable, "--log", "--database", db_path, "--scenario", scenario_name, "--scenario_location", scenarios_directory, "--solver", solver, "--solver_executable", solver_executable, ], shell=False, ) return p, scenario_id, scenario_name
def create_data_table_api(db_path, table, scenario_id): """ :param db_path: :param table: :param scenario_id: :return: """ conn = connect_to_database(db_path=db_path) c = conn.cursor() data_table_api = dict() data_table_api['table'] = table data_table_api['caption'] = c.execute( """SELECT caption FROM ui_scenario_results_table_metadata WHERE results_table = '{}';""".format(table.replace( "-", "_"))).fetchone()[0] data_table_api['columns'] = get_table_data(db_path=db_path, table=table.replace("-", "_"), scenario_id=scenario_id, other_scenarios=[])['columns'] data_table_api['rowsData'] = get_table_data(db_path=db_path, table=table.replace("-", "_"), scenario_id=scenario_id, other_scenarios=[])['rowsData'] return data_table_api
def make_column_values_dict(db_path, msg): """ :param db_path: the path to the database :param msg: the client message (a dictionary) :return: a dictionary of column names and their values for populating/upating the scenarios table Create a dictionary with column names and their values based on the message sent by the client to be used to create a new scenario or update an existing one. """ conn = connect_to_database(db_path=db_path) c = conn.cursor() column_values_dict = dict() column_values_dict["scenario_name"] = msg["scenarioName"] for key in msg.keys(): if key == "scenarioName": pass elif key == "scenarioDescription": column_values_dict["scenario_description"] = \ msg["scenarioDescription"] else: id_column, column_value = \ get_subscenario_id_value(c=c, msg=msg, key=key) column_values_dict[id_column] = column_value return column_values_dict
def check_validation(self, test): """ Check that validate inputs runs without errors, and that there are no validation issues recorded in the status_validation table :return: """ # Check that test validation runs without errors validate_inputs.main( ["--database", DB_PATH, "--scenario", test, "--quiet"] ) # Check that no validation issues are recorded in the db for the test expected_validations = [] conn = connect_to_database(db_path=DB_PATH, detect_types=sqlite3.PARSE_DECLTYPES) c = conn.cursor() validations = c.execute( """ SELECT scenario_name FROM status_validation INNER JOIN (SELECT scenario_id, scenario_name FROM scenarios) USING (scenario_id) WHERE scenario_name = '{}' """.format(test) ) actual_validations = validations.fetchall() self.assertListEqual(expected_validations, actual_validations)
def main(args=None): """ Parse the arguments, get the data in a df, and create the plot :return: if requested, return the plot as JSON object """ if args is None: args = sys.argv[1:] parsed_args = parse_arguments(arguments=args) conn = connect_to_database(db_path=parsed_args.database) c = conn.cursor() scenario_id, scenario = get_scenario_id_and_name( scenario_id_arg=parsed_args.scenario_id, scenario_name_arg=parsed_args.scenario, c=c, script="energy_plot") tech_colors = get_tech_colors(c) tech_plotting_order = get_tech_plotting_order(c) energy_unit = get_unit(c, "energy") plot_title = "{}Energy by Period - {} - Stage {}".format( "{} - ".format(scenario) if parsed_args.scenario_name_in_title else "", parsed_args.load_zone, parsed_args.stage) plot_name = "EnergyPlot-{}-{}".format(parsed_args.load_zone, parsed_args.stage) df = get_plotting_data(conn=conn, scenario_id=scenario_id, load_zone=parsed_args.load_zone, stage=parsed_args.stage) source, x_col_reordered = process_stacked_plot_data( df=df, y_col="energy_mwh", x_col=["period"], category_col="technology") # Multi-level index in CDS will be joined into one column with "_" separator x_col_cds = "_".join(x_col_reordered) x_col_label = ", ".join([x.capitalize() for x in x_col_reordered]) plot = create_stacked_bar_plot(source=source, x_col=x_col_cds, x_label=x_col_label, y_label="Energy ({})".format(energy_unit), category_label="Technology", category_colors=tech_colors, category_order=tech_plotting_order, title=plot_title, ylimit=parsed_args.ylimit) # Show plot in HTML browser file if requested if parsed_args.show: show_plot(plot=plot, plot_name=plot_name, plot_write_directory=parsed_args.plot_write_directory, scenario=scenario) # Return plot in json format if requested if parsed_args.return_json: return json_item(plot, plot_name)
def record_end_time(db_path, scenario, process_id, end_time): """ :param db_path: :param scenario: :param process_id: :param end_time: :return: Record the scenario run's process ID. """ conn = connect_to_database(db_path=db_path) c = conn.cursor() sql = """ UPDATE scenarios SET run_end_time = ? WHERE scenario_name = ? AND run_process_id = ?; """ spin_on_database_lock(conn=conn, cursor=c, sql=sql, data=(end_time, scenario, process_id), many=False) conn.close()
def get(self): """ :return: """ conn = connect_to_database(db_path=self.db_path) c = conn.cursor() plots_query = c.execute( """SELECT results_plot, caption, load_zone_form_control, energy_target_zone_form_control, carbon_cap_zone_form_control, period_form_control, horizon_form_control, start_timepoint_form_control, end_timepoint_form_control, subproblem_form_control, stage_form_control, project_form_control, commit_project_form_control FROM ui_scenario_results_plot_metadata WHERE include = 1;""").fetchall() # TODO: add formGroup, Ymax and button included_plots_api = [] for plot in plots_query: ( results_plot, caption, load_zone_form_control, energy_target_zone_form_control, carbon_cap_zone_form_control, period_form_control, horizon_form_control, start_timepoint_form_control, end_timepoint_form_control, subproblem_form_control, stage_form_control, project_form_control, commit_project_form_control, ) = plot plot_api = { "plotType": results_plot, "caption": caption, "loadZone": [] if load_zone_form_control else "default", "energyTargetZone": [] if energy_target_zone_form_control else "default", "carbonCapZone": [] if carbon_cap_zone_form_control else "default", "period": [] if period_form_control else "default", "horizon": [] if horizon_form_control else "default", "startTimepoint": [] if start_timepoint_form_control else "default", "endTimepoint": [] if end_timepoint_form_control else "default", "subproblem": [] if subproblem_form_control else "default", "stage": [] if stage_form_control else "default", "project": [] if project_form_control else "default", "commitProject": [] if commit_project_form_control else "default", } included_plots_api.append(plot_api) return included_plots_api
def get_table_data(scenario_id, other_scenarios, table, db_path): """ :param scenario_id: :param other_scenarios: :param table: :param db_path: :return: """ conn = connect_to_database(db_path=db_path) c = conn.cursor() query_for_column_names = c.execute( """SELECT * FROM {} LIMIT 1;""".format(table) ) column_names = [s[0] for s in query_for_column_names.description] for index, value in enumerate(column_names): if value == "scenario_id": column_names[index] = "scenario_name" columns_for_query = str() n = 1 for column in column_names: if n < len(column_names): columns_for_query += "{}, ".format(column) else: columns_for_query += "{}".format(column) n += 1 other_scenarios_string = str() if len(other_scenarios) > 0: for scenario in other_scenarios: other_scenarios_string += ", {}".format(scenario) table_data_query = c.execute(""" SELECT {} FROM {} JOIN scenarios USING (scenario_id) WHERE scenario_id in ({}{}); """.format( columns_for_query, table, scenario_id, other_scenarios_string ) ) rows_data = [] for row in table_data_query.fetchall(): row_values = list(row) row_dict = dict(zip(column_names, row_values)) rows_data.append(row_dict) data_table_api = { 'columns': column_names, 'rowsData': rows_data } return data_table_api
def main(args=None): """ Parse the arguments, get the data in a df, and create the plot :return: if requested, return the plot as JSON object """ if args is None: args = sys.argv[1:] parsed_args = parse_arguments(arguments=args) conn = connect_to_database(db_path=parsed_args.database) c = conn.cursor() scenario_id, scenario = get_scenario_id_and_name( scenario_id_arg=parsed_args.scenario_id, scenario_name_arg=parsed_args.scenario, c=c, script="dispatch_plot") tech_colors = get_tech_colors(c) tech_plotting_order = get_tech_plotting_order(c) power_unit = get_unit(c, "power") plot_title = "{}Dispatch Plot - {} - Stage {} - Timepoints {}-{}".format( "{} - ".format(scenario) if parsed_args.scenario_name_in_title else "", parsed_args.load_zone, parsed_args.stage, parsed_args.starting_tmp, parsed_args.ending_tmp) plot_name = "dispatchPlot-{}-{}-{}-{}".format(parsed_args.load_zone, parsed_args.stage, parsed_args.starting_tmp, parsed_args.ending_tmp) df = get_plotting_data(conn=conn, scenario_id=scenario_id, load_zone=parsed_args.load_zone, starting_tmp=parsed_args.starting_tmp, ending_tmp=parsed_args.ending_tmp, stage=parsed_args.stage) plot = create_plot( df=df, title=plot_title, power_unit=power_unit, tech_colors=tech_colors, tech_plotting_order=tech_plotting_order, ylimit=parsed_args.ylimit, ) # Show plot in HTML browser file if requested if parsed_args.show: show_plot(plot=plot, plot_name=plot_name, plot_write_directory=parsed_args.plot_write_directory, scenario=scenario) # Return plot in json format if requested if parsed_args.return_json: return json_item(plot, "plotHTMLTarget")
def main(args=None): """ Parse the arguments, get the data in a df, and create the plot :return: if requested, return the plot as JSON object """ if args is None: args = sys.argv[1:] parsed_args = parse_arguments(arguments=args) conn = connect_to_database(db_path=parsed_args.database) c = conn.cursor() scenario_id, scenario = get_scenario_id_and_name( scenario_id_arg=parsed_args.scenario_id, scenario_name_arg=parsed_args.scenario, c=c, script="carbon_plot" ) carbon_unit = get_unit(c, "carbon_emissions") cost_unit = get_unit(c, "cost") plot_title = "{}Carbon Emissions by Period - {} - Subproblem {} - Stage {}"\ .format( "{} - ".format(scenario) if parsed_args.scenario_name_in_title else "", parsed_args.carbon_cap_zone, parsed_args.subproblem, parsed_args.stage) plot_name = "CarbonPlot-{}-{}-{}".format( parsed_args.carbon_cap_zone, parsed_args.subproblem, parsed_args.stage) df = get_plotting_data( conn=conn, scenario_id=scenario_id, carbon_cap_zone=parsed_args.carbon_cap_zone, subproblem=parsed_args.subproblem, stage=parsed_args.stage ) plot = create_plot( df=df, title=plot_title, carbon_unit=carbon_unit, cost_unit=cost_unit, ylimit=parsed_args.ylimit ) # Show plot in HTML browser file if requested if parsed_args.show: show_plot(plot=plot, plot_name=plot_name, plot_write_directory=parsed_args.plot_write_directory, scenario=scenario) # Return plot in json format if requested if parsed_args.return_json: return json_item(plot, "plotHTMLTarget")
def clear(db_path, scenario_id): """ :param db_path: :param scenario_id: :return: """ conn = connect_to_database(db_path=db_path) delete_scenario_results_and_status(conn=conn, scenario_id=scenario_id)
def delete(db_path, scenario_id): """ :param db_path: :param scenario_id: :return: """ conn = connect_to_database(db_path=db_path) delete_scenario(conn=conn, scenario_id=scenario_id)
def main(args=None): """ Parse the arguments, get the data in a df, and create the plot :return: if requested, return the plot as JSON object """ if args is None: args = sys.argv[1:] parsed_args = parse_arguments(arguments=args) conn = connect_to_database(db_path=parsed_args.database) c = conn.cursor() scenario_id, scenario = get_scenario_id_and_name( scenario_id_arg=parsed_args.scenario_id, scenario_name_arg=parsed_args.scenario, c=c, script="curtailment_variable_heatmap_plot", ) energy_unit = get_unit(c, "energy") plot_title = "{}VER Curtailment by Month-Hour - {} - {} - {}".format( "{} - ".format(scenario) if parsed_args.scenario_name_in_title else "", parsed_args.load_zone, parsed_args.period, parsed_args.stage, ) plot_name = "VariableCurtailmentPlot-{}-{}-{}".format( parsed_args.load_zone, parsed_args.period, parsed_args.stage) df = get_plotting_data( conn=conn, scenario_id=scenario_id, load_zone=parsed_args.load_zone, period=parsed_args.period, stage=parsed_args.stage, ) plot = create_plot(df=df, title=plot_title, energy_unit=energy_unit, ylimit=parsed_args.ylimit) # Show plot in HTML browser file if requested if parsed_args.show: show_plot( plot=plot, plot_name=plot_name, plot_write_directory=parsed_args.plot_write_directory, scenario=scenario, ) # Return plot in json format if requested if parsed_args.return_json: return json_item(plot, "plotHTMLTarget")
def connect_to_db_and_update_run_status(db_path, scenario_id, status_id): conn = connect_to_database(db_path=db_path) c = conn.cursor() scenario_name = get_scenario_name_from_scenario_id( cursor=c, scenario_id=scenario_id ) # Check if running from queue queue_order_id = check_if_in_queue(db_path, scenario_id) remove_from_queue_if_in_queue(db_path, scenario_id, queue_order_id) update_run_status(db_path=db_path, scenario=scenario_name, status_id=status_id)
def remove_scenario_from_queue(db_path, scenario_id): conn = connect_to_database(db_path=db_path) c = conn.cursor() sql = """ UPDATE scenarios SET queue_order_id = NULL, run_status_id = 0 WHERE scenario_id = ?; """ spin_on_database_lock(conn=conn, cursor=c, sql=sql, data=(scenario_id,), many=False)
def get(self): conn = connect_to_database(db_path=self.db_path) c = conn.cursor() validation_status_api = c.execute(""" SELECT validation_status_name, COUNT(validation_status_id) FROM scenarios JOIN mod_validation_status_types USING (validation_status_id) GROUP BY validation_status_name """).fetchall() return validation_status_api
def main(args=None): """ :return: """ if args is None: args = sys.argv[1:] parsed_arguments = parse_arguments(args=args) db_path = parsed_arguments.database scenario_id_arg = parsed_arguments.scenario_id scenario_name_arg = parsed_arguments.scenario scenario_location = parsed_arguments.scenario_location conn = connect_to_database(db_path=db_path) c = conn.cursor() if not parsed_arguments.quiet: print("Processing results... (connected to database {})".format(db_path)) scenario_id, scenario_name = get_scenario_id_and_name( scenario_id_arg=scenario_id_arg, scenario_name_arg=scenario_name_arg, c=c, script="process_results", ) # Determine scenario directory scenario_directory = determine_scenario_directory( scenario_location=scenario_location, scenario_name=scenario_name ) # Go through modules modules_to_use = determine_modules(scenario_directory=scenario_directory) loaded_modules = load_modules(modules_to_use) # Subscenarios subscenarios = SubScenarios(conn=conn, scenario_id=scenario_id) process_results( loaded_modules=loaded_modules, db=conn, cursor=c, scenario_id=scenario_id, subscenarios=subscenarios, quiet=parsed_arguments.quiet, ) # Close the database connection conn.close()
def main(args=None): """ Parse the arguments, get the data in a df, and create the plot :return: if requested, return the plot as JSON object """ if args is None: args = sys.argv[1:] parsed_args = parse_arguments(arguments=args) conn = connect_to_database(db_path=parsed_args.database) c = conn.cursor() scenario_id, scenario = get_scenario_id_and_name( scenario_id_arg=parsed_args.scenario_id, scenario_name_arg=parsed_args.scenario, c=c, script="capacity_factor_plot", ) tech_colors = get_tech_colors(c) plot_title = "{}Capacity Factors by Period - {} - Stage {}".format( "{} - ".format(scenario) if parsed_args.scenario_name_in_title else "", parsed_args.load_zone, parsed_args.stage, ) plot_name = "CapFactorPlot-{}-{}".format(parsed_args.load_zone, parsed_args.stage) df = get_plotting_data( conn=conn, scenario_id=scenario_id, load_zone=parsed_args.load_zone, stage=parsed_args.stage, ) plot = create_plot(df=df, title=plot_title, tech_colors=tech_colors) # Show plot in HTML browser file if requested if parsed_args.show: show_plot( plot=plot, plot_name=plot_name, plot_write_directory=parsed_args.plot_write_directory, scenario=scenario, ) # Return plot in json format if requested if parsed_args.return_json: return json_item(plot, "plotHTMLTarget")
def exit_gracefully(): print('Exiting gracefully') args = sys.argv[1:] parsed_args = parse_arguments(args) conn = connect_to_database(db_path=parsed_args.database) c = conn.cursor() sql = """ UPDATE scenarios SET queue_order_id = NULL; """ conn.commit() spin_on_database_lock(conn=conn, cursor=c, sql=sql, data=(), many=False)
def check_scenario_run_status(db_path, scenario_id): """ Check if there is any running process that contains the given scenario """ conn = connect_to_database(db_path=db_path) c = conn.cursor() run_status, process_id = c.execute(""" SELECT run_status_name, run_process_id FROM scenarios JOIN mod_run_status_types USING (run_status_id) WHERE scenario_id = {} """.format(scenario_id)).fetchone() return run_status, process_id
def create_input_data_table_api(db_path, table_type, ui_table_name_in_db, ui_row_name_in_db, scenario_id): """ :param db_path: :param table_type: :param ui_table_name_in_db: :param ui_row_name_in_db: :param scenario_id: :return: """ # Convert scenario_id to integer, as it's passed as string scenario_id = int(scenario_id) # Connect to database conn = connect_to_database(db_path=db_path) c = conn.cursor() # Make the data table API data_table_api = dict() row_metadata = c.execute("""SELECT ui_row_caption, ui_row_db_{}_table, ui_row_db_subscenario_table_id_column FROM ui_scenario_detail_table_row_metadata WHERE ui_table = '{}' AND ui_table_row = '{}'""".format( table_type, ui_table_name_in_db, ui_row_name_in_db)).fetchone() data_table_api["caption"] = row_metadata[0] input_table = row_metadata[1] subscenario_id_column = row_metadata[2] # Get the subscenario_id for the scenario if scenario_id == 0: subscenario_id = "all" else: subscenario_id = c.execute( """SELECT {} FROM scenarios WHERE scenario_id = {}""".format( subscenario_id_column, scenario_id)).fetchone()[0] column_names, data_rows = get_table_data( c=c, input_table=input_table, subscenario_id_column=subscenario_id_column, subscenario_id=subscenario_id, ) data_table_api["columns"] = column_names data_table_api["rowsData"] = data_rows return data_table_api
def add_scenario_to_queue(db_path, scenario_id): conn = connect_to_database(db_path=db_path) c = conn.cursor() next_queue_id = get_max_queue_order_id(c=c) + 1 sql = """ UPDATE scenarios SET queue_order_id = ?, run_status_id = 5 WHERE scenario_id = ?; """ spin_on_database_lock( conn=conn, cursor=c, sql=sql, data=(next_queue_id, scenario_id), many=False )
def add_or_update_scenario(db_path, msg): """ :param db_path: the database path :param msg: the client message :return: None Create or update a scenario. If the scenario name already exists, we will update the scenario; otherwise, a new scenario is created. """ conn = connect_to_database(db_path=db_path) c = conn.cursor() # Check if this is a new scenario or if we're updating an existing scenario # TODO: implement UI warnings if scenario exists scenario_exists = c.execute("SELECT scenario_name" " FROM scenarios " "WHERE scenario_name = '{}';".format( msg["scenarioName"])).fetchone() if scenario_exists is not None: print("Updating scenario {}".format(msg["scenarioName"])) # TODO: need a process for dealing with updating scenarios that have # been run update_scenario_multiple_columns( io=conn, c=c, scenario_name=msg["scenarioName"], column_values_dict=make_column_values_dict(db_path=db_path, msg=msg), ) else: print("Inserting new scenario {}".format(msg["scenarioName"])) create_scenario( io=conn, c=c, column_values_dict=make_column_values_dict(db_path=db_path, msg=msg), ) scenario_id = c.execute( "SELECT scenario_id FROM scenarios WHERE scenario_name = '{}'".format( msg["scenarioName"])).fetchone()[0] emit("return_new_scenario_id", scenario_id)
def get(self): conn = connect_to_database(db_path=self.db_path) c = conn.cursor() scenarios_query = c.execute( """SELECT scenario_id, scenario_name, validation_status, run_status FROM scenarios_view ORDER by scenario_id ASC;""") scenarios_api = [] for s in scenarios_query: # TODO: make this more robust than relying on column order scenarios_api.append({ 'id': s[0], 'name': s[1], 'validationStatus': s[2], 'runStatus': s[3] }) return scenarios_api
def check_if_in_queue(db_path, scenario): """ :param db_path: :param scenario: :return: Check if we're running from the queue """ conn = connect_to_database(db_path=db_path) c = conn.cursor() queue_order_id = c.execute(""" SELECT queue_order_id FROM scenarios WHERE scenario_name = '{}' """.format(scenario)).fetchone()[0] conn.close() return queue_order_id
def get(self): """ :return: """ conn = connect_to_database(db_path=self.db_path) c = conn.cursor() tables_query = c.execute("""SELECT results_table, caption FROM ui_scenario_results_table_metadata WHERE include = 1;""").fetchall() included_tables_api = [] for table in tables_query: table_api = { "table": table[0].replace("_", "-"), "caption": table[1] } included_tables_api.append(table_api) return included_tables_api
def update_run_status(db_path, scenario, status_id): """ :param db_path: :param scenario: :param status_id: :return: Update the run status in the database for the scenario. """ conn = connect_to_database(db_path=db_path) c = conn.cursor() sql = """ UPDATE scenarios SET run_status_id = ? WHERE scenario_name = ?; """ spin_on_database_lock(conn=conn, cursor=c, sql=sql, data=(status_id, scenario), many=False)
def get(self): conn = connect_to_database(db_path=self.db_path) c = conn.cursor() all_tables = c.execute("""SELECT ui_table FROM ui_scenario_detail_table_metadata WHERE include = 1 ORDER BY ui_table_id ASC;""").fetchall() scenario_new_api = {"allRowIdentifiers": None, "SettingsTables": []} for ui_table in all_tables: row_identifiers, settings_tables = create_scenario_new_api( c=c, ui_table_name_in_db=ui_table[0]) if scenario_new_api["allRowIdentifiers"] is None: scenario_new_api["allRowIdentifiers"] = row_identifiers else: for row_id in row_identifiers: scenario_new_api["allRowIdentifiers"].append(row_id) scenario_new_api["SettingsTables"].append(settings_tables) return scenario_new_api
def exit_gracefully(): """ Clean up before exit """ print("Exiting gracefully") args = sys.argv[1:] parsed_args = parse_arguments(args) db_path = parsed_args.database conn = connect_to_database(db_path) scenario_id, scenario = get_scenario_id_and_name( scenario_id_arg=parsed_args.scenario_id, scenario_name_arg=parsed_args.scenario, c=conn.cursor(), script="run_end_to_end", ) # Check if running from queue queue_order_id = check_if_in_queue(db_path, scenario) remove_from_queue_if_in_queue(db_path, scenario, queue_order_id) update_run_status(db_path, scenario, 4) conn.close()