Example #1
0
def test_create_project_param(qtbot):
    """ Create a single Project parameter.

    Does not user the overarching application due to mouseClick failing
    """
    assert bw.projects.current == "pytest_project"
    assert ProjectParameter.select().count() == 0

    project_db_tab = ParameterDefinitionTab()
    qtbot.addWidget(project_db_tab)
    project_db_tab.build_tables()
    table = project_db_tab.project_table

    signal_list = [
        signals.parameters_changed, signals.parameters_changed,
        signals.parameters_changed
    ]
    with qtbot.waitSignals(signal_list, timeout=1000):
        qtbot.mouseClick(project_db_tab.new_project_param, QtCore.Qt.LeftButton)
        qtbot.mouseClick(project_db_tab.new_project_param, QtCore.Qt.LeftButton)
        qtbot.mouseClick(project_db_tab.new_project_param, QtCore.Qt.LeftButton)
    assert table.rowCount() == 3

    # New parameter is named 'param_1'
    assert table.model.index(0, 0).data() == "param_1"
    assert ProjectParameter.select().count() == 3
    assert ProjectParameter.get_or_none(name="param_1") is not None
Example #2
0
def test_edit_project_param(qtbot, monkeypatch):
    """ Edit the existing parameter to have new values.
    """
    table = ProjectParameterTable()
    qtbot.addWidget(table)
    table.model.sync()

    # Edit both the name and the amount of the first parameter.
    monkeypatch.setattr(
        QtWidgets.QInputDialog, "getText",
        staticmethod(lambda *args, **kwargs: ("test_project", True)))
    table.model.handle_parameter_rename(table.proxy_model.index(0, 0))
    table.model.setData(table.model.index(0, 1), 2.5)

    # Check that parameter is correctly stored in brightway.
    assert ProjectParameter.get(name="test_project").amount == 2.5

    # Now edit the formula directly (without delegate)
    with qtbot.waitSignal(signals.parameters_changed, timeout=1000):
        table.model.setData(table.model.index(0, 2), "2 + 3")
    assert ProjectParameter.get(name="test_project").amount == 5

    # Now edit the formula of the 3rd param to use the 2nd param
    with qtbot.waitSignal(signals.parameters_changed, timeout=1000):
        table.model.setData(table.model.index(2, 2), "param_2 + 3")
    assert ProjectParameter.get(name="param_3").amount == 4
Example #3
0
def resetParams(db_name):
    """Reset project and activity parameters"""
    _param_registry().clear()
    ProjectParameter.delete().execute()
    ActivityParameter.delete().execute()
    DatabaseParameter.delete().execute()
    Group.delete().execute()
def test_update_alter_mean(qtbot, monkeypatch, ab_app):
    param = ProjectParameter.create(name="uc2", amount=1)
    wizard = UncertaintyWizard(param, None)
    qtbot.addWidget(wizard)
    wizard.show()

    # Select the lognormal distribution and set 'loc' and 'scale' fields.
    wizard.type.distribution.setCurrentIndex(LognormalUncertainty.id)
    wizard.type.loc.setText("1")
    wizard.type.scale.setText("0.3")
    wizard.type.generate_plot()
    assert wizard.type.complete

    # Now, monkeypatch Qt to ensure a 'yes' is selected for updating.
    monkeypatch.setattr(QMessageBox, "question",
                        staticmethod(lambda *args: QMessageBox.Yes))
    # Now trigger a 'finish' action
    with qtbot.waitSignal(signals.parameters_changed, timeout=100):
        wizard.button(QWizard.FinishButton).click()

    # Reload param and check that the amount is changed.
    param = ProjectParameter.get(name="uc2")
    assert "loc" in param.data and param.amount != 1
    loc = param.data["loc"]
    assert loc == 1
    assert np.isclose(np.log(param.amount), loc)
Example #5
0
def test_create_project_param(qtbot):
    """ Create a single Project parameter.

    Does not user the overarching application due to mouseClick failing
    """
    assert bw.projects.current == "pytest_project"
    assert ProjectParameter.select().count() == 0

    project_db_tab = ParameterDefinitionTab()
    qtbot.addWidget(project_db_tab)
    project_db_tab.build_tables()
    table = project_db_tab.project_table

    bw.parameters.new_project_parameters([
        {
            "name": "param_1",
            "amount": 1.0
        },
        {
            "name": "param_2",
            "amount": 1.0
        },
        {
            "name": "param_3",
            "amount": 1.0
        },
    ])
    table.model.sync()
    assert table.rowCount() == 3

    # New parameter is named 'param_1'
    assert table.model.index(0, 0).data() == "param_1"
    assert ProjectParameter.select().count() == 3
    assert ProjectParameter.select().where(
        ProjectParameter.name == "param_1").exists()
Example #6
0
def test_append_package():
    ProjectParameter.create(
        name="p1",
        amount=1,
    )
    ProjectParameter.create(
        name="p2",
        amount=1,
    )
    parameters.recalculate()
    pbm = ParameterizedBrightwayModel("project")
    pbm.load_parameter_data()
    pbm.calculate_static()
    for obj in pbm.data.values():
        obj['amount'] = 10
    _, dirpath = pbm.save_presample('project-test')
    pp = PresamplesPackage(dirpath)
    assert len(pp) == 1
    assert pp.parameters['project__p1'] == 10

    Database("db").register()
    Group.create(name="D", order=[])
    DatabaseParameter.create(
        database="db",
        name="db1",
        formula="2 * p1",
        amount=2,
    )
    DatabaseParameter.create(
        database="db",
        name="db2",
        amount=2,
    )
    ActivityParameter.create(
        group="D",
        database="db",
        code="D1",
        name="d1",
        formula="p1 + db1",
        amount=3,
    )
    parameters.recalculate()
    pbm = ParameterizedBrightwayModel("D")
    pbm.load_existing(dirpath)
    expected = {'project__p1': 10, 'project__p2': 10}
    assert pbm.global_params == expected

    pbm.load_parameter_data()
    pbm.data = {'D__d1': pbm.data['D__d1']}
    pbm.data['D__d1']['amount'] = 12
    _, dp = pbm.append_presample(dirpath, 'D-test')
    assert dp == dirpath
    pp = PresamplesPackage(dirpath)
    assert len(pp) == 2
    assert pp.parameters['D__d1'] == 12
    assert pp.parameters['project__p1'] == 10
Example #7
0
def test_calculate_stochastic():
    Database("db").register()
    ProjectParameter.create(
        name="p1",
        amount=1,
    )
    ProjectParameter.create(
        name="p2",
        amount=1,
    )
    parameters.recalculate()
    pbm = ParameterizedBrightwayModel("project")
    pbm.load_parameter_data()
    pbm.data['project__p1']['amount'] = np.ones(10) + 100
    pbm.data['project__p2']['amount'] = np.ones(10) + 10
    _, dirpath_project = pbm.save_presample('project-test')

    pp = PresamplesPackage(dirpath_project)
    assert len(pp) == 1
    assert np.allclose(pp.parameters['project__p1'], np.ones(10) + 100)

    # Create rest of parameters
    Group.create(name="E", order=[])
    ActivityParameter.create(
        group="E",
        database="db",
        code="E1",
        name="e1",
        formula="p1 + p2 + e2",
        amount=4,
    )
    ActivityParameter.create(group="E",
                             database="db",
                             code="E2",
                             name="e2",
                             amount=1,
                             data={
                                 'uncertainty type': 4,
                                 'minimum': 1000,
                                 'maximum': 1100
                             })
    parameters.recalculate()
    pbm = ParameterizedBrightwayModel("E")
    pbm.load_existing(dirpath_project)
    pbm.load_parameter_data()
    result = pbm.calculate_stochastic(10)

    assert np.allclose(result['project__p1'], [101] * 10)
    assert np.allclose(result['project__p2'], [11] * 10)
    assert all(result['E__e2'] >= 1000)
    assert all(result['E__e2'] <= 1100)
    assert np.allclose(result['E__e1'], result['E__e2'] + 101 + 11)
Example #8
0
def resetParams(db_name=None):
    """Clear parameters in live memory (registry) and on disk.
    Clear either all params (project and all db params) or db params from a single database (if db_name provided)"""
    _param_registry().clear(db_name)

    if db_name is None:
        ProjectParameter.delete().execute()
        ActivityParameter.delete().execute()
        DatabaseParameter.delete().execute()
    else:
        ActivityParameter.delete().where(
            ActivityParameter.database == db_name).execute()
        DatabaseParameter.delete().where(
            DatabaseParameter.database == db_name).execute()
        Group.delete().execute()
def test_graph_rebuild(qtbot, bw2test):
    """Test that the graph is correctly built and rebuilt, ensure
    that the 'finish' button is enabled and disabled at the correct
    times.
    """
    param = ProjectParameter.create(name="test1", amount=3)
    wizard = UncertaintyWizard(param, None)
    qtbot.addWidget(wizard)
    wizard.show()

    # Check that the graph exists and distribution is 'unknown'
    assert wizard.type.plot.isVisible()
    assert wizard.type.distribution.currentIndex() == UndefinedUncertainty.id
    assert wizard.button(QWizard.FinishButton).isEnabled()
    # Select an uncertainty distribution, fill out numbers.
    with qtbot.waitSignal(wizard.type.distribution.currentIndexChanged,
                          timeout=100):
        wizard.type.distribution.setCurrentIndex(UniformUncertainty.id)
    assert not wizard.type.complete  # Missing values for valid uncertainty.
    assert not wizard.button(QWizard.FinishButton).isEnabled()

    # When programmatically changing values, no textEdited signal is emitted.
    with qtbot.assertNotEmitted(wizard.type.minimum.textEdited):
        wizard.type.minimum.setText("1")
        wizard.type.generate_plot()
    assert not wizard.type.complete  # Still missing 'maximum'
    assert not wizard.button(QWizard.FinishButton).isEnabled()

    with qtbot.assertNotEmitted(wizard.type.minimum.textEdited):
        wizard.type.maximum.setText("5")
        wizard.type.generate_plot()
    assert wizard.type.complete
    assert wizard.button(QWizard.FinishButton).isEnabled()
def test_lognormal_mean_balance(qtbot, bw2test):
    uncertain = {
        "loc": 2,
        "scale": 0.2,
        "uncertainty type": 2,
    }
    param = ProjectParameter.create(name="uc1", amount=3, data=uncertain)
    wizard = UncertaintyWizard(param, None)
    qtbot.addWidget(wizard)
    wizard.show()

    # Compare loc with mean,
    loc, mean = float(wizard.type.loc.text()), float(wizard.type.mean.text())
    assert np.isclose(np.exp(loc), mean)
    wizard.type.check_negative()
    assert not wizard.field("negative")

    # Alter mean and loc fields in turn to show balancing methods
    with qtbot.assertNotEmitted(wizard.type.mean.textEdited):
        wizard.type.mean.setText("")
        wizard.type.balance_loc_with_mean()
        wizard.type.check_negative()
    assert wizard.type.loc.text() == "nan"
    # Setting the mean to a negative number will still return the same loc
    # value, but it will alter the 'negative' field.
    with qtbot.assertNotEmitted(wizard.type.mean.textEdited):
        wizard.type.mean.setText("-5")
        wizard.type.balance_loc_with_mean()
        wizard.type.check_negative()
    assert np.isclose(np.exp(float(wizard.type.loc.text())), 5)
    assert wizard.field("negative")
Example #11
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 #12
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 #13
0
 def build_df(cls):
     """ Build a dataframe using the ProjectParameters set in brightway
     """
     data = [
         cls.parse_parameter(p) for p in ProjectParameter.select()
     ]
     df = pd.DataFrame(data, columns=cls.combine_columns())
     return df
Example #14
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 #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()),
     ))
def test_update_uncertainty(qtbot, ab_app):
    """Using the signal/controller setup, update the uncertainty of a parameter"""
    param = ProjectParameter.create(name="uc1", amount=3)
    wizard = UncertaintyWizard(param, None)
    qtbot.addWidget(wizard)
    wizard.show()

    wizard.type.distribution.setCurrentIndex(TriangularUncertainty.id)
    wizard.type.minimum.setText("1")
    wizard.type.maximum.setText("5")
    wizard.type.generate_plot()
    assert wizard.type.complete

    # Now trigger a 'finish' action
    with qtbot.waitSignal(signals.parameters_changed, timeout=100):
        wizard.button(QWizard.FinishButton).click()

    # Reload param
    param = ProjectParameter.get(name="uc1")
    assert "loc" in param.data and param.data["loc"] == 3
Example #17
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 #18
0
    def recalculate_project_parameters(self) -> Optional[dict]:
        new_values = self.get_altered_values("project")

        data = ProjectParameter.load()
        if not data:
            return

        for name, amount in new_values.items():
            data[name]["amount"] = amount

        ParameterSet(data).evaluate_and_set_amount_field()
        return self._prune_result_data(data)
Example #19
0
 def add_parameter(self) -> None:
     """ Build a new parameter and immediately store it.
     """
     counter = (ProjectParameter.select().count() +
                DatabaseParameter.select().count())
     try:
         bw.parameters.new_project_parameters([
             {"name": "param_{}".format(counter + 1), "amount": 1.0}
         ], False)
         signals.parameters_changed.emit()
     except ValueError as e:
         simple_warning_box(self, "Name already in use!", str(e))
Example #20
0
    def write_project_parameters(self, data=None, delete_existing=True):
        """Write global parameters to ``ProjectParameter`` database table.

        ``delete_existing`` controls whether new parameters will delete_existing existing parameters, or just update values. The ``name`` field is used to determine if a parameter exists.

        ``data`` should be a list of dictionaries (``self.project_parameters`` is used by default):

        .. code-block:: python

            [{
                'name': name of variable (unique),
                'amount': numeric value of variable (optional),
                'formula': formula in Python as string (optional),
                optional keys like uncertainty, etc. (no limitations)
            }]

        """
        if (data or self.project_parameters) is None:
            return
        if delete_existing:
            ProjectParameter.delete().execute()
        parameters.new_project_parameters(data or self.project_parameters)
Example #21
0
def test_edit_project_param(qtbot):
    """ Edit the existing parameter to have new values.
    """
    table = ProjectParameterTable()
    qtbot.addWidget(table)
    table.sync(table.build_df())

    # Edit both the name and the amount of the first parameter.
    table.rename_parameter(table.proxy_model.index(0, 0), "test_project")
    table.model.setData(table.model.index(0, 1), 2.5)

    # Check that parameter is correctly stored in brightway.
    assert ProjectParameter.get(name="test_project").amount == 2.5

    # Now edit the formula directly (without delegate)
    with qtbot.waitSignal(signals.parameters_changed, timeout=1000):
        table.model.setData(table.model.index(0, 2), "2 + 3")
    assert ProjectParameter.get(name="test_project").amount == 5

    # Now edit the formula of the 3rd param to use the 2nd param
    with qtbot.waitSignal(signals.parameters_changed, timeout=1000):
        table.model.setData(table.model.index(2, 2), "param_2 + 3")
    assert ProjectParameter.get(name="param_3").amount == 4
def test_pedigree(qtbot, bw2test):
    """Configure uncertainty using the pedigree page of the wizard."""
    uncertain = {
        "loc": 2,
        "scale": 0.2,
        "uncertainty type": 2,
        "pedigree": {
            "reliability": 1,
            "completeness": 2,
            "temporal correlation": 2,
            "geographical correlation": 2,
            "further technological correlation": 3
        },
    }
    param = ProjectParameter.create(name="uc1", amount=3, data=uncertain)
    wizard = UncertaintyWizard(param, None)
    qtbot.addWidget(wizard)
    wizard.show()

    # Uncertainty data has pedigree in it.
    assert "pedigree" in wizard.obj.uncertainty

    # Go to the pedigree page
    with qtbot.waitSignal(wizard.currentIdChanged, timeout=100):
        wizard.type.pedigree.click()
    assert wizard.using_pedigree  # Uncertainty/Pedigree data is valid

    loc, mean = float(wizard.pedigree.loc.text()), float(
        wizard.pedigree.mean.text())
    assert np.isclose(np.exp(loc), mean)
    # The uncertainty should be positive
    assert not wizard.field("negative")
    wizard.pedigree.check_negative()
    assert not wizard.field("negative")

    # Alter mean and loc fields in turn to show balancing methods
    with qtbot.assertNotEmitted(wizard.pedigree.mean.textEdited):
        wizard.pedigree.mean.setText("")
        wizard.pedigree.balance_loc_with_mean()
        wizard.pedigree.check_negative()
    assert wizard.pedigree.loc.text() == "nan"
    # Setting the mean to a negative number will still return the same loc
    # value, but it will alter the 'negative' field.
    with qtbot.assertNotEmitted(wizard.pedigree.mean.textEdited):
        wizard.pedigree.mean.setText("-5")
        wizard.pedigree.balance_loc_with_mean()
        wizard.pedigree.check_negative()
    assert np.isclose(np.exp(float(wizard.pedigree.loc.text())), 5)
    assert wizard.field("negative")
Example #23
0
    def add_parameter(self) -> None:
        """ Add a new database parameter to the dataframe

        NOTE: The new parameter uses the first database it can find.
        """
        counter = (ProjectParameter.select().count() +
                   DatabaseParameter.select().count())
        database = next(iter(bw.databases))
        try:
            bw.parameters.new_database_parameters([
                {"name": "param_{}".format(counter + 1), "amount": 1.0}
            ], database, False)
            signals.parameters_changed.emit()
        except ValueError as e:
            simple_warning_box(self, "Name already in use!", str(e))
Example #24
0
 def get_interpreter(self) -> Interpreter:
     """ Use the activity key to determine which symbols are added
     to the formula interpreter.
     """
     interpreter = Interpreter()
     act = ActivityParameter.get_or_none(database=self.key[0],
                                         code=self.key[1])
     if act:
         interpreter.symtable.update(
             ActivityParameter.static(act.group, full=True))
     else:
         print("No parameter found for {}, creating one on formula save".
               format(self.key))
         interpreter.symtable.update(ProjectParameter.static())
         interpreter.symtable.update(DatabaseParameter.static(self.key[0]))
     return interpreter
Example #25
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 #26
0
def export_db(db_name, filename) :
    """Export Db and linked parameters"""
    db = bw.Database(db_name)
    db_params = DatabaseParameter.select().where(DatabaseParameter.database == db_name)

    # Export Db params
    db.metadata["database_parameters"] = [param_data(param) for param in db_params]

    # List of all project params used in this dataset
    used_project_params = list(param.name for param in _listParams(db_name) if param.dbname is None)

    if len(used_project_params) > 0 :
        error('Warning : this DB uses project parameters that are exported as well and might override project params at import time : ', used_project_params)

        proj_params = list(ProjectParameter.get(ProjectParameter.name==name) for name in used_project_params)

        db.metadata["project_parameters"] = [param_data(param) for param in proj_params]

    BW2Package._write_file(filename, [BW2Package._prepare_obj(db, False)])
def test_uncertainty_wizard_simple(qtbot, bw2test, capsys):
    """Use extremely simple text to open the wizard and go to all the pages."""
    param = ProjectParameter.create(name="test1", amount=3)
    wizard = UncertaintyWizard(param, None)
    qtbot.addWidget(wizard)
    wizard.show()

    assert "uncertainty type" in wizard.uncertainty_info
    wizard.extract_uncertainty()
    wizard.extract_lognormal_loc()

    # Go to the pedigree page
    with qtbot.waitSignal(wizard.currentIdChanged, timeout=100):
        wizard.type.pedigree.click()

    # Pedigree is empty, so complaint is issued.
    captured = capsys.readouterr()
    assert "Could not extract pedigree data" in captured.out

    # Now go back for giggles.
    with qtbot.waitSignal(wizard.currentIdChanged, timeout=100):
        wizard.button(QWizard.BackButton).click()
    assert not wizard.using_pedigree
Example #28
0
 def sync(self) -> None:
     self.data.update({
         "project": ProjectParameter.select().iterator(),
         "database": DatabaseParameter.select().iterator(),
         "activity": ActivityParameter.select().iterator(),
     })
Example #29
0
 def get_interpreter() -> Interpreter:
     interpreter = Interpreter()
     interpreter.symtable.update(ProjectParameter.static())
     return interpreter
Example #30
0
 def get_usable_parameters():
     return ([k, v, "project"]
             for k, v in ProjectParameter.static().items())