Skip to content

Carbon Calculation Utilities

Contains functions for carbon calculations.

BasePathwaysCarbonCalculator

BasePathwaysCarbonCalculator(activity)

Base class for carbon calculators for NCS pathways.

This class encapsulates the common logic for preparing the NCS pathways.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

activity property

activity

Gets the activity used to calculate carbon values.

Returns:

Type Description
Activity

The activity for calculating carbon values.

calculation_type property

calculation_type

Returns the type of calculation being performed. Should be overridden by subclasses.

Returns:

Type Description
str

The calculation type name.

pathway_type property

pathway_type

Returns the NCS pathway type used in the carbon calculation. Needs to be overridden in subclasses.

Returns:

Type Description

NCS pathway type to be applied in the calculation.

get_pathways

get_pathways()

Returns NCS pathways based on the type defined in subclass implementations.

Returns:

Type Description
List[NcsPathway]

NCS pathways of the type defined in the subclass. If the type of the NCS pathway in the activity is not defined, then it will be excluded from the list.

Source code in src/cplus_plugin/lib/carbon.py
def get_pathways(self) -> typing.List[NcsPathway]:
    """Returns NCS pathways based on the type defined in
    subclass implementations.

    :returns: NCS pathways of the type defined in the
    subclass. If the type of the NCS pathway in the
    activity is not defined, then it will be excluded
    from the list.
    """
    if self.pathway_type == NcsPathwayType.UNDEFINED:
        return []

    if self._activity is None:
        log(
            f"{LOG_PREFIX} - The activity is invalid, null reference.",
            info=False,
        )
        return []

    if len(self._activity.pathways) == 0:
        log(
            f"{LOG_PREFIX} - There are no pathways in "
            f"{self._activity.name} activity.",
            info=False,
        )
        return []

    type_pathways = [
        pathway
        for pathway in self._activity.pathways
        if pathway.pathway_type == self.pathway_type
    ]

    return type_pathways

run

run()

Calculates carbon value for the referenced activity.

Subclasses need to implement this function.

Returns:

Type Description
float

The total carbon value.

Source code in src/cplus_plugin/lib/carbon.py
def run(self) -> float:
    """Calculates carbon value for the referenced activity.

    Subclasses need to implement this function.

    :returns: The total carbon value.
    :rtype: float
    """
    raise NotImplementedError("Subclasses must implement the 'run' function.")

BaseProtectPathwaysCarbonCalculator

BaseProtectPathwaysCarbonCalculator(activity)

Bases: BasePathwaysCarbonCalculator

Base class for carbon calculators that process protect pathways.

This class encapsulates the common logic for preparing and processing protect NCS pathways before calculating carbon values.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

pathway_type property

pathway_type

Returns the NCS protect pathway type used in the carbon calculation.

Returns:

Type Description

NCS protect pathway type applied in the calculation.

run

run()

Calculates the total carbon value for the referenced activity.

Returns:

Type Description
float

The total carbon value. If there are no protect NCS pathways, returns 0.0. If errors occur, returns -1.0.

Source code in src/cplus_plugin/lib/carbon.py
def run(self) -> float:
    """Calculates the total carbon value for the referenced activity.

    :returns: The total carbon value. If there are no protect NCS pathways,
    returns 0.0. If errors occur, returns -1.0.
    :rtype: float
    """
    prepared_layer = self._prepare_protect_pathways_layer()
    if prepared_layer is None:
        return 0.0

    total_carbon = self._calculate_carbon(prepared_layer)

    if total_carbon == -1.0:
        log(
            f"{LOG_PREFIX} - Error occurred in calculating the total "
            f"{self.calculation_type.lower()}. See preceding logs for details.",
            info=False,
        )
    else:
        log(
            f"Finished calculating the total {self.calculation_type.lower()} "
            f"of {self._activity.name} as {total_carbon!s}"
        )

    return total_carbon

CarbonImpactManageCalculator

CarbonImpactManageCalculator(activity)

Bases: CarbonImpactPathwayCalculator

Class for carbon impact calculation for manage NCS pathways.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

pathway_type property

pathway_type

Returns the NCS manage pathway type used in the carbon calculation.

Returns:

Type Description

NCS manage pathway type applied in the calculation.

CarbonImpactPathwayCalculator

CarbonImpactPathwayCalculator(activity)

Bases: BasePathwaysCarbonCalculator

Generic calculator for NCS pathway area-based carbon impact calculations.

Subclasses only need to override pathway_type and calculation_type.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

run

run()

Calculates the carbon impact for the configured pathway_type.

Returns:

Type Description
float

The total carbon impact value. If there are no matching pathways, returns 0.0. If errors occur, returns -1.0.

Source code in src/cplus_plugin/lib/carbon.py
def run(self) -> float:
    """Calculates the carbon impact for the configured pathway_type.

    :returns: The total carbon impact value. If there are
    no matching pathways, returns 0.0. If errors occur,
    returns -1.0.
    :rtype: float
    """
    pathways = self.get_pathways()

    if len(pathways) == 0:
        log(
            f"{LOG_PREFIX} - There are no {self.pathway_type.name.lower()} pathways in "
            f"{self._activity.name} activity.",
            info=False,
        )
        return 0.0

    pathway_carbon_info = [
        NcsPathwayCarbonInfo(layer, pathway.type_options[CARBON_IMPACT_ATTRIBUTE])
        for pathway in pathways
        for layer in [pathway.to_map_layer()]
        if layer.isValid() and CARBON_IMPACT_ATTRIBUTE in pathway.type_options
    ]

    if len(pathway_carbon_info) == 0:
        log(
            f"{LOG_PREFIX} - There are no valid {self.pathway_type.name.lower()} pathway layers in "
            f"{self._activity.name} activity.",
            info=False,
        )
        return 0.0

    if len(pathway_carbon_info) != len(pathways):
        log(
            f"{LOG_PREFIX} - Some {self.pathway_type.name.lower()} pathway layers are invalid and will be "
            f"excluded from the {self.calculation_type.lower()} calculation.",
            info=False,
        )

    return calculate_pathway_carbon_by_area(pathway_carbon_info)

CarbonImpactProtectCalculator

CarbonImpactProtectCalculator(activity)

Bases: BaseProtectPathwaysCarbonCalculator

Calculates the carbon impact of protect NCS pathways in an activity using the biomass reference layer.

It specifically searches for protect pathways in the activity. If there are no protect pathways is found, it will return 0. This is designed to be called within a QgsExpressionFunction.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

CarbonImpactRestoreCalculator

CarbonImpactRestoreCalculator(activity)

Bases: CarbonImpactPathwayCalculator

Class for carbon impact calculation for restore NCS pathways.

This class differs from CarbonImpactManageCalculator only in the pathway_type it returns (NcsPathwayType.RESTORE), reusing the generic pathway calculation logic provided by CarbonImpactPathwayCalculator.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

pathway_type property

pathway_type

Returns the NCS restore pathway type used in the carbon calculation.

Returns:

Type Description

NCS restore pathway type applied in the calculation.

IrrecoverableCarbonCalculator

IrrecoverableCarbonCalculator(activity)

Bases: BaseProtectPathwaysCarbonCalculator

Calculates the total irrecoverable carbon of an activity using the mean-based reference carbon layer.

It specifically searches for protect pathways in the activity. If there are no protect pathways is found, it will return 0. This is designed to be called within a QgsExpressionFunction.

Source code in src/cplus_plugin/lib/carbon.py
def __init__(self, activity: typing.Union[str, Activity]):
    if isinstance(activity, str):
        activity = settings_manager.get_activity(activity)

    self._activity = activity

NcsPathwayCarbonInfo dataclass

NcsPathwayCarbonInfo(layer, carbon_impact_per_ha)

Container for NcsPathway layer and corresponding carbon impact value.

calculate_activity_naturebase_carbon_impact

calculate_activity_naturebase_carbon_impact(activity)

Calculates the carbon mitigation impact of an activity from Naturbase pathway.

It sums the carbon mitigation values across each NCS Naturebase pathway that constitutes the activity.

Parameters:

Name Type Description Default
activity Activity

The specific activity.

required

Returns:

Type Description
float

Returns the total carbon impact of the activity, or -1.0 if the activity does not exist or lacks Naturebase pathways.

Source code in src/cplus_plugin/lib/carbon.py
def calculate_activity_naturebase_carbon_impact(activity: Activity) -> float:
    """Calculates the carbon mitigation impact of an activity from Naturbase pathway.

    It sums the carbon mitigation values across each NCS Naturebase pathway that constitutes the
    activity.

    :param activity: The specific activity.
    :type activity: Activity

    :returns: Returns the total carbon impact of the activity, or -1.0
    if the activity does not exist or lacks Naturebase pathways.
    :rtype: float
    """
    if activity is None or len(activity.pathways) == 0:
        return -1.0

    pathways = [
        pathway
        for pathway in activity.pathways
        if pathway.name.startswith("Naturebase:")
        and isinstance(pathway.carbon_impact_value, Number)
    ]

    if not pathways:
        return -1.0

    return float(sum(p.carbon_impact_value for p in pathways))

calculate_irrecoverable_carbon_from_mean

calculate_irrecoverable_carbon_from_mean(ncs_pathways_layer)

Calculates the total irrecoverable carbon in tonnes for protect NCS pathways using the reference layer defined in settings that is based on the mean value per hectare.

Parameters:

Name Type Description Default
ncs_pathways_layer QgsRasterLayer

Layer containing an aggregate of protect NCS pathways.

required

Returns:

Type Description
float

The total irrecoverable carbon for protect NCS pathways. If there are any errors, returns -1.0. If no pathways found, returns 0.0.

Source code in src/cplus_plugin/lib/carbon.py
def calculate_irrecoverable_carbon_from_mean(
    ncs_pathways_layer: QgsRasterLayer,
) -> float:
    """Calculates the total irrecoverable carbon in tonnes for protect NCS pathways
    using the reference layer defined in settings that is based on the
    mean value per hectare.

    :param ncs_pathways_layer: Layer containing an aggregate of protect NCS pathways.
    :type ncs_pathways_layer: QgsRasterLayer

    :returns: The total irrecoverable carbon for protect NCS pathways.
    If there are any errors, returns -1.0. If no pathways found, returns 0.0.
    :rtype: float
    """
    source_type_int = settings_manager.get_value(
        Settings.IRRECOVERABLE_CARBON_SOURCE_TYPE,
        default=DataSourceType.UNDEFINED.value,
        setting_type=int,
    )
    reference_source_path = ""
    if source_type_int == DataSourceType.LOCAL.value:
        reference_source_path = settings_manager.get_value(
            Settings.IRRECOVERABLE_CARBON_LOCAL_SOURCE, default=""
        )
    elif source_type_int == DataSourceType.ONLINE.value:
        reference_source_path = settings_manager.get_value(
            Settings.IRRECOVERABLE_CARBON_ONLINE_LOCAL_PATH, default=""
        )

    if not reference_source_path:
        log(
            f"{LOG_PREFIX} - Data source for reference irrecoverable carbon layer not found.",
            info=False,
        )
        return -1.0

    log("Calculating the total irrecoverable carbon from mean...")

    intersecting_pixel_values = _get_intersecting_pixel_values(
        ncs_pathways_layer,
        reference_source_path,
        "mean_irrecoverable_carbon",
        "Irrecoverable Carbon",
    )

    # Empty list indicates that an error occurred
    if intersecting_pixel_values is None:
        return -1.0

    pixel_count = len(intersecting_pixel_values)
    if pixel_count == 0:
        return 0.0

    # Calculate using mean-based approach: mean × pixel_count × area_per_pixel
    ic_mean = sum(intersecting_pixel_values) / float(pixel_count)
    return MEAN_REFERENCE_LAYER_AREA * pixel_count * ic_mean

calculate_pathway_carbon_by_area

calculate_pathway_carbon_by_area(ncs_pathways_carbon_info)

Calculates the carbon impact in tonnes for NCS pathways by multiplying the area of the NCS pathway layers with the user-defined carbon impact rate for the specific NCS pathway.

Parameters:

Name Type Description Default
ncs_pathways_carbon_info List[NcsPathwayCarbonInfo]

Container for pathway rasters and their corresponding carbon impact values.

required

Returns:

Type Description
float

The total carbon impact for NCS pathways. If no pathways found, returns 0.0.

Source code in src/cplus_plugin/lib/carbon.py
def calculate_pathway_carbon_by_area(
    ncs_pathways_carbon_info: typing.List[NcsPathwayCarbonInfo],
) -> float:
    """Calculates the carbon impact in tonnes for NCS pathways
    by multiplying the area of the NCS pathway layers with
    the user-defined carbon impact rate for the specific NCS pathway.

    :param ncs_pathways_carbon_info: Container for pathway rasters
    and their corresponding carbon impact values.
    :type ncs_pathways_carbon_info: typing.List[NcsPathwayCarbonInfo]

    :returns: The total carbon impact for NCS pathways. If no
    pathways found, returns 0.0.
    :rtype: float
    """
    if not ncs_pathways_carbon_info:
        log(
            f"{LOG_PREFIX} - No pathways found for calculating "
            f"carbon impact for pathways.",
            info=False,
        )
        return 0.0

    log("Calculating carbon impact for pathways...")

    total_carbon = 0.0
    for carbon_info in ncs_pathways_carbon_info:
        area = calculate_raster_area(carbon_info.layer, 1)
        if area != -1.0:
            total_carbon += area * carbon_info.carbon_impact_per_ha

    return total_carbon

calculate_stored_carbon

calculate_stored_carbon(ncs_pathways_layer)

Calculates the total stored carbon in tonnes for protect NCS pathways by summing pixel values from the biomass reference layer defined in settings.

Parameters:

Name Type Description Default
ncs_pathways_layer QgsRasterLayer

Layer containing an aggregate of protect NCS pathways.

required

Returns:

Type Description
float

The total stored carbon for protect NCS pathways. If there are any errors, returns -1.0. If no pathways found, returns 0.0.

Source code in src/cplus_plugin/lib/carbon.py
def calculate_stored_carbon(
    ncs_pathways_layer: QgsRasterLayer,
) -> float:
    """Calculates the total stored carbon in tonnes for protect NCS pathways
    by summing pixel values from the biomass reference layer defined in settings.

    :param ncs_pathways_layer: Layer containing an aggregate of protect NCS pathways.
    :type ncs_pathways_layer: QgsRasterLayer

    :returns: The total stored carbon for protect NCS pathways.
    If there are any errors, returns -1.0. If no pathways found, returns 0.0.
    :rtype: float
    """
    reference_source_path = settings_manager.get_value(
        Settings.STORED_CARBON_BIOMASS_PATH, default=""
    )

    if not reference_source_path:
        log(
            f"{LOG_PREFIX} - Data source for reference biomass layer not found.",
            info=False,
        )
        return -1.0

    log("Calculating the stored carbon...")

    intersecting_pixel_values = _get_intersecting_pixel_values(
        ncs_pathways_layer,
        reference_source_path,
        "biomass_stored_carbon",
        "Stored Carbon",
    )

    # Empty list indicates an error occurred
    if intersecting_pixel_values is None:
        return -1.0

    pixel_count = len(intersecting_pixel_values)
    if pixel_count == 0:
        return 0.0

    # Calculate by direct summation of pixel values
    return sum(intersecting_pixel_values)

Last update: November 12, 2025
Back to top