Esempio n. 1
0
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]))
Esempio n. 2
0
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)
Esempio n. 3
0
def path_requests_run(args=None):
    parser = argparse.ArgumentParser(
        description=
        'Compute performance for a list of services provided in a json file or an excel sheet',
        epilog=_help_footer,
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    _add_common_options(parser,
                        network_default=_examples_dir /
                        'meshTopologyExampleV2.xls')
    parser.add_argument('service_filename',
                        nargs='?',
                        type=Path,
                        metavar='SERVICES-REQUESTS.(json|xls|xlsx)',
                        default=_examples_dir / 'meshTopologyExampleV2.xls',
                        help='Input service file')
    parser.add_argument('-bi',
                        '--bidir',
                        action='store_true',
                        help='considers that all demands are bidir')
    parser.add_argument(
        '-o',
        '--output',
        type=Path,
        metavar=_help_fname_json_csv,
        help='Store satisifed requests into a JSON or CSV file')

    args = parser.parse_args(args if args is not None else sys.argv[1:])
    _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}'
    )

    (equipment,
     network) = load_common_data(args.equipment, args.topology,
                                 args.sim_params,
                                 args.save_network_before_autodesign)

    # 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))
    try:
        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}'
        )
    oms_list = build_oms_list(network, equipment)

    try:
        data = load_requests(args.service_filename,
                             equipment,
                             bidir=args.bidir,
                             network=network,
                             network_filename=args.topology)
        rqs = requests_from_json(data, equipment)
    except exceptions.ServiceError as e:
        print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {e}')
        sys.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)
        sys.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}'
        )
        sys.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)',
        '  [email protected] 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 + equipment["SI"]["default"].sys_margins}',
                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)
        if args.output.suffix.lower() == '.json':
            save_json(temp, args.output)
            print(
                f'{ansi_escapes.blue}Saved JSON to {args.output}{ansi_escapes.reset}'
            )
        elif args.output.suffix.lower() == '.csv':
            with open(args.output, "w", encoding='utf-8') as fcsv:
                jsontocsv(temp, equipment, fcsv)
            print(
                f'{ansi_escapes.blue}Saved CSV to {args.output}{ansi_escapes.reset}'
            )
        else:
            print(
                f'{ansi_escapes.red}Cannot save output: neither JSON nor CSV file{ansi_escapes.reset}'
            )
            sys.exit(1)