Source code for darsia.manager.co2analysis
"""Structure for analyzing images of multi-component multi-phase experiments.
The goal of such analysis is to identify distinct components/phases. In practice, it may
have to be tailored to the specific scenario by inheritance. For more general use, a
generalized multicomponent analysis manager should be used. This module is tailored to
CO2 experiments in water, strongly motivated by the International FluidFlower Benchmark
study.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Union
from warnings import warn
import darsia
[docs]
class CO2Analysis(ABC, darsia.ConcentrationAnalysisBase):
"""
General setup for an image analysis of time series aiming at analyzing CO2 evolution.
This class inherits from darsia.TracerAnalysis.
"""
def __init__(
self,
baseline: Union[str, Path, list[str], list[Path]],
config: Union[str, Path],
update_setup: bool = False,
) -> None:
"""
Constructor for two-component analysis, where the two specific components
are identified with CO2(g) and CO2 saturated water. Pure water will be treated
as neutral (third) phase.
Args:
baseline (str, Path or list of such): see darsia.AnalysisBase.
config_source (str or Path): see darsia.AnalysisBase.
update_setup (bool): see darsia.AnalysisBase.
"""
# Call constructor of TracerAnalysis
super().__init__(baseline, config, update_setup)
# Define the specific components - use external methods to allow for further tailoring.
# The main philosophy is to first separate water from the rest, which here will be
# simply called CO2. In the CO2 region, additional separation will be required to
# separate CO2(g) from CO2 saturated water.
# Yet, only proceed if the config contains required keywords.
if "co2" in self.config.keys():
# Define the concentration analysis
self.co2_analysis = self.define_co2_analysis()
# Safety check
if not isinstance(self.co2_analysis, darsia.ConcentrationAnalysis):
raise ValueError("co2_analysis has wrong type.")
# Setup standard data including the cleaning filter
co2_cleaning_filter = self.config["co2"].get(
"cleaning_filter", "cache/cleaning_filter_co2.npy"
)
self._setup_concentration_analysis(
self.co2_analysis,
co2_cleaning_filter,
baseline,
update_setup,
)
else:
warn("CO2 analysis not well-defined.")
if "co2(g)" in self.config.keys():
# Define the concentration analysis
self.co2_gas_analysis = self.define_co2_gas_analysis()
# Safety check
if not isinstance(self.co2_gas_analysis, darsia.ConcentrationAnalysis):
raise ValueError("co2_gas_analysis has wrong type.")
# Setup standard data including the cleaning filter
co2_gas_cleaning_filter = self.config["co2(g)"].get(
"cleaning_filter", "cache/cleaning_filter_co2_gas.npy"
)
self._setup_concentration_analysis(
self.co2_gas_analysis,
co2_gas_cleaning_filter,
baseline,
update_setup,
)
else:
warn("CO2(g) analysis not well-defined.")
[docs]
@abstractmethod
def define_co2_analysis(self) -> darsia.ConcentrationAnalysis:
"""
Empty method which should define self.co2_analysis of type
darsia.ConcentrationAnalysis.
"""
pass
[docs]
@abstractmethod
def define_co2_gas_analysis(self) -> darsia.ConcentrationAnalysis:
"""
Empty method which should define self.co2_gas_analysis of type
darsia.ConcentrationAnalysis.
"""
pass
[docs]
def determine_co2(self) -> darsia.Image:
"""
Extract CO2 from currently loaded image, based on a reference image.
Returns:
darsia.Image: binary image of spatial CO2 distribution.
"""
# Make a copy of the current image
img = self.img.copy()
# Extract binary concentration
co2 = self.co2_analysis(img)
return co2
[docs]
def determine_co2_gas(self) -> darsia.Image:
"""
Extract CO2(g) from currently loaded image, based on a reference image.
Returns:
darsia.Image: binary image of spatial CO2(g) distribution.
"""
# Make a copy of the current image
img = self.img.copy()
# Extract binary concentration
co2 = self.co2_gas_analysis(img)
return co2