Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
435 changes: 435 additions & 0 deletions docs/validation/opera_producer_inventory_172.rst

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
16 changes: 16 additions & 0 deletions openhcs/core/components/parser_metaprogramming.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,22 @@ def construct_filename(self, components: FilenameParseResult) -> str:
"""Construct a filename from one nominal component result."""
pass

def construct_acquisition_filename(
self,
components: FilenameParseResult,
*,
include_all_components: bool = False,
plate_name: str | None = None,
include_site: bool = True,
include_channel: bool = True,
) -> str:
"""Spell a physical acquisition name; semantic identity stays complete.

Formats with folder-encoded axes or acquisition-specific spelling own
those conventions in their existing parser, not in the producer.
"""
return self.construct_filename(components)

def get_component_names(self) -> tuple[str, ...]:
"""Get all component names for this parser."""
return AllComponents.ordered_names()
Expand Down
324 changes: 100 additions & 224 deletions openhcs/demo/synthetic_data.py

Large diffs are not rendered by default.

36 changes: 31 additions & 5 deletions openhcs/microscopes/imagexpress.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,10 @@ def construct_filename(
site_padding: int = 3,
z_padding: int = 3,
timepoint_padding: int = 3,
*,
plate_name: str | None = None,
include_site: bool = True,
include_channel: bool = True,
) -> str:
"""Construct an ImageXpress filename from nominal component values."""

Expand All @@ -425,13 +429,13 @@ def construct_filename(
z_index = components.value_for(AllComponents.Z_INDEX)
timepoint = components.value_for(AllComponents.TIMEPOINT)

parts = [well]
parts = [f"{plate_name}_{well}" if plate_name is not None else well]

# Always add site
parts.append(f"_s{format_filename_component(site, site_padding)}")
if include_site:
parts.append(f"_s{format_filename_component(site, site_padding)}")

# Always add channel
parts.append(f"_w{format_filename_component(channel)}")
if include_channel:
parts.append(f"_w{format_filename_component(channel)}")

if z_index is not None:
parts.append(f"_z{format_filename_component(z_index, z_padding)}")
Expand All @@ -442,6 +446,28 @@ def construct_filename(
base_name = "".join(parts)
return f"{base_name}{components.extension}"

def construct_acquisition_filename(
self,
components: FilenameParseResult,
*,
include_all_components: bool = False,
plate_name: str | None = None,
include_site: bool = True,
include_channel: bool = True,
) -> str:
"""Own MetaXpress acquisition spelling, including folder-only Z axes."""
if not include_all_components or plate_name is not None:
components = components.with_values(
((AllComponents.Z_INDEX, None), (AllComponents.TIMEPOINT, None))
)
return self.construct_filename(
components,
site_padding=0 if plate_name is not None else 3,
plate_name=plate_name,
include_site=include_site if plate_name is not None else True,
include_channel=include_channel if plate_name is not None else True,
)


class ImageXpressMetadataHandler(DiskImageFileListingMetadataHandler):
"""
Expand Down
24 changes: 15 additions & 9 deletions openhcs/microscopes/opera_phenix.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,15 +522,9 @@ def construct_filename(
z_index = components.required_value(AllComponents.Z_INDEX)
timepoint = components.required_value(AllComponents.TIMEPOINT)

# Extract row and column from well name
# Check if well is in Opera Phenix format (e.g., 'R01C03')
match = self._well_pattern.match(well)
if match:
# Extract row and column from Opera Phenix format
row = int(match.group(1))
col = int(match.group(2))
else:
raise ValueError(f"Invalid well format: {well}. Expected format: 'R01C03'")
row_name, column_name = self.extract_component_coordinates(well)
row = ord(row_name) - ord("A") + 1
col = int(column_name)

# Construct filename in Opera Phenix format
site_part = f"f{format_filename_component(site, site_padding)}"
Expand All @@ -542,6 +536,18 @@ def construct_filename(
f"-ch{format_filename_component(channel)}{sk_part}fk1fl1{components.extension}"
)

def construct_acquisition_filename(
self,
components: FilenameParseResult,
*,
include_all_components: bool = False,
plate_name: str | None = None,
include_site: bool = True,
include_channel: bool = True,
) -> str:
"""Keep Harmony's physical field/plane spelling on the format owner."""
return self.construct_filename(components, site_padding=0, z_padding=2)

def remap_field_in_filename(
self, filename: str, xml_parser: Optional[OperaPhenixXmlParser] = None
) -> str:
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/helpers/fixture_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ def create_synthetic_plate_data(
else: # OperaPhenix
sub_dir = "Images"

generator.generate_openhcs_metadata(sub_dir=sub_dir, pixel_size=0.65)
generator.generate_openhcs_metadata(sub_dir=sub_dir)

# Return the plate directory
return plate_dir
Expand Down
Loading
Loading