Source code for fusion.io.generate

import json
from pathlib import Path

from fusion.utils.os import find_project_root


[docs] def create_pt(cores_per_link: int, network_spectrum_dict: dict[tuple, float]) -> dict[str, dict]: """Generate information relevant to the physical topology of the network. :param cores_per_link: The number of cores in each fiber's link :type cores_per_link: int :param network_spectrum_dict: The network spectrum database mapping node pairs to lengths :type network_spectrum_dict: Dict[tuple, float] :return: Physical layer information topology of the network :rtype: Dict[str, Dict] """ fiber_props_dict = { "attenuation": 0.2 / 4.343 * 1e-3, "non_linearity": 1.3e-3, "dispersion": -21.3e-27, "num_cores": cores_per_link, "fiber_type": 0, "bending_radius": 0.05, "mode_coupling_co": 4.0e-4, "propagation_const": 4e6, "core_pitch": 4e-5, # Optical band frequency ranges (in Hz) - standard ITU-T specifications "frequency_start_c": 3e8 / 1565e-9, # C-band start from 1565nm wavelength (~191.69 THz) "frequency_end_c": (3e8 / 1565e-9) + 6.0e12, # C-band end (match v5) "frequency_start_l": 3e8 / 1620e-9, # L-band start: from 1620nm wavelength "frequency_end_l": (3e8 / 1620e-9) + 6.0e12, # L-band end (match v5) "frequency_start_s": 185.0e12, # S-band start: 185.0 THz (~1460 nm) "frequency_end_s": 190.0e12, # S-band end: 190.0 THz (~1530 nm) "c_band_bw": 6.0e12, # Multi-band GSNR parameters (ported from v5 for C+L band calculations) "raman_gain_slope": 0.028 / 1e3 / 1e12, # C_r Raman gain slope "gvd": -22.6 * (1e-12 * 1e-12) / 1e3, # beta2 - Group velocity dispersion "gvd_slope": 0.14 * (1e-12 * 1e-12 * 1e-12) / 1e3, # beta3 - GVD slope } topology_dict = { "nodes": {node: {"type": "CDC"} for nodes in network_spectrum_dict for node in nodes}, "links": {}, } for link_num, (source_node, destination_node) in enumerate(network_spectrum_dict, 1): link_props_dict = { "fiber": fiber_props_dict, "length": network_spectrum_dict[(source_node, destination_node)], "source": source_node, "destination": destination_node, "span_length": 100, } topology_dict["links"][link_num] = link_props_dict # Validation check to ensure we have nodes if not topology_dict["nodes"]: keys_sample = list(network_spectrum_dict.keys())[:5] raise ValueError( f"create_pt generated empty nodes dictionary. Input " f"network_spectrum_dict had {len(network_spectrum_dict)} " f"links: {keys_sample}..." ) return topology_dict
[docs] def create_bw_info(mod_assumption: str, mod_assumptions_path: str | None = None) -> dict[str, dict]: """Determine reach and slots needed for each bandwidth and modulation format. :param mod_assumption: Controls which assumptions to be used :type mod_assumption: str :param mod_assumptions_path: Path to modulation assumptions file :type mod_assumptions_path: Optional[str] :return: The number of spectral slots needed for each bandwidth and modulation format pair :rtype: Dict[str, Dict] :raises FileNotFoundError: If modulation assumptions file is not found :raises NotImplementedError: If unknown modulation assumption is provided """ # Set default path if none provided if not mod_assumptions_path or mod_assumptions_path == "None": project_root = Path(find_project_root()) resolved_path = project_root / "data/json_input/run_mods/mod_formats.json" else: resolved_path = Path(mod_assumptions_path) # Resolve to absolute path if not resolved_path.is_absolute(): project_root = Path(find_project_root()) resolved_path = project_root / resolved_path try: with resolved_path.open("r", encoding="utf-8") as modulation_file: modulation_formats_dict = json.load(modulation_file) if mod_assumption in modulation_formats_dict: result: dict[str, dict] = modulation_formats_dict[mod_assumption] return result except json.JSONDecodeError as json_error: raise FileNotFoundError(f"Could not parse JSON: {json_error.doc}") from json_error except FileNotFoundError as file_error: raise FileNotFoundError(f"File not found: {resolved_path}") from file_error raise NotImplementedError(f"Unknown modulation assumption '{mod_assumption}'")