mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-01 18:47:48 +00:00
fix: linter issues on json_io
add docstrings, typing, small fixes Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: I01d0fabe5e34103077ec2de829e96829e6202e1e
This commit is contained in:
@@ -8,13 +8,15 @@ gnpy.tools.json_io
|
|||||||
Loading and saving data from JSON files in GNPy's internal data format
|
Loading and saving data from JSON files in GNPy's internal data format
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from networkx import DiGraph
|
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import json
|
import json
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from numpy import arange
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
from typing import Union, Dict, List
|
||||||
|
from networkx import DiGraph
|
||||||
|
from numpy import arange
|
||||||
|
|
||||||
|
|
||||||
from gnpy.core import elements
|
from gnpy.core import elements
|
||||||
from gnpy.core.equipment import trx_mode_params, find_type_variety
|
from gnpy.core.equipment import trx_mode_params, find_type_variety
|
||||||
@@ -40,15 +42,21 @@ Model_dual_stage = namedtuple('Model_dual_stage', 'preamp_variety booster_variet
|
|||||||
|
|
||||||
|
|
||||||
class Model_openroadm_preamp:
|
class Model_openroadm_preamp:
|
||||||
pass
|
"""class to hold nf model specific to OpenROADM preamp
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Model_openroadm_booster:
|
class Model_openroadm_booster:
|
||||||
pass
|
"""class to hold nf model specific to OpenROADM booster
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class _JsonThing:
|
class _JsonThing:
|
||||||
|
"""Base class for json equipment
|
||||||
|
"""
|
||||||
def update_attr(self, default_values, kwargs, name):
|
def update_attr(self, default_values, kwargs, name):
|
||||||
|
"""Build the attributes based on kwargs dict
|
||||||
|
"""
|
||||||
clean_kwargs = {k: v for k, v in kwargs.items() if v != ''}
|
clean_kwargs = {k: v for k, v in kwargs.items() if v != ''}
|
||||||
for k, v in default_values.items():
|
for k, v in default_values.items():
|
||||||
setattr(self, k, clean_kwargs.get(k, v))
|
setattr(self, k, clean_kwargs.get(k, v))
|
||||||
@@ -60,6 +68,8 @@ class _JsonThing:
|
|||||||
|
|
||||||
|
|
||||||
class SI(_JsonThing):
|
class SI(_JsonThing):
|
||||||
|
"""Spectrum Information
|
||||||
|
"""
|
||||||
default_values = {
|
default_values = {
|
||||||
"f_min": 191.35e12,
|
"f_min": 191.35e12,
|
||||||
"f_max": 196.1e12,
|
"f_max": 196.1e12,
|
||||||
@@ -78,6 +88,8 @@ class SI(_JsonThing):
|
|||||||
|
|
||||||
|
|
||||||
class Span(_JsonThing):
|
class Span(_JsonThing):
|
||||||
|
"""Span simulations definition
|
||||||
|
"""
|
||||||
default_values = {
|
default_values = {
|
||||||
'power_mode': True,
|
'power_mode': True,
|
||||||
'delta_power_range_db': None,
|
'delta_power_range_db': None,
|
||||||
@@ -97,6 +109,8 @@ class Span(_JsonThing):
|
|||||||
|
|
||||||
|
|
||||||
class Roadm(_JsonThing):
|
class Roadm(_JsonThing):
|
||||||
|
"""List of ROADM and their specs
|
||||||
|
"""
|
||||||
default_values = {
|
default_values = {
|
||||||
'type_variety': 'default',
|
'type_variety': 'default',
|
||||||
'add_drop_osnr': 100,
|
'add_drop_osnr': 100,
|
||||||
@@ -129,6 +143,8 @@ class Roadm(_JsonThing):
|
|||||||
|
|
||||||
|
|
||||||
class Transceiver(_JsonThing):
|
class Transceiver(_JsonThing):
|
||||||
|
"""List of transceivers and their modes
|
||||||
|
"""
|
||||||
default_values = {
|
default_values = {
|
||||||
'type_variety': None,
|
'type_variety': None,
|
||||||
'frequency': None,
|
'frequency': None,
|
||||||
@@ -161,6 +177,8 @@ class Transceiver(_JsonThing):
|
|||||||
|
|
||||||
|
|
||||||
class Fiber(_JsonThing):
|
class Fiber(_JsonThing):
|
||||||
|
"""Fiber default settings
|
||||||
|
"""
|
||||||
default_values = {
|
default_values = {
|
||||||
'type_variety': '',
|
'type_variety': '',
|
||||||
'dispersion': None,
|
'dispersion': None,
|
||||||
@@ -181,10 +199,13 @@ class Fiber(_JsonThing):
|
|||||||
|
|
||||||
|
|
||||||
class RamanFiber(Fiber):
|
class RamanFiber(Fiber):
|
||||||
pass
|
"""Raman Fiber default settings
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Amp(_JsonThing):
|
class Amp(_JsonThing):
|
||||||
|
"""List of amplifiers with their specs
|
||||||
|
"""
|
||||||
default_values = EdfaParams.default_values
|
default_values = EdfaParams.default_values
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
@@ -192,6 +213,8 @@ class Amp(_JsonThing):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, filename, **kwargs):
|
def from_json(cls, filename, **kwargs):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
config = Path(filename).parent / 'default_edfa_config.json'
|
config = Path(filename).parent / 'default_edfa_config.json'
|
||||||
# default_edfa_config.json assumes a DGT profile independantly from fmin/fmax, that's a generic profile
|
# default_edfa_config.json assumes a DGT profile independantly from fmin/fmax, that's a generic profile
|
||||||
type_variety = kwargs['type_variety']
|
type_variety = kwargs['type_variety']
|
||||||
@@ -203,9 +226,9 @@ class Amp(_JsonThing):
|
|||||||
if type_def == 'fixed_gain':
|
if type_def == 'fixed_gain':
|
||||||
try:
|
try:
|
||||||
nf0 = kwargs.pop('nf0')
|
nf0 = kwargs.pop('nf0')
|
||||||
except KeyError: # nf0 is expected for a fixed gain amp
|
except KeyError as exc: # nf0 is expected for a fixed gain amp
|
||||||
msg = f'missing nf0 value input for amplifier: {type_variety} in equipment config'
|
msg = f'missing nf0 value input for amplifier: {type_variety} in equipment config'
|
||||||
raise EquipmentConfigError(msg)
|
raise EquipmentConfigError(msg) from exc
|
||||||
for k in ('nf_min', 'nf_max'):
|
for k in ('nf_min', 'nf_max'):
|
||||||
try:
|
try:
|
||||||
del kwargs[k]
|
del kwargs[k]
|
||||||
@@ -219,9 +242,9 @@ class Amp(_JsonThing):
|
|||||||
try: # nf_min and nf_max are expected for a variable gain amp
|
try: # nf_min and nf_max are expected for a variable gain amp
|
||||||
nf_min = kwargs.pop('nf_min')
|
nf_min = kwargs.pop('nf_min')
|
||||||
nf_max = kwargs.pop('nf_max')
|
nf_max = kwargs.pop('nf_max')
|
||||||
except KeyError:
|
except KeyError as exc:
|
||||||
msg = f'missing nf_min or nf_max value input for amplifier: {type_variety} in equipment config'
|
msg = f'missing nf_min or nf_max value input for amplifier: {type_variety} in equipment config'
|
||||||
raise EquipmentConfigError(msg)
|
raise EquipmentConfigError(msg) from exc
|
||||||
try: # remove all remaining nf inputs
|
try: # remove all remaining nf inputs
|
||||||
del kwargs['nf0']
|
del kwargs['nf0']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -231,8 +254,8 @@ class Amp(_JsonThing):
|
|||||||
elif type_def == 'openroadm':
|
elif type_def == 'openroadm':
|
||||||
try:
|
try:
|
||||||
nf_coef = kwargs.pop('nf_coef')
|
nf_coef = kwargs.pop('nf_coef')
|
||||||
except KeyError: # nf_coef is expected for openroadm amp
|
except KeyError as exc: # nf_coef is expected for openroadm amp
|
||||||
raise EquipmentConfigError(f'missing nf_coef input for amplifier: {type_variety} in equipment config')
|
raise EquipmentConfigError(f'missing nf_coef input for amplifier: {type_variety} in equipment config') from exc
|
||||||
nf_def = Model_openroadm_ila(nf_coef)
|
nf_def = Model_openroadm_ila(nf_coef)
|
||||||
elif type_def == 'openroadm_preamp':
|
elif type_def == 'openroadm_preamp':
|
||||||
nf_def = Model_openroadm_preamp()
|
nf_def = Model_openroadm_preamp()
|
||||||
@@ -242,9 +265,9 @@ class Amp(_JsonThing):
|
|||||||
try: # nf_ram and gain_ram are expected for a hybrid amp
|
try: # nf_ram and gain_ram are expected for a hybrid amp
|
||||||
preamp_variety = kwargs.pop('preamp_variety')
|
preamp_variety = kwargs.pop('preamp_variety')
|
||||||
booster_variety = kwargs.pop('booster_variety')
|
booster_variety = kwargs.pop('booster_variety')
|
||||||
except KeyError:
|
except KeyError as exc:
|
||||||
raise EquipmentConfigError(f'missing preamp/booster variety input for amplifier: {type_variety}'
|
raise EquipmentConfigError(f'missing preamp/booster variety input for amplifier: {type_variety}'
|
||||||
+ ' in equipment config')
|
+ ' in equipment config') from exc
|
||||||
dual_stage_def = Model_dual_stage(preamp_variety, booster_variety)
|
dual_stage_def = Model_dual_stage(preamp_variety, booster_variety)
|
||||||
elif type_def == 'multi_band':
|
elif type_def == 'multi_band':
|
||||||
amplifiers = kwargs['amplifiers']
|
amplifiers = kwargs['amplifiers']
|
||||||
@@ -264,7 +287,7 @@ class Amp(_JsonThing):
|
|||||||
'nf_model': nf_def, 'dual_stage_model': dual_stage_def, 'multi_band': amplifiers})
|
'nf_model': nf_def, 'dual_stage_model': dual_stage_def, 'multi_band': amplifiers})
|
||||||
|
|
||||||
|
|
||||||
def _spectrum_from_json(json_data):
|
def _spectrum_from_json(json_data: dict):
|
||||||
"""JSON_data is a list of spectrum partitions each with
|
"""JSON_data is a list of spectrum partitions each with
|
||||||
{f_min, f_max, baud_rate, roll_off, delta_pdb, slot_width, tx_osnr, label}
|
{f_min, f_max, baud_rate, roll_off, delta_pdb, slot_width, tx_osnr, label}
|
||||||
Creates the per freq Carrier's dict.
|
Creates the per freq Carrier's dict.
|
||||||
@@ -306,17 +329,13 @@ def _spectrum_from_json(json_data):
|
|||||||
previous_part_max_freq = 0.0
|
previous_part_max_freq = 0.0
|
||||||
for index, part in enumerate(json_data):
|
for index, part in enumerate(json_data):
|
||||||
# default delta_pdb is 0 dB
|
# default delta_pdb is 0 dB
|
||||||
if 'delta_pdb' not in part:
|
part.setdefault('delta_pdb', 0)
|
||||||
part['delta_pdb'] = 0
|
|
||||||
# add a label to the partition for the printings
|
# add a label to the partition for the printings
|
||||||
if 'label' not in part:
|
part.setdefault('label', f'{index}-{part["baud_rate"] * 1e-9:.2f}G')
|
||||||
part['label'] = f'{index}-{part["baud_rate"] * 1e-9 :.2f}G'
|
|
||||||
# default tx_osnr is set to 40 dB
|
# default tx_osnr is set to 40 dB
|
||||||
if 'tx_osnr' not in part:
|
part.setdefault('tx_osnr', 40)
|
||||||
part['tx_osnr'] = 40
|
|
||||||
# default tx_power_dbm is set to 0 dBn
|
# default tx_power_dbm is set to 0 dBn
|
||||||
if 'tx_power_dbm' not in part:
|
part.setdefault('tx_power_dbm', 0)
|
||||||
part['tx_power_dbm'] = 0
|
|
||||||
# starting freq is exactly f_min to be consistent with utils.automatic_nch
|
# starting freq is exactly f_min to be consistent with utils.automatic_nch
|
||||||
# first partition min occupation is f_min - slot_width / 2 (central_frequency is f_min)
|
# first partition min occupation is f_min - slot_width / 2 (central_frequency is f_min)
|
||||||
# supposes that carriers are centered on frequency
|
# supposes that carriers are centered on frequency
|
||||||
@@ -324,12 +343,13 @@ def _spectrum_from_json(json_data):
|
|||||||
# check that previous part last channel does not overlap on next part first channel
|
# check that previous part last channel does not overlap on next part first channel
|
||||||
# max center of the part should be below part['f_max'] and aligned on the slot_width
|
# max center of the part should be below part['f_max'] and aligned on the slot_width
|
||||||
msg = 'Not a valid initial spectrum definition:\nprevious spectrum last carrier max occupation ' +\
|
msg = 'Not a valid initial spectrum definition:\nprevious spectrum last carrier max occupation ' +\
|
||||||
f'{previous_part_max_freq * 1e-12 :.5f}GHz ' +\
|
f'{previous_part_max_freq * 1e-12:.5f}GHz ' +\
|
||||||
'overlaps on next spectrum first carrier occupation ' +\
|
'overlaps on next spectrum first carrier occupation ' +\
|
||||||
f'{(part["f_min"] - part["slot_width"] / 2) * 1e-12 :.5f}GHz'
|
f'{(part["f_min"] - part["slot_width"] / 2) * 1e-12:.5f}GHz'
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
max_range = ((part['f_max'] - part['f_min']) // part['slot_width'] + 1) * part['slot_width']
|
max_range = ((part['f_max'] - part['f_min']) // part['slot_width'] + 1) * part['slot_width']
|
||||||
|
previous_part_max_freq = None
|
||||||
for current_freq in arange(part['f_min'],
|
for current_freq in arange(part['f_min'],
|
||||||
part['f_min'] + max_range,
|
part['f_min'] + max_range,
|
||||||
part['slot_width']):
|
part['slot_width']):
|
||||||
@@ -341,17 +361,26 @@ def _spectrum_from_json(json_data):
|
|||||||
return spectrum
|
return spectrum
|
||||||
|
|
||||||
|
|
||||||
def load_equipment(filename):
|
def load_equipment(filename: Path) -> dict:
|
||||||
|
"""Load equipment, returns equipment dict
|
||||||
|
"""
|
||||||
json_data = load_json(filename)
|
json_data = load_json(filename)
|
||||||
return _equipment_from_json(json_data, filename)
|
return _equipment_from_json(json_data, filename)
|
||||||
|
|
||||||
|
|
||||||
def load_initial_spectrum(filename):
|
def load_initial_spectrum(filename: Path) -> dict:
|
||||||
|
"""Load spectrum to propagate, returns spectrum dict
|
||||||
|
"""
|
||||||
json_data = load_json(filename)
|
json_data = load_json(filename)
|
||||||
return _spectrum_from_json(json_data['spectrum'])
|
return _spectrum_from_json(json_data['spectrum'])
|
||||||
|
|
||||||
|
|
||||||
def _update_dual_stage(equipment):
|
def _update_dual_stage(equipment: dict) -> dict:
|
||||||
|
"""Update attributes of all dual stage amps with the preamp and booster attributes
|
||||||
|
(defined in the equipment dictionary)
|
||||||
|
|
||||||
|
Returns the updated equiment dictionary
|
||||||
|
"""
|
||||||
edfa_dict = equipment['Edfa']
|
edfa_dict = equipment['Edfa']
|
||||||
for edfa in edfa_dict.values():
|
for edfa in edfa_dict.values():
|
||||||
if edfa.type_def == 'dual_stage':
|
if edfa.type_def == 'dual_stage':
|
||||||
@@ -395,7 +424,7 @@ def _update_band(equipment: dict) -> dict:
|
|||||||
return equipment
|
return equipment
|
||||||
|
|
||||||
|
|
||||||
def _roadm_restrictions_sanity_check(equipment):
|
def _roadm_restrictions_sanity_check(equipment: dict):
|
||||||
"""verifies that booster and preamp restrictions specified in roadm equipment are listed in the edfa."""
|
"""verifies that booster and preamp restrictions specified in roadm equipment are listed in the edfa."""
|
||||||
for roadm_type, roadm_eqpt in equipment['Roadm'].items():
|
for roadm_type, roadm_eqpt in equipment['Roadm'].items():
|
||||||
restrictions = roadm_eqpt.restrictions['booster_variety_list'] + \
|
restrictions = roadm_eqpt.restrictions['booster_variety_list'] + \
|
||||||
@@ -406,7 +435,7 @@ def _roadm_restrictions_sanity_check(equipment):
|
|||||||
+ 'defined EDFA name')
|
+ 'defined EDFA name')
|
||||||
|
|
||||||
|
|
||||||
def _check_fiber_vs_raman_fiber(equipment):
|
def _check_fiber_vs_raman_fiber(equipment: dict):
|
||||||
"""Ensure that Fiber and RamanFiber with the same name define common properties equally"""
|
"""Ensure that Fiber and RamanFiber with the same name define common properties equally"""
|
||||||
if 'RamanFiber' not in equipment:
|
if 'RamanFiber' not in equipment:
|
||||||
return
|
return
|
||||||
@@ -421,7 +450,7 @@ def _check_fiber_vs_raman_fiber(equipment):
|
|||||||
f'disagrees for "{attr}": {a} != {b}')
|
f'disagrees for "{attr}": {a} != {b}')
|
||||||
|
|
||||||
|
|
||||||
def _equipment_from_json(json_data, filename):
|
def _equipment_from_json(json_data: dict, filename: Path) -> dict:
|
||||||
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
||||||
edfa type type_variety, fiber type_variety
|
edfa type type_variety, fiber type_variety
|
||||||
from the eqpt_config.json (filename parameter)
|
from the eqpt_config.json (filename parameter)
|
||||||
@@ -466,7 +495,12 @@ def _equipment_from_json(json_data, filename):
|
|||||||
return equipment
|
return equipment
|
||||||
|
|
||||||
|
|
||||||
def load_network(filename, equipment):
|
def load_network(filename: Path, equipment: dict) -> DiGraph:
|
||||||
|
"""load network json or excel
|
||||||
|
|
||||||
|
:param filename: input file to read from
|
||||||
|
:param equipment: equipment library
|
||||||
|
"""
|
||||||
if filename.suffix.lower() in ('.xls', '.xlsx'):
|
if filename.suffix.lower() in ('.xls', '.xlsx'):
|
||||||
json_data = xls_to_json_data(filename)
|
json_data = xls_to_json_data(filename)
|
||||||
elif filename.suffix.lower() == '.json':
|
elif filename.suffix.lower() == '.json':
|
||||||
@@ -490,21 +524,22 @@ def _cls_for(equipment_type):
|
|||||||
return elements.Edfa
|
return elements.Edfa
|
||||||
if equipment_type == 'Fused':
|
if equipment_type == 'Fused':
|
||||||
return elements.Fused
|
return elements.Fused
|
||||||
elif equipment_type == 'Roadm':
|
if equipment_type == 'Roadm':
|
||||||
return elements.Roadm
|
return elements.Roadm
|
||||||
elif equipment_type == 'Transceiver':
|
if equipment_type == 'Transceiver':
|
||||||
return elements.Transceiver
|
return elements.Transceiver
|
||||||
elif equipment_type == 'Fiber':
|
if equipment_type == 'Fiber':
|
||||||
return elements.Fiber
|
return elements.Fiber
|
||||||
elif equipment_type == 'RamanFiber':
|
if equipment_type == 'RamanFiber':
|
||||||
return elements.RamanFiber
|
return elements.RamanFiber
|
||||||
elif equipment_type == 'Multiband_amplifier':
|
if equipment_type == 'Multiband_amplifier':
|
||||||
return elements.Multiband_amplifier
|
return elements.Multiband_amplifier
|
||||||
else:
|
|
||||||
raise ConfigurationError(f'Unknown network equipment "{equipment_type}"')
|
raise ConfigurationError(f'Unknown network equipment "{equipment_type}"')
|
||||||
|
|
||||||
|
|
||||||
def network_from_json(json_data, equipment):
|
def network_from_json(json_data: dict, equipment: dict) -> DiGraph:
|
||||||
|
"""create digraph based on json input dict and using equipment library to fill in the gaps
|
||||||
|
"""
|
||||||
# NOTE|dutc: we could use the following, but it would tie our data format
|
# NOTE|dutc: we could use the following, but it would tie our data format
|
||||||
# too closely to the graph library
|
# too closely to the graph library
|
||||||
# from networkx import node_link_graph
|
# from networkx import node_link_graph
|
||||||
@@ -600,14 +635,16 @@ def network_from_json(json_data, equipment):
|
|||||||
else:
|
else:
|
||||||
edge_length = 0.01
|
edge_length = 0.01
|
||||||
g.add_edge(nodes[from_node], nodes[to_node], weight=edge_length)
|
g.add_edge(nodes[from_node], nodes[to_node], weight=edge_length)
|
||||||
except KeyError:
|
except KeyError as exc:
|
||||||
msg = f'can not find {from_node} or {to_node} defined in {cx}'
|
msg = f'can not find {from_node} or {to_node} defined in {cx}'
|
||||||
raise NetworkTopologyError(msg)
|
raise NetworkTopologyError(msg) from exc
|
||||||
|
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
|
||||||
def network_to_json(network):
|
def network_to_json(network: DiGraph) -> dict:
|
||||||
|
"""Export network graph as a json dict
|
||||||
|
"""
|
||||||
data = {
|
data = {
|
||||||
'elements': [n.to_json for n in network]
|
'elements': [n.to_json for n in network]
|
||||||
}
|
}
|
||||||
@@ -621,30 +658,35 @@ def network_to_json(network):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def load_json(filename):
|
def load_json(filename: Path) -> dict:
|
||||||
|
"""load json data, convert from the yang to the legacy
|
||||||
|
supports both legacy ang yang formatted inputs based on yang models
|
||||||
|
"""
|
||||||
with open(filename, 'r', encoding='utf-8') as f:
|
with open(filename, 'r', encoding='utf-8') as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def save_json(obj, filename):
|
def save_json(obj: Dict, filename: Path):
|
||||||
|
"""Save in json format. Use yang formatted data for Topo and Services
|
||||||
|
"""
|
||||||
with open(filename, 'w', encoding='utf-8') as f:
|
with open(filename, 'w', encoding='utf-8') as f:
|
||||||
json.dump(obj, f, indent=2, ensure_ascii=False)
|
json.dump(obj, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
def load_requests(filename, eqpt, bidir, network, network_filename):
|
def load_requests(filename: Path, eqpt: dict, bidir: bool, network: DiGraph, network_filename: str) -> dict:
|
||||||
"""loads the requests from a json or an excel file into a data string"""
|
"""loads the requests from a json or an excel file into a data string"""
|
||||||
if filename.suffix.lower() in ('.xls', '.xlsx'):
|
if filename.suffix.lower() in ('.xls', '.xlsx'):
|
||||||
_logger.info('Automatically converting requests from XLS to JSON')
|
_logger.info('Automatically converting requests from XLS to JSON')
|
||||||
try:
|
try:
|
||||||
return convert_service_sheet(filename, eqpt, network, network_filename=network_filename, bidir=bidir)
|
return convert_service_sheet(filename, eqpt, network, network_filename=network_filename, bidir=bidir)
|
||||||
except ServiceError as this_e:
|
except ServiceError as this_e:
|
||||||
raise ServiceError(f'Service error: {this_e}')
|
raise ServiceError(f'Service error: {this_e}') from this_e
|
||||||
else:
|
else:
|
||||||
return load_json(filename)
|
return load_json(filename)
|
||||||
|
|
||||||
|
|
||||||
def requests_from_json(json_data, equipment):
|
def requests_from_json(json_data: dict, equipment: dict) -> List[PathRequest]:
|
||||||
"""Extract list of requests from data parsed from JSON"""
|
"""Extract list of requests from data parsed from JSON"""
|
||||||
requests_list = []
|
requests_list = []
|
||||||
|
|
||||||
@@ -713,7 +755,7 @@ def requests_from_json(json_data, equipment):
|
|||||||
return requests_list
|
return requests_list
|
||||||
|
|
||||||
|
|
||||||
def _check_one_request(params, f_max_from_si):
|
def _check_one_request(params: dict, f_max_from_si: float):
|
||||||
"""Checks that the requested parameters are consistant (spacing vs nb channel vs transponder mode...)"""
|
"""Checks that the requested parameters are consistant (spacing vs nb channel vs transponder mode...)"""
|
||||||
f_min = params['f_min']
|
f_min = params['f_min']
|
||||||
f_max = params['f_max']
|
f_max = params['f_max']
|
||||||
@@ -723,17 +765,17 @@ def _check_one_request(params, f_max_from_si):
|
|||||||
if params['min_spacing'] > params['spacing']:
|
if params['min_spacing'] > params['spacing']:
|
||||||
msg = f'Request {params["request_id"]} has spacing below transponder ' +\
|
msg = f'Request {params["request_id"]} has spacing below transponder ' +\
|
||||||
f'{params["trx_type"]} {params["trx_mode"]} min spacing value ' +\
|
f'{params["trx_type"]} {params["trx_mode"]} min spacing value ' +\
|
||||||
f'{params["min_spacing"]*1e-9}GHz.\nComputation stopped'
|
f'{params["min_spacing"] * 1e-9}GHz.\nComputation stopped'
|
||||||
raise ServiceError(msg)
|
raise ServiceError(msg)
|
||||||
if f_max > f_max_from_si:
|
if f_max > f_max_from_si:
|
||||||
msg = f'Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"] * 1e-9} GHz' \
|
msg = f'Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"] * 1e-9} GHz' \
|
||||||
+ f' and requested spacing {params["spacing"]*1e-9}GHz is not consistent with frequency range' \
|
+ f' and requested spacing {params["spacing"] * 1e-9}GHz is not consistent with frequency range' \
|
||||||
+ f' {f_min*1e-12} THz, {f_max_from_si*1e-12} THz.' \
|
+ f' {f_min * 1e-12} THz, {f_max_from_si * 1e-12} THz.' \
|
||||||
+ f' Max recommanded nb of channels is {max_recommanded_nb_channels}.'
|
+ f' Max recommanded nb of channels is {max_recommanded_nb_channels}.'
|
||||||
raise ServiceError(msg)
|
raise ServiceError(msg)
|
||||||
# Transponder mode already selected; will it fit to the requested bandwidth?
|
# Transponder mode already selected; will it fit to the requested bandwidth?
|
||||||
if params['trx_mode'] is not None and params['effective_freq_slot'] is not None:
|
if params['trx_mode'] is not None and params['effective_freq_slot'] is not None:
|
||||||
required_nb_of_channels, requested_m = compute_spectrum_slot_vs_bandwidth(params['path_bandwidth'],
|
required_nb_of_channels, _ = compute_spectrum_slot_vs_bandwidth(params['path_bandwidth'],
|
||||||
params['spacing'],
|
params['spacing'],
|
||||||
params['bit_rate'])
|
params['bit_rate'])
|
||||||
_, per_channel_m = compute_spectrum_slot_vs_bandwidth(params['bit_rate'],
|
_, per_channel_m = compute_spectrum_slot_vs_bandwidth(params['bit_rate'],
|
||||||
@@ -774,7 +816,7 @@ def _check_one_request(params, f_max_from_si):
|
|||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
def disjunctions_from_json(json_data):
|
def disjunctions_from_json(json_data: dict) -> List[Disjunction]:
|
||||||
"""reads the disjunction requests from the json dict and create the list
|
"""reads the disjunction requests from the json dict and create the list
|
||||||
of requested disjunctions for this set of requests
|
of requested disjunctions for this set of requests
|
||||||
"""
|
"""
|
||||||
@@ -793,20 +835,30 @@ def disjunctions_from_json(json_data):
|
|||||||
|
|
||||||
|
|
||||||
def convert_service_sheet(
|
def convert_service_sheet(
|
||||||
input_filename,
|
input_filename: Path,
|
||||||
eqpt,
|
eqpt: dict,
|
||||||
network,
|
network: DiGraph,
|
||||||
network_filename=None,
|
network_filename: Union[Path, None] = None,
|
||||||
output_filename='',
|
output_filename: str = '',
|
||||||
bidir=False):
|
bidir: bool = False):
|
||||||
|
"""Converts xls into json format services
|
||||||
|
|
||||||
|
:param input_filename: xls(x) file containing the service sheet
|
||||||
|
:param eqpt: equipment library
|
||||||
|
:param network: network for which these services apply (required for xls inputs to correct names)
|
||||||
|
:param network_filename: optional network file name that was used for network creation
|
||||||
|
(required for xls inputs to correct names)
|
||||||
|
:param output_filename: name of the file where converted data are savec
|
||||||
|
:param bidir: set all services bidir attribute with this bool
|
||||||
|
"""
|
||||||
if output_filename == '':
|
if output_filename == '':
|
||||||
output_filename = f'{str(input_filename)[0:len(str(input_filename))-len(str(input_filename.suffixes[0]))]}_services.json'
|
output_filename = f'{str(input_filename)[0:len(str(input_filename)) - len(str(input_filename.suffixes[0]))]}_services.json'
|
||||||
data = read_service_sheet(input_filename, eqpt, network, network_filename, bidir)
|
data = read_service_sheet(input_filename, eqpt, network, network_filename, bidir)
|
||||||
save_json(data, output_filename)
|
save_json(data, output_filename)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def find_equalisation(params, equalization_types):
|
def find_equalisation(params: Dict, equalization_types: List[str]):
|
||||||
"""Find the equalization(s) defined in params. params can be a dict or a Roadm object.
|
"""Find the equalization(s) defined in params. params can be a dict or a Roadm object.
|
||||||
|
|
||||||
>>> roadm = {'add_drop_osnr': 100, 'pmd': 1, 'pdl': 0.5,
|
>>> roadm = {'add_drop_osnr': 100, 'pmd': 1, 'pdl': 0.5,
|
||||||
@@ -823,7 +875,7 @@ def find_equalisation(params, equalization_types):
|
|||||||
return equalization
|
return equalization
|
||||||
|
|
||||||
|
|
||||||
def merge_equalization(params, extra_params):
|
def merge_equalization(params: dict, extra_params: dict) -> Union[dict, None]:
|
||||||
"""params contains ROADM element config and extra_params default values from equipment library.
|
"""params contains ROADM element config and extra_params default values from equipment library.
|
||||||
If equalization is not defined in ROADM element use the one defined in equipment library.
|
If equalization is not defined in ROADM element use the one defined in equipment library.
|
||||||
Only one type of equalization must be defined: power (target_pch_out_db) or PSD (target_psd_out_mWperGHz)
|
Only one type of equalization must be defined: power (target_pch_out_db) or PSD (target_psd_out_mWperGHz)
|
||||||
|
|||||||
Reference in New Issue
Block a user