Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pint Parameters for Brightway2 (legacy) #125

Draft
wants to merge 21 commits into
base: bw2legacy
Choose a base branch
from

Conversation

BenPortner
Copy link
Member

@BenPortner BenPortner commented Feb 13, 2023

Description

This PR enables the usage of units in parameter formulas. It uses the newly introduced bw2parameter.PintInterpreter and bw2parameter.PintParameterSet classes for this. Units are permanently stored in the data field of the SQLite databases for ProjectParameter, DatabaseParameter and ActivityParameter so they become available again after reloading.

Example

from bw2data.parameters import ProjectParameter
from bw2data import config

config.use_pint_parameters = True

ProjectParameter.create(
    name="p_proj",
    formula="1 kg + 200 g",
)
ProjectParameter.recalculate()
obj = ProjectParameter.get(name="p_proj")
assert obj.amount == 1.2
assert obj.data["unit"] == "kilogram"

Additional Considerations

Optionality vs. usability

Unit parsing and interpretation relies on the pint package, which is currently not part of the mandatory Brightway2 dependencies. I tried to keep it that way. However, this approach requires extra caution from the user. By default, unit parsing is deactivated. It must be switched on actively by setting config.use_pint_parameters = True. If the switch is off and one tries to parse a formula including units, an error will be raised: bw2parameters.errors.MissingName: One or more symbols could not be interpreted. Please check the formula. If it contains units, please set 'bw2parameters.config.use_pint = True': 1 kg + 0.2 kg.

Once a parameter with a unit in its formula is stored in the database, any future manipulation of this parameter or a dependent parameter will require config.use_pint_parameters = True or above error will appear (note: non-unit containing and non-dependent parameters can be processed as usual). To prevent such errors, units may be defined optionally in the data field. This way, parameters can be evaluated with use_pint_parameters on or off. However, in this case the user must take care that parameters are defined compatibly, otherwise unexpected results may occur:

from bw2data.parameters import ProjectParameter
from bw2data import config

# define parameters
ProjectParameter.create(
    name="p_proj3",
    amount=1,
    data={"unit": "kilogram"},
)
ProjectParameter.create(
    name="p_proj4",
    amount=200,
    data={"unit": "gram"},
)
ProjectParameter.create(
    name="p_proj5",
    formula="p_proj3 + p_proj4",
)

# solve with pint -> 1.2 kg
config.use_pint_parameters = True
ProjectParameter.recalculate()
obj = ProjectParameter.get(name="p_proj5")
assert obj.amount == 1.2
assert obj.dict["unit"] == "kilogram"

# solve without pint -> 201 kg
config.use_pint_parameters = False
group = Group.get(name="project")
group.fresh = False
group.save()
ProjectParameter.recalculate()
obj = ProjectParameter.get(name="p_proj5")
assert obj.amount == 201
assert obj.dict["unit"] == "kilogram"

Note that the latter behavior corresponds to the current default: It is left to the user to correctly convert units between formulas. New is the possibility to do so automatically by setting config.use_pint_parameters = True.

Computation time

Invoking pint for the first time carries a time penalty. Any invocations thereafter are as fast as using the default (asteval) interpreter. I attached a benchmark script to this PR. Short summary:

Solving parameters without units 10 times without pint solver took 2.718524694442749 s.
Solving parameters without units 10 times with pint solver took 4.090916156768799 s.
Solving parameters with units 10 times with pint solver took 2.1366446018218994 s.

Requirements

This PR builds on top of two other PRs, which need to be approved and merged first:

Todo (after review):

  • bump version number
  • add dependency bw2parameters >= 1.0
  • add optional install [pint]

Attachments

bw2data-pint-benchmark.py.txt

@BenPortner BenPortner force-pushed the legacy-pint-parameters branch 2 times, most recently from fea510e to 513d895 Compare February 13, 2023 15:06
Benjamin W. Portner added 19 commits February 16, 2023 17:38
…database. Also introducing `no_pint_units` parameter into helper function `get_new_symbols`. Both are needed make sure known project and activity parameters are not interpreted as units
…` and `ActivityParameter` including pint units
@BenPortner BenPortner marked this pull request as draft March 15, 2023 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant