def test_write_only_activity_parameters_no_activate_others(no_init): Database("PCB").register() obj = ExcelImporter() obj.db_name = "PCB" obj.data = deepcopy(DATA) obj.write_database(activate_parameters=False) NEW = [{ 'code': '45cb34db4147e510a2561cceec541f6b', 'database': 'PCB', 'exchanges': [], 'name': 'unmounted printed circuit board', 'type': 'process', 'unit': 'square meter', 'parameters': [{ 'name': 'something_test', 'amount': 2, 'formula': '3 + 2' }], }] obj = ExcelImporter() obj.db_name = "PCB" obj.write_activity_parameters(NEW) assert ActivityParameter.select().count() == 1 assert ActivityParameter.get().formula == '3 + 2' assert 'parameters' not in get_activity( ('PCB', '45cb34db4147e510a2561cceec541f6b')) assert 'parameters' in get_activity( ('PCB', '32aa5ab78beda5b8c8efbc89587de7a5'))
def test_compare_activities_by_grouped_leaves_html(cabgl): result = compare_activities_by_grouped_leaves( [bd.get_activity(("c", "6")), bd.get_activity(("c", "7"))], ("method",), output_format="html", ) assert isinstance(result, str)
def test_compare_activities_by_grouped_leaves_pandas(cabgl): result = compare_activities_by_grouped_leaves( [bd.get_activity(("c", "6")), bd.get_activity(("c", "7"))], ("method",), output_format="pandas", ) assert isinstance(result, pd.DataFrame)
def test_find_differences_in_inputs(fdii): expected = { bd.get_activity(("c", "3")): {"flow": 1}, bd.get_activity(("c", "4")): {"flow": 1.1}, bd.get_activity(("c", "5")): {"flow": 0.95}, } assert find_differences_in_inputs(bd.get_activity(("c", "3"))) == expected
def test_compare_activities_by_grouped_leaves(cabgl): labels, result = compare_activities_by_grouped_leaves( [bd.get_activity(("c", "6")), bd.get_activity(("c", "7"))], ("method",) ) assert labels == [ "activity", "product", "location", "unit", "total", "direct emissions", "product A", "product B", "product C", "product D", ] assert result[0][0] == "6" assert result[1][0] == "7" assert np.allclose( result[0][4:], [251, 6 / 251, (27 + 35 + 56) / 251, 56 / 251, 36 / 251, 35 / 251], ) assert np.allclose( result[1][4:], [212, 0, (30 + 48 + 24) / 212, 48 / 212, 32 / 212, 30 / 212] )
def to_dataframe(self, cutoff=200): """Return all nonzero elements of characterized inventory as Pandas dataframe""" assert mapping, "This method doesn't work with independent LCAs" assert pandas, "This method requires the `pandas` (http://pandas.pydata.org/) library" assert hasattr( self, "characterized_inventory"), "Must do LCIA calculation first" from bw2data import get_activity coo = self.characterized_inventory.tocoo() stacked = np.vstack([np.abs(coo.data), coo.row, coo.col, coo.data]) stacked.sort() rev_activity, _, rev_bio = self.reverse_dict() length = stacked.shape[1] data = [] for x in range(min(cutoff, length)): if stacked[3, length - x - 1] == 0.: continue activity = get_activity(rev_activity[stacked[2, length - x - 1]]) flow = get_activity(rev_bio[stacked[1, length - x - 1]]) data.append((activity['name'], flow['name'], activity.get('location'), stacked[3, length - x - 1])) return pandas.DataFrame( data, columns=['Activity', 'Flow', 'Region', 'Amount'])
def test_write_only_activity_parameters_no_activate_others(no_init): Database("PCB").register() obj = ExcelImporter() obj.db_name = "PCB" obj.data = deepcopy(DATA) obj.write_database(activate_parameters=False) NEW = [ { "code": "45cb34db4147e510a2561cceec541f6b", "database": "PCB", "exchanges": [], "name": "unmounted printed circuit board", "type": "process", "unit": "square meter", "parameters": [{"name": "something_test", "amount": 2, "formula": "3 + 2"}], } ] obj = ExcelImporter() obj.db_name = "PCB" obj.write_activity_parameters(NEW) assert ActivityParameter.select().count() == 1 assert ActivityParameter.get().formula == "3 + 2" assert "parameters" not in get_activity(("PCB", "45cb34db4147e510a2561cceec541f6b")) assert "parameters" in get_activity(("PCB", "32aa5ab78beda5b8c8efbc89587de7a5"))
def test_locations_changed_as_expected(basic): rower = Rower("animals") rower.define_RoWs() rower.label_RoWs() assert get_activity(('animals', 'mutt pup'))['location'] == 'RoW_user_0' assert get_activity(('animals', 'mutt'))['location'] == 'RoW_user_0' assert get_activity(('animals', 'moggy'))['location'] == 'RoW_user_1'
def test_find_differences_in_inputs_locations(fdii): expected = { bd.get_activity(("c", "3")): {"flow": 1}, bd.get_activity(("c", "4")): {"flow": 1.1}, } assert ( find_differences_in_inputs(bd.get_activity(("c", "3")), locations=["here"]) == expected )
def append_one_exchange(cls, df, df_ind_j, conversion_dem_to_fu, exclude_dbs): """Extract info about one input activity, eg name, unit, location, etc and append it to the dataframe df.""" # Extract the activity number k = int(''.join(c for c in df_ind_j.index[0] if c.isdigit())) # Extract information about activity and save it original_str = df_ind_j['DB Act {}'.format(k)] original_db_code = df_ind_j['Activity {}'.format(k)] # Find this input activity in brightway databases db_name = original_db_code.split("'")[1] code = original_db_code.split("'")[3] original_db_code_tuple = (db_name, code) # exclude unnecessary databases if db_name.lower() in exclude_dbs: return df # Compute amount original_on = df_ind_j['On ' + str(k)] original_amount = df_ind_j['Amount Act ' + str(k)] original_cfl = df_ind_j['CFL Act ' + str(k)] computed_amount = original_on \ * original_amount \ * original_cfl \ * conversion_dem_to_fu if db_name == 'ecoinvent 3.3 cutoff' and 'ecoinvent 3.3 cutoff' not in bd.databases: current_project = deepcopy(bd.projects.current) bd.projects.set_current('ecoinvent 3.3 cutoff') # Temporarily switch to ecoinvent 3.3 project act_bw = bd.get_activity(original_db_code_tuple) bd.projects.set_current(current_project) input_act_values_dict = cls.create_input_act_dict(act_bw, computed_amount) else: try: # Find activity using bw functionality act_bw = bd.get_activity(original_db_code_tuple) input_act_values_dict = cls.create_input_act_dict(act_bw, computed_amount) except: # If bd.get_activity does not work for whichever reason, fill info manually # if replace_agribalyse_with_ei and "agribalyse" in db_name.lower(): # db_name = CONSUMPTION_DB_NAME TODO might need to uncomment, or fix this somewhere input_act_values_dict = cls.bw_get_activity_info_manually(original_str, db_name, computed_amount) # Add exchange to the dataframe with database in brightway format input_act_values_dict.update( { 'original_on': original_on, 'original_activity': original_db_code, 'original_db_act': original_str, 'original_cfl_act': original_cfl, 'original_amount': original_amount, } ) df = cls.append_exchanges_in_correct_columns(df, input_act_values_dict) return df
def test_find_differences_in_inputs_tolerances(fdii): assert not find_differences_in_inputs(bd.get_activity(("c", "3")), rel_tol=0.2) expected = { bd.get_activity(("c", "3")): {"flow": 1}, bd.get_activity(("c", "4")): {"flow": 1.1}, } assert ( find_differences_in_inputs(bd.get_activity(("c", "3")), abs_tol=0.075) == expected )
def _add_results(self, res_dict, key, imp): """used in charachterize by flow and processes to groupby impact by year for each flow""" if get_activity(key)['name'] not in res_dict: #just add to dict res_dict[get_activity(key)['name']] = imp else: #groupby and sum impact by year imp[0].extend(res_dict[get_activity(key)['name']][0]) imp[1].extend(res_dict[get_activity(key)['name']][1]) c = collections.defaultdict(int) for yr, im in zip(imp[0], imp[1]): c[yr] += im res_dict[get_activity(key)['name']] = tuple( list(t) for t in zip(*sorted(zip(c.keys(), c.values()))) ) #from https://stackoverflow.com/a/9764364/4929813
def test_with_ecoinvent_generic(): assert not len(Database('animals')) animal_data = { ('animals', 'dogo'): { 'name': 'dogs', 'reference product': 'dog', 'exchanges': [], 'unit': 'kilogram', 'location': 'BR', }, ('animals', 'st bernhard'): { 'name': 'dogs', 'reference product': 'dog', 'exchanges': [], 'unit': 'kilogram', 'location': 'CH', }, ('animals', 'mutt'): { 'name': 'dogs', 'reference product': 'dog', 'exchanges': [], 'unit': 'kilogram', 'location': 'RoW', }, } db = Database('animals') db.write(animal_data) rwr = rower.Rower('animals') rwr.load_existing(rwr.EI_GENERIC) rwr.define_RoWs() rwr.label_RoWs() assert get_activity(('animals', 'mutt'))['location'] == "RoW_88"
def _update_locations_sqlite(self, mapping): count = 0 for k, v in pyprind.prog_bar(mapping.items()): activity = bw2data.get_activity((self.db.name, k)) activity['location'] = v activity.save() count += 1 return count
def compute_exiobase_weights(self): reverse_dict = self.lca.reverse_dict()[0] act_inds = np.where(self.d_exiobase_adjusted != 0)[0] weights = {} for act in act_inds: bw_act = bd.get_activity(reverse_dict[act]).as_dict()['key'] weights[bw_act] = self.d_exiobase_adjusted[act] return weights
def compare_to_previous(self): if not hasattr(self, "previous_reference"): raise ValueError("No previous reference method found") names_found_in_data = { get_activity(cf["input"])["name"].lower() for ds in self.data for cf in ds["exchanges"] if cf.get("input") } names_missing_in_data = { cf["name"].lower() for ds in self.data for cf in ds["exchanges"] if not cf.get("input") } names_in_reference = { get_activity(key)["name"].lower() for key, _ in Method(self.previous_reference).load() } return { "found": names_found_in_data, "missing": names_missing_in_data, "reference": names_in_reference, }
def test_compare_activities_by_grouped_leaves_max_level(cabgl): labels, result = compare_activities_by_grouped_leaves( [bd.get_activity(("c", "6")), bd.get_activity(("c", "7"))], ("method",), max_level=1, ) assert labels == [ "activity", "product", "location", "unit", "total", "direct emissions", "product D", "product C", ] assert result[0][0] == "6" assert result[1][0] == "7" assert np.allclose( result[0][4:], [251, 6 / 251, (35 + 35 + 56 + 56) / 251, (36 + 27) / 251] )
def annotated_top_emissions(self, lca, names=True, **kwargs): """Get list of most damaging biosphere flows in an LCA, sorted by ``abs(direct impact)``. Returns a list of tuples: ``(lca score, inventory amount, activity)``. If ``names`` is False, they returns the process key as the last element. """ ra, rp, rb = lca.reverse_dict() results = [(score, lca.inventory[index, :].sum(), rb[index]) for score, index in self.top_emissions( lca.characterized_inventory, **kwargs)] if names: results = [(x[0], x[1], get_activity(x[2])) for x in results] return results
def annotated_top_processes(self, lca, names=True, **kwargs): """Get list of most damaging processes in an LCA, sorted by ``abs(direct impact)``. Returns a list of tuples: ``(lca score, supply, activity)``. If ``names`` is False, they returns the process key as the last element. """ ra, rp, rb = lca.reverse_dict() results = [(score, lca.supply_array[int(index)], ra[int(index)]) for score, index in self.top_processes( lca.characterized_inventory, **kwargs)] if names: results = [(x[0], x[1], get_activity(x[2])) for x in results] return results
def fix_acrolein(): ERROR = "ReCiPe 2016 only tested for ecoinvent biosphere flows; install base ecoinvent data" assert "biosphere3" in bd.databases, ERROR bio = bd.Database("biosphere3") if bio.metadata.get("acrolein fixed"): return flow = bd.get_activity( ("biosphere3", "fa8bd05b-015d-5a82-878c-bde991551695")) flow["CAS number"] = "107-02-8" flow.save() bio.metadata["acrolein fixed"] = True bd.databases.flush()
def test_compare_activities_by_grouped_leaves_max_cutoff(cabgl): labels, result = compare_activities_by_grouped_leaves( [bd.get_activity(("c", "6")), bd.get_activity(("c", "7"))], ("method",), cutoff=0.2, ) assert labels == [ "activity", "product", "location", "unit", "total", "direct emissions", "product B", "product A", "product C", "product D", ] assert result[0][0] == "6" assert result[1][0] == "7" assert np.allclose( result[0][4:], [251, 6 / 251, (56 + 27 + 35) / 251, (56) / 251, 36 / 251, 35 / 251], )
def calculate(self): """Calculate LCA report data""" lca = LCA(self.activity, self.method) lca.lci() lca.lcia() gt = GraphTraversal().calculate(self.activity, method=self.method) print("FD") force_directed = self.get_force_directed(gt["nodes"], gt["edges"], lca) print("CA") ca = ContributionAnalysis() print("hinton") hinton = ca.hinton_matrix(lca) print("treemap") treemap = self.get_treemap(gt["nodes"], gt["edges"], lca) print("herfindahl") herfindahl = herfindahl_index(lca.characterized_inventory.data) print("concentration") concentration = concentration_ratio(lca.characterized_inventory.data) print("MC:") monte_carlo = self.get_monte_carlo() activity_data = [] for k, v in self.activity.items(): obj = get_activity(k) activity_data.append((obj["name"], "%.2g" % v, obj["unit"])) self.report = { "activity": activity_data, "method": { "name": ": ".join(self.method), "unit": methods[self.method]["unit"], }, "score": float(lca.score), "contribution": { "hinton": hinton, "treemap": treemap, "herfindahl": herfindahl, "concentration": concentration, }, "force_directed": force_directed, "monte carlo": monte_carlo, "metadata": { "type": "Brightway2 serialized LCA report", "version": self.version, "uuid": self.uuid, }, }
def patch_lcia_methods(self, new_biosphere): flows = ["PFC (CO2-eq)", "HFC (CO2-eq)"] for flow in flows: assert get_activity((new_biosphere, flow)) new_data = [((new_biosphere, flow), 1) for flow in flows] count = 0 for name, metadata in methods.items(): if metadata.get("unit") == "kg CO2-Eq": count += 1 obj = Method(name) data = obj.load() data.extend(new_data) obj.write(data) print(f"Patched {count} LCIA methods with unit 'kg CO2-Eq'")
def test_with_ecoinvent_specific_shortcut(): assert not len(Database('animals')) animal_data = { ('animals', "6ccf7e69afcf1b74de5b52ae28bbc1c2"): { 'name': 'dogs', 'reference product': 'dog', 'exchanges': [], 'unit': 'kilogram', 'location': 'RoW', }, } db = Database('animals') db.write(animal_data) rwr = rower.Rower('animals') rwr.apply_existing_activity_map(rwr.EI_3_4_CONSEQUENTIAL) assert get_activity( ('animals', "6ccf7e69afcf1b74de5b52ae28bbc1c2"))['location'] == "RoW_64"
def multi_recurse_tagged_database(activity, amount, methods, method_dicts, lca, label, default_tag, secondary_tags=[]): if isinstance(activity, tuple): activity = get_activity(activity) inputs = list(activity.technosphere()) inside = [exc for exc in inputs if exc['input'][0] == activity['database']] outside = {exc['input']: exc['amount'] * amount for exc in inputs if exc['input'][0] != activity['database']} if outside: outside_scores = [] for n, m in enumerate(methods): lca.switch_method(m) lca.redo_lcia(outside) outside_scores.append(lca.score) else: outside_scores = [0] * len(methods) return { 'activity': activity, 'amount': amount, 'tag': activity.get(label) or default_tag, 'secondary_tags':[activity.get(t[0]) or t[1] for t in secondary_tags], 'impact': outside_scores, 'biosphere': [{ 'amount': exc['amount'] * amount, 'impact': [exc['amount'] * amount * method_dict.get(exc['input'], 0) for method_dict in method_dicts], 'tag': exc.get(label) or activity.get(label) or default_tag, 'secondary_tags':[exc.get(t[0]) or activity.get(t[0]) or t[1] for t in secondary_tags] } for exc in activity.biosphere()], 'technosphere': [multi_recurse_tagged_database(exc.input, exc['amount'] * amount, methods, method_dicts, lca, label, default_tag, secondary_tags) for exc in inside] }
def multi_recurse_tagged_database(activity, amount, methods, method_dicts, lca, label, default_tag, secondary_tags=[]): """Traverse a foreground database and assess activities and biosphere flows by tags using multiple methods. Input arguments: * ``activity``: Activity tuple or object * ``amount``: float * ``methods``: list of LCA methods (tuples) * ``method_dicts``: list of dictionaries of biosphere flow tuples to CFs, e.g. ``{("biosphere", "foo"): 3}`` corresponding to methods in ``methods`` * ``lca``: An ``LCA`` object that is already initialized, i.e. has already calculated LCI * ``label``: string * ``default_tag``: string * ``secondary_tags``: list of tuples in the format (secondary_label, secondary_default_tag). Default is empty list. Returns: .. code-block:: python { 'activity': activity object, 'amount': float, 'tag': string, 'secondary_tags': [list of strings], 'impact': [list of floats (impact of inputs from outside foreground database) with one element per method], 'biosphere': [{ 'amount': float, 'impact': [list of floats with one element per method], 'tag': string, 'secondary_tags': [list of strings] }], 'technosphere': [this data structure] } """ if isinstance(activity, tuple): activity = get_activity(activity) inputs = list(activity.technosphere()) inside = [exc for exc in inputs if exc["input"][0] == activity["database"]] outside = { exc["input"]: exc["amount"] * amount for exc in inputs if exc["input"][0] != activity["database"] } if outside: outside_scores = [] for n, m in enumerate(methods): lca.switch_method(m) lca.redo_lcia(outside) outside_scores.append(lca.score) else: outside_scores = [0] * len(methods) return { "activity": activity, "amount": amount, "tag": activity.get(label) or default_tag, "secondary_tags": [activity.get(t[0]) or t[1] for t in secondary_tags], "impact": outside_scores, "biosphere": [{ "amount": exc["amount"] * amount, "impact": [ exc["amount"] * amount * method_dict.get(exc["input"], 0) for method_dict in method_dicts ], "tag": exc.get(label) or activity.get(label) or default_tag, "secondary_tags": [ exc.get(t[0]) or activity.get(t[0]) or t[1] for t in secondary_tags ], } for exc in activity.biosphere()], "technosphere": [ multi_recurse_tagged_database( exc.input, exc["amount"] * amount, methods, method_dicts, lca, label, default_tag, secondary_tags, ) for exc in inside ], }
def recurse_tagged_database(activity, amount, method_dict, lca, label, default_tag, secondary_tags=[]): """Traverse a foreground database and assess activities and biosphere flows by tags. Input arguments: * ``activity``: Activity tuple or object * ``amount``: float * ``method_dict``: Dictionary of biosphere flow tuples to CFs, e.g. ``{("biosphere", "foo"): 3}`` * ``lca``: An ``LCA`` object that is already initialized, i.e. has already calculated LCI and LCIA with same method as in ``method_dict`` * ``label``: string * ``default_tag``: string * ``secondary_tags``: List of tuples in the format (secondary_label, secondary_default_tag). Default is empty list. Returns: .. code-block:: python { 'activity': activity object, 'amount': float, 'tag': string, 'secondary_tags': [list of strings], 'impact': float (impact of inputs from outside foreground database), 'biosphere': [{ 'amount': float, 'impact': float, 'tag': string, 'secondary_tags': [list of strings] }], 'technosphere': [this data structure] } """ if isinstance(activity, tuple): activity = get_activity(activity) inputs = list(activity.technosphere()) production = list(activity.production()) if len(production) == 1: scale = production[0]["amount"] elif not production: # Assume production amount of 1 scale = 1 else: raise ValueError("Can't scale by production exchange") inside = [exc for exc in inputs if exc["input"][0] == activity["database"]] outside = { exc["input"]: exc["amount"] / scale * amount for exc in inputs if exc["input"][0] != activity["database"] } if outside: lca.redo_lcia(outside) outside_score = lca.score else: outside_score = 0 return { "activity": activity, "amount": amount, "tag": activity.get(label) or default_tag, "secondary_tags": [activity.get(t[0]) or t[1] for t in secondary_tags], "impact": outside_score, "biosphere": [{ "amount": exc["amount"] / scale * amount, "impact": exc["amount"] / scale * amount * method_dict.get(exc["input"], 0), "tag": exc.get(label) or activity.get(label) or default_tag, "secondary_tags": [ exc.get(t[0]) or activity.get(t[0]) or t[1] for t in secondary_tags ], } for exc in activity.biosphere()], "technosphere": [ recurse_tagged_database( exc.input, exc["amount"] / scale * amount, method_dict, lca, label, default_tag, secondary_tags, ) for exc in inside ], }
def get_name(self, key): return get_activity(key).get("name", "Unknown")
def test_calculate_matrix_presamples(): data = { ("test-db", 'b'): { 'exchanges': [], 'type': 'emission', }, ("test-db", 't1'): { 'exchanges': [{ 'amount': 1, 'input': ('test-db', 't2'), 'type': 'technosphere', 'formula': 'foo + bar' }, { 'amount': 1, 'input': ('test-db', 'b'), 'type': 'biosphere', 'formula': 'foo - bar + pppp' }], 'type': 'process', }, ("test-db", 't2'): { 'exchanges': [], 'type': 'process', }, } Database("test-db").write(data) Group.create(name="E", order=[]) data = [{ 'name': 'foo', 'database': 'test-db', 'code': 't1', 'amount': 7, 'uncertainty_type': 4, 'minimum': 0, 'maximum': 14, }, { 'name': 'bar', 'database': 'test-db', 'code': 't1', 'amount': 11, }] parameters.new_project_parameters([{'name': 'pppp', 'amount': 12}]) parameters.new_activity_parameters(data, 'A') parameters.add_exchanges_to_group('A', get_activity(("test-db", 't1'))) parameters.recalculate() pbm = ParameterizedBrightwayModel("A") pbm.load_parameter_data() pbm.calculate_static() pbm.calculate_matrix_presamples() id_, dirpath = pbm.save_presample('test-everything') # Check for file contents pp = PresamplesPackage(dirpath) resources = pp.resources assert len(resources) == 3 assert resources[0]['type'] == 'biosphere' assert resources[0]['samples']['shape'] == [1, 1] assert resources[1]['type'] == 'technosphere' assert resources[1]['samples']['shape'] == [1, 1] assert resources[2]['label'] == 'test-everything' assert resources[2]['samples']['shape'] == [3, 1]
def test_upstream_bio(activity): act = get_activity(("db", "c")) assert len(list(act.upstream())) == 0 assert len(act.upstream()) == 0