From 41d9d156a65784ff12654d6370e5cfedafe51add Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Fri, 4 Mar 2022 18:33:56 +0100 Subject: [PATCH 01/20] Add more tests on amp saturation Signed-off-by: EstherLerouzic Change-Id: Ibba18bed646748d59cfe906b403a9b100c58bb7e --- tests/test_amplifier.py | 54 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index 738c3bc3d..e24735ebb 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -3,11 +3,12 @@ # @Author: Jean-Luc Auge # @Date: 2018-02-02 14:06:55 -from numpy import zeros +from numpy import zeros, array from numpy.testing import assert_allclose from gnpy.core.elements import Transceiver, Edfa, Fiber from gnpy.core.utils import automatic_fmax, lin2db, db2lin, merge_amplifier_restrictions, dbm2watt, watt2dbm -from gnpy.core.info import create_input_spectral_information, ReferenceCarrier +from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information, Pref, \ + ReferenceCarrier from gnpy.core.network import build_network from gnpy.tools.json_io import load_network, load_equipment, network_from_json from pathlib import Path @@ -284,3 +285,52 @@ def test_amp_behaviour(tilt_target, delta_p): print(sig_out) assert_allclose(sig_out, expected_sig_out, rtol=1e-9) + + +@pytest.mark.parametrize('delta_p', [0, None, 20]) +@pytest.mark.parametrize('base_power', [0, 20]) +@pytest.mark.parametrize('delta_pdb_per_channel', + [[0, 1, 3, 0.5, -2], + [0, 0, 0, 0, 0], + [-2, -2, -2, -2, -2], + [0, 2, -2, -5, 4], + [0, 1, 3, 0.5, -2], ]) +def test_amp_saturation(delta_pdb_per_channel, base_power, delta_p): + """Check that amp correctly applies saturation + """ + json_data = { + "elements": [{ + "uid": "Edfa1", + "type": "Edfa", + "type_variety": "test", + "operational": { + "delta_p": delta_p, + "gain_target": 20, + "tilt_target": 0, + "out_voa": 0 + } + }], + "connections": [] + } + equipment = load_equipment(eqpt_library) + network = network_from_json(json_data, equipment) + edfa = [n for n in network.nodes()][0] + frequency = 193e12 + array([0, 50e9, 150e9, 225e9, 275e9]) + slot_width = array([37.5e9, 50e9, 75e9, 50e9, 37.5e9]) + baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) + signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0]) + array(delta_pdb_per_channel) + base_power) + ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) + pref = Pref(p_span0=0, p_spani=-20 + base_power, ref_carrier=ref_carrier) + si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, + signal=signal, baud_rate=baud_rate, roll_off=0.15, + delta_pdb_per_channel=delta_pdb_per_channel, + tx_osnr=None, ref_power=pref) + total_sig_powerin = sum(si.signal) + sig_in = lin2db(si.signal) + si = edfa(si) + sig_out = lin2db(si.signal) + total_sig_powerout = sum(si.signal) + gain = lin2db(total_sig_powerout / total_sig_powerin) + assert watt2dbm(sum(si.signal + si.nli + si.ase)) <= 21.02 + assert pytest.approx(edfa.effective_gain, 1e-13) == gain + assert_allclose(sig_in + gain, sig_out, rtol=1e-13) From 3510d59250b39f020af00ef0f9c9b412725372f1 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 16 Mar 2022 16:54:54 +0100 Subject: [PATCH 02/20] Correct design: apply saturation in all cases Previously saturation was not checked during design if amp type was set. This commit also applies saturation for these amplifiers. This changes some of the autodesign result (since range for selection is changed). For example, this changes some of the gains, or type variety of amplifier of test files. The commit also removes one of the rounding in the design phase, and applies rounding only for printing purpose. It also adds minor refactor on a function In order to keep power sweep behaviour in case of saturation, the saturation check in amplifier element uses initial power targets set by user instead of a possible autodesign delta_p result. Note that gain_mode is unchanged: design in gain mode means that delta_p is set to None during the build process, even if the user defined a value in operational.delta_p. Signed-off-by: EstherLerouzic Change-Id: Idc5cfc8263cf678473acb6ec490207d9d6ba5c0a --- gnpy/core/elements.py | 7 +++- gnpy/core/network.py | 37 ++++++++----------- ..._Global_Topology_auto_design_expected.json | 14 +++---- .../testTopology_auto_design_expected.json | 15 ++++---- tests/invocation/logs_transmission_saturated | 8 ++-- tests/invocation/transmission_saturated | 18 ++++----- 6 files changed, 49 insertions(+), 50 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index a1c0e80ab..872d5839c 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -856,7 +856,12 @@ def interpol_params(self, spectral_info): """in power mode: delta_p is defined and can be used to calculate the power target This power target is used calculate the amplifier gain""" pref = spectral_info.pref - if self.delta_p is not None: + if self.delta_p is not None and self.operational.delta_p is not None: + # use the user defined target + self.target_pch_out_db = round(self.operational.delta_p + pref.p_span0, 2) + self.effective_gain = self.target_pch_out_db - pref.p_spani + elif self.delta_p is not None: + # use the design target if no target were set self.target_pch_out_db = round(self.delta_p + pref.p_span0, 2) self.effective_gain = self.target_pch_out_db - pref.p_spani diff --git a/gnpy/core/network.py b/gnpy/core/network.py index f459f3d13..c9d35202b 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -61,15 +61,8 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restri # power attribut include power AND gain limitations edfa_list = [Edfa_list( variety=edfa_variety, - power=min( - pin - + edfa.gain_flatmax - + TARGET_EXTENDED_GAIN, - edfa.p_max - ) - - power_target, - gain_min=gain_target + 3 - - edfa.gain_min, + power=min(pin + edfa.gain_flatmax + TARGET_EXTENDED_GAIN, edfa.p_max) - power_target, + gain_min=gain_target + 3 - edfa.gain_min, nf=edfa_nf(gain_target, edfa_variety, equipment)) for edfa_variety, edfa in edfa_dict.items() if ((edfa.allowed_for_design or restrictions is not None) and not edfa.raman)] @@ -78,15 +71,8 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restri # do not allow extended gain min for Raman raman_list = [Edfa_list( variety=edfa_variety, - power=min( - pin - + edfa.gain_flatmax - + TARGET_EXTENDED_GAIN, - edfa.p_max - ) - - power_target, - gain_min=gain_target - - edfa.gain_min, + power=min(pin + edfa.gain_flatmax + TARGET_EXTENDED_GAIN, edfa.p_max) - power_target, + gain_min=gain_target - edfa.gain_min, nf=edfa_nf(gain_target, edfa_variety, equipment)) for edfa_variety, edfa in edfa_dict.items() if (edfa.allowed_for_design and edfa.raman)] \ @@ -132,11 +118,11 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restri # =>chose the amp with the best NF among the acceptable ones: selected_edfa = min(acceptable_power_list, key=attrgetter('nf')) # filter on NF # check what are the gain and power limitations of this amp - power_reduction = round(min(selected_edfa.power, 0), 2) + power_reduction = min(selected_edfa.power, 0) if power_reduction < -0.5: logger.warning(f'\n\tWARNING: target gain and power in node {uid}\n' + '\tis beyond all available amplifiers capabilities and/or extended_gain_range:\n' - + f'\ta power reduction of {power_reduction} is applied\n') + + f'\ta power reduction of {round(power_reduction, 2)} is applied\n') return selected_edfa.variety, power_reduction @@ -305,6 +291,15 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d dp += power_reduction gain_target += power_reduction else: + # Check power saturation also in this case + p_max = equipment['Edfa'][node.params.type_variety].p_max + if power_mode: + power_reduction = min(0, p_max - (pref_total_db + dp)) + else: + pout = pref_total_db + prev_dp - node_loss - prev_voa + gain_target + power_reduction = min(0, p_max - pout) + dp += power_reduction + gain_target += power_reduction if node.params.raman and not raman_allowed: if isinstance(prev_node, elements.Fiber): logger.warning(f'\n\tWARNING: raman is used in node {node.uid}\n ' @@ -321,7 +316,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d + f'\tis above user specified amplifier {node.params.type_variety}\n' + '\tmax flat gain: ' + f'{equipment["Edfa"][node.params.type_variety].gain_flatmax}dB ; ' - + f'required gain: {gain_target}dB. Please check amplifier type.\n') + + f'required gain: {round(gain_target, 2)}dB. Please check amplifier type.\n') node.delta_p = dp if power_mode else None node.effective_gain = gain_target diff --git a/tests/data/CORONET_Global_Topology_auto_design_expected.json b/tests/data/CORONET_Global_Topology_auto_design_expected.json index e54068059..86120d591 100644 --- a/tests/data/CORONET_Global_Topology_auto_design_expected.json +++ b/tests/data/CORONET_Global_Topology_auto_design_expected.json @@ -83375,7 +83375,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 28.5006, + "gain_target": 28.5, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -88752,7 +88752,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 28.5032, + "gain_target": 28.5, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -89037,7 +89037,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 28.5006, + "gain_target": 28.5, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -89721,7 +89721,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 28.502, + "gain_target": 28.5, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -89797,7 +89797,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 28.502, + "gain_target": 28.5, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -89911,7 +89911,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 28.5032, + "gain_target": 28.5, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -193159,4 +193159,4 @@ "to_node": "fiber (Warsaw → Vienna)-_(7/7)" } ] -} \ No newline at end of file +} diff --git a/tests/data/testTopology_auto_design_expected.json b/tests/data/testTopology_auto_design_expected.json index c15385236..cd611236f 100644 --- a/tests/data/testTopology_auto_design_expected.json +++ b/tests/data/testTopology_auto_design_expected.json @@ -240,7 +240,6 @@ "east edfa in Rennes_STA to Stbrieuc": -20, "east edfa in Rennes_STA to Ploermel": -20 } - }, "metadata": { "location": { @@ -310,7 +309,7 @@ ], "booster_variety_list": [] }, - "per_degree_pch_out_db":{ + "per_degree_pch_out_db": { "east edfa in b to a": -20, "east edfa in b to f": -20 } @@ -333,7 +332,7 @@ "preamp_variety_list": [], "booster_variety_list": [] }, - "per_degree_pch_out_db":{ + "per_degree_pch_out_db": { "east edfa in c to a": -20, "east edfa in c to d": -20, "east edfa in c to f": -20 @@ -430,7 +429,7 @@ "per_degree_pch_out_db": { "east edfa in g to e": -20, "east edfa in g to h": -20 - } + } }, "metadata": { "location": { @@ -1593,7 +1592,7 @@ "type": "Edfa", "type_variety": "std_medium_gain", "operational": { - "gain_target": 18.5, + "gain_target": 13.177288, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -2235,7 +2234,7 @@ "type": "Edfa", "type_variety": "std_low_gain", "operational": { - "gain_target": 6.5, + "gain_target": 11.822712, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -2292,7 +2291,7 @@ "type": "Edfa", "type_variety": "std_low_gain", "operational": { - "gain_target": 13.82, + "gain_target": 13.822712, "delta_p": null, "tilt_target": 0, "out_voa": 0 @@ -2311,7 +2310,7 @@ "type": "Edfa", "type_variety": "test_fixed_gain", "operational": { - "gain_target": 15.18, + "gain_target": 15.177288, "delta_p": null, "tilt_target": 0, "out_voa": 0 diff --git a/tests/invocation/logs_transmission_saturated b/tests/invocation/logs_transmission_saturated index 99612f67f..ea272d327 100644 --- a/tests/invocation/logs_transmission_saturated +++ b/tests/invocation/logs_transmission_saturated @@ -8,7 +8,7 @@ WARNING gnpy.core.network:network.py WARNING gnpy.core.network:network.py WARNING: effective gain in Node east edfa in Lannion_CAS to Stbrieuc is above user specified amplifier std_low_gain - max flat gain: 16dB ; required gain: 23.0dB. Please check amplifier type. + max flat gain: 16dB ; required gain: 21.18dB. Please check amplifier type. WARNING gnpy.core.network:network.py WARNING: target gain and power in node west edfa in Rennes_STA to Stbrieuc @@ -18,7 +18,7 @@ WARNING gnpy.core.network:network.py WARNING gnpy.core.network:network.py WARNING: effective gain in Node east edfa in Lannion_CAS to Morlaix is above user specified amplifier std_low_gain - max flat gain: 16dB ; required gain: 23.5dB. Please check amplifier type. + max flat gain: 16dB ; required gain: 21.18dB. Please check amplifier type. WARNING gnpy.core.network:network.py WARNING: target gain and power in node west edfa in Brest_KLA to Morlaix @@ -33,7 +33,7 @@ WARNING gnpy.core.network:network.py WARNING gnpy.core.network:network.py WARNING: effective gain in Node west edfa in Lannion_CAS to Corlay is above user specified amplifier test - max flat gain: 25dB ; required gain: 29.82dB. Please check amplifier type. + max flat gain: 25dB ; required gain: 28.0dB. Please check amplifier type. WARNING gnpy.core.network:network.py WARNING: target gain and power in node east edfa in Lorient_KMA to Vannes_KBE @@ -118,7 +118,7 @@ WARNING gnpy.core.network:network.py WARNING gnpy.core.network:network.py WARNING: effective gain in Node east edfa in Brest_KLA to Quimper is above user specified amplifier std_low_gain - max flat gain: 16dB ; required gain: 23.0dB. Please check amplifier type. + max flat gain: 16dB ; required gain: 21.18dB. Please check amplifier type. WARNING gnpy.core.network:network.py WARNING: target gain and power in node east edfa in Quimper to Lorient_KMA diff --git a/tests/invocation/transmission_saturated b/tests/invocation/transmission_saturated index dfbfc65ee..407842d77 100644 --- a/tests/invocation/transmission_saturated +++ b/tests/invocation/transmission_saturated @@ -29,8 +29,8 @@ Edfa east edfa in Lannion_CAS to Corlay pad att_in (dB): 0.00 Power In (dBm): -0.18 Power Out (dBm): 21.01 - Delta_P (dB): 0.00 - target pch (dBm): 3.00 + Delta_P (dB): -1.82 + target pch (dBm): 1.18 effective pch (dBm): 1.18 actual pch out (dBm): 1.18 output VOA (dB): 0.00 @@ -66,10 +66,10 @@ Fiber fiber (Loudeac → Lorient_KMA)-F054 reference pch out (dBm): -26.82 actual pch out (dBm): -26.81 Edfa west edfa in Lorient_KMA to Loudeac - type_variety: test + type_variety: std_medium_gain effective gain(dB): 27.99 (before att_in and before output VOA) - noise figure (dB): 5.76 + noise figure (dB): 5.98 (including att_in) pad att_in (dB): 0.00 Power In (dBm): -6.99 @@ -84,17 +84,17 @@ Roadm roadm Lorient_KMA reference pch out (dBm): -20.00 actual pch out (dBm): -20.00 Transceiver trx Lorient_KMA - GSNR (0.1nm, dB): 23.93 - GSNR (signal bw, dB): 19.85 - OSNR ASE (0.1nm, dB): 24.29 - OSNR ASE (signal bw, dB): 20.20 + GSNR (0.1nm, dB): 23.77 + GSNR (signal bw, dB): 19.69 + OSNR ASE (0.1nm, dB): 24.11 + OSNR ASE (signal bw, dB): 20.03 CD (ps/nm): 2171.00 PMD (ps): 0.46 PDL (dB): 0.00 Latency (ms): 0.64 Transmission result for input power = 3.00 dBm: - Final GSNR (0.1 nm): 23.93 dB + Final GSNR (0.1 nm): 23.77 dB (Invalid source node 'lannion' replaced with trx Lannion_CAS) From 78efb6c6508c6b4d3d3fbc0f4813ff8b77dcdbb3 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 3 Mar 2021 17:38:13 +0100 Subject: [PATCH 03/20] Check element setting before and after propagation In power mode, all elements design attributes should not change except amplifiers' gain in case of power saturation. Signed-off-by: EstherLerouzic Change-Id: I2fec00232c80dd395e4dec20ec531c9c2e127760 --- tests/test_roadm_restrictions.py | 258 ++++++++++++++++++++++++++++++- 1 file changed, 250 insertions(+), 8 deletions(-) diff --git a/tests/test_roadm_restrictions.py b/tests/test_roadm_restrictions.py index 875aeb0dd..7f6a6470e 100644 --- a/tests/test_roadm_restrictions.py +++ b/tests/test_roadm_restrictions.py @@ -13,15 +13,18 @@ from pathlib import Path import pytest from numpy.testing import assert_allclose - +from numpy import ndarray +from copy import deepcopy from gnpy.core.utils import lin2db, automatic_nch -from gnpy.core.elements import Fused, Roadm, Edfa +from gnpy.core.elements import Fused, Roadm, Edfa, Transceiver, EdfaOperational, EdfaParams, Fiber +from gnpy.core.parameters import FiberParams, RoadmParams, FusedParams from gnpy.core.network import build_network from gnpy.tools.json_io import network_from_json, load_equipment, load_json, Amp from gnpy.core.equipment import trx_mode_params -from gnpy.topology.request import PathRequest, compute_constrained_path, ref_carrier -from gnpy.core.info import create_input_spectral_information -from gnpy.core.utils import db2lin +from gnpy.topology.request import PathRequest, compute_constrained_path, ref_carrier, propagate +from gnpy.core.info import create_input_spectral_information, Carrier +from gnpy.core.utils import db2lin, dbm2watt + TEST_DIR = Path(__file__).parent EQPT_LIBRARY_NAME = TEST_DIR / 'data/eqpt_config.json' @@ -218,6 +221,7 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm): power can not be met in this last case. """ equipment = load_equipment(EQPT_LIBRARY_NAME) + equipment['SI']['default'].power_dbm = power_dbm json_network = load_json(TEST_DIR / 'data/twohops_roadm_power_test.json') prev_node = next(n for n in json_network['elements'] if n['uid'] == 'west edfa in node B to ila2') json_network['elements'].remove(prev_node) @@ -274,12 +278,250 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm): assert_allclose(el.ref_pch_out_dbm, effective_pch_out_db, rtol=1e-3) # Check that egress power of roadm is equal to target power assert_allclose(power_out_roadm, db2lin(effective_pch_out_db - 30), rtol=1e-3) - elif prev_node_type == 'fused': - # fused prev_node does reamplfy power after fiber propagation, so input power + if prev_node_type == 'fused': + # fused prev_node does not reamplify power after fiber propagation, so input power # to roadm is low. # check that target power correctly reports power_dbm from previous propagation assert_allclose(el.ref_pch_out_dbm, effective_pch_out_db + power_dbm, rtol=1e-3) - # Check that egress power of roadm is not equalized power out is the same as power in. + # Check that egress power of roadm is not equalized: power out is the same as power in. assert_allclose(power_out_roadm, power_in_roadm, rtol=1e-3) + assert effective_pch_out_db + power_dbm ==\ + pytest.approx(lin2db(min(power_in_roadm) * 1e3), rel=1e-3) else: si = el(si) + + +def create_per_oms_request(network, eqpt, req_power): + """Create requests between every adjacent ROADMs + one additional request crossing several ROADMs + """ + nb_channel = automatic_nch(eqpt['SI']['default'].f_min, eqpt['SI']['default'].f_max, + eqpt['SI']['default'].spacing) + params = { + 'trx_type': '', + 'trx_mode': '', + 'bidir': False, + 'loose_list': ['strict', 'strict'], + 'format': '', + 'path_bandwidth': 100e9, + 'effective_freq_slot': None, + 'nb_channel': nb_channel + } + trx_params = trx_mode_params(eqpt) + params.update(trx_params) + trxs = [e for e in network if isinstance(e, Transceiver)] + req_list = [] + req_id = 0 + for trx in trxs: + source = trx.uid + roadm = next(n for n in network.successors(trx) if isinstance(n, Roadm)) + for degree in roadm.per_degree_pch_out_dbm.keys(): + node = next(n for n in network.nodes() if n.uid == degree) + # find next roadm + while not isinstance(node, Roadm): + node = next(n for n in network.successors(node)) + next_roadm = node + destination = next(n.uid for n in network.successors(next_roadm) if isinstance(n, Transceiver)) + params['request_id'] = req_id + req_id += 1 + params['source'] = source + params['destination'] = destination + params['nodes_list'] = [degree, destination] + req = PathRequest(**params) + req.power = dbm2watt(req_power) + carrier = {key: getattr(req, key) for key in ['baud_rate', 'roll_off', 'tx_osnr']} + carrier['label'] = "" + carrier['slot_width'] = req.spacing + carrier['delta_pdb'] = 0 + req.initial_spectrum = {(req.f_min + req.spacing * f): Carrier(**carrier) + for f in range(1, req.nb_channel + 1)} + req_list.append(req) + # add one additional request crossing several roadms to have a complete view + params['source'] = 'trx Rennes_STA' + params['destination'] = 'trx Vannes_KBE' + params['nodes_list'] = ['roadm Lannion_CAS', 'trx Vannes_KBE'] + params['bidir'] = True + req = PathRequest(**params) + req.power = dbm2watt(req_power) + carrier = {key: getattr(req, key) for key in ['baud_rate', 'roll_off', 'tx_osnr']} + carrier['label'] = "" + carrier['slot_width'] = req.spacing + carrier['delta_pdb'] = 0 + req.initial_spectrum = {(req.f_min + req.spacing * f): Carrier(**carrier) for f in range(1, req.nb_channel + 1)} + req_list.append(req) + return req_list + + +def list_element_attr(element): + """Return the list of keys to be checked depending on element type. List only the keys that are not + created upon element effective propagation + """ + + if isinstance(element, Roadm): + return ['uid', 'name', 'metadata', 'operational', 'type_variety', 'target_pch_out_dbm', + 'passive', 'restrictions', 'per_degree_pch_out_dbm', + 'target_psd_out_mWperGHz', 'per_degree_pch_psd'] + # Dynamically created: 'effective_loss', + if isinstance(element, RoadmParams): + return ['target_pch_out_dbm', 'target_psd_out_mWperGHz', 'per_degree_pch_out_db', 'per_degree_pch_psd', + 'add_drop_osnr', 'pmd', 'restrictions'] + if isinstance(element, Edfa): + return ['variety_list', 'uid', 'name', 'params', 'metadata', 'operational', + 'passive', 'effective_gain', 'delta_p', 'tilt_target', 'out_voa'] + # TODO this exhaustive test highlighted that type_variety is not correctly updated from EdfaParams to + # attributes in preamps + # Dynamically created only with channel propagation: 'att_in', 'channel_freq', 'effective_pch_out_db' + # 'gprofile', 'interpol_dgt', 'interpol_gain_ripple', 'interpol_nf_ripple', 'nch', 'nf', 'pin_db', 'pout_db', + # 'target_pch_out_db', + if isinstance(element, FusedParams): + return ['loss'] + if isinstance(element, EdfaOperational): + return ['delta_p', 'gain_target', 'out_voa', 'tilt_target'] + if isinstance(element, EdfaParams): + return ['f_min', 'f_max', 'type_variety', 'type_def', 'gain_flatmax', 'gain_min', 'p_max', 'nf_model', + 'dual_stage_model', 'nf_fit_coeff', 'nf_ripple', 'dgt', 'gain_ripple', 'out_voa_auto', + 'allowed_for_design', 'raman'] + if isinstance(element, Fiber): + + return ['uid', 'name', 'params', 'metadata', 'operational', 'type_variety', 'passive', + 'lumped_losses', 'z_lumped_losses'] + # Dynamically created 'output_total_power', 'pch_out_db' + if isinstance(element, FiberParams): + return ['_length', '_att_in', '_con_in', '_con_out', '_ref_frequency', '_ref_wavelength', + '_dispersion', '_dispersion_slope', '_dispersion', '_f_dispersion_ref', + '_gamma', '_pmd_coef', '_loss_coef', + '_f_loss_ref', '_lumped_losses'] + if isinstance(element, Fused): + return ['uid', 'name', 'params', 'metadata', 'operational', 'loss', 'passive'] + if isinstance(element, FusedParams): + return ['loss'] + return ['should never come here'] + + +# all initial delta_p are null in topo file, so add random places to change this value +@pytest.mark.parametrize('amp_with_deltap_one', [[], + ['east edfa in Lorient_KMA to Vannes_KBE', + 'east edfa in Stbrieuc to Rennes_STA', + 'west edfa in Lannion_CAS to Morlaix', + 'east edfa in a to b', + 'west edfa in b to a']]) +@pytest.mark.parametrize('power_dbm, req_power', [(0, 0), (0, -3), (3, 3), (0, 3), (3, 0), + (3, 1), (3, 5), (3, 2), (3, 4), (2, 4)]) +def test_compare_design_propagation_settings(power_dbm, req_power, amp_with_deltap_one): + """Check that network design does not change after propagation except for gain in + case of power_saturation during design and/or during propagation: + - in power mode only: + expected behaviour: target power out of roadm does not change + so gain of booster should be reduced/augmented by the exact power difference; + the following amplifiers on the OMS have unchanged gain except if augmentation + of channel power on booster leads to total_power above amplifier max power, + ie if amplifier saturates. + + roadm -----booster (pmax 21dBm, 96 channels= 19.82dB) + pdesign=0dBm pch= 0dBm, ^ -20dBm ^G=20dB, Pch=0dBm, Ptot=19.82dBm + pdesign=0dBm pch= -3dBm ^ -20dBm ^G=17dB, Pch=-3dBm, Ptot=16.82dBm + pdesign=3dBm pch= 3dBm ^ -20dBm ^G=23-1.82dB, Pch=1.18dBm, Ptot=21dBm + amplifier can not handle 96x3dBm channels, amplifier saturation is considered + for the choice of amplifier during design + pdesign=0dBm pch= 3dBm ^ -20dBm ^G=23-1.82dB, Pch=1.18dBm, Ptot=21dBm + amplifier can not handle 96x3dBm channels during propagation, amplifier selection + has been done for 0dBm. Saturation is applied for all amps only during propagation + + Design applies a saturation verification on amplifiers. + This saturation leads to a power reduction to the max power in the amp library, which + is also applied on the amp delta_p and independantly from propagation. + + After design, upon propagation, the amplifier gain and applied delta_p may also change + if total power exceeds max power (eg not the same nb of channels, not the same power per channel + compared to design). + + This test also checks all the possible combinations and expected before/after propagation + gain differences. It also checks delta_p applied due to saturation during design. + """ + eqpt = load_equipment(EQPT_LIBRARY_NAME) + eqpt['SI']['default'].power_dbm = power_dbm + json_network = load_json(NETWORK_FILE_NAME) + for element in json_network['elements']: + # Initialize a value for delta_p + if element['type'] == 'Edfa': + element['operational']['delta_p'] = 0 + element['operational']['out_voa'] \ + if element['operational']['out_voa'] is not None else 0 + # apply a 1 dB delta_p on the set of amps + if element['uid'] in amp_with_deltap_one: + element['operational']['delta_p'] = 1 + + network = network_from_json(json_network, eqpt) + # Build the network once using the default power defined in SI in eqpt config + p_db = power_dbm + p_total_db = p_db + lin2db(automatic_nch(eqpt['SI']['default'].f_min, + eqpt['SI']['default'].f_max, + eqpt['SI']['default'].spacing)) + build_network(network, eqpt, p_db, p_total_db) + # record network settings before propagating + network_copy = deepcopy(network) + # propagate on each oms + req_list = create_per_oms_request(network, eqpt, req_power) + paths = [compute_constrained_path(network, r) for r in req_list] + + # systematic comparison of elements settings before and after propagation + # all amps have 21 dBm max power + pch_max = 21 - lin2db(96) + for path, req in zip(paths, req_list): + # check all elements except source and destination trx + # in order to have clean initialization, use deecopy of paths + pth = deepcopy(path) + _ = propagate(pth, req, eqpt) + previous_power = None + previous_deltap = None + for i, element in enumerate(pth[1:-1]): + element_is_first_amp = False + # index of previous element in path is i + if (isinstance(element, Edfa) and isinstance(pth[i], Roadm)) or element.uid == 'west edfa in d to c': + # oms c to d has no booster but one preamp: the power difference is hold there + element_is_first_amp = True + # find the element with the same id in the network_copy + element_copy = next(n for n in network_copy.nodes() if n.uid == element.uid) + for key in list_element_attr(element): + if not isinstance(getattr(element, key), + (EdfaOperational, EdfaParams, FiberParams, RoadmParams, FusedParams)): + if not key == 'effective_gain': + # for all keys, before and after design should be the same except for gain (in power mode) + if isinstance(getattr(element, key), ndarray): + if len(getattr(element, key)) > 0: + assert getattr(element, key) == getattr(element_copy, key) + else: + assert len(getattr(element_copy, key)) == 0 + else: + assert getattr(element, key) == getattr(element_copy, key) + else: + dp = element.out_voa if element.uid not in amp_with_deltap_one else element.out_voa + 1 + if element_is_first_amp: + assert element.effective_gain - element_copy.effective_gain ==\ + pytest.approx(min(pch_max, req_power + max(element.delta_p, dp)) + - min(pch_max, power_dbm + dp), abs=1e-2) + # if target power is above pch_max then gain should be saturated during propagation + assert element.effective_pch_out_db ==\ + pytest.approx(min(pch_max, req_power + max(element.delta_p, dp)), abs=1e-2) + else: + assert element.effective_gain - element_copy.effective_gain ==\ + pytest.approx(min(pch_max, req_power + max(element.delta_p, dp)) + - min(pch_max, previous_power) + - min(pch_max, power_dbm + element.delta_p) + + min(pch_max, power_dbm + previous_deltap), abs=2e-2) + assert element.delta_p == pytest.approx(min(power_dbm + dp, pch_max) - power_dbm, abs=1e-2) + + previous_deltap = element.delta_p + previous_power = min(pch_max, req_power + max(element.delta_p, dp)) + else: + # for all subkeys, before and after design should be the same + for subkey in list_element_attr(getattr(element, key)): + if isinstance(getattr(getattr(element, key), subkey), list): + assert getattr(getattr(element, key), subkey) == getattr(getattr(element_copy, key), subkey) + elif isinstance(getattr(getattr(element, key), subkey), dict): + for value1, value2 in zip(getattr(getattr(element, key), subkey).values(), + getattr(getattr(element_copy, key), subkey).values()): + assert all(value1 == value2) + elif isinstance(getattr(getattr(element, key), subkey), ndarray): + assert_allclose(getattr(getattr(element, key), subkey), + getattr(getattr(element_copy, key), subkey), rtol=1e-12) + else: + assert getattr(getattr(element, key), subkey) == getattr(getattr(element_copy, key), subkey) From 9c514e80863e7bd0971d578e41857c2f4f881579 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 28 Apr 2021 18:24:51 +0200 Subject: [PATCH 04/20] Add a test on gain mode behaviour This test checks that setting in gain mode forces amp to the gain settings and ignores any power requirements. Change in SI in eqpt config and change in req power (eg power sweep) should have no effect on the propagation. Signed-off-by: EstherLerouzic Change-Id: Iad826f30010fe3110d105b5206d99f502fbf98ff --- tests/test_gain_mode.py | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tests/test_gain_mode.py diff --git a/tests/test_gain_mode.py b/tests/test_gain_mode.py new file mode 100644 index 000000000..5b57035e8 --- /dev/null +++ b/tests/test_gain_mode.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# @Author: Esther Le Rouzic +# @Date: 2019-05-22 +""" +@author: esther.lerouzic +checks behaviour of gain mode +- if all amps have their gains set, check that these gains are used, even if power_dbm or req_power change +- check that saturation is correct in gain mode + +""" + +from pathlib import Path +from numpy.testing import assert_array_equal, assert_allclose + +import pytest +from gnpy.core.utils import lin2db, automatic_nch, dbm2watt +from gnpy.core.network import build_network +from gnpy.tools.json_io import load_equipment, load_network +from gnpy.core.equipment import trx_mode_params +from gnpy.topology.request import PathRequest, compute_constrained_path, propagate + + +TEST_DIR = Path(__file__).parent +EQPT_FILENAME = TEST_DIR / 'data/eqpt_config.json' +NETWORK_FILENAME = TEST_DIR / 'data/perdegreemeshTopologyExampleV2_auto_design_expected.json' + + +def net_setup(equipment): + """Common setup for tests: builds network, equipment + """ + network = load_network(NETWORK_FILENAME, equipment) + spectrum = equipment['SI']['default'] + p_db = spectrum.power_dbm + p_total_db = p_db + lin2db(automatic_nch(spectrum.f_min, spectrum.f_max, spectrum.spacing)) + build_network(network, equipment, p_db, p_total_db) + return network + + +def create_rq(equipment, srce, dest, bdir, nd_list, ls_list, mode, power_dbm): + """Create the usual request list according to parameters + """ + params = { + 'request_id': 'test_request', + 'source': srce, + 'bidir': bdir, + 'destination': dest, + 'trx_type': 'Voyager', + 'trx_mode': mode, + 'format': mode, + 'nodes_list': nd_list, + 'loose_list': ls_list, + 'effective_freq_slot': None, + 'path_bandwidth': 100000000000.0, + 'spacing': 50e9 if mode == 'mode 1' else 75e9, + 'power': dbm2watt(power_dbm) + } + trx_params = trx_mode_params(equipment, params['trx_type'], params['trx_mode'], True) + params.update(trx_params) + f_min = params['f_min'] + f_max_from_si = params['f_max'] + params['nb_channel'] = automatic_nch(f_min, f_max_from_si, params['spacing']) + return PathRequest(**params) + + +@pytest.mark.parametrize("power_dbm", [0, -2, 3]) +@pytest.mark.parametrize("req_power", [1e-3, 0.5e-3, 2e-3]) +def test_gain_mode(req_power, power_dbm): + """ Gains are all set on the selected path, so that since the design is made for 0dBm, + in gain mode, whatever the value of equipment power_dbm or request power, the network is unchanged + and the propagation remains the same as for power mode and 0dBm + """ + equipment = load_equipment(EQPT_FILENAME) + network = net_setup(equipment) + req = create_rq(equipment, 'trx Brest_KLA', 'trx Rennes_STA', False, + ['Edfa0_roadm Brest_KLA', 'roadm Lannion_CAS', 'trx Rennes_STA'], + ['STRICT', 'STRICT', 'STRICT'], 'mode 1', 0) + path = compute_constrained_path(network, req) + # Propagation in power_mode + infos_expected = propagate(path, req, equipment) + # Now set to gain mode + setattr(equipment['Span']['default'], 'power_mode', False) + setattr(equipment['SI']['default'], 'power_dbm', power_dbm) + req.power = req_power + network2 = net_setup(equipment) + path2 = compute_constrained_path(network2, req) + infos_actual = propagate(path2, req, equipment) + + assert_array_equal(infos_expected.baud_rate, infos_actual.baud_rate) + assert_allclose(infos_expected.signal, infos_actual.signal, rtol=1e-14) + assert_allclose(infos_expected.nli, infos_actual.nli, rtol=1e-14) + assert_allclose(infos_expected.ase, infos_actual.ase, rtol=1e-14) + assert_array_equal(infos_expected.roll_off, infos_actual.roll_off) + assert_array_equal(infos_expected.chromatic_dispersion, infos_actual.chromatic_dispersion) + assert_array_equal(infos_expected.pmd, infos_actual.pmd) + assert_array_equal(infos_expected.channel_number, infos_actual.channel_number) + assert_array_equal(infos_expected.number_of_channels, infos_actual.number_of_channels) From 537eb017b584f66295df32be0b2640d061349ae2 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Thu, 24 Mar 2022 17:10:47 +0100 Subject: [PATCH 05/20] Add frequency range in default_edfa profile This range is the property of amps and is independant from user propagation range. Signed-off-by: EstherLerouzic Change-Id: Ib89f1987910aa3121a3b8c859a0a785f7d5e27eb --- gnpy/example-data/default_edfa_config.json | 2 ++ tests/data/default_edfa_config.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/gnpy/example-data/default_edfa_config.json b/gnpy/example-data/default_edfa_config.json index f6efb13a8..8f2bc1c3d 100644 --- a/gnpy/example-data/default_edfa_config.json +++ b/gnpy/example-data/default_edfa_config.json @@ -5,6 +5,8 @@ "gain_ripple": [ 0.0 ], + "f_min": 191.35e12, + "f_max": 196.1e12, "dgt": [ 1.0, 1.017807767853702, diff --git a/tests/data/default_edfa_config.json b/tests/data/default_edfa_config.json index c78e078a9..f0acc864e 100644 --- a/tests/data/default_edfa_config.json +++ b/tests/data/default_edfa_config.json @@ -1,4 +1,6 @@ { + "f_min": 191.35e12, + "f_max": 196.1e12, "nf_ripple": [ 0.0, 0.0, From 7c60b000b5c45cd1c9def1e67ece229254dd569b Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 14:29:28 +0200 Subject: [PATCH 06/20] Add a variable to hold delta_p even if gain mode is selected Let's use a clean convention to hold values that are configured, autodesigned or resulting from propagation. - edfa.operational.delta_p: holds the value set by the user if any. This is needed in case of redesign for power sweep for example. It is never changed. - edfa.delta_p: o if power_mode is true, records the value computed by the design. Applies user defined value except: If the user has set non possible values (eg leading to saturation), then the value is corrected at design phase. If the element is propagated for different conditions than design, for example leading to saturation, then delta_p might be different than the value initially computed during design. o if power_mode is False, it is set to None - edfa._delta_p: records the value computed during design whatever the power mode Signed-off-by: EstherLerouzic Change-Id: I4e130a3abe0a5e3f6c057d89360e50531c168123 --- gnpy/core/elements.py | 9 ++++++++- gnpy/core/network.py | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 872d5839c..5650d52d2 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -776,7 +776,14 @@ def __init__(self, *args, params=None, operational=None, **kwargs): self.passive = False self.att_in = None self.effective_gain = self.operational.gain_target - self.delta_p = self.operational.delta_p # delta P with Pref (power swwep) in power mode + # self.operational.delta_p is defined by user for reference channel + # self.delta_p is set with self.operational.delta_p, but it may be changed during design: + # - if operational.delta_p is None, self.delta_p is computed at design phase + # - if operational.delta_p can not be applied because of saturation, self.delta_p is recomputed + # - if power_mode is False, then it is set to None + self.delta_p = self.operational.delta_p + # self._delta_p contains computed delta_p during design even if power_mode is False + self._delta_p = None self.tilt_target = self.operational.tilt_target self.out_voa = self.operational.out_voa self.propagated_labels = [""] diff --git a/gnpy/core/network.py b/gnpy/core/network.py index c9d35202b..83cc59c9e 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -321,6 +321,8 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d node.delta_p = dp if power_mode else None node.effective_gain = gain_target set_amplifier_voa(node, power_target, power_mode) + # set_amplifier_voa may change delta_p in power_mode + node._delta_p = node.delta_p if power_mode else dp prev_dp = dp prev_voa = voa From 07fd89351b446eb7ce19b3813d16cbac08424246 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 15:01:01 +0200 Subject: [PATCH 07/20] Computes reference input power in ROADM during design input power is computed at design time: so let's record it and use it instead of p_span_i for ROADM reference channel loss computation. Note that this loss parameter is only used for visualisation purpose. No impact on propagation. Since this loss is computed for the reference channel used for design, we need to record input power based on input degrees, and indicate this information within the call function. Note that this will be also usefull later on to implement ROADM parameters Signed-off-by: EstherLerouzic Change-Id: I64d510fc20df72f07158f400964d592d76dc0ce4 --- gnpy/core/elements.py | 13 ++--- gnpy/core/network.py | 69 ++++++++++++++++++++++++- gnpy/topology/request.py | 4 +- tests/invocation/transmission_saturated | 2 +- tests/test_equalization.py | 11 ++-- tests/test_roadm_restrictions.py | 2 +- 6 files changed, 85 insertions(+), 16 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 5650d52d2..9693e1e1a 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -258,6 +258,7 @@ def __init__(self, *args, params=None, **kwargs): self.per_degree_pch_out_dbm = self.params.per_degree_pch_out_db self.per_degree_pch_psd = self.params.per_degree_pch_psd self.per_degree_pch_psw = self.params.per_degree_pch_psw + self.ref_pch_in_dbm = {} @property def to_json(self): @@ -354,7 +355,7 @@ def get_per_degree_power(self, degree, spectral_info): return psd2powerdbm(self.per_degree_pch_psw[degree], spectral_info.slot_width) return self.get_roadm_target_power(spectral_info=spectral_info) - def propagate(self, spectral_info, degree): + def propagate(self, spectral_info, degree, from_degree): """Equalization targets are read from topology file if defined and completed with default definition of the library. If the input power is lower than the target one, use the input power instead because @@ -370,15 +371,15 @@ def propagate(self, spectral_info, degree): per_degree_pch = self.get_per_degree_power(degree, spectral_info=spectral_info) # Definition of ref_pch_out_dbm for the reference channel: - # Depending on propagation upstream from this ROADM, the input power (p_spani) might be smaller than + # Depending on propagation upstream from this ROADM, the input power might be smaller than # the target power out configured for this ROADM degree's egress. Since ROADM does not amplify, # the power out of the ROADM for the ref channel is the min value between target power and input power. # (TODO add a minimum loss for the ROADM crossing) - self.ref_pch_out_dbm = min(spectral_info.pref.p_spani, ref_per_degree_pch) + self.ref_pch_out_dbm = min(self.ref_pch_in_dbm[from_degree], ref_per_degree_pch) # Definition of effective_loss: # Optical power of carriers are equalized by the ROADM, so that the experienced loss is not the same for # different carriers. effective_loss records the loss for the reference carrier. - self.ref_effective_loss = spectral_info.pref.p_spani - self.ref_pch_out_dbm + self.ref_effective_loss = self.ref_pch_in_dbm[from_degree] - self.ref_pch_out_dbm input_power = spectral_info.signal + spectral_info.nli + spectral_info.ase target_power_per_channel = per_degree_pch + spectral_info.delta_pdb_per_channel # Computation of the per channel target power according to equalization policy @@ -415,8 +416,8 @@ def update_pref(self, spectral_info): """ spectral_info.pref = spectral_info.pref._replace(p_spani=self.ref_pch_out_dbm) - def __call__(self, spectral_info, degree): - self.propagate(spectral_info, degree=degree) + def __call__(self, spectral_info, degree, from_degree): + self.propagate(spectral_info, degree=degree, from_degree=from_degree) self.update_pref(spectral_info) return spectral_info diff --git a/gnpy/core/network.py b/gnpy/core/network.py index 83cc59c9e..1f5ca27ec 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -14,7 +14,7 @@ from gnpy.core import elements from gnpy.core.exceptions import ConfigurationError, NetworkTopologyError -from gnpy.core.utils import round2float, convert_length +from gnpy.core.utils import round2float, convert_length, psd2powerdbm from gnpy.core.info import ReferenceCarrier from gnpy.tools.json_io import Amp @@ -352,9 +352,72 @@ def set_roadm_per_degree_targets(roadm, network): raise ConfigurationError(roadm.uid, 'needs an equalization target') +def set_roadm_input_powers(network, roadm, equipment, pref_ch_db): + """Set reference powers at ROADM input for a reference channel and based on the adjacent OMS. + This supposes that there is no dependency on path. For example, the succession: + node power out of element + roadm A (target power -10dBm) -10dBm + fiber A (16 dB loss) -26dBm + roadm B (target power -12dBm) -26dBm + fiber B (10 dB loss) -36dBm + roadm C (target power -14dBm) -36dBm + is not consistent because target powers in roadm B and roadm C can not be met. + input power for the reference channel will be set -26 dBm in roadm B and -22dBm in roadm C, + because at design time we can not know about path. + The function raises a warning if target powers can not be met with the design. + User should be aware that design was not successfull and that power reduction was applied. + Note that this value is only used for visualisation purpose (to compute ROADM loss in elements). + """ + ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, + slot_width=equipment['SI']['default'].spacing) + previous_elements = [n for n in network.predecessors(roadm)] + roadm.ref_pch_in_dbm = {} + for element in previous_elements: + node = element + loss = 0.0 + while isinstance(node, (elements.Fiber, elements.Fused, elements.RamanFiber)): + # go through all predecessors until a power target is found either in an amplifier, a ROADM or a transceiver + # then deduce power at ROADM input from this degree based on this target and crossed losses + loss += node.loss + previous_node = node + node = next(network.predecessors(node)) + if isinstance(node, elements.Edfa): + roadm.ref_pch_in_dbm[element.uid] = pref_ch_db + node._delta_p - node.out_voa - loss + elif isinstance(node, elements.Roadm): + roadm.ref_pch_in_dbm[element.uid] = \ + node.get_per_degree_ref_power(degree=previous_node.uid, ref_carrier=ref_carrier) - loss + elif isinstance(node, elements.Transceiver): + roadm.ref_pch_in_dbm[element.uid] = pref_ch_db - loss + # check if target power can be met + temp = [] + if roadm.per_degree_pch_out_dbm: + temp.append(max([p for p in roadm.per_degree_pch_out_dbm.values()])) + if roadm.per_degree_pch_psd: + temp.append(max([psd2powerdbm(p, ref_carrier.baud_rate) for p in roadm.per_degree_pch_psd.values()])) + if roadm.per_degree_pch_psw: + temp.append(max([psd2powerdbm(p, ref_carrier.slot_width) for p in roadm.per_degree_pch_psw.values()])) + if roadm.params.target_pch_out_db: + temp.append(roadm.params.target_pch_out_db) + if roadm.params.target_psd_out_mWperGHz: + temp.append(psd2powerdbm(roadm.params.target_psd_out_mWperGHz, ref_carrier.baud_rate)) + if roadm.params.target_out_mWperSlotWidth: + temp.append(psd2powerdbm(roadm.params.target_out_mWperSlotWidth, ref_carrier.slot_width)) + if not temp: + raise ConfigurationError(f'Could not find target power/PSD/PSW in ROADM "{roadm.uid}"') + target_to_be_supported = max(temp) + for from_degree, in_power in roadm.ref_pch_in_dbm.items(): + if in_power < target_to_be_supported: + logger.warning( + f'WARNING: maximum target power {target_to_be_supported}dBm ' + + f'in ROADM "{roadm.uid}" can not be met for at least one crossing path. Min input power ' + + f'from "{from_degree}" direction is {round(in_power, 2)}dBm. Please correct input topology.' + ) + + def add_roadm_booster(network, roadm): next_nodes = [n for n in network.successors(roadm) - if not (isinstance(n, elements.Transceiver) or isinstance(n, elements.Fused) or isinstance(n, elements.Edfa))] + if not (isinstance(n, elements.Transceiver) or isinstance(n, elements.Fused) + or isinstance(n, elements.Edfa))] # no amplification for fused spans or TRX for next_node in next_nodes: network.remove_edge(roadm, next_node) @@ -564,6 +627,8 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, no_insert_edfas for roadm in roadms: set_roadm_per_degree_targets(roadm, network) set_egress_amplifier(network, roadm, equipment, pref_ch_db, pref_total_db) + for roadm in roadms: + set_roadm_input_powers(network, roadm, equipment, pref_ch_db) trx = [t for t in network.nodes() if isinstance(t, elements.Transceiver)] for t in trx: diff --git a/gnpy/topology/request.py b/gnpy/topology/request.py index bda43a30f..15595390c 100644 --- a/gnpy/topology/request.py +++ b/gnpy/topology/request.py @@ -350,7 +350,7 @@ def propagate(path, req, equipment): ref_carrier=ref_carrier(equipment)) for i, el in enumerate(path): if isinstance(el, Roadm): - si = el(si, degree=path[i+1].uid) + si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid) else: si = el(si) path[0].update_snr(si.tx_osnr) @@ -395,7 +395,7 @@ def propagate_and_optimize_mode(path, req, equipment): tx_osnr=req.tx_osnr, ref_carrier=ref_carrier(equipment)) for i, el in enumerate(path): if isinstance(el, Roadm): - spc_info = el(spc_info, degree=path[i+1].uid) + spc_info = el(spc_info, degree=path[i + 1].uid, from_degree=path[i - 1].uid) else: spc_info = el(spc_info) for this_mode in modes_to_explore: diff --git a/tests/invocation/transmission_saturated b/tests/invocation/transmission_saturated index 407842d77..b1317759d 100644 --- a/tests/invocation/transmission_saturated +++ b/tests/invocation/transmission_saturated @@ -80,7 +80,7 @@ Edfa west edfa in Lorient_KMA to Loudeac actual pch out (dBm): 1.21 output VOA (dB): 0.00 Roadm roadm Lorient_KMA - effective loss (dB): 21.17 + effective loss (dB): 21.18 reference pch out (dBm): -20.00 actual pch out (dBm): -20.00 Transceiver trx Lorient_KMA diff --git a/tests/test_equalization.py b/tests/test_equalization.py index 4e8061b86..f4aef415a 100644 --- a/tests/test_equalization.py +++ b/tests/test_equalization.py @@ -73,6 +73,7 @@ def test_equalization_combination_degree(delta_pdb_per_channel, degree, equaliza } } roadm = Roadm(**roadm_config) + roadm.ref_pch_in_dbm['tata'] = 0 frequency = 191e12 + array([0, 50e9, 150e9, 225e9, 275e9]) slot_width = array([37.5e9, 50e9, 75e9, 50e9, 37.5e9]) baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) @@ -98,7 +99,7 @@ def test_equalization_combination_degree(delta_pdb_per_channel, degree, equaliza 'metadata': {'location': {'latitude': 0, 'longitude': 0, 'city': None, 'region': None}} } assert roadm.to_json == to_json_before_propagation - si = roadm(si, degree) + si = roadm(si, degree=degree, from_degree='tata') assert roadm.ref_pch_out_dbm == pytest.approx(expected_pch_out_dbm, rel=1e-4) assert_allclose(expected_si, roadm.get_per_degree_power(degree, spectral_info=si), rtol=1e-3) @@ -244,7 +245,8 @@ def test_low_input_power(target_out, delta_pdb_per_channel, correction): } } roadm = Roadm(**roadm_config) - si = roadm(si, 'toto') + roadm.ref_pch_in_dbm['tata'] = 0 + si = roadm(si, degree='toto', from_degree='tata') assert_allclose(watt2dbm(si.signal), target - correction, rtol=1e-5) # in other words check that if target is below input power, target is applied else power is unchanged assert_allclose((watt2dbm(signal) >= target) * target + (watt2dbm(signal) < target) * watt2dbm(signal), @@ -296,7 +298,8 @@ def test_2low_input_power(target_out, delta_pdb_per_channel, correction): } } roadm = Roadm(**roadm_config) - si = roadm(si, 'toto') + roadm.ref_pch_in_dbm['tata'] = 0 + si = roadm(si, degree='toto', from_degree='tata') assert_allclose(watt2dbm(si.signal), target - correction, rtol=1e-5) @@ -537,7 +540,7 @@ def test_equalization(case, deltap, target, mode, slot_width, equalization): spacing=req.spacing, tx_osnr=req.tx_osnr, ref_carrier=ref) for i, el in enumerate(path): if isinstance(el, Roadm): - si = el(si, degree=path[i + 1].uid) + si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid) if case in ['SI', 'nodes', 'degrees']: if equalization == 'target_psd_out_mWperGHz': assert_allclose(power_dbm_to_psd_mw_ghz(watt2dbm(si.signal + si.ase + si.nli), si.baud_rate), diff --git a/tests/test_roadm_restrictions.py b/tests/test_roadm_restrictions.py index 7f6a6470e..3b5736b68 100644 --- a/tests/test_roadm_restrictions.py +++ b/tests/test_roadm_restrictions.py @@ -262,7 +262,7 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm): for i, el in enumerate(path): if isinstance(el, Roadm): power_in_roadm = si.signal + si.ase + si.nli - si = el(si, degree=path[i + 1].uid) + si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid) power_out_roadm = si.signal + si.ase + si.nli if el.uid == 'roadm node B': # if previous was an EDFA, power level at ROADM input is enough for the ROADM to apply its From 2f2920a71667bcd34926722957180de632f0cb89 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 15:54:47 +0200 Subject: [PATCH 08/20] Computes reference input power in fiber during design input power is computed at design time: so let's record it and use it instead of p_span_i for reference channel fiber loss computation. Note that this loss parameter is only used for visualisation purpose. Signed-off-by: EstherLerouzic Change-Id: I16bd792bd6079ce521aafadcf5e21922aa3b4c81 --- gnpy/core/elements.py | 7 ++++++ gnpy/core/network.py | 44 +++++++++++++++++++++++++++++++------ tests/test_amplifier.py | 1 + tests/test_science_utils.py | 4 ++-- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 9693e1e1a..a7131a357 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -483,6 +483,7 @@ def __init__(self, *args, params=None, **kwargs): f"({1e-3 * self.params.length} km), boundaries excluded.") self.lumped_losses = db2lin(- lumped_losses_power) # [linear units] self.z_lumped_losses = array(z_lumped_losses) * 1e3 # [m] + self.ref_pch_in_dbm = None @property def to_json(self): @@ -691,6 +692,12 @@ def __call__(self, spectral_info): self._psig_in = sum(spectral_info.signal) self.propagate(spectral_info) self.update_pref(spectral_info) + # In case of Raman, the resulting loss of the fiber is not equivalent to self.loss + # because of Raman gain. The resulting loss is: + # power_out - power_in. We use the total signal power (sum on all channels) to compute + # this loss. + loss = round(lin2db(self._psig_in / sum(spectral_info.signal)), 2) + self.pch_out_db = self.ref_pch_in_dbm - loss return spectral_info diff --git a/gnpy/core/network.py b/gnpy/core/network.py index 1f5ca27ec..e6efb623e 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -414,6 +414,33 @@ def set_roadm_input_powers(network, roadm, equipment, pref_ch_db): ) +def set_fiber_input_power(network, fiber, equipment, pref_ch_db): + """Set reference powers at fiber input for a reference channel. + Supposes that target power out of ROADMs and amplifiers are consistent. + This is only for visualisation purpose + """ + ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, + slot_width=equipment['SI']['default'].spacing) + loss = 0.0 + node = next(network.predecessors(fiber)) + while isinstance(node, elements.Fused): + loss += node.loss + previous_node = node + node = next(network.predecessors(node)) + if isinstance(node, (elements.Fiber, elements.RamanFiber)) and node.ref_pch_in_dbm is not None: + fiber.ref_pch_in_dbm = node.ref_pch_in_dbm - loss - node.loss + if isinstance(node, (elements.Fiber, elements.RamanFiber)) and node.ref_pch_in_dbm is None: + set_fiber_input_power(network, node, equipment, pref_ch_db) + fiber.ref_pch_in_dbm = node.ref_pch_in_dbm - loss - node.loss + elif isinstance(node, elements.Roadm): + fiber.ref_pch_in_dbm = \ + node.get_per_degree_ref_power(degree=previous_node.uid, ref_carrier=ref_carrier) - loss + elif isinstance(node, elements.Edfa): + fiber.ref_pch_in_dbm = pref_ch_db + node._delta_p - node.out_voa - loss + elif isinstance(node, elements.Transceiver): + fiber.ref_pch_in_dbm = pref_ch_db - loss + + def add_roadm_booster(network, roadm): next_nodes = [n for n in network.successors(roadm) if not (isinstance(n, elements.Transceiver) or isinstance(n, elements.Fused) @@ -609,7 +636,7 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, no_insert_edfas # =>for code clarity (at the expense of speed): roadms = [r for r in network.nodes() if isinstance(r, elements.Roadm)] - + transceivers = [t for t in network.nodes() if isinstance(t, elements.Transceiver)] if not no_insert_edfas: for fiber in fibers: split_fiber(network, fiber, bounds, target_length, equipment) @@ -626,12 +653,15 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, no_insert_edfas for roadm in roadms: set_roadm_per_degree_targets(roadm, network) + for roadm in roadms + transceivers: set_egress_amplifier(network, roadm, equipment, pref_ch_db, pref_total_db) for roadm in roadms: set_roadm_input_powers(network, roadm, equipment, pref_ch_db) - - trx = [t for t in network.nodes() if isinstance(t, elements.Transceiver)] - for t in trx: - next_node = next(network.successors(t), None) - if next_node and not isinstance(next_node, elements.Roadm): - set_egress_amplifier(network, t, equipment, 0, pref_total_db) + for fiber in [f for f in network.nodes() if isinstance(f, (elements.Fiber, elements.RamanFiber))]: + set_fiber_input_power(network, fiber, equipment, pref_ch_db) + + # trx = [t for t in network.nodes() if isinstance(t, elements.Transceiver)] + # for t in trx: + # next_node = next(network.successors(t), None) + # if next_node and not isinstance(next_node, elements.Roadm): + # set_egress_amplifier(network, t, equipment, 0, pref_total_db) diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index e24735ebb..1d4d4aba6 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -234,6 +234,7 @@ def test_amp_behaviour(tilt_target, delta_p): fiber = [n for n in network.nodes() if isinstance(n, Fiber)][0] fiber.params.con_in = 0 fiber.params.con_out = 0 + fiber.ref_pch_in_dbm = 0.0 si = create_input_spectral_information(f_min=191.3e12, f_max=196.05e12, roll_off=0.15, baud_rate=64e9, power=0.001, spacing=75e9, tx_osnr=None) si = fiber(si) diff --git a/tests/test_science_utils.py b/tests/test_science_utils.py index 65b41b35c..b65e0dad0 100644 --- a/tests/test_science_utils.py +++ b/tests/test_science_utils.py @@ -26,7 +26,7 @@ def test_fiber(): """Test the accuracy of propagating the Fiber.""" fiber = Fiber(**load_json(TEST_DIR / 'data' / 'test_science_utils_fiber_config.json')) - + fiber.ref_pch_in_dbm = 0.0 # fix grid spectral information generation spectral_info_input = create_input_spectral_information(f_min=191.3e12, f_max=196.1e12, roll_off=0.15, baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0, @@ -74,7 +74,7 @@ def test_raman_fiber(): ref_carrier=ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) SimParams.set_params(load_json(TEST_DIR / 'data' / 'sim_params.json')) fiber = RamanFiber(**load_json(TEST_DIR / 'data' / 'test_science_utils_fiber_config.json')) - + fiber.ref_pch_in_dbm = 0.0 # propagation spectral_info_out = fiber(spectral_info_input) From 6ac3a517cf4b470b4b3bb414051a312279949ab0 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 16:22:05 +0200 Subject: [PATCH 09/20] refactor build_network: create a separate function to add elements separate function that adds element, from function that configure them Signed-off-by: EstherLerouzic Change-Id: Ica332223bdf7fc599cb007d7513d7cd62d9c5f9c --- gnpy/core/network.py | 81 ++++++++++++++++++++++---------------- gnpy/tools/cli_examples.py | 29 ++++++++++++-- tests/test_parser.py | 3 +- 3 files changed, 73 insertions(+), 40 deletions(-) diff --git a/gnpy/core/network.py b/gnpy/core/network.py index e6efb623e..fb85b8f0d 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -245,13 +245,11 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d visited_nodes = [] while not (isinstance(node, elements.Roadm) or isinstance(node, elements.Transceiver)): # go through all nodes in the OMS (loop until next Roadm instance) - try: - next_node = next(network.successors(node)) - except StopIteration: - raise NetworkTopologyError(f'{type(node).__name__} {node.uid} is not properly connected, please check network topology') + next_node = get_next_node(node, network) visited_nodes.append(node) if next_node in visited_nodes: - raise NetworkTopologyError(f'Loop detected for {type(node).__name__} {node.uid}, please check network topology') + raise NetworkTopologyError(f'Loop detected for {type(node).__name__} {node.uid}, ' + + 'please check network topology') if isinstance(node, elements.Edfa): node_loss = span_loss(network, prev_node) voa = node.out_voa if node.out_voa else 0 @@ -499,7 +497,7 @@ def add_roadm_preamp(network, roadm): def add_inline_amplifier(network, fiber): - next_node = next(network.successors(fiber)) + next_node = get_next_node(fiber, network) if isinstance(next_node, elements.Fiber) or isinstance(next_node, elements.RamanFiber): # no amplification for fused spans or TRX network.remove_edge(fiber, next_node) @@ -543,6 +541,17 @@ def calculate_new_length(fiber_length, bounds, target_length): return (length1, n_spans1) +def get_next_node(node, network): + """get_next node else raise tha appropriate error + """ + try: + next_node = next(network.successors(node)) + return next_node + except StopIteration: + raise NetworkTopologyError( + f'{type(node).__name__} {node.uid} is not properly connected, please check network topology') + + def split_fiber(network, fiber, bounds, target_length, equipment): new_length, n_spans = calculate_new_length(fiber.params.length, bounds, target_length) if n_spans == 1: @@ -587,10 +596,7 @@ def split_fiber(network, fiber, bounds, target_length, equipment): def add_connector_loss(network, fibers, default_con_in, default_con_out, EOL): for fiber in fibers: - try: - next_node = next(network.successors(fiber)) - except StopIteration: - raise NetworkTopologyError(f'Fiber {fiber.uid} is not properly connected, please check network topology') + next_node = get_next_node(fiber, network) if fiber.params.con_in is None: fiber.params.con_in = default_con_in if fiber.params.con_out is None: @@ -605,10 +611,7 @@ def add_fiber_padding(network, fibers, padding): for fiber in network.predecessors(n) if isinstance(fiber, elements.Fiber))""" for fiber in fibers: - try: - next_node = next(network.successors(fiber)) - except StopIteration: - raise NetworkTopologyError(f'Fiber {fiber.uid} is not properly connected, please check network topology') + next_node = get_next_node(fiber, network) if isinstance(next_node, elements.Fused): continue this_span_loss = span_loss(network, fiber) @@ -622,46 +625,54 @@ def add_fiber_padding(network, fibers, padding): first_fiber.params.att_in = first_fiber.params.att_in + padding - this_span_loss -def build_network(network, equipment, pref_ch_db, pref_total_db, no_insert_edfas=False): +def add_missing_elements_in_network(network, equipment): + """Autodesign network: add missing elements. split fibers if their length is too big + add ROADM preamp or booster and inline amplifiers between fibers + """ default_span_data = equipment['Span']['default'] max_length = int(convert_length(default_span_data.max_length, default_span_data.length_units)) min_length = max(int(default_span_data.padding / 0.2 * 1e3), 50_000) bounds = range(min_length, max_length) target_length = max(min_length, min(max_length, 90_000)) + fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] + for fiber in fibers: + split_fiber(network, fiber, bounds, target_length, equipment) + roadms = [r for r in network.nodes() if isinstance(r, elements.Roadm)] + for roadm in roadms: + add_roadm_preamp(network, roadm) + add_roadm_booster(network, roadm) + fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] + for fiber in fibers: + add_inline_amplifier(network, fiber) + - # set roadm loss for gain_mode before to build network +def add_missing_fiber_attributes(network, equipment): + """Fill in connector loss with default values. Add the padding loss is required. + EOL is added as a connector loss + """ + default_span_data = equipment['Span']['default'] fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] add_connector_loss(network, fibers, default_span_data.con_in, default_span_data.con_out, default_span_data.EOL) # don't group split fiber and add amp in the same loop # =>for code clarity (at the expense of speed): + add_fiber_padding(network, fibers, default_span_data.padding) + +def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_losses=True): + """Set roadm equalization target and amplifier gain and power + """ roadms = [r for r in network.nodes() if isinstance(r, elements.Roadm)] transceivers = [t for t in network.nodes() if isinstance(t, elements.Transceiver)] - if not no_insert_edfas: - for fiber in fibers: - split_fiber(network, fiber, bounds, target_length, equipment) - - for roadm in roadms: - add_roadm_preamp(network, roadm) - add_roadm_booster(network, roadm) - - fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] - for fiber in fibers: - add_inline_amplifier(network, fiber) - - add_fiber_padding(network, fibers, default_span_data.padding) + if set_connector_losses: + add_missing_fiber_attributes(network, equipment) + # set roadm equalization targets first for roadm in roadms: set_roadm_per_degree_targets(roadm, network) + # then set amplifiers gain, delta_p and out_voa on each OMS for roadm in roadms + transceivers: set_egress_amplifier(network, roadm, equipment, pref_ch_db, pref_total_db) for roadm in roadms: set_roadm_input_powers(network, roadm, equipment, pref_ch_db) for fiber in [f for f in network.nodes() if isinstance(f, (elements.Fiber, elements.RamanFiber))]: set_fiber_input_power(network, fiber, equipment, pref_ch_db) - - # trx = [t for t in network.nodes() if isinstance(t, elements.Transceiver)] - # for t in trx: - # next_node = next(network.successors(t), None) - # if next_node and not isinstance(next_node, elements.Roadm): - # set_egress_amplifier(network, t, equipment, 0, pref_total_db) diff --git a/gnpy/tools/cli_examples.py b/gnpy/tools/cli_examples.py index ffac2bb45..2f244ff2b 100644 --- a/gnpy/tools/cli_examples.py +++ b/gnpy/tools/cli_examples.py @@ -19,7 +19,7 @@ from gnpy.core.elements import Transceiver, Fiber, RamanFiber from gnpy.core.equipment import trx_mode_params import gnpy.core.exceptions as exceptions -from gnpy.core.network import build_network +from gnpy.core.network import build_network, add_missing_elements_in_network from gnpy.core.parameters import SimParams from gnpy.core.utils import db2lin, lin2db, automatic_nch from gnpy.topology.request import (ResultElement, jsontocsv, compute_path_dsjctn, requests_aggregation, @@ -208,19 +208,29 @@ def transmission_main_example(args=None): print(f'There are {nb_channels} channels propagating') power_mode = equipment['Span']['default'].power_mode print('\n'.join([f'Power mode is set to {power_mode}', - f'=> it can be modified in eqpt_config.json - Span'])) + '=> it can be modified in eqpt_config.json - Span'])) + if not args.no_insert_edfas: + try: + add_missing_elements_in_network(network, equipment) + except exceptions.NetworkTopologyError as e: + print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') + sys.exit(1) + except exceptions.ConfigurationError as e: + print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') + sys.exit(1) # Keep the reference channel for design: the one from SI, with full load same channels pref_ch_db = lin2db(req.power * 1e3) # reference channel power / span (SL=20dB) pref_total_db = pref_ch_db + lin2db(req.nb_channel) # reference total power / span (SL=20dB) try: - build_network(network, equipment, pref_ch_db, pref_total_db, args.no_insert_edfas) + build_network(network, equipment, pref_ch_db, pref_total_db) except exceptions.NetworkTopologyError as e: print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') sys.exit(1) except exceptions.ConfigurationError as e: print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') sys.exit(1) + path = compute_constrained_path(network, req) spans = [s.params.length for s in path if isinstance(s, RamanFiber) or isinstance(s, Fiber)] @@ -330,17 +340,28 @@ def path_requests_run(args=None): # Build the network once using the default power defined in SI in eqpt config # TODO power density: db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by # spacing, f_min and f_max + if not args.no_insert_edfas: + try: + add_missing_elements_in_network(network, equipment) + except exceptions.NetworkTopologyError as e: + print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') + sys.exit(1) + except exceptions.ConfigurationError as e: + print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') + sys.exit(1) + p_db = equipment['SI']['default'].power_dbm p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min, equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) try: - build_network(network, equipment, p_db, p_total_db, args.no_insert_edfas) + build_network(network, equipment, p_db, p_total_db) except exceptions.NetworkTopologyError as e: print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') sys.exit(1) except exceptions.ConfigurationError as e: print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') sys.exit(1) + if args.save_network is not None: save_network(network, args.save_network) print(f'{ansi_escapes.blue}Network (after autodesign) saved to {args.save_network}{ansi_escapes.reset}') diff --git a/tests/test_parser.py b/tests/test_parser.py index 02d41c0e1..16298898e 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -24,7 +24,7 @@ import pytest from copy import deepcopy from gnpy.core.utils import automatic_nch, lin2db -from gnpy.core.network import build_network +from gnpy.core.network import build_network, add_missing_elements_in_network from gnpy.core.exceptions import ServiceError from gnpy.topology.request import (jsontocsv, requests_aggregation, compute_path_dsjctn, deduplicate_disjunctions, compute_path_with_disjunction, ResultElement, PathRequest) @@ -71,6 +71,7 @@ def test_auto_design_generation_fromxlsgainmode(tmpdir, xls_input, expected_json """tests generation of topology json and that the build network gives correct results in gain mode""" equipment = load_equipment(eqpt_filename) network = load_network(xls_input, equipment) + add_missing_elements_in_network(network, equipment) # in order to test the Eqpt sheet and load gain target, # change the power-mode to False (to be in gain mode) equipment['Span']['default'].power_mode = False From b45829d2dfa94256a9b5bd22b534dc5854fd51bf Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 16:40:22 +0200 Subject: [PATCH 10/20] Parametrize verbose in autodesign transmission-main-example and path-request-run functions implement an on-the-fly redesign based on p_span_i. Since we remove p_span_i from elements, we will need to properly call redesign several times before each propagation, to keep the same behaviour of these functions. in this commit we simply enable the possibility to mute warnings. Signed-off-by: EstherLerouzic Change-Id: I3aa3d8fc87325033ef69641078bdd7213e0409eb --- gnpy/core/network.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/gnpy/core/network.py b/gnpy/core/network.py index fb85b8f0d..cd3914982 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -38,7 +38,7 @@ def edfa_nf(gain_target, variety_type, equipment): return amp._calc_nf(True) -def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restrictions=None): +def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restrictions=None, verbose=True): """amplifer selection algorithm @Orange Jean-Luc Augé """ @@ -96,9 +96,10 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restri please increase span fiber padding') else: # TODO: convert to logging - logger.warning(f'\n\tWARNING: target gain in node {uid} is below all available amplifiers min gain: ' - + '\n\tamplifier input padding will be assumed, consider increase span fiber padding ' - + 'instead.\n') + if verbose: + logger.warning(f'\n\tWARNING: target gain in node {uid} is below all available amplifiers min gain: ' + + '\n\tamplifier input padding will be assumed, consider increase span fiber padding ' + + 'instead.\n') acceptable_gain_min_list = edfa_list # filter on gain+power limitation: @@ -119,7 +120,7 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restri selected_edfa = min(acceptable_power_list, key=attrgetter('nf')) # filter on NF # check what are the gain and power limitations of this amp power_reduction = min(selected_edfa.power, 0) - if power_reduction < -0.5: + if power_reduction < -0.5 and verbose: logger.warning(f'\n\tWARNING: target gain and power in node {uid}\n' + '\tis beyond all available amplifiers capabilities and/or extended_gain_range:\n' + f'\ta power reduction of {round(power_reduction, 2)} is applied\n') @@ -222,7 +223,7 @@ def set_amplifier_voa(amp, power_target, power_mode): amp.out_voa = voa -def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_db): +def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_db, verbose): """this node can be a transceiver or a ROADM (same function called in both cases)""" power_mode = equipment['Span']['default'].power_mode ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, @@ -283,7 +284,8 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d restrictions = next_node.restrictions['preamp_variety_list'] else: restrictions = None - edfa_variety, power_reduction = select_edfa(raman_allowed, gain_target, power_target, equipment, node.uid, restrictions) + edfa_variety, power_reduction = select_edfa(raman_allowed, gain_target, power_target, equipment, + node.uid, restrictions, verbose) extra_params = equipment['Edfa'][edfa_variety] node.params.update_params(extra_params.__dict__) dp += power_reduction @@ -308,7 +310,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d # if variety is imposed by user, and if the gain_target (computed or imposed) is also above # variety max gain + extended range, then warn that gain > max_gain + extended range if gain_target - equipment['Edfa'][node.params.type_variety].gain_flatmax - \ - equipment['Span']['default'].target_extended_gain > 1e-2: + equipment['Span']['default'].target_extended_gain > 1e-2 and verbose: # 1e-2 to allow a small margin according to round2float min step logger.warning(f'\n\tWARNING: effective gain in Node {node.uid}\n' + f'\tis above user specified amplifier {node.params.type_variety}\n' @@ -658,7 +660,7 @@ def add_missing_fiber_attributes(network, equipment): add_fiber_padding(network, fibers, default_span_data.padding) -def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_losses=True): +def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_losses=True, verbose=True): """Set roadm equalization target and amplifier gain and power """ roadms = [r for r in network.nodes() if isinstance(r, elements.Roadm)] @@ -671,7 +673,7 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_l set_roadm_per_degree_targets(roadm, network) # then set amplifiers gain, delta_p and out_voa on each OMS for roadm in roadms + transceivers: - set_egress_amplifier(network, roadm, equipment, pref_ch_db, pref_total_db) + set_egress_amplifier(network, roadm, equipment, pref_ch_db, pref_total_db, verbose) for roadm in roadms: set_roadm_input_powers(network, roadm, equipment, pref_ch_db) for fiber in [f for f in network.nodes() if isinstance(f, (elements.Fiber, elements.RamanFiber))]: From 8ea13bb4d6e09c19a935647bab2d8bff6ccdf45d Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 17:30:57 +0200 Subject: [PATCH 11/20] refactor cli to use a common design function Signed-off-by: EstherLerouzic Change-Id: I029d8c7fc29b1e86e1e3b2b64933bae5da134226 --- gnpy/core/network.py | 11 +++++++- gnpy/tools/cli_examples.py | 57 +++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/gnpy/core/network.py b/gnpy/core/network.py index cd3914982..660789de1 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -14,7 +14,7 @@ from gnpy.core import elements from gnpy.core.exceptions import ConfigurationError, NetworkTopologyError -from gnpy.core.utils import round2float, convert_length, psd2powerdbm +from gnpy.core.utils import round2float, convert_length, psd2powerdbm, lin2db, watt2dbm from gnpy.core.info import ReferenceCarrier from gnpy.tools.json_io import Amp @@ -678,3 +678,12 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_l set_roadm_input_powers(network, roadm, equipment, pref_ch_db) for fiber in [f for f in network.nodes() if isinstance(f, (elements.Fiber, elements.RamanFiber))]: set_fiber_input_power(network, fiber, equipment, pref_ch_db) + + +def design_network(reference_channel, network, equipment, verbose=True): + """Network is designed according to reference channel. Verbose indicate if the function should + print all warnings or not + """ + pref_ch_db = watt2dbm(reference_channel.power) # reference channel power + pref_total_db = pref_ch_db + lin2db(reference_channel.nb_channel) # reference total power + build_network(network, equipment, pref_ch_db, pref_total_db, verbose) diff --git a/gnpy/tools/cli_examples.py b/gnpy/tools/cli_examples.py index 2f244ff2b..23961d1db 100644 --- a/gnpy/tools/cli_examples.py +++ b/gnpy/tools/cli_examples.py @@ -19,7 +19,7 @@ from gnpy.core.elements import Transceiver, Fiber, RamanFiber from gnpy.core.equipment import trx_mode_params import gnpy.core.exceptions as exceptions -from gnpy.core.network import build_network, add_missing_elements_in_network +from gnpy.core.network import add_missing_elements_in_network, design_network from gnpy.core.parameters import SimParams from gnpy.core.utils import db2lin, lin2db, automatic_nch from gnpy.topology.request import (ResultElement, jsontocsv, compute_path_dsjctn, requests_aggregation, @@ -204,6 +204,7 @@ def transmission_main_example(args=None): print('User input for spectrum used for propagation instead of SI') params['nb_channel'] = nb_channels req = PathRequest(**params) + pref_ch_db = lin2db(req.power * 1e3) # reference channel power / span (SL=20dB) req.initial_spectrum = initial_spectrum print(f'There are {nb_channels} channels propagating') power_mode = equipment['Span']['default'].power_mode @@ -219,25 +220,8 @@ def transmission_main_example(args=None): print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') sys.exit(1) - # Keep the reference channel for design: the one from SI, with full load same channels - pref_ch_db = lin2db(req.power * 1e3) # reference channel power / span (SL=20dB) - pref_total_db = pref_ch_db + lin2db(req.nb_channel) # reference total power / span (SL=20dB) - try: - build_network(network, equipment, pref_ch_db, pref_total_db) - except exceptions.NetworkTopologyError as e: - print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') - sys.exit(1) - except exceptions.ConfigurationError as e: - print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') - sys.exit(1) - path = compute_constrained_path(network, req) - spans = [s.params.length for s in path if isinstance(s, RamanFiber) or isinstance(s, Fiber)] - print(f'\nThere are {len(spans)} fiber spans over {sum(spans)/1000:.0f} km between {source.uid} ' - f'and {destination.uid}') - print(f'\nNow propagating between {source.uid} and {destination.uid}:') - power_range = [0] if power_mode: # power cannot be changed in gain mode @@ -247,6 +231,20 @@ def transmission_main_example(args=None): power_range = list(linspace(p_start, p_stop, p_num)) except TypeError: print('invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]') + # initial network is designed using req.power. that is that any missing information (amp gain or delta_p) is filled + # using this req.power, previous to any sweep requested later on. + try: + design_network(req, network, equipment, verbose=True) + except exceptions.NetworkTopologyError as e: + print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') + sys.exit(1) + except exceptions.ConfigurationError as e: + print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') + sys.exit(1) + + print(f'\nThere are {len(spans)} fiber spans over {sum(spans)/1000:.0f} km between {source.uid} ' + f'and {destination.uid}') + print(f'\nNow propagating between {source.uid} and {destination.uid}:') for dp_db in power_range: req.power = db2lin(pref_ch_db + dp_db) * 1e-3 # if initial spectrum did not contain any power, now we need to use this one. @@ -350,11 +348,26 @@ def path_requests_run(args=None): print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {e}') sys.exit(1) - p_db = equipment['SI']['default'].power_dbm - p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min, - equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) + params = { + 'request_id': 'reference', + 'trx_type': '', + 'trx_mode': '', + 'source': None, + 'destination': None, + 'bidir': False, + 'nodes_list': [], + 'loose_list': [], + 'format': '', + 'path_bandwidth': 0, + 'effective_freq_slot': None, + 'nb_channel': automatic_nch(equipment['SI']['default'].f_min, equipment['SI']['default'].f_max, + equipment['SI']['default'].spacing) + } + trx_params = trx_mode_params(equipment) + params.update(trx_params) + reference_channel = PathRequest(**params) try: - build_network(network, equipment, p_db, p_total_db) + design_network(reference_channel, network, equipment, verbose=True) except exceptions.NetworkTopologyError as e: print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') sys.exit(1) From e9f9ddb4d6e6d323226c86476bff3d87a35cb5f7 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 17:38:38 +0200 Subject: [PATCH 12/20] restore initial power sweep behaviour if user define a delta_p that is reduced because of saturation, then this initial setting is still kept for power sweep to be sure that the full amplitude of sweep is used. SI power = 0 dBm max power amp1 = 20 dBm, user_defined_delta_p set by user = 3 80 channels, so pch_max = 20 - 10log10(80) = 0.96 dBm power_sweep -> power range [-3, 0] dBm then for initial design, pref = 0 dBm computed_delta_p = min(pch_max, pref + user_defined_delta_p) - pref = 0.96 but for -3 power sweep pref = -3 dBm computed_delta_p = min(pch_max, pref + user_defined_delta_p) - pref = min(0.96, -3 + 3) - (-3) = 3 so the user defined delta_p is applied as much as possible Signed-off-by: EstherLerouzic Change-Id: I8fd459c29aa9754ff9d4868af1d8be8642a31913 --- gnpy/core/network.py | 9 +- gnpy/tools/cli_examples.py | 27 +- tests/data/eqpt_config_sweep.json | 238 +++++++++++++++++ tests/invocation/logs_power_sweep_example | 307 ++++++++++++++++++++++ tests/invocation/power_sweep_example | 154 +++++++++++ tests/test_invocation.py | 2 + 6 files changed, 724 insertions(+), 13 deletions(-) create mode 100644 tests/data/eqpt_config_sweep.json create mode 100644 tests/invocation/logs_power_sweep_example create mode 100644 tests/invocation/power_sweep_example diff --git a/gnpy/core/network.py b/gnpy/core/network.py index 660789de1..46a42d4b9 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -254,10 +254,10 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d if isinstance(node, elements.Edfa): node_loss = span_loss(network, prev_node) voa = node.out_voa if node.out_voa else 0 - if node.delta_p is None: + if node.operational.delta_p is None: dp = target_power(network, next_node, equipment) + voa else: - dp = node.delta_p + dp = node.operational.delta_p if node.effective_gain is None or power_mode: gain_target = node_loss + dp - prev_dp + prev_voa else: # gain mode with effective_gain @@ -680,10 +680,11 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_l set_fiber_input_power(network, fiber, equipment, pref_ch_db) -def design_network(reference_channel, network, equipment, verbose=True): +def design_network(reference_channel, network, equipment, set_connector_losses=True, verbose=True): """Network is designed according to reference channel. Verbose indicate if the function should print all warnings or not """ pref_ch_db = watt2dbm(reference_channel.power) # reference channel power pref_total_db = pref_ch_db + lin2db(reference_channel.nb_channel) # reference total power - build_network(network, equipment, pref_ch_db, pref_total_db, verbose) + build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_losses=set_connector_losses, + verbose=verbose) diff --git a/gnpy/tools/cli_examples.py b/gnpy/tools/cli_examples.py index 23961d1db..2ae7c18f4 100644 --- a/gnpy/tools/cli_examples.py +++ b/gnpy/tools/cli_examples.py @@ -21,7 +21,7 @@ import gnpy.core.exceptions as exceptions from gnpy.core.network import add_missing_elements_in_network, design_network from gnpy.core.parameters import SimParams -from gnpy.core.utils import db2lin, lin2db, automatic_nch +from gnpy.core.utils import db2lin, lin2db, automatic_nch, watt2dbm, dbm2watt from gnpy.topology.request import (ResultElement, jsontocsv, compute_path_dsjctn, requests_aggregation, BLOCKING_NOPATH, correct_json_route_list, deduplicate_disjunctions, compute_path_with_disjunction, @@ -197,16 +197,22 @@ def transmission_main_example(args=None): trx_params['power'] = db2lin(float(args.power)) * 1e-3 params.update(trx_params) initial_spectrum = None - nb_channels = automatic_nch(trx_params['f_min'], trx_params['f_max'], trx_params['spacing']) + params['nb_channel'] = automatic_nch(trx_params['f_min'], trx_params['f_max'], trx_params['spacing']) + # use ref_req to hold reference channel used for design and req for the propagation + # and req to hold channels to be propagated + # apply power sweep on the design and on the channels + ref_req = PathRequest(**params) + pref_ch_db = watt2dbm(ref_req.power) if args.spectrum: + # use the spectrum defined by user for the propagation. + # the nb of channel for design remains the one of the reference channel initial_spectrum = load_initial_spectrum(args.spectrum) - nb_channels = len(initial_spectrum) + params['nb_channel'] = len(initial_spectrum) print('User input for spectrum used for propagation instead of SI') - params['nb_channel'] = nb_channels req = PathRequest(**params) - pref_ch_db = lin2db(req.power * 1e3) # reference channel power / span (SL=20dB) + p_ch_db = watt2dbm(req.power) req.initial_spectrum = initial_spectrum - print(f'There are {nb_channels} channels propagating') + print(f'There are {req.nb_channel} channels propagating') power_mode = equipment['Span']['default'].power_mode print('\n'.join([f'Power mode is set to {power_mode}', '=> it can be modified in eqpt_config.json - Span'])) @@ -234,7 +240,7 @@ def transmission_main_example(args=None): # initial network is designed using req.power. that is that any missing information (amp gain or delta_p) is filled # using this req.power, previous to any sweep requested later on. try: - design_network(req, network, equipment, verbose=True) + design_network(ref_req, network, equipment, set_connector_losses=True, verbose=True) except exceptions.NetworkTopologyError as e: print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {e}') sys.exit(1) @@ -246,14 +252,17 @@ def transmission_main_example(args=None): f'and {destination.uid}') print(f'\nNow propagating between {source.uid} and {destination.uid}:') for dp_db in power_range: - req.power = db2lin(pref_ch_db + dp_db) * 1e-3 + ref_req.power = dbm2watt(pref_ch_db + dp_db) + req.power = dbm2watt(p_ch_db + dp_db) + design_network(ref_req, network, equipment, set_connector_losses=False, verbose=False) # if initial spectrum did not contain any power, now we need to use this one. # note the initial power defines a differential wrt req.power so that if req.power is set to 2mW (3dBm) # and initial spectrum was set to 0, this sets a initial per channel delta power to -3dB, so that # whatever the equalization, -3 dB is applied on all channels (ie initial power in initial spectrum pre-empts # "--power" option) if power_mode: - print(f'\nPropagating with input power = {ansi_escapes.cyan}{lin2db(req.power*1e3):.2f} dBm{ansi_escapes.reset}:') + print(f'\nPropagating with input power = {ansi_escapes.cyan}{watt2dbm(req.power):.2f} ' + + f'dBm{ansi_escapes.reset}:') else: print(f'\nPropagating in {ansi_escapes.cyan}gain mode{ansi_escapes.reset}: power cannot be set manually') infos = propagate(path, req, equipment) diff --git a/tests/data/eqpt_config_sweep.json b/tests/data/eqpt_config_sweep.json new file mode 100644 index 000000000..f7cd61050 --- /dev/null +++ b/tests/data/eqpt_config_sweep.json @@ -0,0 +1,238 @@ +{ + "Edfa": [{ + "type_variety": "CienaDB_medium_gain", + "type_def": "advanced_model", + "gain_flatmax": 25, + "gain_min": 15, + "p_max": 21, + "advanced_config_from_json": "std_medium_gain_advanced_config.json", + "out_voa_auto": false, + "allowed_for_design": true + }, + { + "type_variety": "std_medium_gain", + "type_def": "variable_gain", + "gain_flatmax": 26, + "gain_min": 15, + "p_max": 21, + "nf_min": 6, + "nf_max": 10, + "out_voa_auto": false, + "allowed_for_design": true + }, + { + "type_variety": "std_low_gain", + "type_def": "variable_gain", + "gain_flatmax": 16, + "gain_min": 8, + "p_max": 21, + "nf_min": 7, + "nf_max": 11, + "out_voa_auto": false, + "allowed_for_design": true + }, + { + "type_variety": "test", + "type_def": "variable_gain", + "gain_flatmax": 25, + "gain_min": 15, + "p_max": 21, + "nf_min": 5.8, + "nf_max": 10, + "out_voa_auto": false, + "allowed_for_design": true + }, + { + "type_variety": "test_fixed_gain", + "type_def": "fixed_gain", + "gain_flatmax": 21, + "gain_min": 20, + "p_max": 21, + "nf0": 5, + "allowed_for_design": true + }, + { + "type_variety": "std_booster", + "type_def": "fixed_gain", + "gain_flatmax": 21, + "gain_min": 20, + "p_max": 21, + "nf0": 5, + "allowed_for_design": false + } + ], + "Fiber": [{ + "type_variety": "SSMF", + "dispersion": 1.67e-05, + "effective_area": 83e-12, + "pmd_coef": 1.265e-15 + } + ], + "Span": [{ + "power_mode":true, + "delta_power_range_db": [0,0,0.5], + "max_fiber_lineic_loss_for_raman": 0.25, + "target_extended_gain": 2.5, + "max_length": 150, + "length_units": "km", + "max_loss": 28, + "padding": 10, + "EOL": 0, + "con_in": 0, + "con_out": 0 + } + ], + "Roadm": [{ + "target_pch_out_db": -20, + "add_drop_osnr": 38, + "pmd": 0, + "pdl": 0, + "restrictions": { + "preamp_variety_list":[], + "booster_variety_list":[] + } + } + ], + "SI": [{ + "f_min": 191.35e12, + "f_max": 196.1e12, + "baud_rate": 32e9, + "spacing": 50e9, + "power_dbm": 0, + "power_range_db": [-6,0,0.5], + "roll_off": 0.15, + "tx_osnr": 100, + "sys_margins": 0 + } + ], + "Transceiver":[ + { + "type_variety": "vendorA_trx-type1", + "frequency":{ + "min": 191.4e12, + "max": 196.1e12 + }, + "mode":[ + { + "format": "PS_SP64_1", + "baud_rate": 32e9, + "OSNR": 11, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + }, + { + "format": "PS_SP64_2", + "baud_rate": 64e9, + "OSNR": 15, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 75e9, + "cost": 1 + }, + { + "format": "mode 1", + "baud_rate": 32e9, + "OSNR": 11, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + }, + { + "format": "mode 2", + "baud_rate": 64e9, + "OSNR": 15, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 75e9, + "cost": 1 + } + ] + }, + { + "type_variety": "Voyager_16QAM", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [ + { + "format": "16QAM", + "baud_rate": 32e9, + "OSNR": 19, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + } + ] + }, + { + "type_variety": "Voyager", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [ + { + "format": "mode 1", + "baud_rate": 32e9, + "OSNR": 12, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 50e9, + "cost": 1 + }, + { + "format": "mode 3", + "baud_rate": 44e9, + "OSNR": 18, + "bit_rate": 300e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 62.5e9, + "cost": 1 + }, + { + "format": "mode 2", + "baud_rate": 66e9, + "OSNR": 21, + "bit_rate": 400e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + }, + { + "format": "mode 2 - fake", + "baud_rate": 66e9, + "OSNR": 21, + "bit_rate": 400e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + }, + { + "format": "mode 4", + "baud_rate": 66e9, + "OSNR": 16, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + } + ] + } + ] + +} diff --git a/tests/invocation/logs_power_sweep_example b/tests/invocation/logs_power_sweep_example new file mode 100644 index 000000000..a3d4e771b --- /dev/null +++ b/tests/invocation/logs_power_sweep_example @@ -0,0 +1,307 @@ +INFO gnpy.tools.cli_examples:cli_examples.py source = 'brest' +INFO gnpy.tools.cli_examples:cli_examples.py destination = 'rennes' +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Lorient_KMA to Loudeac + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: effective gain in Node east edfa in Lannion_CAS to Stbrieuc + is above user specified amplifier std_low_gain + max flat gain: 16dB ; required gain: 21.22dB. Please check amplifier type. + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Rennes_STA to Stbrieuc + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: effective gain in Node east edfa in Lannion_CAS to Morlaix + is above user specified amplifier std_low_gain + max flat gain: 16dB ; required gain: 21.22dB. Please check amplifier type. + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Brest_KLA to Morlaix + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Lorient_KMA to Loudeac + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: effective gain in Node west edfa in Lannion_CAS to Corlay + is above user specified amplifier test + max flat gain: 25dB ; required gain: 28.0dB. Please check amplifier type. + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Lorient_KMA to Vannes_KBE + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Vannes_KBE to Lorient_KMA + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Lorient_KMA to Quimper + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Quimper to Lorient_KMA + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Brest_KLA to Quimper + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Vannes_KBE to Lorient_KMA + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Lorient_KMA to Vannes_KBE + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Vannes_KBE to Ploermel + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Ploermel to Vannes_KBE + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Rennes_STA to Ploermel + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Rennes_STA to Stbrieuc + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Stbrieuc to Rennes_STA + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Lannion_CAS to Stbrieuc + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Rennes_STA to Ploermel + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Vannes_KBE to Ploermel + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Brest_KLA to Morlaix + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: effective gain in Node east edfa in Brest_KLA to Quimper + is above user specified amplifier std_low_gain + max flat gain: 16dB ; required gain: 21.22dB. Please check amplifier type. + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in Quimper to Lorient_KMA + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in Lorient_KMA to Quimper + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in a to b + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in b to a + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in a to c + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in c to a + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in b to a + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in a to b + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in b to f + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in f to b + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in c to a + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in a to c + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in d to c + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in c to f + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in f to c + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in d to c + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in c to d + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in d to e + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in e to d + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in e to d + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in d to e + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in e to g + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in g to e + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in f to c + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in c to f + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in f to b + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in b to f + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in f to h + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in h to f + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in g to e + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in e to g + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in g to h + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in h to g + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in h to f + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in f to h + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node east edfa in h to g + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + +WARNING gnpy.core.network:network.py + WARNING: target gain and power in node west edfa in g to h + is beyond all available amplifiers capabilities and/or extended_gain_range: + a power reduction of -1.78 is applied + diff --git a/tests/invocation/power_sweep_example b/tests/invocation/power_sweep_example new file mode 100644 index 000000000..1aacb2ed4 --- /dev/null +++ b/tests/invocation/power_sweep_example @@ -0,0 +1,154 @@ +There are 95 channels propagating +Power mode is set to True +=> it can be modified in eqpt_config.json - Span + +There are 4 fiber spans over 200 km between trx Brest_KLA and trx Rennes_STA + +Now propagating between trx Brest_KLA and trx Rennes_STA: + +Propagating with input power = -3.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 23.73 + GSNR (signal bw, dB): 19.65 + OSNR ASE (0.1nm, dB): 23.99 + OSNR ASE (signal bw, dB): 19.91 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = -2.50 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.01 + GSNR (signal bw, dB): 19.93 + OSNR ASE (0.1nm, dB): 24.37 + OSNR ASE (signal bw, dB): 20.29 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = -2.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.25 + GSNR (signal bw, dB): 20.17 + OSNR ASE (0.1nm, dB): 24.74 + OSNR ASE (signal bw, dB): 20.66 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = -1.50 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.44 + GSNR (signal bw, dB): 20.36 + OSNR ASE (0.1nm, dB): 25.10 + OSNR ASE (signal bw, dB): 21.01 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = -1.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.57 + GSNR (signal bw, dB): 20.49 + OSNR ASE (0.1nm, dB): 25.44 + OSNR ASE (signal bw, dB): 21.36 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = -0.50 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.63 + GSNR (signal bw, dB): 20.55 + OSNR ASE (0.1nm, dB): 25.77 + OSNR ASE (signal bw, dB): 21.69 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = -0.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.60 + GSNR (signal bw, dB): 20.52 + OSNR ASE (0.1nm, dB): 26.09 + OSNR ASE (signal bw, dB): 22.00 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = 0.50 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.42 + GSNR (signal bw, dB): 20.34 + OSNR ASE (0.1nm, dB): 26.29 + OSNR ASE (signal bw, dB): 22.20 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = 1.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.16 + GSNR (signal bw, dB): 20.08 + OSNR ASE (0.1nm, dB): 26.47 + OSNR ASE (signal bw, dB): 22.39 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = 1.50 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.02 + GSNR (signal bw, dB): 19.94 + OSNR ASE (0.1nm, dB): 26.55 + OSNR ASE (signal bw, dB): 22.47 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = 2.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.02 + GSNR (signal bw, dB): 19.94 + OSNR ASE (0.1nm, dB): 26.55 + OSNR ASE (signal bw, dB): 22.47 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = 2.50 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.02 + GSNR (signal bw, dB): 19.94 + OSNR ASE (0.1nm, dB): 26.55 + OSNR ASE (signal bw, dB): 22.47 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +Propagating with input power = 3.00 dBm: +Transceiver trx Rennes_STA + GSNR (0.1nm, dB): 24.02 + GSNR (signal bw, dB): 19.94 + OSNR ASE (0.1nm, dB): 26.55 + OSNR ASE (signal bw, dB): 22.47 + CD (ps/nm): 3340.00 + PMD (ps): 0.57 + PDL (dB): 0.00 + Latency (ms): 0.98 + +(Invalid source node 'brest' replaced with trx Brest_KLA) + +(Invalid destination node 'rennes' replaced with trx Rennes_STA) diff --git a/tests/test_invocation.py b/tests/test_invocation.py index 5e536328d..a5a83f2aa 100644 --- a/tests/test_invocation.py +++ b/tests/test_invocation.py @@ -29,6 +29,8 @@ ['--spectrum', 'gnpy/example-data/initial_spectrum2.json', 'gnpy/example-data/meshTopologyExampleV2.xls', '--show-channels', ]), ('path_requests_run_CD_PMD_PDL_missing', 'logs_path_requests_run_CD_PMD_PDL_missing', path_requests_run, ['tests/data/CORONET_Global_Topology_expected.json', 'tests/data/CORONET_services.json', '-v']), + ('power_sweep_example', 'logs_power_sweep_example', transmission_main_example, + ['tests/data/testTopology_expected.json', 'brest', 'rennes', '-e', 'tests/data/eqpt_config_sweep.json', '--pow', '3']), )) def test_example_invocation(capfd, caplog, output, log, handler, args): """Make sure that our examples produce useful output""" From 87211b35e9e730f99d47ec972166ddc2a1960a96 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 19 Oct 2022 18:27:06 +0200 Subject: [PATCH 13/20] Use design delta_p and gains instead of p_spani Remove the visualisation of the effective_pch in amp because actual and target are the relevant ones. effective_pch was artificially related to a mix of reference channel and noisy channel (mixed between on the fly redesign but using actual ROADM equalisation which includes noise in its actual loss). the change does no more rely on the target power (which is rounded) but on the designed gain, which is not rounded. Propagations are slightly changed for openroadm simulations because of that. (I verified) The gain of amp was estimated on the fly with p_spni also in case of RamanFiber preceding elements. removing p_spani requies that an estimation of Raman gain be done during design. This commit also adds this estimation. Signed-off-by: EstherLerouzic Change-Id: I960b85e99f85a7d168ac5349e325c4928fa5673b --- gnpy/core/elements.py | 12 ++- gnpy/core/network.py | 80 ++++++++++++++++--- gnpy/topology/request.py | 2 + .../openroadm-v4-Stockholm-Gothenburg | 25 ++---- .../openroadm-v5-Stockholm-Gothenburg | 27 ++----- tests/invocation/power_sweep_example | 8 +- .../spectrum1_transmission_main_example | 2 - .../spectrum2_transmission_main_example | 2 - tests/invocation/transmission_main_example | 1 - .../transmission_main_example__raman | 1 - .../invocation/transmission_main_example_long | 19 ----- tests/invocation/transmission_saturated | 2 - tests/test_amplifier.py | 5 +- tests/test_equalization.py | 10 +-- tests/test_network_functions.py | 4 +- tests/test_parser.py | 1 + tests/test_propagation.py | 3 +- tests/test_roadm_restrictions.py | 46 ++++++----- 18 files changed, 131 insertions(+), 119 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index a7131a357..71a9dba38 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -838,9 +838,10 @@ def __str__(self): f' pad att_in (dB): {self.att_in:.2f}', f' Power In (dBm): {self.pin_db:.2f}', f' Power Out (dBm): {self.pout_db:.2f}', - f' Delta_P (dB): ' + (f'{self.delta_p:.2f}' if self.delta_p is not None else 'None'), - f' target pch (dBm): ' + (f'{self.target_pch_out_db:.2f}' if self.target_pch_out_db is not None else 'None'), - f' effective pch (dBm): {self.effective_pch_out_db:.2f}', + ' Delta_P (dB): ' + (f'{self.delta_p:.2f}' + if self.delta_p is not None else 'None'), + ' target pch (dBm): ' + (f'{self.target_pch_out_db:.2f}' + if self.target_pch_out_db is not None else 'None'), f' actual pch out (dBm): {total_pch}', f' output VOA (dB): {self.out_voa:.2f}']) @@ -869,16 +870,14 @@ def interpol_params(self, spectral_info): self.slot_width = self.channel_freq[1] - self.channel_freq[0] """in power mode: delta_p is defined and can be used to calculate the power target - This power target is used calculate the amplifier gain""" + This power target correspond to the channel used for design""" pref = spectral_info.pref if self.delta_p is not None and self.operational.delta_p is not None: # use the user defined target self.target_pch_out_db = round(self.operational.delta_p + pref.p_span0, 2) - self.effective_gain = self.target_pch_out_db - pref.p_spani elif self.delta_p is not None: # use the design target if no target were set self.target_pch_out_db = round(self.delta_p + pref.p_span0, 2) - self.effective_gain = self.target_pch_out_db - pref.p_spani """check power saturation and correct effective gain & power accordingly:""" # Compute the saturation accounting for actual power at the input of the amp @@ -886,7 +885,6 @@ def interpol_params(self, spectral_info): self.effective_gain, self.params.p_max - self.pin_db ) - self.effective_pch_out_db = round(pref.p_spani + self.effective_gain, 2) """check power saturation and correct target_gain accordingly:""" self.nf = self._calc_nf() diff --git a/gnpy/core/network.py b/gnpy/core/network.py index 46a42d4b9..371b3eaa0 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -8,15 +8,17 @@ Working with networks which consist of network elements """ +from copy import deepcopy from operator import attrgetter from collections import namedtuple from logging import getLogger from gnpy.core import elements from gnpy.core.exceptions import ConfigurationError, NetworkTopologyError -from gnpy.core.utils import round2float, convert_length, psd2powerdbm, lin2db, watt2dbm -from gnpy.core.info import ReferenceCarrier -from gnpy.tools.json_io import Amp +from gnpy.core.utils import round2float, convert_length, psd2powerdbm, lin2db, watt2dbm, dbm2watt +from gnpy.core.info import ReferenceCarrier, create_input_spectral_information +from gnpy.tools import json_io +from gnpy.core.parameters import SimParams logger = getLogger(__name__) @@ -134,7 +136,7 @@ def target_power(network, node, equipment): # get_fiber_dp SPAN_LOSS_REF = 20 POWER_SLOPE = 0.3 dp_range = list(equipment['Span']['default'].delta_power_range_db) - node_loss = span_loss(network, node) + node_loss = span_loss(network, node, equipment) try: dp = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2]) @@ -181,12 +183,64 @@ def next_node_generator(network, node): yield from next_node_generator(network, next_node) -def span_loss(network, node): +def estimate_raman_gain(node, equipment): + """If node is RamanFiber, then estimate the possible Raman gain if any + for this purpose propagate a fake signal in a copy. + to be accurate the nb of channel should be the same as in SI, but this increases computation time + """ + f_min = equipment['SI']['default'].f_min + f_max = equipment['SI']['default'].f_max + roll_off = equipment['SI']['default'].roll_off + baud_rate = equipment['SI']['default'].baud_rate + power_dbm = equipment['SI']['default'].power_dbm + power = dbm2watt(equipment['SI']['default'].power_dbm) + spacing = equipment['SI']['default'].spacing + tx_osnr = equipment['SI']['default'].tx_osnr + + sim_params = { + "raman_params": { + "flag": True, + "result_spatial_resolution": 10e3, + "solver_spatial_resolution": 50 + }, + "nli_params": { + "method": "ggn_spectrally_separated", + "dispersion_tolerance": 1, + "phase_shift_tolerance": 0.1, + "computed_channels": [1, 18, 37, 56, 75] + } + } + if isinstance(node, elements.RamanFiber): + # in order to take into account gain generated in RamanFiber, propagate in the RamanFiber with + # SI reference channel. + spectral_info_input = create_input_spectral_information(f_min=f_min, f_max=f_max, roll_off=roll_off, + baud_rate=baud_rate, power=power, spacing=spacing, + tx_osnr=tx_osnr) + n_copy = deepcopy(node) + # need to set ref_pch_in_dbm in order to correctly run propagate of the element, because this + # setting has not yet been done by autodesign + n_copy.ref_pch_in_dbm = power_dbm + SimParams.set_params(sim_params) + pin = watt2dbm(sum(spectral_info_input.signal)) + spectral_info_out = n_copy(spectral_info_input) + pout = watt2dbm(sum(spectral_info_out.signal)) + estimated_gain = pout - pin + node.loss + return round(estimated_gain, 2) + else: + return 0.0 + + +def span_loss(network, node, equipment): """Total loss of a span (Fiber and Fused nodes) which contains the given node""" loss = node.loss if node.passive else 0 loss += sum(n.loss for n in prev_node_generator(network, node)) loss += sum(n.loss for n in next_node_generator(network, node)) - return loss + # add the possible Raman gain + gain = estimate_raman_gain(node, equipment) + gain += sum(estimate_raman_gain(n, equipment) for n in prev_node_generator(network, node)) + gain += sum(estimate_raman_gain(n, equipment) for n in next_node_generator(network, node)) + + return loss - gain def find_first_node(network, node): @@ -252,7 +306,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d raise NetworkTopologyError(f'Loop detected for {type(node).__name__} {node.uid}, ' + 'please check network topology') if isinstance(node, elements.Edfa): - node_loss = span_loss(network, prev_node) + node_loss = span_loss(network, prev_node, equipment) voa = node.out_voa if node.out_voa else 0 if node.operational.delta_p is None: dp = target_power(network, next_node, equipment) + voa @@ -450,7 +504,7 @@ def add_roadm_booster(network, roadm): network.remove_edge(roadm, next_node) amp = elements.Edfa( uid=f'Edfa_booster_{roadm.uid}_to_{next_node.uid}', - params=Amp.default_values, + params=json_io.Amp.default_values, metadata={ 'location': { 'latitude': roadm.lat, @@ -476,7 +530,7 @@ def add_roadm_preamp(network, roadm): network.remove_edge(prev_node, roadm) amp = elements.Edfa( uid=f'Edfa_preamp_{roadm.uid}_from_{prev_node.uid}', - params=Amp.default_values, + params=json_io.Amp.default_values, metadata={ 'location': { 'latitude': roadm.lat, @@ -505,7 +559,7 @@ def add_inline_amplifier(network, fiber): network.remove_edge(fiber, next_node) amp = elements.Edfa( uid=f'Edfa_{fiber.uid}', - params=Amp.default_values, + params=json_io.Amp.default_values, metadata={ 'location': { 'latitude': (fiber.lat + next_node.lat) / 2, @@ -607,7 +661,7 @@ def add_connector_loss(network, fibers, default_con_in, default_con_out, EOL): fiber.params.con_out += EOL -def add_fiber_padding(network, fibers, padding): +def add_fiber_padding(network, fibers, padding, equipment): """last_fibers = (fiber for n in network.nodes() if not (isinstance(n, elements.Fiber) or isinstance(n, elements.Fused)) for fiber in network.predecessors(n) @@ -616,7 +670,7 @@ def add_fiber_padding(network, fibers, padding): next_node = get_next_node(fiber, network) if isinstance(next_node, elements.Fused): continue - this_span_loss = span_loss(network, fiber) + this_span_loss = span_loss(network, fiber, equipment) if this_span_loss < padding: # add a padding att_in at the input of the 1st fiber: # address the case when several fibers are spliced together @@ -657,7 +711,7 @@ def add_missing_fiber_attributes(network, equipment): add_connector_loss(network, fibers, default_span_data.con_in, default_span_data.con_out, default_span_data.EOL) # don't group split fiber and add amp in the same loop # =>for code clarity (at the expense of speed): - add_fiber_padding(network, fibers, default_span_data.padding) + add_fiber_padding(network, fibers, default_span_data.padding, equipment) def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_losses=True, verbose=True): diff --git a/gnpy/topology/request.py b/gnpy/topology/request.py index 15595390c..33c17cc46 100644 --- a/gnpy/topology/request.py +++ b/gnpy/topology/request.py @@ -24,6 +24,7 @@ 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, ReferenceCarrier +from gnpy.core import network as network_module from gnpy.core.exceptions import ServiceError, DisjunctionError from copy import deepcopy from csv import writer @@ -1102,6 +1103,7 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist): # elements to simulate performance, several demands having the same destination # may use the same transponder for the performance simulation. This is why # we use deepcopy: to ensure that each propagation is recorded and not overwritten + network_module.design_network(pathreq, network, equipment, set_connector_losses=False, verbose=False) total_path = deepcopy(pathlist[i]) msg = msg + f'\n\tComputed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}' LOGGER.info(msg) diff --git a/tests/invocation/openroadm-v4-Stockholm-Gothenburg b/tests/invocation/openroadm-v4-Stockholm-Gothenburg index db9ea938c..bbba8ab64 100644 --- a/tests/invocation/openroadm-v4-Stockholm-Gothenburg +++ b/tests/invocation/openroadm-v4-Stockholm-Gothenburg @@ -31,7 +31,6 @@ Edfa Edfa_booster_roadm_Stockholm_to_fiber (Stockholm → Norrköping)_(1/2) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Stockholm → Norrköping)_(1/2) @@ -54,8 +53,7 @@ Edfa Edfa_fiber (Stockholm → Norrköping)_(1/2) Power Out (dBm): 21.84 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 - actual pch out (dBm): 2.02 + actual pch out (dBm): 2.01 output VOA (dB): 0.00 Fiber fiber (Stockholm → Norrköping)_(2/2) type_variety: SSMF @@ -65,7 +63,7 @@ Fiber fiber (Stockholm → Norrköping)_(2/2) (includes conn loss (dB) in: 0.00 out: 0.00) (conn loss out includes EOL margin defined in eqpt_config.json) reference pch out (dBm): -14.33 - actual pch out (dBm): -14.29 + actual pch out (dBm): -14.30 Edfa Edfa_preamp_roadm_Norrköping_from_fiber (Stockholm → Norrköping)_(2/2) type_variety: openroadm_mw_mw_preamp effective gain(dB): 16.33 @@ -73,12 +71,11 @@ Edfa Edfa_preamp_roadm_Norrköping_from_fiber (Stockholm → Norrköping)_(2/2) noise figure (dB): 12.59 (including att_in) pad att_in (dB): 0.00 - Power In (dBm): 5.53 - Power Out (dBm): 21.87 + Power In (dBm): 5.52 + Power Out (dBm): 21.86 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 - actual pch out (dBm): 2.04 + actual pch out (dBm): 2.03 output VOA (dB): 0.00 Roadm roadm_Norrköping effective loss (dB): 22.00 @@ -95,7 +92,6 @@ Edfa Edfa_booster_roadm_Norrköping_to_fiber (Norrköping → Linköping) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Norrköping → Linköping) @@ -118,7 +114,6 @@ Edfa Edfa_preamp_roadm_Linköping_from_fiber (Norrköping → Linköping) Power Out (dBm): 21.83 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.01 output VOA (dB): 0.00 Roadm roadm_Linköping @@ -136,7 +131,6 @@ Edfa Edfa_booster_roadm_Linköping_to_fiber (Linköping → Jönköping) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Linköping → Jönköping) @@ -156,11 +150,10 @@ Edfa Edfa_preamp_roadm_Jönköping_from_fiber (Linköping → Jönköping) (including att_in) pad att_in (dB): 0.00 Power In (dBm): -4.97 - Power Out (dBm): 21.86 + Power Out (dBm): 21.87 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 - actual pch out (dBm): 2.04 + actual pch out (dBm): 2.05 output VOA (dB): 0.00 Roadm roadm_Jönköping effective loss (dB): 22.00 @@ -177,7 +170,6 @@ Edfa Edfa_booster_roadm_Jönköping_to_fiber (Jönköping → Borås) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Jönköping → Borås) @@ -200,7 +192,6 @@ Edfa Edfa_preamp_roadm_Borås_from_fiber (Jönköping → Borås) Power Out (dBm): 21.84 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.02 output VOA (dB): 0.00 Roadm roadm_Borås @@ -218,7 +209,6 @@ Edfa Edfa_booster_roadm_Borås_to_fiber (Borås → Gothenburg) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Borås → Gothenburg) @@ -241,7 +231,6 @@ Edfa Edfa_preamp_roadm_Gothenburg_from_fiber (Borås → Gothenburg) Power Out (dBm): 21.84 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.02 output VOA (dB): 0.00 Roadm roadm_Gothenburg diff --git a/tests/invocation/openroadm-v5-Stockholm-Gothenburg b/tests/invocation/openroadm-v5-Stockholm-Gothenburg index b080291c5..b0c06ddae 100644 --- a/tests/invocation/openroadm-v5-Stockholm-Gothenburg +++ b/tests/invocation/openroadm-v5-Stockholm-Gothenburg @@ -31,7 +31,6 @@ Edfa Edfa_booster_roadm_Stockholm_to_fiber (Stockholm → Norrköping)_(1/2) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Stockholm → Norrköping)_(1/2) @@ -54,8 +53,7 @@ Edfa Edfa_fiber (Stockholm → Norrköping)_(1/2) Power Out (dBm): 21.84 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 - actual pch out (dBm): 2.02 + actual pch out (dBm): 2.01 output VOA (dB): 0.00 Fiber fiber (Stockholm → Norrköping)_(2/2) type_variety: SSMF @@ -65,20 +63,19 @@ Fiber fiber (Stockholm → Norrköping)_(2/2) (includes conn loss (dB) in: 0.00 out: 0.00) (conn loss out includes EOL margin defined in eqpt_config.json) reference pch out (dBm): -14.33 - actual pch out (dBm): -14.29 + actual pch out (dBm): -14.30 Edfa Edfa_preamp_roadm_Norrköping_from_fiber (Stockholm → Norrköping)_(2/2) type_variety: openroadm_mw_mw_preamp_worstcase_ver5 effective gain(dB): 16.33 (before att_in and before output VOA) - noise figure (dB): 11.44 + noise figure (dB): 11.43 (including att_in) pad att_in (dB): 0.00 - Power In (dBm): 5.53 - Power Out (dBm): 21.86 + Power In (dBm): 5.52 + Power Out (dBm): 21.85 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 - actual pch out (dBm): 2.04 + actual pch out (dBm): 2.03 output VOA (dB): 0.00 Roadm roadm_Norrköping effective loss (dB): 22.00 @@ -95,7 +92,6 @@ Edfa Edfa_booster_roadm_Norrköping_to_fiber (Norrköping → Linköping) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Norrköping → Linköping) @@ -118,7 +114,6 @@ Edfa Edfa_preamp_roadm_Linköping_from_fiber (Norrköping → Linköping) Power Out (dBm): 21.83 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.01 output VOA (dB): 0.00 Roadm roadm_Linköping @@ -136,7 +131,6 @@ Edfa Edfa_booster_roadm_Linköping_to_fiber (Linköping → Jönköping) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Linköping → Jönköping) @@ -156,10 +150,9 @@ Edfa Edfa_preamp_roadm_Jönköping_from_fiber (Linköping → Jönköping) (including att_in) pad att_in (dB): 0.00 Power In (dBm): -4.97 - Power Out (dBm): 21.86 + Power Out (dBm): 21.87 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.04 output VOA (dB): 0.00 Roadm roadm_Jönköping @@ -177,7 +170,6 @@ Edfa Edfa_booster_roadm_Jönköping_to_fiber (Jönköping → Borås) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Jönköping → Borås) @@ -200,8 +192,7 @@ Edfa Edfa_preamp_roadm_Borås_from_fiber (Jönköping → Borås) Power Out (dBm): 21.84 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 - actual pch out (dBm): 2.01 + actual pch out (dBm): 2.02 output VOA (dB): 0.00 Roadm roadm_Borås effective loss (dB): 22.00 @@ -218,7 +209,6 @@ Edfa Edfa_booster_roadm_Borås_to_fiber (Borås → Gothenburg) Power Out (dBm): 21.82 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.00 output VOA (dB): 0.00 Fiber fiber (Borås → Gothenburg) @@ -241,7 +231,6 @@ Edfa Edfa_preamp_roadm_Gothenburg_from_fiber (Borås → Gothenburg) Power Out (dBm): 21.84 Delta_P (dB): 0.00 target pch (dBm): 2.00 - effective pch (dBm): 2.00 actual pch out (dBm): 2.02 output VOA (dB): 0.00 Roadm roadm_Gothenburg diff --git a/tests/invocation/power_sweep_example b/tests/invocation/power_sweep_example index 1aacb2ed4..c54309431 100644 --- a/tests/invocation/power_sweep_example +++ b/tests/invocation/power_sweep_example @@ -108,7 +108,7 @@ Transceiver trx Rennes_STA Propagating with input power = 1.50 dBm: Transceiver trx Rennes_STA GSNR (0.1nm, dB): 24.02 - GSNR (signal bw, dB): 19.94 + GSNR (signal bw, dB): 19.93 OSNR ASE (0.1nm, dB): 26.55 OSNR ASE (signal bw, dB): 22.47 CD (ps/nm): 3340.00 @@ -119,7 +119,7 @@ Transceiver trx Rennes_STA Propagating with input power = 2.00 dBm: Transceiver trx Rennes_STA GSNR (0.1nm, dB): 24.02 - GSNR (signal bw, dB): 19.94 + GSNR (signal bw, dB): 19.93 OSNR ASE (0.1nm, dB): 26.55 OSNR ASE (signal bw, dB): 22.47 CD (ps/nm): 3340.00 @@ -130,7 +130,7 @@ Transceiver trx Rennes_STA Propagating with input power = 2.50 dBm: Transceiver trx Rennes_STA GSNR (0.1nm, dB): 24.02 - GSNR (signal bw, dB): 19.94 + GSNR (signal bw, dB): 19.93 OSNR ASE (0.1nm, dB): 26.55 OSNR ASE (signal bw, dB): 22.47 CD (ps/nm): 3340.00 @@ -141,7 +141,7 @@ Transceiver trx Rennes_STA Propagating with input power = 3.00 dBm: Transceiver trx Rennes_STA GSNR (0.1nm, dB): 24.02 - GSNR (signal bw, dB): 19.94 + GSNR (signal bw, dB): 19.93 OSNR ASE (0.1nm, dB): 26.55 OSNR ASE (signal bw, dB): 22.47 CD (ps/nm): 3340.00 diff --git a/tests/invocation/spectrum1_transmission_main_example b/tests/invocation/spectrum1_transmission_main_example index b6a90e648..610d6f2d3 100644 --- a/tests/invocation/spectrum1_transmission_main_example +++ b/tests/invocation/spectrum1_transmission_main_example @@ -32,7 +32,6 @@ Edfa east edfa in Lannion_CAS to Corlay Power Out (dBm): 19.82 Delta_P (dB): 1.00 target pch (dBm): 1.00 - effective pch (dBm): 1.00 actual pch out (dBm): 1.01 output VOA (dB): 0.00 Fiber fiber (Lannion_CAS → Corlay)-F061 @@ -77,7 +76,6 @@ Edfa west edfa in Lorient_KMA to Loudeac Power Out (dBm): 19.85 Delta_P (dB): 1.00 target pch (dBm): 1.00 - effective pch (dBm): 1.00 actual pch out (dBm): 1.05 output VOA (dB): 0.00 Roadm roadm Lorient_KMA diff --git a/tests/invocation/spectrum2_transmission_main_example b/tests/invocation/spectrum2_transmission_main_example index 42dc94cc1..d4b8ab587 100644 --- a/tests/invocation/spectrum2_transmission_main_example +++ b/tests/invocation/spectrum2_transmission_main_example @@ -32,7 +32,6 @@ Edfa east edfa in Lannion_CAS to Corlay Power Out (dBm): 18.79 Delta_P (dB): 1.00 target pch (dBm): 1.00 - effective pch (dBm): 1.00 actual pch out (dBm): mode_1: 1.01, mode_2: 1.02 output VOA (dB): 0.00 Fiber fiber (Lannion_CAS → Corlay)-F061 @@ -77,7 +76,6 @@ Edfa west edfa in Lorient_KMA to Loudeac Power Out (dBm): 18.84 Delta_P (dB): 1.00 target pch (dBm): 1.00 - effective pch (dBm): 1.00 actual pch out (dBm): mode_1: 1.04, mode_2: 1.09 output VOA (dB): 0.00 Roadm roadm Lorient_KMA diff --git a/tests/invocation/transmission_main_example b/tests/invocation/transmission_main_example index a5624b57c..01a46fa8a 100644 --- a/tests/invocation/transmission_main_example +++ b/tests/invocation/transmission_main_example @@ -36,7 +36,6 @@ Edfa Edfa1 Power Out (dBm): 16.82 Delta_P (dB): -2.00 target pch (dBm): -2.00 - effective pch (dBm): -2.00 actual pch out (dBm): -1.99 output VOA (dB): 0.00 Transceiver Site_B diff --git a/tests/invocation/transmission_main_example__raman b/tests/invocation/transmission_main_example__raman index 61d6c4373..0dc242d35 100644 --- a/tests/invocation/transmission_main_example__raman +++ b/tests/invocation/transmission_main_example__raman @@ -38,7 +38,6 @@ Edfa Edfa1 Power Out (dBm): 16.81 Delta_P (dB): -2.00 target pch (dBm): -2.00 - effective pch (dBm): -2.00 actual pch out (dBm): -2.26 output VOA (dB): 0.00 Transceiver Site_B diff --git a/tests/invocation/transmission_main_example_long b/tests/invocation/transmission_main_example_long index 712c61d73..de509eedb 100644 --- a/tests/invocation/transmission_main_example_long +++ b/tests/invocation/transmission_main_example_long @@ -31,7 +31,6 @@ Edfa booster A Power Out (dBm): 19.83 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.01 output VOA (dB): 0.00 Fiber Span1 @@ -54,7 +53,6 @@ Edfa Edfa1 Power Out (dBm): 19.84 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.02 output VOA (dB): 0.00 Fiber Span2 @@ -77,7 +75,6 @@ Edfa Edfa2 Power Out (dBm): 19.85 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.03 output VOA (dB): 0.00 Fiber Span3 @@ -100,7 +97,6 @@ Edfa Edfa3 Power Out (dBm): 19.86 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.04 output VOA (dB): 0.00 Fiber Span4 @@ -123,7 +119,6 @@ Edfa Edfa4 Power Out (dBm): 19.87 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.05 output VOA (dB): 0.00 Fiber Span5 @@ -146,7 +141,6 @@ Edfa Edfa5 Power Out (dBm): 19.88 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.06 output VOA (dB): 0.00 Roadm roadm Site C @@ -164,7 +158,6 @@ Edfa booster C Power Out (dBm): 19.83 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.01 output VOA (dB): 0.00 Fiber Span6 @@ -187,7 +180,6 @@ Edfa Edfa6 Power Out (dBm): 19.84 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.02 output VOA (dB): 0.00 Fiber Span7 @@ -210,7 +202,6 @@ Edfa Edfa7 Power Out (dBm): 19.85 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.03 output VOA (dB): 0.00 Fiber Span8 @@ -233,7 +224,6 @@ Edfa Edfa8 Power Out (dBm): 19.86 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.04 output VOA (dB): 0.00 Fiber Span9 @@ -256,7 +246,6 @@ Edfa Edfa9 Power Out (dBm): 19.87 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.05 output VOA (dB): 0.00 Fiber Span10 @@ -279,7 +268,6 @@ Edfa Edfa10 Power Out (dBm): 19.88 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.06 output VOA (dB): 0.00 Roadm roadm Site D @@ -297,7 +285,6 @@ Edfa booster D Power Out (dBm): 19.83 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.01 output VOA (dB): 0.00 Fiber Span11 @@ -320,7 +307,6 @@ Edfa Edfa11 Power Out (dBm): 19.84 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.02 output VOA (dB): 0.00 Fiber Span12 @@ -343,7 +329,6 @@ Edfa Edfa12 Power Out (dBm): 19.85 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.03 output VOA (dB): 0.00 Roadm roadm Site E @@ -361,7 +346,6 @@ Edfa booster E Power Out (dBm): 19.83 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.01 output VOA (dB): 0.00 Fiber Span13 @@ -384,7 +368,6 @@ Edfa Edfa13 Power Out (dBm): 19.84 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.02 output VOA (dB): 0.00 Fiber Span14 @@ -407,7 +390,6 @@ Edfa Edfa14 Power Out (dBm): 19.85 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.03 output VOA (dB): 0.00 Fiber Span15 @@ -430,7 +412,6 @@ Edfa Edfa15 Power Out (dBm): 19.86 Delta_P (dB): 0.00 target pch (dBm): 0.00 - effective pch (dBm): 0.00 actual pch out (dBm): 0.04 output VOA (dB): 0.00 Roadm roadm Site B diff --git a/tests/invocation/transmission_saturated b/tests/invocation/transmission_saturated index b1317759d..ab608e08f 100644 --- a/tests/invocation/transmission_saturated +++ b/tests/invocation/transmission_saturated @@ -31,7 +31,6 @@ Edfa east edfa in Lannion_CAS to Corlay Power Out (dBm): 21.01 Delta_P (dB): -1.82 target pch (dBm): 1.18 - effective pch (dBm): 1.18 actual pch out (dBm): 1.18 output VOA (dB): 0.00 Fiber fiber (Lannion_CAS → Corlay)-F061 @@ -76,7 +75,6 @@ Edfa west edfa in Lorient_KMA to Loudeac Power Out (dBm): 21.03 Delta_P (dB): -1.82 target pch (dBm): 1.18 - effective pch (dBm): 1.17 actual pch out (dBm): 1.21 output VOA (dB): 0.00 Roadm roadm Lorient_KMA diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index 1d4d4aba6..751a33fb3 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -88,6 +88,7 @@ def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si): si.nli /= db2lin(gain) si.ase /= db2lin(gain) edfa.operational.gain_target = gain + edfa.effective_gain = gain si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) result = edfa.nf @@ -102,6 +103,7 @@ def test_fixed_gain_nf(gain, nf_expected, setup_edfa_fixed_gain, si): si.nli /= db2lin(gain) si.ase /= db2lin(gain) edfa.operational.gain_target = gain + edfa.effective_gain = gain si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0] @@ -126,6 +128,7 @@ def test_compare_nf_models(gain, setup_edfa_variable_gain, si): si.nli /= db2lin(gain) si.ase /= db2lin(gain) edfa.operational.gain_target = gain + edfa.effective_gain = gain # edfa is variable gain type si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) @@ -212,7 +215,7 @@ def test_amp_behaviour(tilt_target, delta_p): "type_variety": "test", "operational": { "delta_p": delta_p, - "gain_target": 20, + "gain_target": 20 + delta_p if delta_p else 20, "tilt_target": tilt_target, "out_voa": 0 } diff --git a/tests/test_equalization.py b/tests/test_equalization.py index f4aef415a..6a8549671 100644 --- a/tests/test_equalization.py +++ b/tests/test_equalization.py @@ -303,11 +303,11 @@ def test_2low_input_power(target_out, delta_pdb_per_channel, correction): assert_allclose(watt2dbm(si.signal), target - correction, rtol=1e-5) -def net_setup(equipment): +def net_setup(equipment, deltap=0): """common setup for tests: builds network, equipment and oms only once""" network = load_network(NETWORK_FILENAME, equipment) spectrum = equipment['SI']['default'] - p_db = spectrum.power_dbm + p_db = spectrum.power_dbm + deltap p_total_db = p_db + lin2db(automatic_nch(spectrum.f_min, spectrum.f_max, spectrum.spacing)) build_network(network, equipment, p_db, p_total_db) return network @@ -450,14 +450,14 @@ def ref_network(): return network -@pytest.mark.parametrize('deltap', [0, +1.2, -0.5]) +@pytest.mark.parametrize('deltap', [0, +1.18, -0.5]) def test_target_psd_out_mwperghz_deltap(deltap): """checks that if target_psd_out_mWperGHz is defined, delta_p of amps is correctly updated - Power over 1.2dBm saturate amp with this test: TODO add a test on this saturation + Power over 1.18dBm saturate amp with this test: TODO add a test on this saturation """ equipment = load_equipment(EQPT_FILENAME) - network = net_setup(equipment) + network = net_setup(equipment, deltap) req = create_voyager_req(equipment, 'trx Brest_KLA', 'trx Vannes_KBE', False, ['trx Vannes_KBE'], ['STRICT'], 'mode 1', 50e9, deltap) temp = [{ diff --git a/tests/test_network_functions.py b/tests/test_network_functions.py index aa8bc2469..b97e858fe 100644 --- a/tests/test_network_functions.py +++ b/tests/test_network_functions.py @@ -49,7 +49,7 @@ def test_span_loss(node, attenuation): network = load_network(NETWORK_FILENAME, equipment) for x in network.nodes(): if x.uid == node: - assert attenuation == span_loss(network, x) + assert attenuation == span_loss(network, x, equipment) return assert not f'node "{node}" referenced from test but not found in the topology' # pragma: no cover @@ -61,4 +61,4 @@ def test_span_loss_unconnected(node): network = load_network(NETWORK_FILENAME, equipment) x = next(x for x in network.nodes() if x.uid == node) with pytest.raises(NetworkTopologyError): - span_loss(network, x) + span_loss(network, x, equipment) diff --git a/tests/test_parser.py b/tests/test_parser.py index 16298898e..27a09c7c4 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -110,6 +110,7 @@ def test_auto_design_generation_fromjson(tmpdir, json_input, power_mode): p_db = equipment['SI']['default'].power_dbm p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min, equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) + add_missing_elements_in_network(network, equipment) build_network(network, equipment, p_db, p_total_db) actual_json_output = tmpdir / json_input.with_name(json_input.stem + '_auto_design').with_suffix('.json').name save_network(network, actual_json_output) diff --git a/tests/test_propagation.py b/tests/test_propagation.py index 519d688ba..63e4e3a65 100644 --- a/tests/test_propagation.py +++ b/tests/test_propagation.py @@ -28,7 +28,6 @@ def nch_and_spacing(request): def propagation(input_power, con_in, con_out, dest): equipment = load_equipment(eqpt_library_name) network = load_network(network_file_name, equipment) - build_network(network, equipment, 0, 20) # parametrize the network elements with the con losses and adapt gain # (assumes all spans are identical) @@ -40,6 +39,8 @@ def propagation(input_power, con_in, con_out, dest): if isinstance(e, Edfa): e.operational.gain_target = loss + con_in + con_out + build_network(network, equipment, 0, 20) + transceivers = {n.uid: n for n in network.nodes() if isinstance(n, Transceiver)} p = input_power diff --git a/tests/test_roadm_restrictions.py b/tests/test_roadm_restrictions.py index 3b5736b68..afe48e16f 100644 --- a/tests/test_roadm_restrictions.py +++ b/tests/test_roadm_restrictions.py @@ -13,12 +13,12 @@ from pathlib import Path import pytest from numpy.testing import assert_allclose -from numpy import ndarray +from numpy import ndarray, mean from copy import deepcopy from gnpy.core.utils import lin2db, automatic_nch from gnpy.core.elements import Fused, Roadm, Edfa, Transceiver, EdfaOperational, EdfaParams, Fiber from gnpy.core.parameters import FiberParams, RoadmParams, FusedParams -from gnpy.core.network import build_network +from gnpy.core.network import build_network, design_network from gnpy.tools.json_io import network_from_json, load_equipment, load_json, Amp from gnpy.core.equipment import trx_mode_params from gnpy.topology.request import PathRequest, compute_constrained_path, ref_carrier, propagate @@ -455,9 +455,8 @@ def test_compare_design_propagation_settings(power_dbm, req_power, amp_with_delt p_total_db = p_db + lin2db(automatic_nch(eqpt['SI']['default'].f_min, eqpt['SI']['default'].f_max, eqpt['SI']['default'].spacing)) - build_network(network, eqpt, p_db, p_total_db) + build_network(network, eqpt, p_db, p_total_db, verbose=False) # record network settings before propagating - network_copy = deepcopy(network) # propagate on each oms req_list = create_per_oms_request(network, eqpt, req_power) paths = [compute_constrained_path(network, r) for r in req_list] @@ -468,10 +467,10 @@ def test_compare_design_propagation_settings(power_dbm, req_power, amp_with_delt for path, req in zip(paths, req_list): # check all elements except source and destination trx # in order to have clean initialization, use deecopy of paths + design_network(req, network, eqpt, verbose=False) + network_copy = deepcopy(network) pth = deepcopy(path) _ = propagate(pth, req, eqpt) - previous_power = None - previous_deltap = None for i, element in enumerate(pth[1:-1]): element_is_first_amp = False # index of previous element in path is i @@ -494,23 +493,26 @@ def test_compare_design_propagation_settings(power_dbm, req_power, amp_with_delt assert getattr(element, key) == getattr(element_copy, key) else: dp = element.out_voa if element.uid not in amp_with_deltap_one else element.out_voa + 1 - if element_is_first_amp: - assert element.effective_gain - element_copy.effective_gain ==\ - pytest.approx(min(pch_max, req_power + max(element.delta_p, dp)) - - min(pch_max, power_dbm + dp), abs=1e-2) - # if target power is above pch_max then gain should be saturated during propagation - assert element.effective_pch_out_db ==\ - pytest.approx(min(pch_max, req_power + max(element.delta_p, dp)), abs=1e-2) + # check that target power is correctly set + assert element.target_pch_out_db == req_power + dp + # check that designed gain is exactly applied except if target power exceeds max power, then + # gain is slightly less than the one computed during design for the noiseless reference, + # because during propagation, noise has accumulated, additing to signal. + # check that delta_p is unchanged unless for saturation + if element.target_pch_out_db > pch_max: + assert element.effective_gain == pytest.approx(element_copy.effective_gain, abs=2e-2) else: - assert element.effective_gain - element_copy.effective_gain ==\ - pytest.approx(min(pch_max, req_power + max(element.delta_p, dp)) - - min(pch_max, previous_power) - - min(pch_max, power_dbm + element.delta_p) - + min(pch_max, power_dbm + previous_deltap), abs=2e-2) - assert element.delta_p == pytest.approx(min(power_dbm + dp, pch_max) - power_dbm, abs=1e-2) - - previous_deltap = element.delta_p - previous_power = min(pch_max, req_power + max(element.delta_p, dp)) + assert element.effective_gain == element_copy.effective_gain + # check that delta_p is unchanged unless for saturation + assert element.delta_p == element_copy.delta_p + if element_is_first_amp: + # if element is first amp on path, then it is the one that will saturate if req_power is + # too high + assert mean(element.pch_out_dbm) ==\ + pytest.approx(min(pch_max, req_power + element.delta_p - element.out_voa), abs=2e-2) + # check that delta_p is unchanged unless due to saturation + assert element.delta_p == pytest.approx(min(req_power + dp, pch_max) - req_power, abs=1e-2) + # check that delta_p is unchanged unless for saturation else: # for all subkeys, before and after design should be the same for subkey in list_element_attr(getattr(element, key)): From 10164495b94f50524b59f8c62733694994854fac Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Fri, 21 Oct 2022 19:11:35 +0200 Subject: [PATCH 14/20] Remove p_spani from Pref next step: remove Pref Signed-off-by: EstherLerouzic Change-Id: I7cc17253a2d7ab3fb42e3d07c1665991cffa6222 --- gnpy/core/elements.py | 31 ------------------------------- gnpy/core/info.py | 16 +++++----------- tests/test_amplifier.py | 8 +++----- tests/test_equalization.py | 6 +++--- tests/test_info.py | 12 ++++++------ tests/test_science_utils.py | 2 +- 6 files changed, 18 insertions(+), 57 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 71a9dba38..218e7a42f 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -408,17 +408,8 @@ def propagate(self, spectral_info, degree, from_degree): self.pch_out_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase) self.propagated_labels = spectral_info.label - def update_pref(self, spectral_info): - """Update Reference power - - This modifies the spectral info in-place. Only the `pref` is updated with new p_spani, - while p_span0 is not changed. - """ - spectral_info.pref = spectral_info.pref._replace(p_spani=self.ref_pch_out_dbm) - def __call__(self, spectral_info, degree, from_degree): self.propagate(spectral_info, degree=degree, from_degree=from_degree) - self.update_pref(spectral_info) return spectral_info @@ -452,13 +443,8 @@ def __str__(self): def propagate(self, spectral_info): spectral_info.apply_attenuation_db(self.loss) - def update_pref(self, spectral_info): - spectral_info.pref = spectral_info.pref._replace(p_span0=spectral_info.pref.p_span0, - p_spani=spectral_info.pref.p_spani - self.loss) - def __call__(self, spectral_info): self.propagate(spectral_info) - self.update_pref(spectral_info) return spectral_info @@ -677,21 +663,10 @@ def propagate(self, spectral_info: SpectralInformation): self.pch_out_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase) self.propagated_labels = spectral_info.label - def update_pref(self, spectral_info): - # in case of Raman, the resulting loss of the fiber is not equivalent to self.loss - # because of Raman gain. In order to correctly update pref, we need the resulting loss: - # power_out - power_in. We use the total signal power (sum on all channels) to compute - # this loss, because pref is a noiseless reference. - loss = round(lin2db(self._psig_in / sum(spectral_info.signal)), 2) - self.pch_out_db = spectral_info.pref.p_spani - loss - spectral_info.pref = spectral_info.pref._replace(p_span0=spectral_info.pref.p_span0, - p_spani=self.pch_out_db) - def __call__(self, spectral_info): # _psig_in records the total signal power of the spectral information before propagation. self._psig_in = sum(spectral_info.signal) self.propagate(spectral_info) - self.update_pref(spectral_info) # In case of Raman, the resulting loss of the fiber is not equivalent to self.loss # because of Raman gain. The resulting loss is: # power_out - power_in. We use the total signal power (sum on all channels) to compute @@ -1120,12 +1095,6 @@ def propagate(self, spectral_info): self.pch_out_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase) self.propagated_labels = spectral_info.label - def update_pref(self, spectral_info): - spectral_info.pref = \ - spectral_info.pref._replace(p_span0=spectral_info.pref.p_span0, - p_spani=spectral_info.pref.p_spani + self.effective_gain - self.out_voa) - def __call__(self, spectral_info): self.propagate(spectral_info) - self.update_pref(spectral_info) return spectral_info diff --git a/gnpy/core/info.py b/gnpy/core/info.py index e0667b97c..725e5b1cd 100644 --- a/gnpy/core/info.py +++ b/gnpy/core/info.py @@ -45,11 +45,10 @@ class Channel( """ -class Pref(namedtuple('Pref', 'p_span0, p_spani, ref_carrier')): +class Pref(namedtuple('Pref', 'p_span0, ref_carrier')): """noiseless reference power in dBm: p_span0: inital target carrier power for a reference channel defined by user - p_spani: carrier power after element i for a reference channel defined by user ref_carrier records the baud rate of the reference channel """ @@ -240,8 +239,7 @@ def __add__(self, other: SpectralInformation): # Note that pref.p_spanx from "self" and "other" must be identical for a given simulation (correspond to the # the simulation setup): # - for a given simulation there is only one design (one p_span0), - # - and p_spani is the propagation result of p_span0 so there should not be different p_spani either. - if (self.pref.p_span0 != other.pref.p_span0) or (self.pref.p_spani != other.pref.p_spani): + if (self.pref.p_span0 != other.pref.p_span0): raise SpectrumError('reference powers of the spectrum are not identical') return SpectralInformation(frequency=append(self.frequency, other.frequency), slot_width=append(self.slot_width, other.slot_width), @@ -257,7 +255,7 @@ def __add__(self, other: SpectralInformation): delta_pdb_per_channel=append(self.delta_pdb_per_channel, other.delta_pdb_per_channel), tx_osnr=append(self.tx_osnr, other.tx_osnr), - ref_power=Pref(self.pref.p_span0, self.pref.p_spani, self.pref.ref_carrier), + ref_power=Pref(self.pref.p_span0, self.pref.ref_carrier), label=append(self.label, other.label)) except SpectrumError: raise SpectrumError('Spectra cannot be summed: channels overlapping.') @@ -329,14 +327,12 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, number_of_channels = automatic_nch(f_min, f_max, spacing) frequency = [(f_min + spacing * i) for i in range(1, number_of_channels + 1)] p_span0 = watt2dbm(power) - p_spani = watt2dbm(power) delta_pdb_per_channel = delta_pdb * ones(number_of_channels) label = [f'{baud_rate * 1e-9 :.2f}G' for i in range(number_of_channels)] return create_arbitrary_spectral_information(frequency, slot_width=spacing, signal=power, baud_rate=baud_rate, roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel, tx_osnr=tx_osnr, - ref_power=Pref(p_span0=p_span0, p_spani=p_spani, - ref_carrier=ref_carrier), + ref_power=Pref(p_span0=p_span0, ref_carrier=ref_carrier), label=label) @@ -357,12 +353,10 @@ def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier], pow tx_osnr = [c.tx_osnr for c in initial_spectrum.values()] label = [c.label for c in initial_spectrum.values()] p_span0 = watt2dbm(power) - p_spani = watt2dbm(power) return create_arbitrary_spectral_information(frequency=frequency, signal=signal, baud_rate=baud_rate, slot_width=slot_width, roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel, tx_osnr=tx_osnr, - ref_power=Pref(p_span0=p_span0, p_spani=p_spani, - ref_carrier=ref_carrier), + ref_power=Pref(p_span0=p_span0, ref_carrier=ref_carrier), label=label) diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index 751a33fb3..10dc7a2d3 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -89,7 +89,6 @@ def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si): si.ase /= db2lin(gain) edfa.operational.gain_target = gain edfa.effective_gain = gain - si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) result = edfa.nf assert pytest.approx(nf_expected, abs=0.01) == result[0] @@ -104,7 +103,6 @@ def test_fixed_gain_nf(gain, nf_expected, setup_edfa_fixed_gain, si): si.ase /= db2lin(gain) edfa.operational.gain_target = gain edfa.effective_gain = gain - si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0] @@ -130,7 +128,7 @@ def test_compare_nf_models(gain, setup_edfa_variable_gain, si): edfa.operational.gain_target = gain edfa.effective_gain = gain # edfa is variable gain type - si.pref = si.pref._replace(p_span0=0, p_spani=-gain) + si.pref = si.pref._replace(p_span0=0) edfa.interpol_params(si) nf_model = edfa.nf[0] @@ -185,7 +183,7 @@ def test_ase_noise(gain, si, setup_trx, bw): si = span(si) print(span) - si.pref = si.pref._replace(p_span0=0, p_spani=-gain) + si.pref = si.pref._replace(p_span0=0) edfa.interpol_params(si) nf = edfa.nf print('nf', nf) @@ -324,7 +322,7 @@ def test_amp_saturation(delta_pdb_per_channel, base_power, delta_p): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0]) + array(delta_pdb_per_channel) + base_power) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, p_spani=-20 + base_power, ref_carrier=ref_carrier) + pref = Pref(p_span0=0, ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, diff --git a/tests/test_equalization.py b/tests/test_equalization.py index 6a8549671..0f51beaee 100644 --- a/tests/test_equalization.py +++ b/tests/test_equalization.py @@ -79,7 +79,7 @@ def test_equalization_combination_degree(delta_pdb_per_channel, degree, equaliza baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, p_spani=0, ref_carrier=ref_carrier) + pref = Pref(p_span0=0, ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, @@ -217,7 +217,7 @@ def test_low_input_power(target_out, delta_pdb_per_channel, correction): signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) target = target_out + array(delta_pdb_per_channel) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, p_spani=-20, ref_carrier=ref_carrier) + pref = Pref(p_span0=0, ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, @@ -270,7 +270,7 @@ def test_2low_input_power(target_out, delta_pdb_per_channel, correction): signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) target = psd2powerdbm(target_out, baud_rate) + array(delta_pdb_per_channel) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, p_spani=-20, ref_carrier=ref_carrier) + pref = Pref(p_span0=0, ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, diff --git a/tests/test_info.py b/tests/test_info.py index 12de82244..1ad32873b 100644 --- a/tests/test_info.py +++ b/tests/test_info.py @@ -13,7 +13,7 @@ def test_create_arbitrary_spectral_information(): baud_rate=32e9, signal=[1, 1, 1], delta_pdb_per_channel=[1, 1, 1], tx_osnr=40.0, - ref_power=Pref(1, 1, None)) + ref_power=Pref(1, None)) assert_array_equal(si.baud_rate, array([32e9, 32e9, 32e9])) assert_array_equal(si.slot_width, array([37.5e9, 37.5e9, 37.5e9])) assert_array_equal(si.signal, ones(3)) @@ -35,7 +35,7 @@ def test_create_arbitrary_spectral_information(): slot_width=array([50e9, 50e9, 50e9]), baud_rate=32e9, signal=array([1, 2, 3]), tx_osnr=40.0, - ref_power=Pref(1, 1, None)) + ref_power=Pref(1, None)) assert_array_equal(si.signal, array([3, 2, 1])) @@ -44,16 +44,16 @@ def test_create_arbitrary_spectral_information(): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=[64e9, 32e9, 64e9], slot_width=50e9, tx_osnr=40.0, - ref_power=Pref(1, 1, None)) + ref_power=Pref(1, None)) with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral ' r'distances between channels: \[\(1, 2\), \(3, 4\)\].'): create_arbitrary_spectral_information(frequency=[193.26e12, 193.3e12, 193.35e12, 193.39e12], signal=1, - tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(1, 1, None)) + tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(1, None)) with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral ' r'distances between channels: \[\(1, 2\), \(2, 3\)\].'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=49e9, - tx_osnr=40.0, roll_off=0.1, ref_power=Pref(1, 1, None)) + tx_osnr=40.0, roll_off=0.1, ref_power=Pref(1, None)) with pytest.raises(SpectrumError, match='Dimension mismatch in input fields.'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=[1, 2], baud_rate=49e9, - tx_osnr=40.0, ref_power=Pref(1, 1, None)) + tx_osnr=40.0, ref_power=Pref(1, None)) diff --git a/tests/test_science_utils.py b/tests/test_science_utils.py index b65e0dad0..1f15831df 100644 --- a/tests/test_science_utils.py +++ b/tests/test_science_utils.py @@ -48,7 +48,7 @@ def test_fiber(): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = 1e-3 + array([0, -1e-4, 3e-4, -2e-4, +2e-4]) delta_pdb_per_channel = [0, 0, 0, 0, 0] - pref = Pref(p_span0=0, p_spani=0, ref_carrier=None) + pref = Pref(p_span0=0, ref_carrier=None) spectral_info_input = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, From 7034d4c6863901603fdaceff81cefec711b7704e Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Sat, 22 Oct 2022 19:07:22 +0200 Subject: [PATCH 15/20] Remove p_span0 from SI reference channel is defined during design. No need to convey it anymore during propagation. move target_pch_out_db definition to the design phase and change its name to be consistent with what it contains (dbm) Signed-off-by: EstherLerouzic Change-Id: I350e4557e8488a614674042de26152ab89b2d245 --- gnpy/core/elements.py | 16 +++------------- gnpy/core/info.py | 15 +++++---------- gnpy/core/network.py | 13 +++++++++++++ tests/test_amplifier.py | 4 +--- tests/test_equalization.py | 6 +++--- tests/test_info.py | 12 ++++++------ tests/test_roadm_restrictions.py | 4 ++-- tests/test_science_utils.py | 2 +- 8 files changed, 34 insertions(+), 38 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 218e7a42f..b7beeb013 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -754,7 +754,7 @@ def __init__(self, *args, params=None, operational=None, **kwargs): self.pin_db = None self.nch = None self.pout_db = None - self.target_pch_out_db = None + self.target_pch_out_dbm = None self.effective_pch_out_db = None self.passive = False self.att_in = None @@ -815,8 +815,8 @@ def __str__(self): f' Power Out (dBm): {self.pout_db:.2f}', ' Delta_P (dB): ' + (f'{self.delta_p:.2f}' if self.delta_p is not None else 'None'), - ' target pch (dBm): ' + (f'{self.target_pch_out_db:.2f}' - if self.target_pch_out_db is not None else 'None'), + ' target pch (dBm): ' + (f'{self.target_pch_out_dbm:.2f}' + if self.target_pch_out_dbm is not None else 'None'), f' actual pch out (dBm): {total_pch}', f' output VOA (dB): {self.out_voa:.2f}']) @@ -844,16 +844,6 @@ def interpol_params(self, spectral_info): # For now, with homogeneous spectrum, we can calculate it as the difference between neighbouring channels. self.slot_width = self.channel_freq[1] - self.channel_freq[0] - """in power mode: delta_p is defined and can be used to calculate the power target - This power target correspond to the channel used for design""" - pref = spectral_info.pref - if self.delta_p is not None and self.operational.delta_p is not None: - # use the user defined target - self.target_pch_out_db = round(self.operational.delta_p + pref.p_span0, 2) - elif self.delta_p is not None: - # use the design target if no target were set - self.target_pch_out_db = round(self.delta_p + pref.p_span0, 2) - """check power saturation and correct effective gain & power accordingly:""" # Compute the saturation accounting for actual power at the input of the amp self.effective_gain = min( diff --git a/gnpy/core/info.py b/gnpy/core/info.py index 725e5b1cd..e7b11299f 100644 --- a/gnpy/core/info.py +++ b/gnpy/core/info.py @@ -45,10 +45,9 @@ class Channel( """ -class Pref(namedtuple('Pref', 'p_span0, ref_carrier')): - """noiseless reference power in dBm: +class Pref(namedtuple('Pref', 'ref_carrier')): + """reference channel used during design: - p_span0: inital target carrier power for a reference channel defined by user ref_carrier records the baud rate of the reference channel """ @@ -238,9 +237,6 @@ def __add__(self, other: SpectralInformation): try: # Note that pref.p_spanx from "self" and "other" must be identical for a given simulation (correspond to the # the simulation setup): - # - for a given simulation there is only one design (one p_span0), - if (self.pref.p_span0 != other.pref.p_span0): - raise SpectrumError('reference powers of the spectrum are not identical') return SpectralInformation(frequency=append(self.frequency, other.frequency), slot_width=append(self.slot_width, other.slot_width), signal=append(self.signal, other.signal), nli=append(self.nli, other.nli), @@ -255,7 +251,7 @@ def __add__(self, other: SpectralInformation): delta_pdb_per_channel=append(self.delta_pdb_per_channel, other.delta_pdb_per_channel), tx_osnr=append(self.tx_osnr, other.tx_osnr), - ref_power=Pref(self.pref.p_span0, self.pref.ref_carrier), + ref_power=Pref(self.pref.ref_carrier), label=append(self.label, other.label)) except SpectrumError: raise SpectrumError('Spectra cannot be summed: channels overlapping.') @@ -326,13 +322,12 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, all arguments are scalar values""" number_of_channels = automatic_nch(f_min, f_max, spacing) frequency = [(f_min + spacing * i) for i in range(1, number_of_channels + 1)] - p_span0 = watt2dbm(power) delta_pdb_per_channel = delta_pdb * ones(number_of_channels) label = [f'{baud_rate * 1e-9 :.2f}G' for i in range(number_of_channels)] return create_arbitrary_spectral_information(frequency, slot_width=spacing, signal=power, baud_rate=baud_rate, roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel, tx_osnr=tx_osnr, - ref_power=Pref(p_span0=p_span0, ref_carrier=ref_carrier), + ref_power=Pref(ref_carrier=ref_carrier), label=label) @@ -356,7 +351,7 @@ def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier], pow return create_arbitrary_spectral_information(frequency=frequency, signal=signal, baud_rate=baud_rate, slot_width=slot_width, roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel, tx_osnr=tx_osnr, - ref_power=Pref(p_span0=p_span0, ref_carrier=ref_carrier), + ref_power=Pref(ref_carrier=ref_carrier), label=label) diff --git a/gnpy/core/network.py b/gnpy/core/network.py index 371b3eaa0..0b7e4a62c 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -374,10 +374,23 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d node.delta_p = dp if power_mode else None node.effective_gain = gain_target + # if voa is not set, then set it and possibly optimize it with gain and update delta_p and + # effective_gain values set_amplifier_voa(node, power_target, power_mode) # set_amplifier_voa may change delta_p in power_mode node._delta_p = node.delta_p if power_mode else dp + # target_pch_out_dbm records target power for design: If user defines one, then this is displayed, + # else display the one computed during design + if node.delta_p is not None and node.operational.delta_p is not None: + # use the user defined target + node.target_pch_out_dbm = round(node.operational.delta_p + pref_ch_db, 2) + elif node.delta_p is not None: + # use the design target if no target were set + node.target_pch_out_dbm = round(node.delta_p + pref_ch_db, 2) + elif node.delta_p is None: + node.target_pch_out_dbm = None + prev_dp = dp prev_voa = voa prev_node = node diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index 10dc7a2d3..415d660af 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -128,7 +128,6 @@ def test_compare_nf_models(gain, setup_edfa_variable_gain, si): edfa.operational.gain_target = gain edfa.effective_gain = gain # edfa is variable gain type - si.pref = si.pref._replace(p_span0=0) edfa.interpol_params(si) nf_model = edfa.nf[0] @@ -183,7 +182,6 @@ def test_ase_noise(gain, si, setup_trx, bw): si = span(si) print(span) - si.pref = si.pref._replace(p_span0=0) edfa.interpol_params(si) nf = edfa.nf print('nf', nf) @@ -322,7 +320,7 @@ def test_amp_saturation(delta_pdb_per_channel, base_power, delta_p): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0]) + array(delta_pdb_per_channel) + base_power) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, ref_carrier=ref_carrier) + pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, diff --git a/tests/test_equalization.py b/tests/test_equalization.py index 0f51beaee..819f644a6 100644 --- a/tests/test_equalization.py +++ b/tests/test_equalization.py @@ -79,7 +79,7 @@ def test_equalization_combination_degree(delta_pdb_per_channel, degree, equaliza baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, ref_carrier=ref_carrier) + pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, @@ -217,7 +217,7 @@ def test_low_input_power(target_out, delta_pdb_per_channel, correction): signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) target = target_out + array(delta_pdb_per_channel) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, ref_carrier=ref_carrier) + pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, @@ -270,7 +270,7 @@ def test_2low_input_power(target_out, delta_pdb_per_channel, correction): signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) target = psd2powerdbm(target_out, baud_rate) + array(delta_pdb_per_channel) ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(p_span0=0, ref_carrier=ref_carrier) + pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, diff --git a/tests/test_info.py b/tests/test_info.py index 1ad32873b..67cf4f4c3 100644 --- a/tests/test_info.py +++ b/tests/test_info.py @@ -13,7 +13,7 @@ def test_create_arbitrary_spectral_information(): baud_rate=32e9, signal=[1, 1, 1], delta_pdb_per_channel=[1, 1, 1], tx_osnr=40.0, - ref_power=Pref(1, None)) + ref_power=Pref(None)) assert_array_equal(si.baud_rate, array([32e9, 32e9, 32e9])) assert_array_equal(si.slot_width, array([37.5e9, 37.5e9, 37.5e9])) assert_array_equal(si.signal, ones(3)) @@ -35,7 +35,7 @@ def test_create_arbitrary_spectral_information(): slot_width=array([50e9, 50e9, 50e9]), baud_rate=32e9, signal=array([1, 2, 3]), tx_osnr=40.0, - ref_power=Pref(1, None)) + ref_power=Pref(None)) assert_array_equal(si.signal, array([3, 2, 1])) @@ -44,16 +44,16 @@ def test_create_arbitrary_spectral_information(): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=[64e9, 32e9, 64e9], slot_width=50e9, tx_osnr=40.0, - ref_power=Pref(1, None)) + ref_power=Pref(None)) with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral ' r'distances between channels: \[\(1, 2\), \(3, 4\)\].'): create_arbitrary_spectral_information(frequency=[193.26e12, 193.3e12, 193.35e12, 193.39e12], signal=1, - tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(1, None)) + tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(None)) with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral ' r'distances between channels: \[\(1, 2\), \(2, 3\)\].'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=49e9, - tx_osnr=40.0, roll_off=0.1, ref_power=Pref(1, None)) + tx_osnr=40.0, roll_off=0.1, ref_power=Pref(None)) with pytest.raises(SpectrumError, match='Dimension mismatch in input fields.'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=[1, 2], baud_rate=49e9, - tx_osnr=40.0, ref_power=Pref(1, None)) + tx_osnr=40.0, ref_power=Pref(None)) diff --git a/tests/test_roadm_restrictions.py b/tests/test_roadm_restrictions.py index afe48e16f..878356c2c 100644 --- a/tests/test_roadm_restrictions.py +++ b/tests/test_roadm_restrictions.py @@ -494,12 +494,12 @@ def test_compare_design_propagation_settings(power_dbm, req_power, amp_with_delt else: dp = element.out_voa if element.uid not in amp_with_deltap_one else element.out_voa + 1 # check that target power is correctly set - assert element.target_pch_out_db == req_power + dp + assert element.target_pch_out_dbm == req_power + dp # check that designed gain is exactly applied except if target power exceeds max power, then # gain is slightly less than the one computed during design for the noiseless reference, # because during propagation, noise has accumulated, additing to signal. # check that delta_p is unchanged unless for saturation - if element.target_pch_out_db > pch_max: + if element.target_pch_out_dbm > pch_max: assert element.effective_gain == pytest.approx(element_copy.effective_gain, abs=2e-2) else: assert element.effective_gain == element_copy.effective_gain diff --git a/tests/test_science_utils.py b/tests/test_science_utils.py index 1f15831df..f18c539cf 100644 --- a/tests/test_science_utils.py +++ b/tests/test_science_utils.py @@ -48,7 +48,7 @@ def test_fiber(): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = 1e-3 + array([0, -1e-4, 3e-4, -2e-4, +2e-4]) delta_pdb_per_channel = [0, 0, 0, 0, 0] - pref = Pref(p_span0=0, ref_carrier=None) + pref = Pref(ref_carrier=None) spectral_info_input = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, From 139c8cc1e753fbdc9fccc853f3af735abd986d7e Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Sun, 23 Oct 2022 08:36:57 +0200 Subject: [PATCH 16/20] Remove Pref, and move ref_carrier definition Finally, ref_carrier is not meant to change after design since it is the carrier used for design. So let's move its definition to networks function. Only ROADM need the ref_carrier baud rate so let's define a dedicated variable in ROADM to hold it. Signed-off-by: EstherLerouzic Change-Id: Ida7e42dd534a04c8df8792b44980f3fd2165ecb6 --- gnpy/core/elements.py | 18 ++++++------- gnpy/core/info.py | 43 ++++++-------------------------- gnpy/core/network.py | 28 +++++++++++---------- gnpy/topology/request.py | 20 +++------------ tests/test_amplifier.py | 10 +++----- tests/test_equalization.py | 21 ++++++---------- tests/test_info.py | 17 ++++++------- tests/test_propagation.py | 5 ++-- tests/test_roadm_restrictions.py | 4 +-- tests/test_science_utils.py | 17 ++++--------- 10 files changed, 62 insertions(+), 121 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index b7beeb013..0305837eb 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -259,6 +259,7 @@ def __init__(self, *args, params=None, **kwargs): self.per_degree_pch_psd = self.params.per_degree_pch_psd self.per_degree_pch_psw = self.params.per_degree_pch_psw self.ref_pch_in_dbm = {} + self.ref_carrier = None @property def to_json(self): @@ -303,8 +304,7 @@ def __str__(self): f' reference pch out (dBm): {self.ref_pch_out_dbm:.2f}', f' actual pch out (dBm): {total_pch}']) - def get_roadm_target_power(self, ref_carrier: ReferenceCarrier = None, - spectral_info: SpectralInformation = None) -> Union[float, ndarray]: + def get_roadm_target_power(self, spectral_info: SpectralInformation = None) -> Union[float, ndarray]: """Computes the power in dBm for a reference carrier or for a spectral information. power is computed based on equalization target. if spectral_info baud_rate is baud_rate = [32e9, 42e9, 64e9, 42e9, 32e9], and @@ -326,22 +326,22 @@ def get_roadm_target_power(self, ref_carrier: ReferenceCarrier = None, if self.target_pch_out_dbm is not None: return self.target_pch_out_dbm if self.target_psd_out_mWperGHz is not None: - return psd2powerdbm(self.target_psd_out_mWperGHz, ref_carrier.baud_rate) + return psd2powerdbm(self.target_psd_out_mWperGHz, self.ref_carrier.baud_rate) if self.target_out_mWperSlotWidth is not None: - return psd2powerdbm(self.target_out_mWperSlotWidth, ref_carrier.slot_width) + return psd2powerdbm(self.target_out_mWperSlotWidth, self.ref_carrier.slot_width) return None - def get_per_degree_ref_power(self, degree, ref_carrier): + def get_per_degree_ref_power(self, degree): """Get the target power in dBm out of ROADM degree for the reference bandwidth If no equalization is defined on this degree use the ROADM level one. """ if degree in self.per_degree_pch_out_dbm: return self.per_degree_pch_out_dbm[degree] elif degree in self.per_degree_pch_psd: - return psd2powerdbm(self.per_degree_pch_psd[degree], ref_carrier.baud_rate) + return psd2powerdbm(self.per_degree_pch_psd[degree], self.ref_carrier.baud_rate) elif degree in self.per_degree_pch_psw: - return psd2powerdbm(self.per_degree_pch_psw[degree], ref_carrier.slot_width) - return self.get_roadm_target_power(ref_carrier) + return psd2powerdbm(self.per_degree_pch_psw[degree], self.ref_carrier.slot_width) + return self.get_roadm_target_power() def get_per_degree_power(self, degree, spectral_info): """Get the target power in dBm out of ROADM degree for the spectral information @@ -366,7 +366,7 @@ def propagate(self, spectral_info, degree, from_degree): # TODO maybe add a minimum loss for the ROADM # find the target power for the reference carrier - ref_per_degree_pch = self.get_per_degree_ref_power(degree, spectral_info.pref.ref_carrier) + ref_per_degree_pch = self.get_per_degree_ref_power(degree) # find the target powers for each signal carrier per_degree_pch = self.get_per_degree_power(degree, spectral_info=spectral_info) diff --git a/gnpy/core/info.py b/gnpy/core/info.py index e7b11299f..711c7c137 100644 --- a/gnpy/core/info.py +++ b/gnpy/core/info.py @@ -45,13 +45,6 @@ class Channel( """ -class Pref(namedtuple('Pref', 'ref_carrier')): - """reference channel used during design: - - ref_carrier records the baud rate of the reference channel - """ - - class SpectralInformation(object): """Class containing the parameters of the entire WDM comb. @@ -59,7 +52,7 @@ class SpectralInformation(object): def __init__(self, frequency: array, baud_rate: array, slot_width: array, signal: array, nli: array, ase: array, roll_off: array, chromatic_dispersion: array, pmd: array, pdl: array, latency: array, - delta_pdb_per_channel: array, tx_osnr: array, ref_power: Pref, label: array): + delta_pdb_per_channel: array, tx_osnr: array, label: array): indices = argsort(frequency) self._frequency = frequency[indices] self._df = outer(ones(frequency.shape), frequency) - outer(frequency, ones(frequency.shape)) @@ -87,18 +80,8 @@ def __init__(self, frequency: array, baud_rate: array, slot_width: array, signal self._latency = latency[indices] self._delta_pdb_per_channel = delta_pdb_per_channel[indices] self._tx_osnr = tx_osnr[indices] - self._pref = ref_power self._label = label[indices] - @property - def pref(self): - """Instance of gnpy.info.Pref""" - return self._pref - - @pref.setter - def pref(self, pref: Pref): - self._pref = pref - @property def frequency(self): return self._frequency @@ -235,8 +218,6 @@ def apply_gain_db(self, gain_db): def __add__(self, other: SpectralInformation): try: - # Note that pref.p_spanx from "self" and "other" must be identical for a given simulation (correspond to the - # the simulation setup): return SpectralInformation(frequency=append(self.frequency, other.frequency), slot_width=append(self.slot_width, other.slot_width), signal=append(self.signal, other.signal), nli=append(self.nli, other.nli), @@ -251,13 +232,11 @@ def __add__(self, other: SpectralInformation): delta_pdb_per_channel=append(self.delta_pdb_per_channel, other.delta_pdb_per_channel), tx_osnr=append(self.tx_osnr, other.tx_osnr), - ref_power=Pref(self.pref.ref_carrier), label=append(self.label, other.label)) except SpectrumError: raise SpectrumError('Spectra cannot be summed: channels overlapping.') - - def _replace(self, carriers, pref): + def _replace(self, carriers): self.chromatic_dispersion = array([c.chromatic_dispersion for c in carriers]) self.pmd = array([c.pmd for c in carriers]) self.pdl = array([c.pdl for c in carriers]) @@ -265,7 +244,6 @@ def _replace(self, carriers, pref): self.signal = array([c.power.signal for c in carriers]) self.nli = array([c.power.nli for c in carriers]) self.ase = array([c.power.ase for c in carriers]) - self.pref = pref return self @@ -280,7 +258,6 @@ def create_arbitrary_spectral_information(frequency: Union[ndarray, Iterable, fl pmd: Union[float, ndarray, Iterable] = 0., pdl: Union[float, ndarray, Iterable] = 0., latency: Union[float, ndarray, Iterable] = 0., - ref_power: Pref = None, label: Union[str, ndarray, Iterable] = None): """This is just a wrapper around the SpectralInformation.__init__() that simplifies the creation of a non-uniform spectral information with NLI and ASE powers set to zero.""" @@ -307,8 +284,7 @@ def create_arbitrary_spectral_information(frequency: Union[ndarray, Iterable, fl chromatic_dispersion=chromatic_dispersion, pmd=pmd, pdl=pdl, latency=latency, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=tx_osnr, - ref_power=ref_power, label=label) + tx_osnr=tx_osnr, label=label) except ValueError as e: if 'could not broadcast' in str(e): raise SpectrumError('Dimension mismatch in input fields.') @@ -316,8 +292,7 @@ def create_arbitrary_spectral_information(frequency: Union[ndarray, Iterable, fl raise -def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing, tx_osnr, delta_pdb=0, - ref_carrier=None): +def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing, tx_osnr, delta_pdb=0): """Creates a fixed slot width spectral information with flat power. all arguments are scalar values""" number_of_channels = automatic_nch(f_min, f_max, spacing) @@ -326,18 +301,15 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, label = [f'{baud_rate * 1e-9 :.2f}G' for i in range(number_of_channels)] return create_arbitrary_spectral_information(frequency, slot_width=spacing, signal=power, baud_rate=baud_rate, roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=tx_osnr, - ref_power=Pref(ref_carrier=ref_carrier), - label=label) + tx_osnr=tx_osnr, label=label) -def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier], power: float, - ref_carrier: ReferenceCarrier) -> SpectralInformation: +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. :param initial_spectrum: indexed by frequency in Hz, with power offset (delta_pdb), baudrate, slot width, tx_osnr and roll off. :param power: power of the request - :param ref_carrier: reference carrier (baudrate) used for the reference channel """ frequency = list(initial_spectrum.keys()) signal = [power * db2lin(c.delta_pdb) for c in initial_spectrum.values()] @@ -351,7 +323,6 @@ def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier], pow return create_arbitrary_spectral_information(frequency=frequency, signal=signal, baud_rate=baud_rate, slot_width=slot_width, roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel, tx_osnr=tx_osnr, - ref_power=Pref(ref_carrier=ref_carrier), label=label) diff --git a/gnpy/core/network.py b/gnpy/core/network.py index 0b7e4a62c..d44e0b83a 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -280,8 +280,6 @@ def set_amplifier_voa(amp, power_target, power_mode): def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_db, verbose): """this node can be a transceiver or a ROADM (same function called in both cases)""" power_mode = equipment['Span']['default'].power_mode - ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, - slot_width=equipment['SI']['default'].spacing) next_oms = (n for n in network.successors(this_node) if not isinstance(n, elements.Transceiver)) for oms in next_oms: # go through all the OMS departing from the ROADM @@ -291,7 +289,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d this_node_out_power = 0.0 # default value if this_node is a transceiver if isinstance(this_node, elements.Roadm): # get target power out from ROADM for the reference carrier based on equalization settings - this_node_out_power = this_node.get_per_degree_ref_power(degree=node.uid, ref_carrier=ref_carrier) + this_node_out_power = this_node.get_per_degree_ref_power(degree=node.uid) # use the target power on this degree prev_dp = this_node_out_power - pref_ch_db dp = prev_dp @@ -397,6 +395,13 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d node = next_node +def set_roadm_ref_carrier(roadm, equipment): + """ref_carrier records carrier information used for design and usefull for equalization + """ + roadm.ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, + slot_width=equipment['SI']['default'].spacing) + + def set_roadm_per_degree_targets(roadm, network): """Set target powers/PSD on all degrees This is needed to populate per_degree_pch_out_dbm or per_degree_pch_psd or per_degree_pch_psw dicts when @@ -435,8 +440,6 @@ def set_roadm_input_powers(network, roadm, equipment, pref_ch_db): User should be aware that design was not successfull and that power reduction was applied. Note that this value is only used for visualisation purpose (to compute ROADM loss in elements). """ - ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, - slot_width=equipment['SI']['default'].spacing) previous_elements = [n for n in network.predecessors(roadm)] roadm.ref_pch_in_dbm = {} for element in previous_elements: @@ -452,7 +455,7 @@ def set_roadm_input_powers(network, roadm, equipment, pref_ch_db): roadm.ref_pch_in_dbm[element.uid] = pref_ch_db + node._delta_p - node.out_voa - loss elif isinstance(node, elements.Roadm): roadm.ref_pch_in_dbm[element.uid] = \ - node.get_per_degree_ref_power(degree=previous_node.uid, ref_carrier=ref_carrier) - loss + node.get_per_degree_ref_power(degree=previous_node.uid) - loss elif isinstance(node, elements.Transceiver): roadm.ref_pch_in_dbm[element.uid] = pref_ch_db - loss # check if target power can be met @@ -460,15 +463,15 @@ def set_roadm_input_powers(network, roadm, equipment, pref_ch_db): if roadm.per_degree_pch_out_dbm: temp.append(max([p for p in roadm.per_degree_pch_out_dbm.values()])) if roadm.per_degree_pch_psd: - temp.append(max([psd2powerdbm(p, ref_carrier.baud_rate) for p in roadm.per_degree_pch_psd.values()])) + temp.append(max([psd2powerdbm(p, roadm.ref_carrier.baud_rate) for p in roadm.per_degree_pch_psd.values()])) if roadm.per_degree_pch_psw: - temp.append(max([psd2powerdbm(p, ref_carrier.slot_width) for p in roadm.per_degree_pch_psw.values()])) + temp.append(max([psd2powerdbm(p, roadm.ref_carrier.slot_width) for p in roadm.per_degree_pch_psw.values()])) if roadm.params.target_pch_out_db: temp.append(roadm.params.target_pch_out_db) if roadm.params.target_psd_out_mWperGHz: - temp.append(psd2powerdbm(roadm.params.target_psd_out_mWperGHz, ref_carrier.baud_rate)) + temp.append(psd2powerdbm(roadm.params.target_psd_out_mWperGHz, roadm.ref_carrier.baud_rate)) if roadm.params.target_out_mWperSlotWidth: - temp.append(psd2powerdbm(roadm.params.target_out_mWperSlotWidth, ref_carrier.slot_width)) + temp.append(psd2powerdbm(roadm.params.target_out_mWperSlotWidth, roadm.ref_carrier.slot_width)) if not temp: raise ConfigurationError(f'Could not find target power/PSD/PSW in ROADM "{roadm.uid}"') target_to_be_supported = max(temp) @@ -486,8 +489,6 @@ def set_fiber_input_power(network, fiber, equipment, pref_ch_db): Supposes that target power out of ROADMs and amplifiers are consistent. This is only for visualisation purpose """ - ref_carrier = ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, - slot_width=equipment['SI']['default'].spacing) loss = 0.0 node = next(network.predecessors(fiber)) while isinstance(node, elements.Fused): @@ -501,7 +502,7 @@ def set_fiber_input_power(network, fiber, equipment, pref_ch_db): fiber.ref_pch_in_dbm = node.ref_pch_in_dbm - loss - node.loss elif isinstance(node, elements.Roadm): fiber.ref_pch_in_dbm = \ - node.get_per_degree_ref_power(degree=previous_node.uid, ref_carrier=ref_carrier) - loss + node.get_per_degree_ref_power(degree=previous_node.uid) - loss elif isinstance(node, elements.Edfa): fiber.ref_pch_in_dbm = pref_ch_db + node._delta_p - node.out_voa - loss elif isinstance(node, elements.Transceiver): @@ -737,6 +738,7 @@ def build_network(network, equipment, pref_ch_db, pref_total_db, set_connector_l add_missing_fiber_attributes(network, equipment) # set roadm equalization targets first for roadm in roadms: + set_roadm_ref_carrier(roadm, equipment) set_roadm_per_degree_targets(roadm, network) # then set amplifiers gain, delta_p and out_voa on each OMS for roadm in roadms + transceivers: diff --git a/gnpy/topology/request.py b/gnpy/topology/request.py index 33c17cc46..50ba90ee1 100644 --- a/gnpy/topology/request.py +++ b/gnpy/topology/request.py @@ -23,7 +23,7 @@ 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, ReferenceCarrier +from gnpy.core.info import create_input_spectral_information, carriers_to_spectral_information from gnpy.core import network as network_module from gnpy.core.exceptions import ServiceError, DisjunctionError from copy import deepcopy @@ -330,25 +330,14 @@ def compute_constrained_path(network, req): return total_path -def ref_carrier(equipment): - """Create a reference carier based SI information with the specified request's power: - req_power records the power in W that the user has defined for a given request - (which might be different from the one used for the design). - """ - return ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, - slot_width=equipment['SI']['default'].spacing) - - def propagate(path, req, equipment): """propagates signals in each element according to initial spectrum set by user""" if req.initial_spectrum is not None: - si = carriers_to_spectral_information(initial_spectrum=req.initial_spectrum, - power=req.power, ref_carrier=ref_carrier(equipment)) + 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, - power=req.power, spacing=req.spacing, tx_osnr=req.tx_osnr, delta_pdb=req.offset_db, - ref_carrier=ref_carrier(equipment)) + power=req.power, spacing=req.spacing, tx_osnr=req.tx_osnr, delta_pdb=req.offset_db) for i, el in enumerate(path): if isinstance(el, Roadm): si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid) @@ -392,8 +381,7 @@ def propagate_and_optimize_mode(path, req, equipment): spc_info = create_input_spectral_information(f_min=req.f_min, f_max=req.f_max, roll_off=equipment['SI']['default'].roll_off, baud_rate=this_br, power=req.power, spacing=req.spacing, - delta_pdb=this_offset, - tx_osnr=req.tx_osnr, ref_carrier=ref_carrier(equipment)) + delta_pdb=this_offset, tx_osnr=req.tx_osnr) for i, el in enumerate(path): if isinstance(el, Roadm): spc_info = el(spc_info, degree=path[i + 1].uid, from_degree=path[i - 1].uid) diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index 415d660af..f0eea2c34 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -7,8 +7,7 @@ from numpy.testing import assert_allclose from gnpy.core.elements import Transceiver, Edfa, Fiber from gnpy.core.utils import automatic_fmax, lin2db, db2lin, merge_amplifier_restrictions, dbm2watt, watt2dbm -from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information, Pref, \ - ReferenceCarrier +from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information from gnpy.core.network import build_network from gnpy.tools.json_io import load_network, load_equipment, network_from_json from pathlib import Path @@ -76,8 +75,7 @@ def si(nch_and_spacing, bw): f_min = 191.3e12 f_max = automatic_fmax(f_min, spacing, nb_channel) return create_input_spectral_information(f_min=f_min, f_max=f_max, roll_off=0.15, baud_rate=bw, power=1e-3, - spacing=spacing, tx_osnr=40.0, - ref_carrier=ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) + spacing=spacing, tx_osnr=40.0) @pytest.mark.parametrize("gain, nf_expected", [(10, 15), (15, 10), (25, 5.8)]) @@ -319,12 +317,10 @@ def test_amp_saturation(delta_pdb_per_channel, base_power, delta_p): slot_width = array([37.5e9, 50e9, 75e9, 50e9, 37.5e9]) baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0]) + array(delta_pdb_per_channel) + base_power) - ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=None, ref_power=pref) + tx_osnr=None) total_sig_powerin = sum(si.signal) sig_in = lin2db(si.signal) si = edfa(si) diff --git a/tests/test_equalization.py b/tests/test_equalization.py index 819f644a6..1277c753d 100644 --- a/tests/test_equalization.py +++ b/tests/test_equalization.py @@ -17,8 +17,7 @@ from gnpy.core.utils import lin2db, automatic_nch, dbm2watt, power_dbm_to_psd_mw_ghz, watt2dbm, psd2powerdbm from gnpy.core.network import build_network from gnpy.core.elements import Roadm -from gnpy.core.info import create_input_spectral_information, Pref, create_arbitrary_spectral_information, \ - ReferenceCarrier +from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information, ReferenceCarrier from gnpy.core.equipment import trx_mode_params from gnpy.core.exceptions import ConfigurationError from gnpy.tools.json_io import network_from_json, load_equipment, load_network, _spectrum_from_json, load_json, \ @@ -74,16 +73,15 @@ def test_equalization_combination_degree(delta_pdb_per_channel, degree, equaliza } roadm = Roadm(**roadm_config) roadm.ref_pch_in_dbm['tata'] = 0 + roadm.ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) frequency = 191e12 + array([0, 50e9, 150e9, 225e9, 275e9]) slot_width = array([37.5e9, 50e9, 75e9, 50e9, 37.5e9]) baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) - ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=None, ref_power=pref) + tx_osnr=None) to_json_before_propagation = { 'uid': 'roadm Lannion_CAS', 'type': 'Roadm', @@ -216,12 +214,10 @@ def test_low_input_power(target_out, delta_pdb_per_channel, correction): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) target = target_out + array(delta_pdb_per_channel) - ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=None, ref_power=pref) + tx_osnr=None) roadm_config = { "uid": "roadm Brest_KLA", "params": { @@ -246,6 +242,7 @@ def test_low_input_power(target_out, delta_pdb_per_channel, correction): } roadm = Roadm(**roadm_config) roadm.ref_pch_in_dbm['tata'] = 0 + roadm.ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) si = roadm(si, degree='toto', from_degree='tata') assert_allclose(watt2dbm(si.signal), target - correction, rtol=1e-5) # in other words check that if target is below input power, target is applied else power is unchanged @@ -269,12 +266,10 @@ def test_2low_input_power(target_out, delta_pdb_per_channel, correction): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = dbm2watt(array([-20.0, -18.0, -22.0, -25.0, -16.0])) target = psd2powerdbm(target_out, baud_rate) + array(delta_pdb_per_channel) - ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) - pref = Pref(ref_carrier=ref_carrier) si = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=None, ref_power=pref) + tx_osnr=None) roadm_config = { "uid": "roadm Brest_KLA", "params": { @@ -299,6 +294,7 @@ def test_2low_input_power(target_out, delta_pdb_per_channel, correction): } roadm = Roadm(**roadm_config) roadm.ref_pch_in_dbm['tata'] = 0 + roadm.ref_carrier = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) si = roadm(si, degree='toto', from_degree='tata') assert_allclose(watt2dbm(si.signal), target - correction, rtol=1e-5) @@ -511,7 +507,6 @@ def test_equalization(case, deltap, target, mode, slot_width, equalization): # boosters = ['east edfa in Brest_KLA to Quimper', 'east edfa in Lorient_KMA to Loudeac', # 'east edfa in Lannion_CAS to Stbrieuc'] target_psd = power_dbm_to_psd_mw_ghz(target, 32e9) - ref = ReferenceCarrier(baud_rate=32e9, slot_width=50e9) if case == 'SI': delattr(equipment['Roadm']['default'], 'target_pch_out_db') setattr(equipment['Roadm']['default'], equalization, target_psd) @@ -537,7 +532,7 @@ def test_equalization(case, deltap, target, mode, slot_width, equalization): path = compute_constrained_path(network, req) 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, power=req.power, - spacing=req.spacing, tx_osnr=req.tx_osnr, ref_carrier=ref) + spacing=req.spacing, tx_osnr=req.tx_osnr) for i, el in enumerate(path): if isinstance(el, Roadm): si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid) diff --git a/tests/test_info.py b/tests/test_info.py index 67cf4f4c3..cceaeae27 100644 --- a/tests/test_info.py +++ b/tests/test_info.py @@ -4,7 +4,7 @@ import pytest from numpy import array, zeros, ones from numpy.testing import assert_array_equal -from gnpy.core.info import create_arbitrary_spectral_information, Pref +from gnpy.core.info import create_arbitrary_spectral_information from gnpy.core.exceptions import SpectrumError @@ -12,8 +12,7 @@ def test_create_arbitrary_spectral_information(): si = create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], baud_rate=32e9, signal=[1, 1, 1], delta_pdb_per_channel=[1, 1, 1], - tx_osnr=40.0, - ref_power=Pref(None)) + tx_osnr=40.0) assert_array_equal(si.baud_rate, array([32e9, 32e9, 32e9])) assert_array_equal(si.slot_width, array([37.5e9, 37.5e9, 37.5e9])) assert_array_equal(si.signal, ones(3)) @@ -34,8 +33,7 @@ def test_create_arbitrary_spectral_information(): si = create_arbitrary_spectral_information(frequency=array([193.35e12, 193.3e12, 193.25e12]), slot_width=array([50e9, 50e9, 50e9]), baud_rate=32e9, signal=array([1, 2, 3]), - tx_osnr=40.0, - ref_power=Pref(None)) + tx_osnr=40.0) assert_array_equal(si.signal, array([3, 2, 1])) @@ -43,17 +41,16 @@ def test_create_arbitrary_spectral_information(): r'larger than the slot width for channels: \[1, 3\].'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=[64e9, 32e9, 64e9], slot_width=50e9, - tx_osnr=40.0, - ref_power=Pref(None)) + tx_osnr=40.0) with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral ' r'distances between channels: \[\(1, 2\), \(3, 4\)\].'): create_arbitrary_spectral_information(frequency=[193.26e12, 193.3e12, 193.35e12, 193.39e12], signal=1, - tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(None)) + tx_osnr=40.0, baud_rate=32e9, slot_width=50e9) with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral ' r'distances between channels: \[\(1, 2\), \(2, 3\)\].'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=49e9, - tx_osnr=40.0, roll_off=0.1, ref_power=Pref(None)) + tx_osnr=40.0, roll_off=0.1) with pytest.raises(SpectrumError, match='Dimension mismatch in input fields.'): create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=[1, 2], baud_rate=49e9, - tx_osnr=40.0, ref_power=Pref(None)) + tx_osnr=40.0) diff --git a/tests/test_propagation.py b/tests/test_propagation.py index 63e4e3a65..9a008248c 100644 --- a/tests/test_propagation.py +++ b/tests/test_propagation.py @@ -6,7 +6,7 @@ import pytest from gnpy.core.elements import Transceiver, Fiber, Edfa, Roadm from gnpy.core.utils import db2lin -from gnpy.core.info import create_input_spectral_information, ReferenceCarrier +from gnpy.core.info import create_input_spectral_information from gnpy.core.network import build_network from gnpy.tools.json_io import load_network, load_equipment from pathlib import Path @@ -47,8 +47,7 @@ def propagation(input_power, con_in, con_out, dest): p = db2lin(p) * 1e-3 spacing = 50e9 # THz si = create_input_spectral_information(f_min=191.3e12, f_max=191.3e12 + 79 * spacing, roll_off=0.15, - baud_rate=32e9, power=p, spacing=spacing, tx_osnr=None, - ref_carrier=ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) + baud_rate=32e9, power=p, spacing=spacing, tx_osnr=None) source = next(transceivers[uid] for uid in transceivers if uid == 'trx A') sink = next(transceivers[uid] for uid in transceivers if uid == dest) path = dijkstra_path(network, source, sink) diff --git a/tests/test_roadm_restrictions.py b/tests/test_roadm_restrictions.py index 878356c2c..4055bb8d7 100644 --- a/tests/test_roadm_restrictions.py +++ b/tests/test_roadm_restrictions.py @@ -21,7 +21,7 @@ from gnpy.core.network import build_network, design_network from gnpy.tools.json_io import network_from_json, load_equipment, load_json, Amp from gnpy.core.equipment import trx_mode_params -from gnpy.topology.request import PathRequest, compute_constrained_path, ref_carrier, propagate +from gnpy.topology.request import PathRequest, compute_constrained_path, propagate from gnpy.core.info import create_input_spectral_information, Carrier from gnpy.core.utils import db2lin, dbm2watt @@ -258,7 +258,7 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm): path = compute_constrained_path(network, req) 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, - power=req.power, spacing=req.spacing, tx_osnr=req.tx_osnr, ref_carrier=ref_carrier(equipment)) + power=req.power, spacing=req.spacing, tx_osnr=req.tx_osnr) for i, el in enumerate(path): if isinstance(el, Roadm): power_in_roadm = si.signal + si.ase + si.nli diff --git a/tests/test_science_utils.py b/tests/test_science_utils.py index f18c539cf..7bc7d1236 100644 --- a/tests/test_science_utils.py +++ b/tests/test_science_utils.py @@ -12,8 +12,7 @@ from numpy import array import pytest -from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information, Pref, \ - ReferenceCarrier +from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information from gnpy.core.elements import Fiber, RamanFiber from gnpy.core.parameters import SimParams from gnpy.tools.json_io import load_json @@ -29,9 +28,7 @@ def test_fiber(): fiber.ref_pch_in_dbm = 0.0 # fix grid spectral information generation spectral_info_input = create_input_spectral_information(f_min=191.3e12, f_max=196.1e12, roll_off=0.15, - baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0, - ref_carrier= - ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) + baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0) # propagation spectral_info_out = fiber(spectral_info_input) @@ -48,11 +45,10 @@ def test_fiber(): baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9]) signal = 1e-3 + array([0, -1e-4, 3e-4, -2e-4, +2e-4]) delta_pdb_per_channel = [0, 0, 0, 0, 0] - pref = Pref(ref_carrier=None) spectral_info_input = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width, signal=signal, baud_rate=baud_rate, roll_off=0.15, delta_pdb_per_channel=delta_pdb_per_channel, - tx_osnr=40.0, ref_power=pref) + tx_osnr=40.0) # propagation spectral_info_out = fiber(spectral_info_input) @@ -70,8 +66,7 @@ def test_raman_fiber(): """Test the accuracy of propagating the RamanFiber.""" # spectral information generation spectral_info_input = create_input_spectral_information(f_min=191.3e12, f_max=196.1e12, roll_off=0.15, - baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0, - ref_carrier=ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) + baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0) SimParams.set_params(load_json(TEST_DIR / 'data' / 'sim_params.json')) fiber = RamanFiber(**load_json(TEST_DIR / 'data' / 'test_science_utils_fiber_config.json')) fiber.ref_pch_in_dbm = 0.0 @@ -108,9 +103,7 @@ def test_fiber_lumped_losses_srs(set_sim_params): """Test the accuracy of Fiber with lumped losses propagation.""" # spectral information generation spectral_info_input = create_input_spectral_information(f_min=191.3e12, f_max=196.1e12, roll_off=0.15, - baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0, - ref_carrier= - ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) + baud_rate=32e9, power=1e-3, spacing=50e9, tx_osnr=40.0) SimParams.set_params(load_json(TEST_DIR / 'data' / 'sim_params.json')) fiber = Fiber(**load_json(TEST_DIR / 'data' / 'test_lumped_losses_raman_fiber_config.json')) From 30a06da6b1ffe61a6f0060b1021f8764131a1b59 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Sun, 23 Oct 2022 09:00:13 +0200 Subject: [PATCH 17/20] Clean a bit, add docstrings Signed-off-by: EstherLerouzic Change-Id: I8639d458ebb090761846387921f9da4fc65a9f64 --- gnpy/core/network.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/gnpy/core/network.py b/gnpy/core/network.py index d44e0b83a..f9b673c91 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -130,6 +130,10 @@ def select_edfa(raman_allowed, gain_target, power_target, equipment, uid, restri def target_power(network, node, equipment): # get_fiber_dp + """Computes target power using J. -L. Auge, V. Curri and E. Le Rouzic, + Open Design for Multi-Vendor Optical Networks, OFC 2019. + equation 4 + """ if isinstance(node, elements.Roadm): return 0 @@ -143,8 +147,8 @@ def target_power(network, node, equipment): # get_fiber_dp dp = max(dp_range[0], dp) dp = min(dp_range[1], dp) except IndexError: - raise ConfigurationError(f'invalid delta_power_range_db definition in eqpt_config[Span]' - f'delta_power_range_db: [lower_bound, upper_bound, step]') + raise ConfigurationError('invalid delta_power_range_db definition in eqpt_config[Span]' + 'delta_power_range_db: [lower_bound, upper_bound, step]') return dp @@ -278,7 +282,12 @@ def set_amplifier_voa(amp, power_target, power_mode): def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_db, verbose): - """this node can be a transceiver or a ROADM (same function called in both cases)""" + """This node can be a transceiver or a ROADM (same function called in both cases). + go through each link staring from this_node until next Roadm or Transceiver and + set gain and delta_p according to configurations set by user. + power_mode = True, set amplifiers delta_p and effective_gain + power_mode = False, set amplifiers effective_gain and ignore delta_p config: set it to None + """ power_mode = equipment['Span']['default'].power_mode next_oms = (n for n in network.successors(this_node) if not isinstance(n, elements.Transceiver)) for oms in next_oms: @@ -592,6 +601,9 @@ def add_inline_amplifier(network, fiber): def calculate_new_length(fiber_length, bounds, target_length): + """If fiber is over boundary, then assume this is a link "intent" and computes the set of + identical fiber spans this link should be composed of. + """ if fiber_length < bounds.stop: return fiber_length, 1 @@ -622,7 +634,10 @@ def get_next_node(node, network): f'{type(node).__name__} {node.uid} is not properly connected, please check network topology') -def split_fiber(network, fiber, bounds, target_length, equipment): +def split_fiber(network, fiber, bounds, target_length): + """If fiber length exceeds boundary then assume this is a link "intent", and replace this one-span link + with an n_spans link, with identical fiber types. + """ new_length, n_spans = calculate_new_length(fiber.params.length, bounds, target_length) if n_spans == 1: return @@ -665,6 +680,8 @@ def split_fiber(network, fiber, bounds, target_length, equipment): def add_connector_loss(network, fibers, default_con_in, default_con_out, EOL): + """Add default connector loss if no loss are defined. EOL repair margin is added as a connector loss + """ for fiber in fibers: next_node = get_next_node(fiber, network) if fiber.params.con_in is None: @@ -676,10 +693,8 @@ def add_connector_loss(network, fibers, default_con_in, default_con_out, EOL): def add_fiber_padding(network, fibers, padding, equipment): - """last_fibers = (fiber for n in network.nodes() - if not (isinstance(n, elements.Fiber) or isinstance(n, elements.Fused)) - for fiber in network.predecessors(n) - if isinstance(fiber, elements.Fiber))""" + """Add a padding att_in at the input of the 1st fiber of a succession of fibers and fused + """ for fiber in fibers: next_node = get_next_node(fiber, network) if isinstance(next_node, elements.Fused): @@ -706,7 +721,7 @@ def add_missing_elements_in_network(network, equipment): target_length = max(min_length, min(max_length, 90_000)) fibers = [f for f in network.nodes() if isinstance(f, elements.Fiber)] for fiber in fibers: - split_fiber(network, fiber, bounds, target_length, equipment) + split_fiber(network, fiber, bounds, target_length) roadms = [r for r in network.nodes() if isinstance(r, elements.Roadm)] for roadm in roadms: add_roadm_preamp(network, roadm) From fb29d729068568c0901b65c12cf35e5af73bdd5a Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Sun, 23 Oct 2022 10:11:03 +0200 Subject: [PATCH 18/20] Add a test on out_voa optimisation function Signed-off-by: EstherLerouzic Change-Id: I36d71d85e5837965f6d5ae47820506d06b3cb94e --- tests/test_amplifier.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/test_amplifier.py b/tests/test_amplifier.py index f0eea2c34..4bc65c0c6 100644 --- a/tests/test_amplifier.py +++ b/tests/test_amplifier.py @@ -8,7 +8,7 @@ from gnpy.core.elements import Transceiver, Edfa, Fiber from gnpy.core.utils import automatic_fmax, lin2db, db2lin, merge_amplifier_restrictions, dbm2watt, watt2dbm from gnpy.core.info import create_input_spectral_information, create_arbitrary_spectral_information -from gnpy.core.network import build_network +from gnpy.core.network import build_network, set_amplifier_voa from gnpy.tools.json_io import load_network, load_equipment, network_from_json from pathlib import Path import pytest @@ -330,3 +330,38 @@ def test_amp_saturation(delta_pdb_per_channel, base_power, delta_p): assert watt2dbm(sum(si.signal + si.nli + si.ase)) <= 21.02 assert pytest.approx(edfa.effective_gain, 1e-13) == gain assert_allclose(sig_in + gain, sig_out, rtol=1e-13) + + +def test_set_out_voa(): + """Check that out_voa is correctly set if out_voa_auto is true + gain is maximized to obtain better NF: + if optimum input power in next span is -3 + pref_ch_db then total power at optimum is 19 -3 = 16dBm. + since amp has 21 dBm p_max, power out of amp can be set to 21dBm increasing out_voa by 5 to keep + same input power in the fiber. Since the optimisation contains a hard coded margin of 1 to account for + possible degradation on max power, the expected voa value is 4, and delta_p and gain are corrected + accordingly. + """ + json_data = { + "elements": [{ + "uid": "Edfa1", + "type": "Edfa", + "type_variety": "test", + "operational": { + "delta_p": -3, + "gain_target": 20, + "tilt_target": 0 + } + }], + "connections": [] + } + equipment = load_equipment(eqpt_library) + network = network_from_json(json_data, equipment) + amp = [n for n in network.nodes()][0] + print(amp.out_voa) + power_target = 19 + amp.delta_p + power_mode = True + amp.params.out_voa_auto = True + set_amplifier_voa(amp, power_target, power_mode) + assert amp.out_voa == 4.0 + assert amp.effective_gain == 20.0 + 4.0 + assert amp.delta_p == -3.0 + 4.0 From c69c2a3af29ee9e963a3d3c3a05745287582e410 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 26 Oct 2022 18:59:27 +0200 Subject: [PATCH 19/20] add invocation test with the 3 equalization settings Signed-off-by: EstherLerouzic Change-Id: I0aee8da7bbf71991c68e163c7188efe1ddf29ff9 --- tests/data/eqpt_config_psd.json | 220 +++++++++++++ tests/data/eqpt_config_psw.json | 220 +++++++++++++ tests/invocation/transmission_long_pow | 437 +++++++++++++++++++++++++ tests/invocation/transmission_long_psd | 437 +++++++++++++++++++++++++ tests/invocation/transmission_long_psw | 437 +++++++++++++++++++++++++ tests/test_invocation.py | 6 + 6 files changed, 1757 insertions(+) create mode 100644 tests/data/eqpt_config_psd.json create mode 100644 tests/data/eqpt_config_psw.json create mode 100644 tests/invocation/transmission_long_pow create mode 100644 tests/invocation/transmission_long_psd create mode 100644 tests/invocation/transmission_long_psw diff --git a/tests/data/eqpt_config_psd.json b/tests/data/eqpt_config_psd.json new file mode 100644 index 000000000..ba84477c3 --- /dev/null +++ b/tests/data/eqpt_config_psd.json @@ -0,0 +1,220 @@ +{ + "Edfa": [{ + "type_variety": "CienaDB_medium_gain", + "type_def": "advanced_model", + "gain_flatmax": 25, + "gain_min": 15, + "p_max": 21, + "advanced_config_from_json": "std_medium_gain_advanced_config.json", + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "std_medium_gain", + "type_def": "variable_gain", + "gain_flatmax": 26, + "gain_min": 15, + "p_max": 21, + "nf_min": 6, + "nf_max": 10, + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "std_low_gain", + "type_def": "variable_gain", + "gain_flatmax": 16, + "gain_min": 8, + "p_max": 21, + "nf_min": 7, + "nf_max": 11, + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "test", + "type_def": "variable_gain", + "gain_flatmax": 25, + "gain_min": 15, + "p_max": 21, + "nf_min": 5.8, + "nf_max": 10, + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "test_fixed_gain", + "type_def": "fixed_gain", + "gain_flatmax": 21, + "gain_min": 20, + "p_max": 21, + "nf0": 5, + "allowed_for_design": true + }, { + "type_variety": "std_booster", + "type_def": "fixed_gain", + "gain_flatmax": 21, + "gain_min": 20, + "p_max": 21, + "nf0": 5, + "allowed_for_design": false + } + ], + "Fiber": [{ + "type_variety": "SSMF", + "dispersion": 1.67e-05, + "effective_area": 83e-12, + "pmd_coef": 1.265e-15 + } + ], + "Span": [{ + "power_mode": true, + "delta_power_range_db": [0, 0, 0.5], + "max_fiber_lineic_loss_for_raman": 0.25, + "target_extended_gain": 2.5, + "max_length": 150, + "length_units": "km", + "max_loss": 28, + "padding": 10, + "EOL": 0, + "con_in": 0, + "con_out": 0 + } + ], + "Roadm": [{ + "target_psd_out_mWperGHz": 3.125e-4, + "add_drop_osnr": 38, + "pmd": 0, + "pdl": 0, + "restrictions": { + "preamp_variety_list": [], + "booster_variety_list": [] + } + } + ], + "SI": [{ + "f_min": 191.35e12, + "f_max": 196.1e12, + "baud_rate": 32e9, + "spacing": 50e9, + "power_dbm": 0, + "power_range_db": [0, 0, 0.5], + "roll_off": 0.15, + "tx_osnr": 100, + "sys_margins": 0 + } + ], + "Transceiver": [{ + "type_variety": "vendorA_trx-type1", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [{ + "format": "PS_SP64_1", + "baud_rate": 32e9, + "OSNR": 11, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + }, { + "format": "PS_SP64_2", + "baud_rate": 64e9, + "OSNR": 15, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 75e9, + "cost": 1 + }, { + "format": "mode 1", + "baud_rate": 32e9, + "OSNR": 11, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + }, { + "format": "mode 2", + "baud_rate": 64e9, + "OSNR": 15, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 75e9, + "cost": 1 + } + ] + }, { + "type_variety": "Voyager_16QAM", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [{ + "format": "16QAM", + "baud_rate": 32e9, + "OSNR": 19, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + } + ] + }, { + "type_variety": "Voyager", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [{ + "format": "mode 1", + "baud_rate": 32e9, + "OSNR": 12, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 50e9, + "cost": 1 + }, { + "format": "mode 3", + "baud_rate": 44e9, + "OSNR": 18, + "bit_rate": 300e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 62.5e9, + "cost": 1 + }, { + "format": "mode 2", + "baud_rate": 66e9, + "OSNR": 21, + "bit_rate": 400e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + }, { + "format": "mode 2 - fake", + "baud_rate": 66e9, + "OSNR": 21, + "bit_rate": 400e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + }, { + "format": "mode 4", + "baud_rate": 66e9, + "OSNR": 16, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + } + ] + } + ] + +} diff --git a/tests/data/eqpt_config_psw.json b/tests/data/eqpt_config_psw.json new file mode 100644 index 000000000..f5200d642 --- /dev/null +++ b/tests/data/eqpt_config_psw.json @@ -0,0 +1,220 @@ +{ + "Edfa": [{ + "type_variety": "CienaDB_medium_gain", + "type_def": "advanced_model", + "gain_flatmax": 25, + "gain_min": 15, + "p_max": 21, + "advanced_config_from_json": "std_medium_gain_advanced_config.json", + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "std_medium_gain", + "type_def": "variable_gain", + "gain_flatmax": 26, + "gain_min": 15, + "p_max": 21, + "nf_min": 6, + "nf_max": 10, + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "std_low_gain", + "type_def": "variable_gain", + "gain_flatmax": 16, + "gain_min": 8, + "p_max": 21, + "nf_min": 7, + "nf_max": 11, + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "test", + "type_def": "variable_gain", + "gain_flatmax": 25, + "gain_min": 15, + "p_max": 21, + "nf_min": 5.8, + "nf_max": 10, + "out_voa_auto": false, + "allowed_for_design": true + }, { + "type_variety": "test_fixed_gain", + "type_def": "fixed_gain", + "gain_flatmax": 21, + "gain_min": 20, + "p_max": 21, + "nf0": 5, + "allowed_for_design": true + }, { + "type_variety": "std_booster", + "type_def": "fixed_gain", + "gain_flatmax": 21, + "gain_min": 20, + "p_max": 21, + "nf0": 5, + "allowed_for_design": false + } + ], + "Fiber": [{ + "type_variety": "SSMF", + "dispersion": 1.67e-05, + "effective_area": 83e-12, + "pmd_coef": 1.265e-15 + } + ], + "Span": [{ + "power_mode": true, + "delta_power_range_db": [0, 0, 0.5], + "max_fiber_lineic_loss_for_raman": 0.25, + "target_extended_gain": 2.5, + "max_length": 150, + "length_units": "km", + "max_loss": 28, + "padding": 10, + "EOL": 0, + "con_in": 0, + "con_out": 0 + } + ], + "Roadm": [{ + "target_out_mWperSlotWidth": 2.0e-4, + "add_drop_osnr": 38, + "pmd": 0, + "pdl": 0, + "restrictions": { + "preamp_variety_list": [], + "booster_variety_list": [] + } + } + ], + "SI": [{ + "f_min": 191.35e12, + "f_max": 196.1e12, + "baud_rate": 32e9, + "spacing": 50e9, + "power_dbm": 0, + "power_range_db": [0, 0, 0.5], + "roll_off": 0.15, + "tx_osnr": 100, + "sys_margins": 0 + } + ], + "Transceiver": [{ + "type_variety": "vendorA_trx-type1", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [{ + "format": "PS_SP64_1", + "baud_rate": 32e9, + "OSNR": 11, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + }, { + "format": "PS_SP64_2", + "baud_rate": 64e9, + "OSNR": 15, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 75e9, + "cost": 1 + }, { + "format": "mode 1", + "baud_rate": 32e9, + "OSNR": 11, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + }, { + "format": "mode 2", + "baud_rate": 64e9, + "OSNR": 15, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 75e9, + "cost": 1 + } + ] + }, { + "type_variety": "Voyager_16QAM", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [{ + "format": "16QAM", + "baud_rate": 32e9, + "OSNR": 19, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 100, + "min_spacing": 50e9, + "cost": 1 + } + ] + }, { + "type_variety": "Voyager", + "frequency": { + "min": 191.4e12, + "max": 196.1e12 + }, + "mode": [{ + "format": "mode 1", + "baud_rate": 32e9, + "OSNR": 12, + "bit_rate": 100e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 50e9, + "cost": 1 + }, { + "format": "mode 3", + "baud_rate": 44e9, + "OSNR": 18, + "bit_rate": 300e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 62.5e9, + "cost": 1 + }, { + "format": "mode 2", + "baud_rate": 66e9, + "OSNR": 21, + "bit_rate": 400e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + }, { + "format": "mode 2 - fake", + "baud_rate": 66e9, + "OSNR": 21, + "bit_rate": 400e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + }, { + "format": "mode 4", + "baud_rate": 66e9, + "OSNR": 16, + "bit_rate": 200e9, + "roll_off": 0.15, + "tx_osnr": 45, + "min_spacing": 75e9, + "cost": 1 + } + ] + } + ] + +} diff --git a/tests/invocation/transmission_long_pow b/tests/invocation/transmission_long_pow new file mode 100644 index 000000000..f7d2e3763 --- /dev/null +++ b/tests/invocation/transmission_long_pow @@ -0,0 +1,437 @@ +User input for spectrum used for propagation instead of SI +There are 60 channels propagating +Power mode is set to True +=> it can be modified in eqpt_config.json - Span + +There are 15 fiber spans over 1200 km between Site_A and Site_B + +Now propagating between Site_A and Site_B: + +Propagating with input power = 0.00 dBm: +Transceiver Site_A + GSNR (0.1nm, dB): mode_1: 40.00, mode_2: 40.00 + GSNR (signal bw, dB): mode_1: 35.92, mode_2: 32.91 + OSNR ASE (0.1nm, dB): mode_1: 40.00, mode_2: 40.00 + OSNR ASE (signal bw, dB): mode_1: 35.92, mode_2: 32.91 + CD (ps/nm): 0.00 + PMD (ps): 0.00 + PDL (dB): 0.00 + Latency (ms): 0.00 +Roadm roadm Site A + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -20.00 +Edfa booster A + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -2.22 + Power Out (dBm): 17.79 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 0.02 + output VOA (dB): 0.00 +Fiber Span1 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -15.98 +Edfa Edfa1 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.80 + Power Out (dBm): 17.80 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 0.03 + output VOA (dB): 0.00 +Fiber Span2 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -15.97 +Edfa Edfa2 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.81 + Power Out (dBm): 17.81 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 0.04 + output VOA (dB): 0.00 +Fiber Span3 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -15.96 +Edfa Edfa3 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.82 + Power Out (dBm): 17.82 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 0.05 + output VOA (dB): 0.00 +Fiber Span4 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.96, mode_2: -15.94 +Edfa Edfa4 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.83 + Power Out (dBm): 17.84 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 0.07 + output VOA (dB): 0.00 +Fiber Span5 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.95, mode_2: -15.93 +Edfa Edfa5 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.84 + Power Out (dBm): 17.85 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 0.08 + output VOA (dB): 0.00 +Roadm roadm Site C + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -20.00 +Edfa booster C + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -2.22 + Power Out (dBm): 17.79 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 0.02 + output VOA (dB): 0.00 +Fiber Span6 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -15.98 +Edfa Edfa6 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.80 + Power Out (dBm): 17.80 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 0.03 + output VOA (dB): 0.00 +Fiber Span7 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -15.97 +Edfa Edfa7 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.81 + Power Out (dBm): 17.81 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 0.04 + output VOA (dB): 0.00 +Fiber Span8 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -15.96 +Edfa Edfa8 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.82 + Power Out (dBm): 17.82 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 0.05 + output VOA (dB): 0.00 +Fiber Span9 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.96, mode_2: -15.94 +Edfa Edfa9 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.83 + Power Out (dBm): 17.83 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 0.07 + output VOA (dB): 0.00 +Fiber Span10 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.95, mode_2: -15.93 +Edfa Edfa10 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.84 + Power Out (dBm): 17.85 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 0.08 + output VOA (dB): 0.00 +Roadm roadm Site D + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -20.00 +Edfa booster D + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -2.22 + Power Out (dBm): 17.79 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 0.02 + output VOA (dB): 0.00 +Fiber Span11 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -15.98 +Edfa Edfa11 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.80 + Power Out (dBm): 17.80 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 0.03 + output VOA (dB): 0.00 +Fiber Span12 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -15.97 +Edfa Edfa12 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.81 + Power Out (dBm): 17.81 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 0.04 + output VOA (dB): 0.00 +Roadm roadm Site E + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -20.00 +Edfa booster E + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -2.22 + Power Out (dBm): 17.79 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 0.02 + output VOA (dB): 0.00 +Fiber Span13 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -15.98 +Edfa Edfa13 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.80 + Power Out (dBm): 17.80 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 0.03 + output VOA (dB): 0.00 +Fiber Span14 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -15.97 +Edfa Edfa14 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 1.81 + Power Out (dBm): 17.81 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 0.04 + output VOA (dB): 0.00 +Fiber Span15 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -15.96 +Edfa Edfa15 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 1.82 + Power Out (dBm): 17.82 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 0.05 + output VOA (dB): 0.00 +Roadm roadm Site B + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -20.00 +Transceiver Site_B + GSNR (0.1nm, dB): mode_1: 18.11, mode_2: 19.18 + GSNR (signal bw, dB): mode_1: 14.02, mode_2: 12.09 + OSNR ASE (0.1nm, dB): mode_1: 19.69, mode_2: 19.62 + OSNR ASE (signal bw, dB): mode_1: 15.61, mode_2: 12.53 + CD (ps/nm): 20040.00 + PMD (ps): 1.39 + PDL (dB): 0.00 + Latency (ms): 5.88 + +Transmission result for input power = 0.00 dBm: + Final GSNR (0.1 nm): 18.56 dB + +(No source node specified: picked Site_A) + +(No destination node specified: picked Site_B) diff --git a/tests/invocation/transmission_long_psd b/tests/invocation/transmission_long_psd new file mode 100644 index 000000000..774ded705 --- /dev/null +++ b/tests/invocation/transmission_long_psd @@ -0,0 +1,437 @@ +User input for spectrum used for propagation instead of SI +There are 60 channels propagating +Power mode is set to True +=> it can be modified in eqpt_config.json - Span + +There are 15 fiber spans over 1200 km between Site_A and Site_B + +Now propagating between Site_A and Site_B: + +Propagating with input power = 0.00 dBm: +Transceiver Site_A + GSNR (0.1nm, dB): mode_1: 40.00, mode_2: 40.00 + GSNR (signal bw, dB): mode_1: 35.92, mode_2: 32.91 + OSNR ASE (0.1nm, dB): mode_1: 40.00, mode_2: 40.00 + OSNR ASE (signal bw, dB): mode_1: 35.92, mode_2: 32.91 + CD (ps/nm): 0.00 + PMD (ps): 0.00 + PDL (dB): 0.00 + Latency (ms): 0.00 +Roadm roadm Site A + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -16.99 +Edfa booster A + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -0.71 + Power Out (dBm): 19.30 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 3.02 + output VOA (dB): 0.00 +Fiber Span1 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -12.98 +Edfa Edfa1 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.31 + Power Out (dBm): 19.31 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 3.03 + output VOA (dB): 0.00 +Fiber Span2 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -12.97 +Edfa Edfa2 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.32 + Power Out (dBm): 19.32 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 3.04 + output VOA (dB): 0.00 +Fiber Span3 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -12.95 +Edfa Edfa3 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.33 + Power Out (dBm): 19.33 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 3.05 + output VOA (dB): 0.00 +Fiber Span4 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.96, mode_2: -12.94 +Edfa Edfa4 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.34 + Power Out (dBm): 19.34 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 3.06 + output VOA (dB): 0.00 +Fiber Span5 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.95, mode_2: -12.93 +Edfa Edfa5 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.35 + Power Out (dBm): 19.35 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.06, mode_2: 3.07 + output VOA (dB): 0.00 +Roadm roadm Site C + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -16.99 +Edfa booster C + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -0.71 + Power Out (dBm): 19.30 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 3.02 + output VOA (dB): 0.00 +Fiber Span6 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -12.98 +Edfa Edfa6 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.31 + Power Out (dBm): 19.31 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 3.03 + output VOA (dB): 0.00 +Fiber Span7 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -12.97 +Edfa Edfa7 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.32 + Power Out (dBm): 19.32 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 3.04 + output VOA (dB): 0.00 +Fiber Span8 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -12.95 +Edfa Edfa8 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.33 + Power Out (dBm): 19.33 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 3.05 + output VOA (dB): 0.00 +Fiber Span9 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.96, mode_2: -12.94 +Edfa Edfa9 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.34 + Power Out (dBm): 19.34 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 3.06 + output VOA (dB): 0.00 +Fiber Span10 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.95, mode_2: -12.93 +Edfa Edfa10 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.35 + Power Out (dBm): 19.35 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.06, mode_2: 3.07 + output VOA (dB): 0.00 +Roadm roadm Site D + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -16.99 +Edfa booster D + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -0.71 + Power Out (dBm): 19.30 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 3.02 + output VOA (dB): 0.00 +Fiber Span11 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -12.98 +Edfa Edfa11 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.31 + Power Out (dBm): 19.31 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 3.03 + output VOA (dB): 0.00 +Fiber Span12 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -12.97 +Edfa Edfa12 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.32 + Power Out (dBm): 19.32 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 3.04 + output VOA (dB): 0.00 +Roadm roadm Site E + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -16.99 +Edfa booster E + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -0.71 + Power Out (dBm): 19.30 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 3.02 + output VOA (dB): 0.00 +Fiber Span13 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -12.98 +Edfa Edfa13 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.31 + Power Out (dBm): 19.31 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 3.03 + output VOA (dB): 0.00 +Fiber Span14 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -12.97 +Edfa Edfa14 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 3.32 + Power Out (dBm): 19.32 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 3.04 + output VOA (dB): 0.00 +Fiber Span15 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -12.96 +Edfa Edfa15 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 3.33 + Power Out (dBm): 19.33 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 3.05 + output VOA (dB): 0.00 +Roadm roadm Site B + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -16.99 +Transceiver Site_B + GSNR (0.1nm, dB): mode_1: 17.91, mode_2: 20.37 + GSNR (signal bw, dB): mode_1: 13.83, mode_2: 13.28 + OSNR ASE (0.1nm, dB): mode_1: 19.69, mode_2: 22.55 + OSNR ASE (signal bw, dB): mode_1: 15.61, mode_2: 15.46 + CD (ps/nm): 20040.00 + PMD (ps): 1.39 + PDL (dB): 0.00 + Latency (ms): 5.88 + +Transmission result for input power = 0.00 dBm: + Final GSNR (0.1 nm): 18.94 dB + +(No source node specified: picked Site_A) + +(No destination node specified: picked Site_B) diff --git a/tests/invocation/transmission_long_psw b/tests/invocation/transmission_long_psw new file mode 100644 index 000000000..1a11cbbd2 --- /dev/null +++ b/tests/invocation/transmission_long_psw @@ -0,0 +1,437 @@ +User input for spectrum used for propagation instead of SI +There are 60 channels propagating +Power mode is set to True +=> it can be modified in eqpt_config.json - Span + +There are 15 fiber spans over 1200 km between Site_A and Site_B + +Now propagating between Site_A and Site_B: + +Propagating with input power = 0.00 dBm: +Transceiver Site_A + GSNR (0.1nm, dB): mode_1: 40.00, mode_2: 40.00 + GSNR (signal bw, dB): mode_1: 35.92, mode_2: 32.91 + OSNR ASE (0.1nm, dB): mode_1: 40.00, mode_2: 40.00 + OSNR ASE (signal bw, dB): mode_1: 35.92, mode_2: 32.91 + CD (ps/nm): 0.00 + PMD (ps): 0.00 + PDL (dB): 0.00 + Latency (ms): 0.00 +Roadm roadm Site A + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -18.24 +Edfa booster A + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -1.40 + Power Out (dBm): 18.61 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 1.77 + output VOA (dB): 0.00 +Fiber Span1 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -14.22 +Edfa Edfa1 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.62 + Power Out (dBm): 18.62 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 1.78 + output VOA (dB): 0.00 +Fiber Span2 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -14.21 +Edfa Edfa2 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.63 + Power Out (dBm): 18.63 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 1.79 + output VOA (dB): 0.00 +Fiber Span3 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -14.20 +Edfa Edfa3 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.64 + Power Out (dBm): 18.64 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 1.80 + output VOA (dB): 0.00 +Fiber Span4 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.96, mode_2: -14.19 +Edfa Edfa4 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.65 + Power Out (dBm): 18.65 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 1.81 + output VOA (dB): 0.00 +Fiber Span5 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.95, mode_2: -14.18 +Edfa Edfa5 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.66 + Power Out (dBm): 18.66 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 1.82 + output VOA (dB): 0.00 +Roadm roadm Site C + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -18.24 +Edfa booster C + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -1.40 + Power Out (dBm): 18.61 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 1.77 + output VOA (dB): 0.00 +Fiber Span6 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -14.23 +Edfa Edfa6 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.62 + Power Out (dBm): 18.62 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 1.78 + output VOA (dB): 0.00 +Fiber Span7 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -14.21 +Edfa Edfa7 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.63 + Power Out (dBm): 18.63 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 1.79 + output VOA (dB): 0.00 +Fiber Span8 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -14.20 +Edfa Edfa8 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.64 + Power Out (dBm): 18.64 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 1.80 + output VOA (dB): 0.00 +Fiber Span9 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.96, mode_2: -14.19 +Edfa Edfa9 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.65 + Power Out (dBm): 18.65 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.04, mode_2: 1.81 + output VOA (dB): 0.00 +Fiber Span10 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.95, mode_2: -14.18 +Edfa Edfa10 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.66 + Power Out (dBm): 18.66 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.05, mode_2: 1.82 + output VOA (dB): 0.00 +Roadm roadm Site D + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -18.24 +Edfa booster D + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -1.40 + Power Out (dBm): 18.61 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 1.77 + output VOA (dB): 0.00 +Fiber Span11 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -14.23 +Edfa Edfa11 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.62 + Power Out (dBm): 18.62 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 1.78 + output VOA (dB): 0.00 +Fiber Span12 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -14.21 +Edfa Edfa12 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.63 + Power Out (dBm): 18.63 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 1.79 + output VOA (dB): 0.00 +Roadm roadm Site E + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -18.24 +Edfa booster E + type_variety: std_medium_gain + effective gain(dB): 20.00 + (before att_in and before output VOA) + noise figure (dB): 6.58 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): -1.40 + Power Out (dBm): 18.61 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.01, mode_2: 1.77 + output VOA (dB): 0.00 +Fiber Span13 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.99, mode_2: -14.23 +Edfa Edfa13 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.62 + Power Out (dBm): 18.62 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.02, mode_2: 1.78 + output VOA (dB): 0.00 +Fiber Span14 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.98, mode_2: -14.22 +Edfa Edfa14 + type_variety: test_fixed_gain + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 9.00 + (including att_in) + pad att_in (dB): 4.00 + Power In (dBm): 2.63 + Power Out (dBm): 18.63 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 1.79 + output VOA (dB): 0.00 +Fiber Span15 + type_variety: SSMF + length (km): 80.00 + pad att_in (dB): 0.00 + total loss (dB): 16.00 + (includes conn loss (dB) in: 0.00 out: 0.00) + (conn loss out includes EOL margin defined in eqpt_config.json) + reference pch out (dBm): -16.00 + actual pch out (dBm): mode_1: -15.97, mode_2: -14.20 +Edfa Edfa15 + type_variety: test + effective gain(dB): 16.00 + (before att_in and before output VOA) + noise figure (dB): 8.86 + (including att_in) + pad att_in (dB): 0.00 + Power In (dBm): 2.64 + Power Out (dBm): 18.64 + Delta_P (dB): 0.00 + target pch (dBm): 0.00 + actual pch out (dBm): mode_1: 0.03, mode_2: 1.80 + output VOA (dB): 0.00 +Roadm roadm Site B + effective loss (dB): 20.00 + reference pch out (dBm): -20.00 + actual pch out (dBm): mode_1: -20.00, mode_2: -18.24 +Transceiver Site_B + GSNR (0.1nm, dB): mode_1: 18.02, mode_2: 20.22 + GSNR (signal bw, dB): mode_1: 13.94, mode_2: 13.12 + OSNR ASE (0.1nm, dB): mode_1: 19.69, mode_2: 21.35 + OSNR ASE (signal bw, dB): mode_1: 15.61, mode_2: 14.26 + CD (ps/nm): 20040.00 + PMD (ps): 1.39 + PDL (dB): 0.00 + Latency (ms): 5.88 + +Transmission result for input power = 0.00 dBm: + Final GSNR (0.1 nm): 18.94 dB + +(No source node specified: picked Site_A) + +(No destination node specified: picked Site_B) diff --git a/tests/test_invocation.py b/tests/test_invocation.py index a5a83f2aa..7a4743453 100644 --- a/tests/test_invocation.py +++ b/tests/test_invocation.py @@ -31,6 +31,12 @@ ['tests/data/CORONET_Global_Topology_expected.json', 'tests/data/CORONET_services.json', '-v']), ('power_sweep_example', 'logs_power_sweep_example', transmission_main_example, ['tests/data/testTopology_expected.json', 'brest', 'rennes', '-e', 'tests/data/eqpt_config_sweep.json', '--pow', '3']), + ('transmission_long_pow', None, transmission_main_example, + ['-e', 'tests/data/eqpt_config.json', 'tests/data/test_long_network.json', '--spectrum', 'gnpy/example-data/initial_spectrum2.json']), + ('transmission_long_psd', None, transmission_main_example, + ['-e', 'tests/data/eqpt_config_psd.json', 'tests/data/test_long_network.json', '--spectrum', 'gnpy/example-data/initial_spectrum2.json', ]), + ('transmission_long_psw', None, transmission_main_example, + ['-e', 'tests/data/eqpt_config_psw.json', 'tests/data/test_long_network.json', '--spectrum', 'gnpy/example-data/initial_spectrum2.json', ]), )) def test_example_invocation(capfd, caplog, output, log, handler, args): """Make sure that our examples produce useful output""" From d7c1a6b75ea72cd50ed1e3b531f68e1414eddac8 Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Mon, 7 Nov 2022 19:30:11 +0100 Subject: [PATCH 20/20] Add a test on EOL Signed-off-by: EstherLerouzic Change-Id: Iddce655a64623a42cdaeaa2e8c269e3a737dd935 --- tests/test_network_functions.py | 112 +++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/tests/test_network_functions.py b/tests/test_network_functions.py index b97e858fe..b075d25ed 100644 --- a/tests/test_network_functions.py +++ b/tests/test_network_functions.py @@ -7,8 +7,10 @@ from pathlib import Path import pytest from gnpy.core.exceptions import NetworkTopologyError -from gnpy.core.network import span_loss -from gnpy.tools.json_io import load_equipment, load_network +from gnpy.core.network import span_loss, build_network +from gnpy.tools.json_io import load_equipment, load_network, network_from_json +from gnpy.core.utils import lin2db, automatic_nch +from gnpy.core.elements import Fiber TEST_DIR = Path(__file__).parent @@ -62,3 +64,109 @@ def test_span_loss_unconnected(node): x = next(x for x in network.nodes() if x.uid == node) with pytest.raises(NetworkTopologyError): span_loss(network, x, equipment) + + +@pytest.mark.parametrize('typ, expected_loss', + [('Edfa', [11, 11]), + ('Fused', [11, 10])]) +def test_eol(typ, expected_loss): + """Check that EOL is added only once on spans. One span can be one fiber or several fused fibers + EOL is then added on the first fiber only. + """ + json_data = { + "elements": [ + { + "uid": "trx SITE1", + "type": "Transceiver" + }, + { + "uid": "trx SITE2", + "type": "Transceiver" + }, + { + "uid": "roadm SITE1", + "type": "Roadm" + }, + { + "uid": "roadm SITE2", + "type": "Roadm" + }, + { + "uid": "fiber (SITE1 → ILA1)", + "type": "Fiber", + "type_variety": "SSMF", + "params": { + "length": 50.0, + "loss_coef": 0.2, + "length_units": "km" + } + }, + { + "uid": "fiber (ILA1 → SITE2)", + "type": "Fiber", + "type_variety": "SSMF", + "params": { + "length": 50.0, + "loss_coef": 0.2, + "length_units": "km" + } + }, + { + "uid": "east edfa in SITE1 to ILA1", + "type": "Edfa" + }, + { + "uid": "west edfa in SITE2 to ILA1", + "type": typ + }, + { + "uid": "east edfa in ILA1 to SITE2", + "type": "Edfa" + } + ], + "connections": [ + { + "from_node": "trx SITE1", + "to_node": "roadm SITE1" + }, + { + "from_node": "roadm SITE1", + "to_node": "east edfa in SITE1 to ILA1" + }, + { + "from_node": "east edfa in SITE1 to ILA1", + "to_node": "fiber (SITE1 → ILA1)" + }, + { + "from_node": "fiber (SITE1 → ILA1)", + "to_node": "east edfa in ILA1 to SITE2" + }, + { + "from_node": "east edfa in ILA1 to SITE2", + "to_node": "fiber (ILA1 → SITE2)" + }, + { + "from_node": "fiber (ILA1 → SITE2)", + "to_node": "west edfa in SITE2 to ILA1" + }, + { + "from_node": "west edfa in SITE2 to ILA1", + "to_node": "roadm SITE2" + }, + { + "from_node": "roadm SITE2", + "to_node": "trx SITE2" + } + ] + } + equipment = load_equipment(EQPT_FILENAME) + equipment['Span']['default'].EOL = 1 + network = network_from_json(json_data, equipment) + p_db = equipment['SI']['default'].power_dbm + p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min, + equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) + + build_network(network, equipment, p_db, p_total_db) + fibers = [f for f in network.nodes() if isinstance(f, Fiber)] + for i in range(2): + assert fibers[i].loss == expected_loss[i]