Utils Module
Overview
At a Glance
- Purpose:
Common utility functions used throughout FUSION
- Location:
fusion/utils/- Key Files:
config.py,logging_config.py,spectrum.py,network.py,random.py,os.py,data.py- Depends On:
fusion.configs.constants,fusion.configs.errors,numpy- Used By:
Nearly all FUSION modules
The utils module provides shared utility functions organized by domain:
configuration handling, logging, spectrum management, network analysis,
random number generation, file operations, and data manipulation.
Important
To avoid circular dependencies, import directly from specific modules rather than from the package:
# Preferred
from fusion.utils.logging_config import get_logger
from fusion.utils.spectrum import find_free_slots
# Avoid (limited exports)
from fusion.utils import get_logger
Module Summary
File |
Purpose |
Functions |
Category |
|---|---|---|---|
|
Configuration type conversion and CLI override handling |
5 |
Configuration |
|
Centralized logging setup with rotation and formatting |
8 + 1 class |
Logging |
|
Directory creation and project root discovery |
2 |
File I/O |
|
Reproducible random number generation for simulations |
3 |
RNG |
|
Spectrum slot/channel finding and overlap detection |
8 |
Spectrum |
|
Path analysis, congestion, fragmentation, modulation |
6 |
Network |
|
Dictionary sorting and manipulation |
2 |
Data |
Helper Function Reference
This section provides a quick reference for all helper functions in each file. Use this to find the right function for your task.
config.py - Configuration Management
- Purpose:
Type conversion, dictionary parsing, CLI argument handling
- Lines:
~126
Function |
Signature |
Description |
|---|---|---|
|
|
Convert “true”, “yes”, “1” to boolean |
|
|
Parse string dict representation using |
|
|
Apply CLI argument override with type conversion |
|
|
Convert with error context; raises |
|
|
Auto-convert dict params based on option name |
Usage Example:
from fusion.utils.config import str_to_bool, safe_type_convert
# Boolean conversion
enabled = str_to_bool("true") # True
enabled = str_to_bool("yes") # True
enabled = str_to_bool("false") # False
# Safe type conversion with error context
value = safe_type_convert("100", int, "num_requests")
logging_config.py - Centralized Logging
- Purpose:
Standardized logging setup with file rotation and formatting
- Lines:
~330
Function |
Signature |
Description |
|---|---|---|
|
|
Configure logger with console/file handlers and rotation |
|
|
Get existing or create basic logger (convenience) |
|
|
Configure simulation-specific logging with naming |
|
|
Decorator to log function calls with args/return |
|
|
Set log level for all FUSION loggers |
|
|
Log to queue (multi-process) or standard logger |
Class |
Purpose |
Key Methods |
|---|---|---|
|
Add contextual info to log messages |
|
Constants:
DEFAULT_FORMAT: Standard log format with timestamp, name, level, messageDETAILED_FORMAT: Includes filename and line number for debuggingLOG_LEVELS: Dict mapping level names to logging constants
Usage Example:
from fusion.utils.logging_config import get_logger, setup_logger
# Simple usage
logger = get_logger(__name__)
logger.info("Starting simulation")
# Advanced with file rotation
logger = setup_logger(
name="simulation",
level="DEBUG",
log_file="sim.log",
max_bytes=10_485_760, # 10MB
backup_count=5
)
# Simulation-specific logging
from fusion.utils.logging_config import configure_simulation_logging
logger = configure_simulation_logging("NSFNet", erlang=300.0, thread_num=1)
os.py - File and Path Operations
- Purpose:
Directory creation and project root discovery
- Lines:
~63
Function |
Signature |
Description |
|---|---|---|
|
|
Create directory with parent dirs; raises |
|
|
Find root by searching for |
Usage Example:
from fusion.utils.os import create_directory, find_project_root
# Create nested directories
create_directory("results/experiment_1/data")
# Find project root from anywhere
root = find_project_root()
config_path = os.path.join(root, "configs", "default.ini")
random.py - Random Number Generation
- Purpose:
Reproducible RNG for simulations using numpy
- Lines:
~79
Function |
Signature |
Description |
|---|---|---|
|
|
Set numpy seed for reproducibility |
|
|
Uniform [0,1] or scaled integer [0, scale) |
|
|
Exponential distribution via inverse transform |
Usage Example:
from fusion.utils.random import (
set_random_seed,
generate_uniform_random_variable,
generate_exponential_random_variable
)
# Reproducible simulation
set_random_seed(42)
# Uniform random for path selection
rand = generate_uniform_random_variable() # [0, 1)
# Scaled integer for node selection
node = generate_uniform_random_variable(14) # [0, 14) integer
# Inter-arrival time (Poisson process)
inter_arrival = generate_exponential_random_variable(scale=10.0)
spectrum.py - Spectrum Allocation Utilities
- Purpose:
Slot/channel finding, overlap detection, multi-core fiber support
- Lines:
~471
Function |
Signature |
Description |
|---|---|---|
|
|
Find unallocated spectral slots per link/core |
|
|
Find contiguous free super-channels |
|
|
Find occupied super-channels on link |
|
|
Find overlapping channels between adjacent cores |
|
|
Find slots available on ALL paths (for 1+1 protection) |
|
|
Get adjacent cores for 7/4/13/19-core layouts |
|
|
Normalize path to set of link tuples |
|
|
Find lightpaths that overlap with new lightpath |
Core Adjacency Diagram:
7-Core Fiber Layout:
1
/ \
6 0 2 Core 0 (center) -> adjacent to 1,2,3,4,5,6
\ / Core 1 -> adjacent to 0,2,6
5 4 3 Core 2 -> adjacent to 0,1,3
...etc (hexagonal pattern)
Usage Example:
from fusion.utils.spectrum import (
find_free_slots,
find_free_channels,
adjacent_core_indices
)
# Find free slots on a link
free = find_free_slots(
network_spectrum=network_state.spectrum,
link_tuple=(0, 1)
)
# Returns: {"c": {0: [0,1,2,5,6], 1: [0,1,2,3,4], ...}}
# Find contiguous channels for allocation
channels = find_free_channels(
network_spectrum=network_state.spectrum,
slots_needed=4,
link_tuple=(0, 1)
)
# Get adjacent cores for crosstalk analysis
adjacent = adjacent_core_indices(core_id=0, cores_per_link=7)
# Returns: [1, 2, 3, 4, 5, 6]
network.py - Network Path and Congestion Utilities
- Purpose:
Path analysis, modulation selection, congestion/fragmentation metrics
- Lines:
~269
Function |
Signature |
Description |
|---|---|---|
|
|
Sum edge weights along path (km) |
|
|
Average congestion % on core along path |
|
|
Choose modulation by max reach; False if too long |
|
|
Return (avg_congestion, scaled_capacity) |
|
|
Compute fragmentation ratio [0,1] along path |
|
|
Time-weighted average bandwidth utilization |
Usage Example:
from fusion.utils.network import (
find_path_length,
get_path_modulation,
find_path_congestion
)
# Calculate path length
path = [0, 3, 5, 8]
length = find_path_length(path, topology) # e.g., 850.5 km
# Select appropriate modulation
mod = get_path_modulation(
modulation_formats=engine_props["mod_per_bw"]["50GHz"],
path_length=length
) # Returns "QPSK", "16-QAM", "64-QAM", or False
# Check path congestion
congestion, capacity = find_path_congestion(
path_list=path,
network_spectrum=spectrum,
band="c"
)
data.py - Data Structure Manipulation
- Purpose:
Dictionary sorting utilities
- Lines:
~41
Function |
Signature |
Description |
|---|---|---|
|
|
Sort keys descending (numeric order) |
|
|
Sort by nested key value ascending |
Usage Example:
from fusion.utils.data import sort_dict_keys, sort_nested_dict_values
# Sort modulation formats by bandwidth (descending)
bw_dict = {"100": {...}, "50": {...}, "200": {...}}
sorted_bw = sort_dict_keys(bw_dict)
# Returns: {"200": {...}, "100": {...}, "50": {...}}
# Sort paths by weight
paths = {
"path1": {"hops": 3, "weight": 0.8},
"path2": {"hops": 2, "weight": 0.3},
}
sorted_paths = sort_nested_dict_values(paths, "weight")
# Returns paths sorted by weight ascending
Architecture
Module Organization
fusion/utils/
+-- __init__.py # Limited exports (get_logger, setup_logger)
+-- config.py # Configuration helpers
+-- logging_config.py # Logging infrastructure
+-- os.py # File/path operations
+-- random.py # RNG for simulations
+-- spectrum.py # Spectrum allocation
+-- network.py # Network analysis
+-- data.py # Data manipulation
+-- tests/ # Unit tests
Dependency Flow
External Dependencies:
+---------------------+
| numpy | <-- random.py, network.py
| networkx | <-- network.py
| logging (stdlib) | <-- logging_config.py
| pathlib (stdlib) | <-- os.py
| ast (stdlib) | <-- config.py
+---------------------+
Internal Dependencies:
+---------------------+
| fusion.configs |
| .constants | <-- os.py (PROJECT_ROOT)
| .errors | <-- config.py (ConfigTypeConversionError)
+---------------------+
Why Utils Exists Here
The fusion/utils/ module exists to:
Avoid circular dependencies: Common functions that multiple modules need (logging, spectrum, network) are centralized here to prevent import cycles between
fusion.core,fusion.sim, andfusion.pipelines.Provide shared infrastructure: Logging configuration, RNG seeding, and path utilities are used everywhere and need a single source of truth.
Keep domain modules focused: By extracting utility functions, domain modules like
fusion.corecan focus on simulation logic.
Note
There is also a fusion/sim/utils/ module with simulation-specific
utilities. The distinction:
fusion/utils/: General utilities used across the entire codebasefusion/sim/utils/: Simulation orchestration utilities
Common Patterns
Backward Compatibility
Many functions support legacy parameter names:
# Both work - new name preferred
find_free_slots(network_spectrum=state) # New
find_free_slots(network_spectrum_dict=state) # Legacy
# Both work - new name preferred
get_path_modulation(modulation_formats=mods) # New
get_path_modulation(mods_dict=mods) # Legacy
Error Handling
Functions raise specific exceptions with context:
Module |
Exception |
Condition |
|---|---|---|
|
|
Type conversion fails |
|
|
Directory path is None |
|
|
Project root not found |
|
|
Negative seed or non-positive scale |
|
|
Missing required parameters |
|
|
Invalid time progression |
Logging Best Practices
# DO: Use get_logger with module name
logger = get_logger(__name__)
# DO: Use appropriate log levels
logger.debug("Detailed debug info")
logger.info("Normal operation info")
logger.warning("Something unexpected")
logger.error("Something failed")
# DON'T: Use print statements
print("Debug info") # Bad!
# DON'T: Create loggers manually
logger = logging.getLogger(__name__) # Use get_logger instead