Esempio n. 1
0
def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
    
    # use a list but a dictionnary might be helpful to find path bathsed on request_id
    # TODO change all these req, dsjct, res lists into dict !
    path_res_list = []

    for i,pathreq in enumerate(pathreqlist):

        # 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}')
        print(f'with path constraint: {[pathreq.source]+pathreq.nodes_list}') #adding first node to be clearer on the output

        total_path = pathlist[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 total_path :
            if pathreq.baud_rate is not None:
                total_path = propagate(total_path,pathreq,equipment)
                # for el in total_path: print(el)
                temp_snr01nm = round(mean(total_path[-1].snr+lin2db(pathreq.baud_rate/(12.5e9))),2)
                if temp_snr01nm < pathreq.OSNR :
                    msg = f'\tWarning! Request {pathreq.request_id} computed path from {pathreq.source} to {pathreq.destination} does not pass with {pathreq.tsp_mode}\n' +\
                    f'\tcomputedSNR in 0.1nm = {temp_snr01nm} - required osnr {pathreq.OSNR}\n'
                    print(msg)
                    logger.warning(msg)
                    total_path = []
            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 :
                    # propagate_and_optimize_mode function returns the mode with the highest bitrate
                    # that passes. if no mode passes, then it returns an empty path
                    pathreq.baud_rate = mode['baud_rate']
                    pathreq.tsp_mode = mode['format']
                    pathreq.format = mode['format']
                    pathreq.OSNR = mode['OSNR']
                    pathreq.tx_osnr = mode['tx_osnr']
                    pathreq.bit_rate = mode['bit_rate']
                else :
                    total_path = []
        # we record the last tranceiver object in order to have th whole 
        # information about spectrum. Important Note: since transceivers 
        # attached to roadms are actually logical elements to simulate
        # performance, several demands having the same destination may use 
        # the same transponder for the performance simaulation. This is why 
        # we use deepcopy: to ensure each propagation is recorded and not 
        # overwritten 
        
        path_res_list.append(deepcopy(total_path))
    return path_res_list
def test_automaticmodefeature(net, eqpt, serv, expected_mode):
    data = load_requests(serv, eqpt, bidir=False)
    equipment = load_equipment(eqpt)
    network = load_network(net, 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)

    rqs = requests_from_json(data, equipment)
    rqs = correct_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}')
        print(f'with path constraint: {[pathreq.source]+pathreq.nodes_list}'
              )  #adding first node to be clearer on the output

        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 compute_path(network, equipment, pathreqlist):

    # This function is obsolete and not relevant with respect to network building: suggest either to correct
    # or to suppress it

    path_res_list = []

    for pathreq in pathreqlist:
        #need to rebuid the network for each path because the total power
        #can be different and the choice of amplifiers in autodesign is power dependant
        #but the design is the same if the total power is the same
        #TODO parametrize the total spectrum power so the same design can be shared
        p_db = lin2db(pathreq.power * 1e3)
        p_total_db = p_db + lin2db(pathreq.nb_channel)
        build_network(network, equipment, p_db, p_total_db)
        pathreq.nodes_list.append(pathreq.destination)
        #we assume that the destination is a strict constraint
        pathreq.loose_list.append('strict')
        print(f'Computing path from {pathreq.source} to {pathreq.destination}')
        print(f'with path constraint: {[pathreq.source]+pathreq.nodes_list}'
              )  #adding first node to be clearer on the output
        total_path = compute_constrained_path(network, pathreq)
        print(
            f'Computed path (roadms):{[e.uid for e in total_path  if isinstance(e, Roadm)]}\n'
        )

        if total_path:
            total_path = propagate(total_path, pathreq, equipment, show=False)
        else:
            total_path = []
        # we record the last tranceiver object in order to have th whole
        # information about spectrum. Important Note: since transceivers
        # attached to roadms are actually logical elements to simulate
        # performance, several demands having the same destination may use
        # the same transponder for the performance simaulation. This is why
        # we use deepcopy: to ensure each propagation is recorded and not
        # overwritten

        path_res_list.append(deepcopy(total_path))
    return path_res_list
Esempio n. 4
0
def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
    """ use a list but a dictionnary might be helpful to find path based on request_id
        TODO change all these req, dsjct, res lists into dict !
    """
    path_res_list = []
    reversed_path_res_list = []
    propagated_reversed_path_res_list = []

    for i, pathreq in enumerate(pathreqlist):

        # 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}')

        # pathlist[i] contains the whole path information for request i
        # last element is a transciver and where the result of the propagation is
        # recorded.
        # Important Note: since transceivers attached to roadms are actually logical
        # 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
        total_path = deepcopy(pathlist[i])
        print(
            f'Computed path (roadms):{[e.uid for e in total_path  if isinstance(e, Roadm)]}'
        )
        # for debug
        # print(f'{pathreq.baud_rate}   {pathreq.power}   {pathreq.spacing}   {pathreq.nb_channel}')
        if total_path:
            if pathreq.baud_rate is not None:
                # means that at this point the mode was entered/forced by user and thus a
                # baud_rate was defined
                total_path = propagate(total_path, pathreq, equipment)
                temp_snr01nm = round(
                    mean(total_path[-1].snr + lin2db(pathreq.baud_rate /
                                                     (12.5e9))), 2)
                if temp_snr01nm < pathreq.OSNR:
                    msg = f'\tWarning! Request {pathreq.request_id} computed path from' +\
                          f' {pathreq.source} to {pathreq.destination} does not pass with' +\
                          f' {pathreq.tsp_mode}\n\tcomputedSNR in 0.1nm = {temp_snr01nm} ' +\
                          f'- required osnr {pathreq.OSNR}'
                    print(msg)
                    LOGGER.warning(msg)
                    pathreq.blocking_reason = 'MODE_NOT_FEASIBLE'
            else:
                total_path, mode = propagate_and_optimize_mode(
                    total_path, pathreq, equipment)
                # if no baudrate satisfies spacing, no mode is returned and the last explored mode
                # a warning is shown in the propagate_and_optimize_mode
                # propagate_and_optimize_mode function returns the mode with the highest bitrate
                # that passes. if no mode passes, then a attribute blocking_reason is added on
                # pathreq that contains the reason for blocking: 'NO_PATH', 'NO_FEASIBLE_MODE', ...
                try:
                    if pathreq.blocking_reason in BLOCKING_NOPATH:
                        total_path = []
                    elif pathreq.blocking_reason in BLOCKING_NOMODE:
                        pathreq.baud_rate = mode['baud_rate']
                        pathreq.tsp_mode = mode['format']
                        pathreq.format = mode['format']
                        pathreq.OSNR = mode['OSNR']
                        pathreq.tx_osnr = mode['tx_osnr']
                        pathreq.bit_rate = mode['bit_rate']
                    # other blocking reason should not appear at this point
                except AttributeError:
                    pathreq.baud_rate = mode['baud_rate']
                    pathreq.tsp_mode = mode['format']
                    pathreq.format = mode['format']
                    pathreq.OSNR = mode['OSNR']
                    pathreq.tx_osnr = mode['tx_osnr']
                    pathreq.bit_rate = mode['bit_rate']

            # reversed path is needed for correct spectrum assignment
            reversed_path = find_reversed_path(pathlist[i])
            if pathreq.bidir:
                # only propagate if bidir is true, but needs the reversed path anyway for
                # correct spectrum assignment
                rev_p = deepcopy(reversed_path)

                print(
                    f'\n\tPropagating Z to A direction {pathreq.destination} to {pathreq.source}'
                )
                print(
                    f'\tPath (roadsm) {[r.uid for r in rev_p if isinstance(r,Roadm)]}\n'
                )
                propagated_reversed_path = propagate(rev_p, pathreq, equipment)
                temp_snr01nm = round(mean(propagated_reversed_path[-1].snr +\
                                          lin2db(pathreq.baud_rate/(12.5e9))), 2)
                if temp_snr01nm < pathreq.OSNR:
                    msg = f'\tWarning! Request {pathreq.request_id} computed path from' +\
                          f' {pathreq.source} to {pathreq.destination} does not pass with' +\
                          f' {pathreq.tsp_mode}\n' +\
                          f'\tcomputedSNR in 0.1nm = {temp_snr01nm} - required osnr {pathreq.OSNR}'
                    print(msg)
                    LOGGER.warning(msg)
                    # TODO selection of mode should also be on reversed direction !!
                    pathreq.blocking_reason = 'MODE_NOT_FEASIBLE'
            else:
                propagated_reversed_path = []
        else:
            msg = 'Total path is empty. No propagation'
            print(msg)
            LOGGER.info(msg)
            reversed_path = []
            propagated_reversed_path = []

        path_res_list.append(total_path)
        reversed_path_res_list.append(reversed_path)
        propagated_reversed_path_res_list.append(propagated_reversed_path)
        # print to have a nice output
        print('')
    return path_res_list, reversed_path_res_list, propagated_reversed_path_res_list
Esempio n. 5
0
def main(network, equipment, source, destination, req=None):
    result_dicts = {}
    network_data = [{
        'network_name': str(args.filename),
        'source': source.uid,
        'destination': destination.uid
    }]
    result_dicts.update({'network': network_data})
    design_data = [{
        'power_mode': equipment['Spans']['default'].power_mode,
        'span_power_range': equipment['Spans']['default'].delta_power_range_db,
        'design_pch': equipment['SI']['default'].power_dbm,
        'baud_rate': equipment['SI']['default'].baud_rate
    }]
    result_dicts.update({'design': design_data})
    simulation_data = []
    result_dicts.update({'simulation results': simulation_data})

    power_mode = equipment['Spans']['default'].power_mode
    print('\n'.join([
        f'Power mode is set to {power_mode}',
        f'=> it can be modified in eqpt_config.json - Spans'
    ]))

    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)
    build_network(network, equipment, pref_ch_db, pref_total_db)
    path = compute_constrained_path(network, req)

    spans = [s.length for s in path if isinstance(s, Fiber)]
    print(
        f'\nThere are {len(spans)} fiber spans over {sum(spans):.0f}m between {source.uid} and {destination.uid}'
    )
    print(f'\nNow propagating between {source.uid} and {destination.uid}:')

    try:
        power_range = list(arange(*equipment['SI']['default'].power_range_db))
        last = equipment['SI']['default'].power_range_db[-2]
        if len(power_range) == 0:  #bad input that will lead to no simulation
            power_range = [0]  #better than an error message
        else:
            power_range.append(last)
    except TypeError:
        print(
            'invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]'
        )
        power_range = [0]

    for dp_db in power_range:
        req.power = db2lin(pref_ch_db + dp_db) * 1e-3
        print(
            f'\nPropagating with input power = {lin2db(req.power*1e3):.2f}dBm :'
        )
        propagate(path, req, equipment, show=len(power_range) == 1)
        print(
            f'\nTransmission result for input power = {lin2db(req.power*1e3):.2f}dBm :'
        )
        print(destination)
        simulation_data.append({
            'Pch_dBm':
            pref_ch_db + dp_db,
            'OSNR_ASE_0.1nm':
            round(mean(destination.osnr_ase_01nm), 2),
            'OSNR_ASE_signal_bw':
            round(mean(destination.osnr_ase), 2),
            'SNR_nli_signal_bw':
            round(mean(destination.osnr_nli), 2),
            'SNR_total_signal_bw':
            round(mean(destination.snr), 2)
        })
    write_csv(result_dicts, 'simulation_result.csv')
    return path