mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-30 01:32:21 +00:00
Only propagates carriers that belong to Amp bandwidth
The commit introduces mux/demux functions in amps and ensures that the propagation is only done on carriers that are in the Amp bandwitdh, ie with all their spectrum including slot width is in bandwidth. For consistency, default amp f_min is changed: Objective is to use amplifiers' band to bound the possible frequencies to be propagated. Since the current default f_min of Amp in json_io.py is higher than the SI one, this would result in a different nb of channels than currently used in tests, and a change in all tests. In order to avoid this, I preferred to change this value and have consistency between SI f_min and Amp f_min. The commits adds a set of functions to make amps band the useable spectrum on each OMS. Thee OMS generation is changed to use the amp band. The commit adds filtering functions (demux and mux) to filter out spectrum which is not in the amplifier band. Spectrum assignment is also corrected to correctly match the amp bandwidth constraint with guardband: center frequency index must be within the usable part of the amp band. This changes a bit the notion of freq_index and guardband in the functions, but this is transparent to user: f_min, f_max represent the amp band, while self.freq_index_min/max represent the center frequency boundary for a reference 50GHz channel. Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: I225b2b2dc0e1f1992c0460f6e08fa9c9bc641edf
This commit is contained in:
committed by
Esther Le Rouzic
parent
5277ae2005
commit
ac8fd770ab
@@ -34,7 +34,7 @@ from gnpy.core.utils import lin2db, db2lin, arrange_frequencies, snr_sum, per_la
|
||||
from gnpy.core.parameters import RoadmParams, FusedParams, FiberParams, PumpParams, EdfaParams, EdfaOperational, \
|
||||
RoadmPath, RoadmImpairment
|
||||
from gnpy.core.science_utils import NliSolver, RamanSolver
|
||||
from gnpy.core.info import SpectralInformation
|
||||
from gnpy.core.info import SpectralInformation, demuxed_spectral_information
|
||||
from gnpy.core.exceptions import NetworkTopologyError, SpectrumError, ParametersError
|
||||
|
||||
|
||||
@@ -1204,5 +1204,10 @@ class Edfa(_Node):
|
||||
self.propagated_labels = spectral_info.label
|
||||
|
||||
def __call__(self, spectral_info):
|
||||
self.propagate(spectral_info)
|
||||
return spectral_info
|
||||
# filter out carriers outside the amplifier band
|
||||
band = next(b for b in self.params.bands)
|
||||
spectral_info = demuxed_spectral_information(spectral_info, band)
|
||||
if spectral_info.carriers:
|
||||
self.propagate(spectral_info)
|
||||
return spectral_info
|
||||
raise ValueError(f'Amp {self.uid} Defined propagation band does not match amplifiers band.')
|
||||
|
||||
@@ -11,7 +11,7 @@ This module contains classes for modelling :class:`SpectralInformation`.
|
||||
from __future__ import annotations
|
||||
from collections import namedtuple
|
||||
from collections.abc import Iterable
|
||||
from typing import Union
|
||||
from typing import Union, List
|
||||
from dataclasses import dataclass
|
||||
from numpy import argsort, mean, array, append, ones, ceil, any, zeros, outer, full, ndarray, asarray
|
||||
|
||||
@@ -317,6 +317,56 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, spacing
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
|
||||
|
||||
def is_in_band(frequency: float, band: dict) -> bool:
|
||||
"""band has {"f_min": value, "f_max": value} format
|
||||
"""
|
||||
if frequency >= band['f_min'] and frequency <= band['f_max']:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def demuxed_spectral_information(input_si: SpectralInformation, band: dict) -> SpectralInformation:
|
||||
"""extract a si based on band
|
||||
"""
|
||||
filtered_indices = [i for i, f in enumerate(input_si.frequency)
|
||||
if is_in_band(f - input_si.slot_width[i] / 2, band)
|
||||
and is_in_band(f + input_si.slot_width[i] / 2, band)]
|
||||
if filtered_indices:
|
||||
frequency = input_si.frequency[filtered_indices]
|
||||
baud_rate = input_si.baud_rate[filtered_indices]
|
||||
slot_width = input_si.slot_width[filtered_indices]
|
||||
signal = input_si.signal[filtered_indices]
|
||||
nli = input_si.nli[filtered_indices]
|
||||
ase = input_si.ase[filtered_indices]
|
||||
roll_off = input_si.roll_off[filtered_indices]
|
||||
chromatic_dispersion = input_si.chromatic_dispersion[filtered_indices]
|
||||
pmd = input_si.pmd[filtered_indices]
|
||||
pdl = input_si.pdl[filtered_indices]
|
||||
latency = input_si.latency[filtered_indices]
|
||||
delta_pdb_per_channel = input_si.delta_pdb_per_channel[filtered_indices]
|
||||
tx_osnr = input_si.tx_osnr[filtered_indices]
|
||||
tx_power = input_si.tx_power[filtered_indices]
|
||||
label = input_si.label[filtered_indices]
|
||||
|
||||
return SpectralInformation(frequency=frequency, baud_rate=baud_rate, slot_width=slot_width, signal=signal,
|
||||
nli=nli, ase=ase, roll_off=roll_off, chromatic_dispersion=chromatic_dispersion,
|
||||
pmd=pmd, pdl=pdl, latency=latency, delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
return None
|
||||
|
||||
|
||||
def muxed_spectral_information(input_si_list: List[SpectralInformation]) -> SpectralInformation:
|
||||
"""return the assembled spectrum
|
||||
"""
|
||||
if input_si_list and len(input_si_list) > 1:
|
||||
si = input_si_list[0] + muxed_spectral_information(input_si_list[1:])
|
||||
return si
|
||||
elif input_si_list and len(input_si_list) == 1:
|
||||
return input_si_list[0]
|
||||
else:
|
||||
raise ValueError('liste vide')
|
||||
|
||||
|
||||
def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier],
|
||||
power: float) -> SpectralInformation:
|
||||
"""Initial spectrum is a dict with key = carrier frequency, and value a Carrier object.
|
||||
|
||||
@@ -463,10 +463,10 @@ class FiberParams(Parameters):
|
||||
|
||||
class EdfaParams:
|
||||
default_values = {
|
||||
'f_min': 191.3e12,
|
||||
'f_max': 196.1e12,
|
||||
'f_min': None,
|
||||
'f_max': None,
|
||||
'multi_band': None,
|
||||
'bands': [],
|
||||
'bands': None,
|
||||
'type_variety': '',
|
||||
'type_def': '',
|
||||
'gain_flatmax': None,
|
||||
@@ -502,9 +502,11 @@ class EdfaParams:
|
||||
# Bandwidth
|
||||
self.f_min = params['f_min']
|
||||
self.f_max = params['f_max']
|
||||
self.bandwidth = self.f_max - self.f_min
|
||||
self.f_cent = (self.f_max + self.f_min) / 2
|
||||
self.bandwidth = self.f_max - self.f_min if self.f_max and self.f_min else None
|
||||
self.f_cent = (self.f_max + self.f_min) / 2 if self.f_max and self.f_min else None
|
||||
self.f_ripple_ref = params['f_ripple_ref']
|
||||
self.bands = [{'f_min': params['f_min'],
|
||||
'f_max': params['f_max']}]
|
||||
|
||||
# Gain
|
||||
self.gain_flatmax = params['gain_flatmax']
|
||||
|
||||
@@ -12,6 +12,7 @@ from csv import writer
|
||||
from numpy import pi, cos, sqrt, log10, linspace, zeros, shape, where, logical_and, mean, array
|
||||
from scipy import constants
|
||||
from copy import deepcopy
|
||||
from typing import List
|
||||
|
||||
from gnpy.core.exceptions import ConfigurationError
|
||||
|
||||
@@ -458,3 +459,49 @@ def calculate_absolute_min_or_zero(x: array) -> array:
|
||||
array([1., 0., 3.])
|
||||
"""
|
||||
return (abs(x) - x) / 2
|
||||
|
||||
|
||||
def find_common_range(amp_bands: List[List[dict]], default_band_f_min: float, default_band_f_max: float) \
|
||||
-> List[dict]:
|
||||
"""Find the common frequency range of bands
|
||||
If there are no amplifiers in the path, then use default band
|
||||
|
||||
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12}, {'f_min': 186e12, 'f_max' : 190e12} ], \
|
||||
[{'f_min': 185e12, 'f_max' : 189e12}, {'f_min': 192e12, 'f_max' : 196e12}], \
|
||||
[{'f_min': 186e12, 'f_max': 193e12}]]
|
||||
>>> find_common_range(amp_bands, 190e12, 195e12)
|
||||
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0}, {'f_min': 192000000000000.0, 'f_max': 193000000000000.0}]
|
||||
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12}, {'f_min': 186e12, 'f_max' : 190e12} ], \
|
||||
[{'f_min': 185e12, 'f_max' : 189e12}, {'f_min': 192e12, 'f_max' : 196e12}], \
|
||||
[{'f_min': 186e12, 'f_max': 192e12}]]
|
||||
>>> find_common_range(amp_bands, 190e12, 195e12)
|
||||
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0}]
|
||||
|
||||
"""
|
||||
_amp_bands = [sorted(amp, key=lambda x: x['f_min']) for amp in amp_bands]
|
||||
_temp = []
|
||||
# remove None bands
|
||||
for amp in _amp_bands:
|
||||
is_band = True
|
||||
for band in amp:
|
||||
if not (is_band and band['f_min'] and band['f_max']):
|
||||
is_band = False
|
||||
if is_band:
|
||||
_temp.append(amp)
|
||||
|
||||
# remove duplicate
|
||||
unique_amp_bands = []
|
||||
for amp in _temp:
|
||||
if amp not in unique_amp_bands:
|
||||
unique_amp_bands.append(amp)
|
||||
if unique_amp_bands:
|
||||
common_range = unique_amp_bands[0]
|
||||
else:
|
||||
if default_band_f_min is None or default_band_f_max is None:
|
||||
return []
|
||||
common_range = [{'f_min': default_band_f_min, 'f_max': default_band_f_max}]
|
||||
for bands in unique_amp_bands:
|
||||
common_range = [{'f_min': max(first['f_min'], second['f_min']), 'f_max': min(first['f_max'], second['f_max'])}
|
||||
for first in common_range for second in bands
|
||||
if max(first['f_min'], second['f_min']) < min(first['f_max'], second['f_max'])]
|
||||
return sorted(common_range, key=lambda x: x['f_min'])
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"gain_ripple": [
|
||||
0.0
|
||||
],
|
||||
"f_min": 191.35e12,
|
||||
"f_max": 196.1e12,
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"dgt": [
|
||||
1.0,
|
||||
1.017807767853702,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
0.0359549,
|
||||
5.82851
|
||||
],
|
||||
"f_min": 191.35e12,
|
||||
"f_max": 196.1e12,
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"nf_ripple": [
|
||||
0.4372876328262819,
|
||||
0.4372876328262819,
|
||||
|
||||
@@ -192,7 +192,7 @@ class Amp(_JsonThing):
|
||||
@classmethod
|
||||
def from_json(cls, filename, **kwargs):
|
||||
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
|
||||
type_variety = kwargs['type_variety']
|
||||
type_def = kwargs.get('type_def', 'variable_gain') # default compatibility with older json eqpt files
|
||||
nf_def = None
|
||||
@@ -367,6 +367,31 @@ def _update_dual_stage(equipment):
|
||||
return equipment
|
||||
|
||||
|
||||
def _update_band(equipment: dict) -> dict:
|
||||
"""Creates a list of bands for this amplifier, and remove other parameters which are not applicable
|
||||
"""
|
||||
amp_dict = equipment['Edfa']
|
||||
for amplifier in amp_dict.values():
|
||||
if amplifier.type_def != 'multi_band':
|
||||
amplifier.bands = [{'f_min': amplifier.f_min,
|
||||
'f_max': amplifier.f_max}]
|
||||
# updates band parameter
|
||||
else:
|
||||
_bands = [{'f_min': amp_dict[a].f_min,
|
||||
'f_max': amp_dict[a].f_max} for a in amp_dict[amplifier.type_variety].multi_band]
|
||||
# remove duplicates
|
||||
amplifier.bands = []
|
||||
for b in _bands:
|
||||
if b not in amplifier.bands:
|
||||
amplifier.bands.append(b)
|
||||
# remove non applicable parameters
|
||||
for key in ['f_min', 'f_max', 'gain_flatmax', 'gain_min', 'p_max', 'nf_model', 'dual_stage_model',
|
||||
'nf_fit_coeff', 'nf_ripple', 'dgt', 'gain_ripple']:
|
||||
delattr(amplifier, key)
|
||||
|
||||
return equipment
|
||||
|
||||
|
||||
def _roadm_restrictions_sanity_check(equipment):
|
||||
"""verifies that booster and preamp restrictions specified in roadm equipment are listed in the edfa."""
|
||||
for roadm_type, roadm_eqpt in equipment['Roadm'].items():
|
||||
@@ -428,6 +453,7 @@ def _equipment_from_json(json_data, filename):
|
||||
raise EquipmentConfigError(f'Unrecognized network element type "{key}"')
|
||||
_check_fiber_vs_raman_fiber(equipment)
|
||||
equipment = _update_dual_stage(equipment)
|
||||
equipment = _update_band(equipment)
|
||||
_roadm_restrictions_sanity_check(equipment)
|
||||
return equipment
|
||||
|
||||
|
||||
@@ -16,14 +16,17 @@ See: draft-ietf-teas-yang-path-computation-01.txt
|
||||
"""
|
||||
|
||||
from collections import namedtuple, OrderedDict
|
||||
from typing import List
|
||||
from logging import getLogger
|
||||
from networkx import (dijkstra_path, NetworkXNoPath,
|
||||
all_simple_paths, shortest_simple_paths)
|
||||
from networkx.utils import pairwise
|
||||
from numpy import mean, argmin
|
||||
from gnpy.core.elements import Transceiver, Roadm
|
||||
from gnpy.core.utils import lin2db
|
||||
from gnpy.core.info import create_input_spectral_information, carriers_to_spectral_information
|
||||
|
||||
from gnpy.core.elements import Transceiver, Roadm, Edfa
|
||||
from gnpy.core.utils import lin2db, find_common_range
|
||||
from gnpy.core.info import create_input_spectral_information, carriers_to_spectral_information, \
|
||||
demuxed_spectral_information, muxed_spectral_information, SpectralInformation
|
||||
from gnpy.core import network as network_module
|
||||
from gnpy.core.exceptions import ServiceError, DisjunctionError
|
||||
from copy import deepcopy
|
||||
@@ -332,14 +335,34 @@ def compute_constrained_path(network, req):
|
||||
return total_path
|
||||
|
||||
|
||||
def filter_si(path: list, equipment: dict, si: SpectralInformation) -> SpectralInformation:
|
||||
"""Filter spectral information based on the amplifiers common range"""
|
||||
# First retrieve f_min, f_max spectrum according to amplifiers' spectrum on the path
|
||||
common_range = find_elements_common_range(path, equipment)
|
||||
# filter out frequencies that should not be created
|
||||
filtered_si = []
|
||||
for band in common_range:
|
||||
temp = demuxed_spectral_information(si, band)
|
||||
if temp:
|
||||
filtered_si.append(temp)
|
||||
if not filtered_si:
|
||||
raise ValueError('Defined propagation band does not match amplifiers band.')
|
||||
return muxed_spectral_information(filtered_si)
|
||||
|
||||
|
||||
def propagate(path, req, equipment):
|
||||
"""propagates signals in each element according to initial spectrum set by user"""
|
||||
"""propagates signals in each element according to initial spectrum set by user
|
||||
Spectrum is specified in request through f_min, f_max and spacing, or initial_spectrum
|
||||
and amps frequency band on the path is used to filter out frequencies"""
|
||||
# generates spectrum based on request
|
||||
if req.initial_spectrum is not None:
|
||||
si = carriers_to_spectral_information(initial_spectrum=req.initial_spectrum, power=req.power)
|
||||
else:
|
||||
si = create_input_spectral_information(
|
||||
f_min=req.f_min, f_max=req.f_max, roll_off=req.roll_off, baud_rate=req.baud_rate,
|
||||
spacing=req.spacing, tx_osnr=req.tx_osnr, tx_power=req.tx_power, delta_pdb=req.offset_db)
|
||||
# filter out frequencies that should not be created
|
||||
si = filter_si(path, equipment, si)
|
||||
roadm_osnr = []
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
@@ -385,6 +408,7 @@ def propagate_and_optimize_mode(path, req, equipment):
|
||||
baud_rate=this_br, spacing=req.spacing,
|
||||
delta_pdb=this_offset, tx_osnr=req.tx_osnr,
|
||||
tx_power=req.tx_power)
|
||||
spc_info = filter_si(path, equipment, spc_info)
|
||||
roadm_osnr = []
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
@@ -1225,3 +1249,11 @@ def _penalty_msg(total_path, msg, min_ind):
|
||||
else:
|
||||
msg += f'\n\t{pretty} penalty not evaluated'
|
||||
return msg
|
||||
|
||||
|
||||
def find_elements_common_range(el_list: list, equipment: dict) -> List[dict]:
|
||||
"""Find the common frequency range of amps of a given list of elements (for example an OMS or a path)
|
||||
If there are no amplifiers in the path, then use the SI
|
||||
"""
|
||||
amp_bands = [n.params.bands for n in el_list if isinstance(n, (Edfa))]
|
||||
return find_common_range(amp_bands, equipment['SI']['default'].f_min, equipment['SI']['default'].f_max)
|
||||
|
||||
@@ -15,28 +15,30 @@ element/oms correspondace
|
||||
|
||||
from collections import namedtuple
|
||||
from logging import getLogger
|
||||
from gnpy.core.elements import Roadm, Transceiver
|
||||
from gnpy.core.elements import Roadm, Transceiver, Edfa
|
||||
from gnpy.core.exceptions import ServiceError, SpectrumError
|
||||
from gnpy.core.utils import order_slots, restore_order
|
||||
from gnpy.topology.request import compute_spectrum_slot_vs_bandwidth
|
||||
from gnpy.topology.request import compute_spectrum_slot_vs_bandwidth, find_elements_common_range
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
GUARDBAND = 25e9
|
||||
|
||||
|
||||
class Bitmap:
|
||||
"""records the spectrum occupation"""
|
||||
|
||||
def __init__(self, f_min, f_max, grid, guardband=0.15e12, bitmap=None):
|
||||
# n is the min index including guardband. Guardband is require to be sure
|
||||
def __init__(self, f_min, f_max, grid, guardband=GUARDBAND, bitmap=None):
|
||||
# n is the min index including guardband. Guardband is required to be sure
|
||||
# that a channel can be assigned with center frequency fmin (means that its
|
||||
# slot occupation goes below freq_index_min
|
||||
n_min = frequency_to_n(f_min - guardband, grid)
|
||||
n_max = frequency_to_n(f_max + guardband, grid) - 1
|
||||
n_min = frequency_to_n(f_min, grid)
|
||||
n_max = frequency_to_n(f_max, grid)
|
||||
self.n_min = n_min
|
||||
self.n_max = n_max
|
||||
self.freq_index_min = frequency_to_n(f_min)
|
||||
self.freq_index_max = frequency_to_n(f_max)
|
||||
self.freq_index_min = frequency_to_n(f_min + guardband)
|
||||
self.freq_index_max = frequency_to_n(f_max - guardband)
|
||||
self.freq_index = list(range(n_min, n_max + 1))
|
||||
self.guardband = guardband
|
||||
if bitmap is None:
|
||||
self.bitmap = [1] * (n_max - n_min + 1)
|
||||
elif len(bitmap) == len(self.freq_index):
|
||||
@@ -83,7 +85,6 @@ class OMS:
|
||||
self.spectrum_bitmap = []
|
||||
self.nb_channels = 0
|
||||
self.service_list = []
|
||||
# TODO
|
||||
|
||||
def __str__(self):
|
||||
return '\n\t'.join([f'{type(self).__name__} {self.oms_id}',
|
||||
@@ -98,7 +99,7 @@ class OMS:
|
||||
self.el_id_list.append(elem.uid)
|
||||
self.el_list.append(elem)
|
||||
|
||||
def update_spectrum(self, f_min, f_max, guardband=0.15e12, existing_spectrum=None, grid=0.00625e12):
|
||||
def update_spectrum(self, f_min, f_max, guardband=GUARDBAND, existing_spectrum=None, grid=0.00625e12):
|
||||
"""Frequencies expressed in Hz.
|
||||
Add 150 GHz margin to enable a center channel on f_min
|
||||
Use ITU-T G694.1 Flexible DWDM grid definition
|
||||
@@ -226,6 +227,40 @@ def align_grids(oms_list):
|
||||
return oms_list
|
||||
|
||||
|
||||
def find_network_freq_range(network, equipment):
|
||||
"""Find the lowest freq from amps and highest freq among all amps to determine the resulting bitmap
|
||||
"""
|
||||
amp_bands = [band for n in network.nodes() if isinstance(n, Edfa) for band in n.params.bands]
|
||||
min_frequencies = [a['f_min'] for a in amp_bands]
|
||||
max_frequencies = [a['f_max'] for a in amp_bands]
|
||||
return min(min_frequencies), max(max_frequencies)
|
||||
|
||||
|
||||
def create_oms_bitmap(oms, equipment, f_min, f_max, guardband, grid):
|
||||
"""Find the highest low freq from oms amps and lowest high freq among oms amps to determine
|
||||
the possible bitmap window.
|
||||
f_min and f_max represent the useable spectrum (not the useable center frequencies)
|
||||
ie n smaller than frequency_to_n(min_freq, grid) are not useable
|
||||
"""
|
||||
n_min = frequency_to_n(f_min, grid)
|
||||
n_max = frequency_to_n(f_max, grid) - 1
|
||||
common_range = find_elements_common_range(oms.el_list, equipment)
|
||||
band0 = common_range[0]
|
||||
band0_n_min = frequency_to_n(band0['f_min'], grid)
|
||||
band0_n_max = frequency_to_n(band0['f_max'], grid)
|
||||
bitmap = [0] * (band0_n_min - n_min) + [1] * (band0_n_max - band0_n_min + 1)
|
||||
i = 1
|
||||
while i < len(common_range):
|
||||
band = common_range[i]
|
||||
band_n_min = frequency_to_n(band['f_min'], grid)
|
||||
band_n_max = frequency_to_n(band['f_max'], grid)
|
||||
bitmap = bitmap + [0] * (band_n_min - band0_n_max - 1) + [1] * (band_n_max - band_n_min + 1)
|
||||
band0_n_max = band_n_max
|
||||
i += 1
|
||||
bitmap = bitmap + [0] * (n_max - band0_n_max)
|
||||
return bitmap
|
||||
|
||||
|
||||
def build_oms_list(network, equipment):
|
||||
"""initialization of OMS list in the network
|
||||
|
||||
@@ -237,7 +272,15 @@ def build_oms_list(network, equipment):
|
||||
"""
|
||||
oms_id = 0
|
||||
oms_list = []
|
||||
for node in [n for n in network.nodes() if isinstance(n, Roadm)]:
|
||||
# identify all vertices of OMS: of course ROADM, but aso links to external chassis transponders
|
||||
oms_vertices = [n for n in network.nodes() if isinstance(n, Roadm)] +\
|
||||
[n for n in network.nodes() if isinstance(n, Transceiver)
|
||||
and not isinstance(next(network.successors(n)), Roadm)]
|
||||
# determine the size of the bitmap common to all the omses: find min and max frequencies of all amps
|
||||
# in the network. These gives the band not the center frequency. Thhen we use a reference channel
|
||||
# slot width (50GHz) to set the f_min, f_max
|
||||
f_min, f_max = find_network_freq_range(network, equipment)
|
||||
for node in oms_vertices:
|
||||
for edge in network.edges([node]):
|
||||
if not isinstance(edge[1], Transceiver):
|
||||
nd_in = edge[0] # nd_in is a Roadm
|
||||
@@ -271,8 +314,9 @@ def build_oms_list(network, equipment):
|
||||
nd_out.oms_list = []
|
||||
nd_out.oms_list.append(oms_id)
|
||||
|
||||
oms.update_spectrum(equipment['SI']['default'].f_min,
|
||||
equipment['SI']['default'].f_max, grid=0.00625e12)
|
||||
bitmap = create_oms_bitmap(oms, equipment, f_min=f_min, f_max=f_max, guardband=GUARDBAND,
|
||||
grid=0.00625e12)
|
||||
oms.update_spectrum(f_min, f_max, guardband=GUARDBAND, grid=0.00625e12, existing_spectrum=bitmap)
|
||||
# oms.assign_spectrum(13,7) gives back (193137500000000.0, 193225000000000.0)
|
||||
# as in the example in the standard
|
||||
# oms.assign_spectrum(13,7)
|
||||
@@ -333,10 +377,11 @@ def aggregate_oms_bitmap(path_oms, oms_list):
|
||||
'el_id_list': 0,
|
||||
'el_list': []
|
||||
}
|
||||
freq_min = nvalue_to_frequency(spectrum.freq_index_min)
|
||||
freq_max = nvalue_to_frequency(spectrum.freq_index_max)
|
||||
freq_min = nvalue_to_frequency(spectrum.n_min)
|
||||
freq_max = nvalue_to_frequency(spectrum.n_max)
|
||||
aggregate_oms = OMS(**params)
|
||||
aggregate_oms.update_spectrum(freq_min, freq_max, grid=0.00625e12, existing_spectrum=bitmap)
|
||||
aggregate_oms.update_spectrum(freq_min, freq_max, grid=0.00625e12, guardband=spectrum.guardband,
|
||||
existing_spectrum=bitmap)
|
||||
return aggregate_oms
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"f_min": 191.35e12,
|
||||
"f_max": 196.1e12,
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"nf_ripple": [
|
||||
0.0,
|
||||
0.0,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{ "nf_fit_coeff": [
|
||||
{
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"nf_fit_coeff": [
|
||||
0.000168241,
|
||||
0.0469961,
|
||||
0.0359549,
|
||||
|
||||
@@ -251,35 +251,35 @@ def test_amp_behaviour(tilt_target, delta_p):
|
||||
else:
|
||||
if delta_p != 2:
|
||||
expected_sig_out = [
|
||||
-32.00529182, -31.93540907, -31.86554231, -31.79417979, -31.71903263,
|
||||
-31.6424009, -31.56531159, -31.48775435, -31.41468382, -31.35973323,
|
||||
-31.32286555, -31.28602346, -31.2472908, -31.20086569, -31.14671746,
|
||||
-31.08702653, -31.01341963, -30.93430243, -30.87791656, -30.84413339,
|
||||
-30.81605918, -30.78824936, -30.76071036, -30.73319161, -30.70494101,
|
||||
-30.67368479, -30.63941012, -30.60178381, -30.55585766, -30.5066561,
|
||||
-30.43426575, -30.33848379, -30.24471112, -30.18220815, -30.15076699,
|
||||
-30.11934744, -30.08776718, -30.05548097, -30.02250068, -29.98954302,
|
||||
-29.95661362, -29.92370274, -29.8854762, -29.84193785, -29.79238328,
|
||||
-29.72452662, -29.6385071, -29.54788144, -29.44581202, -29.33924103,
|
||||
-29.23276107, -29.10289365, -28.91425473, -28.70204648, -28.50670713,
|
||||
-28.3282514, -28.15895225, -28.009065, -27.87864672, -27.76315964,
|
||||
-27.68523133, -27.62260405, -27.58076622]
|
||||
-31.95025022, -31.88168886, -31.81178634, -31.73838831, -31.66318631,
|
||||
-31.58762141, -31.51156294, -31.43760161, -31.38124626, -31.34245197,
|
||||
-31.30629475, -31.26970711, -31.22566555, -31.17412914, -31.11806869,
|
||||
-31.05122228, -30.97358131, -30.90658619, -30.86616148, -30.83854197,
|
||||
-30.81115028, -30.78403337, -30.7570206, -30.73002834, -30.70088634,
|
||||
-30.66844432, -30.63427939, -30.59364514, -30.54659009, -30.49180643,
|
||||
-30.41406352, -30.31434813, -30.22984104, -30.18249387, -30.1516453,
|
||||
-30.12082034, -30.08970494, -30.05779424, -30.02543415, -29.99309889,
|
||||
-29.96078803, -29.92798594, -29.89002127, -29.84689015, -29.79726968,
|
||||
-29.72927112, -29.64485972, -29.55578693, -29.45569694, -29.35111795,
|
||||
-29.24662471, -29.12148491, -28.94244964, -28.73421833, -28.53930479,
|
||||
-28.36231261, -28.19361236, -28.04376778, -27.91280403, -27.79433658,
|
||||
-27.7065072, -27.64495288, -27.59798975]
|
||||
|
||||
else:
|
||||
expected_sig_out = [
|
||||
-30.00529182, -29.93540907, -29.86554231, -29.79417979, -29.71903263,
|
||||
-29.6424009, -29.56531159, -29.48775435, -29.41468382, -29.35973323,
|
||||
-29.32286555, -29.28602346, -29.2472908, -29.20086569, -29.14671746,
|
||||
-29.08702653, -29.01341963, -28.93430243, -28.87791656, -28.84413339,
|
||||
-28.81605918, -28.78824936, -28.76071036, -28.73319161, -28.70494101,
|
||||
-28.67368479, -28.63941012, -28.60178381, -28.55585766, -28.5066561,
|
||||
-28.43426575, -28.33848379, -28.24471112, -28.18220815, -28.15076699,
|
||||
-28.11934744, -28.08776718, -28.05548097, -28.02250068, -27.98954302,
|
||||
-27.95661362, -27.92370274, -27.8854762, -27.84193785, -27.79238328,
|
||||
-27.72452662, -27.6385071, -27.54788144, -27.44581202, -27.33924103,
|
||||
-27.23276107, -27.10289365, -26.91425473, -26.70204648, -26.50670713,
|
||||
-26.3282514, -26.15895225, -26.009065, -25.87864672, -25.76315964,
|
||||
-25.68523133, -25.62260405, -25.58076622]
|
||||
-29.95025022, -29.88168886, -29.81178634, -29.73838831, -29.66318631,
|
||||
-29.58762141, -29.51156294, -29.43760161, -29.38124626, -29.34245197,
|
||||
-29.30629475, -29.26970711, -29.22566555, -29.17412914, -29.11806869,
|
||||
-29.05122228, -28.97358131, -28.90658619, -28.86616148, -28.83854197,
|
||||
-28.81115028, -28.78403337, -28.7570206, -28.73002834, -28.70088634,
|
||||
-28.66844432, -28.63427939, -28.59364514, -28.54659009, -28.49180643,
|
||||
-28.41406352, -28.31434813, -28.22984104, -28.18249387, -28.1516453,
|
||||
-28.12082034, -28.08970494, -28.05779424, -28.02543415, -27.99309889,
|
||||
-27.96078803, -27.92798594, -27.89002127, -27.84689015, -27.79726968,
|
||||
-27.72927112, -27.64485972, -27.55578693, -27.45569694, -27.35111795,
|
||||
-27.24662471, -27.12148491, -26.94244964, -26.73421833, -26.53930479,
|
||||
-26.36231261, -26.19361236, -26.04376778, -25.91280403, -25.79433658,
|
||||
-25.7065072, -25.64495288, -25.59798975]
|
||||
|
||||
print(sig_out)
|
||||
assert_allclose(sig_out, expected_sig_out, rtol=1e-9)
|
||||
|
||||
@@ -33,7 +33,7 @@ SERVICE_FILENAME = DATA_DIR / 'testTopology_services_expected.json'
|
||||
|
||||
grid = 0.00625e12
|
||||
slot = 0.0125e12
|
||||
guardband = 0.15e12
|
||||
guardband = 25.0e9
|
||||
cband_freq_min = 191.3e12
|
||||
cband_freq_max = 196.1e12
|
||||
|
||||
@@ -101,14 +101,15 @@ def test_wrong_values(nval, mval, setup):
|
||||
def test_aligned(nmin, nmax, setup):
|
||||
"""Checks that the OMS grid is correctly aligned
|
||||
|
||||
Note that bitmap index uses guardband on both ends so that if nmin, nmax = -200, +200,
|
||||
Note that bitmap index uses guardband on both ends so that if center frequencies nmin, nmax = -200, +200,
|
||||
min/max navalue in bitmap are -224, +223, which makes 223 -(-224) +1 frequencies.
|
||||
"""
|
||||
network, oms_list = setup
|
||||
nguard = guardband / grid
|
||||
center = 193.1e12
|
||||
freq_min = center + nmin * grid
|
||||
freq_max = center + nmax * grid
|
||||
# amplification band
|
||||
freq_min = center + nmin * grid - guardband
|
||||
freq_max = center + nmax * grid + guardband
|
||||
random_oms = oms_list[10]
|
||||
|
||||
# We're always starting with full C-band
|
||||
@@ -116,9 +117,9 @@ def test_aligned(nmin, nmax, setup):
|
||||
assert pytest.approx(nvalue_to_frequency(random_oms.spectrum_bitmap.freq_index_max) * 1e-12, abs=1e-12) == 196.1
|
||||
ind_max = len(random_oms.spectrum_bitmap.bitmap) - 1
|
||||
|
||||
# "inner" frequencies, without the guard baand
|
||||
# "inner" frequencies, without the guard band
|
||||
inner_n_min = random_oms.spectrum_bitmap.getn(0) + nguard
|
||||
inner_n_max = random_oms.spectrum_bitmap.getn(ind_max) - nguard + 1
|
||||
inner_n_max = random_oms.spectrum_bitmap.getn(ind_max) - nguard
|
||||
assert inner_n_min == random_oms.spectrum_bitmap.freq_index_min
|
||||
assert inner_n_max == random_oms.spectrum_bitmap.freq_index_max
|
||||
assert inner_n_min == -288
|
||||
@@ -136,7 +137,7 @@ def test_aligned(nmin, nmax, setup):
|
||||
|
||||
ind_max = len(random_oms.spectrum_bitmap.bitmap) - 1
|
||||
inner_n_min = random_oms.spectrum_bitmap.getn(0) + nguard
|
||||
inner_n_max = random_oms.spectrum_bitmap.getn(ind_max) - nguard + 1
|
||||
inner_n_max = random_oms.spectrum_bitmap.getn(ind_max) - nguard
|
||||
assert inner_n_min == random_oms.spectrum_bitmap.freq_index_min
|
||||
assert inner_n_max == random_oms.spectrum_bitmap.freq_index_max
|
||||
|
||||
@@ -198,18 +199,20 @@ def test_assign_and_sum(nval1, nval2, setup):
|
||||
|
||||
def test_bitmap_assignment(setup):
|
||||
"""test that a bitmap can be assigned"""
|
||||
network, oms_list = setup
|
||||
_, oms_list = setup
|
||||
random_oms = oms_list[2]
|
||||
random_oms.assign_spectrum(13, 7)
|
||||
|
||||
btmp = deepcopy(random_oms.spectrum_bitmap.bitmap)
|
||||
# try a first assignment that must pass
|
||||
spectrum_btmp = Bitmap(cband_freq_min, cband_freq_max, grid=0.00625e12, guardband=0.15e12, bitmap=btmp)
|
||||
freq_min = nvalue_to_frequency(random_oms.spectrum_bitmap.n_min)
|
||||
freq_max = nvalue_to_frequency(random_oms.spectrum_bitmap.n_max)
|
||||
_ = Bitmap(freq_min, freq_max, grid=0.00625e12, guardband=guardband, bitmap=btmp)
|
||||
|
||||
# try a wrong assignment that should not pass
|
||||
btmp = btmp[1:-1]
|
||||
with pytest.raises(SpectrumError):
|
||||
spectrum_btmp = Bitmap(cband_freq_min, cband_freq_max, grid=0.00625e12, guardband=0.15e12, bitmap=btmp)
|
||||
_ = Bitmap(cband_freq_min, cband_freq_max, grid=0.00625e12, guardband=guardband, bitmap=btmp)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
||||
Reference in New Issue
Block a user