diff --git a/premise/activity_maps.py b/premise/activity_maps.py index 3c894491..8f05c8a3 100644 --- a/premise/activity_maps.py +++ b/premise/activity_maps.py @@ -14,7 +14,7 @@ POWERPLANT_TECHS = VARIABLES_DIR / "electricity_variables.yaml" FUELS_TECHS = VARIABLES_DIR / "fuels_variables.yaml" -MATERIALS_TECHS = DATA_DIR / "utils" / "materials_vars.yml" +MATERIALS_TECHS = DATA_DIR / "metals" / "activities_mapping.yml" DAC_TECHS = VARIABLES_DIR / "direct_air_capture_variables.yaml" CARBON_STORAGE_TECHS = VARIABLES_DIR / "carbon_storage_variables.yaml" CEMENT_TECHS = VARIABLES_DIR / "cement_variables.yaml" @@ -22,7 +22,7 @@ DATA_DIR / "GAINS_emission_factors" / "gains_ecoinvent_sectoral_mapping.yaml" ) ACTIVITIES_METALS_MAPPING = DATA_DIR / "metals" / "activities_mapping.yml" -METALS_MAPPING = DATA_DIR / "metals" / "metals_mapping.yml" +# METALS_MAPPING = DATA_DIR / "metals" / "metals_mapping.yml" def get_mapping(filepath: Path, var: str, model: str = None) -> dict: @@ -159,9 +159,9 @@ def __init__( self.activity_metals_filters = get_mapping( filepath=ACTIVITIES_METALS_MAPPING, var="ecoinvent_aliases" ) - self.metals_filters = get_mapping( - filepath=METALS_MAPPING, var="ecoinvent_aliases" - ) + # self.metals_filters = get_mapping( + # filepath=METALS_MAPPING, var="ecoinvent_aliases" + # ) def generate_activities_using_metals_map(self) -> dict: """ diff --git a/premise/data/metals/activities_mapping.yml b/premise/data/metals/activities_mapping.yml index b01c7980..0c444ce9 100644 --- a/premise/data/metals/activities_mapping.yml +++ b/premise/data/metals/activities_mapping.yml @@ -213,10 +213,10 @@ CdTe: - photovoltaic laminate, CdTe mask: - market -pv_perovskite: - ecoinvent_aliases: - fltr: - - photovoltaic panel, perovskite-Si-tandem, at plant +#pv_perovskite: +# ecoinvent_aliases: +# fltr: +# - photovoltaic panel, perovskite-Si-tandem, at plant Parabolic Trough - SF: ecoinvent_aliases: fltr: diff --git a/premise/data/metals/metals_db.csv b/premise/data/metals/metals_db.csv index cf80c51e..fb8e521b 100644 --- a/premise/data/metals/metals_db.csv +++ b/premise/data/metals/metals_db.csv @@ -323,7 +323,7 @@ Manganese,kg/kWh,2020.0,,,0,0,LTO Nickel,kg/kWh,2020.0,0.07633587786259542,0.07633587786259542,0.07633587786259542,0.07633587786259542,LTO Phosphorus,kg/kWh,2020.0,0.7467302798982189,0.7467302798982188,0.17666666666666667,1.3167938931297711,LTO Titanium,kg/kWh,2020.0,3.466066666666667,3.466066666666667,1.6033333333333335,5.3288,LTO -Pb,kg/kWh,2020.0,14,14,14,14,Lead-Acid +Pb,kg/kWh,2020.0,14,14,14,14,Lead_Acid Vanadium,kg/kWh,2020.0,0.3,0.3,0.3,0.3,NiMH Cobalt,kg/kWh,2020.0,0.19433333333333336,0.17,0.088,0.325,NiMH Nickel,kg/kWh,2020.0,4.083333333333334,4.15,3.7,4.4,NiMH diff --git a/premise/data/metals/metals_mapping.yml b/premise/data/metals/metals_mapping.yml deleted file mode 100644 index 5f44e90c..00000000 --- a/premise/data/metals/metals_mapping.yml +++ /dev/null @@ -1,509 +0,0 @@ -# translation between metals_db names for metals and ecoinvent names --- ---- - -Dysprosium: - ecoinvent_aliases: - fltr: - name: Dysprosium - categories: natural resource - -Neodymium: - ecoinvent_aliases: - fltr: - name: Neodymium, 4% in bastnasite, 0.4% in crude ore - categories: natural resource - -Nickel: - ecoinvent_aliases: - fltr: - name: Nickel - categories: natural resource - -Manganese: - ecoinvent_aliases: - fltr: - name: Manganese - categories: natural resource - -Yttrium: - ecoinvent_aliases: - fltr: - name: Yttrium - categories: natural resource - -Vanadium: - ecoinvent_aliases: - fltr: - name: Vanadium - categories: natural resource - -Cobalt: - ecoinvent_aliases: - fltr: - name: Cobalt - categories: natural resource - -Lithium: - ecoinvent_aliases: - fltr: - name: Lithium - categories: natural resource - -Sulfur: - ecoinvent_aliases: - fltr: - name: Sulfur - categories: natural resource - -Platinum: - ecoinvent_aliases: - fltr: - name: Platinum - categories: natural resource - -Cerium: - ecoinvent_aliases: - fltr: - name: Cerium - categories: natural resource - -Lanthanum: - ecoinvent_aliases: - fltr: - name: Lanthanum - categories: natural resource - -Zirconium: - ecoinvent_aliases: - fltr: - name: Zirconium - categories: natural resource - -Gadolinium: - ecoinvent_aliases: - fltr: - name: Gadolinium - categories: natural resource - -Scandium: - ecoinvent_aliases: - fltr: - name: Scandium - categories: natural resource - -Strontium: - ecoinvent_aliases: - fltr: - name: Strontium - categories: natural resource - -Potassium: - ecoinvent_aliases: - fltr: - name: Potassium - categories: natural resource - -Iridium: - ecoinvent_aliases: - fltr: - name: Iridium - categories: natural resource - -Silver: - ecoinvent_aliases: - fltr: - name: Silver - categories: natural resource - -Germanium: - ecoinvent_aliases: - fltr: - name: Germanium - categories: natural resource - -Indium: - ecoinvent_aliases: - fltr: - name: Indium - categories: natural resource - -Gallium: - ecoinvent_aliases: - fltr: - name: Gallium - categories: natural resource - -Selenium: - ecoinvent_aliases: - fltr: - name: Selenium - categories: natural resource - -Cadmium: - ecoinvent_aliases: - fltr: - name: Cadmium - categories: natural resource - -Tellurium: - ecoinvent_aliases: - fltr: - name: Tellurium - categories: natural resource - -#### NEW - I need to point to the metal compound that goes in the different technologies? not to the mining activities... - -#Aluminium: -# ecoinvent_aliases: -# fltr: market for aluminium, cast alloy -# mask: -# name: -# -#Antimony: -# ecoinvent_aliases: -# fltr: market for antimony -# mask: -# name: -# -#Beryllium: -# ecoinvent_aliases: -# fltr: market for beryllium -# mask: -# name: - -#I NEED TO REFINE THE DEMAND FOR BORATES -## Reference: https://www.borax.com/BoraxCorp/media/Borax-Main/Resources/Data-Sheets/boric-oxide.pdf?ext=.pdf -## https://borates.today/boron-solar-energy-storage/ + permanent magnet (ecoinvent) already demands boric oxide -## -#### Conversion: from boric oxide to boron -#Boron oxide: -# ecoinvent_aliases: -# fltr: market for boric oxide -# mask: -# name: -# -## Reference: https://www.borax.com/products/applications/nuclear-energy -#### ### Conversion: from boron carbide to boron -#Boron carbide: -# ecoinvent_aliases: -# fltr: market for boron carbide -# mask: -# name: -# -#Brass: -# ecoinvent_aliases: -# fltr: market for brass -# mask: -# name: -# -#Cadmium: -# ecoinvent_aliases: -# fltr: market for cadmium -# mask: -# name: -# -##Cerium: -## ecoinvent_aliases: -## fltr: -## mask: -## name: -## -##Chromium: -## ecoinvent_aliases: -## fltr: market for chromite ore concentrate -## mask: -## name: -## -#Cobalt: -# ecoinvent_aliases: -# fltr: market for cobalt sulfate -# mask: -# name: -## -#Copper: -# ecoinvent_aliases: -# fltr: market for copper, cathode -# mask: -# name: -# -#Dysprosium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Erbium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Europium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Gadolinium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Gallium: -# ecoinvent_aliases: -# fltr: market for gallium, semiconductor-grade -# mask: -# name: -# -#Germanium: -# ecoinvent_aliases: -# fltr: market for germanium, concentrate -# mask: -# name: -# -#Gold: -# ecoinvent_aliases: -# fltr: market for gold -# mask: -# name: -# -#Graphite: -# ecoinvent_aliases: -# fltr: market for natural graphite, coated -# mask: -# name: -# -#Hafnium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Indium: -# ecoinvent_aliases: -# fltr: market for indium -# mask: -# name: -# -#Iridium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Lanthanum: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Lead: -# ecoinvent_aliases: -# fltr: market for lead -# mask: -# name: -# -#Lithium: -# ecoinvent_aliases: -# fltr: market for lithium carbonate, battery grade -# mask: -# name: -# -#Magnesium: -# ecoinvent_aliases: -# fltr: market for magnesium -# mask: -# name: -# -#Manganese: -# ecoinvent_aliases: -# fltr: market for manganese -# mask: -# name: -# -#Molybdenum: -# ecoinvent_aliases: -# fltr: market for molybdenum -# mask: -# name: -# -#Neodymium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Nickel: -# ecoinvent_aliases: -# fltr: market for nickel, class 1 -# mask: -# name: -# -#Niobium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Palladium: -# ecoinvent_aliases: -# fltr: market for palladium -# mask: -# name: -# -#Phosphorous: -# ecoinvent_aliases: -# fltr: market for phosphate rock, beneficiated -# mask: -# name: -# -#Platinum: -# ecoinvent_aliases: -# fltr: market for platinum -# mask: -# name: -# -#Potassium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Praseodymium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Rhenium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Rhodium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Ruthenium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Rubidium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Samarium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Scandium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Selenium: -# ecoinvent_aliases: -# fltr: market for selenium -# mask: -# name: -# -#Silicon: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Silver: -# ecoinvent_aliases: -# fltr: market for silver -# mask: -# name: -# -#Sulfur: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Strontium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Tantalum: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Tellurium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Terbium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Tin: -# ecoinvent_aliases: -# fltr: market for tin -# mask: -# name: -# -#Titanium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Tungsten: -# ecoinvent_aliases: -# fltr: market for tungsten carbide powder -# mask: -# name: -# -#Vanadium: -# ecoinvent_aliases: -# fltr: market for vanadium pentoxide -# mask: -# name: -# -#Ytterbium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Yttrium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: -# -#Zinc: -# ecoinvent_aliases: -# fltr: market for zinc -# mask: -# name: -# -#Zirconium: -# ecoinvent_aliases: -# fltr: -# mask: -# name: \ No newline at end of file diff --git a/premise/ecoinvent_modification.py b/premise/ecoinvent_modification.py index eb57e61a..b8b8a226 100644 --- a/premise/ecoinvent_modification.py +++ b/premise/ecoinvent_modification.py @@ -1098,7 +1098,8 @@ def update_metals(self) -> None: modified_datasets=self.modified_datasets, ) - metals.create_metal_markets() + + _update_metals(scenario,self.version, self.system_model, self.modified_datasets) scenario["database"] = metals.database print("Done!\n") diff --git a/premise/metals.py b/premise/metals.py index 182aae5e..89fd84fd 100644 --- a/premise/metals.py +++ b/premise/metals.py @@ -29,7 +29,6 @@ logger = create_logger("metal") - def _update_metals(scenario, version, system_model, modified_datasets): metals = Metals( database=scenario["database"], @@ -43,6 +42,7 @@ def _update_metals(scenario, version, system_model, modified_datasets): ) metals.create_metal_markets() + metals.update_metals_use_in_database() return scenario, modified_datasets @@ -56,6 +56,40 @@ def load_mining_shares_mapping(): df = pd.read_excel(filepath, sheet_name="Shares_mapping") return df +def load_activities_mapping(): + """ + Load mapping for the ecoinvent exchanges to be updated by the new metal intensities + """ + + filepath = DATA_DIR / "metals" / "activities_mapping.xlsx" + df = pd.read_excel(filepath, sheet_name="activities_mapping") + return df + + +# Define a function to replicate rows based on the generated activity sets +def extend_dataframe(df, mapping): + """" + Extend a DataFrame by duplicating rows based on a mapping dictionary. + + Parameters: + - df (pd.DataFrame): The original DataFrame to be extended. + - mapping (dict): A dictionary with keys corresponding to the 'technology' + values in the DataFrame and values that are sets of processes. + """ + + new_rows = [] + + for key, processes in mapping.items(): + # Find the rows in the DataFrame where the 'technology' matches the key + matching_rows = df[df['technology'] == key] + # For each process in the set associated with the key, duplicate the matching rows + for process in processes: + temp_rows = matching_rows.copy() + temp_rows['ecoinvent_technology'] = process + new_rows.extend(temp_rows.to_dict('records')) + new_df = pd.DataFrame(new_rows) + + return new_df def get_ecoinvent_metal_factors(): """ @@ -78,15 +112,17 @@ def get_ecoinvent_metal_factors(): return ds -def load_post_allocation_correction_factors(): - """ - Load yaml file with post-allocation correction factors - """ - - filepath = DATA_DIR / "metals" / "post-allocation correction" / "corrections.yaml" - with open(filepath, "r", encoding="utf-8") as stream: - factors = yaml.safe_load(stream) - return factors +# def load_post_allocation_correction_factors(): +# """ +# Load yaml file with post-allocation correction factors +# +# WE ARE NOT POST-ALLOCATING ANYMORE +# """ +# +# filepath = DATA_DIR / "metals" / "post-allocation correction" / "corrections.yaml" +# with open(filepath, "r", encoding="utf-8") as stream: +# factors = yaml.safe_load(stream) +# return factors def fetch_mapping(filepath: str) -> dict: @@ -119,8 +155,8 @@ def load_conversion_factors(): class Metals(BaseTransformation): """ - Class that modifies emissions of hot pollutants - according to GAINS projections. + Class that modifies metal demand of different technologies + according to the Database built """ def __init__( @@ -146,21 +182,39 @@ def __init__( ) self.version = version - self.metals = iam_data.metals - mapping = InventorySet(self.database, self.version) + self.metals = iam_data.metals # 1 + # Precompute the median values for each metal and origin_var for the year 2020 + self.precomputed_medians = self.metals.sel(variable="median").interp(year=self.year) + + self.activities_mapping = load_activities_mapping() # 4 + + self.conversion_factors = load_conversion_factors() # 3 + # Precompute conversion factors as a dictionary for faster lookups + self.conversion_factors_dict = self.conversion_factors.set_index('Activity')['Conversion_factor'].to_dict() + + inv = InventorySet(self.database, self.version) + self.activities_metals_map: Dict[ str, Set - ] = mapping.generate_activities_using_metals_map() + ] = inv.generate_material_map() + self.rev_activities_metals_map: Dict[str, str] = rev_metals_map( self.activities_metals_map ) + self.extended_dataframe = extend_dataframe(self.activities_mapping,self.activities_metals_map) + self.extended_dataframe['final_technology'] = self.extended_dataframe.apply( + lambda row: row['demanding_process'] if pd.notna(row['demanding_process']) and row[ + 'demanding_process'] != '' else row['ecoinvent_technology'], + axis=1 + ) + # self.metals_map: Dict[str, Set] = mapping.generate_metals_map() - # self.rev_metals_map: Dict[str, str] = rev_metals_map(self.metals_map) - self.conversion_factors = load_conversion_factors() - self.current_metal_use = get_ecoinvent_metal_factors() + # self.rev_metals_map: Dict[str, str] = rev_metals_map(self.metals_map) # 2 + + # self.current_metal_use = get_ecoinvent_metal_factors() - self.biosphere_flow_codes = biosphere_flows_dictionary(version=self.version) + # self.biosphere_flow_codes = biosphere_flows_dictionary(version=self.version) def update_metals_use_in_database(self): """ @@ -171,13 +225,15 @@ def update_metals_use_in_database(self): for ds in self.database: if ds["name"] in self.rev_activities_metals_map: origin_var = self.rev_activities_metals_map[ds["name"]] - self.update_metal_use(ds, origin_var) + ds_name = ds["name"] + self.update_metal_use(ds, ds_name, origin_var) self.write_log(ds, "updated") def update_metal_use( self, dataset: dict, + ds_name: str, technology: str, ) -> dict: """ @@ -188,167 +244,132 @@ def update_metal_use( """ # get the list of metal factors available for this technology + available_metals = self.precomputed_medians.sel(origin_var=technology).dropna(dim='metal', how='all')['metal'].values + mask = self.extended_dataframe['ecoinvent_technology'] == ds_name + matching_rows = self.extended_dataframe[mask] - if technology not in self.metals.origin_var.values: - print(f"Technology {technology} not found in metal intensity database.") - return dataset + if not matching_rows.empty: - data = self.metals.sel(origin_var=technology, variable="median").interp( - year=self.year - ) - metals = [ - m - for m in self.metals.metal.values - if not np.isnan(data.sel(metal=m).values) - ] + ecoinvent_technology = matching_rows['ecoinvent_technology'].iloc[0] + conversion_factor = self.conversion_factors_dict.get(ecoinvent_technology, None) - # Update biosphere exchanges according to use factors --- - for exc in ws.biosphere( - dataset, ws.either(*[ws.equals("name", x) for x in self.rev_metals_map]) - ): - print("Updating metal use for", dataset["name"], exc["name"]) - metal = self.rev_metals_map[exc["name"]] - use_factor = data.sel(metal=metal).values - - # check if there is a conversion factor - if dataset["name"] in self.conversion_factors["Activity"].tolist(): - use_factor *= self.conversion_factors.loc[ - self.conversion_factors["Activity"] == dataset["name"], - "Conversion_factor", - ].values[0] + for metal in available_metals: - else: - print(f"Conversion factor not found for {dataset['name']}.") + unit_converter = matching_rows.loc[matching_rows['Element'] == metal, 'unit_convertor'] - # update the exchange amount - if metal in self.current_metal_use.metal.values: - ecoinvent_factor = self.current_metal_use.sel( - metal=metal, - activity=( - dataset["name"], - dataset["reference product"], - dataset["location"], - ), - ).values - else: - ecoinvent_factor = 0 - - exc["amount"] += use_factor - ecoinvent_factor - - if "log parameters" not in dataset: - dataset["log parameters"] = {} - - if metal not in dataset["log parameters"]: - dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor - dataset["log parameters"][f"{metal} new amount"] = exc["amount"] - - # remove metal from metals list - metals.remove(metal) - - # Add new biosphere exchanges for metals - # not present in the original dataset - for metal in metals: - use_factor = data.sel(metal=metal).values - # check if there is a conversion factor - if dataset["name"] in self.conversion_factors["Activity"].tolist(): - use_factor *= self.conversion_factors.loc[ - self.conversion_factors["Activity"] == dataset["name"], - "Conversion_factor", - ].values[0] - else: - print(f"Conversion factor not found for {dataset['name']}.") - - if self.version != "3.9": - exc_id = ( - f"{metal}, in ground", - "natural resource", - "in ground", - "kilogram", - ) - else: - exc_id = ( - f"{metal}", - "natural resource", - "in ground", - "kilogram", - ) + if not unit_converter.empty: - if metal in self.current_metal_use.metal.values: - if ( - dataset["name"], - dataset["reference product"], - dataset["location"], - ) in self.current_metal_use.activity.values.tolist(): - ecoinvent_factor = self.current_metal_use.sel( - metal=metal, - activity=( - dataset["name"], - dataset["reference product"], - dataset["location"], - ), - ).values - else: - ecoinvent_factor = 0 - else: - ecoinvent_factor = 0 - - exc = { - "name": f"{metal}, in ground", - "amount": use_factor - ecoinvent_factor, - "input": ("biosphere3", self.biosphere_flow_codes[exc_id]), - "type": "biosphere", - "unit": "kilogram", - "comment": (f"{ecoinvent_factor};{use_factor};{technology};{metal}"), - } + unit_convertor_value = unit_converter.iloc[0] + median_value = self.precomputed_medians.sel(metal=metal, origin_var=technology).item() - dataset["exchanges"].append(exc) + if conversion_factor is not None: - if "log parameters" not in dataset: - dataset["log parameters"] = {} + metal_activity = matching_rows.loc[matching_rows['Element'] == metal, 'Activity'].iloc[0] + metal_reference_product = matching_rows.loc[matching_rows['Element'] == metal, 'Reference product'].iloc[0] + result = median_value * unit_convertor_value * conversion_factor + final_technology = matching_rows.loc[matching_rows['Element'] == metal, 'final_technology'].iloc[0] - dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor - dataset["log parameters"][f"{metal} new amount"] = exc["amount"] - return dataset + ### GET METAL MARKET LOCATION + locations = ['World', 'GLO', None] + dataset_metal = None - def post_allocation_correction(self): - """ - Correct for post-allocation in the database. - """ + for location in locations: + try: + if location: + dataset_metal = ws.get_one( + self.database, + ws.equals('name', metal_activity), + ws.equals('location', location) + ) + else: + dataset_metal = ws.get_one( + self.database, + ws.equals('name', metal_activity) + ) + if dataset_metal: # If we found the dataset, break out of the loop + break + except Exception as e: # Replace Exception with the specific exception if possible + print(f"Failed to get dataset for location '{location}': {e}") + print(f"Dataset for metal activity '{metal_activity}' not found in any location.") - factors_list = load_post_allocation_correction_factors() - for dataset in factors_list: - ds = ws.get_one( - self.database, - ws.equals("name", dataset["name"]), - ws.equals("reference product", dataset["reference product"]), - ws.equals("location", dataset["location"]), - ws.equals("unit", dataset["unit"]), - ) - ds["exchanges"].append( - { - "name": dataset["additional flow"]["name"], - "amount": dataset["additional flow"]["amount"], - "unit": dataset["additional flow"]["unit"], - "type": "biosphere", - "categories": tuple( - dataset["additional flow"]["categories"].split("::") - ), - "input": ( - "biosphere3", - self.biosphere_flow_codes[ - dataset["additional flow"]["name"], - dataset["additional flow"]["categories"].split("::")[0], - dataset["additional flow"]["categories"].split("::")[1], - dataset["additional flow"]["unit"], - ], - ), - } - ) + dataset_demand = ws.get_many( + self.database, + ws.equals('name', final_technology), + ) + + for exc in dataset_demand: + print( + f"\nUpdating {metal_reference_product} for {exc['name']}, location:{exc['location']}. New value: {result}") + exchange = { + "uncertainty type": 0, + "amount": result, + "product": metal_reference_product, + "name": metal_activity, + "unit": "kilogram", + "location": dataset_metal["location"], + "type": "technosphere", + } + exc["exchanges"].append(exchange) + else: + print( + f"\nCHECK!!!\n Origin: {technology}, Metal: {metal}, Calculation Result: Conversion factor missing, Ecoinvent Activity: {ecoinvent_technology}, Technology: {matching_rows.loc[matching_rows['Element'] == metal, 'final_technology'].iloc[0]}") + else: + print( + f"\nCHECK!!!\nOrigin: {technology}, Metal: {metal} - No unit converter found, Technology: {matching_rows['final_technology'].iloc[0]}") + else: + print(f"\nCHECK!!!\n No matching rows for {ds_name}.") + + + # if "log parameters" not in dataset: + # dataset["log parameters"] = {} + # + # if metal not in dataset["log parameters"]: + # # dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor + # dataset["log parameters"][f"{metal} new amount"] = exc["amount"] + + return dataset + + # def post_allocation_correction(self): + # """ + # Correct for post-allocation in the database. + # """ + # + # factors_list = load_post_allocation_correction_factors() + # + # for dataset in factors_list: + # ds = ws.get_one( + # self.database, + # ws.equals("name", dataset["name"]), + # ws.equals("reference product", dataset["reference product"]), + # ws.equals("location", dataset["location"]), + # ws.equals("unit", dataset["unit"]), + # ) + # ds["exchanges"].append( + # { + # "name": dataset["additional flow"]["name"], + # "amount": dataset["additional flow"]["amount"], + # "unit": dataset["additional flow"]["unit"], + # "type": "biosphere", + # "categories": tuple( + # dataset["additional flow"]["categories"].split("::") + # ), + # "input": ( + # "biosphere3", + # self.biosphere_flow_codes[ + # dataset["additional flow"]["name"], + # dataset["additional flow"]["categories"].split("::")[0], + # dataset["additional flow"]["categories"].split("::")[1], + # dataset["additional flow"]["unit"], + # ], + # ), + # } + # ) def create_new_mining_activity( - self, name, reference_product, new_locations, geo_mapping + self, name, reference_product, new_locations + # self, name, reference_product, new_locations, geo_mapping ) -> dict: """ Create a new mining activity in a new location. @@ -431,11 +452,12 @@ def create_region_specific_markets(self, df: pd.DataFrame) -> List[dict]: # fetch shares for each location in df shares = self.get_shares(group, new_locations, name, ref_prod) - geography_mapping = self.get_geo_mapping(group, new_locations) + # geography_mapping = self.get_geo_mapping(group, new_locations) # if not, we create it datasets = self.create_new_mining_activity( - name, ref_prod, new_locations, geography_mapping + name, ref_prod, new_locations + # name, ref_prod, new_locations, geography_mapping ) # add new datasets to database @@ -518,7 +540,7 @@ def create_market(self, metal, df): return dataset def create_metal_markets(self): - self.post_allocation_correction() + # self.post_allocation_correction() print("Creating metal markets") @@ -566,11 +588,12 @@ def create_metal_markets(self): k: v for k, v in new_locations.items() if v is not None } - geography_mapping = self.get_geo_mapping(group, new_locations) + # geography_mapping = self.get_geo_mapping(group, new_locations) # if not, we create it datasets = self.create_new_mining_activity( - name, ref_prod, new_locations, geography_mapping + name, ref_prod, new_locations + # name, ref_prod, new_locations, geography_mapping ) self.database.extend(datasets.values()) @@ -590,142 +613,144 @@ def create_metal_markets(self): ] ) - def update_metal_use( - self, - dataset: dict, - technology: str, - ) -> dict: - """ - Update metal use based on metal intensities data. - :param dataset: dataset to adjust metal use for - :param technology: metal intensity variable name to look up - :return: Does not return anything. Modified in place. - """ - - # get the list of metal factors available for this technology - - if technology not in self.metals.origin_var.values: - print(f"Technology {technology} not found in metal intensity database.") - return dataset - - data = self.metals.sel(origin_var=technology, variable="median").interp( - year=self.year - ) - metals = [ - m - for m in self.metals.metal.values - if not np.isnan(data.sel(metal=m).values) - ] - - # Update biosphere exchanges according to DLR use factors - - for exc in ws.biosphere( - dataset, ws.either(*[ws.equals("name", x) for x in self.rev_metals_map]) - ): - print("Updating metal use for", dataset["name"], exc["name"]) - metal = self.rev_metals_map[exc["name"]] - use_factor = data.sel(metal=metal).values - - # check if there is a conversion factor - if dataset["name"] in self.conversion_factors["Activity"].tolist(): - use_factor *= self.conversion_factors.loc[ - self.conversion_factors["Activity"] == dataset["name"], - "Conversion_factor", - ].values[0] - - else: - print(f"Conversion factor not found for {dataset['name']}.") - - # update the exchange amount - if metal in self.current_metal_use.metal.values: - ecoinvent_factor = self.current_metal_use.sel( - metal=metal, - activity=( - dataset["name"], - dataset["reference product"], - dataset["location"], - ), - ).values - else: - ecoinvent_factor = 0 - - exc["amount"] += use_factor - ecoinvent_factor - - if "log parameters" not in dataset: - dataset["log parameters"] = {} - - if metal not in dataset["log parameters"]: - dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor - dataset["log parameters"][f"{metal} new amount"] = exc["amount"] - - # remove metal from metals list - metals.remove(metal) - - # Add new biosphere exchanges for metals - # not present in the original dataset - for metal in metals: - use_factor = data.sel(metal=metal).values - # check if there is a conversion factor - if dataset["name"] in self.conversion_factors["Activity"].tolist(): - use_factor *= self.conversion_factors.loc[ - self.conversion_factors["Activity"] == dataset["name"], - "Conversion_factor", - ].values[0] - else: - print(f"Conversion factor not found for {dataset['name']}.") - - if self.version != "3.9": - exc_id = ( - f"{metal}, in ground", - "natural resource", - "in ground", - "kilogram", - ) - else: - exc_id = ( - f"{metal}", - "natural resource", - "in ground", - "kilogram", - ) - - if metal in self.current_metal_use.metal.values: - if ( - dataset["name"], - dataset["reference product"], - dataset["location"], - ) in self.current_metal_use.activity.values.tolist(): - ecoinvent_factor = self.current_metal_use.sel( - metal=metal, - activity=( - dataset["name"], - dataset["reference product"], - dataset["location"], - ), - ).values - else: - ecoinvent_factor = 0 - else: - ecoinvent_factor = 0 - - exc = { - "name": f"{metal}, in ground", - "amount": use_factor - ecoinvent_factor, - "input": ("biosphere3", self.biosphere_flow_codes[exc_id]), - "type": "biosphere", - "unit": "kilogram", - "comment": (f"{ecoinvent_factor};{use_factor};{technology};{metal}"), - } - - dataset["exchanges"].append(exc) - - if "log parameters" not in dataset: - dataset["log parameters"] = {} - - dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor - dataset["log parameters"][f"{metal} new amount"] = exc["amount"] - - return dataset + # def update_metal_use( + # self, + # dataset: dict, + # technology: str, + # ) -> dict: + # """ + # OLD FUNCTION WHERE WE WERE MODIFYING ENVIRONMENTAL FLOWS + + # Update metal use based on metal intensities data. + # :param dataset: dataset to adjust metal use for + # :param technology: metal intensity variable name to look up + # :return: Does not return anything. Modified in place. + # """ + # + # # get the list of metal factors available for this technology + # + # if technology not in self.metals.origin_var.values: + # print(f"Technology {technology} not found in metal intensity database.") + # return dataset + # + # data = self.metals.sel(origin_var=technology, variable="median").interp( + # year=self.year + # ) + # metals = [ + # m + # for m in self.metals.metal.values + # if not np.isnan(data.sel(metal=m).values) + # ] + # + # # Update biosphere exchanges according to DLR use factors + # + # for exc in ws.biosphere( + # dataset, ws.either(*[ws.equals("name", x) for x in self.rev_metals_map]) + # ): + # print("Updating metal use for", dataset["name"], exc["name"]) + # metal = self.rev_metals_map[exc["name"]] + # use_factor = data.sel(metal=metal).values + # + # # check if there is a conversion factor + # if dataset["name"] in self.conversion_factors["Activity"].tolist(): + # use_factor *= self.conversion_factors.loc[ + # self.conversion_factors["Activity"] == dataset["name"], + # "Conversion_factor", + # ].values[0] + # + # else: + # print(f"Conversion factor not found for {dataset['name']}.") + # + # # update the exchange amount + # if metal in self.current_metal_use.metal.values: + # ecoinvent_factor = self.current_metal_use.sel( + # metal=metal, + # activity=( + # dataset["name"], + # dataset["reference product"], + # dataset["location"], + # ), + # ).values + # else: + # ecoinvent_factor = 0 + # + # exc["amount"] += use_factor - ecoinvent_factor + # + # if "log parameters" not in dataset: + # dataset["log parameters"] = {} + # + # if metal not in dataset["log parameters"]: + # dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor + # dataset["log parameters"][f"{metal} new amount"] = exc["amount"] + # + # # remove metal from metals list + # metals.remove(metal) + # + # # Add new biosphere exchanges for metals + # # not present in the original dataset + # for metal in metals: + # use_factor = data.sel(metal=metal).values + # # check if there is a conversion factor + # if dataset["name"] in self.conversion_factors["Activity"].tolist(): + # use_factor *= self.conversion_factors.loc[ + # self.conversion_factors["Activity"] == dataset["name"], + # "Conversion_factor", + # ].values[0] + # else: + # print(f"Conversion factor not found for {dataset['name']}.") + # + # if self.version != "3.9": + # exc_id = ( + # f"{metal}, in ground", + # "natural resource", + # "in ground", + # "kilogram", + # ) + # else: + # exc_id = ( + # f"{metal}", + # "natural resource", + # "in ground", + # "kilogram", + # ) + # + # if metal in self.current_metal_use.metal.values: + # if ( + # dataset["name"], + # dataset["reference product"], + # dataset["location"], + # ) in self.current_metal_use.activity.values.tolist(): + # ecoinvent_factor = self.current_metal_use.sel( + # metal=metal, + # activity=( + # dataset["name"], + # dataset["reference product"], + # dataset["location"], + # ), + # ).values + # else: + # ecoinvent_factor = 0 + # else: + # ecoinvent_factor = 0 + # + # exc = { + # "name": f"{metal}, in ground", + # "amount": use_factor - ecoinvent_factor, + # "input": ("biosphere3", self.biosphere_flow_codes[exc_id]), + # "type": "biosphere", + # "unit": "kilogram", + # "comment": (f"{ecoinvent_factor};{use_factor};{technology};{metal}"), + # } + # + # dataset["exchanges"].append(exc) + # + # if "log parameters" not in dataset: + # dataset["log parameters"] = {} + # + # dataset["log parameters"][f"{metal} old amount"] = ecoinvent_factor + # dataset["log parameters"][f"{metal} new amount"] = exc["amount"] + # + # return dataset def write_log(self, dataset, status="created"): """