def setup_trx(): """init transceiver class to access snr and osnr calculations""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) build_network(network, equipment, 0, 20) trx = [n for n in network.nodes() if isinstance(n, Transceiver)][0] return trx
def test_excel_service_json_generation(xls_input, expected_json_output): """ test services creation """ equipment = load_equipment(eqpt_filename) network = load_network(DATA_DIR / 'testTopology.xls', equipment) # Build the network once using the default power defined in SI in eqpt config 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) from_xls = read_service_sheet(xls_input, equipment, network, network_filename=DATA_DIR / 'testTopology.xls') expected = load_json(expected_json_output) results = compare_services(expected, from_xls) assert not results.requests.missing assert not results.requests.extra assert not results.requests.different assert not results.synchronizations.missing assert not results.synchronizations.extra assert not results.synchronizations.different
def setup_edfa_fixed_gain(): """init edfa class by reading the 2nd edfa in test_network.json file""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) build_network(network, equipment, 0, 20) edfa = [n for n in network.nodes() if isinstance(n, Edfa)][1] yield edfa
def test_auto_design_generation_fromxlsgainmode(tmpdir, xls_input, expected_json_output): """ tests generation of topology json test that the build network gives correct results in gain mode """ equipment = load_equipment(eqpt_filename) network = load_network(xls_input, 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 # Build the network once using the default power defined in SI in eqpt config 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) actual_json_output = tmpdir / xls_input.with_name( xls_input.stem + '_auto_design').with_suffix('.json').name save_network(network, actual_json_output) actual = load_json(actual_json_output) unlink(actual_json_output) expected = load_json(expected_json_output) results = compare_networks(expected, actual) assert not results.elements.missing assert not results.elements.extra assert not results.elements.different assert not results.connections.missing assert not results.connections.extra assert not results.connections.different
def load_common_data(equipment_filename, topology_filename, simulation_filename, save_raw_network_filename): '''Load common configuration from JSON files''' try: equipment = load_equipment(equipment_filename) network = load_network(topology_filename, equipment) if save_raw_network_filename is not None: save_network(network, save_raw_network_filename) print(f'{ansi_escapes.blue}Raw network (no optimizations) saved to {save_raw_network_filename}{ansi_escapes.reset}') sim_params = SimParams(**load_json(simulation_filename)) if simulation_filename is not None else None if not sim_params: if next((node for node in network if isinstance(node, RamanFiber)), None) is not None: print(f'{ansi_escapes.red}Invocation error:{ansi_escapes.reset} ' f'RamanFiber requires passing simulation params via --sim-params') sys.exit(1) else: Simulation.set_params(sim_params) except exceptions.EquipmentConfigError as e: print(f'{ansi_escapes.red}Configuration error in the equipment library:{ansi_escapes.reset} {e}') sys.exit(1) 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) except exceptions.ParametersError as e: print(f'{ansi_escapes.red}Simulation parameters error:{ansi_escapes.reset} {e}') sys.exit(1) except exceptions.ServiceError as e: print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {e}') sys.exit(1) return (equipment, network)
def test_span_loss_unconnected(node): '''Fused node that has no next and no previous nodes should be detected''' equipment = load_equipment(EQPT_FILENAME) 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)
def load_files(gnpy_topology): """ Load GNPy equipment Library and create network from topology""" eqpt_library = load_equipment( '../examples/default_equipment_data/eqpt_config.json') gnpy_network = network_from_json(topology_to_json(gnpy_topology), eqpt_library) return eqpt_library, gnpy_network
def test_span_loss(node, attenuation): equipment = load_equipment(EQPT_FILENAME) network = load_network(NETWORK_FILENAME, equipment) for x in network.nodes(): if x.uid == node: assert attenuation == span_loss(network, x) return assert not f'node "{node}" referenced from test but not found in the topology' # pragma: no cover
def setup_edfa_variable_gain(): """init edfa class by reading test_network.json file remove all gain and nf ripple""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) build_network(network, equipment, 0, 20) edfa = [n for n in network.nodes() if isinstance(n, Edfa)][0] edfa.gain_ripple = zeros(96) edfa.interpol_nf_ripple = zeros(96) yield edfa
def equipment(): """init transceiver class to access snr and osnr calculations""" equipment = load_equipment(EQPT_LIBRARY_NAME) # define some booster and preamps restrictions_list = [{ 'type_variety': 'booster_medium_gain', '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': False }, { 'type_variety': 'preamp_medium_gain', 'type_def': 'variable_gain', 'gain_flatmax': 26, 'gain_min': 15, 'p_max': 23, 'nf_min': 6, 'nf_max': 10, 'out_voa_auto': False, 'allowed_for_design': False }, { 'type_variety': 'preamp_high_gain', 'type_def': 'variable_gain', 'gain_flatmax': 35, 'gain_min': 25, 'p_max': 21, 'nf_min': 5.5, 'nf_max': 7, 'out_voa_auto': False, 'allowed_for_design': False }, { 'type_variety': 'preamp_low_gain', 'type_def': 'variable_gain', 'gain_flatmax': 16, 'gain_min': 8, 'p_max': 23, 'nf_min': 6.5, 'nf_max': 11, 'out_voa_auto': False, 'allowed_for_design': False }] # add them to the library for entry in restrictions_list: equipment['Edfa'][entry['type_variety']] = Amp.from_json( EQPT_LIBRARY_NAME, **entry) return equipment
def test_setup(): """ common setup for tests: builds network, equipment and oms only once """ equipment = load_equipment(EQPT_LIBRARY_NAME) network = load_network(NETWORK_FILE_NAME, equipment) # Build the network once using the default power defined in SI in eqpt config # power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by # spacing, f_min and f_max 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) build_oms_list(network, equipment) return network, equipment
def test_no_amp_feature(node_uid): ''' Check that booster is not placed on a roadm if fused is specified test_parser covers partly this behaviour. This test should guaranty that the feature is preserved even if convert is changed ''' equipment = load_equipment(EQPT_LIBRARY_NAME) json_network = load_json(NETWORK_FILE_NAME) for elem in json_network['elements']: if elem['uid'] == node_uid: # replace edfa node by a fused node in the topology elem['type'] = 'Fused' elem.pop('type_variety') elem.pop('operational') elem['params'] = {'loss': 0} next_node_uid = next(conn['to_node'] for conn in json_network['connections'] if conn['from_node'] == node_uid) previous_node_uid = next(conn['from_node'] for conn in json_network['connections'] if conn['to_node'] == node_uid) network = network_from_json(json_network, equipment) # Build the network once using the default power defined in SI in eqpt config # power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by # spacing, f_min and f_max 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) node = next(nd for nd in network.nodes() if nd.uid == node_uid) next_node = next(network.successors(node)) previous_node = next(network.predecessors(node)) if not isinstance(node, Fused): raise AssertionError() if not node.params.loss == 0.0: raise AssertionError() if not next_node_uid == next_node.uid: raise AssertionError() if not previous_node_uid == previous_node.uid: raise AssertionError()
def test_compare_nf_models(gain, setup_edfa_variable_gain, si): """ compare the 2 amplifier models (polynomial and estimated from nf_min and max) => nf_model vs nf_poly_fit for intermediate gain values: between gain_min and gain_flatmax some discrepancy is expected but target < 0.5dB => unitary test for Edfa._calc_nf (and Edfa.interpol_params)""" edfa = setup_edfa_variable_gain frequencies = array([c.frequency for c in si.carriers]) pin = array( [c.power.signal + c.power.nli + c.power.ase for c in si.carriers]) pin = pin / db2lin(gain) baud_rates = array([c.baud_rate for c in si.carriers]) edfa.operational.gain_target = gain # edfa is variable gain type pref = Pref(0, -gain, lin2db(len(frequencies))) edfa.interpol_params(frequencies, pin, baud_rates, pref) nf_model = edfa.nf[0] # change edfa type variety to a polynomial el_config = { "uid": "Edfa1", "operational": { "gain_target": gain, "tilt_target": 0 }, "metadata": { "location": { "region": "", "latitude": 2, "longitude": 0 } } } equipment = load_equipment(eqpt_library) extra_params = equipment['Edfa']['CienaDB_medium_gain'] temp = el_config.setdefault('params', {}) temp = merge_amplifier_restrictions(temp, extra_params.__dict__) el_config['params'] = temp edfa = Edfa(**el_config) # edfa is variable gain type edfa.interpol_params(frequencies, pin, baud_rates, pref) nf_poly = edfa.nf[0] print(nf_poly, nf_model) assert pytest.approx(nf_model, abs=0.5) == nf_poly
def test_ase_noise(gain, si, setup_trx, bw): """testing 3 different ways of calculating osnr: 1-pin-edfa.nf+58 vs 2-pout/pase afet propagate 3-Transceiver osnr_ase_01nm => unitary test for Edfa.noise_profile (Edfa.interpol_params, Edfa.propagate)""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) edfa = next(n for n in network.nodes() if n.uid == 'Edfa1') span = next(n for n in network.nodes() if n.uid == 'Span1') # update span1 and Edfa1 according to new gain before building network # updating span 1 avoids to overload amp span.params.length = gain * 1e3 / 0.2 edfa.operational.gain_target = gain build_network(network, equipment, 0, 20) edfa.gain_ripple = zeros(96) edfa.interpol_nf_ripple = zeros(96) # propagate in span1 to have si with the correct power level si = span(si) print(span) frequencies = array([c.frequency for c in si.carriers]) pin = array( [c.power.signal + c.power.nli + c.power.ase for c in si.carriers]) baud_rates = array([c.baud_rate for c in si.carriers]) pref = Pref(0, -gain, lin2db(len(frequencies))) edfa.interpol_params(frequencies, pin, baud_rates, pref) nf = edfa.nf print('nf', nf) pin = lin2db(pin[0] * 1e3) osnr_expected = pin - nf[0] + 58 si = edfa(si) print(edfa) pout = array([c.power.signal for c in si.carriers]) pase = array([c.power.ase for c in si.carriers]) osnr = lin2db(pout[0] / pase[0]) - lin2db(12.5e9 / bw) assert pytest.approx(osnr_expected, abs=0.01) == osnr trx = setup_trx si = trx(si) osnr = trx.osnr_ase_01nm[0] assert pytest.approx(osnr_expected, abs=0.01) == osnr
def test_auto_design_generation_fromjson(tmpdir, json_input, power_mode): """test that autodesign creates same file as an input file already autodesigned """ equipment = load_equipment(eqpt_filename) network = load_network(json_input, 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 = power_mode # Build the network once using the default power defined in SI in eqpt config 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) actual_json_output = tmpdir / json_input.with_name( json_input.stem + '_auto_design').with_suffix('.json').name save_network(network, actual_json_output) actual = load_json(actual_json_output) unlink(actual_json_output) assert actual == load_json(json_input)
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) for e in network.nodes(): if isinstance(e, Fiber): loss = e.params.loss_coef * e.params.length e.params.con_in = con_in e.params.con_out = con_out if isinstance(e, Edfa): e.operational.gain_target = loss + con_in + con_out transceivers = { n.uid: n for n in network.nodes() if isinstance(n, Transceiver) } p = input_power p = db2lin(p) * 1e-3 spacing = 50e9 # THz si = create_input_spectral_information(191.3e12, 191.3e12 + 79 * spacing, 0.15, 32e9, p, spacing) 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) for el in path: si = el(si) print(el) # remove this line when sweeping across several powers edfa_sample = next(el for el in path if isinstance(el, Edfa)) nf = mean(edfa_sample.nf) print(f'pw: {input_power} conn in: {con_in} con out: {con_out}', f'[email protected]: {round(mean(sink.osnr_ase_01nm),2)}', f'SNR@bandwitdth: {round(mean(sink.snr),2)}') return sink, nf, path
path computation and writes results to a CSV file. See: draft-ietf-teas-yang-path-computation-01.txt """ from argparse import ArgumentParser from pathlib import Path from json import loads from gnpy.tools.json_io import load_equipment from gnpy.topology.request import jsontocsv parser = ArgumentParser( description='A function that writes json path results in an excel sheet.') parser.add_argument('filename', nargs='?', type=Path) parser.add_argument('output_filename', nargs='?', type=Path) parser.add_argument('eqpt_filename', nargs='?', type=Path, default=Path(__file__).parent / 'eqpt_config.json') if __name__ == '__main__': args = parser.parse_args() with open(args.output_filename, 'w', encoding='utf-8') as file: with open(args.filename, encoding='utf-8') as f: print(f'Reading {args.filename}') json_data = loads(f.read()) equipment = load_equipment(args.eqpt_filename) print(f'Writing in {args.output_filename}') jsontocsv(json_data, equipment, file)
def test_excel_ila_constraints(source, destination, route_list, hoptype, expected_correction): """ add different kind of constraints to test all correct_route cases """ service_xls_input = DATA_DIR / 'testTopology.xls' network_json_input = DATA_DIR / 'testTopology_auto_design_expected.json' equipment = load_equipment(eqpt_filename) network = load_network(network_json_input, equipment) # increase length of one span to trigger automatic fiber splitting included by autodesign # so that the test also covers this case next(node for node in network.nodes() if node.uid == 'fiber (Brest_KLA → Quimper)-').length = 200000 next(node for node in network.nodes() if node.uid == 'fiber (Quimper → Brest_KLA)-').length = 200000 default_si = equipment['SI']['default'] p_db = default_si.power_dbm p_total_db = p_db + lin2db( automatic_nch(default_si.f_min, default_si.f_max, default_si.spacing)) build_network(network, equipment, p_db, p_total_db) # create params for a request based on input nodes_list = route_list.split(' | ') if route_list is not None else [] params = { 'request_id': '0', 'source': source, 'bidir': False, 'destination': destination, 'trx_type': '', 'trx_mode': '', 'format': '', 'spacing': '', 'nodes_list': nodes_list, 'loose_list': [hoptype for node in nodes_list] if route_list is not None else '', 'f_min': 0, 'f_max': 0, 'baud_rate': 0, 'OSNR': None, 'bit_rate': None, 'cost': None, 'roll_off': 0, 'tx_osnr': 0, 'min_spacing': None, 'nb_channel': 0, 'power': 0, 'path_bandwidth': 0, } request = PathRequest(**params) if expected_correction != 'Fail': [request] = correct_xls_route_list(service_xls_input, network, [request]) assert request.nodes_list == expected_correction else: with pytest.raises(ServiceError): [request] = correct_xls_route_list(service_xls_input, network, [request])
def test_json_response_generation(xls_input, expected_response_file): """ tests if json response is correctly generated for all combinations of requests """ equipment = load_equipment(eqpt_filename) network = load_network(xls_input, 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) data = read_service_sheet(xls_input, equipment, network) # change one of the request with bidir option to cover bidir case as well data['path-request'][2]['bidirectional'] = True oms_list = build_oms_list(network, equipment) rqs = requests_from_json(data, equipment) dsjn = disjunctions_from_json(data) dsjn = deduplicate_disjunctions(dsjn) rqs, dsjn = requests_aggregation(rqs, dsjn) pths = compute_path_dsjctn(network, equipment, rqs, dsjn) propagatedpths, reversed_pths, reversed_propagatedpths = \ compute_path_with_disjunction(network, equipment, rqs, pths) pth_assign_spectrum(pths, rqs, oms_list, reversed_pths) result = [] for i, pth in enumerate(propagatedpths): # test ServiceError handling : when M is zero at this point, the # json result should not be created if there is no blocking reason if i == 1: my_rq = deepcopy(rqs[i]) my_rq.M = 0 with pytest.raises(ServiceError): ResultElement(my_rq, pth, reversed_propagatedpths[i]).json my_rq.blocking_reason = 'NO_SPECTRUM' ResultElement(my_rq, pth, reversed_propagatedpths[i]).json result.append(ResultElement(rqs[i], pth, reversed_propagatedpths[i])) temp = {'response': [n.json for n in result]} expected = load_json(expected_response_file) for i, response in enumerate(temp['response']): if i == 2: # compare response must be False because z-a metric is missing # (request with bidir option to cover bidir case) assert not compare_response(expected['response'][i], response) print(f'response {response["response-id"]} should not match') expected['response'][2]['path-properties']['z-a-path-metric'] = [{ 'metric-type': 'SNR-bandwidth', 'accumulative-value': 22.809999999999999 }, { 'metric-type': 'SNR-0.1nm', 'accumulative-value': 26.890000000000001 }, { 'metric-type': 'OSNR-bandwidth', 'accumulative-value': 26.239999999999998 }, { 'metric-type': 'OSNR-0.1nm', 'accumulative-value': 30.32 }, { 'metric-type': 'reference_power', 'accumulative-value': 0.0012589254117941673 }, { 'metric-type': 'path_bandwidth', 'accumulative-value': 60000000000.0 }] # test should be OK now else: assert compare_response(expected['response'][i], response) print(f'response {response["response-id"]} is not correct')
def test_csv_response_generation(tmpdir, json_input): """ tests if generated csv is consistant with expected generation same columns (order not important) """ json_data = load_json(json_input) equipment = load_equipment(eqpt_filename) csv_filename = Path(tmpdir / json_input.name).with_suffix('.csv') with open(csv_filename, 'w', encoding='utf-8') as fcsv: jsontocsv(json_data, equipment, fcsv) expected_csv_filename = json_input.parent / (json_input.stem + '_expected.csv') # expected header # csv_header = \ # [ # 'response-id', # 'source', # 'destination', # 'path_bandwidth', # 'Pass?', # 'nb of tsp pairs', # 'total cost', # 'transponder-type', # 'transponder-mode', # 'OSNR-0.1nm', # 'SNR-0.1nm', # 'SNR-bandwidth', # 'baud rate (Gbaud)', # 'input power (dBm)', # 'path', # 'spectrum (N,M)', # 'reversed path OSNR-0.1nm', # 'reversed path SNR-0.1nm', # 'reversed path SNR-bandwidth' # ] resp = read_csv(csv_filename) print(resp) unlink(csv_filename) expected_resp = read_csv(expected_csv_filename) print(expected_resp) resp_header = list(resp.head(0)) expected_resp_header = list(expected_resp.head(0)) # check that headers are the same resp_header.sort() expected_resp_header.sort() print('headers are differents') print(resp_header) print(expected_resp_header) assert resp_header == expected_resp_header # for each header checks that the output are as expected resp.sort_values(by=['response-id']) expected_resp.sort_values(by=['response-id']) for column in expected_resp: assert list(resp[column].fillna('')) == list( expected_resp[column].fillna('')) print('results are different') print(list(resp[column])) print(list(expected_resp[column])) print(type(list(resp[column])[-1]))
compute_path_dsjctn, deduplicate_disjunctions, compute_path_with_disjunction, ResultElement, PathRequest) from gnpy.topology.spectrum_assignment import build_oms_list, pth_assign_spectrum from gnpy.tools.convert import convert_file from gnpy.tools.json_io import (load_json, load_network, save_network, load_equipment, requests_from_json, disjunctions_from_json, network_to_json, network_from_json) from gnpy.tools.service_sheet import read_service_sheet, correct_xls_route_list TEST_DIR = Path(__file__).parent DATA_DIR = TEST_DIR / 'data' eqpt_filename = DATA_DIR / 'eqpt_config.json' equipment = load_equipment(eqpt_filename) @pytest.mark.parametrize( 'xls_input,expected_json_output', { DATA_DIR / 'CORONET_Global_Topology.xlsx': DATA_DIR / 'CORONET_Global_Topology_expected.json', DATA_DIR / 'testTopology.xls': DATA_DIR / 'testTopology_expected.json', DATA_DIR / 'perdegreemeshTopologyExampleV2.xls': DATA_DIR / 'perdegreemeshTopologyExampleV2_expected.json' }.items()) def test_excel_json_generation(tmpdir, xls_input, expected_json_output): """ tests generation of topology json """ xls_copy = Path(tmpdir) / xls_input.name
def test_automaticmodefeature(net, eqpt, serv, expected_mode): equipment = load_equipment(eqpt) network = load_network(net, equipment) data = load_requests(serv, eqpt, bidir=False, network=network, network_filename=net) # Build the network once using the default power defined in SI in eqpt config # power density : db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by # spacing, f_min and f_max 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) rqs = requests_from_json(data, equipment) rqs = correct_json_route_list(network, rqs) dsjn = [] pths = compute_path_dsjctn(network, equipment, rqs, dsjn) path_res_list = [] for i, pathreq in enumerate(rqs): # use the power specified in requests but might be different from the one specified for design # the power is an optional parameter for requests definition # if optional, use the one defines in eqt_config.json p_db = lin2db(pathreq.power * 1e3) p_total_db = p_db + lin2db(pathreq.nb_channel) print(f'request {pathreq.request_id}') print(f'Computing path from {pathreq.source} to {pathreq.destination}') # adding first node to be clearer on the output print(f'with path constraint: {[pathreq.source]+pathreq.nodes_list}') total_path = pths[i] print( f'Computed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}\n' ) # for debug # print(f'{pathreq.baud_rate} {pathreq.power} {pathreq.spacing} {pathreq.nb_channel}') if pathreq.baud_rate is not None: print(pathreq.format) path_res_list.append(pathreq.format) total_path = propagate(total_path, pathreq, equipment) else: total_path, mode = propagate_and_optimize_mode( total_path, pathreq, equipment) # if no baudrate satisfies spacing, no mode is returned and an empty path is returned # a warning is shown in the propagate_and_optimize_mode if mode is not None: print(mode['format']) path_res_list.append(mode['format']) else: print('nok') path_res_list.append('nok') print(path_res_list) assert path_res_list == expected_mode
def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm): ''' Check that egress power of roadm is equal to target power if input power is greater than target power else, that it is equal to input power. Use a simple two hops A-B-C topology for the test where the prev_node in ROADM B is either an amplifier or a fused, so that the target power can not be met in this last case. ''' equipment = load_equipment(EQPT_LIBRARY_NAME) 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) if prev_node_type == 'edfa': prev_node = {'uid': 'west edfa in node B to ila2', 'type': 'Edfa'} elif prev_node_type == 'fused': prev_node = {'uid': 'west edfa in node B to ila2', 'type': 'Fused'} prev_node['params'] = {'loss': 0} json_network['elements'].append(prev_node) network = network_from_json(json_network, equipment) p_total_db = power_dbm + lin2db( automatic_nch(equipment['SI']['default'].f_min, equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) build_network(network, equipment, power_dbm, p_total_db) params = { 'request_id': 0, 'trx_type': '', 'trx_mode': '', 'source': 'trx node A', 'destination': 'trx node C', 'bidir': False, 'nodes_list': ['trx node C'], 'loose_list': ['strict'], 'format': '', 'path_bandwidth': 100e9, 'effective_freq_slot': None, } trx_params = trx_mode_params(equipment) params.update(trx_params) req = PathRequest(**params) req.power = db2lin(power_dbm - 30) path = compute_constrained_path(network, req) si = create_input_spectral_information(req.f_min, req.f_max, req.roll_off, req.baud_rate, req.power, req.spacing) for i, el in enumerate(path): if isinstance(el, Roadm): carriers_power_in_roadm = min([ c.power.signal + c.power.nli + c.power.ase for c in si.carriers ]) si = el(si, degree=path[i + 1].uid) if el.uid == 'roadm node B': print('input', carriers_power_in_roadm) # if previous was an EDFA, power level at ROADM input is enough for the ROADM to apply its # target power (as specified in equipment ie -20 dBm) # if it is a Fused, the input power to the ROADM is smaller than the target power, and the # ROADM cannot apply this target. In this case, it is assumed that the ROADM has 0 dB loss # so the output power will be the same as the input power, which for this particular case # corresponds to -22dBm + power_dbm # next step (for ROADM modelling) will be to apply a minimum loss for ROADMs ! if prev_node_type == 'edfa': assert el.effective_pch_out_db == effective_pch_out_db if prev_node_type == 'fused': # then output power == input_power == effective_pch_out_db + power_dbm assert effective_pch_out_db + power_dbm == \ pytest.approx(lin2db(carriers_power_in_roadm * 1e3), rel=1e-3) assert el.effective_pch_out_db == effective_pch_out_db + power_dbm for carrier in si.carriers: print(carrier.power.signal + carrier.power.nli + carrier.power.ase) power = carrier.power.signal + carrier.power.nli + carrier.power.ase if prev_node_type == 'edfa': # edfa prev_node sets input power to roadm to a high enough value: # Check that egress power of roadm is equal to target power assert power == pytest.approx( db2lin(effective_pch_out_db - 30), rel=1e-3) elif prev_node_type == 'fused': # fused prev_node does reamplfy power after fiber propagation, so input power # to roadm is low. # Check that egress power of roadm is equalized to the min carrier input power. assert power == pytest.approx(carriers_power_in_roadm, rel=1e-3) else: si = el(si)
def test_roadm_target_power(prev_node_type, effective_pch_out_db): ''' Check that egress power of roadm is equal to target power if input power is greater than target power else, that it is equal to input power. Use a simple two hops A-B-C topology for the test where the prev_node in ROADM B is either an amplifier or a fused, so that the target power can not be met in this last case. ''' equipment = load_equipment(EQPT_LIBRARY_NAME) 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) if prev_node_type == 'edfa': prev_node = {'uid': 'west edfa in node B to ila2', 'type': 'Edfa'} elif prev_node_type == 'fused': prev_node = {'uid': 'west edfa in node B to ila2', 'type': 'Fused'} prev_node['params'] = {'loss': 0} json_network['elements'].append(prev_node) network = network_from_json(json_network, equipment) # Build the network once using the default power defined in SI in eqpt config 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) params = {} params['request_id'] = 0 params['trx_type'] = '' params['trx_mode'] = '' params['source'] = 'trx node A' params['destination'] = 'trx node C' params['bidir'] = False params['nodes_list'] = ['trx node C'] params['loose_list'] = ['strict'] params['format'] = '' params['path_bandwidth'] = 100e9 trx_params = trx_mode_params(equipment) params.update(trx_params) req = PathRequest(**params) path = compute_constrained_path(network, req) si = create_input_spectral_information(req.f_min, req.f_max, req.roll_off, req.baud_rate, req.power, req.spacing) for i, el in enumerate(path): if isinstance(el, Roadm): carriers_power_in_roadm = min([ c.power.signal + c.power.nli + c.power.ase for c in si.carriers ]) si = el(si, degree=path[i + 1].uid) if el.uid == 'roadm node B': print('input', carriers_power_in_roadm) assert el.effective_pch_out_db == effective_pch_out_db for carrier in si.carriers: print(carrier.power.signal + carrier.power.nli + carrier.power.ase) power = carrier.power.signal + carrier.power.nli + carrier.power.ase if prev_node_type == 'edfa': # edfa prev_node sets input power to roadm to a high enough value: # Check that egress power of roadm is equal to target power assert power == pytest.approx( db2lin(effective_pch_out_db - 30), rel=1e-3) elif prev_node_type == 'fused': # fused prev_node does reamplfy power after fiber propagation, so input power # to roadm is low. # Check that egress power of roadm is equalized to the min carrier input power. assert power == pytest.approx(carriers_power_in_roadm, rel=1e-3) else: si = el(si)
def equipment(): equipment = load_equipment(EQPT_FILENAME) return equipment