Component System
OpenHCS uses a dynamic component system to organize microscopy data processing across different dimensions. The system provides two main enums - AllComponents and VariableComponents - that serve different purposes in the processing pipeline.
Understanding Component Types
OpenHCS distinguishes between components that are available for user configuration and those used for internal operations:
AllComponents: Complete component set including the multiprocessing axis VariableComponents: User-selectable components excluding the multiprocessing axis GroupBy: VariableComponents with an additional NONE option for routing
from openhcs.constants import AllComponents, VariableComponents, GroupBy
# AllComponents includes all dimensions
list(AllComponents) # [SITE, CHANNEL, Z_INDEX, WELL]
# VariableComponents excludes multiprocessing axis (WELL by default)
list(VariableComponents) # [SITE, CHANNEL, Z_INDEX]
# GroupBy adds NONE option to VariableComponents
list(GroupBy) # [SITE, CHANNEL, Z_INDEX, NONE]
Dynamic Enum Generation
Components are created dynamically from configuration when first accessed:
# Enums are generated lazily from ComponentConfiguration
from openhcs.constants import get_openhcs_config
config = get_openhcs_config()
# Configuration determines:
# - All available components (SITE, CHANNEL, Z_INDEX, WELL)
# - Multiprocessing axis (WELL)
# - Remaining components for user selection (SITE, CHANNEL, Z_INDEX)
The configuration drives which components are available and how they’re filtered for different use cases.
When to Use Each Component Type
AllComponents: Internal Operations
Use AllComponents for operations that need access to the complete dimensional space:
# Cache addressing requires full component set
orchestrator.cache_component_keys([AllComponents.WELL, AllComponents.SITE])
# Getting component keys for any dimension
axis_values = orchestrator.get_component_keys(MULTIPROCESSING_AXIS) # Dynamic axis
sites = orchestrator.get_component_keys(AllComponents.SITE)
When to use AllComponents: - Cache operations and full-space addressing - Orchestrator component key operations - Internal system operations that need complete dimensional access
VariableComponents: User Configuration
Use VariableComponents for step configuration and user-facing operations:
from openhcs.core.steps.function_step import FunctionStep
from openhcs.core.pipeline_config import LazyStepMaterializationConfig
# Step configuration with user-selectable components
step = FunctionStep(
func=(normalize_images, {}),
variable_components=[VariableComponents.SITE, VariableComponents.CHANNEL],
materialization_config=LazyStepMaterializationConfig()
)
When to use VariableComponents: - Step configuration in pipelines - UI component dropdowns and selectors - User-facing configuration options - Pattern discovery and grouping operations
GroupBy: Function Routing
Use GroupBy for dictionary function patterns and conditional routing:
# Route different channels to different functions
step = FunctionStep(
func={
'1': (analyze_nuclei, {}), # Channel 1 → nuclei analysis
'2': (analyze_neurites, {}) # Channel 2 → neurite analysis
},
group_by=GroupBy.CHANNEL,
variable_components=[VariableComponents.SITE]
)
# No grouping option
step = FunctionStep(
func=(process_all_data, {}),
group_by=GroupBy.NONE,
variable_components=[VariableComponents.SITE]
)
See also
- Pattern Grouping and Special Output Path Resolution
Comprehensive explanation of how
group_byworks for both dict and list patterns, including special output namespacing
GroupBy properties:
# Access underlying component value
assert GroupBy.CHANNEL.component == "channel"
assert GroupBy.NONE.component is None
# String value for pattern operations
component_string = GroupBy.CHANNEL.value # "channel"
Multiprocessing Axis
The multiprocessing axis determines how parallel processing is partitioned:
from openhcs.constants import MULTIPROCESSING_AXIS
# Get multiprocessing axis component (WELL by default)
axis = MULTIPROCESSING_AXIS # Returns the configured multiprocessing component
# Use in orchestrator operations
wells_to_process = orchestrator.get_component_keys(MULTIPROCESSING_AXIS)
Key characteristics: - Excluded from VariableComponents (not user-selectable) - Included in AllComponents (available for internal operations) - Used by compiler and orchestrator for task partitioning - Configurable through ComponentConfiguration
Practical Usage Examples
Step Configuration
from openhcs.core.steps.function_step import FunctionStep
from openhcs.processing.backends.processors.numpy_processor import create_composite
# Process each site separately, combining channels
composite_step = FunctionStep(
func=create_composite,
variable_components=[VariableComponents.SITE],
name="create_composite"
)
Cache Operations
# Cache all component types for fast access
orchestrator.cache_component_keys(list(AllComponents))
# Get cached component keys for current multiprocessing axis
from openhcs.constants import MULTIPROCESSING_AXIS
available_axis_values = orchestrator.get_component_keys(MULTIPROCESSING_AXIS)
Pattern Discovery
# Group patterns by component for organization
if group_by and group_by != GroupBy.NONE:
component_string = group_by.value
grouped_patterns = pattern_discovery.group_patterns_by_component(
patterns, component=component_string
)
UI Component Population
# Populate dropdown with user-selectable components
component_options = list(VariableComponents)
# Populate GroupBy selector with NONE option
groupby_options = list(GroupBy)
Integration with Configuration
The component system integrates with OpenHCS configuration for customization:
from openhcs.core.components.framework import ComponentConfigurationFactory
# Custom component configuration
config = ComponentConfigurationFactory.create_configuration(
component_enum=MyCustomEnum,
multiprocessing_axis=MyCustomEnum.BATCH,
default_variable=[MyCustomEnum.SAMPLE],
default_group_by=MyCustomEnum.CONDITION
)
This enables different microscopy setups to define their own component dimensions while maintaining the same processing patterns.
Performance Characteristics
Lazy Loading: Enums created only when first accessed
Caching: Enum instances cached to avoid recreation
Memory Overhead: Minimal - single enum instances per component set
Access Time: O(1) after initial creation
The lazy loading ensures minimal startup overhead while caching provides fast subsequent access.