Source code for scenariocompass.historical_vetting

import logging
from pathlib import Path

from nomenclature.processor import Processor, DataValidator
from nomenclature.processor.data_validator import WarningEnum
from pyam import IamDataFrame
from pyam.exceptions import format_log_message
from pyam.utils import make_index

here = Path(__file__).absolute().parent
criteria_dir = here.parent / "criteria" / "validate_data"


logger = logging.getLogger(__name__)


[docs] class HistoricalVetting(Processor): prefix: str = "Historical Vetting" vetting_indicator: str = "Vetting|SCI 2025" validators: list[DataValidator] = [ DataValidator.from_file(criteria_dir / "historical_emissions.yaml"), DataValidator.from_file(criteria_dir / "historical_energy_balances.yaml"), ] def _update_names(self): """Reset validator-item-names to "Historical Vetting|<Variable>|<Year>" """ for validator in self.validators: for item in validator.criteria_items: item.name = "|".join([self.prefix, item.variable[0], str(item.year[0])]) @property def criteria_names(self): """Get the names of historical vetting criteria""" self._update_names() names = list() for validator in self.validators: for item in validator.criteria_items: names.append(item.name) return names def apply(self, df: IamDataFrame) -> IamDataFrame: self._update_names() df = self.reset_apply(df) # assume that all scenarios passed the vetting df.set_meta(name=self.vetting_indicator, meta="passed") # check that required variables exist required_variable_list = [] for validator in self.validators: required_variable_list.extend(validator.input_data["variable"]) missing_data = df.require_data( variable=required_variable_list, year=[2020, 2025], ) if missing_data is not None: logger.warning( format_log_message( "The following data are missing to do historical vetting", missing_data, ) ) df.set_meta( name=self.vetting_indicator, meta="insufficient reporting", index=make_index(missing_data, ["model", "scenario"]), ) # change error to warning and run validation # TODO consider custom log message for failing validation for validator in self.validators: # make copy of validator to not change error-level in actual instance _validator = validator.model_copy() for item in _validator.criteria_items: item.validation[0].warning_level = WarningEnum(40) df = _validator.apply(df) # assign aggregate meta-indicator from all validation criteria items for col in df.meta.columns: if col.startswith(self.prefix): df.meta[col] = df.meta[col].replace({"high": "failed"}) vetting_result = df.meta[ [col for col in df.meta.columns if col.startswith(self.prefix)] ] failed_vetting = vetting_result.apply( lambda x: any([i == "failed" for i in x]), axis=1 ) df.set_meta( name=self.vetting_indicator, meta="failed", index=failed_vetting[failed_vetting].index, ) return df def reset_apply(self, df: IamDataFrame) -> IamDataFrame: vetting_cols = [ col for col in self.criteria_names + [self.vetting_indicator] if col in df.meta.columns ] if vetting_cols: logger.info(f"Resetting {len(vetting_cols)} historical vetting criteria") df.meta.drop(vetting_cols, axis=1, inplace=True) else: logger.info("No historical vetting criteria to reset") return df