Example #1
0
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
Example #2
0
    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)
Example #3
0
    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()
Example #5
0
    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()
Example #7
0
    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()
Example #9
0
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
Example #10
0
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()))
Example #11
0
 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()
Example #12
0
 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()]
Example #13
0
 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)
Example #14
0
    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
Example #15
0
 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()),
     ))
Example #16
0
 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)
Example #17
0
    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)
Example #18
0
 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()
Example #19
0
 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()
Example #21
0
 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
Example #22
0
 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()
Example #23
0
    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()
Example #24
0
 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()
Example #25
0
 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()
Example #26
0
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()
Example #27
0
 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()
Example #28
0
 def sync(self) -> None:
     self.data.update({
         "project": ProjectParameter.select().iterator(),
         "database": DatabaseParameter.select().iterator(),
         "activity": ActivityParameter.select().iterator(),
     })