Merge pull request #81 from Orange-OpenSource/test_update

Test update
This commit is contained in:
James
2018-06-22 11:24:44 -04:00
committed by GitHub
29 changed files with 3181 additions and 201 deletions

View File

@@ -5,5 +5,7 @@ python:
install:
- pip install -r requirements.txt
# command to run tests
before_script:
- export PYTHONPATH=$PYTHONPATH:/home/travis/build/Orange-OpenSource/gnpy/examples
script:
- pytest

View File

@@ -115,7 +115,7 @@ Eqpt sheet
Eqt sheet is optional. It lists the amplifiers types and characteristics on each degree of the *Node A* line.
Links sheet must contain sixteen columns::
<-- east cable from a to z --> <-- west from z to -->
<-- east cable from a to z --> <-- west from z to a -->
Node A ; Node Z ; amp type ; att_in ; amp gain ; tilt ; att_out ; amp type ; att_in ; amp gain ; tilt ; att_out
If the sheet is present, it MUST have as many lines as egress directions of ROADMs defined in Links Sheet.
@@ -172,9 +172,80 @@ then Eqpt sheet should contain:
# to be completed #
(in progress)
Service sheet
-------------
Service sheet is optional. It lists the services for which path and feasibility must be computed with path_requests_run.py.
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** 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)
- **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)
- **Destination** is mandatory. It is the name of the destination node (as listed in Nodes sheet). Source MUST be a ROADM node. (TODO: relax this and accept trx entries)
- **TRX type and mode** are mandatory. They are the variety type and selected mode of the transceiver to be used for the propagation simulation. These modes MUST be defined in the equipment library. The format of the mode is used as the name of the mode. (TODO: maybe add another mode id on Transceiver library ?). In particular the mode selection defines the channel baudrate to be used for the propagation simulation.
- **System: spacing ; System: input power (dBm) ; System: nb of channels** are mandatory input defining the system parameters for the propagation simulation.
- spacing is the channel spacing defined in GHz
- input power is the channel optical input power in dBm
- nb of channels is the number of channels to be used for the simulation.
- **routing: disjoint from ; routing: path ; routing: is loose?** are optional.
- disjoint from: (work not started) identifies the requests from which this request must be disjoint. It is not used yet
- path: is the set of ROADM nodes that must be used by the path. It must contain the list of ROADM names that the path must cross. TODO : only ROADM nodes are accepted in this release. Relax this with any type of nodes.
- is loose? (in progress) 'no' value means that the list of nodes should be strictly followed, while any other value means that the constraint may be relaxed if the node is not reachable.
# to be completed #
convert_service_sheet.py
------------------------
`convert_service_sheet.py <examples/convert_service_sheet.py>`_ converts the service sheet to a json file following the Yang model for requesting Path Computation defined in `draft-ietf-teas-yang-path-computation-01.txt <https://www.ietf.org/id/draft-ietf-teas-yang-path-computation-01.pdf>`_. TODO: verify that this implementation is correct + give feedback to ietf on what is missing for our specific application.
For PSE use, additional fields with trx type and mode have been added to the te-bandwidth field.
**Usage**: convert_service_sheet.py [-h] [-v] [-o OUTPUT] [workbook_name.xls]
.. code-block:: shell
$ cd examples
$ python convert_service_sheet.py meshTopologyExampleV2.xls -o service_file.json
-o output_file.json is an optional parameter:
- if not used, the program output the json data on standard output and on a json file with name 'workbook_name_services.json'.
A template for the json file can be found here: `service_template.json <service_template.json>`_
path_requests_run.py
------------------------
**Usage**: path_requests_run.py [-h] [-v] [-o OUTPUT]
[network_filename xls or json] [service_filename xls or json] [eqpt_filename json]
.. code-block:: shell
$ cd examples
$ python path_requests_run.py meshTopologyExampleV2.xls service_file.json eqpt_file -o output_file.json
A function that computes performances for a list of services provided in the service file (accepts json or excel format.
If no output file is given, the computation is shown on standard output for demo.
If a file is specified with the optional -o argument, the result of the computation is converted into a json format following the Yang model for requesting Path Computation defined in `draft-ietf-teas-yang-path-computation-01.txt <https://www.ietf.org/id/draft-ietf-teas-yang-path-computation-01.pdf>`_. TODO: verify that this implementation is correct + give feedback to ietf on what is missing for our specific application.
A template for the result of computation json file can be found here: `path_result_template.json <path_result_template.json>`_
Important note: path_requests_run.py is not a dimensionning tool, it only computes path feasibility assuming full load with system parameters input in the service file. The network topology is created only once for the set of requests. As a result the transceiver element acts as a "logical starting/stopping point" for the spectral information propagation. At that point it is not meant to represent the capacity of add drop ports
As a result transponder type is not part of the network info. it is related to the list of services requests.
(in progress)

203
examples/compare_json.py Normal file
View File

@@ -0,0 +1,203 @@
from json import loads
from pathlib import Path
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('expected_output', type=Path, metavar='FILE')
parser.add_argument('actual_output', type=Path, metavar='FILE')
parser.add_argument('-o', '--output', default=None)
def compare_network_file(expected_output, actual_output):
with open(expected_output) as f:
expected_json = f.read()
with open(actual_output) as f:
actual_json = f.read()
expected_data = loads(expected_json)
actual_data = loads(actual_json)
print(f'Comparing:'
f'\n\t{expected_output}'
f'\n\t{actual_output}')
expected_elements = expected_data['elements']
actual_elements = actual_data['elements']
expected_elements = {el['uid']: el for el in expected_elements}
actual_elements = {el['uid']: el for el in actual_elements}
missing = set(expected_elements) - set(actual_elements)
extra = set(actual_elements) - set(expected_elements)
different = [(expected_elements[x], actual_elements[x]) for
x in set(expected_elements) & set(actual_elements)
if expected_elements[x] != actual_elements[x]]
identical = True
msg = []
if missing:
msg.append(f'Missing Elements (by uid): {len(missing)}/{len(expected_elements)}')
for x in sorted(missing):
msg.append(f'\t{expected_elements[x]}')
identical = False
if extra:
msg.append(f'Extra Elements (by uid): {len(extra)}/{len(expected_elements)}')
for x in sorted(extra):
msg.append(f'\t{actual_elements[x]}')
identical = False
if different:
msg.append(f'Different Elements: {len(different)}/{len(expected_elements)}')
for x, y in sorted(different, key=lambda xy: xy[0]['uid']):
msg.append(f'\t- Expected: {x}\n\t Actual: {y}')
identical = False
if not missing and not extra and not different:
msg.append('All elements match!')
identical = True
expected_connections = expected_data['connections']
actual_connections = actual_data['connections']
missing = []
for x in sorted(expected_connections, key=lambda d: (d['from_node'], d['to_node'])):
if x not in actual_connections:
missing.append(x)
extra = []
for x in sorted(actual_connections, key=lambda d: (d['from_node'], d['to_node'])):
if x not in expected_connections:
extra.append(x)
if missing:
msg.append(f'Missing Connections: {len(missing)}/{len(expected_connections)}')
for x in missing:
msg.append(f'\t{x}')
identical = False
if extra:
msg.append(f'Extra Connections: {len(extra)}/{len(expected_connections)}')
for x in extra:
msg.append(f'\t{x}')
identical = False
if not missing and not extra:
msg.append('All connections match!')
return identical,msg
def compare_service_file(expected_output, actual_output):
with open(expected_output) as f:
expected_json = f.read()
with open(actual_output) as f:
actual_json = f.read()
expected_data = loads(expected_json)
actual_data = loads(actual_json)
print(f'Comparing:'
f'\n\t{expected_output}'
f'\n\t{actual_output}')
expected_elements = expected_data['path-request']
actual_elements = actual_data['path-request']
expected_elements = {el['request-id']: el for el in expected_elements}
actual_elements = {el['request-id']: el for el in actual_elements}
missing = set(expected_elements) - set(actual_elements)
extra = set(actual_elements) - set(expected_elements)
different = [(expected_elements[x], actual_elements[x]) for
x in set(expected_elements) & set(actual_elements)
if expected_elements[x] != actual_elements[x]]
identical = True
msg = []
if missing:
msg.append(f'Missing requests (by request-id): {len(missing)}/{len(expected_elements)}')
for x in sorted(missing):
msg.append(f'\t{expected_elements[x]}')
identical = False
if extra:
msg.append(f'Extra requests (by request-id): {len(extra)}/{len(expected_elements)}')
for x in sorted(extra):
msg.append(f'\t{actual_elements[x]}')
identical = False
if different:
msg.append(f'Different requests: {len(different)}/{len(expected_elements)}')
for x, y in sorted(different, key=lambda xy: xy[0]['request-id']):
msg.append(f'\t- Expected: {x}\n\t Actual: {y}')
identical = False
if not missing and not extra and not different:
msg.append('All elements match!')
expected_elements = expected_data['synchronisation']
actual_elements = actual_data['synchronisation']
expected_elements = {el['synchonization-id']: el for el in expected_elements}
actual_elements = {el['synchonization-id']: el for el in actual_elements}
missing = set(expected_elements) - set(actual_elements)
extra = set(actual_elements) - set(expected_elements)
different = [(expected_elements[x], actual_elements[x]) for
x in set(expected_elements) & set(actual_elements)
if expected_elements[x] != actual_elements[x]]
if missing:
msg.append(f'Missing synchronisations (by synchronisation-id): {len(missing)}/{len(expected_elements)}')
for x in sorted(missing):
msg.append(f'\t{expected_elements[x]}')
identical = False
if extra:
msg.append(f'Extra synchronisations (by synchronisation-id): {len(extra)}/{len(expected_elements)}')
for x in sorted(extra):
msg.append(f'\t{actual_elements[x]}')
identical = False
if different:
msg.append(f'Different synchronisations: {len(different)}/{len(expected_elements)}')
for x, y in sorted(different, key=lambda xy: xy[0]['synchonization-id']):
msg.append(f'\t- Expected: {x}\n\t Actual: {y}')
identical = False
if not missing and not extra and not different:
msg.append('All synchronisations match!')
return identical,msg
def compare_result_file(expected_output, actual_output):
with open(expected_output) as f:
expected_json = f.read()
with open(actual_output) as f:
actual_json = f.read()
expected_data = loads(expected_json)
actual_data = loads(actual_json)
print(f'Comparing:'
f'\n\t{expected_output}'
f'\n\t{actual_output}')
expected_elements = expected_data['path']
actual_elements = actual_data['path']
expected_elements = {el['path-id']: el for el in expected_elements}
actual_elements = {el['path-id']: el for el in actual_elements}
missing = set(expected_elements) - set(actual_elements)
extra = set(actual_elements) - set(expected_elements)
different = [(expected_elements[x], actual_elements[x]) for
x in set(expected_elements) & set(actual_elements)
if expected_elements[x] != actual_elements[x]]
identical = True
msg = []
if missing:
msg.append(f'Missing paths (by path-id): {len(missing)}/{len(expected_elements)}')
for x in sorted(missing):
msg.append(f'\t{expected_elements[x]}')
identical = False
if extra:
msg.append(f'Extra paths (by path-id): {len(extra)}/{len(expected_elements)}')
for x in sorted(extra):
msg.append(f'\t{actual_elements[x]}')
identical = False
if different:
msg.append(f'Different paths: {len(different)}/{len(expected_elements)}')
for x, y in sorted(different, key=lambda xy: xy[0]['path-id']):
msg.append(f'\t- Expected: {x}\n\t Actual: {y}')
identical = False
if not missing and not extra and not different:
msg.append('All elements match!')
return identical,msg
if __name__ == '__main__':
args = parser.parse_args()
identical,msg = compare_result_file(args.expected_output, args.actual_output)
print(identical)
if args.output:
with open(args.output,"w") as f:
f.write('\n'.join(msg))

View File

@@ -0,0 +1,220 @@
#!/usr/bin/env python3
# TelecomInfraProject/gnpy/examples
# Module name : convert_service_sheet.py
# Version :
# License : BSD 3-Clause Licence
# Copyright (c) 2018, Telecom Infra Project
"""
@author: esther.lerouzic
@author: jeanluc-auge
xls parser, that can be called to create a json request file in accordance with:
Yang model for requesting Path Computation
draft-ietf-teas-yang-path-computation-01.txt.
"""
from sys import exit
try:
from xlrd import open_workbook, XL_CELL_EMPTY
except ModuleNotFoundError:
exit('Required: `pip install xlrd`')
from argparse import ArgumentParser
from collections import namedtuple
from logging import getLogger, basicConfig, CRITICAL, DEBUG, INFO
from json import dumps
from pathlib import Path
from gnpy.core.equipment import load_equipment
from gnpy.core.utils import db2lin, lin2db
SERVICES_COLUMN = 11
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
all_rows = lambda sheet, start=0: (sheet.row(x) for x in range(start, sheet.nrows))
logger = getLogger(__name__)
parser = ArgumentParser()
parser.add_argument('workbook', nargs='?', type = Path , default='meshTopologyExampleV2.xls')
parser.add_argument('-v', '--verbose', action='count')
parser.add_argument('-o', '--output', default=None)
# Type for input data
class Request(namedtuple('Request', 'request_id source destination trx_type mode \
spacing power nb_channel disjoint_from nodes_list is_loose')):
def __new__(cls, request_id, source, destination, trx_type, mode , spacing , power , nb_channel , disjoint_from ='' , nodes_list = None, is_loose = ''):
return super().__new__(cls, request_id, source, destination, trx_type, mode, spacing, power, nb_channel, disjoint_from, nodes_list, is_loose)
# Type for output data: // from dutc
class Element:
def __eq__(self, other):
return type(self) == type(other) and self.uid == other.uid
def __hash__(self):
return hash((type(self), self.uid))
class Request_element(Element):
def __init__(self,Request,eqpt_filename):
self.request_id = int(Request.request_id)
self.source = Request.source
self.destination = Request.destination
self.srctpid = f'trx {Request.source}'
self.dsttpid = f'trx {Request.destination}'
# test that trx_type belongs to eqpt_config.json
# if not replace it with a default
equipment = load_equipment(eqpt_filename)
if equipment['Transceiver'][Request.trx_type]:
self.trx_type = Request.trx_type
self.mode = Request.mode
else:
#TODO : this case must raise an error instead of using Voyager
self.trx_type = 'Voyager_16QAM'
print(f'Transceiver type {Request.trx_type} is not defined in {eqpt_filename}')
print('replaced by Voyager_16QAM')
self.spacing = Request.spacing * 1e9
self.power = db2lin(Request.power) * 1e-3
self.nb_channel = int(Request.nb_channel)
if isinstance(Request.disjoint_from,str):
self.disjoint_from = [int(n) for n in Request.disjoint_from.split()]
else:
self.disjoint_from = [int(Request.disjoint_from)]
self.nodes_list = []
if Request.nodes_list :
self.nodes_list = Request.nodes_list.split(' | ')
try :
self.nodes_list.remove(self.source)
msg = f'{self.source} removed from explicit path node-list'
logger.info(msg)
print(msg)
except ValueError:
msg = f'{self.source} already removed from explicit path node-list'
logger.info(msg)
# print(msg)
try :
self.nodes_list.remove(self.destination)
msg = f'{self.destination} removed from explicit path node-list'
logger.info(msg)
print(msg)
except ValueError:
msg = f'{self.destination} already removed from explicit path node-list'
logger.info(msg)
# print(msg)
self.loose = 'loose'
if Request.is_loose == 'no' :
self.loose = 'strict'
uid = property(lambda self: repr(self))
@property
def pathrequest(self):
return {
'request-id':self.request_id,
'source': self.source,
'destination': self.destination,
'src-tp-id': self.srctpid,
'dst-tp-id': self.dsttpid,
'path-constraints':{
'te-bandwidth': {
'technology': 'flexi-grid',
'trx_type' : self.trx_type,
'trx_mode' : self.mode,
'effective-freq-slot':[{'n': 'null','m': 'null'}] ,
'spacing' : self.spacing,
'max-nb-of-channel' : self.nb_channel,
'output-power' : self.power
}
},
'optimizations': {
'explicit-route-include-objects': [
{
'index': self.nodes_list.index(node),
'unnumbered-hop':{
'node-id': f'{node}',
'link-tp-id': 'link-tp-id is not used',
'hop-type': 'loose',
'direction': 'direction is not used'
},
'label-hop':{
'te-label': {
'generic': 'generic is not used',
'direction': 'direction is not used'
}
}
}
for node in self.nodes_list
]
}
}
@property
def pathsync(self):
if self.disjoint_from :
return {'synchonization-id':self.request_id,
'svec': {
'relaxable' : 'False',
'link-diverse': 'True',
'node-diverse': 'True',
'request-id-number': [self.request_id]+ [n for n in self.disjoint_from]
}
}
# TO-DO: avoid multiple entries with same synchronisation vectors
@property
def json(self):
return self.pathrequest , self.pathsync
def convert_service_sheet(input_filename, eqpt_filename, output_filename='', filter_region=[]):
service = parse_excel(input_filename)
req = [Request_element(n,eqpt_filename) for n in service]
# dumps the output into a json file with name
# split_filename = [input_filename[0:len(input_filename)-len(suffix_filename)] , suffix_filename[1:]]
if output_filename=='':
output_filename = f'{str(input_filename)[0:len(str(input_filename))-len(str(input_filename.suffixes[0]))]}_services.json'
# for debug
# print(json_filename)
data = {
'path-request': [n.json[0] for n in req],
'synchronisation': [n.json[1] for n in req
if n.json[1] is not None]
}
with open(output_filename, 'w') as f:
f.write(dumps(data, indent=2))
return data
# to be used from dutc
def parse_row(row, fieldnames):
return {f: r.value for f, r in zip(fieldnames, row[0:SERVICES_COLUMN])
if r.ctype != XL_CELL_EMPTY}
#
def parse_excel(input_filename):
with open_workbook(input_filename) as wb:
service_sheet = wb.sheet_by_name('Service')
services = list(parse_service_sheet(service_sheet))
return services
def parse_service_sheet(service_sheet):
logger.info(f'Validating headers on {service_sheet.name!r}')
header = [x.value.strip() for x in service_sheet.row(4)[0:SERVICES_COLUMN]]
expected = ['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?']
if header != expected:
msg = f'Malformed header on Service sheet: {header} != {expected}'
logger.critical(msg)
raise ValueError(msg)
service_fieldnames = 'request_id source destination trx_type mode spacing power nb_channel disjoint_from nodes_list is_loose'.split()
# Important Note: it reads all colum on each row so that
# it is not possible to write annotation in the excel sheet
# outside the SERVICES_COLUMN ... TO BE IMPROVED
# request_id should be unique for disjunction constraints (not used yet)
for row in all_rows(service_sheet, start=5):
yield Request(**parse_row(row[0:SERVICES_COLUMN], service_fieldnames))
if __name__ == '__main__':
args = parser.parse_args()
basicConfig(level={2: DEBUG, 1: INFO, 0: CRITICAL}.get(args.verbose, CRITICAL))
logger.info(f'Converting Service sheet {args.workbook!r} into gnpy JSON format')
if args.output is None:
data = convert_service_sheet(args.workbook,'eqpt_config.json')
print(dumps(data, indent=2))
else:
data = convert_service_sheet(args.workbook,'eqpt_config.json',args.output)

View File

@@ -93,10 +93,10 @@ def create_eqt_template(links,nodes, links_by_src , links_by_dest, input_filenam
temp = []
i = 0
for lk in links:
temp = [lk.src , lk.dest]
tab.append(temp)
# print(temp)
my_file.write(f'{temp[0]}\t{temp[1]}\n')
if [e for n,e in nodes if n==lk.src][0] != 'FUSED' :
temp = [lk.src , lk.dest]
tab.append(temp)
my_file.write(f'{temp[0]}\t{temp[1]}\n')
for n in nodes :
if n.eqt.lower() == 'roadm' :
for src in links_by_dest[n.nodename] :

View File

@@ -20,6 +20,14 @@
"p_max": 21,
"nf_min": 7,
"nf_max": 11
},
{
"type_variety": "test",
"gain_flatmax": 25,
"gain_min": 15,
"p_max": 21,
"nf_min": 5.8,
"nf_max": 10
}
],
"Fiber":[{
@@ -41,11 +49,50 @@
"loss": 20
}],
"SI":[{
"f_min": 193.1e12,
"Nch": 96,
"f_min": 191.3e12,
"Nch": 80,
"baud_rate": 32e9,
"spacing": 50e9,
"spacing": 75e9,
"roll_off": 0.15,
"power": 1e-3
}]
"power": 1.2589e-3
}],
"Transceiver":[
{
"type_variety": "vendorA_trx-type1",
"frequency":{
"min": 191.35e12,
"max": 196.1e12
},
"mode":[
{
"format": "PS_SP64_1",
"baudrate": 32e9,
"OSNR": 9,
"bit_rate": 100e9
},
{
"format": "PS_SP64_2",
"baudrate": 66e9,
"OSNR": 10,
"bit_rate": 200e9
}
]
},
{
"type_variety": "Voyager_16QAM",
"frequency":{
"min": 191.35e12,
"max": 196.1e12
},
"mode":[
{
"format": "16QAM",
"baudrate": 32e9,
"OSNR": 15,
"bit_rate": 200e9
}
]
}
]
}

View File

@@ -6,8 +6,8 @@
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Transceiver"
@@ -18,8 +18,8 @@
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Transceiver"
@@ -30,8 +30,8 @@
"location": {
"city": "Vannes_KBE",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 4.0
}
},
"type": "Transceiver"
@@ -42,8 +42,8 @@
"location": {
"city": "Rennes_STA",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 0.0,
"longitude": 0.0
}
},
"type": "Transceiver"
@@ -54,8 +54,8 @@
"location": {
"city": "Brest_KLA",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 4.0,
"longitude": 0.0
}
},
"type": "Transceiver"
@@ -66,8 +66,8 @@
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Roadm"
@@ -78,8 +78,8 @@
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Roadm"
@@ -90,8 +90,8 @@
"location": {
"city": "Vannes_KBE",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 4.0
}
},
"type": "Roadm"
@@ -102,8 +102,8 @@
"location": {
"city": "Rennes_STA",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 0.0,
"longitude": 0.0
}
},
"type": "Roadm"
@@ -114,8 +114,8 @@
"location": {
"city": "Brest_KLA",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 4.0,
"longitude": 0.0
}
},
"type": "Roadm"
@@ -126,8 +126,8 @@
"location": {
"city": "Corlay",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 1.0
}
},
"type": "Fused"
@@ -138,8 +138,8 @@
"location": {
"city": "Loudeac",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 2.0
}
},
"type": "Fused"
@@ -150,8 +150,8 @@
"location": {
"city": "Morlaix",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 3.0,
"longitude": 0.0
}
},
"type": "Fused"
@@ -162,8 +162,8 @@
"location": {
"city": "Corlay",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 1.0
}
},
"type": "Fused"
@@ -174,8 +174,8 @@
"location": {
"city": "Loudeac",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 2.0,
"longitude": 2.0
}
},
"type": "Fused"
@@ -186,18 +186,18 @@
"location": {
"city": "Morlaix",
"region": "RLD",
"latitude": 0,
"longitude": 0
"latitude": 3.0,
"longitude": 0.0
}
},
"type": "Fused"
},
{
"uid": "fiber (Lannion_CAS \u2192 Corlay)-",
"uid": "fiber (Lannion_CAS \u2192 Corlay)-F061",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 0.5
}
},
"type": "Fiber",
@@ -209,11 +209,11 @@
}
},
{
"uid": "fiber (Corlay \u2192 Loudeac)-",
"uid": "fiber (Corlay \u2192 Loudeac)-F010",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 1.5
}
},
"type": "Fiber",
@@ -225,11 +225,11 @@
}
},
{
"uid": "fiber (Loudeac \u2192 Lorient_KMA)-",
"uid": "fiber (Loudeac \u2192 Lorient_KMA)-F054",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 2.5
}
},
"type": "Fiber",
@@ -241,11 +241,11 @@
}
},
{
"uid": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F01",
"uid": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 3.5
}
},
"type": "Fiber",
@@ -257,10 +257,10 @@
}
},
{
"uid": "fiber (Lannion_CAS \u2192 Stbrieuc)-",
"uid": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 1.5,
"longitude": 0.0
}
},
@@ -273,10 +273,10 @@
}
},
{
"uid": "fiber (Stbrieuc \u2192 Rennes_STA)-",
"uid": "fiber (Stbrieuc \u2192 Rennes_STA)-F057",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 0.5,
"longitude": 0.0
}
},
@@ -289,10 +289,10 @@
}
},
{
"uid": "fiber (Lannion_CAS \u2192 Morlaix)-",
"uid": "fiber (Lannion_CAS \u2192 Morlaix)-F059",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 2.5,
"longitude": 0.0
}
},
@@ -305,10 +305,10 @@
}
},
{
"uid": "fiber (Morlaix \u2192 Brest_KLA)-",
"uid": "fiber (Morlaix \u2192 Brest_KLA)-F060",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 3.5,
"longitude": 0.0
}
},
@@ -321,11 +321,11 @@
}
},
{
"uid": "fiber (Corlay \u2192 Lannion_CAS)-",
"uid": "fiber (Corlay \u2192 Lannion_CAS)-F061",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 0.5
}
},
"type": "Fiber",
@@ -337,11 +337,11 @@
}
},
{
"uid": "fiber (Loudeac \u2192 Corlay)-",
"uid": "fiber (Loudeac \u2192 Corlay)-F010",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 1.5
}
},
"type": "Fiber",
@@ -353,11 +353,11 @@
}
},
{
"uid": "fiber (Lorient_KMA \u2192 Loudeac)-",
"uid": "fiber (Lorient_KMA \u2192 Loudeac)-F054",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 2.5
}
},
"type": "Fiber",
@@ -369,11 +369,11 @@
}
},
{
"uid": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F01",
"uid": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055",
"metadata": {
"location": {
"latitude": 0.0,
"longitude": 0.0
"latitude": 2.0,
"longitude": 3.5
}
},
"type": "Fiber",
@@ -385,10 +385,10 @@
}
},
{
"uid": "fiber (Stbrieuc \u2192 Lannion_CAS)-",
"uid": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 1.5,
"longitude": 0.0
}
},
@@ -401,10 +401,10 @@
}
},
{
"uid": "fiber (Rennes_STA \u2192 Stbrieuc)-",
"uid": "fiber (Rennes_STA \u2192 Stbrieuc)-F057",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 0.5,
"longitude": 0.0
}
},
@@ -417,10 +417,10 @@
}
},
{
"uid": "fiber (Morlaix \u2192 Lannion_CAS)-",
"uid": "fiber (Morlaix \u2192 Lannion_CAS)-F059",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 2.5,
"longitude": 0.0
}
},
@@ -433,10 +433,10 @@
}
},
{
"uid": "fiber (Brest_KLA \u2192 Morlaix)-",
"uid": "fiber (Brest_KLA \u2192 Morlaix)-F060",
"metadata": {
"location": {
"latitude": 0.0,
"latitude": 3.5,
"longitude": 0.0
}
},
@@ -452,122 +452,122 @@
"connections": [
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Corlay)-"
"to_node": "fiber (Lannion_CAS \u2192 Corlay)-F061"
},
{
"from_node": "fiber (Corlay \u2192 Lannion_CAS)-",
"from_node": "fiber (Corlay \u2192 Lannion_CAS)-F061",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-"
"to_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056"
},
{
"from_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-",
"from_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Morlaix)-"
"to_node": "fiber (Lannion_CAS \u2192 Morlaix)-F059"
},
{
"from_node": "fiber (Morlaix \u2192 Lannion_CAS)-",
"from_node": "fiber (Morlaix \u2192 Lannion_CAS)-F059",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Corlay)-",
"from_node": "fiber (Lannion_CAS \u2192 Corlay)-F061",
"to_node": "ingress fused spans in Corlay"
},
{
"from_node": "ingress fused spans in Corlay",
"to_node": "fiber (Corlay \u2192 Loudeac)-"
"to_node": "fiber (Corlay \u2192 Loudeac)-F010"
},
{
"from_node": "fiber (Loudeac \u2192 Corlay)-",
"from_node": "fiber (Loudeac \u2192 Corlay)-F010",
"to_node": "egress fused spans in Corlay"
},
{
"from_node": "egress fused spans in Corlay",
"to_node": "fiber (Corlay \u2192 Lannion_CAS)-"
"to_node": "fiber (Corlay \u2192 Lannion_CAS)-F061"
},
{
"from_node": "fiber (Corlay \u2192 Loudeac)-",
"from_node": "fiber (Corlay \u2192 Loudeac)-F010",
"to_node": "ingress fused spans in Loudeac"
},
{
"from_node": "ingress fused spans in Loudeac",
"to_node": "fiber (Loudeac \u2192 Lorient_KMA)-"
"to_node": "fiber (Loudeac \u2192 Lorient_KMA)-F054"
},
{
"from_node": "fiber (Lorient_KMA \u2192 Loudeac)-",
"from_node": "fiber (Lorient_KMA \u2192 Loudeac)-F054",
"to_node": "egress fused spans in Loudeac"
},
{
"from_node": "egress fused spans in Loudeac",
"to_node": "fiber (Loudeac \u2192 Corlay)-"
"to_node": "fiber (Loudeac \u2192 Corlay)-F010"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "fiber (Lorient_KMA \u2192 Loudeac)-"
"to_node": "fiber (Lorient_KMA \u2192 Loudeac)-F054"
},
{
"from_node": "fiber (Loudeac \u2192 Lorient_KMA)-",
"from_node": "fiber (Loudeac \u2192 Lorient_KMA)-F054",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F01"
"to_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055"
},
{
"from_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F01",
"from_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Vannes_KBE",
"to_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F01"
"to_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055"
},
{
"from_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F01",
"from_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055",
"to_node": "roadm Vannes_KBE"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-",
"to_node": "fiber (Stbrieuc \u2192 Rennes_STA)-"
"from_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056",
"to_node": "fiber (Stbrieuc \u2192 Rennes_STA)-F057"
},
{
"from_node": "fiber (Rennes_STA \u2192 Stbrieuc)-",
"to_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-"
"from_node": "fiber (Rennes_STA \u2192 Stbrieuc)-F057",
"to_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056"
},
{
"from_node": "roadm Rennes_STA",
"to_node": "fiber (Rennes_STA \u2192 Stbrieuc)-"
"to_node": "fiber (Rennes_STA \u2192 Stbrieuc)-F057"
},
{
"from_node": "fiber (Stbrieuc \u2192 Rennes_STA)-",
"from_node": "fiber (Stbrieuc \u2192 Rennes_STA)-F057",
"to_node": "roadm Rennes_STA"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Morlaix)-",
"from_node": "fiber (Lannion_CAS \u2192 Morlaix)-F059",
"to_node": "ingress fused spans in Morlaix"
},
{
"from_node": "ingress fused spans in Morlaix",
"to_node": "fiber (Morlaix \u2192 Brest_KLA)-"
"to_node": "fiber (Morlaix \u2192 Brest_KLA)-F060"
},
{
"from_node": "fiber (Brest_KLA \u2192 Morlaix)-",
"from_node": "fiber (Brest_KLA \u2192 Morlaix)-F060",
"to_node": "egress fused spans in Morlaix"
},
{
"from_node": "egress fused spans in Morlaix",
"to_node": "fiber (Morlaix \u2192 Lannion_CAS)-"
"to_node": "fiber (Morlaix \u2192 Lannion_CAS)-F059"
},
{
"from_node": "roadm Brest_KLA",
"to_node": "fiber (Brest_KLA \u2192 Morlaix)-"
"to_node": "fiber (Brest_KLA \u2192 Morlaix)-F060"
},
{
"from_node": "fiber (Morlaix \u2192 Brest_KLA)-",
"from_node": "fiber (Morlaix \u2192 Brest_KLA)-F060",
"to_node": "roadm Brest_KLA"
},
{

Binary file not shown.

View File

@@ -0,0 +1,286 @@
#!/usr/bin/env python3
# TelecomInfraProject/gnpy/examples
# Module name : path_requests_run.py
# Version :
# License : BSD 3-Clause Licence
# Copyright (c) 2018, Telecom Infra Project
"""
@author: esther.lerouzic
@author: jeanluc-auge
read json request file in accordance with:
Yang model for requesting Path Computation
draft-ietf-teas-yang-path-computation-01.txt.
and returns path results in terms of path and feasibility
"""
from sys import exit
from argparse import ArgumentParser
from pathlib import Path
from collections import namedtuple
from logging import getLogger, basicConfig, CRITICAL, DEBUG, INFO
from json import dumps, loads
from networkx import (draw_networkx_nodes, draw_networkx_edges,
draw_networkx_labels, dijkstra_path, NetworkXNoPath)
from numpy import mean
from examples.convert_service_sheet import convert_service_sheet, Request_element, Element
from gnpy.core.utils import load_json
from gnpy.core.network import load_network, build_network
from gnpy.core.equipment import load_equipment
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused
from gnpy.core.utils import db2lin, lin2db
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power
from copy import copy, deepcopy
from numpy import log10
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
logger = getLogger(__name__)
parser = ArgumentParser(description = 'A function that computes performances 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')
parser.add_argument('service_filename', nargs='?', type = Path, default= Path(__file__).parent / 'meshTopologyExampleV2.xls')
parser.add_argument('eqpt_filename', nargs='?', type = Path, default=Path(__file__).parent / 'eqpt_config.json')
parser.add_argument('-v', '--verbose', action='count')
parser.add_argument('-o', '--output', default=None)
class Path_request():
def __init__(self,jsondata,tspjsondata):
self.request_id = jsondata['request-id']
self.source = jsondata['src-tp-id']
self.destination = jsondata['dst-tp-id']
# retrieving baudrate out of transponder type and mode (format)
self.tsp = jsondata['path-constraints']['te-bandwidth']['trx_type']
self.tsp_mode = jsondata['path-constraints']['te-bandwidth']['trx_mode']
# for debug
# print(tsp)
try:
baudrate = next(m['baudrate']
for t in tspjsondata if t['type_variety'] == self.tsp
for m in t['mode'] if m['format'] == self.tsp_mode)
except StopIteration:
msg = f'could not find tsp : {self.tsp} with mode: {self.tsp_mode} in eqpt library'
logger.critical(msg)
raise ValueError(msg)
self.baudrate = baudrate
nodes_list = jsondata['optimizations']['explicit-route-include-objects']
self.nodes_list = [n['unnumbered-hop']['node-id'] for n in nodes_list]
# create a list for individual loose capability for each node ...
# even if convert_service_sheet fills it with the same value
self.loose_list = [n['unnumbered-hop']['hop-type'] for n in nodes_list]
self.spacing = jsondata['path-constraints']['te-bandwidth']['spacing']
self.power = jsondata['path-constraints']['te-bandwidth']['output-power']
self.nb_channel = jsondata['path-constraints']['te-bandwidth']['max-nb-of-channel']
def __str__(self):
return '\n\t'.join([ f'{type(self).__name__} {self.request_id}',
f'source: {self.source}',
f'destination: {self.destination}'])
def __repr__(self):
return '\n\t'.join([ f'{type(self).__name__} {self.request_id}',
f'source: {self.source}',
f'destination: {self.destination}',
f'trx type: {self.tsp}',
f'baudrate: {self.baudrate}',
f'spacing: {self.spacing}',
f'power: {self.power}'
'\n'])
class Result_element(Element):
def __init__(self,path_request,computed_path):
self.path_id = int(path_request.request_id)
self.path_request = path_request
self.computed_path = computed_path
hop_type = []
for e in computed_path :
if isinstance(e, Transceiver) :
hop_type.append(' - '.join([path_request.tsp,path_request.tsp_mode]))
else:
hop_type.append('not recorded')
self.hop_type = hop_type
uid = property(lambda self: repr(self))
@property
def pathresult(self):
return {
'path-id': self.path_id,
'path-properties':{
'path-metric': [
{
'metric-type': 'SNR@bandwidth',
'accumulative-value': round(mean(self.computed_path[-1].snr),2)
},
{
'metric-type': 'SNR@0.1nm',
'accumulative-value': round(mean(self.computed_path[-1].snr+10*log10(self.path_request.baudrate/12.5)),2)
}
],
'path-srlgs': {
'usage': 'not used yet',
'values': 'not used yet'
},
'path-route-objects': [
{
'path-route-object': {
'index': self.computed_path.index(n),
'unnumbered-hop': {
'node-id': n.uid,
'link-tp-id': n.uid,
'hop-type': self.hop_type[self.computed_path.index(n)],
'direction': 'not used'
},
'label-hop': {
'te-label': {
'generic': 'not used yet',
'direction': 'not used yet'
}
}
}
} for n in self.computed_path
]
}
}
@property
def json(self):
return self.pathresult
def load_SI(filename):
with open(filename) as f:
json_data = loads(f.read())
return json_data['SI'][0]
def load_Transceiver(filename):
with open(filename) as f:
json_data = loads(f.read())
return json_data['Transceiver']
def requests_from_json(json_data,eqpt_filename):
requests_list = []
tspjsondata = load_Transceiver(eqpt_filename)
for req in json_data['path-request']:
#print(f'{req}')
requests_list.append(Path_request(req,tspjsondata))
return requests_list
def load_requests(filename,eqpt_filename):
if filename.suffix.lower() == '.xls':
logger.info('Automatically converting requests from XLS to JSON')
json_data = convert_service_sheet(filename,eqpt_filename)
else:
with open(filename) as f:
json_data = loads(f.read())
return json_data
def compute_path(network, pathreqlist):
# temporary : repeats calls from transmission_main_example
# to be merged when ready
path_res_list = []
trx = [n for n in network.nodes() if isinstance(n, Transceiver)]
roadm = [n for n in network.nodes() if isinstance(n, Roadm)]
edfa = [n for n in network.nodes() if isinstance(n, Edfa)]
# TODO include also fused in the element check : too difficult because of direction
# fused = [n for n in network.nodes() if isinstance(n, Fused)]
sidata = load_SI(args.eqpt_filename)
for pathreq in pathreqlist:
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 explicit path: {pathreq.nodes_list}')
source = next(el for el in trx if el.uid == pathreq.source)
# start the path with its source
total_path = [source]
for n in pathreq.nodes_list:
# print(n)
try :
node = next(el for el in trx if el.uid == n)
except StopIteration:
try:
node = next(el for el in roadm if el.uid == f'roadm {n}')
except StopIteration:
try:
node = next(el for el in edfa
if el.uid.startswith(f'egress edfa in {n}'))
except StopIteration:
msg = f'could not find node : {n} in network topology: \
not a trx, roadm, edfa or fused element'
logger.critical(msg)
raise ValueError(msg)
# extend path list without repeating source -> skip first element in the list
try:
total_path.extend(dijkstra_path(network, source, node)[1:])
source = node
except NetworkXNoPath:
# for debug
# print(pathreq.loose_list)
# print(pathreq.nodes_list.index(n))
if pathreq.loose_list[pathreq.nodes_list.index(n)] == 'loose':
print(f'could not find a path from {source.uid} to loose node : {n} in network topology')
print(f'node {n} is skipped')
else:
msg = f'could not find a path from {source.uid} to node : {n} in network topology'
logger.critical(msg)
raise ValueError(msg)
# for debug
# print(f'{pathreq.baudrate} {pathreq.power} {pathreq.spacing} {pathreq.nb_channel}')
si = create_input_spectral_information(
sidata['f_min'], sidata['roll_off'],
pathreq.baudrate, pathreq.power, pathreq.spacing, pathreq.nb_channel)
for el in total_path:
si = el(si)
# print(el)
# 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(destination))
path_res_list.append(deepcopy(total_path))
return path_res_list
def path_result_json(pathresult):
data = {
'path': [n.json for n in pathresult]
}
return data
if __name__ == '__main__':
args = parser.parse_args()
basicConfig(level={2: DEBUG, 1: INFO, 0: CRITICAL}.get(args.verbose, CRITICAL))
logger.info(f'Computing path requests {args.service_filename} into JSON format')
# for debug
# print( args.eqpt_filename)
data = load_requests(args.service_filename,args.eqpt_filename)
equipment = load_equipment(args.eqpt_filename)
network = load_network(args.network_filename,equipment)
build_network(network, equipment=equipment)
pths = requests_from_json(data, args.eqpt_filename)
print(pths)
test = compute_path(network,pths)
if args.output is None:
#TODO write results
print("demand\t\t\t\tsnr@bandwidth\tsnr@0.1nm")
for i, p in enumerate(test):
print(f'{pths[i].source} to {pths[i].destination} : {round(mean(p[-1].snr),2)} ,\
{round(mean(p[-1].snr+10*log10(pths[i].baudrate/(12.5e9))),2)}')
else:
result = []
for p in test:
result.append(Result_element(pths[test.index(p)],p))
with open(args.output, 'w') as f:
f.write(dumps(path_result_json(result), indent=2))

View File

@@ -5,8 +5,8 @@ reads from network json (default = examples/edfa/edfa_example_network.json)
propagates a 96 channels comb
'''
from gnpy.core.equipment import equipment_from_json
from gnpy.core.utils import db2lin, lin2db, load_json
from gnpy.core.equipment import load_equipment
from gnpy.core.utils import db2lin, lin2db
from argparse import ArgumentParser
from sys import exit
from pathlib import Path
@@ -18,8 +18,7 @@ from matplotlib.pyplot import show, axis, figure, title
from networkx import (draw_networkx_nodes, draw_networkx_edges,
draw_networkx_labels, dijkstra_path)
from convert import convert_file
from gnpy.core import network_from_json, build_network
from gnpy.core import load_network, build_network
from gnpy.core.elements import Transceiver, Fiber, Edfa, Roadm
from gnpy.core.info import SpectralInformation, Channel, Power
@@ -49,22 +48,6 @@ def plot_results(network, path, source, sink):
show()
def load_network(filename, equipment):
json_filename = ''
if args.filename.suffix.lower() == '.xls':
logger.info('Automatically generating topology JSON file')
json_filename = convert_file(args.filename)
elif args.filename.suffix.lower() == '.json':
json_filename = args.filename
else:
raise ValueError(f'unsuported topology filename extension {args.filename.suffix.lower()}')
json_data = load_json(json_filename)
return network_from_json(json_data, equipment)
def load_equipment(filename):
json_data = load_json(filename)
return equipment_from_json(json_data, filename)
def main(network, equipment, source, sink):
build_network(network, equipment=equipment)
path = dijkstra_path(network, source, sink)
@@ -108,6 +91,7 @@ if __name__ == '__main__':
# logger.info(equipment)
network = load_network(args.filename, equipment)
print(network)
transceivers = {n.uid: n for n in network.nodes() if isinstance(n, Transceiver)}

View File

@@ -167,7 +167,7 @@ def convert_file(input_filename, filter_region=[]):
'params': {'length': round(x.west_distance, 3),
'length_units': x.distance_units,
'loss_coef': x.west_lineic}
}
} # missing ILA construction
for x in links] +
[{'uid': f'egress edfa in {e.from_city} to {e.to_city}',
'metadata': {'location': {'city': nodes_by_city[e.from_city].city,

View File

@@ -11,13 +11,14 @@ from operator import itemgetter
from math import isclose
from pathlib import Path
from json import loads
from gnpy.core.utils import lin2db, db2lin
from gnpy.core.utils import lin2db, db2lin, load_json
from collections import namedtuple
Model = namedtuple('Model', 'nf1 nf2 delta_p')
Fiber = namedtuple('Fiber', 'type_variety dispersion gamma')
Spans = namedtuple('Spans', 'max_length length_units max_loss padding EOL con_loss')
Roadms = namedtuple('Roadms', 'loss')
Transceiver = namedtuple('Transceiver', 'type_variety frequency mode')
SI = namedtuple('SI', 'f_min Nch baud_rate spacing roll_off power')
EdfaBase = namedtuple(
'EdfaBase',
@@ -107,6 +108,11 @@ def edfa_nf(gain, variety_type, equipment):
nf_avg = polyval(edfa.nf_fit_coeff, dg)
return nf_avg + pad # input VOA = 1 for 1 NF degradation
def load_equipment(filename):
json_data = load_json(filename)
return equipment_from_json(json_data, filename)
def equipment_from_json(json_data, filename):
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
edfa type type_variety, fiber type_variety

View File

@@ -49,6 +49,13 @@ class SpectralInformation(namedtuple('SpectralInformation', 'carriers'), Conveni
return super().__new__(cls, carriers)
def create_input_spectral_information(f_min, roll_off, baudrate, power, spacing, nb_channel):
si = SpectralInformation() # !! SI units W, Hz
si = si.update(carriers=tuple(
Channel(f, (f_min+spacing*f),
baudrate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1)))
return si
if __name__ == '__main__':
si = SpectralInformation(
Channel(1, 193.95e12, 32e9, 0.15, # 193.95 THz, 32 Gbaud

View File

@@ -7,7 +7,7 @@ gnpy.core.network
This module contains functions for constructing networks of network elements.
'''
from gnpy.core.convert import convert_file
from networkx import DiGraph
from logging import getLogger
from operator import itemgetter
@@ -15,9 +15,21 @@ from gnpy.core import elements
from gnpy.core.elements import Fiber, Edfa, Transceiver, Roadm, Fused
from gnpy.core.equipment import edfa_nf
from gnpy.core.units import UNITS
from gnpy.core.utils import load_json
logger = getLogger(__name__)
def load_network(filename, equipment):
json_filename = ''
if filename.suffix.lower() == '.xls':
logger.info('Automatically generating topology JSON file')
json_filename = convert_file(filename)
elif filename.suffix.lower() == '.json':
json_filename = filename
else:
raise ValueError(f'unsuported topology filename extension {filename.suffix.lower()}')
json_data = load_json(json_filename)
return network_from_json(json_data, equipment)
def network_from_json(json_data, equipment):
# NOTE|dutc: we could use the following, but it would tie our data format

40
path_result_template.json Normal file
View File

@@ -0,0 +1,40 @@
{
"paths": [
{
"path": {
"path-id": null,
"path-properties": {
"path-metric": [
{
"metric-type": null,
"accumulative-value": null
}
],
"path-srlgs": {
"usage": "not used yet",
"values": ["not used yet"]
},
"path-route-objects": [
{
"path-route-object": {
"index": null,
"unnumbered-hop": {
"node-id": null,
"link-tp-id": null,
"hop-type": null,
"direction": "not used"
},
"label-hop": {
"te-label": {
"generic": "not used yet",
"direction": "not used yet"
}
}
}
}
]
}
}
}
]
}

59
service-template.json Normal file
View File

@@ -0,0 +1,59 @@
{
"path-request": [
{
"request-id": null,
"source": null,
"destination": null,
"src-tp-id": null,
"dst-tp-id": null,
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": null,
"trx_mode": null,
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": null,
"max-nb-of-channel": null,
"output-power": null
}
},
"optimizations": {
"explicit-route-include-objects": {
"route-object-include-object": [
{
"index": null,
"unnumbered-hop": {
"node-id": null,
"link-tp-id": "link-tp-id is not used",
"hop-type": null,
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
}
]
}
}
}],
"synchronization": [
{
"synchronization-id": null,
"svec": {
"relaxable": "True",
"link-diverse": "False",
"node-diverse": "False",
"request-id-number": [
null ]
},
}
]
}

View File

@@ -33,6 +33,7 @@ setup(
'Topic :: Scientific/Engineering :: Physics',
],
keywords='optics network fiber communication route planning optimization',
packages=find_packages(exclude=['examples', 'docs', 'tests']), # Required
#packages=find_packages(exclude=['examples', 'docs', 'tests']), # Required
packages=find_packages(exclude=['docs', 'tests']), # Required
install_requires=list(open('requirements.txt'))
)

View File

@@ -7,19 +7,18 @@ from gnpy.core.elements import Edfa
import numpy as np
from json import load, dumps
import pytest
from gnpy.core import network_from_json
from gnpy.core.elements import Transceiver, Fiber, Edfa
from gnpy.core.utils import lin2db, db2lin , load_json
from gnpy.core.info import SpectralInformation, Channel, Power
from gnpy.core.equipment import read_eqpt_library
from gnpy.core.network import build_network
from examples.convert import convert_file
from gnpy.core.utils import lin2db, db2lin
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power
from gnpy.core.equipment import load_equipment
from gnpy.core.network import build_network, load_network
from pathlib import Path
import filecmp
#network_file_name = 'tests/test_network.json'
network_file_name = 'tests/test_network.json'
eqpt_library_name = 'examples/eqpt_config.json'
network_file_name = Path(__file__).parent.parent / 'tests/test_network.json'
#network_file_name = Path(__file__).parent.parent / 'examples/edfa_example_network.json'
eqpt_library_name = Path(__file__).parent.parent / 'examples/eqpt_config.json'
@pytest.fixture(params=[(96, 0.05e12), (60, 0.075e12), (45, 0.1e12), (2, 0.1e12)],
ids=['50GHz spacing', '75GHz spacing', '100GHz spacing', '2 channels'])
@@ -38,23 +37,24 @@ def setup_edfa():
"""init edfa class by reading test_network.json file
remove all gain and nf ripple"""
# eqpt_library = pytest_eqpt_library()
read_eqpt_library(eqpt_library_name)
with open(network_file_name) as network_file:
network_json = load(network_file)
network = network_from_json(network_json)
equipment = load_equipment(eqpt_library_name)
network = load_network(network_file_name,equipment)
build_network(network, equipment=equipment)
edfa = [n for n in network.nodes() if isinstance(n, Edfa)][0]
#edfa.params.dgt = np.zeros(96)
edfa.params.gain_ripple = np.zeros(96)
edfa.params.nf_ripple = np.zeros(96)
# edfa.params.gain_ripple = np.zeros(96)
# edfa.params.nf_ripple = np.zeros(96)
edfa.gain_ripple = np.zeros(96)
edfa.interpol_nf_ripple = np.zeros(96)
yield edfa
@pytest.fixture()
def setup_trx():
"""init transceiver class to access snr and osnr calculations"""
with open(network_file_name) as network_file:
network_json = load(network_file)
network = network_from_json(network_json)
equipment = load_equipment(eqpt_library_name)
network = load_network(network_file_name,equipment)
build_network(network, equipment=equipment)
trx = [n for n in network.nodes() if isinstance(n, Transceiver)][0]
return trx
@@ -62,10 +62,7 @@ def setup_trx():
def si(nch_and_spacing, bw):
"""parametrize a channel comb with nch, spacing and signal bw"""
nch, spacing = nch_and_spacing
si = SpectralInformation()
si = si.update(carriers=tuple(Channel(f, 191.3e12+spacing*f,
bw, 0.15, Power(1e-6, 0, 0)) for f in range(1,nch+1)))
return si
return create_input_spectral_information(191.3e12, 0.15, bw, 1e-6, spacing, nch)
@pytest.mark.parametrize("enabled", [True, False])
@pytest.mark.parametrize("gain, nf_expected", [(10, 15), (15, 10), (25, 5.8)])
@@ -80,7 +77,7 @@ def test_nf_calc(gain, nf_expected, enabled, setup_edfa, si):
pin = np.array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
baud_rates = np.array([c.baud_rate for c in si.carriers])
edfa.operational.gain_target = gain
edfa.params.nf_model_enabled = enabled
# edfa.params.nf_model_enabled = enabled
edfa.interpol_params(frequencies, pin, baud_rates)
nf = edfa.nf
@@ -99,11 +96,11 @@ def test_compare_nf_models(gain, setup_edfa, si):
pin = np.array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
baud_rates = np.array([c.baud_rate for c in si.carriers])
edfa.operational.gain_target = gain
edfa.params.nf_model_enabled = True
# edfa.params.nf_model_enabled = True
edfa.interpol_params(frequencies, pin, baud_rates)
nf_model = edfa.nf[0]
edfa.params.nf_model_enabled = False
# edfa.params.nf_model_enabled = False
edfa.interpol_params(frequencies, pin, baud_rates)
nf_poly = edfa.nf[0]
dif = abs(nf_model - nf_poly)
@@ -130,7 +127,7 @@ def test_ase_noise(gain, si, setup_edfa, setup_trx, bw):
pin = np.array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
baud_rates = np.array([c.baud_rate for c in si.carriers])
edfa.operational.gain_target = gain
edfa.params.nf_model_enabled = False
# edfa.params.nf_model_enabled = False
edfa.interpol_params(frequencies, pin, baud_rates)
nf = edfa.nf
pin = lin2db(pin[0]*1e3)
@@ -150,39 +147,3 @@ def test_ase_noise(gain, si, setup_edfa, setup_trx, bw):
assert dif < 0.01
# adding tests to check the parser non regression
# convention of naming of test files:
# - excelTest... .xls for the xls undertest
# - test... .json for the reference output
excel_filename = ['tests/excelTestFile.xls',
'examples/CORONET_Global_Topology.xls']
test_filenames = {'tests/excelTestFile.xls':'tests/testFile.json',
'examples/CORONET_Global_Topology.xls':'tests/CORONET_Global_Topology.json'}
@pytest.mark.parametrize("inputfile",excel_filename)
def test_excel_json_generation(inputfile) :
convert_file(Path(inputfile))
json_filename = f'{inputfile[:-3]}json'
test_filename = test_filenames[inputfile]
print(json_filename)
print(test_filename)
assert filecmp.cmp(json_filename,test_filename) is True
# assume json entries
# test that the build network gives correct results
# json_filename = ['tests/testFile.json',
# 'examples/CORONET_Global_Topology.json']
# @pytest.mark.parametrize("inputfile",json_filename)
# def test_network_generation(inputfile) :
# json_data = load_json(inputfile)
# read_eqpt_library(Path(eqpt_library_name))
# network = network_from_json(json_data)
# build_network(network)
# for n in network.nodes():
# print(f'elements: {n},\n')
# print(',connections: [\n')
# for u, v in network.edges():
# print(f'[from_node: {u.uid}, to_node: {v.uid} ]')
# assert False

Binary file not shown.

View File

@@ -0,0 +1,82 @@
{
"path-request": [
{
"request-id": 0,
"source": "BREST_KLA",
"destination": "Vannes_KBE",
"src-tp-id": "trx BREST_KLA",
"dst-tp-id": "trx Vannes_KBE",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.001
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 1,
"source": "Lorient_KMA",
"destination": "Vannes_KBE",
"src-tp-id": "trx Lorient_KMA",
"dst-tp-id": "trx Vannes_KBE",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.001
}
},
"optimizations": {
"explicit-route-include-objects": []
}
}
],
"synchronisation": [
{
"synchonization-id": 0,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
0,
1
]
}
},
{
"synchonization-id": 1,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
1,
0
]
}
}
]
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,768 @@
{
"elements": [
{
"uid": "trx Lannion_CAS",
"metadata": {
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Lorient_KMA",
"metadata": {
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Vannes_KBE",
"metadata": {
"location": {
"city": "Vannes_KBE",
"region": "RLD",
"latitude": 2.0,
"longitude": 4.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Rennes_STA",
"metadata": {
"location": {
"city": "Rennes_STA",
"region": "RLD",
"latitude": 0.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Brest_KLA",
"metadata": {
"location": {
"city": "Brest_KLA",
"region": "RLD",
"latitude": 4.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx toto",
"metadata": {
"location": {
"city": "toto",
"region": "",
"latitude": 6.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx tata",
"metadata": {
"location": {
"city": "tata",
"region": "",
"latitude": 7.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "roadm Lannion_CAS",
"metadata": {
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Lorient_KMA",
"metadata": {
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Vannes_KBE",
"metadata": {
"location": {
"city": "Vannes_KBE",
"region": "RLD",
"latitude": 2.0,
"longitude": 4.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Rennes_STA",
"metadata": {
"location": {
"city": "Rennes_STA",
"region": "RLD",
"latitude": 0.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Brest_KLA",
"metadata": {
"location": {
"city": "Brest_KLA",
"region": "RLD",
"latitude": 4.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm toto",
"metadata": {
"location": {
"city": "toto",
"region": "",
"latitude": 6.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm tata",
"metadata": {
"location": {
"city": "tata",
"region": "",
"latitude": 7.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "ingress fused spans in Corlay",
"metadata": {
"location": {
"city": "Corlay",
"region": "RLD",
"latitude": 2.0,
"longitude": 1.0
}
},
"type": "Fused"
},
{
"uid": "ingress fused spans in Loudeac",
"metadata": {
"location": {
"city": "Loudeac",
"region": "RLD",
"latitude": 2.0,
"longitude": 2.0
}
},
"type": "Fused"
},
{
"uid": "ingress fused spans in Morlaix",
"metadata": {
"location": {
"city": "Morlaix",
"region": "RLD",
"latitude": 3.0,
"longitude": 0.0
}
},
"type": "Fused"
},
{
"uid": "egress fused spans in Corlay",
"metadata": {
"location": {
"city": "Corlay",
"region": "RLD",
"latitude": 2.0,
"longitude": 1.0
}
},
"type": "Fused"
},
{
"uid": "egress fused spans in Loudeac",
"metadata": {
"location": {
"city": "Loudeac",
"region": "RLD",
"latitude": 2.0,
"longitude": 2.0
}
},
"type": "Fused"
},
{
"uid": "egress fused spans in Morlaix",
"metadata": {
"location": {
"city": "Morlaix",
"region": "RLD",
"latitude": 3.0,
"longitude": 0.0
}
},
"type": "Fused"
},
{
"uid": "fiber (Lannion_CAS \u2192 Corlay)-F061",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 0.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 20.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Corlay \u2192 Loudeac)-F010",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 1.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 50.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Loudeac \u2192 Lorient_KMA)-F054",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 2.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 3.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 10.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056",
"metadata": {
"location": {
"latitude": 1.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Stbrieuc \u2192 Rennes_STA)-F057",
"metadata": {
"location": {
"latitude": 0.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 65.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lannion_CAS \u2192 Morlaix)-F059",
"metadata": {
"location": {
"latitude": 2.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 40.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Morlaix \u2192 Brest_KLA)-F060",
"metadata": {
"location": {
"latitude": 3.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 35.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (toto \u2192 tata)-",
"metadata": {
"location": {
"latitude": 6.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 80.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Corlay \u2192 Lannion_CAS)-F061",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 0.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 20.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Loudeac \u2192 Corlay)-F010",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 1.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 50.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lorient_KMA \u2192 Loudeac)-F054",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 2.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 3.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 10.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056",
"metadata": {
"location": {
"latitude": 1.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Rennes_STA \u2192 Stbrieuc)-F057",
"metadata": {
"location": {
"latitude": 0.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 65.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Morlaix \u2192 Lannion_CAS)-F059",
"metadata": {
"location": {
"latitude": 2.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 40.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Brest_KLA \u2192 Morlaix)-F060",
"metadata": {
"location": {
"latitude": 3.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 35.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (tata \u2192 toto)-",
"metadata": {
"location": {
"latitude": 6.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 80.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "egress edfa in Lannion_CAS to Corlay",
"metadata": {
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Edfa",
"type_variety": "test",
"operational": {
"gain_target": 0,
"tilt_target": 0
}
},
{
"uid": "egress edfa in Lorient_KMA to Loudeac",
"metadata": {
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Edfa",
"type_variety": "test",
"operational": {
"gain_target": 0,
"tilt_target": 0
}
}
],
"connections": [
{
"from_node": "roadm Lannion_CAS",
"to_node": "egress edfa in Lannion_CAS to Corlay"
},
{
"from_node": "egress edfa in Lannion_CAS to Corlay",
"to_node": "fiber (Lannion_CAS \u2192 Corlay)-F061"
},
{
"from_node": "fiber (Corlay \u2192 Lannion_CAS)-F061",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056"
},
{
"from_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Morlaix)-F059"
},
{
"from_node": "fiber (Morlaix \u2192 Lannion_CAS)-F059",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Corlay)-F061",
"to_node": "ingress fused spans in Corlay"
},
{
"from_node": "ingress fused spans in Corlay",
"to_node": "fiber (Corlay \u2192 Loudeac)-F010"
},
{
"from_node": "fiber (Loudeac \u2192 Corlay)-F010",
"to_node": "egress fused spans in Corlay"
},
{
"from_node": "egress fused spans in Corlay",
"to_node": "fiber (Corlay \u2192 Lannion_CAS)-F061"
},
{
"from_node": "fiber (Corlay \u2192 Loudeac)-F010",
"to_node": "ingress fused spans in Loudeac"
},
{
"from_node": "ingress fused spans in Loudeac",
"to_node": "fiber (Loudeac \u2192 Lorient_KMA)-F054"
},
{
"from_node": "fiber (Lorient_KMA \u2192 Loudeac)-F054",
"to_node": "egress fused spans in Loudeac"
},
{
"from_node": "egress fused spans in Loudeac",
"to_node": "fiber (Loudeac \u2192 Corlay)-F010"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "egress edfa in Lorient_KMA to Loudeac"
},
{
"from_node": "egress edfa in Lorient_KMA to Loudeac",
"to_node": "fiber (Lorient_KMA \u2192 Loudeac)-F054"
},
{
"from_node": "fiber (Loudeac \u2192 Lorient_KMA)-F054",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055"
},
{
"from_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Vannes_KBE",
"to_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055"
},
{
"from_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055",
"to_node": "roadm Vannes_KBE"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056",
"to_node": "fiber (Stbrieuc \u2192 Rennes_STA)-F057"
},
{
"from_node": "fiber (Rennes_STA \u2192 Stbrieuc)-F057",
"to_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056"
},
{
"from_node": "roadm Rennes_STA",
"to_node": "fiber (Rennes_STA \u2192 Stbrieuc)-F057"
},
{
"from_node": "fiber (Stbrieuc \u2192 Rennes_STA)-F057",
"to_node": "roadm Rennes_STA"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Morlaix)-F059",
"to_node": "ingress fused spans in Morlaix"
},
{
"from_node": "ingress fused spans in Morlaix",
"to_node": "fiber (Morlaix \u2192 Brest_KLA)-F060"
},
{
"from_node": "fiber (Brest_KLA \u2192 Morlaix)-F060",
"to_node": "egress fused spans in Morlaix"
},
{
"from_node": "egress fused spans in Morlaix",
"to_node": "fiber (Morlaix \u2192 Lannion_CAS)-F059"
},
{
"from_node": "roadm Brest_KLA",
"to_node": "fiber (Brest_KLA \u2192 Morlaix)-F060"
},
{
"from_node": "fiber (Morlaix \u2192 Brest_KLA)-F060",
"to_node": "roadm Brest_KLA"
},
{
"from_node": "roadm toto",
"to_node": "fiber (toto \u2192 tata)-"
},
{
"from_node": "fiber (tata \u2192 toto)-",
"to_node": "roadm toto"
},
{
"from_node": "roadm tata",
"to_node": "fiber (tata \u2192 toto)-"
},
{
"from_node": "fiber (toto \u2192 tata)-",
"to_node": "roadm tata"
},
{
"from_node": "trx Lannion_CAS",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "trx Lannion_CAS"
},
{
"from_node": "trx Lorient_KMA",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "trx Lorient_KMA"
},
{
"from_node": "trx Vannes_KBE",
"to_node": "roadm Vannes_KBE"
},
{
"from_node": "roadm Vannes_KBE",
"to_node": "trx Vannes_KBE"
},
{
"from_node": "trx Rennes_STA",
"to_node": "roadm Rennes_STA"
},
{
"from_node": "roadm Rennes_STA",
"to_node": "trx Rennes_STA"
},
{
"from_node": "trx Brest_KLA",
"to_node": "roadm Brest_KLA"
},
{
"from_node": "roadm Brest_KLA",
"to_node": "trx Brest_KLA"
},
{
"from_node": "trx toto",
"to_node": "roadm toto"
},
{
"from_node": "roadm toto",
"to_node": "trx toto"
},
{
"from_node": "trx tata",
"to_node": "roadm tata"
},
{
"from_node": "roadm tata",
"to_node": "trx tata"
}
]
}

View File

@@ -0,0 +1,219 @@
{
"path-request": [
{
"request-id": 0,
"source": "Lorient_KMA",
"destination": "Vannes_KBE",
"src-tp-id": "trx Lorient_KMA",
"dst-tp-id": "trx Vannes_KBE",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 1,
"source": "Brest_KLA",
"destination": "Vannes_KBE",
"src-tp-id": "trx Brest_KLA",
"dst-tp-id": "trx Vannes_KBE",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": [
{
"index": 0,
"unnumbered-hop": {
"node-id": "Lannion_CAS",
"link-tp-id": "link-tp-id is not used",
"hop-type": "loose",
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
},
{
"index": 1,
"unnumbered-hop": {
"node-id": "Lorient_KMA",
"link-tp-id": "link-tp-id is not used",
"hop-type": "loose",
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
}
]
}
},
{
"request-id": 3,
"source": "Lannion_CAS",
"destination": "Rennes_STA",
"src-tp-id": "trx Lannion_CAS",
"dst-tp-id": "trx Rennes_STA",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "vendorA_trx-type1",
"trx_mode": "PS_SP64_1",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 4,
"source": "Rennes_STA",
"destination": "Lannion_CAS",
"src-tp-id": "trx Rennes_STA",
"dst-tp-id": "trx Lannion_CAS",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "vendorA_trx-type1",
"trx_mode": "PS_SP64_2",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 75000000000.0,
"max-nb-of-channel": 64,
"output-power": 0.0019952623149688794
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 5,
"source": "Lorient_KMA",
"destination": "Lannion_CAS",
"src-tp-id": "trx Lorient_KMA",
"dst-tp-id": "trx Lannion_CAS",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": [
{
"index": 0,
"unnumbered-hop": {
"node-id": "toto",
"link-tp-id": "link-tp-id is not used",
"hop-type": "loose",
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
}
]
}
}
],
"synchronisation": [
{
"synchonization-id": 0,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
0,
0
]
}
},
{
"synchonization-id": 3,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
3,
4
]
}
},
{
"synchonization-id": 5,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
5,
0
]
}
}
]
}

View File

@@ -0,0 +1,726 @@
{
"elements": [
{
"uid": "trx Lannion_CAS",
"metadata": {
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Lorient_KMA",
"metadata": {
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Vannes_KBE",
"metadata": {
"location": {
"city": "Vannes_KBE",
"region": "RLD",
"latitude": 2.0,
"longitude": 4.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Rennes_STA",
"metadata": {
"location": {
"city": "Rennes_STA",
"region": "RLD",
"latitude": 0.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx Brest_KLA",
"metadata": {
"location": {
"city": "Brest_KLA",
"region": "RLD",
"latitude": 4.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx toto",
"metadata": {
"location": {
"city": "toto",
"region": "",
"latitude": 6.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "trx tata",
"metadata": {
"location": {
"city": "tata",
"region": "",
"latitude": 7.0,
"longitude": 0.0
}
},
"type": "Transceiver"
},
{
"uid": "roadm Lannion_CAS",
"metadata": {
"location": {
"city": "Lannion_CAS",
"region": "RLD",
"latitude": 2.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Lorient_KMA",
"metadata": {
"location": {
"city": "Lorient_KMA",
"region": "RLD",
"latitude": 2.0,
"longitude": 3.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Vannes_KBE",
"metadata": {
"location": {
"city": "Vannes_KBE",
"region": "RLD",
"latitude": 2.0,
"longitude": 4.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Rennes_STA",
"metadata": {
"location": {
"city": "Rennes_STA",
"region": "RLD",
"latitude": 0.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm Brest_KLA",
"metadata": {
"location": {
"city": "Brest_KLA",
"region": "RLD",
"latitude": 4.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm toto",
"metadata": {
"location": {
"city": "toto",
"region": "",
"latitude": 6.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "roadm tata",
"metadata": {
"location": {
"city": "tata",
"region": "",
"latitude": 7.0,
"longitude": 0.0
}
},
"type": "Roadm"
},
{
"uid": "ingress fused spans in Corlay",
"metadata": {
"location": {
"city": "Corlay",
"region": "RLD",
"latitude": 2.0,
"longitude": 1.0
}
},
"type": "Fused"
},
{
"uid": "ingress fused spans in Loudeac",
"metadata": {
"location": {
"city": "Loudeac",
"region": "RLD",
"latitude": 2.0,
"longitude": 2.0
}
},
"type": "Fused"
},
{
"uid": "ingress fused spans in Morlaix",
"metadata": {
"location": {
"city": "Morlaix",
"region": "RLD",
"latitude": 3.0,
"longitude": 0.0
}
},
"type": "Fused"
},
{
"uid": "egress fused spans in Corlay",
"metadata": {
"location": {
"city": "Corlay",
"region": "RLD",
"latitude": 2.0,
"longitude": 1.0
}
},
"type": "Fused"
},
{
"uid": "egress fused spans in Loudeac",
"metadata": {
"location": {
"city": "Loudeac",
"region": "RLD",
"latitude": 2.0,
"longitude": 2.0
}
},
"type": "Fused"
},
{
"uid": "egress fused spans in Morlaix",
"metadata": {
"location": {
"city": "Morlaix",
"region": "RLD",
"latitude": 3.0,
"longitude": 0.0
}
},
"type": "Fused"
},
{
"uid": "fiber (Lannion_CAS \u2192 Corlay)-F061",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 0.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 20.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Corlay \u2192 Loudeac)-F010",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 1.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 50.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Loudeac \u2192 Lorient_KMA)-F054",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 2.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 3.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 10.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056",
"metadata": {
"location": {
"latitude": 1.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Stbrieuc \u2192 Rennes_STA)-F057",
"metadata": {
"location": {
"latitude": 0.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 65.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lannion_CAS \u2192 Morlaix)-F059",
"metadata": {
"location": {
"latitude": 2.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 40.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Morlaix \u2192 Brest_KLA)-F060",
"metadata": {
"location": {
"latitude": 3.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 35.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (toto \u2192 tata)-",
"metadata": {
"location": {
"latitude": 6.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 80.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Corlay \u2192 Lannion_CAS)-F061",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 0.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 20.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Loudeac \u2192 Corlay)-F010",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 1.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 50.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Lorient_KMA \u2192 Loudeac)-F054",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 2.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055",
"metadata": {
"location": {
"latitude": 2.0,
"longitude": 3.5
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 10.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056",
"metadata": {
"location": {
"latitude": 1.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 60.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Rennes_STA \u2192 Stbrieuc)-F057",
"metadata": {
"location": {
"latitude": 0.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 65.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Morlaix \u2192 Lannion_CAS)-F059",
"metadata": {
"location": {
"latitude": 2.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 40.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (Brest_KLA \u2192 Morlaix)-F060",
"metadata": {
"location": {
"latitude": 3.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 35.0,
"length_units": "km",
"loss_coef": 0.2
}
},
{
"uid": "fiber (tata \u2192 toto)-",
"metadata": {
"location": {
"latitude": 6.5,
"longitude": 0.0
}
},
"type": "Fiber",
"type_variety": "SSMF",
"params": {
"length": 80.0,
"length_units": "km",
"loss_coef": 0.2
}
}
],
"connections": [
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Corlay)-F061"
},
{
"from_node": "fiber (Corlay \u2192 Lannion_CAS)-F061",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056"
},
{
"from_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "fiber (Lannion_CAS \u2192 Morlaix)-F059"
},
{
"from_node": "fiber (Morlaix \u2192 Lannion_CAS)-F059",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Corlay)-F061",
"to_node": "ingress fused spans in Corlay"
},
{
"from_node": "ingress fused spans in Corlay",
"to_node": "fiber (Corlay \u2192 Loudeac)-F010"
},
{
"from_node": "fiber (Loudeac \u2192 Corlay)-F010",
"to_node": "egress fused spans in Corlay"
},
{
"from_node": "egress fused spans in Corlay",
"to_node": "fiber (Corlay \u2192 Lannion_CAS)-F061"
},
{
"from_node": "fiber (Corlay \u2192 Loudeac)-F010",
"to_node": "ingress fused spans in Loudeac"
},
{
"from_node": "ingress fused spans in Loudeac",
"to_node": "fiber (Loudeac \u2192 Lorient_KMA)-F054"
},
{
"from_node": "fiber (Lorient_KMA \u2192 Loudeac)-F054",
"to_node": "egress fused spans in Loudeac"
},
{
"from_node": "egress fused spans in Loudeac",
"to_node": "fiber (Loudeac \u2192 Corlay)-F010"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "fiber (Lorient_KMA \u2192 Loudeac)-F054"
},
{
"from_node": "fiber (Loudeac \u2192 Lorient_KMA)-F054",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055"
},
{
"from_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Vannes_KBE",
"to_node": "fiber (Vannes_KBE \u2192 Lorient_KMA)-F055"
},
{
"from_node": "fiber (Lorient_KMA \u2192 Vannes_KBE)-F055",
"to_node": "roadm Vannes_KBE"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Stbrieuc)-F056",
"to_node": "fiber (Stbrieuc \u2192 Rennes_STA)-F057"
},
{
"from_node": "fiber (Rennes_STA \u2192 Stbrieuc)-F057",
"to_node": "fiber (Stbrieuc \u2192 Lannion_CAS)-F056"
},
{
"from_node": "roadm Rennes_STA",
"to_node": "fiber (Rennes_STA \u2192 Stbrieuc)-F057"
},
{
"from_node": "fiber (Stbrieuc \u2192 Rennes_STA)-F057",
"to_node": "roadm Rennes_STA"
},
{
"from_node": "fiber (Lannion_CAS \u2192 Morlaix)-F059",
"to_node": "ingress fused spans in Morlaix"
},
{
"from_node": "ingress fused spans in Morlaix",
"to_node": "fiber (Morlaix \u2192 Brest_KLA)-F060"
},
{
"from_node": "fiber (Brest_KLA \u2192 Morlaix)-F060",
"to_node": "egress fused spans in Morlaix"
},
{
"from_node": "egress fused spans in Morlaix",
"to_node": "fiber (Morlaix \u2192 Lannion_CAS)-F059"
},
{
"from_node": "roadm Brest_KLA",
"to_node": "fiber (Brest_KLA \u2192 Morlaix)-F060"
},
{
"from_node": "fiber (Morlaix \u2192 Brest_KLA)-F060",
"to_node": "roadm Brest_KLA"
},
{
"from_node": "roadm toto",
"to_node": "fiber (toto \u2192 tata)-"
},
{
"from_node": "fiber (tata \u2192 toto)-",
"to_node": "roadm toto"
},
{
"from_node": "roadm tata",
"to_node": "fiber (tata \u2192 toto)-"
},
{
"from_node": "fiber (toto \u2192 tata)-",
"to_node": "roadm tata"
},
{
"from_node": "trx Lannion_CAS",
"to_node": "roadm Lannion_CAS"
},
{
"from_node": "roadm Lannion_CAS",
"to_node": "trx Lannion_CAS"
},
{
"from_node": "trx Lorient_KMA",
"to_node": "roadm Lorient_KMA"
},
{
"from_node": "roadm Lorient_KMA",
"to_node": "trx Lorient_KMA"
},
{
"from_node": "trx Vannes_KBE",
"to_node": "roadm Vannes_KBE"
},
{
"from_node": "roadm Vannes_KBE",
"to_node": "trx Vannes_KBE"
},
{
"from_node": "trx Rennes_STA",
"to_node": "roadm Rennes_STA"
},
{
"from_node": "roadm Rennes_STA",
"to_node": "trx Rennes_STA"
},
{
"from_node": "trx Brest_KLA",
"to_node": "roadm Brest_KLA"
},
{
"from_node": "roadm Brest_KLA",
"to_node": "trx Brest_KLA"
},
{
"from_node": "trx toto",
"to_node": "roadm toto"
},
{
"from_node": "roadm toto",
"to_node": "trx toto"
},
{
"from_node": "trx tata",
"to_node": "roadm tata"
},
{
"from_node": "roadm tata",
"to_node": "trx tata"
}
]
}

View File

@@ -0,0 +1,219 @@
{
"path-request": [
{
"request-id": 0,
"source": "Lorient_KMA",
"destination": "Vannes_KBE",
"src-tp-id": "trx Lorient_KMA",
"dst-tp-id": "trx Vannes_KBE",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 1,
"source": "Brest_KLA",
"destination": "Vannes_KBE",
"src-tp-id": "trx Brest_KLA",
"dst-tp-id": "trx Vannes_KBE",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": [
{
"index": 0,
"unnumbered-hop": {
"node-id": "Lannion_CAS",
"link-tp-id": "link-tp-id is not used",
"hop-type": "loose",
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
},
{
"index": 1,
"unnumbered-hop": {
"node-id": "Lorient_KMA",
"link-tp-id": "link-tp-id is not used",
"hop-type": "loose",
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
}
]
}
},
{
"request-id": 3,
"source": "Lannion_CAS",
"destination": "Rennes_STA",
"src-tp-id": "trx Lannion_CAS",
"dst-tp-id": "trx Rennes_STA",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "vendorA_trx-type1",
"trx_mode": "PS_SP64_1",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 4,
"source": "Rennes_STA",
"destination": "Lannion_CAS",
"src-tp-id": "trx Rennes_STA",
"dst-tp-id": "trx Lannion_CAS",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "vendorA_trx-type1",
"trx_mode": "PS_SP64_2",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 75000000000.0,
"max-nb-of-channel": 64,
"output-power": 0.0019952623149688794
}
},
"optimizations": {
"explicit-route-include-objects": []
}
},
{
"request-id": 5,
"source": "Lorient_KMA",
"destination": "Lannion_CAS",
"src-tp-id": "trx Lorient_KMA",
"dst-tp-id": "trx Lannion_CAS",
"path-constraints": {
"te-bandwidth": {
"technology": "flexi-grid",
"trx_type": "Voyager_16QAM",
"trx_mode": "16QAM",
"effective-freq-slot": [
{
"n": "null",
"m": "null"
}
],
"spacing": 50000000000.0,
"max-nb-of-channel": 80,
"output-power": 0.0012589254117941673
}
},
"optimizations": {
"explicit-route-include-objects": [
{
"index": 0,
"unnumbered-hop": {
"node-id": "toto",
"link-tp-id": "link-tp-id is not used",
"hop-type": "loose",
"direction": "direction is not used"
},
"label-hop": {
"te-label": {
"generic": "generic is not used",
"direction": "direction is not used"
}
}
}
]
}
}
],
"synchronisation": [
{
"synchonization-id": 0,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
0,
0
]
}
},
{
"synchonization-id": 3,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
3,
4
]
}
},
{
"synchonization-id": 5,
"svec": {
"relaxable": "False",
"link-diverse": "True",
"node-diverse": "True",
"request-id-number": [
5,
0
]
}
}
]
}

67
tests/parsers_test.py Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: Esther Le Rouzic
# @Date: 2018-06-15
from gnpy.core.elements import Edfa
import numpy as np
from json import load, dumps
import pytest
from gnpy.core import network_from_json
from gnpy.core.elements import Transceiver, Fiber, Edfa
from gnpy.core.utils import lin2db, db2lin
from gnpy.core.info import SpectralInformation, Channel, Power
from examples.compare_json import compare_network_file, compare_service_file, compare_result_file
from gnpy.core.convert import convert_file
from examples.convert_service_sheet import convert_service_sheet
from pathlib import Path
import filecmp
network_file_name = 'tests/test_network.json'
eqpt_library_name = 'examples/eqpt_config.json'
# adding tests to check the parser non regression
# convention of naming of test files:
#
# - ..._expected.json for the reference output
excel_filename = ['tests/excelTestFile.xls',
'examples/CORONET_Global_Topology.xls',
'tests/meshTopologyExampleV2.xls',
'tests/meshTopologyExampleV2Eqpt.xls']
network_test_filenames = {
'tests/excelTestFile.xls' : 'tests/excelTestFile_expected.json',
'examples/CORONET_Global_Topology.xls': 'tests/CORONET_Global_Topology_expected.json',
'tests/meshTopologyExampleV2.xls' : 'tests/meshTopologyExampleV2_expected.json',
'tests/meshTopologyExampleV2Eqpt.xls' : 'tests/meshTopologyExampleV2Eqpt_expected.json'}
@pytest.mark.parametrize("inputfile",excel_filename)
def test_excel_json_generation(inputfile) :
convert_file(Path(inputfile))
# actual
json_filename = f'{inputfile[:-3]}json'
# expected
expected_filename = network_test_filenames[inputfile]
assert compare_network_file(expected_filename,json_filename)[0] is True
# assume json entries
# test that the build network gives correct results
# TODO !!
excel_filename = ['tests/excelTestFile.xls',
'tests/meshTopologyExampleV2.xls',
'tests/meshTopologyExampleV2Eqpt.xls']
service_test_filenames = {
'tests/excelTestFile.xls' : 'tests/excelTestFile_services_expected.json',
'tests/meshTopologyExampleV2.xls' : 'tests/meshTopologyExampleV2_services_expected.json',
'tests/meshTopologyExampleV2Eqpt.xls' : 'tests/meshTopologyExampleV2Eqpt_services_expected.json'}
@pytest.mark.parametrize("inputfile",excel_filename)
def test_excel_service_json_generation(inputfile) :
convert_service_sheet(Path(inputfile),eqpt_library_name)
# actual
json_filename = f'{inputfile[:-4]}_services.json'
# expected
test_filename = service_test_filenames[inputfile]
assert compare_service_file(test_filename,json_filename)[0] is True