mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-30 09:42:22 +00:00
Compare commits
32 Commits
v2.4
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
049b077ee4 | ||
|
|
ab2080a805 | ||
|
|
8ab54e76df | ||
|
|
f015c6abed | ||
|
|
71293c1c18 | ||
|
|
bd7c70f902 | ||
|
|
20c92d4338 | ||
|
|
f0158e7202 | ||
|
|
62408ddc98 | ||
|
|
b4f87b36db | ||
|
|
9f49a115a1 | ||
|
|
c7d2305589 | ||
|
|
5826a649de | ||
|
|
fa826391f6 | ||
|
|
3481ba8ee3 | ||
|
|
b4ab0b55de | ||
|
|
0370b45d8a | ||
|
|
468e689094 | ||
|
|
aafd82b16d | ||
|
|
60ee331153 | ||
|
|
3a8ce74355 | ||
|
|
fd44463238 | ||
|
|
84ba2da553 | ||
|
|
e693d96ca1 | ||
|
|
81cb7f8133 | ||
|
|
3471969956 | ||
|
|
7a0985c362 | ||
|
|
b79a9e2e67 | ||
|
|
1e037fe6f5 | ||
|
|
0897be57c1 | ||
|
|
4172b06b19 | ||
|
|
32a4875e46 |
@@ -5,17 +5,16 @@ set -e
|
||||
IMAGE_NAME=telecominfraproject/oopt-gnpy
|
||||
IMAGE_TAG=$(git describe --tags)
|
||||
|
||||
if [[ "${TRAVIS_BRANCH}" == "experimental/2019-summit" ]]; then
|
||||
IMAGE_NAME=telecominfraproject/oopt-gnpy-experimental
|
||||
fi
|
||||
|
||||
ALREADY_FOUND=0
|
||||
docker pull ${IMAGE_NAME}:${IMAGE_TAG} && ALREADY_FOUND=1
|
||||
|
||||
if [[ $ALREADY_FOUND == 0 ]]; then
|
||||
docker build . -t ${IMAGE_NAME}
|
||||
docker tag ${IMAGE_NAME} ${IMAGE_NAME}:${IMAGE_TAG}
|
||||
|
||||
# shared directory setup: do not clobber the real data
|
||||
mkdir trash
|
||||
cd trash
|
||||
docker run -it --rm --volume $(pwd):/shared ${IMAGE_NAME} ./transmission_main_example.py
|
||||
else
|
||||
echo "Image ${IMAGE_NAME}:${IMAGE_TAG} already available, will just update the other tags"
|
||||
fi
|
||||
@@ -43,5 +42,11 @@ if [[ "${TRAVIS_PULL_REQUEST}" == "false" ]]; then
|
||||
docker push ${IMAGE_NAME}:${IMAGE_TAG}
|
||||
fi
|
||||
docker push ${IMAGE_NAME}:stable
|
||||
elif [[ "${TRAVIS_BRANCH}" == "experimental/2019-summit" ]]; then
|
||||
echo "Publishing ad-hoc image for the TIP Summit demo"
|
||||
do_docker_login
|
||||
if [[ $ALREADY_FOUND == 0 ]]; then
|
||||
docker push ${IMAGE_NAME}:${IMAGE_TAG}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -2,6 +2,7 @@ FROM python:3.7-slim
|
||||
COPY . /oopt-gnpy
|
||||
WORKDIR /oopt-gnpy
|
||||
RUN python setup.py install
|
||||
WORKDIR /shared/examples
|
||||
WORKDIR /shared
|
||||
ENTRYPOINT ["/oopt-gnpy/.docker-entry.sh"]
|
||||
CMD ["/bin/bash"]
|
||||
CMD ["python", "examples/path_requests_run.py", "examples/2019-demo-topology.json", "examples/2019-demo-services.json", "examples/2019-demo-equipment.json", "--rest"]
|
||||
EXPOSE 5000
|
||||
|
||||
124
examples/2019-demo-equipment.json
Normal file
124
examples/2019-demo-equipment.json
Normal file
@@ -0,0 +1,124 @@
|
||||
{ "Edfa":[
|
||||
|
||||
{
|
||||
"type_variety": "fixed27",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 27,
|
||||
"p_max": 21,
|
||||
"nf0": 5.5,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
|
||||
{
|
||||
"type_variety": "fixed22",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 22,
|
||||
"gain_min": 22,
|
||||
"p_max": 21,
|
||||
"nf0": 5.5,
|
||||
"allowed_for_design": false
|
||||
}
|
||||
],
|
||||
"Fiber":[{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"gamma": 0.00127
|
||||
},
|
||||
{
|
||||
"type_variety": "NZDF",
|
||||
"dispersion": 0.5e-05,
|
||||
"gamma": 0.00146
|
||||
},
|
||||
{
|
||||
"type_variety": "LOF",
|
||||
"dispersion": 2.2e-05,
|
||||
"gamma": 0.000843
|
||||
}
|
||||
],
|
||||
"Span":[{
|
||||
"power_mode": false,
|
||||
"delta_power_range_db": [-2,3,0.5],
|
||||
"max_fiber_lineic_loss_for_raman": 0.25,
|
||||
"target_extended_gain": 2.5,
|
||||
"max_length": 150,
|
||||
"length_units": "km",
|
||||
"max_loss": 28,
|
||||
"padding": 10,
|
||||
"EOL": 0,
|
||||
"con_in": 0,
|
||||
"con_out": 0
|
||||
}
|
||||
],
|
||||
"Roadm":[{
|
||||
"target_pch_out_db": -25,
|
||||
"add_drop_osnr": 30.00,
|
||||
"restrictions": {
|
||||
"preamp_variety_list":[],
|
||||
"booster_variety_list":[]
|
||||
}
|
||||
}],
|
||||
"SI":[{
|
||||
"f_min": 191.6e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max":195.1e12,
|
||||
"spacing": 50e9,
|
||||
"power_dbm": 0,
|
||||
"power_range_db": [0,0,1],
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"sys_margins": 2
|
||||
}],
|
||||
"Transceiver":[
|
||||
{
|
||||
"type_variety": "Cassini",
|
||||
"frequency":{
|
||||
"min": 191.35e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode":[
|
||||
{
|
||||
|
||||
"format": "dp-qpsk",
|
||||
"baud_rate": 32e9,
|
||||
"OSNR": 11,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost":1
|
||||
},
|
||||
{
|
||||
"format": "16-qam",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 15,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost":1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type_variety": "Voyager",
|
||||
"frequency":{
|
||||
"min": 191.35e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode":[
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": 32e9,
|
||||
"OSNR": 12,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
67
examples/2019-demo-services.json
Normal file
67
examples/2019-demo-services.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"path-request": [
|
||||
{
|
||||
"request-id": "first",
|
||||
"source": "netconf:10.0.254.93:830",
|
||||
"destination": "netconf:10.0.254.94:830",
|
||||
"src-tp-id": "trx-Amsterdam",
|
||||
"dst-tp-id": "trx-Bremen",
|
||||
"bidirectional": true,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Cassini",
|
||||
"trx_mode": null,
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"request-id": "second",
|
||||
"source": "netconf:10.0.254.93:830",
|
||||
"destination": "netconf:10.0.254.94:830",
|
||||
"src-tp-id": "trx-Amsterdam",
|
||||
"dst-tp-id": "trx-Bremen",
|
||||
"bidirectional": true,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Cassini",
|
||||
"trx_mode": null,
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"synchronization": [
|
||||
{
|
||||
"synchronization-id": "some redundancy please",
|
||||
"svec": {
|
||||
"relaxable": "false",
|
||||
"disjointness": "node link",
|
||||
"request-id-number": [
|
||||
"first",
|
||||
"second"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1263
examples/2019-demo-topology.json
Normal file
1263
examples/2019-demo-topology.json
Normal file
File diff suppressed because it is too large
Load Diff
179
examples/2019-generate-tip-demo.py
Normal file
179
examples/2019-generate-tip-demo.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# How many nodes in the ring topology? Up to eight is supported, then I ran out of cities..
|
||||
HOW_MANY = 3
|
||||
|
||||
# city names
|
||||
ALL_CITIES = [
|
||||
'Amsterdam',
|
||||
'Bremen',
|
||||
'Cologne',
|
||||
'Dueseldorf',
|
||||
'Eindhoven',
|
||||
'Frankfurt',
|
||||
'Ghent',
|
||||
'Hague',
|
||||
]
|
||||
# end of configurable parameters
|
||||
|
||||
|
||||
J = {
|
||||
"elements": [],
|
||||
"connections": [],
|
||||
}
|
||||
|
||||
def unidir_join(a, b):
|
||||
global J
|
||||
J["connections"].append(
|
||||
{"from_node": a, "to_node": b}
|
||||
)
|
||||
|
||||
def mk_edfa(name, gain, voa=0.0):
|
||||
global J
|
||||
J["elements"].append(
|
||||
{"uid": name, "type": "Edfa", "type_variety": f"fixed{gain}", "operational": {"gain_target": gain, "out_voa": voa}}
|
||||
)
|
||||
|
||||
def add_att(a, b, att):
|
||||
global J
|
||||
if att > 0:
|
||||
uid = f"att-({a})-({b})"
|
||||
else:
|
||||
uid = f"splice-({a})-({b})"
|
||||
J["elements"].append(
|
||||
{"uid": uid, "type": "Fused", "params": {"loss": att}},
|
||||
)
|
||||
unidir_join(a, uid)
|
||||
unidir_join(uid, b)
|
||||
return uid
|
||||
|
||||
def build_fiber(city1, city2):
|
||||
global J
|
||||
J["elements"].append(
|
||||
{
|
||||
"uid": f"fiber-{city1}-{city2}",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": 50,
|
||||
"length_units": "km",
|
||||
"loss_coef": 0.2,
|
||||
"con_in": 1.5,
|
||||
"con_out": 1.5,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
def unidir_patch(a, b):
|
||||
global J
|
||||
uid = f"patch-({a})-({b})"
|
||||
J["elements"].append(
|
||||
{
|
||||
"uid": uid,
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": 0,
|
||||
"length_units": "km",
|
||||
"loss_coef": 0.2,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5,
|
||||
}
|
||||
}
|
||||
)
|
||||
add_att(a, uid, 0.0)
|
||||
add_att(uid, b, 0.0)
|
||||
|
||||
for CITY in (ALL_CITIES[x] for x in range(0, HOW_MANY)):
|
||||
J["elements"].append(
|
||||
{"uid": f"trx-{CITY}", "type": "Transceiver"}
|
||||
)
|
||||
target_pwr = [
|
||||
{"to_node": f"trx-{CITY}", "target_pch_out_db": -25},
|
||||
{"to_node": f"splice-(roadm-{CITY}-AD)-(patch-(roadm-{CITY}-AD)-(roadm-{CITY}-L1))", "target_pch_out_db": -12},
|
||||
{"to_node": f"splice-(roadm-{CITY}-AD)-(patch-(roadm-{CITY}-AD)-(roadm-{CITY}-L2))", "target_pch_out_db": -12},
|
||||
]
|
||||
J["elements"].append(
|
||||
{"uid": f"roadm-{CITY}-AD", "type": "Roadm", "params": {"target_pch_out_db": -2.0, "per_degree_target_pch_out_db": target_pwr}}
|
||||
)
|
||||
unidir_join(f"trx-{CITY}", f"roadm-{CITY}-AD")
|
||||
unidir_join(f"roadm-{CITY}-AD", f"trx-{CITY}")
|
||||
|
||||
for n in (1,2):
|
||||
target_pwr = [
|
||||
{"to_node": f"roadm-{CITY}-L{n}-booster", "target_pch_out_db": -23},
|
||||
{"to_node": f"splice-(roadm-{CITY}-L{n})-(patch-(roadm-{CITY}-L{n})-(roadm-{CITY}-AD))", "target_pch_out_db": -12},
|
||||
]
|
||||
for m in (1,2):
|
||||
if m == n:
|
||||
continue
|
||||
target_pwr.append(
|
||||
{"to_node": f"splice-(roadm-{CITY}-L{n})-(patch-(roadm-{CITY}-L{n})-(roadm-{CITY}-L{m}))", "target_pch_out_db": -12},
|
||||
)
|
||||
J["elements"].append(
|
||||
{"uid": f"roadm-{CITY}-L{n}", "type": "Roadm", "params": {"target_pch_out_db": -23.0, "per_degree_target_pch_out_db": target_pwr}}
|
||||
)
|
||||
mk_edfa(f"roadm-{CITY}-L{n}-booster", 22)
|
||||
mk_edfa(f"roadm-{CITY}-L{n}-preamp", 27)
|
||||
unidir_join(f"roadm-{CITY}-L{n}", f"roadm-{CITY}-L{n}-booster")
|
||||
unidir_join(f"roadm-{CITY}-L{n}-preamp", f"roadm-{CITY}-L{n}")
|
||||
|
||||
unidir_patch(f"roadm-{CITY}-AD", f"roadm-{CITY}-L{n}")
|
||||
unidir_patch(f"roadm-{CITY}-L{n}", f"roadm-{CITY}-AD")
|
||||
for m in (1,2):
|
||||
if m == n:
|
||||
continue
|
||||
#add_att(f"roadm-{CITY}-L{n}", f"roadm-{CITY}-L{m}", 22)
|
||||
unidir_patch(f"roadm-{CITY}-L{n}", f"roadm-{CITY}-L{m}")
|
||||
|
||||
for city1, city2 in ((ALL_CITIES[i], ALL_CITIES[i + 1] if i < HOW_MANY - 1 else ALL_CITIES[0]) for i in range(0, HOW_MANY)):
|
||||
build_fiber(city1, city2)
|
||||
unidir_join(f"roadm-{city1}-L1-booster", f"fiber-{city1}-{city2}")
|
||||
unidir_join(f"fiber-{city1}-{city2}", f"roadm-{city2}-L2-preamp")
|
||||
build_fiber(city2, city1)
|
||||
unidir_join(f"roadm-{city2}-L2-booster", f"fiber-{city2}-{city1}")
|
||||
unidir_join(f"fiber-{city2}-{city1}", f"roadm-{city1}-L1-preamp")
|
||||
|
||||
|
||||
for _, E in enumerate(J["elements"]):
|
||||
uid = E["uid"]
|
||||
if uid.startswith("roadm-") and (uid.endswith("-L1-booster") or uid.endswith("-L2-booster")):
|
||||
E["operational"]["out_voa"] = 12.0
|
||||
#if uid.endswith("-AD-add"):
|
||||
# E["operational"]["out_voa"] = 21
|
||||
|
||||
translate = {
|
||||
#"trx-Amsterdam": "10.0.254.93",
|
||||
#"trx-Bremen": "10.0.254.94",
|
||||
"trx-Amsterdam": "10.0.254.76",
|
||||
"trx-Bremen": "10.0.254.77",
|
||||
|
||||
# Amsterdam A/D: coherent-v9u
|
||||
"roadm-Amsterdam-AD": "10.0.254.107",
|
||||
# Bremen A/D: -spi
|
||||
"roadm-Bremen-AD": "10.0.254.225",
|
||||
|
||||
# Amsterdam -> Bremen ...QR79
|
||||
"roadm-Amsterdam-L1": "10.0.254.78",
|
||||
# Bremen -> Amsterdam ...QCP9
|
||||
"roadm-Bremen-L2": "10.0.254.102",
|
||||
|
||||
# Bremen -> Cologne ...WKP
|
||||
"roadm-Bremen-L1": "10.0.254.100",
|
||||
# Cologne -> Bremen ...QLK6
|
||||
"roadm-Cologne-L2": "10.0.254.104",
|
||||
|
||||
# Cologne -> Amsterdam ...TQQ
|
||||
"roadm-Cologne-L1": "10.0.254.99",
|
||||
# Amsterdam -> Cologne ...Q7JS
|
||||
"roadm-Amsterdam-L2": "10.0.254.79",
|
||||
|
||||
# spare Line/Degree ...QC8B
|
||||
"spare-line-degree": "10.0.254.101",
|
||||
# spare Add/Drop: ...NNN
|
||||
"spare-add-drop": "10.0.254.228",
|
||||
}
|
||||
|
||||
import json
|
||||
s = json.dumps(J, indent=2)
|
||||
for (old, new) in translate.items():
|
||||
s = s.replace(f'"{old}"', f'"netconf:{new}:830"')
|
||||
print(s)
|
||||
1033
examples/demo.json
Normal file
1033
examples/demo.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ from json import dumps, loads
|
||||
from numpy import mean
|
||||
from gnpy.core.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, save_network
|
||||
from gnpy.core.network import load_network, build_network, save_network, network_from_json
|
||||
from gnpy.core.equipment import load_equipment, trx_mode_params, automatic_nch
|
||||
from gnpy.core.elements import Transceiver, Roadm
|
||||
from gnpy.core.utils import db2lin, lin2db
|
||||
@@ -38,6 +38,9 @@ from copy import copy, deepcopy
|
||||
from textwrap import dedent
|
||||
from math import ceil
|
||||
|
||||
from flask import Flask, jsonify, make_response, request
|
||||
from flask_restful import Api, Resource, reqparse, fields
|
||||
|
||||
#EQPT_LIBRARY_FILENAME = Path(__file__).parent / 'eqpt_config.json'
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
@@ -58,7 +61,12 @@ PARSER.add_argument('-bi', '--bidir', action='store_true',\
|
||||
PARSER.add_argument('-v', '--verbose', action='count', default=0,\
|
||||
help='increases verbosity for each occurence')
|
||||
PARSER.add_argument('-o', '--output', type=Path)
|
||||
PARSER.add_argument('-r', '--rest', action='count', default=0, help='use the REST API')
|
||||
|
||||
NETWORK_FILENAME = 'topoDemov1.json' #'disagregatedTopoDemov1.json' #
|
||||
|
||||
APP = Flask(__name__, static_url_path="")
|
||||
API = Api(APP)
|
||||
|
||||
def requests_from_json(json_data, equipment):
|
||||
""" converts the json data into a list of requests elements
|
||||
@@ -360,32 +368,9 @@ def path_result_json(pathresult):
|
||||
}
|
||||
return data
|
||||
|
||||
def main(args):
|
||||
""" main function that calls all functions
|
||||
def compute_requests(network, data, equipment):
|
||||
""" Main program calling functions
|
||||
"""
|
||||
LOGGER.info(f'Computing path requests {args.service_filename} into JSON format')
|
||||
print('\x1b[1;34;40m' +\
|
||||
f'Computing path requests {args.service_filename} into JSON format'+ '\x1b[0m')
|
||||
# for debug
|
||||
# print( args.eqpt_filename)
|
||||
|
||||
try:
|
||||
data = load_requests(args.service_filename, args.eqpt_filename, args.bidir)
|
||||
equipment = load_equipment(args.eqpt_filename)
|
||||
network = load_network(args.network_filename, equipment)
|
||||
except EquipmentConfigError as this_e:
|
||||
print(f'{ansi_escapes.red}Configuration error in the equipment library:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
except NetworkTopologyError as this_e:
|
||||
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
except ConfigurationError as this_e:
|
||||
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
except ServiceError as this_e:
|
||||
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
|
||||
# Build the network once using the default power defined in SI in eqpt config
|
||||
# TODO power density: db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by
|
||||
# spacing, f_min and f_max
|
||||
@@ -394,7 +379,7 @@ def main(args):
|
||||
p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\
|
||||
equipment['SI']['default'].f_max, equipment['SI']['default'].spacing))
|
||||
build_network(network, equipment, p_db, p_total_db)
|
||||
save_network(args.network_filename, network)
|
||||
save_network(ARGS.network_filename, network)
|
||||
|
||||
oms_list = build_oms_list(network, equipment)
|
||||
|
||||
@@ -402,7 +387,7 @@ def main(args):
|
||||
rqs = requests_from_json(data, equipment)
|
||||
except ServiceError as this_e:
|
||||
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
raise this_e
|
||||
# check that request ids are unique. Non unique ids, may
|
||||
# mess the computation: better to stop the computation
|
||||
all_ids = [r.request_id for r in rqs]
|
||||
@@ -411,12 +396,13 @@ def main(args):
|
||||
all_ids.remove(item)
|
||||
msg = f'Requests id {all_ids} are not unique'
|
||||
LOGGER.critical(msg)
|
||||
exit()
|
||||
raise ServiceError(msg)
|
||||
try:
|
||||
rqs = correct_route_list(network, rqs)
|
||||
except ServiceError as this_e:
|
||||
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
raise this_e
|
||||
#exit(1)
|
||||
# pths = compute_path(network, equipment, rqs)
|
||||
dsjn = disjunctions_from_json(data)
|
||||
|
||||
@@ -440,7 +426,7 @@ def main(args):
|
||||
pths = compute_path_dsjctn(network, equipment, rqs, dsjn)
|
||||
except DisjunctionError as this_e:
|
||||
print(f'{ansi_escapes.red}Disjunction error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
raise this_e
|
||||
|
||||
print('\x1b[1;34;40m' + f'Propagating on selected path' + '\x1b[0m')
|
||||
propagatedpths, reversed_pths, reversed_propagatedpths = \
|
||||
@@ -493,20 +479,89 @@ def main(args):
|
||||
print('\x1b[1;33;40m'+f'Result summary shows mean SNR and OSNR (average over all channels)' +\
|
||||
'\x1b[0m')
|
||||
|
||||
if args.output:
|
||||
return propagatedpths, reversed_propagatedpths, rqs
|
||||
|
||||
|
||||
def launch_cli(network, data, equipment):
|
||||
""" Compute requests using network, data and equipment with client line interface
|
||||
"""
|
||||
propagatedpths, reversed_propagatedpths, rqs = compute_requests(network, data, equipment)
|
||||
#Generate the output
|
||||
if ARGS.output :
|
||||
result = []
|
||||
# assumes that list of rqs and list of propgatedpths have same order
|
||||
for i, pth in enumerate(propagatedpths):
|
||||
result.append(Result_element(rqs[i], pth, reversed_propagatedpths[i]))
|
||||
temp = path_result_json(result)
|
||||
fnamecsv = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.csv'
|
||||
fnamejson = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.json'
|
||||
fnamecsv = f'{str(ARGS.output)[0:len(str(ARGS.output))-len(str(ARGS.output.suffix))]}.csv'
|
||||
fnamejson = f'{str(ARGS.output)[0:len(str(ARGS.output))-len(str(ARGS.output.suffix))]}.json'
|
||||
with open(fnamejson, 'w', encoding='utf-8') as fjson:
|
||||
fjson.write(dumps(path_result_json(result), indent=2, ensure_ascii=False))
|
||||
with open(fnamecsv, "w", encoding='utf-8') as fcsv:
|
||||
jsontocsv(temp, equipment, fcsv)
|
||||
print('\x1b[1;34;40m'+f'saving in {args.output} and {fnamecsv}'+ '\x1b[0m')
|
||||
print('\x1b[1;34;40m'+f'saving in {ARGS.output} and {fnamecsv}'+ '\x1b[0m')
|
||||
|
||||
class GnpyAPI(Resource):
|
||||
""" Compute requests using network, data and equipment with rest api
|
||||
"""
|
||||
def get(self):
|
||||
return {"ping": True}, 200
|
||||
|
||||
def post(self):
|
||||
data = request.get_json()
|
||||
equipment = load_equipment('examples/2019-demo-equipment.json')
|
||||
topo_json = load_json('examples/2019-demo-topology.json')
|
||||
network = network_from_json(topo_json, equipment)
|
||||
try:
|
||||
propagatedpths, reversed_propagatedpths, rqs = compute_requests(network, data, equipment)
|
||||
# Generate the output
|
||||
result = []
|
||||
#assumes that list of rqs and list of propgatedpths have same order
|
||||
for i, pth in enumerate(propagatedpths):
|
||||
result.append(Result_element(rqs[i], pth, reversed_propagatedpths[i]))
|
||||
|
||||
return {"result":path_result_json(result)}, 201
|
||||
except ServiceError as this_e:
|
||||
msg = f'Service error: {this_e}'
|
||||
return {"result": msg}, 400
|
||||
|
||||
API.add_resource(GnpyAPI, '/gnpy-experimental')
|
||||
|
||||
def main(args):
|
||||
""" main function that calls all functions
|
||||
"""
|
||||
LOGGER.info(f'Computing path requests {args.service_filename} into JSON format')
|
||||
print('\x1b[1;34;40m' +\
|
||||
f'Computing path requests {args.service_filename} into JSON format'+ '\x1b[0m')
|
||||
# for debug
|
||||
# print( args.eqpt_filename)
|
||||
|
||||
try:
|
||||
data = load_requests(args.service_filename, args.eqpt_filename, args.bidir)
|
||||
equipment = load_equipment(args.eqpt_filename)
|
||||
network = load_network(args.network_filename, equipment)
|
||||
except EquipmentConfigError as this_e:
|
||||
print(f'{ansi_escapes.red}Configuration error in the equipment library:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
except NetworkTopologyError as this_e:
|
||||
print(f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
except ConfigurationError as this_e:
|
||||
print(f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
except ServiceError as this_e:
|
||||
print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}')
|
||||
exit(1)
|
||||
# input_str = raw_input("How will you use your program: c:[cli] , a:[api] ?")
|
||||
# print(input_str)
|
||||
#
|
||||
if ((args.rest == 1) and (args.output is None)):
|
||||
print('you have chosen the rest mode')
|
||||
APP.run(host='0.0.0.0', port=5000, debug=True)
|
||||
elif ((args.rest > 1) or ((args.rest == 1) and (args.output is not None))):
|
||||
print('command is not well formulated')
|
||||
else:
|
||||
launch_cli(network, data, equipment)
|
||||
|
||||
if __name__ == '__main__':
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
180
examples/serviceDemov1.json
Normal file
180
examples/serviceDemov1.json
Normal file
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"path-request": [
|
||||
{
|
||||
"request-id": "0",
|
||||
"source": "trx site_a",
|
||||
"destination": "trx site_b",
|
||||
"src-tp-id": "trx site_a",
|
||||
"dst-tp-id": "trx site_b",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": null,
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"request-id": "1",
|
||||
"source": "trx site_a",
|
||||
"destination": "trx site_b",
|
||||
"src-tp-id": "trx site_a",
|
||||
"dst-tp-id": "trx site_b",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": "mode 1",
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 200000000000.0
|
||||
}
|
||||
},
|
||||
"explicit-route-objects": {
|
||||
"route-object-include-exclude": [
|
||||
{
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"index": 0,
|
||||
"num-unnum-hop": {
|
||||
"node-id": "Span1ab",
|
||||
"link-tp-id": "link-tp-id is not used",
|
||||
"hop-type": "STRICT"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"request-id": "2",
|
||||
"source": "trx site_a",
|
||||
"destination": "trx site_b",
|
||||
"src-tp-id": "trx site_a",
|
||||
"dst-tp-id": "trx site_b",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": "mode 1",
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 200000000000.0
|
||||
}
|
||||
},
|
||||
"explicit-route-objects": {
|
||||
"route-object-include-exclude": [
|
||||
{
|
||||
"explicit-route-usage": "route-include-ero",
|
||||
"index": 0,
|
||||
"num-unnum-hop": {
|
||||
"node-id": "roadm site_c",
|
||||
"link-tp-id": "link-tp-id is not used",
|
||||
"hop-type": "STRICT"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"request-id": "3",
|
||||
"source": "trx site_a",
|
||||
"destination": "trx site_b",
|
||||
"src-tp-id": "trx site_a",
|
||||
"dst-tp-id": "trx site_b",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": null,
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"request-id": "4",
|
||||
"source": "trx site_a",
|
||||
"destination": "trx site_b",
|
||||
"src-tp-id": "trx site_a",
|
||||
"dst-tp-id": "trx site_b",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": null,
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": "null",
|
||||
"M": "null"
|
||||
}
|
||||
],
|
||||
"spacing": 50000000000.0,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"synchronization": [
|
||||
{
|
||||
"synchronization-id": "x",
|
||||
"svec": {
|
||||
"relaxable": "false",
|
||||
"disjointness": "node link",
|
||||
"request-id-number": [
|
||||
"3",
|
||||
"0"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"synchronization-id": "y",
|
||||
"svec": {
|
||||
"relaxable": "false",
|
||||
"disjointness": "node link",
|
||||
"request-id-number": [
|
||||
"4",
|
||||
"3",
|
||||
"0"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
703
examples/topoDemov1.json
Normal file
703
examples/topoDemov1.json
Normal file
@@ -0,0 +1,703 @@
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"uid": "trx site_a",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0,
|
||||
"longitude": 0,
|
||||
"city": "Site a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "roadm site_a",
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"target_pch_out_db": -20,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0,
|
||||
"longitude": 0,
|
||||
"city": "Site a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1ab",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 100.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1ba",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 100.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span2ab",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span2ba",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "roadm site_b",
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"target_pch_out_db": -20,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0,
|
||||
"longitude": 0,
|
||||
"city": "Site b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "trx site_b",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 2,
|
||||
"longitude": 0,
|
||||
"city": "Site b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster1 site_a",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp site_b",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster1 site_b",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp1 site_a",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster2 site_a",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp2 site_b",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster2 site_b",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp2 site_a",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster3 site_a",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp3 site_b",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster3 site_b",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site b",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp3 site_a",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_a",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "roadm site_c",
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"target_pch_out_db": -20,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0,
|
||||
"longitude": 0,
|
||||
"city": "Site c",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster1 site_c",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site c",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp1 site_c",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_c",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "booster2 site_c",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_medium_gain",
|
||||
"operational": {
|
||||
"gain_target": 19.0,
|
||||
"delta_p": -1.0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site c",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "preamp2 site_c",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 18.0,
|
||||
"delta_p": 0,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 0.5,
|
||||
"longitude": 0.0,
|
||||
"city": "Site_c",
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1ac",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1ca",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1bc",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1cb",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"type_variety": "SSMF",
|
||||
"length": 80.0,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"latitude": 1,
|
||||
"longitude": 0,
|
||||
"city": null,
|
||||
"region": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "trx site_a",
|
||||
"to_node": "roadm site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_a",
|
||||
"to_node": "booster1 site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "booster1 site_a",
|
||||
"to_node": "Span1ab"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1ab",
|
||||
"to_node": "preamp site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp site_b",
|
||||
"to_node": "roadm site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_b",
|
||||
"to_node": "trx site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_a",
|
||||
"to_node": "booster2 site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "booster2 site_a",
|
||||
"to_node": "Span2ab"
|
||||
},
|
||||
{
|
||||
"from_node": "Span2ab",
|
||||
"to_node": "preamp2 site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp2 site_b",
|
||||
"to_node": "roadm site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_b",
|
||||
"to_node": "booster1 site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "booster1 site_b",
|
||||
"to_node": "Span1ba"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1ba",
|
||||
"to_node": "preamp1 site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp1 site_a",
|
||||
"to_node": "roadm site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_b",
|
||||
"to_node": "booster2 site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "booster2 site_b",
|
||||
"to_node": "Span2ba"
|
||||
},
|
||||
{
|
||||
"from_node": "Span2ba",
|
||||
"to_node": "preamp2 site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp2 site_a",
|
||||
"to_node": "roadm site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_a",
|
||||
"to_node": "booster3 site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "booster3 site_a",
|
||||
"to_node": "Span1ac"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1ac",
|
||||
"to_node": "preamp1 site_c"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp1 site_c",
|
||||
"to_node": "roadm site_c"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_c",
|
||||
"to_node": "booster1 site_c"
|
||||
},
|
||||
{
|
||||
"from_node": "booster1 site_c",
|
||||
"to_node": "Span1cb"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1cb",
|
||||
"to_node": "preamp3 site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp3 site_b",
|
||||
"to_node": "roadm site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_b",
|
||||
"to_node": "booster3 site_b"
|
||||
},
|
||||
{
|
||||
"from_node": "booster3 site_b",
|
||||
"to_node": "Span1bc"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1bc",
|
||||
"to_node": "preamp2 site_c"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp2 site_c",
|
||||
"to_node": "roadm site_c"
|
||||
},
|
||||
{
|
||||
"from_node": "roadm site_c",
|
||||
"to_node": "booster2 site_c"
|
||||
},
|
||||
{
|
||||
"from_node": "booster2 site_c",
|
||||
"to_node": "Span1ca"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1ca",
|
||||
"to_node": "preamp3 site_a"
|
||||
},
|
||||
{
|
||||
"from_node": "preamp3 site_a",
|
||||
"to_node": "roadm site_a"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -118,16 +118,19 @@ class Transceiver(Node):
|
||||
self._calc_snr(spectral_info)
|
||||
return spectral_info
|
||||
|
||||
RoadmParams = namedtuple('RoadmParams', 'target_pch_out_db add_drop_osnr restrictions')
|
||||
RoadmParams = namedtuple('RoadmParams', 'target_pch_out_db add_drop_osnr restrictions per_degree_target_pch_out_db')
|
||||
|
||||
class Roadm(Node):
|
||||
def __init__(self, *args, params, **kwargs):
|
||||
if 'per_degree_target_pch_out_db' not in params.keys():
|
||||
params['per_degree_target_pch_out_db'] = []
|
||||
super().__init__(*args, params=RoadmParams(**params), **kwargs)
|
||||
self.loss = 0 #auto-design interest
|
||||
self.effective_loss = None
|
||||
self.effective_pch_out_db = self.params.target_pch_out_db
|
||||
self.passive = True
|
||||
self.restrictions = self.params.restrictions
|
||||
self.per_degree_target_pch_out_db = self.params.per_degree_target_pch_out_db
|
||||
|
||||
@property
|
||||
def to_json(self):
|
||||
@@ -135,7 +138,8 @@ class Roadm(Node):
|
||||
'type' : type(self).__name__,
|
||||
'params' : {
|
||||
'target_pch_out_db' : self.effective_pch_out_db,
|
||||
'restrictions' : self.restrictions
|
||||
'restrictions' : self.restrictions,
|
||||
'per_degree_target_pch_out_db': self.per_degree_target_pch_out_db
|
||||
},
|
||||
'metadata' : {
|
||||
'location': self.metadata['location']._asdict()
|
||||
@@ -150,15 +154,26 @@ class Roadm(Node):
|
||||
f' effective loss (dB): {self.effective_loss:.2f}',
|
||||
f' pch out (dBm): {self.effective_pch_out_db!r}'])
|
||||
|
||||
def propagate(self, pref, *carriers):
|
||||
def propagate(self, pref, *carriers, degree):
|
||||
#pin_target and loss are read from eqpt_config.json['Roadm']
|
||||
#all ingress channels in xpress are set to this power level
|
||||
#but add channels are not, so we define an effective loss
|
||||
#in the case of add channels
|
||||
self.effective_pch_out_db = min(pref.p_spani, self.params.target_pch_out_db)
|
||||
if self.per_degree_target_pch_out_db:
|
||||
# find the target power on this degree
|
||||
try:
|
||||
temp = next(el['target_pch_out_db'] \
|
||||
for el in self.per_degree_target_pch_out_db if el['to_node']==degree)
|
||||
except StopIteration:
|
||||
# if no target power is defined on this degree use the global one
|
||||
temp = self.params.target_pch_out_db
|
||||
else:
|
||||
# if no per degree target power are defined, use the global one
|
||||
temp = self.params.target_pch_out_db
|
||||
self.effective_pch_out_db = min(pref.p_spani, temp)
|
||||
self.effective_loss = pref.p_spani - self.effective_pch_out_db
|
||||
carriers_power = array([c.power.signal +c.power.nli+c.power.ase for c in carriers])
|
||||
carriers_att = list(map(lambda x : lin2db(x*1e3)-self.params.target_pch_out_db, carriers_power))
|
||||
carriers_att = list(map(lambda x : lin2db(x*1e3)-self.effective_pch_out_db, carriers_power))
|
||||
exceeding_att = -min(list(filter(lambda x: x < 0, carriers_att)), default = 0)
|
||||
carriers_att = list(map(lambda x: db2lin(x+exceeding_att), carriers_att))
|
||||
for carrier_att, carrier in zip(carriers_att, carriers) :
|
||||
@@ -171,8 +186,8 @@ class Roadm(Node):
|
||||
def update_pref(self, pref):
|
||||
return pref._replace(p_span0=pref.p_span0, p_spani=self.effective_pch_out_db)
|
||||
|
||||
def __call__(self, spectral_info):
|
||||
carriers = tuple(self.propagate(spectral_info.pref, *spectral_info.carriers))
|
||||
def __call__(self, spectral_info, degree):
|
||||
carriers = tuple(self.propagate(spectral_info.pref, *spectral_info.carriers, degree=degree))
|
||||
pref = self.update_pref(spectral_info.pref)
|
||||
return spectral_info._replace(carriers=carriers, pref=pref)
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ def prev_node_generator(network, node):
|
||||
except StopIteration:
|
||||
raise NetworkTopologyError(f'Node {node.uid} is not properly connected, please check network topology')
|
||||
# yield and re-iterate
|
||||
if isinstance(prev_node, Fused) or isinstance(node, Fused):
|
||||
if isinstance(prev_node, Fused) or isinstance(node, Fused) and not isinstance(prev_node, Roadm):
|
||||
yield prev_node
|
||||
yield from prev_node_generator(network, prev_node)
|
||||
else:
|
||||
@@ -247,7 +247,7 @@ def next_node_generator(network, node):
|
||||
except StopIteration:
|
||||
raise NetworkTopologyError('Node {node.uid} is not properly connected, please check network topology')
|
||||
# yield and re-iterate
|
||||
if isinstance(next_node, Fused) or isinstance(node, Fused):
|
||||
if isinstance(next_node, Fused) or isinstance(node, Fused) and not isinstance(next_node, Roadm):
|
||||
yield next_node
|
||||
yield from next_node_generator(network, next_node)
|
||||
else:
|
||||
@@ -315,7 +315,18 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
||||
# node = find_last_node(next_node)
|
||||
# next_node = next(n for n in network.successors(node))
|
||||
# next_node = find_last_node(next_node)
|
||||
prev_dp = getattr(node.params, 'target_pch_out_db', 0)
|
||||
|
||||
if node.per_degree_target_pch_out_db:
|
||||
# find the target power on this degree
|
||||
try:
|
||||
prev_dp = next(el["target_pch_out_db"] for el in \
|
||||
node.per_degree_target_pch_out_db if el["to_node"]==next_node.uid)
|
||||
except StopIteration:
|
||||
# if no target power is defined on this degree use the global one
|
||||
prev_dp = getattr(node.params, 'target_pch_out_db', 0)
|
||||
else:
|
||||
# if no per degree target power is given use the global one
|
||||
prev_dp = getattr(node.params, 'target_pch_out_db', 0)
|
||||
dp = prev_dp
|
||||
prev_voa = 0
|
||||
voa = 0
|
||||
|
||||
@@ -122,6 +122,15 @@ BLOCKING_NOPATH = ['NO_PATH', 'NO_PATH_WITH_CONSTRAINT',\
|
||||
BLOCKING_NOMODE = ['NO_FEASIBLE_MODE', 'MODE_NOT_FEASIBLE']
|
||||
BLOCKING_NOSPECTRUM = 'NO_SPECTRUM'
|
||||
|
||||
def element_to_node_type(element):
|
||||
if isinstance(element, Transceiver):
|
||||
return "transceiver"
|
||||
if isinstance(element, Edfa):
|
||||
return "EDFA"
|
||||
if isinstance(element, Roadm):
|
||||
return "ROADM"
|
||||
return None
|
||||
|
||||
class Result_element(Element):
|
||||
def __init__(self, path_request, computed_path, reversed_computed_path=None):
|
||||
self.path_id = path_request.request_id
|
||||
@@ -131,13 +140,13 @@ class Result_element(Element):
|
||||
if reversed_computed_path is not None:
|
||||
self.reversed_computed_path = reversed_computed_path
|
||||
uid = property(lambda self: repr(self))
|
||||
@property
|
||||
def detailed_path_json(self):
|
||||
|
||||
def detailed_path_json(self, path):
|
||||
""" a function that builds path object for normal and blocking cases
|
||||
"""
|
||||
index = 0
|
||||
pro_list = []
|
||||
for element in self.computed_path:
|
||||
for element in path:
|
||||
temp = {
|
||||
'path-route-object': {
|
||||
'index': index,
|
||||
@@ -148,6 +157,9 @@ class Result_element(Element):
|
||||
}
|
||||
}
|
||||
}
|
||||
node_type = element_to_node_type(element)
|
||||
if (node_type is not None):
|
||||
temp['path-route-object']['num-unnum-hop']['gnpy-node-type'] = node_type
|
||||
pro_list.append(temp)
|
||||
index += 1
|
||||
if self.path_request.M > 0:
|
||||
@@ -180,6 +192,31 @@ class Result_element(Element):
|
||||
}
|
||||
pro_list.append(temp)
|
||||
index += 1
|
||||
if isinstance(element, Roadm):
|
||||
temp = {
|
||||
'path-route-object': {
|
||||
'index': index,
|
||||
'target-channel-power' : {
|
||||
'value' : element.effective_pch_out_db,
|
||||
}
|
||||
}
|
||||
}
|
||||
pro_list.append(temp)
|
||||
index += 1
|
||||
if isinstance(element, Edfa):
|
||||
temp = {
|
||||
'path-route-object': {
|
||||
'index': index,
|
||||
'target-channel-power' : {
|
||||
'value': element.effective_pch_out_db,
|
||||
},
|
||||
'output-voa': {
|
||||
'value': element.out_voa,
|
||||
}
|
||||
}
|
||||
}
|
||||
pro_list.append(temp)
|
||||
index += 1
|
||||
return pro_list
|
||||
@property
|
||||
def path_properties(self):
|
||||
@@ -218,12 +255,13 @@ class Result_element(Element):
|
||||
path_properties = {
|
||||
'path-metric': path_metric(self.computed_path, self.path_request),
|
||||
'z-a-path-metric': path_metric(self.reversed_computed_path, self.path_request),
|
||||
'path-route-objects': self.detailed_path_json
|
||||
'path-route-objects': self.detailed_path_json(self.computed_path),
|
||||
'reversed-path-route-objects': self.detailed_path_json(self.reversed_computed_path),
|
||||
}
|
||||
else:
|
||||
path_properties = {
|
||||
'path-metric': path_metric(self.computed_path, self.path_request),
|
||||
'path-route-objects': self.detailed_path_json
|
||||
'path-route-objects': self.detailed_path_json(self.computed_path)
|
||||
}
|
||||
return path_properties
|
||||
|
||||
@@ -383,8 +421,13 @@ def propagate(path, req, equipment):
|
||||
si = create_input_spectral_information(
|
||||
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
||||
req.power, req.spacing)
|
||||
for el in path:
|
||||
si = el(si)
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
next_el = path[i+1]
|
||||
si = el(si, degree=next_el.uid)
|
||||
else:
|
||||
si = el(si)
|
||||
print(el)
|
||||
path[-1].update_snr(req.tx_osnr, equipment['Roadm']['default'].add_drop_osnr)
|
||||
return path
|
||||
|
||||
@@ -393,9 +436,13 @@ def propagate2(path, req, equipment):
|
||||
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
||||
req.power, req.spacing)
|
||||
infos = {}
|
||||
for el in path:
|
||||
for i, el in enumerate(path):
|
||||
before_si = si
|
||||
after_si = si = el(si)
|
||||
if isinstance(el, Roadm):
|
||||
next_el = path[i+1]
|
||||
after_si = si = el(si, degree=next_el.uid)
|
||||
else:
|
||||
after_si = si = el(si)
|
||||
infos[el] = before_si, after_si
|
||||
path[-1].update_snr(req.tx_osnr, equipment['Roadm']['default'].add_drop_osnr)
|
||||
return infos
|
||||
@@ -424,8 +471,12 @@ def propagate_and_optimize_mode(path, req, equipment):
|
||||
spc_info = create_input_spectral_information(req.f_min, req.f_max,
|
||||
equipment['SI']['default'].roll_off,
|
||||
this_br, req.power, req.spacing)
|
||||
for el in path:
|
||||
spc_info = el(spc_info)
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
next_el = path[i+1]
|
||||
spc_info = el(spc_info, degree=next_el.uid)
|
||||
else:
|
||||
spc_info = el(spc_info)
|
||||
for this_mode in modes_to_explore:
|
||||
if path[-1].snr is not None:
|
||||
path[-1].update_snr(this_mode['tx_osnr'], equipment['Roadm']['default'].add_drop_osnr)
|
||||
|
||||
@@ -59,6 +59,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -1,5 +1,7 @@
|
||||
alabaster>=0.7.12,<1
|
||||
docutils==0.15.2
|
||||
flask==1.0.2
|
||||
flask-restful==0.3.7
|
||||
matplotlib>=3.1.0,<4
|
||||
networkx>=2.3,<3
|
||||
numpy>=1.16.1,<2
|
||||
|
||||
@@ -47,24 +47,25 @@
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": null,
|
||||
"trx_mode": null,
|
||||
"trx_type": "name of the tsp type_variety as listed in the library",
|
||||
"trx_mode": "optional, name of the mode as listed in the tsp type_variety",
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"n": "null",
|
||||
"m": "null"
|
||||
}
|
||||
],
|
||||
"spacing": null,
|
||||
"max-nb-of-channel": null,
|
||||
"output-power": null,
|
||||
"path_bandwidth": null
|
||||
}
|
||||
"spacing": mandatory decimal Hz,
|
||||
"max-nb-of-channel": optional integer,
|
||||
"output-power": optional decimal W,
|
||||
"path_bandwidth": optional bit/s
|
||||
}
|
||||
}
|
||||
}],
|
||||
"synchronization": [
|
||||
}
|
||||
],
|
||||
"synchronization": [ list of disjunctions, optional
|
||||
{
|
||||
"synchronization-id": null,
|
||||
"synchronization-id": "3",
|
||||
"svec": {
|
||||
"relaxable": "True",
|
||||
"disjointness": "node link",
|
||||
@@ -72,5 +73,5 @@
|
||||
null, null ]
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user