def test_delete_activity_param(qtbot): """ Remove activity parameters. """ project_db_tab = ParameterDefinitionTab() qtbot.addWidget(project_db_tab) project_db_tab.build_tables() table = project_db_tab.activity_table rect = table.visualRect(table.proxy_model.index(0, 0)) qtbot.mouseClick(table.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) group = table.get_current_group() # Now delete the parameter for the selected row. table.delete_parameter(table.currentIndex()) assert table.rowCount() == 2 assert ActivityParameter.select().count() == 2 assert Group.get_or_none(name=group) # And delete the other two parameters one by one. table.delete_parameter(table.proxy_model.index(0, 0)) table.delete_parameter(table.proxy_model.index(0, 0)) assert table.rowCount() == 0 assert ActivityParameter.select().count() == 0 # Group is automatically removed with the last parameter gone assert Group.get_or_none(name=group) is None
def get_usable_parameters(self): """ Use the `key` set for the table to determine the database and group of the activity, using that information to constrain the usable parameters. """ project = ([k, v, "project"] for k, v in ProjectParameter.static().items()) if self.key is None: return project database = ([k, v, "database"] for k, v in DatabaseParameter.static(self.key[0]).items()) # Determine if the activity is already part of a parameter group. query = (Group.select().join( ActivityParameter, on=(Group.name == ActivityParameter.group)).where( ActivityParameter.database == self.key[0], ActivityParameter.code == self.key[1]).distinct()) if query.exists(): group = query.get() # First, build a list for parameters in the same group activity = ([p.name, p.amount, "activity"] for p in ActivityParameter.select().where( ActivityParameter.group == group.name)) # Then extend the list with parameters from groups in the `order` # field additions = ([p.name, p.amount, "activity"] for p in ActivityParameter.select().where( ActivityParameter.group << group.order)) activity = itertools.chain(activity, additions) else: activity = [] return itertools.chain(project, database, activity)
def delete_parameter(self, proxy) -> None: """ Override the base method to include additional logic. If there are multiple `ActivityParameters` for a single activity, only delete the selected instance, otherwise use `bw.parameters.remove_from_group` to clear out the `ParameterizedExchanges` as well. """ key = self.get_key(proxy) query = (ActivityParameter.select() .where(ActivityParameter.database == key[0], ActivityParameter.code == key[1])) if query.count() > 1: super().delete_parameter(proxy) else: act = bw.get_activity(key) group = self.get_current_group(proxy) bw.parameters.remove_from_group(group, act) # Also clear the group if there are no more parameters in it exists = (ActivityParameter.select() .where(ActivityParameter.group == group).exists()) if not exists: with bw.parameters.db.atomic(): Group.delete().where(Group.name == group).execute() bw.parameters.recalculate() signals.parameters_changed.emit()
def test_delete_parameterized_exchange(): db = DatabaseChooser("example") db.register() a = db.new_activity(code="A", name="An activity") a.save() b = db.new_activity(code="B", name="Another activity") b.save() exc = a.new_exchange(amount=0, input=b, type="technosphere", formula="foo * bar + 4") exc.save() activity_data = [{ 'name': 'reference_me', 'formula': 'sqrt(25)', 'database': 'example', 'code': "B", }, { 'name': 'bar', 'formula': 'reference_me + 2', 'database': 'example', 'code': "A", }] parameters.new_activity_parameters(activity_data, "my group") parameters.add_exchanges_to_group("my group", a) assert ActivityParameter.select().count() == 2 assert ParameterizedExchange.select().count() == 1 exc.delete() assert ActivityParameter.select().count() == 2 assert not ParameterizedExchange.select().count()
def delete_parameter(self, parameter: ParameterBase) -> None: """ Remove the given parameter from the project. If there are multiple `ActivityParameters` for a single activity, only delete the selected instance, otherwise use `bw.parameters.remove_from_group` to clear out the `ParameterizedExchanges` as well. """ if isinstance(parameter, ActivityParameter): db = parameter.database code = parameter.code amount = (ActivityParameter.select() .where((ActivityParameter.database == db) & (ActivityParameter.code == code)) .count()) if amount > 1: with bw.parameters.db.atomic(): parameter.delete_instance() else: group = parameter.group act = bw.get_activity((db, code)) bw.parameters.remove_from_group(group, act) # Also clear the group if there are no more parameters in it exists = (ActivityParameter.select() .where(ActivityParameter.group == group).exists()) if not exists: with bw.parameters.db.atomic(): Group.delete().where(Group.name == group).execute() else: with bw.parameters.db.atomic(): parameter.delete_instance() # After deleting things, recalculate and signal changes bw.parameters.recalculate() signals.parameters_changed.emit()
def test_delete_activity_parameters(): db = DatabaseChooser("example") db.register() a = db.new_activity(code="A", name="An activity") a.save() b = db.new_activity(code="B", name="Another activity") b.save() a.new_exchange( amount=0, input=b, type="technosphere", formula="foo * bar + 4" ).save() activity_data = [ { "name": "reference_me", "formula": "sqrt(25)", "database": "example", "code": "B", }, { "name": "bar", "formula": "reference_me + 2", "database": "example", "code": "A", }, ] parameters.new_activity_parameters(activity_data, "my group") parameters.add_exchanges_to_group("my group", a) assert ActivityParameter.select().count() == 2 assert ParameterizedExchange.select().count() == 1 a.delete() assert ActivityParameter.select().count() == 1 assert not ParameterizedExchange.select().count()
def _prepare_activity_parameters(self, data=None, delete_existing=True): data = self.data if data is None else data def supplement_activity_parameter(ds, dct): dct.update({'database': self.db_name, 'code': ds['code']}) if 'group' not in dct: dct['group'] = "{}:{}".format(dct['database'], dct['code']) return dct activity_parameters = [ supplement_activity_parameter(ds, dct) for ds in data for dct in ds.pop("parameters", []) ] by_group = lambda x: x['group'] activity_parameters = sorted(activity_parameters, key=by_group) # Delete all parameterized exchanges because # all exchanges are re-written, even on # update, which means ids are unreliable # Must add exchanges again manually bad_groups = tuple({o[0] for o in ActivityParameter.select( ActivityParameter.group).where( ActivityParameter.database == self.db_name ).tuples()}) ParameterizedExchange.delete().where( ParameterizedExchange.group << bad_groups ).execute() if delete_existing: # Delete existing parameters and p. exchanges if necessary ActivityParameter.delete().where(ActivityParameter.group << bad_groups ).execute() else: # Delete activity parameters # where the group name changed name_changed = tuple({o[0] for o in ActivityParameter.select( ActivityParameter.group).where( ActivityParameter.database == self.db_name, ActivityParameter.code << tuple( [m['code'] for m in activity_parameters] ), ~(ActivityParameter.group << tuple( [m['group'] for m in activity_parameters] )) ).tuples()}) ActivityParameter.delete().where(ActivityParameter.group << name_changed ).execute() return activity_parameters
def delete_activity(self, key): act = bw.get_activity(key) nu = len(act.upstream()) if nu: text = "activities consume" if nu > 1 else "activity consumes" QtWidgets.QMessageBox.information( None, "Not possible.", """Can't delete {}. {} upstream {} its reference product. Upstream exchanges must be modified or deleted.""".format(act, nu, text) ) else: # Check if the activity is parameterized: query = ActivityParameter.select().where( ActivityParameter.database == act[0], ActivityParameter.code == act[1] ) if query.exists(): # Remove all activity parameters Controller.delete_activity_parameter(act.key) act.delete() bw.databases.set_modified(act["database"]) signals.metadata_changed.emit(act.key) signals.database_changed.emit(act["database"]) signals.databases_changed.emit() signals.calculation_setup_changed.emit()
def test_create_activity_param(qtbot): """ Create several activity parameters. TODO: Figure out some way of performing a drag action between tables. Use method calls for now. Until the above is implemented, take shortcuts and don't check db validity """ project_db_tab = ParameterDefinitionTab() qtbot.addWidget(project_db_tab) project_db_tab.build_tables() table = project_db_tab.activity_table # Open the order column just because we can col = table.COLUMNS.index("order") assert table.isColumnHidden(col) with qtbot.waitSignal(project_db_tab.show_order.stateChanged, timeout=1000): qtbot.mouseClick(project_db_tab.show_order, QtCore.Qt.LeftButton) assert not table.isColumnHidden(col) # Create multiple parameters for a single activity act_key = ("testdb", "act1") for _ in range(3): table.add_parameter(act_key) # Test created parameters assert ActivityParameter.select().count() == 3 # First of the multiple parameters assert table.proxy_model.index(0, 0).data() == "act_1" # Second of the multiple parameters assert table.proxy_model.index(1, 0).data() == "act_2" # The group name for the `testdb` parameters is the same. loc = table.visualRect(table.proxy_model.index(0, 0)) qtbot.mouseClick(table.viewport(), QtCore.Qt.LeftButton, pos=loc.center()) group = table.get_current_group() assert table.proxy_model.index(2, table.COLUMNS.index("group")).data() == group
def process_brightway_parameters() -> Iterable[tuple]: """ Converts brightway parameters of all types into a simple structure in order of possible dependency. """ return itertools.chain( ((p.name, "project", p.amount) for p in ProjectParameter.select()), ((p.name, p.database, p.amount) for p in DatabaseParameter.select()), ((p.name, p.group, p.amount) for p in ActivityParameter.select()))
def recalculate_exchanges(): """ Will iterate through all activity parameters and rerun the formula interpretation for all exchanges. """ for param in ActivityParameter.select().iterator(): act = bw.get_activity((param.database, param.code)) bw.parameters.add_exchanges_to_group(param.group, act) ActivityParameter.recalculate_exchanges(param.group) signals.parameters_changed.emit()
def __init__(self): self._project_params = ProjectParameter.load() self._db_params = { p.database: DatabaseParameter.load(p.database) for p in DatabaseParameter.select( DatabaseParameter.database).distinct() } self._act_params = { p.group: ActivityParameter.load(p.group) for p in ActivityParameter.select( ActivityParameter.group).distinct() } self._distinct_act_params = [ p for p in (ActivityParameter.select(ActivityParameter.group, ActivityParameter.database).distinct()) ] self._exc_params = [p for p in ParameterizedExchange.select()]
def __init__(self, seed: Optional[int] = None): super().__init__() parameters = itertools.chain(ProjectParameter.select(), DatabaseParameter.select(), ActivityParameter.select()) self.uncertainties = UncertaintyBase.from_dicts( *[getattr(p, "data", {}) for p in parameters]) self.mc_generator = MCRandomNumberGenerator(self.uncertainties, seed=seed)
def recalculate_scenario( self, scenario_values: Iterable[float]) -> (np.ndarray, np.ndarray): """ Convenience function that takes new parameter values and returns a fully-formed set of exchange amounts and indices. All parameter types are recalculated in turn before interpreting the ParameterizedExchange formulas into amounts. """ self.param_values = replace_amounts(self.param_values, scenario_values) global_project = self.recalculate_project_parameters() all_db = {} for p in DatabaseParameter.select( DatabaseParameter.database).distinct(): db = self.recalculate_database_parameters(p.database, global_project) all_db[p.database] = {x: y for x, y in db.items()} if db else {} complete_data = [] complete_indices = [] for p in ActivityParameter.select( ActivityParameter.group, ActivityParameter.database).distinct(): combination = {x: y for x, y in global_project.items() } if global_project else {} combination.update(all_db.get(p.database, {})) act = self.recalculate_activity_parameters(p.group, combination) combination.update(act) recalculated = self.recalculate_exchanges( p.group, global_params=combination) # If the parameter group contains no ParameterizedExchanges, skip. if not recalculated: continue # `data` contains the recalculated amounts for the exchanges. ids, data = zip(*recalculated) indices = [] for pk in ids: exc = ExchangeDataset.get_by_id(pk) input_key = (exc.input_database, exc.input_code) output_key = (exc.output_database, exc.output_code) if exc.input_database == bw.config.biosphere: indices.append((input_key, output_key, "biosphere")) else: indices.append((input_key, output_key, "technosphere")) complete_data.extend(data) complete_indices.extend(indices) # After recalculating all the exchanges and adding all samples and indices # to lists, format them according to presamples requirements: # eg: samples as a column of floats and indices as a row of tuples. samples = np.array(complete_data) samples = samples.reshape(1, -1).T indices = np.array(complete_indices) return samples, indices
def from_bw_parameters(cls) -> 'Parameters': """Construct a Parameters list from brightway2 parameters.""" return cls(chain( (Parameter(p.name, "project", p.amount, "project") for p in ProjectParameter.select()), (Parameter(p.name, p.database, p.amount, "database") for p in DatabaseParameter.select()), (Parameter(p.name, p.group, p.amount, "activity") for p in ActivityParameter.select()), ))
def get_activity_groups(self, proxy, ignore_groups: list = None): """ Helper method to look into the Group and determine which if any other groups the current activity can depend on """ db = self.get_key(proxy)[0] ignore_groups = [] if ignore_groups is None else ignore_groups return (param.group for param in ( ActivityParameter.select(ActivityParameter.group).where( ActivityParameter.database == db).distinct()) if param.group not in ignore_groups)
def get_usable_parameters(): """ Include all types of parameters. NOTE: This method does not take into account which formula is being edited, and therefore does not restrict which database or activity parameters are returned. """ database = DataBaseParameterTable.get_usable_parameters() activity = ([p.name, p.amount, "activity ({})".format(p.group)] for p in ActivityParameter.select()) return itertools.chain(database, activity)
def sync(self, *args, **kwargs) -> None: self.beginResetModel() self.root.clear() self.endResetModel() self._data.update({ "project": ProjectParameter.select().iterator(), "database": DatabaseParameter.select().iterator(), "activity": ActivityParameter.select().iterator(), }) self.setup_model_data() self.updated.emit()
def get_activity_parameters(self, act): data = [ o.dict for o in ActivityParameter.select().where( ActivityParameter.database == act[0], ActivityParameter.code == act[1], ) ] if not data: return {} dct = self.order_dicts(data, "parameter") dct["group"] = ActivityParameter.get(database=act[0], code=act[1],).group return dct
def delete_activity_parameter(key: tuple) -> None: """Remove all activity parameters and underlying exchange parameters for the given key. """ query = ActivityParameter.select(ActivityParameter.group).where( ActivityParameter.database == key[0], ActivityParameter.code == key[1], ) for p in query.iterator(): bw.parameters.remove_from_group(p.group, key) bw.parameters.recalculate() signals.parameters_changed.emit()
def build_df(cls): """ Build a dataframe using the ActivityParameters set in brightway """ data = [ cls.parse_parameter(p) for p in (ActivityParameter.select(ActivityParameter, Group.order). join(Group, on=(ActivityParameter.group == Group.name )).namedtuples()) ] df = pd.DataFrame(data, columns=cls.combine_columns()) # Convert the 'order' column from list into string df["order"] = df["order"].apply(", ".join) return df
def sync(self) -> None: """ Build a dataframe using the ActivityParameters set in brightway """ generate = (self.parse_parameter(p) for p in ( ActivityParameter.select(ActivityParameter, Group.order).join( Group, on=( ActivityParameter.group == Group.name)).namedtuples())) data = [x for x in generate if "key" in x] self._dataframe = pd.DataFrame(data, columns=self.columns()) # Convert the 'order' column from list into string self._dataframe["order"] = self._dataframe["order"].apply(", ".join) self.group_col = self._dataframe.columns.get_loc("group") self.param_col = self._dataframe.columns.get_loc("parameter") self.key_col = self._dataframe.columns.get_loc("key") self.order_col = self._dataframe.columns.get_loc("order") self.updated.emit()
def parameterize_exchanges(self, key: tuple) -> None: """ Used whenever a formula is set on an exchange in an activity. If no `ActivityParameter` exists for the key, generate one immediately """ group = bc.build_activity_group_name(key) if not (ActivityParameter.select() .where(ActivityParameter.group == group).count()): ActivityParameterTable.add_parameter(key) act = bw.get_activity(key) with bw.parameters.db.atomic(): bw.parameters.remove_exchanges_from_group(group, act) bw.parameters.add_exchanges_to_group(group, act) ActivityParameter.recalculate_exchanges(group) signals.parameters_changed.emit()
def clear_broken_activity_parameter(database: str, code: str, group: str) -> None: """Take the given information and attempt to remove all of the downstream parameter information. """ with bw.parameters.db.atomic() as txn: bw.parameters.remove_exchanges_from_group(group, None, False) ActivityParameter.delete().where( ActivityParameter.database == database, ActivityParameter.code == code ).execute() # Do commit to ensure .exists() call does not include deleted params txn.commit() exists = (ActivityParameter.select() .where(ActivityParameter.group == group) .exists()) if not exists: # Also clear Group if it is not in use anymore Group.delete().where(Group.name == group).execute()
def add_parameter(self, key: tuple) -> None: """ Given the activity key, generate a new row with data from the activity and immediately call `new_activity_parameters`. """ act = bw.get_activity(key) prep_name = bc.clean_activity_name(act.get("name")) group = bc.build_activity_group_name(key, prep_name) count = (ActivityParameter.select().where( ActivityParameter.group == group).count()) row = { "name": "{}_{}".format(prep_name, count + 1), "amount": act.get("amount", 1.0), "formula": act.get("formula", ""), "database": key[0], "code": key[1], } # Save the new parameter immediately. bw.parameters.new_activity_parameters([row], group) signals.parameters_changed.emit()
def test_database_delete_parameters(): db = DatabaseChooser("example") db.register() a = db.new_activity(code="A", name="An activity") a.save() b = db.new_activity(code="B", name="Another activity") b.save() a.new_exchange(amount=0, input=b, type="technosphere", formula="foo * bar + 4").save() database_data = [{ 'name': 'red', 'formula': '(blue ** 2) / 5', }, { 'name': 'blue', 'amount': 12 }] parameters.new_database_parameters(database_data, "example") activity_data = [{ 'name': 'reference_me', 'formula': 'sqrt(red - 20)', 'database': 'example', 'code': "B", }, { 'name': 'bar', 'formula': 'reference_me + 2', 'database': 'example', 'code': "A", }] parameters.new_activity_parameters(activity_data, "my group") parameters.add_exchanges_to_group("my group", a) assert ActivityParameter.select().count() == 2 assert ParameterizedExchange.select().count() == 1 assert DatabaseParameter.select().count() == 2 assert len(parameters) == 4 del databases['example'] assert not len(parameters) assert not ParameterizedExchange.select().count()
def delete_activity_parameter(key: tuple) -> None: """Remove all activity parameters and underlying exchange parameters for the given activity key. """ query = (ActivityParameter .select(ActivityParameter.group) .where((ActivityParameter.database == key[0]) & (ActivityParameter.code == key[1])) .tuples()) if not query.exists(): return groups = set(p[0] for p in query) for group in groups: bw.parameters.remove_from_group(group, key) exists = (ActivityParameter.select() .where(ActivityParameter.group == group) .exists()) if not exists: Group.delete().where(Group.name == group).execute() bw.parameters.recalculate() signals.parameters_changed.emit()
def sync(self) -> None: self.data.update({ "project": ProjectParameter.select().iterator(), "database": DatabaseParameter.select().iterator(), "activity": ActivityParameter.select().iterator(), })