Feat: Add spacing info in the design_band info

This will be used to compute the max total power for design per OMS.

Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com>
Change-Id: I392f06c792af9f32d4a14324c683bd3fae655de8
This commit is contained in:
EstherLerouzic
2025-02-17 18:01:24 +01:00
parent 4df6cc6b23
commit f447c908bc
5 changed files with 208 additions and 68 deletions

View File

@@ -26,7 +26,7 @@ from gnpy.core import elements
from gnpy.core.equipment import find_type_variety, find_type_varieties from gnpy.core.equipment import find_type_variety, find_type_varieties
from gnpy.core.exceptions import ConfigurationError, NetworkTopologyError from gnpy.core.exceptions import ConfigurationError, NetworkTopologyError
from gnpy.core.utils import round2float, convert_length, psd2powerdbm, lin2db, watt2dbm, dbm2watt, automatic_nch, \ from gnpy.core.utils import round2float, convert_length, psd2powerdbm, lin2db, watt2dbm, dbm2watt, automatic_nch, \
find_common_range find_common_range, get_spacing_from_band, reorder_per_degree_design_bands
from gnpy.core.info import ReferenceCarrier, create_input_spectral_information from gnpy.core.info import ReferenceCarrier, create_input_spectral_information
from gnpy.core.parameters import SimParams, EdfaParams, find_band_name, FrequencyBand, MultiBandParams from gnpy.core.parameters import SimParams, EdfaParams, find_band_name, FrequencyBand, MultiBandParams
from gnpy.core.science_utils import RamanSolver from gnpy.core.science_utils import RamanSolver
@@ -1330,8 +1330,11 @@ def set_per_degree_design_band(node: Union[elements.Roadm, elements.Transceiver]
""" """
next_oms = (n for n in network.successors(node)) next_oms = (n for n in network.successors(node))
if len(node.design_bands) == 0: if len(node.design_bands) == 0:
node.design_bands = [{'f_min': si.f_min, 'f_max': si.f_max} for si in equipment['SI'].values()] node.design_bands = [{'f_min': si.f_min, 'f_max': si.f_max, 'spacing': si.spacing}
for si in equipment['SI'].values()]
# complete node.per_degree_design_bands with node.design_bands spacing when it is missing.
# Use the spacing from SI if nothing is specified.
update_design_bands_spacing(node, equipment['SI']['default'].spacing)
default_is_single_band = len(node.design_bands) == 1 default_is_single_band = len(node.design_bands) == 1
for next_node in next_oms: for next_node in next_oms:
# get all the elements from the OMS and retrieve their amps types and bands # get all the elements from the OMS and retrieve their amps types and bands
@@ -1347,14 +1350,14 @@ def set_per_degree_design_band(node: Union[elements.Roadm, elements.Transceiver]
if oms_is_single_band == default_is_single_band: if oms_is_single_band == default_is_single_band:
amp_bands.append(node.design_bands) amp_bands.append(node.design_bands)
common_range = find_common_range(amp_bands, None, None) common_range = find_common_range(amp_bands, None, None, equipment['SI']['default'].spacing, node.design_bands)
# node.per_degree_design_bands has already been populated with node.params.per_degree_design_bands loaded # node.per_degree_design_bands has already been populated with node.params.per_degree_design_bands loaded
# from the json. # from the json.
# let's complete the dict with the design band of degrees for which there was no definition # let's complete the dict with the design band of degrees for which there was no definition
if next_node.uid not in node.per_degree_design_bands: if next_node.uid not in node.per_degree_design_bands:
if common_range: if common_range:
# if degree design band was not defined, then use the common_range computed with the oms amplifiers # if degree design band was not defined, then use the common_range computed with the oms amplifiers
# already defined # already defined.
node.per_degree_design_bands[next_node.uid] = common_range node.per_degree_design_bands[next_node.uid] = common_range
elif oms_is_single_band is None or (oms_is_single_band == default_is_single_band): elif oms_is_single_band is None or (oms_is_single_band == default_is_single_band):
# else if no amps are defined (no bands) then use default ROADM bands # else if no amps are defined (no bands) then use default ROADM bands
@@ -1364,14 +1367,42 @@ def set_per_degree_design_band(node: Union[elements.Roadm, elements.Transceiver]
# unsupported case: single band OMS with default multiband design band # unsupported case: single band OMS with default multiband design band
raise NetworkTopologyError(f"in {node.uid} degree {next_node.uid}: inconsistent design multiband/" raise NetworkTopologyError(f"in {node.uid} degree {next_node.uid}: inconsistent design multiband/"
+ " single band definition on a single band/ multiband OMS") + " single band definition on a single band/ multiband OMS")
if next_node.uid in node.params.per_degree_design_bands: # reorder per_degree_design_bands.
# order bands per min frequency in params.per_degree_design_bands for those degree that are defined there reorder_per_degree_design_bands(node.per_degree_design_bands)
node.params.per_degree_design_bands[next_node.uid] = \ reorder_per_degree_design_bands(node.params.per_degree_design_bands)
sorted(node.params.per_degree_design_bands[next_node.uid], key=lambda x: x['f_min'])
# order the bands per min frequency in .per_degree_design_bands (all degrees must exist there)
node.per_degree_design_bands[next_node.uid] = \
sorted(node.per_degree_design_bands[next_node.uid], key=lambda x: x['f_min'])
# check node.params.per_degree_design_bands keys # check node.params.per_degree_design_bands keys
check_per_degree_design_bands_keys(node, network)
def update_design_bands_spacing(node: Union[elements.Roadm, elements.Transceiver],
default_spacing: float):
"""
Update the spacing of design bands for a given node.
This function iterates through the design bands associated with the node and updates
their spacing based on the frequency range defined by 'f_min' and 'f_max'. If a specific
spacing cannot be determined from the design bands, the default spacing is used.
:param node: The node object which can be either a Roadm or Transceiver instance.
:type node: Union[elements.Roadm, elements.Transceiver]
:param default_spacing: The default spacing to use if no specific spacing can be determined.
:type default_spacing: float
"""
for design_bands in node.per_degree_design_bands.values():
for design_band in design_bands:
temp = get_spacing_from_band(node.design_bands, design_band['f_min'], design_band['f_max'])
default_spacing = temp if temp is not None else default_spacing
design_band['spacing'] = design_band.get('spacing', default_spacing)
def check_per_degree_design_bands_keys(node: Union[elements.Roadm, elements.Transceiver], network: DiGraph):
"""Checks that per_degree_design_bands keys are existing uid of elements in the network
:param node: a ROADM or a Transceiver element
:type node: Union[elements.Roadm, elements.Transceiver]
:param network: the network containing the node and its connections
:type network: DiGraph
"""
if node.params.per_degree_design_bands: if node.params.per_degree_design_bands:
next_oms_uid = [n.uid for n in network.successors(node)] next_oms_uid = [n.uid for n in network.successors(node)]
for degree in node.params.per_degree_design_bands.keys(): for degree in node.params.per_degree_design_bands.keys():

View File

@@ -17,7 +17,7 @@ from csv import writer
from numpy import pi, cos, sqrt, log10, linspace, zeros, shape, where, logical_and, mean, array from numpy import pi, cos, sqrt, log10, linspace, zeros, shape, where, logical_and, mean, array
from scipy import constants from scipy import constants
from copy import deepcopy from copy import deepcopy
from typing import List, Union from typing import List, Union, Dict
from gnpy.core.exceptions import ConfigurationError from gnpy.core.exceptions import ConfigurationError
@@ -628,49 +628,124 @@ def nice_column_str(data: List[List[str]], max_length: int = 30, padding: int =
return '\n'.join(nice_str) return '\n'.join(nice_str)
def find_common_range(amp_bands: List[List[dict]], default_band_f_min: float, default_band_f_max: float) \ def filter_valid_amp_bands(amp_bands: List[List[dict]]) -> List[List[dict]]:
-> List[dict]: """Filter out invalid amplifier bands that lack f_min or f_max.
"""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}]
:param amp_bands: A list of lists containing amplifier band dictionaries.
:type amp_bands: List[List[dict]]
:return: A filtered list of amplifier bands that contain valid f_min and f_max.
:rtype: List[List[dict]]
""" """
_amp_bands = [sorted(amp, key=lambda x: x['f_min']) for amp in amp_bands] return [amp for amp in amp_bands if all(band.get('f_min') is not None and band.get('f_max') is not None
_temp = [] for band in amp)]
# 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
def remove_duplicates(amp_bands: List[List[dict]]) -> List[List[dict]]:
"""Remove duplicate amplifier bands.
:param amp_bands: A list of lists containing amplifier band dictionaries.
:type amp_bands: List[List[dict]]
:return: A list of unique amplifier bands.
:rtype: List[List[dict]]
"""
unique_amp_bands = [] unique_amp_bands = []
for amp in _temp: for amp in amp_bands:
if amp not in unique_amp_bands: if amp not in unique_amp_bands:
unique_amp_bands.append(amp) unique_amp_bands.append(amp)
return unique_amp_bands
def calculate_spacing(first: dict, second: dict, default_spacing: float, default_design_bands: Union[List[Dict], None],
f_min: float, f_max: float) -> float:
"""Calculate the spacing for the given frequency range.
:param first: The first amplifier band dictionary.
:type first: dict
:param second: The second amplifier band dictionary.
:type second: dict
:param default_spacing: The default spacing to use if no specific spacing can be determined.
:type default_spacing: float
:param default_design_bands: Optional list of design bands to determine spacing from.
:type default_design_bands: Union[List[Dict], None]
:param f_min: The minimum frequency of the range.
:type f_min: float
:param f_max: The maximum frequency of the range.
:type f_max: float
:return: The calculated spacing for the given frequency range.
:rtype: float
"""
if first.get('spacing') is not None and second.get('spacing') is not None:
return max(first['spacing'], second['spacing'])
elif first.get('spacing') is not None:
return first['spacing']
elif second.get('spacing') is not None:
return second['spacing']
elif default_design_bands:
temp = get_spacing_from_band(default_design_bands, f_min, f_max)
return temp if temp is not None else default_spacing
return default_spacing
def find_common_range(amp_bands: List[List[dict]], default_band_f_min: Union[float, None],
default_band_f_max: Union[float, None], default_spacing: float,
default_design_bands: Union[List[Dict], None] = None) -> List[dict]:
"""
Find the common frequency range of amplifier bands.
If there are no amplifiers in the path, then use the default band parameters.
:param amp_bands: A list of lists containing amplifier band dictionaries, each with 'f_min', 'f_max',
and optionally 'spacing'.
:type amp_bands: List[List[dict]]
:param default_band_f_min: The minimum frequency of the default band.
:type default_band_f_min: Union[float, None]
:param default_band_f_max: The maximum frequency of the default band.
:type default_band_f_max: Union[float, None]
:param default_spacing: The default spacing to use if no specific spacing can be determined.
:type default_spacing: float
:param default_design_bands: Optional list of design bands to determine spacing from.
:type default_design_bands: Union[List[Dict], None]
:return: A list of dictionaries representing the common frequency ranges with their respective spacings.
:rtype: List[dict]
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12, 'spacing': 70e9}, {'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, 50e9)
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0, 'spacing': 50000000000.0}, \
{'f_min': 192000000000000.0, 'f_max': 193000000000000.0, 'spacing': 70000000000.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, 50e9)
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0, 'spacing': 50000000000.0}]
"""
# Step 1: Filter and sort amplifier bands
_amp_bands = [sorted(amp, key=lambda x: x['f_min']) for amp in filter_valid_amp_bands(amp_bands)]
unique_amp_bands = remove_duplicates(_amp_bands)
# Step 2: Handle cases with no valid bands
if unique_amp_bands: if unique_amp_bands:
common_range = unique_amp_bands[0] common_range = unique_amp_bands[0]
else: else:
if default_band_f_min is None or default_band_f_max is None: if default_band_f_min is None or default_band_f_max is None:
return [] return []
common_range = [{'f_min': default_band_f_min, 'f_max': default_band_f_max}] return [{'f_min': default_band_f_min, 'f_max': default_band_f_max, 'spacing': None}]
# Step 3: Calculate common frequency range
for bands in unique_amp_bands: 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'])} new_common_range = []
for first in common_range for second in bands for first in common_range:
if max(first['f_min'], second['f_min']) < min(first['f_max'], second['f_max'])] for second in bands:
f_min = max(first['f_min'], second['f_min'])
f_max = min(first['f_max'], second['f_max'])
if f_min < f_max:
spacing = calculate_spacing(first, second, default_spacing, default_design_bands, f_min, f_max)
new_common_range.append({'f_min': f_min, 'f_max': f_max, 'spacing': spacing})
common_range = new_common_range
return sorted(common_range, key=lambda x: x['f_min']) return sorted(common_range, key=lambda x: x['f_min'])
@@ -715,3 +790,36 @@ def convert_pmd_lineic(pmd: Union[float, None], length: float, length_unit: str)
if pmd: if pmd:
return pmd * 1e-12 / sqrt(convert_length(length, length_unit)) return pmd * 1e-12 / sqrt(convert_length(length, length_unit))
return None return None
def get_spacing_from_band(design_bands: List[Dict], f_min, f_max):
"""Retrieve the spacing for a frequency range based on design bands.
This function checks if the midpoint of the provided frequency range (f_min, f_max)
falls within any of the design bands. If it does, the corresponding spacing is returned.
:param design_bands: A list of design band dictionaries, each containing 'f_min', 'f_max', and 'spacing'.
:type design_bands: List[Dict]
:param f_min: The minimum frequency of the range.
:type f_min: float
:param f_max: The maximum frequency of the range.
:type f_max: float
:return: The spacing corresponding to the design band that contains the midpoint of the range,
or None if no such band exists.
:rtype: Union[float, None]
"""
midpoint = (f_min + f_max) / 2
for band in design_bands:
if midpoint >= band['f_min'] and midpoint <= band['f_max']:
return band['spacing']
return None
def reorder_per_degree_design_bands(per_degree_design_bands: dict):
"""Sort the design bands for each degree by their minimum frequency (f_min).
This function modifies the input dictionary in place, sorting the design bands for each unique identifier.
:param per_degree_design_bands: A dictionary where keys are unique identifiers and values are lists of design band dictionaries.
:type per_degree_design_bands: Dict[str, List[Dict]]
"""
for uid, design_bands in per_degree_design_bands.items():
per_degree_design_bands[uid] = sorted(design_bands, key=lambda x: x['f_min'])

View File

@@ -52,7 +52,7 @@
"preamp_variety_list": [], "preamp_variety_list": [],
"booster_variety_list": [] "booster_variety_list": []
}, },
"design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12}] "design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12, "spacing": 50e9}]
}, },
"metadata": { "metadata": {
"location": { "location": {
@@ -71,7 +71,7 @@
"preamp_variety_list": [], "preamp_variety_list": [],
"booster_variety_list": [] "booster_variety_list": []
}, },
"design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12}] "design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12, "spacing": 50e9}]
}, },
"metadata": { "metadata": {
"location": { "location": {
@@ -90,7 +90,7 @@
"preamp_variety_list": [], "preamp_variety_list": [],
"booster_variety_list": [] "booster_variety_list": []
}, },
"design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12}] "design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12, "spacing": 50e9}]
}, },
"metadata": { "metadata": {
"location": { "location": {
@@ -109,7 +109,7 @@
"preamp_variety_list": [], "preamp_variety_list": [],
"booster_variety_list": [] "booster_variety_list": []
}, },
"design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12}] "design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12, "spacing": 50e9}]
}, },
"metadata": { "metadata": {
"location": { "location": {

View File

@@ -1305,4 +1305,5 @@ def find_elements_common_range(el_list: list, equipment: dict) -> List[dict]:
If there are no amplifiers in the path, then use the SI 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, Multiband_amplifier))] amp_bands = [n.params.bands for n in el_list if isinstance(n, (Edfa, Multiband_amplifier))]
return find_common_range(amp_bands, equipment['SI']['default'].f_min, equipment['SI']['default'].f_max) return find_common_range(amp_bands, equipment['SI']['default'].f_min, equipment['SI']['default'].f_max,
equipment['SI']['default'].spacing)

View File

@@ -619,14 +619,14 @@ def network_base(case, site_type, length=50.0, amplifier_type='Multiband_amplifi
elif case == 'monoband_roadm': elif case == 'monoband_roadm':
roadm1['params'] = { roadm1['params'] = {
'design_bands': [ 'design_bands': [
{'f_min': 192.3e12, 'f_max': 196.0e12} {'f_min': 192.3e12, 'f_max': 196.0e12, 'spacing': 50e9}
] ]
} }
elif case == 'monoband_per_degree': elif case == 'monoband_per_degree':
roadm1['params'] = { roadm1['params'] = {
'per_degree_design_bands': { 'per_degree_design_bands': {
'east edfa in SITE1 to ILA1': [ 'east edfa in SITE1 to ILA1': [
{'f_min': 191.5e12, 'f_max': 195.0e12} {'f_min': 191.5e12, 'f_max': 195.0e12, 'spacing': 50e9}
] ]
} }
} }
@@ -670,19 +670,19 @@ def network_base(case, site_type, length=50.0, amplifier_type='Multiband_amplifi
@pytest.mark.parametrize('case, site_type, amplifier_type, expected_design_bands, expected_per_degree_design_bands', [ @pytest.mark.parametrize('case, site_type, amplifier_type, expected_design_bands, expected_per_degree_design_bands', [
('monoband_no_design_band', 'Edfa', 'Edfa', ('monoband_no_design_band', 'Edfa', 'Edfa',
[{'f_min': 191.3e12, 'f_max': 196.1e12}], [{'f_min': 191.3e12, 'f_max': 196.1e12}]), [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}], [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}]),
('monoband_roadm', 'Edfa', 'Edfa', ('monoband_roadm', 'Edfa', 'Edfa',
[{'f_min': 192.3e12, 'f_max': 196.0e12}], [{'f_min': 192.3e12, 'f_max': 196.0e12}]), [{'f_min': 192.3e12, 'f_max': 196.0e12, 'spacing': 50e9}], [{'f_min': 192.3e12, 'f_max': 196.0e12, 'spacing': 50e9}]),
('monoband_per_degree', 'Edfa', 'Edfa', ('monoband_per_degree', 'Edfa', 'Edfa',
[{'f_min': 191.3e12, 'f_max': 196.1e12}], [{'f_min': 191.5e12, 'f_max': 195.0e12}]), [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}], [{'f_min': 191.5e12, 'f_max': 195.0e12, 'spacing': 50e9}]),
('monoband_design', 'Edfa', 'Edfa', ('monoband_design', 'Edfa', 'Edfa',
[{'f_min': 191.3e12, 'f_max': 196.1e12}], [{'f_min': 191.3e12, 'f_max': 196.1e12}]), [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}], [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}]),
('design', 'Fused', 'Multiband_amplifier', ('design', 'Fused', 'Multiband_amplifier',
[{'f_min': 191.3e12, 'f_max': 196.1e12}], [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}],
[{'f_min': 186.55e12, 'f_max': 190.05e12}, {'f_min': 191.25e12, 'f_max': 196.15e12}]), [{'f_min': 186.55e12, 'f_max': 190.05e12, 'spacing': 50e9}, {'f_min': 191.25e12, 'f_max': 196.15e12, 'spacing': 50e9}]),
('no_design', 'Fused', 'Multiband_amplifier', ('no_design', 'Fused', 'Multiband_amplifier',
[{'f_min': 191.3e12, 'f_max': 196.1e12}], [{'f_min': 191.3e12, 'f_max': 196.1e12, 'spacing': 50e9}],
[{'f_min': 187.0e12, 'f_max': 190.0e12}, {'f_min': 191.3e12, 'f_max': 196.0e12}])]) [{'f_min': 187.0e12, 'f_max': 190.0e12, 'spacing': 50e9}, {'f_min': 191.3e12, 'f_max': 196.0e12, 'spacing': 50e9}])])
def test_design_band(case, site_type, amplifier_type, expected_design_bands, expected_per_degree_design_bands): def test_design_band(case, site_type, amplifier_type, expected_design_bands, expected_per_degree_design_bands):
"""Check design_band is the one defined: """Check design_band is the one defined:
- in SI if nothing is defined, - in SI if nothing is defined,
@@ -964,20 +964,20 @@ def network_wo_booster(site_type, bands):
@pytest.mark.parametrize('site_type, expected_type, bands, expected_bands', [ @pytest.mark.parametrize('site_type, expected_type, bands, expected_bands', [
('Multiband_amplifier', Multiband_amplifier, ('Multiband_amplifier', Multiband_amplifier,
[{'f_min': 187.0e12, 'f_max': 190.0e12}, {'f_min': 191.3e12, 'f_max': 196.0e12}], [{'f_min': 187.0e12, 'f_max': 190.0e12, "spacing": 50e9}, {'f_min': 191.3e12, 'f_max': 196.0e12, "spacing": 50e9}],
[{'f_min': 187.0e12, 'f_max': 190.0e12}, {'f_min': 191.3e12, 'f_max': 196.0e12}]), [{'f_min': 187.0e12, 'f_max': 190.0e12, "spacing": 50e9}, {'f_min': 191.3e12, 'f_max': 196.0e12, "spacing": 50e9}]),
('Edfa', Edfa, ('Edfa', Edfa,
[{'f_min': 191.4e12, 'f_max': 196.1e12}], [{'f_min': 191.4e12, 'f_max': 196.1e12, "spacing": 50e9}],
[{'f_min': 191.4e12, 'f_max': 196.1e12}]), [{'f_min': 191.4e12, 'f_max': 196.1e12, "spacing": 50e9}]),
('Edfa', Edfa, ('Edfa', Edfa,
[{'f_min': 191.2e12, 'f_max': 196.0e12}], [{'f_min': 191.2e12, 'f_max': 196.0e12, "spacing": 50e9}],
[]), []),
('Fused', Multiband_amplifier, ('Fused', Multiband_amplifier,
[{'f_min': 187.0e12, 'f_max': 190.0e12}, {'f_min': 191.3e12, 'f_max': 196.0e12}], [{'f_min': 187.0e12, 'f_max': 190.0e12, "spacing": 50e9}, {'f_min': 191.3e12, 'f_max': 196.0e12, "spacing": 50e9}],
[{'f_min': 187.0e12, 'f_max': 190.0e12}, {'f_min': 191.3e12, 'f_max': 196.0e12}]), [{'f_min': 187.0e12, 'f_max': 190.0e12, "spacing": 50e9}, {'f_min': 191.3e12, 'f_max': 196.0e12, "spacing": 50e9}]),
('Fused', Edfa, ('Fused', Edfa,
[{'f_min': 191.3e12, 'f_max': 196.0e12}], [{'f_min': 191.3e12, 'f_max': 196.0e12, "spacing": 50e9}],
[{'f_min': 191.3e12, 'f_max': 196.0e12}])]) [{'f_min': 191.3e12, 'f_max': 196.0e12, "spacing": 50e9}])])
def test_insert_amp(site_type, expected_type, bands, expected_bands): def test_insert_amp(site_type, expected_type, bands, expected_bands):
"""Check: """Check:
- if amplifiers are defined in multiband they are used for design, - if amplifiers are defined in multiband they are used for design,