mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-02 02:57:52 +00:00
examples: move path_requests_run to gnpy.tools
Change-Id: Id23dfa81bf9a9b347ea9c99f77d5735b62911d67
This commit is contained in:
@@ -12,183 +12,8 @@ of path and feasibilty.
|
|||||||
See: draft-ietf-teas-yang-path-computation-01.txt
|
See: draft-ietf-teas-yang-path-computation-01.txt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sys import exit
|
from gnpy.tools.cli_examples import path_requests_run
|
||||||
from argparse import ArgumentParser
|
|
||||||
from pathlib import Path
|
|
||||||
from logging import getLogger, basicConfig, CRITICAL, DEBUG, INFO
|
|
||||||
from json import dumps
|
|
||||||
from numpy import mean
|
|
||||||
from gnpy.core import ansi_escapes
|
|
||||||
from gnpy.core.utils import automatic_nch
|
|
||||||
from gnpy.core.network import build_network
|
|
||||||
from gnpy.core.utils import lin2db
|
|
||||||
import gnpy.core.exceptions as exceptions
|
|
||||||
from gnpy.topology.request import (ResultElement, jsontocsv, compute_path_dsjctn, requests_aggregation,
|
|
||||||
BLOCKING_NOPATH, correct_json_route_list,
|
|
||||||
deduplicate_disjunctions, compute_path_with_disjunction)
|
|
||||||
from gnpy.topology.spectrum_assignment import build_oms_list, pth_assign_spectrum
|
|
||||||
import gnpy.tools.cli_examples as cli_examples
|
|
||||||
from gnpy.tools.json_io import load_requests, save_network, requests_from_json, disjunctions_from_json
|
|
||||||
from math import ceil
|
|
||||||
|
|
||||||
LOGGER = getLogger(__name__)
|
|
||||||
|
|
||||||
PARSER = ArgumentParser(description='Compute performance for a list of services provided in a json file or an excel sheet.')
|
|
||||||
PARSER.add_argument('network_filename', nargs='?', type=Path,
|
|
||||||
default=Path(__file__).parent / 'meshTopologyExampleV2.xls',
|
|
||||||
help='input topology file in xls or json')
|
|
||||||
PARSER.add_argument('service_filename', nargs='?', type=Path,
|
|
||||||
default=Path(__file__).parent / 'meshTopologyExampleV2.xls',
|
|
||||||
help='input service file in xls or json')
|
|
||||||
PARSER.add_argument('eqpt_filename', nargs='?', type=Path,
|
|
||||||
default=Path(__file__).parent / 'eqpt_config.json',
|
|
||||||
help='input equipment library in json. Default is eqpt_config.json')
|
|
||||||
PARSER.add_argument('-bi', '--bidir', action='store_true',
|
|
||||||
help='considers that all demands are bidir')
|
|
||||||
PARSER.add_argument('-v', '--verbose', action='count', default=0,
|
|
||||||
help='increases verbosity for each occurence')
|
|
||||||
PARSER.add_argument('-o', '--output', type=Path)
|
|
||||||
|
|
||||||
|
|
||||||
def path_result_json(pathresult):
|
|
||||||
""" create the response dictionnary
|
|
||||||
"""
|
|
||||||
data = {
|
|
||||||
'response': [n.json for n in pathresult]
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
|
||||||
""" main function that calls all functions
|
|
||||||
"""
|
|
||||||
LOGGER.info(f'Computing path requests {args.service_filename} into JSON format')
|
|
||||||
print(f'{ansi_escapes.blue}Computing path requests {args.service_filename} into JSON format{ansi_escapes.reset}')
|
|
||||||
# for debug
|
|
||||||
# print( args.eqpt_filename)
|
|
||||||
|
|
||||||
(equipment, network) = cli_examples.load_common_data(args.eqpt_filename, args.network_filename)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
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)
|
|
||||||
save_network(args.network_filename, network)
|
|
||||||
oms_list = build_oms_list(network, equipment)
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = load_requests(args.service_filename, equipment, bidir=args.bidir,
|
|
||||||
network=network, network_filename=args.network_filename)
|
|
||||||
rqs = requests_from_json(data, equipment)
|
|
||||||
except exceptions.ServiceError as e:
|
|
||||||
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {e}')
|
|
||||||
exit(1)
|
|
||||||
# check that request ids are unique. Non unique ids, may
|
|
||||||
# mess the computation: better to stop the computation
|
|
||||||
all_ids = [r.request_id for r in rqs]
|
|
||||||
if len(all_ids) != len(set(all_ids)):
|
|
||||||
for item in list(set(all_ids)):
|
|
||||||
all_ids.remove(item)
|
|
||||||
msg = f'Requests id {all_ids} are not unique'
|
|
||||||
LOGGER.critical(msg)
|
|
||||||
exit()
|
|
||||||
rqs = correct_json_route_list(network, rqs)
|
|
||||||
|
|
||||||
# pths = compute_path(network, equipment, rqs)
|
|
||||||
dsjn = disjunctions_from_json(data)
|
|
||||||
|
|
||||||
print(f'{ansi_escapes.blue}List of disjunctions{ansi_escapes.reset}')
|
|
||||||
print(dsjn)
|
|
||||||
# need to warn or correct in case of wrong disjunction form
|
|
||||||
# disjunction must not be repeated with same or different ids
|
|
||||||
dsjn = deduplicate_disjunctions(dsjn)
|
|
||||||
|
|
||||||
# Aggregate demands with same exact constraints
|
|
||||||
print(f'{ansi_escapes.blue}Aggregating similar requests{ansi_escapes.reset}')
|
|
||||||
|
|
||||||
rqs, dsjn = requests_aggregation(rqs, dsjn)
|
|
||||||
# TODO export novel set of aggregated demands in a json file
|
|
||||||
|
|
||||||
print(f'{ansi_escapes.blue}The following services have been requested:{ansi_escapes.reset}')
|
|
||||||
print(rqs)
|
|
||||||
|
|
||||||
print(f'{ansi_escapes.blue}Computing all paths with constraints{ansi_escapes.reset}')
|
|
||||||
try:
|
|
||||||
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
|
||||||
except exceptions.DisjunctionError as this_e:
|
|
||||||
print(f'{ansi_escapes.red}Disjunction error:{ansi_escapes.reset} {this_e}')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
print(f'{ansi_escapes.blue}Propagating on selected path{ansi_escapes.reset}')
|
|
||||||
propagatedpths, reversed_pths, reversed_propagatedpths = compute_path_with_disjunction(
|
|
||||||
network, equipment, rqs, pths)
|
|
||||||
# Note that deepcopy used in compute_path_with_disjunction returns
|
|
||||||
# a list of nodes which are not belonging to network (they are copies of the node objects).
|
|
||||||
# so there can not be propagation on these nodes.
|
|
||||||
|
|
||||||
pth_assign_spectrum(pths, rqs, oms_list, reversed_pths)
|
|
||||||
|
|
||||||
print(f'{ansi_escapes.blue}Result summary{ansi_escapes.reset}')
|
|
||||||
header = ['req id', ' demand', ' snr@bandwidth A-Z (Z-A)', ' snr@0.1nm A-Z (Z-A)',
|
|
||||||
' Receiver minOSNR', ' mode', ' Gbit/s', ' nb of tsp pairs',
|
|
||||||
'N,M or blocking reason']
|
|
||||||
data = []
|
|
||||||
data.append(header)
|
|
||||||
for i, this_p in enumerate(propagatedpths):
|
|
||||||
rev_pth = reversed_propagatedpths[i]
|
|
||||||
if rev_pth and this_p:
|
|
||||||
psnrb = f'{round(mean(this_p[-1].snr),2)} ({round(mean(rev_pth[-1].snr),2)})'
|
|
||||||
psnr = f'{round(mean(this_p[-1].snr_01nm), 2)}' +\
|
|
||||||
f' ({round(mean(rev_pth[-1].snr_01nm),2)})'
|
|
||||||
elif this_p:
|
|
||||||
psnrb = f'{round(mean(this_p[-1].snr),2)}'
|
|
||||||
psnr = f'{round(mean(this_p[-1].snr_01nm),2)}'
|
|
||||||
|
|
||||||
try:
|
|
||||||
if rqs[i].blocking_reason in BLOCKING_NOPATH:
|
|
||||||
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} :',
|
|
||||||
f'-', f'-', f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',
|
|
||||||
f'-', f'{rqs[i].blocking_reason}']
|
|
||||||
else:
|
|
||||||
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,
|
|
||||||
psnr, f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9, 2)}',
|
|
||||||
f'-', f'{rqs[i].blocking_reason}']
|
|
||||||
except AttributeError:
|
|
||||||
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,
|
|
||||||
psnr, f'{rqs[i].OSNR}', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',
|
|
||||||
f'{ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) }', f'({rqs[i].N},{rqs[i].M})']
|
|
||||||
data.append(line)
|
|
||||||
|
|
||||||
col_width = max(len(word) for row in data for word in row[2:]) # padding
|
|
||||||
firstcol_width = max(len(row[0]) for row in data) # padding
|
|
||||||
secondcol_width = max(len(row[1]) for row in data) # padding
|
|
||||||
for row in data:
|
|
||||||
firstcol = ''.join(row[0].ljust(firstcol_width))
|
|
||||||
secondcol = ''.join(row[1].ljust(secondcol_width))
|
|
||||||
remainingcols = ''.join(word.center(col_width, ' ') for word in row[2:])
|
|
||||||
print(f'{firstcol} {secondcol} {remainingcols}')
|
|
||||||
print(f'{ansi_escapes.yellow}Result summary shows mean SNR and OSNR (average over all channels){ansi_escapes.reset}')
|
|
||||||
|
|
||||||
if args.output:
|
|
||||||
result = []
|
|
||||||
# assumes that list of rqs and list of propgatedpths have same order
|
|
||||||
for i, pth in enumerate(propagatedpths):
|
|
||||||
result.append(ResultElement(rqs[i], pth, reversed_propagatedpths[i]))
|
|
||||||
temp = path_result_json(result)
|
|
||||||
fnamecsv = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.csv'
|
|
||||||
fnamejson = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.json'
|
|
||||||
with open(fnamejson, 'w', encoding='utf-8') as fjson:
|
|
||||||
fjson.write(dumps(path_result_json(result), indent=2, ensure_ascii=False))
|
|
||||||
with open(fnamecsv, "w", encoding='utf-8') as fcsv:
|
|
||||||
jsontocsv(temp, equipment, fcsv)
|
|
||||||
print(f'{ansi_escapes.blue}saving in {args.output} and {fnamecsv}{ansi_escapes.reset}')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
ARGS = PARSER.parse_args()
|
path_requests_run()
|
||||||
basicConfig(level={2: DEBUG, 1: INFO, 0: CRITICAL}.get(ARGS.verbose, DEBUG))
|
|
||||||
main(ARGS)
|
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ Common code for CLI examples
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
from json import dumps
|
||||||
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
from sys import exit
|
from sys import exit
|
||||||
|
from math import ceil
|
||||||
from numpy import linspace, mean
|
from numpy import linspace, mean
|
||||||
import logging
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import gnpy.core.ansi_escapes as ansi_escapes
|
import gnpy.core.ansi_escapes as ansi_escapes
|
||||||
from gnpy.core.elements import Transceiver, Fiber, RamanFiber
|
from gnpy.core.elements import Transceiver, Fiber, RamanFiber
|
||||||
@@ -21,9 +23,13 @@ import gnpy.core.exceptions as exceptions
|
|||||||
from gnpy.core.network import build_network
|
from gnpy.core.network import build_network
|
||||||
from gnpy.core.parameters import SimParams
|
from gnpy.core.parameters import SimParams
|
||||||
from gnpy.core.science_utils import Simulation
|
from gnpy.core.science_utils import Simulation
|
||||||
from gnpy.core.utils import db2lin, lin2db, write_csv
|
from gnpy.core.utils import db2lin, lin2db, write_csv, automatic_nch
|
||||||
from gnpy.tools.json_io import load_equipment, load_network, load_json, save_network
|
from gnpy.topology.request import (ResultElement, jsontocsv, compute_path_dsjctn, requests_aggregation,
|
||||||
from gnpy.topology.request import PathRequest, compute_constrained_path, propagate2
|
BLOCKING_NOPATH, correct_json_route_list,
|
||||||
|
deduplicate_disjunctions, compute_path_with_disjunction,
|
||||||
|
PathRequest, compute_constrained_path, propagate2)
|
||||||
|
from gnpy.topology.spectrum_assignment import build_oms_list, pth_assign_spectrum
|
||||||
|
from gnpy.tools.json_io import load_equipment, load_network, load_json, load_requests, save_network, requests_from_json, disjunctions_from_json
|
||||||
from gnpy.tools.plots import plot_baseline, plot_results
|
from gnpy.tools.plots import plot_baseline, plot_results
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
@@ -277,3 +283,153 @@ def transmission_main_example():
|
|||||||
|
|
||||||
if args.plot:
|
if args.plot:
|
||||||
plot_results(network, path, source, destination, infos)
|
plot_results(network, path, source, destination, infos)
|
||||||
|
|
||||||
|
|
||||||
|
def _path_result_json(pathresult):
|
||||||
|
return {'response': [n.json for n in pathresult]}
|
||||||
|
|
||||||
|
|
||||||
|
def path_requests_run():
|
||||||
|
parser = ArgumentParser(description='Compute performance for a list of services provided in a json file or an excel sheet.')
|
||||||
|
parser.add_argument('network_filename', nargs='?', type=Path,
|
||||||
|
default=_examples_dir / 'meshTopologyExampleV2.xls',
|
||||||
|
help='input topology file in xls or json')
|
||||||
|
parser.add_argument('service_filename', nargs='?', type=Path,
|
||||||
|
default=_examples_dir / 'meshTopologyExampleV2.xls',
|
||||||
|
help='input service file in xls or json')
|
||||||
|
parser.add_argument('eqpt_filename', nargs='?', type=Path,
|
||||||
|
default=_examples_dir / 'eqpt_config.json',
|
||||||
|
help='input equipment library in json. Default is eqpt_config.json')
|
||||||
|
parser.add_argument('-bi', '--bidir', action='store_true',
|
||||||
|
help='considers that all demands are bidir')
|
||||||
|
parser.add_argument('-v', '--verbose', action='count', default=0,
|
||||||
|
help='increases verbosity for each occurence')
|
||||||
|
parser.add_argument('-o', '--output', type=Path)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
_setup_logging(args)
|
||||||
|
|
||||||
|
_logger.info(f'Computing path requests {args.service_filename} into JSON format')
|
||||||
|
print(f'{ansi_escapes.blue}Computing path requests {os.path.relpath(args.service_filename)} into JSON format{ansi_escapes.reset}')
|
||||||
|
# for debug
|
||||||
|
# print( args.eqpt_filename)
|
||||||
|
|
||||||
|
(equipment, network) = load_common_data(args.eqpt_filename, args.network_filename)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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)
|
||||||
|
save_network(args.network_filename, network)
|
||||||
|
oms_list = build_oms_list(network, equipment)
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = load_requests(args.service_filename, equipment, bidir=args.bidir,
|
||||||
|
network=network, network_filename=args.network_filename)
|
||||||
|
rqs = requests_from_json(data, equipment)
|
||||||
|
except exceptions.ServiceError as e:
|
||||||
|
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {e}')
|
||||||
|
exit(1)
|
||||||
|
# check that request ids are unique. Non unique ids, may
|
||||||
|
# mess the computation: better to stop the computation
|
||||||
|
all_ids = [r.request_id for r in rqs]
|
||||||
|
if len(all_ids) != len(set(all_ids)):
|
||||||
|
for item in list(set(all_ids)):
|
||||||
|
all_ids.remove(item)
|
||||||
|
msg = f'Requests id {all_ids} are not unique'
|
||||||
|
_logger.critical(msg)
|
||||||
|
exit()
|
||||||
|
rqs = correct_json_route_list(network, rqs)
|
||||||
|
|
||||||
|
# pths = compute_path(network, equipment, rqs)
|
||||||
|
dsjn = disjunctions_from_json(data)
|
||||||
|
|
||||||
|
print(f'{ansi_escapes.blue}List of disjunctions{ansi_escapes.reset}')
|
||||||
|
print(dsjn)
|
||||||
|
# need to warn or correct in case of wrong disjunction form
|
||||||
|
# disjunction must not be repeated with same or different ids
|
||||||
|
dsjn = deduplicate_disjunctions(dsjn)
|
||||||
|
|
||||||
|
# Aggregate demands with same exact constraints
|
||||||
|
print(f'{ansi_escapes.blue}Aggregating similar requests{ansi_escapes.reset}')
|
||||||
|
|
||||||
|
rqs, dsjn = requests_aggregation(rqs, dsjn)
|
||||||
|
# TODO export novel set of aggregated demands in a json file
|
||||||
|
|
||||||
|
print(f'{ansi_escapes.blue}The following services have been requested:{ansi_escapes.reset}')
|
||||||
|
print(rqs)
|
||||||
|
|
||||||
|
print(f'{ansi_escapes.blue}Computing all paths with constraints{ansi_escapes.reset}')
|
||||||
|
try:
|
||||||
|
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
||||||
|
except exceptions.DisjunctionError as this_e:
|
||||||
|
print(f'{ansi_escapes.red}Disjunction error:{ansi_escapes.reset} {this_e}')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print(f'{ansi_escapes.blue}Propagating on selected path{ansi_escapes.reset}')
|
||||||
|
propagatedpths, reversed_pths, reversed_propagatedpths = compute_path_with_disjunction(
|
||||||
|
network, equipment, rqs, pths)
|
||||||
|
# Note that deepcopy used in compute_path_with_disjunction returns
|
||||||
|
# a list of nodes which are not belonging to network (they are copies of the node objects).
|
||||||
|
# so there can not be propagation on these nodes.
|
||||||
|
|
||||||
|
pth_assign_spectrum(pths, rqs, oms_list, reversed_pths)
|
||||||
|
|
||||||
|
print(f'{ansi_escapes.blue}Result summary{ansi_escapes.reset}')
|
||||||
|
header = ['req id', ' demand', ' snr@bandwidth A-Z (Z-A)', ' snr@0.1nm A-Z (Z-A)',
|
||||||
|
' Receiver minOSNR', ' mode', ' Gbit/s', ' nb of tsp pairs',
|
||||||
|
'N,M or blocking reason']
|
||||||
|
data = []
|
||||||
|
data.append(header)
|
||||||
|
for i, this_p in enumerate(propagatedpths):
|
||||||
|
rev_pth = reversed_propagatedpths[i]
|
||||||
|
if rev_pth and this_p:
|
||||||
|
psnrb = f'{round(mean(this_p[-1].snr),2)} ({round(mean(rev_pth[-1].snr),2)})'
|
||||||
|
psnr = f'{round(mean(this_p[-1].snr_01nm), 2)}' +\
|
||||||
|
f' ({round(mean(rev_pth[-1].snr_01nm),2)})'
|
||||||
|
elif this_p:
|
||||||
|
psnrb = f'{round(mean(this_p[-1].snr),2)}'
|
||||||
|
psnr = f'{round(mean(this_p[-1].snr_01nm),2)}'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if rqs[i].blocking_reason in BLOCKING_NOPATH:
|
||||||
|
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} :',
|
||||||
|
f'-', f'-', f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',
|
||||||
|
f'-', f'{rqs[i].blocking_reason}']
|
||||||
|
else:
|
||||||
|
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,
|
||||||
|
psnr, f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9, 2)}',
|
||||||
|
f'-', f'{rqs[i].blocking_reason}']
|
||||||
|
except AttributeError:
|
||||||
|
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,
|
||||||
|
psnr, f'{rqs[i].OSNR}', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',
|
||||||
|
f'{ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) }', f'({rqs[i].N},{rqs[i].M})']
|
||||||
|
data.append(line)
|
||||||
|
|
||||||
|
col_width = max(len(word) for row in data for word in row[2:]) # padding
|
||||||
|
firstcol_width = max(len(row[0]) for row in data) # padding
|
||||||
|
secondcol_width = max(len(row[1]) for row in data) # padding
|
||||||
|
for row in data:
|
||||||
|
firstcol = ''.join(row[0].ljust(firstcol_width))
|
||||||
|
secondcol = ''.join(row[1].ljust(secondcol_width))
|
||||||
|
remainingcols = ''.join(word.center(col_width, ' ') for word in row[2:])
|
||||||
|
print(f'{firstcol} {secondcol} {remainingcols}')
|
||||||
|
print(f'{ansi_escapes.yellow}Result summary shows mean SNR and OSNR (average over all channels){ansi_escapes.reset}')
|
||||||
|
|
||||||
|
if args.output:
|
||||||
|
result = []
|
||||||
|
# assumes that list of rqs and list of propgatedpths have same order
|
||||||
|
for i, pth in enumerate(propagatedpths):
|
||||||
|
result.append(ResultElement(rqs[i], pth, reversed_propagatedpths[i]))
|
||||||
|
temp = _path_result_json(result)
|
||||||
|
fnamecsv = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.csv'
|
||||||
|
fnamejson = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.json'
|
||||||
|
with open(fnamejson, 'w', encoding='utf-8') as fjson:
|
||||||
|
fjson.write(dumps(_path_result_json(result), indent=2, ensure_ascii=False))
|
||||||
|
with open(fnamecsv, "w", encoding='utf-8') as fcsv:
|
||||||
|
jsontocsv(temp, equipment, fcsv)
|
||||||
|
print(f'{ansi_escapes.blue}saving in {args.output} and {fnamecsv}{ansi_escapes.reset}')
|
||||||
|
|||||||
Reference in New Issue
Block a user