Source code for ewokstomo.tasks.reconstruct_volume
from pathlib import Path
import warnings
from ewokstomo.tasks.utils import (
_get_technique_from_nabu_config,
_get_output_format_from_nabu_config,
)
from ewokscore import Task
from ewokscore.model import BaseInputModel
from ewokscore.model import BaseOutputModel
from pydantic import Field
from nabu.pipeline.fullfield.reconstruction import FullFieldReconstructor
from nabu.pipeline.fullfield.processconfig import ProcessConfig
import gc
[docs]
class ReconstructVolumeOutputsModel(BaseOutputModel):
reconstructed_volume_path: str = Field(
...,
description="The file path to the saved reconstructed volume.",
)
nabu_dict: dict = Field(
...,
description="The Nabu configuration dictionary used for reconstruction.",
)
processing_options: dict = Field(
...,
description="The resolved Nabu processing options used by ProcessConfig.",
)
[docs]
class ReconstructVolume( # type: ignore[call-arg]
Task,
input_model=ReconstructVolumeInputsModel,
output_model=ReconstructVolumeOutputsModel,
):
[docs]
def run(self):
"""
Task that reconstructs a volume from full-field tomography data using Nabu:
"""
warnings.filterwarnings(
"ignore",
message="invalid value encountered in divide",
category=RuntimeWarning,
module="nabu\\.preproc\\.flatfield",
)
overwritten_config_fields = self.get_input_value("config_dict")
nx_path = Path(self.get_input_value("nx_path"))
slice_index_range = self.get_input_value("slice_index_range", None)
if not nx_path.exists():
raise FileNotFoundError(f"NX file not found: {nx_path}")
technique = _get_technique_from_nabu_config(overwritten_config_fields)
output_format = _get_output_format_from_nabu_config(overwritten_config_fields)
output_dir = nx_path.parent.parent / "volumes"
output_dir.mkdir(exist_ok=True)
output_dir = output_dir / f"{nx_path.stem}_{technique}_32Bit_{output_format}"
output_dir.mkdir(exist_ok=True)
# Prepare the configuration for nabu
overwritten_config_fields["dataset"]["location"] = str(nx_path)
overwritten_config_fields["output"]["location"] = str(output_dir)
if slice_index_range is not None:
start_idx, end_idx = slice_index_range
overwritten_config_fields["reconstruction"]["start_z"] = start_idx
overwritten_config_fields["reconstruction"]["end_z"] = end_idx
else:
overwritten_config_fields["reconstruction"]["start_z"] = 0
overwritten_config_fields["reconstruction"]["end_z"] = -1
proc = ProcessConfig(conf_dict=overwritten_config_fields)
file_prefix = f"{nx_path.stem}"
proc.processing_options["save"]["file_prefix"] = file_prefix
proc.nabu_config["output"]["file_prefix"] = file_prefix
overwritten_config_fields["output"]["file_prefix"] = file_prefix
reconstructor = FullFieldReconstructor(proc)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
reconstructor.reconstruct()
reconstructor.finalize_files_saving()
del reconstructor
try:
import cupy
cupy.get_default_memory_pool().free_all_blocks()
cupy.get_default_pinned_memory_pool().free_all_blocks()
except Exception:
print("Could not free GPU memory")
gc.collect()
save_options = proc.processing_options["save"]
save_options = proc.processing_options["save"]
output_location = Path(save_options["location"])
file_prefix = save_options["file_prefix"]
file_format = save_options["file_format"].lower()
if file_format in ("hdf5", "h5"):
reconstructed_path = str(output_location / f"{file_prefix}.{file_format}")
else:
reconstructed_path = str(output_location / f"{file_prefix}")
self.outputs.reconstructed_volume_path = reconstructed_path
self.outputs.nabu_dict = overwritten_config_fields
self.outputs.processing_options = proc.processing_options