mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-31 18:18:00 +00:00
Merge pull request #104 from Orange-OpenSource/path_resquest_rundemo
Path resquest rundemo
This commit is contained in:
@@ -189,7 +189,7 @@ Service sheet must contain 11 columns::
|
|||||||
|
|
||||||
route id ; Source ; Destination ; TRX type ; Mode ; System: spacing ; System: input power (dBm) ; System: nb of channels ; routing: disjoint from ; routing: path ; routing: is loose?
|
route id ; Source ; Destination ; TRX type ; Mode ; System: spacing ; System: input power (dBm) ; System: nb of channels ; routing: disjoint from ; routing: path ; routing: is loose?
|
||||||
|
|
||||||
- **route id** is mandatory. It must be unique. It is the identifier of the request. It must be an integer value (TODO: relax this format in future development to accept any strings)
|
- **route id** is mandatory. It must be unique. It is the identifier of the request. It can be an integer or a string (do not use blank or dash)
|
||||||
|
|
||||||
- **Source** is mandatory. It is the name of the source node (as listed in Nodes sheet). Source MUST be a ROADM node. (TODO: relax this and accept trx entries)
|
- **Source** is mandatory. It is the name of the source node (as listed in Nodes sheet). Source MUST be a ROADM node. (TODO: relax this and accept trx entries)
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,16 @@ class Element:
|
|||||||
|
|
||||||
class Request_element(Element):
|
class Request_element(Element):
|
||||||
def __init__(self,Request,eqpt_filename):
|
def __init__(self,Request,eqpt_filename):
|
||||||
self.request_id = int(Request.request_id)
|
# request_id is str
|
||||||
|
# excel has automatic number formatting that adds .0 on integer values
|
||||||
|
# the next lines recover the pure int value, assuming this .0 is unwanted
|
||||||
|
if not isinstance(Request.request_id,str):
|
||||||
|
value = str(int(Request.request_id))
|
||||||
|
if value.endswith('.0'):
|
||||||
|
value = value[:-2]
|
||||||
|
self.request_id = value
|
||||||
|
else:
|
||||||
|
self.request_id = Request.request_id
|
||||||
self.source = Request.source
|
self.source = Request.source
|
||||||
self.destination = Request.destination
|
self.destination = Request.destination
|
||||||
self.srctpid = f'trx {Request.source}'
|
self.srctpid = f'trx {Request.source}'
|
||||||
@@ -61,21 +70,27 @@ class Request_element(Element):
|
|||||||
# test that trx_type belongs to eqpt_config.json
|
# test that trx_type belongs to eqpt_config.json
|
||||||
# if not replace it with a default
|
# if not replace it with a default
|
||||||
equipment = load_equipment(eqpt_filename)
|
equipment = load_equipment(eqpt_filename)
|
||||||
|
try :
|
||||||
if equipment['Transceiver'][Request.trx_type]:
|
if equipment['Transceiver'][Request.trx_type]:
|
||||||
self.trx_type = Request.trx_type
|
self.trx_type = Request.trx_type
|
||||||
|
if [mode for mode in equipment['Transceiver'][Request.trx_type].mode]:
|
||||||
self.mode = Request.mode
|
self.mode = Request.mode
|
||||||
else:
|
except KeyError:
|
||||||
#TODO : this case must raise an error instead of using Voyager
|
msg = f'could not find tsp : {Request.trx_type} with mode: {Request.mode} in eqpt library \nComputation stopped.'
|
||||||
self.trx_type = 'Voyager_16QAM'
|
#print(msg)
|
||||||
print(f'Transceiver type {Request.trx_type} is not defined in {eqpt_filename}')
|
logger.critical(msg)
|
||||||
print('replaced by Voyager_16QAM')
|
exit()
|
||||||
|
# excel input are in GHz and dBm
|
||||||
self.spacing = Request.spacing * 1e9
|
self.spacing = Request.spacing * 1e9
|
||||||
self.power = db2lin(Request.power) * 1e-3
|
self.power = db2lin(Request.power) * 1e-3
|
||||||
self.nb_channel = int(Request.nb_channel)
|
self.nb_channel = int(Request.nb_channel)
|
||||||
if isinstance(Request.disjoint_from,str):
|
if not isinstance(Request.disjoint_from,str):
|
||||||
self.disjoint_from = [int(n) for n in Request.disjoint_from.split()]
|
value = str(int(Request.disjoint_from))
|
||||||
|
if value.endswith('.0'):
|
||||||
|
value = value[:-2]
|
||||||
else:
|
else:
|
||||||
self.disjoint_from = [int(Request.disjoint_from)]
|
value = Request.disjoint_from
|
||||||
|
self.disjoint_from = [n for n in value.split()]
|
||||||
self.nodes_list = []
|
self.nodes_list = []
|
||||||
if Request.nodes_list :
|
if Request.nodes_list :
|
||||||
self.nodes_list = Request.nodes_list.split(' | ')
|
self.nodes_list = Request.nodes_list.split(' | ')
|
||||||
@@ -83,7 +98,7 @@ class Request_element(Element):
|
|||||||
self.nodes_list.remove(self.source)
|
self.nodes_list.remove(self.source)
|
||||||
msg = f'{self.source} removed from explicit path node-list'
|
msg = f'{self.source} removed from explicit path node-list'
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
print(msg)
|
# print(msg)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
msg = f'{self.source} already removed from explicit path node-list'
|
msg = f'{self.source} already removed from explicit path node-list'
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
@@ -92,7 +107,7 @@ class Request_element(Element):
|
|||||||
self.nodes_list.remove(self.destination)
|
self.nodes_list.remove(self.destination)
|
||||||
msg = f'{self.destination} removed from explicit path node-list'
|
msg = f'{self.destination} removed from explicit path node-list'
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
print(msg)
|
# print(msg)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
msg = f'{self.destination} already removed from explicit path node-list'
|
msg = f'{self.destination} already removed from explicit path node-list'
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
{
|
{
|
||||||
"type_variety": "std_low_gain",
|
"type_variety": "std_low_gain",
|
||||||
"type_def": "variable_gain",
|
"type_def": "variable_gain",
|
||||||
"gain_flatmax": 17,
|
"gain_flatmax": 16,
|
||||||
"gain_min": 8,
|
"gain_min": 8,
|
||||||
"p_max": 22,
|
"p_max": 22,
|
||||||
"nf_min": 6.5,
|
"nf_min": 6.5,
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"gain_min": 20,
|
"gain_min": 20,
|
||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf0": 5.5,
|
"nf0": 5.5,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
@@ -90,6 +90,20 @@
|
|||||||
"max": 196.1e12
|
"max": 196.1e12
|
||||||
},
|
},
|
||||||
"mode":[
|
"mode":[
|
||||||
|
{
|
||||||
|
"format": "mode 1",
|
||||||
|
"baud_rate": 32e9,
|
||||||
|
"OSNR": 11,
|
||||||
|
"bit_rate": 100e9,
|
||||||
|
"roll_off": 0.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "mode 2",
|
||||||
|
"baud_rate": 66e9,
|
||||||
|
"OSNR": 15,
|
||||||
|
"bit_rate": 200e9,
|
||||||
|
"roll_off": 0.15
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"format": "PS_SP64_1",
|
"format": "PS_SP64_1",
|
||||||
"baud_rate": 32e9,
|
"baud_rate": 32e9,
|
||||||
@@ -107,6 +121,30 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"type_variety": "Voyager",
|
||||||
|
"frequency":{
|
||||||
|
"min": 191.35e12,
|
||||||
|
"max": 196.1e12
|
||||||
|
},
|
||||||
|
"mode":[
|
||||||
|
{
|
||||||
|
"format": "16QAM",
|
||||||
|
"baud_rate": 32e9,
|
||||||
|
"OSNR": 19,
|
||||||
|
"bit_rate": 200e9,
|
||||||
|
"roll_off": 0.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "QPSK",
|
||||||
|
"baud_rate": 32e9,
|
||||||
|
"OSNR": 12,
|
||||||
|
"bit_rate": 100e9,
|
||||||
|
"roll_off": 0.15
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
"type_variety": "Voyager_16QAM",
|
"type_variety": "Voyager_16QAM",
|
||||||
"frequency":{
|
"frequency":{
|
||||||
"min": 191.35e12,
|
"min": 191.35e12,
|
||||||
@@ -119,7 +157,15 @@
|
|||||||
"OSNR": 19,
|
"OSNR": 19,
|
||||||
"bit_rate": 200e9,
|
"bit_rate": 200e9,
|
||||||
"roll_off": 0.15
|
"roll_off": 0.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "QPSK",
|
||||||
|
"baud_rate": 32e9,
|
||||||
|
"OSNR": 12,
|
||||||
|
"bit_rate": 100e9,
|
||||||
|
"roll_off": 0.15
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
BIN
examples/meshTopologyToy.xls
Normal file
BIN
examples/meshTopologyToy.xls
Normal file
Binary file not shown.
@@ -30,7 +30,7 @@ from gnpy.core.network import load_network, build_network, set_roadm_loss
|
|||||||
from gnpy.core.equipment import load_equipment, trx_mode_params
|
from gnpy.core.equipment import load_equipment, trx_mode_params
|
||||||
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused
|
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
from gnpy.core.request import Path_request, Result_element, compute_constrained_path, propagate
|
from gnpy.core.request import Path_request, Result_element, compute_constrained_path, propagate, jsontocsv
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
|
|
||||||
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
|
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
|
||||||
@@ -97,14 +97,15 @@ def compute_path(network, equipment, pathreqlist):
|
|||||||
#we assume that the destination is a strict constraint
|
#we assume that the destination is a strict constraint
|
||||||
pathreq.loose_list.append('strict')
|
pathreq.loose_list.append('strict')
|
||||||
print(f'Computing path from {pathreq.source} to {pathreq.destination}')
|
print(f'Computing path from {pathreq.source} to {pathreq.destination}')
|
||||||
print(f'with explicit path: {[pathreq.source]+pathreq.nodes_list}') #adding first node to be clearer on the output
|
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)
|
total_path = compute_constrained_path(network, pathreq)
|
||||||
|
print(f'Computed path (roadms):{[e.uid for e in total_path if isinstance(e, Roadm)]}\n')
|
||||||
# for debug
|
# for debug
|
||||||
# print(f'{pathreq.baud_rate} {pathreq.power} {pathreq.spacing} {pathreq.nb_channel}')
|
# print(f'{pathreq.baud_rate} {pathreq.power} {pathreq.spacing} {pathreq.nb_channel}')
|
||||||
|
if total_path :
|
||||||
total_path = propagate(total_path,pathreq,equipment, show=False)
|
total_path = propagate(total_path,pathreq,equipment, show=False)
|
||||||
|
else:
|
||||||
|
total_path = []
|
||||||
# we record the last tranceiver object in order to have th whole
|
# we record the last tranceiver object in order to have th whole
|
||||||
# information about spectrum. Important Note: since transceivers
|
# information about spectrum. Important Note: since transceivers
|
||||||
# attached to roadms are actually logical elements to simulate
|
# attached to roadms are actually logical elements to simulate
|
||||||
@@ -136,16 +137,32 @@ if __name__ == '__main__':
|
|||||||
print(pths)
|
print(pths)
|
||||||
test = compute_path(network, equipment, pths)
|
test = compute_path(network, equipment, pths)
|
||||||
|
|
||||||
if args.output is None:
|
|
||||||
#TODO write results
|
#TODO write results
|
||||||
print("demand\t\t\t\tsnr@bandwidth\tsnr@0.1nm")
|
|
||||||
|
|
||||||
|
header = ['demand','snr@bandwidth','snr@0.1nm','Receiver minOSNR']
|
||||||
|
data = []
|
||||||
|
data.append(header)
|
||||||
for i, p in enumerate(test):
|
for i, p in enumerate(test):
|
||||||
print(f'{pths[i].source} to {pths[i].destination} : {round(mean(p[-1].snr),2)} ,\
|
if p:
|
||||||
{round(mean(p[-1].snr+lin2db(pths[i].baud_rate/(12.5e9))),2)}')
|
line = [f'{pths[i].source} to {pths[i].destination} : ', f'{round(mean(p[-1].snr),2)}',\
|
||||||
|
f'{round(mean(p[-1].snr+lin2db(pths[i].baud_rate/(12.5e9))),2)}',\
|
||||||
|
f'{pths[i].OSNR}']
|
||||||
else:
|
else:
|
||||||
|
line = [f'no path from {pths[i].source} to {pths[i].destination} ']
|
||||||
|
data.append(line)
|
||||||
|
|
||||||
|
col_width = max(len(word) for row in data for word in row) # padding
|
||||||
|
for row in data:
|
||||||
|
print(''.join(word.ljust(col_width) for word in row))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if args.output :
|
||||||
result = []
|
result = []
|
||||||
for p in test:
|
for p in test:
|
||||||
result.append(Result_element(pths[test.index(p)],p))
|
result.append(Result_element(pths[test.index(p)],p))
|
||||||
with open(args.output, 'w') as f:
|
with open(args.output, 'w') as f:
|
||||||
f.write(dumps(path_result_json(result), indent=2))
|
f.write(dumps(path_result_json(result), indent=2))
|
||||||
|
fnamecsv = next(s for s in args.output.split('.')) + '.csv'
|
||||||
|
with open(fnamecsv,"w") as fcsv :
|
||||||
|
jsontocsv(path_result_json(result),equipment,fcsv)
|
||||||
@@ -14,80 +14,26 @@ and write results in an CSV file
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sys import exit
|
|
||||||
from csv import writer
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from json import dumps, loads
|
from json import loads
|
||||||
from gnpy.core.equipment import load_equipment
|
from gnpy.core.equipment import load_equipment
|
||||||
from gnpy.core.utils import lin2db
|
from gnpy.core.request import jsontocsv
|
||||||
|
|
||||||
START_LINE = 5
|
|
||||||
|
|
||||||
|
|
||||||
parser = ArgumentParser(description = 'A function that writes json path results in an excel sheet.')
|
parser = ArgumentParser(description = 'A function that writes json path results in an excel sheet.')
|
||||||
parser.add_argument('filename', nargs='?', type = Path)
|
parser.add_argument('filename', nargs='?', type = Path)
|
||||||
parser.add_argument('eqpt_filename', nargs='?', type = Path)
|
|
||||||
|
|
||||||
parser.add_argument('output_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__':
|
if __name__ == '__main__':
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
print(f'coucou {args.output_filename}')
|
|
||||||
with open(args.output_filename,"w") as file :
|
|
||||||
mywriter = writer(file)
|
|
||||||
mywriter.writerow(('path-id','source','destination','transponder-type',\
|
|
||||||
'transponder-mode','baud rate (Gbaud)', 'input power (dBm)','path','OSNR@bandwidth','OSNR@0.1nm','SNR@bandwidth','SNR@0.1nm','Pass?'))
|
|
||||||
|
|
||||||
|
with open(args.output_filename,"w") as file :
|
||||||
with open(args.filename) as f:
|
with open(args.filename) as f:
|
||||||
|
print(f'Reading {args.filename}')
|
||||||
json_data = loads(f.read())
|
json_data = loads(f.read())
|
||||||
equipment = load_equipment(args.eqpt_filename)
|
equipment = load_equipment(args.eqpt_filename)
|
||||||
tspjsondata = equipment['Transceiver']
|
print(f'Writing in {args.output_filename}')
|
||||||
#print(tspjsondata)
|
jsontocsv(json_data,equipment,file)
|
||||||
for p in json_data['path']:
|
|
||||||
path_id = int(p['path-id'])
|
|
||||||
source = p['path-properties']['path-route-objects'][0]\
|
|
||||||
['path-route-object']['unnumbered-hop']['node-id']
|
|
||||||
destination = p['path-properties']['path-route-objects'][-1]\
|
|
||||||
['path-route-object']['unnumbered-hop']['node-id']
|
|
||||||
pth = ' | '.join([ e['path-route-object']['unnumbered-hop']['node-id']
|
|
||||||
for e in p['path-properties']['path-route-objects']])
|
|
||||||
|
|
||||||
[tsp,mode] = p['path-properties']['path-route-objects'][0]\
|
|
||||||
['path-route-object']['unnumbered-hop']['hop-type'].split(' - ')
|
|
||||||
|
|
||||||
# find the min acceptable OSNR, baud rate from the eqpt library based on tsp (tupe) and mode (format)
|
|
||||||
try:
|
|
||||||
[minosnr, baud_rate] = next([m['OSNR'] , m['baud_rate']]
|
|
||||||
for m in equipment['Transceiver'][tsp].mode if m['format']==mode)
|
|
||||||
|
|
||||||
# for debug
|
|
||||||
# print(f'coucou {baud_rate}')
|
|
||||||
except IndexError:
|
|
||||||
msg = f'could not find tsp : {self.tsp} with mode: {self.tsp_mode} in eqpt library'
|
|
||||||
|
|
||||||
raise ValueError(msg)
|
|
||||||
output_snr = next(e['accumulative-value']
|
|
||||||
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'SNR@0.1nm')
|
|
||||||
output_snrbandwidth = next(e['accumulative-value']
|
|
||||||
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'SNR@bandwidth')
|
|
||||||
output_osnr = next(e['accumulative-value']
|
|
||||||
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'OSNR@0.1nm')
|
|
||||||
output_osnrbandwidth = next(e['accumulative-value']
|
|
||||||
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'OSNR@bandwidth')
|
|
||||||
power = next(e['accumulative-value']
|
|
||||||
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'reference_power')
|
|
||||||
mywriter.writerow((path_id,
|
|
||||||
source,
|
|
||||||
destination,
|
|
||||||
tsp,
|
|
||||||
mode,
|
|
||||||
baud_rate*1e-9,
|
|
||||||
round(lin2db(power)+30,2),
|
|
||||||
pth,
|
|
||||||
output_osnrbandwidth,
|
|
||||||
output_osnr,
|
|
||||||
output_snrbandwidth,
|
|
||||||
output_snr,
|
|
||||||
output_snr >= minosnr
|
|
||||||
))
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ def target_power(network, node, equipment): #get_fiber_dp
|
|||||||
exit()
|
exit()
|
||||||
if isinstance(node, Roadm) or not power_mode:
|
if isinstance(node, Roadm) or not power_mode:
|
||||||
dp = 0
|
dp = 0
|
||||||
print(f'{repr(node)} delta power in:\n{dp}dB')
|
# print(f'{repr(node)} delta power in:\n{dp}dB')
|
||||||
return dp
|
return dp
|
||||||
|
|
||||||
|
|
||||||
@@ -252,6 +252,7 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
|||||||
prev_dp = dp
|
prev_dp = dp
|
||||||
prev_node = node
|
prev_node = node
|
||||||
node = next_node
|
node = next_node
|
||||||
|
# print(f'{node.uid}')
|
||||||
next_node = next(n for n in network.successors(node))
|
next_node = next(n for n in network.successors(node))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ from gnpy.core.network import set_roadm_loss
|
|||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power
|
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
|
from csv import writer
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
RequestParams = namedtuple('RequestParams','request_id source destination trx_type'+
|
RequestParams = namedtuple('RequestParams','request_id source destination trx_type'+
|
||||||
' trx_mode nodes_list loose_list spacing power nb_channel frequency format baud_rate OSNR bit_rate roll_off')
|
' trx_mode nodes_list loose_list spacing power nb_channel frequency format baud_rate OSNR bit_rate roll_off')
|
||||||
@@ -55,17 +59,19 @@ class Path_request:
|
|||||||
f'destination: {self.destination}'])
|
f'destination: {self.destination}'])
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '\n\t'.join([ f'{type(self).__name__} {self.request_id}',
|
return '\n\t'.join([ f'{type(self).__name__} {self.request_id}',
|
||||||
f'source: {self.source}',
|
f'source: \t{self.source}',
|
||||||
f'destination: {self.destination}',
|
f'destination:\t{self.destination}',
|
||||||
f'trx type: {self.tsp}',
|
f'trx type:\t{self.tsp}',
|
||||||
f'baud_rate: {self.baud_rate}',
|
f'trx mode:\t{self.tsp_mode}',
|
||||||
f'spacing: {self.spacing}',
|
f'baud_rate:\t{self.baud_rate * 1e-9} Gbaud',
|
||||||
f'power: {self.power}'
|
f'bit_rate:\t{self.bit_rate * 1e-9} Gb/s',
|
||||||
|
f'spacing:\t{self.spacing * 1e-9} GHz',
|
||||||
|
f'power: \t{round(lin2db(self.power)+30,2)} dBm'
|
||||||
'\n'])
|
'\n'])
|
||||||
|
|
||||||
class Result_element(Element):
|
class Result_element(Element):
|
||||||
def __init__(self,path_request,computed_path):
|
def __init__(self,path_request,computed_path):
|
||||||
self.path_id = int(path_request.request_id)
|
self.path_id = path_request.request_id
|
||||||
self.path_request = path_request
|
self.path_request = path_request
|
||||||
self.computed_path = computed_path
|
self.computed_path = computed_path
|
||||||
hop_type = []
|
hop_type = []
|
||||||
@@ -78,6 +84,75 @@ class Result_element(Element):
|
|||||||
uid = property(lambda self: repr(self))
|
uid = property(lambda self: repr(self))
|
||||||
@property
|
@property
|
||||||
def pathresult(self):
|
def pathresult(self):
|
||||||
|
if not self.computed_path:
|
||||||
|
return {
|
||||||
|
'path-id': self.path_id,
|
||||||
|
'path-properties':{
|
||||||
|
'path-metric': [
|
||||||
|
{
|
||||||
|
'metric-type': 'SNR@bandwidth',
|
||||||
|
'accumulative-value': 'None'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'metric-type': 'SNR@0.1nm',
|
||||||
|
'accumulative-value': 'None'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'metric-type': 'OSNR@bandwidth',
|
||||||
|
'accumulative-value': 'None'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'metric-type': 'OSNR@0.1nm',
|
||||||
|
'accumulative-value': 'None'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'metric-type': 'reference_power',
|
||||||
|
'accumulative-value': self.path_request.power
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'path-srlgs': {
|
||||||
|
'usage': 'not used yet',
|
||||||
|
'values': 'not used yet'
|
||||||
|
},
|
||||||
|
'path-route-objects': [
|
||||||
|
{
|
||||||
|
'path-route-object': {
|
||||||
|
'index': 0,
|
||||||
|
'unnumbered-hop': {
|
||||||
|
'node-id': self.path_request.source,
|
||||||
|
'link-tp-id': self.path_request.source,
|
||||||
|
'hop-type': ' - '.join([self.path_request.tsp, self.path_request.tsp_mode]),
|
||||||
|
'direction': 'not used'
|
||||||
|
},
|
||||||
|
'label-hop': {
|
||||||
|
'te-label': {
|
||||||
|
'generic': 'not used yet',
|
||||||
|
'direction': 'not used yet'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'path-route-object': {
|
||||||
|
'index': 1,
|
||||||
|
'unnumbered-hop': {
|
||||||
|
'node-id': self.path_request.destination,
|
||||||
|
'link-tp-id': self.path_request.destination,
|
||||||
|
'hop-type': ' - '.join([self.path_request.tsp, self.path_request.tsp_mode]),
|
||||||
|
'direction': 'not used'
|
||||||
|
},
|
||||||
|
'label-hop': {
|
||||||
|
'te-label': {
|
||||||
|
'generic': 'not used yet',
|
||||||
|
'direction': 'not used yet'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
return {
|
return {
|
||||||
'path-id': self.path_id,
|
'path-id': self.path_id,
|
||||||
'path-properties':{
|
'path-properties':{
|
||||||
@@ -139,6 +214,8 @@ def compute_constrained_path(network, req):
|
|||||||
edfa = [n for n in network.nodes() if isinstance(n, Edfa)]
|
edfa = [n for n in network.nodes() if isinstance(n, Edfa)]
|
||||||
source = next(el for el in trx if el.uid == req.source)
|
source = next(el for el in trx if el.uid == req.source)
|
||||||
# start the path with its source
|
# start the path with its source
|
||||||
|
# TODO : avoid loops due to constraints , guess name base on string,
|
||||||
|
# avoid crashing if on req is not correct
|
||||||
total_path = [source]
|
total_path = [source]
|
||||||
for n in req.nodes_list:
|
for n in req.nodes_list:
|
||||||
# print(n)
|
# print(n)
|
||||||
@@ -170,7 +247,16 @@ def compute_constrained_path(network, req):
|
|||||||
else:
|
else:
|
||||||
msg = f'could not find a path from {source.uid} to node : {n} in network topology'
|
msg = f'could not find a path from {source.uid} to node : {n} in network topology'
|
||||||
logger.critical(msg)
|
logger.critical(msg)
|
||||||
raise ValueError(msg)
|
#raise ValueError(msg)
|
||||||
|
print(msg)
|
||||||
|
total_path = []
|
||||||
|
|
||||||
|
# preparing disjonction feature
|
||||||
|
# for p in all_simple_paths(network,\
|
||||||
|
# source=next(el for el in trx if el.uid == req.source),\
|
||||||
|
# target=next(el for el in trx if el.uid == req.destination)):
|
||||||
|
# print([e.uid for e in p if isinstance(e,Roadm)])
|
||||||
|
|
||||||
return total_path
|
return total_path
|
||||||
|
|
||||||
def propagate(path, req, equipment, show=False):
|
def propagate(path, req, equipment, show=False):
|
||||||
@@ -184,3 +270,68 @@ def propagate(path, req, equipment, show=False):
|
|||||||
if show :
|
if show :
|
||||||
print(el)
|
print(el)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def jsontocsv(json_data,equipment,fileout):
|
||||||
|
# read json path result file in accordance with:
|
||||||
|
# Yang model for requesting Path Computation
|
||||||
|
# draft-ietf-teas-yang-path-computation-01.txt.
|
||||||
|
# and write results in an CSV file
|
||||||
|
|
||||||
|
mywriter = writer(fileout)
|
||||||
|
mywriter.writerow(('path-id','source','destination','transponder-type',\
|
||||||
|
'transponder-mode','baud rate (Gbaud)', 'input power (dBm)','path',\
|
||||||
|
'OSNR@bandwidth','OSNR@0.1nm','SNR@bandwidth','SNR@0.1nm','Pass?'))
|
||||||
|
tspjsondata = equipment['Transceiver']
|
||||||
|
#print(tspjsondata)
|
||||||
|
for p in json_data['path']:
|
||||||
|
path_id = p['path-id']
|
||||||
|
source = p['path-properties']['path-route-objects'][0]\
|
||||||
|
['path-route-object']['unnumbered-hop']['node-id']
|
||||||
|
destination = p['path-properties']['path-route-objects'][-1]\
|
||||||
|
['path-route-object']['unnumbered-hop']['node-id']
|
||||||
|
pth = ' | '.join([ e['path-route-object']['unnumbered-hop']['node-id']
|
||||||
|
for e in p['path-properties']['path-route-objects']])
|
||||||
|
|
||||||
|
[tsp,mode] = p['path-properties']['path-route-objects'][0]\
|
||||||
|
['path-route-object']['unnumbered-hop']['hop-type'].split(' - ')
|
||||||
|
|
||||||
|
# find the min acceptable OSNR, baud rate from the eqpt library based on tsp (tupe) and mode (format)
|
||||||
|
try:
|
||||||
|
[minosnr, baud_rate] = next([m['OSNR'] , m['baud_rate']]
|
||||||
|
for m in equipment['Transceiver'][tsp].mode if m['format']==mode)
|
||||||
|
|
||||||
|
# for debug
|
||||||
|
# print(f'coucou {baud_rate}')
|
||||||
|
except IndexError:
|
||||||
|
msg = f'could not find tsp : {self.tsp} with mode: {self.tsp_mode} in eqpt library'
|
||||||
|
|
||||||
|
raise ValueError(msg)
|
||||||
|
output_snr = next(e['accumulative-value']
|
||||||
|
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'SNR@0.1nm')
|
||||||
|
output_snrbandwidth = next(e['accumulative-value']
|
||||||
|
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'SNR@bandwidth')
|
||||||
|
output_osnr = next(e['accumulative-value']
|
||||||
|
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'OSNR@0.1nm')
|
||||||
|
output_osnrbandwidth = next(e['accumulative-value']
|
||||||
|
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'OSNR@bandwidth')
|
||||||
|
power = next(e['accumulative-value']
|
||||||
|
for e in p['path-properties']['path-metric'] if e['metric-type'] == 'reference_power')
|
||||||
|
if isinstance(output_snr, str):
|
||||||
|
isok = ''
|
||||||
|
else:
|
||||||
|
isok = output_snr >= minosnr
|
||||||
|
mywriter.writerow((path_id,
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
tsp,
|
||||||
|
mode,
|
||||||
|
baud_rate*1e-9,
|
||||||
|
round(lin2db(power)+30,2),
|
||||||
|
pth,
|
||||||
|
output_osnrbandwidth,
|
||||||
|
output_osnr,
|
||||||
|
output_snrbandwidth,
|
||||||
|
output_snr,
|
||||||
|
isok
|
||||||
|
))
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"path-request": [
|
"path-request": [
|
||||||
{
|
{
|
||||||
"request-id": 0,
|
"request-id": "0",
|
||||||
"source": "BREST_KLA",
|
"source": "BREST_KLA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "Vannes_KBE",
|
||||||
"src-tp-id": "trx BREST_KLA",
|
"src-tp-id": "trx BREST_KLA",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 1,
|
"request-id": "1",
|
||||||
"source": "Lorient_KMA",
|
"source": "Lorient_KMA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "Vannes_KBE",
|
||||||
"src-tp-id": "trx Lorient_KMA",
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
@@ -55,26 +55,26 @@
|
|||||||
],
|
],
|
||||||
"synchronisation": [
|
"synchronisation": [
|
||||||
{
|
{
|
||||||
"synchonization-id": 0,
|
"synchonization-id": "0",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
0,
|
"0",
|
||||||
1
|
"1"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"synchonization-id": 1,
|
"synchonization-id": "1",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
1,
|
"1",
|
||||||
0
|
"0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"path-request": [
|
"path-request": [
|
||||||
{
|
{
|
||||||
"request-id": 0,
|
"request-id": "0",
|
||||||
"source": "Lorient_KMA",
|
"source": "Lorient_KMA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "Vannes_KBE",
|
||||||
"src-tp-id": "trx Lorient_KMA",
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 1,
|
"request-id": "1",
|
||||||
"source": "Brest_KLA",
|
"source": "Brest_KLA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "Vannes_KBE",
|
||||||
"src-tp-id": "trx Brest_KLA",
|
"src-tp-id": "trx Brest_KLA",
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 3,
|
"request-id": "3",
|
||||||
"source": "Lannion_CAS",
|
"source": "Lannion_CAS",
|
||||||
"destination": "Rennes_STA",
|
"destination": "Rennes_STA",
|
||||||
"src-tp-id": "trx Lannion_CAS",
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 4,
|
"request-id": "4",
|
||||||
"source": "Rennes_STA",
|
"source": "Rennes_STA",
|
||||||
"destination": "Lannion_CAS",
|
"destination": "Lannion_CAS",
|
||||||
"src-tp-id": "trx Rennes_STA",
|
"src-tp-id": "trx Rennes_STA",
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 5,
|
"request-id": "5",
|
||||||
"source": "Lorient_KMA",
|
"source": "Lorient_KMA",
|
||||||
"destination": "Lannion_CAS",
|
"destination": "Lannion_CAS",
|
||||||
"src-tp-id": "trx Lorient_KMA",
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
@@ -180,38 +180,38 @@
|
|||||||
],
|
],
|
||||||
"synchronisation": [
|
"synchronisation": [
|
||||||
{
|
{
|
||||||
"synchonization-id": 0,
|
"synchonization-id": "0",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
0,
|
"0",
|
||||||
0
|
"0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"synchonization-id": 3,
|
"synchonization-id": "3",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
3,
|
"3",
|
||||||
4
|
"4"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"synchonization-id": 5,
|
"synchonization-id": "5",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
5,
|
"5",
|
||||||
0
|
"0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"path-request": [
|
"path-request": [
|
||||||
{
|
{
|
||||||
"request-id": 0,
|
"request-id": "0",
|
||||||
"source": "Lorient_KMA",
|
"source": "Lorient_KMA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "Vannes_KBE",
|
||||||
"src-tp-id": "trx Lorient_KMA",
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 1,
|
"request-id": "1",
|
||||||
"source": "Brest_KLA",
|
"source": "Brest_KLA",
|
||||||
"destination": "Vannes_KBE",
|
"destination": "Vannes_KBE",
|
||||||
"src-tp-id": "trx Brest_KLA",
|
"src-tp-id": "trx Brest_KLA",
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 3,
|
"request-id": "3",
|
||||||
"source": "Lannion_CAS",
|
"source": "Lannion_CAS",
|
||||||
"destination": "Rennes_STA",
|
"destination": "Rennes_STA",
|
||||||
"src-tp-id": "trx Lannion_CAS",
|
"src-tp-id": "trx Lannion_CAS",
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 4,
|
"request-id": "4",
|
||||||
"source": "Rennes_STA",
|
"source": "Rennes_STA",
|
||||||
"destination": "Lannion_CAS",
|
"destination": "Lannion_CAS",
|
||||||
"src-tp-id": "trx Rennes_STA",
|
"src-tp-id": "trx Rennes_STA",
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"request-id": 5,
|
"request-id": "5",
|
||||||
"source": "Lorient_KMA",
|
"source": "Lorient_KMA",
|
||||||
"destination": "Lannion_CAS",
|
"destination": "Lannion_CAS",
|
||||||
"src-tp-id": "trx Lorient_KMA",
|
"src-tp-id": "trx Lorient_KMA",
|
||||||
@@ -180,38 +180,38 @@
|
|||||||
],
|
],
|
||||||
"synchronisation": [
|
"synchronisation": [
|
||||||
{
|
{
|
||||||
"synchonization-id": 0,
|
"synchonization-id": "0",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
0,
|
"0",
|
||||||
0
|
"0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"synchonization-id": 3,
|
"synchonization-id": "3",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
3,
|
"3",
|
||||||
4
|
"4"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"synchonization-id": 5,
|
"synchonization-id": "5",
|
||||||
"svec": {
|
"svec": {
|
||||||
"relaxable": "False",
|
"relaxable": "False",
|
||||||
"link-diverse": "True",
|
"link-diverse": "True",
|
||||||
"node-diverse": "True",
|
"node-diverse": "True",
|
||||||
"request-id-number": [
|
"request-id-number": [
|
||||||
5,
|
"5",
|
||||||
0
|
"0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user